aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Iis/ca/scaexec.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Iis/ca/scaexec.cpp')
-rw-r--r--src/ext/Iis/ca/scaexec.cpp1184
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********************************************************************/
11extern "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);
54LExit:
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********************************************************************/
74extern "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
109LExit:
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 * *****************************************************************/
131extern "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
161LExit:
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 * *****************************************************************/
183static 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
219LExit:
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 * *****************************************************************/
234static 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
363LExit:
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 * *****************************************************************/
386static 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);
431LExit:
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 * *****************************************************************/
446static 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);
566LExit:
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 * ****************************************************************/
583static 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);
601LExit:
602 return hr;
603}
604
605
606/********************************************************************
607 DeleteMetabaseKey - Deletes metabase keys
608
609 Input: deferred CustomActionData - Key
610 ******************************************************************/
611static 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);
647LExit:
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 *******************************************************************/
661extern "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
816LExit:
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 *******************************************************************/
842extern "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
884LExit:
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 * *****************************************************************/
904extern "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
970LExit:
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********************************************************************/
993extern "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
1069LExit:
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********************************************************************/
1092extern "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
1168LExit:
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}