https://git.reactos.org/?p=reactos.git;a=commitdiff;h=033146ca23bc3122e9ffe9...
commit 033146ca23bc3122e9ffe96257e178ff0c618aff Author: Eric Kohl eric.kohl@reactos.org AuthorDate: Sat Sep 8 20:55:13 2018 +0200 Commit: Eric Kohl eric.kohl@reactos.org CommitDate: Sat Sep 8 20:55:13 2018 +0200
[NETAPI] Implement NetGroupEnum --- dll/win32/netapi32/CMakeLists.txt | 1 + dll/win32/netapi32/group.c | 20 -- dll/win32/netapi32/group_new.c | 457 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 458 insertions(+), 20 deletions(-)
diff --git a/dll/win32/netapi32/CMakeLists.txt b/dll/win32/netapi32/CMakeLists.txt index c5066c09e4..d714bb24b8 100644 --- a/dll/win32/netapi32/CMakeLists.txt +++ b/dll/win32/netapi32/CMakeLists.txt @@ -21,6 +21,7 @@ list(APPEND SOURCE display.c dssetup.c group.c + group_new.c local_group.c misc.c nbcmdqueue.c diff --git a/dll/win32/netapi32/group.c b/dll/win32/netapi32/group.c index 92627ece51..cac6be73b0 100644 --- a/dll/win32/netapi32/group.c +++ b/dll/win32/netapi32/group.c @@ -86,26 +86,6 @@ NetGroupDelUser(IN LPCWSTR servername, }
-/************************************************************ - * NetGroupEnum (NETAPI32.@) - * - */ -NET_API_STATUS -WINAPI -NetGroupEnum(IN LPCWSTR servername, - IN DWORD level, - OUT LPBYTE *bufptr, - IN DWORD prefmaxlen, - OUT LPDWORD entriesread, - OUT LPDWORD totalentries, - IN OUT PDWORD_PTR resume_handle) -{ - FIXME("(%s, %d, %p, %d, %p, %p, %p) stub!\n", debugstr_w(servername), - level, bufptr, prefmaxlen, entriesread, totalentries, resume_handle); - return ERROR_ACCESS_DENIED; -} - - /************************************************************ * NetGroupGetInfo (NETAPI32.@) * diff --git a/dll/win32/netapi32/group_new.c b/dll/win32/netapi32/group_new.c new file mode 100644 index 0000000000..5fa38313cf --- /dev/null +++ b/dll/win32/netapi32/group_new.c @@ -0,0 +1,457 @@ +/* + * PROJECT: ReactOS NetAPI DLL + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: SAM service group interface code + * COPYRIGHT: Copyright 2018 Eric Kohl (eric.kohl@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "netapi32.h" + +WINE_DEFAULT_DEBUG_CHANNEL(netapi32); + +typedef enum _ENUM_PHASE +{ + BuiltinPhase, + AccountPhase, + DonePhase +} ENUM_PHASE; + +typedef struct _ENUM_CONTEXT +{ + SAM_HANDLE ServerHandle; + SAM_HANDLE DomainHandle; + SAM_HANDLE BuiltinDomainHandle; + SAM_HANDLE AccountDomainHandle; + + SAM_ENUMERATE_HANDLE EnumerationContext; + PSAM_RID_ENUMERATION Buffer; + ULONG Returned; + ULONG Index; + ENUM_PHASE Phase; +} ENUM_CONTEXT, *PENUM_CONTEXT; + + +/* FUNCTIONS *****************************************************************/ + +static +NET_API_STATUS +BuildGroupInfoBuffer( + _In_ PGROUP_GENERAL_INFORMATION GroupInfo, + _In_ DWORD Level, + _In_ DWORD GroupId, + _Out_ LPVOID *Buffer) +{ + PVOID GroupBuffer = NULL; + PGROUP_INFO_0 GroupInfo0; + PGROUP_INFO_1 GroupInfo1; + PGROUP_INFO_2 GroupInfo2; + PGROUP_INFO_3 GroupInfo3; + PWSTR Ptr; + ULONG Size = 0; + NET_API_STATUS ApiStatus = NERR_Success; + + *Buffer = NULL; + + switch (Level) + { + case 0: + Size = sizeof(GROUP_INFO_0) + + GroupInfo->Name.Length + sizeof(WCHAR); + break; + + case 1: + Size = sizeof(GROUP_INFO_1) + + GroupInfo->Name.Length + sizeof(WCHAR) + + GroupInfo->AdminComment.Length + sizeof(WCHAR); + break; + + case 2: + Size = sizeof(GROUP_INFO_2) + + GroupInfo->Name.Length + sizeof(WCHAR) + + GroupInfo->AdminComment.Length + sizeof(WCHAR); + break; + + case 3: + Size = sizeof(GROUP_INFO_3) + + GroupInfo->Name.Length + sizeof(WCHAR) + + GroupInfo->AdminComment.Length + sizeof(WCHAR); + /* FIXME: Sid size */ + break; + + default: + ApiStatus = ERROR_INVALID_LEVEL; + goto done; + } + + ApiStatus = NetApiBufferAllocate(Size, &GroupBuffer); + if (ApiStatus != NERR_Success) + goto done; + + ZeroMemory(GroupBuffer, Size); + + switch (Level) + { + case 0: + GroupInfo0 = (PGROUP_INFO_0)GroupBuffer; + + Ptr = (PWSTR)((ULONG_PTR)GroupInfo0 + sizeof(LOCALGROUP_INFO_0)); + GroupInfo0->grpi0_name = Ptr; + + memcpy(GroupInfo0->grpi0_name, + GroupInfo->Name.Buffer, + GroupInfo->Name.Length); + GroupInfo0->grpi0_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL; + break; + + case 1: + GroupInfo1 = (PGROUP_INFO_1)GroupBuffer; + + Ptr = (PWSTR)((ULONG_PTR)GroupInfo1 + sizeof(GROUP_INFO_1)); + GroupInfo1->grpi1_name = Ptr; + + memcpy(GroupInfo1->grpi1_name, + GroupInfo->Name.Buffer, + GroupInfo->Name.Length); + GroupInfo1->grpi1_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL; + + Ptr = (PWSTR)((ULONG_PTR)Ptr + GroupInfo->Name.Length + sizeof(WCHAR)); + GroupInfo1->grpi1_comment = Ptr; + + memcpy(GroupInfo1->grpi1_comment, + GroupInfo->AdminComment.Buffer, + GroupInfo->AdminComment.Length); + GroupInfo1->grpi1_comment[GroupInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL; + break; + + case 2: + GroupInfo2 = (PGROUP_INFO_2)GroupBuffer; + + Ptr = (PWSTR)((ULONG_PTR)GroupInfo2 + sizeof(GROUP_INFO_2)); + GroupInfo2->grpi2_name = Ptr; + + memcpy(GroupInfo2->grpi2_name, + GroupInfo->Name.Buffer, + GroupInfo->Name.Length); + GroupInfo2->grpi2_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL; + + Ptr = (PWSTR)((ULONG_PTR)Ptr + GroupInfo->Name.Length + sizeof(WCHAR)); + GroupInfo2->grpi2_comment = Ptr; + + memcpy(GroupInfo2->grpi2_comment, + GroupInfo->AdminComment.Buffer, + GroupInfo->AdminComment.Length); + GroupInfo2->grpi2_comment[GroupInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL; + + GroupInfo2->grpi2_group_id = GroupId; + + GroupInfo2->grpi2_attributes= GroupInfo->Attributes; + break; + + case 3: + GroupInfo3 = (PGROUP_INFO_3)GroupBuffer; + + Ptr = (PWSTR)((ULONG_PTR)GroupInfo3 + sizeof(GROUP_INFO_3)); + GroupInfo3->grpi3_name = Ptr; + + memcpy(GroupInfo3->grpi3_name, + GroupInfo->Name.Buffer, + GroupInfo->Name.Length); + GroupInfo3->grpi3_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL; + + Ptr = (PWSTR)((ULONG_PTR)Ptr + GroupInfo->Name.Length + sizeof(WCHAR)); + GroupInfo3->grpi3_comment = Ptr; + + memcpy(GroupInfo3->grpi3_comment, + GroupInfo->AdminComment.Buffer, + GroupInfo->AdminComment.Length); + GroupInfo3->grpi3_comment[GroupInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL; + + GroupInfo3->grpi3_group_sid = NULL; /* FIXME */ + + GroupInfo3->grpi3_attributes= GroupInfo->Attributes; + break; + } + +done: + if (ApiStatus == NERR_Success) + { + *Buffer = GroupBuffer; + } + else + { + if (GroupBuffer != NULL) + NetApiBufferFree(GroupBuffer); + } + + return ApiStatus; +} + + +static +VOID +FreeGroupInfo( + PGROUP_GENERAL_INFORMATION GroupInfo) +{ + if (GroupInfo->Name.Buffer != NULL) + SamFreeMemory(GroupInfo->Name.Buffer); + + if (GroupInfo->AdminComment.Buffer != NULL) + SamFreeMemory(GroupInfo->AdminComment.Buffer); + + SamFreeMemory(GroupInfo); +} + + +/* PUBLIC FUNCTIONS **********************************************************/ + +NET_API_STATUS +WINAPI +NetGroupEnum( + _In_opt_ LPCWSTR servername, + _In_ DWORD level, + _Out_ LPBYTE *bufptr, + _In_ DWORD prefmaxlen, + _Out_ LPDWORD entriesread, + _Out_ LPDWORD totalentries, + _Inout_opt_ PDWORD_PTR resume_handle) +{ + UNICODE_STRING ServerName; + PSAM_RID_ENUMERATION CurrentGroup; + PENUM_CONTEXT EnumContext = NULL; + ULONG i; + SAM_HANDLE GroupHandle = NULL; + PGROUP_GENERAL_INFORMATION GroupInfo = NULL; + PVOID Buffer = NULL; + NET_API_STATUS ApiStatus = NERR_Success; + NTSTATUS Status = STATUS_SUCCESS; + + TRACE("NetGroupEnum(%s, %d, %p, %d, %p, %p, %p)\n", debugstr_w(servername), + level, bufptr, prefmaxlen, entriesread, totalentries, resume_handle); + + *entriesread = 0; + *totalentries = 0; + *bufptr = NULL; + + if (servername != NULL) + RtlInitUnicodeString(&ServerName, servername); + + if (resume_handle != NULL && *resume_handle != 0) + { + EnumContext = (PENUM_CONTEXT)*resume_handle; + } + else + { + ApiStatus = NetApiBufferAllocate(sizeof(ENUM_CONTEXT), (PVOID*)&EnumContext); + if (ApiStatus != NERR_Success) + goto done; + + EnumContext->EnumerationContext = 0; + EnumContext->Buffer = NULL; + EnumContext->Returned = 0; + EnumContext->Index = 0; + + Status = SamConnect((servername != NULL) ? &ServerName : NULL, + &EnumContext->ServerHandle, + SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN, + NULL); + if (!NT_SUCCESS(Status)) + { + ERR("SamConnect failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + Status = OpenAccountDomain(EnumContext->ServerHandle, + (servername != NULL) ? &ServerName : NULL, + DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP, + &EnumContext->AccountDomainHandle); + if (!NT_SUCCESS(Status)) + { + ERR("OpenAccountDomain failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + Status = OpenBuiltinDomain(EnumContext->ServerHandle, + DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP, + &EnumContext->BuiltinDomainHandle); + if (!NT_SUCCESS(Status)) + { + ERR("OpenBuiltinDomain failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + EnumContext->Phase = AccountPhase; //BuiltinPhase; + EnumContext->DomainHandle = EnumContext->AccountDomainHandle; //BuiltinDomainHandle; + } + + +// while (TRUE) +// { + TRACE("EnumContext->Index: %lu\n", EnumContext->Index); + TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned); + + if (EnumContext->Index >= EnumContext->Returned) + { + TRACE("Calling SamEnumerateGroupsInDomain\n"); + + Status = SamEnumerateGroupsInDomain(EnumContext->DomainHandle, + &EnumContext->EnumerationContext, + (PVOID *)&EnumContext->Buffer, + prefmaxlen, + &EnumContext->Returned); + + TRACE("SamEnumerateGroupsInDomain returned (Status %08lx)\n", Status); + if (!NT_SUCCESS(Status)) + { + ERR("SamEnumerateAliasesInDomain failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + if (Status == STATUS_MORE_ENTRIES) + { + ApiStatus = NERR_BufTooSmall; + goto done; + } + } + + TRACE("EnumContext: %lu\n", EnumContext); + TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned); + TRACE("EnumContext->Buffer: %p\n", EnumContext->Buffer); + + /* Get a pointer to the current group */ + CurrentGroup = &EnumContext->Buffer[EnumContext->Index]; + + TRACE("RID: %lu\n", CurrentGroup->RelativeId); + + Status = SamOpenGroup(EnumContext->DomainHandle, + GROUP_READ_INFORMATION, + CurrentGroup->RelativeId, + &GroupHandle); + if (!NT_SUCCESS(Status)) + { + ERR("SamOpenGroup failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + Status = SamQueryInformationGroup(GroupHandle, + GroupGeneralInformation, + (PVOID *)&GroupInfo); + if (!NT_SUCCESS(Status)) + { + ERR("SamQueryInformationGroup failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + SamCloseHandle(GroupHandle); + GroupHandle = NULL; + + TRACE("Name: %S\n", GroupInfo->Name.Buffer); + TRACE("Comment: %S\n", GroupInfo->AdminComment.Buffer); + + ApiStatus = BuildGroupInfoBuffer(GroupInfo, + level, + CurrentGroup->RelativeId, + &Buffer); + if (ApiStatus != NERR_Success) + goto done; + + if (GroupInfo != NULL) + { + FreeGroupInfo(GroupInfo); + GroupInfo = NULL; + } + + EnumContext->Index++; + + (*entriesread)++; + + if (EnumContext->Index == EnumContext->Returned) + { + switch (EnumContext->Phase) + { + case BuiltinPhase: + EnumContext->Phase = AccountPhase; + EnumContext->DomainHandle = EnumContext->AccountDomainHandle; + EnumContext->EnumerationContext = 0; + EnumContext->Index = 0; + EnumContext->Returned = 0; + + if (EnumContext->Buffer != NULL) + { + for (i = 0; i < EnumContext->Returned; i++) + { + SamFreeMemory(EnumContext->Buffer[i].Name.Buffer); + } + + SamFreeMemory(EnumContext->Buffer); + EnumContext->Buffer = NULL; + } + break; + + case AccountPhase: + case DonePhase: + EnumContext->Phase = DonePhase; + break; + } + } +// } + +done: + if (ApiStatus == NERR_Success && EnumContext != NULL && EnumContext->Phase != DonePhase) + ApiStatus = ERROR_MORE_DATA; + + if (EnumContext != NULL) + *totalentries = EnumContext->Returned; + + if (resume_handle == NULL || ApiStatus != ERROR_MORE_DATA) + { + if (EnumContext != NULL) + { + if (EnumContext->BuiltinDomainHandle != NULL) + SamCloseHandle(EnumContext->BuiltinDomainHandle); + + if (EnumContext->AccountDomainHandle != NULL) + SamCloseHandle(EnumContext->AccountDomainHandle); + + if (EnumContext->ServerHandle != NULL) + SamCloseHandle(EnumContext->ServerHandle); + + if (EnumContext->Buffer != NULL) + { + for (i = 0; i < EnumContext->Returned; i++) + { + SamFreeMemory(EnumContext->Buffer[i].Name.Buffer); + } + + SamFreeMemory(EnumContext->Buffer); + } + + NetApiBufferFree(EnumContext); + EnumContext = NULL; + } + } + + if (GroupHandle != NULL) + SamCloseHandle(GroupHandle); + + if (GroupInfo != NULL) + FreeGroupInfo(GroupInfo); + + if (resume_handle != NULL) + *resume_handle = (DWORD_PTR)EnumContext; + + *bufptr = (LPBYTE)Buffer; + + TRACE("return %lu\n", ApiStatus); + + return ApiStatus; +} + +/* EOF */