https://git.reactos.org/?p=reactos.git;a=commitdiff;h=be97da34accdf65aafaded...
commit be97da34accdf65aafaded60c3be1131a2b3cd97 Author: Timo Kreuzer timo.kreuzer@reactos.org AuthorDate: Sun Mar 10 22:19:12 2019 +0100 Commit: Timo Kreuzer timo.kreuzer@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;