https://git.reactos.org/?p=reactos.git;a=commitdiff;h=faf62979728ec2e6a596ec6f3921e318f168bcfc
commit faf62979728ec2e6a596ec6f3921e318f168bcfc Author: Eric Kohl <eric.k...@reactos.org> AuthorDate: Sun Jan 5 16:38:04 2025 +0100 Commit: Eric Kohl <eric.k...@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 {