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