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