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