diff --git a/src/ext/Util/ca/scacost.h b/src/ext/Util/ca/scacost.h index 978e40bc3..d10860057 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 cc54150ba..136828aa3 100644 --- a/src/ext/Util/ca/scaexec.cpp +++ b/src/ext/Util/ca/scaexec.cpp @@ -293,146 +293,6 @@ static HRESULT RemoveUserFromGroup( 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, @@ -866,7 +726,6 @@ static HRESULT RemoveUserInternal( } static HRESULT RemoveGroupInternal( - LPWSTR wzGroupCaData, LPWSTR wzDomain, LPWSTR wzName, int iAttributes @@ -874,9 +733,6 @@ static HRESULT RemoveGroupInternal( { HRESULT hr = S_OK; - LPWSTR pwz = NULL; - LPWSTR pwzGroup = NULL; - LPWSTR pwzGroupDomain = NULL; LPWSTR pwzServerName = NULL; // @@ -895,41 +751,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; } @@ -1414,6 +1238,7 @@ extern "C" UINT __stdcall RemoveUser( return WcaFinalize(er); } + /******************************************************************** CreateGroup - CUSTOM ACTION ENTRY POINT for creating groups @@ -1434,8 +1259,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; @@ -1575,24 +1398,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: @@ -1608,8 +1413,6 @@ extern "C" UINT __stdcall CreateGroup( ReleaseStr(pwzDomain); ReleaseStr(pwzComment); ReleaseStr(pwzScriptKey); - ReleaseStr(pwzGroup); - ReleaseStr(pwzGroupDomain); if (fInitializedCom) { @@ -1726,7 +1529,7 @@ extern "C" UINT __stdcall CreateGroupRollback( } } - hr = RemoveGroupInternal(pwz, pwzDomain, pwzName, iAttributes); + hr = RemoveGroupInternal(pwzDomain, pwzName, iAttributes); LExit: WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); @@ -1803,7 +1606,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); @@ -1823,3 +1626,254 @@ extern "C" UINT __stdcall RemoveGroup( 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 c484c1d2c..3d2c3bebe 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 @@ HRESULT ScaGroupRead( /* **************************************************************** 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 8666d8521..e16d7a95e 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 11ee487de..1198280fa 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,17 +24,17 @@ 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 { - StrAllocString(ppwzServerName, pwzDomain, 0); + hr = StrAllocString(ppwzServerName, pwzDomain, 0); + ExitOnFailure(hr, "failed to allocate memory for string"); 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 1351fbfde..cef7fecba 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 18a19d12e..2aeb54f4c 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 d71dd8244..c9a184ab8 100644 --- a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs +++ b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs @@ -404,10 +404,10 @@ public void CanCreateUserGroupWithComment() 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 aff7dd0da..4b1e43b52 100644 --- a/src/ext/Util/wixext/UtilCompiler.cs +++ b/src/ext/Util/wixext/UtilCompiler.cs @@ -1475,7 +1475,7 @@ private void ParseGroupElement(Intermediate intermediate, IntermediateSection se 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 @@ private void ParseGroupElement(Intermediate intermediate, IntermediateSection se 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 @@ private void ParseGroupRefElement(Intermediate intermediate, IntermediateSection } 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 53b75b8d8..a236ece91 100644 --- a/src/ext/Util/wixext/UtilDecompiler.cs +++ b/src/ext/Util/wixext/UtilDecompiler.cs @@ -478,14 +478,26 @@ private void DecompileGroupGroup6Table(Table table) { 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 c812f73d4..f459d51af 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 df53c7d4b..71166d4fc 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/caDecor.h b/src/ext/caDecor.h index 060032cf8..4a09e0759 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 256d7586b..236b21540 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 2f874057b..52a1a6bfb 100644 --- a/src/test/burn/WixTestTools/UserGroupVerifier.cs +++ b/src/test/burn/WixTestTools/UserGroupVerifier.cs @@ -151,7 +151,7 @@ public static void VerifyIsNotMemberOf(string domainName, string memberName, par /// 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 @@ private static GroupPrincipal GetGroup(string domainName, string groupName) { 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 29b908da0..4e70717f8 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 fb35bc1e1..3013e5a02 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 191d605c0..15328cb32 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 796c4ecdf..d7cf31682 100644 --- a/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionGroupTests.cs +++ b/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionGroupTests.cs @@ -256,11 +256,11 @@ public void CanNestGroups() 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");