From d77dca43e87e8711b19910a8fd49138f939bf0a4 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Tue, 4 May 2021 22:48:58 -0700 Subject: Move Msmq.wixext into ext --- src/ext/Msmq/ca/mqqueueexec.cpp | 927 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 927 insertions(+) create mode 100644 src/ext/Msmq/ca/mqqueueexec.cpp (limited to 'src/ext/Msmq/ca/mqqueueexec.cpp') diff --git a/src/ext/Msmq/ca/mqqueueexec.cpp b/src/ext/Msmq/ca/mqqueueexec.cpp new file mode 100644 index 00000000..e4304ab8 --- /dev/null +++ b/src/ext/Msmq/ca/mqqueueexec.cpp @@ -0,0 +1,927 @@ +// 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; +} -- cgit v1.2.3-55-g6feb