https://git.reactos.org/?p=reactos.git;a=commitdiff;h=be97da34accdf65aafade…
commit be97da34accdf65aafaded60c3be1131a2b3cd97
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Sun Mar 10 22:19:12 2019 +0100
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Tue Apr 2 01:45:51 2019 +0200
[NETAPI32] Fix NetUserEnum to work on x64
The previous implementation used the resume_handle parameter to return a pointer to
the active enumeration context, but resume_handle is a DWORD. To support 64 bit pointers,
the enumeration context is inserted into a global linked list and given a unique 32 bit
value as identifier for later lookup.
The way the function is implemented, leaking a data structure while the MSDN
description does not indicate that, seems a little questionable in general, but that is
something that I leave to the original author to investigate.
---
dll/win32/netapi32/netapi32.c | 2 +
dll/win32/netapi32/netapi32.h | 3 ++
dll/win32/netapi32/user.c | 100 +++++++++++++++++++++++++++++++++++++-----
3 files changed, 95 insertions(+), 10 deletions(-)
diff --git a/dll/win32/netapi32/netapi32.c b/dll/win32/netapi32/netapi32.c
index 5775aa46bd..576da6a37a 100644
--- a/dll/win32/netapi32/netapi32.c
+++ b/dll/win32/netapi32/netapi32.c
@@ -26,6 +26,8 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID
lpvReserved)
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
+ InitializeListHead(&g_EnumContextListHead);
+ InitializeCriticalSection(&g_EnumContextListLock);
DisableThreadLibraryCalls(hinstDLL);
NetBIOSInit();
NetBTInit();
diff --git a/dll/win32/netapi32/netapi32.h b/dll/win32/netapi32/netapi32.h
index 50b5255d6a..451865707f 100644
--- a/dll/win32/netapi32/netapi32.h
+++ b/dll/win32/netapi32/netapi32.h
@@ -30,6 +30,9 @@
#include "nbnamecache.h"
#include "netbios.h"
+extern LIST_ENTRY g_EnumContextListHead;
+extern CRITICAL_SECTION g_EnumContextListLock;
+
NET_API_STATUS
WINAPI
NetpNtStatusToApiStatus(NTSTATUS Status);
diff --git a/dll/win32/netapi32/user.c b/dll/win32/netapi32/user.c
index a867b786ec..699ae839b8 100644
--- a/dll/win32/netapi32/user.c
+++ b/dll/win32/netapi32/user.c
@@ -36,6 +36,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
typedef struct _ENUM_CONTEXT
{
+ LIST_ENTRY ListLink;
+ ULONG EnumHandle;
+
SAM_HANDLE ServerHandle;
SAM_HANDLE BuiltinDomainHandle;
SAM_HANDLE AccountDomainHandle;
@@ -50,6 +53,9 @@ typedef struct _ENUM_CONTEXT
} ENUM_CONTEXT, *PENUM_CONTEXT;
+LIST_ENTRY g_EnumContextListHead;
+CRITICAL_SECTION g_EnumContextListLock;
+LONG g_EnumContextHandle = 0;
static
ULONG
@@ -2662,6 +2668,86 @@ done:
return ApiStatus;
}
+static
+NET_API_STATUS
+AllocateEnumContext(
+ PENUM_CONTEXT *AllocatedEnumContext)
+{
+ NET_API_STATUS ApiStatus;
+ PENUM_CONTEXT EnumContext;
+
+ /* Allocate the context structure */
+ ApiStatus = NetApiBufferAllocate(sizeof(ENUM_CONTEXT), (PVOID*)&EnumContext);
+ if (ApiStatus != NERR_Success)
+ return ApiStatus;
+
+ /* Initialize the fields */
+ EnumContext->EnumerationContext = 0;
+ EnumContext->Buffer = NULL;
+ EnumContext->Count = 0;
+ EnumContext->Index = 0;
+ EnumContext->BuiltinDone = FALSE;
+
+ /* Set a "unique" handle */
+ EnumContext->EnumHandle = InterlockedIncrement(&g_EnumContextHandle);
+ if (EnumContext->EnumHandle == 0)
+ {
+ EnumContext->EnumHandle = InterlockedIncrement(&g_EnumContextHandle);
+ }
+
+ /* Insert the context in the list */
+ EnterCriticalSection(&g_EnumContextListLock);
+ InsertTailList(&g_EnumContextListHead, &EnumContext->ListLink);
+ LeaveCriticalSection(&g_EnumContextListLock);
+
+ *AllocatedEnumContext = EnumContext;
+ return NERR_Success;
+}
+
+static
+VOID
+FreeEnumContext(
+ PENUM_CONTEXT EnumContext)
+
+{
+ /* Remove the context from the list */
+ EnterCriticalSection(&g_EnumContextListLock);
+ RemoveEntryList(&EnumContext->ListLink);
+ LeaveCriticalSection(&g_EnumContextListLock);
+
+ /* Free it */
+ NetApiBufferFree(EnumContext);
+}
+
+static
+PENUM_CONTEXT
+LookupEnumContext(
+ SAM_ENUMERATE_HANDLE EnumerationHandle)
+{
+ PENUM_CONTEXT FoundEnumContext = NULL;
+ PLIST_ENTRY ListEntry;
+
+ /* Acquire the list lock */
+ EnterCriticalSection(&g_EnumContextListLock);
+
+ /* Search the list for the handle */
+ for (ListEntry = g_EnumContextListHead.Flink;
+ ListEntry != &g_EnumContextListHead;
+ ListEntry = ListEntry->Flink)
+ {
+ PENUM_CONTEXT EnumContext = CONTAINING_RECORD(ListEntry, ENUM_CONTEXT,
ListLink);
+ if (EnumContext->EnumHandle == EnumerationHandle)
+ {
+ FoundEnumContext = EnumContext;
+ break;
+ }
+ }
+
+ /* Release the list lock */
+ LeaveCriticalSection(&g_EnumContextListLock);
+
+ return FoundEnumContext;
+}
/************************************************************
* NetUserEnum (NETAPI32.@)
@@ -2699,20 +2785,14 @@ NetUserEnum(LPCWSTR servername,
if (resume_handle != NULL && *resume_handle != 0)
{
- EnumContext = (PENUM_CONTEXT)*resume_handle;
+ EnumContext = LookupEnumContext(*resume_handle);
}
else
{
- ApiStatus = NetApiBufferAllocate(sizeof(ENUM_CONTEXT),
(PVOID*)&EnumContext);
+ ApiStatus = AllocateEnumContext(&EnumContext);
if (ApiStatus != NERR_Success)
goto done;
- EnumContext->EnumerationContext = 0;
- EnumContext->Buffer = NULL;
- EnumContext->Count = 0;
- EnumContext->Index = 0;
- EnumContext->BuiltinDone = FALSE;
-
Status = SamConnect((servername != NULL) ? &ServerName : NULL,
&EnumContext->ServerHandle,
SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
@@ -2892,7 +2972,7 @@ done:
SamFreeMemory(EnumContext->Buffer);
}
- NetApiBufferFree(EnumContext);
+ FreeEnumContext(EnumContext);
EnumContext = NULL;
}
}
@@ -2901,7 +2981,7 @@ done:
SamCloseHandle(UserHandle);
if (resume_handle != NULL)
- *resume_handle = (DWORD_PTR)EnumContext;
+ *resume_handle = EnumContext ? EnumContext->EnumHandle : 0;
*bufptr = (LPBYTE)Buffer;