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