aboutsummaryrefslogtreecommitdiff
path: root/src/ca/scafilter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ca/scafilter.cpp')
-rw-r--r--src/ca/scafilter.cpp510
1 files changed, 510 insertions, 0 deletions
diff --git a/src/ca/scafilter.cpp b/src/ca/scafilter.cpp
new file mode 100644
index 00000000..9d9014fd
--- /dev/null
+++ b/src/ca/scafilter.cpp
@@ -0,0 +1,510 @@
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// prototypes
6static HRESULT ReadFilterLoadOrder(
7 __in IMSAdminBase* piMetabase,
8 __in LPCWSTR wzFilterRoot,
9 __out LPWSTR *ppwzLoadOrder
10 );
11static HRESULT AddFilterToLoadOrder(
12 __in LPCWSTR wzFilter,
13 __in int iLoadOrder,
14 __inout LPWSTR *ppwzLoadOrder
15 );
16static HRESULT RemoveFilterFromLoadOrder(
17 __in LPCWSTR wzFilter,
18 __inout LPWSTR *ppwzLoadOrder
19 );
20
21
22UINT __stdcall ScaFiltersRead(
23 __in IMSAdminBase* piMetabase,
24 __in SCA_WEB* pswList,
25 __in WCA_WRAPQUERY_HANDLE hWebBaseQuery,
26 __inout SCA_FILTER** ppsfList,
27 __inout LPWSTR *ppwzCustomActionData
28 )
29{
30 HRESULT hr = S_OK;
31 MSIHANDLE hRec;
32 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
33 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
34
35 LPWSTR pwzData = NULL;
36
37 SCA_FILTER* psf = NULL;
38 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
39
40 hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
41 ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead");
42
43 if (0 == WcaGetQueryRecords(hWrapQuery))
44 {
45 WcaLog(LOGMSG_VERBOSE, "Skipping ScaFiltersRead() - no IIsFilter table");
46 ExitFunction1(hr = S_FALSE);
47 }
48
49 // loop through all the filters
50 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
51 {
52 // Get the Component first. If the component is not being modified during
53 // this transaction, skip processing this whole record.
54 hr = WcaGetRecordString(hRec, fqComponent, &pwzData);
55 ExitOnFailure(hr, "failed to get IIsFilter.Component");
56
57 hr = WcaGetRecordInteger(hRec, fqInstalled, (int *)&isInstalled);
58 ExitOnFailure(hr, "Failed to get Component installed state for IIs filter");
59
60 hr = WcaGetRecordInteger(hRec, fqAction, (int *)&isAction);
61 ExitOnFailure(hr, "Failed to get Component action state for IIs filter");
62
63 if (!WcaIsInstalling(isInstalled, isAction) &&
64 !WcaIsReInstalling(isInstalled, isAction) &&
65 !WcaIsUninstalling(isInstalled, isAction))
66 {
67 continue; // skip this record.
68 }
69
70 hr = AddFilterToList(ppsfList);
71 ExitOnFailure(hr, "failed to add filter to list");
72
73 psf = *ppsfList;
74
75 hr = ::StringCchCopyW(psf->wzComponent, countof(psf->wzComponent), pwzData);
76 ExitOnFailure(hr, "failed to copy component name: %ls", pwzData);
77
78 psf->isInstalled = isInstalled;
79 psf->isAction = isAction;
80
81 hr = WcaGetRecordString(hRec, fqWeb, &pwzData);
82 ExitOnFailure(hr, "Failed to get Web for VirtualDir");
83
84 if (*pwzData)
85 {
86 hr = ScaWebsGetBase(piMetabase, pswList, pwzData, psf->wzWebBase, countof(psf->wzWebBase), hWebBaseQuery);
87 if (FAILED(hr) && WcaIsUninstalling(isInstalled, isAction))
88 {
89 // If we're uninstalling, don't bother finding the existing web, just leave the filter root empty
90 hr = S_OK;
91 }
92 ExitOnFailure(hr, "Failed to get base of web for Filter");
93
94 if (0 != lstrlenW(psf->wzWebBase))
95 {
96 hr = ::StringCchPrintfW(psf->wzFilterRoot, countof(psf->wzFilterRoot), L"%s/Filters", psf->wzWebBase);
97 ExitOnFailure(hr, "Failed to allocate filter base string");
98 }
99 }
100 else
101 {
102 hr = ::StringCchCopyW(psf->wzFilterRoot, countof(psf->wzFilterRoot), L"/LM/W3SVC/Filters");
103 ExitOnFailure(hr, "Failed to allocate global filter base string");
104 }
105
106 // filter key
107 hr = WcaGetRecordString(hRec, fqFilter, &pwzData);
108 ExitOnFailure(hr, "Failed to get Filter.Filter");
109 hr = ::StringCchCopyW(psf->wzKey, countof(psf->wzKey), pwzData);
110 ExitOnFailure(hr, "Failed to copy key string to filter object");
111
112 // filter path
113 hr = WcaGetRecordString(hRec, fqPath, &pwzData);
114 ExitOnFailure(hr, "Failed to get Filter.Path");
115 hr = ::StringCchCopyW(psf->wzPath, countof(psf->wzPath), pwzData);
116 ExitOnFailure(hr, "Failed to copy path string to filter object");
117
118 // filter description
119 hr = WcaGetRecordString(hRec, fqDescription, &pwzData);
120 ExitOnFailure(hr, "Failed to get Filter.Description");
121 hr = ::StringCchCopyW(psf->wzDescription, countof(psf->wzDescription), pwzData);
122 ExitOnFailure(hr, "Failed to copy description string to filter object");
123
124 // filter flags
125 hr = WcaGetRecordInteger(hRec, fqFlags, &psf->iFlags);
126 ExitOnFailure(hr, "Failed to get Filter.Flags");
127
128 // filter load order
129 hr = WcaGetRecordInteger(hRec, fqLoadOrder, &psf->iLoadOrder);
130 ExitOnFailure(hr, "Failed to get Filter.LoadOrder");
131 }
132
133 if (E_NOMOREITEMS == hr)
134 {
135 hr = S_OK;
136 }
137 ExitOnFailure(hr, "Failure while processing filters");
138
139LExit:
140 WcaFinishUnwrapQuery(hWrapQuery);
141
142 ReleaseStr(pwzData);
143 return hr;
144}
145
146
147HRESULT ScaFiltersInstall(
148 __in IMSAdminBase* piMetabase,
149 __in SCA_FILTER* psfList
150 )
151{
152 HRESULT hr = S_OK;
153 SCA_FILTER* psf = psfList;
154 LPCWSTR wzPreviousFilterRoot = NULL;
155 LPWSTR pwzLoadOrder = NULL;
156
157 while (psf)
158 {
159 if (WcaIsInstalling(psf->isInstalled, psf->isAction))
160 {
161 if (!wzPreviousFilterRoot || CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, 0, wzPreviousFilterRoot, -1, psf->wzFilterRoot, -1))
162 {
163 if (pwzLoadOrder)
164 {
165 hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder);
166 ExitOnFailure(hr, "Failed to write filter load order to metabase");
167
168 ReleaseNullStr(pwzLoadOrder);
169 }
170
171 hr = ReadFilterLoadOrder(piMetabase, psf->wzFilterRoot, &pwzLoadOrder);
172 ExitOnFailure(hr, "Failed to read filter load order.");
173
174 wzPreviousFilterRoot = psf->wzFilterRoot;
175 }
176
177 hr = ScaCreateMetabaseKey(piMetabase, psf->wzFilterRoot, psf->wzKey);
178 ExitOnFailure(hr, "Failed to create key for filter '%ls'", psf->wzKey);
179
180 hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsFilter");
181 ExitOnFailure(hr, "Failed to write key type for filter '%ls'", psf->wzKey);
182
183 // filter path
184 hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_IMAGE_PATH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)psf->wzPath);
185 ExitOnFailure(hr, "Failed to write Path for filter '%ls'", psf->wzKey);
186
187 // filter description
188 hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_DESCRIPTION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)psf->wzDescription);
189 ExitOnFailure(hr, "Failed to write Description for filter '%ls'", psf->wzKey);
190
191 // filter flags
192 if (MSI_NULL_INTEGER != psf->iFlags)
193 {
194 hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psf->iFlags));
195 ExitOnFailure(hr, "Failed to write Flags for filter '%ls'", psf->wzKey);
196 }
197
198 // filter load order
199 if (MSI_NULL_INTEGER != psf->iLoadOrder)
200 {
201 hr = AddFilterToLoadOrder(psf->wzKey, psf->iLoadOrder, &pwzLoadOrder);
202 ExitOnFailure(hr, "Failed to add filter '%ls' to load order.", psf->wzKey);
203 }
204 }
205
206 psf = psf->psfNext;
207 }
208
209 if (pwzLoadOrder)
210 {
211 Assert(wzPreviousFilterRoot && *wzPreviousFilterRoot);
212
213 hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder);
214 ExitOnFailure(hr, "Failed to write filter load order to metabase");
215 }
216
217LExit:
218 ReleaseStr(pwzLoadOrder);
219 return hr;
220}
221
222
223HRESULT ScaFiltersUninstall(
224 __in IMSAdminBase* piMetabase,
225 __in SCA_FILTER* psfList
226 )
227{
228 HRESULT hr = S_OK;
229 SCA_FILTER* psf = psfList;
230 LPCWSTR wzPreviousFilterRoot = NULL;
231 LPWSTR pwzLoadOrder = NULL;
232
233 while (psf)
234 {
235 if (WcaIsUninstalling(psf->isInstalled, psf->isAction))
236 {
237 if (!wzPreviousFilterRoot || CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, 0, wzPreviousFilterRoot, -1, psf->wzFilterRoot, -1))
238 {
239 if (pwzLoadOrder)
240 {
241 hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder);
242 ExitOnFailure(hr, "Failed to write filter load order to metabase");
243
244 ReleaseNullStr(pwzLoadOrder);
245 }
246
247 hr = ReadFilterLoadOrder(piMetabase, psf->wzFilterRoot, &pwzLoadOrder);
248 ExitOnFailure(hr, "Failed to read filter load order.");
249
250 wzPreviousFilterRoot = psf->wzFilterRoot;
251 }
252
253 hr = RemoveFilterFromLoadOrder(psf->wzKey, &pwzLoadOrder);
254 ExitOnFailure(hr, "Failed to remove filter '%ls' from load order", psf->wzKey);
255
256 // remove the filter from the load order and remove the filter's key
257 if (0 != lstrlenW(psf->wzFilterRoot))
258 {
259 hr = ScaDeleteMetabaseKey(piMetabase, psf->wzFilterRoot, psf->wzKey);
260 ExitOnFailure(hr, "Failed to remove web '%ls' from metabase", psf->wzKey);
261 }
262 }
263
264 psf = psf->psfNext;
265 }
266
267 if (pwzLoadOrder)
268 {
269 Assert(wzPreviousFilterRoot && *wzPreviousFilterRoot);
270
271 hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder);
272 ExitOnFailure(hr, "Failed to write filter load order to metabase");
273 }
274
275LExit:
276 return hr;
277}
278
279
280void ScaFiltersFreeList(
281 __in SCA_FILTER* psfList
282 )
283{
284 SCA_FILTER* psfDelete = psfList;
285 while (psfList)
286 {
287 psfDelete = psfList;
288 psfList = psfList->psfNext;
289
290 MemFree(psfDelete);
291 }
292}
293
294HRESULT AddFilterToList(
295 __inout SCA_FILTER** ppsfList)
296{
297 HRESULT hr = S_OK;
298 SCA_FILTER* psf = static_cast<SCA_FILTER*>(MemAlloc(sizeof(SCA_FILTER), TRUE));
299 ExitOnNull(psf, hr, E_OUTOFMEMORY, "failed to add filter to filter list");
300
301 psf->psfNext = *ppsfList;
302 *ppsfList = psf;
303
304LExit:
305 return hr;
306}
307
308// private helper functions
309
310
311static HRESULT ReadFilterLoadOrder(
312 __in IMSAdminBase* piMetabase,
313 __in LPCWSTR wzFilterRoot,
314 __out LPWSTR *ppwzLoadOrder
315 )
316{
317 HRESULT hr = S_OK;
318 METADATA_HANDLE mhRoot = NULL;
319
320 METADATA_RECORD mr;
321 DWORD dwRequired = 0;
322 DWORD cchData = 255;
323
324 ::ZeroMemory(&mr, sizeof(mr));
325 mr.dwMDIdentifier = MD_FILTER_LOAD_ORDER;
326 mr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
327 mr.dwMDUserType = IIS_MD_UT_SERVER;
328 mr.dwMDDataType = ALL_METADATA;
329 mr.dwMDDataLen = cchData;
330 mr.pbMDData = static_cast<BYTE*>(MemAlloc(mr.dwMDDataLen * sizeof(WCHAR), TRUE));
331 ExitOnNull(mr.pbMDData, hr, E_OUTOFMEMORY, "failed to allocate memory for MDData in metadata record");
332
333 hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, wzFilterRoot, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 10, &mhRoot);
334 for (int i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--)
335 {
336 ::Sleep(1000);
337 WcaLog(LOGMSG_STANDARD, "Failed to open root key, retrying %d time(s)...", i);
338 hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, wzFilterRoot, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 10, &mhRoot);
339 }
340
341 if (SUCCEEDED(hr))
342 {
343 hr = piMetabase->GetData(mhRoot, L"", &mr, &dwRequired);
344 if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr)
345 {
346 mr.dwMDDataLen = cchData = dwRequired;
347
348 LPVOID pv = MemReAlloc(mr.pbMDData, mr.dwMDDataLen * sizeof(WCHAR), TRUE);
349 ExitOnNull(pv, hr, E_OUTOFMEMORY, "failed to allocate memory for MDData in metadata record");
350 mr.pbMDData = static_cast<BYTE*>(pv);
351
352 hr = piMetabase->GetData(mhRoot, L"", &mr, &dwRequired);
353 }
354 }
355
356 // The /Filters node or /Filters/FilterLoadOrder property might not exist (yet).
357 if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr)
358 {
359 hr = S_OK;
360 }
361 ExitOnFailure(hr, "Failed to get filter load order.");
362
363 hr = StrAllocString(ppwzLoadOrder, reinterpret_cast<LPCWSTR>(mr.pbMDData), 0);
364 ExitOnFailure(hr, "Failed to allocate string for filter load order.");
365
366LExit:
367 ReleaseMem(mr.pbMDData);
368
369 if (mhRoot)
370 {
371 piMetabase->CloseKey(mhRoot);
372 }
373
374 return hr;
375}
376
377
378static HRESULT AddFilterToLoadOrder(
379 __in LPCWSTR wzFilter,
380 __in int iLoadOrder,
381 __inout LPWSTR *ppwzLoadOrder
382 )
383{
384 HRESULT hr = S_OK;
385 LPCWSTR wzLoadOrder = *ppwzLoadOrder;
386 int cchFilter = lstrlenW(wzFilter);
387 LPWSTR pwzTemp = NULL;
388
389 // If the filter name ends with '\0' or ',' and
390 // the filter name begins at the beginning of the list or with ','
391 // Then we've found the exact filter by name.
392 //
393 // If the filter isn't already in the load order, add it
394 if (wzLoadOrder && *wzLoadOrder)
395 {
396 LPCWSTR pwz = wcsstr(wzLoadOrder, wzFilter);
397
398 if (NULL != pwz &&
399 (L'\0' == *(pwz + cchFilter) || L',' == *(pwz + cchFilter)) &&
400 (pwz == wzLoadOrder || L',' == *(pwz - 1)))
401 {
402 // Filter already in the load order, no work to do.
403 }
404 else
405 {
406 pwz = NULL;
407 if (0 <= iLoadOrder)
408 {
409 pwz = wzLoadOrder;
410 for (int i = 0; i < iLoadOrder && pwz; ++i)
411 {
412 pwz = wcsstr(pwz, L",");
413 }
414 }
415
416 if (NULL == pwz) // put the filter at the end of the order
417 {
418 Assert(wzLoadOrder && *wzLoadOrder);
419
420 // tack on a comma since there are other filters in the order
421 hr = StrAllocConcat(ppwzLoadOrder, L",", 1);
422 ExitOnFailure(hr, "Failed to append a comma to filter load order.");
423
424 hr = StrAllocConcat(ppwzLoadOrder, wzFilter, cchFilter);
425 ExitOnFailure(hr, "Failed to append the filter on to the load order.");
426 }
427 else if (L',' == *pwz) // put the filter in the middle of the order
428 {
429 hr = StrAllocString(&pwzTemp, wzLoadOrder, pwz - wzLoadOrder + 1);
430 ExitOnFailure(hr, "Failed to copy first half of filter load order to temp string.");
431
432 hr = StrAllocConcat(&pwzTemp, wzFilter, 0);
433 ExitOnFailure(hr, "Failed to copy filter into load order.");
434
435 hr = StrAllocConcat(&pwzTemp, pwz, 0);
436 ExitOnFailure(hr, "Failed to copy remaining filter load order back onto load order.");
437
438 hr = StrAllocString(ppwzLoadOrder, pwzTemp, 0);
439 ExitOnFailure(hr, "Failed to copy temp string to load order string.");
440 }
441 else // put the filter at the beginning of the order
442 {
443 hr = StrAllocPrefix(ppwzLoadOrder, L",", 1);
444 ExitOnFailure(hr, "Failed to prepend a comma to filter load order.");
445
446 hr = StrAllocPrefix(ppwzLoadOrder, wzFilter, cchFilter);
447 ExitOnFailure(hr, "Failed to prepend the filter on to the load order.");
448 }
449 }
450 }
451 else
452 {
453 hr = StrAllocString(ppwzLoadOrder, wzFilter, cchFilter);
454 ExitOnFailure(hr, "Failed to add filter to load order.");
455 }
456
457LExit:
458 ReleaseStr(pwzTemp);
459 return hr;
460}
461
462
463static HRESULT RemoveFilterFromLoadOrder(
464 __in LPCWSTR wzFilter,
465 __inout LPWSTR *ppwzLoadOrder
466 )
467{
468 HRESULT hr = S_OK;
469 int cchFilter = lstrlenW(wzFilter);
470
471 LPCWSTR pwzStart = NULL;
472 LPWSTR pwzFind = NULL;
473
474 pwzStart = pwzFind = *ppwzLoadOrder;
475 while (NULL != (pwzFind = wcsstr(pwzFind, wzFilter)))
476 {
477 // Make sure to only match [wzFilter] and NOT foo[wzFilter]bar
478 if (pwzFind == pwzStart || L',' == *(pwzFind - 1))
479 {
480 int cchRemainder = lstrlenW(pwzFind) - cchFilter + 1; // add one to include the null terminator
481
482 if (L'\0' == *(pwzFind + cchFilter))
483 {
484 if (pwzFind == pwzStart)
485 {
486 memmove(pwzFind, pwzFind + cchFilter, cchRemainder * sizeof(WCHAR)); // copy down the null terminator
487 }
488 else
489 {
490 memmove(pwzFind - 1, pwzFind + cchFilter, cchRemainder * sizeof(WCHAR)); // copy down the null terminator over top the trailing ","
491 }
492 }
493 else if (L',' == *(pwzFind + cchFilter))
494 {
495 memmove(pwzFind, pwzFind + cchFilter + 1, (cchRemainder - 1) * sizeof(WCHAR)); // skip copying the ","
496 }
497 else // skip past the partial match
498 {
499 pwzFind = pwzFind + cchFilter;
500 }
501 }
502 else // skip past the partial match
503 {
504 pwzFind = pwzFind + cchFilter;
505 }
506 }
507
508//LExit:
509 return hr;
510}