diff options
Diffstat (limited to 'src/tools/heat/IIsWebSiteHarvester.cs')
-rw-r--r-- | src/tools/heat/IIsWebSiteHarvester.cs | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/src/tools/heat/IIsWebSiteHarvester.cs b/src/tools/heat/IIsWebSiteHarvester.cs new file mode 100644 index 00000000..6e5e29c7 --- /dev/null +++ b/src/tools/heat/IIsWebSiteHarvester.cs | |||
@@ -0,0 +1,439 @@ | |||
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 | namespace WixToolset.Harvesters | ||
4 | { | ||
5 | using System; | ||
6 | using System.DirectoryServices; | ||
7 | using System.Globalization; | ||
8 | using System.Runtime.InteropServices; | ||
9 | using WixToolset.Data; | ||
10 | using WixToolset.Harvesters.Data; | ||
11 | using WixToolset.Harvesters.Extensibility; | ||
12 | using IIs = WixToolset.Harvesters.Serialize.IIs; | ||
13 | using Wix = WixToolset.Harvesters.Serialize; | ||
14 | |||
15 | /// <summary> | ||
16 | /// The web site harvester for the WiX Toolset Internet Information Services Extension. | ||
17 | /// </summary> | ||
18 | public sealed class IIsWebSiteHarvester : BaseHarvesterExtension | ||
19 | { | ||
20 | /// <summary> | ||
21 | /// Harvest a WiX document. | ||
22 | /// </summary> | ||
23 | /// <param name="argument">The argument for harvesting.</param> | ||
24 | /// <returns>The harvested Fragment.</returns> | ||
25 | public override Wix.Fragment[] Harvest(string argument) | ||
26 | { | ||
27 | DirectoryHarvester directoryHarvester = new DirectoryHarvester(); | ||
28 | directoryHarvester.Core = this.Core; | ||
29 | directoryHarvester.KeepEmptyDirectories = true; | ||
30 | |||
31 | IIsWebSiteHarvester iisWebSiteHarvester = new IIsWebSiteHarvester(); | ||
32 | iisWebSiteHarvester.Core = this.Core; | ||
33 | |||
34 | IIs.WebSite webSite = iisWebSiteHarvester.HarvestWebSite(argument); | ||
35 | |||
36 | Wix.Component component = new Wix.Component(); | ||
37 | component.AddChild(new Wix.CreateFolder()); | ||
38 | component.AddChild(webSite); | ||
39 | |||
40 | this.Core.RootDirectory = webSite.Directory; | ||
41 | Wix.Directory directory = directoryHarvester.HarvestDirectory(webSite.Directory, true); | ||
42 | directory.AddChild(component); | ||
43 | |||
44 | Wix.Fragment fragment = new Wix.Fragment(); | ||
45 | fragment.AddChild(directory); | ||
46 | |||
47 | return new Wix.Fragment[] { fragment }; | ||
48 | } | ||
49 | |||
50 | /// <summary> | ||
51 | /// Harvest a web site. | ||
52 | /// </summary> | ||
53 | /// <param name="name">The name of the web site.</param> | ||
54 | /// <returns>The harvested web site.</returns> | ||
55 | public IIs.WebSite HarvestWebSite(string name) | ||
56 | { | ||
57 | try | ||
58 | { | ||
59 | DirectoryEntry directoryEntry = new DirectoryEntry("IIS://localhost/W3SVC"); | ||
60 | |||
61 | foreach (DirectoryEntry childEntry in directoryEntry.Children) | ||
62 | { | ||
63 | if ("IIsWebServer" == childEntry.SchemaClassName) | ||
64 | { | ||
65 | if (String.Equals((string)childEntry.Properties["ServerComment"].Value, name, StringComparison.OrdinalIgnoreCase)) | ||
66 | { | ||
67 | return this.HarvestWebSite(childEntry); | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | catch (COMException ce) | ||
73 | { | ||
74 | // 0x8007005 - access denied | ||
75 | // If we don't have permission to harvest a website, it's likely because we're on | ||
76 | // Vista or higher and aren't an Admin. | ||
77 | if ((0x80070005 == unchecked((uint)ce.ErrorCode))) | ||
78 | { | ||
79 | throw new WixException(HarvesterErrors.InsufficientPermissionHarvestWebSite()); | ||
80 | } | ||
81 | // 0x80005000 - unknown error | ||
82 | else if ((0x80005000 == unchecked((uint)ce.ErrorCode))) | ||
83 | { | ||
84 | throw new WixException(HarvesterErrors.CannotHarvestWebSite()); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | throw new WixException(HarvesterErrors.WebSiteNotFound(name)); | ||
89 | } | ||
90 | |||
91 | /// <summary> | ||
92 | /// Harvest a web site. | ||
93 | /// </summary> | ||
94 | /// <param name="webSiteEntry">The web site directory entry.</param> | ||
95 | /// <returns>The harvested web site.</returns> | ||
96 | private IIs.WebSite HarvestWebSite(DirectoryEntry webSiteEntry) | ||
97 | { | ||
98 | IIs.WebSite webSite = new IIs.WebSite(); | ||
99 | |||
100 | foreach (string propertyName in webSiteEntry.Properties.PropertyNames) | ||
101 | { | ||
102 | PropertyValueCollection property = webSiteEntry.Properties[propertyName]; | ||
103 | PropertyValueCollection parentProperty = webSiteEntry.Parent.Properties[propertyName]; | ||
104 | |||
105 | if (null == parentProperty.Value || parentProperty.Value.ToString() != property.Value.ToString()) | ||
106 | { | ||
107 | switch (propertyName) | ||
108 | { | ||
109 | case "SecureBindings": | ||
110 | IIs.WebAddress secureWebAddress = this.HarvestBindings(propertyName, property); | ||
111 | if (null != secureWebAddress) | ||
112 | { | ||
113 | webSite.AddChild(secureWebAddress); | ||
114 | } | ||
115 | break; | ||
116 | case "ServerBindings": | ||
117 | IIs.WebAddress webAddress = this.HarvestBindings(propertyName, property); | ||
118 | if (null != webAddress) | ||
119 | { | ||
120 | webSite.AddChild(webAddress); | ||
121 | } | ||
122 | break; | ||
123 | case "ServerComment": | ||
124 | webSite.Description = (string)property.Value; | ||
125 | break; | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | |||
130 | foreach (DirectoryEntry childEntry in webSiteEntry.Children) | ||
131 | { | ||
132 | switch (childEntry.SchemaClassName) | ||
133 | { | ||
134 | case "IIsFilters": | ||
135 | string loadOrder = (string)childEntry.Properties["FilterLoadOrder"].Value; | ||
136 | if (loadOrder.Length > 0) | ||
137 | { | ||
138 | string[] filterNames = loadOrder.Split(",".ToCharArray()); | ||
139 | |||
140 | for (int i = 0; i < filterNames.Length; i++) | ||
141 | { | ||
142 | using (DirectoryEntry webFilterEntry = new DirectoryEntry(String.Concat(childEntry.Path, '/', filterNames[i]))) | ||
143 | { | ||
144 | IIs.WebFilter webFilter = this.HarvestWebFilter(webFilterEntry); | ||
145 | |||
146 | webFilter.LoadOrder = (i + 1).ToString(CultureInfo.InvariantCulture); | ||
147 | |||
148 | webSite.AddChild(webFilter); | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | break; | ||
153 | case "IIsWebDirectory": | ||
154 | this.HarvestWebDirectory(childEntry, webSite); | ||
155 | break; | ||
156 | case "IIsWebVirtualDir": | ||
157 | foreach (string propertyName in childEntry.Properties.PropertyNames) | ||
158 | { | ||
159 | PropertyValueCollection property = childEntry.Properties[propertyName]; | ||
160 | |||
161 | switch (propertyName) | ||
162 | { | ||
163 | case "Path": | ||
164 | webSite.Directory = (string)property.Value; | ||
165 | break; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | IIs.WebDirProperties webDirProps = this.HarvestWebDirProperties(childEntry); | ||
170 | if (null != webDirProps) | ||
171 | { | ||
172 | webSite.AddChild(webDirProps); | ||
173 | } | ||
174 | |||
175 | foreach (DirectoryEntry child2Entry in childEntry.Children) | ||
176 | { | ||
177 | switch (child2Entry.SchemaClassName) | ||
178 | { | ||
179 | case "IIsWebDirectory": | ||
180 | this.HarvestWebDirectory(child2Entry, webSite); | ||
181 | break; | ||
182 | case "IIsWebVirtualDir": | ||
183 | this.HarvestWebVirtualDir(child2Entry, webSite); | ||
184 | break; | ||
185 | } | ||
186 | } | ||
187 | break; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | return webSite; | ||
192 | } | ||
193 | |||
194 | /// <summary> | ||
195 | /// Harvest bindings. | ||
196 | /// </summary> | ||
197 | /// <param name="propertyName">The property name of the bindings property.</param> | ||
198 | /// <param name="bindingsProperty">The bindings property.</param> | ||
199 | /// <returns>The harvested bindings.</returns> | ||
200 | private IIs.WebAddress HarvestBindings(string propertyName, PropertyValueCollection bindingsProperty) | ||
201 | { | ||
202 | if (1 == bindingsProperty.Count) | ||
203 | { | ||
204 | IIs.WebAddress webAddress = new IIs.WebAddress(); | ||
205 | |||
206 | string[] bindings = ((string)bindingsProperty[0]).Split(":".ToCharArray()); | ||
207 | |||
208 | if (0 < bindings[0].Length) | ||
209 | { | ||
210 | webAddress.IP = bindings[0]; | ||
211 | } | ||
212 | |||
213 | if (0 < bindings[1].Length) | ||
214 | { | ||
215 | webAddress.Port = bindings[1]; | ||
216 | } | ||
217 | |||
218 | if (0 < bindings[2].Length) | ||
219 | { | ||
220 | webAddress.Header = bindings[2]; | ||
221 | } | ||
222 | |||
223 | if ("SecureBindings" == propertyName) | ||
224 | { | ||
225 | webAddress.Secure = IIs.YesNoType.yes; | ||
226 | } | ||
227 | |||
228 | return webAddress; | ||
229 | } | ||
230 | |||
231 | return null; | ||
232 | } | ||
233 | |||
234 | /// <summary> | ||
235 | /// Harvest a web directory. | ||
236 | /// </summary> | ||
237 | /// <param name="webDirectoryEntry">The web directory directory entry.</param> | ||
238 | /// <param name="webSite">The parent web site.</param> | ||
239 | private void HarvestWebDirectory(DirectoryEntry webDirectoryEntry, IIs.WebSite webSite) | ||
240 | { | ||
241 | foreach (DirectoryEntry childEntry in webDirectoryEntry.Children) | ||
242 | { | ||
243 | switch (childEntry.SchemaClassName) | ||
244 | { | ||
245 | case "IIsWebDirectory": | ||
246 | this.HarvestWebDirectory(childEntry, webSite); | ||
247 | break; | ||
248 | case "IIsWebVirtualDir": | ||
249 | this.HarvestWebVirtualDir(childEntry, webSite); | ||
250 | break; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | IIs.WebDirProperties webDirProperties = this.HarvestWebDirProperties(webDirectoryEntry); | ||
255 | |||
256 | if (null != webDirProperties) | ||
257 | { | ||
258 | IIs.WebDir webDir = new IIs.WebDir(); | ||
259 | |||
260 | int indexOfRoot = webDirectoryEntry.Path.IndexOf("ROOT/", StringComparison.OrdinalIgnoreCase); | ||
261 | webDir.Path = webDirectoryEntry.Path.Substring(indexOfRoot + 5); | ||
262 | |||
263 | webDir.AddChild(webDirProperties); | ||
264 | |||
265 | webSite.AddChild(webDir); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | /// <summary> | ||
270 | /// Harvest a web filter. | ||
271 | /// </summary> | ||
272 | /// <param name="webFilterEntry">The web filter directory entry.</param> | ||
273 | /// <returns>The harvested web filter.</returns> | ||
274 | private IIs.WebFilter HarvestWebFilter(DirectoryEntry webFilterEntry) | ||
275 | { | ||
276 | IIs.WebFilter webFilter = new IIs.WebFilter(); | ||
277 | |||
278 | webFilter.Name = webFilterEntry.Name; | ||
279 | |||
280 | foreach (string propertyName in webFilterEntry.Properties.PropertyNames) | ||
281 | { | ||
282 | PropertyValueCollection property = webFilterEntry.Properties[propertyName]; | ||
283 | |||
284 | switch (propertyName) | ||
285 | { | ||
286 | case "FilterDescription": | ||
287 | webFilter.Description = (string)property.Value; | ||
288 | break; | ||
289 | case "FilterFlags": | ||
290 | webFilter.Flags = (int)property.Value; | ||
291 | break; | ||
292 | case "FilterPath": | ||
293 | webFilter.Path = (string)property.Value; | ||
294 | break; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | return webFilter; | ||
299 | } | ||
300 | |||
301 | /// <summary> | ||
302 | /// Harvest a web directory's properties. | ||
303 | /// </summary> | ||
304 | /// <param name="directoryEntry">The web directory directory entry.</param> | ||
305 | /// <returns>The harvested web directory's properties.</returns> | ||
306 | private IIs.WebDirProperties HarvestWebDirProperties(DirectoryEntry directoryEntry) | ||
307 | { | ||
308 | bool foundProperties = false; | ||
309 | IIs.WebDirProperties webDirProperties = new IIs.WebDirProperties(); | ||
310 | |||
311 | // Cannot read properties for "iisadmin" site. | ||
312 | if (String.Equals("iisadmin", directoryEntry.Name, StringComparison.OrdinalIgnoreCase) && | ||
313 | String.Equals("ROOT", directoryEntry.Parent.Name, StringComparison.OrdinalIgnoreCase)) | ||
314 | { | ||
315 | return null; | ||
316 | } | ||
317 | |||
318 | foreach (string propertyName in directoryEntry.Properties.PropertyNames) | ||
319 | { | ||
320 | PropertyValueCollection property = directoryEntry.Properties[propertyName]; | ||
321 | PropertyValueCollection parentProperty = directoryEntry.Parent.Properties[propertyName]; | ||
322 | |||
323 | if (null == parentProperty.Value || parentProperty.Value.ToString() != property.Value.ToString()) | ||
324 | { | ||
325 | switch (propertyName) | ||
326 | { | ||
327 | case "AccessFlags": | ||
328 | int access = (int)property.Value; | ||
329 | |||
330 | if (0x1 == (access & 0x1)) | ||
331 | { | ||
332 | webDirProperties.Read = IIs.YesNoType.yes; | ||
333 | } | ||
334 | |||
335 | if (0x2 == (access & 0x2)) | ||
336 | { | ||
337 | webDirProperties.Write = IIs.YesNoType.yes; | ||
338 | } | ||
339 | |||
340 | if (0x4 == (access & 0x4)) | ||
341 | { | ||
342 | webDirProperties.Execute = IIs.YesNoType.yes; | ||
343 | } | ||
344 | |||
345 | if (0x200 == (access & 0x200)) | ||
346 | { | ||
347 | webDirProperties.Script = IIs.YesNoType.yes; | ||
348 | } | ||
349 | |||
350 | foundProperties = true; | ||
351 | break; | ||
352 | case "AuthFlags": | ||
353 | int authorization = (int)property.Value; | ||
354 | |||
355 | if (0x1 == (authorization & 0x1)) | ||
356 | { | ||
357 | webDirProperties.AnonymousAccess = IIs.YesNoType.yes; | ||
358 | } | ||
359 | |||
360 | if (0x2 == (authorization & 0x2)) | ||
361 | { | ||
362 | webDirProperties.BasicAuthentication = IIs.YesNoType.yes; | ||
363 | } | ||
364 | |||
365 | if (0x4 == (authorization & 0x4)) | ||
366 | { | ||
367 | webDirProperties.WindowsAuthentication = IIs.YesNoType.yes; | ||
368 | } | ||
369 | |||
370 | if (0x10 == (authorization & 0x10)) | ||
371 | { | ||
372 | webDirProperties.DigestAuthentication = IIs.YesNoType.yes; | ||
373 | } | ||
374 | |||
375 | if (0x40 == (authorization & 0x40)) | ||
376 | { | ||
377 | webDirProperties.PassportAuthentication = IIs.YesNoType.yes; | ||
378 | } | ||
379 | |||
380 | foundProperties = true; | ||
381 | break; | ||
382 | } | ||
383 | } | ||
384 | } | ||
385 | |||
386 | return foundProperties ? webDirProperties : null; | ||
387 | } | ||
388 | |||
389 | /// <summary> | ||
390 | /// Harvest a web virtual directory. | ||
391 | /// </summary> | ||
392 | /// <param name="webVirtualDirEntry">The web virtual directory directory entry.</param> | ||
393 | /// <param name="webSite">The parent web site.</param> | ||
394 | private void HarvestWebVirtualDir(DirectoryEntry webVirtualDirEntry, IIs.WebSite webSite) | ||
395 | { | ||
396 | IIs.WebVirtualDir webVirtualDir = new IIs.WebVirtualDir(); | ||
397 | |||
398 | foreach (string propertyName in webVirtualDirEntry.Properties.PropertyNames) | ||
399 | { | ||
400 | PropertyValueCollection property = webVirtualDirEntry.Properties[propertyName]; | ||
401 | PropertyValueCollection parentProperty = webVirtualDirEntry.Parent.Properties[propertyName]; | ||
402 | |||
403 | if (null == parentProperty.Value || parentProperty.Value.ToString() != property.Value.ToString()) | ||
404 | { | ||
405 | switch (propertyName) | ||
406 | { | ||
407 | case "Path": | ||
408 | webVirtualDir.Directory = (string)property.Value; | ||
409 | break; | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | int indexOfRoot = webVirtualDirEntry.Path.IndexOf("ROOT/", StringComparison.OrdinalIgnoreCase); | ||
415 | webVirtualDir.Alias = webVirtualDirEntry.Path.Substring(indexOfRoot + 5); | ||
416 | |||
417 | IIs.WebDirProperties webDirProps = this.HarvestWebDirProperties(webVirtualDirEntry); | ||
418 | if (webDirProps != null) | ||
419 | { | ||
420 | webVirtualDir.AddChild(webDirProps); | ||
421 | } | ||
422 | |||
423 | foreach (DirectoryEntry childEntry in webVirtualDirEntry.Children) | ||
424 | { | ||
425 | switch (childEntry.SchemaClassName) | ||
426 | { | ||
427 | case "IIsWebDirectory": | ||
428 | this.HarvestWebDirectory(childEntry, webSite); | ||
429 | break; | ||
430 | case "IIsWebVirtualDir": | ||
431 | this.HarvestWebVirtualDir(childEntry, webSite); | ||
432 | break; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | webSite.AddChild(webVirtualDir); | ||
437 | } | ||
438 | } | ||
439 | } | ||