diff options
Diffstat (limited to 'src/ext/Util/ca/scaexec.cpp')
| -rw-r--r-- | src/ext/Util/ca/scaexec.cpp | 375 |
1 files changed, 265 insertions, 110 deletions
diff --git a/src/ext/Util/ca/scaexec.cpp b/src/ext/Util/ca/scaexec.cpp index 5845c1b4..7bd271d1 100644 --- a/src/ext/Util/ca/scaexec.cpp +++ b/src/ext/Util/ca/scaexec.cpp | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | 2 | ||
| 3 | #include "precomp.h" | 3 | #include "precomp.h" |
| 4 | 4 | ||
| 5 | |||
| 6 | /******************************************************************** | 5 | /******************************************************************** |
| 7 | * CreateSmb - CUSTOM ACTION ENTRY POINT for creating fileshares | 6 | * CreateSmb - CUSTOM ACTION ENTRY POINT for creating fileshares |
| 8 | * | 7 | * |
| @@ -520,55 +519,88 @@ static HRESULT ModifyUserLocalBatchRight( | |||
| 520 | return hr; | 519 | return hr; |
| 521 | } | 520 | } |
| 522 | 521 | ||
| 523 | static void SetUserPasswordAndAttributes( | 522 | static HRESULT ApplyAttributes(int iAttributes, DWORD* pFlags) |
| 524 | __in USER_INFO_1* puserInfo, | ||
| 525 | __in LPWSTR wzPassword, | ||
| 526 | __in int iAttributes | ||
| 527 | ) | ||
| 528 | { | 523 | { |
| 529 | Assert(puserInfo); | 524 | HRESULT hr = S_OK; |
| 530 | |||
| 531 | // Set the User's password | ||
| 532 | puserInfo->usri1_password = wzPassword; | ||
| 533 | 525 | ||
| 534 | // Apply the Attributes | ||
| 535 | if (SCAU_DONT_EXPIRE_PASSWRD & iAttributes) | 526 | if (SCAU_DONT_EXPIRE_PASSWRD & iAttributes) |
| 536 | { | 527 | { |
| 537 | puserInfo->usri1_flags |= UF_DONT_EXPIRE_PASSWD; | 528 | *pFlags |= UF_DONT_EXPIRE_PASSWD; |
| 538 | } | 529 | } |
| 539 | else | 530 | else |
| 540 | { | 531 | { |
| 541 | puserInfo->usri1_flags &= ~UF_DONT_EXPIRE_PASSWD; | 532 | *pFlags &= ~UF_DONT_EXPIRE_PASSWD; |
| 542 | } | 533 | } |
| 543 | 534 | ||
| 544 | if (SCAU_PASSWD_CANT_CHANGE & iAttributes) | 535 | if (SCAU_PASSWD_CANT_CHANGE & iAttributes) |
| 545 | { | 536 | { |
| 546 | puserInfo->usri1_flags |= UF_PASSWD_CANT_CHANGE; | 537 | *pFlags |= UF_PASSWD_CANT_CHANGE; |
| 547 | } | 538 | } |
| 548 | else | 539 | else |
| 549 | { | 540 | { |
| 550 | puserInfo->usri1_flags &= ~UF_PASSWD_CANT_CHANGE; | 541 | *pFlags &= ~UF_PASSWD_CANT_CHANGE; |
| 551 | } | 542 | } |
| 552 | 543 | ||
| 553 | if (SCAU_DISABLE_ACCOUNT & iAttributes) | 544 | if (SCAU_DISABLE_ACCOUNT & iAttributes) |
| 554 | { | 545 | { |
| 555 | puserInfo->usri1_flags |= UF_ACCOUNTDISABLE; | 546 | *pFlags |= UF_ACCOUNTDISABLE; |
| 556 | } | 547 | } |
| 557 | else | 548 | else |
| 558 | { | 549 | { |
| 559 | puserInfo->usri1_flags &= ~UF_ACCOUNTDISABLE; | 550 | *pFlags &= ~UF_ACCOUNTDISABLE; |
| 560 | } | 551 | } |
| 561 | 552 | ||
| 562 | if (SCAU_PASSWD_CHANGE_REQD_ON_LOGIN & iAttributes) // TODO: for some reason this doesn't work | 553 | if (SCAU_PASSWD_CHANGE_REQD_ON_LOGIN & iAttributes) // TODO: for some reason this doesn't work |
| 563 | { | 554 | { |
| 564 | puserInfo->usri1_flags |= UF_PASSWORD_EXPIRED; | 555 | *pFlags |= UF_PASSWORD_EXPIRED; |
| 565 | } | 556 | } |
| 566 | else | 557 | else |
| 567 | { | 558 | { |
| 568 | puserInfo->usri1_flags &= ~UF_PASSWORD_EXPIRED; | 559 | *pFlags &= ~UF_PASSWORD_EXPIRED; |
| 560 | } | ||
| 561 | |||
| 562 | return hr; | ||
| 563 | } | ||
| 564 | |||
| 565 | static HRESULT ApplyComment(int iAttributes, LPWSTR pwzComment, LPWSTR* ppComment) | ||
| 566 | { | ||
| 567 | HRESULT hr = S_OK; | ||
| 568 | |||
| 569 | if (SCAU_REMOVE_COMMENT & iAttributes) | ||
| 570 | { | ||
| 571 | *ppComment = L""; | ||
| 572 | } | ||
| 573 | else if (pwzComment && *pwzComment) | ||
| 574 | { | ||
| 575 | *ppComment = pwzComment; | ||
| 569 | } | 576 | } |
| 577 | |||
| 578 | return hr; | ||
| 579 | } | ||
| 580 | |||
| 581 | static NET_API_STATUS SetUserPassword(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in LPWSTR pwzPassword) | ||
| 582 | { | ||
| 583 | _USER_INFO_1003 userInfo1003; | ||
| 584 | |||
| 585 | userInfo1003.usri1003_password = pwzPassword; | ||
| 586 | return ::NetUserSetInfo(pwzServerName, pwzName, 1003, reinterpret_cast<LPBYTE>(&userInfo1003), NULL); | ||
| 570 | } | 587 | } |
| 571 | 588 | ||
| 589 | static NET_API_STATUS SetUserComment(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in LPWSTR pwzComment) | ||
| 590 | { | ||
| 591 | _USER_INFO_1007 userInfo1007; | ||
| 592 | |||
| 593 | userInfo1007.usri1007_comment = pwzComment; | ||
| 594 | return ::NetUserSetInfo(pwzServerName, pwzName, 1007, reinterpret_cast<LPBYTE>(&userInfo1007), NULL); | ||
| 595 | } | ||
| 596 | |||
| 597 | static NET_API_STATUS SetUserFlags(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in DWORD flags) | ||
| 598 | { | ||
| 599 | _USER_INFO_1008 userInfo1008; | ||
| 600 | |||
| 601 | userInfo1008.usri1008_flags = flags; | ||
| 602 | return ::NetUserSetInfo(pwzServerName, pwzName, 1008, reinterpret_cast<LPBYTE>(&userInfo1008), NULL); | ||
| 603 | } | ||
| 572 | 604 | ||
| 573 | static HRESULT RemoveUserInternal( | 605 | static HRESULT RemoveUserInternal( |
| 574 | LPWSTR wzGroupCaData, | 606 | LPWSTR wzGroupCaData, |
| @@ -624,7 +656,12 @@ static HRESULT RemoveUserInternal( | |||
| 624 | } | 656 | } |
| 625 | if (ERROR_SUCCESS == er) | 657 | if (ERROR_SUCCESS == er) |
| 626 | { | 658 | { |
| 627 | wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix | 659 | if (2 <= wcslen(pDomainControllerInfo->DomainControllerName)) |
| 660 | { | ||
| 661 | wz = pDomainControllerInfo->DomainControllerName + 2; // Add 2 so that we don't get the \\ prefix. | ||
| 662 | // Pass the entire string if it is too short | ||
| 663 | // to have a \\ prefix. | ||
| 664 | } | ||
| 628 | } | 665 | } |
| 629 | else | 666 | else |
| 630 | { | 667 | { |
| @@ -680,6 +717,41 @@ LExit: | |||
| 680 | return hr; | 717 | return hr; |
| 681 | } | 718 | } |
| 682 | 719 | ||
| 720 | static HRESULT GetServerName(LPWSTR pwzDomain, LPWSTR* ppwzServerName) | ||
| 721 | { | ||
| 722 | HRESULT hr = S_OK; | ||
| 723 | |||
| 724 | PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; | ||
| 725 | UINT er; | ||
| 726 | |||
| 727 | if (pwzDomain && *pwzDomain) | ||
| 728 | { | ||
| 729 | er = ::DsGetDcNameW(NULL, (LPCWSTR)pwzDomain, NULL, NULL, NULL, &pDomainControllerInfo); | ||
| 730 | if (RPC_S_SERVER_UNAVAILABLE == er) | ||
| 731 | { | ||
| 732 | // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag | ||
| 733 | er = ::DsGetDcNameW(NULL, (LPCWSTR)pwzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo); | ||
| 734 | } | ||
| 735 | if (ERROR_SUCCESS == er | ||
| 736 | && 2 <= wcslen(pDomainControllerInfo->DomainControllerName) | ||
| 737 | && '\\' == *pDomainControllerInfo->DomainControllerName | ||
| 738 | && '\\' == *pDomainControllerInfo->DomainControllerName + 1) | ||
| 739 | { | ||
| 740 | *ppwzServerName = pDomainControllerInfo->DomainControllerName + 2; // Skip the \\ prefix | ||
| 741 | } | ||
| 742 | else | ||
| 743 | { | ||
| 744 | *ppwzServerName = pwzDomain; | ||
| 745 | } | ||
| 746 | } | ||
| 747 | |||
| 748 | if (pDomainControllerInfo) | ||
| 749 | { | ||
| 750 | ::NetApiBufferFree((LPVOID)pDomainControllerInfo); | ||
| 751 | } | ||
| 752 | |||
| 753 | return hr; | ||
| 754 | } | ||
| 683 | 755 | ||
| 684 | /******************************************************************** | 756 | /******************************************************************** |
| 685 | CreateUser - CUSTOM ACTION ENTRY POINT for creating users | 757 | CreateUser - CUSTOM ACTION ENTRY POINT for creating users |
| @@ -688,7 +760,7 @@ LExit: | |||
| 688 | * *****************************************************************/ | 760 | * *****************************************************************/ |
| 689 | extern "C" UINT __stdcall CreateUser( | 761 | extern "C" UINT __stdcall CreateUser( |
| 690 | __in MSIHANDLE hInstall | 762 | __in MSIHANDLE hInstall |
| 691 | ) | 763 | ) |
| 692 | { | 764 | { |
| 693 | //AssertSz(0, "Debug CreateUser"); | 765 | //AssertSz(0, "Debug CreateUser"); |
| 694 | 766 | ||
| @@ -699,11 +771,11 @@ extern "C" UINT __stdcall CreateUser( | |||
| 699 | LPWSTR pwz = NULL; | 771 | LPWSTR pwz = NULL; |
| 700 | LPWSTR pwzName = NULL; | 772 | LPWSTR pwzName = NULL; |
| 701 | LPWSTR pwzDomain = NULL; | 773 | LPWSTR pwzDomain = NULL; |
| 774 | LPWSTR pwzComment = NULL; | ||
| 702 | LPWSTR pwzScriptKey = NULL; | 775 | LPWSTR pwzScriptKey = NULL; |
| 703 | LPWSTR pwzPassword = NULL; | 776 | LPWSTR pwzPassword = NULL; |
| 704 | LPWSTR pwzGroup = NULL; | 777 | LPWSTR pwzGroup = NULL; |
| 705 | LPWSTR pwzGroupDomain = NULL; | 778 | LPWSTR pwzGroupDomain = NULL; |
| 706 | PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; | ||
| 707 | int iAttributes = 0; | 779 | int iAttributes = 0; |
| 708 | BOOL fInitializedCom = FALSE; | 780 | BOOL fInitializedCom = FALSE; |
| 709 | 781 | ||
| @@ -711,10 +783,10 @@ extern "C" UINT __stdcall CreateUser( | |||
| 711 | int iOriginalAttributes = 0; | 783 | int iOriginalAttributes = 0; |
| 712 | int iRollbackAttributes = 0; | 784 | int iRollbackAttributes = 0; |
| 713 | 785 | ||
| 714 | USER_INFO_1 userInfo; | 786 | USER_INFO_1 userInfo1; |
| 715 | USER_INFO_1* puserInfo = NULL; | 787 | USER_INFO_1* pUserInfo1 = NULL; |
| 716 | DWORD dw; | 788 | DWORD dw; |
| 717 | LPCWSTR wz = NULL; | 789 | LPWSTR pwzServerName = NULL; |
| 718 | 790 | ||
| 719 | hr = WcaInitialize(hInstall, "CreateUser"); | 791 | hr = WcaInitialize(hInstall, "CreateUser"); |
| 720 | ExitOnFailure(hr, "failed to initialize"); | 792 | ExitOnFailure(hr, "failed to initialize"); |
| @@ -723,7 +795,7 @@ extern "C" UINT __stdcall CreateUser( | |||
| 723 | ExitOnFailure(hr, "failed to initialize COM"); | 795 | ExitOnFailure(hr, "failed to initialize COM"); |
| 724 | fInitializedCom = TRUE; | 796 | fInitializedCom = TRUE; |
| 725 | 797 | ||
| 726 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | 798 | hr = WcaGetProperty(L"CustomActionData", &pwzData); |
| 727 | ExitOnFailure(hr, "failed to get CustomActionData"); | 799 | ExitOnFailure(hr, "failed to get CustomActionData"); |
| 728 | 800 | ||
| 729 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | 801 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); |
| @@ -738,6 +810,9 @@ extern "C" UINT __stdcall CreateUser( | |||
| 738 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | 810 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); |
| 739 | ExitOnFailure(hr, "failed to read domain from custom action data"); | 811 | ExitOnFailure(hr, "failed to read domain from custom action data"); |
| 740 | 812 | ||
| 813 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
| 814 | ExitOnFailure(hr, "failed to read user comment from custom action data"); | ||
| 815 | |||
| 741 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | 816 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); |
| 742 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | 817 | ExitOnFailure(hr, "failed to read attributes from custom action data"); |
| 743 | 818 | ||
| @@ -747,96 +822,155 @@ extern "C" UINT __stdcall CreateUser( | |||
| 747 | hr = WcaReadStringFromCaData(&pwz, &pwzPassword); | 822 | hr = WcaReadStringFromCaData(&pwz, &pwzPassword); |
| 748 | ExitOnFailure(hr, "failed to read password from custom action data"); | 823 | ExitOnFailure(hr, "failed to read password from custom action data"); |
| 749 | 824 | ||
| 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 | |||
| 782 | if (!(SCAU_DONT_CREATE_USER & iAttributes)) | 825 | if (!(SCAU_DONT_CREATE_USER & iAttributes)) |
| 783 | { | 826 | { |
| 784 | ::ZeroMemory(&userInfo, sizeof(USER_INFO_1)); | 827 | pUserInfo1 = &userInfo1; |
| 785 | userInfo.usri1_name = pwzName; | 828 | ::ZeroMemory(pUserInfo1, sizeof(USER_INFO_1)); |
| 786 | userInfo.usri1_priv = USER_PRIV_USER; | 829 | pUserInfo1->usri1_name = pwzName; |
| 787 | userInfo.usri1_flags = UF_SCRIPT; | 830 | pUserInfo1->usri1_priv = USER_PRIV_USER; |
| 788 | userInfo.usri1_home_dir = NULL; | 831 | pUserInfo1->usri1_flags = UF_SCRIPT; |
| 789 | userInfo.usri1_comment = NULL; | 832 | pUserInfo1->usri1_home_dir = NULL; |
| 790 | userInfo.usri1_script_path = NULL; | 833 | pUserInfo1->usri1_comment = NULL; |
| 791 | 834 | pUserInfo1->usri1_script_path = NULL; | |
| 792 | SetUserPasswordAndAttributes(&userInfo, pwzPassword, iAttributes); | 835 | |
| 836 | // Set the user's password | ||
| 837 | pUserInfo1->usri1_password = pwzPassword; | ||
| 838 | |||
| 839 | // Set the user's comment | ||
| 840 | hr = ApplyComment(iAttributes, pwzComment, &pUserInfo1->usri1_comment); | ||
| 841 | ExitOnFailure(hr, "failed to apply comment"); | ||
| 842 | |||
| 843 | // Set the user's flags | ||
| 844 | hr = ApplyAttributes(iAttributes, &pUserInfo1->usri1_flags); | ||
| 845 | ExitOnFailure(hr, "failed to apply attributes"); | ||
| 793 | 846 | ||
| 794 | // | 847 | // |
| 795 | // Create the User | 848 | // Create the User |
| 796 | // | 849 | // |
| 797 | if (pwzDomain && *pwzDomain) | 850 | hr = GetServerName(pwzDomain, &pwzServerName); |
| 851 | ExitOnFailure(hr, "failed to get server name"); | ||
| 852 | |||
| 853 | er = ::NetUserAdd(pwzServerName, 1, reinterpret_cast<LPBYTE>(pUserInfo1), &dw); | ||
| 854 | if (NERR_UserExists == er) | ||
| 798 | { | 855 | { |
| 799 | er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, NULL, &pDomainControllerInfo ); | 856 | er = ERROR_SUCCESS; // Make sure that we don't report this situation as an error |
| 800 | if (RPC_S_SERVER_UNAVAILABLE == er) | 857 | // if we fall through the tests that follow. |
| 801 | { | 858 | if (SCAU_FAIL_IF_EXISTS & iAttributes) |
| 802 | // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag | ||
| 803 | er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo ); | ||
| 804 | } | ||
| 805 | if (ERROR_SUCCESS == er) | ||
| 806 | { | 859 | { |
| 807 | wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix | 860 | hr = HRESULT_FROM_WIN32(er); |
| 861 | ExitOnFailure(hr, "User was not supposed to exist, but does."); | ||
| 808 | } | 862 | } |
| 809 | else | ||
| 810 | { | ||
| 811 | wz = pwzDomain; | ||
| 812 | } | ||
| 813 | } | ||
| 814 | 863 | ||
| 815 | er = ::NetUserAdd(wz, 1, reinterpret_cast<LPBYTE>(&userInfo), &dw); | ||
| 816 | if (NERR_UserExists == er) | ||
| 817 | { | ||
| 818 | if (SCAU_UPDATE_IF_EXISTS & iAttributes) | 864 | if (SCAU_UPDATE_IF_EXISTS & iAttributes) |
| 819 | { | 865 | { |
| 820 | er = ::NetUserGetInfo(wz, pwzName, 1, reinterpret_cast<LPBYTE*>(&puserInfo)); | 866 | pUserInfo1 = NULL; |
| 821 | if (NERR_Success == er) | 867 | er = ::NetUserGetInfo(pwzServerName, pwzName, 1, reinterpret_cast<LPBYTE*>(&pUserInfo1)); |
| 868 | if (ERROR_SUCCESS == er) | ||
| 822 | { | 869 | { |
| 823 | // Change the existing user's password and attributes again then try | 870 | // There is no rollback scheduled if the key is empty. |
| 824 | // to update user with this new data | 871 | // Best effort to get original configuration and save it in the script so rollback can restore it. |
| 825 | SetUserPasswordAndAttributes(puserInfo, pwzPassword, iAttributes); | 872 | |
| 873 | if (*pwzScriptKey) | ||
| 874 | { | ||
| 875 | // Try to open the rollback script | ||
| 876 | hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); | ||
| 877 | |||
| 878 | if (INVALID_HANDLE_VALUE != hRollbackScript) | ||
| 879 | { | ||
| 880 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); | ||
| 881 | } | ||
| 882 | else | ||
| 883 | { | ||
| 884 | hRollbackScript = NULL; | ||
| 885 | hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); | ||
| 886 | ExitOnFailure(hr, "Failed to open rollback CustomAction script."); | ||
| 887 | |||
| 888 | iRollbackAttributes = 0; | ||
| 889 | hr = GetExistingUserRightsAssignments(pwzDomain, pwzName, &iOriginalAttributes); | ||
| 890 | if (FAILED(hr)) | ||
| 891 | { | ||
| 892 | WcaLogError(hr, "failed to get existing user rights: %ls, continuing anyway.", pwzName); | ||
| 893 | } | ||
| 894 | else | ||
| 895 | { | ||
| 896 | if (!(SCAU_ALLOW_LOGON_AS_SERVICE & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes)) | ||
| 897 | { | ||
| 898 | iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_SERVICE; | ||
| 899 | } | ||
| 900 | |||
| 901 | if (!(SCAU_ALLOW_LOGON_AS_BATCH & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes)) | ||
| 902 | { | ||
| 903 | iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_BATCH; | ||
| 904 | } | ||
| 905 | } | ||
| 906 | |||
| 907 | hr = WcaCaScriptWriteString(hRollbackScript, pUserInfo1->usri1_comment); | ||
| 908 | ExitOnFailure(hr, "Failed to add rollback comment to rollback script."); | ||
| 909 | |||
| 910 | if (!pUserInfo1->usri1_comment || !*pUserInfo1->usri1_comment) | ||
| 911 | { | ||
| 912 | iRollbackAttributes |= SCAU_REMOVE_COMMENT; | ||
| 913 | } | ||
| 914 | |||
| 915 | hr = WcaCaScriptWriteNumber(hRollbackScript, iRollbackAttributes); | ||
| 916 | ExitOnFailure(hr, "Failed to add rollback attributes to rollback script."); | ||
| 917 | |||
| 918 | // Nudge the system to get all our rollback data written to disk. | ||
| 919 | WcaCaScriptFlush(hRollbackScript); | ||
| 920 | } | ||
| 921 | } | ||
| 922 | } | ||
| 826 | 923 | ||
| 827 | er = ::NetUserSetInfo(wz, pwzName, 1, reinterpret_cast<LPBYTE>(puserInfo), &dw); | 924 | if (ERROR_SUCCESS == er) |
| 925 | { | ||
| 926 | hr = HRESULT_FROM_WIN32(::SetUserPassword(pwzServerName, pwzName, pwzPassword)); | ||
| 927 | if (FAILED(hr)) | ||
| 928 | { | ||
| 929 | WcaLogError(hr, "failed to set user password for user %ls\\%ls, continuing anyway.", pwzServerName, pwzName); | ||
| 930 | } | ||
| 931 | |||
| 932 | if (SCAU_REMOVE_COMMENT & iAttributes) | ||
| 933 | { | ||
| 934 | hr = HRESULT_FROM_WIN32(SetUserComment(pwzServerName, pwzName, L"")); | ||
| 935 | if (FAILED(hr)) | ||
| 936 | { | ||
| 937 | WcaLogError(hr, "failed to clear user comment for user %ls\\%ls, continuing anyway.", pwzServerName, pwzName); | ||
| 938 | } | ||
| 939 | } | ||
| 940 | else if (pwzComment && *pwzComment) | ||
| 941 | { | ||
| 942 | hr = HRESULT_FROM_WIN32(SetUserComment(pwzServerName, pwzName, pwzComment)); | ||
| 943 | if (FAILED(hr)) | ||
| 944 | { | ||
| 945 | WcaLogError(hr, "failed to set user comment to %ls for user %ls\\%ls, continuing anyway.", pwzComment, pwzServerName, pwzName); | ||
| 946 | } | ||
| 947 | } | ||
| 948 | |||
| 949 | DWORD flags = pUserInfo1->usri1_flags; | ||
| 950 | |||
| 951 | hr = ApplyAttributes(iAttributes, &flags); | ||
| 952 | if (FAILED(hr)) | ||
| 953 | { | ||
| 954 | WcaLogError(hr, "failed to apply attributes for user %ls\\%ls, continuing anyway.", pwzServerName, pwzName); | ||
| 955 | } | ||
| 956 | |||
| 957 | hr = HRESULT_FROM_WIN32(SetUserFlags(pwzServerName, pwzName, flags)); | ||
| 958 | if (FAILED(hr)) | ||
| 959 | { | ||
| 960 | WcaLogError(hr, "failed to set user flags for user %ls\\%ls, continuing anyway.", pwzServerName, pwzName); | ||
| 961 | } | ||
| 828 | } | 962 | } |
| 829 | } | 963 | } |
| 830 | else if (!(SCAU_FAIL_IF_EXISTS & iAttributes)) | ||
| 831 | { | ||
| 832 | er = NERR_Success; | ||
| 833 | } | ||
| 834 | } | 964 | } |
| 835 | else if (NERR_PasswordTooShort == er || NERR_PasswordTooLong == er) | 965 | else if (NERR_PasswordTooShort == er || NERR_PasswordTooLong == er) |
| 836 | { | 966 | { |
| 837 | MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreatePswd, "failed to create user: %ls due to invalid password.", pwzName); | 967 | MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreatePswd, "failed to create user: %ls due to invalid password.", pwzName); |
| 838 | } | 968 | } |
| 839 | MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreate, "failed to create user: %ls", pwzName); | 969 | |
| 970 | if (ERROR_SUCCESS != er) | ||
| 971 | { | ||
| 972 | MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreate, "failed to create user: %ls", pwzName); | ||
| 973 | } | ||
| 840 | } | 974 | } |
| 841 | 975 | ||
| 842 | if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes) | 976 | if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes) |
| @@ -851,14 +985,15 @@ extern "C" UINT __stdcall CreateUser( | |||
| 851 | MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as batch job rights to user: %ls", pwzName); | 985 | MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as batch job rights to user: %ls", pwzName); |
| 852 | } | 986 | } |
| 853 | 987 | ||
| 854 | // | 988 | // |
| 855 | // Add the users to groups | 989 | // Add the users to groups |
| 856 | // | 990 | // |
| 857 | while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) | 991 | while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) |
| 858 | { | 992 | { |
| 859 | hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); | 993 | hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); |
| 860 | ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup); | 994 | ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup); |
| 861 | 995 | ||
| 996 | WcaLog(LOGMSG_STANDARD, "Adding user %ls\\%ls to group %ls\\%ls", pwzDomain, pwzName, pwzGroupDomain, pwzGroup); | ||
| 862 | hr = AddUserToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain); | 997 | hr = AddUserToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain); |
| 863 | MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add user: %ls to group %ls", pwzName, pwzGroup); | 998 | MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add user: %ls to group %ls", pwzName, pwzGroup); |
| 864 | } | 999 | } |
| @@ -866,24 +1001,23 @@ extern "C" UINT __stdcall CreateUser( | |||
| 866 | { | 1001 | { |
| 867 | hr = S_OK; | 1002 | hr = S_OK; |
| 868 | } | 1003 | } |
| 1004 | |||
| 869 | ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName); | 1005 | ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName); |
| 870 | 1006 | ||
| 1007 | ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName); | ||
| 1008 | |||
| 871 | LExit: | 1009 | LExit: |
| 872 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); | 1010 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); |
| 873 | 1011 | ||
| 874 | if (puserInfo) | 1012 | if (pUserInfo1 && pUserInfo1 != &userInfo1) |
| 875 | { | 1013 | { |
| 876 | ::NetApiBufferFree((LPVOID)puserInfo); | 1014 | ::NetApiBufferFree((LPVOID)pUserInfo1); |
| 877 | } | ||
| 878 | |||
| 879 | if (pDomainControllerInfo) | ||
| 880 | { | ||
| 881 | ::NetApiBufferFree((LPVOID)pDomainControllerInfo); | ||
| 882 | } | 1015 | } |
| 883 | 1016 | ||
| 884 | ReleaseStr(pwzData); | 1017 | ReleaseStr(pwzData); |
| 885 | ReleaseStr(pwzName); | 1018 | ReleaseStr(pwzName); |
| 886 | ReleaseStr(pwzDomain); | 1019 | ReleaseStr(pwzDomain); |
| 1020 | ReleaseStr(pwzComment); | ||
| 887 | ReleaseStr(pwzScriptKey); | 1021 | ReleaseStr(pwzScriptKey); |
| 888 | ReleaseStr(pwzPassword); | 1022 | ReleaseStr(pwzPassword); |
| 889 | ReleaseStr(pwzGroup); | 1023 | ReleaseStr(pwzGroup); |
| @@ -922,15 +1056,17 @@ extern "C" UINT __stdcall CreateUserRollback( | |||
| 922 | 1056 | ||
| 923 | LPWSTR pwzData = NULL; | 1057 | LPWSTR pwzData = NULL; |
| 924 | LPWSTR pwz = NULL; | 1058 | LPWSTR pwz = NULL; |
| 1059 | LPWSTR pwzScriptKey = NULL; | ||
| 925 | LPWSTR pwzName = NULL; | 1060 | LPWSTR pwzName = NULL; |
| 926 | LPWSTR pwzDomain = NULL; | 1061 | LPWSTR pwzDomain = NULL; |
| 927 | LPWSTR pwzScriptKey = NULL; | 1062 | LPWSTR pwzComment = NULL; |
| 928 | int iAttributes = 0; | 1063 | int iAttributes = 0; |
| 929 | BOOL fInitializedCom = FALSE; | 1064 | BOOL fInitializedCom = FALSE; |
| 930 | 1065 | ||
| 931 | WCA_CASCRIPT_HANDLE hRollbackScript = NULL; | 1066 | WCA_CASCRIPT_HANDLE hRollbackScript = NULL; |
| 932 | LPWSTR pwzRollbackData = NULL; | 1067 | LPWSTR pwzRollbackData = NULL; |
| 933 | int iOriginalAttributes = 0; | 1068 | int iOriginalAttributes = 0; |
| 1069 | LPWSTR pwzOriginalComment = NULL; | ||
| 934 | 1070 | ||
| 935 | hr = WcaInitialize(hInstall, "CreateUserRollback"); | 1071 | hr = WcaInitialize(hInstall, "CreateUserRollback"); |
| 936 | ExitOnFailure(hr, "failed to initialize"); | 1072 | ExitOnFailure(hr, "failed to initialize"); |
| @@ -957,6 +1093,9 @@ extern "C" UINT __stdcall CreateUserRollback( | |||
| 957 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | 1093 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); |
| 958 | ExitOnFailure(hr, "failed to read domain from custom action data"); | 1094 | ExitOnFailure(hr, "failed to read domain from custom action data"); |
| 959 | 1095 | ||
| 1096 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
| 1097 | ExitOnFailure(hr, "failed to read comment from custom action data"); | ||
| 1098 | |||
| 960 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | 1099 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); |
| 961 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | 1100 | ExitOnFailure(hr, "failed to read attributes from custom action data"); |
| 962 | 1101 | ||
| @@ -978,6 +1117,15 @@ extern "C" UINT __stdcall CreateUserRollback( | |||
| 978 | WcaLog(LOGMSG_TRACEONLY, "Rollback Data: %ls", pwzRollbackData); | 1117 | WcaLog(LOGMSG_TRACEONLY, "Rollback Data: %ls", pwzRollbackData); |
| 979 | 1118 | ||
| 980 | pwz = pwzRollbackData; | 1119 | pwz = pwzRollbackData; |
| 1120 | hr = WcaReadStringFromCaData(&pwz, &pwzOriginalComment); | ||
| 1121 | if (FAILED(hr)) | ||
| 1122 | { | ||
| 1123 | WcaLogError(hr, "failed to read comment from rollback data, continuing anyway"); | ||
| 1124 | } | ||
| 1125 | else | ||
| 1126 | { | ||
| 1127 | pwzComment = pwzOriginalComment; | ||
| 1128 | } | ||
| 981 | hr = WcaReadIntegerFromCaData(&pwz, &iOriginalAttributes); | 1129 | hr = WcaReadIntegerFromCaData(&pwz, &iOriginalAttributes); |
| 982 | if (FAILED(hr)) | 1130 | if (FAILED(hr)) |
| 983 | { | 1131 | { |
| @@ -998,8 +1146,10 @@ LExit: | |||
| 998 | ReleaseStr(pwzData); | 1146 | ReleaseStr(pwzData); |
| 999 | ReleaseStr(pwzName); | 1147 | ReleaseStr(pwzName); |
| 1000 | ReleaseStr(pwzDomain); | 1148 | ReleaseStr(pwzDomain); |
| 1149 | ReleaseStr(pwzComment); | ||
| 1001 | ReleaseStr(pwzScriptKey); | 1150 | ReleaseStr(pwzScriptKey); |
| 1002 | ReleaseStr(pwzRollbackData); | 1151 | ReleaseStr(pwzRollbackData); |
| 1152 | ReleaseStr(pwzOriginalComment); | ||
| 1003 | 1153 | ||
| 1004 | if (fInitializedCom) | 1154 | if (fInitializedCom) |
| 1005 | { | 1155 | { |
| @@ -1033,6 +1183,7 @@ extern "C" UINT __stdcall RemoveUser( | |||
| 1033 | LPWSTR pwz = NULL; | 1183 | LPWSTR pwz = NULL; |
| 1034 | LPWSTR pwzName = NULL; | 1184 | LPWSTR pwzName = NULL; |
| 1035 | LPWSTR pwzDomain = NULL; | 1185 | LPWSTR pwzDomain = NULL; |
| 1186 | LPWSTR pwzComment = NULL; | ||
| 1036 | int iAttributes = 0; | 1187 | int iAttributes = 0; |
| 1037 | BOOL fInitializedCom = FALSE; | 1188 | BOOL fInitializedCom = FALSE; |
| 1038 | 1189 | ||
| @@ -1058,6 +1209,9 @@ extern "C" UINT __stdcall RemoveUser( | |||
| 1058 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | 1209 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); |
| 1059 | ExitOnFailure(hr, "failed to read domain from custom action data"); | 1210 | ExitOnFailure(hr, "failed to read domain from custom action data"); |
| 1060 | 1211 | ||
| 1212 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
| 1213 | ExitOnFailure(hr, "failed to read comment from custom action data"); | ||
| 1214 | |||
| 1061 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | 1215 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); |
| 1062 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | 1216 | ExitOnFailure(hr, "failed to read attributes from custom action data"); |
| 1063 | 1217 | ||
| @@ -1067,6 +1221,7 @@ LExit: | |||
| 1067 | ReleaseStr(pwzData); | 1221 | ReleaseStr(pwzData); |
| 1068 | ReleaseStr(pwzName); | 1222 | ReleaseStr(pwzName); |
| 1069 | ReleaseStr(pwzDomain); | 1223 | ReleaseStr(pwzDomain); |
| 1224 | ReleaseStr(pwzComment); | ||
| 1070 | 1225 | ||
| 1071 | if (fInitializedCom) | 1226 | if (fInitializedCom) |
| 1072 | { | 1227 | { |
