Skip to content
/ wix Public

Commit f507768

Browse files
committed
Add/Remove Group Membership rollback handled.
Fixups to a few test cases. Signed-off-by: Bevan Weiss <bevan.weiss@gmail.com>
1 parent 15772ee commit f507768

File tree

17 files changed

+347
-133
lines changed

17 files changed

+347
-133
lines changed

src/ext/Util/ca/scaexec.cpp

Lines changed: 80 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ static HRESULT RemoveGroupInternal(
716716
//
717717
if (!(SCAG_DONT_CREATE_GROUP & iAttributes))
718718
{
719-
GetDomainServerName(wzDomain, &pwzServerName, DS_WRITABLE_REQUIRED);
719+
hr = GetDomainFromServerName(&pwzServerName, wzDomain, DS_WRITABLE_REQUIRED);
720720

721721
NET_API_STATUS er = ::NetLocalGroupDel(pwzServerName, wzName);
722722
hr = HRESULT_FROM_WIN32(er);
@@ -1218,9 +1218,13 @@ extern "C" UINT __stdcall RemoveUser(
12181218

12191219

12201220
/********************************************************************
1221-
CreateGroup - CUSTOM ACTION ENTRY POINT for creating groups
1221+
CreateGroup - CUSTOM ACTION ENTRY POINT for creating groups
1222+
For domain parent group, must be run as Impersonated=true
1223+
For non-domain parent group, must be run as Impersonated=false (for elevation)
12221224
1223-
Input: deferred CustomActionData - GroupName\tDomain\tComment\tAttributes
1225+
Input: deferred CustomActionData - GroupName\tDomain\tComment\tAttributes\tScriptKey(empty for no rollback)
1226+
1227+
Output: Script for RollbackCreateGroup - OriginalComment\tRollbackAttributes
12241228
* *****************************************************************/
12251229
extern "C" UINT __stdcall CreateGroup(
12261230
__in MSIHANDLE hInstall
@@ -1281,8 +1285,8 @@ extern "C" UINT __stdcall CreateGroup(
12811285

12821286
if (!(SCAG_DONT_CREATE_GROUP & iAttributes))
12831287
{
1284-
hr = GetDomainServerName(pwzDomain, &pwzServerName, DS_WRITABLE_REQUIRED);
1285-
ExitOnFailure(hr, "failed to find Domain %ls.", pwzDomain);
1288+
hr = GetDomainFromServerName(&pwzServerName, pwzDomain, DS_WRITABLE_REQUIRED);
1289+
ExitOnFailure(hr, "failed to find writable server for domain %ls.", pwzDomain);
12861290

12871291
// Set the group's comment
12881292
if (SCAG_REMOVE_COMMENT & iAttributes)
@@ -1304,7 +1308,7 @@ extern "C" UINT __stdcall CreateGroup(
13041308
{
13051309
if (SCAG_FAIL_IF_EXISTS & iAttributes)
13061310
{
1307-
MessageExitOnFailure(hr, msierrGRPFailedGroupCreateExists, "Group (%ls) was not supposed to exist, but does", pwzName);
1311+
MessageExitOnFailure(hr, msierrGRPFailedGroupCreateExists, "Group (%ls\\%ls) was not supposed to exist, but does", pwzDomain, pwzName);
13081312
}
13091313

13101314
hr = S_OK; // Make sure that we don't report this situation as an error
@@ -1359,7 +1363,7 @@ extern "C" UINT __stdcall CreateGroup(
13591363
hr = SetGroupComment(pwzServerName, pwzName, L"");
13601364
if (FAILED(hr))
13611365
{
1362-
WcaLogError(hr, "failed to clear comment for group %ls\\%ls, continuing anyway.", pwzServerName, pwzName);
1366+
WcaLogError(hr, "failed to clear comment for group %ls\\%ls, continuing anyway.", pwzDomain, pwzName);
13631367
hr = S_OK;
13641368
}
13651369
}
@@ -1368,14 +1372,14 @@ extern "C" UINT __stdcall CreateGroup(
13681372
hr = SetGroupComment(pwzServerName, pwzName, pwzComment);
13691373
if (FAILED(hr))
13701374
{
1371-
WcaLogError(hr, "failed to set comment to %ls for group %ls\\%ls, continuing anyway.", pwzComment, pwzServerName, pwzName);
1375+
WcaLogError(hr, "failed to set comment to '%ls' for group %ls\\%ls, continuing anyway.", pwzComment, pwzDomain, pwzName);
13721376
hr = S_OK;
13731377
}
13741378
}
13751379
}
13761380
}
13771381
}
1378-
MessageExitOnFailure(hr, msierrGRPFailedGroupCreate, "failed to create group: %ls", pwzName);
1382+
MessageExitOnFailure(hr, msierrGRPFailedGroupCreate, "failed to create group: %ls\\%ls", pwzDomain, pwzName);
13791383
}
13801384

13811385
LExit:
@@ -1391,6 +1395,7 @@ extern "C" UINT __stdcall CreateGroup(
13911395
ReleaseStr(pwzDomain);
13921396
ReleaseStr(pwzComment);
13931397
ReleaseStr(pwzScriptKey);
1398+
ReleaseStr(pwzServerName);
13941399

13951400
if (fInitializedCom)
13961401
{
@@ -1412,6 +1417,11 @@ extern "C" UINT __stdcall CreateGroup(
14121417

14131418
/********************************************************************
14141419
CreateGroupRollback - CUSTOM ACTION ENTRY POINT for CreateGroup rollback
1420+
For domain parent group, must be run as Impersonated=true
1421+
For non-domain parent group, must be run as Impersonated=false (for elevation)
1422+
1423+
Input: rollback CustomActionData - ScriptKey\tGroupName\tDomain\tComment\tRollbackAttributes
1424+
rollback script - OriginalComment\tRollbackAttributes
14151425
14161426
* *****************************************************************/
14171427
extern "C" UINT __stdcall CreateGroupRollback(
@@ -1429,7 +1439,7 @@ extern "C" UINT __stdcall CreateGroupRollback(
14291439
LPWSTR pwzName = NULL;
14301440
LPWSTR pwzDomain = NULL;
14311441
LPWSTR pwzComment = NULL;
1432-
int iAttributes = 0;
1442+
int iRollbackAttributes = 0;
14331443
BOOL fInitializedCom = FALSE;
14341444

14351445
WCA_CASCRIPT_HANDLE hRollbackScript = NULL;
@@ -1454,7 +1464,7 @@ extern "C" UINT __stdcall CreateGroupRollback(
14541464
//
14551465
pwz = pwzData;
14561466
hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey);
1457-
ExitOnFailure(hr, "failed to read encoding key from custom action data");
1467+
ExitOnFailure(hr, "failed to read script key from custom action data");
14581468

14591469
hr = WcaReadStringFromCaData(&pwz, &pwzName);
14601470
ExitOnFailure(hr, "failed to read name from custom action data");
@@ -1465,8 +1475,8 @@ extern "C" UINT __stdcall CreateGroupRollback(
14651475
hr = WcaReadStringFromCaData(&pwz, &pwzComment);
14661476
ExitOnFailure(hr, "failed to read comment from custom action data");
14671477

1468-
hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
1469-
ExitOnFailure(hr, "failed to read attributes from custom action data");
1478+
hr = WcaReadIntegerFromCaData(&pwz, &iRollbackAttributes);
1479+
ExitOnFailure(hr, "failed to read rollback attributes from custom action data");
14701480

14711481
// Best effort to read original configuration from CreateUser.
14721482
hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript);
@@ -1502,12 +1512,12 @@ extern "C" UINT __stdcall CreateGroupRollback(
15021512
}
15031513
else
15041514
{
1505-
iAttributes |= iOriginalAttributes;
1515+
iRollbackAttributes |= iOriginalAttributes;
15061516
}
15071517
}
15081518
}
15091519

1510-
hr = RemoveGroupInternal(pwzDomain, pwzName, iAttributes);
1520+
hr = RemoveGroupInternal(pwzDomain, pwzName, iRollbackAttributes);
15111521

15121522
LExit:
15131523
WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE);
@@ -1535,9 +1545,12 @@ extern "C" UINT __stdcall CreateGroupRollback(
15351545

15361546

15371547
/********************************************************************
1538-
RemoveGroup - CUSTOM ACTION ENTRY POINT for removing groups
1548+
RemoveGroup - CUSTOM ACTION ENTRY POINT for removing groups
1549+
For domain parent group, must be run as Impersonated=true
1550+
For non-domain parent group, must be run as Impersonated=false (for elevation)
1551+
NOTE: This action can't be rolled back, so should only be performed in commit phase
15391552
1540-
Input: deferred CustomActionData - Name\tDomain
1553+
Input: commit CustomActionData - Name\tDomain\tComment\tAttributes
15411554
* *****************************************************************/
15421555
extern "C" UINT __stdcall RemoveGroup(
15431556
MSIHANDLE hInstall
@@ -1605,7 +1618,7 @@ extern "C" UINT __stdcall RemoveGroup(
16051618
return WcaFinalize(er);
16061619
}
16071620

1608-
HRESULT AlterGroupMembership(bool remove, bool isRollback = false)
1621+
HRESULT AlterGroupMembership(bool remove, bool isRollback)
16091622
{
16101623
HRESULT hr = S_OK;
16111624
NET_API_STATUS er = ERROR_SUCCESS;
@@ -1617,22 +1630,13 @@ HRESULT AlterGroupMembership(bool remove, bool isRollback = false)
16171630
LPWSTR pwzChildName = NULL;
16181631
LPWSTR pwzChildDomain = NULL;
16191632
int iAttributes = 0;
1633+
LPWSTR pwzScriptKey = NULL;
16201634
LPWSTR pwzChildFullName = NULL;
16211635
LPWSTR pwzServerName = NULL;
16221636
LOCALGROUP_MEMBERS_INFO_3 memberInfo3 = {};
1623-
WCA_CASCRIPT_HANDLE phRollbackScript = NULL;
1637+
WCA_CASCRIPT_HANDLE hRollbackScript = NULL;
16241638

1625-
if (isRollback)
1626-
{
1627-
// Get a CaScript key
1628-
hr = WcaCaScriptOpen(WCA_ACTION_NONE, WCA_CASCRIPT_ROLLBACK, FALSE, remove ? L"AddGroupMembershipRollback" : L"RemoveGroupMembershipRollback", &phRollbackScript);
1629-
hr = WcaCaScriptReadAsCustomActionData(phRollbackScript, &pwzData);
1630-
}
1631-
else
1632-
{
1633-
hr = WcaCaScriptCreate(WCA_ACTION_NONE, WCA_CASCRIPT_ROLLBACK, FALSE, remove ? L"RemoveGroupMembershipRollback" : L"AddGroupMembershipRollback", TRUE, &phRollbackScript);
1634-
hr = WcaGetProperty(L"CustomActionData", &pwzData);
1635-
}
1639+
hr = WcaGetProperty(L"CustomActionData", &pwzData);
16361640
ExitOnFailure(hr, "failed to get CustomActionData");
16371641

16381642
WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
@@ -1656,8 +1660,28 @@ HRESULT AlterGroupMembership(bool remove, bool isRollback = false)
16561660
hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
16571661
ExitOnFailure(hr, "failed to read attributes from custom action data");
16581662

1659-
hr = GetDomainServerName(pwzParentDomain, &pwzServerName, DS_WRITABLE_REQUIRED);
1660-
ExitOnFailure(hr, "failed to contact domain server %ls", pwzParentDomain);
1663+
hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey);
1664+
ExitOnFailure(hr, "failed to read scriptkey from custom action data");
1665+
1666+
if (isRollback)
1667+
{
1668+
// if the script file doesn't exist, then we'll abandon this rollback
1669+
hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript);
1670+
if (S_OK == hr)
1671+
{
1672+
WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE);
1673+
}
1674+
else
1675+
{
1676+
WcaLog(LOGMSG_VERBOSE, "Rollback of parent: %ls\\%ls, child: %ls\\%ls relationship not performed, rollback script not found", pwzParentDomain, pwzParentName, pwzChildDomain, pwzChildName);
1677+
hr = S_OK;
1678+
ExitFunction();
1679+
}
1680+
}
1681+
1682+
1683+
hr = GetDomainFromServerName(&pwzServerName, pwzParentDomain, DS_WRITABLE_REQUIRED);
1684+
ExitOnFailure(hr, "failed to obtain writable server for domain %ls", pwzParentDomain);
16611685

16621686
if (*pwzChildDomain)
16631687
{
@@ -1679,16 +1703,13 @@ HRESULT AlterGroupMembership(bool remove, bool isRollback = false)
16791703
}
16801704
hr = HRESULT_FROM_WIN32(er);
16811705

1706+
// if there was no error, the action succeeded, and we should flag that it's something which might need
1707+
// to be rolled back
16821708
if (S_OK == hr && !isRollback)
16831709
{
1684-
// we need to log rollback data, we can just use exactly the same data we used to do the initial action though
1685-
WcaCaScriptWriteString(phRollbackScript, pwzParentName);
1686-
WcaCaScriptWriteString(phRollbackScript, pwzParentDomain);
1687-
WcaCaScriptWriteString(phRollbackScript, pwzChildName);
1688-
WcaCaScriptWriteString(phRollbackScript, pwzChildDomain);
1689-
WcaCaScriptWriteNumber(phRollbackScript, iAttributes);
1690-
WcaCaScriptFlush(phRollbackScript);
1691-
WcaCaScriptClose(phRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE);
1710+
// we create a script file, the rollback matching this scriptkey will occur if the file exists
1711+
hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript);
1712+
WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE);
16921713
}
16931714

16941715
if (remove)
@@ -1716,6 +1737,7 @@ HRESULT AlterGroupMembership(bool remove, bool isRollback = false)
17161737
ReleaseStr(pwzChildDomain);
17171738
ReleaseStr(pwzChildFullName);
17181739
ReleaseStr(pwzServerName);
1740+
ReleaseStr(pwzScriptKey);
17191741

17201742
if (SCAG_NON_VITAL & iAttributes)
17211743
{
@@ -1725,10 +1747,12 @@ HRESULT AlterGroupMembership(bool remove, bool isRollback = false)
17251747
}
17261748

17271749
/********************************************************************
1728-
AddGroupmembership - CUSTOM ACTION ENTRY POINT for creating groups
1750+
AddGroupMembership - CUSTOM ACTION ENTRY POINT for adding Group Membership
1751+
For domain parent group, must be run as Impersonated=true
1752+
For non-domain parent group, must be run as Impersonated=false (for elevation)
17291753
17301754
Input: deferred CustomActionData -
1731-
ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes
1755+
ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes\tScriptkey
17321756
* *****************************************************************/
17331757
extern "C" UINT __stdcall AddGroupMembership(
17341758
__in MSIHANDLE hInstall
@@ -1758,10 +1782,13 @@ extern "C" UINT __stdcall AddGroupMembership(
17581782
}
17591783

17601784
/********************************************************************
1761-
AddGroupmembership - CUSTOM ACTION ENTRY POINT for creating groups
1785+
AddGroupMembershipRollback - CUSTOM ACTION ENTRY POINT for rolling back
1786+
adding Group Membership
1787+
For domain parent group, must be run as Impersonated=true
1788+
For non-domain parent group, must be run as Impersonated=false (for elevation)
17621789
17631790
Input: deferred CustomActionData -
1764-
ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes
1791+
ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes\tScriptkey
17651792
* *****************************************************************/
17661793
extern "C" UINT __stdcall AddGroupMembershipRollback(
17671794
__in MSIHANDLE hInstall
@@ -1791,10 +1818,12 @@ extern "C" UINT __stdcall AddGroupMembershipRollback(
17911818
}
17921819

17931820
/********************************************************************
1794-
RemoveGroupMembership - CUSTOM ACTION ENTRY POINT for creating groups
1821+
RemoveGroupMembership - CUSTOM ACTION ENTRY POINT for removing group memberships
1822+
For domain parent group, must be run as Impersonated=true
1823+
For non-domain parent group, must be run as Impersonated=false (for elevation)
17951824
17961825
Input: deferred CustomActionData -
1797-
ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes
1826+
ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes\tScriptkey
17981827
* *****************************************************************/
17991828
extern "C" UINT __stdcall RemoveGroupMembership(
18001829
__in MSIHANDLE hInstall
@@ -1824,10 +1853,13 @@ extern "C" UINT __stdcall RemoveGroupMembership(
18241853
}
18251854

18261855
/********************************************************************
1827-
RemoveGroupMembershipRollback - CUSTOM ACTION ENTRY POINT for creating groups
1856+
RemoveGroupMembershipRollback - CUSTOM ACTION ENTRY POINT for rolling back
1857+
removing group memberships
1858+
For domain parent group, must be run as Impersonated=true
1859+
For non-domain parent group, must be run as Impersonated=false (for elevation)
18281860
18291861
Input: deferred CustomActionData -
1830-
ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes
1862+
ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes\tScriptkey
18311863
* *****************************************************************/
18321864
extern "C" UINT __stdcall RemoveGroupMembershipRollback(
18331865
__in MSIHANDLE hInstall

0 commit comments

Comments
 (0)