diff options
Diffstat (limited to 'src/ext/Iis/ca/scaexec.cpp')
-rw-r--r-- | src/ext/Iis/ca/scaexec.cpp | 1184 |
1 files changed, 1184 insertions, 0 deletions
diff --git a/src/ext/Iis/ca/scaexec.cpp b/src/ext/Iis/ca/scaexec.cpp new file mode 100644 index 00000000..df25e8db --- /dev/null +++ b/src/ext/Iis/ca/scaexec.cpp | |||
@@ -0,0 +1,1184 @@ | |||
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 | StartMetabaseTransaction - CUSTOM ACTION ENTRY POINT for backing up metabase | ||
8 | |||
9 | Input: deferred CustomActionData - BackupName | ||
10 | ********************************************************************/ | ||
11 | extern "C" UINT __stdcall StartMetabaseTransaction(MSIHANDLE hInstall) | ||
12 | { | ||
13 | //AssertSz(FALSE, "debug StartMetabaseTransaction here"); | ||
14 | HRESULT hr = S_OK; | ||
15 | UINT er = ERROR_SUCCESS; | ||
16 | |||
17 | IMSAdminBase* piMetabase = NULL; | ||
18 | LPWSTR pwzData = NULL; | ||
19 | BOOL fInitializedCom = FALSE; | ||
20 | |||
21 | // initialize | ||
22 | hr = WcaInitialize(hInstall, "StartMetabaseTransaction"); | ||
23 | ExitOnFailure(hr, "failed to initialize StartMetabaseTransaction"); | ||
24 | |||
25 | hr = ::CoInitialize(NULL); | ||
26 | ExitOnFailure(hr, "failed to initialize COM"); | ||
27 | fInitializedCom = TRUE; | ||
28 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
29 | if (hr == REGDB_E_CLASSNOTREG) | ||
30 | { | ||
31 | WcaLog(LOGMSG_STANDARD, "Failed to get IIMSAdminBase to backup - continuing"); | ||
32 | hr = S_OK; | ||
33 | } | ||
34 | else | ||
35 | { | ||
36 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
37 | |||
38 | hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||
39 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
40 | |||
41 | // back up the metabase | ||
42 | Assert(lstrlenW(pwzData) < MD_BACKUP_MAX_LEN); | ||
43 | |||
44 | // MD_BACKUP_OVERWRITE = Overwrite if a backup of the same name and version exists in the backup location | ||
45 | hr = piMetabase->Backup(pwzData, MD_BACKUP_NEXT_VERSION, MD_BACKUP_OVERWRITE | MD_BACKUP_FORCE_BACKUP | MD_BACKUP_SAVE_FIRST); | ||
46 | if (MD_WARNING_SAVE_FAILED == hr) | ||
47 | { | ||
48 | WcaLog(LOGMSG_STANDARD, "Failed to save metabase before backing up - continuing"); | ||
49 | hr = S_OK; | ||
50 | } | ||
51 | MessageExitOnFailure(hr, msierrIISFailedStartTransaction, "failed to begin metabase transaction: '%ls'", pwzData); | ||
52 | } | ||
53 | hr = WcaProgressMessage(COST_IIS_TRANSACTIONS, FALSE); | ||
54 | LExit: | ||
55 | ReleaseStr(pwzData); | ||
56 | ReleaseObject(piMetabase); | ||
57 | |||
58 | if (fInitializedCom) | ||
59 | { | ||
60 | ::CoUninitialize(); | ||
61 | } | ||
62 | |||
63 | if (FAILED(hr)) | ||
64 | er = ERROR_INSTALL_FAILURE; | ||
65 | return WcaFinalize(er); | ||
66 | } | ||
67 | |||
68 | |||
69 | /******************************************************************** | ||
70 | RollbackMetabaseTransaction - CUSTOM ACTION ENTRY POINT for unbacking up metabase | ||
71 | |||
72 | Input: deferred CustomActionData - BackupName | ||
73 | ********************************************************************/ | ||
74 | extern "C" UINT __stdcall RollbackMetabaseTransaction(MSIHANDLE hInstall) | ||
75 | { | ||
76 | //AssertSz(FALSE, "debug RollbackMetabaseTransaction here"); | ||
77 | HRESULT hr = S_OK; | ||
78 | UINT er = ERROR_SUCCESS; | ||
79 | |||
80 | IMSAdminBase* piMetabase = NULL; | ||
81 | LPWSTR pwzData = NULL; | ||
82 | BOOL fInitializedCom = FALSE; | ||
83 | |||
84 | hr = WcaInitialize(hInstall, "RollbackMetabaseTransaction"); | ||
85 | ExitOnFailure(hr, "failed to initialize"); | ||
86 | |||
87 | hr = ::CoInitialize(NULL); | ||
88 | ExitOnFailure(hr, "failed to initialize COM"); | ||
89 | fInitializedCom = TRUE; | ||
90 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
91 | if (hr == REGDB_E_CLASSNOTREG) | ||
92 | { | ||
93 | WcaLog(LOGMSG_STANDARD, "Failed to get IIMSAdminBase to rollback - continuing"); | ||
94 | hr = S_OK; | ||
95 | ExitFunction(); | ||
96 | } | ||
97 | ExitOnFailure(hr, "failed to get IID_IIMSAdminBase object"); | ||
98 | |||
99 | |||
100 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
101 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
102 | |||
103 | hr = piMetabase->Restore(pwzData, MD_BACKUP_HIGHEST_VERSION, 0); | ||
104 | ExitOnFailure(hr, "failed to rollback metabase transaction: '%ls'", pwzData); | ||
105 | |||
106 | hr = piMetabase->DeleteBackup(pwzData, MD_BACKUP_HIGHEST_VERSION); | ||
107 | ExitOnFailure(hr, "failed to cleanup metabase transaction '%ls', continuing", pwzData); | ||
108 | |||
109 | LExit: | ||
110 | ReleaseStr(pwzData); | ||
111 | ReleaseObject(piMetabase); | ||
112 | |||
113 | if (fInitializedCom) | ||
114 | { | ||
115 | ::CoUninitialize(); | ||
116 | } | ||
117 | |||
118 | if (FAILED(hr)) | ||
119 | { | ||
120 | er = ERROR_INSTALL_FAILURE; | ||
121 | } | ||
122 | return WcaFinalize(er); | ||
123 | } | ||
124 | |||
125 | |||
126 | /******************************************************************** | ||
127 | CommitMetabaseTransaction - CUSTOM ACTION ENTRY POINT for unbacking up metabase | ||
128 | |||
129 | Input: deferred CustomActionData - BackupName | ||
130 | * *****************************************************************/ | ||
131 | extern "C" UINT __stdcall CommitMetabaseTransaction(MSIHANDLE hInstall) | ||
132 | { | ||
133 | HRESULT hr = S_OK; | ||
134 | UINT er = ERROR_SUCCESS; | ||
135 | |||
136 | IMSAdminBase* piMetabase = NULL; | ||
137 | LPWSTR pwzData = NULL; | ||
138 | BOOL fInitializedCom = FALSE; | ||
139 | |||
140 | hr = WcaInitialize(hInstall, "CommitMetabaseTransaction"); | ||
141 | ExitOnFailure(hr, "failed to initialize"); | ||
142 | |||
143 | hr = ::CoInitialize(NULL); | ||
144 | ExitOnFailure(hr, "failed to initialize COM"); | ||
145 | fInitializedCom = TRUE; | ||
146 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
147 | if (hr == REGDB_E_CLASSNOTREG) | ||
148 | { | ||
149 | WcaLog(LOGMSG_STANDARD, "Failed to get IIMSAdminBase to commit - continuing"); | ||
150 | hr = S_OK; | ||
151 | ExitFunction(); | ||
152 | } | ||
153 | ExitOnFailure(hr, "failed to get IID_IIMSAdminBase object"); | ||
154 | |||
155 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
156 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
157 | |||
158 | hr = piMetabase->DeleteBackup(pwzData, MD_BACKUP_HIGHEST_VERSION); | ||
159 | ExitOnFailure(hr, "failed to cleanup metabase transaction: '%ls'", pwzData); | ||
160 | |||
161 | LExit: | ||
162 | ReleaseStr(pwzData); | ||
163 | ReleaseObject(piMetabase); | ||
164 | |||
165 | if (fInitializedCom) | ||
166 | { | ||
167 | ::CoUninitialize(); | ||
168 | } | ||
169 | |||
170 | if (FAILED(hr)) | ||
171 | { | ||
172 | er = ERROR_INSTALL_FAILURE; | ||
173 | } | ||
174 | return WcaFinalize(er); | ||
175 | } | ||
176 | |||
177 | |||
178 | /******************************************************************** | ||
179 | CreateMetabaseKey - Installs metabase keys | ||
180 | |||
181 | Input: deferred CustomActionData - Key | ||
182 | * *****************************************************************/ | ||
183 | static HRESULT CreateMetabaseKey(__in LPWSTR* ppwzCustomActionData, __in IMSAdminBase* piMetabase) | ||
184 | { | ||
185 | //AssertSz(FALSE, "debug CreateMetabaseKey here"); | ||
186 | HRESULT hr = S_OK; | ||
187 | METADATA_HANDLE mhRoot = 0; | ||
188 | LPWSTR pwzData = NULL; | ||
189 | LPCWSTR pwzKey; | ||
190 | |||
191 | int i; | ||
192 | |||
193 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
194 | ExitOnFailure(hr, "failed to read key from custom action data"); | ||
195 | |||
196 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhRoot); | ||
197 | for (i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--) | ||
198 | { | ||
199 | ::Sleep(1000); | ||
200 | WcaLog(LOGMSG_STANDARD, "failed to open root key, retrying %d time(s)...", i); | ||
201 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhRoot); | ||
202 | } | ||
203 | MessageExitOnFailure(hr, msierrIISFailedOpenKey, "failed to open metabase key: %ls", L"/LM"); | ||
204 | |||
205 | pwzKey = pwzData + 3; | ||
206 | |||
207 | WcaLog(LOGMSG_VERBOSE, "Creating Metabase Key: %ls", pwzKey); | ||
208 | |||
209 | hr = piMetabase->AddKey(mhRoot, pwzKey); | ||
210 | if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) == hr) | ||
211 | { | ||
212 | WcaLog(LOGMSG_VERBOSE, "Key `%ls` already existed, continuing.", pwzData); | ||
213 | hr = S_OK; | ||
214 | } | ||
215 | MessageExitOnFailure(hr, msierrIISFailedCreateKey, "failed to create metabase key: %ls", pwzKey); | ||
216 | |||
217 | hr = WcaProgressMessage(COST_IIS_CREATEKEY, FALSE); | ||
218 | |||
219 | LExit: | ||
220 | if (mhRoot) | ||
221 | { | ||
222 | piMetabase->CloseKey(mhRoot); | ||
223 | } | ||
224 | |||
225 | return hr; | ||
226 | } | ||
227 | |||
228 | |||
229 | /******************************************************************** | ||
230 | WriteMetabaseValue -Installs metabase values | ||
231 | |||
232 | Input: deferred CustomActionData - Key\tIdentifier\tAttributes\tUserType\tDataType\tData | ||
233 | * *****************************************************************/ | ||
234 | static HRESULT WriteMetabaseValue(__in LPWSTR* ppwzCustomActionData, __in IMSAdminBase* piMetabase) | ||
235 | { | ||
236 | //AssertSz(FALSE, "debug WriteMetabaseValue here"); | ||
237 | HRESULT hr = S_OK; | ||
238 | |||
239 | METADATA_HANDLE mhKey = 0; | ||
240 | |||
241 | LPWSTR pwzKey = NULL; | ||
242 | LPWSTR pwzTemp = NULL; | ||
243 | DWORD dwData = 0; | ||
244 | DWORD dwTemp = 0; | ||
245 | BOOL fFreeData = FALSE; | ||
246 | METADATA_RECORD mr; | ||
247 | ::ZeroMemory((LPVOID)&mr, sizeof(mr)); | ||
248 | METADATA_RECORD mrGet; | ||
249 | ::ZeroMemory((LPVOID)&mrGet, sizeof(mrGet)); | ||
250 | |||
251 | int i; | ||
252 | |||
253 | // get the key first | ||
254 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzKey); | ||
255 | ExitOnFailure(hr, "failed to read key"); | ||
256 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&mr.dwMDIdentifier)); | ||
257 | ExitOnFailure(hr, "failed to read identifier"); | ||
258 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&mr.dwMDAttributes)); | ||
259 | ExitOnFailure(hr, "failed to read attributes"); | ||
260 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&mr.dwMDUserType)); | ||
261 | ExitOnFailure(hr, "failed to read user type"); | ||
262 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&mr.dwMDDataType)); | ||
263 | ExitOnFailure(hr, "failed to read data type"); | ||
264 | |||
265 | switch (mr.dwMDDataType) // data | ||
266 | { | ||
267 | case DWORD_METADATA: | ||
268 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&dwData)); | ||
269 | mr.dwMDDataLen = sizeof(dwData); | ||
270 | mr.pbMDData = reinterpret_cast<BYTE*>(&dwData); | ||
271 | break; | ||
272 | case STRING_METADATA: | ||
273 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzTemp); | ||
274 | mr.dwMDDataLen = (lstrlenW(pwzTemp) + 1) * sizeof(WCHAR); | ||
275 | mr.pbMDData = reinterpret_cast<BYTE*>(pwzTemp); | ||
276 | break; | ||
277 | case MULTISZ_METADATA: | ||
278 | { | ||
279 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzTemp); | ||
280 | mr.dwMDDataLen = (lstrlenW(pwzTemp) + 1) * sizeof(WCHAR); | ||
281 | for (LPWSTR pwzT = pwzTemp; *pwzT; ++pwzT) | ||
282 | { | ||
283 | if (MAGIC_MULTISZ_CHAR == *pwzT) | ||
284 | { | ||
285 | *pwzT = L'\0'; | ||
286 | } | ||
287 | } | ||
288 | mr.pbMDData = reinterpret_cast<BYTE*>(pwzTemp); | ||
289 | } | ||
290 | break; | ||
291 | case BINARY_METADATA: | ||
292 | hr = WcaReadStreamFromCaData(ppwzCustomActionData, &mr.pbMDData, reinterpret_cast<DWORD_PTR *>(&mr.dwMDDataLen)); | ||
293 | fFreeData = TRUE; | ||
294 | break; | ||
295 | default: | ||
296 | hr = E_UNEXPECTED; | ||
297 | break; | ||
298 | } | ||
299 | ExitOnFailure(hr, "failed to parse CustomActionData into metabase record"); | ||
300 | |||
301 | WcaLog(LOGMSG_VERBOSE, "Writing Metabase Value Under Key: %ls ID: %d", pwzKey, mr.dwMDIdentifier); | ||
302 | |||
303 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhKey); | ||
304 | for (i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--) | ||
305 | { | ||
306 | ::Sleep(1000); | ||
307 | WcaLog(LOGMSG_STANDARD, "failed to open '%ls' key, retrying %d time(s)...", pwzKey, i); | ||
308 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhKey); | ||
309 | } | ||
310 | MessageExitOnFailure(hr, msierrIISFailedOpenKey, "failed to open metabase key: %ls", pwzKey); | ||
311 | |||
312 | if (lstrlenW(pwzKey) < 3) | ||
313 | { | ||
314 | ExitOnFailure(hr = E_INVALIDARG, "Key didn't begin with \"/LM\" as expected - key value: %ls", pwzKey); | ||
315 | } | ||
316 | |||
317 | hr = piMetabase->SetData(mhKey, pwzKey + 3, &mr); // pwzKey + 3 to skip "/LM" that was used to open the key. | ||
318 | |||
319 | // This means we're trying to write to a secure key without the secure flag set - let's try again with the secure flag set | ||
320 | if (MD_ERROR_CANNOT_REMOVE_SECURE_ATTRIBUTE == hr) | ||
321 | { | ||
322 | mr.dwMDAttributes |= METADATA_SECURE; | ||
323 | hr = piMetabase->SetData(mhKey, pwzKey + 3, &mr); | ||
324 | } | ||
325 | |||
326 | // If IIS6 returned failure, let's check if the correct value exists in the metabase before actually failing the CA | ||
327 | if (FAILED(hr)) | ||
328 | { | ||
329 | // Backup the original failure error, so we can log it below if necessary | ||
330 | HRESULT hrOldValue = hr; | ||
331 | |||
332 | mrGet.dwMDIdentifier = mr.dwMDIdentifier; | ||
333 | mrGet.dwMDAttributes = METADATA_NO_ATTRIBUTES; | ||
334 | mrGet.dwMDUserType = mr.dwMDUserType; | ||
335 | mrGet.dwMDDataType = mr.dwMDDataType; | ||
336 | mrGet.dwMDDataLen = mr.dwMDDataLen; | ||
337 | mrGet.pbMDData = static_cast<BYTE*>(MemAlloc(mr.dwMDDataLen, TRUE)); | ||
338 | |||
339 | hr = piMetabase->GetData(mhKey, pwzKey + 3, &mrGet, &dwTemp); | ||
340 | if (SUCCEEDED(hr)) | ||
341 | { | ||
342 | if (mrGet.dwMDDataType == mr.dwMDDataType && mrGet.dwMDDataLen == mr.dwMDDataLen && 0 == memcmp(mrGet.pbMDData, mr.pbMDData, mr.dwMDDataLen)) | ||
343 | { | ||
344 | WcaLog(LOGMSG_VERBOSE, "Received error while writing metabase value under key: %ls ID: %d with error 0x%x, but the correct value is in the metabase - continuing", pwzKey, mr.dwMDIdentifier, hrOldValue); | ||
345 | hr = S_OK; | ||
346 | } | ||
347 | else | ||
348 | { | ||
349 | WcaLog(LOGMSG_VERBOSE, "Succeeded in checking metabase value after write value, but the values didn't match"); | ||
350 | hr = hrOldValue; | ||
351 | } | ||
352 | } | ||
353 | else | ||
354 | { | ||
355 | WcaLog(LOGMSG_VERBOSE, "Failed to check value after metabase write failure (error code 0x%x)", hr); | ||
356 | hr = hrOldValue; | ||
357 | } | ||
358 | } | ||
359 | MessageExitOnFailure(hr, msierrIISFailedWriteData, "failed to write data to metabase key: %ls", pwzKey); | ||
360 | |||
361 | hr = WcaProgressMessage(COST_IIS_WRITEVALUE, FALSE); | ||
362 | |||
363 | LExit: | ||
364 | ReleaseStr(pwzTemp); | ||
365 | ReleaseStr(pwzKey); | ||
366 | |||
367 | if (mhKey) | ||
368 | { | ||
369 | piMetabase->CloseKey(mhKey); | ||
370 | } | ||
371 | |||
372 | if (fFreeData && mr.pbMDData) | ||
373 | { | ||
374 | MemFree(mr.pbMDData); | ||
375 | } | ||
376 | |||
377 | return hr; | ||
378 | } | ||
379 | |||
380 | |||
381 | /******************************************************************** | ||
382 | DeleteMetabaseValue -Installs metabase values | ||
383 | |||
384 | Input: deferred CustomActionData - Key\tIdentifier\tAttributes\tUserType\tDataType\tData | ||
385 | * *****************************************************************/ | ||
386 | static HRESULT DeleteMetabaseValue(__in LPWSTR* ppwzCustomActionData, __in IMSAdminBase* piMetabase) | ||
387 | { | ||
388 | //AssertSz(FALSE, "debug DeleteMetabaseValue here"); | ||
389 | HRESULT hr = S_OK; | ||
390 | |||
391 | METADATA_HANDLE mhKey = 0; | ||
392 | |||
393 | LPWSTR pwzKey = NULL; | ||
394 | DWORD dwIdentifier = 0; | ||
395 | DWORD dwDataType = 0; | ||
396 | |||
397 | int i; | ||
398 | |||
399 | // get the key first | ||
400 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzKey); | ||
401 | ExitOnFailure(hr, "failed to read key"); | ||
402 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&dwIdentifier)); | ||
403 | ExitOnFailure(hr, "failed to read identifier"); | ||
404 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&dwDataType)); | ||
405 | ExitOnFailure(hr, "failed to read data type"); | ||
406 | |||
407 | WcaLog(LOGMSG_VERBOSE, "Deleting Metabase Value Under Key: %ls ID: %d", pwzKey, dwIdentifier); | ||
408 | |||
409 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhKey); | ||
410 | for (i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--) | ||
411 | { | ||
412 | ::Sleep(1000); | ||
413 | WcaLog(LOGMSG_STANDARD, "failed to open '%ls' key, retrying %d time(s)...", pwzKey, i); | ||
414 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhKey); | ||
415 | } | ||
416 | MessageExitOnFailure(hr, msierrIISFailedOpenKey, "failed to open metabase key: %ls", pwzKey); | ||
417 | |||
418 | if (lstrlenW(pwzKey) < 3) | ||
419 | { | ||
420 | ExitOnFailure(hr = E_INVALIDARG, "Key didn't begin with \"/LM\" as expected - key value: %ls", pwzKey); | ||
421 | } | ||
422 | |||
423 | hr = piMetabase->DeleteData(mhKey, pwzKey + 3, dwIdentifier, dwDataType); // pwzKey + 3 to skip "/LM" that was used to open the key. | ||
424 | if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) | ||
425 | { | ||
426 | hr = S_OK; | ||
427 | } | ||
428 | MessageExitOnFailure(hr, msierrIISFailedDeleteValue, "failed to delete value %d from metabase key: %ls", dwIdentifier, pwzKey); | ||
429 | |||
430 | hr = WcaProgressMessage(COST_IIS_DELETEVALUE, FALSE); | ||
431 | LExit: | ||
432 | ReleaseStr(pwzKey); | ||
433 | |||
434 | if (mhKey) | ||
435 | piMetabase->CloseKey(mhKey); | ||
436 | |||
437 | return hr; | ||
438 | } | ||
439 | |||
440 | |||
441 | /******************************************************************** | ||
442 | DeleteAspApp - Deletes applications in IIS | ||
443 | |||
444 | Input: deferred CustomActionData - MetabaseRoot\tRecursive | ||
445 | * *****************************************************************/ | ||
446 | static HRESULT DeleteAspApp(__in LPWSTR* ppwzCustomActionData, __in IMSAdminBase* piMetabase, __in ICatalogCollection* pApplicationCollection, __in IWamAdmin* piWam) | ||
447 | { | ||
448 | const int BUFFER_BYTES = 512; | ||
449 | const BSTR bstrPropName = SysAllocString(L"Deleteable"); | ||
450 | |||
451 | HRESULT hr = S_OK; | ||
452 | ICatalogObject* pApplication = NULL; | ||
453 | |||
454 | LPWSTR pwzRoot = NULL; | ||
455 | DWORD dwActualBufferSize = 0; | ||
456 | long lSize = 0; | ||
457 | long lIndex = 0; | ||
458 | long lChanges = 0; | ||
459 | |||
460 | VARIANT keyValue; | ||
461 | ::VariantInit(&keyValue); | ||
462 | VARIANT propValue; | ||
463 | propValue.vt = VT_BOOL; | ||
464 | propValue.boolVal = TRUE; | ||
465 | |||
466 | METADATA_RECORD mr; | ||
467 | // Get current set of web service extensions. | ||
468 | ::ZeroMemory(&mr, sizeof(mr)); | ||
469 | mr.dwMDIdentifier = MD_APP_PACKAGE_ID; | ||
470 | mr.dwMDAttributes = 0; | ||
471 | mr.dwMDUserType = ASP_MD_UT_APP; | ||
472 | mr.dwMDDataType = STRING_METADATA; | ||
473 | mr.pbMDData = new unsigned char[BUFFER_BYTES]; | ||
474 | mr.dwMDDataLen = BUFFER_BYTES; | ||
475 | |||
476 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzRoot); // MetabaseRoot | ||
477 | ExitOnFailure(hr, "failed to get metabase root"); | ||
478 | |||
479 | hr = piMetabase->GetData(METADATA_MASTER_ROOT_HANDLE, pwzRoot, &mr, &dwActualBufferSize); | ||
480 | if (HRESULT_FROM_WIN32(MD_ERROR_DATA_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
481 | { | ||
482 | // This one doesn't have an independent app GUID associated with it - it may have been already partially deleted, or a low isolation app | ||
483 | WcaLog(LOGMSG_VERBOSE, "No independent COM+ application found associated with %ls. It either doesn't exist, or was already removed - continuing", pwzRoot); | ||
484 | ExitFunction1(hr = S_OK); | ||
485 | } | ||
486 | MessageExitOnFailure(hr, msierrIISFailedDeleteApp, "failed to get GUID for application at path: %ls", pwzRoot); | ||
487 | |||
488 | WcaLog(LOGMSG_VERBOSE, "Deleting ASP App (used query: %ls) with GUID: %ls", pwzRoot, (LPWSTR)(mr.pbMDData)); | ||
489 | |||
490 | // Delete the application association from IIS's point of view before it's obliterated from the application collection | ||
491 | hr = piWam->AppDelete(pwzRoot, FALSE); | ||
492 | if (FAILED(hr)) | ||
493 | { | ||
494 | // This isn't necessarily an error if we fail here, but let's log a failure if it happens | ||
495 | WcaLog(LOGMSG_VERBOSE, "error 0x%x: failed to call IWamAdmin::AppDelete() while removing web application - continuing"); | ||
496 | hr = S_OK; | ||
497 | } | ||
498 | |||
499 | if (!pApplicationCollection) | ||
500 | { | ||
501 | WcaLog(LOGMSG_STANDARD, "Could not remove application with GUID %ls because the application collection could not be found", (LPWSTR)(mr.pbMDData)); | ||
502 | ExitFunction1(hr = S_OK); | ||
503 | } | ||
504 | |||
505 | hr = pApplicationCollection->Populate(); | ||
506 | MessageExitOnFailure(hr, msierrIISFailedDeleteApp, "failed to populate Application collection"); | ||
507 | |||
508 | hr = pApplicationCollection->get_Count(&lSize); | ||
509 | MessageExitOnFailure(hr, msierrIISFailedDeleteApp, "failed to get size of Application collection"); | ||
510 | WcaLog(LOGMSG_TRACEONLY, "Found %u items in application collection", lSize); | ||
511 | |||
512 | // No need to check this too early, as we may not even need this to have successfully allocated | ||
513 | ExitOnNull(bstrPropName, hr, E_OUTOFMEMORY, "failed to allocate memory for \"Deleteable\" string"); | ||
514 | |||
515 | for (lIndex = 0; lIndex < lSize; ++lIndex) | ||
516 | { | ||
517 | hr = pApplicationCollection->get_Item(lIndex, reinterpret_cast<IDispatch**>(&pApplication)); | ||
518 | MessageExitOnFailure(hr, msierrIISFailedDeleteApp, "failed to get COM+ application while enumerating through COM+ applications"); | ||
519 | |||
520 | hr = pApplication->get_Key(&keyValue); | ||
521 | MessageExitOnFailure(hr, msierrIISFailedDeleteApp, "failed to get key of COM+ application while enumerating through COM+ applications"); | ||
522 | |||
523 | WcaLog(LOGMSG_TRACEONLY, "While enumerating through COM+ applications, found an application with GUID: %ls", (LPWSTR)keyValue.bstrVal); | ||
524 | |||
525 | if (VT_BSTR == keyValue.vt && 0 == lstrcmpW((LPWSTR)keyValue.bstrVal, (LPWSTR)(mr.pbMDData))) | ||
526 | { | ||
527 | hr = pApplication->put_Value(bstrPropName, propValue); | ||
528 | if (FAILED(hr)) | ||
529 | { | ||
530 | // This isn't necessarily a critical error unless we fail to actually delete it in the next step | ||
531 | WcaLog(LOGMSG_VERBOSE, "error 0x%x: failed to ensure COM+ application with guid %ls is deletable - continuing", hr, (LPWSTR)(mr.pbMDData)); | ||
532 | } | ||
533 | |||
534 | hr = pApplicationCollection->SaveChanges(&lChanges); | ||
535 | if (FAILED(hr)) | ||
536 | { | ||
537 | // This isn't necessarily a critical error unless we fail to actually delete it in the next step | ||
538 | WcaLog(LOGMSG_VERBOSE, "error 0x%x: failed to save changes while ensuring COM+ application with guid %ls is deletable - continuing", hr, (LPWSTR)(mr.pbMDData)); | ||
539 | } | ||
540 | |||
541 | hr = pApplicationCollection->Remove(lIndex); | ||
542 | if (FAILED(hr)) | ||
543 | { | ||
544 | WcaLog(LOGMSG_STANDARD, "error 0x%x: failed to remove COM+ application with guid %ls. The COM application will not be removed", hr, (LPWSTR)(mr.pbMDData)); | ||
545 | } | ||
546 | else | ||
547 | { | ||
548 | hr = pApplicationCollection->SaveChanges(&lChanges); | ||
549 | if (FAILED(hr)) | ||
550 | { | ||
551 | WcaLog(LOGMSG_STANDARD, "error 0x%x: failed to save changes when removing COM+ application with guid %ls. The COM application will not be removed - continuing", hr, (LPWSTR)(mr.pbMDData)); | ||
552 | } | ||
553 | else | ||
554 | { | ||
555 | WcaLog(LOGMSG_VERBOSE, "Found and removed application with GUID %ls", (LPWSTR)(mr.pbMDData)); | ||
556 | } | ||
557 | } | ||
558 | |||
559 | // We've found the right key and successfully deleted the app - let's exit the loop now | ||
560 | lIndex = lSize; | ||
561 | } | ||
562 | } | ||
563 | // If we didn't find it, it isn't an error, because the application we want to delete doesn't seem to exist! | ||
564 | |||
565 | hr = WcaProgressMessage(COST_IIS_DELETEAPP, FALSE); | ||
566 | LExit: | ||
567 | ReleaseBSTR(bstrPropName); | ||
568 | |||
569 | ReleaseStr(pwzRoot); | ||
570 | // Don't release pApplication, because it points to an object within the collection | ||
571 | |||
572 | delete [] mr.pbMDData; | ||
573 | |||
574 | return hr; | ||
575 | } | ||
576 | |||
577 | |||
578 | /******************************************************************** | ||
579 | CreateAspApp - Creates applications in IIS | ||
580 | |||
581 | Input: deferred CustomActionData - MetabaseRoot\tInProc | ||
582 | * ****************************************************************/ | ||
583 | static HRESULT CreateAspApp(__in LPWSTR* ppwzCustomActionData, __in IWamAdmin* piWam) | ||
584 | { | ||
585 | HRESULT hr = S_OK; | ||
586 | |||
587 | LPWSTR pwzRoot = NULL; | ||
588 | BOOL fInProc; | ||
589 | |||
590 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzRoot); // MetabaseRoot | ||
591 | ExitOnFailure(hr, "failed to get metabase root"); | ||
592 | hr = WcaReadIntegerFromCaData(ppwzCustomActionData, reinterpret_cast<int *>(&fInProc)); // InProc | ||
593 | ExitOnFailure(hr, "failed to get in proc flag"); | ||
594 | |||
595 | WcaLog(LOGMSG_VERBOSE, "Creating ASP App: %ls", pwzRoot); | ||
596 | |||
597 | hr = piWam->AppCreate(pwzRoot, fInProc); | ||
598 | MessageExitOnFailure(hr, msierrIISFailedCreateApp, "failed to create web application: %ls", pwzRoot); | ||
599 | |||
600 | hr = WcaProgressMessage(COST_IIS_CREATEAPP, FALSE); | ||
601 | LExit: | ||
602 | return hr; | ||
603 | } | ||
604 | |||
605 | |||
606 | /******************************************************************** | ||
607 | DeleteMetabaseKey - Deletes metabase keys | ||
608 | |||
609 | Input: deferred CustomActionData - Key | ||
610 | ******************************************************************/ | ||
611 | static HRESULT DeleteMetabaseKey(__in LPWSTR *ppwzCustomActionData, __in IMSAdminBase* piMetabase) | ||
612 | { | ||
613 | HRESULT hr = S_OK; | ||
614 | |||
615 | METADATA_HANDLE mhRoot = 0; | ||
616 | |||
617 | LPWSTR pwzData = NULL; | ||
618 | |||
619 | LPCWSTR pwzKey; | ||
620 | int i; | ||
621 | |||
622 | hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData); | ||
623 | ExitOnFailure(hr, "failed to read key to be deleted"); | ||
624 | |||
625 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhRoot); | ||
626 | for (i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--) | ||
627 | { | ||
628 | ::Sleep(1000); | ||
629 | WcaLog(LOGMSG_STANDARD, "failed to open root key, retrying %d time(s)...", i); | ||
630 | hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, L"/LM", METADATA_PERMISSION_WRITE, 10, &mhRoot); | ||
631 | } | ||
632 | MessageExitOnFailure(hr, msierrIISFailedOpenKey, "failed to open metabase key: %ls", L"/LM"); | ||
633 | |||
634 | pwzKey = pwzData + 3; | ||
635 | |||
636 | WcaLog(LOGMSG_VERBOSE, "Deleting Metabase Key: %ls", pwzKey); | ||
637 | |||
638 | hr = piMetabase->DeleteKey(mhRoot, pwzKey); | ||
639 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) | ||
640 | { | ||
641 | WcaLog(LOGMSG_STANDARD, "Key `%ls` did not exist, continuing.", pwzData); | ||
642 | hr = S_OK; | ||
643 | } | ||
644 | MessageExitOnFailure(hr, msierrIISFailedDeleteKey, "failed to delete metabase key: %ls", pwzData); | ||
645 | |||
646 | hr = WcaProgressMessage(COST_IIS_DELETEKEY, FALSE); | ||
647 | LExit: | ||
648 | if (mhRoot) | ||
649 | { | ||
650 | piMetabase->CloseKey(mhRoot); | ||
651 | } | ||
652 | |||
653 | return hr; | ||
654 | } | ||
655 | |||
656 | |||
657 | /******************************************************************** | ||
658 | WriteMetabaseChanges - CUSTOM ACTION ENTRY POINT for IIS Metabase changes | ||
659 | |||
660 | *******************************************************************/ | ||
661 | extern "C" UINT __stdcall WriteMetabaseChanges(MSIHANDLE hInstall) | ||
662 | { | ||
663 | //AssertSz(FALSE, "debug WriteMetabaseChanges here"); | ||
664 | HRESULT hr = S_OK; | ||
665 | UINT er = ERROR_SUCCESS; | ||
666 | IMSAdminBase* piMetabase = NULL; | ||
667 | IWamAdmin* piWam = NULL; | ||
668 | ICOMAdminCatalog* pCatalog = NULL; | ||
669 | ICatalogCollection* pApplicationCollection = NULL; | ||
670 | WCA_CASCRIPT_HANDLE hWriteMetabaseScript = NULL; | ||
671 | BSTR bstrApplications = SysAllocString(L"Applications"); | ||
672 | BOOL fInitializedCom = FALSE; | ||
673 | |||
674 | LPWSTR pwzData = NULL; | ||
675 | LPWSTR pwz = NULL; | ||
676 | LPWSTR pwzScriptKey = NULL; | ||
677 | METABASE_ACTION maAction = MBA_UNKNOWNACTION; | ||
678 | |||
679 | hr = WcaInitialize(hInstall, "WriteMetabaseChanges"); | ||
680 | ExitOnFailure(hr, "failed to initialize"); | ||
681 | |||
682 | hr = ::CoInitialize(NULL); | ||
683 | ExitOnFailure(hr, "failed to initialize COM"); | ||
684 | fInitializedCom = TRUE; | ||
685 | |||
686 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
687 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
688 | |||
689 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
690 | |||
691 | // Get the CaScript key | ||
692 | hr = WcaReadStringFromCaData(&pwzData, &pwzScriptKey); | ||
693 | ExitOnFailure(hr, "Failed to get CaScript key from custom action data"); | ||
694 | |||
695 | hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_SCHEDULED, FALSE, pwzScriptKey, &hWriteMetabaseScript); | ||
696 | ExitOnFailure(hr, "Failed to open CaScript file"); | ||
697 | |||
698 | // The rest of our existing custom action data string should be empty - go ahead and overwrite it | ||
699 | ReleaseNullStr(pwzData); | ||
700 | hr = WcaCaScriptReadAsCustomActionData(hWriteMetabaseScript, &pwzData); | ||
701 | ExitOnFailure(hr, "Failed to read script into CustomAction data."); | ||
702 | |||
703 | pwz = pwzData; | ||
704 | |||
705 | while (S_OK == (hr = WcaReadIntegerFromCaData(&pwz, (int *)&maAction))) | ||
706 | { | ||
707 | switch (maAction) | ||
708 | { | ||
709 | case MBA_CREATEAPP: | ||
710 | if (NULL == piWam) | ||
711 | { | ||
712 | hr = ::CoCreateInstance(CLSID_WamAdmin, NULL, CLSCTX_ALL, IID_IWamAdmin, reinterpret_cast<void**>(&piWam)); | ||
713 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IWamAdmin object"); | ||
714 | } | ||
715 | |||
716 | hr = CreateAspApp(&pwz, piWam); | ||
717 | ExitOnFailure(hr, "failed to create ASP App"); | ||
718 | break; | ||
719 | case MBA_DELETEAPP: | ||
720 | if (NULL == piMetabase) | ||
721 | { | ||
722 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
723 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
724 | } | ||
725 | |||
726 | if (NULL == pCatalog) | ||
727 | { | ||
728 | hr = CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pCatalog); | ||
729 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_ICOMAdmin object"); | ||
730 | |||
731 | hr = pCatalog->GetCollection(bstrApplications, reinterpret_cast<IDispatch**>(&pApplicationCollection)); | ||
732 | if (FAILED(hr)) | ||
733 | { | ||
734 | hr = S_OK; | ||
735 | WcaLog(LOGMSG_STANDARD, "error 0x%x: failed to get ApplicationCollection object for list of COM+ applications - COM+ applications will not be able to be uninstalled - continuing", hr); | ||
736 | } | ||
737 | } | ||
738 | |||
739 | if (NULL == piWam) | ||
740 | { | ||
741 | hr = ::CoCreateInstance(CLSID_WamAdmin, NULL, CLSCTX_ALL, IID_IWamAdmin, reinterpret_cast<void**>(&piWam)); | ||
742 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IWamAdmin object"); | ||
743 | } | ||
744 | |||
745 | hr = DeleteAspApp(&pwz, piMetabase, pApplicationCollection, piWam); | ||
746 | ExitOnFailure(hr, "failed to delete ASP App"); | ||
747 | break; | ||
748 | case MBA_CREATEKEY: | ||
749 | if (NULL == piMetabase) | ||
750 | { | ||
751 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
752 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
753 | } | ||
754 | |||
755 | hr = CreateMetabaseKey(&pwz, piMetabase); | ||
756 | ExitOnFailure(hr, "failed to create metabase key"); | ||
757 | break; | ||
758 | case MBA_DELETEKEY: | ||
759 | if (NULL == piMetabase) | ||
760 | { | ||
761 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
762 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
763 | } | ||
764 | |||
765 | hr = DeleteMetabaseKey(&pwz, piMetabase); | ||
766 | ExitOnFailure(hr, "failed to delete metabase key"); | ||
767 | break; | ||
768 | case MBA_WRITEVALUE: | ||
769 | if (NULL == piMetabase) | ||
770 | { | ||
771 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
772 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
773 | } | ||
774 | |||
775 | hr = WriteMetabaseValue(&pwz, piMetabase); | ||
776 | ExitOnFailure(hr, "failed to write metabase value"); | ||
777 | break; | ||
778 | case MBA_DELETEVALUE: | ||
779 | if (NULL == piMetabase) | ||
780 | { | ||
781 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<void**>(&piMetabase)); | ||
782 | MessageExitOnFailure(hr, msierrIISCannotConnect, "failed to get IID_IIMSAdminBase object"); | ||
783 | } | ||
784 | |||
785 | hr = DeleteMetabaseValue(&pwz, piMetabase); | ||
786 | ExitOnFailure(hr, "failed to delete metabase value"); | ||
787 | break; | ||
788 | default: | ||
789 | ExitOnFailure(hr = E_UNEXPECTED, "Unexpected metabase action specified: %d", maAction); | ||
790 | break; | ||
791 | } | ||
792 | } | ||
793 | if (E_NOMOREITEMS == hr) // If there are no more items, all is well | ||
794 | { | ||
795 | if (NULL != piMetabase) | ||
796 | { | ||
797 | hr = piMetabase->SaveData(); | ||
798 | for (int i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--) | ||
799 | { | ||
800 | ::Sleep(1000); | ||
801 | WcaLog(LOGMSG_VERBOSE, "Failed to force save of metabase data, retrying %d time(s)...", i); | ||
802 | hr = piMetabase->SaveData(); | ||
803 | } | ||
804 | if (FAILED(hr)) | ||
805 | { | ||
806 | WcaLog(LOGMSG_VERBOSE, "Failed to force save of metabase data: 0x%x - continuing", hr); | ||
807 | } | ||
808 | hr = S_OK; | ||
809 | } | ||
810 | else | ||
811 | { | ||
812 | hr = S_OK; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | LExit: | ||
817 | WcaCaScriptClose(hWriteMetabaseScript, WCA_CASCRIPT_CLOSE_DELETE); | ||
818 | |||
819 | ReleaseBSTR(bstrApplications); | ||
820 | ReleaseStr(pwzScriptKey); | ||
821 | ReleaseStr(pwzData); | ||
822 | ReleaseObject(piMetabase); | ||
823 | ReleaseObject(piWam); | ||
824 | ReleaseObject(pCatalog); | ||
825 | ReleaseObject(pApplicationCollection); | ||
826 | |||
827 | if (fInitializedCom) | ||
828 | { | ||
829 | ::CoUninitialize(); | ||
830 | } | ||
831 | |||
832 | if (FAILED(hr)) | ||
833 | { | ||
834 | er = ERROR_INSTALL_FAILURE; | ||
835 | } | ||
836 | return WcaFinalize(er); | ||
837 | } | ||
838 | /******************************************************************** | ||
839 | WriteIIS7ConfigChanges - CUSTOM ACTION ENTRY POINT for IIS7 config changes | ||
840 | |||
841 | *******************************************************************/ | ||
842 | extern "C" UINT __stdcall WriteIIS7ConfigChanges(MSIHANDLE hInstall) | ||
843 | { | ||
844 | //AssertSz(FALSE, "debug WriteIIS7ConfigChanges here"); | ||
845 | HRESULT hr = S_OK; | ||
846 | UINT er = ERROR_SUCCESS; | ||
847 | LPWSTR pwzData = NULL; | ||
848 | LPWSTR pwzScriptKey = NULL; | ||
849 | LPWSTR pwzHashString = NULL; | ||
850 | BYTE rgbActualHash[SHA1_HASH_LEN] = { }; | ||
851 | DWORD dwHashedBytes = SHA1_HASH_LEN; | ||
852 | |||
853 | WCA_CASCRIPT_HANDLE hWriteIis7Script = NULL; | ||
854 | |||
855 | hr = WcaInitialize(hInstall, "WriteIIS7ConfigChanges"); | ||
856 | ExitOnFailure(hr, "Failed to initialize"); | ||
857 | |||
858 | hr = WcaGetProperty( L"CustomActionData", &pwzScriptKey); | ||
859 | ExitOnFailure(hr, "Failed to get CustomActionData"); | ||
860 | WcaLog(LOGMSG_TRACEONLY, "Script WriteIIS7ConfigChanges: %ls", pwzScriptKey); | ||
861 | |||
862 | hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_SCHEDULED, FALSE, pwzScriptKey, &hWriteIis7Script); | ||
863 | ExitOnFailure(hr, "Failed to open CaScript file"); | ||
864 | |||
865 | hr = WcaCaScriptReadAsCustomActionData(hWriteIis7Script, &pwzData); | ||
866 | ExitOnFailure(hr, "Failed to read script into CustomAction data."); | ||
867 | |||
868 | hr = CrypHashBuffer((BYTE*)pwzData, sizeof(pwzData) * sizeof(WCHAR), PROV_RSA_AES, CALG_SHA1, rgbActualHash, dwHashedBytes); | ||
869 | ExitOnFailure(hr, "Failed to calculate hash of CustomAction data."); | ||
870 | |||
871 | hr = StrAlloc(&pwzHashString, ((dwHashedBytes * 2) + 1)); | ||
872 | ExitOnFailure(hr, "Failed to allocate string for script hash"); | ||
873 | |||
874 | hr = StrHexEncode(rgbActualHash, dwHashedBytes, pwzHashString, ((dwHashedBytes * 2) + 1)); | ||
875 | ExitOnFailure(hr, "Failed to convert hash bytes to string."); | ||
876 | |||
877 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData WriteIIS7ConfigChanges: %ls", pwzData); | ||
878 | WcaLog(LOGMSG_VERBOSE, "Custom action data hash: %ls", pwzHashString); | ||
879 | WcaLog(LOGMSG_VERBOSE, "CustomActionData WriteIIS7ConfigChanges length: %d", wcslen(pwzData)); | ||
880 | |||
881 | hr = IIS7ConfigChanges(hInstall, pwzData); | ||
882 | ExitOnFailure(hr, "WriteIIS7ConfigChanges Failed."); | ||
883 | |||
884 | LExit: | ||
885 | WcaCaScriptClose(hWriteIis7Script, WCA_CASCRIPT_CLOSE_DELETE); | ||
886 | ReleaseStr(pwzScriptKey); | ||
887 | ReleaseStr(pwzData); | ||
888 | ReleaseStr(pwzHashString); | ||
889 | |||
890 | if (FAILED(hr)) | ||
891 | { | ||
892 | er = ERROR_INSTALL_FAILURE; | ||
893 | } | ||
894 | |||
895 | return WcaFinalize(er); | ||
896 | } | ||
897 | |||
898 | |||
899 | /******************************************************************** | ||
900 | CommitIIS7ConfigTransaction - CUSTOM ACTION ENTRY POINT for unbacking up config | ||
901 | |||
902 | Input: deferred CustomActionData - BackupName | ||
903 | * *****************************************************************/ | ||
904 | extern "C" UINT __stdcall CommitIIS7ConfigTransaction(MSIHANDLE hInstall) | ||
905 | { | ||
906 | HRESULT hr = S_OK; | ||
907 | UINT er = ERROR_SUCCESS; | ||
908 | LPWSTR pwzData = NULL; | ||
909 | WCHAR wzConfigCopy[MAX_PATH]; | ||
910 | DWORD dwSize = 0; | ||
911 | |||
912 | BOOL fIsWow64Process = FALSE; | ||
913 | BOOL fIsFSRedirectDisabled = FALSE; | ||
914 | |||
915 | hr = WcaInitialize(hInstall, "CommitIIS7ConfigTransaction"); | ||
916 | ExitOnFailure(hr, "failed to initialize IIS7 commit transaction"); | ||
917 | |||
918 | WcaInitializeWow64(); | ||
919 | fIsWow64Process = WcaIsWow64Process(); | ||
920 | if (fIsWow64Process) | ||
921 | { | ||
922 | hr = WcaDisableWow64FSRedirection(); | ||
923 | if(FAILED(hr)) | ||
924 | { | ||
925 | //eat this error | ||
926 | hr = S_OK; | ||
927 | } | ||
928 | else | ||
929 | { | ||
930 | fIsFSRedirectDisabled = TRUE; | ||
931 | } | ||
932 | } | ||
933 | |||
934 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
935 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
936 | |||
937 | // Config AdminMgr changes already committed, just | ||
938 | // delete backup config file. | ||
939 | |||
940 | dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\applicationHost.config", | ||
941 | wzConfigCopy, | ||
942 | MAX_PATH | ||
943 | ); | ||
944 | if ( dwSize == 0 ) | ||
945 | { | ||
946 | ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); | ||
947 | } | ||
948 | |||
949 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, L"."); | ||
950 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of ."); | ||
951 | |||
952 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, pwzData); | ||
953 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of extension"); | ||
954 | |||
955 | if (!::DeleteFileW(wzConfigCopy)) | ||
956 | { | ||
957 | hr = HRESULT_FROM_WIN32(GetLastError()); | ||
958 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || | ||
959 | HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
960 | { | ||
961 | WcaLog(LOGMSG_STANDARD, "Failed to delete backup applicationHost, not found - continuing"); | ||
962 | hr = S_OK; | ||
963 | } | ||
964 | else | ||
965 | { | ||
966 | ExitOnFailure(hr, "failed to delete config backup"); | ||
967 | } | ||
968 | } | ||
969 | |||
970 | LExit: | ||
971 | ReleaseStr(pwzData); | ||
972 | |||
973 | // Make sure we revert FS Redirection if necessary before exiting | ||
974 | if (fIsFSRedirectDisabled) | ||
975 | { | ||
976 | fIsFSRedirectDisabled = FALSE; | ||
977 | WcaRevertWow64FSRedirection(); | ||
978 | } | ||
979 | WcaFinalizeWow64(); | ||
980 | |||
981 | |||
982 | if (FAILED(hr)) | ||
983 | { | ||
984 | er = ERROR_INSTALL_FAILURE; | ||
985 | } | ||
986 | return WcaFinalize(er); | ||
987 | } | ||
988 | /******************************************************************** | ||
989 | StartIIS7Config Transaction - CUSTOM ACTION ENTRY POINT for backing up config | ||
990 | |||
991 | Input: deferred CustomActionData - BackupName | ||
992 | ********************************************************************/ | ||
993 | extern "C" UINT __stdcall StartIIS7ConfigTransaction(MSIHANDLE hInstall) | ||
994 | { | ||
995 | HRESULT hr = S_OK; | ||
996 | UINT er = ERROR_SUCCESS; | ||
997 | LPWSTR pwzData = NULL; | ||
998 | WCHAR wzConfigSource[MAX_PATH]; | ||
999 | WCHAR wzConfigCopy[MAX_PATH]; | ||
1000 | DWORD dwSize = 0; | ||
1001 | |||
1002 | |||
1003 | BOOL fIsWow64Process = FALSE; | ||
1004 | BOOL fIsFSRedirectDisabled = FALSE; | ||
1005 | |||
1006 | // initialize | ||
1007 | hr = WcaInitialize(hInstall, "StartIIS7ConfigTransaction"); | ||
1008 | ExitOnFailure(hr, "failed to initialize StartIIS7ConfigTransaction"); | ||
1009 | |||
1010 | WcaInitializeWow64(); | ||
1011 | fIsWow64Process = WcaIsWow64Process(); | ||
1012 | if (fIsWow64Process) | ||
1013 | { | ||
1014 | hr = WcaDisableWow64FSRedirection(); | ||
1015 | if(FAILED(hr)) | ||
1016 | { | ||
1017 | //eat this error | ||
1018 | hr = S_OK; | ||
1019 | } | ||
1020 | else | ||
1021 | { | ||
1022 | fIsFSRedirectDisabled = TRUE; | ||
1023 | } | ||
1024 | } | ||
1025 | |||
1026 | hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||
1027 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
1028 | |||
1029 | |||
1030 | dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\applicationHost.config", | ||
1031 | wzConfigSource, | ||
1032 | MAX_PATH | ||
1033 | ); | ||
1034 | if ( dwSize == 0 ) | ||
1035 | { | ||
1036 | ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); | ||
1037 | } | ||
1038 | hr = ::StringCchCopyW(wzConfigCopy, MAX_PATH, wzConfigSource); | ||
1039 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCopyW"); | ||
1040 | |||
1041 | //add ca action as extension | ||
1042 | |||
1043 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, L"."); | ||
1044 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of ."); | ||
1045 | |||
1046 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, pwzData); | ||
1047 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of extension"); | ||
1048 | |||
1049 | if ( !::CopyFileW(wzConfigSource, wzConfigCopy, FALSE) ) | ||
1050 | { | ||
1051 | hr = HRESULT_FROM_WIN32(GetLastError()); | ||
1052 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || | ||
1053 | HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
1054 | { | ||
1055 | // IIS may not be installed on the machine, we'll fail later if we try to install anything | ||
1056 | WcaLog(LOGMSG_STANDARD, "Failed to back up applicationHost, not found - continuing"); | ||
1057 | hr = S_OK; | ||
1058 | } | ||
1059 | else | ||
1060 | { | ||
1061 | ExitOnFailure(hr, "Failed to copy config backup %ls -> %ls", wzConfigSource, wzConfigCopy); | ||
1062 | } | ||
1063 | } | ||
1064 | |||
1065 | |||
1066 | hr = WcaProgressMessage(COST_IIS_TRANSACTIONS, FALSE); | ||
1067 | |||
1068 | |||
1069 | LExit: | ||
1070 | |||
1071 | ReleaseStr(pwzData); | ||
1072 | |||
1073 | // Make sure we revert FS Redirection if necessary before exiting | ||
1074 | if (fIsFSRedirectDisabled) | ||
1075 | { | ||
1076 | fIsFSRedirectDisabled = FALSE; | ||
1077 | WcaRevertWow64FSRedirection(); | ||
1078 | } | ||
1079 | WcaFinalizeWow64(); | ||
1080 | |||
1081 | if (FAILED(hr)) | ||
1082 | er = ERROR_INSTALL_FAILURE; | ||
1083 | return WcaFinalize(er); | ||
1084 | } | ||
1085 | |||
1086 | |||
1087 | /******************************************************************** | ||
1088 | RollbackIIS7ConfigTransaction - CUSTOM ACTION ENTRY POINT for unbacking up config | ||
1089 | |||
1090 | Input: deferred CustomActionData - BackupName | ||
1091 | ********************************************************************/ | ||
1092 | extern "C" UINT __stdcall RollbackIIS7ConfigTransaction(MSIHANDLE hInstall) | ||
1093 | { | ||
1094 | HRESULT hr = S_OK; | ||
1095 | UINT er = ERROR_SUCCESS; | ||
1096 | LPWSTR pwzData = NULL; | ||
1097 | WCHAR wzConfigSource[MAX_PATH]; | ||
1098 | WCHAR wzConfigCopy[MAX_PATH]; | ||
1099 | DWORD dwSize = 0; | ||
1100 | |||
1101 | BOOL fIsWow64Process = FALSE; | ||
1102 | BOOL fIsFSRedirectDisabled = FALSE; | ||
1103 | |||
1104 | hr = WcaInitialize(hInstall, "RollbackIIS7ConfigTransaction"); | ||
1105 | ExitOnFailure(hr, "failed to initialize"); | ||
1106 | |||
1107 | WcaInitializeWow64(); | ||
1108 | fIsWow64Process = WcaIsWow64Process(); | ||
1109 | if (fIsWow64Process) | ||
1110 | { | ||
1111 | hr = WcaDisableWow64FSRedirection(); | ||
1112 | if(FAILED(hr)) | ||
1113 | { | ||
1114 | //eat this error | ||
1115 | hr = S_OK; | ||
1116 | } | ||
1117 | else | ||
1118 | { | ||
1119 | fIsFSRedirectDisabled = TRUE; | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
1124 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
1125 | |||
1126 | dwSize = ExpandEnvironmentStringsW(L"%windir%\\system32\\inetsrv\\config\\applicationHost.config", | ||
1127 | wzConfigSource, | ||
1128 | MAX_PATH | ||
1129 | ); | ||
1130 | if ( dwSize == 0 ) | ||
1131 | { | ||
1132 | ExitWithLastError(hr, "failed to get ExpandEnvironmentStrings"); | ||
1133 | } | ||
1134 | hr = ::StringCchCopyW(wzConfigCopy, MAX_PATH, wzConfigSource); | ||
1135 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCopyW"); | ||
1136 | |||
1137 | //add ca action as extension | ||
1138 | |||
1139 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, L"."); | ||
1140 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of ."); | ||
1141 | |||
1142 | hr = ::StringCchCatW(wzConfigCopy, MAX_PATH, pwzData); | ||
1143 | ExitOnFailure(hr, "Commit IIS7 failed StringCchCatW of extension"); | ||
1144 | |||
1145 | //copy is reverse of start transaction | ||
1146 | if (!::CopyFileW(wzConfigCopy, wzConfigSource, FALSE)) | ||
1147 | { | ||
1148 | hr = HRESULT_FROM_WIN32(GetLastError()); | ||
1149 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || | ||
1150 | HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
1151 | { | ||
1152 | WcaLog(LOGMSG_STANDARD, "Failed to restore applicationHost, not found - continuing"); | ||
1153 | hr = S_OK; | ||
1154 | } | ||
1155 | else | ||
1156 | { | ||
1157 | ExitOnFailure(hr, "failed to restore config backup"); | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | if (!::DeleteFileW(wzConfigCopy)) | ||
1162 | { | ||
1163 | ExitWithLastError(hr, "failed to delete config backup"); | ||
1164 | } | ||
1165 | |||
1166 | hr = WcaProgressMessage(COST_IIS_TRANSACTIONS, FALSE); | ||
1167 | |||
1168 | LExit: | ||
1169 | ReleaseStr(pwzData); | ||
1170 | |||
1171 | // Make sure we revert FS Redirection if necessary before exiting | ||
1172 | if (fIsFSRedirectDisabled) | ||
1173 | { | ||
1174 | fIsFSRedirectDisabled = FALSE; | ||
1175 | WcaRevertWow64FSRedirection(); | ||
1176 | } | ||
1177 | WcaFinalizeWow64(); | ||
1178 | |||
1179 | if (FAILED(hr)) | ||
1180 | { | ||
1181 | er = ERROR_INSTALL_FAILURE; | ||
1182 | } | ||
1183 | return WcaFinalize(er); | ||
1184 | } | ||