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;