From 644276562dcadd65fcb0e9a7c06c704cdda36423 Mon Sep 17 00:00:00 2001 From: Bevan Weiss Date: Sat, 6 Jul 2024 21:03:57 +1000 Subject: 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 --- src/ext/Util/ca/scacost.h | 2 + src/ext/Util/ca/scaexec.cpp | 454 ++++++++++++--------- src/ext/Util/ca/scagroup.cpp | 412 +++++++++++++++++-- src/ext/Util/ca/scagroup.h | 10 +- src/ext/Util/ca/scanet.cpp | 5 +- src/ext/Util/ca/scasched.cpp | 6 + src/ext/Util/ca/utilca.def | 4 + .../WixToolsetTest.Util/UtilExtensionFixture.cs | 8 +- src/ext/Util/wixext/UtilCompiler.cs | 7 +- src/ext/Util/wixext/UtilDecompiler.cs | 18 +- src/ext/Util/wixlib/UtilExtension.wxs | 7 +- src/ext/Util/wixlib/UtilExtension_Platform.wxi | 20 +- src/ext/Util/wixlib/es-es.wxl | 2 +- src/ext/Util/wixlib/fr-fr.wxl | 2 +- src/ext/caDecor.h | 10 + src/ext/caDecor.wxi | 5 + src/test/burn/WixTestTools/UserGroupVerifier.cs | 24 +- .../ProductCommentFail/product_fail.wxs | 2 +- .../ProductFail/product_fail.wxs | 2 +- .../ProductNestedGroups/product.wxs | 6 +- .../UtilExtensionGroupTests.cs | 8 +- 21 files changed, 736 insertions(+), 278 deletions(-) (limited to 'src') 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; const UINT COST_USER_DELETE = 10000; const UINT COST_GROUP_ADD = 10000; const UINT COST_GROUP_DELETE = 10000; +const UINT COST_GROUPMEMBERSHIP_ADD = 10000; +const UINT COST_GROUPMEMBERSHIP_DELETE = 10000; const UINT COST_PERFMONMANIFEST_REGISTER = 1000; const 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: return hr; } -static HRESULT AddGroupToGroup( - __in LPWSTR wzMember, - __in LPCWSTR wzMemberDomain, - __in LPCWSTR wzGroup, - __in LPCWSTR wzGroupDomain -) -{ - Assert(wzMember && *wzMember && wzMemberDomain && wzGroup && *wzGroup && wzGroupDomain); - - HRESULT hr = S_OK; - IADsGroup* pGroup = NULL; - BSTR bstrMember = NULL; - BSTR bstrGroup = NULL; - LPWSTR pwzMember = NULL; - LPWSTR pwzServerName = NULL; - LOCALGROUP_MEMBERS_INFO_3 lgmi {}; - - GetDomainServerName(wzGroupDomain, &pwzServerName); - - // Try adding it to the local group - if (wzMemberDomain) - { - hr = StrAllocFormatted(&pwzMember, L"%s\\%s", wzMemberDomain, wzMember); - ExitOnFailure(hr, "failed to allocate group domain string"); - } - - lgmi.lgrmi3_domainandname = (NULL == pwzMember ? wzMember : pwzMember); - NET_API_STATUS ui = ::NetLocalGroupAddMembers(pwzServerName, wzGroup, 3, reinterpret_cast(&lgmi), 1); - hr = HRESULT_FROM_WIN32(ui); - if (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr) // if they're already a member of the group don't report an error - { - hr = S_OK; - } - - // - // If we failed, try active directory - // - if (FAILED(hr)) - { - 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); - - hr = UserCreateADsPath(wzMemberDomain, wzMember, &bstrMember); - ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzMember, wzMemberDomain); - - hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup); - ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzGroup, wzGroupDomain); - - hr = ::ADsGetObject(bstrGroup, IID_IADsGroup, reinterpret_cast(&pGroup)); - ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast(bstrGroup)); - - hr = pGroup->Add(bstrMember); - if ((HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hr) || (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr)) - hr = S_OK; - - ExitOnFailure(hr, "Failed to add group %ls to group '%ls'.", reinterpret_cast(bstrMember), reinterpret_cast(bstrGroup)); - } - -LExit: - ReleaseStr(pwzServerName); - ReleaseStr(pwzMember); - ReleaseBSTR(bstrMember); - ReleaseBSTR(bstrGroup); - ReleaseObject(pGroup); - - return hr; -} - -static HRESULT RemoveGroupFromGroup( - __in LPWSTR wzMember, - __in LPCWSTR wzMemberDomain, - __in LPCWSTR wzGroup, - __in LPCWSTR wzGroupDomain -) -{ - Assert(wzMember && *wzMember && wzMemberDomain && wzGroup && *wzGroup && wzGroupDomain); - - HRESULT hr = S_OK; - IADsGroup* pGroup = NULL; - BSTR bstrMember = NULL; - BSTR bstrGroup = NULL; - LPWSTR pwzMember = NULL; - LPWSTR pwzServerName = NULL; - LOCALGROUP_MEMBERS_INFO_3 lgmi {}; - - GetDomainServerName(wzGroupDomain, &pwzServerName, DS_WRITABLE_REQUIRED); - - // Try removing it from the local group - if (wzMemberDomain) - { - hr = StrAllocFormatted(&pwzMember, L"%s\\%s", wzMemberDomain, wzMember); - ExitOnFailure(hr, "failed to allocate group domain string"); - } - - lgmi.lgrmi3_domainandname = (NULL == pwzMember ? wzMember : pwzMember); - NET_API_STATUS ui = ::NetLocalGroupDelMembers(pwzServerName, wzGroup, 3, reinterpret_cast(&lgmi), 1); - hr = HRESULT_FROM_WIN32(ui); - if (HRESULT_FROM_WIN32(ERROR_MEMBER_NOT_IN_ALIAS) == hr - || HRESULT_FROM_WIN32(NERR_GroupNotFound) == hr - || 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 - { - hr = S_OK; - } - - // - // If we failed, try active directory - // - if (FAILED(hr)) - { - 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); - - hr = UserCreateADsPath(wzMemberDomain, wzMember, &bstrMember); - ExitOnFailure(hr, "failed to create group ADsPath in order to remove group: %ls domain: %ls from a group", wzMember, wzMemberDomain); - - hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup); - ExitOnFailure(hr, "failed to create group ADsPath in order to remove group from group: %ls domain: %ls", wzGroup, wzGroupDomain); - - hr = ::ADsGetObject(bstrGroup, IID_IADsGroup, reinterpret_cast(&pGroup)); - if ((HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)) // if parent group not found, no need to remove membership from group - { - hr = S_OK; - ExitFunction(); - } - ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast(bstrGroup)); - - hr = pGroup->Remove(bstrMember); - if ((HRESULT_FROM_WIN32(ERROR_MEMBER_NOT_IN_ALIAS) == hr)) // if already not a member, no need to worry about error - hr = S_OK; - ExitOnFailure(hr, "Failed to remove group %ls from group '%ls'.", reinterpret_cast(bstrMember), reinterpret_cast(bstrGroup)); - } - -LExit: - ReleaseStr(pwzServerName); - ReleaseStr(pwzMember); - ReleaseBSTR(bstrMember); - ReleaseBSTR(bstrGroup); - ReleaseObject(pGroup); - - return hr; -} - static HRESULT GetUserHasRight( __in LSA_HANDLE hPolicy, __in PSID pUserSid, @@ -842,7 +702,6 @@ LExit: } static HRESULT RemoveGroupInternal( - LPWSTR wzGroupCaData, LPWSTR wzDomain, LPWSTR wzName, int iAttributes @@ -850,9 +709,6 @@ static HRESULT RemoveGroupInternal( { HRESULT hr = S_OK; - LPWSTR pwz = NULL; - LPWSTR pwzGroup = NULL; - LPWSTR pwzGroupDomain = NULL; LPWSTR pwzServerName = NULL; // @@ -871,41 +727,9 @@ static HRESULT RemoveGroupInternal( } ExitOnFailure(hr, "failed to delete group: %ls", wzName); } - else - { - // - // Remove the group from other groups - // - pwz = wzGroupCaData; - while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) - { - hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); - if (FAILED(hr)) - { - WcaLogError(hr, "failed to get domain for group: %ls, continuing anyway.", pwzGroup); - } - else - { - hr = RemoveGroupFromGroup(wzName, wzDomain, pwzGroup, pwzGroupDomain); - if (FAILED(hr)) - { - WcaLogError(hr, "failed to remove group: %ls from group %ls, continuing anyway.", wzName, pwzGroup); - } - } - } - - if (E_NOMOREITEMS == hr) // if there are no more items, all is well - { - hr = S_OK; - } - - ExitOnFailure(hr, "failed to get next group from which to remove group:%ls", wzName); - } LExit: ReleaseStr(pwzServerName); - ReleaseStr(pwzGroup); - ReleaseStr(pwzGroupDomain); return hr; } @@ -1392,6 +1216,7 @@ LExit: return WcaFinalize(er); } + /******************************************************************** CreateGroup - CUSTOM ACTION ENTRY POINT for creating groups @@ -1412,8 +1237,6 @@ extern "C" UINT __stdcall CreateGroup( LPWSTR pwzDomain = NULL; LPWSTR pwzComment = NULL; LPWSTR pwzScriptKey = NULL; - LPWSTR pwzGroup = NULL; - LPWSTR pwzGroupDomain = NULL; int iAttributes = 0; BOOL fInitializedCom = FALSE; @@ -1553,24 +1376,6 @@ extern "C" UINT __stdcall CreateGroup( } } MessageExitOnFailure(hr, msierrGRPFailedGroupCreate, "failed to create group: %ls", pwzName); - - // - // Add the groups to groups - // - while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) - { - hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); - ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup); - - WcaLog(LOGMSG_STANDARD, "Adding group %ls\\%ls to group %ls\\%ls", pwzDomain, pwzName, pwzGroupDomain, pwzGroup); - hr = AddGroupToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain); - MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add group: %ls to group %ls", pwzName, pwzGroup); - } - if (E_NOMOREITEMS == hr) // if there are no more items, all is well - { - hr = S_OK; - } - ExitOnFailure(hr, "failed to get next group in which to include group: %ls", pwzName); } LExit: @@ -1586,8 +1391,6 @@ LExit: ReleaseStr(pwzDomain); ReleaseStr(pwzComment); ReleaseStr(pwzScriptKey); - ReleaseStr(pwzGroup); - ReleaseStr(pwzGroupDomain); if (fInitializedCom) { @@ -1704,7 +1507,7 @@ extern "C" UINT __stdcall CreateGroupRollback( } } - hr = RemoveGroupInternal(pwz, pwzDomain, pwzName, iAttributes); + hr = RemoveGroupInternal(pwzDomain, pwzName, iAttributes); LExit: WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); @@ -1781,7 +1584,7 @@ extern "C" UINT __stdcall RemoveGroup( hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); ExitOnFailure(hr, "failed to read attributes from custom action data"); - hr = RemoveGroupInternal(pwz, pwzDomain, pwzName, iAttributes); + hr = RemoveGroupInternal(pwzDomain, pwzName, iAttributes); LExit: ReleaseStr(pwzData); @@ -1801,3 +1604,254 @@ LExit: return WcaFinalize(er); } + +HRESULT AlterGroupMembership(bool remove, bool isRollback = false) +{ + HRESULT hr = S_OK; + NET_API_STATUS er = ERROR_SUCCESS; + + LPWSTR pwzData = NULL; + LPWSTR pwz = NULL; + LPWSTR pwzParentName = NULL; + LPWSTR pwzParentDomain = NULL; + LPWSTR pwzChildName = NULL; + LPWSTR pwzChildDomain = NULL; + int iAttributes = 0; + LPWSTR pwzChildFullName = NULL; + LPWSTR pwzServerName = NULL; + LOCALGROUP_MEMBERS_INFO_3 memberInfo3 = {}; + WCA_CASCRIPT_HANDLE phRollbackScript = NULL; + + if (isRollback) + { + // Get a CaScript key + hr = WcaCaScriptOpen(WCA_ACTION_NONE, WCA_CASCRIPT_ROLLBACK, FALSE, remove ? L"AddGroupMembershipRollback" : L"RemoveGroupMembershipRollback", &phRollbackScript); + hr = WcaCaScriptReadAsCustomActionData(phRollbackScript, &pwzData); + } + else + { + hr = WcaCaScriptCreate(WCA_ACTION_NONE, WCA_CASCRIPT_ROLLBACK, FALSE, remove ? L"RemoveGroupMembershipRollback" : L"AddGroupMembershipRollback", TRUE, &phRollbackScript); + hr = WcaGetProperty(L"CustomActionData", &pwzData); + } + ExitOnFailure(hr, "failed to get CustomActionData"); + + WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); + + // + // Read in the CustomActionData + // + pwz = pwzData; + hr = WcaReadStringFromCaData(&pwz, &pwzParentName); + ExitOnFailure(hr, "failed to read group name from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &pwzParentDomain); + ExitOnFailure(hr, "failed to read domain from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &pwzChildName); + ExitOnFailure(hr, "failed to read group comment from custom action data"); + + hr = WcaReadStringFromCaData(&pwz, &pwzChildDomain); + ExitOnFailure(hr, "failed to read group comment from custom action data"); + + hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); + ExitOnFailure(hr, "failed to read attributes from custom action data"); + + hr = GetDomainServerName(pwzParentDomain, &pwzServerName, DS_WRITABLE_REQUIRED); + ExitOnFailure(hr, "failed to contact domain server %ls", pwzParentDomain); + + if (*pwzChildDomain) + { + StrAllocFormatted(&pwzChildFullName, L"%ls\\%ls", pwzChildDomain, pwzChildName); + } + else + { + StrAllocFormatted(&pwzChildFullName, L"%ls", pwzChildName); + } + memberInfo3.lgrmi3_domainandname = pwzChildFullName; + + if (remove) + { + er = ::NetLocalGroupDelMembers(pwzServerName, pwzParentName, 3, (LPBYTE)&memberInfo3, 1); + } + else + { + er = ::NetLocalGroupAddMembers(pwzServerName, pwzParentName, 3, (LPBYTE)&memberInfo3, 1); + } + hr = HRESULT_FROM_WIN32(er); + + if (S_OK == hr && !isRollback) + { + // we need to log rollback data, we can just use exactly the same data we used to do the initial action though + WcaCaScriptWriteString(phRollbackScript, pwzParentName); + WcaCaScriptWriteString(phRollbackScript, pwzParentDomain); + WcaCaScriptWriteString(phRollbackScript, pwzChildName); + WcaCaScriptWriteString(phRollbackScript, pwzChildDomain); + WcaCaScriptWriteNumber(phRollbackScript, iAttributes); + WcaCaScriptFlush(phRollbackScript); + WcaCaScriptClose(phRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); + } + + if (remove) + { + if (HRESULT_FROM_WIN32(NERR_GroupNotFound) == hr + || HRESULT_FROM_WIN32(ERROR_NO_SUCH_MEMBER) == hr + || HRESULT_FROM_WIN32(ERROR_MEMBER_NOT_IN_ALIAS) == hr) + { + hr = S_OK; + } + } + else + { + if (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr) + { + hr = S_OK; + } + } + +LExit: + ReleaseStr(pwzData); + ReleaseStr(pwzParentName); + ReleaseStr(pwzParentDomain); + ReleaseStr(pwzChildName); + ReleaseStr(pwzChildDomain); + ReleaseStr(pwzChildFullName); + ReleaseStr(pwzServerName); + + if (SCAG_NON_VITAL & iAttributes) + { + return S_OK; + } + return hr; +} + +/******************************************************************** + AddGroupmembership - CUSTOM ACTION ENTRY POINT for creating groups + + Input: deferred CustomActionData - + ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes + * *****************************************************************/ +extern "C" UINT __stdcall AddGroupMembership( + __in MSIHANDLE hInstall +) +{ + //AssertSz(0, "Debug AddGroupMembership"); + + HRESULT hr = S_OK; + + BOOL fInitializedCom = FALSE; + + hr = WcaInitialize(hInstall, "AddGroupMembership"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to initialize COM"); + fInitializedCom = TRUE; + + hr = AlterGroupMembership(false, false); + +LExit: + if (fInitializedCom) + { + ::CoUninitialize(); + } + return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILED : ERROR_SUCCESS); +} + +/******************************************************************** + AddGroupmembership - CUSTOM ACTION ENTRY POINT for creating groups + + Input: deferred CustomActionData - + ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes + * *****************************************************************/ +extern "C" UINT __stdcall AddGroupMembershipRollback( + __in MSIHANDLE hInstall +) +{ + //AssertSz(0, "Debug AddGroupMembershipRollback"); + + HRESULT hr = S_OK; + + BOOL fInitializedCom = FALSE; + + hr = WcaInitialize(hInstall, "AddGroupMembershipRollback"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to initialize COM"); + fInitializedCom = TRUE; + + hr = AlterGroupMembership(true, true); + +LExit: + if (fInitializedCom) + { + ::CoUninitialize(); + } + return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILED : ERROR_SUCCESS); +} + +/******************************************************************** + RemoveGroupMembership - CUSTOM ACTION ENTRY POINT for creating groups + + Input: deferred CustomActionData - + ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes + * *****************************************************************/ +extern "C" UINT __stdcall RemoveGroupMembership( + __in MSIHANDLE hInstall +) +{ + //AssertSz(0, "Debug RemoveGroupMembership"); + + HRESULT hr = S_OK; + + BOOL fInitializedCom = FALSE; + + hr = WcaInitialize(hInstall, "RemoveGroupMembership"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to initialize COM"); + fInitializedCom = TRUE; + + hr = AlterGroupMembership(true, false); + +LExit: + if (fInitializedCom) + { + ::CoUninitialize(); + } + return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILED : ERROR_SUCCESS); +} + +/******************************************************************** + RemoveGroupMembershipRollback - CUSTOM ACTION ENTRY POINT for creating groups + + Input: deferred CustomActionData - + ParentGroupName\tParentGroupDomain\tChildGroupName\tChildGroupDomain\tAttributes + * *****************************************************************/ +extern "C" UINT __stdcall RemoveGroupMembershipRollback( + __in MSIHANDLE hInstall +) +{ + //AssertSz(0, "Debug RemoveGroupMembershipRollback"); + + HRESULT hr = S_OK; + + BOOL fInitializedCom = FALSE; + + hr = WcaInitialize(hInstall, "RemoveGroupMembershipRollback"); + ExitOnFailure(hr, "failed to initialize"); + + hr = ::CoInitialize(NULL); + ExitOnFailure(hr, "failed to initialize COM"); + fInitializedCom = TRUE; + + hr = AlterGroupMembership(false, true); + +LExit: + if (fInitializedCom) + { + ::CoUninitialize(); + } + return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILED : ERROR_SUCCESS); +} 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 @@ LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Group`=?"; enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; -LPCWSTR vcsGroupGroupQuery = L"SELECT `Parent_`, `Child_` FROM `Wix6GroupGroup` WHERE `Child_`=?"; -enum eGroupGroupQuery { vggqParent = 1, vggqChild }; +LPCWSTR vcsGroupParentsQuery = L"SELECT `Parent_`,`Component_`,`Name`,`Domain`,`Child_` FROM `Wix6GroupGroup`,`Wix4Group` WHERE `Wix6GroupGroup`.`Parent_`=`Wix4Group`.`Group` AND `Wix6GroupGroup`.`Child_`=?"; +enum eGroupParentsQuery { vgpqParent = 1, vgpqParentComponent, vgpqParentName, vgpqParentDomain, vgpqChild }; + +LPCWSTR vcsGroupChildrenQuery = L"SELECT `Parent_`,`Child_`,`Component_`,`Name`,`Domain` FROM `Wix6GroupGroup`,`Wix4Group` WHERE `Wix6GroupGroup`.`Child_`=`Wix4Group`.`Group` AND `Wix6GroupGroup`.`Parent_`=?"; +enum eGroupChildrenQuery { vgcqParent = 1, vgcqChild, vgcqChildComponent, vgcqChildName, vgcqChildDomain }; LPCWSTR vActionableGroupQuery = L"SELECT `Group`,`Component_`,`Name`,`Domain`,`Comment`,`Attributes` FROM `Wix4Group`,`Wix6Group` WHERE `Component_` IS NOT NULL AND `Group`=`Group_`"; enum eActionableGroupQuery { vagqGroup = 1, vagqComponent, vagqName, vagqDomain, vagqComment, vagqAttributes }; @@ -16,7 +19,6 @@ static HRESULT AddGroupToList( __inout SCA_GROUP** ppsgList ); - HRESULT __stdcall ScaGetGroup( __in LPCWSTR wzGroup, __out SCA_GROUP* pscag @@ -160,11 +162,149 @@ void ScaGroupFreeList( { psgDelete = psgList; psgList = psgList->psgNext; + ScaGroupFreeList(psgDelete->psgParents); + ScaGroupFreeList(psgDelete->psgChildren); MemFree(psgDelete); } } +HRESULT ScaGroupGetParents( + __inout SCA_GROUP* psg +) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + SCA_GROUP* psgParent = NULL; + PMSIHANDLE hView, hParamRec, hRec; + LPWSTR pwzTempStr = NULL; + + if (S_OK != WcaTableExists(L"Wix6GroupGroup")) + { + WcaLog(LOGMSG_VERBOSE, "Wix6GroupGroup Table does not exist, exiting"); + ExitFunction1(hr = S_FALSE); + } + + // setup the query parameter record + hParamRec = ::MsiCreateRecord(1); + hr = WcaSetRecordString(hParamRec, 1, psg->wzKey); + + // + // loop through all the groups + // + hr = WcaOpenView(vcsGroupParentsQuery, &hView); + ExitOnFailure(hr, "failed to open view on Wix6GroupGroup,Wix4Group table(s)"); + hr = WcaExecuteView(hView, hParamRec); + ExitOnFailure(hr, "failed to open view on Wix4Group,Wix6Group table(s)"); + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = AddGroupToList(&psg->psgParents); + ExitOnFailure(hr, "failed to add group to list"); + + psgParent = psg->psgParents; + + if (::MsiRecordIsNull(hRec, vgcqChildComponent)) + { + psgParent->isInstalled = INSTALLSTATE_NOTUSED; + psgParent->isAction = INSTALLSTATE_NOTUSED; + } + else + { + hr = WcaGetRecordString(hRec, vgpqParentComponent, &pwzTempStr); + ExitOnFailure(hr, "failed to get Wix4Group.Component"); + wcsncpy_s(psgParent->wzComponent, pwzTempStr, MAX_DARWIN_KEY); + ReleaseNullStr(pwzTempStr); + + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), psgParent->wzComponent, &psgParent->isInstalled, &psgParent->isAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to get Component state for Wix4Group"); + } + + hr = WcaGetRecordString(hRec, vgpqParentName, &pwzTempStr); + ExitOnFailure(hr, "failed to get Wix4Group.Name"); + wcsncpy_s(psgParent->wzName, pwzTempStr, MAX_DARWIN_COLUMN); + ReleaseNullStr(pwzTempStr); + + + hr = WcaGetRecordString(hRec, vgpqParentDomain, &pwzTempStr); + ExitOnFailure(hr, "failed to get Wix4Group.Domain"); + wcsncpy_s(psgParent->wzDomain, pwzTempStr, MAX_DARWIN_COLUMN); + ReleaseNullStr(pwzTempStr); + } + +LExit: + ReleaseNullStr(pwzTempStr); + return hr; +} + +HRESULT ScaGroupGetChildren( + __inout SCA_GROUP* psg +) +{ + HRESULT hr = S_OK; + UINT er = ERROR_SUCCESS; + SCA_GROUP* psgChild = NULL; + PMSIHANDLE hView, hParamRec, hRec; + LPWSTR pwzTempStr = NULL; + + if (S_OK != WcaTableExists(L"Wix6GroupGroup")) + { + WcaLog(LOGMSG_VERBOSE, "Wix6GroupGroup Table does not exist, exiting"); + ExitFunction1(hr = S_FALSE); + } + + // setup the query parameter record + hParamRec = ::MsiCreateRecord(1); + hr = WcaSetRecordString(hParamRec, 1, psg->wzKey); + + // + // loop through all the groups + // + hr = WcaOpenView(vcsGroupChildrenQuery, &hView); + ExitOnFailure(hr, "failed to open view on Wix6GroupGroup,Wix4Group table(s)"); + hr = WcaExecuteView(hView, hParamRec); + ExitOnFailure(hr, "failed to open view on Wix4Group,Wix6Group table(s)"); + while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) + { + hr = AddGroupToList(&psg->psgChildren); + ExitOnFailure(hr, "failed to add group to list"); + + psgChild = psg->psgChildren; + + if (::MsiRecordIsNull(hRec, vgcqChildComponent)) + { + psgChild->isInstalled = INSTALLSTATE_NOTUSED; + psgChild->isAction = INSTALLSTATE_NOTUSED; + } + else + { + hr = WcaGetRecordString(hRec, vgcqChildComponent, &pwzTempStr); + ExitOnFailure(hr, "failed to get Wix4Group.Component"); + wcsncpy_s(psgChild->wzComponent, pwzTempStr, MAX_DARWIN_KEY); + ReleaseNullStr(pwzTempStr); + + er = ::MsiGetComponentStateW(WcaGetInstallHandle(), psgChild->wzComponent, &psgChild->isInstalled, &psgChild->isAction); + hr = HRESULT_FROM_WIN32(er); + ExitOnFailure(hr, "failed to get Component state for Wix4Group"); + } + + hr = WcaGetRecordString(hRec, vgcqChildName, &pwzTempStr); + ExitOnFailure(hr, "failed to get Wix4Group.Name"); + wcsncpy_s(psgChild->wzName, pwzTempStr, MAX_DARWIN_COLUMN); + ReleaseNullStr(pwzTempStr); + + + hr = WcaGetRecordString(hRec, vgcqChildDomain, &pwzTempStr); + ExitOnFailure(hr, "failed to get Wix4Group.Domain"); + wcsncpy_s(psgChild->wzDomain, pwzTempStr, MAX_DARWIN_COLUMN); + ReleaseNullStr(pwzTempStr); + } + +LExit: + ReleaseNullStr(pwzTempStr); + return hr; +} + HRESULT ScaGroupRead( __out SCA_GROUP** ppsgList @@ -179,7 +319,7 @@ HRESULT ScaGroupRead( LPWSTR pwzData = NULL; - BOOL fGroupGroupExists = FALSE; + //BOOL fGroupGroupExists = FALSE; SCA_GROUP *psg = NULL; @@ -196,11 +336,6 @@ HRESULT ScaGroupRead( ExitFunction1(hr = S_FALSE); } - if (S_OK == WcaTableExists(L"Wix6GroupGroup")) - { - fGroupGroupExists = TRUE; - } - // // loop through all the groups // @@ -230,21 +365,26 @@ HRESULT ScaGroupRead( psg->isAction = isAction; hr = ::StringCchCopyW(psg->wzComponent, countof(psg->wzComponent), pwzData); ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); + ReleaseNullStr(pwzData); hr = WcaGetRecordString(hRec, vagqGroup, &pwzData); ExitOnFailure(hr, "failed to get Wix4Group.Group"); hr = ::StringCchCopyW(psg->wzKey, countof(psg->wzKey), pwzData); ExitOnFailure(hr, "failed to copy group key: %ls", pwzData); + ReleaseNullStr(pwzData); hr = WcaGetRecordFormattedString(hRec, vagqName, &pwzData); ExitOnFailure(hr, "failed to get Wix4Group.Name"); hr = ::StringCchCopyW(psg->wzName, countof(psg->wzName), pwzData); ExitOnFailure(hr, "failed to copy group name: %ls", pwzData); + ReleaseNullStr(pwzData); hr = WcaGetRecordFormattedString(hRec, vagqDomain, &pwzData); ExitOnFailure(hr, "failed to get Wix4Group.Domain"); hr = ::StringCchCopyW(psg->wzDomain, countof(psg->wzDomain), pwzData); ExitOnFailure(hr, "failed to copy group domain: %ls", pwzData); + ReleaseNullStr(pwzData); + hr = WcaGetRecordFormattedString(hRec, vagqComment, &pwzData); ExitOnFailure(hr, "failed to get Wix6Group.Comment"); hr = ::StringCchCopyW(psg->wzComment, countof(psg->wzComment), pwzData); @@ -253,36 +393,9 @@ HRESULT ScaGroupRead( hr = WcaGetRecordInteger(hRec, vagqAttributes, &psg->iAttributes); ExitOnFailure(hr, "failed to get Wix6Group.Attributes"); - // Check if this group is to be added to any other groups - if (fGroupGroupExists) - { - hGroupRec = ::MsiCreateRecord(1); - hr = WcaSetRecordString(hGroupRec, 1, psg->wzKey); - ExitOnFailure(hr, "Failed to create group record for querying Wix6GroupGroup table"); - - hr = WcaOpenExecuteView(vcsGroupGroupQuery, &hGroupGroupView); - ExitOnFailure(hr, "Failed to open view on Wix6GroupGroup table for group %ls", psg->wzKey);/* - hr = WcaExecuteView(hGroupGroupView, hGroupRec); - ExitOnFailure(hr, "Failed to execute view on Wix6GroupGroup table for group: %ls", psg->wzKey);*/ + ScaGroupGetParents(psg); - while (S_OK == (hr = WcaFetchRecord(hGroupGroupView, &hRec))) - { - hr = WcaGetRecordString(hRec, vggqParent, &pwzData); - ExitOnFailure(hr, "failed to get Wix6GroupGroup.Parent"); - - hr = AddGroupToList(&(psg->psgGroups)); - ExitOnFailure(hr, "failed to add group to list"); - - hr = ScaGetGroup(pwzData, psg->psgGroups); - ExitOnFailure(hr, "failed to get information for group: %ls", pwzData); - } - - if (E_NOMOREITEMS == hr) - { - hr = S_OK; - } - ExitOnFailure(hr, "failed to enumerate selected rows from Wix4UserGroup table"); - } + ScaGroupGetChildren(psg); } } @@ -301,7 +414,6 @@ LExit: /* **************************************************************** ScaGroupExecute - Schedules group account creation or removal based on component state. - ******************************************************************/ HRESULT ScaGroupExecute( __in SCA_GROUP *psgList @@ -428,7 +540,7 @@ HRESULT ScaGroupExecute( hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); ExitOnFailure(hr, "failed to add group attributes to rollback custom action data for group: %ls", psg->wzKey); - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateGroupRollback"), pwzRollbackData, COST_GROUP_DELETE); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"CreateGroupRollback"), pwzRollbackData, COST_GROUP_DELETE); ExitOnFailure(hr, "failed to schedule CreateGroupRollback"); } else @@ -441,7 +553,7 @@ HRESULT ScaGroupExecute( // // Schedule the creation now. // - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateGroup"), pwzActionData, COST_GROUP_ADD); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"CreateGroup"), pwzActionData, COST_GROUP_ADD); ExitOnFailure(hr, "failed to schedule CreateGroup"); } else if (((GROUP_EXISTS_YES == geGroupExists) @@ -457,7 +569,7 @@ HRESULT ScaGroupExecute( // // Note: We can't rollback the removal of a group which is why RemoveGroup is a commit // CustomAction. - hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RemoveGroup"), pwzActionData, COST_GROUP_DELETE); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"RemoveGroup"), pwzActionData, COST_GROUP_DELETE); ExitOnFailure(hr, "failed to schedule RemoveGroup"); } @@ -501,3 +613,219 @@ static HRESULT AddGroupToList( LExit: return hr; } + +/* **************************************************************** +ScaGroupMembershipRemoveParentsExecute - Schedules group membership removal +based on parent/child component state +******************************************************************/ +HRESULT ScaGroupMembershipRemoveParentsExecute( + __in SCA_GROUP* psg +) +{ + HRESULT hr = S_OK; + LPWSTR pwzActionData = NULL; + + for (SCA_GROUP* psgp = psg->psgParents; psgp; psgp = psgp->psgNext) + { + Assert(psgp->wzName); + if (WcaIsUninstalling(psg->isInstalled, psg->isAction) + || WcaIsUninstalling(psgp->isInstalled, psgp->isAction)) + { + hr = WcaWriteStringToCaData(psgp->wzName, &pwzActionData); + ExitOnFailure(hr, "Failed to add parent group name to custom action data: %ls", psgp->wzName); + hr = WcaWriteStringToCaData(psgp->wzDomain, &pwzActionData); + ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psgp->wzDomain); + hr = WcaWriteStringToCaData(psg->wzName, &pwzActionData); + ExitOnFailure(hr, "Failed to add child group name to custom action data: %ls", psg->wzName); + hr = WcaWriteStringToCaData(psg->wzDomain, &pwzActionData); + ExitOnFailure(hr, "Failed to add child group domain to custom action data: %ls", psg->wzDomain); + hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData); + ExitOnFailure(hr, "Failed to add group attributes to custom action data: %i", psg->iAttributes); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"RemoveGroupMembership"), pwzActionData, COST_GROUPMEMBERSHIP_DELETE); + + LExit: + ReleaseNullStr(pwzActionData); + if (hr != S_OK && !(psg->iAttributes & SCAG_NON_VITAL)) + { + return hr; + } + } + } + return S_OK; +} + +/* **************************************************************** +ScaGroupMembershipRemoveChildrenExecute - +******************************************************************/ +HRESULT ScaGroupMembershipRemoveChildrenExecute( + __in SCA_GROUP* psg +) +{ + HRESULT hr = S_OK; + LPWSTR pwzActionData = NULL; + + for (SCA_GROUP* psgc = psg->psgChildren; psgc; psgc = psgc->psgNext) + { + Assert(psgc->wzName); + if (WcaIsUninstalling(psg->isInstalled, psg->isAction) + || WcaIsUninstalling(psgc->isInstalled, psgc->isAction)) + { + hr = WcaWriteStringToCaData(psg->wzName, &pwzActionData); + ExitOnFailure(hr, "Failed to add parent group name to custom action data: %ls", psg->wzName); + hr = WcaWriteStringToCaData(psg->wzDomain, &pwzActionData); + ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psg->wzDomain); + hr = WcaWriteStringToCaData(psgc->wzName, &pwzActionData); + ExitOnFailure(hr, "Failed to add child group name to custom action data: %ls", psgc->wzName); + hr = WcaWriteStringToCaData(psgc->wzDomain, &pwzActionData); + ExitOnFailure(hr, "Failed to add child group domain to custom action data: %ls", psgc->wzDomain); + hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData); + ExitOnFailure(hr, "Failed to add group attributes to custom action data: %i", psg->iAttributes); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"RemoveGroupMembership"), pwzActionData, COST_GROUPMEMBERSHIP_DELETE); + + LExit: + ReleaseNullStr(pwzActionData); + + if (hr != S_OK && !(psg->iAttributes & SCAG_NON_VITAL)) + { + return hr; + } + } + } + return S_OK; +} + +/* **************************************************************** +ScaGroupMembershipRemoveExecute - Schedules group membership removal +based on parent/child component state +******************************************************************/ +HRESULT ScaGroupMembershipRemoveExecute( + __in SCA_GROUP* psgList +) +{ + HRESULT hr = S_OK; + + // Loop through all the users to be configured. + for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext) + { + Assert(psg->wzName); + // first we loop through the Parents + hr = ScaGroupMembershipRemoveParentsExecute(psg); + ExitOnFailure(hr, "Failed to remove parent membership for vital group: %ls", psg->wzKey); + + // then through the Children + hr = ScaGroupMembershipRemoveChildrenExecute(psg); + ExitOnFailure(hr, "Failed to remove child membership for vital group: %ls", psg->wzKey); + } + +LExit: + return hr; +} + +/* **************************************************************** +ScaGroupMembershipAddParentsExecute - Schedules group membership removal +based on parent/child component state +******************************************************************/ +HRESULT ScaGroupMembershipAddParentsExecute( + __in SCA_GROUP* psg +) +{ + HRESULT hr = S_OK; + LPWSTR pwzActionData = NULL; + + for (SCA_GROUP* psgp = psg->psgParents; psgp; psgp = psgp->psgNext) + { + Assert(psgp->wzName); + if (WcaIsInstalling(psg->isInstalled, psg->isAction) + || WcaIsInstalling(psgp->isInstalled, psgp->isAction)) + { + hr = WcaWriteStringToCaData(psgp->wzName, &pwzActionData); + ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psgp->wzName); + hr = WcaWriteStringToCaData(psgp->wzDomain, &pwzActionData); + ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psgp->wzDomain); + hr = WcaWriteStringToCaData(psg->wzName, &pwzActionData); + ExitOnFailure(hr, "Failed to add child group name to custom action data: %ls", psg->wzName); + hr = WcaWriteStringToCaData(psg->wzDomain, &pwzActionData); + ExitOnFailure(hr, "Failed to add child group domain to custom action data: %ls", psg->wzDomain); + hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData); + ExitOnFailure(hr, "Failed to add group attributes to custom action data: %i", psg->iAttributes); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"AddGroupMembership"), pwzActionData, COST_GROUPMEMBERSHIP_ADD); + + LExit: + ReleaseNullStr(pwzActionData); + + if (hr != S_OK && !(psg->iAttributes & SCAG_NON_VITAL)) + { + return hr; + } + } + } + return S_OK; +} + +/* **************************************************************** +ScaGroupMembershipAddChildrenExecute - Schedules group membership removal +based on parent/child component state +******************************************************************/ +HRESULT ScaGroupMembershipAddChildrenExecute( + __in SCA_GROUP* psg +) +{ + HRESULT hr = S_OK; + LPWSTR pwzActionData = NULL; + + // then through the Children + for (SCA_GROUP* psgc = psg->psgChildren; psgc; psgc = psgc->psgNext) + { + Assert(psgc->wzName); + if (WcaIsInstalling(psg->isInstalled, psg->isAction) + || WcaIsInstalling(psgc->isInstalled, psgc->isAction)) + { + hr = WcaWriteStringToCaData(psg->wzName, &pwzActionData); + ExitOnFailure(hr, "Failed to add child group name to custom action data: %ls", psg->wzName); + hr = WcaWriteStringToCaData(psg->wzDomain, &pwzActionData); + ExitOnFailure(hr, "Failed to add child group domain to custom action data: %ls", psg->wzDomain); + hr = WcaWriteStringToCaData(psgc->wzName, &pwzActionData); + ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psgc->wzName); + hr = WcaWriteStringToCaData(psgc->wzDomain, &pwzActionData); + ExitOnFailure(hr, "Failed to add parent group domain to custom action data: %ls", psgc->wzDomain); + hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData); + ExitOnFailure(hr, "Failed to add group attributes to custom action data: %i", psg->iAttributes); + hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION6(L"AddGroupMembership"), pwzActionData, COST_GROUPMEMBERSHIP_ADD); + + LExit: + ReleaseNullStr(pwzActionData); + if (hr != S_OK && !(psg->iAttributes & SCAG_NON_VITAL)) + { + return hr; + } + } + } + return S_OK; +} + +/* **************************************************************** +ScaGroupMembershipAddExecute - Schedules group membership addition +based on parent/child component state +******************************************************************/ +HRESULT ScaGroupMembershipAddExecute( + __in SCA_GROUP* psgList +) +{ + HRESULT hr = S_OK; + + // Loop through all the users to be configured. + for (SCA_GROUP* psg = psgList; psg; psg = psg->psgNext) + { + Assert(psg->wzName); + // first we loop through the Parents + hr = ScaGroupMembershipAddParentsExecute(psg); + ExitOnFailure(hr, "Failed to add parent membership for vital group: %ls", psg->wzKey); + + // then through the Children + hr = ScaGroupMembershipAddChildrenExecute(psg); + ExitOnFailure(hr, "Failed to add child membership for vital group: %ls", psg->wzKey); + } + +LExit: + return hr; +} 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 WCHAR wzComment[MAX_DARWIN_COLUMN + 1]; INT iAttributes; - SCA_GROUP* psgGroups; + SCA_GROUP* psgParents; + SCA_GROUP* psgChildren; SCA_GROUP *psgNext; }; + // prototypes HRESULT __stdcall ScaGetGroup( __in LPCWSTR wzGroup, @@ -42,6 +44,12 @@ void ScaGroupFreeList( HRESULT ScaGroupRead( __inout SCA_GROUP** ppsgList ); +HRESULT ScaGroupMembershipRemoveExecute( + __in SCA_GROUP* psgList + ); +HRESULT ScaGroupMembershipAddExecute( + __in SCA_GROUP* psgList +); HRESULT ScaGroupExecute( __in SCA_GROUP*psgList ); 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 @@ // 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. #include "precomp.h" -#include "scanet.h" HRESULT GetDomainServerName(LPCWSTR pwzDomain, LPWSTR* ppwzServerName, ULONG flags) @@ -25,16 +24,16 @@ HRESULT GetDomainServerName(LPCWSTR pwzDomain, LPWSTR* ppwzServerName, ULONG fla if ('\\' == *pDomainControllerInfo->DomainControllerName && '\\' == *pDomainControllerInfo->DomainControllerName + 1) { hr = StrAllocString(ppwzServerName, pDomainControllerInfo->DomainControllerName + 2, 0); - ExitOnFailure(hr, "failed to allocate memory for string"); } else { hr = StrAllocString(ppwzServerName, pDomainControllerInfo->DomainControllerName, 0); - ExitOnFailure(hr, "failed to allocate memory for string"); } + ExitOnFailure(hr, "failed to allocate memory for string"); } else { + // we won't report any potential string allocation failure, the domain failure is more interesting StrAllocString(ppwzServerName, pwzDomain, 0); hr = HRESULT_FROM_WIN32(er); 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( hr = ScaGroupRead(&psgList); ExitOnFailure(hr, "failed to read Wix4Group,Wix6Group table(s)"); + hr = ScaGroupMembershipRemoveExecute(psgList); + ExitOnFailure(hr, "failed to remove Group Memberships") + hr = ScaGroupExecute(psgList); ExitOnFailure(hr, "failed to add/remove Group actions"); + hr = ScaGroupMembershipAddExecute(psgList); + ExitOnFailure(hr, "failed to add Group Memberships") + LExit: if (psgList) { 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 CreateGroup CreateGroupRollback RemoveGroup + AddGroupMembership + AddGroupMembershipRollback + RemoveGroupMembership + RemoveGroupMembershipRollback CreateUser CreateUserRollback 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 WixAssert.CompareLineByLine(new[] { "Binary:Wix4UtilCA_X64\t[Binary data]", - "CustomAction:Wix4ConfigureGroups_X64\t1\tWix4UtilCA_X64\tConfigureGroups\t", - "CustomAction:Wix4CreateGroup_X64\t11265\tWix4UtilCA_X64\tCreateGroup\t", - "CustomAction:Wix4CreateGroupRollback_X64\t11521\tWix4UtilCA_X64\tCreateGroupRollback\t", - "CustomAction:Wix4RemoveGroup_X64\t11841\tWix4UtilCA_X64\tRemoveGroup\t", + "CustomAction:Wix6ConfigureGroups_X64\t1\tWix4UtilCA_X64\tConfigureGroups\t", + "CustomAction:Wix6CreateGroup_X64\t3073\tWix4UtilCA_X64\tCreateGroup\t", + "CustomAction:Wix6CreateGroupRollback_X64\t3329\tWix4UtilCA_X64\tCreateGroupRollback\t", + "CustomAction:Wix6RemoveGroup_X64\t3649\tWix4UtilCA_X64\tRemoveGroup\t", "Wix4Group:TEST_GROUP00\tComponent1\ttestName00\t", "Wix4Group:TEST_GROUP01\tComponent1\ttestName01\t", "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 if (null != componentId) { - this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureGroups", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix6ConfigureGroups", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); } foreach (var child in element.Elements()) @@ -1488,7 +1488,7 @@ namespace WixToolset.Util this.ParseGroupRefElement(intermediate, section, child, id.Id, groupType:true); break; default: - //this.ParseHelper.UnexpectedElement(element, child); + this.ParseHelper.UnexpectedElement(element, child); break; } } @@ -1561,6 +1561,9 @@ namespace WixToolset.Util } else { + // Add reference to bring in fragment + this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix6AddGroupMembership", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); + section.AddSymbol(new GroupGroupSymbol(sourceLineNumbers) { 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 { foreach (var row in table.Rows) { + var parentId = row.FieldAsString(0); + var parentExists = this.DecompilerHelper.TryGetIndexedElement("Group", parentId, out var parentGroup); + var childId = row.FieldAsString(1); - if (this.DecompilerHelper.TryGetIndexedElement("Group", childId, out var group)) + var childExists = this.DecompilerHelper.TryGetIndexedElement("Group", childId, out var childGroup); + + if (parentExists && childExists) { - group.Add(new XElement(UtilConstants.GroupRefName, new XAttribute("Id", row.FieldAsString(0)))); + childGroup.Add(new XElement(UtilConstants.GroupRefName, new XAttribute("Id", parentId))); } else { - this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(), "Parent_", childId, "Group")); + if(!parentExists) + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(), "Parent_", parentId, "Group")); + } + if (!childExists) + { + this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(), "Child_", childId, "Group")); + } } } } 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,11 +17,16 @@ - + + + + + + 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,18 +134,24 @@ - - - - + + + - - + - + + + + + + + + + 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 @@ - + 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 @@ - + 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 @@ #else #define CUSTOM_ACTION_DECORATION5(f) L"Wix5" f L"_X86" #endif + +#if defined(_M_ARM64) +#define CUSTOM_ACTION_DECORATION6(f) L"Wix6" f L"_A64" +#elif defined(_M_AMD64) +#define CUSTOM_ACTION_DECORATION6(f) L"Wix6" f L"_X64" +#elif defined(_M_ARM) +#define CUSTOM_ACTION_DECORATION6(f) L"Wix6" f L"_ARM" +#else +#define CUSTOM_ACTION_DECORATION6(f) L"Wix6" f L"_X86" +#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 @@ + + + + + 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 /// list of groups to check for membership private static void IsMemberOf(string domainName, string memberName, bool shouldBeMember, params string[] groupNames) { - GroupPrincipal group = GetGroup(domainName, memberName); + Principal group = GetPrincipal(domainName, memberName); Assert.False(null == group, String.Format("Group '{0}' was not found under domain '{1}'.", memberName, domainName)); bool missedAGroup = false; @@ -186,11 +186,29 @@ namespace WixTestTools { if (String.IsNullOrEmpty(domainName)) { - return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Machine), IdentityType.Name, groupName); + return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Machine), groupName); } else { - return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain,domainName), IdentityType.Name, groupName); + return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain,domainName), groupName); + } + } + + /// + /// Returns the Principal object for a given name + /// + /// Domain name to look under, if Empty the LocalMachine is assumed as the domain + /// + /// Principal Object if found, or null other wise + private static Principal GetPrincipal(string domainName, string name) + { + if (String.IsNullOrEmpty(domainName)) + { + return Principal.FindByIdentity(new PrincipalContext(ContextType.Machine), name); + } + else + { + return Principal.FindByIdentity(new PrincipalContext(ContextType.Domain, domainName), name); } } } 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 @@ - + 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 @@ - + 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 @@ - + - + @@ -26,8 +26,6 @@ - - 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 productNestedGroups.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); // Verify group nested membership - UserGroupVerifier.VerifyIsMemberOf(String.Empty, "Administrators", new string[] { "testName1", "testName2" }); - UserGroupVerifier.VerifyIsMemberOf(String.Empty, "Power Users", new string[] { "testName1" }); + UserGroupVerifier.VerifyIsMemberOf(String.Empty, "Authenticated Users", new string[] { "testName1", "testName2" }); + UserGroupVerifier.VerifyIsMemberOf(String.Empty, "Everyone", new string[] { "testName1" }); - UserGroupVerifier.VerifyIsNotMemberOf(String.Empty, "Administrators", new string[] { "testName3" }); - UserGroupVerifier.VerifyIsNotMemberOf(String.Empty, "Power Users", new string[] { "testName2", "testName3" }); + UserGroupVerifier.VerifyIsNotMemberOf(String.Empty, "Authenticated Users", new string[] { "testName3" }); + UserGroupVerifier.VerifyIsNotMemberOf(String.Empty, "Everyone", new string[] { "testName2", "testName3" }); // clean up UserGroupVerifier.DeleteLocalGroup("testName1"); -- cgit v1.2.3-55-g6feb