From da05d9ace17c51b1dba644eace0aea05e056ca8b Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Sun, 23 Dec 2012 18:56:13 +0000 Subject: [PATCH] [NETAPI32] - Implement NetUserEnum partially. - Move common code into a separate file. svn path=/trunk/; revision=57980 --- reactos/dll/win32/netapi32/CMakeLists.txt | 1 + reactos/dll/win32/netapi32/local_group.c | 93 ----- reactos/dll/win32/netapi32/misc.c | 127 ++++++ reactos/dll/win32/netapi32/netapi32.h | 7 + reactos/dll/win32/netapi32/user.c | 487 +++++++++++++++++++++- 5 files changed, 614 insertions(+), 101 deletions(-) create mode 100644 reactos/dll/win32/netapi32/misc.c diff --git a/reactos/dll/win32/netapi32/CMakeLists.txt b/reactos/dll/win32/netapi32/CMakeLists.txt index 64de1e01a9b..457eca53333 100644 --- a/reactos/dll/win32/netapi32/CMakeLists.txt +++ b/reactos/dll/win32/netapi32/CMakeLists.txt @@ -11,6 +11,7 @@ list(APPEND SOURCE ds.c group.c local_group.c + misc.c nbcmdqueue.c nbnamecache.c nbt.c diff --git a/reactos/dll/win32/netapi32/local_group.c b/reactos/dll/win32/netapi32/local_group.c index 546eed45a87..46655ca0381 100644 --- a/reactos/dll/win32/netapi32/local_group.c +++ b/reactos/dll/win32/netapi32/local_group.c @@ -56,99 +56,6 @@ typedef struct _ENUM_CONTEXT } ENUM_CONTEXT, *PENUM_CONTEXT; -static SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; - - -static -NTSTATUS -GetAccountDomainSid(PSID *AccountDomainSid) -{ - PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL; - LSA_OBJECT_ATTRIBUTES ObjectAttributes; - LSA_HANDLE PolicyHandle = NULL; - ULONG Length = 0; - NTSTATUS Status; - - memset(&ObjectAttributes, 0, sizeof(LSA_OBJECT_ATTRIBUTES)); - - Status = LsaOpenPolicy(NULL, - &ObjectAttributes, - POLICY_VIEW_LOCAL_INFORMATION, - &PolicyHandle); - if (!NT_SUCCESS(Status)) - { - ERR("LsaOpenPolicy failed (Status %08lx)\n", Status); - return Status; - } - - Status = LsaQueryInformationPolicy(PolicyHandle, - PolicyAccountDomainInformation, - (PVOID *)&AccountDomainInfo); - if (!NT_SUCCESS(Status)) - { - ERR("LsaQueryInformationPolicy failed (Status %08lx)\n", Status); - goto done; - } - - Length = RtlLengthSid(AccountDomainInfo->DomainSid); - - *AccountDomainSid = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length); - if (*AccountDomainSid == NULL) - { - ERR("Failed to allocate SID\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; - goto done; - } - - memcpy(*AccountDomainSid, AccountDomainInfo->DomainSid, Length); - -done: - if (AccountDomainInfo != NULL) - LsaFreeMemory(AccountDomainInfo); - - LsaClose(PolicyHandle); - - return Status; -} - - -static -NTSTATUS -GetBuiltinDomainSid(PSID *BuiltinDomainSid) -{ - PSID Sid = NULL; - PULONG Ptr; - NTSTATUS Status = STATUS_SUCCESS; - - *BuiltinDomainSid = NULL; - - Sid = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - RtlLengthRequiredSid(1)); - if (Sid == NULL) - return STATUS_INSUFFICIENT_RESOURCES; - - Status = RtlInitializeSid(Sid, - &NtAuthority, - 1); - if (!NT_SUCCESS(Status)) - goto done; - - Ptr = RtlSubAuthoritySid(Sid, 0); - *Ptr = SECURITY_BUILTIN_DOMAIN_RID; - - *BuiltinDomainSid = Sid; - -done: - if (!NT_SUCCESS(Status)) - { - if (Sid != NULL) - RtlFreeHeap(RtlGetProcessHeap(), 0, Sid); - } - - return Status; -} - /************************************************************ * NetLocalGroupAdd (NETAPI32.@) diff --git a/reactos/dll/win32/netapi32/misc.c b/reactos/dll/win32/netapi32/misc.c new file mode 100644 index 00000000000..0a46d559e43 --- /dev/null +++ b/reactos/dll/win32/netapi32/misc.c @@ -0,0 +1,127 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: NetAPI DLL + * FILE: reactos/dll/win32/netapi32/misc.c + * PURPOSE: Helper functions + * + * PROGRAMMERS: Eric Kohl + */ + +/* INCLUDES ******************************************************************/ + +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "lmcons.h" +#include "ntsecapi.h" +#include "wine/debug.h" + +#define NTOS_MODE_USER +#include +#include "ntsam.h" +#include "netapi32.h" + + +WINE_DEFAULT_DEBUG_CHANNEL(netapi32); + + +/* GLOBALS *******************************************************************/ + +static SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; + + +/* FUNCTIONS *****************************************************************/ + +NTSTATUS +GetAccountDomainSid(PSID *AccountDomainSid) +{ + PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL; + LSA_OBJECT_ATTRIBUTES ObjectAttributes; + LSA_HANDLE PolicyHandle = NULL; + ULONG Length = 0; + NTSTATUS Status; + + memset(&ObjectAttributes, 0, sizeof(LSA_OBJECT_ATTRIBUTES)); + + Status = LsaOpenPolicy(NULL, + &ObjectAttributes, + POLICY_VIEW_LOCAL_INFORMATION, + &PolicyHandle); + if (!NT_SUCCESS(Status)) + { + ERR("LsaOpenPolicy failed (Status %08lx)\n", Status); + return Status; + } + + Status = LsaQueryInformationPolicy(PolicyHandle, + PolicyAccountDomainInformation, + (PVOID *)&AccountDomainInfo); + if (!NT_SUCCESS(Status)) + { + ERR("LsaQueryInformationPolicy failed (Status %08lx)\n", Status); + goto done; + } + + Length = RtlLengthSid(AccountDomainInfo->DomainSid); + + *AccountDomainSid = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length); + if (*AccountDomainSid == NULL) + { + ERR("Failed to allocate SID\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto done; + } + + memcpy(*AccountDomainSid, AccountDomainInfo->DomainSid, Length); + +done: + if (AccountDomainInfo != NULL) + LsaFreeMemory(AccountDomainInfo); + + LsaClose(PolicyHandle); + + return Status; +} + + +NTSTATUS +GetBuiltinDomainSid(PSID *BuiltinDomainSid) +{ + PSID Sid = NULL; + PULONG Ptr; + NTSTATUS Status = STATUS_SUCCESS; + + *BuiltinDomainSid = NULL; + + Sid = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + RtlLengthRequiredSid(1)); + if (Sid == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + Status = RtlInitializeSid(Sid, + &NtAuthority, + 1); + if (!NT_SUCCESS(Status)) + goto done; + + Ptr = RtlSubAuthoritySid(Sid, 0); + *Ptr = SECURITY_BUILTIN_DOMAIN_RID; + + *BuiltinDomainSid = Sid; + +done: + if (!NT_SUCCESS(Status)) + { + if (Sid != NULL) + RtlFreeHeap(RtlGetProcessHeap(), 0, Sid); + } + + return Status; +} + +/* EOF */ diff --git a/reactos/dll/win32/netapi32/netapi32.h b/reactos/dll/win32/netapi32/netapi32.h index f7a0a7a57e3..67f55485567 100644 --- a/reactos/dll/win32/netapi32/netapi32.h +++ b/reactos/dll/win32/netapi32/netapi32.h @@ -6,5 +6,12 @@ NET_API_STATUS WINAPI NetpNtStatusToApiStatus(NTSTATUS Status); +/* misc.c */ + +NTSTATUS +GetAccountDomainSid(PSID *AccountDomainSid); + +NTSTATUS +GetBuiltinDomainSid(PSID *BuiltinDomainSid); #endif \ No newline at end of file diff --git a/reactos/dll/win32/netapi32/user.c b/reactos/dll/win32/netapi32/user.c index 6db0c81acba..1f6262e48eb 100644 --- a/reactos/dll/win32/netapi32/user.c +++ b/reactos/dll/win32/netapi32/user.c @@ -35,8 +35,29 @@ #include "wine/unicode.h" #include "wine/list.h" +#define NTOS_MODE_USER +#include +#include "ntsam.h" +#include "netapi32.h" + WINE_DEFAULT_DEBUG_CHANNEL(netapi32); + +typedef struct _ENUM_CONTEXT +{ + SAM_HANDLE ServerHandle; + SAM_HANDLE BuiltinDomainHandle; + SAM_HANDLE AccountDomainHandle; + + SAM_ENUMERATE_HANDLE EnumerationContext; + PSAM_RID_ENUMERATION Buffer; + ULONG Returned; + ULONG Index; + BOOLEAN BuiltinDone; + +} ENUM_CONTEXT, *PENUM_CONTEXT; + + /* NOTE: So far, this is implemented to support tests that require user logins, * but not designed to handle real user databases. Those should probably * be synced with either the host's user database or with Samba. @@ -134,7 +155,7 @@ end: } /************************************************************ - * NetUserAdd (NETAPI32.@) + * NetUserAdd (NETAPI32.@) */ NET_API_STATUS WINAPI @@ -257,7 +278,7 @@ NetUserChangePassword(LPCWSTR domainname, /************************************************************ - * NetUserDel (NETAPI32.@) + * NetUserDel (NETAPI32.@) */ NET_API_STATUS WINAPI @@ -287,7 +308,7 @@ NetUserDel(LPCWSTR servername, /************************************************************ - * NetUserEnum (NETAPI32.@) + * NetUserEnum (NETAPI32.@) */ NET_API_STATUS WINAPI @@ -300,15 +321,466 @@ NetUserEnum(LPCWSTR servername, LPDWORD totalentries, LPDWORD resume_handle) { - FIXME("(%s,%d, 0x%d,%p,%d,%p,%p,%p) stub!\n", debugstr_w(servername), level, - filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle); + PSAM_RID_ENUMERATION CurrentUser; + PENUM_CONTEXT EnumContext = NULL; + LPVOID Buffer = NULL; + PSID DomainSid = NULL; + PUSER_INFO_0 UserInfo0; + PUSER_INFO_1 UserInfo1; + PUSER_INFO_20 UserInfo20; - return ERROR_ACCESS_DENIED; + LPWSTR Ptr; + ULONG i; + ULONG Size; + + SAM_HANDLE UserHandle = NULL; + PUSER_ACCOUNT_INFORMATION UserInfo = NULL; + + NET_API_STATUS ApiStatus = NERR_Success; + NTSTATUS Status = STATUS_SUCCESS; + + FIXME("(%s %d 0x%d %p %d %p %p %p) stub!\n", debugstr_w(servername), level, + filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle); + + *entriesread = 0; + *totalentries = 0; + *bufptr = NULL; + + 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; + EnumContext->BuiltinDone = FALSE; + + Status = SamConnect(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 = GetAccountDomainSid(&DomainSid); + if (!NT_SUCCESS(Status)) + { + ERR("GetAccountDomainSid failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + Status = SamOpenDomain(EnumContext->ServerHandle, + DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP, + DomainSid, + &EnumContext->AccountDomainHandle); + + RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid); + + if (!NT_SUCCESS(Status)) + { + ERR("SamOpenDomain failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + Status = GetBuiltinDomainSid(&DomainSid); + if (!NT_SUCCESS(Status)) + { + ERR("GetAccountDomainSid failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + Status = SamOpenDomain(EnumContext->ServerHandle, + DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP, + DomainSid, + &EnumContext->BuiltinDomainHandle); + + RtlFreeHeap(RtlGetProcessHeap(), 0, DomainSid); + + if (!NT_SUCCESS(Status)) + { + ERR("SamOpenDomain failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + } + +// while (TRUE) +// { + TRACE("EnumContext->Index: %lu\n", EnumContext->Index); + TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned); + + if (EnumContext->Index >= EnumContext->Returned) + { +// if (EnumContext->BuiltinDone == TRUE) +// { +// ApiStatus = NERR_Success; +// goto done; +// } + + TRACE("Calling SamEnumerateUsersInDomain\n"); + Status = SamEnumerateUsersInDomain(EnumContext->AccountDomainHandle, //BuiltinDomainHandle, + &EnumContext->EnumerationContext, + 0, + (PVOID *)&EnumContext->Buffer, + prefmaxlen, + &EnumContext->Returned); + + TRACE("SamEnumerateUsersInDomain returned (Status %08lx)\n", Status); + if (!NT_SUCCESS(Status)) + { + ERR("SamEnumerateUsersInDomain failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + if (Status == STATUS_MORE_ENTRIES) + { + ApiStatus = NERR_BufTooSmall; + goto done; + } + else + { + EnumContext->BuiltinDone = TRUE; + } + } + + 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 user */ + CurrentUser = &EnumContext->Buffer[EnumContext->Index]; + + TRACE("RID: %lu\n", CurrentUser->RelativeId); + + Status = SamOpenUser(EnumContext->AccountDomainHandle, //BuiltinDomainHandle, + USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT, + CurrentUser->RelativeId, + &UserHandle); + if (!NT_SUCCESS(Status)) + { + ERR("SamOpenUser failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + Status = SamQueryInformationUser(UserHandle, + UserAccountInformation, + (PVOID *)&UserInfo); + if (!NT_SUCCESS(Status)) + { + ERR("SamQueryInformationUser failed (Status %08lx)\n", Status); + ApiStatus = NetpNtStatusToApiStatus(Status); + goto done; + } + + SamCloseHandle(UserHandle); + UserHandle = NULL; + + switch (level) + { + case 0: + Size = sizeof(USER_INFO_0) + + UserInfo->UserName.Length + sizeof(WCHAR); + break; + + case 1: + Size = sizeof(USER_INFO_1) + + UserInfo->UserName.Length + sizeof(WCHAR); + + if (UserInfo->HomeDirectory.Length > 0) + Size += UserInfo->HomeDirectory.Length + sizeof(WCHAR); + + if (UserInfo->AdminComment.Length > 0) + Size += UserInfo->AdminComment.Length + sizeof(WCHAR); + + if (UserInfo->ScriptPath.Length > 0) + Size = UserInfo->ScriptPath.Length + sizeof(WCHAR); + break; + +// case 2: +// case 3: +// case 10: +// case 11: + + case 20: + Size = sizeof(USER_INFO_20) + + UserInfo->UserName.Length + sizeof(WCHAR); + + if (UserInfo->FullName.Length > 0) + Size += UserInfo->FullName.Length + sizeof(WCHAR); + + if (UserInfo->AdminComment.Length > 0) + Size += UserInfo->AdminComment.Length + sizeof(WCHAR); + break; + +// case 23: + + default: + ApiStatus = ERROR_INVALID_LEVEL; + goto done; + } + + ApiStatus = NetApiBufferAllocate(Size, &Buffer); + if (ApiStatus != NERR_Success) + goto done; + + switch (level) + { + case 0: + UserInfo0 = (PUSER_INFO_0)Buffer; + + Ptr = (LPWSTR)((ULONG_PTR)UserInfo0 + sizeof(USER_INFO_0)); + UserInfo0->usri0_name = Ptr; + + memcpy(UserInfo0->usri0_name, + UserInfo->UserName.Buffer, + UserInfo->UserName.Length); + UserInfo0->usri0_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL; + break; + + case 1: + UserInfo1 = (PUSER_INFO_1)Buffer; + + Ptr = (LPWSTR)((ULONG_PTR)UserInfo1 + sizeof(USER_INFO_1)); + + UserInfo1->usri1_name = Ptr; + + memcpy(UserInfo1->usri1_name, + UserInfo->UserName.Buffer, + UserInfo->UserName.Length); + UserInfo1->usri1_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL; + + Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR)); + + UserInfo1->usri1_password = NULL; + + UserInfo1->usri1_password_age = 0; /* FIXME */ + + UserInfo1->usri1_priv = 0; /* FIXME */ + + if (UserInfo->HomeDirectory.Length > 0) + { + UserInfo1->usri1_home_dir = Ptr; + + memcpy(UserInfo1->usri1_home_dir, + UserInfo->HomeDirectory.Buffer, + UserInfo->HomeDirectory.Length); + UserInfo1->usri1_home_dir[UserInfo->HomeDirectory.Length / sizeof(WCHAR)] = UNICODE_NULL; + + Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->HomeDirectory.Length + sizeof(WCHAR)); + } + + if (UserInfo->AdminComment.Length > 0) + { + UserInfo1->usri1_comment = Ptr; + + memcpy(UserInfo1->usri1_comment, + UserInfo->AdminComment.Buffer, + UserInfo->AdminComment.Length); + UserInfo1->usri1_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL; + + Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR)); + } + + UserInfo1->usri1_flags = UserInfo->UserAccountControl; + + if (UserInfo->ScriptPath.Length > 0) + { + UserInfo1->usri1_script_path = Ptr; + + memcpy(UserInfo1->usri1_script_path, + UserInfo->ScriptPath.Buffer, + UserInfo->ScriptPath.Length); + UserInfo1->usri1_script_path[UserInfo->ScriptPath.Length / sizeof(WCHAR)] = UNICODE_NULL; + } + break; + +// case 2: +// case 3: +// case 10: +// case 11: + + case 20: + UserInfo20 = (PUSER_INFO_20)Buffer; + + Ptr = (LPWSTR)((ULONG_PTR)UserInfo20 + sizeof(USER_INFO_20)); + + UserInfo20->usri20_name = Ptr; + + memcpy(UserInfo20->usri20_name, + UserInfo->UserName.Buffer, + UserInfo->UserName.Length); + UserInfo20->usri20_name[UserInfo->UserName.Length / sizeof(WCHAR)] = UNICODE_NULL; + + Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->UserName.Length + sizeof(WCHAR)); + + if (UserInfo->FullName.Length > 0) + { + UserInfo20->usri20_full_name = Ptr; + + memcpy(UserInfo20->usri20_full_name, + UserInfo->FullName.Buffer, + UserInfo->FullName.Length); + UserInfo20->usri20_full_name[UserInfo->FullName.Length / sizeof(WCHAR)] = UNICODE_NULL; + + Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->FullName.Length + sizeof(WCHAR)); + } + + if (UserInfo->AdminComment.Length > 0) + { + UserInfo20->usri20_comment = Ptr; + + memcpy(UserInfo20->usri20_comment, + UserInfo->AdminComment.Buffer, + UserInfo->AdminComment.Length); + UserInfo20->usri20_comment[UserInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL; + + Ptr = (LPWSTR)((ULONG_PTR)Ptr + UserInfo->AdminComment.Length + sizeof(WCHAR)); + } + + UserInfo20->usri20_flags = UserInfo->UserAccountControl; + UserInfo20->usri20_user_id = CurrentUser->RelativeId; + break; + +// case 23: + } + + if (UserInfo != NULL) + { + if (UserInfo->UserName.Buffer != NULL) + SamFreeMemory(UserInfo->UserName.Buffer); + + if (UserInfo->FullName.Buffer != NULL) + SamFreeMemory(UserInfo->FullName.Buffer); + + if (UserInfo->HomeDirectory.Buffer != NULL) + SamFreeMemory(UserInfo->HomeDirectory.Buffer); + + if (UserInfo->HomeDirectoryDrive.Buffer != NULL) + SamFreeMemory(UserInfo->HomeDirectoryDrive.Buffer); + + if (UserInfo->ScriptPath.Buffer != NULL) + SamFreeMemory(UserInfo->ScriptPath.Buffer); + + if (UserInfo->ProfilePath.Buffer != NULL) + SamFreeMemory(UserInfo->ProfilePath.Buffer); + + if (UserInfo->AdminComment.Buffer != NULL) + SamFreeMemory(UserInfo->AdminComment.Buffer); + + if (UserInfo->WorkStations.Buffer != NULL) + SamFreeMemory(UserInfo->WorkStations.Buffer); + + if (UserInfo->LogonHours.LogonHours != NULL) + SamFreeMemory(UserInfo->LogonHours.LogonHours); + + SamFreeMemory(UserInfo); + UserInfo = NULL; + } + + EnumContext->Index++; + + (*entriesread)++; +// } + +done: + if (ApiStatus == NERR_Success && EnumContext->Index < EnumContext->Returned) + 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 (UserHandle != NULL) + SamCloseHandle(UserHandle); + + if (UserInfo != NULL) + { + if (UserInfo->UserName.Buffer != NULL) + SamFreeMemory(UserInfo->UserName.Buffer); + + if (UserInfo->FullName.Buffer != NULL) + SamFreeMemory(UserInfo->FullName.Buffer); + + if (UserInfo->HomeDirectory.Buffer != NULL) + SamFreeMemory(UserInfo->HomeDirectory.Buffer); + + if (UserInfo->HomeDirectoryDrive.Buffer != NULL) + SamFreeMemory(UserInfo->HomeDirectoryDrive.Buffer); + + if (UserInfo->ScriptPath.Buffer != NULL) + SamFreeMemory(UserInfo->ScriptPath.Buffer); + + if (UserInfo->ProfilePath.Buffer != NULL) + SamFreeMemory(UserInfo->ProfilePath.Buffer); + + if (UserInfo->AdminComment.Buffer != NULL) + SamFreeMemory(UserInfo->AdminComment.Buffer); + + if (UserInfo->WorkStations.Buffer != NULL) + SamFreeMemory(UserInfo->WorkStations.Buffer); + + if (UserInfo->LogonHours.LogonHours != NULL) + SamFreeMemory(UserInfo->LogonHours.LogonHours); + + SamFreeMemory(UserInfo); + } + + if (resume_handle != NULL) + *resume_handle = (DWORD_PTR)EnumContext; + + *bufptr = (LPBYTE)Buffer; + + TRACE("return %lu\n", ApiStatus); + + return ApiStatus; } /************************************************************ - * NetUserGetGroups (NETAPI32.@) + * NetUserGetGroups (NETAPI32.@) */ NET_API_STATUS WINAPI @@ -592,7 +1064,6 @@ NetUserSetGroups(LPCWSTR servername, } - /****************************************************************************** * NetUserSetInfo (NETAPI32.@) */