https://git.reactos.org/?p=reactos.git;a=commitdiff;h=faf62979728ec2e6a596e…
commit faf62979728ec2e6a596ec6f3921e318f168bcfc
Author: Eric Kohl <eric.kohl(a)reactos.org>
AuthorDate: Sun Jan 5 16:38:04 2025 +0100
Commit: Eric Kohl <eric.kohl(a)reactos.org>
CommitDate: Sun Jan 5 16:38:04 2025 +0100
[NETAPI32][WKSSVC][IDL] Implement NetrWkstaUserEnum
- TODO: Take PreferredMaximumLength and ResumeHandle into account
---
base/services/wkssvc/rpcserver.c | 239 ++++++++++++++++++++++++++++++++++++-
dll/win32/netapi32/wksta_new.c | 32 +++--
sdk/include/reactos/idl/wkssvc.idl | 13 +-
3 files changed, 267 insertions(+), 17 deletions(-)
diff --git a/base/services/wkssvc/rpcserver.c b/base/services/wkssvc/rpcserver.c
index fe39af081bc..fc9cf12433b 100644
--- a/base/services/wkssvc/rpcserver.c
+++ b/base/services/wkssvc/rpcserver.c
@@ -447,12 +447,243 @@ NetrWkstaUserEnum(
unsigned long *TotalEntries,
unsigned long *ResumeHandle)
{
- ERR("NetrWkstaUserEnum(%p %p 0x%lx %p %p)\n",
- ServerName, UserInfo, PreferredMaximumLength, TotalEntries, ResumeHandle);
+ MSV1_0_ENUMUSERS_REQUEST EnumRequest;
+ PMSV1_0_ENUMUSERS_RESPONSE EnumResponseBuffer = NULL;
+ MSV1_0_GETUSERINFO_REQUEST UserInfoRequest;
+ PMSV1_0_GETUSERINFO_RESPONSE UserInfoResponseBuffer = NULL;
+ PMSV1_0_GETUSERINFO_RESPONSE *UserInfoArray = NULL;
+ DWORD EnumResponseBufferSize = 0;
+ DWORD UserInfoResponseBufferSize = 0;
+ NTSTATUS Status, ProtocolStatus;
+ ULONG i, start, count;
+ PLUID pLogonId;
+ PULONG pEnumHandle;
+ DWORD dwResult = NERR_Success;
+ PWKSTA_USER_INFO_0 pUserInfo0 = NULL;
+ PWKSTA_USER_INFO_1 pUserInfo1 = NULL;
- UNIMPLEMENTED;
- return 0;
+ TRACE("NetrWkstaUserEnum(%p %p 0x%lx %p %p)\n",
+ ServerName, UserInfo, PreferredMaximumLength, TotalEntries, ResumeHandle);
+
+ if (UserInfo->Level > 1)
+ {
+ ERR("Invalid Level %lu\n", UserInfo->Level);
+ return ERROR_INVALID_LEVEL;
+ }
+
+ /* Enumerate all currently logged-on users */
+ EnumRequest.MessageType = MsV1_0EnumerateUsers;
+ Status = LsaCallAuthenticationPackage(LsaHandle,
+ LsaAuthenticationPackage,
+ &EnumRequest,
+ sizeof(EnumRequest),
+ (PVOID*)&EnumResponseBuffer,
+ &EnumResponseBufferSize,
+ &ProtocolStatus);
+
+ TRACE("LsaCallAuthenticationPackage Status 0x%08lx ResponseBufferSize
%lu\n", Status, EnumResponseBufferSize);
+ if (!NT_SUCCESS(Status))
+ {
+ dwResult = RtlNtStatusToDosError(Status);
+ goto done;
+ }
+
+ TRACE("LoggedOnUsers: %lu\n",
EnumResponseBuffer->NumberOfLoggedOnUsers);
+ TRACE("ResponseBuffer: 0x%p\n", EnumResponseBuffer);
+ TRACE("LogonIds: 0x%p\n", EnumResponseBuffer->LogonIds);
+ TRACE("EnumHandles: 0x%p\n", EnumResponseBuffer->EnumHandles);
+ if (EnumResponseBuffer->NumberOfLoggedOnUsers > 0)
+ {
+ pLogonId = EnumResponseBuffer->LogonIds;
+ pEnumHandle = EnumResponseBuffer->EnumHandles;
+ TRACE("pLogonId: 0x%p\n", pLogonId);
+ TRACE("pEnumHandle: 0x%p\n", pEnumHandle);
+
+ UserInfoArray = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ EnumResponseBuffer->NumberOfLoggedOnUsers *
sizeof(PMSV1_0_GETUSERINFO_RESPONSE));
+ if (UserInfoArray == NULL)
+ {
+ dwResult = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ for (i = 0; i < EnumResponseBuffer->NumberOfLoggedOnUsers; i++)
+ {
+ TRACE("Logon %lu: 0x%08lx %lu\n", i, pLogonId->LowPart,
*pEnumHandle);
+
+ UserInfoRequest.MessageType = MsV1_0GetUserInfo;
+ UserInfoRequest.LogonId = *pLogonId;
+ Status = LsaCallAuthenticationPackage(LsaHandle,
+ LsaAuthenticationPackage,
+ &UserInfoRequest,
+ sizeof(UserInfoRequest),
+ (PVOID*)&UserInfoResponseBuffer,
+ &UserInfoResponseBufferSize,
+ &ProtocolStatus);
+ TRACE("LsaCallAuthenticationPackage:MsV1_0GetUserInfo Status 0x%08lx
ResponseBufferSize %lu\n", Status, UserInfoResponseBufferSize);
+ if (!NT_SUCCESS(Status))
+ {
+ dwResult = RtlNtStatusToDosError(Status);
+ goto done;
+ }
+
+ UserInfoArray[i] = UserInfoResponseBuffer;
+
+ TRACE("UserName: %wZ\n", &UserInfoArray[i]->UserName);
+ TRACE("LogonDomain: %wZ\n",
&UserInfoArray[i]->LogonDomainName);
+ TRACE("LogonServer: %wZ\n",
&UserInfoArray[i]->LogonServer);
+
+ pLogonId++;
+ pEnumHandle++;
+ }
+
+ if (PreferredMaximumLength == MAX_PREFERRED_LENGTH)
+ {
+ start = 0;
+ count = EnumResponseBuffer->NumberOfLoggedOnUsers;
+ }
+ else
+ {
+ FIXME("Calculate the start index and the number of matching array
entries!");
+ dwResult = ERROR_CALL_NOT_IMPLEMENTED;
+ goto done;
+ }
+
+ switch (UserInfo->Level)
+ {
+ case 0:
+ pUserInfo0 = midl_user_allocate(count * sizeof(WKSTA_USER_INFO_0));
+ if (pUserInfo0 == NULL)
+ {
+ ERR("\n");
+ dwResult = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ ZeroMemory(pUserInfo0, count * sizeof(WKSTA_USER_INFO_0));
+
+ for (i = 0; i < 0 + count; i++)
+ {
+ pUserInfo0[i].wkui0_username = midl_user_allocate(UserInfoArray[start
+ i]->UserName.Length + sizeof(WCHAR));
+ if (pUserInfo0[i].wkui0_username == NULL)
+ {
+ ERR("\n");
+ dwResult = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ ZeroMemory(pUserInfo0[i].wkui0_username, UserInfoArray[start +
i]->UserName.Length + sizeof(WCHAR));
+ CopyMemory(pUserInfo0[i].wkui0_username, UserInfoArray[start +
i]->UserName.Buffer, UserInfoArray[start + i]->UserName.Length);
+ }
+
+ UserInfo->WkstaUserInfo.Level0.EntriesRead = count;
+ UserInfo->WkstaUserInfo.Level0.Buffer = pUserInfo0;
+ *TotalEntries = EnumResponseBuffer->NumberOfLoggedOnUsers;
+ *ResumeHandle = 0;
+ break;
+
+ case 1:
+ pUserInfo1 = midl_user_allocate(count * sizeof(WKSTA_USER_INFO_1));
+ if (pUserInfo1 == NULL)
+ {
+ ERR("\n");
+ dwResult = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ ZeroMemory(pUserInfo1, count * sizeof(WKSTA_USER_INFO_1));
+
+ for (i = 0; i < 0 + count; i++)
+ {
+ pUserInfo1[i].wkui1_username = midl_user_allocate(UserInfoArray[start
+ i]->UserName.Length + sizeof(WCHAR));
+ if (pUserInfo1[i].wkui1_username == NULL)
+ {
+ ERR("\n");
+ dwResult = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ ZeroMemory(pUserInfo1[i].wkui1_username, UserInfoArray[start +
i]->UserName.Length + sizeof(WCHAR));
+ CopyMemory(pUserInfo1[i].wkui1_username, UserInfoArray[start +
i]->UserName.Buffer, UserInfoArray[start + i]->UserName.Length);
+
+ pUserInfo1[i].wkui1_logon_domain =
midl_user_allocate(UserInfoArray[start + i]->LogonDomainName.Length + sizeof(WCHAR));
+ if (pUserInfo1[i].wkui1_logon_domain == NULL)
+ {
+ ERR("\n");
+ dwResult = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ ZeroMemory(pUserInfo1[i].wkui1_logon_domain, UserInfoArray[start +
i]->LogonDomainName.Length + sizeof(WCHAR));
+ CopyMemory(pUserInfo1[i].wkui1_logon_domain, UserInfoArray[start +
i]->LogonDomainName.Buffer, UserInfoArray[start + i]->LogonDomainName.Length);
+
+ // FIXME: wkui1_oth_domains
+
+ pUserInfo1[i].wkui1_logon_server =
midl_user_allocate(UserInfoArray[start + i]->LogonServer.Length + sizeof(WCHAR));
+ if (pUserInfo1[i].wkui1_logon_server == NULL)
+ {
+ ERR("\n");
+ dwResult = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ ZeroMemory(pUserInfo1[i].wkui1_logon_server, UserInfoArray[start +
i]->LogonServer.Length + sizeof(WCHAR));
+ CopyMemory(pUserInfo1[i].wkui1_logon_server, UserInfoArray[start +
i]->LogonServer.Buffer, UserInfoArray[start + i]->LogonServer.Length);
+ }
+
+ UserInfo->WkstaUserInfo.Level1.EntriesRead = count;
+ UserInfo->WkstaUserInfo.Level1.Buffer = pUserInfo1;
+ *TotalEntries = EnumResponseBuffer->NumberOfLoggedOnUsers;
+ *ResumeHandle = 0;
+ break;
+
+ break;
+ }
+ }
+ else
+ {
+ if (UserInfo->Level == 0)
+ {
+ UserInfo->WkstaUserInfo.Level0.Buffer = NULL;
+ UserInfo->WkstaUserInfo.Level0.EntriesRead = 0;
+ }
+ else
+ {
+ UserInfo->WkstaUserInfo.Level1.Buffer = NULL;
+ UserInfo->WkstaUserInfo.Level1.EntriesRead = 0;
+ }
+
+ *TotalEntries = 0;
+ dwResult = NERR_Success;
+ }
+
+done:
+ if (UserInfoArray !=NULL)
+ {
+
+ for (i = 0; i < EnumResponseBuffer->NumberOfLoggedOnUsers; i++)
+ {
+ if (UserInfoArray[i]->UserName.Buffer != NULL)
+ LsaFreeReturnBuffer(UserInfoArray[i]->UserName.Buffer);
+
+ if (UserInfoArray[i]->LogonDomainName.Buffer != NULL)
+ LsaFreeReturnBuffer(UserInfoArray[i]->LogonDomainName.Buffer);
+
+ if (UserInfoArray[i]->LogonServer.Buffer != NULL)
+ LsaFreeReturnBuffer(UserInfoArray[i]->LogonServer.Buffer);
+
+ LsaFreeReturnBuffer(UserInfoArray[i]);
+ }
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, UserInfoArray);
+ }
+
+ if (EnumResponseBuffer != NULL)
+ LsaFreeReturnBuffer(EnumResponseBuffer);
+
+ return dwResult;
}
diff --git a/dll/win32/netapi32/wksta_new.c b/dll/win32/netapi32/wksta_new.c
index f427f3cd35f..48873eefbab 100644
--- a/dll/win32/netapi32/wksta_new.c
+++ b/dll/win32/netapi32/wksta_new.c
@@ -1057,8 +1057,8 @@ NetWkstaUserEnum(
_Inout_ LPDWORD resumehandle)
{
WKSTA_USER_ENUM_STRUCT UserEnumInfo;
- WKSTA_USER_INFO_0_CONTAINER Container0;
- WKSTA_USER_INFO_1_CONTAINER Container1;
+// WKSTA_USER_INFO_0_CONTAINER Container0;
+// WKSTA_USER_INFO_1_CONTAINER Container1;
NET_API_STATUS status;
TRACE("NetWkstaUserEnum(%s, %d, %p, %d, %p, %p, %p)\n",
debugstr_w(servername),
@@ -1068,15 +1068,19 @@ NetWkstaUserEnum(
switch (level)
{
case 0:
- UserEnumInfo.WkstaUserInfo.Level0 = &Container0;
- Container0.EntriesRead = 0;
- Container0.Buffer = NULL;
+// UserEnumInfo.WkstaUserInfo.Level0 = &Container0;
+// Container0.EntriesRead = 0;
+// Container0.Buffer = NULL;
+ UserEnumInfo.WkstaUserInfo.Level0.EntriesRead = 0;
+ UserEnumInfo.WkstaUserInfo.Level0.Buffer = NULL;
break;
case 1:
- UserEnumInfo.WkstaUserInfo.Level1 = &Container1;
- Container1.EntriesRead = 0;
- Container1.Buffer = NULL;
+// UserEnumInfo.WkstaUserInfo.Level1 = &Container1;
+// Container1.EntriesRead = 0;
+// Container1.Buffer = NULL;
+ UserEnumInfo.WkstaUserInfo.Level1.EntriesRead = 0;
+ UserEnumInfo.WkstaUserInfo.Level1.Buffer = NULL;
break;
default:
@@ -1095,13 +1099,17 @@ NetWkstaUserEnum(
switch (level)
{
case 0:
- *bufptr = (LPBYTE)UserEnumInfo.WkstaUserInfo.Level0->Buffer;
- *entriesread = UserEnumInfo.WkstaUserInfo.Level0->EntriesRead;
+// *bufptr = (LPBYTE)UserEnumInfo.WkstaUserInfo.Level0->Buffer;
+// *entriesread = UserEnumInfo.WkstaUserInfo.Level0->EntriesRead;
+ *bufptr = (LPBYTE)UserEnumInfo.WkstaUserInfo.Level0.Buffer;
+ *entriesread = UserEnumInfo.WkstaUserInfo.Level0.EntriesRead;
break;
case 1:
- *bufptr = (LPBYTE)UserEnumInfo.WkstaUserInfo.Level1->Buffer;
- *entriesread = UserEnumInfo.WkstaUserInfo.Level1->EntriesRead;
+// *bufptr = (LPBYTE)UserEnumInfo.WkstaUserInfo.Level1->Buffer;
+// *entriesread = UserEnumInfo.WkstaUserInfo.Level1->EntriesRead;
+ *bufptr = (LPBYTE)UserEnumInfo.WkstaUserInfo.Level1.Buffer;
+ *entriesread = UserEnumInfo.WkstaUserInfo.Level1.EntriesRead;
break;
}
}
diff --git a/sdk/include/reactos/idl/wkssvc.idl b/sdk/include/reactos/idl/wkssvc.idl
index 88cf97f6057..6e5cce98ead 100644
--- a/sdk/include/reactos/idl/wkssvc.idl
+++ b/sdk/include/reactos/idl/wkssvc.idl
@@ -311,7 +311,7 @@ typedef struct _WKSTA_USER_INFO_1_CONTAINER
unsigned long EntriesRead;
[size_is(EntriesRead)] LPWKSTA_USER_INFO_1 Buffer;
} WKSTA_USER_INFO_1_CONTAINER, *PWKSTA_USER_INFO_1_CONTAINER,
*LPWKSTA_USER_INFO_1_CONTAINER;
-
+/*
typedef struct _WKSTA_USER_ENUM_STRUCT
{
unsigned long Level;
@@ -322,6 +322,17 @@ typedef struct _WKSTA_USER_ENUM_STRUCT
[default] ;
} WkstaUserInfo;
} WKSTA_USER_ENUM_STRUCT, *PWKSTA_USER_ENUM_STRUCT, *LPWKSTA_USER_ENUM_STRUCT;
+*/
+typedef struct _WKSTA_USER_ENUM_STRUCT
+{
+ unsigned long Level;
+ [switch_is(Level)] union _WKSTA_USER_ENUM_UNION
+ {
+ [case(0)] WKSTA_USER_INFO_0_CONTAINER Level0;
+ [case(1)] WKSTA_USER_INFO_1_CONTAINER Level1;
+ [default] ;
+ } WkstaUserInfo;
+} WKSTA_USER_ENUM_STRUCT, *PWKSTA_USER_ENUM_STRUCT, *LPWKSTA_USER_ENUM_STRUCT;
typedef struct _WKSTA_TRANSPORT_INFO_0_CONTAINER
{