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