aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Util/ca/scaexec.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Util/ca/scaexec.cpp')
-rw-r--r--src/ext/Util/ca/scaexec.cpp375
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
523static void SetUserPasswordAndAttributes( 522static 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
565static 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
581static 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
589static 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
597static 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
573static HRESULT RemoveUserInternal( 605static 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
720static 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 * *****************************************************************/
689extern "C" UINT __stdcall CreateUser( 761extern "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))) 991while (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
1007ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName);
1008
871LExit: 1009LExit:
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 {