https://git.reactos.org/?p=reactos.git;a=commitdiff;h=033146ca23bc3122e9ffe…
commit 033146ca23bc3122e9ffe96257e178ff0c618aff
Author: Eric Kohl <eric.kohl(a)reactos.org>
AuthorDate: Sat Sep 8 20:55:13 2018 +0200
Commit: Eric Kohl <eric.kohl(a)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(a)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 */