aboutsummaryrefslogtreecommitdiff
path: root/src/ca
diff options
context:
space:
mode:
Diffstat (limited to 'src/ca')
-rw-r--r--src/ca/mqcost.h9
-rw-r--r--src/ca/mqexec.cpp214
-rw-r--r--src/ca/mqqueueexec.cpp927
-rw-r--r--src/ca/mqqueueexec.h30
-rw-r--r--src/ca/mqqueuesched.cpp582
-rw-r--r--src/ca/mqqueuesched.h92
-rw-r--r--src/ca/mqsched.cpp219
-rw-r--r--src/ca/mqutilexec.cpp380
-rw-r--r--src/ca/mqutilexec.h23
-rw-r--r--src/ca/mqutilsched.cpp43
-rw-r--r--src/ca/mqutilsched.h9
11 files changed, 2528 insertions, 0 deletions
diff --git a/src/ca/mqcost.h b/src/ca/mqcost.h
new file mode 100644
index 00000000..a40b7437
--- /dev/null
+++ b/src/ca/mqcost.h
@@ -0,0 +1,9 @@
1#pragma once
2// 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.
3
4
5#define COST_MESSAGE_QUEUE_CREATE 10000
6#define COST_MESSAGE_QUEUE_DELETE 10000
7
8#define COST_MESSAGE_QUEUE_PERMISSION_ADD 10000
9#define COST_MESSAGE_QUEUE_PERMISSION_REMOVE 10000
diff --git a/src/ca/mqexec.cpp b/src/ca/mqexec.cpp
new file mode 100644
index 00000000..bac54f31
--- /dev/null
+++ b/src/ca/mqexec.cpp
@@ -0,0 +1,214 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5/********************************************************************
6 DllMain - standard entry point for all WiX CustomActions
7
8********************************************************************/
9extern "C" BOOL WINAPI DllMain(
10 IN HINSTANCE hInst,
11 IN ULONG ulReason,
12 IN LPVOID)
13{
14 switch(ulReason)
15 {
16 case DLL_PROCESS_ATTACH:
17 WcaGlobalInitialize(hInst);
18 break;
19
20 case DLL_PROCESS_DETACH:
21 WcaGlobalFinalize();
22 break;
23 }
24
25 return TRUE;
26}
27
28/********************************************************************
29 MessageQueuingExecuteInstall - CUSTOM ACTION ENTRY POINT
30
31 Input: deferred CustomActionData - MessageQueuingExecuteInstall
32********************************************************************/
33extern "C" UINT __stdcall MessageQueuingExecuteInstall(MSIHANDLE hInstall)
34{
35 HRESULT hr = S_OK;
36 UINT er = ERROR_SUCCESS;
37
38 LPWSTR pwzCustomActionData = NULL;
39 LPWSTR pwzData = NULL;
40
41 // initialize
42 hr = WcaInitialize(hInstall, "MessageQueuingExecuteInstall");
43 ExitOnFailure(hr, "Failed to initialize MessageQueuingExecuteInstall");
44
45 hr = MqiInitialize();
46 ExitOnFailure(hr, "Failed to initialize");
47
48 // get custom action data
49 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
50 ExitOnFailure(hr, "Failed to get CustomActionData");
51 pwzData = pwzCustomActionData;
52
53 // create message queues
54 hr = MqiCreateMessageQueues(&pwzData);
55 ExitOnFailure(hr, "Failed to create message queues");
56 if (S_FALSE == hr) ExitFunction();
57
58 // add message queue permissions
59 hr = MqiAddMessageQueuePermissions(&pwzData);
60 ExitOnFailure(hr, "Failed to add message queue permissions");
61 if (S_FALSE == hr) ExitFunction();
62
63 hr = S_OK;
64
65LExit:
66 // clean up
67 ReleaseStr(pwzCustomActionData);
68
69 // uninitialize
70 MqiUninitialize();
71
72 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
73 return WcaFinalize(er);
74}
75
76/********************************************************************
77 MessageQueuingRollbackInstall - CUSTOM ACTION ENTRY POINT
78
79 Input: deferred CustomActionData - MessageQueuingRollbackInstall
80********************************************************************/
81extern "C" UINT __stdcall MessageQueuingRollbackInstall(MSIHANDLE hInstall)
82{
83 HRESULT hr = S_OK;
84 UINT er = ERROR_SUCCESS;
85
86 LPWSTR pwzCustomActionData = NULL;
87 LPWSTR pwzData = NULL;
88
89 // initialize
90 hr = WcaInitialize(hInstall, "MessageQueuingRollbackInstall");
91 ExitOnFailure(hr, "Failed to initialize MessageQueuingRollbackInstall");
92
93 hr = MqiInitialize();
94 ExitOnFailure(hr, "Failed to initialize");
95
96 // get custom action data
97 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
98 ExitOnFailure(hr, "Failed to get CustomActionData");
99 pwzData = pwzCustomActionData;
100
101 // add message queue permissions
102 hr = MqiRollbackAddMessageQueuePermissions(&pwzData);
103 ExitOnFailure(hr, "Failed to rollback add message queue permissions");
104
105 // create message queues
106 hr = MqiRollbackCreateMessageQueues(&pwzData);
107 ExitOnFailure(hr, "Failed to rollback create message queues");
108
109 hr = S_OK;
110
111LExit:
112 // clean up
113 ReleaseStr(pwzCustomActionData);
114
115 // uninitialize
116 MqiUninitialize();
117
118 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
119 return WcaFinalize(er);
120}
121
122/********************************************************************
123 MessageQueuingExecuteUninstall - CUSTOM ACTION ENTRY POINT
124
125 Input: deferred CustomActionData - MessageQueuingExecuteUninstall
126********************************************************************/
127extern "C" UINT __stdcall MessageQueuingExecuteUninstall(MSIHANDLE hInstall)
128{
129 HRESULT hr = S_OK;
130 UINT er = ERROR_SUCCESS;
131
132 LPWSTR pwzCustomActionData = NULL;
133 LPWSTR pwzData = NULL;
134
135 // initialize
136 hr = WcaInitialize(hInstall, "MessageQueuingExecuteUninstall");
137 ExitOnFailure(hr, "Failed to initialize MessageQueuingExecuteUninstall");
138
139 hr = MqiInitialize();
140 ExitOnFailure(hr, "Failed to initialize");
141
142 // get custom action data
143 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
144 ExitOnFailure(hr, "Failed to get CustomActionData");
145 pwzData = pwzCustomActionData;
146
147 // remove message queue permissions
148 hr = MqiRemoveMessageQueuePermissions(&pwzData);
149 ExitOnFailure(hr, "Failed to remove message queue permissions");
150 if (S_FALSE == hr) ExitFunction();
151
152 // delete message queues
153 hr = MqiDeleteMessageQueues(&pwzData);
154 ExitOnFailure(hr, "Failed to delete message queues");
155 if (S_FALSE == hr) ExitFunction();
156
157 hr = S_OK;
158
159LExit:
160 // clean up
161 ReleaseStr(pwzCustomActionData);
162
163 // uninitialize
164 MqiUninitialize();
165
166 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
167 return WcaFinalize(er);
168}
169
170/********************************************************************
171 MessageQueuingRollbackUninstall - CUSTOM ACTION ENTRY POINT
172
173 Input: deferred CustomActionData - MessageQueuingRollbackUninstall
174********************************************************************/
175extern "C" UINT __stdcall MessageQueuingRollbackUninstall(MSIHANDLE hInstall)
176{
177 HRESULT hr = S_OK;
178 UINT er = ERROR_SUCCESS;
179
180 LPWSTR pwzCustomActionData = NULL;
181 LPWSTR pwzData = NULL;
182
183 // initialize
184 hr = WcaInitialize(hInstall, "MessageQueuingRollbackUninstall");
185 ExitOnFailure(hr, "Failed to initialize MessageQueuingRollbackUninstall");
186
187 hr = MqiInitialize();
188 ExitOnFailure(hr, "Failed to initialize");
189
190 // get custom action data
191 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
192 ExitOnFailure(hr, "Failed to get CustomActionData");
193 pwzData = pwzCustomActionData;
194
195 // delete message queues
196 hr = MqiRollbackDeleteMessageQueues(&pwzData);
197 ExitOnFailure(hr, "Failed to delete message queues");
198
199 // remove message queue permissions
200 hr = MqiRollbackRemoveMessageQueuePermissions(&pwzData);
201 ExitOnFailure(hr, "Failed to remove message queue permissions");
202
203 hr = S_OK;
204
205LExit:
206 // clean up
207 ReleaseStr(pwzCustomActionData);
208
209 // uninitialize
210 MqiUninitialize();
211
212 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
213 return WcaFinalize(er);
214}
diff --git a/src/ca/mqqueueexec.cpp b/src/ca/mqqueueexec.cpp
new file mode 100644
index 00000000..f5b99da7
--- /dev/null
+++ b/src/ca/mqqueueexec.cpp
@@ -0,0 +1,927 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private typedefs
7
8typedef HRESULT (__stdcall *MQCreateQueueFunc)(PSECURITY_DESCRIPTOR, MQQUEUEPROPS*, LPWSTR, LPDWORD);
9typedef HRESULT (__stdcall *MQDeleteQueueFunc)(LPCWSTR);
10typedef HRESULT (__stdcall *MQPathNameToFormatNameFunc)(LPCWSTR, LPWSTR, LPDWORD);
11typedef HRESULT (__stdcall *MQGetQueueSecurityFunc)(LPCWSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, LPDWORD);
12typedef HRESULT (__stdcall *MQSetQueueSecurityFunc)(LPCWSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR);
13
14
15// private enums
16
17enum eMessageQueueAttributes
18{
19 mqaAuthenticate = (1 << 0),
20 mqaJournal = (1 << 1),
21 mqaTransactional = (1 << 2)
22};
23
24enum eMessageQueuePrivacyLevel
25{
26 mqplNone = 0,
27 mqplOptional = 1,
28 mqplBody = 2
29};
30
31enum eMessageQueuePermission
32{
33 mqpDeleteMessage = (1 << 0),
34 mqpPeekMessage = (1 << 1),
35 mqpWriteMessage = (1 << 2),
36 mqpDeleteJournalMessage = (1 << 3),
37 mqpSetQueueProperties = (1 << 4),
38 mqpGetQueueProperties = (1 << 5),
39 mqpDeleteQueue = (1 << 6),
40 mqpGetQueuePermissions = (1 << 7),
41 mqpChangeQueuePermissions = (1 << 8),
42 mqpTakeQueueOwnership = (1 << 9),
43 mqpReceiveMessage = (1 << 10),
44 mqpReceiveJournalMessage = (1 << 11),
45 mqpQueueGenericRead = (1 << 12),
46 mqpQueueGenericWrite = (1 << 13),
47 mqpQueueGenericExecute = (1 << 14),
48 mqpQueueGenericAll = (1 << 15)
49};
50
51
52// private structs
53
54struct MQI_MESSAGE_QUEUE_ATTRIBUTES
55{
56 LPWSTR pwzKey;
57 int iBasePriority;
58 int iJournalQuota;
59 LPWSTR pwzLabel;
60 LPWSTR pwzMulticastAddress;
61 LPWSTR pwzPathName;
62 int iPrivLevel;
63 int iQuota;
64 LPWSTR pwzServiceTypeGuid;
65 int iAttributes;
66};
67
68struct MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES
69{
70 LPWSTR pwzKey;
71 LPWSTR pwzPathName;
72 LPWSTR pwzDomain;
73 LPWSTR pwzName;
74 int iPermissions;
75};
76
77
78// prototypes for private helper functions
79
80static HRESULT ReadMessageQueueAttributes(
81 LPWSTR* ppwzData,
82 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
83 );
84static void FreeMessageQueueAttributes(
85 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
86 );
87static HRESULT ReadMessageQueuePermissionAttributes(
88 LPWSTR* ppwzData,
89 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs
90 );
91static void FreeMessageQueuePermissionAttributes(
92 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs
93 );
94static HRESULT CreateMessageQueue(
95 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
96 );
97static HRESULT DeleteMessageQueue(
98 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
99 );
100static HRESULT SetMessageQueuePermissions(
101 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs,
102 BOOL fRevoke
103 );
104static void SetAccessPermissions(
105 int iPermissions,
106 LPDWORD pgrfAccessPermissions
107 );
108
109
110// private variables
111
112static HMODULE ghMQRT;
113static MQCreateQueueFunc gpfnMQCreateQueue;
114static MQDeleteQueueFunc gpfnMQDeleteQueue;
115static MQPathNameToFormatNameFunc gpfnMQPathNameToFormatName;
116static MQGetQueueSecurityFunc gpfnMQGetQueueSecurity;
117static MQSetQueueSecurityFunc gpfnMQSetQueueSecurity;
118
119
120// function definitions
121
122HRESULT MqiInitialize()
123{
124 HRESULT hr = S_OK;
125
126 // load mqrt.dll
127 ghMQRT = ::LoadLibraryW(L"mqrt.dll");
128 ExitOnNull(ghMQRT, hr, E_FAIL, "Failed to load mqrt.dll");
129
130 // get MQCreateQueue function address
131 gpfnMQCreateQueue = (MQCreateQueueFunc)::GetProcAddress(ghMQRT, "MQCreateQueue");
132 ExitOnNull(gpfnMQCreateQueue, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQCreateQueue() function");
133
134 // get MQDeleteQueue function address
135 gpfnMQDeleteQueue = (MQDeleteQueueFunc)::GetProcAddress(ghMQRT, "MQDeleteQueue");
136 ExitOnNull(gpfnMQDeleteQueue, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQDeleteQueue() function");
137
138 // get MQPathNameToFormatName function address
139 gpfnMQPathNameToFormatName = (MQPathNameToFormatNameFunc)::GetProcAddress(ghMQRT, "MQPathNameToFormatName");
140 ExitOnNull(gpfnMQPathNameToFormatName, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQPathNameToFormatName() function");
141
142 // get MQGetQueueSecurity function address
143 gpfnMQGetQueueSecurity = (MQGetQueueSecurityFunc)::GetProcAddress(ghMQRT, "MQGetQueueSecurity");
144 ExitOnNull(gpfnMQGetQueueSecurity, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQGetQueueSecurity() function");
145
146 // get MQSetQueueSecurity function address
147 gpfnMQSetQueueSecurity = (MQSetQueueSecurityFunc)::GetProcAddress(ghMQRT, "MQSetQueueSecurity");
148 ExitOnNull(gpfnMQSetQueueSecurity, hr, HRESULT_FROM_WIN32(::GetLastError()), "Failed get address for MQSetQueueSecurity() function");
149
150 hr = S_OK;
151
152LExit:
153 return hr;
154}
155
156void MqiUninitialize()
157{
158 if (ghMQRT)
159 ::FreeLibrary(ghMQRT);
160}
161
162HRESULT MqiCreateMessageQueues(
163 LPWSTR* ppwzData
164 )
165{
166 HRESULT hr = S_OK;
167
168 int iCnt = 0;
169
170 MQI_MESSAGE_QUEUE_ATTRIBUTES attrs;
171 ::ZeroMemory(&attrs, sizeof(attrs));
172
173 // ger count
174 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
175 ExitOnFailure(hr, "Failed to read count");
176
177 for (int i = 0; i < iCnt; i++)
178 {
179 // read attributes from CustomActionData
180 hr = ReadMessageQueueAttributes(ppwzData, &attrs);
181 ExitOnFailure(hr, "Failed to read attributes");
182
183 // progress message
184 hr = PcaActionDataMessage(1, attrs.pwzPathName);
185 ExitOnFailure(hr, "Failed to send progress messages, key: %S", attrs.pwzKey);
186
187 // create message queue
188 hr = CreateMessageQueue(&attrs);
189 ExitOnFailure(hr, "Failed to create message queue, key: %S", attrs.pwzKey);
190
191 // progress tics
192 hr = WcaProgressMessage(COST_MESSAGE_QUEUE_CREATE, FALSE);
193 ExitOnFailure(hr, "Failed to update progress");
194 }
195
196 hr = S_OK;
197
198LExit:
199 // clean up
200 FreeMessageQueueAttributes(&attrs);
201
202 return hr;
203}
204
205HRESULT MqiRollbackCreateMessageQueues(
206 LPWSTR* ppwzData
207 )
208{
209 HRESULT hr = S_OK;
210
211 int iCnt = 0;
212
213 MQI_MESSAGE_QUEUE_ATTRIBUTES attrs;
214 ::ZeroMemory(&attrs, sizeof(attrs));
215
216 // ger count
217 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
218 ExitOnFailure(hr, "Failed to read count");
219
220 for (int i = 0; i < iCnt; i++)
221 {
222 // read attributes from CustomActionData
223 hr = ReadMessageQueueAttributes(ppwzData, &attrs);
224 ExitOnFailure(hr, "Failed to read attributes");
225
226 // create message queue
227 hr = DeleteMessageQueue(&attrs);
228 if (FAILED(hr))
229 WcaLog(LOGMSG_STANDARD, "Failed to delete message queue, hr: 0x%x, key: %S", hr, attrs.pwzKey);
230 }
231
232 hr = S_OK;
233
234LExit:
235 // clean up
236 FreeMessageQueueAttributes(&attrs);
237
238 return hr;
239}
240
241HRESULT MqiDeleteMessageQueues(
242 LPWSTR* ppwzData
243 )
244{
245 HRESULT hr = S_OK;
246
247 int iCnt = 0;
248
249 MQI_MESSAGE_QUEUE_ATTRIBUTES attrs;
250 ::ZeroMemory(&attrs, sizeof(attrs));
251
252 // ger count
253 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
254 ExitOnFailure(hr, "Failed to read count");
255
256 for (int i = 0; i < iCnt; i++)
257 {
258 // read attributes from CustomActionData
259 hr = ReadMessageQueueAttributes(ppwzData, &attrs);
260 ExitOnFailure(hr, "Failed to read attributes");
261
262 // progress message
263 hr = PcaActionDataMessage(1, attrs.pwzPathName);
264 ExitOnFailure(hr, "Failed to send progress messages, key: %S", attrs.pwzKey);
265
266 // create message queue
267 hr = DeleteMessageQueue(&attrs);
268 if (FAILED(hr))
269 {
270 WcaLog(LOGMSG_STANDARD, "Failed to delete queue, hr: 0x%x, key: %S", hr, attrs.pwzKey);
271 continue;
272 }
273
274 // progress tics
275 hr = WcaProgressMessage(COST_MESSAGE_QUEUE_DELETE, FALSE);
276 ExitOnFailure(hr, "Failed to update progress");
277 }
278
279 hr = S_OK;
280
281LExit:
282 // clean up
283 FreeMessageQueueAttributes(&attrs);
284
285 return hr;
286}
287
288HRESULT MqiRollbackDeleteMessageQueues(
289 LPWSTR* ppwzData
290 )
291{
292 HRESULT hr = S_OK;
293
294 int iCnt = 0;
295
296 MQI_MESSAGE_QUEUE_ATTRIBUTES attrs;
297 ::ZeroMemory(&attrs, sizeof(attrs));
298
299 // ger count
300 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
301 ExitOnFailure(hr, "Failed to read count");
302
303 for (int i = 0; i < iCnt; i++)
304 {
305 // read attributes from CustomActionData
306 hr = ReadMessageQueueAttributes(ppwzData, &attrs);
307 ExitOnFailure(hr, "Failed to read attributes");
308
309 // create message queue
310 hr = CreateMessageQueue(&attrs);
311 if (FAILED(hr))
312 WcaLog(LOGMSG_STANDARD, "Failed to create message queue, hr: 0x%x, key: %S", hr, attrs.pwzKey);
313 }
314
315 hr = S_OK;
316
317LExit:
318 // clean up
319 FreeMessageQueueAttributes(&attrs);
320
321 return hr;
322}
323
324HRESULT MqiAddMessageQueuePermissions(
325 LPWSTR* ppwzData
326 )
327{
328 HRESULT hr = S_OK;
329
330 int iCnt = 0;
331
332 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs;
333 ::ZeroMemory(&attrs, sizeof(attrs));
334
335 // ger count
336 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
337 ExitOnFailure(hr, "Failed to read count");
338
339 for (int i = 0; i < iCnt; i++)
340 {
341 // read attributes from CustomActionData
342 hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs);
343 ExitOnFailure(hr, "Failed to read attributes");
344
345 // progress message
346 hr = PcaActionDataMessage(1, attrs.pwzPathName);
347 ExitOnFailure(hr, "Failed to send progress messages");
348
349 // add message queue permission
350 hr = SetMessageQueuePermissions(&attrs, FALSE);
351 ExitOnFailure(hr, "Failed to add message queue permission");
352
353 // progress tics
354 hr = WcaProgressMessage(COST_MESSAGE_QUEUE_PERMISSION_ADD, FALSE);
355 ExitOnFailure(hr, "Failed to update progress");
356 }
357
358 hr = S_OK;
359
360LExit:
361 // clean up
362 FreeMessageQueuePermissionAttributes(&attrs);
363
364 return hr;
365}
366
367HRESULT MqiRollbackAddMessageQueuePermissions(
368 LPWSTR* ppwzData
369 )
370{
371 HRESULT hr = S_OK;
372
373 int iCnt = 0;
374
375 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs;
376 ::ZeroMemory(&attrs, sizeof(attrs));
377
378 // ger count
379 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
380 ExitOnFailure(hr, "Failed to read count");
381
382 for (int i = 0; i < iCnt; i++)
383 {
384 // read attributes from CustomActionData
385 hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs);
386 ExitOnFailure(hr, "Failed to read attributes");
387
388 // add message queue permission
389 hr = SetMessageQueuePermissions(&attrs, TRUE);
390 if (FAILED(hr))
391 WcaLog(LOGMSG_STANDARD, "Failed to rollback add message queue permission, hr: 0x%x, key: %S", hr, attrs.pwzKey);
392 }
393
394 hr = S_OK;
395
396LExit:
397 // clean up
398 FreeMessageQueuePermissionAttributes(&attrs);
399
400 return hr;
401}
402
403HRESULT MqiRemoveMessageQueuePermissions(
404 LPWSTR* ppwzData
405 )
406{
407 HRESULT hr = S_OK;
408
409 int iCnt = 0;
410
411 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs;
412 ::ZeroMemory(&attrs, sizeof(attrs));
413
414 // ger count
415 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
416 ExitOnFailure(hr, "Failed to read count");
417
418 for (int i = 0; i < iCnt; i++)
419 {
420 // read attributes from CustomActionData
421 hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs);
422 ExitOnFailure(hr, "Failed to read attributes");
423
424 // progress message
425 hr = PcaActionDataMessage(1, attrs.pwzPathName);
426 ExitOnFailure(hr, "Failed to send progress messages");
427
428 // add message queue permission
429 hr = SetMessageQueuePermissions(&attrs, TRUE);
430 ExitOnFailure(hr, "Failed to remove message queue permission");
431
432 // progress tics
433 hr = WcaProgressMessage(COST_MESSAGE_QUEUE_PERMISSION_ADD, FALSE);
434 ExitOnFailure(hr, "Failed to update progress");
435 }
436
437 hr = S_OK;
438
439LExit:
440 // clean up
441 FreeMessageQueuePermissionAttributes(&attrs);
442
443 return hr;
444}
445
446HRESULT MqiRollbackRemoveMessageQueuePermissions(
447 LPWSTR* ppwzData
448 )
449{
450 HRESULT hr = S_OK;
451
452 int iCnt = 0;
453
454 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES attrs;
455 ::ZeroMemory(&attrs, sizeof(attrs));
456
457 // ger count
458 hr = WcaReadIntegerFromCaData(ppwzData, &iCnt);
459 ExitOnFailure(hr, "Failed to read count");
460
461 for (int i = 0; i < iCnt; i++)
462 {
463 // read attributes from CustomActionData
464 hr = ReadMessageQueuePermissionAttributes(ppwzData, &attrs);
465 ExitOnFailure(hr, "Failed to read attributes");
466
467 // add message queue permission
468 hr = SetMessageQueuePermissions(&attrs, FALSE);
469 if (FAILED(hr))
470 WcaLog(LOGMSG_STANDARD, "Failed to rollback remove message queue permission, hr: 0x%x, key: %S", hr, attrs.pwzKey);
471 }
472
473 hr = S_OK;
474
475LExit:
476 // clean up
477 FreeMessageQueuePermissionAttributes(&attrs);
478
479 return hr;
480}
481
482
483// helper function definitions
484
485static HRESULT ReadMessageQueueAttributes(
486 LPWSTR* ppwzData,
487 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
488 )
489{
490 HRESULT hr = S_OK;
491
492 // read message queue information from custom action data
493 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
494 ExitOnFailure(hr, "Failed to read key from custom action data");
495 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iBasePriority);
496 ExitOnFailure(hr, "Failed to read base priority from custom action data");
497 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iJournalQuota);
498 ExitOnFailure(hr, "Failed to read journal quota from custom action data");
499 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzLabel);
500 ExitOnFailure(hr, "Failed to read label from custom action data");
501 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzMulticastAddress);
502 ExitOnFailure(hr, "Failed to read multicast address from custom action data");
503 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPathName);
504 ExitOnFailure(hr, "Failed to read path name from custom action data");
505 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iPrivLevel);
506 ExitOnFailure(hr, "Failed to read privacy level from custom action data");
507 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iQuota);
508 ExitOnFailure(hr, "Failed to read quota from custom action data");
509 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzServiceTypeGuid);
510 ExitOnFailure(hr, "Failed to read service type guid from custom action data");
511 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iAttributes);
512 ExitOnFailure(hr, "Failed to read attributes from custom action data");
513
514 hr = S_OK;
515
516LExit:
517 return hr;
518}
519
520static void FreeMessageQueueAttributes(
521 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
522 )
523{
524 ReleaseStr(pAttrs->pwzKey);
525 ReleaseStr(pAttrs->pwzLabel);
526 ReleaseStr(pAttrs->pwzMulticastAddress);
527 ReleaseStr(pAttrs->pwzPathName);
528 ReleaseStr(pAttrs->pwzServiceTypeGuid);
529}
530
531static HRESULT ReadMessageQueuePermissionAttributes(
532 LPWSTR* ppwzData,
533 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs
534 )
535{
536 HRESULT hr = S_OK;
537
538 // read message queue permission information from custom action data
539 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzKey);
540 ExitOnFailure(hr, "Failed to read key from custom action data");
541 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzPathName);
542 ExitOnFailure(hr, "Failed to read path name from custom action data");
543 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzDomain);
544 ExitOnFailure(hr, "Failed to read domain from custom action data");
545 hr = WcaReadStringFromCaData(ppwzData, &pAttrs->pwzName);
546 ExitOnFailure(hr, "Failed to read name from custom action data");
547 hr = WcaReadIntegerFromCaData(ppwzData, &pAttrs->iPermissions);
548 ExitOnFailure(hr, "Failed to read permissions from custom action data");
549
550 hr = S_OK;
551
552LExit:
553 return hr;
554}
555
556static void FreeMessageQueuePermissionAttributes(
557 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs
558 )
559{
560 ReleaseStr(pAttrs->pwzKey);
561 ReleaseStr(pAttrs->pwzPathName);
562 ReleaseStr(pAttrs->pwzDomain);
563 ReleaseStr(pAttrs->pwzName);
564}
565
566static HRESULT CreateMessageQueue(
567 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
568 )
569{
570 HRESULT hr = S_OK;
571
572 SECURITY_DESCRIPTOR sd;
573 PSID pOwner = NULL;
574 DWORD cbDacl = 0;
575 PACL pDacl = NULL;
576 QUEUEPROPID aPropID[11];
577 MQPROPVARIANT aPropVar[11];
578 MQQUEUEPROPS props;
579
580 GUID guidType;
581
582 DWORD dwFormatNameLength = 0;
583
584 ::ZeroMemory(&sd, sizeof(sd));
585 ::ZeroMemory(aPropID, sizeof(aPropID));
586 ::ZeroMemory(aPropVar, sizeof(aPropVar));
587 ::ZeroMemory(&props, sizeof(props));
588 ::ZeroMemory(&guidType, sizeof(guidType));
589
590 // initialize security descriptor
591 if (!::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
592 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to initialize security descriptor");
593
594 // set security descriptor owner
595 hr = PcaAccountNameToSid(L"\\Administrators", &pOwner);
596 ExitOnFailure(hr, "Failed to get sid for account name");
597
598 if (!::SetSecurityDescriptorOwner(&sd, pOwner, FALSE))
599 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set security descriptor owner");
600
601 // set security descriptor DACL
602 cbDacl = sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + ::GetLengthSid(pOwner);
603 pDacl = (PACL)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, cbDacl);
604 ExitOnNull(pDacl, hr, E_OUTOFMEMORY, "Failed to allocate buffer for DACL");
605
606 if (!::InitializeAcl(pDacl, cbDacl, ACL_REVISION))
607 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to initialize DACL");
608
609 if (!::AddAccessAllowedAce(pDacl, ACL_REVISION, MQSEC_QUEUE_GENERIC_ALL, pOwner))
610 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to add ACE to DACL");
611
612 if (!::SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE))
613 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set security descriptor DACL");
614
615 // set property values
616 props.aPropID = aPropID;
617 props.aPropVar = aPropVar;
618
619 aPropID[0] = PROPID_Q_LABEL;
620 aPropVar[0].vt = VT_LPWSTR;
621 aPropVar[0].pwszVal = pAttrs->pwzLabel;
622
623 aPropID[1] = PROPID_Q_PATHNAME;
624 aPropVar[1].vt = VT_LPWSTR;
625 aPropVar[1].pwszVal = pAttrs->pwzPathName;
626
627 aPropID[2] = PROPID_Q_AUTHENTICATE;
628 aPropVar[2].vt = VT_UI1;
629 aPropVar[2].bVal = mqaAuthenticate == (pAttrs->iAttributes & mqaAuthenticate);
630
631 aPropID[3] = PROPID_Q_JOURNAL;
632 aPropVar[3].vt = VT_UI1;
633 aPropVar[3].bVal = mqaJournal == (pAttrs->iAttributes & mqaJournal);
634
635 aPropID[4] = PROPID_Q_TRANSACTION;
636 aPropVar[4].vt = VT_UI1;
637 aPropVar[4].bVal = mqaTransactional == (pAttrs->iAttributes & mqaTransactional);
638
639 props.cProp = 5;
640
641 if (MSI_NULL_INTEGER != pAttrs->iBasePriority)
642 {
643 aPropID[props.cProp] = PROPID_Q_BASEPRIORITY;
644 aPropVar[props.cProp].vt = VT_I2;
645 aPropVar[props.cProp].iVal = (SHORT)pAttrs->iBasePriority;
646 props.cProp++;
647 }
648
649 if (MSI_NULL_INTEGER != pAttrs->iJournalQuota)
650 {
651 aPropID[props.cProp] = PROPID_Q_JOURNAL_QUOTA;
652 aPropVar[props.cProp].vt = VT_UI4;
653 aPropVar[props.cProp].ulVal = (ULONG)pAttrs->iJournalQuota;
654 props.cProp++;
655 }
656
657 if (*pAttrs->pwzMulticastAddress)
658 {
659 aPropID[props.cProp] = PROPID_Q_MULTICAST_ADDRESS;
660 aPropVar[props.cProp].vt = VT_LPWSTR;
661 aPropVar[props.cProp].pwszVal = pAttrs->pwzMulticastAddress;
662 props.cProp++;
663 }
664
665 if (MSI_NULL_INTEGER != pAttrs->iPrivLevel)
666 {
667 aPropID[props.cProp] = PROPID_Q_PRIV_LEVEL;
668 aPropVar[props.cProp].vt = VT_UI4;
669 switch (pAttrs->iPrivLevel)
670 {
671 case mqplNone:
672 aPropVar[props.cProp].ulVal = MQ_PRIV_LEVEL_NONE;
673 break;
674 case mqplBody:
675 aPropVar[props.cProp].ulVal = MQ_PRIV_LEVEL_BODY;
676 break;
677 case mqplOptional:
678 aPropVar[props.cProp].ulVal = MQ_PRIV_LEVEL_OPTIONAL;
679 break;
680 }
681 props.cProp++;
682 }
683
684 if (MSI_NULL_INTEGER != pAttrs->iQuota)
685 {
686 aPropID[props.cProp] = PROPID_Q_QUOTA;
687 aPropVar[props.cProp].vt = VT_UI4;
688 aPropVar[props.cProp].ulVal = (ULONG)pAttrs->iQuota;
689 props.cProp++;
690 }
691
692 if (*pAttrs->pwzServiceTypeGuid)
693 {
694 // parse guid string
695 hr = PcaGuidFromString(pAttrs->pwzServiceTypeGuid, &guidType);
696 ExitOnFailure(hr, "Failed to parse service type GUID string");
697
698 aPropID[props.cProp] = PROPID_Q_TYPE;
699 aPropVar[props.cProp].vt = VT_CLSID;
700 aPropVar[props.cProp].puuid = &guidType;
701 props.cProp++;
702 }
703
704 // create message queue
705 hr = gpfnMQCreateQueue(&sd, &props, NULL, &dwFormatNameLength);
706 ExitOnFailure(hr, "Failed to create message queue");
707
708 // log
709 WcaLog(LOGMSG_VERBOSE, "Message queue created, key: %S, PathName: '%S'", pAttrs->pwzKey, pAttrs->pwzPathName);
710
711 hr = S_OK;
712
713LExit:
714 // clean up
715 if (pOwner)
716 ::HeapFree(::GetProcessHeap(), 0, pOwner);
717 if (pDacl)
718 ::HeapFree(::GetProcessHeap(), 0, pDacl);
719
720 return hr;
721}
722
723static HRESULT DeleteMessageQueue(
724 MQI_MESSAGE_QUEUE_ATTRIBUTES* pAttrs
725 )
726{
727 HRESULT hr = S_OK;
728
729 LPWSTR pwzFormatName = NULL;
730 DWORD dwCount = 128;
731
732 // get format name
733 hr = StrAlloc(&pwzFormatName, dwCount);
734 ExitOnFailure(hr, "Failed to allocate format name string");
735 do {
736 hr = gpfnMQPathNameToFormatName(pAttrs->pwzPathName, pwzFormatName, &dwCount);
737 switch (hr)
738 {
739 case MQ_ERROR_QUEUE_NOT_FOUND:
740 ExitFunction1(hr = S_OK); // nothing to delete
741 case MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL:
742 hr = StrAlloc(&pwzFormatName, dwCount);
743 ExitOnFailure(hr, "Failed to reallocate format name string");
744 hr = S_FALSE; // retry
745 break;
746 default:
747 ExitOnFailure(hr, "Failed to get format name");
748 hr = S_OK;
749 }
750 } while (S_FALSE == hr);
751
752 // delete queue
753 hr = gpfnMQDeleteQueue(pwzFormatName);
754 ExitOnFailure(hr, "Failed to delete queue");
755
756 // log
757 WcaLog(LOGMSG_VERBOSE, "Message queue deleted, key: %S, PathName: '%S'", pAttrs->pwzKey, pAttrs->pwzPathName);
758
759 hr = S_OK;
760
761LExit:
762 // clean up
763 ReleaseStr(pwzFormatName);
764
765 return hr;
766}
767
768static HRESULT SetMessageQueuePermissions(
769 MQI_MESSAGE_QUEUE_PERMISSION_ATTRIBUTES* pAttrs,
770 BOOL fRevoke
771 )
772{
773 HRESULT hr = S_OK;
774 DWORD er = ERROR_SUCCESS;
775
776 DWORD dw = 0;
777
778 LPWSTR pwzAccount = NULL;
779 LPWSTR pwzFormatName = NULL;
780
781 PSECURITY_DESCRIPTOR psd = NULL;
782 PSECURITY_DESCRIPTOR ptsd = NULL;
783
784 PACL pAclExisting = NULL;
785 PACL pAclNew = NULL;
786 BOOL fDaclPresent = FALSE;
787 BOOL fDaclDefaulted = FALSE;
788
789 PSID psid = NULL;
790
791 EXPLICIT_ACCESSW ea;
792 SECURITY_DESCRIPTOR sdNew;
793
794 ::ZeroMemory(&ea, sizeof(ea));
795 ::ZeroMemory(&sdNew, sizeof(sdNew));
796
797 // get format name
798 dw = 128;
799 hr = StrAlloc(&pwzFormatName, dw);
800 ExitOnFailure(hr, "Failed to allocate format name string");
801 do {
802 hr = gpfnMQPathNameToFormatName(pAttrs->pwzPathName, pwzFormatName, &dw);
803 if (MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL == hr)
804 {
805 hr = StrAlloc(&pwzFormatName, dw);
806 ExitOnFailure(hr, "Failed to reallocate format name string");
807 hr = S_FALSE; // retry
808 }
809 else
810 {
811 ExitOnFailure(hr, "Failed to get format name");
812 hr = S_OK;
813 }
814 } while (S_FALSE == hr);
815
816 // get queue security information
817 dw = 256;
818 psd = (PSECURITY_DESCRIPTOR)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dw);
819 ExitOnNull(psd, hr, E_OUTOFMEMORY, "Failed to allocate buffer for security descriptor");
820 do {
821 hr = gpfnMQGetQueueSecurity(pwzFormatName, DACL_SECURITY_INFORMATION, psd, dw, &dw);
822 if (MQ_ERROR_SECURITY_DESCRIPTOR_TOO_SMALL == hr)
823 {
824 ptsd = (PSECURITY_DESCRIPTOR)::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, psd, dw);
825 ExitOnNull(ptsd, hr, E_OUTOFMEMORY, "Failed to reallocate buffer for security descriptor");
826 psd = ptsd;
827 hr = S_FALSE; // retry
828 }
829 else
830 {
831 ExitOnFailure(hr, "Failed to get queue security information");
832 hr = S_OK;
833 }
834 } while (S_FALSE == hr);
835
836 // get dacl
837 if (!::GetSecurityDescriptorDacl(psd, &fDaclPresent, &pAclExisting, &fDaclDefaulted))
838 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to get DACL for security descriptor");
839 if (!fDaclPresent || !pAclExisting)
840 ExitOnFailure(hr = E_ACCESSDENIED, "Failed to get DACL for security descriptor, access denied");
841
842 // build account name string
843 hr = PcaBuildAccountName(pAttrs->pwzDomain, pAttrs->pwzName, &pwzAccount);
844 ExitOnFailure(hr, "Failed to build account name string");
845
846 // get sid for account name
847 hr = PcaAccountNameToSid(pwzAccount, &psid);
848 ExitOnFailure(hr, "Failed to get SID for account name");
849
850 // set acl entry
851 SetAccessPermissions(pAttrs->iPermissions, &ea.grfAccessPermissions);
852 ea.grfAccessMode = fRevoke ? REVOKE_ACCESS : SET_ACCESS;
853 ea.grfInheritance = NO_INHERITANCE;
854 ::BuildTrusteeWithSidW(&ea.Trustee, psid);
855
856 er = ::SetEntriesInAclW(1, &ea, pAclExisting, &pAclNew);
857 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set ACL entry");
858
859 // create new security descriptor
860 if (!::InitializeSecurityDescriptor(&sdNew, SECURITY_DESCRIPTOR_REVISION))
861 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to initialize security descriptor");
862
863 if (!::SetSecurityDescriptorDacl(&sdNew, TRUE, pAclNew, FALSE))
864 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to set DACL for security descriptor");
865
866 // set queue security information
867 hr = gpfnMQSetQueueSecurity(pwzFormatName, DACL_SECURITY_INFORMATION, &sdNew);
868 ExitOnFailure(hr, "Failed to set queue security information");
869
870 // log
871 WcaLog(LOGMSG_VERBOSE, "Permission set for message queue, key: %S, PathName: '%S'", pAttrs->pwzKey, pAttrs->pwzPathName);
872
873 hr = S_OK;
874
875LExit:
876 // clean up
877 ReleaseStr(pwzFormatName);
878 ReleaseStr(pwzAccount);
879
880 if (psd)
881 ::HeapFree(::GetProcessHeap(), 0, psd);
882 if (psid)
883 ::HeapFree(::GetProcessHeap(), 0, psid);
884 if (pAclNew)
885 ::LocalFree(pAclNew);
886
887 return hr;
888}
889
890static void SetAccessPermissions(
891 int iPermissions,
892 LPDWORD pgrfAccessPermissions
893 )
894{
895 if (iPermissions & mqpDeleteMessage)
896 *pgrfAccessPermissions |= MQSEC_DELETE_MESSAGE;
897 if (iPermissions & mqpPeekMessage)
898 *pgrfAccessPermissions |= MQSEC_PEEK_MESSAGE;
899 if (iPermissions & mqpWriteMessage)
900 *pgrfAccessPermissions |= MQSEC_WRITE_MESSAGE;
901 if (iPermissions & mqpDeleteJournalMessage)
902 *pgrfAccessPermissions |= MQSEC_DELETE_JOURNAL_MESSAGE;
903 if (iPermissions & mqpSetQueueProperties)
904 *pgrfAccessPermissions |= MQSEC_SET_QUEUE_PROPERTIES;
905 if (iPermissions & mqpGetQueueProperties)
906 *pgrfAccessPermissions |= MQSEC_GET_QUEUE_PROPERTIES;
907 if (iPermissions & mqpDeleteQueue)
908 *pgrfAccessPermissions |= MQSEC_DELETE_QUEUE;
909 if (iPermissions & mqpGetQueuePermissions)
910 *pgrfAccessPermissions |= MQSEC_GET_QUEUE_PERMISSIONS;
911 if (iPermissions & mqpChangeQueuePermissions)
912 *pgrfAccessPermissions |= MQSEC_CHANGE_QUEUE_PERMISSIONS;
913 if (iPermissions & mqpTakeQueueOwnership)
914 *pgrfAccessPermissions |= MQSEC_TAKE_QUEUE_OWNERSHIP;
915 if (iPermissions & mqpReceiveMessage)
916 *pgrfAccessPermissions |= MQSEC_RECEIVE_MESSAGE;
917 if (iPermissions & mqpReceiveJournalMessage)
918 *pgrfAccessPermissions |= MQSEC_RECEIVE_JOURNAL_MESSAGE;
919 if (iPermissions & mqpQueueGenericRead)
920 *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_READ;
921 if (iPermissions & mqpQueueGenericWrite)
922 *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_WRITE;
923 if (iPermissions & mqpQueueGenericExecute)
924 *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_EXECUTE;
925 if (iPermissions & mqpQueueGenericAll)
926 *pgrfAccessPermissions |= MQSEC_QUEUE_GENERIC_ALL;
927}
diff --git a/src/ca/mqqueueexec.h b/src/ca/mqqueueexec.h
new file mode 100644
index 00000000..37ceea50
--- /dev/null
+++ b/src/ca/mqqueueexec.h
@@ -0,0 +1,30 @@
1#pragma once
2// 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.
3
4
5HRESULT MqiInitialize();
6void MqiUninitialize();
7HRESULT MqiCreateMessageQueues(
8 LPWSTR* ppwzData
9 );
10HRESULT MqiRollbackCreateMessageQueues(
11 LPWSTR* ppwzData
12 );
13HRESULT MqiDeleteMessageQueues(
14 LPWSTR* ppwzData
15 );
16HRESULT MqiRollbackDeleteMessageQueues(
17 LPWSTR* ppwzData
18 );
19HRESULT MqiAddMessageQueuePermissions(
20 LPWSTR* ppwzData
21 );
22HRESULT MqiRollbackAddMessageQueuePermissions(
23 LPWSTR* ppwzData
24 );
25HRESULT MqiRemoveMessageQueuePermissions(
26 LPWSTR* ppwzData
27 );
28HRESULT MqiRollbackRemoveMessageQueuePermissions(
29 LPWSTR* ppwzData
30 );
diff --git a/src/ca/mqqueuesched.cpp b/src/ca/mqqueuesched.cpp
new file mode 100644
index 00000000..4f40a4aa
--- /dev/null
+++ b/src/ca/mqqueuesched.cpp
@@ -0,0 +1,582 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// sql queries
7
8LPCWSTR vcsMessageQueueQuery =
9 L"SELECT `MessageQueue`, `Component_`, `BasePriority`, `JournalQuota`, `Label`, `MulticastAddress`, `PathName`, `PrivLevel`, `Quota`, `ServiceTypeGuid`, `Attributes` FROM `MessageQueue`";
10enum eMessageQueueQuery { mqqMessageQueue = 1, mqqComponent, mqqBasePriority, mqqJournalQuota, mqqLabel, mqqMulticastAddress, mqqPathName, mqqPrivLevel, mqqQuota, mqqServiceTypeGuid, mqqAttributes };
11
12LPCWSTR vcsMessageQueueUserPermissionQuery =
13 L"SELECT `MessageQueueUserPermission`, `MessageQueue_`, `MessageQueueUserPermission`.`Component_`, `Domain`, `Name`, `Permissions` FROM `MessageQueueUserPermission`, `User` WHERE `User_` = `User`";
14LPCWSTR vcsMessageQueueGroupPermissionQuery =
15 L"SELECT `MessageQueueGroupPermission`, `MessageQueue_`, `MessageQueueGroupPermission`.`Component_`, `Domain`, `Name`, `Permissions` FROM `MessageQueueGroupPermission`, `Group` WHERE `Group_` = `Group`";
16enum eMessageQueuePermissionQuery { mqpqMessageQueuePermission = 1, mqpqMessageQueue, mqpqComponent, mqpqDomain, mqpqName, mqpqPermissions };
17
18
19// prototypes for private helper functions
20
21static HRESULT MqiMessageQueueFindByKey(
22 MQI_MESSAGE_QUEUE_LIST* pList,
23 LPCWSTR pwzKey,
24 MQI_MESSAGE_QUEUE** ppItm
25 );
26static HRESULT AddMessageQueueToActionData(
27 MQI_MESSAGE_QUEUE* pItm,
28 LPWSTR* ppwzActionData
29 );
30static HRESULT MessageQueueTrusteePermissionsRead(
31 LPCWSTR pwzQuery,
32 MQI_MESSAGE_QUEUE_LIST* pMessageQueueList,
33 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
34 );
35static HRESULT AddMessageQueuePermissionToActionData(
36 MQI_MESSAGE_QUEUE_PERMISSION* pItm,
37 LPWSTR* ppwzActionData
38 );
39
40
41// private typedefs
42
43typedef HRESULT (__stdcall *MQPathNameToFormatNameFunc)(LPCWSTR, LPWSTR, LPDWORD);
44
45
46// private variables
47
48static HMODULE ghMQRT;
49static MQPathNameToFormatNameFunc gpfnMQPathNameToFormatName;
50
51
52// function definitions
53
54HRESULT MqiInitialize()
55{
56 HRESULT hr = S_OK;
57
58 // load mqrt.dll
59 ghMQRT = ::LoadLibraryW(L"mqrt.dll");
60 if (!ghMQRT)
61 {
62 ExitFunction1(hr = S_FALSE);
63 }
64
65 // get MQPathNameToFormatName function address
66 gpfnMQPathNameToFormatName = (MQPathNameToFormatNameFunc)::GetProcAddress(ghMQRT, "MQPathNameToFormatName");
67 ExitOnNullWithLastError(gpfnMQPathNameToFormatName, hr, "Failed get address for MQPathNameToFormatName() function");
68
69 hr = S_OK;
70
71LExit:
72 return hr;
73}
74
75void MqiUninitialize()
76{
77 if (ghMQRT)
78 {
79 ::FreeLibrary(ghMQRT);
80 }
81}
82
83HRESULT MqiMessageQueueRead(
84 MQI_MESSAGE_QUEUE_LIST* pList
85 )
86{
87 HRESULT hr = S_OK;
88 UINT er = ERROR_SUCCESS;
89
90 PMSIHANDLE hView, hRec;
91
92 MQI_MESSAGE_QUEUE* pItm = NULL;
93 LPWSTR pwzData = NULL;
94
95 // loop through all partitions
96 hr = WcaOpenExecuteView(vcsMessageQueueQuery, &hView);
97 ExitOnFailure(hr, "Failed to execute view on MessageQueue table");
98
99 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
100 {
101 // create entry
102 pItm = (MQI_MESSAGE_QUEUE*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MQI_MESSAGE_QUEUE));
103 if (!pItm)
104 ExitFunction1(hr = E_OUTOFMEMORY);
105
106 // get key
107 hr = WcaGetRecordString(hRec, mqqMessageQueue, &pwzData);
108 ExitOnFailure(hr, "Failed to get key");
109 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
110
111 // get component install state
112 hr = WcaGetRecordString(hRec, mqqComponent, &pwzData);
113 ExitOnFailure(hr, "Failed to get component");
114
115 // get component install state
116 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
117 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
118
119 // get base priority
120 hr = WcaGetRecordInteger(hRec, mqqBasePriority, &pItm->iBasePriority);
121 ExitOnFailure(hr, "Failed to get base priority");
122
123 // get journal quota
124 hr = WcaGetRecordInteger(hRec, mqqJournalQuota, &pItm->iJournalQuota);
125 ExitOnFailure(hr, "Failed to get journal quota");
126
127 // get label
128 hr = WcaGetRecordFormattedString(hRec, mqqLabel, &pwzData);
129 ExitOnFailure(hr, "Failed to get label");
130 StringCchCopyW(pItm->wzLabel, countof(pItm->wzLabel), pwzData);
131
132 // get multicast address
133 hr = WcaGetRecordFormattedString(hRec, mqqMulticastAddress, &pwzData);
134 ExitOnFailure(hr, "Failed to get multicast address");
135 StringCchCopyW(pItm->wzMulticastAddress, countof(pItm->wzMulticastAddress), pwzData);
136
137 // get path name
138 hr = WcaGetRecordFormattedString(hRec, mqqPathName, &pwzData);
139 ExitOnFailure(hr, "Failed to get path name");
140 StringCchCopyW(pItm->wzPathName, countof(pItm->wzPathName), pwzData);
141
142 // get privacy level
143 hr = WcaGetRecordInteger(hRec, mqqPrivLevel, &pItm->iPrivLevel);
144 ExitOnFailure(hr, "Failed to get privacy level");
145
146 // get quota
147 hr = WcaGetRecordInteger(hRec, mqqQuota, &pItm->iQuota);
148 ExitOnFailure(hr, "Failed to get quota");
149
150 // get service type guid
151 hr = WcaGetRecordFormattedString(hRec, mqqServiceTypeGuid, &pwzData);
152 ExitOnFailure(hr, "Failed to get service type guid");
153 StringCchCopyW(pItm->wzServiceTypeGuid, countof(pItm->wzServiceTypeGuid), pwzData);
154
155 // get attributes
156 hr = WcaGetRecordInteger(hRec, mqqAttributes, &pItm->iAttributes);
157 ExitOnFailure(hr, "Failed to get attributes");
158
159 // increment counters
160 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
161 pList->iInstallCount++;
162 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
163 pList->iUninstallCount++;
164
165 // add entry
166 pItm->pNext = pList->pFirst;
167 pList->pFirst = pItm;
168 pItm = NULL;
169 }
170
171 if (E_NOMOREITEMS == hr)
172 hr = S_OK;
173
174LExit:
175 // clean up
176 if (pItm)
177 ::HeapFree(::GetProcessHeap(), 0, pItm);
178
179 ReleaseStr(pwzData);
180
181 return hr;
182}
183
184HRESULT MqiMessageQueueVerify(
185 MQI_MESSAGE_QUEUE_LIST* pList
186 )
187{
188 HRESULT hr = S_OK;
189 LPWSTR pwzFormatName = NULL;
190 DWORD dwCount = 128;
191
192 for (MQI_MESSAGE_QUEUE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
193 {
194 // queues that are being installed only
195 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
196 continue;
197
198 // get format name
199 hr = StrAlloc(&pwzFormatName, dwCount);
200 ExitOnFailure(hr, "Failed to allocate format name string");
201 do {
202 hr = gpfnMQPathNameToFormatName(pItm->wzPathName, pwzFormatName, &dwCount);
203 switch (hr)
204 {
205 case MQ_ERROR_QUEUE_NOT_FOUND:
206 break; // break
207 case MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL:
208 hr = StrAlloc(&pwzFormatName, dwCount);
209 ExitOnFailure(hr, "Failed to reallocate format name string");
210 hr = S_FALSE; // retry
211 break;
212 default:
213 ExitOnFailure(hr, "Failed to get format name");
214 hr = S_OK;
215 }
216 } while (S_FALSE == hr);
217
218 if (MQ_ERROR_QUEUE_NOT_FOUND == hr)
219 {
220 continue;
221 }
222 pItm->fExists = TRUE;
223 pList->iInstallCount--;
224
225 // clean up
226 ReleaseNullStr(pwzFormatName);
227 }
228
229 hr = S_OK;
230
231LExit:
232 ReleaseStr(pwzFormatName);
233 return hr;
234}
235
236HRESULT MqiMessageQueueInstall(
237 MQI_MESSAGE_QUEUE_LIST* pList,
238 BOOL fRollback,
239 LPWSTR* ppwzActionData
240 )
241{
242 HRESULT hr = S_OK;
243
244 // add count to action data
245 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
246 ExitOnFailure(hr, "Failed to add count to custom action data");
247
248 for (MQI_MESSAGE_QUEUE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
249 {
250 // queues that are being installed only
251 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
252 continue;
253
254 // if the queue exists we should not try to create it
255 if (pItm->fExists && !fRollback)
256 {
257 continue;
258 }
259
260 // add message queue to action data
261 hr = AddMessageQueueToActionData(pItm, ppwzActionData);
262 ExitOnFailure(hr, "Failed to add message queue to action data");
263 }
264
265 hr = S_OK;
266
267LExit:
268 return hr;
269}
270
271HRESULT MqiMessageQueueUninstall(
272 MQI_MESSAGE_QUEUE_LIST* pList,
273 BOOL fRollback,
274 LPWSTR* ppwzActionData
275 )
276{
277 HRESULT hr = S_OK;
278
279 // add count to action data
280 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
281 ExitOnFailure(hr, "Failed to add count to custom action data");
282
283 for (MQI_MESSAGE_QUEUE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
284 {
285 // queues that are being uninstalled only
286 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
287 continue;
288
289 // if we did not create the queue we should not try to delete it
290 if (pItm->fExists && fRollback)
291 {
292 continue;
293 }
294
295 // add message queue to action data
296 hr = AddMessageQueueToActionData(pItm, ppwzActionData);
297 ExitOnFailure(hr, "Failed to add message queue to action data");
298 }
299
300 hr = S_OK;
301
302LExit:
303 return hr;
304}
305
306void MqiMessageQueueFreeList(
307 MQI_MESSAGE_QUEUE_LIST* pList
308 )
309{
310 MQI_MESSAGE_QUEUE* pItm = pList->pFirst;
311 while (pItm)
312 {
313 MQI_MESSAGE_QUEUE* pDelete = pItm;
314 pItm = pItm->pNext;
315 ::HeapFree(::GetProcessHeap(), 0, pDelete);
316 }
317}
318
319HRESULT MqiMessageQueuePermissionRead(
320 MQI_MESSAGE_QUEUE_LIST* pMessageQueueList,
321 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
322 )
323{
324 HRESULT hr = S_OK;
325
326 // read message queue user permissions
327 if (S_OK == WcaTableExists(L"MessageQueueUserPermission"))
328 {
329 hr = MessageQueueTrusteePermissionsRead(vcsMessageQueueUserPermissionQuery, pMessageQueueList, pList);
330 ExitOnFailure(hr, "Failed to read message queue user permissions");
331 }
332
333 // read message queue group permissions
334 if (S_OK == WcaTableExists(L"MessageQueueGroupPermission"))
335 {
336 hr = MessageQueueTrusteePermissionsRead(vcsMessageQueueGroupPermissionQuery, pMessageQueueList, pList);
337 ExitOnFailure(hr, "Failed to read message queue group permissions");
338 }
339
340 hr = S_OK;
341
342LExit:
343 return hr;
344}
345
346HRESULT MqiMessageQueuePermissionInstall(
347 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList,
348 LPWSTR* ppwzActionData
349 )
350{
351 HRESULT hr = S_OK;
352
353 // add count to action data
354 hr = WcaWriteIntegerToCaData(pList->iInstallCount, ppwzActionData);
355 ExitOnFailure(hr, "Failed to add count to custom action data");
356
357 for (MQI_MESSAGE_QUEUE_PERMISSION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
358 {
359 // queue permissions that are being installed only
360 if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction))
361 continue;
362
363 // add message queue permission to action data
364 hr = AddMessageQueuePermissionToActionData(pItm, ppwzActionData);
365 ExitOnFailure(hr, "Failed to add message queue permission to action data");
366 }
367
368 hr = S_OK;
369
370LExit:
371 return hr;
372}
373
374HRESULT MqiMessageQueuePermissionUninstall(
375 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList,
376 LPWSTR* ppwzActionData
377 )
378{
379 HRESULT hr = S_OK;
380
381 // add count to action data
382 hr = WcaWriteIntegerToCaData(pList->iUninstallCount, ppwzActionData);
383 ExitOnFailure(hr, "Failed to add count to custom action data");
384
385 for (MQI_MESSAGE_QUEUE_PERMISSION* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
386 {
387 // queue permissions that are being uninstalled only
388 if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
389 continue;
390
391 // add message queue permission to action data
392 hr = AddMessageQueuePermissionToActionData(pItm, ppwzActionData);
393 ExitOnFailure(hr, "Failed to add message queue permission to action data");
394 }
395
396 hr = S_OK;
397
398LExit:
399 return hr;
400}
401
402void MqiMessageQueuePermissionFreeList(
403 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
404 )
405{
406 MQI_MESSAGE_QUEUE_PERMISSION* pItm = pList->pFirst;
407 while (pItm)
408 {
409 MQI_MESSAGE_QUEUE_PERMISSION* pDelete = pItm;
410 pItm = pItm->pNext;
411 ::HeapFree(::GetProcessHeap(), 0, pDelete);
412 }
413}
414
415
416// helper function definitions
417
418static HRESULT MqiMessageQueueFindByKey(
419 MQI_MESSAGE_QUEUE_LIST* pList,
420 LPCWSTR pwzKey,
421 MQI_MESSAGE_QUEUE** ppItm
422 )
423{
424 for (MQI_MESSAGE_QUEUE* pItm = pList->pFirst; pItm; pItm = pItm->pNext)
425 {
426 if (0 == lstrcmpW(pItm->wzKey, pwzKey))
427 {
428 *ppItm = pItm;
429 return S_OK;
430 }
431 }
432
433 return S_FALSE;
434}
435
436static HRESULT AddMessageQueueToActionData(
437 MQI_MESSAGE_QUEUE* pItm,
438 LPWSTR* ppwzActionData
439 )
440{
441 HRESULT hr = S_OK;
442
443 // add message queue information to custom action data
444 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
445 ExitOnFailure(hr, "Failed to add key to custom action data");
446 hr = WcaWriteIntegerToCaData(pItm->iBasePriority, ppwzActionData);
447 ExitOnFailure(hr, "Failed to add base priority to custom action data");
448 hr = WcaWriteIntegerToCaData(pItm->iJournalQuota, ppwzActionData);
449 ExitOnFailure(hr, "Failed to add journal quota to custom action data");
450 hr = WcaWriteStringToCaData(pItm->wzLabel, ppwzActionData);
451 ExitOnFailure(hr, "Failed to add label to custom action data");
452 hr = WcaWriteStringToCaData(pItm->wzMulticastAddress, ppwzActionData);
453 ExitOnFailure(hr, "Failed to add multicast address to custom action data");
454 hr = WcaWriteStringToCaData(pItm->wzPathName, ppwzActionData);
455 ExitOnFailure(hr, "Failed to add path name to custom action data");
456 hr = WcaWriteIntegerToCaData(pItm->iPrivLevel, ppwzActionData);
457 ExitOnFailure(hr, "Failed to add privacy level to custom action data");
458 hr = WcaWriteIntegerToCaData(pItm->iQuota, ppwzActionData);
459 ExitOnFailure(hr, "Failed to add quota to custom action data");
460 hr = WcaWriteStringToCaData(pItm->wzServiceTypeGuid, ppwzActionData);
461 ExitOnFailure(hr, "Failed to add service type guid to custom action data");
462 hr = WcaWriteIntegerToCaData(pItm->iAttributes, ppwzActionData);
463 ExitOnFailure(hr, "Failed to add attributes to custom action data");
464
465 hr = S_OK;
466
467LExit:
468 return hr;
469}
470
471static HRESULT MessageQueueTrusteePermissionsRead(
472 LPCWSTR pwzQuery,
473 MQI_MESSAGE_QUEUE_LIST* pMessageQueueList,
474 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
475 )
476{
477 HRESULT hr = S_OK;
478 UINT er = ERROR_SUCCESS;
479
480 PMSIHANDLE hView, hRec;
481
482 LPWSTR pwzData = NULL;
483
484 MQI_MESSAGE_QUEUE_PERMISSION* pItm = NULL;
485
486 // loop through all application roles
487 hr = WcaOpenExecuteView(pwzQuery, &hView);
488 ExitOnFailure(hr, "Failed to execute view on table");
489
490 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
491 {
492 // create entry
493 pItm = (MQI_MESSAGE_QUEUE_PERMISSION*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MQI_MESSAGE_QUEUE_PERMISSION));
494 if (!pItm)
495 ExitFunction1(hr = E_OUTOFMEMORY);
496
497 // get key
498 hr = WcaGetRecordString(hRec, mqpqMessageQueuePermission, &pwzData);
499 ExitOnFailure(hr, "Failed to get key");
500 StringCchCopyW(pItm->wzKey, countof(pItm->wzKey), pwzData);
501
502 // get component
503 hr = WcaGetRecordString(hRec, mqpqComponent, &pwzData);
504 ExitOnFailure(hr, "Failed to get component");
505
506 // get component install state
507 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &pItm->isInstalled, &pItm->isAction);
508 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to get component state");
509
510 // get message queue
511 hr = WcaGetRecordString(hRec, mqpqMessageQueue, &pwzData);
512 ExitOnFailure(hr, "Failed to get application role");
513
514 hr = MqiMessageQueueFindByKey(pMessageQueueList, pwzData, &pItm->pMessageQueue);
515 if (S_FALSE == hr)
516 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
517 ExitOnFailure(hr, "Failed to find message queue, key: %S", pwzData);
518
519 // get user domain
520 hr = WcaGetRecordFormattedString(hRec, mqpqDomain, &pwzData);
521 ExitOnFailure(hr, "Failed to get domain");
522 StringCchCopyW(pItm->wzDomain, countof(pItm->wzDomain), pwzData);
523
524 // get user name
525 hr = WcaGetRecordFormattedString(hRec, mqpqName, &pwzData);
526 ExitOnFailure(hr, "Failed to get name");
527 StringCchCopyW(pItm->wzName, countof(pItm->wzName), pwzData);
528
529 // get permissions
530 hr = WcaGetRecordInteger(hRec, mqpqPermissions, &pItm->iPermissions);
531 ExitOnFailure(hr, "Failed to get permissions");
532
533 // set references & increment counters
534 if (WcaIsInstalling(pItm->isInstalled, pItm->isAction))
535 pList->iInstallCount++;
536 if (WcaIsUninstalling(pItm->isInstalled, pItm->isAction))
537 pList->iUninstallCount++;
538
539 // add entry
540 if (pList->pFirst)
541 pItm->pNext = pList->pFirst;
542 pList->pFirst = pItm;
543 pItm = NULL;
544 }
545
546 if (E_NOMOREITEMS == hr)
547 hr = S_OK;
548
549LExit:
550 // clean up
551 ReleaseStr(pwzData);
552
553 if (pItm)
554 ::HeapFree(::GetProcessHeap(), 0, pItm);
555
556 return hr;
557}
558
559static HRESULT AddMessageQueuePermissionToActionData(
560 MQI_MESSAGE_QUEUE_PERMISSION* pItm,
561 LPWSTR* ppwzActionData
562 )
563{
564 HRESULT hr = S_OK;
565
566 // add message queue information to custom action data
567 hr = WcaWriteStringToCaData(pItm->wzKey, ppwzActionData);
568 ExitOnFailure(hr, "Failed to add key to custom action data");
569 hr = WcaWriteStringToCaData(pItm->pMessageQueue->wzPathName, ppwzActionData);
570 ExitOnFailure(hr, "Failed to add path name to custom action data");
571 hr = WcaWriteStringToCaData(pItm->wzDomain, ppwzActionData);
572 ExitOnFailure(hr, "Failed to add domain to custom action data");
573 hr = WcaWriteStringToCaData(pItm->wzName, ppwzActionData);
574 ExitOnFailure(hr, "Failed to add name to custom action data");
575 hr = WcaWriteIntegerToCaData(pItm->iPermissions, ppwzActionData);
576 ExitOnFailure(hr, "Failed to add permissions to custom action data");
577
578 hr = S_OK;
579
580LExit:
581 return hr;
582}
diff --git a/src/ca/mqqueuesched.h b/src/ca/mqqueuesched.h
new file mode 100644
index 00000000..b063ca28
--- /dev/null
+++ b/src/ca/mqqueuesched.h
@@ -0,0 +1,92 @@
1#pragma once
2// 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.
3
4
5struct MQI_MESSAGE_QUEUE
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 int iBasePriority;
9 int iJournalQuota;
10 WCHAR wzLabel[MAX_DARWIN_COLUMN + 1];
11 WCHAR wzMulticastAddress[MAX_DARWIN_COLUMN + 1];
12 WCHAR wzPathName[MAX_DARWIN_COLUMN + 1];
13 int iPrivLevel;
14 int iQuota;
15 WCHAR wzServiceTypeGuid[MAX_DARWIN_COLUMN + 1];
16 int iAttributes;
17
18 INSTALLSTATE isInstalled, isAction;
19 BOOL fExists;
20
21 MQI_MESSAGE_QUEUE* pNext;
22};
23
24struct MQI_MESSAGE_QUEUE_LIST
25{
26 MQI_MESSAGE_QUEUE* pFirst;
27
28 int iInstallCount;
29 int iUninstallCount;
30};
31
32struct MQI_MESSAGE_QUEUE_PERMISSION
33{
34 WCHAR wzKey[MAX_DARWIN_KEY + 1];
35 WCHAR wzDomain[MAX_DARWIN_COLUMN + 1];
36 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
37 int iPermissions;
38
39 MQI_MESSAGE_QUEUE* pMessageQueue;
40
41 INSTALLSTATE isInstalled, isAction;
42
43 MQI_MESSAGE_QUEUE_PERMISSION* pNext;
44};
45
46struct MQI_MESSAGE_QUEUE_PERMISSION_LIST
47{
48 MQI_MESSAGE_QUEUE_PERMISSION* pFirst;
49
50 int iInstallCount;
51 int iUninstallCount;
52};
53
54
55// function prototypes
56
57HRESULT MqiInitialize();
58void MqiUninitialize();
59HRESULT MqiMessageQueueRead(
60 MQI_MESSAGE_QUEUE_LIST* pList
61 );
62HRESULT MqiMessageQueueVerify(
63 MQI_MESSAGE_QUEUE_LIST* pList
64 );
65HRESULT MqiMessageQueueInstall(
66 MQI_MESSAGE_QUEUE_LIST* pList,
67 BOOL fRollback,
68 LPWSTR* ppwzActionData
69 );
70HRESULT MqiMessageQueueUninstall(
71 MQI_MESSAGE_QUEUE_LIST* pList,
72 BOOL fRollback,
73 LPWSTR* ppwzActionData
74 );
75void MqiMessageQueueFreeList(
76 MQI_MESSAGE_QUEUE_LIST* pList
77 );
78HRESULT MqiMessageQueuePermissionRead(
79 MQI_MESSAGE_QUEUE_LIST* pMessageQueueList,
80 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
81 );
82HRESULT MqiMessageQueuePermissionInstall(
83 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList,
84 LPWSTR* ppwzActionData
85 );
86HRESULT MqiMessageQueuePermissionUninstall(
87 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList,
88 LPWSTR* ppwzActionData
89 );
90void MqiMessageQueuePermissionFreeList(
91 MQI_MESSAGE_QUEUE_PERMISSION_LIST* pList
92 );
diff --git a/src/ca/mqsched.cpp b/src/ca/mqsched.cpp
new file mode 100644
index 00000000..cefce853
--- /dev/null
+++ b/src/ca/mqsched.cpp
@@ -0,0 +1,219 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6/********************************************************************
7 DllMain - standard entry point for all WiX CustomActions
8
9********************************************************************/
10extern "C" BOOL WINAPI DllMain(
11 IN HINSTANCE hInst,
12 IN ULONG ulReason,
13 IN LPVOID)
14{
15 switch(ulReason)
16 {
17 case DLL_PROCESS_ATTACH:
18 WcaGlobalInitialize(hInst);
19 break;
20
21 case DLL_PROCESS_DETACH:
22 WcaGlobalFinalize();
23 break;
24 }
25
26 return TRUE;
27}
28
29/********************************************************************
30 MessageQueuingInstall - CUSTOM ACTION ENTRY POINT for installing MSMQ message queues
31
32********************************************************************/
33extern "C" UINT __stdcall MessageQueuingInstall(MSIHANDLE hInstall)
34{
35 HRESULT hr = S_OK;
36 UINT er = ERROR_SUCCESS;
37
38 MQI_MESSAGE_QUEUE_LIST lstMessageQueues;
39 MQI_MESSAGE_QUEUE_PERMISSION_LIST lstMessageQueuePermissions;
40
41 int iCost = 0;
42 LPWSTR pwzRollbackActionData = NULL;
43 LPWSTR pwzExecuteActionData = NULL;
44
45 ::ZeroMemory(&lstMessageQueues, sizeof(lstMessageQueues));
46 ::ZeroMemory(&lstMessageQueuePermissions, sizeof(lstMessageQueuePermissions));
47
48 // initialize
49 hr = WcaInitialize(hInstall, "MessageQueuingInstall");
50 ExitOnFailure(hr, "Failed to initialize");
51
52 do
53 {
54 hr = MqiInitialize();
55 if (S_FALSE == hr)
56 {
57 WcaLog(LOGMSG_STANDARD, "Failed to load mqrt.dll.");
58 er = WcaErrorMessage(msierrMsmqCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
59 switch (er)
60 {
61 case IDABORT:
62 ExitFunction1(hr = E_FAIL); // bail with error
63 case IDRETRY:
64 break; // retry
65 case IDIGNORE: __fallthrough;
66 default:
67 ExitFunction1(hr = S_OK); // pretend everything is okay and bail
68 }
69 }
70 ExitOnFailure(hr, "Failed to initialize MSMQ.");
71 } while (S_FALSE == hr);
72
73 // read message queues
74 hr = MqiMessageQueueRead(&lstMessageQueues);
75 ExitOnFailure(hr, "Failed to read MessageQueue table");
76
77 // read message queue permissions
78 hr = MqiMessageQueuePermissionRead(&lstMessageQueues, &lstMessageQueuePermissions);
79 ExitOnFailure(hr, "Failed to read message queue permissions");
80
81 // verify message queue elementes
82 hr = MqiMessageQueueVerify(&lstMessageQueues);
83 ExitOnFailure(hr, "Failed to verify message queue elements.");
84
85 if (lstMessageQueues.iInstallCount || lstMessageQueuePermissions.iInstallCount)
86 {
87 // schedule rollback action
88 hr = MqiMessageQueuePermissionInstall(&lstMessageQueuePermissions, &pwzRollbackActionData);
89 ExitOnFailure(hr, "Failed to add message queue permissions to rollback action data");
90
91 hr = MqiMessageQueueInstall(&lstMessageQueues, TRUE, &pwzRollbackActionData);
92 ExitOnFailure(hr, "Failed to add message queues to rollback action data");
93
94 hr = WcaDoDeferredAction(L"MessageQueuingRollbackInstall", pwzRollbackActionData, 0);
95 ExitOnFailure(hr, "Failed to schedule MessageQueuingRollbackInstall");
96
97 // schedule execute action
98 hr = MqiMessageQueueInstall(&lstMessageQueues, FALSE, &pwzExecuteActionData);
99 ExitOnFailure(hr, "Failed to add message queues to execute action data");
100 iCost += lstMessageQueues.iInstallCount * COST_MESSAGE_QUEUE_CREATE;
101
102 hr = MqiMessageQueuePermissionInstall(&lstMessageQueuePermissions, &pwzExecuteActionData);
103 ExitOnFailure(hr, "Failed to add message queue permissions to execute action data");
104 iCost += lstMessageQueues.iInstallCount * COST_MESSAGE_QUEUE_PERMISSION_ADD;
105
106 hr = WcaDoDeferredAction(L"MessageQueuingExecuteInstall", pwzExecuteActionData, iCost);
107 ExitOnFailure(hr, "Failed to schedule MessageQueuingExecuteInstall");
108 }
109
110 hr = S_OK;
111
112LExit:
113 // clean up
114 MqiMessageQueueFreeList(&lstMessageQueues);
115 MqiMessageQueuePermissionFreeList(&lstMessageQueuePermissions);
116
117 ReleaseStr(pwzRollbackActionData);
118 ReleaseStr(pwzExecuteActionData);
119
120 // uninitialize
121 MqiUninitialize();
122
123 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
124 return WcaFinalize(er);
125}
126
127
128/********************************************************************
129 MessageQueuingUninstall - CUSTOM ACTION ENTRY POINT for uninstalling MSMQ message queues
130
131********************************************************************/
132extern "C" UINT __stdcall MessageQueuingUninstall(MSIHANDLE hInstall)
133{
134 HRESULT hr = S_OK;
135 UINT er = ERROR_SUCCESS;
136
137 MQI_MESSAGE_QUEUE_LIST lstMessageQueues;
138 MQI_MESSAGE_QUEUE_PERMISSION_LIST lstMessageQueuePermissions;
139
140 int iCost = 0;
141 LPWSTR pwzRollbackActionData = NULL;
142 LPWSTR pwzExecuteActionData = NULL;
143
144 ::ZeroMemory(&lstMessageQueues, sizeof(lstMessageQueues));
145 ::ZeroMemory(&lstMessageQueuePermissions, sizeof(lstMessageQueuePermissions));
146
147 // initialize
148 hr = WcaInitialize(hInstall, "MessageQueuingUninstall");
149 ExitOnFailure(hr, "Failed to initialize");
150
151 do
152 {
153 hr = MqiInitialize();
154 if (S_FALSE == hr)
155 {
156 WcaLog(LOGMSG_STANDARD, "Failed to load mqrt.dll.");
157 er = WcaErrorMessage(msierrMsmqCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
158 switch (er)
159 {
160 case IDABORT:
161 ExitFunction1(hr = E_FAIL); // bail with error
162 case IDRETRY:
163 break; // retry
164 case IDIGNORE: __fallthrough;
165 default:
166 ExitFunction1(hr = S_OK); // pretend everything is okay and bail
167 }
168 }
169 ExitOnFailure(hr, "Failed to initialize MSMQ.");
170 } while (S_FALSE == hr);
171
172 // read message queues
173 hr = MqiMessageQueueRead(&lstMessageQueues);
174 ExitOnFailure(hr, "Failed to read MessageQueue table");
175
176 // read message queue permissions
177 hr = MqiMessageQueuePermissionRead(&lstMessageQueues, &lstMessageQueuePermissions);
178 ExitOnFailure(hr, "Failed to read message queue permissions");
179
180 if (lstMessageQueues.iUninstallCount || lstMessageQueuePermissions.iUninstallCount)
181 {
182 // schedule rollback action
183 hr = MqiMessageQueueUninstall(&lstMessageQueues, TRUE, &pwzRollbackActionData);
184 ExitOnFailure(hr, "Failed to add message queues to rollback action data");
185
186 hr = MqiMessageQueuePermissionUninstall(&lstMessageQueuePermissions, &pwzRollbackActionData);
187 ExitOnFailure(hr, "Failed to add message queue permissions to rollback action data");
188
189 hr = WcaDoDeferredAction(L"MessageQueuingRollbackUninstall", pwzRollbackActionData, 0);
190 ExitOnFailure(hr, "Failed to schedule MessageQueuingRollbackUninstall");
191
192 // schedule execute action
193 hr = MqiMessageQueuePermissionUninstall(&lstMessageQueuePermissions, &pwzExecuteActionData);
194 ExitOnFailure(hr, "Failed to add message queue permissions to execute action data");
195
196 hr = MqiMessageQueueUninstall(&lstMessageQueues, FALSE, &pwzExecuteActionData);
197 ExitOnFailure(hr, "Failed to add message queues to execute action data");
198 iCost += lstMessageQueues.iUninstallCount * COST_MESSAGE_QUEUE_DELETE;
199
200 hr = WcaDoDeferredAction(L"MessageQueuingExecuteUninstall", pwzExecuteActionData, iCost);
201 ExitOnFailure(hr, "Failed to schedule MessageQueuingExecuteUninstall");
202 }
203
204 hr = S_OK;
205
206LExit:
207 // clean up
208 MqiMessageQueueFreeList(&lstMessageQueues);
209 MqiMessageQueuePermissionFreeList(&lstMessageQueuePermissions);
210
211 ReleaseStr(pwzRollbackActionData);
212 ReleaseStr(pwzExecuteActionData);
213
214 // uninitialize
215 MqiUninitialize();
216
217 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
218 return WcaFinalize(er);
219}
diff --git a/src/ca/mqutilexec.cpp b/src/ca/mqutilexec.cpp
new file mode 100644
index 00000000..a9c56e02
--- /dev/null
+++ b/src/ca/mqutilexec.cpp
@@ -0,0 +1,380 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// private structs
7
8struct PCA_WELLKNOWN_SID
9{
10 LPCWSTR pwzName;
11 SID_IDENTIFIER_AUTHORITY iaIdentifierAuthority;
12 BYTE nSubAuthorityCount;
13 DWORD dwSubAuthority[8];
14};
15
16
17// well known SIDs
18
19PCA_WELLKNOWN_SID wsWellKnownSids[] = {
20 {L"\\Everyone", SECURITY_WORLD_SID_AUTHORITY, 1, {SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0}},
21 {L"\\Administrators", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0}},
22 {L"\\LocalSystem", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0}},
23 {L"\\LocalService", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0}},
24 {L"\\NetworkService", SECURITY_NT_AUTHORITY, 1, {SECURITY_NETWORK_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0}},
25 {L"\\AuthenticatedUser", SECURITY_NT_AUTHORITY, 1, {SECURITY_AUTHENTICATED_USER_RID, 0, 0, 0, 0, 0, 0, 0}},
26 {L"\\Guests", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS, 0, 0, 0, 0, 0, 0}},
27 {L"\\Users", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0}},
28 {L"\\CREATOR OWNER", SECURITY_NT_AUTHORITY, 1, {SECURITY_CREATOR_OWNER_RID, 0, 0, 0, 0, 0, 0, 0}},
29 {NULL, SECURITY_NULL_SID_AUTHORITY, 0, {0, 0, 0, 0, 0, 0, 0, 0}}
30};
31
32
33// prototypes for private helper functions
34
35static HRESULT CreateSidFromDomainRidPair(
36 PSID pDomainSid,
37 DWORD dwRid,
38 PSID* ppSid
39 );
40static HRESULT InitLsaUnicodeString(
41 PLSA_UNICODE_STRING plusStr,
42 LPCWSTR pwzStr,
43 DWORD dwLen
44 );
45static void FreeLsaUnicodeString(
46 PLSA_UNICODE_STRING plusStr
47 );
48
49
50// function definitions
51
52HRESULT PcaActionDataMessage(
53 DWORD cArgs,
54 ...
55 )
56{
57 HRESULT hr = S_OK;
58 UINT er = ERROR_SUCCESS;
59
60 PMSIHANDLE hRec;
61 va_list args;
62
63 // record
64 hRec = ::MsiCreateRecord(cArgs);
65 ExitOnNull(hRec, hr, E_OUTOFMEMORY, "Failed to create record");
66
67 va_start(args, cArgs);
68 for (DWORD i = 1; i <= cArgs; i++)
69 {
70 LPCWSTR pwzArg = va_arg(args, WCHAR*);
71 if (pwzArg && *pwzArg)
72 {
73 er = ::MsiRecordSetStringW(hRec, i, pwzArg);
74 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to set record field string");
75 }
76 }
77 va_end(args);
78
79 // message
80 er = WcaProcessMessage(INSTALLMESSAGE_ACTIONDATA, hRec);
81 if (0 == er || IDOK == er || IDYES == er)
82 {
83 hr = S_OK;
84 }
85 else if (ERROR_INSTALL_USEREXIT == er || IDABORT == er || IDCANCEL == er)
86 {
87 WcaSetReturnValue(ERROR_INSTALL_USEREXIT); // note that the user said exit
88 hr = S_FALSE;
89 }
90 else
91 hr = E_UNEXPECTED;
92
93LExit:
94 return hr;
95}
96
97HRESULT PcaAccountNameToSid(
98 LPCWSTR pwzAccountName,
99 PSID* ppSid
100 )
101{
102 HRESULT hr = S_OK;
103 UINT er = ERROR_SUCCESS;
104 NTSTATUS st = 0;
105
106 PSID pSid = NULL;
107 LSA_OBJECT_ATTRIBUTES loaAttributes;
108 LSA_HANDLE lsahPolicy = NULL;
109 LSA_UNICODE_STRING lusName;
110 PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL;
111 PLSA_TRANSLATED_SID pltsSid = NULL;
112
113 ::ZeroMemory(&loaAttributes, sizeof(loaAttributes));
114 ::ZeroMemory(&lusName, sizeof(lusName));
115
116 // identify well known SIDs
117 for (PCA_WELLKNOWN_SID* pWS = wsWellKnownSids; pWS->pwzName; pWS++)
118 {
119 if (0 == lstrcmpiW(pwzAccountName, pWS->pwzName))
120 {
121 // allocate SID buffer
122 pSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, ::GetSidLengthRequired(pWS->nSubAuthorityCount));
123 ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID");
124
125 // initialize SID
126 ::InitializeSid(pSid, &pWS->iaIdentifierAuthority, pWS->nSubAuthorityCount);
127
128 // copy sub autorities
129 for (DWORD i = 0; i < pWS->nSubAuthorityCount; i++)
130 *::GetSidSubAuthority(pSid, i) = pWS->dwSubAuthority[i];
131
132 break;
133 }
134 }
135
136 // lookup name
137 if (!pSid)
138 {
139 // open policy handle
140 st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy);
141 er = ::LsaNtStatusToWinError(st);
142 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle");
143
144 // create account name lsa unicode string
145 hr = InitLsaUnicodeString(&lusName, pwzAccountName, wcslen(pwzAccountName));
146 ExitOnFailure(hr, "Failed to initialize account name string");
147
148 // lookup name
149 st = ::LsaLookupNames(lsahPolicy, 1, &lusName, &plrdsDomains, &pltsSid);
150 er = ::LsaNtStatusToWinError(st);
151 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names");
152
153 if (SidTypeDomain == pltsSid->Use)
154 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported");
155
156 // convert sid
157 hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pSid);
158 ExitOnFailure(hr, "Failed to convert SID");
159 }
160
161 *ppSid = pSid;
162 pSid = NULL;
163
164 hr = S_OK;
165
166LExit:
167 // clean up
168 if (pSid)
169 ::HeapFree(::GetProcessHeap(), 0, pSid);
170 if (lsahPolicy)
171 ::LsaClose(lsahPolicy);
172 if (plrdsDomains)
173 ::LsaFreeMemory(plrdsDomains);
174 if (pltsSid)
175 ::LsaFreeMemory(pltsSid);
176 FreeLsaUnicodeString(&lusName);
177
178 return hr;
179}
180
181HRESULT PcaSidToAccountName(
182 PSID pSid,
183 LPWSTR* ppwzAccountName
184 )
185{
186 HRESULT hr = S_OK;
187 UINT er = ERROR_SUCCESS;
188 NTSTATUS st = 0;
189
190 LSA_OBJECT_ATTRIBUTES loaAttributes;
191 LSA_HANDLE lsahPolicy = NULL;
192 PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL;
193 PLSA_TRANSLATED_NAME pltnName = NULL;
194
195 LPWSTR pwzDomain = NULL;
196 LPWSTR pwzName = NULL;
197
198 ::ZeroMemory(&loaAttributes, sizeof(loaAttributes));
199
200 // open policy handle
201 st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy);
202 er = ::LsaNtStatusToWinError(st);
203 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle");
204
205 // lookup SID
206 st = ::LsaLookupSids(lsahPolicy, 1, &pSid, &plrdsDomains, &pltnName);
207 er = ::LsaNtStatusToWinError(st);
208 ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup SID");
209
210 if (SidTypeDomain == pltnName->Use)
211 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Domain SIDs not supported");
212
213 // format account name string
214 if (SidTypeWellKnownGroup != pltnName->Use)
215 {
216 PLSA_UNICODE_STRING plusDomain = &plrdsDomains->Domains[pltnName->DomainIndex].Name;
217 hr = StrAllocString(&pwzDomain, plusDomain->Buffer, plusDomain->Length / sizeof(WCHAR));
218 ExitOnFailure(hr, "Failed to allocate name string");
219 }
220
221 hr = StrAllocString(&pwzName, pltnName->Name.Buffer, pltnName->Name.Length / sizeof(WCHAR));
222 ExitOnFailure(hr, "Failed to allocate domain string");
223
224 hr = StrAllocFormatted(ppwzAccountName, L"%s\\%s", pwzDomain ? pwzDomain : L"", pwzName);
225 ExitOnFailure(hr, "Failed to format account name string");
226
227 hr = S_OK;
228
229LExit:
230 // clean up
231 if (lsahPolicy)
232 ::LsaClose(lsahPolicy);
233 if (plrdsDomains)
234 ::LsaFreeMemory(plrdsDomains);
235 if (pltnName)
236 ::LsaFreeMemory(pltnName);
237
238 ReleaseStr(pwzDomain);
239 ReleaseStr(pwzName);
240
241 return hr;
242}
243
244HRESULT PcaBuildAccountName(
245 LPCWSTR pwzDomain,
246 LPCWSTR pwzName,
247 LPWSTR* ppwzAccount
248 )
249{
250 HRESULT hr = S_OK;
251
252 WCHAR wzComputerName[MAX_COMPUTERNAME_LENGTH + 1];
253 ::ZeroMemory(wzComputerName, sizeof(wzComputerName));
254
255 // if domain is '.', get computer name
256 if (0 == lstrcmpW(pwzDomain, L"."))
257 {
258 DWORD dwSize = countof(wzComputerName);
259 if (!::GetComputerNameW(wzComputerName, &dwSize))
260 ExitOnFailure(hr = HRESULT_FROM_WIN32(::GetLastError()), "Failed to get computer name");
261 }
262
263 // build account name
264 hr = StrAllocFormatted(ppwzAccount, L"%s\\%s", *wzComputerName ? wzComputerName : pwzDomain, pwzName);
265 ExitOnFailure(hr, "Failed to build domain user name");
266
267 hr = S_OK;
268
269LExit:
270 return hr;
271}
272
273HRESULT PcaGuidFromString(
274 LPCWSTR pwzGuid,
275 LPGUID pGuid
276 )
277{
278 HRESULT hr = S_OK;
279
280 int cch = 0;
281
282 WCHAR wz[39];
283 ::ZeroMemory(wz, sizeof(wz));
284
285 cch = lstrlenW(pwzGuid);
286
287 if (38 == cch && L'{' == pwzGuid[0] && L'}' == pwzGuid[37])
288 StringCchCopyW(wz, countof(wz), pwzGuid);
289 else if (36 == cch)
290 StringCchPrintfW(wz, countof(wz), L"{%s}", pwzGuid);
291 else
292 ExitFunction1(hr = E_INVALIDARG);
293
294 hr = ::CLSIDFromString(wz, pGuid);
295
296LExit:
297 return hr;
298}
299
300
301// helper function definitions
302
303static HRESULT CreateSidFromDomainRidPair(
304 PSID pDomainSid,
305 DWORD dwRid,
306 PSID* ppSid
307 )
308{
309 HRESULT hr = S_OK;
310
311 PSID pSid = NULL;
312
313 // get domain SID sub authority count
314 UCHAR ucSubAuthorityCount = *::GetSidSubAuthorityCount(pDomainSid);
315
316 // allocate SID buffer
317 DWORD dwLengthRequired = ::GetSidLengthRequired(ucSubAuthorityCount + (UCHAR)1);
318 if (*ppSid)
319 {
320 SIZE_T ccb = ::HeapSize(::GetProcessHeap(), 0, *ppSid);
321 if (-1 == ccb)
322 ExitOnFailure(hr = E_FAIL, "Failed to get size of SID buffer");
323
324 if (ccb < dwLengthRequired)
325 {
326 pSid = (PSID)::HeapReAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, *ppSid, dwLengthRequired);
327 ExitOnNull(pSid, hr, E_OUTOFMEMORY, "Failed to reallocate buffer for SID, len: %d", dwLengthRequired);
328 *ppSid = pSid;
329 }
330 }
331 else
332 {
333 *ppSid = (PSID)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, dwLengthRequired);
334 ExitOnNull(*ppSid, hr, E_OUTOFMEMORY, "Failed to allocate buffer for SID, len: %d", dwLengthRequired);
335 }
336
337 ::InitializeSid(*ppSid, ::GetSidIdentifierAuthority(pDomainSid), ucSubAuthorityCount + (UCHAR)1);
338
339 // copy sub autorities
340 DWORD i = 0;
341 for (; i < ucSubAuthorityCount; i++)
342 *::GetSidSubAuthority(*ppSid, i) = *::GetSidSubAuthority(pDomainSid, i);
343 *::GetSidSubAuthority(*ppSid, i) = dwRid;
344
345 hr = S_OK;
346
347LExit:
348 return hr;
349}
350
351static HRESULT InitLsaUnicodeString(
352 PLSA_UNICODE_STRING plusStr,
353 LPCWSTR pwzStr,
354 DWORD dwLen
355 )
356{
357 HRESULT hr = S_OK;
358
359 plusStr->Length = (USHORT)dwLen * sizeof(WCHAR);
360 plusStr->MaximumLength = (USHORT)(dwLen + 1) * sizeof(WCHAR);
361
362 plusStr->Buffer = (WCHAR*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) * (dwLen + 1));
363 ExitOnNull(plusStr->Buffer, hr, E_OUTOFMEMORY, "Failed to allocate account name string");
364
365 hr = StringCchCopyW(plusStr->Buffer, dwLen + 1, pwzStr);
366 ExitOnFailure(hr, "Failed to copy buffer");
367
368 hr = S_OK;
369
370LExit:
371 return hr;
372}
373
374static void FreeLsaUnicodeString(
375 PLSA_UNICODE_STRING plusStr
376 )
377{
378 if (plusStr->Buffer)
379 ::HeapFree(::GetProcessHeap(), 0, plusStr->Buffer);
380}
diff --git a/src/ca/mqutilexec.h b/src/ca/mqutilexec.h
new file mode 100644
index 00000000..d3dc17a1
--- /dev/null
+++ b/src/ca/mqutilexec.h
@@ -0,0 +1,23 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3HRESULT PcaActionDataMessage(
4 DWORD cArgs,
5 ...
6 );
7HRESULT PcaAccountNameToSid(
8 LPCWSTR pwzAccountName,
9 PSID* ppSid
10 );
11HRESULT PcaSidToAccountName(
12 PSID pSid,
13 LPWSTR* ppwzAccountName
14 );
15HRESULT PcaBuildAccountName(
16 LPCWSTR pwzDomain,
17 LPCWSTR pwzName,
18 LPWSTR* ppwzAccount
19 );
20HRESULT PcaGuidFromString(
21 LPCWSTR pwzGuid,
22 GUID* pGuid
23 );
diff --git a/src/ca/mqutilsched.cpp b/src/ca/mqutilsched.cpp
new file mode 100644
index 00000000..4353a6d6
--- /dev/null
+++ b/src/ca/mqutilsched.cpp
@@ -0,0 +1,43 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// function definitions
7
8HRESULT PcaGuidToRegFormat(
9 LPWSTR pwzGuid,
10 LPWSTR pwzDest,
11 SIZE_T cchDest
12 )
13{
14 HRESULT hr = S_OK;
15
16 GUID guid = GUID_NULL;
17 int cch = 0;
18
19 WCHAR wz[39];
20 ::ZeroMemory(wz, sizeof(wz));
21
22 cch = lstrlenW(pwzGuid);
23
24 if (38 == cch && L'{' == pwzGuid[0] && L'}' == pwzGuid[37])
25 StringCchCopyW(wz, countof(wz), pwzGuid);
26 else if (36 == cch)
27 StringCchPrintfW(wz, countof(wz), L"{%s}", pwzGuid);
28 else
29 ExitFunction1(hr = E_INVALIDARG);
30
31 // convert string to guid
32 hr = ::CLSIDFromString(wz, &guid);
33 ExitOnFailure(hr, "Failed to parse guid string");
34
35 // convert guid to string
36 if (0 == ::StringFromGUID2(guid, pwzDest, cchDest))
37 ExitOnFailure(hr = E_FAIL, "Failed to convert guid to string");
38
39 hr = S_OK;
40
41LExit:
42 return hr;
43}
diff --git a/src/ca/mqutilsched.h b/src/ca/mqutilsched.h
new file mode 100644
index 00000000..e172257d
--- /dev/null
+++ b/src/ca/mqutilsched.h
@@ -0,0 +1,9 @@
1#pragma once
2// 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.
3
4
5HRESULT PcaGuidToRegFormat(
6 LPWSTR pwzGuid,
7 LPWSTR pwzDest,
8 SIZE_T cchDest
9 );