[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.
This commit is contained in:
Timo Kreuzer 2019-03-10 22:19:12 +01:00
parent 61e35141e8
commit be97da34ac
3 changed files with 95 additions and 10 deletions

View file

@ -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();

View file

@ -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);

View file

@ -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;