[NETAPI32] NetUserEnum, NetUserGetInfo: Get the user privileges and auth flags for...
[reactos.git] / dll / win32 / netapi32 / group_new.c
1 /*
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)
6 */
7
8 /* INCLUDES ******************************************************************/
9
10 #include "netapi32.h"
11
12 WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
13
14 typedef enum _ENUM_PHASE
15 {
16 BuiltinPhase,
17 AccountPhase,
18 DonePhase
19 } ENUM_PHASE;
20
21 typedef struct _GROUP_ENUM_CONTEXT
22 {
23 SAM_HANDLE ServerHandle;
24 SAM_HANDLE DomainHandle;
25 SAM_HANDLE BuiltinDomainHandle;
26 SAM_HANDLE AccountDomainHandle;
27
28 SAM_ENUMERATE_HANDLE EnumerationContext;
29 PSAM_RID_ENUMERATION Buffer;
30 ULONG Returned;
31 ULONG Index;
32 ENUM_PHASE Phase;
33 } GROUP_ENUM_CONTEXT, *PGROUP_ENUM_CONTEXT;
34
35 typedef struct _USER_ENUM_CONTEXT
36 {
37 SAM_HANDLE ServerHandle;
38 SAM_HANDLE DomainHandle;
39 SAM_HANDLE GroupHandle;
40
41 ULONG MemberCount;
42 PULONG MemberIds;
43 PULONG Attributes;
44 PUNICODE_STRING Names;
45
46 ULONG Start;
47 ULONG Count;
48 } USER_ENUM_CONTEXT, *PUSER_ENUM_CONTEXT;
49
50
51 /* FUNCTIONS *****************************************************************/
52
53 static
54 NET_API_STATUS
55 BuildGroupInfoBuffer(
56 _In_ PGROUP_GENERAL_INFORMATION GroupInfo,
57 _In_ DWORD Level,
58 _In_ DWORD GroupId,
59 _Out_ LPVOID *Buffer)
60 {
61 PVOID GroupBuffer = NULL;
62 PGROUP_INFO_0 GroupInfo0;
63 PGROUP_INFO_1 GroupInfo1;
64 PGROUP_INFO_2 GroupInfo2;
65 PGROUP_INFO_3 GroupInfo3;
66 PWSTR Ptr;
67 ULONG Size = 0;
68 NET_API_STATUS ApiStatus = NERR_Success;
69
70 *Buffer = NULL;
71
72 switch (Level)
73 {
74 case 0:
75 Size = sizeof(GROUP_INFO_0) +
76 GroupInfo->Name.Length + sizeof(WCHAR);
77 break;
78
79 case 1:
80 Size = sizeof(GROUP_INFO_1) +
81 GroupInfo->Name.Length + sizeof(WCHAR) +
82 GroupInfo->AdminComment.Length + sizeof(WCHAR);
83 break;
84
85 case 2:
86 Size = sizeof(GROUP_INFO_2) +
87 GroupInfo->Name.Length + sizeof(WCHAR) +
88 GroupInfo->AdminComment.Length + sizeof(WCHAR);
89 break;
90
91 case 3:
92 Size = sizeof(GROUP_INFO_3) +
93 GroupInfo->Name.Length + sizeof(WCHAR) +
94 GroupInfo->AdminComment.Length + sizeof(WCHAR);
95 /* FIXME: Sid size */
96 break;
97
98 default:
99 ApiStatus = ERROR_INVALID_LEVEL;
100 goto done;
101 }
102
103 ApiStatus = NetApiBufferAllocate(Size, &GroupBuffer);
104 if (ApiStatus != NERR_Success)
105 goto done;
106
107 ZeroMemory(GroupBuffer, Size);
108
109 switch (Level)
110 {
111 case 0:
112 GroupInfo0 = (PGROUP_INFO_0)GroupBuffer;
113
114 Ptr = (PWSTR)((ULONG_PTR)GroupInfo0 + sizeof(LOCALGROUP_INFO_0));
115 GroupInfo0->grpi0_name = Ptr;
116
117 memcpy(GroupInfo0->grpi0_name,
118 GroupInfo->Name.Buffer,
119 GroupInfo->Name.Length);
120 GroupInfo0->grpi0_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
121 break;
122
123 case 1:
124 GroupInfo1 = (PGROUP_INFO_1)GroupBuffer;
125
126 Ptr = (PWSTR)((ULONG_PTR)GroupInfo1 + sizeof(GROUP_INFO_1));
127 GroupInfo1->grpi1_name = Ptr;
128
129 memcpy(GroupInfo1->grpi1_name,
130 GroupInfo->Name.Buffer,
131 GroupInfo->Name.Length);
132 GroupInfo1->grpi1_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
133
134 Ptr = (PWSTR)((ULONG_PTR)Ptr + GroupInfo->Name.Length + sizeof(WCHAR));
135 GroupInfo1->grpi1_comment = Ptr;
136
137 memcpy(GroupInfo1->grpi1_comment,
138 GroupInfo->AdminComment.Buffer,
139 GroupInfo->AdminComment.Length);
140 GroupInfo1->grpi1_comment[GroupInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
141 break;
142
143 case 2:
144 GroupInfo2 = (PGROUP_INFO_2)GroupBuffer;
145
146 Ptr = (PWSTR)((ULONG_PTR)GroupInfo2 + sizeof(GROUP_INFO_2));
147 GroupInfo2->grpi2_name = Ptr;
148
149 memcpy(GroupInfo2->grpi2_name,
150 GroupInfo->Name.Buffer,
151 GroupInfo->Name.Length);
152 GroupInfo2->grpi2_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
153
154 Ptr = (PWSTR)((ULONG_PTR)Ptr + GroupInfo->Name.Length + sizeof(WCHAR));
155 GroupInfo2->grpi2_comment = Ptr;
156
157 memcpy(GroupInfo2->grpi2_comment,
158 GroupInfo->AdminComment.Buffer,
159 GroupInfo->AdminComment.Length);
160 GroupInfo2->grpi2_comment[GroupInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
161
162 GroupInfo2->grpi2_group_id = GroupId;
163
164 GroupInfo2->grpi2_attributes= GroupInfo->Attributes;
165 break;
166
167 case 3:
168 GroupInfo3 = (PGROUP_INFO_3)GroupBuffer;
169
170 Ptr = (PWSTR)((ULONG_PTR)GroupInfo3 + sizeof(GROUP_INFO_3));
171 GroupInfo3->grpi3_name = Ptr;
172
173 memcpy(GroupInfo3->grpi3_name,
174 GroupInfo->Name.Buffer,
175 GroupInfo->Name.Length);
176 GroupInfo3->grpi3_name[GroupInfo->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
177
178 Ptr = (PWSTR)((ULONG_PTR)Ptr + GroupInfo->Name.Length + sizeof(WCHAR));
179 GroupInfo3->grpi3_comment = Ptr;
180
181 memcpy(GroupInfo3->grpi3_comment,
182 GroupInfo->AdminComment.Buffer,
183 GroupInfo->AdminComment.Length);
184 GroupInfo3->grpi3_comment[GroupInfo->AdminComment.Length / sizeof(WCHAR)] = UNICODE_NULL;
185
186 GroupInfo3->grpi3_group_sid = NULL; /* FIXME */
187
188 GroupInfo3->grpi3_attributes= GroupInfo->Attributes;
189 break;
190 }
191
192 done:
193 if (ApiStatus == NERR_Success)
194 {
195 *Buffer = GroupBuffer;
196 }
197 else
198 {
199 if (GroupBuffer != NULL)
200 NetApiBufferFree(GroupBuffer);
201 }
202
203 return ApiStatus;
204 }
205
206
207 static
208 VOID
209 FreeGroupInfo(
210 _In_ PGROUP_GENERAL_INFORMATION GroupInfo)
211 {
212 if (GroupInfo->Name.Buffer != NULL)
213 SamFreeMemory(GroupInfo->Name.Buffer);
214
215 if (GroupInfo->AdminComment.Buffer != NULL)
216 SamFreeMemory(GroupInfo->AdminComment.Buffer);
217
218 SamFreeMemory(GroupInfo);
219 }
220
221
222 static
223 NET_API_STATUS
224 OpenGroupByName(
225 _In_ SAM_HANDLE DomainHandle,
226 _In_ PUNICODE_STRING GroupName,
227 _In_ ULONG DesiredAccess,
228 _Out_ PSAM_HANDLE GroupHandle,
229 _Out_ PULONG RelativeId)
230 {
231 PULONG RelativeIds = NULL;
232 PSID_NAME_USE Use = NULL;
233 NET_API_STATUS ApiStatus = NERR_Success;
234 NTSTATUS Status = STATUS_SUCCESS;
235
236 /* Get the RID for the given user name */
237 Status = SamLookupNamesInDomain(DomainHandle,
238 1,
239 GroupName,
240 &RelativeIds,
241 &Use);
242 if (!NT_SUCCESS(Status))
243 {
244 WARN("SamLookupNamesInDomain failed (Status %08lx)\n", Status);
245 return NetpNtStatusToApiStatus(Status);
246 }
247
248 /* Fail, if it is not an alias account */
249 if (Use[0] != SidTypeGroup)
250 {
251 ERR("Object is not a group!\n");
252 ApiStatus = NERR_GroupNotFound;
253 goto done;
254 }
255
256 /* Open the alias account */
257 Status = SamOpenGroup(DomainHandle,
258 DesiredAccess,
259 RelativeIds[0],
260 GroupHandle);
261 if (!NT_SUCCESS(Status))
262 {
263 ERR("SamOpenGroup failed (Status %08lx)\n", Status);
264 ApiStatus = NetpNtStatusToApiStatus(Status);
265 goto done;
266 }
267
268 if (RelativeId != NULL)
269 *RelativeId = RelativeIds[0];
270
271 done:
272 if (RelativeIds != NULL)
273 SamFreeMemory(RelativeIds);
274
275 if (Use != NULL)
276 SamFreeMemory(Use);
277
278 return ApiStatus;
279 }
280
281
282 /* PUBLIC FUNCTIONS **********************************************************/
283
284 NET_API_STATUS
285 WINAPI
286 NetGroupAdd(
287 _In_opt_ LPCWSTR servername,
288 _In_ DWORD level,
289 _In_ LPBYTE buf,
290 _Out_opt_ LPDWORD parm_err)
291 {
292 GROUP_ADM_COMMENT_INFORMATION AdminComment;
293 GROUP_ATTRIBUTE_INFORMATION AttributeInfo;
294 UNICODE_STRING ServerName;
295 UNICODE_STRING GroupName;
296 SAM_HANDLE ServerHandle = NULL;
297 SAM_HANDLE DomainHandle = NULL;
298 SAM_HANDLE GroupHandle = NULL;
299 PWSTR Name = NULL;
300 PWSTR Comment = NULL;
301 ULONG Attributes = 0;
302 ULONG RelativeId;
303 NET_API_STATUS ApiStatus = NERR_Success;
304 NTSTATUS Status = STATUS_SUCCESS;
305
306 TRACE("NetGroupAdd(%s, %d, %p, %p)\n",
307 debugstr_w(servername), level, buf, parm_err);
308
309 if (parm_err != NULL)
310 *parm_err = PARM_ERROR_NONE;
311
312 /* Initialize the Server name*/
313 if (servername != NULL)
314 RtlInitUnicodeString(&ServerName, servername);
315
316 /* Initialize the Alias name*/
317 switch (level)
318 {
319 case 0:
320 Name = ((PGROUP_INFO_0)buf)->grpi0_name;
321 Comment = NULL;
322 Attributes = 0;
323 break;
324
325 case 1:
326 Name = ((PGROUP_INFO_1)buf)->grpi1_name;
327 Comment = ((PGROUP_INFO_1)buf)->grpi1_comment;
328 Attributes = 0;
329 break;
330
331 case 2:
332 Name = ((PGROUP_INFO_2)buf)->grpi2_name;
333 Comment = ((PGROUP_INFO_2)buf)->grpi2_comment;
334 Attributes = ((PGROUP_INFO_2)buf)->grpi2_attributes;
335 break;
336
337 case 3:
338 Name = ((PGROUP_INFO_3)buf)->grpi3_name;
339 Comment = ((PGROUP_INFO_3)buf)->grpi3_comment;
340 Attributes = ((PGROUP_INFO_3)buf)->grpi3_attributes;
341 break;
342
343 default:
344 return ERROR_INVALID_LEVEL;
345 }
346
347 RtlInitUnicodeString(&GroupName, Name);
348
349 /* Connect to the SAM Server */
350 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
351 &ServerHandle,
352 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
353 NULL);
354 if (!NT_SUCCESS(Status))
355 {
356 ERR("SamConnect failed (Status %08lx)\n", Status);
357 ApiStatus = NetpNtStatusToApiStatus(Status);
358 goto done;
359 }
360
361 /* Open the account domain */
362 Status = OpenAccountDomain(ServerHandle,
363 (servername != NULL) ? &ServerName : NULL,
364 DOMAIN_CREATE_GROUP | DOMAIN_LOOKUP,
365 &DomainHandle);
366 if (!NT_SUCCESS(Status))
367 {
368 ERR("SamOpenDomain failed (Status %08lx)\n", Status);
369 ApiStatus = NetpNtStatusToApiStatus(Status);
370 goto done;
371 }
372
373 /* Try to open the group account */
374 ApiStatus = OpenGroupByName(DomainHandle,
375 &GroupName,
376 GROUP_READ_INFORMATION,
377 &GroupHandle,
378 NULL);
379 if (ApiStatus == NERR_Success)
380 {
381 ERR("OpenGroupByName: Group %wZ already exists!\n", &GroupName);
382
383 SamCloseHandle(GroupHandle);
384 ApiStatus = ERROR_GROUP_EXISTS;
385 goto done;
386 }
387
388 ApiStatus = NERR_Success;
389
390 /* Create the group */
391 Status = SamCreateGroupInDomain(DomainHandle,
392 &GroupName,
393 DELETE | GROUP_WRITE_ACCOUNT,
394 &GroupHandle,
395 &RelativeId);
396 if (!NT_SUCCESS(Status))
397 {
398 ERR("SamCreateGroupInDomain failed (Status %08lx)\n", Status);
399 ApiStatus = NetpNtStatusToApiStatus(Status);
400 goto done;
401 }
402
403 TRACE("Created group \"%wZ\" (RID: %lu)\n", &GroupName, RelativeId);
404
405 /* Set the admin comment */
406 if (level == 1 || level == 2 || level == 3)
407 {
408 RtlInitUnicodeString(&AdminComment.AdminComment, Comment);
409
410 Status = SamSetInformationGroup(GroupHandle,
411 GroupAdminCommentInformation,
412 &AdminComment);
413 if (!NT_SUCCESS(Status))
414 {
415 ERR("SamSetInformationAlias failed (Status %08lx)\n", Status);
416 ApiStatus = NetpNtStatusToApiStatus(Status);
417
418 /* Delete the Alias if the Comment could not be set */
419 SamDeleteGroup(GroupHandle);
420
421 goto done;
422 }
423 }
424
425 /* Set the attributes */
426 if (level == 2 || level == 3)
427 {
428 AttributeInfo.Attributes = Attributes;
429
430 Status = SamSetInformationGroup(GroupHandle,
431 GroupAttributeInformation,
432 &AttributeInfo);
433 if (!NT_SUCCESS(Status))
434 {
435 ERR("SamSetInformationAlias failed (Status %08lx)\n", Status);
436 ApiStatus = NetpNtStatusToApiStatus(Status);
437
438 /* Delete the Alias if the Attributes could not be set */
439 SamDeleteGroup(GroupHandle);
440
441 goto done;
442 }
443 }
444
445 done:
446 if (GroupHandle != NULL)
447 {
448 if (ApiStatus != NERR_Success)
449 SamDeleteGroup(GroupHandle);
450 else
451 SamCloseHandle(GroupHandle);
452 }
453
454 if (DomainHandle != NULL)
455 SamCloseHandle(DomainHandle);
456
457 if (ServerHandle != NULL)
458 SamCloseHandle(ServerHandle);
459
460 return ApiStatus;
461 }
462
463
464 NET_API_STATUS
465 WINAPI
466 NetGroupAddUser(
467 _In_opt_ LPCWSTR servername,
468 _In_ LPCWSTR groupname,
469 _In_ LPCWSTR username)
470 {
471 UNICODE_STRING ServerName;
472 UNICODE_STRING GroupName;
473 UNICODE_STRING UserName;
474 SAM_HANDLE ServerHandle = NULL;
475 SAM_HANDLE DomainHandle = NULL;
476 SAM_HANDLE GroupHandle = NULL;
477 PULONG RelativeIds = NULL;
478 PSID_NAME_USE Use = NULL;
479 NET_API_STATUS ApiStatus = NERR_Success;
480 NTSTATUS Status = STATUS_SUCCESS;
481
482 TRACE("NetGroupAddUser(%s, %s, %s)\n",
483 debugstr_w(servername), debugstr_w(groupname), debugstr_w(username));
484
485 if (servername != NULL)
486 RtlInitUnicodeString(&ServerName, servername);
487
488 RtlInitUnicodeString(&GroupName, groupname);
489
490 RtlInitUnicodeString(&UserName, username);
491
492 /* Connect to the SAM Server */
493 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
494 &ServerHandle,
495 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
496 NULL);
497 if (!NT_SUCCESS(Status))
498 {
499 ERR("SamConnect failed (Status %08lx)\n", Status);
500 ApiStatus = NetpNtStatusToApiStatus(Status);
501 goto done;
502 }
503
504 /* Open the Acount Domain */
505 Status = OpenAccountDomain(ServerHandle,
506 (servername != NULL) ? &ServerName : NULL,
507 DOMAIN_LOOKUP,
508 &DomainHandle);
509 if (!NT_SUCCESS(Status))
510 {
511 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
512 ApiStatus = NetpNtStatusToApiStatus(Status);
513 goto done;
514 }
515
516 /* Open the group account */
517 ApiStatus = OpenGroupByName(DomainHandle,
518 &GroupName,
519 GROUP_ADD_MEMBER,
520 &GroupHandle,
521 NULL);
522 if (ApiStatus != NERR_Success)
523 {
524 ERR("OpenGroupByName failed (ApiStatus %lu)\n", ApiStatus);
525 if (ApiStatus == ERROR_NONE_MAPPED)
526 ApiStatus = NERR_GroupNotFound;
527 goto done;
528 }
529
530 Status = SamLookupNamesInDomain(DomainHandle,
531 1,
532 &UserName,
533 &RelativeIds,
534 &Use);
535 if (!NT_SUCCESS(Status))
536 {
537 ERR("SamLookupNamesInDomain failed (Status %08lx)\n", Status);
538 ApiStatus = NetpNtStatusToApiStatus(Status);
539 goto done;
540 }
541
542 /* Fail, if it is not a user account */
543 if (Use[0] != SidTypeUser)
544 {
545 ERR("Object is not a user!\n");
546 ApiStatus = NERR_GroupNotFound;
547 goto done;
548 }
549
550 Status = SamAddMemberToGroup(GroupHandle,
551 RelativeIds[0],
552 0);
553 if (!NT_SUCCESS(Status))
554 {
555 ERR("SamAddMemberToGroup failed (Status %lu)\n", Status);
556 ApiStatus = NetpNtStatusToApiStatus(Status);
557 goto done;
558 }
559
560 done:
561 if (RelativeIds != NULL)
562 SamFreeMemory(RelativeIds);
563
564 if (Use != NULL)
565 SamFreeMemory(Use);
566
567 if (GroupHandle != NULL)
568 SamCloseHandle(GroupHandle);
569
570 if (DomainHandle != NULL)
571 SamCloseHandle(DomainHandle);
572
573 if (ServerHandle != NULL)
574 SamCloseHandle(ServerHandle);
575
576 return ApiStatus;
577 }
578
579
580 NET_API_STATUS
581 WINAPI
582 NetGroupDel(
583 _In_opt_ LPCWSTR servername,
584 _In_ IN LPCWSTR groupname)
585 {
586 UNICODE_STRING ServerName;
587 UNICODE_STRING GroupName;
588 SAM_HANDLE ServerHandle = NULL;
589 SAM_HANDLE DomainHandle = NULL;
590 SAM_HANDLE GroupHandle = NULL;
591 NET_API_STATUS ApiStatus = NERR_Success;
592 NTSTATUS Status = STATUS_SUCCESS;
593
594 TRACE("NetGroupDel(%s, %s)\n",
595 debugstr_w(servername), debugstr_w(groupname));
596
597 if (servername != NULL)
598 RtlInitUnicodeString(&ServerName, servername);
599
600 RtlInitUnicodeString(&GroupName, groupname);
601
602 /* Connect to the SAM Server */
603 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
604 &ServerHandle,
605 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
606 NULL);
607 if (!NT_SUCCESS(Status))
608 {
609 ERR("SamConnect failed (Status %08lx)\n", Status);
610 ApiStatus = NetpNtStatusToApiStatus(Status);
611 goto done;
612 }
613
614 /* Open the Acount Domain */
615 Status = OpenAccountDomain(ServerHandle,
616 (servername != NULL) ? &ServerName : NULL,
617 DOMAIN_LOOKUP,
618 &DomainHandle);
619 if (!NT_SUCCESS(Status))
620 {
621 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
622 ApiStatus = NetpNtStatusToApiStatus(Status);
623 goto done;
624 }
625
626 /* Open the group */
627 ApiStatus = OpenGroupByName(DomainHandle,
628 &GroupName,
629 DELETE,
630 &GroupHandle,
631 NULL);
632 if (ApiStatus != NERR_Success)
633 {
634 ERR("OpenGroupByName failed (ApiStatus %lu)\n", ApiStatus);
635 if (ApiStatus == ERROR_NONE_MAPPED)
636 ApiStatus = NERR_GroupNotFound;
637 goto done;
638 }
639
640 /* Delete the group */
641 Status = SamDeleteGroup(GroupHandle);
642 if (!NT_SUCCESS(Status))
643 {
644 ERR("SamDeleteGroup failed (Status %08lx)\n", Status);
645 ApiStatus = NetpNtStatusToApiStatus(Status);
646 goto done;
647 }
648
649 done:
650 if (GroupHandle != NULL)
651 SamCloseHandle(GroupHandle);
652
653 if (DomainHandle != NULL)
654 SamCloseHandle(DomainHandle);
655
656 if (ServerHandle != NULL)
657 SamCloseHandle(ServerHandle);
658
659 return ApiStatus;
660 }
661
662
663 NET_API_STATUS
664 WINAPI
665 NetGroupDelUser(
666 _In_opt_ LPCWSTR servername,
667 _In_ LPCWSTR groupname,
668 _In_ LPCWSTR username)
669 {
670 UNICODE_STRING ServerName;
671 UNICODE_STRING GroupName;
672 UNICODE_STRING UserName;
673 SAM_HANDLE ServerHandle = NULL;
674 SAM_HANDLE DomainHandle = NULL;
675 SAM_HANDLE GroupHandle = NULL;
676 PULONG RelativeIds = NULL;
677 PSID_NAME_USE Use = NULL;
678 NET_API_STATUS ApiStatus = NERR_Success;
679 NTSTATUS Status = STATUS_SUCCESS;
680
681 TRACE("NetGroupDelUser(%s, %s, %s)\n",
682 debugstr_w(servername), debugstr_w(groupname), debugstr_w(username));
683
684 if (servername != NULL)
685 RtlInitUnicodeString(&ServerName, servername);
686
687 RtlInitUnicodeString(&GroupName, groupname);
688
689 RtlInitUnicodeString(&UserName, username);
690
691 /* Connect to the SAM Server */
692 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
693 &ServerHandle,
694 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
695 NULL);
696 if (!NT_SUCCESS(Status))
697 {
698 ERR("SamConnect failed (Status %08lx)\n", Status);
699 ApiStatus = NetpNtStatusToApiStatus(Status);
700 goto done;
701 }
702
703 /* Open the Acount Domain */
704 Status = OpenAccountDomain(ServerHandle,
705 (servername != NULL) ? &ServerName : NULL,
706 DOMAIN_LOOKUP,
707 &DomainHandle);
708 if (!NT_SUCCESS(Status))
709 {
710 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
711 ApiStatus = NetpNtStatusToApiStatus(Status);
712 goto done;
713 }
714
715 /* Open the group account */
716 ApiStatus = OpenGroupByName(DomainHandle,
717 &GroupName,
718 GROUP_REMOVE_MEMBER,
719 &GroupHandle,
720 NULL);
721 if (ApiStatus != NERR_Success)
722 {
723 ERR("OpenGroupByName failed (ApiStatus %lu)\n", ApiStatus);
724 if (ApiStatus == ERROR_NONE_MAPPED)
725 ApiStatus = NERR_GroupNotFound;
726 goto done;
727 }
728
729 Status = SamLookupNamesInDomain(DomainHandle,
730 1,
731 &UserName,
732 &RelativeIds,
733 &Use);
734 if (!NT_SUCCESS(Status))
735 {
736 ERR("SamLookupNamesInDomain failed (Status %08lx)\n", Status);
737 ApiStatus = NetpNtStatusToApiStatus(Status);
738 goto done;
739 }
740
741 /* Fail, if it is not a user account */
742 if (Use[0] != SidTypeUser)
743 {
744 ERR("Object is not a user!\n");
745 ApiStatus = NERR_GroupNotFound;
746 goto done;
747 }
748
749 Status = SamRemoveMemberFromGroup(GroupHandle,
750 RelativeIds[0]);
751 if (!NT_SUCCESS(Status))
752 {
753 ERR("SamRemoveMemberFromGroup failed (Status %lu)\n", Status);
754 ApiStatus = NetpNtStatusToApiStatus(Status);
755 goto done;
756 }
757
758 done:
759 if (RelativeIds != NULL)
760 SamFreeMemory(RelativeIds);
761
762 if (Use != NULL)
763 SamFreeMemory(Use);
764
765 if (GroupHandle != NULL)
766 SamCloseHandle(GroupHandle);
767
768 if (DomainHandle != NULL)
769 SamCloseHandle(DomainHandle);
770
771 if (ServerHandle != NULL)
772 SamCloseHandle(ServerHandle);
773
774 return ApiStatus;
775 }
776
777
778 NET_API_STATUS
779 WINAPI
780 NetGroupEnum(
781 _In_opt_ LPCWSTR servername,
782 _In_ DWORD level,
783 _Out_ LPBYTE *bufptr,
784 _In_ DWORD prefmaxlen,
785 _Out_ LPDWORD entriesread,
786 _Out_ LPDWORD totalentries,
787 _Inout_opt_ PDWORD_PTR resume_handle)
788 {
789 UNICODE_STRING ServerName;
790 PSAM_RID_ENUMERATION CurrentGroup;
791 PGROUP_ENUM_CONTEXT EnumContext = NULL;
792 ULONG i;
793 SAM_HANDLE GroupHandle = NULL;
794 PGROUP_GENERAL_INFORMATION GroupInfo = NULL;
795 PVOID Buffer = NULL;
796 NET_API_STATUS ApiStatus = NERR_Success;
797 NTSTATUS Status = STATUS_SUCCESS;
798
799 TRACE("NetGroupEnum(%s, %d, %p, %d, %p, %p, %p)\n", debugstr_w(servername),
800 level, bufptr, prefmaxlen, entriesread, totalentries, resume_handle);
801
802 *entriesread = 0;
803 *totalentries = 0;
804 *bufptr = NULL;
805
806 if (servername != NULL)
807 RtlInitUnicodeString(&ServerName, servername);
808
809 if (resume_handle != NULL && *resume_handle != 0)
810 {
811 EnumContext = (PGROUP_ENUM_CONTEXT)*resume_handle;
812 }
813 else
814 {
815 ApiStatus = NetApiBufferAllocate(sizeof(GROUP_ENUM_CONTEXT), (PVOID*)&EnumContext);
816 if (ApiStatus != NERR_Success)
817 goto done;
818
819 EnumContext->EnumerationContext = 0;
820 EnumContext->Buffer = NULL;
821 EnumContext->Returned = 0;
822 EnumContext->Index = 0;
823
824 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
825 &EnumContext->ServerHandle,
826 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
827 NULL);
828 if (!NT_SUCCESS(Status))
829 {
830 ERR("SamConnect failed (Status %08lx)\n", Status);
831 ApiStatus = NetpNtStatusToApiStatus(Status);
832 goto done;
833 }
834
835 Status = OpenAccountDomain(EnumContext->ServerHandle,
836 (servername != NULL) ? &ServerName : NULL,
837 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
838 &EnumContext->AccountDomainHandle);
839 if (!NT_SUCCESS(Status))
840 {
841 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
842 ApiStatus = NetpNtStatusToApiStatus(Status);
843 goto done;
844 }
845
846 Status = OpenBuiltinDomain(EnumContext->ServerHandle,
847 DOMAIN_LIST_ACCOUNTS | DOMAIN_LOOKUP,
848 &EnumContext->BuiltinDomainHandle);
849 if (!NT_SUCCESS(Status))
850 {
851 ERR("OpenBuiltinDomain failed (Status %08lx)\n", Status);
852 ApiStatus = NetpNtStatusToApiStatus(Status);
853 goto done;
854 }
855
856 EnumContext->Phase = AccountPhase; //BuiltinPhase;
857 EnumContext->DomainHandle = EnumContext->AccountDomainHandle; //BuiltinDomainHandle;
858 }
859
860
861 // while (TRUE)
862 // {
863 TRACE("EnumContext->Index: %lu\n", EnumContext->Index);
864 TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned);
865
866 if (EnumContext->Index >= EnumContext->Returned)
867 {
868 TRACE("Calling SamEnumerateGroupsInDomain\n");
869
870 Status = SamEnumerateGroupsInDomain(EnumContext->DomainHandle,
871 &EnumContext->EnumerationContext,
872 (PVOID *)&EnumContext->Buffer,
873 prefmaxlen,
874 &EnumContext->Returned);
875
876 TRACE("SamEnumerateGroupsInDomain returned (Status %08lx)\n", Status);
877 if (!NT_SUCCESS(Status))
878 {
879 ERR("SamEnumerateAliasesInDomain failed (Status %08lx)\n", Status);
880 ApiStatus = NetpNtStatusToApiStatus(Status);
881 goto done;
882 }
883
884 if (Status == STATUS_MORE_ENTRIES)
885 {
886 ApiStatus = NERR_BufTooSmall;
887 goto done;
888 }
889 }
890
891 TRACE("EnumContext: %lu\n", EnumContext);
892 TRACE("EnumContext->Returned: %lu\n", EnumContext->Returned);
893 TRACE("EnumContext->Buffer: %p\n", EnumContext->Buffer);
894
895 /* Get a pointer to the current group */
896 CurrentGroup = &EnumContext->Buffer[EnumContext->Index];
897
898 TRACE("RID: %lu\n", CurrentGroup->RelativeId);
899
900 Status = SamOpenGroup(EnumContext->DomainHandle,
901 GROUP_READ_INFORMATION,
902 CurrentGroup->RelativeId,
903 &GroupHandle);
904 if (!NT_SUCCESS(Status))
905 {
906 ERR("SamOpenGroup failed (Status %08lx)\n", Status);
907 ApiStatus = NetpNtStatusToApiStatus(Status);
908 goto done;
909 }
910
911 Status = SamQueryInformationGroup(GroupHandle,
912 GroupGeneralInformation,
913 (PVOID *)&GroupInfo);
914 if (!NT_SUCCESS(Status))
915 {
916 ERR("SamQueryInformationGroup failed (Status %08lx)\n", Status);
917 ApiStatus = NetpNtStatusToApiStatus(Status);
918 goto done;
919 }
920
921 SamCloseHandle(GroupHandle);
922 GroupHandle = NULL;
923
924 TRACE("Name: %S\n", GroupInfo->Name.Buffer);
925 TRACE("Comment: %S\n", GroupInfo->AdminComment.Buffer);
926
927 ApiStatus = BuildGroupInfoBuffer(GroupInfo,
928 level,
929 CurrentGroup->RelativeId,
930 &Buffer);
931 if (ApiStatus != NERR_Success)
932 goto done;
933
934 if (GroupInfo != NULL)
935 {
936 FreeGroupInfo(GroupInfo);
937 GroupInfo = NULL;
938 }
939
940 EnumContext->Index++;
941
942 (*entriesread)++;
943
944 if (EnumContext->Index == EnumContext->Returned)
945 {
946 switch (EnumContext->Phase)
947 {
948 case BuiltinPhase:
949 EnumContext->Phase = AccountPhase;
950 EnumContext->DomainHandle = EnumContext->AccountDomainHandle;
951 EnumContext->EnumerationContext = 0;
952 EnumContext->Index = 0;
953 EnumContext->Returned = 0;
954
955 if (EnumContext->Buffer != NULL)
956 {
957 for (i = 0; i < EnumContext->Returned; i++)
958 {
959 SamFreeMemory(EnumContext->Buffer[i].Name.Buffer);
960 }
961
962 SamFreeMemory(EnumContext->Buffer);
963 EnumContext->Buffer = NULL;
964 }
965 break;
966
967 case AccountPhase:
968 case DonePhase:
969 EnumContext->Phase = DonePhase;
970 break;
971 }
972 }
973 // }
974
975 done:
976 if (ApiStatus == NERR_Success && EnumContext != NULL && EnumContext->Phase != DonePhase)
977 ApiStatus = ERROR_MORE_DATA;
978
979 if (EnumContext != NULL)
980 *totalentries = EnumContext->Returned;
981
982 if (resume_handle == NULL || ApiStatus != ERROR_MORE_DATA)
983 {
984 if (EnumContext != NULL)
985 {
986 if (EnumContext->BuiltinDomainHandle != NULL)
987 SamCloseHandle(EnumContext->BuiltinDomainHandle);
988
989 if (EnumContext->AccountDomainHandle != NULL)
990 SamCloseHandle(EnumContext->AccountDomainHandle);
991
992 if (EnumContext->ServerHandle != NULL)
993 SamCloseHandle(EnumContext->ServerHandle);
994
995 if (EnumContext->Buffer != NULL)
996 {
997 for (i = 0; i < EnumContext->Returned; i++)
998 {
999 SamFreeMemory(EnumContext->Buffer[i].Name.Buffer);
1000 }
1001
1002 SamFreeMemory(EnumContext->Buffer);
1003 }
1004
1005 NetApiBufferFree(EnumContext);
1006 EnumContext = NULL;
1007 }
1008 }
1009
1010 if (GroupHandle != NULL)
1011 SamCloseHandle(GroupHandle);
1012
1013 if (GroupInfo != NULL)
1014 FreeGroupInfo(GroupInfo);
1015
1016 if (resume_handle != NULL)
1017 *resume_handle = (DWORD_PTR)EnumContext;
1018
1019 *bufptr = (LPBYTE)Buffer;
1020
1021 TRACE("return %lu\n", ApiStatus);
1022
1023 return ApiStatus;
1024 }
1025
1026
1027 NET_API_STATUS
1028 WINAPI
1029 NetGroupGetInfo(
1030 _In_opt_ LPCWSTR servername,
1031 _In_ LPCWSTR groupname,
1032 _In_ DWORD level,
1033 _Out_ LPBYTE *bufptr)
1034 {
1035 UNICODE_STRING ServerName;
1036 UNICODE_STRING GroupName;
1037 SAM_HANDLE ServerHandle = NULL;
1038 SAM_HANDLE DomainHandle = NULL;
1039 SAM_HANDLE GroupHandle = NULL;
1040 PGROUP_GENERAL_INFORMATION GroupInfo = NULL;
1041 PVOID Buffer = NULL;
1042 ULONG RelativeId;
1043 NET_API_STATUS ApiStatus = NERR_Success;
1044 NTSTATUS Status = STATUS_SUCCESS;
1045
1046 TRACE("NetGroupGetInfo(%s, %s, %d, %p)\n",
1047 debugstr_w(servername), debugstr_w(groupname), level, bufptr);
1048
1049 if (servername != NULL)
1050 RtlInitUnicodeString(&ServerName, servername);
1051
1052 RtlInitUnicodeString(&GroupName, groupname);
1053
1054 /* Connect to the SAM Server */
1055 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
1056 &ServerHandle,
1057 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
1058 NULL);
1059 if (!NT_SUCCESS(Status))
1060 {
1061 ERR("SamConnect failed (Status %08lx)\n", Status);
1062 ApiStatus = NetpNtStatusToApiStatus(Status);
1063 goto done;
1064 }
1065
1066 /* Open the Acount Domain */
1067 Status = OpenAccountDomain(ServerHandle,
1068 (servername != NULL) ? &ServerName : NULL,
1069 DOMAIN_LOOKUP,
1070 &DomainHandle);
1071 if (!NT_SUCCESS(Status))
1072 {
1073 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
1074 ApiStatus = NetpNtStatusToApiStatus(Status);
1075 goto done;
1076 }
1077
1078 /* Open the group account in the account domain */
1079 ApiStatus = OpenGroupByName(DomainHandle,
1080 &GroupName,
1081 GROUP_READ_INFORMATION,
1082 &GroupHandle,
1083 &RelativeId);
1084 if (ApiStatus != NERR_Success)
1085 {
1086 ERR("OpenGroupByName failed (ApiStatus %lu)\n", ApiStatus);
1087 if (ApiStatus == ERROR_NONE_MAPPED)
1088 ApiStatus = NERR_GroupNotFound;
1089 goto done;
1090 }
1091
1092 Status = SamQueryInformationGroup(GroupHandle,
1093 GroupGeneralInformation,
1094 (PVOID *)&GroupInfo);
1095 if (!NT_SUCCESS(Status))
1096 {
1097 ERR("SamQueryInformationGroup failed (Status %08lx)\n", Status);
1098 ApiStatus = NetpNtStatusToApiStatus(Status);
1099 goto done;
1100 }
1101
1102 ApiStatus = BuildGroupInfoBuffer(GroupInfo,
1103 level,
1104 RelativeId,
1105 &Buffer);
1106 if (ApiStatus != NERR_Success)
1107 goto done;
1108
1109 done:
1110 if (GroupInfo != NULL)
1111 FreeGroupInfo(GroupInfo);
1112
1113 if (GroupHandle != NULL)
1114 SamCloseHandle(GroupHandle);
1115
1116 if (DomainHandle != NULL)
1117 SamCloseHandle(DomainHandle);
1118
1119 if (ServerHandle != NULL)
1120 SamCloseHandle(ServerHandle);
1121
1122 *bufptr = (LPBYTE)Buffer;
1123
1124 return ApiStatus;
1125 }
1126
1127
1128 NET_API_STATUS
1129 WINAPI
1130 NetGroupGetUsers(
1131 _In_opt_ LPCWSTR servername,
1132 _In_ LPCWSTR groupname,
1133 _In_ DWORD level,
1134 _Out_ LPBYTE *bufptr,
1135 _In_ DWORD prefmaxlen,
1136 _Out_ LPDWORD entriesread,
1137 _Out_ LPDWORD totalentries,
1138 _Inout_ PDWORD_PTR resume_handle)
1139 {
1140 UNICODE_STRING ServerName;
1141 UNICODE_STRING GroupName;
1142 PGROUP_USERS_INFO_0 UserInfo0;
1143 PGROUP_USERS_INFO_1 UserInfo1;
1144 PUSER_ENUM_CONTEXT EnumContext = NULL;
1145 PVOID Buffer = NULL;
1146 ULONG i, idx, Size;
1147 PWSTR Ptr;
1148 NET_API_STATUS ApiStatus = NERR_Success;
1149 NTSTATUS Status = STATUS_SUCCESS;
1150
1151 TRACE("NetGroupGetUsers(%s, %s, %d, %p, %d, %p, %p, %p)\n",
1152 debugstr_w(servername), debugstr_w(groupname), level, bufptr,
1153 prefmaxlen, entriesread, totalentries, resume_handle);
1154
1155 *entriesread = 0;
1156 *totalentries = 0;
1157 *bufptr = NULL;
1158
1159 if (servername != NULL)
1160 RtlInitUnicodeString(&ServerName, servername);
1161
1162 RtlInitUnicodeString(&GroupName, groupname);
1163
1164 if (resume_handle != NULL && *resume_handle != 0)
1165 {
1166 EnumContext = (PUSER_ENUM_CONTEXT)*resume_handle;
1167 }
1168 else
1169 {
1170 ApiStatus = NetApiBufferAllocate(sizeof(USER_ENUM_CONTEXT), (PVOID*)&EnumContext);
1171 if (ApiStatus != NERR_Success)
1172 goto done;
1173
1174 EnumContext->MemberCount = 0;
1175 EnumContext->MemberIds = NULL;
1176 EnumContext->Attributes = NULL;
1177 EnumContext->Names = NULL;
1178 EnumContext->Start = 0;
1179 EnumContext->Count = 0;
1180
1181 /* Connect to the SAM Server */
1182 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
1183 &EnumContext->ServerHandle,
1184 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
1185 NULL);
1186 if (!NT_SUCCESS(Status))
1187 {
1188 ERR("SamConnect failed (Status %08lx)\n", Status);
1189 ApiStatus = NetpNtStatusToApiStatus(Status);
1190 goto done;
1191 }
1192
1193 /* Open the Acount Domain */
1194 Status = OpenAccountDomain(EnumContext->ServerHandle,
1195 (servername != NULL) ? &ServerName : NULL,
1196 DOMAIN_LOOKUP,
1197 &EnumContext->DomainHandle);
1198 if (!NT_SUCCESS(Status))
1199 {
1200 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
1201 ApiStatus = NetpNtStatusToApiStatus(Status);
1202 goto done;
1203 }
1204
1205 /* Open the group account */
1206 ApiStatus = OpenGroupByName(EnumContext->DomainHandle,
1207 &GroupName,
1208 GROUP_LIST_MEMBERS,
1209 &EnumContext->GroupHandle,
1210 NULL);
1211 if (ApiStatus != NERR_Success)
1212 {
1213 ERR("OpenGroupByName failed (ApiStatus %lu)\n", ApiStatus);
1214 if (ApiStatus == ERROR_NONE_MAPPED)
1215 ApiStatus = NERR_GroupNotFound;
1216 goto done;
1217 }
1218
1219 /* Get the group members */
1220 Status = SamGetMembersInGroup(EnumContext->GroupHandle,
1221 &EnumContext->MemberIds,
1222 &EnumContext->Attributes,
1223 &EnumContext->MemberCount);
1224 if (!NT_SUCCESS(Status))
1225 {
1226 ERR("SamGetMembersInGroup failed (Status %08lx)\n", Status);
1227 ApiStatus = NetpNtStatusToApiStatus(Status);
1228 goto done;
1229 }
1230
1231 if (EnumContext->MemberCount > 0)
1232 {
1233 /* Get all member names */
1234 Status = SamLookupIdsInDomain(EnumContext->DomainHandle,
1235 EnumContext->MemberCount,
1236 EnumContext->MemberIds,
1237 &EnumContext->Names,
1238 NULL);
1239 if (!NT_SUCCESS(Status))
1240 {
1241 ERR("SamLookupIdsInDomain failed (Status %08lx)\n", Status);
1242 ApiStatus = NetpNtStatusToApiStatus(Status);
1243 goto done;
1244 }
1245 }
1246 }
1247
1248 /* Calculate the required buffer size */
1249 Size = 0;
1250 if (prefmaxlen == -1)
1251 {
1252 Size = EnumContext->MemberCount *
1253 ((level == 0) ? sizeof(GROUP_USERS_INFO_0) : sizeof(GROUP_USERS_INFO_1));
1254 for (i = EnumContext->Start; i < EnumContext->MemberCount; i++)
1255 Size += EnumContext->Names[i].Length + sizeof(WCHAR);
1256
1257 EnumContext->Count = EnumContext->MemberCount;
1258 }
1259 else
1260 {
1261 for (i = EnumContext->Start; i < EnumContext->MemberCount; i++)
1262 {
1263 Size += (level == 0) ? sizeof(GROUP_USERS_INFO_0) : sizeof(GROUP_USERS_INFO_1);
1264 Size += EnumContext->Names[i].Length + sizeof(WCHAR);
1265
1266 EnumContext->Count++;
1267
1268 if (Size >= prefmaxlen)
1269 break;
1270 }
1271 }
1272
1273 TRACE("Buffer size: %lu\n", Size);
1274
1275 /* Allocate and clear the buffer */
1276 ApiStatus = NetApiBufferAllocate(Size, &Buffer);
1277 if (ApiStatus != NERR_Success)
1278 goto done;
1279
1280 ZeroMemory(Buffer, Size);
1281
1282 /* Fill the buffer */
1283 if (level == 0)
1284 Ptr = (PWCHAR)((LONG_PTR)Buffer + EnumContext->Count * sizeof(GROUP_USERS_INFO_0));
1285 else
1286 Ptr = (PWCHAR)((LONG_PTR)Buffer + EnumContext->Count * sizeof(GROUP_USERS_INFO_1));
1287
1288 for (i = 0; i < EnumContext->Count; i++)
1289 {
1290 idx = EnumContext->Start + i;
1291
1292 if (level == 0)
1293 {
1294 UserInfo0 = (PGROUP_USERS_INFO_0)Buffer;
1295
1296 UserInfo0[i].grui0_name = Ptr;
1297
1298 memcpy(UserInfo0[i].grui0_name,
1299 EnumContext->Names[idx].Buffer,
1300 EnumContext->Names[idx].Length);
1301 UserInfo0[i].grui0_name[EnumContext->Names[idx].Length / sizeof(WCHAR)] = UNICODE_NULL;
1302
1303 Ptr = (PWSTR)((ULONG_PTR)Ptr + EnumContext->Names[idx].Length + sizeof(WCHAR));
1304 }
1305 else
1306 {
1307 UserInfo1 = (PGROUP_USERS_INFO_1)Buffer;
1308
1309 UserInfo1[i].grui1_name = Ptr;
1310
1311 memcpy(UserInfo1[i].grui1_name,
1312 EnumContext->Names[idx].Buffer,
1313 EnumContext->Names[idx].Length);
1314 UserInfo1[i].grui1_name[EnumContext->Names[idx].Length / sizeof(WCHAR)] = UNICODE_NULL;
1315
1316 UserInfo1[i].grui1_attributes = EnumContext->Attributes[idx];
1317
1318 Ptr = (PWSTR)((ULONG_PTR)Ptr + EnumContext->Names[idx].Length + sizeof(WCHAR));
1319 }
1320 }
1321
1322 /* Set the new start index */
1323 EnumContext->Start += EnumContext->Count;
1324
1325 /* Only return ERROR_MORE_DATA if we are not done yet */
1326 if (EnumContext->MemberCount > EnumContext->Start)
1327 ApiStatus = ERROR_MORE_DATA;
1328 else
1329 ApiStatus = NERR_Success;
1330
1331 done:
1332 if (EnumContext != NULL)
1333 {
1334 *entriesread = EnumContext->Count;
1335 *totalentries = EnumContext->MemberCount;
1336 }
1337
1338 if (resume_handle == NULL || ApiStatus != ERROR_MORE_DATA)
1339 {
1340 if (EnumContext != NULL)
1341 {
1342 if (EnumContext->Names != NULL)
1343 {
1344 for (i = 0; i < EnumContext->MemberCount; i++)
1345 SamFreeMemory(EnumContext->Names[i].Buffer);
1346
1347 SamFreeMemory(EnumContext->Names);
1348 }
1349
1350 if (EnumContext->Attributes != NULL)
1351 SamFreeMemory(EnumContext->Attributes);
1352
1353 if (EnumContext->MemberIds != NULL)
1354 SamFreeMemory(EnumContext->MemberIds);
1355
1356
1357 if (EnumContext->GroupHandle != NULL)
1358 SamCloseHandle(EnumContext->GroupHandle);
1359
1360 if (EnumContext->DomainHandle != NULL)
1361 SamCloseHandle(EnumContext->DomainHandle);
1362
1363 if (EnumContext->ServerHandle != NULL)
1364 SamCloseHandle(EnumContext->ServerHandle);
1365
1366 NetApiBufferFree(EnumContext);
1367 EnumContext = NULL;
1368 }
1369 }
1370
1371 *bufptr = (LPBYTE)Buffer;
1372
1373 if (resume_handle != NULL)
1374 *resume_handle = (DWORD_PTR)EnumContext;
1375
1376 return ApiStatus;
1377 }
1378
1379
1380 NET_API_STATUS
1381 WINAPI
1382 NetGroupSetInfo(
1383 _In_opt_ LPCWSTR servername,
1384 _In_ LPCWSTR groupname,
1385 _In_ DWORD level,
1386 _In_ LPBYTE buf,
1387 _Out_opt_ LPDWORD parm_err)
1388 {
1389 UNICODE_STRING ServerName;
1390 UNICODE_STRING GroupName;
1391 SAM_HANDLE ServerHandle = NULL;
1392 SAM_HANDLE DomainHandle = NULL;
1393 SAM_HANDLE GroupHandle = NULL;
1394 GROUP_NAME_INFORMATION GroupNameInfo;
1395 GROUP_ADM_COMMENT_INFORMATION AdminCommentInfo;
1396 GROUP_ATTRIBUTE_INFORMATION AttributeInfo;
1397 NET_API_STATUS ApiStatus = NERR_Success;
1398 NTSTATUS Status = STATUS_SUCCESS;
1399
1400 TRACE("NetGroupSetInfo(%s, %s, %d, %p, %p)\n",
1401 debugstr_w(servername), debugstr_w(groupname), level, buf, parm_err);
1402
1403 if (parm_err != NULL)
1404 *parm_err = PARM_ERROR_NONE;
1405
1406 if (servername != NULL)
1407 RtlInitUnicodeString(&ServerName, servername);
1408
1409 RtlInitUnicodeString(&GroupName, groupname);
1410
1411 /* Connect to the SAM Server */
1412 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
1413 &ServerHandle,
1414 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
1415 NULL);
1416 if (!NT_SUCCESS(Status))
1417 {
1418 ERR("SamConnect failed (Status %08lx)\n", Status);
1419 ApiStatus = NetpNtStatusToApiStatus(Status);
1420 goto done;
1421 }
1422
1423 /* Open the Acount Domain */
1424 Status = OpenAccountDomain(ServerHandle,
1425 (servername != NULL) ? &ServerName : NULL,
1426 DOMAIN_LOOKUP,
1427 &DomainHandle);
1428 if (!NT_SUCCESS(Status))
1429 {
1430 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
1431 ApiStatus = NetpNtStatusToApiStatus(Status);
1432 goto done;
1433 }
1434
1435 /* Open the group */
1436 ApiStatus = OpenGroupByName(DomainHandle,
1437 &GroupName,
1438 GROUP_WRITE_ACCOUNT,
1439 &GroupHandle,
1440 NULL);
1441 if (ApiStatus != NERR_Success)
1442 {
1443 WARN("OpenGroupByName failed (ApiStatus %lu)\n", ApiStatus);
1444 if (ApiStatus == ERROR_NONE_MAPPED)
1445 ApiStatus = NERR_GroupNotFound;
1446 goto done;
1447 }
1448
1449 switch (level)
1450 {
1451 case 0:
1452 /* Set the group name */
1453 RtlInitUnicodeString(&GroupNameInfo.Name,
1454 ((PGROUP_INFO_0)buf)->grpi0_name);
1455
1456 Status = SamSetInformationGroup(GroupHandle,
1457 GroupNameInformation,
1458 &GroupNameInfo);
1459 if (!NT_SUCCESS(Status))
1460 {
1461 ERR("SamSetInformationGroup failed (ApiStatus %lu)\n", ApiStatus);
1462 ApiStatus = NetpNtStatusToApiStatus(Status);
1463 goto done;
1464 }
1465 break;
1466
1467 case 1:
1468 /* Set the group name */
1469 RtlInitUnicodeString(&GroupNameInfo.Name,
1470 ((PGROUP_INFO_1)buf)->grpi1_name);
1471
1472 Status = SamSetInformationGroup(GroupHandle,
1473 GroupNameInformation,
1474 &GroupNameInfo);
1475 if (!NT_SUCCESS(Status))
1476 {
1477 ERR("SamSetInformationGroup failed (ApiStatus %lu)\n", ApiStatus);
1478 ApiStatus = NetpNtStatusToApiStatus(Status);
1479 goto done;
1480 }
1481
1482 /* Set the admin comment */
1483 RtlInitUnicodeString(&AdminCommentInfo.AdminComment,
1484 ((PGROUP_INFO_1)buf)->grpi1_comment);
1485
1486 Status = SamSetInformationGroup(GroupHandle,
1487 GroupAdminCommentInformation,
1488 &AdminCommentInfo);
1489 if (!NT_SUCCESS(Status))
1490 {
1491 ERR("SamSetInformationGroup failed (ApiStatus %lu)\n", ApiStatus);
1492 ApiStatus = NetpNtStatusToApiStatus(Status);
1493 goto done;
1494 }
1495 break;
1496
1497 case 2:
1498 /* Set the group name */
1499 RtlInitUnicodeString(&GroupNameInfo.Name,
1500 ((PGROUP_INFO_2)buf)->grpi2_name);
1501
1502 Status = SamSetInformationGroup(GroupHandle,
1503 GroupNameInformation,
1504 &GroupNameInfo);
1505 if (!NT_SUCCESS(Status))
1506 {
1507 ERR("SamSetInformationGroup failed (ApiStatus %lu)\n", ApiStatus);
1508 ApiStatus = NetpNtStatusToApiStatus(Status);
1509 goto done;
1510 }
1511
1512 /* Set the admin comment */
1513 RtlInitUnicodeString(&AdminCommentInfo.AdminComment,
1514 ((PGROUP_INFO_2)buf)->grpi2_comment);
1515
1516 Status = SamSetInformationGroup(GroupHandle,
1517 GroupAdminCommentInformation,
1518 &AdminCommentInfo);
1519 if (!NT_SUCCESS(Status))
1520 {
1521 ERR("SamSetInformationGroup failed (ApiStatus %lu)\n", ApiStatus);
1522 ApiStatus = NetpNtStatusToApiStatus(Status);
1523 goto done;
1524 }
1525
1526 /* Set the attributes */
1527 AttributeInfo.Attributes = ((PGROUP_INFO_2)buf)->grpi2_attributes;
1528
1529 Status = SamSetInformationGroup(GroupHandle,
1530 GroupAttributeInformation,
1531 &AttributeInfo);
1532 if (!NT_SUCCESS(Status))
1533 {
1534 ERR("SamSetInformationGroup failed (ApiStatus %lu)\n", ApiStatus);
1535 ApiStatus = NetpNtStatusToApiStatus(Status);
1536 goto done;
1537 }
1538 break;
1539
1540 case 3:
1541 /* Set the group name */
1542 RtlInitUnicodeString(&GroupNameInfo.Name,
1543 ((PGROUP_INFO_3)buf)->grpi3_name);
1544
1545 Status = SamSetInformationGroup(GroupHandle,
1546 GroupNameInformation,
1547 &GroupNameInfo);
1548 if (!NT_SUCCESS(Status))
1549 {
1550 ERR("SamSetInformationGroup failed (ApiStatus %lu)\n", ApiStatus);
1551 ApiStatus = NetpNtStatusToApiStatus(Status);
1552 goto done;
1553 }
1554
1555 /* Set the admin comment */
1556 RtlInitUnicodeString(&AdminCommentInfo.AdminComment,
1557 ((PGROUP_INFO_3)buf)->grpi3_comment);
1558
1559 Status = SamSetInformationGroup(GroupHandle,
1560 GroupAdminCommentInformation,
1561 &AdminCommentInfo);
1562 if (!NT_SUCCESS(Status))
1563 {
1564 ERR("SamSetInformationGroup failed (ApiStatus %lu)\n", ApiStatus);
1565 ApiStatus = NetpNtStatusToApiStatus(Status);
1566 goto done;
1567 }
1568
1569 /* Set the attributes */
1570 AttributeInfo.Attributes = ((PGROUP_INFO_3)buf)->grpi3_attributes;
1571
1572 Status = SamSetInformationGroup(GroupHandle,
1573 GroupAttributeInformation,
1574 &AttributeInfo);
1575 if (!NT_SUCCESS(Status))
1576 {
1577 ERR("SamSetInformationGroup failed (ApiStatus %lu)\n", ApiStatus);
1578 ApiStatus = NetpNtStatusToApiStatus(Status);
1579 goto done;
1580 }
1581 break;
1582
1583 case 1002:
1584 /* Set the admin comment */
1585 RtlInitUnicodeString(&AdminCommentInfo.AdminComment,
1586 ((PGROUP_INFO_1002)buf)->grpi1002_comment);
1587
1588 Status = SamSetInformationGroup(GroupHandle,
1589 GroupAdminCommentInformation,
1590 &AdminCommentInfo);
1591 if (!NT_SUCCESS(Status))
1592 {
1593 ERR("SamSetInformationGroup failed (ApiStatus %lu)\n", ApiStatus);
1594 ApiStatus = NetpNtStatusToApiStatus(Status);
1595 goto done;
1596 }
1597 break;
1598
1599 case 1005:
1600 /* Set the attributes */
1601 AttributeInfo.Attributes = ((PGROUP_INFO_1005)buf)->grpi1005_attributes;
1602
1603 Status = SamSetInformationGroup(GroupHandle,
1604 GroupAttributeInformation,
1605 &AttributeInfo);
1606 if (!NT_SUCCESS(Status))
1607 {
1608 ERR("SamSetInformationGroup failed (ApiStatus %lu)\n", ApiStatus);
1609 ApiStatus = NetpNtStatusToApiStatus(Status);
1610 goto done;
1611 }
1612 break;
1613
1614 default:
1615 ApiStatus = ERROR_INVALID_LEVEL;
1616 goto done;
1617 }
1618
1619 done:
1620 if (GroupHandle != NULL)
1621 SamCloseHandle(GroupHandle);
1622
1623 if (DomainHandle != NULL)
1624 SamCloseHandle(DomainHandle);
1625
1626 if (ServerHandle != NULL)
1627 SamCloseHandle(ServerHandle);
1628
1629 return ApiStatus;
1630 }
1631
1632
1633 NET_API_STATUS
1634 WINAPI
1635 NetGroupSetUsers(
1636 _In_opt_ LPCWSTR servername,
1637 _In_ LPCWSTR groupname,
1638 _In_ DWORD level,
1639 _In_ LPBYTE buf,
1640 _In_ DWORD totalentries)
1641 {
1642 UNICODE_STRING ServerName;
1643 UNICODE_STRING GroupName;
1644 SAM_HANDLE ServerHandle = NULL;
1645 SAM_HANDLE DomainHandle = NULL;
1646 SAM_HANDLE GroupHandle = NULL;
1647 ULONG OldMemberCount = 0;
1648 PULONG OldMemberIDs = NULL;
1649 PULONG OldAttributes = NULL;
1650 PUNICODE_STRING NamesArray = NULL;
1651 PGROUP_USERS_INFO_0 UserInfo0;
1652 PGROUP_USERS_INFO_1 UserInfo1;
1653 PULONG NewMemberIDs = NULL;
1654 PSID_NAME_USE NewMemberUse = NULL;
1655 ULONG i, j;
1656 BOOL Found;
1657 NET_API_STATUS ApiStatus = NERR_Success;
1658 NTSTATUS Status = STATUS_SUCCESS;
1659
1660 TRACE("NetGroupSetUsers(%s, %s, %d, %p, %d) stub!\n",
1661 debugstr_w(servername), debugstr_w(groupname), level, buf, totalentries);
1662
1663 if (servername != NULL)
1664 RtlInitUnicodeString(&ServerName, servername);
1665
1666 RtlInitUnicodeString(&GroupName, groupname);
1667
1668 /* Connect to the SAM Server */
1669 Status = SamConnect((servername != NULL) ? &ServerName : NULL,
1670 &ServerHandle,
1671 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
1672 NULL);
1673 if (!NT_SUCCESS(Status))
1674 {
1675 ERR("SamConnect failed (Status %08lx)\n", Status);
1676 ApiStatus = NetpNtStatusToApiStatus(Status);
1677 goto done;
1678 }
1679
1680 /* Open the Acount Domain */
1681 Status = OpenAccountDomain(ServerHandle,
1682 (servername != NULL) ? &ServerName : NULL,
1683 DOMAIN_LOOKUP,
1684 &DomainHandle);
1685 if (!NT_SUCCESS(Status))
1686 {
1687 ERR("OpenAccountDomain failed (Status %08lx)\n", Status);
1688 ApiStatus = NetpNtStatusToApiStatus(Status);
1689 goto done;
1690 }
1691
1692 /* Open the group account in the account domain */
1693 ApiStatus = OpenGroupByName(DomainHandle,
1694 &GroupName,
1695 GROUP_LIST_MEMBERS | GROUP_ADD_MEMBER | GROUP_REMOVE_MEMBER,
1696 &GroupHandle,
1697 NULL);
1698 if (ApiStatus != NERR_Success)
1699 {
1700 ERR("OpenGroupByName failed (ApiStatus %lu)\n", ApiStatus);
1701 if (ApiStatus == ERROR_NONE_MAPPED)
1702 ApiStatus = NERR_GroupNotFound;
1703 goto done;
1704 }
1705
1706 /* Get the group members */
1707 Status = SamGetMembersInGroup(GroupHandle,
1708 &OldMemberIDs,
1709 &OldAttributes,
1710 &OldMemberCount);
1711 if (!NT_SUCCESS(Status))
1712 {
1713 ERR("SamGetMembersInGroup failed (Status %08lx)\n", Status);
1714 ApiStatus = NetpNtStatusToApiStatus(Status);
1715 goto done;
1716 }
1717
1718 NamesArray = RtlAllocateHeap(RtlGetProcessHeap(),
1719 HEAP_ZERO_MEMORY,
1720 totalentries * sizeof(UNICODE_STRING));
1721 if (NamesArray == NULL)
1722 {
1723 ERR("RtlAllocateHeap failed\n");
1724 ApiStatus = ERROR_OUTOFMEMORY;
1725 goto done;
1726 }
1727
1728 UserInfo0 = (PGROUP_USERS_INFO_0)buf;
1729 UserInfo1 = (PGROUP_USERS_INFO_1)buf;
1730 for (i = 0; i < totalentries; i++)
1731 {
1732 if (level == 0)
1733 RtlInitUnicodeString(&NamesArray[i], UserInfo0[i].grui0_name);
1734 else
1735 RtlInitUnicodeString(&NamesArray[i], UserInfo1[i].grui1_name);
1736 }
1737
1738 Status = SamLookupNamesInDomain(DomainHandle,
1739 totalentries,
1740 NamesArray,
1741 &NewMemberIDs,
1742 &NewMemberUse);
1743 if (!NT_SUCCESS(Status))
1744 {
1745 ERR("SamLookupNamesInDomain failed (Status %08lx)\n", Status);
1746
1747 if (Status == STATUS_NONE_MAPPED)
1748 {
1749 ApiStatus = NERR_UserNotFound;
1750 goto done;
1751 }
1752
1753 ApiStatus = NetpNtStatusToApiStatus(Status);
1754 goto done;
1755 }
1756
1757 /* Add members and set attributes for existing members */
1758 for (i = 0; i < totalentries; i++)
1759 {
1760 Found = FALSE;
1761 for (j = 0; j < OldMemberCount; j++)
1762 {
1763 if (NewMemberIDs[i] == OldMemberIDs[j])
1764 {
1765 if (level == 1)
1766 {
1767 Status = SamSetMemberAttributesOfGroup(GroupHandle,
1768 NewMemberIDs[i],
1769 UserInfo1[i].grui1_attributes);
1770 if (!NT_SUCCESS(Status))
1771 {
1772 ERR("SamSetMemberAttributesOfGroup failed (Status %lu)\n", Status);
1773 ApiStatus = NetpNtStatusToApiStatus(Status);
1774 goto done;
1775 }
1776 }
1777
1778 Found = TRUE;
1779 break;
1780 }
1781 }
1782
1783 if (Found == FALSE)
1784 {
1785 TRACE("Add member %lx\n", NewMemberIDs[i]);
1786
1787 if (NewMemberUse[i] != SidTypeUser)
1788 {
1789 ERR("New member is not a user!\n");
1790 ApiStatus = NERR_GroupNotFound;
1791 goto done;
1792 }
1793
1794 Status = SamAddMemberToGroup(GroupHandle,
1795 NewMemberIDs[i],
1796 (level == 0) ? 0 : UserInfo1[i].grui1_attributes);
1797 if (!NT_SUCCESS(Status))
1798 {
1799 ERR("SamAddMemberToGroup failed (Status %lu)\n", Status);
1800 ApiStatus = NetpNtStatusToApiStatus(Status);
1801 goto done;
1802 }
1803 }
1804 }
1805
1806 /* Remove members */
1807 for (i = 0; i < OldMemberCount; i++)
1808 {
1809 Found = FALSE;
1810 for (j = 0; j < totalentries; j++)
1811 {
1812 if (OldMemberIDs[i] == NewMemberIDs[j])
1813 {
1814 Found = TRUE;
1815 break;
1816 }
1817 }
1818
1819 if (Found == FALSE)
1820 {
1821 TRACE("Delete member %lx\n", OldMemberIDs[i]);
1822
1823 Status = SamRemoveMemberFromGroup(GroupHandle,
1824 OldMemberIDs[i]);
1825 if (!NT_SUCCESS(Status))
1826 {
1827 ERR("SamRemoveMemberFromGroup failed (Status %lu)\n", Status);
1828 ApiStatus = NetpNtStatusToApiStatus(Status);
1829 goto done;
1830 }
1831 }
1832 }
1833
1834 done:
1835 if (NewMemberUse != NULL)
1836 SamFreeMemory(NewMemberUse);
1837
1838 if (NewMemberIDs != NULL)
1839 SamFreeMemory(NewMemberIDs);
1840
1841 if (NamesArray != NULL)
1842 RtlFreeHeap(RtlGetProcessHeap(), 0, NamesArray);
1843
1844 if (OldMemberIDs != NULL)
1845 SamFreeMemory(OldMemberIDs);
1846
1847 if (GroupHandle != NULL)
1848 SamCloseHandle(GroupHandle);
1849
1850 if (DomainHandle != NULL)
1851 SamCloseHandle(DomainHandle);
1852
1853 if (ServerHandle != NULL)
1854 SamCloseHandle(ServerHandle);
1855
1856 return ApiStatus;
1857 }
1858
1859 /* EOF */