aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBevan Weiss <bevan.weiss@gmail.com>2024-07-06 21:03:57 +1000
committerRob Mensching <rob@firegiant.com>2025-02-11 23:14:49 -0800
commit644276562dcadd65fcb0e9a7c06c704cdda36423 (patch)
treef42af115bf5354d1c1691c44d517388f6c369b16
parent7b1bb025dea1d1e9e144cce0dcbba2d86f053b8f (diff)
downloadwix-644276562dcadd65fcb0e9a7c06c704cdda36423.tar.gz
wix-644276562dcadd65fcb0e9a7c06c704cdda36423.tar.bz2
wix-644276562dcadd65fcb0e9a7c06c704cdda36423.zip
Group Add/Remove working.
Local group membership Add/Remove working, however with BUILTIN local system groups .NET doesn't appear to locate them as either groups nor basic security Principals. Still needs work to fix the test for nested groups. Ideally with some way to test for domain groups. Signed-off-by: Bevan Weiss <bevan.weiss@gmail.com>
-rw-r--r--src/ext/Util/ca/scacost.h2
-rw-r--r--src/ext/Util/ca/scaexec.cpp454
-rw-r--r--src/ext/Util/ca/scagroup.cpp412
-rw-r--r--src/ext/Util/ca/scagroup.h10
-rw-r--r--src/ext/Util/ca/scanet.cpp5
-rw-r--r--src/ext/Util/ca/scasched.cpp6
-rw-r--r--src/ext/Util/ca/utilca.def4
-rw-r--r--src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs8
-rw-r--r--src/ext/Util/wixext/UtilCompiler.cs7
-rw-r--r--src/ext/Util/wixext/UtilDecompiler.cs18
-rw-r--r--src/ext/Util/wixlib/UtilExtension.wxs7
-rw-r--r--src/ext/Util/wixlib/UtilExtension_Platform.wxi20
-rw-r--r--src/ext/Util/wixlib/es-es.wxl2
-rw-r--r--src/ext/Util/wixlib/fr-fr.wxl2
-rw-r--r--src/ext/caDecor.h10
-rw-r--r--src/ext/caDecor.wxi5
-rw-r--r--src/test/burn/WixTestTools/UserGroupVerifier.cs24
-rw-r--r--src/test/msi/TestData/UtilExtensionGroupTests/ProductCommentFail/product_fail.wxs2
-rw-r--r--src/test/msi/TestData/UtilExtensionGroupTests/ProductFail/product_fail.wxs2
-rw-r--r--src/test/msi/TestData/UtilExtensionGroupTests/ProductNestedGroups/product.wxs6
-rw-r--r--src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionGroupTests.cs8
21 files changed, 736 insertions, 278 deletions
diff --git a/src/ext/Util/ca/scacost.h b/src/ext/Util/ca/scacost.h
index 978e40bc..d1086005 100644
--- a/src/ext/Util/ca/scacost.h
+++ b/src/ext/Util/ca/scacost.h
@@ -11,6 +11,8 @@ const UINT COST_USER_ADD = 10000;
11const UINT COST_USER_DELETE = 10000; 11const UINT COST_USER_DELETE = 10000;
12const UINT COST_GROUP_ADD = 10000; 12const UINT COST_GROUP_ADD = 10000;
13const UINT COST_GROUP_DELETE = 10000; 13const UINT COST_GROUP_DELETE = 10000;
14const UINT COST_GROUPMEMBERSHIP_ADD = 10000;
15const UINT COST_GROUPMEMBERSHIP_DELETE = 10000;
14 16
15const UINT COST_PERFMONMANIFEST_REGISTER = 1000; 17const UINT COST_PERFMONMANIFEST_REGISTER = 1000;
16const UINT COST_PERFMONMANIFEST_UNREGISTER = 1000; 18const UINT COST_PERFMONMANIFEST_UNREGISTER = 1000;
diff --git a/src/ext/Util/ca/scaexec.cpp b/src/ext/Util/ca/scaexec.cpp
index 5a750c6b..64f4c823 100644
--- a/src/ext/Util/ca/scaexec.cpp
+++ b/src/ext/Util/ca/scaexec.cpp
@@ -291,146 +291,6 @@ LExit:
291 return hr; 291 return hr;
292} 292}
293 293
294static HRESULT AddGroupToGroup(
295 __in LPWSTR wzMember,
296 __in LPCWSTR wzMemberDomain,
297 __in LPCWSTR wzGroup,
298 __in LPCWSTR wzGroupDomain
299)
300{
301 Assert(wzMember && *wzMember && wzMemberDomain && wzGroup && *wzGroup && wzGroupDomain);
302
303 HRESULT hr = S_OK;
304 IADsGroup* pGroup = NULL;
305 BSTR bstrMember = NULL;
306 BSTR bstrGroup = NULL;
307 LPWSTR pwzMember = NULL;
308 LPWSTR pwzServerName = NULL;
309 LOCALGROUP_MEMBERS_INFO_3 lgmi {};
310
311 GetDomainServerName(wzGroupDomain, &pwzServerName);
312
313 // Try adding it to the local group
314 if (wzMemberDomain)
315 {
316 hr = StrAllocFormatted(&pwzMember, L"%s\\%s", wzMemberDomain, wzMember);
317 ExitOnFailure(hr, "failed to allocate group domain string");
318 }
319
320 lgmi.lgrmi3_domainandname = (NULL == pwzMember ? wzMember : pwzMember);
321 NET_API_STATUS ui = ::NetLocalGroupAddMembers(pwzServerName, wzGroup, 3, reinterpret_cast<LPBYTE>(&lgmi), 1);
322 hr = HRESULT_FROM_WIN32(ui);
323 if (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr) // if they're already a member of the group don't report an error
324 {
325 hr = S_OK;
326 }
327
328 //
329 // If we failed, try active directory
330 //
331 if (FAILED(hr))
332 {
333 WcaLog(LOGMSG_VERBOSE, "Failed to add group: %ls, domain %ls to group: %ls, domain: %ls with error 0x%x. Attempting to use Active Directory", wzMember, wzMemberDomain, wzGroup, wzGroupDomain, hr);
334
335 hr = UserCreateADsPath(wzMemberDomain, wzMember, &bstrMember);
336 ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzMember, wzMemberDomain);
337
338 hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup);
339 ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzGroup, wzGroupDomain);
340
341 hr = ::ADsGetObject(bstrGroup, IID_IADsGroup, reinterpret_cast<void**>(&pGroup));
342 ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast<WCHAR*>(bstrGroup));
343
344 hr = pGroup->Add(bstrMember);
345 if ((HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hr) || (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr))
346 hr = S_OK;
347
348 ExitOnFailure(hr, "Failed to add group %ls to group '%ls'.", reinterpret_cast<WCHAR*>(bstrMember), reinterpret_cast<WCHAR*>(bstrGroup));
349 }
350
351LExit:
352 ReleaseStr(pwzServerName);
353 ReleaseStr(pwzMember);
354 ReleaseBSTR(bstrMember);
355 ReleaseBSTR(bstrGroup);
356 ReleaseObject(pGroup);
357
358 return hr;
359}
360
361static HRESULT RemoveGroupFromGroup(
362 __in LPWSTR wzMember,
363 __in LPCWSTR wzMemberDomain,
364 __in LPCWSTR wzGroup,
365 __in LPCWSTR wzGroupDomain
366)
367{
368 Assert(wzMember && *wzMember && wzMemberDomain && wzGroup && *wzGroup && wzGroupDomain);
369
370 HRESULT hr = S_OK;
371 IADsGroup* pGroup = NULL;
372 BSTR bstrMember = NULL;
373 BSTR bstrGroup = NULL;
374 LPWSTR pwzMember = NULL;
375 LPWSTR pwzServerName = NULL;
376 LOCALGROUP_MEMBERS_INFO_3 lgmi {};
377
378 GetDomainServerName(wzGroupDomain, &pwzServerName, DS_WRITABLE_REQUIRED);
379
380 // Try removing it from the local group
381 if (wzMemberDomain)
382 {
383 hr = StrAllocFormatted(&pwzMember, L"%s\\%s", wzMemberDomain, wzMember);
384 ExitOnFailure(hr, "failed to allocate group domain string");
385 }
386
387 lgmi.lgrmi3_domainandname = (NULL == pwzMember ? wzMember : pwzMember);
388 NET_API_STATUS ui = ::NetLocalGroupDelMembers(pwzServerName, wzGroup, 3, reinterpret_cast<LPBYTE>(&lgmi), 1);
389 hr = HRESULT_FROM_WIN32(ui);
390 if (HRESULT_FROM_WIN32(ERROR_MEMBER_NOT_IN_ALIAS) == hr
391 || HRESULT_FROM_WIN32(NERR_GroupNotFound) == hr
392 || HRESULT_FROM_WIN32(ERROR_NO_SUCH_MEMBER) == hr) // if they're already not a member of the group, or the group doesn't exist, don't report an error
393 {
394 hr = S_OK;
395 }
396
397 //
398 // If we failed, try active directory
399 //
400 if (FAILED(hr))
401 {
402 WcaLog(LOGMSG_VERBOSE, "Failed to remove group: %ls, domain %ls from group: %ls, domain: %ls with error 0x%x. Attempting to use Active Directory", wzMember, wzMemberDomain, wzGroup, wzGroupDomain, hr);
403
404 hr = UserCreateADsPath(wzMemberDomain, wzMember, &bstrMember);
405 ExitOnFailure(hr, "failed to create group ADsPath in order to remove group: %ls domain: %ls from a group", wzMember, wzMemberDomain);
406
407 hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup);
408 ExitOnFailure(hr, "failed to create group ADsPath in order to remove group from group: %ls domain: %ls", wzGroup, wzGroupDomain);
409
410 hr = ::ADsGetObject(bstrGroup, IID_IADsGroup, reinterpret_cast<void**>(&pGroup));
411 if ((HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)) // if parent group not found, no need to remove membership from group
412 {
413 hr = S_OK;
414 ExitFunction();
415 }
416 ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast<WCHAR*>(bstrGroup));
417
418 hr = pGroup->Remove(bstrMember);
419 if ((HRESULT_FROM_WIN32(ERROR_MEMBER_NOT_IN_ALIAS) == hr)) // if already not a member, no need to worry about error
420 hr = S_OK;
421 ExitOnFailure(hr, "Failed to remove group %ls from group '%ls'.", reinterpret_cast<WCHAR*>(bstrMember), reinterpret_cast<WCHAR*>(bstrGroup));
422 }
423
424LExit:
425 ReleaseStr(pwzServerName);
426 ReleaseStr(pwzMember);
427 ReleaseBSTR(bstrMember);
428 ReleaseBSTR(bstrGroup);
429 ReleaseObject(pGroup);
430
431 return hr;
432}
433
434static HRESULT GetUserHasRight( 294static HRESULT GetUserHasRight(
435 __in LSA_HANDLE hPolicy, 295 __in LSA_HANDLE hPolicy,
436 __in PSID pUserSid, 296 __in PSID pUserSid,
@@ -842,7 +702,6 @@ LExit:
842} 702}
843 703
844static HRESULT RemoveGroupInternal( 704static HRESULT RemoveGroupInternal(
845 LPWSTR wzGroupCaData,
846 LPWSTR wzDomain, 705 LPWSTR wzDomain,
847 LPWSTR wzName, 706 LPWSTR wzName,
848 int iAttributes 707 int iAttributes
@@ -850,9 +709,6 @@ static HRESULT RemoveGroupInternal(
850{ 709{
851 HRESULT hr = S_OK; 710 HRESULT hr = S_OK;
852 711
853 LPWSTR pwz = NULL;
854 LPWSTR pwzGroup = NULL;
855 LPWSTR pwzGroupDomain = NULL;
856 LPWSTR pwzServerName = NULL; 712 LPWSTR pwzServerName = NULL;
857 713
858 // 714 //
@@ -871,41 +727,9 @@ static HRESULT RemoveGroupInternal(
871 } 727 }
872 ExitOnFailure(hr, "failed to delete group: %ls", wzName); 728 ExitOnFailure(hr, "failed to delete group: %ls", wzName);
873 } 729 }
874 else
875 {
876 //
877 // Remove the group from other groups
878 //
879 pwz = wzGroupCaData;
880 while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup)))
881 {
882 hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain);
883 730
884 if (FAILED(hr))
885 {
886 WcaLogError(hr, "failed to get domain for group: %ls, continuing anyway.", pwzGroup);
887 }
888 else
889 {
890 hr = RemoveGroupFromGroup(wzName, wzDomain, pwzGroup, pwzGroupDomain);
891 if (FAILED(hr))
892 {
893 WcaLogError(hr, "failed to remove group: %ls from group %ls, continuing anyway.", wzName, pwzGroup);
894 }
895 }
896 }
897
898 if (E_NOMOREITEMS == hr) // if there are no more items, all is well
899 {
900 hr = S_OK;
901 }
902
903 ExitOnFailure(hr, "failed to get next group from which to remove group:%ls", wzName);
904 }
905LExit: 731LExit:
906 ReleaseStr(pwzServerName); 732 ReleaseStr(pwzServerName);
907 ReleaseStr(pwzGroup);
908 ReleaseStr(pwzGroupDomain);
909 733
910 return hr; 734 return hr;
911} 735}
@@ -1392,6 +1216,7 @@ LExit:
1392 return WcaFinalize(er); 1216 return WcaFinalize(er);
1393} 1217}
1394 1218
1219
1395/******************************************************************** 1220/********************************************************************
1396 CreateGroup - CUSTOM ACTION ENTRY POINT for creating groups 1221 CreateGroup - CUSTOM ACTION ENTRY POINT for creating groups
1397 1222
@@ -1412,8 +1237,6 @@ extern "C" UINT __stdcall CreateGroup(
1412 LPWSTR pwzDomain = NULL; 1237 LPWSTR pwzDomain = NULL;
1413 LPWSTR pwzComment = NULL; 1238 LPWSTR pwzComment = NULL;
1414 LPWSTR pwzScriptKey = NULL; 1239 LPWSTR pwzScriptKey = NULL;
1415 LPWSTR pwzGroup = NULL;
1416 LPWSTR pwzGroupDomain = NULL;
1417 int iAttributes = 0; 1240 int iAttributes = 0;
1418 BOOL fInitializedCom = FALSE; 1241 BOOL fInitializedCom = FALSE;
1419 1242
@@ -1553,24 +1376,6 @@ extern "C" UINT __stdcall CreateGroup(
1553 } 1376 }
1554 } 1377 }
1555 MessageExitOnFailure(hr, msierrGRPFailedGroupCreate, "failed to create group: %ls", pwzName); 1378 MessageExitOnFailure(hr, msierrGRPFailedGroupCreate, "failed to create group: %ls", pwzName);
1556
1557 //
1558 // Add the groups to groups
1559 //
1560 while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup)))
1561 {
1562 hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain);
1563 ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup);
1564
1565 WcaLog(LOGMSG_STANDARD, "Adding group %ls\\%ls to group %ls\\%ls", pwzDomain, pwzName, pwzGroupDomain, pwzGroup);
1566 hr = AddGroupToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain);
1567 MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add group: %ls to group %ls", pwzName, pwzGroup);
1568 }
1569 if (E_NOMOREITEMS == hr) // if there are no more items, all is well
1570 {
1571 hr = S_OK;
1572 }
1573 ExitOnFailure(hr, "failed to get next group in which to include group: %ls", pwzName);
1574 } 1379 }
1575 1380
1576LExit: 1381LExit:
@@ -1586,8 +1391,6 @@ LExit:
1586 ReleaseStr(pwzDomain); 1391 ReleaseStr(pwzDomain);
1587 ReleaseStr(pwzComment); 1392 ReleaseStr(pwzComment);
1588 ReleaseStr(pwzScriptKey); 1393 ReleaseStr(pwzScriptKey);
1589 ReleaseStr(pwzGroup);
1590 ReleaseStr(pwzGroupDomain);
1591 1394
1592 if (fInitializedCom) 1395 if (fInitializedCom)
1593 { 1396 {
@@ -1704,7 +1507,7 @@ extern "C" UINT __stdcall CreateGroupRollback(
1704 } 1507 }
1705 } 1508 }
1706 1509
1707 hr = RemoveGroupInternal(pwz, pwzDomain, pwzName, iAttributes); 1510 hr = RemoveGroupInternal(pwzDomain, pwzName, iAttributes);
1708 1511
1709LExit: 1512LExit:
1710 WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); 1513 WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE);
@@ -1781,7 +1584,7 @@ extern "C" UINT __stdcall RemoveGroup(
1781 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); 1584 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
1782 ExitOnFailure(hr, "failed to read attributes from custom action data"); 1585 ExitOnFailure(hr, "failed to read attributes from custom action data");
1783 1586
1784 hr = RemoveGroupInternal(pwz, pwzDomain, pwzName, iAttributes); 1587 hr = RemoveGroupInternal(pwzDomain, pwzName, iAttributes);
1785 1588
1786LExit: 1589LExit:
1787 ReleaseStr(pwzData); 1590 ReleaseStr(pwzData);
@@ -1801,3 +1604,254 @@ LExit:
1801 1604
1802 return WcaFinalize(er); 1605 return WcaFinalize(er);
1803} 1606}
1607
1608HRESULT AlterGroupMembership(bool remove, bool isRollback = false)
1609{
1610 HRESULT hr = S_OK;
1611 NET_API_STATUS er = ERROR_SUCCESS;
1612
1613 LPWSTR pwzData = NULL;
1614 LPWSTR pwz = NULL;
1615 LPWSTR pwzParentName = NULL;
1616 LPWSTR pwzParentDomain = NULL;
1617 LPWSTR pwzChildName = NULL;
1618 LPWSTR pwzChildDomain = NULL;
1619 int iAttributes = 0;
1620 LPWSTR pwzChildFullName = NULL;
1621 LPWSTR pwzServerName = NULL;
1622 LOCALGROUP_MEMBERS_INFO_3 memberInfo3 = {};
1623 WCA_CASCRIPT_HANDLE phRollbackScript = NULL;
1624
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 }
1636 ExitOnFailure(hr, "failed to get CustomActionData");
1637
1638 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData);
1639
1640 //
1641 // Read in the CustomActionData
1642 //
1643 pwz = pwzData;
1644 hr = WcaReadStringFromCaData(&pwz, &pwzParentName);
1645 ExitOnFailure(hr, "failed to read group name from custom action data");
1646
1647 hr = WcaReadStringFromCaData(&pwz, &pwzParentDomain);
1648 ExitOnFailure(hr, "failed to read domain from custom action data");
1649
1650 hr = WcaReadStringFromCaData(&pwz, &pwzChildName);
1651 ExitOnFailure(hr, "failed to read group comment from custom action data");
1652
1653 hr = WcaReadStringFromCaData(&pwz, &pwzChildDomain);
1654 ExitOnFailure(hr, "failed to read group comment from custom action data");
1655
1656 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
1657 ExitOnFailure(hr, "failed to read attributes from custom action data");
1658
1659 hr = GetDomainServerName(pwzParentDomain, &pwzServerName, DS_WRITABLE_REQUIRED);
1660 ExitOnFailure(hr, "failed to contact domain server %ls", pwzParentDomain);
1661
1662 if (*pwzChildDomain)
1663 {
1664 StrAllocFormatted(&pwzChildFullName, L"%ls\\%ls", pwzChildDomain, pwzChildName);
1665 }
1666 else
1667 {
1668 StrAllocFormatted(&pwzChildFullName, L"%ls", pwzChildName);
1669 }
1670 memberInfo3.lgrmi3_domainandname = pwzChildFullName;
1671
1672 if (remove)
1673 {
1674 er = ::NetLocalGroupDelMembers(pwzServerName, pwzParentName, 3, (LPBYTE)&memberInfo3, 1);
1675 }
1676 else
1677 {
1678 er = ::NetLocalGroupAddMembers(pwzServerName, pwzParentName, 3, (LPBYTE)&memberInfo3, 1);
1679 }
1680 hr = HRESULT_FROM_WIN32(er);
1681
1682 if (S_OK == hr && !isRollback)
1683 {
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);
1692 }
1693
1694 if (remove)
1695 {
1696 if (HRESULT_FROM_WIN32(NERR_GroupNotFound) == hr
1697 || HRESULT_FROM_WIN32(ERROR_NO_SUCH_MEMBER) == hr
1698 || HRESULT_FROM_WIN32(ERROR_MEMBER_NOT_IN_ALIAS) == hr)
1699 {
1700 hr = S_OK;
1701 }
1702 }
1703 else
1704 {
1705 if (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr)
1706 {
1707 hr = S_OK;
1708 }
1709 }
1710
1711LExit:
1712 ReleaseStr(pwzData);
1713 ReleaseStr(pwzParentName);
1714 ReleaseStr(pwzParentDomain);
1715 ReleaseStr(pwzChildName);
1716 ReleaseStr(pwzChildDomain);
1717 ReleaseStr(pwzChildFullName);
1718 ReleaseStr(pwzServerName);
1719
1720 if (SCAG_NON_VITAL & iAttributes)
1721 {
1722 return S_OK;
1723 }
1724 return hr;
1725}
1726
1727/********************************************************************
1728 AddGroupmembership - CUSTOM ACTION ENTRY POINT for creating groups
1729
1730 Input: deferred CustomActionData -
1731 ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes
1732 * *****************************************************************/
1733extern "C" UINT __stdcall AddGroupMembership(
1734 __in MSIHANDLE hInstall
1735)
1736{
1737 //AssertSz(0, "Debug AddGroupMembership");
1738
1739 HRESULT hr = S_OK;
1740
1741 BOOL fInitializedCom = FALSE;
1742
1743 hr = WcaInitialize(hInstall, "AddGroupMembership");
1744 ExitOnFailure(hr, "failed to initialize");
1745
1746 hr = ::CoInitialize(NULL);
1747 ExitOnFailure(hr, "failed to initialize COM");
1748 fInitializedCom = TRUE;
1749
1750 hr = AlterGroupMembership(false, false);
1751
1752LExit:
1753 if (fInitializedCom)
1754 {
1755 ::CoUninitialize();
1756 }
1757 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILED : ERROR_SUCCESS);
1758}
1759
1760/********************************************************************
1761 AddGroupmembership - CUSTOM ACTION ENTRY POINT for creating groups
1762
1763 Input: deferred CustomActionData -
1764 ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes
1765 * *****************************************************************/
1766extern "C" UINT __stdcall AddGroupMembershipRollback(
1767 __in MSIHANDLE hInstall
1768)
1769{
1770 //AssertSz(0, "Debug AddGroupMembershipRollback");
1771
1772 HRESULT hr = S_OK;
1773
1774 BOOL fInitializedCom = FALSE;
1775
1776 hr = WcaInitialize(hInstall, "AddGroupMembershipRollback");
1777 ExitOnFailure(hr, "failed to initialize");
1778
1779 hr = ::CoInitialize(NULL);
1780 ExitOnFailure(hr, "failed to initialize COM");
1781 fInitializedCom = TRUE;
1782
1783 hr = AlterGroupMembership(true, true);
1784
1785LExit:
1786 if (fInitializedCom)
1787 {
1788 ::CoUninitialize();
1789 }
1790 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILED : ERROR_SUCCESS);
1791}
1792
1793/********************************************************************
1794 RemoveGroupMembership - CUSTOM ACTION ENTRY POINT for creating groups
1795
1796 Input: deferred CustomActionData -
1797 ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes
1798 * *****************************************************************/
1799extern "C" UINT __stdcall RemoveGroupMembership(
1800 __in MSIHANDLE hInstall
1801)
1802{
1803 //AssertSz(0, "Debug RemoveGroupMembership");
1804
1805 HRESULT hr = S_OK;
1806
1807 BOOL fInitializedCom = FALSE;
1808
1809 hr = WcaInitialize(hInstall, "RemoveGroupMembership");
1810 ExitOnFailure(hr, "failed to initialize");
1811
1812 hr = ::CoInitialize(NULL);
1813 ExitOnFailure(hr, "failed to initialize COM");
1814 fInitializedCom = TRUE;
1815
1816 hr = AlterGroupMembership(true, false);
1817
1818LExit:
1819 if (fInitializedCom)
1820 {
1821 ::CoUninitialize();
1822 }
1823 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILED : ERROR_SUCCESS);
1824}
1825
1826/********************************************************************
1827 RemoveGroupMembershipRollback - CUSTOM ACTION ENTRY POINT for creating groups
1828
1829 Input: deferred CustomActionData -
1830 ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes
1831 * *****************************************************************/
1832extern "C" UINT __stdcall RemoveGroupMembershipRollback(
1833 __in MSIHANDLE hInstall
1834)
1835{
1836 //AssertSz(0, "Debug RemoveGroupMembershipRollback");
1837
1838 HRESULT hr = S_OK;
1839
1840 BOOL fInitializedCom = FALSE;
1841
1842 hr = WcaInitialize(hInstall, "RemoveGroupMembershipRollback");
1843 ExitOnFailure(hr, "failed to initialize");
1844
1845 hr = ::CoInitialize(NULL);
1846 ExitOnFailure(hr, "failed to initialize COM");
1847 fInitializedCom = TRUE;
1848
1849 hr = AlterGroupMembership(false, true);
1850
1851LExit:
1852 if (fInitializedCom)
1853 {
1854 ::CoUninitialize();
1855 }
1856 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILED : ERROR_SUCCESS);
1857}
diff --git a/src/ext/Util/ca/scagroup.cpp b/src/ext/Util/ca/scagroup.cpp
index c484c1d2..3d2c3beb 100644
--- a/src/ext/Util/ca/scagroup.cpp
+++ b/src/ext/Util/ca/scagroup.cpp
@@ -6,8 +6,11 @@
6LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Group`=?"; 6LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Group`=?";
7enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; 7enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain };
8 8
9LPCWSTR vcsGroupGroupQuery = L"SELECT `Parent_`, `Child_` FROM `Wix6GroupGroup` WHERE `Child_`=?"; 9LPCWSTR vcsGroupParentsQuery = L"SELECT `Parent_`,`Component_`,`Name`,`Domain`,`Child_` FROM `Wix6GroupGroup`,`Wix4Group` WHERE `Wix6GroupGroup`.`Parent_`=`Wix4Group`.`Group` AND `Wix6GroupGroup`.`Child_`=?";
10enum eGroupGroupQuery { vggqParent = 1, vggqChild }; 10enum eGroupParentsQuery { vgpqParent = 1, vgpqParentComponent, vgpqParentName, vgpqParentDomain, vgpqChild };
11
12LPCWSTR vcsGroupChildrenQuery = L"SELECT `Parent_`,`Child_`,`Component_`,`Name`,`Domain` FROM `Wix6GroupGroup`,`Wix4Group` WHERE `Wix6GroupGroup`.`Child_`=`Wix4Group`.`Group` AND `Wix6GroupGroup`.`Parent_`=?";
13enum eGroupChildrenQuery { vgcqParent = 1, vgcqChild, vgcqChildComponent, vgcqChildName, vgcqChildDomain };
11 14
12LPCWSTR vActionableGroupQuery = L"SELECT `Group`,`Component_`,`Name`,`Domain`,`Comment`,`Attributes` FROM `Wix4Group`,`Wix6Group` WHERE `Component_` IS NOT NULL AND `Group`=`Group_`"; 15LPCWSTR vActionableGroupQuery = L"SELECT `Group`,`Component_`,`Name`,`Domain`,`Comment`,`Attributes` FROM `Wix4Group`,`Wix6Group` WHERE `Component_` IS NOT NULL AND `Group`=`Group_`";
13enum eActionableGroupQuery { vagqGroup = 1, vagqComponent, vagqName, vagqDomain, vagqComment, vagqAttributes }; 16enum eActionableGroupQuery { vagqGroup = 1, vagqComponent, vagqName, vagqDomain, vagqComment, vagqAttributes };
@@ -16,7 +19,6 @@ static HRESULT AddGroupToList(
16 __inout SCA_GROUP** ppsgList 19 __inout SCA_GROUP** ppsgList
17 ); 20 );
18 21
19
20HRESULT __stdcall ScaGetGroup( 22HRESULT __stdcall ScaGetGroup(
21 __in LPCWSTR wzGroup, 23 __in LPCWSTR wzGroup,
22 __out SCA_GROUP* pscag 24 __out SCA_GROUP* pscag
@@ -160,11 +162,149 @@ void ScaGroupFreeList(
160 { 162 {
161 psgDelete = psgList; 163 psgDelete = psgList;
162 psgList = psgList->psgNext; 164 psgList = psgList->psgNext;
165 ScaGroupFreeList(psgDelete->psgParents);
166 ScaGroupFreeList(psgDelete->psgChildren);
163 167
164 MemFree(psgDelete); 168 MemFree(psgDelete);
165 } 169 }
166} 170}
167 171
172HRESULT ScaGroupGetParents(
173 __inout SCA_GROUP* psg
174)
175{
176 HRESULT hr = S_OK;
177 UINT er = ERROR_SUCCESS;
178 SCA_GROUP* psgParent = NULL;
179 PMSIHANDLE hView, hParamRec, hRec;
180 LPWSTR pwzTempStr = NULL;
181
182 if (S_OK != WcaTableExists(L"Wix6GroupGroup"))
183 {
184 WcaLog(LOGMSG_VERBOSE, "Wix6GroupGroup Table does not exist, exiting");
185 ExitFunction1(hr = S_FALSE);
186 }
187
188 // setup the query parameter record
189 hParamRec = ::MsiCreateRecord(1);
190 hr = WcaSetRecordString(hParamRec, 1, psg->wzKey);
191
192 //
193 // loop through all the groups
194 //
195 hr = WcaOpenView(vcsGroupParentsQuery, &hView);
196 ExitOnFailure(hr, "failed to open view on Wix6GroupGroup,Wix4Group table(s)");
197 hr = WcaExecuteView(hView, hParamRec);
198 ExitOnFailure(hr, "failed to open view on Wix4Group,Wix6Group table(s)");
199 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
200 {
201 hr = AddGroupToList(&psg->psgParents);
202 ExitOnFailure(hr, "failed to add group to list");
203
204 psgParent = psg->psgParents;
205
206 if (::MsiRecordIsNull(hRec, vgcqChildComponent))
207 {
208 psgParent->isInstalled = INSTALLSTATE_NOTUSED;
209 psgParent->isAction = INSTALLSTATE_NOTUSED;
210 }
211 else
212 {
213 hr = WcaGetRecordString(hRec, vgpqParentComponent, &pwzTempStr);
214 ExitOnFailure(hr, "failed to get Wix4Group.Component");
215 wcsncpy_s(psgParent->wzComponent, pwzTempStr, MAX_DARWIN_KEY);
216 ReleaseNullStr(pwzTempStr);
217
218 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), psgParent->wzComponent, &psgParent->isInstalled, &psgParent->isAction);
219 hr = HRESULT_FROM_WIN32(er);
220 ExitOnFailure(hr, "failed to get Component state for Wix4Group");
221 }
222
223 hr = WcaGetRecordString(hRec, vgpqParentName, &pwzTempStr);
224 ExitOnFailure(hr, "failed to get Wix4Group.Name");
225 wcsncpy_s(psgParent->wzName, pwzTempStr, MAX_DARWIN_COLUMN);
226 ReleaseNullStr(pwzTempStr);
227
228
229 hr = WcaGetRecordString(hRec, vgpqParentDomain, &pwzTempStr);
230 ExitOnFailure(hr, "failed to get Wix4Group.Domain");
231 wcsncpy_s(psgParent->wzDomain, pwzTempStr, MAX_DARWIN_COLUMN);
232 ReleaseNullStr(pwzTempStr);
233 }
234
235LExit:
236 ReleaseNullStr(pwzTempStr);
237 return hr;
238}
239
240HRESULT ScaGroupGetChildren(
241 __inout SCA_GROUP* psg
242)
243{
244 HRESULT hr = S_OK;
245 UINT er = ERROR_SUCCESS;
246 SCA_GROUP* psgChild = NULL;
247 PMSIHANDLE hView, hParamRec, hRec;
248 LPWSTR pwzTempStr = NULL;
249
250 if (S_OK != WcaTableExists(L"Wix6GroupGroup"))
251 {
252 WcaLog(LOGMSG_VERBOSE, "Wix6GroupGroup Table does not exist, exiting");
253 ExitFunction1(hr = S_FALSE);
254 }
255
256 // setup the query parameter record
257 hParamRec = ::MsiCreateRecord(1);
258 hr = WcaSetRecordString(hParamRec, 1, psg->wzKey);
259
260 //
261 // loop through all the groups
262 //
263 hr = WcaOpenView(vcsGroupChildrenQuery, &hView);
264 ExitOnFailure(hr, "failed to open view on Wix6GroupGroup,Wix4Group table(s)");
265 hr = WcaExecuteView(hView, hParamRec);
266 ExitOnFailure(hr, "failed to open view on Wix4Group,Wix6Group table(s)");
267 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
268 {
269 hr = AddGroupToList(&psg->psgChildren);
270 ExitOnFailure(hr, "failed to add group to list");
271
272 psgChild = psg->psgChildren;
273
274 if (::MsiRecordIsNull(hRec, vgcqChildComponent))
275 {
276 psgChild->isInstalled = INSTALLSTATE_NOTUSED;
277 psgChild->isAction = INSTALLSTATE_NOTUSED;
278 }
279 else
280 {
281 hr = WcaGetRecordString(hRec, vgcqChildComponent, &pwzTempStr);
282 ExitOnFailure(hr, "failed to get Wix4Group.Component");
283 wcsncpy_s(psgChild->wzComponent, pwzTempStr, MAX_DARWIN_KEY);
284 ReleaseNullStr(pwzTempStr);
285
286 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), psgChild->wzComponent, &psgChild->isInstalled, &psgChild->isAction);
287 hr = HRESULT_FROM_WIN32(er);
288 ExitOnFailure(hr, "failed to get Component state for Wix4Group");
289 }
290
291 hr = WcaGetRecordString(hRec, vgcqChildName, &pwzTempStr);
292 ExitOnFailure(hr, "failed to get Wix4Group.Name");
293 wcsncpy_s(psgChild->wzName, pwzTempStr, MAX_DARWIN_COLUMN);
294 ReleaseNullStr(pwzTempStr);
295
296
297 hr = WcaGetRecordString(hRec, vgcqChildDomain, &pwzTempStr);
298 ExitOnFailure(hr, "failed to get Wix4Group.Domain");
299 wcsncpy_s(psgChild->wzDomain, pwzTempStr, MAX_DARWIN_COLUMN);
300 ReleaseNullStr(pwzTempStr);
301 }
302
303LExit:
304 ReleaseNullStr(pwzTempStr);
305 return hr;
306}
307
168 308
169HRESULT ScaGroupRead( 309HRESULT ScaGroupRead(
170 __out SCA_GROUP** ppsgList 310 __out SCA_GROUP** ppsgList
@@ -179,7 +319,7 @@ HRESULT ScaGroupRead(
179 319
180 LPWSTR pwzData = NULL; 320 LPWSTR pwzData = NULL;
181 321
182 BOOL fGroupGroupExists = FALSE; 322 //BOOL fGroupGroupExists = FALSE;
183 323
184 SCA_GROUP *psg = NULL; 324 SCA_GROUP *psg = NULL;
185 325
@@ -196,11 +336,6 @@ HRESULT ScaGroupRead(
196 ExitFunction1(hr = S_FALSE); 336 ExitFunction1(hr = S_FALSE);
197 } 337 }
198 338
199 if (S_OK == WcaTableExists(L"Wix6GroupGroup"))
200 {
201 fGroupGroupExists = TRUE;
202 }
203
204 // 339 //
205 // loop through all the groups 340 // loop through all the groups
206 // 341 //
@@ -230,21 +365,26 @@ HRESULT ScaGroupRead(
230 psg->isAction = isAction; 365 psg->isAction = isAction;
231 hr = ::StringCchCopyW(psg->wzComponent, countof(psg->wzComponent), pwzData); 366 hr = ::StringCchCopyW(psg->wzComponent, countof(psg->wzComponent), pwzData);
232 ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); 367 ExitOnFailure(hr, "failed to copy component name: %ls", pwzData);
368 ReleaseNullStr(pwzData);
233 369
234 hr = WcaGetRecordString(hRec, vagqGroup, &pwzData); 370 hr = WcaGetRecordString(hRec, vagqGroup, &pwzData);
235 ExitOnFailure(hr, "failed to get Wix4Group.Group"); 371 ExitOnFailure(hr, "failed to get Wix4Group.Group");
236 hr = ::StringCchCopyW(psg->wzKey, countof(psg->wzKey), pwzData); 372 hr = ::StringCchCopyW(psg->wzKey, countof(psg->wzKey), pwzData);
237 ExitOnFailure(hr, "failed to copy group key: %ls", pwzData); 373 ExitOnFailure(hr, "failed to copy group key: %ls", pwzData);
374 ReleaseNullStr(pwzData);
238 375
239 hr = WcaGetRecordFormattedString(hRec, vagqName, &pwzData); 376 hr = WcaGetRecordFormattedString(hRec, vagqName, &pwzData);
240 ExitOnFailure(hr, "failed to get Wix4Group.Name"); 377 ExitOnFailure(hr, "failed to get Wix4Group.Name");
241 hr = ::StringCchCopyW(psg->wzName, countof(psg->wzName), pwzData); 378 hr = ::StringCchCopyW(psg->wzName, countof(psg->wzName), pwzData);
242 ExitOnFailure(hr, "failed to copy group name: %ls", pwzData); 379 ExitOnFailure(hr, "failed to copy group name: %ls", pwzData);
380 ReleaseNullStr(pwzData);
243 381
244 hr = WcaGetRecordFormattedString(hRec, vagqDomain, &pwzData); 382 hr = WcaGetRecordFormattedString(hRec, vagqDomain, &pwzData);
245 ExitOnFailure(hr, "failed to get Wix4Group.Domain"); 383 ExitOnFailure(hr, "failed to get Wix4Group.Domain");
246 hr = ::StringCchCopyW(psg->wzDomain, countof(psg->wzDomain), pwzData); 384 hr = ::StringCchCopyW(psg->wzDomain, countof(psg->wzDomain), pwzData);
247 ExitOnFailure(hr, "failed to copy group domain: %ls", pwzData); 385 ExitOnFailure(hr, "failed to copy group domain: %ls", pwzData);
386 ReleaseNullStr(pwzData);
387
248 hr = WcaGetRecordFormattedString(hRec, vagqComment, &pwzData); 388 hr = WcaGetRecordFormattedString(hRec, vagqComment, &pwzData);
249 ExitOnFailure(hr, "failed to get Wix6Group.Comment"); 389 ExitOnFailure(hr, "failed to get Wix6Group.Comment");
250 hr = ::StringCchCopyW(psg->wzComment, countof(psg->wzComment), pwzData); 390 hr = ::StringCchCopyW(psg->wzComment, countof(psg->wzComment), pwzData);
@@ -253,36 +393,9 @@ HRESULT ScaGroupRead(
253 hr = WcaGetRecordInteger(hRec, vagqAttributes, &psg->iAttributes); 393 hr = WcaGetRecordInteger(hRec, vagqAttributes, &psg->iAttributes);
254 ExitOnFailure(hr, "failed to get Wix6Group.Attributes"); 394 ExitOnFailure(hr, "failed to get Wix6Group.Attributes");
255 395
256 // Check if this group is to be added to any other groups 396 ScaGroupGetParents(psg);
257 if (fGroupGroupExists)
258 {
259 hGroupRec = ::MsiCreateRecord(1);
260 hr = WcaSetRecordString(hGroupRec, 1, psg->wzKey);
261 ExitOnFailure(hr, "Failed to create group record for querying Wix6GroupGroup table");
262
263 hr = WcaOpenExecuteView(vcsGroupGroupQuery, &hGroupGroupView);
264 ExitOnFailure(hr, "Failed to open view on Wix6GroupGroup table for group %ls", psg->wzKey);/*
265 hr = WcaExecuteView(hGroupGroupView, hGroupRec);
266 ExitOnFailure(hr, "Failed to execute view on Wix6GroupGroup table for group: %ls", psg->wzKey);*/
267 397
268 while (S_OK == (hr = WcaFetchRecord(hGroupGroupView, &hRec))) 398 ScaGroupGetChildren(psg);
269 {
270 hr = WcaGetRecordString(hRec, vggqParent, &pwzData);
271 ExitOnFailure(hr, "failed to get Wix6GroupGroup.Parent");
272
273 hr = AddGroupToList(&(psg->psgGroups));
274 ExitOnFailure(hr, "failed to add group to list");
275
276 hr = ScaGetGroup(pwzData, psg->psgGroups);
277 ExitOnFailure(hr, "failed to get information for group: %ls", pwzData);
278 }
279
280 if (E_NOMOREITEMS == hr)
281 {
282 hr = S_OK;
283 }
284 ExitOnFailure(hr, "failed to enumerate selected rows from Wix4UserGroup table");
285 }
286 } 399 }
287 } 400 }
288 401
@@ -301,7 +414,6 @@ LExit:
301/* **************************************************************** 414/* ****************************************************************
302ScaGroupExecute - Schedules group account creation or removal based on 415ScaGroupExecute - Schedules group account creation or removal based on
303component state. 416component state.
304
305******************************************************************/ 417******************************************************************/
306HRESULT ScaGroupExecute( 418HRESULT ScaGroupExecute(
307 __in SCA_GROUP *psgList 419 __in SCA_GROUP *psgList
@@ -428,7 +540,7 @@ HRESULT ScaGroupExecute(
428 hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); 540 hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData);
429 ExitOnFailure(hr, "failed to add group attributes to rollback custom action data for group: %ls", psg->wzKey); 541 ExitOnFailure(hr, "failed to add group attributes to rollback custom action data for group: %ls", psg->wzKey);
430 542
431 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateGroupRollback"), pwzRollbackData, COST_GROUP_DELETE); 543 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"CreateGroupRollback"), pwzRollbackData, COST_GROUP_DELETE);
432 ExitOnFailure(hr, "failed to schedule CreateGroupRollback"); 544 ExitOnFailure(hr, "failed to schedule CreateGroupRollback");
433 } 545 }
434 else 546 else
@@ -441,7 +553,7 @@ HRESULT ScaGroupExecute(
441 // 553 //
442 // Schedule the creation now. 554 // Schedule the creation now.
443 // 555 //
444 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateGroup"), pwzActionData, COST_GROUP_ADD); 556 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"CreateGroup"), pwzActionData, COST_GROUP_ADD);
445 ExitOnFailure(hr, "failed to schedule CreateGroup"); 557 ExitOnFailure(hr, "failed to schedule CreateGroup");
446 } 558 }
447 else if (((GROUP_EXISTS_YES == geGroupExists) 559 else if (((GROUP_EXISTS_YES == geGroupExists)
@@ -457,7 +569,7 @@ HRESULT ScaGroupExecute(
457 // 569 //
458 // Note: We can't rollback the removal of a group which is why RemoveGroup is a commit 570 // Note: We can't rollback the removal of a group which is why RemoveGroup is a commit
459 // CustomAction. 571 // CustomAction.
460 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RemoveGroup"), pwzActionData, COST_GROUP_DELETE); 572 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"RemoveGroup"), pwzActionData, COST_GROUP_DELETE);
461 ExitOnFailure(hr, "failed to schedule RemoveGroup"); 573 ExitOnFailure(hr, "failed to schedule RemoveGroup");
462 } 574 }
463 575
@@ -501,3 +613,219 @@ static HRESULT AddGroupToList(
501LExit: 613LExit:
502 return hr; 614 return hr;
503} 615}
616
617/* ****************************************************************
618ScaGroupMembershipRemoveParentsExecute - Schedules group membership removal
619based on parent/child component state
620******************************************************************/
621HRESULT ScaGroupMembershipRemoveParentsExecute(
622 __in SCA_GROUP* psg
623)
624{
625 HRESULT hr = S_OK;
626 LPWSTR pwzActionData = NULL;
627
628 for (SCA_GROUP* psgp = psg->psgParents; psgp; psgp = psgp->psgNext)
629 {
630 Assert(psgp->wzName);
631 if (WcaIsUninstalling(psg->isInstalled, psg->isAction)
632 || WcaIsUninstalling(psgp->isInstalled, psgp->isAction))
633 {
634 hr = WcaWriteStringToCaData(psgp->wzName, &pwzActionData);
635 ExitOnFailure(hr, "Failed to add parent group name to custom action data: %ls", psgp->wzName);
636 hr = WcaWriteStringToCaData(psgp->wzDomain, &pwzActionData);
637 ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psgp->wzDomain);
638 hr = WcaWriteStringToCaData(psg->wzName, &pwzActionData);
639 ExitOnFailure(hr, "Failed to add child group name to custom action data: %ls", psg->wzName);
640 hr = WcaWriteStringToCaData(psg->wzDomain, &pwzActionData);
641 ExitOnFailure(hr, "Failed to add child group domain to custom action data: %ls", psg->wzDomain);
642 hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData);
643 ExitOnFailure(hr, "Failed to add group attributes to custom action data: %i", psg->iAttributes);
644 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"RemoveGroupMembership"), pwzActionData, COST_GROUPMEMBERSHIP_DELETE);
645
646 LExit:
647 ReleaseNullStr(pwzActionData);
648 if (hr != S_OK && !(psg->iAttributes & SCAG_NON_VITAL))
649 {
650 return hr;
651 }
652 }
653 }
654 return S_OK;
655}
656
657/* ****************************************************************
658ScaGroupMembershipRemoveChildrenExecute -
659******************************************************************/
660HRESULT ScaGroupMembershipRemoveChildrenExecute(
661 __in SCA_GROUP* psg
662)
663{
664 HRESULT hr = S_OK;
665 LPWSTR pwzActionData = NULL;
666
667 for (SCA_GROUP* psgc = psg->psgChildren; psgc; psgc = psgc->psgNext)
668 {
669 Assert(psgc->wzName);
670 if (WcaIsUninstalling(psg->isInstalled, psg->isAction)
671 || WcaIsUninstalling(psgc->isInstalled, psgc->isAction))
672 {
673 hr = WcaWriteStringToCaData(psg->wzName, &pwzActionData);
674 ExitOnFailure(hr, "Failed to add parent group name to custom action data: %ls", psg->wzName);
675 hr = WcaWriteStringToCaData(psg->wzDomain, &pwzActionData);
676 ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psg->wzDomain);
677 hr = WcaWriteStringToCaData(psgc->wzName, &pwzActionData);
678 ExitOnFailure(hr, "Failed to add child group name to custom action data: %ls", psgc->wzName);
679 hr = WcaWriteStringToCaData(psgc->wzDomain, &pwzActionData);
680 ExitOnFailure(hr, "Failed to add child group domain to custom action data: %ls", psgc->wzDomain);
681 hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData);
682 ExitOnFailure(hr, "Failed to add group attributes to custom action data: %i", psg->iAttributes);
683 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"RemoveGroupMembership"), pwzActionData, COST_GROUPMEMBERSHIP_DELETE);
684
685 LExit:
686 ReleaseNullStr(pwzActionData);
687
688 if (hr != S_OK && !(psg->iAttributes & SCAG_NON_VITAL))
689 {
690 return hr;
691 }
692 }
693 }
694 return S_OK;
695}
696
697/* ****************************************************************
698ScaGroupMembershipRemoveExecute - Schedules group membership removal
699based on parent/child component state
700******************************************************************/
701HRESULT ScaGroupMembershipRemoveExecute(
702 __in SCA_GROUP* psgList
703)
704{
705 HRESULT hr = S_OK;
706
707 // Loop through all the users to be configured.
708 for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext)
709 {
710 Assert(psg->wzName);
711 // first we loop through the Parents
712 hr = ScaGroupMembershipRemoveParentsExecute(psg);
713 ExitOnFailure(hr, "Failed to remove parent membership for vital group: %ls", psg->wzKey);
714
715 // then through the Children
716 hr = ScaGroupMembershipRemoveChildrenExecute(psg);
717 ExitOnFailure(hr, "Failed to remove child membership for vital group: %ls", psg->wzKey);
718 }
719
720LExit:
721 return hr;
722}
723
724/* ****************************************************************
725ScaGroupMembershipAddParentsExecute - Schedules group membership removal
726based on parent/child component state
727******************************************************************/
728HRESULT ScaGroupMembershipAddParentsExecute(
729 __in SCA_GROUP* psg
730)
731{
732 HRESULT hr = S_OK;
733 LPWSTR pwzActionData = NULL;
734
735 for (SCA_GROUP* psgp = psg->psgParents; psgp; psgp = psgp->psgNext)
736 {
737 Assert(psgp->wzName);
738 if (WcaIsInstalling(psg->isInstalled, psg->isAction)
739 || WcaIsInstalling(psgp->isInstalled, psgp->isAction))
740 {
741 hr = WcaWriteStringToCaData(psgp->wzName, &pwzActionData);
742 ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psgp->wzName);
743 hr = WcaWriteStringToCaData(psgp->wzDomain, &pwzActionData);
744 ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psgp->wzDomain);
745 hr = WcaWriteStringToCaData(psg->wzName, &pwzActionData);
746 ExitOnFailure(hr, "Failed to add child group name to custom action data: %ls", psg->wzName);
747 hr = WcaWriteStringToCaData(psg->wzDomain, &pwzActionData);
748 ExitOnFailure(hr, "Failed to add child group domain to custom action data: %ls", psg->wzDomain);
749 hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData);
750 ExitOnFailure(hr, "Failed to add group attributes to custom action data: %i", psg->iAttributes);
751 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"AddGroupMembership"), pwzActionData, COST_GROUPMEMBERSHIP_ADD);
752
753 LExit:
754 ReleaseNullStr(pwzActionData);
755
756 if (hr != S_OK && !(psg->iAttributes & SCAG_NON_VITAL))
757 {
758 return hr;
759 }
760 }
761 }
762 return S_OK;
763}
764
765/* ****************************************************************
766ScaGroupMembershipAddChildrenExecute - Schedules group membership removal
767based on parent/child component state
768******************************************************************/
769HRESULT ScaGroupMembershipAddChildrenExecute(
770 __in SCA_GROUP* psg
771)
772{
773 HRESULT hr = S_OK;
774 LPWSTR pwzActionData = NULL;
775
776 // then through the Children
777 for (SCA_GROUP* psgc = psg->psgChildren; psgc; psgc = psgc->psgNext)
778 {
779 Assert(psgc->wzName);
780 if (WcaIsInstalling(psg->isInstalled, psg->isAction)
781 || WcaIsInstalling(psgc->isInstalled, psgc->isAction))
782 {
783 hr = WcaWriteStringToCaData(psg->wzName, &pwzActionData);
784 ExitOnFailure(hr, "Failed to add child group name to custom action data: %ls", psg->wzName);
785 hr = WcaWriteStringToCaData(psg->wzDomain, &pwzActionData);
786 ExitOnFailure(hr, "Failed to add child group domain to custom action data: %ls", psg->wzDomain);
787 hr = WcaWriteStringToCaData(psgc->wzName, &pwzActionData);
788 ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psgc->wzName);
789 hr = WcaWriteStringToCaData(psgc->wzDomain, &pwzActionData);
790 ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psgc->wzDomain);
791 hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData);
792 ExitOnFailure(hr, "Failed to add group attributes to custom action data: %i", psg->iAttributes);
793 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"AddGroupMembership"), pwzActionData, COST_GROUPMEMBERSHIP_ADD);
794
795 LExit:
796 ReleaseNullStr(pwzActionData);
797 if (hr != S_OK && !(psg->iAttributes & SCAG_NON_VITAL))
798 {
799 return hr;
800 }
801 }
802 }
803 return S_OK;
804}
805
806/* ****************************************************************
807ScaGroupMembershipAddExecute - Schedules group membership addition
808based on parent/child component state
809******************************************************************/
810HRESULT ScaGroupMembershipAddExecute(
811 __in SCA_GROUP* psgList
812)
813{
814 HRESULT hr = S_OK;
815
816 // Loop through all the users to be configured.
817 for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext)
818 {
819 Assert(psg->wzName);
820 // first we loop through the Parents
821 hr = ScaGroupMembershipAddParentsExecute(psg);
822 ExitOnFailure(hr, "Failed to add parent membership for vital group: %ls", psg->wzKey);
823
824 // then through the Children
825 hr = ScaGroupMembershipAddChildrenExecute(psg);
826 ExitOnFailure(hr, "Failed to add child membership for vital group: %ls", psg->wzKey);
827 }
828
829LExit:
830 return hr;
831}
diff --git a/src/ext/Util/ca/scagroup.h b/src/ext/Util/ca/scagroup.h
index 8666d852..e16d7a95 100644
--- a/src/ext/Util/ca/scagroup.h
+++ b/src/ext/Util/ca/scagroup.h
@@ -21,11 +21,13 @@ struct SCA_GROUP
21 WCHAR wzComment[MAX_DARWIN_COLUMN + 1]; 21 WCHAR wzComment[MAX_DARWIN_COLUMN + 1];
22 INT iAttributes; 22 INT iAttributes;
23 23
24 SCA_GROUP* psgGroups; 24 SCA_GROUP* psgParents;
25 SCA_GROUP* psgChildren;
25 26
26 SCA_GROUP *psgNext; 27 SCA_GROUP *psgNext;
27}; 28};
28 29
30
29// prototypes 31// prototypes
30HRESULT __stdcall ScaGetGroup( 32HRESULT __stdcall ScaGetGroup(
31 __in LPCWSTR wzGroup, 33 __in LPCWSTR wzGroup,
@@ -42,6 +44,12 @@ void ScaGroupFreeList(
42HRESULT ScaGroupRead( 44HRESULT ScaGroupRead(
43 __inout SCA_GROUP** ppsgList 45 __inout SCA_GROUP** ppsgList
44 ); 46 );
47HRESULT ScaGroupMembershipRemoveExecute(
48 __in SCA_GROUP* psgList
49 );
50HRESULT ScaGroupMembershipAddExecute(
51 __in SCA_GROUP* psgList
52);
45HRESULT ScaGroupExecute( 53HRESULT ScaGroupExecute(
46 __in SCA_GROUP*psgList 54 __in SCA_GROUP*psgList
47 ); 55 );
diff --git a/src/ext/Util/ca/scanet.cpp b/src/ext/Util/ca/scanet.cpp
index 11ee487d..a8ad0316 100644
--- a/src/ext/Util/ca/scanet.cpp
+++ b/src/ext/Util/ca/scanet.cpp
@@ -1,7 +1,6 @@
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. 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 2
3#include "precomp.h" 3#include "precomp.h"
4#include "scanet.h"
5 4
6 5
7HRESULT GetDomainServerName(LPCWSTR pwzDomain, LPWSTR* ppwzServerName, ULONG flags) 6HRESULT GetDomainServerName(LPCWSTR pwzDomain, LPWSTR* ppwzServerName, ULONG flags)
@@ -25,16 +24,16 @@ HRESULT GetDomainServerName(LPCWSTR pwzDomain, LPWSTR* ppwzServerName, ULONG fla
25 if ('\\' == *pDomainControllerInfo->DomainControllerName && '\\' == *pDomainControllerInfo->DomainControllerName + 1) 24 if ('\\' == *pDomainControllerInfo->DomainControllerName && '\\' == *pDomainControllerInfo->DomainControllerName + 1)
26 { 25 {
27 hr = StrAllocString(ppwzServerName, pDomainControllerInfo->DomainControllerName + 2, 0); 26 hr = StrAllocString(ppwzServerName, pDomainControllerInfo->DomainControllerName + 2, 0);
28 ExitOnFailure(hr, "failed to allocate memory for string");
29 } 27 }
30 else 28 else
31 { 29 {
32 hr = StrAllocString(ppwzServerName, pDomainControllerInfo->DomainControllerName, 0); 30 hr = StrAllocString(ppwzServerName, pDomainControllerInfo->DomainControllerName, 0);
33 ExitOnFailure(hr, "failed to allocate memory for string");
34 } 31 }
32 ExitOnFailure(hr, "failed to allocate memory for string");
35 } 33 }
36 else 34 else
37 { 35 {
36 // we won't report any potential string allocation failure, the domain failure is more interesting
38 StrAllocString(ppwzServerName, pwzDomain, 0); 37 StrAllocString(ppwzServerName, pwzDomain, 0);
39 hr = HRESULT_FROM_WIN32(er); 38 hr = HRESULT_FROM_WIN32(er);
40 ExitOnFailure(hr, "failed to contact domain %ls", pwzDomain); 39 ExitOnFailure(hr, "failed to contact domain %ls", pwzDomain);
diff --git a/src/ext/Util/ca/scasched.cpp b/src/ext/Util/ca/scasched.cpp
index 1351fbfd..cef7fecb 100644
--- a/src/ext/Util/ca/scasched.cpp
+++ b/src/ext/Util/ca/scasched.cpp
@@ -153,9 +153,15 @@ extern "C" UINT __stdcall ConfigureGroups(
153 hr = ScaGroupRead(&psgList); 153 hr = ScaGroupRead(&psgList);
154 ExitOnFailure(hr, "failed to read Wix4Group,Wix6Group table(s)"); 154 ExitOnFailure(hr, "failed to read Wix4Group,Wix6Group table(s)");
155 155
156 hr = ScaGroupMembershipRemoveExecute(psgList);
157 ExitOnFailure(hr, "failed to remove Group Memberships")
158
156 hr = ScaGroupExecute(psgList); 159 hr = ScaGroupExecute(psgList);
157 ExitOnFailure(hr, "failed to add/remove Group actions"); 160 ExitOnFailure(hr, "failed to add/remove Group actions");
158 161
162 hr = ScaGroupMembershipAddExecute(psgList);
163 ExitOnFailure(hr, "failed to add Group Memberships")
164
159LExit: 165LExit:
160 if (psgList) 166 if (psgList)
161 { 167 {
diff --git a/src/ext/Util/ca/utilca.def b/src/ext/Util/ca/utilca.def
index 18a19d12..2aeb54f4 100644
--- a/src/ext/Util/ca/utilca.def
+++ b/src/ext/Util/ca/utilca.def
@@ -46,6 +46,10 @@ EXPORTS
46 CreateGroup 46 CreateGroup
47 CreateGroupRollback 47 CreateGroupRollback
48 RemoveGroup 48 RemoveGroup
49 AddGroupMembership
50 AddGroupMembershipRollback
51 RemoveGroupMembership
52 RemoveGroupMembershipRollback
49 CreateUser 53 CreateUser
50 CreateUserRollback 54 CreateUserRollback
51 RemoveUser 55 RemoveUser
diff --git a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs
index d71dd824..c9a184ab 100644
--- a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs
+++ b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs
@@ -404,10 +404,10 @@ namespace WixToolsetTest.Util
404 WixAssert.CompareLineByLine(new[] 404 WixAssert.CompareLineByLine(new[]
405 { 405 {
406 "Binary:Wix4UtilCA_X64\t[Binary data]", 406 "Binary:Wix4UtilCA_X64\t[Binary data]",
407 "CustomAction:Wix4ConfigureGroups_X64\t1\tWix4UtilCA_X64\tConfigureGroups\t", 407 "CustomAction:Wix6ConfigureGroups_X64\t1\tWix4UtilCA_X64\tConfigureGroups\t",
408 "CustomAction:Wix4CreateGroup_X64\t11265\tWix4UtilCA_X64\tCreateGroup\t", 408 "CustomAction:Wix6CreateGroup_X64\t3073\tWix4UtilCA_X64\tCreateGroup\t",
409 "CustomAction:Wix4CreateGroupRollback_X64\t11521\tWix4UtilCA_X64\tCreateGroupRollback\t", 409 "CustomAction:Wix6CreateGroupRollback_X64\t3329\tWix4UtilCA_X64\tCreateGroupRollback\t",
410 "CustomAction:Wix4RemoveGroup_X64\t11841\tWix4UtilCA_X64\tRemoveGroup\t", 410 "CustomAction:Wix6RemoveGroup_X64\t3649\tWix4UtilCA_X64\tRemoveGroup\t",
411 "Wix4Group:TEST_GROUP00\tComponent1\ttestName00\t", 411 "Wix4Group:TEST_GROUP00\tComponent1\ttestName00\t",
412 "Wix4Group:TEST_GROUP01\tComponent1\ttestName01\t", 412 "Wix4Group:TEST_GROUP01\tComponent1\ttestName01\t",
413 "Wix4Group:TEST_GROUP02\tComponent1\ttestName02\t", 413 "Wix4Group:TEST_GROUP02\tComponent1\ttestName02\t",
diff --git a/src/ext/Util/wixext/UtilCompiler.cs b/src/ext/Util/wixext/UtilCompiler.cs
index aff7dd0d..4b1e43b5 100644
--- a/src/ext/Util/wixext/UtilCompiler.cs
+++ b/src/ext/Util/wixext/UtilCompiler.cs
@@ -1475,7 +1475,7 @@ namespace WixToolset.Util
1475 1475
1476 if (null != componentId) 1476 if (null != componentId)
1477 { 1477 {
1478 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureGroups", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); 1478 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix6ConfigureGroups", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1479 } 1479 }
1480 1480
1481 foreach (var child in element.Elements()) 1481 foreach (var child in element.Elements())
@@ -1488,7 +1488,7 @@ namespace WixToolset.Util
1488 this.ParseGroupRefElement(intermediate, section, child, id.Id, groupType:true); 1488 this.ParseGroupRefElement(intermediate, section, child, id.Id, groupType:true);
1489 break; 1489 break;
1490 default: 1490 default:
1491 //this.ParseHelper.UnexpectedElement(element, child); 1491 this.ParseHelper.UnexpectedElement(element, child);
1492 break; 1492 break;
1493 } 1493 }
1494 } 1494 }
@@ -1561,6 +1561,9 @@ namespace WixToolset.Util
1561 } 1561 }
1562 else 1562 else
1563 { 1563 {
1564 // Add reference to bring in fragment
1565 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix6AddGroupMembership", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
1566
1564 section.AddSymbol(new GroupGroupSymbol(sourceLineNumbers) 1567 section.AddSymbol(new GroupGroupSymbol(sourceLineNumbers)
1565 { 1568 {
1566 ChildGroupRef = childId, 1569 ChildGroupRef = childId,
diff --git a/src/ext/Util/wixext/UtilDecompiler.cs b/src/ext/Util/wixext/UtilDecompiler.cs
index 53b75b8d..a236ece9 100644
--- a/src/ext/Util/wixext/UtilDecompiler.cs
+++ b/src/ext/Util/wixext/UtilDecompiler.cs
@@ -478,14 +478,26 @@ namespace WixToolset.Util
478 { 478 {
479 foreach (var row in table.Rows) 479 foreach (var row in table.Rows)
480 { 480 {
481 var parentId = row.FieldAsString(0);
482 var parentExists = this.DecompilerHelper.TryGetIndexedElement("Group", parentId, out var parentGroup);
483
481 var childId = row.FieldAsString(1); 484 var childId = row.FieldAsString(1);
482 if (this.DecompilerHelper.TryGetIndexedElement("Group", childId, out var group)) 485 var childExists = this.DecompilerHelper.TryGetIndexedElement("Group", childId, out var childGroup);
486
487 if (parentExists && childExists)
483 { 488 {
484 group.Add(new XElement(UtilConstants.GroupRefName, new XAttribute("Id", row.FieldAsString(0)))); 489 childGroup.Add(new XElement(UtilConstants.GroupRefName, new XAttribute("Id", parentId)));
485 } 490 }
486 else 491 else
487 { 492 {
488 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(), "Parent_", childId, "Group")); 493 if(!parentExists)
494 {
495 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(), "Parent_", parentId, "Group"));
496 }
497 if (!childExists)
498 {
499 this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(), "Child_", childId, "Group"));
500 }
489 } 501 }
490 } 502 }
491 } 503 }
diff --git a/src/ext/Util/wixlib/UtilExtension.wxs b/src/ext/Util/wixlib/UtilExtension.wxs
index bc0f651d..aa262eca 100644
--- a/src/ext/Util/wixlib/UtilExtension.wxs
+++ b/src/ext/Util/wixlib/UtilExtension.wxs
@@ -17,12 +17,17 @@
17 <Fragment> 17 <Fragment>
18 <UI Id="ConfigureGroupsErrorText"> 18 <UI Id="ConfigureGroupsErrorText">
19 <Error Id="$(var.msierrGRPFailedGroupCreate)" Message="!(loc.msierrGRPFailedGroupCreate)" /> 19 <Error Id="$(var.msierrGRPFailedGroupCreate)" Message="!(loc.msierrGRPFailedGroupCreate)" />
20 <Error Id="$(var.msierrGRPFailedGroupGroupAdd)" Message="!(loc.msierrGRPFailedGroupGroupAdd)" />
21 <Error Id="$(var.msierrGRPFailedGroupCreateExists)" Message="!(loc.msierrGRPFailedGroupCreateExists)" /> 20 <Error Id="$(var.msierrGRPFailedGroupCreateExists)" Message="!(loc.msierrGRPFailedGroupCreateExists)" />
22 </UI> 21 </UI>
23 </Fragment> 22 </Fragment>
24 23
25 <Fragment> 24 <Fragment>
25 <UI Id="ConfigureGroupGroupsErrorText">
26 <Error Id="$(var.msierrGRPFailedGroupGroupAdd)" Message="!(loc.msierrGRPFailedGroupGroupAdd)" />
27 </UI>
28 </Fragment>
29
30 <Fragment>
26 <UI Id="ConfigureSmbErrorsText"> 31 <UI Id="ConfigureSmbErrorsText">
27 <Error Id="$(var.msierrSMBFailedCreate)" Message="!(loc.msierrSMBFailedCreate)" /> 32 <Error Id="$(var.msierrSMBFailedCreate)" Message="!(loc.msierrSMBFailedCreate)" />
28 <Error Id="$(var.msierrSMBFailedDrop)" Message="!(loc.msierrSMBFailedDrop)" /> 33 <Error Id="$(var.msierrSMBFailedDrop)" Message="!(loc.msierrSMBFailedDrop)" />
diff --git a/src/ext/Util/wixlib/UtilExtension_Platform.wxi b/src/ext/Util/wixlib/UtilExtension_Platform.wxi
index df53c7d4..71166d4f 100644
--- a/src/ext/Util/wixlib/UtilExtension_Platform.wxi
+++ b/src/ext/Util/wixlib/UtilExtension_Platform.wxi
@@ -134,19 +134,25 @@
134 134
135 <Fragment> 135 <Fragment>
136 <UIRef Id="ConfigureGroupsErrorText" /> 136 <UIRef Id="ConfigureGroupsErrorText" />
137 137 <CustomAction Id="$(var.Prefix6)ConfigureGroups$(var.Suffix)" DllEntry="ConfigureGroups" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
138 <CustomAction Id="$(var.Prefix)ConfigureGroups$(var.Suffix)" DllEntry="ConfigureGroups" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" /> 138 <CustomAction Id="$(var.Prefix6)CreateGroup$(var.Suffix)" DllEntry="CreateGroup" Impersonate="no" Execute="deferred" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
139 <CustomAction Id="$(var.Prefix)CreateGroup$(var.Suffix)" DllEntry="CreateGroup" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" /> 139 <CustomAction Id="$(var.Prefix6)CreateGroupRollback$(var.Suffix)" DllEntry="CreateGroupRollback" Impersonate="no" Execute="rollback" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
140 <CustomAction Id="$(var.Prefix)CreateGroupRollback$(var.Suffix)" DllEntry="CreateGroupRollback" Impersonate="no" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
141 <!-- RemoveGroup is a type commit action because it is not possible to rollback the removal of a group --> 140 <!-- RemoveGroup is a type commit action because it is not possible to rollback the removal of a group -->
142 <CustomAction Id="$(var.Prefix)RemoveGroup$(var.Suffix)" DllEntry="RemoveGroup" Impersonate="no" Execute="commit" Return="ignore" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" /> 141 <CustomAction Id="$(var.Prefix6)RemoveGroup$(var.Suffix)" DllEntry="RemoveGroup" Impersonate="no" Execute="commit" Return="ignore" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
143
144 <InstallExecuteSequence> 142 <InstallExecuteSequence>
145 <Custom Action="virtual $(var.Prefix)ConfigureGroups$(var.Suffix)" Before="InstallFiles" Condition="VersionNT &gt; 400" /> 143 <Custom Action="virtual $(var.Prefix6)ConfigureGroups$(var.Suffix)" Before="InstallFiles" Condition="VersionNT &gt; 400" />
146 </InstallExecuteSequence> 144 </InstallExecuteSequence>
147 </Fragment> 145 </Fragment>
148 146
149 <Fragment> 147 <Fragment>
148 <UIRef Id="ConfigureGroupGroupsErrorText" />
149 <CustomAction Id="$(var.Prefix6)AddGroupMembership$(var.Suffix)" DllEntry="AddGroupMembership" Impersonate="no" Execute="deferred" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
150 <CustomAction Id="$(var.Prefix6)AddGroupMembershipRollback$(var.Suffix)" DllEntry="AddGroupMembershipRollback" Impersonate="no" Execute="rollback" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
151 <CustomAction Id="$(var.Prefix6)RemoveGroupMembership$(var.Suffix)" DllEntry="RemoveGroupMembership" Impersonate="no" Execute="deferred" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
152 <CustomAction Id="$(var.Prefix6)RemoveGroupMembershipRollback$(var.Suffix)" DllEntry="RemoveGroupMembershipRollback" Impersonate="no" Execute="rollback" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
153 </Fragment>
154
155 <Fragment>
150 <UIRef Id="ConfigureUsersErrorText" /> 156 <UIRef Id="ConfigureUsersErrorText" />
151 157
152 <CustomAction Id="$(var.Prefix)ConfigureUsers$(var.Suffix)" DllEntry="ConfigureUsers" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" /> 158 <CustomAction Id="$(var.Prefix)ConfigureUsers$(var.Suffix)" DllEntry="ConfigureUsers" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" />
diff --git a/src/ext/Util/wixlib/es-es.wxl b/src/ext/Util/wixlib/es-es.wxl
index 3756027a..e5a85ab0 100644
--- a/src/ext/Util/wixlib/es-es.wxl
+++ b/src/ext/Util/wixlib/es-es.wxl
@@ -8,7 +8,7 @@
8 <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="La creación del usuario ha fracasado porque ya existe. ([2] [3] [4] [5])" /> 8 <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="La creación del usuario ha fracasado porque ya existe. ([2] [3] [4] [5])" />
9 9
10 <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="La creación del grupo ha fracasado. ([2] [3] [4] [5])" /> 10 <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="La creación del grupo ha fracasado. ([2] [3] [4] [5])" />
11 <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="El aditamento del grupo al grupo ha fracasado. ([2] [3] [4] [5])" /> 11 <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="El aditamento del grupo al grupo ha fracasado. ([2] [3] [4] [5])" />
12 <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="La creación del grupo ha fracasado porque ya existe. ([2] [3] [4] [5])" /> 12 <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="La creación del grupo ha fracasado porque ya existe. ([2] [3] [4] [5])" />
13 13
14 <String Id="msierrSMBFailedCreate" Overridable="yes" Value="La creación de la red compartida ha fracasado. ([2] [3] [4] [5])" /> 14 <String Id="msierrSMBFailedCreate" Overridable="yes" Value="La creación de la red compartida ha fracasado. ([2] [3] [4] [5])" />
diff --git a/src/ext/Util/wixlib/fr-fr.wxl b/src/ext/Util/wixlib/fr-fr.wxl
index 4b9aa9ad..407292ac 100644
--- a/src/ext/Util/wixlib/fr-fr.wxl
+++ b/src/ext/Util/wixlib/fr-fr.wxl
@@ -8,7 +8,7 @@
8 <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="La création de l'utilisateur a échoué car il existe dejà. ([2] [3] [4] [5])" /> 8 <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="La création de l'utilisateur a échoué car il existe dejà. ([2] [3] [4] [5])" />
9 9
10 <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="La création du groupe a échoué. ([2] [3] [4] [5])" /> 10 <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="La création du groupe a échoué. ([2] [3] [4] [5])" />
11 <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="L'ajout du groupe au groupe a échoué. ([2] [3] [4] [5])" /> 11 <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="L'ajout du groupe au groupe a échoué. ([2] [3] [4] [5])" />
12 <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="La création du groupe a échoué car il existe dejà. ([2] [3] [4] [5])" /> 12 <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="La création du groupe a échoué car il existe dejà. ([2] [3] [4] [5])" />
13 13
14 <String Id="msierrSMBFailedCreate" Overridable="yes" Value="La création du partage reseau a échoué. ([2] [3] [4] [5])" /> 14 <String Id="msierrSMBFailedCreate" Overridable="yes" Value="La création du partage reseau a échoué. ([2] [3] [4] [5])" />
diff --git a/src/ext/caDecor.h b/src/ext/caDecor.h
index 060032cf..4a09e075 100644
--- a/src/ext/caDecor.h
+++ b/src/ext/caDecor.h
@@ -21,3 +21,13 @@
21#else 21#else
22#define CUSTOM_ACTION_DECORATION5(f) L"Wix5" f L"_X86" 22#define CUSTOM_ACTION_DECORATION5(f) L"Wix5" f L"_X86"
23#endif 23#endif
24
25#if defined(_M_ARM64)
26#define CUSTOM_ACTION_DECORATION6(f) L"Wix6" f L"_A64"
27#elif defined(_M_AMD64)
28#define CUSTOM_ACTION_DECORATION6(f) L"Wix6" f L"_X64"
29#elif defined(_M_ARM)
30#define CUSTOM_ACTION_DECORATION6(f) L"Wix6" f L"_ARM"
31#else
32#define CUSTOM_ACTION_DECORATION6(f) L"Wix6" f L"_X86"
33#endif
diff --git a/src/ext/caDecor.wxi b/src/ext/caDecor.wxi
index 256d7586..236b2154 100644
--- a/src/ext/caDecor.wxi
+++ b/src/ext/caDecor.wxi
@@ -14,6 +14,11 @@
14 14
15 <?define Prefix5="Wix5" ?> 15 <?define Prefix5="Wix5" ?>
16 16
17 <?ifdef Prefix6 ?>
18 <?undef Prefix6 ?>
19 <?endif?>
20 <?define Prefix6="Wix6" ?>
21
17 <?ifndef platform ?> 22 <?ifndef platform ?>
18 <?define platform="x86" ?> 23 <?define platform="x86" ?>
19 <?endif?> 24 <?endif?>
diff --git a/src/test/burn/WixTestTools/UserGroupVerifier.cs b/src/test/burn/WixTestTools/UserGroupVerifier.cs
index 2f874057..52a1a6bf 100644
--- a/src/test/burn/WixTestTools/UserGroupVerifier.cs
+++ b/src/test/burn/WixTestTools/UserGroupVerifier.cs
@@ -151,7 +151,7 @@ namespace WixTestTools
151 /// <param name="groupNames">list of groups to check for membership</param> 151 /// <param name="groupNames">list of groups to check for membership</param>
152 private static void IsMemberOf(string domainName, string memberName, bool shouldBeMember, params string[] groupNames) 152 private static void IsMemberOf(string domainName, string memberName, bool shouldBeMember, params string[] groupNames)
153 { 153 {
154 GroupPrincipal group = GetGroup(domainName, memberName); 154 Principal group = GetPrincipal(domainName, memberName);
155 Assert.False(null == group, String.Format("Group '{0}' was not found under domain '{1}'.", memberName, domainName)); 155 Assert.False(null == group, String.Format("Group '{0}' was not found under domain '{1}'.", memberName, domainName));
156 156
157 bool missedAGroup = false; 157 bool missedAGroup = false;
@@ -186,11 +186,29 @@ namespace WixTestTools
186 { 186 {
187 if (String.IsNullOrEmpty(domainName)) 187 if (String.IsNullOrEmpty(domainName))
188 { 188 {
189 return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Machine), IdentityType.Name, groupName); 189 return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Machine), groupName);
190 } 190 }
191 else 191 else
192 { 192 {
193 return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain,domainName), IdentityType.Name, groupName); 193 return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain,domainName), groupName);
194 }
195 }
196
197 /// <summary>
198 /// Returns the Principal object for a given name
199 /// </summary>
200 /// <param name="domainName">Domain name to look under, if Empty the LocalMachine is assumed as the domain</param>
201 /// <param name="name"></param>
202 /// <returns>Principal Object if found, or null other wise</returns>
203 private static Principal GetPrincipal(string domainName, string name)
204 {
205 if (String.IsNullOrEmpty(domainName))
206 {
207 return Principal.FindByIdentity(new PrincipalContext(ContextType.Machine), name);
208 }
209 else
210 {
211 return Principal.FindByIdentity(new PrincipalContext(ContextType.Domain, domainName), name);
194 } 212 }
195 } 213 }
196 } 214 }
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductCommentFail/product_fail.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductCommentFail/product_fail.wxs
index 29b908da..4e70717f 100644
--- a/src/test/msi/TestData/UtilExtensionGroupTests/ProductCommentFail/product_fail.wxs
+++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductCommentFail/product_fail.wxs
@@ -8,7 +8,7 @@
8 </ComponentGroup> 8 </ComponentGroup>
9 9
10 <InstallExecuteSequence> 10 <InstallExecuteSequence>
11 <Custom Action="CaFail" After="Wix4ConfigureGroups_X86" /> 11 <Custom Action="CaFail" After="Wix6ConfigureGroups_X86" />
12 </InstallExecuteSequence> 12 </InstallExecuteSequence>
13 </Fragment> 13 </Fragment>
14 14
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductFail/product_fail.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductFail/product_fail.wxs
index fb35bc1e..3013e5a0 100644
--- a/src/test/msi/TestData/UtilExtensionGroupTests/ProductFail/product_fail.wxs
+++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductFail/product_fail.wxs
@@ -11,7 +11,7 @@
11 <Property Id="TEMPUSERNAME" Secure="yes" /> 11 <Property Id="TEMPUSERNAME" Secure="yes" />
12 12
13 <InstallExecuteSequence> 13 <InstallExecuteSequence>
14 <Custom Action="CaFail" After="Wix4ConfigureGroups_X86" /> 14 <Custom Action="CaFail" After="Wix6ConfigureGroups_X86" />
15 </InstallExecuteSequence> 15 </InstallExecuteSequence>
16 </Fragment> 16 </Fragment>
17 17
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductNestedGroups/product.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNestedGroups/product.wxs
index 191d605c..15328cb3 100644
--- a/src/test/msi/TestData/UtilExtensionGroupTests/ProductNestedGroups/product.wxs
+++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNestedGroups/product.wxs
@@ -12,11 +12,11 @@
12 </Fragment> 12 </Fragment>
13 13
14 <Fragment> 14 <Fragment>
15 <util:Group Id="ADMIN" Name="Administrators" > 15 <util:Group Id="AUTH_USERS" Name="Authenticated Users" >
16 <util:GroupRef Id="TEST_GROUP1" /> 16 <util:GroupRef Id="TEST_GROUP1" />
17 <util:GroupRef Id="TEST_GROUP2" /> 17 <util:GroupRef Id="TEST_GROUP2" />
18 </util:Group> 18 </util:Group>
19 <util:Group Id="POWER_USERS" Name="Power Users" > 19 <util:Group Id="EVERYONE" Name="Everyone" >
20 <util:GroupRef Id="TEST_GROUP1" /> 20 <util:GroupRef Id="TEST_GROUP1" />
21 </util:Group> 21 </util:Group>
22 22
@@ -26,8 +26,6 @@
26 <util:Group Id="TEST_GROUP1" Name="testName1" Comment="Group1" CreateGroup="yes" RemoveOnUninstall="yes" /> 26 <util:Group Id="TEST_GROUP1" Name="testName1" Comment="Group1" CreateGroup="yes" RemoveOnUninstall="yes" />
27 27
28 <util:Group Id="TEST_GROUP2" Name="testName2" Comment="Group2" RemoveOnUninstall="no" UpdateIfExists="yes" /> 28 <util:Group Id="TEST_GROUP2" Name="testName2" Comment="Group2" RemoveOnUninstall="no" UpdateIfExists="yes" />
29
30 <util:Group Id="TEST_GROUP3" Name="testName3" Comment="Group3" />
31 </Component> 29 </Component>
32 </Fragment> 30 </Fragment>
33</Wix> 31</Wix>
diff --git a/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionGroupTests.cs b/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionGroupTests.cs
index 796c4ecd..d7cf3168 100644
--- a/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionGroupTests.cs
+++ b/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionGroupTests.cs
@@ -256,11 +256,11 @@ namespace WixToolsetTest.MsiE2E
256 productNestedGroups.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); 256 productNestedGroups.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS);
257 257
258 // Verify group nested membership 258 // Verify group nested membership
259 UserGroupVerifier.VerifyIsMemberOf(String.Empty, "Administrators", new string[] { "testName1", "testName2" }); 259 UserGroupVerifier.VerifyIsMemberOf(String.Empty, "Authenticated Users", new string[] { "testName1", "testName2" });
260 UserGroupVerifier.VerifyIsMemberOf(String.Empty, "Power Users", new string[] { "testName1" }); 260 UserGroupVerifier.VerifyIsMemberOf(String.Empty, "Everyone", new string[] { "testName1" });
261 261
262 UserGroupVerifier.VerifyIsNotMemberOf(String.Empty, "Administrators", new string[] { "testName3" }); 262 UserGroupVerifier.VerifyIsNotMemberOf(String.Empty, "Authenticated Users", new string[] { "testName3" });
263 UserGroupVerifier.VerifyIsNotMemberOf(String.Empty, "Power Users", new string[] { "testName2", "testName3" }); 263 UserGroupVerifier.VerifyIsNotMemberOf(String.Empty, "Everyone", new string[] { "testName2", "testName3" });
264 264
265 // clean up 265 // clean up
266 UserGroupVerifier.DeleteLocalGroup("testName1"); 266 UserGroupVerifier.DeleteLocalGroup("testName1");