// 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" // private typedefs typedef HRESULT (__stdcall *MQCreateQueueFunc)(PSECURITY_DESCRIPTOR, MQQUEUEPROPS*, LPWSTR, LPDWORD); typedef HRESULT (__stdcall *MQDeleteQueueFunc)(LPCWSTR); typedef HRESULT (__stdcall *MQPathNameToFormatNameFunc)(LPCWSTR, LPWSTR, LPDWORD); typedef HRESULT (__stdcall *MQGetQueueSecurityFunc)(LPCWSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, LPDWORD); typedef HRESULT (__stdcall *MQSetQueueSecurityFunc)(LPCWSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); // private enums enum eMessageQueueAttributes { mqaAuthenticate = (1 << 0), mqaJournal = (1 << 1), mqaTransactional = (1 << 2) }; enum eMessageQueuePrivacyLevel { mqplNone = 0, mqplOptional = 1, mqplBody = 2 }; enum eMessageQueuePermission { mqpDeleteMessage = (1 << 0), mqpPeekMessage = (1 << 1), mqpWriteMessage = (1 << 2), mqpDeleteJournalMessage = (1 << 3), mqpSetQueueProperties = (1 << 4), mqpGetQueueProperties = (1 << 5), mqpDeleteQueue = (1 << 6), mqpGetQueuePermissions = (1 << 7), mqpChangeQueuePermissions = (1 << 8), mqpTakeQueueOwnership = (1 << 9), mqpReceiveMessage = (1 << 10), mqpReceiveJournalMessage = (1 << 11), mqpQueueGenericRead = (1 << 12), mqpQueueGenericWrite = (1 << 13), mqpQueueGenericExecute = (1 << 14), mqpQueueGenericAll = (1 << 15) }; // private structs struct MQI_MESSAGE_QUEUE_ATTRIBUTES { LPWSTR pwzKey; int iBasePriority; int iJournalQuota; LPWSTR pwzLabel; LPWSTR pwzMulticastAddress; LPWSTR pwzPathName; int iPrivLevel; int iQuota; LPWSTR pwzServiceTypeGuid; int iAttributes; }; struct MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES { LPWSTR pwzKey; LPWSTR pwzPathName; LPWSTR pwzDomain; LPWSTR pwzName; int iPermissions; }; // prototypes for private helper functions static HRESULT ReadMessageQueueAttributes( LPWSTR* ppwzData, MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs ); static void FreeMessageQueueAttributes( MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs ); static HRESULT ReadMessageQueuePermissionAttributes( LPWSTR* ppwzData, MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs ); static void FreeMessageQueuePermissionAttributes( MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs ); static HRESULT CreateMessageQueue( MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs ); static HRESULT DeleteMessageQueue( MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs ); static HRESULT SetMessageQueuePermissions( MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs, BOOL fRevoke ); static void SetAccessPermissions( int iPermissions, LPDWORD pgrfAccessPermissions ); // private variables static HMODULE ghMQRT; static MQCreateQueueFunc gpfnMQCreateQueue; static MQDeleteQueueFunc gpfnMQDeleteQueue; static MQPathNameToFormatNameFunc gpfnMQPathNameToFormatName; static MQGetQueueSecurityFunc gpfnMQGetQueueSecurity; static MQSetQueueSecurityFunc gpfnMQSetQueueSecurity; // function definitions HRESULT MqiExecInitialize() { HRESULT hr = S_OK; // load mqrt.dll ghMQRT = ::LoadLibraryW(L"mqrt.dll"); ExitOnNull(ghMQRT, hr, E_FAIL, "Failed to load mqrt.dll"); // get MQCreateQueue function address gpfnMQCreateQueue = (MQCreateQueueFunc)::GetProcAddress(ghMQRT, "MQCreateQueue"); ExitOnNull(gpfnMQCreateQueue, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQCreateQueue() function"); // get MQDeleteQueue function address gpfnMQDeleteQueue = (MQDeleteQueueFunc)::GetProcAddress(ghMQRT, "MQDeleteQueue"); ExitOnNull(gpfnMQDeleteQueue, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQDeleteQueue() function"); // get MQPathNameToFormatName function address gpfnMQPathNameToFormatName = (MQPathNameToFormatNameFunc)::GetProcAddress(ghMQRT, "MQPathNameToFormatName"); ExitOnNull(gpfnMQPathNameToFormatName, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQPathNameToFormatName() function"); // get MQGetQueueSecurity function address gpfnMQGetQueueSecurity = (MQGetQueueSecurityFunc)::GetProcAddress(ghMQRT, "MQGetQueueSecurity"); ExitOnNull(gpfnMQGetQueueSecurity, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQGetQueueSecurity() function"); // get MQSetQueueSecurity function address gpfnMQSetQueueSecurity = (MQSetQueueSecurityFunc)::GetProcAddress(ghMQRT, "MQSetQueueSecurity"); ExitOnNull(gpfnMQSetQueueSecurity, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQSetQueueSecurity() function"); hr = S_OK; LExit: return hr; } void MqiExecUninitialize() { if (ghMQRT) ::FreeLibrary(ghMQRT); } HRESULT MqiCreateMessageQueues( LPWSTR* ppwzData ) { HRESULT hr = S_OK; int iCnt = 0; MQI_MESSAGE_QUEUE_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // ger count hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadMessageQueueAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // progress message hr = PcaActionDataMessage(1, attrs.pwzPathName); ExitOnFailure(hr, "Failed to send progress messages, key: %S", attrs.pwzKey); // create message queue hr = CreateMessageQueue(&attrs); ExitOnFailure(hr, "Failed to create message queue, key: %S", attrs.pwzKey); // progress tics hr = WcaProgressMessage(COST_MESSAGE_QUEUE_CREATE, FALSE); ExitOnFailure(hr, "Failed to update progress"); } hr = S_OK; LExit: // clean up FreeMessageQueueAttributes(&attrs); return hr; } HRESULT MqiRollbackCreateMessageQueues( LPWSTR* ppwzData ) { HRESULT hr = S_OK; int iCnt = 0; MQI_MESSAGE_QUEUE_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // ger count hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadMessageQueueAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // create message queue hr = DeleteMessageQueue(&attrs); if (FAILED(hr)) WcaLog(LOGMSG_STANDARD, "Failed to delete message queue, hr: 0x%x, key: %S", hr, attrs.pwzKey); } hr = S_OK; LExit: // clean up FreeMessageQueueAttributes(&attrs); return hr; } HRESULT MqiDeleteMessageQueues( LPWSTR* ppwzData ) { HRESULT hr = S_OK; int iCnt = 0; MQI_MESSAGE_QUEUE_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // ger count hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadMessageQueueAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // progress message hr = PcaActionDataMessage(1, attrs.pwzPathName); ExitOnFailure(hr, "Failed to send progress messages, key: %S", attrs.pwzKey); // create message queue hr = DeleteMessageQueue(&attrs); if (FAILED(hr)) { WcaLog(LOGMSG_STANDARD, "Failed to delete queue, hr: 0x%x, key: %S", hr, attrs.pwzKey); continue; } // progress tics hr = WcaProgressMessage(COST_MESSAGE_QUEUE_DELETE, FALSE); ExitOnFailure(hr, "Failed to update progress"); } hr = S_OK; LExit: // clean up FreeMessageQueueAttributes(&attrs); return hr; } HRESULT MqiRollbackDeleteMessageQueues( LPWSTR* ppwzData ) { HRESULT hr = S_OK; int iCnt = 0; MQI_MESSAGE_QUEUE_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // ger count hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadMessageQueueAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // create message queue hr = CreateMessageQueue(&attrs); if (FAILED(hr)) WcaLog(LOGMSG_STANDARD, "Failed to create message queue, hr: 0x%x, key: %S", hr, attrs.pwzKey); } hr = S_OK; LExit: // clean up FreeMessageQueueAttributes(&attrs); return hr; } HRESULT MqiAddMessageQueuePermissions( LPWSTR* ppwzData ) { HRESULT hr = S_OK; int iCnt = 0; MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // ger count hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // progress message hr = PcaActionDataMessage(1, attrs.pwzPathName); ExitOnFailure(hr, "Failed to send progress messages"); // add message queue permission hr = SetMessageQueuePermissions(&attrs, FALSE); ExitOnFailure(hr, "Failed to add message queue permission"); // progress tics hr = WcaProgressMessage(COST_MESSAGE_QUEUE_PERMISSION_ADD, FALSE); ExitOnFailure(hr, "Failed to update progress"); } hr = S_OK; LExit: // clean up FreeMessageQueuePermissionAttributes(&attrs); return hr; } HRESULT MqiRollbackAddMessageQueuePermissions( LPWSTR* ppwzData ) { HRESULT hr = S_OK; int iCnt = 0; MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // ger count hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // add message queue permission hr = SetMessageQueuePermissions(&attrs, TRUE); if (FAILED(hr)) WcaLog(LOGMSG_STANDARD, "Failed to rollback add message queue permission, hr: 0x%x, key: %S", hr, attrs.pwzKey); } hr = S_OK; LExit: // clean up FreeMessageQueuePermissionAttributes(&attrs); return hr; } HRESULT MqiRemoveMessageQueuePermissions( LPWSTR* ppwzData ) { HRESULT hr = S_OK; int iCnt = 0; MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // ger count hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // progress message hr = PcaActionDataMessage(1, attrs.pwzPathName); ExitOnFailure(hr, "Failed to send progress messages"); // add message queue permission hr = SetMessageQueuePermissions(&attrs, TRUE); ExitOnFailure(hr, "Failed to remove message queue permission"); // progress tics hr = WcaProgressMessage(COST_MESSAGE_QUEUE_PERMISSION_ADD, FALSE); ExitOnFailure(hr, "Failed to update progress"); } hr = S_OK; LExit: // clean up FreeMessageQueuePermissionAttributes(&attrs); return hr; } HRESULT MqiRollbackRemoveMessageQueuePermissions( LPWSTR* ppwzData ) { HRESULT hr = S_OK; int iCnt = 0; MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs; ::ZeroMemory(&attrs, sizeof(attrs)); // ger count hr = WcaReadIntegerFromCaData(ppwzData, &iCnt); ExitOnFailure(hr, "Failed to read count"); for (int i = 0; i < iCnt; i++) { // read attributes from CustomActionData hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs); ExitOnFailure(hr, "Failed to read attributes"); // add message queue permission hr = SetMessageQueuePermissions(&attrs, FALSE); if (FAILED(hr)) WcaLog(LOGMSG_STANDARD, "Failed to rollback remove message queue permission, hr: 0x%x, key: %S", hr, attrs.pwzKey); } hr = S_OK; LExit: // clean up FreeMessageQueuePermissionAttributes(&attrs); return hr; } // helper function definitions static HRESULT ReadMessageQueueAttributes( LPWSTR* ppwzData, MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; // read message queue information from custom action data hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); ExitOnFailure(hr, "Failed to read key from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iBasePriority); ExitOnFailure(hr, "Failed to read base priority from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iJournalQuota); ExitOnFailure(hr, "Failed to read journal quota from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzLabel); ExitOnFailure(hr, "Failed to read label from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzMulticastAddress); ExitOnFailure(hr, "Failed to read multicast address from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPathName); ExitOnFailure(hr, "Failed to read path name from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iPrivLevel); ExitOnFailure(hr, "Failed to read privacy level from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iQuota); ExitOnFailure(hr, "Failed to read quota from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzServiceTypeGuid); ExitOnFailure(hr, "Failed to read service type guid from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iAttributes); ExitOnFailure(hr, "Failed to read attributes from custom action data"); hr = S_OK; LExit: return hr; } static void FreeMessageQueueAttributes( MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs ) { ReleaseStr(pAttrs->pwzKey); ReleaseStr(pAttrs->pwzLabel); ReleaseStr(pAttrs->pwzMulticastAddress); ReleaseStr(pAttrs->pwzPathName); ReleaseStr(pAttrs->pwzServiceTypeGuid); } static HRESULT ReadMessageQueuePermissionAttributes( LPWSTR* ppwzData, MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; // read message queue permission information from custom action data hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey); ExitOnFailure(hr, "Failed to read key from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPathName); ExitOnFailure(hr, "Failed to read path name from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzDomain); ExitOnFailure(hr, "Failed to read domain from custom action data"); hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName); ExitOnFailure(hr, "Failed to read name from custom action data"); hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iPermissions); ExitOnFailure(hr, "Failed to read permissions from custom action data"); hr = S_OK; LExit: return hr; } static void FreeMessageQueuePermissionAttributes( MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs ) { ReleaseStr(pAttrs->pwzKey); ReleaseStr(pAttrs->pwzPathName); ReleaseStr(pAttrs->pwzDomain); ReleaseStr(pAttrs->pwzName); } static HRESULT CreateMessageQueue( MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; SECURITY_DESCRIPTOR sd; PSID pOwner = NULL; DWORD cbDacl = 0; PACL pDacl = NULL; QUEUEPROPID aPropID[11]; MQPROPVARIANT aPropVar[11]; MQQUEUEPROPS props; GUID guidType; DWORD dwFormatNameLength = 0; ::ZeroMemory(&sd, sizeof(sd)); ::ZeroMemory(aPropID, sizeof(aPropID)); ::ZeroMemory(aPropVar, sizeof(aPropVar)); ::ZeroMemory(&props, sizeof(props)); ::ZeroMemory(&guidType, sizeof(guidType)); // initialize security descriptor if (!::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to initialize security descriptor"); // set security descriptor owner hr = PcaAccountNameToSid(L"\\Administrators", &pOwner); ExitOnFailure(hr, "Failed to get sid for account name"); if (!::SetSecurityDescriptorOwner(&sd, pOwner, FALSE)) ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set security descriptor owner"); // set security descriptor DACL cbDacl = sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + ::GetLengthSid(pOwner); pDacl = (PACL)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, cbDacl); ExitOnNull(pDacl, hr, E_OUTOFMEMORY, "Failed to allocate buffer for DACL"); if (!::InitializeAcl(pDacl, cbDacl, ACL_REVISION)) ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to initialize DACL"); if (!::AddAccessAllowedAce(pDacl, ACL_REVISION, MQSEC_QUEUE_GENERIC_ALL, pOwner)) ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to add ACE to DACL"); if (!::SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE)) ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set security descriptor DACL"); // set property values props.aPropID = aPropID; props.aPropVar = aPropVar; aPropID[0] = PROPID_Q_LABEL; aPropVar[0].vt = VT_LPWSTR; aPropVar[0].pwszVal = pAttrs->pwzLabel; aPropID[1] = PROPID_Q_PATHNAME; aPropVar[1].vt = VT_LPWSTR; aPropVar[1].pwszVal = pAttrs->pwzPathName; aPropID[2] = PROPID_Q_AUTHENTICATE; aPropVar[2].vt = VT_UI1; aPropVar[2].bVal = mqaAuthenticate == (pAttrs->iAttributes & mqaAuthenticate); aPropID[3] = PROPID_Q_JOURNAL; aPropVar[3].vt = VT_UI1; aPropVar[3].bVal = mqaJournal == (pAttrs->iAttributes & mqaJournal); aPropID[4] = PROPID_Q_TRANSACTION; aPropVar[4].vt = VT_UI1; aPropVar[4].bVal = mqaTransactional == (pAttrs->iAttributes & mqaTransactional); props.cProp = 5; if (MSI_NULL_INTEGER != pAttrs->iBasePriority) { aPropID[props.cProp] = PROPID_Q_BASEPRIORITY; aPropVar[props.cProp].vt = VT_I2; aPropVar[props.cProp].iVal = (SHORT)pAttrs->iBasePriority; props.cProp++; } if (MSI_NULL_INTEGER != pAttrs->iJournalQuota) { aPropID[props.cProp] = PROPID_Q_JOURNAL_QUOTA; aPropVar[props.cProp].vt = VT_UI4; aPropVar[props.cProp].ulVal = (ULONG)pAttrs->iJournalQuota; props.cProp++; } if (*pAttrs->pwzMulticastAddress) { aPropID[props.cProp] = PROPID_Q_MULTICAST_ADDRESS; aPropVar[props.cProp].vt = VT_LPWSTR; aPropVar[props.cProp].pwszVal = pAttrs->pwzMulticastAddress; props.cProp++; } if (MSI_NULL_INTEGER != pAttrs->iPrivLevel) { aPropID[props.cProp] = PROPID_Q_PRIV_LEVEL; aPropVar[props.cProp].vt = VT_UI4; switch (pAttrs->iPrivLevel) { case mqplNone: aPropVar[props.cProp].ulVal = MQ_PRIV_LEVEL_NONE; break; case mqplBody: aPropVar[props.cProp].ulVal = MQ_PRIV_LEVEL_BODY; break; case mqplOptional: aPropVar[props.cProp].ulVal = MQ_PRIV_LEVEL_OPTIONAL; break; } props.cProp++; } if (MSI_NULL_INTEGER != pAttrs->iQuota) { aPropID[props.cProp] = PROPID_Q_QUOTA; aPropVar[props.cProp].vt = VT_UI4; aPropVar[props.cProp].ulVal = (ULONG)pAttrs->iQuota; props.cProp++; } if (*pAttrs->pwzServiceTypeGuid) { // parse guid string hr = PcaGuidFromString(pAttrs->pwzServiceTypeGuid, &guidType); ExitOnFailure(hr, "Failed to parse service type GUID string"); aPropID[props.cProp] = PROPID_Q_TYPE; aPropVar[props.cProp].vt = VT_CLSID; aPropVar[props.cProp].puuid = &guidType; props.cProp++; } // create message queue hr = gpfnMQCreateQueue(&sd, &props, NULL, &dwFormatNameLength); ExitOnFailure(hr, "Failed to create message queue"); // log WcaLog(LOGMSG_VERBOSE, "Message queue created, key: %S, PathName: '%S'", pAttrs->pwzKey, pAttrs->pwzPathName); hr = S_OK; LExit: // clean up if (pOwner) ::HeapFree(::GetProcessHeap(), 0, pOwner); if (pDacl) ::HeapFree(::GetProcessHeap(), 0, pDacl); return hr; } static HRESULT DeleteMessageQueue( MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs ) { HRESULT hr = S_OK; LPWSTR pwzFormatName = NULL; DWORD dwCount = 128; // get format name hr = StrAlloc(&pwzFormatName, dwCount); ExitOnFailure(hr, "Failed to allocate format name string"); do { hr = gpfnMQPathNameToFormatName(pAttrs->pwzPathName, pwzFormatName, &dwCount); switch (hr) { case MQ_ERROR_QUEUE_NOT_FOUND: ExitFunction1(hr = S_OK); // nothing to delete case MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL: hr = StrAlloc(&pwzFormatName, dwCount); ExitOnFailure(hr, "Failed to reallocate format name string"); hr = S_FALSE; // retry break; default: ExitOnFailure(hr, "Failed to get format name"); hr = S_OK; } } while (S_FALSE == hr); // delete queue hr = gpfnMQDeleteQueue(pwzFormatName); ExitOnFailure(hr, "Failed to delete queue"); // log WcaLog(LOGMSG_VERBOSE, "Message queue deleted, key: %S, PathName: '%S'", pAttrs->pwzKey, pAttrs->pwzPathName); hr = S_OK; LExit: // clean up ReleaseStr(pwzFormatName); return hr; } static HRESULT SetMessageQueuePermissions( MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs, BOOL fRevoke ) { HRESULT hr = S_OK; DWORD er = ERROR_SUCCESS; DWORD dw = 0; LPWSTR pwzAccount = NULL; LPWSTR pwzFormatName = NULL; PSECURITY_DESCRIPTOR psd = NULL; PSECURITY_DESCRIPTOR ptsd = NULL; PACL pAclExisting = NULL; PACL pAclNew = NULL; BOOL fDaclPresent = FALSE; BOOL fDaclDefaulted = FALSE; PSID psid = NULL; EXPLICIT_ACCESSW ea; SECURITY_DESCRIPTOR sdNew; ::ZeroMemory(&ea, sizeof(ea)); ::ZeroMemory(&sdNew, sizeof(sdNew)); // get format name dw = 128; hr = StrAlloc(&pwzFormatName, dw); ExitOnFailure(hr, "Failed to allocate format name string"); do { hr = gpfnMQPathNameToFormatName(pAttrs->pwzPathName, pwzFormatName, &dw); if (MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL == hr) { hr = StrAlloc(&pwzFormatName, dw); ExitOnFailure(hr, "Failed to reallocate format name string"); hr = S_FALSE; // retry } else { ExitOnFailure(hr, "Failed to get format name"); hr = S_OK; } } while (S_FALSE == hr); // get queue security information dw = 256; psd = (PSECURITY_DESCRIPTOR)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dw); ExitOnNull(psd, hr, E_OUTOFMEMORY, "Failed to allocate buffer for security descriptor"); do { hr = gpfnMQGetQueueSecurity(pwzFormatName, DACL_SECURITY_INFORMATION, psd, dw, &dw); if (MQ_ERROR_SECURITY_DESCRIPTOR_TOO_SMALL == hr) { ptsd = (PSECURITY_DESCRIPTOR)::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, psd, dw); ExitOnNull(ptsd, hr, E_OUTOFMEMORY, "Failed to reallocate buffer for security descriptor"); psd = ptsd; hr = S_FALSE; // retry } else { ExitOnFailure(hr, "Failed to get queue security information"); hr = S_OK; } } while (S_FALSE == hr); // get dacl if (!::GetSecurityDescriptorDacl(psd, &fDaclPresent, &pAclExisting, &fDaclDefaulted)) ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to get DACL for security descriptor"); if (!fDaclPresent || !pAclExisting) ExitOnFailure(hr = E_ACCESSDENIED, "Failed to get DACL for security descriptor, access denied"); // build account name string hr = PcaBuildAccountName(pAttrs->pwzDomain, pAttrs->pwzName, &pwzAccount); ExitOnFailure(hr, "Failed to build account name string"); // get sid for account name hr = PcaAccountNameToSid(pwzAccount, &psid); ExitOnFailure(hr, "Failed to get SID for account name"); // set acl entry SetAccessPermissions(pAttrs->iPermissions, &ea.grfAccessPermissions); ea.grfAccessMode = fRevoke ? REVOKE_ACCESS : SET_ACCESS; ea.grfInheritance = NO_INHERITANCE; ::BuildTrusteeWithSidW(&ea.Trustee, psid); er = ::SetEntriesInAclW(1, &ea, pAclExisting, &pAclNew); ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set ACL entry"); // create new security descriptor if (!::InitializeSecurityDescriptor(&sdNew, SECURITY_DESCRIPTOR_REVISION)) ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to initialize security descriptor"); if (!::SetSecurityDescriptorDacl(&sdNew, TRUE, pAclNew, FALSE)) ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set DACL for security descriptor"); // set queue security information hr = gpfnMQSetQueueSecurity(pwzFormatName, DACL_SECURITY_INFORMATION, &sdNew); ExitOnFailure(hr, "Failed to set queue security information"); // log WcaLog(LOGMSG_VERBOSE, "Permission set for message queue, key: %S, PathName: '%S'", pAttrs->pwzKey, pAttrs->pwzPathName); hr = S_OK; LExit: // clean up ReleaseStr(pwzFormatName); ReleaseStr(pwzAccount); if (psd) ::HeapFree(::GetProcessHeap(), 0, psd); if (psid) ::HeapFree(::GetProcessHeap(), 0, psid); if (pAclNew) ::LocalFree(pAclNew); return hr; } static void SetAccessPermissions( int iPermissions, LPDWORD pgrfAccessPermissions ) { if (iPermissions & mqpDeleteMessage) *pgrfAccessPermissions |= MQSEC_DELETE_MESSAGE; if (iPermissions & mqpPeekMessage) *pgrfAccessPermissions |= MQSEC_PEEK_MESSAGE; if (iPermissions & mqpWriteMessage) *pgrfAccessPermissions |= MQSEC_WRITE_MESSAGE; if (iPermissions & mqpDeleteJournalMessage) *pgrfAccessPermissions |= MQSEC_DELETE_JOURNAL_MESSAGE; if (iPermissions & mqpSetQueueProperties) *pgrfAccessPermissions |= MQSEC_SET_QUEUE_PROPERTIES; if (iPermissions & mqpGetQueueProperties) *pgrfAccessPermissions |= MQSEC_GET_QUEUE_PROPERTIES; if (iPermissions & mqpDeleteQueue) *pgrfAccessPermissions |= MQSEC_DELETE_QUEUE; if (iPermissions & mqpGetQueuePermissions) *pgrfAccessPermissions |= MQSEC_GET_QUEUE_PERMISSIONS; if (iPermissions & mqpChangeQueuePermissions) *pgrfAccessPermissions |= MQSEC_CHANGE_QUEUE_PERMISSIONS; if (iPermissions & mqpTakeQueueOwnership) *pgrfAccessPermissions |= MQSEC_TAKE_QUEUE_OWNERSHIP; if (iPermissions & mqpReceiveMessage) *pgrfAccessPermissions |= MQSEC_RECEIVE_MESSAGE; if (iPermissions & mqpReceiveJournalMessage) *pgrfAccessPermissions |= MQSEC_RECEIVE_JOURNAL_MESSAGE; if (iPermissions & mqpQueueGenericRead) *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_READ; if (iPermissions & mqpQueueGenericWrite) *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_WRITE; if (iPermissions & mqpQueueGenericExecute) *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_EXECUTE; if (iPermissions & mqpQueueGenericAll) *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_ALL; }