aboutsummaryrefslogtreecommitdiff
path: root/src/dutil/metautil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dutil/metautil.cpp')
-rw-r--r--src/dutil/metautil.cpp356
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
13static 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********************************************************************/
23extern "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
128LExit:
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********************************************************************/
143extern "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);
217LExit:
218 MetaFreeValue(&mr);
219 return hr;
220}
221
222
223/********************************************************************
224 MetaOpenKey - open key
225
226********************************************************************/
227extern "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********************************************************************/
257extern "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
301LExit:
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********************************************************************/
317extern "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********************************************************************/
335static 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}