2 * PROJECT: ReactOS NetAPI DLL
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: SAM service group interface code
5 * COPYRIGHT: Copyright 2018 Eric Kohl (eric.kohl@reactos.org)
8 /* INCLUDES ******************************************************************/
12 WINE_DEFAULT_DEBUG_CHANNEL(netapi32
);
14 typedef enum _ENUM_PHASE
21 typedef struct _ENUM_CONTEXT
23 SAM_HANDLE ServerHandle
;
24 SAM_HANDLE DomainHandle
;
25 SAM_HANDLE BuiltinDomainHandle
;
26 SAM_HANDLE AccountDomainHandle
;
28 SAM_ENUMERATE_HANDLE EnumerationContext
;
29 PSAM_RID_ENUMERATION Buffer
;
33 } ENUM_CONTEXT
, *PENUM_CONTEXT
;
36 /* FUNCTIONS *****************************************************************/
41 _In_ PGROUP_GENERAL_INFORMATION GroupInfo
,
46 PVOID GroupBuffer
= NULL
;
47 PGROUP_INFO_0 GroupInfo0
;
48 PGROUP_INFO_1 GroupInfo1
;
49 PGROUP_INFO_2 GroupInfo2
;
50 PGROUP_INFO_3 GroupInfo3
;
53 NET_API_STATUS ApiStatus
= NERR_Success
;
60 Size
= sizeof(GROUP_INFO_0
) +
61 GroupInfo
->Name
.Length
+ sizeof(WCHAR
);
65 Size
= sizeof(GROUP_INFO_1
) +
66 GroupInfo
->Name
.Length
+ sizeof(WCHAR
) +
67 GroupInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
71 Size
= sizeof(GROUP_INFO_2
) +
72 GroupInfo
->Name
.Length
+ sizeof(WCHAR
) +
73 GroupInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
77 Size
= sizeof(GROUP_INFO_3
) +
78 GroupInfo
->Name
.Length
+ sizeof(WCHAR
) +
79 GroupInfo
->AdminComment
.Length
+ sizeof(WCHAR
);
84 ApiStatus
= ERROR_INVALID_LEVEL
;
88 ApiStatus
= NetApiBufferAllocate(Size
, &GroupBuffer
);
89 if (ApiStatus
!= NERR_Success
)
92 ZeroMemory(GroupBuffer
, Size
);
97 GroupInfo0
= (PGROUP_INFO_0
)GroupBuffer
;
99 Ptr
= (PWSTR
)((ULONG_PTR
)GroupInfo0
+ sizeof(LOCALGROUP_INFO_0
));
100 GroupInfo0
->grpi0_name
= Ptr
;
102 memcpy(GroupInfo0
->grpi0_name
,
103 GroupInfo
->Name
.Buffer
,
104 GroupInfo
->Name
.Length
);
105 GroupInfo0
->grpi0_name
[GroupInfo
->Name
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
109 GroupInfo1
= (PGROUP_INFO_1
)GroupBuffer
;
111 Ptr
= (PWSTR
)((ULONG_PTR
)GroupInfo1
+ sizeof(GROUP_INFO_1
));
112 GroupInfo1
->grpi1_name
= Ptr
;
114 memcpy(GroupInfo1
->grpi1_name
,
115 GroupInfo
->Name
.Buffer
,
116 GroupInfo
->Name
.Length
);
117 GroupInfo1
->grpi1_name
[GroupInfo
->Name
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
119 Ptr
= (PWSTR
)((ULONG_PTR
)Ptr
+ GroupInfo
->Name
.Length
+ sizeof(WCHAR
));
120 GroupInfo1
->grpi1_comment
= Ptr
;
122 memcpy(GroupInfo1
->grpi1_comment
,
123 GroupInfo
->AdminComment
.Buffer
,
124 GroupInfo
->AdminComment
.Length
);
125 GroupInfo1
->grpi1_comment
[GroupInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
129 GroupInfo2
= (PGROUP_INFO_2
)GroupBuffer
;
131 Ptr
= (PWSTR
)((ULONG_PTR
)GroupInfo2
+ sizeof(GROUP_INFO_2
));
132 GroupInfo2
->grpi2_name
= Ptr
;
134 memcpy(GroupInfo2
->grpi2_name
,
135 GroupInfo
->Name
.Buffer
,
136 GroupInfo
->Name
.Length
);
137 GroupInfo2
->grpi2_name
[GroupInfo
->Name
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
139 Ptr
= (PWSTR
)((ULONG_PTR
)Ptr
+ GroupInfo
->Name
.Length
+ sizeof(WCHAR
));
140 GroupInfo2
->grpi2_comment
= Ptr
;
142 memcpy(GroupInfo2
->grpi2_comment
,
143 GroupInfo
->AdminComment
.Buffer
,
144 GroupInfo
->AdminComment
.Length
);
145 GroupInfo2
->grpi2_comment
[GroupInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
147 GroupInfo2
->grpi2_group_id
= GroupId
;
149 GroupInfo2
->grpi2_attributes
= GroupInfo
->Attributes
;
153 GroupInfo3
= (PGROUP_INFO_3
)GroupBuffer
;
155 Ptr
= (PWSTR
)((ULONG_PTR
)GroupInfo3
+ sizeof(GROUP_INFO_3
));
156 GroupInfo3
->grpi3_name
= Ptr
;
158 memcpy(GroupInfo3
->grpi3_name
,
159 GroupInfo
->Name
.Buffer
,
160 GroupInfo
->Name
.Length
);
161 GroupInfo3
->grpi3_name
[GroupInfo
->Name
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
163 Ptr
= (PWSTR
)((ULONG_PTR
)Ptr
+ GroupInfo
->Name
.Length
+ sizeof(WCHAR
));
164 GroupInfo3
->grpi3_comment
= Ptr
;
166 memcpy(GroupInfo3
->grpi3_comment
,
167 GroupInfo
->AdminComment
.Buffer
,
168 GroupInfo
->AdminComment
.Length
);
169 GroupInfo3
->grpi3_comment
[GroupInfo
->AdminComment
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
171 GroupInfo3
->grpi3_group_sid
= NULL
; /* FIXME */
173 GroupInfo3
->grpi3_attributes
= GroupInfo
->Attributes
;
178 if (ApiStatus
== NERR_Success
)
180 *Buffer
= GroupBuffer
;
184 if (GroupBuffer
!= NULL
)
185 NetApiBufferFree(GroupBuffer
);
195 _In_ PGROUP_GENERAL_INFORMATION GroupInfo
)
197 if (GroupInfo
->Name
.Buffer
!= NULL
)
198 SamFreeMemory(GroupInfo
->Name
.Buffer
);
200 if (GroupInfo
->AdminComment
.Buffer
!= NULL
)
201 SamFreeMemory(GroupInfo
->AdminComment
.Buffer
);
203 SamFreeMemory(GroupInfo
);
210 _In_ SAM_HANDLE DomainHandle
,
211 _In_ PUNICODE_STRING GroupName
,
212 _In_ ULONG DesiredAccess
,
213 _Out_ PSAM_HANDLE GroupHandle
,
214 _Out_ PULONG RelativeId
)
216 PULONG RelativeIds
= NULL
;
217 PSID_NAME_USE Use
= NULL
;
218 NET_API_STATUS ApiStatus
= NERR_Success
;
219 NTSTATUS Status
= STATUS_SUCCESS
;
221 /* Get the RID for the given user name */
222 Status
= SamLookupNamesInDomain(DomainHandle
,
227 if (!NT_SUCCESS(Status
))
229 ERR("SamLookupNamesInDomain failed (Status %08lx)\n", Status
);
230 return NetpNtStatusToApiStatus(Status
);
233 /* Fail, if it is not an alias account */
234 if (Use
[0] != SidTypeGroup
)
236 ERR("Object is not a group!\n");
237 ApiStatus
= NERR_GroupNotFound
;
241 /* Open the alias account */
242 Status
= SamOpenGroup(DomainHandle
,
246 if (!NT_SUCCESS(Status
))
248 ERR("SamOpenGroup failed (Status %08lx)\n", Status
);
249 ApiStatus
= NetpNtStatusToApiStatus(Status
);
253 if (RelativeId
!= NULL
)
254 *RelativeId
= RelativeIds
[0];
257 if (RelativeIds
!= NULL
)
258 SamFreeMemory(RelativeIds
);
267 /* PUBLIC FUNCTIONS **********************************************************/
272 _In_opt_ LPCWSTR servername
,
274 _Out_ LPBYTE
*bufptr
,
275 _In_ DWORD prefmaxlen
,
276 _Out_ LPDWORD entriesread
,
277 _Out_ LPDWORD totalentries
,
278 _Inout_opt_ PDWORD_PTR resume_handle
)
280 UNICODE_STRING ServerName
;
281 PSAM_RID_ENUMERATION CurrentGroup
;
282 PENUM_CONTEXT EnumContext
= NULL
;
284 SAM_HANDLE GroupHandle
= NULL
;
285 PGROUP_GENERAL_INFORMATION GroupInfo
= NULL
;
287 NET_API_STATUS ApiStatus
= NERR_Success
;
288 NTSTATUS Status
= STATUS_SUCCESS
;
290 TRACE("NetGroupEnum(%s, %d, %p, %d, %p, %p, %p)\n", debugstr_w(servername
),
291 level
, bufptr
, prefmaxlen
, entriesread
, totalentries
, resume_handle
);
297 if (servername
!= NULL
)
298 RtlInitUnicodeString(&ServerName
, servername
);
300 if (resume_handle
!= NULL
&& *resume_handle
!= 0)
302 EnumContext
= (PENUM_CONTEXT
)*resume_handle
;
306 ApiStatus
= NetApiBufferAllocate(sizeof(ENUM_CONTEXT
), (PVOID
*)&EnumContext
);
307 if (ApiStatus
!= NERR_Success
)
310 EnumContext
->EnumerationContext
= 0;
311 EnumContext
->Buffer
= NULL
;
312 EnumContext
->Returned
= 0;
313 EnumContext
->Index
= 0;
315 Status
= SamConnect((servername
!= NULL
) ? &ServerName
: NULL
,
316 &EnumContext
->ServerHandle
,
317 SAM_SERVER_CONNECT
| SAM_SERVER_LOOKUP_DOMAIN
,
319 if (!NT_SUCCESS(Status
))
321 ERR("SamConnect failed (Status %08lx)\n", Status
);
322 ApiStatus
= NetpNtStatusToApiStatus(Status
);
326 Status
= OpenAccountDomain(EnumContext
->ServerHandle
,
327 (servername
!= NULL
) ? &ServerName
: NULL
,
328 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
329 &EnumContext
->AccountDomainHandle
);
330 if (!NT_SUCCESS(Status
))
332 ERR("OpenAccountDomain failed (Status %08lx)\n", Status
);
333 ApiStatus
= NetpNtStatusToApiStatus(Status
);
337 Status
= OpenBuiltinDomain(EnumContext
->ServerHandle
,
338 DOMAIN_LIST_ACCOUNTS
| DOMAIN_LOOKUP
,
339 &EnumContext
->BuiltinDomainHandle
);
340 if (!NT_SUCCESS(Status
))
342 ERR("OpenBuiltinDomain failed (Status %08lx)\n", Status
);
343 ApiStatus
= NetpNtStatusToApiStatus(Status
);
347 EnumContext
->Phase
= AccountPhase
; //BuiltinPhase;
348 EnumContext
->DomainHandle
= EnumContext
->AccountDomainHandle
; //BuiltinDomainHandle;
354 TRACE("EnumContext->Index: %lu\n", EnumContext
->Index
);
355 TRACE("EnumContext->Returned: %lu\n", EnumContext
->Returned
);
357 if (EnumContext
->Index
>= EnumContext
->Returned
)
359 TRACE("Calling SamEnumerateGroupsInDomain\n");
361 Status
= SamEnumerateGroupsInDomain(EnumContext
->DomainHandle
,
362 &EnumContext
->EnumerationContext
,
363 (PVOID
*)&EnumContext
->Buffer
,
365 &EnumContext
->Returned
);
367 TRACE("SamEnumerateGroupsInDomain returned (Status %08lx)\n", Status
);
368 if (!NT_SUCCESS(Status
))
370 ERR("SamEnumerateAliasesInDomain failed (Status %08lx)\n", Status
);
371 ApiStatus
= NetpNtStatusToApiStatus(Status
);
375 if (Status
== STATUS_MORE_ENTRIES
)
377 ApiStatus
= NERR_BufTooSmall
;
382 TRACE("EnumContext: %lu\n", EnumContext
);
383 TRACE("EnumContext->Returned: %lu\n", EnumContext
->Returned
);
384 TRACE("EnumContext->Buffer: %p\n", EnumContext
->Buffer
);
386 /* Get a pointer to the current group */
387 CurrentGroup
= &EnumContext
->Buffer
[EnumContext
->Index
];
389 TRACE("RID: %lu\n", CurrentGroup
->RelativeId
);
391 Status
= SamOpenGroup(EnumContext
->DomainHandle
,
392 GROUP_READ_INFORMATION
,
393 CurrentGroup
->RelativeId
,
395 if (!NT_SUCCESS(Status
))
397 ERR("SamOpenGroup failed (Status %08lx)\n", Status
);
398 ApiStatus
= NetpNtStatusToApiStatus(Status
);
402 Status
= SamQueryInformationGroup(GroupHandle
,
403 GroupGeneralInformation
,
404 (PVOID
*)&GroupInfo
);
405 if (!NT_SUCCESS(Status
))
407 ERR("SamQueryInformationGroup failed (Status %08lx)\n", Status
);
408 ApiStatus
= NetpNtStatusToApiStatus(Status
);
412 SamCloseHandle(GroupHandle
);
415 TRACE("Name: %S\n", GroupInfo
->Name
.Buffer
);
416 TRACE("Comment: %S\n", GroupInfo
->AdminComment
.Buffer
);
418 ApiStatus
= BuildGroupInfoBuffer(GroupInfo
,
420 CurrentGroup
->RelativeId
,
422 if (ApiStatus
!= NERR_Success
)
425 if (GroupInfo
!= NULL
)
427 FreeGroupInfo(GroupInfo
);
431 EnumContext
->Index
++;
435 if (EnumContext
->Index
== EnumContext
->Returned
)
437 switch (EnumContext
->Phase
)
440 EnumContext
->Phase
= AccountPhase
;
441 EnumContext
->DomainHandle
= EnumContext
->AccountDomainHandle
;
442 EnumContext
->EnumerationContext
= 0;
443 EnumContext
->Index
= 0;
444 EnumContext
->Returned
= 0;
446 if (EnumContext
->Buffer
!= NULL
)
448 for (i
= 0; i
< EnumContext
->Returned
; i
++)
450 SamFreeMemory(EnumContext
->Buffer
[i
].Name
.Buffer
);
453 SamFreeMemory(EnumContext
->Buffer
);
454 EnumContext
->Buffer
= NULL
;
460 EnumContext
->Phase
= DonePhase
;
467 if (ApiStatus
== NERR_Success
&& EnumContext
!= NULL
&& EnumContext
->Phase
!= DonePhase
)
468 ApiStatus
= ERROR_MORE_DATA
;
470 if (EnumContext
!= NULL
)
471 *totalentries
= EnumContext
->Returned
;
473 if (resume_handle
== NULL
|| ApiStatus
!= ERROR_MORE_DATA
)
475 if (EnumContext
!= NULL
)
477 if (EnumContext
->BuiltinDomainHandle
!= NULL
)
478 SamCloseHandle(EnumContext
->BuiltinDomainHandle
);
480 if (EnumContext
->AccountDomainHandle
!= NULL
)
481 SamCloseHandle(EnumContext
->AccountDomainHandle
);
483 if (EnumContext
->ServerHandle
!= NULL
)
484 SamCloseHandle(EnumContext
->ServerHandle
);
486 if (EnumContext
->Buffer
!= NULL
)
488 for (i
= 0; i
< EnumContext
->Returned
; i
++)
490 SamFreeMemory(EnumContext
->Buffer
[i
].Name
.Buffer
);
493 SamFreeMemory(EnumContext
->Buffer
);
496 NetApiBufferFree(EnumContext
);
501 if (GroupHandle
!= NULL
)
502 SamCloseHandle(GroupHandle
);
504 if (GroupInfo
!= NULL
)
505 FreeGroupInfo(GroupInfo
);
507 if (resume_handle
!= NULL
)
508 *resume_handle
= (DWORD_PTR
)EnumContext
;
510 *bufptr
= (LPBYTE
)Buffer
;
512 TRACE("return %lu\n", ApiStatus
);
521 _In_opt_ LPCWSTR servername
,
522 _In_ LPCWSTR groupname
,
524 _Out_ LPBYTE
*bufptr
)
526 UNICODE_STRING ServerName
;
527 UNICODE_STRING GroupName
;
528 SAM_HANDLE ServerHandle
= NULL
;
529 SAM_HANDLE DomainHandle
= NULL
;
530 SAM_HANDLE GroupHandle
= NULL
;
531 PGROUP_GENERAL_INFORMATION GroupInfo
= NULL
;
534 NET_API_STATUS ApiStatus
= NERR_Success
;
535 NTSTATUS Status
= STATUS_SUCCESS
;
537 TRACE("NetGroupGetInfo(%s, %s, %d, %p)\n",
538 debugstr_w(servername
), debugstr_w(groupname
), level
, bufptr
);
540 if (servername
!= NULL
)
541 RtlInitUnicodeString(&ServerName
, servername
);
543 RtlInitUnicodeString(&GroupName
, groupname
);
545 /* Connect to the SAM Server */
546 Status
= SamConnect((servername
!= NULL
) ? &ServerName
: NULL
,
548 SAM_SERVER_CONNECT
| SAM_SERVER_LOOKUP_DOMAIN
,
550 if (!NT_SUCCESS(Status
))
552 ERR("SamConnect failed (Status %08lx)\n", Status
);
553 ApiStatus
= NetpNtStatusToApiStatus(Status
);
557 /* Open the Acount Domain */
558 Status
= OpenAccountDomain(ServerHandle
,
559 (servername
!= NULL
) ? &ServerName
: NULL
,
562 if (!NT_SUCCESS(Status
))
564 ERR("OpenAccountDomain failed (Status %08lx)\n", Status
);
565 ApiStatus
= NetpNtStatusToApiStatus(Status
);
569 /* Open the group account in the account domain */
570 ApiStatus
= OpenGroupByName(DomainHandle
,
572 GROUP_READ_INFORMATION
,
575 if (ApiStatus
!= NERR_Success
)
577 ERR("OpenGroupByName failed (ApiStatus %lu)\n", ApiStatus
);
578 if (ApiStatus
== ERROR_NONE_MAPPED
)
579 ApiStatus
= NERR_GroupNotFound
;
583 Status
= SamQueryInformationGroup(GroupHandle
,
584 GroupGeneralInformation
,
585 (PVOID
*)&GroupInfo
);
586 if (!NT_SUCCESS(Status
))
588 ERR("SamQueryInformationGroup failed (Status %08lx)\n", Status
);
589 ApiStatus
= NetpNtStatusToApiStatus(Status
);
593 ApiStatus
= BuildGroupInfoBuffer(GroupInfo
,
597 if (ApiStatus
!= NERR_Success
)
601 if (GroupInfo
!= NULL
)
602 FreeGroupInfo(GroupInfo
);
604 if (GroupHandle
!= NULL
)
605 SamCloseHandle(GroupHandle
);
607 if (DomainHandle
!= NULL
)
608 SamCloseHandle(DomainHandle
);
610 if (ServerHandle
!= NULL
)
611 SamCloseHandle(ServerHandle
);
613 *bufptr
= (LPBYTE
)Buffer
;