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