diff options
Diffstat (limited to 'src/dutil/metautil.cpp')
-rw-r--r-- | src/dutil/metautil.cpp | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/src/dutil/metautil.cpp b/src/dutil/metautil.cpp new file mode 100644 index 00000000..612b1127 --- /dev/null +++ b/src/dutil/metautil.cpp | |||
@@ -0,0 +1,356 @@ | |||
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 | // okay, this may look a little weird, but metautil.h cannot be in the | ||
6 | // pre-compiled header because we need to #define these things so the | ||
7 | // correct GUID's get pulled into this object file | ||
8 | #include <initguid.h> | ||
9 | #include "metautil.h" | ||
10 | |||
11 | |||
12 | // prototypes | ||
13 | static void Sort( | ||
14 | __in_ecount(cArray) DWORD dwArray[], | ||
15 | __in int cArray | ||
16 | ); | ||
17 | |||
18 | |||
19 | /******************************************************************** | ||
20 | MetaFindWebBase - finds a metabase base string that matches IP, Port and Header | ||
21 | |||
22 | ********************************************************************/ | ||
23 | extern "C" HRESULT DAPI MetaFindWebBase( | ||
24 | __in IMSAdminBaseW* piMetabase, | ||
25 | __in_z LPCWSTR wzIP, | ||
26 | __in int iPort, | ||
27 | __in_z LPCWSTR wzHeader, | ||
28 | __in BOOL fSecure, | ||
29 | __out_ecount(cchWebBase) LPWSTR wzWebBase, | ||
30 | __in DWORD cchWebBase | ||
31 | ) | ||
32 | { | ||
33 | Assert(piMetabase && cchWebBase); | ||
34 | |||
35 | HRESULT hr = S_OK; | ||
36 | |||
37 | BOOL fFound = FALSE; | ||
38 | |||
39 | WCHAR wzKey[METADATA_MAX_NAME_LEN]; | ||
40 | WCHAR wzSubkey[METADATA_MAX_NAME_LEN]; | ||
41 | DWORD dwIndex = 0; | ||
42 | |||
43 | METADATA_RECORD mr; | ||
44 | METADATA_RECORD mrAddress; | ||
45 | |||
46 | LPWSTR pwzExists = NULL; | ||
47 | LPWSTR pwzIPExists = NULL; | ||
48 | LPWSTR pwzPortExists = NULL; | ||
49 | int iPortExists = 0; | ||
50 | LPCWSTR pwzHeaderExists = NULL; | ||
51 | |||
52 | memset(&mr, 0, sizeof(mr)); | ||
53 | mr.dwMDIdentifier = MD_KEY_TYPE; | ||
54 | mr.dwMDAttributes = METADATA_INHERIT; | ||
55 | mr.dwMDUserType = IIS_MD_UT_SERVER; | ||
56 | mr.dwMDDataType = ALL_METADATA; | ||
57 | |||
58 | memset(&mrAddress, 0, sizeof(mrAddress)); | ||
59 | mrAddress.dwMDIdentifier = (fSecure) ? MD_SECURE_BINDINGS : MD_SERVER_BINDINGS; | ||
60 | mrAddress.dwMDAttributes = METADATA_INHERIT; | ||
61 | mrAddress.dwMDUserType = IIS_MD_UT_SERVER; | ||
62 | mrAddress.dwMDDataType = ALL_METADATA; | ||
63 | |||
64 | // loop through the "web keys" looking for the "IIsWebServer" key that matches wzWeb | ||
65 | for (dwIndex = 0; SUCCEEDED(hr); ++dwIndex) | ||
66 | { | ||
67 | hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC", wzSubkey, dwIndex); | ||
68 | if (FAILED(hr)) | ||
69 | break; | ||
70 | |||
71 | ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%s", wzSubkey); | ||
72 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr); | ||
73 | if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) | ||
74 | { | ||
75 | hr = S_FALSE; // didn't find anything, try next one | ||
76 | continue; | ||
77 | } | ||
78 | ExitOnFailure(hr, "failed to get key from metabase while searching for web servers"); | ||
79 | |||
80 | // if we have an IIsWebServer store the key | ||
81 | if (0 == lstrcmpW(L"IIsWebServer", (LPCWSTR)mr.pbMDData)) | ||
82 | { | ||
83 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mrAddress); | ||
84 | if (MD_ERROR_DATA_NOT_FOUND == hr) | ||
85 | hr = S_FALSE; | ||
86 | ExitOnFailure(hr, "failed to get address from metabase while searching for web servers"); | ||
87 | |||
88 | // break down the first address into parts | ||
89 | pwzIPExists = reinterpret_cast<LPWSTR>(mrAddress.pbMDData); | ||
90 | pwzExists = wcsstr(pwzIPExists, L":"); | ||
91 | if (NULL == pwzExists) | ||
92 | continue; | ||
93 | |||
94 | *pwzExists = L'\0'; | ||
95 | |||
96 | pwzPortExists = pwzExists + 1; | ||
97 | pwzExists = wcsstr(pwzPortExists, L":"); | ||
98 | if (NULL == pwzExists) | ||
99 | continue; | ||
100 | |||
101 | *pwzExists = L'\0'; | ||
102 | iPortExists = wcstol(pwzPortExists, NULL, 10); | ||
103 | |||
104 | pwzHeaderExists = pwzExists + 1; | ||
105 | |||
106 | // compare the passed in address with the address listed for this web | ||
107 | if (S_OK == hr && | ||
108 | (0 == lstrcmpW(wzIP, pwzIPExists) || 0 == lstrcmpW(wzIP, L"*")) && | ||
109 | iPort == iPortExists && | ||
110 | 0 == lstrcmpW(wzHeader, pwzHeaderExists)) | ||
111 | { | ||
112 | // if the passed in buffer wasn't big enough | ||
113 | hr = ::StringCchCopyW(wzWebBase, cchWebBase, wzKey); | ||
114 | ExitOnFailure(hr, "failed to copy in web base: %ls", wzKey); | ||
115 | |||
116 | fFound = TRUE; | ||
117 | break; | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | |||
122 | if (E_NOMOREITEMS == hr) | ||
123 | { | ||
124 | Assert(!fFound); | ||
125 | hr = S_FALSE; | ||
126 | } | ||
127 | |||
128 | LExit: | ||
129 | MetaFreeValue(&mrAddress); | ||
130 | MetaFreeValue(&mr); | ||
131 | |||
132 | if (!fFound && SUCCEEDED(hr)) | ||
133 | hr = S_FALSE; | ||
134 | |||
135 | return hr; | ||
136 | } | ||
137 | |||
138 | |||
139 | /******************************************************************** | ||
140 | MetaFindFreeWebBase - finds the next metabase base string | ||
141 | |||
142 | ********************************************************************/ | ||
143 | extern "C" HRESULT DAPI MetaFindFreeWebBase( | ||
144 | __in IMSAdminBaseW* piMetabase, | ||
145 | __out_ecount(cchWebBase) LPWSTR wzWebBase, | ||
146 | __in DWORD cchWebBase | ||
147 | ) | ||
148 | { | ||
149 | Assert(piMetabase); | ||
150 | |||
151 | HRESULT hr = S_OK; | ||
152 | |||
153 | WCHAR wzKey[METADATA_MAX_NAME_LEN]; | ||
154 | WCHAR wzSubkey[METADATA_MAX_NAME_LEN]; | ||
155 | DWORD dwSubKeys[100]; | ||
156 | int cSubKeys = 0; | ||
157 | DWORD dwIndex = 0; | ||
158 | |||
159 | int i; | ||
160 | DWORD dwKey; | ||
161 | |||
162 | METADATA_RECORD mr; | ||
163 | |||
164 | memset(&mr, 0, sizeof(mr)); | ||
165 | mr.dwMDIdentifier = MD_KEY_TYPE; | ||
166 | mr.dwMDAttributes = 0; | ||
167 | mr.dwMDUserType = IIS_MD_UT_SERVER; | ||
168 | mr.dwMDDataType = STRING_METADATA; | ||
169 | |||
170 | // loop through the "web keys" looking for the "IIsWebServer" key that matches wzWeb | ||
171 | for (dwIndex = 0; SUCCEEDED(hr); ++dwIndex) | ||
172 | { | ||
173 | hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC", wzSubkey, dwIndex); | ||
174 | if (FAILED(hr)) | ||
175 | break; | ||
176 | |||
177 | ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%s", wzSubkey); | ||
178 | |||
179 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr); | ||
180 | if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) | ||
181 | { | ||
182 | hr = S_FALSE; // didn't find anything, try next one | ||
183 | continue; | ||
184 | } | ||
185 | ExitOnFailure(hr, "failed to get key from metabase while searching for free web root"); | ||
186 | |||
187 | // if we have a IIsWebServer get the address information | ||
188 | if (0 == lstrcmpW(L"IIsWebServer", reinterpret_cast<LPCWSTR>(mr.pbMDData))) | ||
189 | { | ||
190 | if (cSubKeys >= countof(dwSubKeys)) | ||
191 | { | ||
192 | hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); | ||
193 | ExitOnFailure(hr, "Insufficient buffer to track all sub-WebSites"); | ||
194 | } | ||
195 | |||
196 | dwSubKeys[cSubKeys] = wcstol(wzSubkey, NULL, 10); | ||
197 | ++cSubKeys; | ||
198 | Sort(dwSubKeys, cSubKeys); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | if (E_NOMOREITEMS == hr) | ||
203 | hr = S_OK; | ||
204 | ExitOnFailure(hr, "failed to find free web root"); | ||
205 | |||
206 | // find the lowest free web root | ||
207 | dwKey = 1; | ||
208 | for (i = 0; i < cSubKeys; ++i) | ||
209 | { | ||
210 | if (dwKey < dwSubKeys[i]) | ||
211 | break; | ||
212 | |||
213 | dwKey = dwSubKeys[i] + 1; | ||
214 | } | ||
215 | |||
216 | hr = ::StringCchPrintfW(wzWebBase, cchWebBase, L"/LM/W3SVC/%u", dwKey); | ||
217 | LExit: | ||
218 | MetaFreeValue(&mr); | ||
219 | return hr; | ||
220 | } | ||
221 | |||
222 | |||
223 | /******************************************************************** | ||
224 | MetaOpenKey - open key | ||
225 | |||
226 | ********************************************************************/ | ||
227 | extern "C" HRESULT DAPI MetaOpenKey( | ||
228 | __in IMSAdminBaseW* piMetabase, | ||
229 | __in METADATA_HANDLE mhKey, | ||
230 | __in_z LPCWSTR wzKey, | ||
231 | __in DWORD dwAccess, | ||
232 | __in DWORD cRetries, | ||
233 | __out METADATA_HANDLE* pmh | ||
234 | ) | ||
235 | { | ||
236 | Assert(piMetabase && pmh); | ||
237 | |||
238 | HRESULT hr = S_OK; | ||
239 | |||
240 | // loop while the key is busy | ||
241 | do | ||
242 | { | ||
243 | hr = piMetabase->OpenKey(mhKey, wzKey, dwAccess, 10, pmh); | ||
244 | if (HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr) | ||
245 | ::SleepEx(1000, TRUE); | ||
246 | } while (HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr && 0 < cRetries--); | ||
247 | |||
248 | return hr; | ||
249 | } | ||
250 | |||
251 | |||
252 | /******************************************************************** | ||
253 | MetaGetValue - finds the next metabase base string | ||
254 | |||
255 | NOTE: piMetabase is optional | ||
256 | ********************************************************************/ | ||
257 | extern "C" HRESULT DAPI MetaGetValue( | ||
258 | __in IMSAdminBaseW* piMetabase, | ||
259 | __in METADATA_HANDLE mhKey, | ||
260 | __in_z LPCWSTR wzKey, | ||
261 | __inout METADATA_RECORD* pmr | ||
262 | ) | ||
263 | { | ||
264 | Assert(pmr); | ||
265 | |||
266 | HRESULT hr = S_OK; | ||
267 | BOOL fInitialized = FALSE; | ||
268 | DWORD cbRequired = 0; | ||
269 | |||
270 | if (!piMetabase) | ||
271 | { | ||
272 | hr = ::CoInitialize(NULL); | ||
273 | ExitOnFailure(hr, "failed to initialize COM"); | ||
274 | fInitialized = TRUE; | ||
275 | |||
276 | hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<LPVOID*>(&piMetabase)); | ||
277 | ExitOnFailure(hr, "failed to get IID_IMSAdminBaseW object"); | ||
278 | } | ||
279 | |||
280 | if (!pmr->pbMDData) | ||
281 | { | ||
282 | pmr->dwMDDataLen = 256; | ||
283 | pmr->pbMDData = static_cast<BYTE*>(MemAlloc(pmr->dwMDDataLen, TRUE)); | ||
284 | ExitOnNull(pmr->pbMDData, hr, E_OUTOFMEMORY, "failed to allocate memory for metabase value"); | ||
285 | } | ||
286 | else // set the size of the data to the actual size of the memory | ||
287 | pmr->dwMDDataLen = (DWORD)MemSize(pmr->pbMDData); | ||
288 | |||
289 | hr = piMetabase->GetData(mhKey, wzKey, pmr, &cbRequired); | ||
290 | if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) | ||
291 | { | ||
292 | pmr->dwMDDataLen = cbRequired; | ||
293 | BYTE* pb = static_cast<BYTE*>(MemReAlloc(pmr->pbMDData, pmr->dwMDDataLen, TRUE)); | ||
294 | ExitOnNull(pb, hr, E_OUTOFMEMORY, "failed to reallocate memory for metabase value"); | ||
295 | |||
296 | pmr->pbMDData = pb; | ||
297 | hr = piMetabase->GetData(mhKey, wzKey, pmr, &cbRequired); | ||
298 | } | ||
299 | ExitOnFailure(hr, "failed to get metabase data"); | ||
300 | |||
301 | LExit: | ||
302 | if (fInitialized) | ||
303 | { | ||
304 | ReleaseObject(piMetabase); | ||
305 | ::CoUninitialize(); | ||
306 | } | ||
307 | |||
308 | return hr; | ||
309 | } | ||
310 | |||
311 | |||
312 | /******************************************************************** | ||
313 | MetaFreeValue - frees data in METADATA_RECORD remove MetaGetValue() | ||
314 | |||
315 | NOTE: METADATA_RECORD must have been returned from MetaGetValue() above | ||
316 | ********************************************************************/ | ||
317 | extern "C" void DAPI MetaFreeValue( | ||
318 | __in METADATA_RECORD* pmr | ||
319 | ) | ||
320 | { | ||
321 | Assert(pmr); | ||
322 | |||
323 | ReleaseNullMem(pmr->pbMDData); | ||
324 | } | ||
325 | |||
326 | |||
327 | // | ||
328 | // private | ||
329 | // | ||
330 | |||
331 | /******************************************************************** | ||
332 | Sort - quick and dirty insertion sort | ||
333 | |||
334 | ********************************************************************/ | ||
335 | static void Sort( | ||
336 | __in_ecount(cArray) DWORD dwArray[], | ||
337 | __in int cArray | ||
338 | ) | ||
339 | { | ||
340 | int i, j; | ||
341 | DWORD dwData; | ||
342 | |||
343 | for (i = 1; i < cArray; ++i) | ||
344 | { | ||
345 | dwData = dwArray[i]; | ||
346 | |||
347 | j = i - 1; | ||
348 | while (0 <= j && dwArray[j] > dwData) | ||
349 | { | ||
350 | dwArray[j + 1] = dwArray[j]; | ||
351 | j--; | ||
352 | } | ||
353 | |||
354 | dwArray[j + 1] = dwData; | ||
355 | } | ||
356 | } | ||