[NETAPI32] Implement NetGroupGetUsers

This commit is contained in:
Eric Kohl 2018-09-10 22:04:53 +02:00
parent 31c981c02a
commit 74620c94d3
2 changed files with 267 additions and 22 deletions

View file

@ -23,28 +23,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
/************************************************************
* NetGroupGetUsers (NETAPI32.@)
*
*/
NET_API_STATUS
WINAPI
NetGroupGetUsers(IN LPCWSTR servername,
IN LPCWSTR groupname,
IN DWORD level,
OUT LPBYTE *bufptr,
IN DWORD prefmaxlen,
OUT LPDWORD entriesread,
OUT LPDWORD totalentries,
IN OUT PDWORD_PTR resume_handle)
{
FIXME("(%s, %s, %d, %p, %d, %p, %p, %p) stub!\n", debugstr_w(servername),
debugstr_w(groupname), level, bufptr, prefmaxlen, entriesread,
totalentries, resume_handle);
return ERROR_ACCESS_DENIED;
}
/************************************************************
* NetGroupSetUsers (NETAPI32.@)
*

View file

@ -32,6 +32,21 @@ typedef struct _ENUM_CONTEXT
ENUM_PHASE Phase;
} ENUM_CONTEXT, *PENUM_CONTEXT;
typedef struct _USER_ENUM_CONTEXT
{
SAM_HANDLE ServerHandle;
SAM_HANDLE DomainHandle;
SAM_HANDLE GroupHandle;
ULONG MemberCount;
PULONG MemberIds;
PULONG Attributes;
PUNICODE_STRING Names;
ULONG Start;
ULONG Count;
} USER_ENUM_CONTEXT, *PUSER_ENUM_CONTEXT;
/* FUNCTIONS *****************************************************************/
@ -1107,6 +1122,258 @@ done:
}
NET_API_STATUS
WINAPI
NetGroupGetUsers(
_In_opt_ LPCWSTR servername,
_In_ LPCWSTR groupname,
_In_ DWORD level,
_Out_ LPBYTE *bufptr,
_In_ DWORD prefmaxlen,
_Out_ LPDWORD entriesread,
_Out_ LPDWORD totalentries,
_Inout_ PDWORD_PTR resume_handle)
{
UNICODE_STRING ServerName;
UNICODE_STRING GroupName;
PGROUP_USERS_INFO_0 UserInfo0;
PGROUP_USERS_INFO_1 UserInfo1;
PUSER_ENUM_CONTEXT EnumContext = NULL;
PVOID Buffer = NULL;
ULONG i, idx, Size;
PWSTR Ptr;
NET_API_STATUS ApiStatus = NERR_Success;
NTSTATUS Status = STATUS_SUCCESS;
TRACE("NetGroupGetUsers(%s, %s, %d, %p, %d, %p, %p, %p)\n",
debugstr_w(servername), debugstr_w(groupname), level, bufptr,
prefmaxlen, entriesread, totalentries, resume_handle);
*entriesread = 0;
*totalentries = 0;
*bufptr = NULL;
if (servername != NULL)
RtlInitUnicodeString(&ServerName, servername);
RtlInitUnicodeString(&GroupName, groupname);
if (resume_handle != NULL && *resume_handle != 0)
{
EnumContext = (PUSER_ENUM_CONTEXT)*resume_handle;
}
else
{
ApiStatus = NetApiBufferAllocate(sizeof(ENUM_CONTEXT), (PVOID*)&EnumContext);
if (ApiStatus != NERR_Success)
goto done;
EnumContext->MemberCount = 0;
EnumContext->MemberIds = NULL;
EnumContext->Attributes = NULL;
EnumContext->Names = NULL;
EnumContext->Start = 0;
EnumContext->Count = 0;
/* Connect to the SAM Server */
Status = SamConnect((servername != NULL) ? &ServerName : 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;
}
/* Open the Acount Domain */
Status = OpenAccountDomain(EnumContext->ServerHandle,
(servername != NULL) ? &ServerName : NULL,
DOMAIN_LOOKUP,
&EnumContext->DomainHandle);
if (!NT_SUCCESS(Status))
{
ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
ApiStatus = NetpNtStatusToApiStatus(Status);
goto done;
}
/* Open the group account */
ApiStatus = OpenGroupByName(EnumContext->DomainHandle,
&GroupName,
GROUP_LIST_MEMBERS,
&EnumContext->GroupHandle,
NULL);
if (ApiStatus != NERR_Success)
{
ERR("OpenGroupByName failed (ApiStatus %lu)\n", ApiStatus);
if (ApiStatus == ERROR_NONE_MAPPED)
ApiStatus = NERR_GroupNotFound;
goto done;
}
/* Get the group members */
Status = SamGetMembersInGroup(EnumContext->GroupHandle,
&EnumContext->MemberIds,
&EnumContext->Attributes,
&EnumContext->MemberCount);
if (!NT_SUCCESS(Status))
{
ERR("SamGetMembersInGroup failed (Status %08lx)\n", Status);
ApiStatus = NetpNtStatusToApiStatus(Status);
goto done;
}
if (EnumContext->MemberCount > 0)
{
/* Get all member names */
Status = SamLookupIdsInDomain(EnumContext->DomainHandle,
EnumContext->MemberCount,
EnumContext->MemberIds,
&EnumContext->Names,
NULL);
if (!NT_SUCCESS(Status))
{
ERR("SamLookupIdsInDomain failed (Status %08lx)\n", Status);
ApiStatus = NetpNtStatusToApiStatus(Status);
goto done;
}
}
}
/* Calculate the required buffer size */
Size = 0;
if (prefmaxlen == -1)
{
Size = EnumContext->MemberCount *
((level == 0) ? sizeof(GROUP_USERS_INFO_0) : sizeof(GROUP_USERS_INFO_1));
for (i = EnumContext->Start; i < EnumContext->MemberCount; i++)
Size += EnumContext->Names[i].Length + sizeof(WCHAR);
EnumContext->Count = EnumContext->MemberCount;
}
else
{
for (i = EnumContext->Start; i < EnumContext->MemberCount; i++)
{
Size += (level == 0) ? sizeof(GROUP_USERS_INFO_0) : sizeof(GROUP_USERS_INFO_1);
Size += EnumContext->Names[i].Length + sizeof(WCHAR);
EnumContext->Count++;
if (Size >= prefmaxlen)
break;
}
}
TRACE("Buffer size: %lu\n", Size);
/* Allocate and clear the buffer */
ApiStatus = NetApiBufferAllocate(Size, &Buffer);
if (ApiStatus != NERR_Success)
goto done;
ZeroMemory(Buffer, Size);
/* Fill the buffer */
if (level == 0)
Ptr = (PWCHAR)((LONG_PTR)Buffer + EnumContext->Count * sizeof(GROUP_USERS_INFO_0));
else
Ptr = (PWCHAR)((LONG_PTR)Buffer + EnumContext->Count * sizeof(GROUP_USERS_INFO_1));
for (i = 0; i < EnumContext->Count; i++)
{
idx = EnumContext->Start + i;
if (level == 0)
{
UserInfo0 = (PGROUP_USERS_INFO_0)Buffer;
UserInfo0[i].grui0_name = Ptr;
memcpy(UserInfo0[i].grui0_name,
EnumContext->Names[idx].Buffer,
EnumContext->Names[idx].Length);
UserInfo0[i].grui0_name[EnumContext->Names[idx].Length / sizeof(WCHAR)] = UNICODE_NULL;
Ptr = (PWSTR)((ULONG_PTR)Ptr + EnumContext->Names[idx].Length + sizeof(WCHAR));
}
else
{
UserInfo1 = (PGROUP_USERS_INFO_1)Buffer;
UserInfo1[i].grui1_name = Ptr;
memcpy(UserInfo1[i].grui1_name,
EnumContext->Names[idx].Buffer,
EnumContext->Names[idx].Length);
UserInfo1[i].grui1_name[EnumContext->Names[idx].Length / sizeof(WCHAR)] = UNICODE_NULL;
UserInfo1[i].grui1_attributes = EnumContext->Attributes[idx];
Ptr = (PWSTR)((ULONG_PTR)Ptr + EnumContext->Names[idx].Length + sizeof(WCHAR));
}
}
/* Set the new start index */
EnumContext->Start += EnumContext->Count;
/* Only return ERROR_MORE_DATA if we are not done yet */
if (EnumContext->MemberCount > EnumContext->Start)
ApiStatus = ERROR_MORE_DATA;
else
ApiStatus = NERR_Success;
done:
if (EnumContext != NULL)
{
*entriesread = EnumContext->Count;
*totalentries = EnumContext->MemberCount;
}
if (resume_handle == NULL || ApiStatus != ERROR_MORE_DATA)
{
if (EnumContext != NULL)
{
if (EnumContext->Names != NULL)
{
for (i = 0; i < EnumContext->MemberCount; i++)
SamFreeMemory(EnumContext->Names[i].Buffer);
SamFreeMemory(EnumContext->Names);
}
if (EnumContext->Attributes != NULL)
SamFreeMemory(EnumContext->Attributes);
if (EnumContext->MemberIds != NULL)
SamFreeMemory(EnumContext->MemberIds);
if (EnumContext->GroupHandle != NULL)
SamCloseHandle(EnumContext->GroupHandle);
if (EnumContext->DomainHandle != NULL)
SamCloseHandle(EnumContext->DomainHandle);
if (EnumContext->ServerHandle != NULL)
SamCloseHandle(EnumContext->ServerHandle);
NetApiBufferFree(EnumContext);
EnumContext = NULL;
}
}
*bufptr = (LPBYTE)Buffer;
if (resume_handle != NULL)
*resume_handle = (DWORD_PTR)EnumContext;
return ApiStatus;
}
NET_API_STATUS
WINAPI
NetGroupSetInfo(