diff options
| author | Ron Martin <cpuwzd@comcast.net> | 2022-08-29 18:38:07 -0400 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2022-10-21 19:08:08 -0700 |
| commit | 08cdc6aa2b9dd0e273a3c3a22893616d26342a0e (patch) | |
| tree | 1d0b9f7e21cec02abfda50b1a3c6d0c24308998b /src/ext | |
| parent | 40bd65379768f99ec28bffe2691ba43c78c9e9c4 (diff) | |
| download | wix-08cdc6aa2b9dd0e273a3c3a22893616d26342a0e.tar.gz wix-08cdc6aa2b9dd0e273a3c3a22893616d26342a0e.tar.bz2 wix-08cdc6aa2b9dd0e273a3c3a22893616d26342a0e.zip | |
Support add, modify and remove comments on user accounts
Fixes 5371
Diffstat (limited to 'src/ext')
| -rw-r--r-- | src/ext/Iis/ca/sca.h | 1 | ||||
| -rw-r--r-- | src/ext/Util/ca/sca.h | 3 | ||||
| -rw-r--r-- | src/ext/Util/ca/scaexec.cpp | 375 | ||||
| -rw-r--r-- | src/ext/Util/ca/scauser.cpp | 62 | ||||
| -rw-r--r-- | src/ext/Util/ca/scauser.h | 7 | ||||
| -rw-r--r-- | src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/Package.wxs | 15 | ||||
| -rw-r--r-- | src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/PackageComponents.wxs | 76 | ||||
| -rw-r--r-- | src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs | 76 | ||||
| -rw-r--r-- | src/ext/Util/wixext/Symbols/UserSymbol.cs | 10 | ||||
| -rw-r--r-- | src/ext/Util/wixext/UtilCompiler.cs | 22 | ||||
| -rw-r--r-- | src/ext/Util/wixext/UtilDecompiler.cs | 6 | ||||
| -rw-r--r-- | src/ext/Util/wixext/UtilTableDefinitions.cs | 1 |
12 files changed, 521 insertions, 133 deletions
diff --git a/src/ext/Iis/ca/sca.h b/src/ext/Iis/ca/sca.h index 64567dcb..6921613b 100644 --- a/src/ext/Iis/ca/sca.h +++ b/src/ext/Iis/ca/sca.h | |||
| @@ -121,4 +121,5 @@ enum SCAU_ATTRIBUTES | |||
| 121 | SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100, | 121 | SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100, |
| 122 | SCAU_DONT_CREATE_USER = 0x00000200, | 122 | SCAU_DONT_CREATE_USER = 0x00000200, |
| 123 | SCAU_NON_VITAL = 0x00000400, | 123 | SCAU_NON_VITAL = 0x00000400, |
| 124 | SCAU_REMOVE_COMMENT = 0x00000800, | ||
| 124 | }; | 125 | }; |
diff --git a/src/ext/Util/ca/sca.h b/src/ext/Util/ca/sca.h index 599122ff..84f5ffd9 100644 --- a/src/ext/Util/ca/sca.h +++ b/src/ext/Util/ca/sca.h | |||
| @@ -16,4 +16,5 @@ enum SCAU_ATTRIBUTES | |||
| 16 | SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100, | 16 | SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100, |
| 17 | SCAU_DONT_CREATE_USER = 0x00000200, | 17 | SCAU_DONT_CREATE_USER = 0x00000200, |
| 18 | SCAU_NON_VITAL = 0x00000400, | 18 | SCAU_NON_VITAL = 0x00000400, |
| 19 | }; \ No newline at end of file | 19 | SCAU_REMOVE_COMMENT = 0x00000800, |
| 20 | }; | ||
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 | { |
diff --git a/src/ext/Util/ca/scauser.cpp b/src/ext/Util/ca/scauser.cpp index f92ebf1b..dc5bebba 100644 --- a/src/ext/Util/ca/scauser.cpp +++ b/src/ext/Util/ca/scauser.cpp | |||
| @@ -2,8 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | #include "precomp.h" | 3 | #include "precomp.h" |
| 4 | 4 | ||
| 5 | LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Password` FROM `Wix4User` WHERE `User`=?"; | 5 | LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Comment`, `Password` FROM `Wix4User` WHERE `User`=?"; |
| 6 | enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqPassword }; | 6 | enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqComment, vuqPassword }; |
| 7 | 7 | ||
| 8 | LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Group`=?"; | 8 | LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Group`=?"; |
| 9 | enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; | 9 | enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; |
| @@ -11,8 +11,8 @@ enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; | |||
| 11 | LPCWSTR vcsUserGroupQuery = L"SELECT `User_`, `Group_` FROM `Wix4UserGroup` WHERE `User_`=?"; | 11 | LPCWSTR vcsUserGroupQuery = L"SELECT `User_`, `Group_` FROM `Wix4UserGroup` WHERE `User_`=?"; |
| 12 | enum eUserGroupQuery { vugqUser = 1, vugqGroup }; | 12 | enum eUserGroupQuery { vugqUser = 1, vugqGroup }; |
| 13 | 13 | ||
| 14 | LPCWSTR vActionableQuery = L"SELECT `User`,`Component_`,`Name`,`Domain`,`Password`,`Attributes` FROM `Wix4User` WHERE `Component_` IS NOT NULL"; | 14 | LPCWSTR vActionableQuery = L"SELECT `User`,`Component_`,`Name`,`Domain`,`Password`,`Comment`,`Attributes` FROM `Wix4User` WHERE `Component_` IS NOT NULL"; |
| 15 | enum eActionableQuery { vaqUser = 1, vaqComponent, vaqName, vaqDomain, vaqPassword, vaqAttributes }; | 15 | enum eActionableQuery { vaqUser = 1, vaqComponent, vaqName, vaqDomain, vaqPassword, vaqComment, vaqAttributes }; |
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | static HRESULT AddUserToList( | 18 | static HRESULT AddUserToList( |
| @@ -78,6 +78,11 @@ HRESULT __stdcall ScaGetUser( | |||
| 78 | hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); | 78 | hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); |
| 79 | ExitOnFailure(hr, "Failed to copy domain string to user object"); | 79 | ExitOnFailure(hr, "Failed to copy domain string to user object"); |
| 80 | 80 | ||
| 81 | hr = WcaGetRecordFormattedString(hRec, vuqComment, &pwzData); | ||
| 82 | ExitOnFailure(hr, "Failed to get Wix4User.Comment"); | ||
| 83 | hr = ::StringCchCopyW(pscau->wzComment, countof(pscau->wzComment), pwzData); | ||
| 84 | ExitOnFailure(hr, "Failed to copy comment string to user object"); | ||
| 85 | |||
| 81 | hr = WcaGetRecordFormattedString(hRec, vuqPassword, &pwzData); | 86 | hr = WcaGetRecordFormattedString(hRec, vuqPassword, &pwzData); |
| 82 | ExitOnFailure(hr, "Failed to get Wix4User.Password"); | 87 | ExitOnFailure(hr, "Failed to get Wix4User.Password"); |
| 83 | hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); | 88 | hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); |
| @@ -154,6 +159,11 @@ HRESULT __stdcall ScaGetUserDeferred( | |||
| 154 | hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); | 159 | hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); |
| 155 | ExitOnFailure(hr, "Failed to copy domain string to user object (in deferred CA)"); | 160 | ExitOnFailure(hr, "Failed to copy domain string to user object (in deferred CA)"); |
| 156 | 161 | ||
| 162 | hr = WcaGetRecordString(hRec, vuqComment, &pwzData); | ||
| 163 | ExitOnFailure(hr, "Failed to get Wix4User.Comment"); | ||
| 164 | hr = ::StringCchCopyW(pscau->wzComment, countof(pscau->wzComment), pwzData); | ||
| 165 | ExitOnFailure(hr, "Failed to copy comment string to user object (in deferred CA)"); | ||
| 166 | |||
| 157 | hr = WcaGetRecordString(hRec, vuqPassword, &pwzData); | 167 | hr = WcaGetRecordString(hRec, vuqPassword, &pwzData); |
| 158 | ExitOnFailure(hr, "Failed to get Wix4User.Password"); | 168 | ExitOnFailure(hr, "Failed to get Wix4User.Password"); |
| 159 | hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); | 169 | hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); |
| @@ -316,7 +326,7 @@ HRESULT ScaUserRead( | |||
| 316 | ExitOnFailure(hr, "failed to get Component state for Wix4User"); | 326 | ExitOnFailure(hr, "failed to get Component state for Wix4User"); |
| 317 | 327 | ||
| 318 | // don't bother if we aren't installing or uninstalling this component | 328 | // don't bother if we aren't installing or uninstalling this component |
| 319 | if (WcaIsInstalling(isInstalled, isAction) || WcaIsUninstalling(isInstalled, isAction)) | 329 | if (WcaIsInstalling(isInstalled, isAction) || WcaIsUninstalling(isInstalled, isAction)) |
| 320 | { | 330 | { |
| 321 | // | 331 | // |
| 322 | // Add the user to the list and populate it's values | 332 | // Add the user to the list and populate it's values |
| @@ -345,6 +355,10 @@ HRESULT ScaUserRead( | |||
| 345 | ExitOnFailure(hr, "failed to get Wix4User.Domain"); | 355 | ExitOnFailure(hr, "failed to get Wix4User.Domain"); |
| 346 | hr = ::StringCchCopyW(psu->wzDomain, countof(psu->wzDomain), pwzData); | 356 | hr = ::StringCchCopyW(psu->wzDomain, countof(psu->wzDomain), pwzData); |
| 347 | ExitOnFailure(hr, "failed to copy user domain: %ls", pwzData); | 357 | ExitOnFailure(hr, "failed to copy user domain: %ls", pwzData); |
| 358 | hr = WcaGetRecordFormattedString(hRec, vaqComment, &pwzData); | ||
| 359 | ExitOnFailure(hr, "failed to get Wix4User.Comment"); | ||
| 360 | hr = ::StringCchCopyW(psu->wzComment, countof(psu->wzComment), pwzData); | ||
| 361 | ExitOnFailure(hr, "failed to copy user comment: %ls", pwzData); | ||
| 348 | 362 | ||
| 349 | hr = WcaGetRecordFormattedString(hRec, vaqPassword, &pwzData); | 363 | hr = WcaGetRecordFormattedString(hRec, vaqPassword, &pwzData); |
| 350 | ExitOnFailure(hr, "failed to get Wix4User.Password"); | 364 | ExitOnFailure(hr, "failed to get Wix4User.Password"); |
| @@ -492,15 +506,16 @@ HRESULT ScaUserExecute( | |||
| 492 | { | 506 | { |
| 493 | USER_EXISTS ueUserExists = USER_EXISTS_INDETERMINATE; | 507 | USER_EXISTS ueUserExists = USER_EXISTS_INDETERMINATE; |
| 494 | 508 | ||
| 495 | // Always put the User Name and Domain plus Attributes on the front of the CustomAction | 509 | // Always put the User Name, Domain, and Comment on the front of the CustomAction data. |
| 496 | // data. Sometimes we'll add more data. | 510 | // The attributes will be added when we have finished adjusting them. Sometimes we'll |
| 511 | // add more data. | ||
| 497 | Assert(psu->wzName); | 512 | Assert(psu->wzName); |
| 498 | hr = WcaWriteStringToCaData(psu->wzName, &pwzActionData); | 513 | hr = WcaWriteStringToCaData(psu->wzName, &pwzActionData); |
| 499 | ExitOnFailure(hr, "Failed to add user name to custom action data: %ls", psu->wzName); | 514 | ExitOnFailure(hr, "Failed to add user name to custom action data: %ls", psu->wzName); |
| 500 | hr = WcaWriteStringToCaData(psu->wzDomain, &pwzActionData); | 515 | hr = WcaWriteStringToCaData(psu->wzDomain, &pwzActionData); |
| 501 | ExitOnFailure(hr, "Failed to add user domain to custom action data: %ls", psu->wzDomain); | 516 | ExitOnFailure(hr, "Failed to add user domain to custom action data: %ls", psu->wzDomain); |
| 502 | hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData); | 517 | hr = WcaWriteStringToCaData(psu->wzComment, &pwzActionData); |
| 503 | ExitOnFailure(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey); | 518 | ExitOnFailure(hr, "Failed to add user comment to custom action data: %ls", psu->wzComment); |
| 504 | 519 | ||
| 505 | // Check to see if the user already exists since we have to be very careful when adding | 520 | // Check to see if the user already exists since we have to be very careful when adding |
| 506 | // and removing users. Note: MSDN says that it is safe to call these APIs from any | 521 | // and removing users. Note: MSDN says that it is safe to call these APIs from any |
| @@ -520,7 +535,12 @@ HRESULT ScaUserExecute( | |||
| 520 | } | 535 | } |
| 521 | if (ERROR_SUCCESS == er) | 536 | if (ERROR_SUCCESS == er) |
| 522 | { | 537 | { |
| 523 | wzDomain = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix | 538 | if (2 <= wcslen(pDomainControllerInfo->DomainControllerName)) |
| 539 | { | ||
| 540 | wzDomain = pDomainControllerInfo->DomainControllerName + 2; // Add 2 so that we don't get the \\ prefix. | ||
| 541 | // Pass the entire string if it is too short | ||
| 542 | // to have a \\ prefix. | ||
| 543 | } | ||
| 524 | } | 544 | } |
| 525 | } | 545 | } |
| 526 | 546 | ||
| @@ -544,23 +564,32 @@ HRESULT ScaUserExecute( | |||
| 544 | 564 | ||
| 545 | if (WcaIsInstalling(psu->isInstalled, psu->isAction)) | 565 | if (WcaIsInstalling(psu->isInstalled, psu->isAction)) |
| 546 | { | 566 | { |
| 547 | // If the user exists, check to see if we are supposed to fail if user the exists before | 567 | // If the user exists, check to see if we are supposed to fail if the user exists before |
| 548 | // the install. | 568 | // the install. |
| 549 | if (USER_EXISTS_YES == ueUserExists) | 569 | if (USER_EXISTS_YES == ueUserExists) |
| 550 | { | 570 | { |
| 551 | // Reinstalls will always fail if we don't remove the check for "fail if exists". | 571 | // Re-installs will always fail if we don't remove the check for "fail if exists". |
| 552 | if (WcaIsReInstalling(psu->isInstalled, psu->isAction)) | 572 | if (WcaIsReInstalling(psu->isInstalled, psu->isAction)) |
| 553 | { | 573 | { |
| 554 | psu->iAttributes &= ~SCAU_FAIL_IF_EXISTS; | 574 | psu->iAttributes &= ~SCAU_FAIL_IF_EXISTS; |
| 575 | |||
| 576 | // If install would create the user, re-install should be able to update the user. | ||
| 577 | if (!(psu->iAttributes & SCAU_DONT_CREATE_USER)) | ||
| 578 | { | ||
| 579 | psu->iAttributes |= SCAU_UPDATE_IF_EXISTS; | ||
| 580 | } | ||
| 555 | } | 581 | } |
| 556 | 582 | ||
| 557 | if ((SCAU_FAIL_IF_EXISTS & (psu->iAttributes)) && !(SCAU_UPDATE_IF_EXISTS & (psu->iAttributes))) | 583 | if (SCAU_FAIL_IF_EXISTS & psu->iAttributes && !(SCAU_UPDATE_IF_EXISTS & psu->iAttributes)) |
| 558 | { | 584 | { |
| 559 | hr = HRESULT_FROM_WIN32(NERR_UserExists); | 585 | hr = HRESULT_FROM_WIN32(NERR_UserExists); |
| 560 | MessageExitOnFailure(hr, msierrUSRFailedUserCreateExists, "Failed to create user: %ls because user already exists.", psu->wzName); | 586 | MessageExitOnFailure(hr, msierrUSRFailedUserCreateExists, "Failed to create user: %ls because user already exists.", psu->wzName); |
| 561 | } | 587 | } |
| 562 | } | 588 | } |
| 563 | 589 | ||
| 590 | hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData); | ||
| 591 | ExitOnFailure(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey); | ||
| 592 | |||
| 564 | // Rollback only if the user already exists, we couldn't determine if the user exists, or we are going to create the user | 593 | // Rollback only if the user already exists, we couldn't determine if the user exists, or we are going to create the user |
| 565 | if ((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists) || !(psu->iAttributes & SCAU_DONT_CREATE_USER)) | 594 | if ((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists) || !(psu->iAttributes & SCAU_DONT_CREATE_USER)) |
| 566 | { | 595 | { |
| @@ -597,7 +626,6 @@ HRESULT ScaUserExecute( | |||
| 597 | ExitOnFailure(hr, "Failed to add user domain to rollback custom action data: %ls", psu->wzDomain); | 626 | ExitOnFailure(hr, "Failed to add user domain to rollback custom action data: %ls", psu->wzDomain); |
| 598 | hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); | 627 | hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); |
| 599 | ExitOnFailure(hr, "failed to add user attributes to rollback custom action data for user: %ls", psu->wzKey); | 628 | ExitOnFailure(hr, "failed to add user attributes to rollback custom action data for user: %ls", psu->wzKey); |
| 600 | |||
| 601 | // If the user already exists, add relevant group information to rollback data | 629 | // If the user already exists, add relevant group information to rollback data |
| 602 | if (USER_EXISTS_YES == ueUserExists || USER_EXISTS_INDETERMINATE == ueUserExists) | 630 | if (USER_EXISTS_YES == ueUserExists || USER_EXISTS_INDETERMINATE == ueUserExists) |
| 603 | { | 631 | { |
| @@ -630,11 +658,13 @@ HRESULT ScaUserExecute( | |||
| 630 | } | 658 | } |
| 631 | else if (((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists)) && WcaIsUninstalling(psu->isInstalled, psu->isAction) && !(psu->iAttributes & SCAU_DONT_REMOVE_ON_UNINSTALL)) | 659 | else if (((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists)) && WcaIsUninstalling(psu->isInstalled, psu->isAction) && !(psu->iAttributes & SCAU_DONT_REMOVE_ON_UNINSTALL)) |
| 632 | { | 660 | { |
| 661 | hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData); | ||
| 662 | ExitOnFailure(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey); | ||
| 663 | |||
| 633 | // Add user's group information - this will ensure the user can be removed from any groups they were added to, if the user isn't be deleted | 664 | // Add user's group information - this will ensure the user can be removed from any groups they were added to, if the user isn't be deleted |
| 634 | hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); | 665 | hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); |
| 635 | ExitOnFailure(hr, "failed to add group information to custom action data"); | 666 | ExitOnFailure(hr, "failed to add group information to custom action data"); |
| 636 | 667 | ||
| 637 | // | ||
| 638 | // Schedule the removal because the user exists and we don't have any flags set | 668 | // Schedule the removal because the user exists and we don't have any flags set |
| 639 | // that say, don't remove the user on uninstall. | 669 | // that say, don't remove the user on uninstall. |
| 640 | // | 670 | // |
| @@ -642,7 +672,7 @@ HRESULT ScaUserExecute( | |||
| 642 | // CustomAction. | 672 | // CustomAction. |
| 643 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RemoveUser"), pwzActionData, COST_USER_DELETE); | 673 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RemoveUser"), pwzActionData, COST_USER_DELETE); |
| 644 | ExitOnFailure(hr, "failed to schedule RemoveUser"); | 674 | ExitOnFailure(hr, "failed to schedule RemoveUser"); |
| 645 | } | 675 | } |
| 646 | 676 | ||
| 647 | ReleaseNullStr(pwzScriptKey); | 677 | ReleaseNullStr(pwzScriptKey); |
| 648 | ReleaseNullStr(pwzActionData); | 678 | ReleaseNullStr(pwzActionData); |
diff --git a/src/ext/Util/ca/scauser.h b/src/ext/Util/ca/scauser.h index a5fd5ea8..3da847b5 100644 --- a/src/ext/Util/ca/scauser.h +++ b/src/ext/Util/ca/scauser.h | |||
| @@ -31,6 +31,7 @@ struct SCA_USER | |||
| 31 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; | 31 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; |
| 32 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; | 32 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; |
| 33 | WCHAR wzPassword[MAX_DARWIN_COLUMN + 1]; | 33 | WCHAR wzPassword[MAX_DARWIN_COLUMN + 1]; |
| 34 | WCHAR wzComment[MAX_DARWIN_COLUMN + 1]; | ||
| 34 | INT iAttributes; | 35 | INT iAttributes; |
| 35 | 36 | ||
| 36 | SCA_GROUP *psgGroups; | 37 | SCA_GROUP *psgGroups; |
| @@ -41,16 +42,16 @@ struct SCA_USER | |||
| 41 | 42 | ||
| 42 | // prototypes | 43 | // prototypes |
| 43 | HRESULT __stdcall ScaGetUser( | 44 | HRESULT __stdcall ScaGetUser( |
| 44 | __in LPCWSTR wzUser, | 45 | __in LPCWSTR wzUser, |
| 45 | __out SCA_USER* pscau | 46 | __out SCA_USER* pscau |
| 46 | ); | 47 | ); |
| 47 | HRESULT __stdcall ScaGetUserDeferred( | 48 | HRESULT __stdcall ScaGetUserDeferred( |
| 48 | __in LPCWSTR wzUser, | 49 | __in LPCWSTR wzUser, |
| 49 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | 50 | __in WCA_WRAPQUERY_HANDLE hUserQuery, |
| 50 | __out SCA_USER* pscau | 51 | __out SCA_USER* pscau |
| 51 | ); | 52 | ); |
| 52 | HRESULT __stdcall ScaGetGroup( | 53 | HRESULT __stdcall ScaGetGroup( |
| 53 | __in LPCWSTR wzGroup, | 54 | __in LPCWSTR wzGroup, |
| 54 | __out SCA_GROUP* pscag | 55 | __out SCA_GROUP* pscag |
| 55 | ); | 56 | ); |
| 56 | void ScaUserFreeList( | 57 | void ScaUserFreeList( |
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/Package.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/Package.wxs new file mode 100644 index 00000000..af861986 --- /dev/null +++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/Package.wxs | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 2 | <Package Name="CreateUser" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
| 3 | <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." /> | ||
| 4 | |||
| 5 | <Feature Id="ProductFeature" Title="MsiPackage"> | ||
| 6 | <ComponentGroupRef Id="ProductComponents" /> | ||
| 7 | </Feature> | ||
| 8 | </Package> | ||
| 9 | |||
| 10 | <Fragment> | ||
| 11 | <StandardDirectory Id="ProgramFilesFolder"> | ||
| 12 | <Directory Id="INSTALLFOLDER" Name="CreateUser" /> | ||
| 13 | </StandardDirectory> | ||
| 14 | </Fragment> | ||
| 15 | </Wix> | ||
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/PackageComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/PackageComponents.wxs new file mode 100644 index 00000000..9fc7ba23 --- /dev/null +++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/PackageComponents.wxs | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 3 | <Fragment> | ||
| 4 | <ComponentGroup Id="ProductComponents"> | ||
| 5 | <ComponentRef Id="Component1" /> | ||
| 6 | </ComponentGroup> | ||
| 7 | </Fragment> | ||
| 8 | <Fragment> | ||
| 9 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 10 | <util:User Id="TEST_USER00" Name="testName00" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 11 | <util:User Id="TEST_USER01" Name="testName01" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 12 | <util:User Id="TEST_USER02" Name="testName02" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 13 | <util:User Id="TEST_USER03" Name="testName03" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 14 | <util:User Id="TEST_USER04" Name="testName04" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 15 | <util:User Id="TEST_USER05" Name="testName05" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 16 | <util:User Id="TEST_USER06" Name="testName06" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 17 | <util:User Id="TEST_USER07" Name="testName07" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 18 | <util:User Id="TEST_USER10" Name="testName10" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 19 | <util:User Id="TEST_USER11" Name="testName11" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 20 | <util:User Id="TEST_USER12" Name="testName12" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 21 | <util:User Id="TEST_USER13" Name="testName13" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 22 | <util:User Id="TEST_USER14" Name="testName14" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 23 | <util:User Id="TEST_USER15" Name="testName15" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 24 | <util:User Id="TEST_USER16" Name="testName16" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 25 | <util:User Id="TEST_USER17" Name="testName17" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 26 | <util:User Id="TEST_USER20" Name="testName20" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 27 | <util:User Id="TEST_USER21" Name="testName21" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 28 | <util:User Id="TEST_USER22" Name="testName22" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 29 | <util:User Id="TEST_USER23" Name="testName23" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 30 | <util:User Id="TEST_USER24" Name="testName24" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 31 | <util:User Id="TEST_USER25" Name="testName25" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 32 | <util:User Id="TEST_USER26" Name="testName26" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 33 | <util:User Id="TEST_USER27" Name="testName27" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 34 | <util:User Id="TEST_USER30" Name="testName30" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 35 | <util:User Id="TEST_USER31" Name="testName31" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 36 | <util:User Id="TEST_USER32" Name="testName32" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 37 | <util:User Id="TEST_USER33" Name="testName33" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 38 | <util:User Id="TEST_USER34" Name="testName34" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 39 | <util:User Id="TEST_USER35" Name="testName35" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 40 | <util:User Id="TEST_USER36" Name="testName36" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 41 | <util:User Id="TEST_USER37" Name="testName37" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 42 | <util:User Id="TEST_USER40" Name="testName40" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 43 | <util:User Id="TEST_USER41" Name="testName41" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 44 | <util:User Id="TEST_USER42" Name="testName42" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 45 | <util:User Id="TEST_USER43" Name="testName43" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 46 | <util:User Id="TEST_USER44" Name="testName44" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 47 | <util:User Id="TEST_USER45" Name="testName45" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 48 | <util:User Id="TEST_USER46" Name="testName46" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 49 | <util:User Id="TEST_USER47" Name="testName47" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 50 | <util:User Id="TEST_USER50" Name="testName50" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 51 | <util:User Id="TEST_USER51" Name="testName51" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 52 | <util:User Id="TEST_USER52" Name="testName52" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 53 | <util:User Id="TEST_USER53" Name="testName53" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 54 | <util:User Id="TEST_USER54" Name="testName54" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 55 | <util:User Id="TEST_USER55" Name="testName55" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 56 | <util:User Id="TEST_USER56" Name="testName56" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 57 | <util:User Id="TEST_USER57" Name="testName57" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 58 | <util:User Id="TEST_USER60" Name="testName60" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 59 | <util:User Id="TEST_USER61" Name="testName61" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 60 | <util:User Id="TEST_USER62" Name="testName62" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 61 | <util:User Id="TEST_USER63" Name="testName63" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 62 | <util:User Id="TEST_USER64" Name="testName64" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 63 | <util:User Id="TEST_USER65" Name="testName65" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 64 | <util:User Id="TEST_USER66" Name="testName66" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 65 | <util:User Id="TEST_USER67" Name="testName67" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 66 | <util:User Id="TEST_USER70" Name="testName70" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 67 | <util:User Id="TEST_USER71" Name="testName71" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 68 | <util:User Id="TEST_USER72" Name="testName72" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 69 | <util:User Id="TEST_USER73" Name="testName73" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 70 | <util:User Id="TEST_USER74" Name="testName74" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 71 | <util:User Id="TEST_USER75" Name="testName75" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 72 | <util:User Id="TEST_USER76" Name="testName76" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 73 | <util:User Id="TEST_USER77" Name="testName77" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 74 | </Component> | ||
| 75 | </Fragment> | ||
| 76 | </Wix> | ||
diff --git a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs index 24641fce..3da5f671 100644 --- a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs +++ b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs | |||
| @@ -297,6 +297,82 @@ namespace WixToolsetTest.Util | |||
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | [Fact] | 299 | [Fact] |
| 300 | public void CanCreateUserAccountWithComment() | ||
| 301 | { | ||
| 302 | var folder = TestData.Get(@"TestData\CreateUser"); | ||
| 303 | var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); | ||
| 304 | |||
| 305 | var results = build.BuildAndQuery(Build, "Wix4User"); | ||
| 306 | WixAssert.CompareLineByLine(new[] | ||
| 307 | { | ||
| 308 | "Wix4User:TEST_USER00\tComponent1\ttestName00\t\ttest123!@#\tTest Comment 1\t1792", | ||
| 309 | "Wix4User:TEST_USER01\tComponent1\ttestName01\t\ttest123!@#\tTest Comment 1\t1796", | ||
| 310 | "Wix4User:TEST_USER02\tComponent1\ttestName02\t\ttest123!@#\t\t3840", | ||
| 311 | "Wix4User:TEST_USER03\tComponent1\ttestName03\t\ttest123!@#\t\t3844", | ||
| 312 | "Wix4User:TEST_USER04\tComponent1\ttestName04\t\ttest123!@#\tTest Comment 1\t1280", | ||
| 313 | "Wix4User:TEST_USER05\tComponent1\ttestName05\t\ttest123!@#\tTest Comment 1\t1284", | ||
| 314 | "Wix4User:TEST_USER06\tComponent1\ttestName06\t\ttest123!@#\t\t3328", | ||
| 315 | "Wix4User:TEST_USER07\tComponent1\ttestName07\t\ttest123!@#\t\t3332", | ||
| 316 | "Wix4User:TEST_USER10\tComponent1\ttestName10\t\ttest123!@#\tTest Comment 1\t1808", | ||
| 317 | "Wix4User:TEST_USER11\tComponent1\ttestName11\t\ttest123!@#\tTest Comment 1\t1812", | ||
| 318 | "Wix4User:TEST_USER12\tComponent1\ttestName12\t\ttest123!@#\t\t3856", | ||
| 319 | "Wix4User:TEST_USER13\tComponent1\ttestName13\t\ttest123!@#\t\t3860", | ||
| 320 | "Wix4User:TEST_USER14\tComponent1\ttestName14\t\ttest123!@#\tTest Comment 1\t1296", | ||
| 321 | "Wix4User:TEST_USER15\tComponent1\ttestName15\t\ttest123!@#\tTest Comment 1\t1300", | ||
| 322 | "Wix4User:TEST_USER16\tComponent1\ttestName16\t\ttest123!@#\t\t3344", | ||
| 323 | "Wix4User:TEST_USER17\tComponent1\ttestName17\t\ttest123!@#\t\t3348", | ||
| 324 | "Wix4User:TEST_USER20\tComponent1\ttestName20\t\ttest123!@#\tTest Comment 1\t768", | ||
| 325 | "Wix4User:TEST_USER21\tComponent1\ttestName21\t\ttest123!@#\tTest Comment 1\t772", | ||
| 326 | "Wix4User:TEST_USER22\tComponent1\ttestName22\t\ttest123!@#\t\t2816", | ||
| 327 | "Wix4User:TEST_USER23\tComponent1\ttestName23\t\ttest123!@#\t\t2820", | ||
| 328 | "Wix4User:TEST_USER24\tComponent1\ttestName24\t\ttest123!@#\tTest Comment 1\t256", | ||
| 329 | "Wix4User:TEST_USER25\tComponent1\ttestName25\t\ttest123!@#\tTest Comment 1\t260", | ||
| 330 | "Wix4User:TEST_USER26\tComponent1\ttestName26\t\ttest123!@#\t\t2304", | ||
| 331 | "Wix4User:TEST_USER27\tComponent1\ttestName27\t\ttest123!@#\t\t2308", | ||
| 332 | "Wix4User:TEST_USER30\tComponent1\ttestName30\t\ttest123!@#\tTest Comment 1\t784", | ||
| 333 | "Wix4User:TEST_USER31\tComponent1\ttestName31\t\ttest123!@#\tTest Comment 1\t788", | ||
| 334 | "Wix4User:TEST_USER32\tComponent1\ttestName32\t\ttest123!@#\t\t2832", | ||
| 335 | "Wix4User:TEST_USER33\tComponent1\ttestName33\t\ttest123!@#\t\t2836", | ||
| 336 | "Wix4User:TEST_USER34\tComponent1\ttestName34\t\ttest123!@#\tTest Comment 1\t272", | ||
| 337 | "Wix4User:TEST_USER35\tComponent1\ttestName35\t\ttest123!@#\tTest Comment 1\t276", | ||
| 338 | "Wix4User:TEST_USER36\tComponent1\ttestName36\t\ttest123!@#\t\t2320", | ||
| 339 | "Wix4User:TEST_USER37\tComponent1\ttestName37\t\ttest123!@#\t\t2324", | ||
| 340 | "Wix4User:TEST_USER40\tComponent1\ttestName40\t\ttest123!@#\tTest Comment 1\t1536", | ||
| 341 | "Wix4User:TEST_USER41\tComponent1\ttestName41\t\ttest123!@#\tTest Comment 1\t1540", | ||
| 342 | "Wix4User:TEST_USER42\tComponent1\ttestName42\t\ttest123!@#\t\t3584", | ||
| 343 | "Wix4User:TEST_USER43\tComponent1\ttestName43\t\ttest123!@#\t\t3588", | ||
| 344 | "Wix4User:TEST_USER44\tComponent1\ttestName44\t\ttest123!@#\tTest Comment 1\t1024", | ||
| 345 | "Wix4User:TEST_USER45\tComponent1\ttestName45\t\ttest123!@#\tTest Comment 1\t1028", | ||
| 346 | "Wix4User:TEST_USER46\tComponent1\ttestName46\t\ttest123!@#\t\t3072", | ||
| 347 | "Wix4User:TEST_USER47\tComponent1\ttestName47\t\ttest123!@#\t\t3076", | ||
| 348 | "Wix4User:TEST_USER50\tComponent1\ttestName50\t\ttest123!@#\tTest Comment 1\t1552", | ||
| 349 | "Wix4User:TEST_USER51\tComponent1\ttestName51\t\ttest123!@#\tTest Comment 1\t1556", | ||
| 350 | "Wix4User:TEST_USER52\tComponent1\ttestName52\t\ttest123!@#\t\t3600", | ||
| 351 | "Wix4User:TEST_USER53\tComponent1\ttestName53\t\ttest123!@#\t\t3604", | ||
| 352 | "Wix4User:TEST_USER54\tComponent1\ttestName54\t\ttest123!@#\tTest Comment 1\t1040", | ||
| 353 | "Wix4User:TEST_USER55\tComponent1\ttestName55\t\ttest123!@#\tTest Comment 1\t1044", | ||
| 354 | "Wix4User:TEST_USER56\tComponent1\ttestName56\t\ttest123!@#\t\t3088", | ||
| 355 | "Wix4User:TEST_USER57\tComponent1\ttestName57\t\ttest123!@#\t\t3092", | ||
| 356 | "Wix4User:TEST_USER60\tComponent1\ttestName60\t\ttest123!@#\tTest Comment 1\t512", | ||
| 357 | "Wix4User:TEST_USER61\tComponent1\ttestName61\t\ttest123!@#\tTest Comment 1\t516", | ||
| 358 | "Wix4User:TEST_USER62\tComponent1\ttestName62\t\ttest123!@#\t\t2560", | ||
| 359 | "Wix4User:TEST_USER63\tComponent1\ttestName63\t\ttest123!@#\t\t2564", | ||
| 360 | "Wix4User:TEST_USER64\tComponent1\ttestName64\t\ttest123!@#\tTest Comment 1\t0", | ||
| 361 | "Wix4User:TEST_USER65\tComponent1\ttestName65\t\ttest123!@#\tTest Comment 1\t4", | ||
| 362 | "Wix4User:TEST_USER66\tComponent1\ttestName66\t\ttest123!@#\t\t2048", | ||
| 363 | "Wix4User:TEST_USER67\tComponent1\ttestName67\t\ttest123!@#\t\t2052", | ||
| 364 | "Wix4User:TEST_USER70\tComponent1\ttestName70\t\ttest123!@#\tTest Comment 1\t528", | ||
| 365 | "Wix4User:TEST_USER71\tComponent1\ttestName71\t\ttest123!@#\tTest Comment 1\t532", | ||
| 366 | "Wix4User:TEST_USER72\tComponent1\ttestName72\t\ttest123!@#\t\t2576", | ||
| 367 | "Wix4User:TEST_USER73\tComponent1\ttestName73\t\ttest123!@#\t\t2580", | ||
| 368 | "Wix4User:TEST_USER74\tComponent1\ttestName74\t\ttest123!@#\tTest Comment 1\t16", | ||
| 369 | "Wix4User:TEST_USER75\tComponent1\ttestName75\t\ttest123!@#\tTest Comment 1\t20", | ||
| 370 | "Wix4User:TEST_USER76\tComponent1\ttestName76\t\ttest123!@#\t\t2064", | ||
| 371 | "Wix4User:TEST_USER77\tComponent1\ttestName77\t\ttest123!@#\t\t2068", | ||
| 372 | }, results.OrderBy(s => s).ToArray()); | ||
| 373 | } | ||
| 374 | |||
| 375 | [Fact] | ||
| 300 | public void CanBuildBundleWithWarningsWithSearchesUsingDiscouragedVariableNames() | 376 | public void CanBuildBundleWithWarningsWithSearchesUsingDiscouragedVariableNames() |
| 301 | { | 377 | { |
| 302 | var folder = TestData.Get("TestData", "BundleWithSearches"); | 378 | var folder = TestData.Get("TestData", "BundleWithSearches"); |
diff --git a/src/ext/Util/wixext/Symbols/UserSymbol.cs b/src/ext/Util/wixext/Symbols/UserSymbol.cs index 5f00064b..6ea810de 100644 --- a/src/ext/Util/wixext/Symbols/UserSymbol.cs +++ b/src/ext/Util/wixext/Symbols/UserSymbol.cs | |||
| @@ -15,6 +15,7 @@ namespace WixToolset.Util | |||
| 15 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Name), IntermediateFieldType.String), | 15 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Name), IntermediateFieldType.String), |
| 16 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Domain), IntermediateFieldType.String), | 16 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Domain), IntermediateFieldType.String), |
| 17 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Password), IntermediateFieldType.String), | 17 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Password), IntermediateFieldType.String), |
| 18 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Comment), IntermediateFieldType.String), | ||
| 18 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Attributes), IntermediateFieldType.Number), | 19 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Attributes), IntermediateFieldType.Number), |
| 19 | }, | 20 | }, |
| 20 | typeof(UserSymbol)); | 21 | typeof(UserSymbol)); |
| @@ -31,6 +32,7 @@ namespace WixToolset.Util.Symbols | |||
| 31 | Name, | 32 | Name, |
| 32 | Domain, | 33 | Domain, |
| 33 | Password, | 34 | Password, |
| 35 | Comment, | ||
| 34 | Attributes, | 36 | Attributes, |
| 35 | } | 37 | } |
| 36 | 38 | ||
| @@ -70,10 +72,16 @@ namespace WixToolset.Util.Symbols | |||
| 70 | set => this.Set((int)UserSymbolFields.Password, value); | 72 | set => this.Set((int)UserSymbolFields.Password, value); |
| 71 | } | 73 | } |
| 72 | 74 | ||
| 75 | public string Comment | ||
| 76 | { | ||
| 77 | get => this.Fields[(int)UserSymbolFields.Comment].AsString(); | ||
| 78 | set => this.Set((int)UserSymbolFields.Comment, value); | ||
| 79 | } | ||
| 80 | |||
| 73 | public int Attributes | 81 | public int Attributes |
| 74 | { | 82 | { |
| 75 | get => this.Fields[(int)UserSymbolFields.Attributes].AsNumber(); | 83 | get => this.Fields[(int)UserSymbolFields.Attributes].AsNumber(); |
| 76 | set => this.Set((int)UserSymbolFields.Attributes, value); | 84 | set => this.Set((int)UserSymbolFields.Attributes, value); |
| 77 | } | 85 | } |
| 78 | } | 86 | } |
| 79 | } \ No newline at end of file | 87 | } |
diff --git a/src/ext/Util/wixext/UtilCompiler.cs b/src/ext/Util/wixext/UtilCompiler.cs index a6e4b835..d937b4f1 100644 --- a/src/ext/Util/wixext/UtilCompiler.cs +++ b/src/ext/Util/wixext/UtilCompiler.cs | |||
| @@ -34,6 +34,7 @@ namespace WixToolset.Util | |||
| 34 | internal const int UserDontRemoveOnUninstall = 0x00000100; | 34 | internal const int UserDontRemoveOnUninstall = 0x00000100; |
| 35 | internal const int UserDontCreateUser = 0x00000200; | 35 | internal const int UserDontCreateUser = 0x00000200; |
| 36 | internal const int UserNonVital = 0x00000400; | 36 | internal const int UserNonVital = 0x00000400; |
| 37 | internal const int UserRemoveComment = 0x00000800; | ||
| 37 | 38 | ||
| 38 | private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(?<!\[\\\]|\[\\|\\\[)\]", RegexOptions.ExplicitCapture | RegexOptions.Compiled); | 39 | private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(?<!\[\\\]|\[\\|\\\[)\]", RegexOptions.ExplicitCapture | RegexOptions.Compiled); |
| 39 | 40 | ||
| @@ -3251,6 +3252,7 @@ namespace WixToolset.Util | |||
| 3251 | int attributes = 0; | 3252 | int attributes = 0; |
| 3252 | string domain = null; | 3253 | string domain = null; |
| 3253 | string name = null; | 3254 | string name = null; |
| 3255 | string comment = null; | ||
| 3254 | string password = null; | 3256 | string password = null; |
| 3255 | 3257 | ||
| 3256 | foreach (var attrib in element.Attributes()) | 3258 | foreach (var attrib in element.Attributes()) |
| @@ -3273,6 +3275,14 @@ namespace WixToolset.Util | |||
| 3273 | attributes |= UserPasswdCantChange; | 3275 | attributes |= UserPasswdCantChange; |
| 3274 | } | 3276 | } |
| 3275 | break; | 3277 | break; |
| 3278 | case "Comment": | ||
| 3279 | if (null == componentId) | ||
| 3280 | { | ||
| 3281 | this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); | ||
| 3282 | } | ||
| 3283 | |||
| 3284 | comment = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); | ||
| 3285 | break; | ||
| 3276 | case "CreateUser": | 3286 | case "CreateUser": |
| 3277 | if (null == componentId) | 3287 | if (null == componentId) |
| 3278 | { | 3288 | { |
| @@ -3357,6 +3367,12 @@ namespace WixToolset.Util | |||
| 3357 | attributes |= UserDontExpirePasswrd; | 3367 | attributes |= UserDontExpirePasswrd; |
| 3358 | } | 3368 | } |
| 3359 | break; | 3369 | break; |
| 3370 | case "RemoveComment": | ||
| 3371 | if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
| 3372 | { | ||
| 3373 | attributes |= UserRemoveComment; | ||
| 3374 | } | ||
| 3375 | break; | ||
| 3360 | case "RemoveOnUninstall": | 3376 | case "RemoveOnUninstall": |
| 3361 | if (null == componentId) | 3377 | if (null == componentId) |
| 3362 | { | 3378 | { |
| @@ -3411,6 +3427,11 @@ namespace WixToolset.Util | |||
| 3411 | this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); | 3427 | this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); |
| 3412 | } | 3428 | } |
| 3413 | 3429 | ||
| 3430 | if (null != comment && (UserRemoveComment & attributes) != 0) | ||
| 3431 | { | ||
| 3432 | this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Comment", "RemoveComment")); | ||
| 3433 | } | ||
| 3434 | |||
| 3414 | foreach (var child in element.Elements()) | 3435 | foreach (var child in element.Elements()) |
| 3415 | { | 3436 | { |
| 3416 | if (this.Namespace == child.Name.Namespace) | 3437 | if (this.Namespace == child.Name.Namespace) |
| @@ -3450,6 +3471,7 @@ namespace WixToolset.Util | |||
| 3450 | Name = name, | 3471 | Name = name, |
| 3451 | Domain = domain, | 3472 | Domain = domain, |
| 3452 | Password = password, | 3473 | Password = password, |
| 3474 | Comment = comment, | ||
| 3453 | Attributes = attributes, | 3475 | Attributes = attributes, |
| 3454 | }); | 3476 | }); |
| 3455 | } | 3477 | } |
diff --git a/src/ext/Util/wixext/UtilDecompiler.cs b/src/ext/Util/wixext/UtilDecompiler.cs index 7d95fcef..1201fdd5 100644 --- a/src/ext/Util/wixext/UtilDecompiler.cs +++ b/src/ext/Util/wixext/UtilDecompiler.cs | |||
| @@ -559,13 +559,14 @@ namespace WixToolset.Util | |||
| 559 | { | 559 | { |
| 560 | foreach (var row in table.Rows) | 560 | foreach (var row in table.Rows) |
| 561 | { | 561 | { |
| 562 | var attributes = row.FieldAsNullableInteger(5) ?? 0; | 562 | var attributes = row.FieldAsNullableInteger(6) ?? 0; |
| 563 | 563 | ||
| 564 | var user = new XElement(UtilConstants.UserName, | 564 | var user = new XElement(UtilConstants.UserName, |
| 565 | new XAttribute("Id", row.FieldAsString(0)), | 565 | new XAttribute("Id", row.FieldAsString(0)), |
| 566 | new XAttribute("Name", row.FieldAsString(2)), | 566 | new XAttribute("Name", row.FieldAsString(2)), |
| 567 | AttributeIfNotNull("Domain", row, 3), | 567 | AttributeIfNotNull("Domain", row, 3), |
| 568 | AttributeIfNotNull("Password", row, 4), | 568 | AttributeIfNotNull("Password", row, 4), |
| 569 | AttributeIfNotNull("Comment", row, 5), | ||
| 569 | AttributeIfTrue("PasswordNeverExpires", UtilCompiler.UserDontExpirePasswrd == (attributes & UtilCompiler.UserDontExpirePasswrd)), | 570 | AttributeIfTrue("PasswordNeverExpires", UtilCompiler.UserDontExpirePasswrd == (attributes & UtilCompiler.UserDontExpirePasswrd)), |
| 570 | AttributeIfTrue("CanNotChangePassword", UtilCompiler.UserPasswdCantChange == (attributes & UtilCompiler.UserPasswdCantChange)), | 571 | AttributeIfTrue("CanNotChangePassword", UtilCompiler.UserPasswdCantChange == (attributes & UtilCompiler.UserPasswdCantChange)), |
| 571 | AttributeIfTrue("PasswordExpired", UtilCompiler.UserPasswdChangeReqdOnLogin == (attributes & UtilCompiler.UserPasswdChangeReqdOnLogin)), | 572 | AttributeIfTrue("PasswordExpired", UtilCompiler.UserPasswdChangeReqdOnLogin == (attributes & UtilCompiler.UserPasswdChangeReqdOnLogin)), |
| @@ -573,7 +574,8 @@ namespace WixToolset.Util | |||
| 573 | AttributeIfTrue("FailIfExists", UtilCompiler.UserFailIfExists == (attributes & UtilCompiler.UserFailIfExists)), | 574 | AttributeIfTrue("FailIfExists", UtilCompiler.UserFailIfExists == (attributes & UtilCompiler.UserFailIfExists)), |
| 574 | AttributeIfTrue("UpdateIfExists", UtilCompiler.UserUpdateIfExists == (attributes & UtilCompiler.UserUpdateIfExists)), | 575 | AttributeIfTrue("UpdateIfExists", UtilCompiler.UserUpdateIfExists == (attributes & UtilCompiler.UserUpdateIfExists)), |
| 575 | AttributeIfTrue("LogonAsService", UtilCompiler.UserLogonAsService == (attributes & UtilCompiler.UserLogonAsService)), | 576 | AttributeIfTrue("LogonAsService", UtilCompiler.UserLogonAsService == (attributes & UtilCompiler.UserLogonAsService)), |
| 576 | AttributeIfTrue("LogonAsService", UtilCompiler.UserLogonAsService == (attributes & UtilCompiler.UserLogonAsService)) | 577 | AttributeIfTrue("LogonAsBatchJob", UtilCompiler.UserLogonAsBatchJob == (attributes & UtilCompiler.UserLogonAsBatchJob)), |
| 578 | AttributeIfTrue("RemoveComment", UtilCompiler.UserRemoveComment == (attributes & UtilCompiler.UserRemoveComment)) | ||
| 577 | ); | 579 | ); |
| 578 | 580 | ||
| 579 | if (UtilCompiler.UserDontRemoveOnUninstall == (attributes & UtilCompiler.UserDontRemoveOnUninstall)) | 581 | if (UtilCompiler.UserDontRemoveOnUninstall == (attributes & UtilCompiler.UserDontRemoveOnUninstall)) |
diff --git a/src/ext/Util/wixext/UtilTableDefinitions.cs b/src/ext/Util/wixext/UtilTableDefinitions.cs index 57c18b6c..33e6d3d1 100644 --- a/src/ext/Util/wixext/UtilTableDefinitions.cs +++ b/src/ext/Util/wixext/UtilTableDefinitions.cs | |||
| @@ -229,6 +229,7 @@ namespace WixToolset.Util | |||
| 229 | new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "User name", modularizeType: ColumnModularizeType.Property), | 229 | new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "User name", modularizeType: ColumnModularizeType.Property), |
| 230 | new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User domain", modularizeType: ColumnModularizeType.Property), | 230 | new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User domain", modularizeType: ColumnModularizeType.Property), |
| 231 | new ColumnDefinition("Password", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User password", modularizeType: ColumnModularizeType.Property), | 231 | new ColumnDefinition("Password", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User password", modularizeType: ColumnModularizeType.Property), |
| 232 | new ColumnDefinition("Comment", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User comment", modularizeType: ColumnModularizeType.Property), | ||
| 232 | new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 0, maxValue: 65535, description: "Attributes describing how to create the user"), | 233 | new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 0, maxValue: 65535, description: "Attributes describing how to create the user"), |
| 233 | }, | 234 | }, |
| 234 | symbolIdIsPrimaryKey: true | 235 | symbolIdIsPrimaryKey: true |
