diff options
| author | Rob Mensching <rob@firegiant.com> | 2021-04-11 14:15:32 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2021-04-12 19:28:07 -0700 |
| commit | 4b3f52f14bce8a032fcc476556cc4d60aa20241b (patch) | |
| tree | 227e8bfd5263e7d7acb8d37715155e61ad1051ba /src/ca/scaexec.cpp | |
| parent | ae7e9817bb10d635e031e51496f2e529595a9cfe (diff) | |
| download | wix-4b3f52f14bce8a032fcc476556cc4d60aa20241b.tar.gz wix-4b3f52f14bce8a032fcc476556cc4d60aa20241b.tar.bz2 wix-4b3f52f14bce8a032fcc476556cc4d60aa20241b.zip | |
Fix rollback of user rights
Diffstat (limited to 'src/ca/scaexec.cpp')
| -rw-r--r-- | src/ca/scaexec.cpp | 433 |
1 files changed, 354 insertions, 79 deletions
diff --git a/src/ca/scaexec.cpp b/src/ca/scaexec.cpp index ab9e6599..5845c1b4 100644 --- a/src/ca/scaexec.cpp +++ b/src/ca/scaexec.cpp | |||
| @@ -293,6 +293,110 @@ LExit: | |||
| 293 | } | 293 | } |
| 294 | 294 | ||
| 295 | 295 | ||
| 296 | static HRESULT GetUserHasRight( | ||
| 297 | __in LSA_HANDLE hPolicy, | ||
| 298 | __in PSID pUserSid, | ||
| 299 | __in LPWSTR wzRight, | ||
| 300 | __out BOOL* fHasRight | ||
| 301 | ) | ||
| 302 | { | ||
| 303 | HRESULT hr = S_OK; | ||
| 304 | NTSTATUS nt = 0; | ||
| 305 | LSA_UNICODE_STRING lucPrivilege = { 0 }; | ||
| 306 | PLSA_ENUMERATION_INFORMATION rgSids = NULL; | ||
| 307 | ULONG cSids = 0; | ||
| 308 | *fHasRight = FALSE; | ||
| 309 | |||
| 310 | lucPrivilege.Buffer = wzRight; | ||
| 311 | lucPrivilege.Length = static_cast<USHORT>(lstrlenW(lucPrivilege.Buffer) * sizeof(WCHAR)); | ||
| 312 | lucPrivilege.MaximumLength = (lucPrivilege.Length + 1) * sizeof(WCHAR); | ||
| 313 | |||
| 314 | nt = ::LsaEnumerateAccountsWithUserRight(hPolicy, &lucPrivilege, reinterpret_cast<PVOID*>(&rgSids), &cSids); | ||
| 315 | hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); | ||
| 316 | ExitOnFailure(hr, "Failed to enumerate users for right: %ls", lucPrivilege.Buffer); | ||
| 317 | |||
| 318 | for (DWORD i = 0; i < cSids; ++i) | ||
| 319 | { | ||
| 320 | PLSA_ENUMERATION_INFORMATION pInfo = rgSids + i; | ||
| 321 | if (::EqualSid(pUserSid, pInfo->Sid)) | ||
| 322 | { | ||
| 323 | *fHasRight = TRUE; | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | LExit: | ||
| 329 | if (rgSids) | ||
| 330 | { | ||
| 331 | ::LsaFreeMemory(rgSids); | ||
| 332 | } | ||
| 333 | |||
| 334 | return hr; | ||
| 335 | } | ||
| 336 | |||
| 337 | |||
| 338 | static HRESULT GetExistingUserRightsAssignments( | ||
| 339 | __in_opt LPCWSTR wzDomain, | ||
| 340 | __in LPCWSTR wzName, | ||
| 341 | __inout int* iAttributes | ||
| 342 | ) | ||
| 343 | { | ||
| 344 | HRESULT hr = S_OK; | ||
| 345 | NTSTATUS nt = 0; | ||
| 346 | BOOL fHasRight = FALSE; | ||
| 347 | |||
| 348 | LSA_HANDLE hPolicy = NULL; | ||
| 349 | LSA_OBJECT_ATTRIBUTES objectAttributes = { 0 }; | ||
| 350 | |||
| 351 | LPWSTR pwzUser = NULL; | ||
| 352 | PSID psid = NULL; | ||
| 353 | |||
| 354 | if (wzDomain && *wzDomain) | ||
| 355 | { | ||
| 356 | hr = StrAllocFormatted(&pwzUser, L"%s\\%s", wzDomain, wzName); | ||
| 357 | ExitOnFailure(hr, "Failed to allocate user with domain string"); | ||
| 358 | } | ||
| 359 | else | ||
| 360 | { | ||
| 361 | hr = StrAllocString(&pwzUser, wzName, 0); | ||
| 362 | ExitOnFailure(hr, "Failed to allocate string from user name."); | ||
| 363 | } | ||
| 364 | |||
| 365 | hr = AclGetAccountSid(NULL, pwzUser, &psid); | ||
| 366 | ExitOnFailure(hr, "Failed to get SID for user: %ls", pwzUser); | ||
| 367 | |||
| 368 | nt = ::LsaOpenPolicy(NULL, &objectAttributes, POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION, &hPolicy); | ||
| 369 | hr = HRESULT_FROM_WIN32(::LsaNtStatusToWinError(nt)); | ||
| 370 | ExitOnFailure(hr, "Failed to open LSA policy store"); | ||
| 371 | |||
| 372 | hr = GetUserHasRight(hPolicy, psid, L"SeServiceLogonRight", &fHasRight); | ||
| 373 | ExitOnFailure(hr, "Failed to check LogonAsService right"); | ||
| 374 | |||
| 375 | if (fHasRight) | ||
| 376 | { | ||
| 377 | *iAttributes |= SCAU_ALLOW_LOGON_AS_SERVICE; | ||
| 378 | } | ||
| 379 | |||
| 380 | hr = GetUserHasRight(hPolicy, psid, L"SeBatchLogonRight", &fHasRight); | ||
| 381 | ExitOnFailure(hr, "Failed to check LogonAsBatchJob right"); | ||
| 382 | |||
| 383 | if (fHasRight) | ||
| 384 | { | ||
| 385 | *iAttributes |= SCAU_ALLOW_LOGON_AS_BATCH; | ||
| 386 | } | ||
| 387 | |||
| 388 | LExit: | ||
| 389 | if (hPolicy) | ||
| 390 | { | ||
| 391 | ::LsaClose(hPolicy); | ||
| 392 | } | ||
| 393 | |||
| 394 | ReleaseSid(psid); | ||
| 395 | ReleaseStr(pwzUser); | ||
| 396 | return hr; | ||
| 397 | } | ||
| 398 | |||
| 399 | |||
| 296 | static HRESULT ModifyUserLocalServiceRight( | 400 | static HRESULT ModifyUserLocalServiceRight( |
| 297 | __in_opt LPCWSTR wzDomain, | 401 | __in_opt LPCWSTR wzDomain, |
| 298 | __in LPCWSTR wzName, | 402 | __in LPCWSTR wzName, |
| @@ -466,6 +570,117 @@ static void SetUserPasswordAndAttributes( | |||
| 466 | } | 570 | } |
| 467 | 571 | ||
| 468 | 572 | ||
| 573 | static HRESULT RemoveUserInternal( | ||
| 574 | LPWSTR wzGroupCaData, | ||
| 575 | LPWSTR wzDomain, | ||
| 576 | LPWSTR wzName, | ||
| 577 | int iAttributes | ||
| 578 | ) | ||
| 579 | { | ||
| 580 | HRESULT hr = S_OK; | ||
| 581 | UINT er = ERROR_SUCCESS; | ||
| 582 | |||
| 583 | LPWSTR pwz = NULL; | ||
| 584 | LPWSTR pwzGroup = NULL; | ||
| 585 | LPWSTR pwzGroupDomain = NULL; | ||
| 586 | LPCWSTR wz = NULL; | ||
| 587 | PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; | ||
| 588 | |||
| 589 | // | ||
| 590 | // Remove the logon as service privilege. | ||
| 591 | // | ||
| 592 | if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes) | ||
| 593 | { | ||
| 594 | hr = ModifyUserLocalServiceRight(wzDomain, wzName, FALSE); | ||
| 595 | if (FAILED(hr)) | ||
| 596 | { | ||
| 597 | WcaLogError(hr, "Failed to remove logon as service right from user, continuing..."); | ||
| 598 | hr = S_OK; | ||
| 599 | } | ||
| 600 | } | ||
| 601 | |||
| 602 | if (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes) | ||
| 603 | { | ||
| 604 | hr = ModifyUserLocalBatchRight(wzDomain, wzName, FALSE); | ||
| 605 | if (FAILED(hr)) | ||
| 606 | { | ||
| 607 | WcaLogError(hr, "Failed to remove logon as batch job right from user, continuing..."); | ||
| 608 | hr = S_OK; | ||
| 609 | } | ||
| 610 | } | ||
| 611 | |||
| 612 | // | ||
| 613 | // Remove the User Account if the user was created by us. | ||
| 614 | // | ||
| 615 | if (!(SCAU_DONT_CREATE_USER & iAttributes)) | ||
| 616 | { | ||
| 617 | if (wzDomain && *wzDomain) | ||
| 618 | { | ||
| 619 | er = ::DsGetDcNameW(NULL, (LPCWSTR)wzDomain, NULL, NULL, NULL, &pDomainControllerInfo); | ||
| 620 | if (RPC_S_SERVER_UNAVAILABLE == er) | ||
| 621 | { | ||
| 622 | // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag | ||
| 623 | er = ::DsGetDcNameW(NULL, (LPCWSTR)wzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo); | ||
| 624 | } | ||
| 625 | if (ERROR_SUCCESS == er) | ||
| 626 | { | ||
| 627 | wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix | ||
| 628 | } | ||
| 629 | else | ||
| 630 | { | ||
| 631 | wz = wzDomain; | ||
| 632 | } | ||
| 633 | } | ||
| 634 | |||
| 635 | er = ::NetUserDel(wz, wzName); | ||
| 636 | if (NERR_UserNotFound == er) | ||
| 637 | { | ||
| 638 | er = NERR_Success; | ||
| 639 | } | ||
| 640 | ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to delete user account: %ls", wzName); | ||
| 641 | } | ||
| 642 | else | ||
| 643 | { | ||
| 644 | // | ||
| 645 | // Remove the user from the groups | ||
| 646 | // | ||
| 647 | pwz = wzGroupCaData; | ||
| 648 | while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) | ||
| 649 | { | ||
| 650 | hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); | ||
| 651 | |||
| 652 | if (FAILED(hr)) | ||
| 653 | { | ||
| 654 | WcaLogError(hr, "failed to get domain for group: %ls, continuing anyway.", pwzGroup); | ||
| 655 | } | ||
| 656 | else | ||
| 657 | { | ||
| 658 | hr = RemoveUserFromGroup(wzName, wzDomain, pwzGroup, pwzGroupDomain); | ||
| 659 | if (FAILED(hr)) | ||
| 660 | { | ||
| 661 | WcaLogError(hr, "failed to remove user: %ls from group %ls, continuing anyway.", wzName, pwzGroup); | ||
| 662 | } | ||
| 663 | } | ||
| 664 | } | ||
| 665 | |||
| 666 | if (E_NOMOREITEMS == hr) // if there are no more items, all is well | ||
| 667 | { | ||
| 668 | hr = S_OK; | ||
| 669 | } | ||
| 670 | |||
| 671 | ExitOnFailure(hr, "failed to get next group from which to remove user:%ls", wzName); | ||
| 672 | } | ||
| 673 | |||
| 674 | LExit: | ||
| 675 | if (pDomainControllerInfo) | ||
| 676 | { | ||
| 677 | ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo)); | ||
| 678 | } | ||
| 679 | |||
| 680 | return hr; | ||
| 681 | } | ||
| 682 | |||
| 683 | |||
| 469 | /******************************************************************** | 684 | /******************************************************************** |
| 470 | CreateUser - CUSTOM ACTION ENTRY POINT for creating users | 685 | CreateUser - CUSTOM ACTION ENTRY POINT for creating users |
| 471 | 686 | ||
| @@ -484,6 +699,7 @@ extern "C" UINT __stdcall CreateUser( | |||
| 484 | LPWSTR pwz = NULL; | 699 | LPWSTR pwz = NULL; |
| 485 | LPWSTR pwzName = NULL; | 700 | LPWSTR pwzName = NULL; |
| 486 | LPWSTR pwzDomain = NULL; | 701 | LPWSTR pwzDomain = NULL; |
| 702 | LPWSTR pwzScriptKey = NULL; | ||
| 487 | LPWSTR pwzPassword = NULL; | 703 | LPWSTR pwzPassword = NULL; |
| 488 | LPWSTR pwzGroup = NULL; | 704 | LPWSTR pwzGroup = NULL; |
| 489 | LPWSTR pwzGroupDomain = NULL; | 705 | LPWSTR pwzGroupDomain = NULL; |
| @@ -491,6 +707,10 @@ extern "C" UINT __stdcall CreateUser( | |||
| 491 | int iAttributes = 0; | 707 | int iAttributes = 0; |
| 492 | BOOL fInitializedCom = FALSE; | 708 | BOOL fInitializedCom = FALSE; |
| 493 | 709 | ||
| 710 | WCA_CASCRIPT_HANDLE hRollbackScript = NULL; | ||
| 711 | int iOriginalAttributes = 0; | ||
| 712 | int iRollbackAttributes = 0; | ||
| 713 | |||
| 494 | USER_INFO_1 userInfo; | 714 | USER_INFO_1 userInfo; |
| 495 | USER_INFO_1* puserInfo = NULL; | 715 | USER_INFO_1* puserInfo = NULL; |
| 496 | DWORD dw; | 716 | DWORD dw; |
| @@ -521,9 +741,44 @@ extern "C" UINT __stdcall CreateUser( | |||
| 521 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | 741 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); |
| 522 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | 742 | ExitOnFailure(hr, "failed to read attributes from custom action data"); |
| 523 | 743 | ||
| 744 | hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); | ||
| 745 | ExitOnFailure(hr, "failed to read encoding key from custom action data"); | ||
| 746 | |||
| 524 | hr = WcaReadStringFromCaData(&pwz, &pwzPassword); | 747 | hr = WcaReadStringFromCaData(&pwz, &pwzPassword); |
| 525 | ExitOnFailure(hr, "failed to read password from custom action data"); | 748 | ExitOnFailure(hr, "failed to read password from custom action data"); |
| 526 | 749 | ||
| 750 | // There is no rollback scheduled if the key is empty. | ||
| 751 | // Best effort to get original configuration and save it in the script so rollback can restore it. | ||
| 752 | if (*pwzScriptKey) | ||
| 753 | { | ||
| 754 | hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); | ||
| 755 | ExitOnFailure(hr, "Failed to open rollback CustomAction script."); | ||
| 756 | |||
| 757 | iRollbackAttributes = 0; | ||
| 758 | hr = GetExistingUserRightsAssignments(pwzDomain, pwzName, &iOriginalAttributes); | ||
| 759 | if (FAILED(hr)) | ||
| 760 | { | ||
| 761 | WcaLogError(hr, "failed to get existing user rights: %ls, continuing anyway.", pwzName); | ||
| 762 | } | ||
| 763 | else | ||
| 764 | { | ||
| 765 | if (!(SCAU_ALLOW_LOGON_AS_SERVICE & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes)) | ||
| 766 | { | ||
| 767 | iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_SERVICE; | ||
| 768 | } | ||
| 769 | if (!(SCAU_ALLOW_LOGON_AS_BATCH & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes)) | ||
| 770 | { | ||
| 771 | iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_BATCH; | ||
| 772 | } | ||
| 773 | } | ||
| 774 | |||
| 775 | hr = WcaCaScriptWriteNumber(hRollbackScript, iRollbackAttributes); | ||
| 776 | ExitOnFailure(hr, "Failed to add data to rollback script."); | ||
| 777 | |||
| 778 | // Nudge the system to get all our rollback data written to disk. | ||
| 779 | WcaCaScriptFlush(hRollbackScript); | ||
| 780 | } | ||
| 781 | |||
| 527 | if (!(SCAU_DONT_CREATE_USER & iAttributes)) | 782 | if (!(SCAU_DONT_CREATE_USER & iAttributes)) |
| 528 | { | 783 | { |
| 529 | ::ZeroMemory(&userInfo, sizeof(USER_INFO_1)); | 784 | ::ZeroMemory(&userInfo, sizeof(USER_INFO_1)); |
| @@ -614,6 +869,8 @@ extern "C" UINT __stdcall CreateUser( | |||
| 614 | ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName); | 869 | ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName); |
| 615 | 870 | ||
| 616 | LExit: | 871 | LExit: |
| 872 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); | ||
| 873 | |||
| 617 | if (puserInfo) | 874 | if (puserInfo) |
| 618 | { | 875 | { |
| 619 | ::NetApiBufferFree((LPVOID)puserInfo); | 876 | ::NetApiBufferFree((LPVOID)puserInfo); |
| @@ -627,6 +884,7 @@ LExit: | |||
| 627 | ReleaseStr(pwzData); | 884 | ReleaseStr(pwzData); |
| 628 | ReleaseStr(pwzName); | 885 | ReleaseStr(pwzName); |
| 629 | ReleaseStr(pwzDomain); | 886 | ReleaseStr(pwzDomain); |
| 887 | ReleaseStr(pwzScriptKey); | ||
| 630 | ReleaseStr(pwzPassword); | 888 | ReleaseStr(pwzPassword); |
| 631 | ReleaseStr(pwzGroup); | 889 | ReleaseStr(pwzGroup); |
| 632 | ReleaseStr(pwzGroupDomain); | 890 | ReleaseStr(pwzGroupDomain); |
| @@ -650,15 +908,14 @@ LExit: | |||
| 650 | 908 | ||
| 651 | 909 | ||
| 652 | /******************************************************************** | 910 | /******************************************************************** |
| 653 | RemoveUser - CUSTOM ACTION ENTRY POINT for removing users | 911 | CreateUserRollback - CUSTOM ACTION ENTRY POINT for CreateUser rollback |
| 654 | 912 | ||
| 655 | Input: deferred CustomActionData - Name\tDomain | ||
| 656 | * *****************************************************************/ | 913 | * *****************************************************************/ |
| 657 | extern "C" UINT __stdcall RemoveUser( | 914 | extern "C" UINT __stdcall CreateUserRollback( |
| 658 | MSIHANDLE hInstall | 915 | MSIHANDLE hInstall |
| 659 | ) | 916 | ) |
| 660 | { | 917 | { |
| 661 | //AssertSz(0, "Debug RemoveAccount"); | 918 | //AssertSz(0, "Debug CreateUserRollback"); |
| 662 | 919 | ||
| 663 | HRESULT hr = S_OK; | 920 | HRESULT hr = S_OK; |
| 664 | UINT er = ERROR_SUCCESS; | 921 | UINT er = ERROR_SUCCESS; |
| @@ -666,15 +923,16 @@ extern "C" UINT __stdcall RemoveUser( | |||
| 666 | LPWSTR pwzData = NULL; | 923 | LPWSTR pwzData = NULL; |
| 667 | LPWSTR pwz = NULL; | 924 | LPWSTR pwz = NULL; |
| 668 | LPWSTR pwzName = NULL; | 925 | LPWSTR pwzName = NULL; |
| 669 | LPWSTR pwzDomain= NULL; | 926 | LPWSTR pwzDomain = NULL; |
| 670 | LPWSTR pwzGroup = NULL; | 927 | LPWSTR pwzScriptKey = NULL; |
| 671 | LPWSTR pwzGroupDomain = NULL; | ||
| 672 | int iAttributes = 0; | 928 | int iAttributes = 0; |
| 673 | LPCWSTR wz = NULL; | ||
| 674 | PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; | ||
| 675 | BOOL fInitializedCom = FALSE; | 929 | BOOL fInitializedCom = FALSE; |
| 676 | 930 | ||
| 677 | hr = WcaInitialize(hInstall, "RemoveUser"); | 931 | WCA_CASCRIPT_HANDLE hRollbackScript = NULL; |
| 932 | LPWSTR pwzRollbackData = NULL; | ||
| 933 | int iOriginalAttributes = 0; | ||
| 934 | |||
| 935 | hr = WcaInitialize(hInstall, "CreateUserRollback"); | ||
| 678 | ExitOnFailure(hr, "failed to initialize"); | 936 | ExitOnFailure(hr, "failed to initialize"); |
| 679 | 937 | ||
| 680 | hr = ::CoInitialize(NULL); | 938 | hr = ::CoInitialize(NULL); |
| @@ -690,6 +948,9 @@ extern "C" UINT __stdcall RemoveUser( | |||
| 690 | // Read in the CustomActionData | 948 | // Read in the CustomActionData |
| 691 | // | 949 | // |
| 692 | pwz = pwzData; | 950 | pwz = pwzData; |
| 951 | hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); | ||
| 952 | ExitOnFailure(hr, "failed to read encoding key from custom action data"); | ||
| 953 | |||
| 693 | hr = WcaReadStringFromCaData(&pwz, &pwzName); | 954 | hr = WcaReadStringFromCaData(&pwz, &pwzName); |
| 694 | ExitOnFailure(hr, "failed to read name from custom action data"); | 955 | ExitOnFailure(hr, "failed to read name from custom action data"); |
| 695 | 956 | ||
| @@ -699,96 +960,110 @@ extern "C" UINT __stdcall RemoveUser( | |||
| 699 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | 960 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); |
| 700 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | 961 | ExitOnFailure(hr, "failed to read attributes from custom action data"); |
| 701 | 962 | ||
| 702 | // | 963 | // Best effort to read original configuration from CreateUser. |
| 703 | // Remove the logon as service privilege. | 964 | hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); |
| 704 | // | 965 | if (FAILED(hr)) |
| 705 | if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes) | ||
| 706 | { | 966 | { |
| 707 | hr = ModifyUserLocalServiceRight(pwzDomain, pwzName, FALSE); | 967 | WcaLogError(hr, "Failed to open rollback CustomAction script, continuing anyway."); |
| 708 | if (FAILED(hr)) | ||
| 709 | { | ||
| 710 | WcaLogError(hr, "Failed to remove logon as service right from user, continuing..."); | ||
| 711 | hr = S_OK; | ||
| 712 | } | ||
| 713 | } | 968 | } |
| 714 | 969 | else | |
| 715 | if (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes) | ||
| 716 | { | 970 | { |
| 717 | hr = ModifyUserLocalBatchRight(pwzDomain, pwzName, FALSE); | 971 | hr = WcaCaScriptReadAsCustomActionData(hRollbackScript, &pwzRollbackData); |
| 718 | if (FAILED(hr)) | 972 | if (FAILED(hr)) |
| 719 | { | 973 | { |
| 720 | WcaLogError(hr, "Failed to remove logon as batch job right from user, continuing..."); | 974 | WcaLogError(hr, "Failed to read rollback script into CustomAction data, continuing anyway."); |
| 721 | hr = S_OK; | ||
| 722 | } | 975 | } |
| 723 | } | 976 | else |
| 724 | |||
| 725 | // | ||
| 726 | // Remove the User Account if the user was created by us. | ||
| 727 | // | ||
| 728 | if (!(SCAU_DONT_CREATE_USER & iAttributes)) | ||
| 729 | { | ||
| 730 | if (pwzDomain && *pwzDomain) | ||
| 731 | { | 977 | { |
| 732 | er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, NULL, &pDomainControllerInfo ); | 978 | WcaLog(LOGMSG_TRACEONLY, "Rollback Data: %ls", pwzRollbackData); |
| 733 | if (RPC_S_SERVER_UNAVAILABLE == er) | ||
| 734 | { | ||
| 735 | // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag | ||
| 736 | er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo ); | ||
| 737 | } | ||
| 738 | if (ERROR_SUCCESS == er) | ||
| 739 | { | ||
| 740 | wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix | ||
| 741 | } | ||
| 742 | else | ||
| 743 | { | ||
| 744 | wz = pwzDomain; | ||
| 745 | } | ||
| 746 | } | ||
| 747 | |||
| 748 | er = ::NetUserDel(wz, pwzName); | ||
| 749 | if (NERR_UserNotFound == er) | ||
| 750 | { | ||
| 751 | er = NERR_Success; | ||
| 752 | } | ||
| 753 | ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "failed to delete user account: %ls", pwzName); | ||
| 754 | } | ||
| 755 | else | ||
| 756 | { | ||
| 757 | // | ||
| 758 | // Remove the user from the groups | ||
| 759 | // | ||
| 760 | while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) | ||
| 761 | { | ||
| 762 | hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); | ||
| 763 | 979 | ||
| 980 | pwz = pwzRollbackData; | ||
| 981 | hr = WcaReadIntegerFromCaData(&pwz, &iOriginalAttributes); | ||
| 764 | if (FAILED(hr)) | 982 | if (FAILED(hr)) |
| 765 | { | 983 | { |
| 766 | WcaLogError(hr, "failed to get domain for group: %ls, continuing anyway.", pwzGroup); | 984 | WcaLogError(hr, "failed to read attributes from rollback data, continuing anyway"); |
| 767 | } | 985 | } |
| 768 | else | 986 | else |
| 769 | { | 987 | { |
| 770 | hr = RemoveUserFromGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain); | 988 | iAttributes |= iOriginalAttributes; |
| 771 | if (FAILED(hr)) | ||
| 772 | { | ||
| 773 | WcaLogError(hr, "failed to remove user: %ls from group %ls, continuing anyway.", pwzName, pwzGroup); | ||
| 774 | } | ||
| 775 | } | 989 | } |
| 776 | } | 990 | } |
| 991 | } | ||
| 777 | 992 | ||
| 778 | if (E_NOMOREITEMS == hr) // if there are no more items, all is well | 993 | hr = RemoveUserInternal(pwz, pwzDomain, pwzName, iAttributes); |
| 779 | { | 994 | |
| 780 | hr = S_OK; | 995 | LExit: |
| 781 | } | 996 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); |
| 997 | |||
| 998 | ReleaseStr(pwzData); | ||
| 999 | ReleaseStr(pwzName); | ||
| 1000 | ReleaseStr(pwzDomain); | ||
| 1001 | ReleaseStr(pwzScriptKey); | ||
| 1002 | ReleaseStr(pwzRollbackData); | ||
| 782 | 1003 | ||
| 783 | ExitOnFailure(hr, "failed to get next group from which to remove user:%ls", pwzName); | 1004 | if (fInitializedCom) |
| 1005 | { | ||
| 1006 | ::CoUninitialize(); | ||
| 784 | } | 1007 | } |
| 785 | 1008 | ||
| 786 | LExit: | 1009 | if (FAILED(hr)) |
| 787 | if (pDomainControllerInfo) | ||
| 788 | { | 1010 | { |
| 789 | ::NetApiBufferFree(static_cast<LPVOID>(pDomainControllerInfo)); | 1011 | er = ERROR_INSTALL_FAILURE; |
| 790 | } | 1012 | } |
| 791 | 1013 | ||
| 1014 | return WcaFinalize(er); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | |||
| 1018 | /******************************************************************** | ||
| 1019 | RemoveUser - CUSTOM ACTION ENTRY POINT for removing users | ||
| 1020 | |||
| 1021 | Input: deferred CustomActionData - Name\tDomain | ||
| 1022 | * *****************************************************************/ | ||
| 1023 | extern "C" UINT __stdcall RemoveUser( | ||
| 1024 | MSIHANDLE hInstall | ||
| 1025 | ) | ||
| 1026 | { | ||
| 1027 | //AssertSz(0, "Debug RemoveUser"); | ||
| 1028 | |||
| 1029 | HRESULT hr = S_OK; | ||
| 1030 | UINT er = ERROR_SUCCESS; | ||
| 1031 | |||
| 1032 | LPWSTR pwzData = NULL; | ||
| 1033 | LPWSTR pwz = NULL; | ||
| 1034 | LPWSTR pwzName = NULL; | ||
| 1035 | LPWSTR pwzDomain = NULL; | ||
| 1036 | int iAttributes = 0; | ||
| 1037 | BOOL fInitializedCom = FALSE; | ||
| 1038 | |||
| 1039 | hr = WcaInitialize(hInstall, "RemoveUser"); | ||
| 1040 | ExitOnFailure(hr, "failed to initialize"); | ||
| 1041 | |||
| 1042 | hr = ::CoInitialize(NULL); | ||
| 1043 | ExitOnFailure(hr, "failed to initialize COM"); | ||
| 1044 | fInitializedCom = TRUE; | ||
| 1045 | |||
| 1046 | hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||
| 1047 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 1048 | |||
| 1049 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
| 1050 | |||
| 1051 | // | ||
| 1052 | // Read in the CustomActionData | ||
| 1053 | // | ||
| 1054 | pwz = pwzData; | ||
| 1055 | hr = WcaReadStringFromCaData(&pwz, &pwzName); | ||
| 1056 | ExitOnFailure(hr, "failed to read name from custom action data"); | ||
| 1057 | |||
| 1058 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | ||
| 1059 | ExitOnFailure(hr, "failed to read domain from custom action data"); | ||
| 1060 | |||
| 1061 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | ||
| 1062 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | ||
| 1063 | |||
| 1064 | hr = RemoveUserInternal(pwz, pwzDomain, pwzName, iAttributes); | ||
| 1065 | |||
| 1066 | LExit: | ||
| 792 | ReleaseStr(pwzData); | 1067 | ReleaseStr(pwzData); |
| 793 | ReleaseStr(pwzName); | 1068 | ReleaseStr(pwzName); |
| 794 | ReleaseStr(pwzDomain); | 1069 | ReleaseStr(pwzDomain); |
