aboutsummaryrefslogtreecommitdiff
path: root/src/ext
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-05-11 08:05:16 -0700
committerRob Mensching <rob@firegiant.com>2021-05-11 08:05:16 -0700
commit400d3eaae96f9cf9d15b448240b944473964ee31 (patch)
treed2fa7d0e7e246da1b748136f152018d019411709 /src/ext
parente835776f17056097559c13f25b4c875c7361bd5b (diff)
parent7c8e34de56b3348c5a421cd0cced183e1394c5c7 (diff)
downloadwix-400d3eaae96f9cf9d15b448240b944473964ee31.tar.gz
wix-400d3eaae96f9cf9d15b448240b944473964ee31.tar.bz2
wix-400d3eaae96f9cf9d15b448240b944473964ee31.zip
Merge Iis.wixext
Diffstat (limited to 'src/ext')
-rw-r--r--src/ext/Iis/CSharp.Build.props11
-rw-r--r--src/ext/Iis/Cpp.Build.props86
-rw-r--r--src/ext/Iis/Directory.Build.props29
-rw-r--r--src/ext/Iis/Directory.Build.targets48
-rw-r--r--src/ext/Iis/Iis.wixext.sln58
-rw-r--r--src/ext/Iis/README.md2
-rw-r--r--src/ext/Iis/appveyor.cmd14
-rw-r--r--src/ext/Iis/appveyor.yml40
-rw-r--r--src/ext/Iis/ca/CustomMsiErrors.h48
-rw-r--r--src/ext/Iis/ca/caDecor.h13
-rw-r--r--src/ext/Iis/ca/dllmain.cpp26
-rw-r--r--src/ext/Iis/ca/iisca.cpp3
-rw-r--r--src/ext/Iis/ca/iisca.def30
-rw-r--r--src/ext/Iis/ca/iisca.vcxproj147
-rw-r--r--src/ext/Iis/ca/packages.config5
-rw-r--r--src/ext/Iis/ca/precomp.h66
-rw-r--r--src/ext/Iis/ca/sca.h124
-rw-r--r--src/ext/Iis/ca/scaapppool.cpp594
-rw-r--r--src/ext/Iis/ca/scaapppool.h88
-rw-r--r--src/ext/Iis/ca/scaapppool7.cpp401
-rw-r--r--src/ext/Iis/ca/scaapppool7.h36
-rw-r--r--src/ext/Iis/ca/scacert.cpp1482
-rw-r--r--src/ext/Iis/ca/scacert.h23
-rw-r--r--src/ext/Iis/ca/scacertexec.cpp431
-rw-r--r--src/ext/Iis/ca/scacost.h15
-rw-r--r--src/ext/Iis/ca/scaexec.cpp1184
-rw-r--r--src/ext/Iis/ca/scaexecIIS7.cpp4205
-rw-r--r--src/ext/Iis/ca/scaexecIIS7.h5
-rw-r--r--src/ext/Iis/ca/scafilter.cpp510
-rw-r--r--src/ext/Iis/ca/scafilter.h46
-rw-r--r--src/ext/Iis/ca/scafilter7.cpp284
-rw-r--r--src/ext/Iis/ca/scafilter7.h21
-rw-r--r--src/ext/Iis/ca/scahttpheader.cpp323
-rw-r--r--src/ext/Iis/ca/scahttpheader.h40
-rw-r--r--src/ext/Iis/ca/scahttpheader7.cpp130
-rw-r--r--src/ext/Iis/ca/scahttpheader7.h15
-rw-r--r--src/ext/Iis/ca/scaiis.cpp481
-rw-r--r--src/ext/Iis/ca/scaiis.h33
-rw-r--r--src/ext/Iis/ca/scaiis7.cpp74
-rw-r--r--src/ext/Iis/ca/scaiis7.h17
-rw-r--r--src/ext/Iis/ca/scamimemap.cpp200
-rw-r--r--src/ext/Iis/ca/scamimemap.h33
-rw-r--r--src/ext/Iis/ca/scamimemap7.cpp68
-rw-r--r--src/ext/Iis/ca/scamimemap7.h10
-rw-r--r--src/ext/Iis/ca/scaproperty.cpp252
-rw-r--r--src/ext/Iis/ca/scaproperty.h54
-rw-r--r--src/ext/Iis/ca/scaproperty7.cpp108
-rw-r--r--src/ext/Iis/ca/scaproperty7.h26
-rw-r--r--src/ext/Iis/ca/scasched.cpp823
-rw-r--r--src/ext/Iis/ca/scassl.cpp115
-rw-r--r--src/ext/Iis/ca/scassl.h36
-rw-r--r--src/ext/Iis/ca/scassl7.cpp34
-rw-r--r--src/ext/Iis/ca/scassl7.h8
-rw-r--r--src/ext/Iis/ca/scauser.cpp91
-rw-r--r--src/ext/Iis/ca/scauser.h39
-rw-r--r--src/ext/Iis/ca/scavdir.cpp331
-rw-r--r--src/ext/Iis/ca/scavdir.h71
-rw-r--r--src/ext/Iis/ca/scavdir7.cpp380
-rw-r--r--src/ext/Iis/ca/scavdir7.h66
-rw-r--r--src/ext/Iis/ca/scaweb.cpp1187
-rw-r--r--src/ext/Iis/ca/scaweb.h123
-rw-r--r--src/ext/Iis/ca/scaweb7.cpp953
-rw-r--r--src/ext/Iis/ca/scaweb7.h97
-rw-r--r--src/ext/Iis/ca/scawebapp.cpp194
-rw-r--r--src/ext/Iis/ca/scawebapp.h42
-rw-r--r--src/ext/Iis/ca/scawebapp7.cpp120
-rw-r--r--src/ext/Iis/ca/scawebapp7.h10
-rw-r--r--src/ext/Iis/ca/scawebappext.cpp207
-rw-r--r--src/ext/Iis/ca/scawebappext.h32
-rw-r--r--src/ext/Iis/ca/scawebappext7.cpp61
-rw-r--r--src/ext/Iis/ca/scawebappext7.h9
-rw-r--r--src/ext/Iis/ca/scawebdir.cpp241
-rw-r--r--src/ext/Iis/ca/scawebdir.h57
-rw-r--r--src/ext/Iis/ca/scawebdir7.cpp219
-rw-r--r--src/ext/Iis/ca/scawebdir7.h51
-rw-r--r--src/ext/Iis/ca/scaweberr.cpp371
-rw-r--r--src/ext/Iis/ca/scaweberr.h30
-rw-r--r--src/ext/Iis/ca/scaweberr7.cpp88
-rw-r--r--src/ext/Iis/ca/scaweberr7.h10
-rw-r--r--src/ext/Iis/ca/scaweblog.cpp177
-rw-r--r--src/ext/Iis/ca/scaweblog.h27
-rw-r--r--src/ext/Iis/ca/scaweblog7.cpp120
-rw-r--r--src/ext/Iis/ca/scaweblog7.h14
-rw-r--r--src/ext/Iis/ca/scawebprop.cpp301
-rw-r--r--src/ext/Iis/ca/scawebprop.h60
-rw-r--r--src/ext/Iis/ca/scawebprop7.cpp155
-rw-r--r--src/ext/Iis/ca/scawebprop7.h12
-rw-r--r--src/ext/Iis/ca/scawebsvcext.cpp343
-rw-r--r--src/ext/Iis/ca/scawebsvcext.h35
-rw-r--r--src/ext/Iis/ca/scawebsvcext7.cpp106
-rw-r--r--src/ext/Iis/ca/scawebsvcext7.h8
-rw-r--r--src/ext/Iis/nuget.config17
-rw-r--r--src/ext/Iis/test/WixToolsetTest.Iis/IisExtensionFixture.cs32
-rw-r--r--src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/Package.en-us.wxl11
-rw-r--r--src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/Package.wxs17
-rw-r--r--src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/PackageComponents.wxs16
-rw-r--r--src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/example.txt1
-rw-r--r--src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.csproj41
-rw-r--r--src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.v3.ncrunchproject5
-rw-r--r--src/ext/Iis/wix.snkbin0 -> 596 bytes
-rw-r--r--src/ext/Iis/wixext/IIsCompiler.cs2620
-rw-r--r--src/ext/Iis/wixext/IIsDecompiler.cs1549
-rw-r--r--src/ext/Iis/wixext/IIsExtensionData.cs30
-rw-r--r--src/ext/Iis/wixext/IisErrors.cs78
-rw-r--r--src/ext/Iis/wixext/IisExtensionFactory.cs18
-rw-r--r--src/ext/Iis/wixext/IisTableDefinitions.cs324
-rw-r--r--src/ext/Iis/wixext/IisWindowsInstallerBackendBinderExtension.cs13
-rw-r--r--src/ext/Iis/wixext/Symbols/CertificateHashSymbol.cs55
-rw-r--r--src/ext/Iis/wixext/Symbols/CertificateSymbol.cs103
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsAppPoolSymbol.cs159
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsFilterSymbol.cs95
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsHttpHeaderSymbol.cs95
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsMimeMapSymbol.cs71
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsPropertySymbol.cs63
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsWebAddressSymbol.cs79
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsWebApplicationExtensionSymbol.cs79
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsWebApplicationSymbol.cs127
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsWebDirPropertiesSymbol.cs151
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsWebDirSymbol.cs79
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsWebErrorSymbol.cs87
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsWebLogSymbol.cs47
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsWebServiceExtensionSymbol.cs79
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsWebSiteCertificatesSymbol.cs55
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsWebSiteSymbol.cs135
-rw-r--r--src/ext/Iis/wixext/Symbols/IIsWebVirtualDirSymbol.cs87
-rw-r--r--src/ext/Iis/wixext/Symbols/IisSymbolDefinitions.cs107
-rw-r--r--src/ext/Iis/wixext/WixToolset.Iis.wixext.csproj31
-rw-r--r--src/ext/Iis/wixext/WixToolset.Iis.wixext.targets11
-rw-r--r--src/ext/Iis/wixlib/IIsExtension.wxs58
-rw-r--r--src/ext/Iis/wixlib/IIsExtension_Platform.wxi66
-rw-r--r--src/ext/Iis/wixlib/IIsExtension_arm64.wxs7
-rw-r--r--src/ext/Iis/wixlib/IIsExtension_x64.wxs7
-rw-r--r--src/ext/Iis/wixlib/IIsExtension_x86.wxs7
-rw-r--r--src/ext/Iis/wixlib/caDecor.wxi39
-rw-r--r--src/ext/Iis/wixlib/caerr.wxi96
-rw-r--r--src/ext/Iis/wixlib/de-de.wxl55
-rw-r--r--src/ext/Iis/wixlib/en-us.wxl55
-rw-r--r--src/ext/Iis/wixlib/iis.v3.ncrunchproject5
-rw-r--r--src/ext/Iis/wixlib/iis.wixproj26
-rw-r--r--src/ext/Iis/wixlib/ja-jp.wxl47
-rw-r--r--src/ext/Iis/wixlib/pt-br.wxl50
141 files changed, 26478 insertions, 0 deletions
diff --git a/src/ext/Iis/CSharp.Build.props b/src/ext/Iis/CSharp.Build.props
new file mode 100644
index 00000000..b12f4c6e
--- /dev/null
+++ b/src/ext/Iis/CSharp.Build.props
@@ -0,0 +1,11 @@
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 Do NOT modify this file. Update the canonical version in Home\repo-template\src\CSharp.Build.props
4 then update all of the repos.
5-->
6<Project>
7 <PropertyGroup>
8 <SignAssembly>true</SignAssembly>
9 <AssemblyOriginatorKeyFile>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)wix.snk))</AssemblyOriginatorKeyFile>
10 </PropertyGroup>
11</Project>
diff --git a/src/ext/Iis/Cpp.Build.props b/src/ext/Iis/Cpp.Build.props
new file mode 100644
index 00000000..9b7a1bb5
--- /dev/null
+++ b/src/ext/Iis/Cpp.Build.props
@@ -0,0 +1,86 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project>
5 <PropertyGroup>
6 <Platform Condition=" '$(Platform)' == '' OR '$(Platform)' == 'AnyCPU' ">Win32</Platform>
7 <IntDir>$(BaseIntermediateOutputPath)$(Configuration)\$(Platform)\</IntDir>
8 <OutDir>$(OutputPath)$(Platform)\</OutDir>
9 </PropertyGroup>
10
11 <PropertyGroup Condition="'$(WindowsTargetPlatformVersion)'=='' AND '$(VisualStudioVersion)'>='15.0'">
12 <WindowsTargetPlatformVersion>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))</WindowsTargetPlatformVersion>
13 </PropertyGroup>
14
15 <ItemDefinitionGroup>
16 <ClCompile>
17 <DisableSpecificWarnings>$(DisableSpecificCompilerWarnings)</DisableSpecificWarnings>
18 <WarningLevel>Level4</WarningLevel>
19 <AdditionalIncludeDirectories>$(ProjectDir)inc;$(MSBuildProjectDirectory);$(IntDir);$(SqlCESdkIncludePath);$(ProjectAdditionalIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
20 <PreprocessorDefinitions>WIN32;_WINDOWS;_WIN32_MSI=500;_WIN32_WINNT=0x0501;$(ArmPreprocessorDefinitions);$(UnicodePreprocessorDefinitions);_CRT_STDIO_LEGACY_WIDE_SPECIFIERS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
21 <PrecompiledHeader>Use</PrecompiledHeader>
22 <PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
23 <CallingConvention Condition="'$(Platform)'=='Win32'">StdCall</CallingConvention>
24 <TreatWarningAsError>true</TreatWarningAsError>
25 <ExceptionHandling>false</ExceptionHandling>
26 <AdditionalOptions>-YlprecompDefine</AdditionalOptions>
27 <AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
28 <MultiProcessorCompilation Condition=" $(NUMBER_OF_PROCESSORS) &gt; 4 ">true</MultiProcessorCompilation>
29 </ClCompile>
30 <ResourceCompile>
31 <PreprocessorDefinitions>$(ArmPreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
32 <AdditionalIncludeDirectories>$(ProjectAdditionalResourceIncludeDirectories);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
33 </ResourceCompile>
34 <Lib>
35 <AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ProjectAdditionalLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
36 </Lib>
37 <Link>
38 <SubSystem>$(ProjectSubSystem)</SubSystem>
39 <ModuleDefinitionFile>$(ProjectModuleDefinitionFile)</ModuleDefinitionFile>
40 <NoEntryPoint>$(ResourceOnlyDll)</NoEntryPoint>
41 <GenerateDebugInformation>true</GenerateDebugInformation>
42 <AdditionalDependencies>$(ProjectAdditionalLinkLibraries);advapi32.lib;comdlg32.lib;user32.lib;oleaut32.lib;gdi32.lib;shell32.lib;ole32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
43 <AdditionalLibraryDirectories>$(OutDir);$(AdditionalMultiTargetLibraryPath);$(ArmLibraryDirectories);$(ProjectAdditionalLinkLibraryDirectories);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
44 <AdditionalOptions Condition=" $(PlatformToolset.StartsWith('v14')) ">/IGNORE:4099 %(AdditionalOptions)</AdditionalOptions>
45 </Link>
46 </ItemDefinitionGroup>
47
48 <ItemDefinitionGroup Condition=" '$(Platform)'=='Win32' and '$(PlatformToolset)'!='v100'">
49 <ClCompile>
50 <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
51 </ClCompile>
52 </ItemDefinitionGroup>
53 <ItemDefinitionGroup Condition=" '$(Platform)'=='arm' ">
54 <ClCompile>
55 <CallingConvention>CDecl</CallingConvention>
56 </ClCompile>
57 </ItemDefinitionGroup>
58 <ItemDefinitionGroup Condition=" '$(ConfigurationType)'=='StaticLibrary' ">
59 <ClCompile>
60 <DebugInformationFormat>OldStyle</DebugInformationFormat>
61 <OmitDefaultLibName>true</OmitDefaultLibName>
62 <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
63 </ClCompile>
64 </ItemDefinitionGroup>
65 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Debug' ">
66 <ClCompile>
67 <Optimization>Disabled</Optimization>
68 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
69 <PreprocessorDefinitions>_DEBUG;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
70 <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
71 </ClCompile>
72 </ItemDefinitionGroup>
73 <ItemDefinitionGroup Condition=" '$(Configuration)'=='Release' ">
74 <ClCompile>
75 <Optimization>MinSpace</Optimization>
76 <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
77 <FunctionLevelLinking>true</FunctionLevelLinking>
78 <IntrinsicFunctions>true</IntrinsicFunctions>
79 <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
80 </ClCompile>
81 <Link>
82 <EnableCOMDATFolding>true</EnableCOMDATFolding>
83 <OptimizeReferences>true</OptimizeReferences>
84 </Link>
85 </ItemDefinitionGroup>
86</Project>
diff --git a/src/ext/Iis/Directory.Build.props b/src/ext/Iis/Directory.Build.props
new file mode 100644
index 00000000..f83cc154
--- /dev/null
+++ b/src/ext/Iis/Directory.Build.props
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3<!--
4 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.Build.props
5 then update all of the repos.
6-->
7<Project>
8 <PropertyGroup>
9 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
10 <EnableSourceLink Condition=" '$(NCrunch)' == '1' ">false</EnableSourceLink>
11 <MSBuildWarningsAsMessages>MSB3246</MSBuildWarningsAsMessages>
12
13 <ProjectName Condition=" '$(ProjectName)' == '' ">$(MSBuildProjectName)</ProjectName>
14 <BaseOutputPath>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\))</BaseOutputPath>
15 <BaseIntermediateOutputPath>$(BaseOutputPath)obj\$(ProjectName)\</BaseIntermediateOutputPath>
16 <OutputPath>$(BaseOutputPath)$(Configuration)\</OutputPath>
17
18 <Authors>WiX Toolset Team</Authors>
19 <Company>WiX Toolset</Company>
20 <Copyright>Copyright (c) .NET Foundation and contributors. All rights reserved.</Copyright>
21 <PackageLicenseExpression>MS-RL</PackageLicenseExpression>
22 <Product>WiX Toolset</Product>
23 </PropertyGroup>
24
25 <Import Project="CSharp.Build.props" Condition=" '$(MSBuildProjectExtension)'=='.csproj' and Exists('CSharp.Build.props') " />
26 <Import Project="Cpp.Build.props" Condition=" Exists('Cpp.Build.props') And '$(MSBuildProjectExtension)'=='.vcxproj' " />
27 <Import Project="Wix.Build.props" Condition=" Exists('Wix.Build.props') And '$(MSBuildProjectExtension)'=='.wixproj' " />
28 <Import Project="Custom.Build.props" Condition=" Exists('Custom.Build.props') " />
29</Project>
diff --git a/src/ext/Iis/Directory.Build.targets b/src/ext/Iis/Directory.Build.targets
new file mode 100644
index 00000000..dac7452a
--- /dev/null
+++ b/src/ext/Iis/Directory.Build.targets
@@ -0,0 +1,48 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3<!--
4 Do NOT modify this file. Update the canonical version in Home\repo-template\src\Directory.Build.targets
5 then update all of the repos.
6-->
7<!--
8 Replace PackageReferences with ProjectReferences when the projects can be found in .sln.
9 See the original here: https://github.com/dotnet/sdk/issues/1151#issuecomment-385133284
10-->
11<Project>
12 <PropertyGroup>
13 <ReplacePackageReferences>true</ReplacePackageReferences>
14 <TheSolutionPath Condition=" '$(NCrunch)'=='' ">$(SolutionPath)</TheSolutionPath>
15 <TheSolutionPath Condition=" '$(NCrunch)'=='1' ">$(NCrunchOriginalSolutionPath)</TheSolutionPath>
16 </PropertyGroup>
17
18 <Choose>
19 <When Condition="$(ReplacePackageReferences) AND '$(TheSolutionPath)' != '' AND '$(TheSolutionPath)' != '*undefined*' AND Exists('$(TheSolutionPath)')">
20
21 <PropertyGroup>
22 <SolutionFileContent>$([System.IO.File]::ReadAllText($(TheSolutionPath)))</SolutionFileContent>
23 <SmartSolutionDir>$([System.IO.Path]::GetDirectoryName( $(TheSolutionPath) ))</SmartSolutionDir>
24 <RegexPattern>(?&lt;="[PackageName]", ")(.*)(?=", ")</RegexPattern>
25 </PropertyGroup>
26
27 <ItemGroup>
28 <!-- Keep the identity of the PackageReference -->
29 <SmartPackageReference Include="@(PackageReference)">
30 <PackageName>%(Identity)</PackageName>
31 <InSolution>$(SolutionFileContent.Contains('\%(Identity).csproj'))</InSolution>
32 </SmartPackageReference>
33
34 <!-- Filter them by mapping them to another ItemGroup using the WithMetadataValue item function -->
35 <PackageInSolution Include="@(SmartPackageReference->WithMetadataValue('InSolution', True))">
36 <Pattern>$(RegexPattern.Replace('[PackageName]','%(PackageName)') )</Pattern>
37 <SmartPath>$([System.Text.RegularExpressions.Regex]::Match('$(SolutionFileContent)', '%(Pattern)'))</SmartPath>
38 </PackageInSolution>
39
40 <ProjectReference Include="@(PackageInSolution->'$(SmartSolutionDir)\%(SmartPath)' )"/>
41
42 <!-- Remove the package references that are now referenced as projects -->
43 <PackageReference Remove="@(PackageInSolution->'%(PackageName)' )"/>
44 </ItemGroup>
45
46 </When>
47 </Choose>
48</Project>
diff --git a/src/ext/Iis/Iis.wixext.sln b/src/ext/Iis/Iis.wixext.sln
new file mode 100644
index 00000000..85323fde
--- /dev/null
+++ b/src/ext/Iis/Iis.wixext.sln
@@ -0,0 +1,58 @@
1
2Microsoft Visual Studio Solution File, Format Version 12.00
3# Visual Studio Version 16
4VisualStudioVersion = 16.0.30204.135
5MinimumVisualStudioVersion = 10.0.40219.1
6Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iisca", "src\ca\iisca.vcxproj", "{CB3FB8C4-14BF-4EA6-9F01-7FB258E5AEF3}"
7EndProject
8Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "iis", "src\wixlib\iis.wixproj", "{92FE99D2-355D-4F52-A7C1-10EECB4A5BB1}"
9EndProject
10Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Iis.wixext", "src\wixext\WixToolset.Iis.wixext.csproj", "{612029FB-B5D4-4D7E-B794-A0E202BFE493}"
11EndProject
12Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.Iis", "src\test\WixToolsetTest.Iis\WixToolsetTest.Iis.csproj", "{E62712D7-31A1-49E4-B1F4-0084FAD14193}"
13EndProject
14Global
15 GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 Debug|Any CPU = Debug|Any CPU
17 Debug|x86 = Debug|x86
18 Release|Any CPU = Release|Any CPU
19 Release|x86 = Release|x86
20 EndGlobalSection
21 GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 {CB3FB8C4-14BF-4EA6-9F01-7FB258E5AEF3}.Debug|Any CPU.ActiveCfg = Debug|Win32
23 {CB3FB8C4-14BF-4EA6-9F01-7FB258E5AEF3}.Debug|Any CPU.Build.0 = Debug|Win32
24 {CB3FB8C4-14BF-4EA6-9F01-7FB258E5AEF3}.Debug|x86.ActiveCfg = Debug|Win32
25 {CB3FB8C4-14BF-4EA6-9F01-7FB258E5AEF3}.Debug|x86.Build.0 = Debug|Win32
26 {CB3FB8C4-14BF-4EA6-9F01-7FB258E5AEF3}.Release|Any CPU.ActiveCfg = Release|Win32
27 {CB3FB8C4-14BF-4EA6-9F01-7FB258E5AEF3}.Release|x86.ActiveCfg = Release|Win32
28 {CB3FB8C4-14BF-4EA6-9F01-7FB258E5AEF3}.Release|x86.Build.0 = Release|Win32
29 {92FE99D2-355D-4F52-A7C1-10EECB4A5BB1}.Debug|Any CPU.ActiveCfg = Debug|x86
30 {92FE99D2-355D-4F52-A7C1-10EECB4A5BB1}.Debug|x86.ActiveCfg = Debug|x86
31 {92FE99D2-355D-4F52-A7C1-10EECB4A5BB1}.Debug|x86.Build.0 = Debug|x86
32 {92FE99D2-355D-4F52-A7C1-10EECB4A5BB1}.Release|Any CPU.ActiveCfg = Release|x86
33 {92FE99D2-355D-4F52-A7C1-10EECB4A5BB1}.Release|x86.ActiveCfg = Release|x86
34 {92FE99D2-355D-4F52-A7C1-10EECB4A5BB1}.Release|x86.Build.0 = Release|x86
35 {612029FB-B5D4-4D7E-B794-A0E202BFE493}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 {612029FB-B5D4-4D7E-B794-A0E202BFE493}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 {612029FB-B5D4-4D7E-B794-A0E202BFE493}.Debug|x86.ActiveCfg = Debug|Any CPU
38 {612029FB-B5D4-4D7E-B794-A0E202BFE493}.Debug|x86.Build.0 = Debug|Any CPU
39 {612029FB-B5D4-4D7E-B794-A0E202BFE493}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 {612029FB-B5D4-4D7E-B794-A0E202BFE493}.Release|Any CPU.Build.0 = Release|Any CPU
41 {612029FB-B5D4-4D7E-B794-A0E202BFE493}.Release|x86.ActiveCfg = Release|Any CPU
42 {612029FB-B5D4-4D7E-B794-A0E202BFE493}.Release|x86.Build.0 = Release|Any CPU
43 {E62712D7-31A1-49E4-B1F4-0084FAD14193}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 {E62712D7-31A1-49E4-B1F4-0084FAD14193}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 {E62712D7-31A1-49E4-B1F4-0084FAD14193}.Debug|x86.ActiveCfg = Debug|Any CPU
46 {E62712D7-31A1-49E4-B1F4-0084FAD14193}.Debug|x86.Build.0 = Debug|Any CPU
47 {E62712D7-31A1-49E4-B1F4-0084FAD14193}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 {E62712D7-31A1-49E4-B1F4-0084FAD14193}.Release|Any CPU.Build.0 = Release|Any CPU
49 {E62712D7-31A1-49E4-B1F4-0084FAD14193}.Release|x86.ActiveCfg = Release|Any CPU
50 {E62712D7-31A1-49E4-B1F4-0084FAD14193}.Release|x86.Build.0 = Release|Any CPU
51 EndGlobalSection
52 GlobalSection(SolutionProperties) = preSolution
53 HideSolutionNode = FALSE
54 EndGlobalSection
55 GlobalSection(ExtensibilityGlobals) = postSolution
56 SolutionGuid = {89256463-14A3-4968-8688-F75EC230B021}
57 EndGlobalSection
58EndGlobal
diff --git a/src/ext/Iis/README.md b/src/ext/Iis/README.md
new file mode 100644
index 00000000..ddb21a82
--- /dev/null
+++ b/src/ext/Iis/README.md
@@ -0,0 +1,2 @@
1# Iis.wixext
2WixToolset.Iis.wixext - Iis WiX Toolset Extension
diff --git a/src/ext/Iis/appveyor.cmd b/src/ext/Iis/appveyor.cmd
new file mode 100644
index 00000000..af993a8f
--- /dev/null
+++ b/src/ext/Iis/appveyor.cmd
@@ -0,0 +1,14 @@
1@setlocal
2@pushd %~dp0
3
4nuget restore || exit /b
5
6msbuild -p:Configuration=Release -t:Restore || exit /b
7
8msbuild -p:Configuration=Release src\test\WixToolsetTest.Iis\WixToolsetTest.Iis.csproj || exit /b
9dotnet test -c Release --no-build src\test\WixToolsetTest.Iis || exit /b
10
11msbuild -p:Configuration=Release -t:Pack src\wixext\WixToolset.Iis.wixext.csproj || exit /b
12
13@popd
14@endlocal \ No newline at end of file
diff --git a/src/ext/Iis/appveyor.yml b/src/ext/Iis/appveyor.yml
new file mode 100644
index 00000000..7c686b04
--- /dev/null
+++ b/src/ext/Iis/appveyor.yml
@@ -0,0 +1,40 @@
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# Do NOT modify this file. Update the canonical version in Home\repo-template\src\appveyor.yml
4# then update all of the repos.
5
6branches:
7 only:
8 - master
9 - develop
10
11image: Visual Studio 2019
12
13version: 0.0.0.{build}
14configuration: Release
15
16environment:
17 DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
18 DOTNET_CLI_TELEMETRY_OPTOUT: 1
19 NUGET_XMLDOC_MODE: skip
20
21build_script:
22 - appveyor.cmd
23
24pull_requests:
25 do_not_increment_build_number: true
26
27nuget:
28 disable_publish_on_pr: true
29
30skip_branch_with_pr: true
31skip_tags: true
32
33artifacts:
34- path: build\Release\**\*.nupkg
35 name: nuget
36
37notifications:
38- provider: Slack
39 incoming_webhook:
40 secure: p5xuu+4x2JHfwGDMDe5KcG1k7gZxqYc4jWVwvyNZv5cvkubPD2waJs5yXMAXZNN7Z63/3PWHb7q4KoY/99AjauYa1nZ4c5qYqRPFRBKTHfA=
diff --git a/src/ext/Iis/ca/CustomMsiErrors.h b/src/ext/Iis/ca/CustomMsiErrors.h
new file mode 100644
index 00000000..1fd8d050
--- /dev/null
+++ b/src/ext/Iis/ca/CustomMsiErrors.h
@@ -0,0 +1,48 @@
1#pragma once
2// 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.
3
4#define msierrIISCannotConnect 26001
5#define msierrIISFailedReadWebSite 26002
6#define msierrIISFailedReadWebDirs 26003
7#define msierrIISFailedReadVDirs 26004
8#define msierrIISFailedReadFilters 26005
9#define msierrIISFailedReadAppPool 26006
10#define msierrIISFailedReadMimeMap 26007
11#define msierrIISFailedReadProp 26008
12#define msierrIISFailedReadWebSvcExt 26009
13#define msierrIISFailedReadWebError 26010
14#define msierrIISFailedReadHttpHeader 26011
15
16#define msierrIISFailedSchedTransaction 26031
17#define msierrIISFailedSchedInstallWebs 26032
18#define msierrIISFailedSchedInstallWebDirs 26033
19#define msierrIISFailedSchedInstallVDirs 26034
20#define msierrIISFailedSchedInstallFilters 26035
21#define msierrIISFailedSchedInstallAppPool 26036
22#define msierrIISFailedSchedInstallProp 26037
23#define msierrIISFailedSchedInstallWebSvcExt 26038
24
25#define msierrIISFailedSchedUninstallWebs 26051
26#define msierrIISFailedSchedUninstallWebDirs 26052
27#define msierrIISFailedSchedUninstallVDirs 26053
28#define msierrIISFailedSchedUninstallFilters 26054
29#define msierrIISFailedSchedUninstallAppPool 26055
30#define msierrIISFailedSchedUninstallProp 26056
31#define msierrIISFailedSchedUninstallWebSvcExt 26057
32
33#define msierrIISFailedStartTransaction 26101
34#define msierrIISFailedOpenKey 26102
35#define msierrIISFailedCreateKey 26103
36#define msierrIISFailedWriteData 26104
37#define msierrIISFailedCreateApp 26105
38#define msierrIISFailedDeleteKey 26106
39#define msierrIISFailedDeleteApp 26107
40#define msierrIISFailedDeleteValue 26108
41#define msierrIISFailedCommitInUse 26109
42
43// Last available value 26200
44
45#define msierrCERTFailedOpen 26351
46#define msierrCERTFailedAdd 26352
47
48// Last available value 26450
diff --git a/src/ext/Iis/ca/caDecor.h b/src/ext/Iis/ca/caDecor.h
new file mode 100644
index 00000000..da274650
--- /dev/null
+++ b/src/ext/Iis/ca/caDecor.h
@@ -0,0 +1,13 @@
1#pragma once
2// 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.
3
4
5#if defined(_M_ARM64)
6#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_A64"
7#elif defined(_M_AMD64)
8#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X64"
9#elif defined(_M_ARM)
10#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_ARM"
11#else
12#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X86"
13#endif
diff --git a/src/ext/Iis/ca/dllmain.cpp b/src/ext/Iis/ca/dllmain.cpp
new file mode 100644
index 00000000..35ae6d1c
--- /dev/null
+++ b/src/ext/Iis/ca/dllmain.cpp
@@ -0,0 +1,26 @@
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/********************************************************************
6DllMain - standard entry point for all WiX custom actions
7
8********************************************************************/
9extern "C" BOOL WINAPI DllMain(
10 IN HINSTANCE hInst,
11 IN ULONG ulReason,
12 IN LPVOID)
13{
14 switch(ulReason)
15 {
16 case DLL_PROCESS_ATTACH:
17 WcaGlobalInitialize(hInst);
18 break;
19
20 case DLL_PROCESS_DETACH:
21 WcaGlobalFinalize();
22 break;
23 }
24
25 return TRUE;
26}
diff --git a/src/ext/Iis/ca/iisca.cpp b/src/ext/Iis/ca/iisca.cpp
new file mode 100644
index 00000000..37664a1c
--- /dev/null
+++ b/src/ext/Iis/ca/iisca.cpp
@@ -0,0 +1,3 @@
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"
diff --git a/src/ext/Iis/ca/iisca.def b/src/ext/Iis/ca/iisca.def
new file mode 100644
index 00000000..b9127da6
--- /dev/null
+++ b/src/ext/Iis/ca/iisca.def
@@ -0,0 +1,30 @@
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
4LIBRARY "iisca"
5
6EXPORTS
7;scacert.cpp
8 InstallCertificates
9 UninstallCertificates
10;scacertexec.cpp
11 AddUserCertificate
12 AddMachineCertificate
13 DeleteUserCertificate
14 DeleteMachineCertificate
15;scaexec.cpp
16 StartMetabaseTransaction
17 RollbackMetabaseTransaction
18 CommitMetabaseTransaction
19
20 WriteMetabaseChanges
21
22 StartIIS7ConfigTransaction
23 RollbackIIS7ConfigTransaction
24 CommitIIS7ConfigTransaction
25
26 WriteIIS7ConfigChanges
27;scasched.cpp
28 ConfigureIIs
29 ConfigureIIsExec
30 ConfigureIIs7Exec
diff --git a/src/ext/Iis/ca/iisca.vcxproj b/src/ext/Iis/ca/iisca.vcxproj
new file mode 100644
index 00000000..eb1174be
--- /dev/null
+++ b/src/ext/Iis/ca/iisca.vcxproj
@@ -0,0 +1,147 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
4 <Import Project="..\..\packages\WixToolset.DUtil.4.0.30\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.30\build\WixToolset.DUtil.props')" />
5 <Import Project="..\..\packages\WixToolset.WcaUtil.4.0.16\build\WixToolset.WcaUtil.props" Condition="Exists('..\..\packages\WixToolset.WcaUtil.4.0.16\build\WixToolset.WcaUtil.props')" />
6
7 <ItemGroup Label="ProjectConfigurations">
8 <ProjectConfiguration Include="Debug|Win32">
9 <Configuration>Debug</Configuration>
10 <Platform>Win32</Platform>
11 </ProjectConfiguration>
12 <ProjectConfiguration Include="Release|Win32">
13 <Configuration>Release</Configuration>
14 <Platform>Win32</Platform>
15 </ProjectConfiguration>
16 <ProjectConfiguration Include="Debug|x64">
17 <Configuration>Debug</Configuration>
18 <Platform>x64</Platform>
19 </ProjectConfiguration>
20 <ProjectConfiguration Include="Release|x64">
21 <Configuration>Release</Configuration>
22 <Platform>x64</Platform>
23 </ProjectConfiguration>
24 <ProjectConfiguration Include="Debug|ARM64">
25 <Configuration>Debug</Configuration>
26 <Platform>ARM64</Platform>
27 </ProjectConfiguration>
28 <ProjectConfiguration Include="Release|ARM64">
29 <Configuration>Release</Configuration>
30 <Platform>ARM64</Platform>
31 </ProjectConfiguration>
32 </ItemGroup>
33
34 <PropertyGroup Label="Globals">
35 <ProjectGuid>{CB3FB8C4-14BF-4EA6-9F01-7FB258E5AEF3}</ProjectGuid>
36 <ConfigurationType>DynamicLibrary</ConfigurationType>
37 <TargetName>iisca</TargetName>
38 <PlatformToolset>v142</PlatformToolset>
39 <CharacterSet>Unicode</CharacterSet>
40 <ProjectModuleDefinitionFile>iisca.def</ProjectModuleDefinitionFile>
41 <Description>WiX Toolset Iis CustomAction</Description>
42 </PropertyGroup>
43
44 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
45 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
46
47 <PropertyGroup>
48 <ProjectAdditionalLinkLibraries>crypt32.lib;msi.lib;Ws2_32.lib</ProjectAdditionalLinkLibraries>
49 </PropertyGroup>
50
51 <ItemGroup>
52 <ClCompile Include="dllmain.cpp">
53 <PrecompiledHeader>Create</PrecompiledHeader>
54 </ClCompile>
55 <ClCompile Include="iisca.cpp" />
56 <ClCompile Include="scaapppool.cpp" />
57 <ClCompile Include="scaapppool7.cpp" />
58 <ClCompile Include="scacert.cpp" />
59 <ClCompile Include="scacertexec.cpp" />
60 <ClCompile Include="scaexec.cpp" />
61 <ClCompile Include="scaexecIIS7.cpp" />
62 <ClCompile Include="scafilter.cpp" />
63 <ClCompile Include="scafilter7.cpp" />
64 <ClCompile Include="scahttpheader.cpp" />
65 <ClCompile Include="scahttpheader7.cpp" />
66 <ClCompile Include="scaiis.cpp" />
67 <ClCompile Include="scaiis7.cpp" />
68 <ClCompile Include="scamimemap.cpp" />
69 <ClCompile Include="scamimemap7.cpp" />
70 <ClCompile Include="scaproperty.cpp" />
71 <ClCompile Include="scaproperty7.cpp" />
72 <ClCompile Include="scasched.cpp" />
73 <ClCompile Include="scassl.cpp" />
74 <ClCompile Include="scassl7.cpp" />
75 <ClCompile Include="scauser.cpp" />
76 <ClCompile Include="scavdir.cpp" />
77 <ClCompile Include="scavdir7.cpp" />
78 <ClCompile Include="scaweb.cpp" />
79 <ClCompile Include="scaweb7.cpp" />
80 <ClCompile Include="scawebapp.cpp" />
81 <ClCompile Include="scawebapp7.cpp" />
82 <ClCompile Include="scawebappext.cpp" />
83 <ClCompile Include="scawebappext7.cpp" />
84 <ClCompile Include="scawebdir.cpp" />
85 <ClCompile Include="scawebdir7.cpp" />
86 <ClCompile Include="scaweberr.cpp" />
87 <ClCompile Include="scaweberr7.cpp" />
88 <ClCompile Include="scaweblog.cpp" />
89 <ClCompile Include="scaweblog7.cpp" />
90 <ClCompile Include="scawebprop.cpp" />
91 <ClCompile Include="scawebprop7.cpp" />
92 <ClCompile Include="scawebsvcext.cpp" />
93 <ClCompile Include="scawebsvcext7.cpp" />
94 <ClInclude Include="caSuffix.h" />
95 <ClInclude Include="CustomMsiErrors.h" />
96 <ClInclude Include="precomp.h" />
97 <ClInclude Include="sca.h" />
98 <ClInclude Include="scaapppool.h" />
99 <ClInclude Include="scaapppool7.h" />
100 <ClInclude Include="scacert.h" />
101 <ClInclude Include="scacost.h" />
102 <ClInclude Include="scaexecIIS7.h" />
103 <ClInclude Include="scafilter.h" />
104 <ClInclude Include="scafilter7.h" />
105 <ClInclude Include="scahttpheader.h" />
106 <ClInclude Include="scahttpheader7.h" />
107 <ClInclude Include="scaiis.h" />
108 <ClInclude Include="scaiis7.h" />
109 <ClInclude Include="scamimemap.h" />
110 <ClInclude Include="scamimemap7.h" />
111 <ClInclude Include="scaproperty.h" />
112 <ClInclude Include="scaproperty7.h" />
113 <ClInclude Include="scassl.h" />
114 <ClInclude Include="scassl7.h" />
115 <ClInclude Include="scauser.h" />
116 <ClInclude Include="scavdir.h" />
117 <ClInclude Include="scavdir7.h" />
118 <ClInclude Include="scaweb.h" />
119 <ClInclude Include="scaweb7.h" />
120 <ClInclude Include="scawebapp.h" />
121 <ClInclude Include="scawebapp7.h" />
122 <ClInclude Include="scawebappext.h" />
123 <ClInclude Include="scawebappext7.h" />
124 <ClInclude Include="scawebdir.h" />
125 <ClInclude Include="scawebdir7.h" />
126 <ClInclude Include="scaweberr.h" />
127 <ClInclude Include="scaweberr7.h" />
128 <ClInclude Include="scaweblog.h" />
129 <ClInclude Include="scaweblog7.h" />
130 <ClInclude Include="scawebprop.h" />
131 <ClInclude Include="scawebprop7.h" />
132 <ClInclude Include="scawebsvcext.h" />
133 <ClInclude Include="scawebsvcext7.h" />
134 <None Include="packages.config" />
135 <None Include="iisca.def" />
136 </ItemGroup>
137
138 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
139
140 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
141 <PropertyGroup>
142 <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
143 </PropertyGroup>
144 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.30\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.30\build\WixToolset.DUtil.props'))" />
145 <Error Condition="!Exists('..\..\packages\WixToolset.WcaUtil.4.0.16\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.WcaUtil.4.0.16\build\WixToolset.WcaUtil.props'))" />
146 </Target>
147</Project> \ No newline at end of file
diff --git a/src/ext/Iis/ca/packages.config b/src/ext/Iis/ca/packages.config
new file mode 100644
index 00000000..e3dc0e43
--- /dev/null
+++ b/src/ext/Iis/ca/packages.config
@@ -0,0 +1,5 @@
1<?xml version="1.0" encoding="utf-8"?>
2<packages>
3 <package id="WixToolset.DUtil" version="4.0.30" targetFramework="native" />
4 <package id="WixToolset.WcaUtil" version="4.0.16" targetFramework="native" />
5</packages> \ No newline at end of file
diff --git a/src/ext/Iis/ca/precomp.h b/src/ext/Iis/ca/precomp.h
new file mode 100644
index 00000000..85ee0890
--- /dev/null
+++ b/src/ext/Iis/ca/precomp.h
@@ -0,0 +1,66 @@
1#pragma once
2// 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.
3
4
5#if _WIN32_MSI < 150
6#define _WIN32_MSI 150
7#endif
8
9#include <windows.h>
10#include <msiquery.h>
11#include <msidefs.h>
12#include <strsafe.h>
13
14#include <lm.h> // NetApi32.lib
15
16#include <Dsgetdc.h>
17#include <ComAdmin.h>
18#include <ahadmin.h> // IIS 7 config
19
20#define MAXUINT USHRT_MAX
21
22#include "wcautil.h"
23#include "wcawow64.h"
24#include "wcawrapquery.h"
25
26#include "certutil.h"
27#include "cryputil.h"
28#include "fileutil.h"
29#include "iis7util.h"
30#include "memutil.h"
31#include "metautil.h"
32#include "strutil.h"
33#include "userutil.h"
34#include "wiutil.h"
35
36#include "CustomMsiErrors.h"
37#include "sca.h"
38#include "scacost.h"
39#include "scacert.h"
40#include "scafilter.h"
41
42#include "scaiis.h"
43#include "scaiis7.h"
44#include "scaproperty.h"
45#include "scaweb.h"
46#include "scawebdir.h"
47#include "scawebsvcext.h"
48#include "scavdir.h"
49#include "scaweb7.h"
50#include "scaapppool7.h"
51#include "scavdir7.h"
52#include "scawebapp7.h"
53#include "scawebappext7.h"
54#include "scamimemap7.h"
55#include "scawebprop7.h"
56#include "scaweblog7.h"
57#include "scafilter7.h"
58#include "scahttpheader7.h"
59#include "scaweberr7.h"
60#include "scawebsvcext7.h"
61#include "scaproperty7.h"
62#include "scawebdir7.h"
63#include "scassl7.h"
64#include "scaexecIIS7.h"
65
66#include "caDecor.h"
diff --git a/src/ext/Iis/ca/sca.h b/src/ext/Iis/ca/sca.h
new file mode 100644
index 00000000..64567dcb
--- /dev/null
+++ b/src/ext/Iis/ca/sca.h
@@ -0,0 +1,124 @@
1#pragma once
2// 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.
3
4
5#define MAGIC_MULTISZ_CHAR 127
6
7// Generic action enum.
8enum SCA_ACTION
9{
10 SCA_ACTION_NONE,
11 SCA_ACTION_INSTALL,
12 SCA_ACTION_UNINSTALL
13};
14
15
16// IIS Metabase actions
17enum METABASE_ACTION
18{
19 MBA_UNKNOWNACTION = 0,
20 MBA_CREATEKEY,
21 MBA_DELETEKEY,
22 MBA_WRITEVALUE,
23 MBA_DELETEVALUE,
24 MBA_CREATEAPP,
25 MBA_DELETEAPP,
26};
27
28// IIS 7 Config actions
29enum IIS_CONFIG_ACTION
30{
31 IIS_CREATE,
32 IIS_DELETE,
33 IIS_SITE,
34 IIS_APPLICATION,
35 IIS_APPPOOL,
36 IIS_APPPOOL_RECYCLE_MIN,
37 IIS_APPPOOL_RECYCLE_REQ,
38 IIS_APPPOOL_RECYCLE_TIMES,
39 IIS_APPPOOL_RECYCLE_VIRMEM,
40 IIS_APPPOOL_RECYCLE_PRIVMEM,
41 IIS_APPPOOL_RECYCLE_IDLTIMEOUT,
42 IIS_APPPOOL_RECYCLE_QUEUELIMIT,
43 IIS_APPPOOL_RECYCLE_CPU_PCT,
44 IIS_APPPOOL_RECYCLE_CPU_REFRESH,
45 IIS_APPPOOL_RECYCLE_CPU_ACTION,
46 IIS_APPPOOL_MAXPROCESS,
47 IIS_APPPOOL_IDENTITY,
48 IIS_APPPOOL_USER,
49 IIS_APPPOOL_PWD,
50 IIS_APPPOOL_32BIT,
51 IIS_APPPOOL_MANAGED_PIPELINE_MODE,
52 IIS_APPPOOL_MANAGED_RUNTIME_VERSION,
53 IIS_APPPOOL_END,
54 IIS_APPEXT_BEGIN,
55 IIS_APPEXT,
56 IIS_APPEXT_END,
57 IIS_VDIR,
58 IIS_BINDING,
59 IIS_MIMEMAP_BEGIN,
60 IIS_MIMEMAP,
61 IIS_MIMEMAP_END,
62 IIS_DIRPROP_BEGIN,
63 IIS_DIRPROP_ACCESS,
64 IIS_DIRPROP_AUTH,
65 IIS_DIRPROP_USER,
66 IIS_DIRPROP_PWD,
67 IIS_DIRPROP_PWDCTRL,
68 IIS_DIRPROP_LOG,
69 IIS_DIRPROP_DEFDOCS,
70 IIS_DIRPROP_SSLFLAGS,
71 IIS_DIRPROP_AUTHPROVID,
72 IIS_DIRPROP_ASPERROR,
73 IIS_DIRPROP_HTTPEXPIRES,
74 IIS_DIRPROP_MAXAGE,
75 IIS_DIRPROP_CACHECUST,
76 IIS_DIRPROP_NOCUSTERROR,
77 IIS_DIRPROP_LOGVISITS,
78 IIS_DIRPROP_END,
79 IIS_WEBLOG,
80 IIS_FILTER_BEGIN,
81 IIS_FILTER_GLOBAL_BEGIN,
82 IIS_FILTER,
83 IIS_FILTER_END,
84 IIS_HTTP_HEADER_BEGIN,
85 IIS_HTTP_HEADER,
86 IIS_HTTP_HEADER_END,
87 IIS_WEBERROR_BEGIN,
88 IIS_WEBERROR,
89 IIS_WEBERROR_END,
90 IIS_WEB_SVC_EXT,
91 IIS_PROPERTY,
92 IIS_PROPERTY_MAXBAND,
93 IIS_PROPERTY_LOGUTF8,
94 IIS_WEBDIR,
95 IIS_ASP_BEGIN,
96 IIS_ASP_SESSIONSTATE,
97 IIS_ASP_SESSIONTIMEOUT,
98 IIS_ASP_BUFFER,
99 IIS_ASP_PARENTPATHS,
100 IIS_ASP_SCRIPTLANG,
101 IIS_ASP_SCRIPTTIMEOUT,
102 IIS_ASP_SCRIPTSERVERDEBUG,
103 IIS_ASP_SCRIPTCLIENTDEBUG,
104 IIS_ASP_END,
105 IIS_SSL_BINDING
106};
107
108
109// user creation attributes definitions
110enum SCAU_ATTRIBUTES
111{
112 SCAU_DONT_EXPIRE_PASSWRD = 0x00000001,
113 SCAU_PASSWD_CANT_CHANGE = 0x00000002,
114 SCAU_PASSWD_CHANGE_REQD_ON_LOGIN = 0x00000004,
115 SCAU_DISABLE_ACCOUNT = 0x00000008,
116 SCAU_FAIL_IF_EXISTS = 0x00000010,
117 SCAU_UPDATE_IF_EXISTS = 0x00000020,
118 SCAU_ALLOW_LOGON_AS_SERVICE = 0x00000040,
119 SCAU_ALLOW_LOGON_AS_BATCH = 0x00000080,
120
121 SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100,
122 SCAU_DONT_CREATE_USER = 0x00000200,
123 SCAU_NON_VITAL = 0x00000400,
124};
diff --git a/src/ext/Iis/ca/scaapppool.cpp b/src/ext/Iis/ca/scaapppool.cpp
new file mode 100644
index 00000000..781c55ca
--- /dev/null
+++ b/src/ext/Iis/ca/scaapppool.cpp
@@ -0,0 +1,594 @@
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/*------------------------------------------------------------------
6AppPool table:
7
8Column Type Nullable Example Value
9AppPool s72 No TestPool
10Name s72 No "TestPool"
11Component_ s72 No ComponentName
12Attributes i2 No 8 (APATTR_OTHERUSER)
13User_ s72 Yes UserKey
14RecycleMinutes i2 Yes 500
15RecycleRequests i2 Yes 5000
16RecycleTimes s72 Yes "1:45,13:30,22:00"
17IdleTimeout i2 Yes 15
18QueueLimit i2 Yes 500
19CPUMon s72 Yes "65,500,1" (65% CPU usage, 500 minutes, Shutdown Action)
20MaxProc i2 Yes 5
21ManagedRuntimeVersion s72 Yes "v2.0"
22ManagedPipelineMode s72 Yes "Integrated"
23
24Notes:
25RecycleTimes is a comma delimeted list of times. CPUMon is a
26comma delimeted list of the following format:
27<percent CPU usage>,<refress minutes>,<Action>. The values for
28Action are 1 (Shutdown) and 0 (No Action).
29
30------------------------------------------------------------------*/
31
32enum eAppPoolQuery { apqAppPool = 1, apqName, apqComponent, apqAttributes, apqUser, apqRecycleMinutes, apqRecycleRequests, apqRecycleTimes, apqVirtualMemory, apqPrivateMemory, apqIdleTimeout, apqQueueLimit, apqCpuMon, apqMaxProc, apqManagedRuntimeVersion, apqManagedPipelineMode, apqInstalled, apqAction };
33
34enum eComponentAttrQuery { caqComponent = 1, caqAttributes };
35
36// prototypes
37static HRESULT AppPoolExists(
38 __in IMSAdminBase* piMetabase,
39 __in LPCWSTR wzAppPool
40 );
41
42// functions
43
44void ScaAppPoolFreeList(
45 __in SCA_APPPOOL* psapList
46 )
47{
48 SCA_APPPOOL* psapDelete = psapList;
49 while (psapList)
50 {
51 psapDelete = psapList;
52 psapList = psapList->psapNext;
53
54 MemFree(psapDelete);
55 }
56}
57
58
59HRESULT ScaAppPoolRead(
60 __inout SCA_APPPOOL** ppsapList,
61 __in WCA_WRAPQUERY_HANDLE hUserQuery,
62 __inout LPWSTR *ppwzCustomActionData
63 )
64{
65 Assert(ppsapList);
66
67 HRESULT hr = S_OK;
68
69 MSIHANDLE hRec, hRecComp;
70 LPWSTR pwzData = NULL;
71 SCA_APPPOOL* psap = NULL;
72 WCA_WRAPQUERY_HANDLE hAppPoolQuery = NULL;
73 WCA_WRAPQUERY_HANDLE hComponentQuery = NULL;
74
75 hr = WcaBeginUnwrapQuery(&hAppPoolQuery, ppwzCustomActionData);
76 ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead");
77
78 if (0 == WcaGetQueryRecords(hAppPoolQuery))
79 {
80 WcaLog(LOGMSG_VERBOSE, "Skipping ScaAppPoolRead() - required table not present");
81 ExitFunction1(hr = S_FALSE);
82 }
83
84 hr = WcaBeginUnwrapQuery(&hComponentQuery, ppwzCustomActionData);
85 ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead");
86
87 // loop through all the AppPools
88 while (S_OK == (hr = WcaFetchWrappedRecord(hAppPoolQuery, &hRec)))
89 {
90 // Add this record's information into the list of things to process.
91 hr = AddAppPoolToList(ppsapList);
92 ExitOnFailure(hr, "failed to add app pool to app pool list");
93
94 psap = *ppsapList;
95
96 hr = WcaGetRecordString(hRec, apqComponent, &pwzData);
97 ExitOnFailure(hr, "failed to get AppPool.Component");
98
99 if (pwzData && *pwzData)
100 {
101 psap->fHasComponent = TRUE;
102
103 hr = ::StringCchCopyW(psap->wzComponent, countof(psap->wzComponent), pwzData);
104 ExitOnFailure(hr, "failed to copy component name: %ls", pwzData);
105
106 hr = WcaGetRecordInteger(hRec, apqInstalled, (int *)&psap->isInstalled);
107 ExitOnFailure(hr, "Failed to get Component installed state for app pool");
108
109 hr = WcaGetRecordInteger(hRec, apqAction, (int *)&psap->isAction);
110 ExitOnFailure(hr, "Failed to get Component action state for app pool");
111
112 WcaFetchWrappedReset(hComponentQuery);
113 hr = WcaFetchWrappedRecordWhereString(hComponentQuery, caqComponent, psap->wzComponent, &hRecComp);
114 ExitOnFailure(hr, "Failed to fetch Component.Attributes for Component '%ls'", psap->wzComponent);
115
116 hr = WcaGetRecordInteger(hRecComp, caqAttributes, &psap->iCompAttributes);
117 ExitOnFailure(hr, "failed to get Component.Attributes");
118 }
119
120 hr = WcaGetRecordString(hRec, apqAppPool, &pwzData);
121 ExitOnFailure(hr, "failed to get AppPool.AppPool");
122 hr = ::StringCchCopyW(psap->wzAppPool, countof(psap->wzAppPool), pwzData);
123 ExitOnFailure(hr, "failed to copy AppPool name: %ls", pwzData);
124
125 hr = WcaGetRecordString(hRec, apqName, &pwzData);
126 ExitOnFailure(hr, "failed to get AppPool.Name");
127 hr = ::StringCchCopyW(psap->wzName, countof(psap->wzName), pwzData);
128 ExitOnFailure(hr, "failed to copy app pool name: %ls", pwzData);
129 hr = ::StringCchPrintfW(psap->wzKey, countof(psap->wzKey), L"/LM/W3SVC/AppPools/%s", pwzData);
130 ExitOnFailure(hr, "failed to format app pool key name");
131
132 hr = WcaGetRecordInteger(hRec, apqAttributes, &psap->iAttributes);
133 ExitOnFailure(hr, "failed to get AppPool.Attributes");
134
135 hr = WcaGetRecordString(hRec, apqUser, &pwzData);
136 ExitOnFailure(hr, "failed to get AppPool.User");
137 hr = ScaGetUserDeferred(pwzData, hUserQuery, &psap->suUser);
138 ExitOnFailure(hr, "failed to get user: %ls", pwzData);
139
140 hr = WcaGetRecordInteger(hRec, apqRecycleRequests, &psap->iRecycleRequests);
141 ExitOnFailure(hr, "failed to get AppPool.RecycleRequests");
142
143 hr = WcaGetRecordInteger(hRec, apqRecycleMinutes, &psap->iRecycleMinutes);
144 ExitOnFailure(hr, "failed to get AppPool.Minutes");
145
146 hr = WcaGetRecordString(hRec, apqRecycleTimes, &pwzData);
147 ExitOnFailure(hr, "failed to get AppPool.RecycleTimes");
148 hr = ::StringCchCopyW(psap->wzRecycleTimes, countof(psap->wzRecycleTimes), pwzData);
149 ExitOnFailure(hr, "failed to copy recycle value: %ls", pwzData);
150
151 hr = WcaGetRecordInteger(hRec, apqVirtualMemory, &psap->iVirtualMemory);
152 ExitOnFailure(hr, "failed to get AppPool.VirtualMemory");
153
154 hr = WcaGetRecordInteger(hRec, apqPrivateMemory, &psap->iPrivateMemory);
155 ExitOnFailure(hr, "failed to get AppPool.PrivateMemory");
156
157 hr = WcaGetRecordInteger(hRec, apqIdleTimeout, &psap->iIdleTimeout);
158 ExitOnFailure(hr, "failed to get AppPool.IdleTimeout");
159
160 hr = WcaGetRecordInteger(hRec, apqQueueLimit, &psap->iQueueLimit);
161 ExitOnFailure(hr, "failed to get AppPool.QueueLimit");
162
163 hr = WcaGetRecordString(hRec, apqCpuMon, &pwzData);
164 ExitOnFailure(hr, "failed to get AppPool.CPUMon");
165 hr = ::StringCchCopyW(psap->wzCpuMon, countof(psap->wzCpuMon), pwzData);
166 ExitOnFailure(hr, "failed to copy cpu monitor value: %ls", pwzData);
167
168 hr = WcaGetRecordInteger(hRec, apqMaxProc, &psap->iMaxProcesses);
169 ExitOnFailure(hr, "failed to get AppPool.MaxProc");
170
171 hr = WcaGetRecordString(hRec, apqManagedRuntimeVersion, &pwzData);
172 ExitOnFailure(hr, "failed to get AppPool.ManagedRuntimeVersion");
173 hr = ::StringCchCopyW(psap->wzManagedRuntimeVersion, countof(psap->wzManagedRuntimeVersion), pwzData);
174 ExitOnFailure(hr, "failed to copy ManagedRuntimeVersion value: %ls", pwzData);
175
176 hr = WcaGetRecordString(hRec, apqManagedPipelineMode, &pwzData);
177 ExitOnFailure(hr, "failed to get AppPool.ManagedPipelineMode");
178 hr = ::StringCchCopyW(psap->wzManagedPipelineMode, countof(psap->wzManagedPipelineMode), pwzData);
179 ExitOnFailure(hr, "failed to copy ManagedPipelineMode value: %ls", pwzData);
180
181 }
182
183 if (E_NOMOREITEMS == hr)
184 {
185 hr = S_OK;
186 }
187 ExitOnFailure(hr, "failure while processing AppPools");
188
189LExit:
190 WcaFinishUnwrapQuery(hAppPoolQuery);
191 WcaFinishUnwrapQuery(hComponentQuery);
192
193 ReleaseStr(pwzData);
194 return hr;
195}
196
197
198HRESULT ScaFindAppPool(
199 __in IMSAdminBase* piMetabase,
200 __in LPCWSTR wzAppPool,
201 __out_ecount(cchName) LPWSTR wzName,
202 __in DWORD cchName,
203 __in SCA_APPPOOL *psapList
204 )
205{
206 Assert(piMetabase && wzAppPool && *wzAppPool && wzName && *wzName);
207
208 HRESULT hr = S_OK;
209
210 // check memory first
211 SCA_APPPOOL* psap = psapList;
212 for (; psap; psap = psap->psapNext)
213 {
214 if (0 == lstrcmpW(psap->wzAppPool, wzAppPool))
215 {
216 break;
217 }
218 }
219 ExitOnNull(psap, hr, HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Could not find the app pool: %ls", wzAppPool);
220
221 // copy the web app pool name
222 hr = ::StringCchCopyW(wzName, cchName, psap->wzName);
223 ExitOnFailure(hr, "failed to copy app pool name while finding app pool: %ls", psap->wzName);
224
225 // if it's not being installed now, check if it exists already
226 if (!psap->fHasComponent)
227 {
228 hr = AppPoolExists(piMetabase, psap->wzName);
229 ExitOnFailure(hr, "failed to check for existence of app pool: %ls", psap->wzName);
230 }
231
232LExit:
233 return hr;
234}
235
236
237static HRESULT AppPoolExists(
238 __in IMSAdminBase* piMetabase,
239 __in LPCWSTR wzAppPool
240 )
241{
242 Assert(piMetabase && wzAppPool && *wzAppPool);
243
244 HRESULT hr = S_OK;
245 WCHAR wzSubKey[METADATA_MAX_NAME_LEN];
246
247 for (DWORD dwIndex = 0; SUCCEEDED(hr); ++dwIndex)
248 {
249 hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/AppPools", wzSubKey, dwIndex);
250 if (SUCCEEDED(hr) && 0 == lstrcmpW(wzSubKey, wzAppPool))
251 {
252 hr = S_OK;
253 break;
254 }
255 }
256
257 if (E_NOMOREITEMS == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
258 {
259 hr = S_FALSE;
260 }
261
262 return hr;
263}
264
265
266HRESULT ScaAppPoolInstall(
267 __in IMSAdminBase* piMetabase,
268 __in SCA_APPPOOL* psapList
269 )
270{
271 Assert(piMetabase);
272
273 HRESULT hr = S_OK;
274
275 for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext)
276 {
277 // if we are installing the app pool
278 if (psap->fHasComponent && WcaIsInstalling(psap->isInstalled, psap->isAction))
279 {
280 hr = ScaWriteAppPool(piMetabase, psap);
281 ExitOnFailure(hr, "failed to write AppPool '%ls' to metabase", psap->wzAppPool);
282 }
283 }
284
285LExit:
286 return hr;
287}
288
289
290HRESULT ScaAppPoolUninstall(
291 __in IMSAdminBase* piMetabase,
292 __in SCA_APPPOOL* psapList
293 )
294{
295 Assert(piMetabase);
296
297 HRESULT hr = S_OK;
298
299 for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext)
300 {
301 // if we are uninstalling the app pool
302 if (psap->fHasComponent && WcaIsUninstalling(psap->isInstalled, psap->isAction))
303 {
304 hr = ScaRemoveAppPool(piMetabase, psap);
305 ExitOnFailure(hr, "Failed to remove AppPool '%ls' from metabase", psap->wzAppPool);
306 }
307 }
308
309LExit:
310 return hr;
311}
312
313
314HRESULT ScaWriteAppPool(
315 __in IMSAdminBase* piMetabase,
316 __in SCA_APPPOOL* psap
317 )
318{
319 Assert(piMetabase && psap);
320
321 HRESULT hr = S_OK;
322 DWORD dwIdentity = 0xFFFFFFFF;
323 BOOL fExists = FALSE;
324 LPWSTR pwzValue = NULL;
325 LPWSTR wz = NULL;
326
327 hr = AppPoolExists(piMetabase, psap->wzName);
328 ExitOnFailure(hr, "failed to check if app pool already exists");
329 if (S_FALSE == hr)
330 {
331 // didn't find the AppPool key, so we need to create it
332 hr = ScaCreateMetabaseKey(piMetabase, psap->wzKey, L"");
333 ExitOnFailure(hr, "failed to create AppPool key: %ls", psap->wzKey);
334
335 // mark it as an AppPool
336 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsApplicationPool");
337 ExitOnFailure(hr, "failed to mark key as AppPool key: %ls", psap->wzKey);
338
339 // TODO: Make this an Attribute?
340 // set autostart value
341 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_AUTO_START, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)1);
342 ExitOnFailure(hr, "failed to mark key as AppPool key: %ls", psap->wzKey);
343 }
344 else
345 {
346 fExists = TRUE;
347 }
348
349 //
350 // Set the AppPool Recycling Tab
351 //
352 if (MSI_NULL_INTEGER != psap->iRecycleMinutes)
353 {
354 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_TIME, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iRecycleMinutes));
355 ExitOnFailure(hr, "failed to set periodic restart time");
356 }
357
358 if (MSI_NULL_INTEGER != psap->iRecycleRequests)
359 {
360 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_REQUEST_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iRecycleRequests));
361 ExitOnFailure(hr, "failed to set periodic restart request count");
362 }
363
364 if (*psap->wzRecycleTimes)
365 {
366 // Add another NULL' onto pwz since it's a 'MULTISZ'
367 hr = StrAllocString(&pwzValue, psap->wzRecycleTimes, 0);
368 ExitOnFailure(hr, "failed to allocate string for MULTISZ");
369 hr = StrAllocConcat(&pwzValue, L"\0", 1);
370 ExitOnFailure(hr, "failed to add second null to RecycleTime multisz");
371
372 // Replace the commas with NULLs
373 wz = pwzValue;
374 while (NULL != (wz = wcschr(wz, L',')))
375 {
376 *wz = L'\0';
377 ++wz;
378 }
379
380 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_SCHEDULE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, (LPVOID)pwzValue);
381 ExitOnFailure(hr, "failed to set periodic restart schedule");
382 }
383
384 if (MSI_NULL_INTEGER != psap->iVirtualMemory)
385 {
386 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iVirtualMemory));
387 ExitOnFailure(hr, "failed to set periodic restart memory count");
388 }
389
390 if (MSI_NULL_INTEGER != psap->iPrivateMemory)
391 {
392 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_PRIVATE_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iPrivateMemory));
393 ExitOnFailure(hr, "failed to set periodic restart private memory count");
394 }
395
396
397 //
398 // Set AppPool Performance Tab
399 //
400 if (MSI_NULL_INTEGER != psap->iIdleTimeout)
401 {
402 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_IDLE_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iIdleTimeout));
403 ExitOnFailure(hr, "failed to set idle timeout value");
404 }
405
406 if (MSI_NULL_INTEGER != psap->iQueueLimit)
407 {
408 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_UL_APPPOOL_QUEUE_LENGTH, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iQueueLimit));
409 ExitOnFailure(hr, "failed to set request queue limit value");
410 }
411
412 if (*psap->wzCpuMon)
413 {
414 hr = StrAllocString(&pwzValue, psap->wzCpuMon, 0);
415 ExitOnFailure(hr, "failed to allocate CPUMonitor string");
416
417 DWORD dwPercent = 0;
418 DWORD dwRefreshMinutes = 0;
419 DWORD dwAction = 0;
420
421 dwPercent = wcstoul(pwzValue, &wz, 10);
422 if (100 < dwPercent)
423 {
424 ExitOnFailure(hr = E_INVALIDARG, "invalid maximum cpu percentage value: %d", dwPercent);
425 }
426 if (wz && L',' == *wz)
427 {
428 ++wz;
429 dwRefreshMinutes = wcstoul(wz, &wz, 10);
430 if (wz && L',' == *wz)
431 {
432 ++wz;
433 dwAction = wcstoul(wz, &wz, 10);
434 }
435 }
436
437 if (dwPercent)
438 {
439 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_LIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)(dwPercent * 1000)));
440 ExitOnFailure(hr, "failed to set CPU percentage max");
441 }
442 if (dwRefreshMinutes)
443 {
444 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_RESET_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwRefreshMinutes));
445 ExitOnFailure(hr, "failed to set refresh CPU minutes");
446 }
447 if (dwAction)
448 {
449 // 0 = No Action
450 // 1 = Shutdown
451 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_ACTION, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwAction));
452 ExitOnFailure(hr, "failed to set CPU action");
453 }
454 }
455
456 if (MSI_NULL_INTEGER != psap->iMaxProcesses)
457 {
458 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_MAX_PROCESS_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iMaxProcesses));
459 ExitOnFailure(hr, "failed to set web garden maximum worker processes");
460 }
461
462 // TODO: Health Tab if anyone wants it?
463
464 //
465 // Set the AppPool Identity tab
466 //
467 if (psap->iAttributes & APATTR_NETSERVICE)
468 {
469 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE;
470 }
471 else if (psap->iAttributes & APATTR_LOCSERVICE)
472 {
473 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE;
474 }
475 else if (psap->iAttributes & APATTR_LOCSYSTEM)
476 {
477 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM;
478 }
479 else if (psap->iAttributes & APATTR_OTHERUSER)
480 {
481 if (!*psap->suUser.wzDomain || CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzDomain, -1, L".", -1))
482 {
483 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"NetworkService", -1))
484 {
485 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE;
486 }
487 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"LocalService", -1))
488 {
489 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE;
490 }
491 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"LocalSystem", -1))
492 {
493 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM;
494 }
495 else
496 {
497 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER;
498 }
499 }
500 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzDomain, -1, L"NT AUTHORITY", -1))
501 {
502 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"NETWORK SERVICE", -1))
503 {
504 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE;
505 }
506 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"SERVICE", -1))
507 {
508 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE;
509 }
510 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"SYSTEM", -1))
511 {
512 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM;
513 }
514 else
515 {
516 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER;
517 }
518 }
519 else
520 {
521 dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER;
522 }
523 }
524
525 if (-1 != dwIdentity)
526 {
527 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_IDENTITY_TYPE, METADATA_INHERIT , IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwIdentity));
528 ExitOnFailure(hr, "failed to set app pool identity");
529
530 if (MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER == dwIdentity)
531 {
532 if (*psap->suUser.wzDomain)
533 {
534 hr = StrAllocFormatted(&pwzValue, L"%s\\%s", psap->suUser.wzDomain, psap->suUser.wzName);
535 ExitOnFailure(hr, "failed to format user name: %ls domain: %ls", psap->suUser.wzName, psap->suUser.wzDomain);
536 }
537 else
538 {
539 hr = StrAllocFormatted(&pwzValue, L"%s", psap->suUser.wzName);
540 ExitOnFailure(hr, "failed to format user name: %ls", psap->suUser.wzName);
541 }
542
543 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_WAM_USER_NAME, METADATA_INHERIT , IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pwzValue);
544 ExitOnFailure(hr, "failed to set app pool identity name");
545
546 hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_WAM_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)psap->suUser.wzPassword);
547 ExitOnFailure(hr, "failed to set app pool identity password");
548 }
549 }
550
551LExit:
552 ReleaseStr(pwzValue);
553
554 return hr;
555}
556
557
558HRESULT ScaRemoveAppPool(
559 __in IMSAdminBase* piMetabase,
560 __in SCA_APPPOOL* psap
561 )
562{
563 Assert(piMetabase && psap);
564
565 HRESULT hr = S_OK;
566
567 // simply remove the root key and everything else is pulled at the same time
568 if (0 != lstrlenW(psap->wzKey))
569 {
570 hr = ScaDeleteMetabaseKey(piMetabase, psap->wzKey, L"");
571 ExitOnFailure(hr, "failed to delete AppPool key: %ls", psap->wzKey);
572 }
573
574 // TODO: Maybe check to make sure any web sites that are using this AppPool are put back in the 'DefaultAppPool'
575
576LExit:
577 return hr;
578}
579
580
581HRESULT AddAppPoolToList(
582 __in SCA_APPPOOL** ppsapList
583 )
584{
585 HRESULT hr = S_OK;
586 SCA_APPPOOL* psap = static_cast<SCA_APPPOOL*>(MemAlloc(sizeof(SCA_APPPOOL), TRUE));
587 ExitOnNull(psap, hr, E_OUTOFMEMORY, "failed to allocate memory for new element in app pool list");
588
589 psap->psapNext = *ppsapList;
590 *ppsapList = psap;
591
592LExit:
593 return hr;
594}
diff --git a/src/ext/Iis/ca/scaapppool.h b/src/ext/Iis/ca/scaapppool.h
new file mode 100644
index 00000000..68575fcb
--- /dev/null
+++ b/src/ext/Iis/ca/scaapppool.h
@@ -0,0 +1,88 @@
1#pragma once
2// 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.
3
4
5#include "scauser.h"
6
7// Identity
8#define APATTR_NETSERVICE 0x0001 // Network Service
9#define APATTR_LOCSERVICE 0x0002 // Local Service
10#define APATTR_LOCSYSTEM 0x0004 // Local System
11#define APATTR_OTHERUSER 0x0008 // Other User
12
13struct SCA_APPPOOL
14{
15 // iis app pool configuation information
16 WCHAR wzAppPool[MAX_DARWIN_KEY + 1];
17 WCHAR wzName[METADATA_MAX_NAME_LEN + 1];
18 WCHAR wzKey[METADATA_MAX_NAME_LEN + 1];
19 WCHAR wzComponent[METADATA_MAX_NAME_LEN + 1];
20 BOOL fHasComponent;
21 INSTALLSTATE isInstalled;
22 INSTALLSTATE isAction;
23 INT iAttributes;
24
25 SCA_USER suUser;
26
27 INT iRecycleRequests;
28 INT iRecycleMinutes;
29 WCHAR wzRecycleTimes[MAX_DARWIN_KEY + 1];
30 INT iVirtualMemory;
31 INT iPrivateMemory;
32
33 INT iIdleTimeout;
34 INT iQueueLimit;
35 WCHAR wzCpuMon[MAX_DARWIN_KEY + 1];
36 INT iMaxProcesses;
37 WCHAR wzManagedPipelineMode[MAX_DARWIN_KEY + 1];
38 WCHAR wzManagedRuntimeVersion[MAX_DARWIN_KEY + 1];
39
40 int iCompAttributes;
41
42 SCA_APPPOOL *psapNext;
43};
44
45
46// prototypes
47
48HRESULT ScaAppPoolRead(
49 __inout SCA_APPPOOL** ppsapList,
50 __in WCA_WRAPQUERY_HANDLE hUserQuery,
51 __inout LPWSTR *ppwzCustomActionData
52 );
53
54void ScaAppPoolFreeList(
55 __in SCA_APPPOOL* psapList
56 );
57
58HRESULT ScaFindAppPool(
59 __in IMSAdminBase* piMetabase,
60 __in LPCWSTR wzAppPool,
61 __out_ecount(cchName) LPWSTR wzName,
62 __in DWORD cchName,
63 __in SCA_APPPOOL *psapList
64 );
65
66HRESULT ScaAppPoolInstall(
67 __in IMSAdminBase* piMetabase,
68 __in SCA_APPPOOL* psapList
69 );
70
71HRESULT ScaAppPoolUninstall(
72 __in IMSAdminBase* piMetabase,
73 __in SCA_APPPOOL* psapList
74 );
75
76HRESULT ScaWriteAppPool(
77 __in IMSAdminBase* piMetabase,
78 __in SCA_APPPOOL* psap
79 );
80
81HRESULT ScaRemoveAppPool(
82 __in IMSAdminBase* piMetabase,
83 __in SCA_APPPOOL* psap
84 );
85
86HRESULT AddAppPoolToList(
87 __in SCA_APPPOOL** ppsapList
88 );
diff --git a/src/ext/Iis/ca/scaapppool7.cpp b/src/ext/Iis/ca/scaapppool7.cpp
new file mode 100644
index 00000000..0fac4346
--- /dev/null
+++ b/src/ext/Iis/ca/scaapppool7.cpp
@@ -0,0 +1,401 @@
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 AppPoolExists(
7 __in LPCWSTR wzAppPool
8 );
9
10// functions
11HRESULT ScaFindAppPool7(
12 __in LPCWSTR wzAppPool,
13 __out_ecount(cchName) LPWSTR wzName,
14 __in DWORD cchName,
15 __in SCA_APPPOOL *psapList
16 )
17{
18 Assert(wzAppPool && *wzAppPool && wzName && *wzName);
19
20 HRESULT hr = S_OK;
21
22 // check memory first
23 SCA_APPPOOL* psap = psapList;
24 for (; psap; psap = psap->psapNext)
25 {
26 if (0 == wcscmp(psap->wzAppPool, wzAppPool))
27 {
28 break;
29 }
30 }
31 ExitOnNull(psap, hr, HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Could not find the app pool: %ls", wzAppPool);
32
33 // copy the web app pool name
34#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
35 hr = ::StringCchCopyW(wzName, cchName, psap->wzName);
36 ExitOnFailure(hr, "failed to copy app pool name while finding app pool: %ls", psap->wzName);
37
38 // if it's not being installed now, check if it exists already
39 if (!psap->fHasComponent)
40 {
41 hr = AppPoolExists(psap->wzName);
42 ExitOnFailure(hr, "failed to check for existence of app pool: %ls", psap->wzName);
43 }
44
45LExit:
46 return hr;
47}
48
49
50static HRESULT AppPoolExists(
51 __in LPCWSTR /*wzAppPool*/
52 )
53{
54 HRESULT hr = S_OK;
55
56 //this function checks for existance of app pool in IIS7 config
57 //at schedule time, we will defer this to execute time.
58
59 return hr;
60}
61
62
63HRESULT ScaAppPoolInstall7(
64 __in SCA_APPPOOL* psapList
65 )
66{
67 HRESULT hr = S_OK;
68
69 for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext)
70 {
71 // if we are installing the app pool
72 if (psap->fHasComponent && WcaIsInstalling(psap->isInstalled, psap->isAction))
73 {
74 hr = ScaWriteAppPool7(psap);
75 ExitOnFailure(hr, "failed to write AppPool '%ls' to metabase", psap->wzAppPool);
76 }
77 }
78
79LExit:
80 return hr;
81}
82
83
84HRESULT ScaAppPoolUninstall7(
85 __in SCA_APPPOOL* psapList
86 )
87{
88
89 HRESULT hr = S_OK;
90
91 for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext)
92 {
93 // if we are uninstalling the app pool
94 if (psap->fHasComponent && WcaIsUninstalling(psap->isInstalled, psap->isAction))
95 {
96 hr = ScaRemoveAppPool7(psap);
97 ExitOnFailure(hr, "Failed to remove AppPool '%ls' from metabase", psap->wzAppPool);
98 }
99 }
100
101LExit:
102 return hr;
103}
104
105
106HRESULT ScaWriteAppPool7(
107 __in const SCA_APPPOOL* psap
108 )
109{
110 Assert(psap);
111
112 HRESULT hr = S_OK;
113 DWORD dwIdentity = 0xFFFFFFFF;
114 LPWSTR pwzValue = NULL;
115 LPWSTR wz = NULL;
116
117 //create the app pool
118 hr = ScaWriteConfigID(IIS_APPPOOL);
119 ExitOnFailure(hr, "failed to write AppPool key.");
120
121 hr = ScaWriteConfigID(IIS_CREATE);
122 ExitOnFailure(hr, "failed to write AppPool create action.");
123
124 hr = ScaWriteConfigString(psap->wzName);
125 ExitOnFailure(hr, "failed to write AppPool name: %ls", psap->wzName);
126
127 // Now do all the optional stuff
128
129 // Set the AppPool Recycling Tab
130 if (MSI_NULL_INTEGER != psap->iRecycleMinutes)
131 {
132 hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_MIN);
133 ExitOnFailure(hr, "failed to set periodic restart time id");
134 hr = ScaWriteConfigInteger(psap->iRecycleMinutes);
135 ExitOnFailure(hr, "failed to set periodic restart time");
136 }
137
138 if (MSI_NULL_INTEGER != psap->iRecycleRequests)
139 {
140 hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_REQ);
141 ExitOnFailure(hr, "failed to set periodic restart request count id");
142 hr = ScaWriteConfigInteger(psap->iRecycleRequests);
143 ExitOnFailure(hr, "failed to set periodic restart request count");
144 }
145
146 if (*psap->wzRecycleTimes)
147 {
148 hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_TIMES);
149 ExitOnFailure(hr, "failed to set periodic restart schedule id");
150 hr = ScaWriteConfigString(psap->wzRecycleTimes);
151 ExitOnFailure(hr, "failed to set periodic restart schedule");
152 }
153
154 if (MSI_NULL_INTEGER != psap->iVirtualMemory)
155 {
156 hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_VIRMEM);
157 ExitOnFailure(hr, "failed to set periodic restart memory count id");
158 hr = ScaWriteConfigInteger(psap->iVirtualMemory);
159 ExitOnFailure(hr, "failed to set periodic restart memory count");
160 }
161
162 if (MSI_NULL_INTEGER != psap->iPrivateMemory)
163 {
164 hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_PRIVMEM);
165 ExitOnFailure(hr, "failed to set periodic restart private memory count id");
166 hr = ScaWriteConfigInteger(psap->iPrivateMemory);
167 ExitOnFailure(hr, "failed to set periodic restart private memory count");
168 }
169
170 // Set AppPool Performance Tab
171 if (MSI_NULL_INTEGER != psap->iIdleTimeout)
172 {
173 hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_IDLTIMEOUT);
174 ExitOnFailure(hr, "failed to set idle timeout value id");
175 hr = ScaWriteConfigInteger(psap->iIdleTimeout);
176 ExitOnFailure(hr, "failed to set idle timeout value");
177 }
178
179 if (MSI_NULL_INTEGER != psap->iQueueLimit)
180 {
181 hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_QUEUELIMIT);
182 ExitOnFailure(hr, "failed to set request queue limit value id");
183 hr = ScaWriteConfigInteger(psap->iQueueLimit);
184 ExitOnFailure(hr, "failed to set request queue limit value");
185 }
186 if (*psap->wzCpuMon)
187 {
188#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
189 hr = ::StrAllocString(&pwzValue, psap->wzCpuMon, 0);
190 ExitOnFailure(hr, "failed to allocate CPUMonitor string");
191
192 DWORD dwPercent = 0;
193 DWORD dwRefreshMinutes = 0;
194 DWORD dwAction = 0;
195
196 dwPercent = wcstoul(pwzValue, &wz, 10);
197 if (100 < dwPercent)
198 {
199 ExitOnFailure(hr = E_INVALIDARG, "invalid maximum cpu percentage value: %d", dwPercent);
200 }
201 if (wz && L',' == *wz)
202 {
203 ++wz;
204 dwRefreshMinutes = wcstoul(wz, &wz, 10);
205 if (wz && L',' == *wz)
206 {
207 ++wz;
208 dwAction = wcstoul(wz, &wz, 10);
209 }
210 }
211 if (dwPercent)
212 {
213 hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_CPU_PCT);
214 ExitOnFailure(hr, "failed to set recycle pct id");
215 hr = ScaWriteConfigInteger(dwPercent);
216 ExitOnFailure(hr, "failed to set CPU percentage max");
217 }
218 if (dwRefreshMinutes)
219 {
220 hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_CPU_REFRESH);
221 ExitOnFailure(hr, "failed to set recycle refresh id");
222 hr = ScaWriteConfigInteger(dwRefreshMinutes);
223 ExitOnFailure(hr, "failed to set refresh CPU minutes");
224 }
225 if (dwAction)
226 {
227 // 0 = No Action
228 // 1 = Shutdown
229 hr = ScaWriteConfigID(IIS_APPPOOL_RECYCLE_CPU_ACTION);
230 ExitOnFailure(hr, "failed to set recycle refresh id");
231 hr = ScaWriteConfigInteger(dwAction);
232 ExitOnFailure(hr, "failed to set CPU action");
233 }
234 }
235
236 if (MSI_NULL_INTEGER != psap->iMaxProcesses)
237 {
238 hr = ScaWriteConfigID(IIS_APPPOOL_MAXPROCESS);
239 ExitOnFailure(hr, "Failed to write max processes config ID");
240
241 hr = ScaWriteConfigInteger(psap->iMaxProcesses);
242 ExitOnFailure(hr, "failed to set web garden maximum worker processes");
243 }
244
245 hr = ScaWriteConfigID(IIS_APPPOOL_32BIT);
246 ExitOnFailure(hr, "Failed to write 32 bit app pool config ID");
247 hr = ScaWriteConfigInteger(psap->iCompAttributes & msidbComponentAttributes64bit ? 0 : 1);
248 ExitOnFailure(hr, "Failed to write 32 bit app pool config value");
249
250 //
251 // Set the AppPool Identity tab
252 //
253 if (psap->iAttributes & APATTR_APPPOOLIDENTITY)
254 {
255 dwIdentity = 4;
256 }
257 else if (psap->iAttributes & APATTR_NETSERVICE)
258 {
259 dwIdentity = 2;
260 }
261 else if (psap->iAttributes & APATTR_LOCSERVICE)
262 {
263 dwIdentity = 1;
264 }
265 else if (psap->iAttributes & APATTR_LOCSYSTEM)
266 {
267 dwIdentity = 0;
268 }
269 else if (psap->iAttributes & APATTR_OTHERUSER)
270 {
271 if (!*psap->suUser.wzDomain || 0 == _wcsicmp(psap->suUser.wzDomain, L"."))
272 {
273 if (0 == _wcsicmp(psap->suUser.wzName, L"NetworkService"))
274 {
275 dwIdentity = 2;
276 }
277 else if (0 == _wcsicmp(psap->suUser.wzName, L"LocalService"))
278 {
279 dwIdentity = 1;
280 }
281 else if (0 == _wcsicmp(psap->suUser.wzName, L"LocalSystem"))
282 {
283 dwIdentity = 0;
284 }
285 else
286 {
287 dwIdentity = 3;
288 }
289 }
290 else if (0 == _wcsicmp(psap->suUser.wzDomain, L"NT AUTHORITY"))
291 {
292 if (0 == _wcsicmp(psap->suUser.wzName, L"NETWORK SERVICE"))
293 {
294 dwIdentity = 2;
295 }
296 else if (0 == _wcsicmp(psap->suUser.wzName, L"SERVICE"))
297 {
298 dwIdentity = 1;
299 }
300 else if (0 == _wcsicmp(psap->suUser.wzName, L"SYSTEM"))
301 {
302 dwIdentity = 0;
303 }
304 else
305 {
306 dwIdentity = 3;
307 }
308 }
309 else
310 {
311 dwIdentity = 3;
312 }
313 }
314
315 if (-1 != dwIdentity)
316 {
317 hr = ScaWriteConfigID(IIS_APPPOOL_IDENTITY);
318 ExitOnFailure(hr, "failed to set app pool identity id");
319 hr = ScaWriteConfigInteger(dwIdentity);
320 ExitOnFailure(hr, "failed to set app pool identity");
321
322 if (3 == dwIdentity)
323 {
324 if (*psap->suUser.wzDomain)
325 {
326 hr = StrAllocFormatted(&pwzValue, L"%s\\%s", psap->suUser.wzDomain, psap->suUser.wzName);
327 ExitOnFailure(hr, "failed to format user name: %ls domain: %ls", psap->suUser.wzName, psap->suUser.wzDomain);
328 }
329 else
330 {
331 hr = StrAllocFormatted(&pwzValue, L"%s", psap->suUser.wzName);
332 ExitOnFailure(hr, "failed to format user name: %ls", psap->suUser.wzName);
333 }
334
335 hr = ScaWriteConfigID(IIS_APPPOOL_USER);
336 ExitOnFailure(hr, "failed to set app pool identity name id");
337 hr = ScaWriteConfigString(pwzValue);
338 ExitOnFailure(hr, "failed to set app pool identity name");
339
340 hr = ScaWriteConfigID(IIS_APPPOOL_PWD);
341 ExitOnFailure(hr, "failed to set app pool identity password id");
342 hr = ScaWriteConfigString(psap->suUser.wzPassword);
343 ExitOnFailure(hr, "failed to set app pool identity password");
344 }
345 }
346
347 if (*psap->wzManagedPipelineMode)
348 {
349 hr = ScaWriteConfigID(IIS_APPPOOL_MANAGED_PIPELINE_MODE);
350 ExitOnFailure(hr, "failed to set app pool integrated mode");
351 hr = ScaWriteConfigString(psap->wzManagedPipelineMode);
352 ExitOnFailure(hr, "failed to set app pool managed pipeline mode value");
353 }
354
355 if (*psap->wzManagedRuntimeVersion)
356 {
357 hr = ScaWriteConfigID(IIS_APPPOOL_MANAGED_RUNTIME_VERSION);
358 ExitOnFailure(hr, "failed to set app pool managed runtime version mode");
359 hr = ScaWriteConfigString(psap->wzManagedRuntimeVersion);
360 ExitOnFailure(hr, "failed to set app pool managed runtime version value");
361 }
362
363 //
364 //The number of properties above is variable so we put an end tag in so the
365 //execute CA will know when to stop looking for AppPool properties
366 //
367 hr = ScaWriteConfigID(IIS_APPPOOL_END);
368 ExitOnFailure(hr, "failed to set app pool end of properties id");
369
370LExit:
371 ReleaseStr(pwzValue);
372
373 return hr;
374}
375
376
377HRESULT ScaRemoveAppPool7(
378 __in const SCA_APPPOOL* psap
379 )
380{
381 Assert(psap);
382
383 HRESULT hr = S_OK;
384
385 //do not delete the default App Pool
386 if (0 != _wcsicmp(psap->wzAppPool, L"DefaultAppPool"))
387 {
388 //delete the app pool
389 hr = ScaWriteConfigID(IIS_APPPOOL);
390 ExitOnFailure(hr, "failed to write AppPool key.");
391
392 hr = ScaWriteConfigID(IIS_DELETE);
393 ExitOnFailure(hr, "failed to write AppPool delete action.");
394
395 hr = ScaWriteConfigString(psap->wzName);
396 ExitOnFailure(hr, "failed to delete AppPool: %ls", psap->wzName);
397 }
398
399LExit:
400 return hr;
401}
diff --git a/src/ext/Iis/ca/scaapppool7.h b/src/ext/Iis/ca/scaapppool7.h
new file mode 100644
index 00000000..1f49d899
--- /dev/null
+++ b/src/ext/Iis/ca/scaapppool7.h
@@ -0,0 +1,36 @@
1#pragma once
2// 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.
3
4
5#include "scauser.h"
6
7// Identity
8#define APATTR_NETSERVICE 0x0001 // Network Service
9#define APATTR_LOCSERVICE 0x0002 // Local Service
10#define APATTR_LOCSYSTEM 0x0004 // Local System
11#define APATTR_OTHERUSER 0x0008 // Other User
12#define APATTR_APPPOOLIDENTITY 0x0010 // ApplicationPoolIdentity
13
14// prototypes
15HRESULT ScaFindAppPool7(
16 __in LPCWSTR wzAppPool,
17 __out_ecount(cchName) LPWSTR wzName,
18 __in DWORD cchName,
19 __in SCA_APPPOOL *psapList
20 );
21
22HRESULT ScaAppPoolInstall7(
23 __in SCA_APPPOOL* psapList
24 );
25
26HRESULT ScaAppPoolUninstall7(
27 __in SCA_APPPOOL* psapList
28 );
29
30HRESULT ScaWriteAppPool7(
31 __in const SCA_APPPOOL* psap
32 );
33
34HRESULT ScaRemoveAppPool7(
35 __in const SCA_APPPOOL* psap
36 );
diff --git a/src/ext/Iis/ca/scacert.cpp b/src/ext/Iis/ca/scacert.cpp
new file mode 100644
index 00000000..5eae905a
--- /dev/null
+++ b/src/ext/Iis/ca/scacert.cpp
@@ -0,0 +1,1482 @@
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 ConfigureCertificates(
7 __in SCA_ACTION saAction
8 );
9
10static LPCWSTR StoreMapping(
11 __in int iStore
12 );
13
14static HRESULT FindExistingCertificate(
15 __in LPCWSTR wzName,
16 __in DWORD dwStoreLocation,
17 __in LPCWSTR wzStore,
18 __out BYTE** prgbCertificate,
19 __out DWORD* pcbCertificate
20 );
21
22static HRESULT ResolveCertificate(
23 __in LPCWSTR wzId,
24 __in LPCWSTR wzName,
25 __in DWORD dwStoreLocation,
26 __in LPCWSTR wzStoreName,
27 __in DWORD dwAttributess,
28 __in LPCWSTR wzData,
29 __in LPCWSTR wzPFXPassword,
30 __out BYTE** ppbCertificate,
31 __out DWORD* pcbCertificate
32 );
33
34static HRESULT ReadCertificateFile(
35 __in LPCWSTR wzPath,
36 __out BYTE** prgbData,
37 __out DWORD* pcbData
38 );
39
40static HRESULT CertificateToHash(
41 __in BYTE* pbCertificate,
42 __in DWORD cbCertificate,
43 __in DWORD dwStoreLocation,
44 __in LPCWSTR wzPFXPassword,
45 __in BYTE rgbHash[],
46 __in DWORD cbHash
47 );
48
49/*
50HRESULT ScaGetCertificateByPath(LPCWSTR pwzName, BOOL fIsInstalling,
51 BOOL fIsUninstalling, INT iStore,
52 INT iStoreLocation, LPCWSTR wzSslCertificate,
53 LPCWSTR wzPFXPassword, BSTR* pbstrCertificate,
54 DWORD* pcbCertificate, BYTE* pbaHashBuffer);
55
56HRESULT ScaGetCertificateByRequest(LPCWSTR pwzName, BOOL fIsInstalling,
57 BOOL fIsUninstalling, INT iStore,
58 INT iStoreLocation, LPCWSTR wzDistinguishedName,
59 LPCWSTR wzCA, BSTR* pbstrCertificate,
60 DWORD* pcbCertificate, BYTE* pbaHashBuffer);
61
62HRESULT ScaSslNewCertificate(LPCWSTR pwzName, INT iStore,
63 INT iStoreLocation, LPCWSTR wzComputerName,
64 LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthorityOrig,
65 BSTR* pbstrCertificate, DWORD* pcbCertificate,
66 BYTE* pbaHashBuffer);
67
68HRESULT ScaSslExistingCertificateByName(LPCWSTR pwzName, INT iStore,
69 INT iStoreLocation, BSTR* pbstrCertificate,
70 DWORD* pcbCertificate, BYTE* pbaHashBuffer);
71
72HRESULT ScaSslExistingCertificateByBinaryData(INT iStore, INT iStoreLocation,
73 BYTE* pwzData, DWORD cchData);
74
75HRESULT CreateEnroll(ICEnroll2 **hEnroll, INT iStore,
76 INT iStoreLocation);
77
78HRESULT RequestCertificate(LPCWSTR pwzName, INT iStore,
79 INT iStoreLocation, LPCWSTR wzComputerName,
80 LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthority,
81 BSTR *pbstrCertificate);
82
83VOID ParseCertificateAuthority(__in LPCWSTR wzCertificateAuthorityOrig, __out LPWSTR *pwzBuffer,
84 __out LPWSTR **hwzCAArray, __out int *piCAArray);
85*/
86
87
88LPCWSTR vcsCertQuery = L"SELECT `Certificate`, `Name`, `Component_`, `StoreLocation`, `StoreName`, `Attributes`, `Binary_`, `CertificatePath`, `PFXPassword` FROM `Certificate`";
89enum eCertQuery { cqCertificate = 1, cqName, cqComponent, cqStoreLocation, cqStoreName, cqAttributes, cqCertificateBinary, cqCertificatePath, cqPFXPassword };
90
91
92/********************************************************************
93InstallCertificates - CUSTOM ACTION ENTRY POINT for installing
94 certificates
95
96********************************************************************/
97extern "C" UINT __stdcall InstallCertificates(
98 __in MSIHANDLE hInstall
99 )
100{
101 HRESULT hr = S_OK;
102 UINT er = ERROR_SUCCESS;
103
104 // initialize
105 hr = WcaInitialize(hInstall, "InstallCertificates");
106 ExitOnFailure(hr, "Failed to initialize");
107
108 hr = ConfigureCertificates(SCA_ACTION_INSTALL);
109
110LExit:
111 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
112 return WcaFinalize(er);
113}
114
115
116/********************************************************************
117UninstallCertificates - CUSTOM ACTION ENTRY POINT for uninstalling
118 certificates
119
120********************************************************************/
121extern "C" UINT __stdcall UninstallCertificates(
122 __in MSIHANDLE hInstall
123 )
124{
125 HRESULT hr = S_OK;
126 UINT er = ERROR_SUCCESS;
127
128 // initialize
129 hr = WcaInitialize(hInstall, "UninstallCertificates");
130 ExitOnFailure(hr, "Failed to initialize");
131
132 hr = ConfigureCertificates(SCA_ACTION_UNINSTALL);
133
134LExit:
135 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
136 return WcaFinalize(er);
137}
138
139
140static HRESULT ConfigureCertificates(
141 __in SCA_ACTION saAction
142 )
143{
144 //AssertSz(FALSE, "debug ConfigureCertificates().");
145
146 HRESULT hr = S_OK;
147 DWORD er = ERROR_SUCCESS;
148
149 PMSIHANDLE hViewCertificate;
150 PMSIHANDLE hRecCertificate;
151 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
152 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
153
154 WCHAR* pwzId = NULL;
155 WCHAR* pwzName = NULL;
156 WCHAR* pwzComponent = NULL;
157 int iData = 0;
158 DWORD dwStoreLocation = 0;
159 LPWSTR pwzStoreName = 0;
160 DWORD dwAttributes = 0;
161 WCHAR* pwzData = NULL;
162 WCHAR* pwzPFXPassword = NULL;
163 WCHAR* pwzCaData = NULL;
164 WCHAR* pwzRollbackCaData = NULL;
165
166 BYTE* pbCertificate = NULL;
167 DWORD cbCertificate = 0;
168 DWORD_PTR cbPFXPassword = 0;
169
170 // Bail quickly if the Certificate table isn't around.
171 if (S_OK != WcaTableExists(L"Certificate"))
172 {
173 WcaLog(LOGMSG_VERBOSE, "Skipping ConfigureCertificates() - required table not present.");
174 ExitFunction1(hr = S_FALSE);
175 }
176
177 // Process the Certificate table.
178 hr = WcaOpenExecuteView(vcsCertQuery, &hViewCertificate);
179 ExitOnFailure(hr, "failed to open view on Certificate table");
180
181 while (SUCCEEDED(hr = WcaFetchRecord(hViewCertificate, &hRecCertificate)))
182 {
183 hr = WcaGetRecordString(hRecCertificate, cqCertificate, &pwzId); // the id is just useful to have up front
184 ExitOnFailure(hr, "failed to get Certificate.Certificate");
185
186 hr = WcaGetRecordString(hRecCertificate, cqComponent, &pwzComponent);
187 ExitOnFailure(hr, "failed to get Certificate.Component_");
188
189 er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction);
190 hr = HRESULT_FROM_WIN32(er);
191 ExitOnFailure(hr, "failed to get state for component: %ls", pwzComponent);
192
193 if (!(WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL == saAction) &&
194 !(WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL == saAction) &&
195 !(WcaIsReInstalling(isInstalled, isAction)))
196 {
197 WcaLog(LOGMSG_VERBOSE, "Skipping non-action certificate: %ls", pwzId);
198 continue;
199 }
200
201 // extract the rest of the data from the Certificate table
202 hr = WcaGetRecordFormattedString(hRecCertificate, cqName, &pwzName);
203 ExitOnFailure(hr, "failed to get Certificate.Name");
204
205 hr = WcaGetRecordInteger(hRecCertificate, cqStoreLocation, &iData);
206 ExitOnFailure(hr, "failed to get Certificate.StoreLocation");
207
208 switch (iData)
209 {
210 case SCA_CERTSYSTEMSTORE_CURRENTUSER:
211 dwStoreLocation = CERT_SYSTEM_STORE_CURRENT_USER;
212 break;
213 case SCA_CERTSYSTEMSTORE_LOCALMACHINE:
214 dwStoreLocation = CERT_SYSTEM_STORE_LOCAL_MACHINE;
215 break;
216 default:
217 hr = E_INVALIDARG;
218 ExitOnFailure(hr, "Invalid store location value: %d", iData);
219 }
220
221 hr = WcaGetRecordString(hRecCertificate, cqStoreName, &pwzStoreName);
222 ExitOnFailure(hr, "failed to get Certificate.StoreName");
223
224 hr = WcaGetRecordInteger(hRecCertificate, cqAttributes, reinterpret_cast<int*>(&dwAttributes));
225 ExitOnFailure(hr, "failed to get Certificate.Attributes");
226
227 if (dwAttributes & SCA_CERT_ATTRIBUTE_BINARYDATA)
228 {
229 hr = WcaGetRecordString(hRecCertificate, cqCertificateBinary, &pwzData);
230 ExitOnFailure(hr, "failed to get Certificate.Binary_");
231 }
232 else
233 {
234 hr = WcaGetRecordFormattedString(hRecCertificate, cqCertificatePath, &pwzData);
235 ExitOnFailure(hr, "failed to get Certificate.CertificatePath");
236 }
237
238 hr = WcaGetRecordFormattedString(hRecCertificate, cqPFXPassword, &pwzPFXPassword);
239 ExitOnFailure(hr, "failed to get Certificate.PFXPassword");
240
241 // Write the common data (for both install and uninstall) to the CustomActionData
242 // to pass data to the deferred CustomAction.
243 hr = StrAllocString(&pwzCaData, pwzName, 0);
244 ExitOnFailure(hr, "Failed to pass Certificate.Certificate to deferred CustomAction.");
245 hr = WcaWriteStringToCaData(pwzStoreName, &pwzCaData);
246 ExitOnFailure(hr, "Failed to pass Certificate.StoreName to deferred CustomAction.");
247 hr = WcaWriteIntegerToCaData(dwAttributes, &pwzCaData);
248 ExitOnFailure(hr, "Failed to pass Certificate.Attributes to deferred CustomAction.");
249
250 // Copy the rollback data from the deferred data because it's the same up to this point.
251 hr = StrAllocString(&pwzRollbackCaData, pwzCaData, 0);
252 ExitOnFailure(hr, "Failed to allocate string for rollback CustomAction.");
253
254 // Finally, schedule the correct deferred CustomAction to actually do work.
255 LPCWSTR wzAction = NULL;
256 LPCWSTR wzRollbackAction = NULL;
257 DWORD dwCost = 0;
258 if (SCA_ACTION_UNINSTALL == saAction)
259 {
260 // Find an existing certificate one (if there is one) to so we have it for rollback.
261 hr = FindExistingCertificate(pwzName, dwStoreLocation, pwzStoreName, &pbCertificate, &cbCertificate);
262 ExitOnFailure(hr, "Failed to search for existing certificate with friendly name: %ls", pwzName);
263
264 if (pbCertificate)
265 {
266 hr = WcaWriteStreamToCaData(pbCertificate, cbCertificate, &pwzRollbackCaData);
267 ExitOnFailure(hr, "Failed to pass Certificate.Data to rollback CustomAction.");
268
269 hr = WcaWriteStringToCaData(pwzPFXPassword, &pwzRollbackCaData);
270 ExitOnFailure(hr, "Failed to pass Certificate.PFXPassword to rollback CustomAction.");
271
272 hr = WcaWriteIntegerToCaData(dwAttributes, &pwzCaData);
273 ExitOnFailure(hr, "Failed to pass Certificate.Attributes to deferred CustomAction.");
274 }
275
276 // Pick the right action to run based on what store we're uninstalling from.
277 if (CERT_SYSTEM_STORE_LOCAL_MACHINE == dwStoreLocation)
278 {
279 wzAction = CUSTOM_ACTION_DECORATION(L"DeleteMachineCertificate");
280 if (pbCertificate)
281 {
282 wzRollbackAction = L"RollbackDeleteMachineCertificate";
283 }
284 }
285 else
286 {
287 wzAction = CUSTOM_ACTION_DECORATION(L"DeleteUserCertificate");
288 if (pbCertificate)
289 {
290 wzRollbackAction = L"RollbackDeleteUserCertificate";
291 }
292 }
293 dwCost = COST_CERT_DELETE;
294 }
295 else
296 {
297 // Actually get the certificate, resolve it to a blob, and get the blob's hash.
298 hr = ResolveCertificate(pwzId, pwzName, dwStoreLocation, pwzStoreName, dwAttributes, pwzData, pwzPFXPassword, &pbCertificate, &cbCertificate);
299 ExitOnFailure(hr, "Failed to resolve certificate: %ls", pwzId);
300
301 hr = WcaWriteStreamToCaData(pbCertificate, cbCertificate, &pwzCaData);
302 ExitOnFailure(hr, "Failed to pass Certificate.Data to deferred CustomAction.");
303
304 hr = WcaWriteStringToCaData(pwzPFXPassword, &pwzCaData);
305 ExitOnFailure(hr, "Failed to pass Certificate.PFXPassword to deferred CustomAction.");
306
307 // Pick the right action to run based on what store we're installing into.
308 if (CERT_SYSTEM_STORE_LOCAL_MACHINE == dwStoreLocation)
309 {
310 wzAction = CUSTOM_ACTION_DECORATION(L"AddMachineCertificate");
311 wzRollbackAction = CUSTOM_ACTION_DECORATION(L"RollbackAddMachineCertificate");
312 }
313 else
314 {
315 wzAction = CUSTOM_ACTION_DECORATION(L"AddUserCertificate");
316 wzRollbackAction = CUSTOM_ACTION_DECORATION(L"RollbackAddUserCertificate");
317 }
318 dwCost = COST_CERT_ADD;
319 }
320
321 if (wzRollbackAction)
322 {
323 hr = WcaDoDeferredAction(wzRollbackAction, pwzRollbackCaData, dwCost);
324 ExitOnFailure(hr, "Failed to schedule rollback certificate action '%ls' for: %ls", wzRollbackAction, pwzId);
325 }
326
327 hr = WcaDoDeferredAction(wzAction, pwzCaData, dwCost);
328 ExitOnFailure(hr, "Failed to schedule certificate action '%ls' for: %ls", wzAction, pwzId);
329
330 // Clean up for the next certificate.
331 ReleaseNullMem(pbCertificate);
332 }
333
334 if (E_NOMOREITEMS == hr)
335 {
336 hr = S_OK;
337 }
338
339LExit:
340 if (NULL != pwzPFXPassword && SUCCEEDED(StrSize(pwzPFXPassword, &cbPFXPassword)))
341 {
342 SecureZeroMemory(pwzPFXPassword, cbPFXPassword);
343 }
344
345 ReleaseMem(pbCertificate);
346 ReleaseStr(pwzCaData);
347 ReleaseStr(pwzPFXPassword);
348 ReleaseStr(pwzData);
349 ReleaseStr(pwzName);
350 ReleaseStr(pwzStoreName);
351 ReleaseStr(pwzComponent);
352 ReleaseStr(pwzId);
353
354 return hr;
355}
356
357
358static HRESULT ResolveCertificate(
359 __in LPCWSTR wzId,
360 __in LPCWSTR /*wzName*/,
361 __in DWORD dwStoreLocation,
362 __in LPCWSTR /*wzStoreName*/,
363 __in DWORD dwAttributes,
364 __in LPCWSTR wzData,
365 __in LPCWSTR wzPFXPassword,
366 __out BYTE** ppbCertificate,
367 __out DWORD* pcbCertificate
368 )
369{
370 HRESULT hr = S_OK;
371
372 LPWSTR pwzSql = NULL;
373 PMSIHANDLE hView;
374 PMSIHANDLE hRec;
375 MSIHANDLE hCertificateHashView = NULL;
376 MSIHANDLE hCertificateHashColumns = NULL;
377
378 BYTE rgbCertificateHash[CB_CERTIFICATE_HASH] = { 0 };
379 WCHAR wzEncodedCertificateHash[CB_CERTIFICATE_HASH * 2 + 1] = { 0 };
380
381 PMSIHANDLE hViewCertificateRequest, hRecCertificateRequest;
382
383 WCHAR* pwzDistinguishedName = NULL;
384 WCHAR* pwzCA = NULL;
385
386 BYTE* pbData = NULL;
387 DWORD cbData = 0;
388
389 if (dwAttributes & SCA_CERT_ATTRIBUTE_REQUEST)
390 {
391 hr = E_NOTIMPL;
392 ExitOnFailure(hr, "Installing certificates by requesting them from a certificate authority is not currently supported");
393 //if (dwAttributes & SCA_CERT_ATTRIBUTE_OVERWRITE)
394 //{
395 // // try to overwrite with the patch to a cert file
396 // WcaLog(LOGMSG_VERBOSE, "ConfigureCertificates - Overwrite with SSLCERTIFICATE");
397 // hr = ScaGetCertificateByPath(pwzName, fIsInstalling, fIsUninstalling,
398 // iStore, iStoreLocation, pwzData, wzPFXPassword, pbstrCertificate, pcbCertificate, pbaHashBuffer);
399 //}
400 //if (hr != S_OK)
401 //{
402 // if (fIsUninstalling && !fIsInstalling)
403 // {
404 // // for uninstall, we just want to find the existing certificate
405 // hr = ScaSslExistingCertificateByName(pwzName, iStore, iStoreLocation, pbstrCertificate, pcbCertificate, pbaHashBuffer);
406 // ExitOnFailure(hr, "Failed Retrieving existing certificate during uninstall");
407 // // ok if no existing cert
408 // if (S_OK != hr)
409 // hr = S_OK;
410 // }
411 // else
412 // {
413 // // still no certificate
414 // // user has request this certificate, try to locate DistinguishedName and CA
415 // hr = WcaTableExists(L"CertificateRequest");
416 // ExitOnFailure(hr, "CertificateRequest is referenced but not found");
417 // WcaLog(LOGMSG_VERBOSE, "ConfigureCertificates - CertificateRequest table present");
418 // cchSQLView = 255 + lstrlenW(pwzName);
419 // pwzSQLView = new WCHAR[cchSQLView];
420 // if (pwzSQLView)
421 // {
422 // hr = ::StringCchPrintfW(pwzSQLView, cchSQLView, L"SELECT `DistinguishedName`, `CA` FROM `CertificateRequest` WHERE `Certificate_`=\'%s\'", pwzName);
423 // ExitOnFailure(hr, "::StringCchPrintfW failed");
424 // hr = WcaOpenExecuteView(pwzSQLView, &hViewCertificateRequest);
425 // ExitOnFailure(hr, "failed to open view on CertificateRequest table");
426 // hr = WcaFetchSingleRecord(hViewCertificateRequest, &hRecCertificateRequest);
427 // ExitOnFailure(hr, "failed to retrieve request from CertificateRequest table");
428 // hr = WcaGetRecordString(hRecCertificateRequest, 1, &pwzDistinguishedName);
429 // ExitOnFailure(hr, "failed to get DistinguishedName");
430 // hr = WcaGetRecordString(hRecCertificateRequest, 2, &pwzCA);
431 // ExitOnFailure(hr, "failed to get CA");
432 // if (pwzDistinguishedName && pwzCA && *pwzDistinguishedName && *pwzCA)
433 // {
434 // hr = ScaGetCertificateByRequest(pwzName, fIsInstalling, fIsUninstalling, iStore, iStoreLocation, pwzDistinguishedName, pwzCA, pbstrCertificate, pcbCertificate, pbaHashBuffer);
435 // }
436 // else
437 // {
438 // hr = E_FAIL;
439 // ExitOnFailure(hr, "CertificateRequest entry is empty");
440 // }
441 // }
442 // else
443 // {
444 // hr = E_FAIL;
445 // ExitOnFailure(hr, "Out of memory");
446 // }
447 // }
448 //}
449 }
450 else if (dwAttributes & SCA_CERT_ATTRIBUTE_BINARYDATA)
451 {
452 // get the binary stream in Binary
453 hr = WcaTableExists(L"Binary");
454 if (S_OK != hr)
455 {
456 if (SUCCEEDED(hr))
457 {
458 hr = E_UNEXPECTED;
459 }
460 ExitOnFailure(hr, "Binary was referenced but there is no Binary table.");
461 }
462
463 hr = StrAllocFormatted(&pwzSql, L"SELECT `Data` FROM `Binary` WHERE `Name`=\'%s\'", wzData);
464 ExitOnFailure(hr, "Failed to allocate Binary table query.");
465
466 hr = WcaOpenExecuteView(pwzSql, &hView);
467 ExitOnFailure(hr, "Failed to open view on Binary table");
468
469 hr = WcaFetchSingleRecord(hView, &hRec);
470 ExitOnFailure(hr, "Failed to retrieve request from Binary table");
471
472 hr = WcaGetRecordStream(hRec, 1, &pbData, &cbData);
473 ExitOnFailure(hr, "Failed to ready Binary.Data for certificate.");
474 }
475 else if (dwAttributes == SCA_CERT_ATTRIBUTE_DEFAULT)
476 {
477 hr = ReadCertificateFile(wzData, &pbData, &cbData);
478 ExitOnFailure(hr, "Failed to read certificate from file path.");
479 }
480 else
481 {
482 hr = E_INVALIDARG;
483 ExitOnFailure(hr, "Invalid Certificate.Attributes.");
484 }
485
486 // If we have loaded a certificate, update the Certificate.Hash column.
487 if (pbData)
488 {
489 hr = CertificateToHash(pbData, cbData, dwStoreLocation, wzPFXPassword, rgbCertificateHash, countof(rgbCertificateHash));
490 ExitOnFailure(hr, "Failed to get SHA1 hash of certificate.");
491
492 hr = StrHexEncode(rgbCertificateHash, countof(rgbCertificateHash), wzEncodedCertificateHash, countof(wzEncodedCertificateHash));
493 ExitOnFailure(hr, "Failed to hex encode SHA1 hash of certificate.");
494
495 // Update the CertificateHash table.
496 hr = WcaAddTempRecord(&hCertificateHashView, &hCertificateHashColumns, L"CertificateHash", NULL, 0, 2, wzId, wzEncodedCertificateHash);
497 ExitOnFailure(hr, "Failed to add encoded has for certificate: %ls", wzId);
498 }
499
500 *ppbCertificate = pbData;
501 *pcbCertificate = cbData;
502 pbData = NULL;
503
504LExit:
505 if (hCertificateHashColumns)
506 {
507 ::MsiCloseHandle(hCertificateHashColumns);
508 }
509
510 if (hCertificateHashView)
511 {
512 ::MsiCloseHandle(hCertificateHashView);
513 }
514
515 ReleaseStr(pwzDistinguishedName);
516 ReleaseStr(pwzCA);
517 ReleaseMem(pbData);
518 ReleaseStr(pwzSql);
519
520 return hr;
521}
522
523
524static HRESULT ReadCertificateFile(
525 __in LPCWSTR wzPath,
526 __out BYTE** prgbData,
527 __out DWORD* pcbData
528 )
529{
530 HRESULT hr = S_OK;
531
532 PCCERT_CONTEXT pCertContext = NULL;
533 DWORD dwContentType;
534 BYTE* pbData = NULL;
535 DWORD cbData = 0;
536
537 if (!::CryptQueryObject(CERT_QUERY_OBJECT_FILE, reinterpret_cast<LPCVOID>(wzPath), CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &dwContentType, NULL, NULL, NULL, (LPCVOID*)&pCertContext))
538 {
539 ExitOnFailure(hr, "Failed to read certificate from file: %ls", wzPath);
540 }
541
542 if (pCertContext)
543 {
544 cbData = pCertContext->cbCertEncoded;
545 pbData = static_cast<BYTE*>(MemAlloc(cbData, FALSE));
546 ExitOnNull(pbData, hr, E_OUTOFMEMORY, "Failed to allocate memory to read certificate from file: %ls", wzPath);
547
548 CopyMemory(pbData, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
549 }
550 else
551 {
552 // If we have a PFX blob, get the first certificate out of the PFX and use that instead of the PFX.
553 if (dwContentType & CERT_QUERY_CONTENT_PFX)
554 {
555 hr = FileRead(&pbData, &cbData, wzPath);
556 ExitOnFailure(hr, "Failed to read PFX file: %ls", wzPath);
557 }
558 else
559 {
560 hr = E_UNEXPECTED;
561 ExitOnFailure(hr, "Unexpected certificate type read from disk.");
562 }
563 }
564
565 *pcbData = cbData;
566 *prgbData = pbData;
567 pbData = NULL;
568
569LExit:
570 ReleaseMem(pbData);
571 return hr;
572}
573
574
575static HRESULT CertificateToHash(
576 __in BYTE* pbCertificate,
577 __in DWORD cbCertificate,
578 __in DWORD dwStoreLocation,
579 __in LPCWSTR wzPFXPassword,
580 __in BYTE rgbHash[],
581 __in DWORD cbHash
582 )
583{
584 HRESULT hr = S_OK;
585
586 HCERTSTORE hPfxCertStore = NULL;
587 PCCERT_CONTEXT pCertContext = NULL;
588 PCCERT_CONTEXT pCertContextEnum = NULL;
589 CRYPT_DATA_BLOB blob = { 0 };
590 CRYPT_KEY_PROV_INFO* pPfxInfo = NULL;
591 DWORD dwKeyset = (CERT_SYSTEM_STORE_CURRENT_USER == dwStoreLocation) ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET;
592 DWORD dwEncodingType;
593 DWORD dwContentType;
594 DWORD dwFormatType;
595
596 blob.pbData = pbCertificate;
597 blob.cbData = cbCertificate;
598
599 if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertContext))
600 {
601 ExitWithLastError(hr, "Failed to process certificate as a valid certificate.");
602 }
603
604 if (!pCertContext)
605 {
606 // If we have a PFX blob, get the first certificate out of the PFX and use that instead of the PFX.
607 if (dwContentType & CERT_QUERY_CONTENT_PFX)
608 {
609 // If we fail and our password is blank, also try passing in NULL for the password (according to the docs)
610 hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, wzPFXPassword, dwKeyset);
611 if (NULL == hPfxCertStore && !*wzPFXPassword)
612 {
613 hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, NULL, dwKeyset);
614 }
615 ExitOnNullWithLastError(hPfxCertStore, hr, "Failed to open PFX file.");
616
617 // Find the first cert with a private key, or just use the last one
618 for (pCertContextEnum = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContextEnum);
619 pCertContextEnum;
620 pCertContextEnum = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContextEnum))
621 {
622 pCertContext = pCertContextEnum;
623
624 if (pCertContext && CertHasPrivateKey(pCertContext, NULL))
625 {
626 break;
627 }
628 }
629
630 ExitOnNullWithLastError(pCertContext, hr, "Failed to read first certificate out of PFX file.");
631
632 // Ignore failures, the worst that happens is some parts of the PFX get left behind.
633 CertReadProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, &pPfxInfo, NULL);
634 }
635 else
636 {
637 hr = E_UNEXPECTED;
638 ExitOnFailure(hr, "Unexpected certificate type processed.");
639 }
640 }
641
642 DWORD cb = cbHash;
643 if (!::CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, static_cast<LPVOID>(rgbHash), &cb))
644 {
645 ExitWithLastError(hr, "Failed to get certificate SHA1 hash property.");
646 }
647 AssertSz(cb == cbHash, "Did not correctly read certificate SHA1 hash.");
648
649LExit:
650 if (pCertContext)
651 {
652 ::CertFreeCertificateContext(pCertContext);
653 }
654
655 if (hPfxCertStore)
656 {
657 ::CertCloseStore(hPfxCertStore, 0);
658 }
659
660 if (pPfxInfo)
661 {
662 HCRYPTPROV hProvIgnored = NULL; // ignored on deletes.
663 ::CryptAcquireContextW(&hProvIgnored, pPfxInfo->pwszContainerName, pPfxInfo->pwszProvName, pPfxInfo->dwProvType, dwKeyset | CRYPT_DELETEKEYSET | CRYPT_SILENT);
664
665 MemFree(pPfxInfo);
666 }
667
668 return hr;
669}
670
671
672static HRESULT FindExistingCertificate(
673 __in LPCWSTR wzName,
674 __in DWORD dwStoreLocation,
675 __in LPCWSTR wzStore,
676 __out BYTE** prgbCertificate,
677 __out DWORD* pcbCertificate
678 )
679{
680 HRESULT hr = S_OK;
681 HCERTSTORE hCertStore = NULL;
682 PCCERT_CONTEXT pCertContext = NULL;
683 BYTE* pbCertificate = NULL;
684 DWORD cbCertificate = 0;
685
686 hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwStoreLocation | CERT_STORE_READONLY_FLAG, wzStore);
687 MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "Failed to open certificate store.");
688
689 // Loop through the certificate, looking for certificates that match our friendly name.
690 pCertContext = CertFindCertificateInStore(hCertStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL);
691 while (pCertContext)
692 {
693 WCHAR wzFriendlyName[256] = { 0 };
694 DWORD cbFriendlyName = sizeof(wzFriendlyName);
695
696 if (::CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, reinterpret_cast<BYTE*>(wzFriendlyName), &cbFriendlyName) &&
697 CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, 0, wzName, -1, wzFriendlyName, -1))
698 {
699 // If the certificate with matching friendly name is valid, let's use that.
700 long lVerify = ::CertVerifyTimeValidity(NULL, pCertContext->pCertInfo);
701 if (0 == lVerify)
702 {
703 cbCertificate = pCertContext->cbCertEncoded;
704 pbCertificate = static_cast<BYTE*>(MemAlloc(cbCertificate, FALSE));
705 ExitOnNull(pbCertificate, hr, E_OUTOFMEMORY, "Failed to allocate memory to copy out exist certificate.");
706
707 CopyMemory(pbCertificate, pCertContext->pbCertEncoded, cbCertificate);
708 break; // found a matching certificate, no more searching necessary
709 }
710 }
711
712 // Next certificate in the store.
713 PCCERT_CONTEXT pNext = ::CertFindCertificateInStore(hCertStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, pCertContext);
714 // old pCertContext is freed by CertFindCertificateInStore
715 pCertContext = pNext;
716 }
717
718 *prgbCertificate = pbCertificate;
719 *pcbCertificate = cbCertificate;
720 pbCertificate = NULL;
721
722LExit:
723 ReleaseMem(pbCertificate);
724
725 if (pCertContext)
726 {
727 ::CertFreeCertificateContext(pCertContext);
728 }
729
730 if (hCertStore)
731 {
732 ::CertCloseStore(hCertStore, 0);
733 }
734
735 return hr;
736}
737
738/*
739HRESULT CreateEnroll(ICEnroll2 **hEnroll, INT iStore, INT iStoreLocation)
740{
741 ICEnroll2 *pEnroll = NULL;
742 HRESULT hr = S_OK;
743 LONG lFlags;
744 DWORD dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT;
745
746 // create IEntroll
747 hr = CoCreateInstance( CLSID_CEnroll, NULL, CLSCTX_INPROC_SERVER, IID_ICEnroll2, (void **)&pEnroll );
748 if (FAILED(hr))
749 return hr;
750
751 switch (iStore)
752 {
753 case SCA_CERT_STORENAME_MY:
754 pEnroll->get_MyStoreFlags(&lFlags);
755 lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
756 lFlags |= dwFlags;
757 // following call will change Request store flags also
758 pEnroll->put_MyStoreFlags(lFlags);
759 break;
760 case SCA_CERT_STORENAME_CA:
761 pEnroll->get_CAStoreFlags(&lFlags);
762 lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
763 lFlags |= dwFlags;
764 // following call will change Request store flags also
765 pEnroll->put_CAStoreFlags(lFlags);
766 break;
767 case SCA_CERT_STORENAME_REQUEST:
768 pEnroll->get_RequestStoreFlags(&lFlags);
769 lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
770 lFlags |= dwFlags;
771 // following call will change Request store flags also
772 pEnroll->put_RequestStoreFlags(lFlags);
773 break;
774 case SCA_CERT_STORENAME_ROOT:
775 pEnroll->get_RootStoreFlags(&lFlags);
776 lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
777 lFlags |= dwFlags;
778 // following call will change Request store flags also
779 pEnroll->put_RootStoreFlags(lFlags);
780 break;
781 default:
782 hr = E_FAIL;
783 return hr;
784 }
785
786 pEnroll->get_GenKeyFlags(&lFlags);
787 lFlags |= CRYPT_EXPORTABLE;
788 pEnroll->put_GenKeyFlags(lFlags);
789
790 pEnroll->put_KeySpec(AT_KEYEXCHANGE);
791 pEnroll->put_ProviderType(PROV_RSA_SCHANNEL);
792 pEnroll->put_DeleteRequestCert(TRUE);
793
794 *hEnroll = pEnroll;
795 return hr;
796}
797
798
799HRESULT RequestCertificate(LPCWSTR pwzName, INT iStore, INT iStoreLocation,
800 LPCWSTR wzComputerName, LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthority,
801 BSTR *pbstrCertificate)
802{
803 if (pbstrCertificate == NULL)
804 return E_INVALIDARG;
805
806 HRESULT hr;
807 ICEnroll2 *pEnroll = NULL;
808 ICertRequest *pCertRequest = NULL;
809 BSTR bstrRequest = NULL;
810 LONG nDisposition;
811
812 BSTR bstrCertificateUsage = NULL;
813 BSTR bstrCertificateAttributes = NULL;
814 BSTR bstrCertificateAuthority = NULL;
815
816 // equivalent to: sprintf(bstrDistinguishedName, L"%s,CN=%s", wzDistinguishedName, wzComputerName);
817 DWORD cchComputerName = lstrlenW(wzComputerName);
818 DWORD cchDistinguishedName = lstrlenW(wzDistinguishedName);
819 CONST DWORD cchbstrDistinguishedName = 5 + cchComputerName + cchDistinguishedName;
820 BSTR bstrDistinguishedName = SysAllocStringLen(NULL, cchbstrDistinguishedName);
821 ExitOnNull(bstrDistinguishedName, hr, E_OUTOFMEMORY, "Failed to allocate space for distinguished name.");
822 ::StringCchCopyW((WCHAR*) bstrDistinguishedName, cchbstrDistinguishedName, wzDistinguishedName);
823 ::StringCchCatW((WCHAR*) bstrDistinguishedName, cchbstrDistinguishedName, L",CN=");
824 ::StringCchCatW((WCHAR*) bstrDistinguishedName, cchbstrDistinguishedName, wzComputerName);
825
826 bstrCertificateUsage = SysAllocString(WIDE(szOID_PKIX_KP_SERVER_AUTH));
827 ExitOnNull(bstrCertificateUsage, hr, E_OUTOFMEMORY, "Failed to allocate space for Certificate Usage.");
828 bstrCertificateAttributes = SysAllocString(L"CertificateTemplate:WebServer");
829 bstrCertificateAuthority = SysAllocString(wzCertificateAuthority);
830 ExitOnNull(bstrCertificateAuthority, hr, E_OUTOFMEMORY, "Failed to allocate space for Certificate Authority.");
831
832 hr = CreateEnroll(&pEnroll, iStore, iStoreLocation);
833 ExitOnFailure(hr, "failed CoCreateInstance IEnroll");
834
835 hr = pEnroll->createPKCS10(bstrDistinguishedName, bstrCertificateUsage, &bstrRequest);
836 ExitOnFailure(hr, "failed createPKCS10");
837
838 hr = CoCreateInstance(CLSID_CCertRequest, NULL, CLSCTX_INPROC_SERVER, IID_ICertRequest, (void **)&pCertRequest);
839 ExitOnFailure(hr, "failed CoCreateInstance ICertRequest");
840
841 hr = pCertRequest->Submit(CR_IN_BASE64 | CR_IN_PKCS10, bstrRequest, bstrCertificateAttributes, bstrCertificateAuthority, &nDisposition);
842 ExitOnFailure(hr, "failed ICertRequest.Submit");
843
844 hr = (nDisposition == CR_DISP_ISSUED) ? S_OK : E_FAIL;
845 ExitOnFailure(hr, "failed CR_DISP_ISSUED");
846
847 hr = pCertRequest->GetCertificate(CR_OUT_BASE64, pbstrCertificate);
848 ExitOnFailure(hr, "failed ICertRequest.GetCertificate");
849
850 // save the certificate in place, cannot be passed to a deferred custom action
851 hr = pEnroll->acceptPKCS7(*pbstrCertificate);
852 ExitOnFailure(hr, "failed accept certificate into MY store");
853
854LExit:
855 ReleaseObject(pCertRequest);
856 ReleaseBSTR(bstrRequest);
857 ReleaseObject(pEnroll);
858 ReleaseBSTR(bstrCertificateAuthority);
859 ReleaseBSTR(bstrCertificateAttributes);
860 ReleaseBSTR(bstrDistinguishedName);
861
862 return hr;
863}
864
865
866VOID ParseCertificateAuthority(__in LPCWSTR wzCertificateAuthorityOrig, __out LPWSTR *pwzBuffer, __out LPWSTR **hwzCAArray, __out int *piCAArray)
867{
868 // @asAuthorities = split /;/, $sAuthority;
869 CONST WCHAR wchDelimiter = L';';
870
871 // copy constant into a buffer
872 Assert(wzCertificateAuthorityOrig);
873
874 INT cchCA = lstrlenW(wzCertificateAuthorityOrig) + 1;
875 WCHAR* wzBuffer = new WCHAR[cchCA];
876 if (!wzBuffer)
877 return;
878
879 ::StringCchCopyW(wzBuffer, cchCA, wzCertificateAuthorityOrig);
880
881 // determine the number of strings in the field
882 int iCAArray = 1;
883 int i;
884 for (i = 0; i < cchCA; ++i)
885 {
886 if (wzBuffer[i] == wchDelimiter)
887 ++iCAArray;
888 }
889 LPWSTR *pwzCAArray = (LPWSTR*) new BYTE[iCAArray * sizeof(LPWSTR)];
890 if (!pwzCAArray)
891 {
892 return;
893 }
894
895 pwzCAArray[0] = wzBuffer;
896 iCAArray = 0;
897 for (i = 0; i < cchCA; ++i)
898 {
899 if (wzBuffer[i] != wchDelimiter)
900 continue;
901 wzBuffer[i] = 0; // convert buffer into MULTISZ
902 pwzCAArray[iCAArray] = &wzBuffer[i+1];
903 ++iCAArray;
904 }
905
906 *pwzBuffer = wzBuffer;
907 *hwzCAArray = pwzCAArray;
908 *piCAArray = iCAArray;
909}
910
911
912HRESULT ScaSslExistingCertificateByBinaryData(INT iStore, INT iStoreLocation, BYTE* pwzData, DWORD cchData)
913{
914 HRESULT hr = S_FALSE;
915 HCERTSTORE hCertStore = NULL;
916 PCCERT_CONTEXT pCertCtx = NULL, pCertCtxExisting = NULL;
917 DWORD dwFlags = 0;
918 LPCWSTR wzStore = StoreMapping(iStore);
919 CERT_BLOB blob;
920
921 dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT;
922 hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwFlags, wzStore);
923 MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "failed to open certificate store, OK on uninstall");
924
925 blob.pbData = pwzData;
926 blob.cbData = cchData;
927
928 if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL,
929 0, NULL, NULL, NULL, NULL, NULL, (LPCVOID*)&pCertCtx))
930 ExitOnLastError(hr, "failed to parse the certificate blob, OK on uninstall");
931
932 pCertCtxExisting = CertFindCertificateInStore(
933 hCertStore,
934 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
935 0,
936 CERT_FIND_EXISTING,
937 pCertCtx,
938 NULL);
939
940 if (pCertCtxExisting)
941 {
942 hr = S_OK;
943 }
944
945LExit:
946 if (pCertCtx)
947 {
948 CertFreeCertificateContext(pCertCtx);
949 pCertCtx = NULL;
950 }
951 if (pCertCtxExisting)
952 {
953 CertFreeCertificateContext(pCertCtxExisting);
954 pCertCtxExisting = NULL;
955 }
956 if (hCertStore)
957 {
958 CertCloseStore(hCertStore, 0);
959 hCertStore = NULL;
960 }
961
962 return hr;
963}
964
965
966HRESULT ScaSslExistingCertificateByName(LPCWSTR pwzName, INT iStore, INT iStoreLocation,
967 BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer)
968{
969 HRESULT hr = S_FALSE;
970 HCERTSTORE hSystemStore = NULL;
971 PCCERT_CONTEXT pTargetCert = NULL;
972 WCHAR wzFriendlyName[MAX_PATH] = {0};
973 DWORD dwFriendlyNameLen = sizeof(wzFriendlyName);
974
975 // Call CertOpenStore to open the CA store.
976 hSystemStore = CertOpenStore(
977 CERT_STORE_PROV_SYSTEM_REGISTRY,
978 0,
979 NULL,
980 (iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT) | CERT_STORE_OPEN_EXISTING_FLAG,
981 StoreMapping(iStore));
982 if (hSystemStore == NULL)
983 ExitFunction();
984
985 // Get a particular certificate using CertFindCertificateInStore.
986 pTargetCert = CertFindCertificateInStore(
987 hSystemStore,
988 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
989 0,
990 CERT_FIND_ANY,
991 NULL,
992 NULL);
993 while (pTargetCert != NULL)
994 {
995 if ((CertGetCertificateContextProperty(pTargetCert, CERT_FRIENDLY_NAME_PROP_ID,
996 (BYTE*)wzFriendlyName, &dwFriendlyNameLen)) &&
997 lstrcmpW(wzFriendlyName, pwzName) == 0)
998 {
999 // pTargetCert is a pointer to the desired certificate.
1000 // Check the certificate's validity.
1001 switch (CertVerifyTimeValidity(
1002 NULL,
1003 pTargetCert->pCertInfo))
1004 {
1005 case 1:
1006 // Certificate is expired
1007 WcaLog(LOGMSG_STANDARD, "The SSL certificate has expired");
1008 // always remove it
1009 {
1010 PCCERT_CONTEXT pDupCertContext = CertDuplicateCertificateContext(pTargetCert);
1011 if (pDupCertContext && CertDeleteCertificateFromStore(pDupCertContext))
1012 {
1013 WcaLog(LOGMSG_STANDARD, "A SSL certificate has removed");
1014 }
1015 }
1016 break;
1017 case 0:
1018 // Certificate is valid
1019 WcaLog(LOGMSG_STANDARD, "The SSL certificate is valid");
1020 hr = S_OK;
1021 if (pbaHashBuffer)
1022 {
1023 // if the certificate already exists and is valid, use that one
1024 DWORD dwHashSize = CB_CERTIFICATE_HASH;
1025 hr = CertGetCertificateContextProperty(pTargetCert, CERT_SHA1_HASH_PROP_ID, (VOID*)pbaHashBuffer, &dwHashSize)
1026 ? S_OK : E_FAIL;
1027 ExitOnFailure(hr, "failed CertGetCertificateContextProperty CERT_SHA1_HASH_PROP_ID");
1028 Assert(pbstrCertificate);
1029 Assert(pcbCertificate);
1030 ReleaseBSTR(*pbstrCertificate);
1031
1032 *pbstrCertificate = SysAllocStringByteLen((LPCSTR)(pTargetCert->pbCertEncoded), pTargetCert->cbCertEncoded);
1033 *pcbCertificate = pTargetCert->cbCertEncoded;
1034 }
1035 ExitFunction();
1036 break;
1037 default:
1038 // Certificate not valid yet, ignore it
1039 WcaLog(LOGMSG_STANDARD, "The SSL certificate is not valid");
1040 break;
1041 }
1042 }
1043 pTargetCert = CertFindCertificateInStore(
1044 hSystemStore,
1045 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1046 0,
1047 CERT_FIND_ANY,
1048 NULL,
1049 pTargetCert);
1050 wzFriendlyName[0] = 0;
1051 dwFriendlyNameLen = sizeof(wzFriendlyName);
1052 }
1053
1054LExit:
1055 // Clean up memory and quit.
1056 if (pTargetCert)
1057 {
1058 CertFreeCertificateContext(pTargetCert);
1059 pTargetCert = NULL;
1060 }
1061 if (hSystemStore)
1062 {
1063 CertCloseStore(hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG);
1064 hSystemStore = NULL;
1065 }
1066
1067 return hr;
1068}
1069
1070
1071HRESULT ScaSslNewCertificate(LPCWSTR pwzName, INT iStore, INT iStoreLocation, LPCWSTR wzComputerName, LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthorityOrig,
1072 BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer)
1073{
1074
1075 if (pbstrCertificate == NULL)
1076 return E_INVALIDARG;
1077
1078 HRESULT hr = S_OK;
1079 LPWSTR wzCABuffer = NULL;
1080 LPWSTR *wzCAArray = NULL;
1081 int iCAArray = 0;
1082
1083 // otherwise call the CA for one
1084 ParseCertificateAuthority(wzCertificateAuthorityOrig, &wzCABuffer, &wzCAArray, &iCAArray);
1085
1086 // try each authority three times
1087 for (int i = 0; i < 3 * iCAArray; ++i)
1088 {
1089 LPCWSTR wzCA = wzCAArray[i % iCAArray];
1090 if (NULL == wzCA || NULL == wzCA[0]) continue;
1091 WcaLog(LOGMSG_STANDARD, "Requesting SSL certificate from %ls", wzCA);
1092 hr = RequestCertificate(pwzName, iStore, iStoreLocation, wzComputerName, wzDistinguishedName, wzCA, pbstrCertificate);
1093 if (hr == S_OK && pbstrCertificate)
1094 {
1095 // set the friendly name
1096 CRYPT_HASH_BLOB hblob;
1097 CERT_BLOB blob;
1098 HCERTSTORE hCertStore = NULL;
1099 PCCERT_CONTEXT pCertCtxExisting = NULL;
1100
1101 blob.pbData = (BYTE*)pwzName;
1102 blob.cbData = (lstrlenW(pwzName) + 1) * sizeof(pwzName[0]); // including terminating null
1103
1104 *pcbCertificate = SysStringByteLen(*pbstrCertificate);
1105 hr = CertificateToHash(*pbstrCertificate, pbaHashBuffer);
1106 ExitOnFailure(hr, "failed to CertificateToHash for an existing certificate");
1107
1108 hblob.pbData = pbaHashBuffer;
1109 hblob.cbData = CB_CERTIFICATE_HASH;
1110
1111 hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, (iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT), StoreMapping(iStore));
1112 MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "failed to open certificate store");
1113
1114 pCertCtxExisting = CertFindCertificateInStore(
1115 hCertStore,
1116 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1117 0,
1118 CERT_FIND_HASH,
1119 &hblob,
1120 NULL);
1121
1122 if (pCertCtxExisting)
1123 {
1124 CertSetCertificateContextProperty(
1125 pCertCtxExisting,
1126 CERT_FRIENDLY_NAME_PROP_ID,
1127 0,
1128 &blob);
1129 }
1130
1131 if (pCertCtxExisting)
1132 {
1133 CertFreeCertificateContext(pCertCtxExisting);
1134 pCertCtxExisting = NULL;
1135 }
1136 if (hCertStore)
1137 {
1138 CertCloseStore(hCertStore, 0);
1139 hCertStore = NULL;
1140 }
1141 ExitFunction();
1142 }
1143 if (pbstrCertificate && *pbstrCertificate)
1144 {
1145 SysFreeString(*pbstrCertificate);
1146 pbstrCertificate = NULL;
1147 }
1148 }
1149 hr = E_FAIL;
1150 ExitOnFailure(hr, "failed to RequestCertificate");
1151
1152LExit:
1153 if (wzCABuffer)
1154 {
1155 delete wzCABuffer;
1156 }
1157 if (wzCAArray)
1158 {
1159 delete wzCAArray;
1160 }
1161
1162 return hr;
1163}
1164
1165
1166HRESULT ScaGetCertificateByRequest(LPCWSTR pwzName, BOOL fIsInstalling, BOOL fIsUninstalling,
1167 INT iStore, INT iStoreLocation,
1168 LPCWSTR wzDistinguishedName, LPCWSTR wzCA,
1169 BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer)
1170{
1171 HRESULT hr = S_OK;
1172 WCHAR wzComputerName[MAX_COMPUTER_NAME] = {0};
1173 WCHAR* pwzData = NULL;
1174 DWORD cchData = 0;
1175
1176 // override %COMPUTERNAME% with DOMAINNAME property
1177 hr = WcaGetProperty( L"DOMAINNAME", &pwzData);
1178 ExitOnFailure(hr, "Failed to get Property DOMAINNAME");
1179 if (*pwzData)
1180 {
1181 // if DOMAINNAME is set, use it
1182 ::StringCchCopyW(wzComputerName, MAX_COMPUTER_NAME, pwzData);
1183 }
1184 else
1185 {
1186 // otherwise get the intranet name given by %COMPUTERNAME%
1187 GetEnvironmentVariableW(L"COMPUTERNAME", wzComputerName, MAX_COMPUTER_NAME);
1188 }
1189
1190 hr = ScaSslExistingCertificateByName(pwzName, iStore, iStoreLocation, pbstrCertificate, pcbCertificate, pbaHashBuffer);
1191 ExitOnFailure(hr, "Failed ScaSslExistingCertificateByName");
1192 if (S_OK != hr)
1193 {
1194 if (!fIsUninstalling && fIsInstalling)
1195 {
1196 // if no existing cert and not on uninstall, hit the authority
1197 WcaLog(LOGMSG_STANDARD, "Adding certificate: requested, %ls", wzDistinguishedName);
1198 hr = ScaSslNewCertificate(pwzName, iStore, iStoreLocation, wzComputerName, wzDistinguishedName, wzCA,
1199 pbstrCertificate, pcbCertificate, pbaHashBuffer);
1200 ExitOnFailure(hr, "Failed ScaSslNewCertificate");
1201 }
1202 else
1203 {
1204 // if no existing cert and uninstall
1205 hr = S_OK;
1206 }
1207 }
1208
1209LExit:
1210 ReleaseStr(pwzData);
1211
1212 return hr;
1213}
1214
1215
1216HRESULT ScaInstallCertificateByContext(LPCWSTR pwzName, INT iStore, INT iStoreLocation,
1217 PCCERT_CONTEXT pCertContext)
1218{
1219 HRESULT hr = S_OK;
1220 HCERTSTORE hCertStore = NULL;
1221 DWORD dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT;
1222 CERT_BLOB blob;
1223
1224 hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwFlags, StoreMapping(iStore));
1225 if (hCertStore == NULL)
1226 MessageExitOnLastError(hr, msierrCERTFailedOpen, "failed to open certificate store");
1227
1228 blob.pbData = (BYTE*)pwzName;
1229 blob.cbData = (lstrlenW(pwzName) + 1) * sizeof(pwzName[0]); // including terminating null
1230 CertSetCertificateContextProperty(
1231 pCertContext,
1232 CERT_FRIENDLY_NAME_PROP_ID,
1233 0,
1234 &blob);
1235
1236 if (!CertAddCertificateContextToStore(
1237 hCertStore,
1238 pCertContext,
1239 CERT_STORE_ADD_REPLACE_EXISTING,
1240 NULL))
1241 {
1242 hr = E_FAIL;
1243 MessageExitOnLastError(hr, msierrCERTFailedAdd, "failed to add certificate to the store");
1244 }
1245
1246LExit:
1247 if (hCertStore)
1248 {
1249 CertCloseStore(hCertStore, 0);
1250 hCertStore = NULL;
1251 }
1252
1253 return hr;
1254}
1255
1256
1257HRESULT ScaGetCertificateByPath(LPCWSTR pwzName, BOOL fIsInstalling, BOOL fIsUninstalling,
1258 INT iStore, INT iStoreLocation, LPCWSTR wzSslCertificate, LPCWSTR wzPFXPassword,
1259 BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer)
1260{
1261 Assert(wzSslCertificate);
1262 HRESULT hr = S_OK;
1263 PCCERT_CONTEXT pCertContext = NULL;
1264 DWORD dwEncodingType = 0;
1265 DWORD dwContentType = 0;
1266 DWORD dwFormatType = 0;
1267 DWORD dwHashSize = CB_CERTIFICATE_HASH;
1268 HANDLE hPfxFile = INVALID_HANDLE_VALUE;
1269 CRYPT_DATA_BLOB blob;
1270
1271 blob.pbData = NULL;
1272 blob.cbData = 0;
1273
1274 if (wzSslCertificate && wzSslCertificate[0] != 0)
1275 {
1276 if (!::CryptQueryObject(CERT_QUERY_OBJECT_FILE, (LPVOID)wzSslCertificate, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL,
1277 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertContext))
1278 hr = fIsUninstalling ? S_FALSE : HRESULT_FROM_WIN32(::GetLastError()); // don't fail on uninstall
1279 ExitOnFailure(hr, "failed CryptQueryObject");
1280 }
1281 else
1282 {
1283 hr = S_FALSE;
1284 ExitFunction();
1285 }
1286
1287 if (!pCertContext)
1288 {
1289 // this is a pfx?
1290 // make sure to exit this block of code properly for clean up blob.pbData
1291 if (dwContentType & CERT_QUERY_CONTENT_PFX)
1292 {
1293 DWORD iSize = 0, iReadSize = 0;
1294 HCERTSTORE hPfxCertStore = NULL;
1295
1296 hPfxFile = ::CreateFileW(wzSslCertificate, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1297 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1298 hr = (hPfxFile != INVALID_HANDLE_VALUE) ? S_OK : E_FAIL;
1299 ExitOnFailure(hr, "failed CryptQueryObject, file handle is null");
1300 iSize = ::GetFileSize(hPfxFile, NULL);
1301 hr = (iSize > 0) ? S_OK : E_FAIL;
1302 ExitOnFailure(hr, "failed CryptQueryObject, file size is 0");
1303 blob.pbData = new BYTE[iSize];
1304 blob.cbData = iSize;
1305 hr = (blob.pbData) ? S_OK : E_FAIL;
1306 ExitOnFailure(hr, "out of memory for blob");
1307
1308 if (::ReadFile(hPfxFile, (LPVOID)blob.pbData, iSize, &iReadSize, NULL))
1309 {
1310 hPfxCertStore = PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, wzPFXPassword,
1311 (iStoreLocation == SCA_CERTSYSTEMSTORE_CURRENTUSER) ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET);
1312 if (hPfxCertStore)
1313 {
1314 pCertContext = CertEnumCertificatesInStore(hPfxCertStore, NULL);
1315 // work only with the first certificate in pfx
1316 if (pCertContext)
1317 {
1318 hr = CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, (VOID*)pbaHashBuffer, &dwHashSize)
1319 ? S_OK : E_FAIL;
1320 ExitOnFailure(hr, "failed CertGetCertificateContextProperty CERT_SHA1_HASH_PROP_ID");
1321 ReleaseBSTR(*pbstrCertificate);
1322
1323 *pbstrCertificate = SysAllocStringByteLen((LPCSTR)(pCertContext->pbCertEncoded), pCertContext->cbCertEncoded);
1324 *pcbCertificate = pCertContext->cbCertEncoded;
1325 if (fIsInstalling)
1326 {
1327 // install the certificate, cannot defer because the data required cannot be passed
1328 hr = ScaInstallCertificateByContext(pwzName, iStore, iStoreLocation, pCertContext);
1329 }
1330 }
1331 else
1332 hr = E_FAIL;
1333 }
1334 else
1335 hr = E_FAIL;
1336 }
1337 else
1338 hr = E_FAIL;
1339 }
1340 else
1341 {
1342 ExitOnFailure(hr = E_FAIL, "failed CryptQueryObject, unknown data");
1343 }
1344 }
1345 else
1346 {
1347 // return cert and its hash
1348 hr = CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, (VOID*)pbaHashBuffer, &dwHashSize)
1349 ? S_OK : E_FAIL;
1350 ExitOnFailure(hr, "failed CertGetCertificateContextProperty CERT_SHA1_HASH_PROP_ID");
1351 ReleaseBSTR(*pbstrCertificate);
1352
1353 *pbstrCertificate = SysAllocStringByteLen((LPCSTR)(pCertContext->pbCertEncoded), pCertContext->cbCertEncoded);
1354 *pcbCertificate = pCertContext->cbCertEncoded;
1355 if (fIsInstalling)
1356 {
1357 // install the certificate, cannot defer because the data required cannot be passed
1358 hr = ScaInstallCertificateByContext(pwzName, iStore, iStoreLocation, pCertContext);
1359 }
1360 }
1361
1362LExit:
1363 if (pCertContext)
1364 {
1365 CertFreeCertificateContext(pCertContext);
1366 pCertContext = NULL;
1367 }
1368 if (hPfxFile != INVALID_HANDLE_VALUE)
1369 {
1370 CloseHandle(hPfxFile);
1371 hPfxFile = INVALID_HANDLE_VALUE;
1372 }
1373 if (blob.pbData)
1374 {
1375 delete [] blob.pbData;
1376 blob.pbData = NULL;
1377 blob.cbData = 0;
1378 }
1379
1380 return hr;
1381}
1382
1383
1384HRESULT ScaInstallCertificateByBinaryData(BOOL fAddCert, INT iStore, INT iStoreLocation, LPCWSTR wzName, BYTE* pwzData, DWORD cchData,
1385 LPCWSTR wzPFXPassword)
1386{
1387 Assert(wzName);
1388 Assert(pwzData);
1389 Assert(cchData);
1390 HRESULT hr = S_OK;
1391 HCERTSTORE hCertStore = NULL, hPfxCertStore = NULL;
1392 PCCERT_CONTEXT pCertCtx = NULL, pCertCtxExisting = NULL;
1393 DWORD dwFlags, dwEncodingType, dwContentType, dwFormatType;
1394 CERT_BLOB blob;
1395 LPCWSTR wzStore = StoreMapping(iStore);
1396
1397 dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT;
1398 hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwFlags, wzStore);
1399 MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "failed to open certificate store");
1400
1401 blob.pbData = pwzData;
1402 blob.cbData = cchData;
1403
1404 if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL,
1405 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertCtx))
1406 ExitOnLastError(hr, "failed to parse the certificate blob");
1407 ExitOnNull(pCertCtx, hr, E_UNEXPECTED, "failed to parse the certificate blob");
1408
1409 blob.pbData = (BYTE*)wzName;
1410 blob.cbData = (lstrlenW(wzName) + 1) * sizeof(wzName[0]); // including terminating null
1411
1412 CertSetCertificateContextProperty(
1413 pCertCtx,
1414 CERT_FRIENDLY_NAME_PROP_ID,
1415 0,
1416 &blob);
1417
1418 if (fAddCert)
1419 {
1420 // Add
1421 WcaLog(LOGMSG_STANDARD, "Adding certificate: binary name, %ls", wzName);
1422 if (!CertAddCertificateContextToStore(
1423 hCertStore,
1424 pCertCtx,
1425 CERT_STORE_ADD_REPLACE_EXISTING,
1426 NULL))
1427 {
1428 hr = E_FAIL;
1429 MessageExitOnLastError(hr, msierrCERTFailedAdd, "failed to add certificate to the store");
1430 }
1431 }
1432 else
1433 {
1434 // Delete
1435 WcaLog(LOGMSG_STANDARD, "Deleting certificate provided: binary name, %ls", wzName);
1436 pCertCtxExisting = CertFindCertificateInStore(
1437 hCertStore,
1438 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1439 0,
1440 CERT_FIND_EXISTING,
1441 pCertCtx,
1442 NULL);
1443
1444 if (pCertCtxExisting)
1445 {
1446 if (!CertDeleteCertificateFromStore(pCertCtxExisting))
1447 {
1448 ExitOnLastError(hr, "failed to delete certificate");
1449 }
1450 else
1451 {
1452 pCertCtxExisting = NULL;
1453 }
1454 }
1455 }
1456
1457LExit:
1458 if (pCertCtx)
1459 {
1460 CertFreeCertificateContext(pCertCtx);
1461 pCertCtx = NULL;
1462 }
1463 if (pCertCtxExisting)
1464 {
1465 CertFreeCertificateContext(pCertCtxExisting);
1466 pCertCtxExisting = NULL;
1467 }
1468 // order is important for store
1469 if (hCertStore)
1470 {
1471 CertCloseStore(hCertStore, 0);
1472 hCertStore = NULL;
1473 }
1474 if (hPfxCertStore)
1475 {
1476 CertCloseStore(hPfxCertStore, 0);
1477 hPfxCertStore = NULL;
1478 }
1479
1480 return hr;
1481}
1482*/
diff --git a/src/ext/Iis/ca/scacert.h b/src/ext/Iis/ca/scacert.h
new file mode 100644
index 00000000..39b00d3d
--- /dev/null
+++ b/src/ext/Iis/ca/scacert.h
@@ -0,0 +1,23 @@
1#pragma once
2// 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.
3
4
5#define CB_CERTIFICATE_HASH 20
6
7// Certificate.Attribute
8enum SCA_CERT_ATTRIBUTES
9{
10 SCA_CERT_ATTRIBUTE_DEFAULT = 0,
11 SCA_CERT_ATTRIBUTE_REQUEST = 1,
12 SCA_CERT_ATTRIBUTE_BINARYDATA = 2,
13 SCA_CERT_ATTRIBUTE_OVERWRITE = 4,
14 SCA_CERT_ATTRIBUTE_VITAL = 8,
15};
16
17
18// Certificate.StoreLocation
19enum SCA_CERTSYSTEMSTORE
20{
21 SCA_CERTSYSTEMSTORE_CURRENTUSER = 1,
22 SCA_CERTSYSTEMSTORE_LOCALMACHINE = 2,
23};
diff --git a/src/ext/Iis/ca/scacertexec.cpp b/src/ext/Iis/ca/scacertexec.cpp
new file mode 100644
index 00000000..95870c79
--- /dev/null
+++ b/src/ext/Iis/ca/scacertexec.cpp
@@ -0,0 +1,431 @@
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#define SIXTY_FOUR_MEG 64 * 1024 * 1024
6
7// prototypes
8static HRESULT ExecuteCertificateOperation(
9 __in MSIHANDLE hInstall,
10 __in SCA_ACTION saAction,
11 __in DWORD dwStoreRoot
12 );
13
14static HRESULT ReadCertificateFile(
15 __in LPCWSTR wzPath,
16 __out BYTE** prgbData,
17 __out DWORD* pcbData
18 );
19
20static HRESULT InstallCertificatePackage(
21 __in HCERTSTORE hStore,
22 __in BOOL fUserCertificateStore,
23 __in LPCWSTR wzName,
24 __in_opt BYTE* rgbData,
25 __in DWORD cbData,
26 __in BOOL fVital,
27 __in_opt LPCWSTR wzPFXPassword
28 );
29
30static HRESULT UninstallCertificatePackage(
31 __in HCERTSTORE hStore,
32 __in BOOL fUserCertificateStore,
33 __in LPCWSTR wzName
34 );
35
36static HRESULT AddCertificate(
37 __in HCERTSTORE hStore,
38 __in PCCERT_CONTEXT pCertContext,
39 __in LPCWSTR wzCertificateUniqueName,
40 __in BOOL fVital
41);
42
43/* ****************************************************************
44 AddUserCertificate - CUSTOM ACTION ENTRY POINT for adding per-user
45 certificates
46
47 * ***************************************************************/
48extern "C" UINT __stdcall AddUserCertificate(
49 __in MSIHANDLE hInstall
50 )
51{
52 HRESULT hr = S_OK;
53 DWORD er = ERROR_SUCCESS;
54
55 hr = WcaInitialize(hInstall, "AddUserCertificate");
56 ExitOnFailure(hr, "Failed to initialize AddUserCertificate.");
57
58 hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_INSTALL, CERT_SYSTEM_STORE_CURRENT_USER);
59 ExitOnFailure(hr, "Failed to install per-user certificate.");
60
61LExit:
62 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
63 return WcaFinalize(er);
64}
65
66
67/* ****************************************************************
68 AddMachineCertificate - CUSTOM ACTION ENTRY POINT for adding
69 per-machine certificates
70
71 * ***************************************************************/
72extern "C" UINT __stdcall AddMachineCertificate(
73 __in MSIHANDLE hInstall
74 )
75{
76 HRESULT hr = S_OK;
77 DWORD er = ERROR_SUCCESS;
78
79 hr = WcaInitialize(hInstall, "AddMachineCertificate");
80 ExitOnFailure(hr, "Failed to initialize AddMachineCertificate.");
81
82 hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_INSTALL, CERT_SYSTEM_STORE_LOCAL_MACHINE);
83 ExitOnFailure(hr, "Failed to install per-machine certificate.");
84
85LExit:
86 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
87 return WcaFinalize(er);
88}
89
90
91/* ****************************************************************
92 DeleteUserCertificate - CUSTOM ACTION ENTRY POINT for deleting
93 per-user certificates
94
95 * ***************************************************************/
96extern "C" UINT __stdcall DeleteUserCertificate(
97 __in MSIHANDLE hInstall
98 )
99{
100 HRESULT hr = S_OK;
101 DWORD er = ERROR_SUCCESS;
102
103 hr = WcaInitialize(hInstall, "DeleteUserCertificate");
104 ExitOnFailure(hr, "Failed to initialize DeleteUserCertificate.");
105
106 hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_UNINSTALL, CERT_SYSTEM_STORE_CURRENT_USER);
107 ExitOnFailure(hr, "Failed to uninstall per-user certificate.");
108
109LExit:
110 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
111 return WcaFinalize(er);
112}
113
114
115/* ****************************************************************
116 DeleteMachineCertificate - CUSTOM ACTION ENTRY POINT for deleting
117 per-machine certificates
118
119 * ***************************************************************/
120extern "C" UINT __stdcall DeleteMachineCertificate(
121 __in MSIHANDLE hInstall
122 )
123{
124 HRESULT hr = S_OK;
125 DWORD er = ERROR_SUCCESS;
126
127 hr = WcaInitialize(hInstall, "DeleteMachineCertificate");
128 ExitOnFailure(hr, "Failed to initialize DeleteMachineCertificate.");
129
130 hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_UNINSTALL, CERT_SYSTEM_STORE_LOCAL_MACHINE);
131 ExitOnFailure(hr, "Failed to uninstall per-machine certificate.");
132
133LExit:
134 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
135 return WcaFinalize(er);
136}
137
138
139static HRESULT ExecuteCertificateOperation(
140 __in MSIHANDLE /*hInstall*/,
141 __in SCA_ACTION saAction,
142 __in DWORD dwStoreLocation
143 )
144{
145 //AssertSz(FALSE, "Debug ExecuteCertificateOperation() here.");
146 Assert(saAction & SCA_ACTION_INSTALL || saAction & SCA_ACTION_UNINSTALL);
147
148 HRESULT hr = S_OK;
149 LPWSTR pwzCaData = NULL;
150 LPWSTR pwz;
151 LPWSTR pwzName = NULL;
152 LPWSTR pwzStore = NULL;
153 int iAttributes = 0;
154 LPWSTR pwzPFXPassword = NULL;
155 LPWSTR pwzFilePath = NULL;
156 BYTE* pbData = NULL;
157 DWORD cbData = 0;
158 DWORD_PTR cbPFXPassword = 0;
159
160 BOOL fUserStoreLocation = (CERT_SYSTEM_STORE_CURRENT_USER == dwStoreLocation);
161 HCERTSTORE hCertStore = NULL;
162
163 hr = WcaGetProperty(L"CustomActionData", &pwzCaData);
164 ExitOnFailure(hr, "Failed to get CustomActionData");
165
166 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCaData);
167
168 pwz = pwzCaData;
169 hr = WcaReadStringFromCaData(&pwz, &pwzName);
170 ExitOnFailure(hr, "Failed to parse certificate name.");
171 hr = WcaReadStringFromCaData(&pwz, &pwzStore);
172 ExitOnFailure(hr, "Failed to parse CustomActionData, StoreName");
173 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
174 ExitOnFailure(hr, "Failed to parse certificate attribute");
175 if (SCA_ACTION_INSTALL == saAction) // install operations need more data
176 {
177 hr = WcaReadStreamFromCaData(&pwz, &pbData, (DWORD_PTR*)&cbData);
178 ExitOnFailure(hr, "Failed to parse certificate stream.");
179
180 hr = WcaReadStringFromCaData(&pwz, &pwzPFXPassword);
181 ExitOnFailure(hr, "Failed to parse certificate password.");
182 }
183
184 // Open the right store.
185 hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwStoreLocation | CERT_STORE_MAXIMUM_ALLOWED_FLAG, pwzStore);
186 MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "Failed to open certificate store: %ls", pwzStore);
187
188 if (SCA_ACTION_INSTALL == saAction) // install operations need more data
189 {
190 // Uninstall existing versions of this package. Ignore any failures
191 // This is needed to clean up the private key of a cert when we replace an existing cert
192 // CertAddCertificateContextToStore(CERT_STORE_ADD_REPLACE_EXISTING) does not remove the private key if the cert is replaced
193 UninstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName);
194
195 hr = InstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName, pbData, cbData, iAttributes & SCA_CERT_ATTRIBUTE_VITAL, pwzPFXPassword);
196 ExitOnFailure(hr, "Failed to install certificate.");
197 }
198 else
199 {
200 Assert(SCA_ACTION_UNINSTALL == saAction);
201
202 hr = UninstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName);
203 ExitOnFailure(hr, "Failed to uninstall certificate.");
204 }
205
206LExit:
207 if (NULL != pwzPFXPassword && SUCCEEDED(StrSize(pwzPFXPassword, &cbPFXPassword)))
208 {
209 SecureZeroMemory(pwzPFXPassword, cbPFXPassword);
210 }
211
212 if (hCertStore)
213 {
214 if (!::CertCloseStore(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG))
215 {
216 WcaLog(LOGMSG_VERBOSE, "Cert store was closed but not all resources were freed. Error 0x%x", GetLastError());
217 }
218 }
219
220 ReleaseMem(pbData);
221 ReleaseStr(pwzFilePath);
222 ReleaseStr(pwzPFXPassword);
223 ReleaseStr(pwzStore);
224 ReleaseStr(pwzName);
225 ReleaseStr(pwzCaData);
226 return hr;
227}
228
229
230static HRESULT InstallCertificatePackage(
231 __in HCERTSTORE hStore,
232 __in BOOL fUserCertificateStore,
233 __in LPCWSTR wzName,
234 __in_opt BYTE* rgbData,
235 __in DWORD cbData,
236 __in BOOL fVital,
237 __in_opt LPCWSTR wzPFXPassword
238 )
239{
240 HRESULT hr = S_OK;
241
242 HCERTSTORE hPfxCertStore = NULL;
243 PCCERT_CONTEXT pCertContext = NULL;
244 CERT_BLOB blob = { 0 };
245 DWORD dwKeyset = fUserCertificateStore ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET;
246 DWORD dwEncodingType;
247 DWORD dwContentType;
248 DWORD dwFormatType;
249 LPWSTR pwzUniqueName = NULL;
250 int iUniqueId = 0;
251
252 // Figure out what type of blob (certificate or PFX) we're dealing with here.
253 blob.pbData = rgbData;
254 blob.cbData = cbData;
255
256 if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL, 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertContext))
257 {
258 ExitWithLastError(hr, "Failed to parse the certificate blob: %ls", wzName);
259 }
260
261 hr = StrAllocFormatted(&pwzUniqueName, L"%s_wixCert_%d", wzName, ++iUniqueId);
262 ExitOnFailure(hr, "Failed to format unique name");
263
264 if (!pCertContext)
265 {
266 // If we have a PFX blob, get the first certificate out of the PFX and use that instead of the PFX.
267 if (dwContentType & CERT_QUERY_CONTENT_PFX)
268 {
269 ExitOnNull(wzPFXPassword, hr, E_INVALIDARG, "Failed to import PFX blob because no password was provided");
270
271 // If we fail and our password is blank, also try passing in NULL for the password (according to the docs)
272 hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, wzPFXPassword, dwKeyset);
273 if (NULL == hPfxCertStore && !*wzPFXPassword)
274 {
275 hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, NULL, dwKeyset);
276 }
277 ExitOnNullWithLastError(hPfxCertStore, hr, "Failed to open PFX file.");
278
279 // Install all certificates in the PFX
280 for (pCertContext = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContext);
281 pCertContext;
282 pCertContext = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContext))
283 {
284 hr = AddCertificate(hStore, pCertContext, pwzUniqueName, fVital);
285 MessageExitOnFailure(hr, msierrCERTFailedAdd, "Failed to add certificate to the store.");
286
287 hr = StrAllocFormatted(&pwzUniqueName, L"%s_wixCert_%d", wzName, ++iUniqueId);
288 ExitOnFailure(hr, "Failed to format unique name");
289 }
290 }
291 else
292 {
293 hr = E_UNEXPECTED;
294 ExitOnFailure(hr, "Unexpected certificate type processed.");
295 }
296 }
297 else
298 {
299 hr = AddCertificate(hStore, pCertContext, pwzUniqueName, fVital);
300 MessageExitOnFailure(hr, msierrCERTFailedAdd, "Failed to add certificate to the store.");
301 }
302
303 hr = WcaProgressMessage(COST_CERT_ADD, FALSE);
304 ExitOnFailure(hr, "Failed to send install progress message.");
305
306LExit:
307 ReleaseStr(pwzUniqueName);
308
309 if (pCertContext)
310 {
311 ::CertFreeCertificateContext(pCertContext);
312 }
313
314 // Close the stores after the context's are released.
315 if (hPfxCertStore)
316 {
317 if (!::CertCloseStore(hPfxCertStore, CERT_CLOSE_STORE_CHECK_FLAG))
318 {
319 WcaLog(LOGMSG_VERBOSE, "PFX cert store was closed but not all resources were freed. Error 0x%x", GetLastError());
320 }
321 }
322
323 return hr;
324}
325
326
327static HRESULT UninstallCertificatePackage(
328 __in HCERTSTORE hStore,
329 __in BOOL fUserCertificateStore,
330 __in LPCWSTR wzName
331 )
332{
333 HRESULT hr = S_OK;
334 DWORD er = ERROR_SUCCESS;
335 PCCERT_CONTEXT pCertContext = NULL;
336 CRYPT_KEY_PROV_INFO* pPrivateKeyInfo = NULL;
337 LPWSTR pwzUniquePrefix = NULL;
338 int ccUniquePrefix = 0;
339
340 hr = StrAllocFormatted(&pwzUniquePrefix, L"%s_wixCert_", wzName);
341 ExitOnFailure(hr, "Failed to format unique name");
342 ccUniquePrefix = ::lstrlenW(pwzUniquePrefix);
343
344 WcaLog(LOGMSG_STANDARD, "Deleting certificate that begin with friendly name: %ls", pwzUniquePrefix);
345
346 // Loop through all certificates in the store, deleting the ones that begin with our prefix.
347 while (NULL != (pCertContext = ::CertFindCertificateInStore(hStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, pCertContext)))
348 {
349 WCHAR wzFriendlyName[256] = { 0 };
350 DWORD cbFriendlyName = sizeof(wzFriendlyName);
351
352 if (::CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, reinterpret_cast<BYTE*>(wzFriendlyName), &cbFriendlyName) &&
353 lstrlenW(wzFriendlyName) >= ccUniquePrefix &&
354 CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, 0, pwzUniquePrefix, ccUniquePrefix, wzFriendlyName, ccUniquePrefix))
355 {
356 PCCERT_CONTEXT pCertContextDelete = ::CertDuplicateCertificateContext(pCertContext); // duplicate the context so we can delete it with out disrupting the looping
357 if(pCertContextDelete)
358 {
359 // Delete the certificate and if successful delete the matching private key as well.
360 if (::CertDeleteCertificateFromStore(pCertContextDelete))
361 {
362 // If we found private key info, delete it.
363 hr = CertReadProperty(pCertContextDelete, CERT_KEY_PROV_INFO_PROP_ID, &pPrivateKeyInfo, NULL);
364 if (SUCCEEDED(hr))
365 {
366 HCRYPTPROV hProvIgnored = NULL; // ignored on deletes.
367 DWORD dwKeyset = fUserCertificateStore ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET;
368
369 if (!::CryptAcquireContextW(&hProvIgnored, pPrivateKeyInfo->pwszContainerName, pPrivateKeyInfo->pwszProvName, pPrivateKeyInfo->dwProvType, dwKeyset | CRYPT_DELETEKEYSET | CRYPT_SILENT))
370 {
371 er = ::GetLastError();
372 hr = HRESULT_FROM_WIN32(er);
373 }
374
375 ReleaseNullMem(pPrivateKeyInfo);
376 }
377 else // don't worry about failures to delete private keys.
378 {
379 hr = S_OK;
380 }
381 }
382 else
383 {
384 er = ::GetLastError();
385 hr = HRESULT_FROM_WIN32(er);
386 }
387
388 if (FAILED(hr))
389 {
390 WcaLog(LOGMSG_STANDARD, "Failed to delete certificate with friendly name: %ls, continuing anyway. Error: 0x%x", wzFriendlyName, hr);
391 }
392
393 pCertContextDelete = NULL;
394 }
395 }
396 }
397
398 hr = WcaProgressMessage(COST_CERT_DELETE, FALSE);
399 ExitOnFailure(hr, "Failed to send uninstall progress message.");
400
401LExit:
402 ReleaseStr(pwzUniquePrefix);
403 ReleaseMem(pPrivateKeyInfo);
404 if(pCertContext)
405 {
406 ::CertFreeCertificateContext(pCertContext);
407 }
408
409 return hr;
410}
411
412static HRESULT AddCertificate(
413 __in HCERTSTORE hStore,
414 __in PCCERT_CONTEXT pCertContext,
415 __in LPCWSTR wzCertificateUniqueName,
416 __in BOOL fVital
417)
418{
419 HRESULT hr = S_OK;
420
421 WcaLog(LOGMSG_STANDARD, "Adding certificate: %ls", wzCertificateUniqueName);
422
423 hr = CertInstallSingleCertificate(hStore, pCertContext, wzCertificateUniqueName);
424 if (FAILED(hr) && !fVital)
425 {
426 WcaLog(LOGMSG_STANDARD, "Could not add non-vital certificate: %ls due to error: 0x%x, continuing...", wzCertificateUniqueName, hr);
427 hr = S_FALSE;
428 }
429
430 return hr;
431}
diff --git a/src/ext/Iis/ca/scacost.h b/src/ext/Iis/ca/scacost.h
new file mode 100644
index 00000000..be92cf26
--- /dev/null
+++ b/src/ext/Iis/ca/scacost.h
@@ -0,0 +1,15 @@
1#pragma once
2// 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.
3
4
5const UINT COST_IIS_TRANSACTIONS = 10000;
6
7const UINT COST_IIS_CREATEKEY = 5000;
8const UINT COST_IIS_DELETEKEY = 5000;
9const UINT COST_IIS_WRITEVALUE = 5000;
10const UINT COST_IIS_DELETEVALUE = 5000;
11const UINT COST_IIS_CREATEAPP = 5000;
12const UINT COST_IIS_DELETEAPP = 5000;
13
14const UINT COST_CERT_ADD = 5000;
15const UINT COST_CERT_DELETE = 5000;
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}
diff --git a/src/ext/Iis/ca/scaexecIIS7.cpp b/src/ext/Iis/ca/scaexecIIS7.cpp
new file mode 100644
index 00000000..108007a1
--- /dev/null
+++ b/src/ext/Iis/ca/scaexecIIS7.cpp
@@ -0,0 +1,4205 @@
1#pragma once
2// 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.
3
4
5#include "precomp.h"
6
7//local CAData action functions
8HRESULT IIS7Site(
9 __inout LPWSTR *ppwzCustomActionData,
10 __in IAppHostWritableAdminManager *pAdminMgr
11 );
12
13HRESULT IIS7Application(
14 __inout LPWSTR *ppwzCustomActionData,
15 __in IAppHostWritableAdminManager *pAdminMgr
16 );
17HRESULT IIS7VDir(
18 __inout LPWSTR *ppwzCustomActionData,
19 __in IAppHostWritableAdminManager *pAdminMgr
20 );
21HRESULT IIS7Binding(
22 __inout LPWSTR *ppwzCustomActionData,
23 __in IAppHostWritableAdminManager *pAdminMgr
24 );
25HRESULT IIS7AppPool(
26 __inout LPWSTR *ppwzCustomActionData,
27 __in IAppHostWritableAdminManager *pAdminMgr
28 );
29HRESULT IIS7AppExtension(
30 __inout LPWSTR *ppwzCustomActionData,
31 __in IAppHostWritableAdminManager *pAdminMgr
32 );
33HRESULT IIS7MimeMap(
34 __inout LPWSTR *ppwzCustomActionData,
35 __in IAppHostWritableAdminManager *pAdminMgr
36 );
37HRESULT IIS7DirProperties(
38 __inout LPWSTR *ppwzCustomActionData,
39 __in IAppHostWritableAdminManager *pAdminMgr
40 );
41HRESULT IIS7WebLog(
42 __inout LPWSTR *ppwzCustomActionData,
43 __in IAppHostWritableAdminManager *pAdminMgr
44 );
45HRESULT IIS7FilterGlobal(
46 __inout LPWSTR *ppwzCustomActionData,
47 __in IAppHostWritableAdminManager *pAdminMgr
48 );
49HRESULT IIS7FilterSite(
50 __inout LPWSTR *ppwzCustomActionData,
51 __in IAppHostWritableAdminManager *pAdminMgr
52 );
53HRESULT IIS7HttpHeader(
54 __inout LPWSTR *ppwzCustomActionData,
55 __in IAppHostWritableAdminManager *pAdminMgr
56 );
57HRESULT IIS7WebError(
58 __inout LPWSTR *ppwzCustomActionData,
59 __in IAppHostWritableAdminManager *pAdminMgr
60 );
61HRESULT IIS7WebSvcExt(
62 __inout LPWSTR *ppwzCustomActionData,
63 __in IAppHostWritableAdminManager *pAdminMgr
64 );
65HRESULT IIS7WebProperty(
66 __inout LPWSTR *ppwzCustomActionData,
67 __in IAppHostWritableAdminManager *pAdminMgr
68 );
69HRESULT IIS7WebDir(
70 __inout LPWSTR *ppwzCustomActionData,
71 __in IAppHostWritableAdminManager *pAdminMgr
72 );
73HRESULT IIS7AspProperty(
74 __inout LPWSTR *ppwzCustomActionData,
75 __in IAppHostWritableAdminManager *pAdminMgr
76 );
77HRESULT IIS7SslBinding(
78 __inout LPWSTR *ppwzCustomActionData,
79 __in IAppHostWritableAdminManager *pAdminMgr
80 );
81//local helper functions
82
83static HRESULT GetNextAvailableSiteId(
84 IAppHostWritableAdminManager *pAdminMgr,
85 DWORD *plSiteId
86 );
87static HRESULT GetSiteElement(
88 IAppHostWritableAdminManager *pAdminMgr,
89 LPCWSTR swSiteName,
90 IAppHostElement **pSiteElement,
91 BOOL* fFound
92 );
93static HRESULT GetApplicationElement(
94 IAppHostElement *pSiteElement,
95 LPCWSTR swAppPath,
96 IAppHostElement **pAppElement,
97 BOOL* fFound
98 );
99static HRESULT GetApplicationElementForVDir(
100 IAppHostElement *pSiteElement,
101 LPCWSTR swVDirPath,
102 IAppHostElement **ppAppElement,
103 LPCWSTR *ppwzVDirSubPath,
104 BOOL* fFound
105 );
106
107static HRESULT CreateApplication(
108 IAppHostElement *pSiteElement,
109 LPCWSTR swAppPath,
110 IAppHostElement **pAppElement
111 );
112static HRESULT DeleteApplication(
113 IAppHostElement *pSiteElement,
114 LPCWSTR swAppPath
115 );
116
117static HRESULT SetAppPool(
118 IAppHostElement *pAppElementpAppElement,
119 LPCWSTR pwzAppPool
120 );
121static HRESULT CreateVdir(
122 IAppHostElement *pAppElement,
123 LPCWSTR pwzVDirPath,
124 LPCWSTR pwzVDirPhyDir
125 );
126static HRESULT DeleteVdir(
127 IAppHostElement *pAppElement,
128 LPCWSTR pwzVDirPath
129 );
130
131static HRESULT CreateBinding(
132 IAppHostElement *pSiteElem,
133 LPCWSTR pwzProtocol,
134 LPCWSTR pwzInfo
135 );
136static HRESULT DeleteBinding(
137 IAppHostElement *pSiteElem,
138 LPCWSTR pwzProtocol,
139 LPCWSTR pwzInfo
140 );
141
142static HRESULT CreateSslBinding(
143 IAppHostElement *pSiteElem,
144 LPCWSTR pwzStoreName,
145 LPCWSTR pwzEncodedCertificateHash
146 );
147static HRESULT DeleteSslBinding(
148 IAppHostElement *pSiteElem,
149 LPCWSTR pwzStoreName,
150 LPCWSTR pwzEncodedCertificateHash
151 );
152
153static HRESULT CreateSite(
154 IAppHostElementCollection *pAdminMgr,
155 LPCWSTR swSiteName,
156 IAppHostElement **pSiteElement
157 );
158
159static HRESULT DeleteAppPool(
160 IAppHostWritableAdminManager *pAdminMgr,
161 LPCWSTR swAppPoolName
162 );
163static HRESULT CreateAppPool(
164 __inout LPWSTR *ppwzCustomActionData,
165 IAppHostWritableAdminManager *pAdminMgr,
166 LPCWSTR swAppPoolName
167 );
168
169static HRESULT SetDirPropAuthentications(
170 IAppHostWritableAdminManager *pAdminMgr,
171 LPCWSTR wcConfigPath,
172 DWORD dwData
173 );
174static HRESULT SetDirPropAuthProvider(
175 IAppHostWritableAdminManager *pAdminMgr,
176 LPCWSTR wszConfigPath,
177 __in LPWSTR wszData
178 );
179static HRESULT SetDirPropDefDoc(
180 IAppHostWritableAdminManager *pAdminMgr,
181 LPCWSTR wszConfigPath,
182 __in LPWSTR wszData
183 );
184
185static HRESULT ClearLocationTag(
186 IAppHostWritableAdminManager *pAdminMgr,
187 LPCWSTR swLocationPath
188 );
189
190static HRESULT CreateWebLog(
191 IAppHostElement *pSiteElem,
192 LPCWSTR pwzFormat
193 );
194
195static HRESULT CreateGlobalFilter(
196 __inout LPWSTR *ppwzCustomActionData,
197 IAppHostElement *pSection
198 );
199static HRESULT DeleteGlobalFilter(
200 __inout LPWSTR *ppwzCustomActionData,
201 IAppHostElement *pSection
202 );
203
204static HRESULT CreateSiteFilter(
205 __inout LPWSTR *ppwzCustomActionData,
206 IAppHostWritableAdminManager *pAdminMgr
207 );
208static HRESULT DeleteSiteFilter(
209 __inout LPWSTR *ppwzCustomActionData,
210 IAppHostWritableAdminManager *pAdminMgr
211 );
212
213static HRESULT DeleteCollectionElement(
214 __in IAppHostElementCollection *pCollection,
215 __in LPCWSTR pwzElementName,
216 __in LPCWSTR pwzAttributeName,
217 __in LPCWSTR pwzAttributeValue
218 );
219
220struct SCA_WEB_ERROR_SERVER
221{
222 int iErrorCode;
223 int iSubCode;
224 WCHAR wzFile[MAX_PATH];
225 WCHAR wzLangPath[MAX_PATH];
226 int iResponseMode;
227 SCA_WEB_ERROR_SERVER *psweNext;
228};
229static HRESULT AddWebErrorToList(
230 SCA_WEB_ERROR_SERVER** ppsweList
231 );
232static void ScaWebErrorFreeList7(
233 SCA_WEB_ERROR_SERVER *psweList
234 );
235static HRESULT PopulateHttpErrors(
236 IAppHostElement *pSection,
237 SCA_WEB_ERROR_SERVER **psweList
238 );
239static HRESULT GetErrorFromList(
240 const SCA_WEB_ERROR_SERVER & we,
241 SCA_WEB_ERROR_SERVER **ppsweList,
242 SCA_WEB_ERROR_SERVER **pswe,
243 BOOL *fFound
244 );
245
246static void ConvSecToHMS(
247 int Sec,
248 __out_ecount(cchDest) LPWSTR wcTime,
249 size_t cchDest
250 );
251static void ConvSecToDHMS(
252 unsigned int Sec,
253 __out_ecount(cchDest) LPWSTR wcTime,
254 size_t cchDest
255 );
256
257////////////////////////////////////////////////////////////////////
258// ScopeBSTR: Local helper class to construct & free BSTR from LPWSTR
259//
260/////////////////////////////////////////////////////////////////////
261class ScopeBSTR
262{
263public:
264 BSTR m_str;
265
266 ScopeBSTR()
267 {
268 m_str = NULL;
269 }
270
271 ScopeBSTR( __in LPCWSTR pSrc)
272 {
273 if (pSrc == NULL)
274 {
275 m_str = NULL;
276 }
277 else
278 {
279 m_str = ::SysAllocString(pSrc);
280
281 }
282 }
283
284 ~ScopeBSTR()
285 {
286 ::SysFreeString(m_str);
287 }
288
289 operator BSTR()
290 {
291 return m_str;
292 }
293};
294
295
296/********************************************************************
297 IIS7ConfigChanges - Start of IIS7 config changes
298
299 *******************************************************************/
300HRESULT IIS7ConfigChanges(MSIHANDLE /*hInstall*/, __inout LPWSTR pwzData)
301{
302 HRESULT hr = S_OK;
303 BOOL fInitializedCom = FALSE;
304
305 IAppHostWritableAdminManager *pAdminMgr = NULL;
306
307 LPWSTR pwz = NULL;
308 LPWSTR pwzLast = NULL;
309 LPWSTR pwzBackup = NULL;
310 DWORD cchData = lstrlenW(pwzData);
311 int iAction = -1;
312
313 int iRetryCount = 0;
314
315 hr = ::CoInitialize(NULL);
316 ExitOnFailure(hr, "Failed to initialize COM");
317 fInitializedCom = TRUE;
318
319 pwz = pwzLast = pwzData;
320
321 hr = StrAllocString(&pwzBackup, pwz, 0);
322 ExitOnFailure(hr, "Failed to backup custom action data");
323
324 while (S_OK == (hr = WcaReadIntegerFromCaData(&pwz, &iAction)))
325 {
326 if (NULL == pAdminMgr)
327 {
328 hr = ::CoCreateInstance( __uuidof(AppHostWritableAdminManager),
329 NULL,
330 CLSCTX_INPROC_SERVER,
331 __uuidof(IAppHostWritableAdminManager),
332 reinterpret_cast<void**> (&pAdminMgr));
333 ExitOnFailure(hr , "Failed to open AppHostWritableAdminManager to configure IIS7");
334 }
335
336 switch (iAction)
337 {
338 case IIS_SITE:
339 {
340#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
341 hr = IIS7Site(&pwz, pAdminMgr);
342 ExitOnFailure(hr, "Failed to configure IIS site.");
343 break;
344 }
345 case IIS_APPLICATION:
346 {
347#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
348 hr = IIS7Application(&pwz, pAdminMgr);
349 ExitOnFailure(hr, "Failed to configure IIS application.");
350 break;
351 }
352 case IIS_VDIR:
353 {
354#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
355 hr = IIS7VDir(&pwz, pAdminMgr);
356 ExitOnFailure(hr, "Failed to configure IIS VDir.");
357 break;
358 }
359 case IIS_BINDING:
360 {
361#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
362 hr = IIS7Binding(&pwz, pAdminMgr);
363 ExitOnFailure(hr, "Failed to configure IIS site binding.");
364 break;
365 }
366 case IIS_APPPOOL:
367 {
368#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
369 hr = IIS7AppPool(&pwz, pAdminMgr);
370 ExitOnFailure(hr, "Failed to configure IIS appPool.");
371 break;
372 }
373 case IIS_APPEXT_BEGIN:
374 {
375#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
376 hr = IIS7AppExtension(&pwz, pAdminMgr);
377 ExitOnFailure(hr, "Failed to configure IIS AppExtension.");
378 break;
379 }
380 case IIS_MIMEMAP_BEGIN:
381 {
382#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
383 hr = IIS7MimeMap(&pwz, pAdminMgr);
384 ExitOnFailure(hr, "Failed to configure IIS MimeMap.");
385 break;
386 }
387 case IIS_DIRPROP_BEGIN:
388 {
389#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
390 hr = IIS7DirProperties(&pwz, pAdminMgr);
391 ExitOnFailure(hr, "Failed to configure IIS DirProperties.");
392 break;
393 }
394 case IIS_WEBLOG:
395 {
396#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
397 hr = IIS7WebLog(&pwz, pAdminMgr);
398 ExitOnFailure(hr, "Failed to configure IIS WebLog.");
399 break;
400 }
401 case IIS_FILTER_GLOBAL_BEGIN:
402 {
403#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
404 hr = IIS7FilterGlobal(&pwz, pAdminMgr);
405 ExitOnFailure(hr, "Failed to configure IIS filter global.");
406 break;
407 }
408 case IIS_FILTER_BEGIN:
409 {
410#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
411 hr = IIS7FilterSite(&pwz, pAdminMgr);
412 ExitOnFailure(hr, "Failed to configure IIS Filter.");
413 break;
414 }
415 case IIS_HTTP_HEADER_BEGIN:
416 {
417#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
418 hr = IIS7HttpHeader(&pwz, pAdminMgr);
419 ExitOnFailure(hr, "Failed to configure IIS http Header.");
420 break;
421 }
422 case IIS_WEBERROR_BEGIN:
423 {
424#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
425 hr = IIS7WebError(&pwz, pAdminMgr);
426 ExitOnFailure(hr, "Failed to configure IIS http Errors.");
427 break;
428 }
429 case IIS_WEB_SVC_EXT:
430 {
431#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
432 hr = IIS7WebSvcExt(&pwz, pAdminMgr);
433 ExitOnFailure(hr, "Failed to configure IIS web svc ext.");
434 break;
435 }
436 case IIS_PROPERTY:
437 {
438#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
439 hr = IIS7WebProperty(&pwz, pAdminMgr);
440 ExitOnFailure(hr, "Failed to configure IIS web property.");
441 break;
442 }
443 case IIS_WEBDIR:
444 {
445#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
446 hr = IIS7WebDir(&pwz, pAdminMgr);
447 ExitOnFailure(hr, "Failed to configure IIS web directory.");
448 break;
449 }
450 case IIS_ASP_BEGIN:
451 {
452#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
453 hr = IIS7AspProperty(&pwz, pAdminMgr);
454 ExitOnFailure(hr, "Failed to configure IIS Asp property.");
455 break;
456 }
457 case IIS_SSL_BINDING:
458#pragma prefast(suppress:26010, "This is a prefast issue - pAdminMgr is correctly allocated")
459 hr = IIS7SslBinding(&pwz, pAdminMgr);
460 ExitOnFailure(hr, "Failed to configure IIS SSL binding.");
461 break;
462
463 default:
464 ExitOnFailure(hr = E_UNEXPECTED, "IIS7ConfigChanges: Unexpected IIS Config action specified: %d", iAction);
465 break;
466 }
467 if (S_OK == hr)
468 {
469 // commit config changes now to close out IIS Admin changes,
470 // the Rollback or Commit defered CAs will determine final commit status.
471 hr = pAdminMgr->CommitChanges();
472
473 // Our transaction may have been interrupted.
474 if (hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION) || hr == HRESULT_FROM_WIN32(ERROR_TRANSACTIONAL_CONFLICT))
475 {
476 WcaLog(LOGMSG_VERBOSE, "Sharing violation or transactional conflict during attempt to save changes to applicationHost.config");
477 if (++iRetryCount > 30)
478 {
479 if (IDRETRY == WcaErrorMessage(msierrIISFailedCommitInUse, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0))
480 {
481 iRetryCount = 0;
482 }
483 else
484 {
485 ExitOnFailure(hr, "Failed to Commit IIS Config Changes, in silent mode or user has chosen to cancel");
486 }
487 }
488
489 // Throw away the changes since IIS has no way to remove uncommited changes from an AdminManager.
490 ReleaseNullObject(pAdminMgr);
491
492 // Restore our CA data backup
493 pwz = pwzLast;
494 hr = ::StringCchCopyW(pwz, cchData - (pwz - pwzData) + 1, pwzBackup);
495 ExitOnFailure(hr , "Failed to restore custom action data backup");
496
497 }
498 else if (FAILED(hr))
499 {
500 ExitOnFailure(hr , "Failed to Commit IIS Config Changes");
501 }
502 else
503 {
504 // store a backup of CA data @ the last place that we successfully commited changes unless we are done.
505 if(NULL != pwz)
506 {
507 pwzLast = pwz;
508 hr = StrAllocString(&pwzBackup, pwz, 0);
509 ExitOnFailure(hr, "Failed to backup custom action data");
510 }
511 }
512 }
513 }
514 if (E_NOMOREITEMS == hr) // If there are no more items, all is well
515 {
516 hr = S_OK;
517 }
518LExit:
519 ReleaseObject(pAdminMgr);
520 ReleaseStr(pwzBackup);
521
522 if (fInitializedCom)
523 {
524 ::CoUninitialize();
525 }
526
527 return hr;
528}
529//-------------------------------------------------------------------------------------------------
530// IIS7AspProperty
531// Called by WriteIIS7ConfigChanges
532// Processes asp properties for WebApplication
533//
534//-------------------------------------------------------------------------------------------------
535
536HRESULT IIS7AspProperty(
537 __inout LPWSTR *ppwzCustomActionData,
538 __in IAppHostWritableAdminManager *pAdminMgr
539 )
540{
541 HRESULT hr = S_OK;
542
543 int iAction = -1;
544 int iData = 0;
545
546 LPWSTR pwzData = NULL;
547 LPWSTR pwzSiteName = NULL;
548 LPWSTR pwzPathName = NULL;
549 LPWSTR pwzLocationPath = NULL;
550 WCHAR wcTime[60];
551
552 IAppHostElement *pSection = NULL;
553 IAppHostElement *pElement = NULL;
554
555 //read web site key
556 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
557 ExitOnFailure(hr, "Failed read webDir webkey");
558
559 //read path key
560 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzPathName);
561 ExitOnFailure(hr, "Failed read webDir path");
562
563 //Construct Location path
564 hr = StrAllocFormatted(&pwzLocationPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzSiteName);
565 ExitOnFailure(hr, "failed to format webDir location");
566 //
567 //Do not append trailing '/' for default vDir
568 //
569 if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzPathName, -1, L"/", -1))
570 {
571 hr = StrAllocConcat(&pwzLocationPath, L"/", 0);
572 ExitOnFailure(hr, "failed to copy location WebDir '/'");
573 hr = StrAllocConcat(&pwzLocationPath, pwzPathName, 0);
574 ExitOnFailure(hr, "failed to copy location WebDir path");
575 }
576
577 //get asp section at config path location tag
578 hr = pAdminMgr->GetAdminSection( ScopeBSTR(IIS_CONFIG_ASP_SECTION), pwzLocationPath, &pSection);
579 ExitOnFailure(hr, "Failed get httpErrors section");
580
581 // Get action
582 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
583 ExitOnFailure(hr, "Failed to read property action");
584
585 while (IIS_ASP_END != iAction)
586 {
587 switch (iAction)
588 {
589 case IIS_ASP_SESSIONSTATE:
590 {
591 //system.webServer/asp /session | allowSessionState
592 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
593 ExitOnFailure(hr, "Failed to read asp session state");
594 hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_SESSION), &pElement);
595 ExitOnFailure(hr, "Failed to get asp session element");
596 hr = Iis7PutPropertyBool( pElement, IIS_CONFIG_ALLOWSTATE, iData);
597 ExitOnFailure(hr, "Failed to put asp session value");
598 ReleaseNullObject(pElement);
599 break;
600 }
601 case IIS_ASP_SESSIONTIMEOUT:
602 {
603 //system.webServer/asp /session | timeout
604 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
605 ExitOnFailure(hr, "Failed to read asp session timeout");
606 hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_SESSION), &pElement);
607 ExitOnFailure(hr, "Failed to get asp session timeout");
608 *wcTime = '\0';
609 ConvSecToHMS(iData * 60, wcTime, countof( wcTime));
610 hr = Iis7PutPropertyString( pElement, IIS_CONFIG_TIMEOUT, wcTime);
611 ExitOnFailure(hr, "Failed to put asp timeout value");
612 ReleaseNullObject(pElement);
613 break;
614 }
615 case IIS_ASP_BUFFER:
616 {
617 //system.webServer/asp | bufferingOn
618 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
619 ExitOnFailure(hr, "Failed to read asp bufferingOn");
620 hr = Iis7PutPropertyBool( pSection, IIS_CONFIG_BUFFERING, iData);
621 ExitOnFailure(hr, "Failed to put asp bufferingOn value");
622 break;
623 }
624 case IIS_ASP_PARENTPATHS:
625 {
626 //system.webServer/asp | enableParentPaths
627 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
628 ExitOnFailure(hr, "Failed to read asp ParentPaths");
629 hr = Iis7PutPropertyBool( pSection, IIS_CONFIG_PARENTPATHS, iData);
630 ExitOnFailure(hr, "Failed to put asp ParentPaths value");
631 break;
632 }
633 case IIS_ASP_SCRIPTLANG:
634 {
635 //system.webServer/asp | scriptLanguage
636 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
637 ExitOnFailure(hr, "Failed to read asp scriptLanguage");
638 hr = Iis7PutPropertyString( pSection, IIS_CONFIG_SCRIPTLANG, pwzData);
639 ExitOnFailure(hr, "Failed to put asp scriptLanguage value");
640 break;
641 }
642 case IIS_ASP_SCRIPTTIMEOUT:
643 {
644 //system.webServer/asp /limits | scriptTimeout
645 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
646 ExitOnFailure(hr, "Failed to read asp scriptTimeout");
647 hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_LIMITS), &pElement);
648 ExitOnFailure(hr, "Failed to get asp session element");
649 *wcTime = '\0';
650 ConvSecToHMS(iData, wcTime, countof( wcTime));
651 hr = Iis7PutPropertyString( pElement, IIS_CONFIG_SCRIPTTIMEOUT, wcTime);
652 ExitOnFailure(hr, "Failed to put asp scriptTimeout value");
653 ReleaseNullObject(pElement);
654 break;
655
656 }
657 case IIS_ASP_SCRIPTSERVERDEBUG:
658 {
659 //system.webServer/asp | appAllowDebugging
660 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
661 ExitOnFailure(hr, "Failed to read asp appAllowDebugging");
662 hr = Iis7PutPropertyBool( pSection, IIS_CONFIG_ALLOWDEBUG, iData);
663 ExitOnFailure(hr, "Failed to put asp appAllowDebugging value");
664 break;
665 }
666 case IIS_ASP_SCRIPTCLIENTDEBUG:
667 {
668 //system.webServer/asp | appAllowClientDebug
669 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
670 ExitOnFailure(hr, "Failed to read asp appAllowClientDebug");
671 hr = Iis7PutPropertyBool( pSection, IIS_CONFIG_ALLOWCLIENTDEBUG, iData);
672 ExitOnFailure(hr, "Failed to put asp appAllowClientDebug value");
673 break;
674 }
675 default:
676 {
677 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for asp properties");
678 break;
679 }
680 }
681 // Get next action
682 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
683 ExitOnFailure(hr, "Failed to read asp prop action");
684 }
685
686LExit:
687 ReleaseStr(pwzData);
688 ReleaseStr(pwzSiteName);
689 ReleaseStr(pwzPathName);
690 ReleaseStr(pwzLocationPath);
691 ReleaseObject(pSection);
692 ReleaseObject(pElement);
693
694 return hr;
695}
696
697//-------------------------------------------------------------------------------------------------
698// IIS7WebDir
699// Called by WriteIIS7ConfigChanges
700// Processes WebDir
701//
702//-------------------------------------------------------------------------------------------------
703HRESULT IIS7WebDir(
704 __inout LPWSTR *ppwzCustomActionData,
705 __in IAppHostWritableAdminManager *pAdminMgr
706 )
707{
708 HRESULT hr = S_OK;
709
710 int iAction = -1;
711
712 LPWSTR pwzSiteName = NULL;
713 LPWSTR pwzPathName = NULL;
714 LPWSTR pwzLocationPath = NULL;
715
716 // Get action
717 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
718 ExitOnFailure(hr, "Failed to read property action");
719
720 //read web site key
721 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
722 ExitOnFailure(hr, "Failed read webDir webkey");
723
724 //read path key
725 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzPathName);
726 ExitOnFailure(hr, "Failed read webDir path");
727
728 switch (iAction)
729 {
730 case IIS_CREATE:
731 {
732 //no action needed for create since WebDir has a
733 //WebDirProperties element that will create and populate
734 //location tag
735 break;
736 }
737 case IIS_DELETE:
738 {
739 //Construct Location path
740 hr = StrAllocString(&pwzLocationPath, pwzSiteName, 0);
741 ExitOnFailure(hr, "failed to copy location WebDir web name");
742 //
743 //Do not append trailing '/' for default vDir
744 //
745 if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzPathName, -1, L"/", -1))
746 {
747 hr = StrAllocConcat(&pwzLocationPath, L"/", 0);
748 ExitOnFailure(hr, "failed to copy location WebDir '/'");
749 hr = StrAllocConcat(&pwzLocationPath, pwzPathName, 0);
750 ExitOnFailure(hr, "failed to copy location WebDir path");
751 }
752 // and delete location tag for this application
753 hr = ClearLocationTag(pAdminMgr, pwzLocationPath);
754 ExitOnFailure(hr, "failed to clear location tag for %ls", pwzLocationPath)
755 break;
756 }
757 default:
758 {
759 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for WebDir");
760 break;
761 }
762 }
763LExit:
764 ReleaseStr(pwzSiteName);
765 ReleaseStr(pwzPathName);
766 ReleaseStr(pwzLocationPath);
767
768 return hr;
769}
770
771//-------------------------------------------------------------------------------------------------
772// IIS7WebProperty
773// Called by WriteIIS7ConfigChanges
774// Processes isapiCgiRestriction
775//
776//-------------------------------------------------------------------------------------------------
777HRESULT IIS7WebProperty(
778 __inout LPWSTR *ppwzCustomActionData,
779 __in IAppHostWritableAdminManager *pAdminMgr
780 )
781{
782 HRESULT hr = S_OK;
783
784 int iAction = -1;
785 int iData = 0;
786
787 IAppHostElement *pSection = NULL;
788
789 // Get action
790 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
791 ExitOnFailure(hr, "Failed to read property action");
792
793 switch (iAction)
794 {
795 case IIS_PROPERTY_MAXBAND:
796 {
797 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
798 ExitOnFailure(hr, "Failed to read property max band");
799 //set value at system.applicationHost/webLimits | maxGlobalBandwidth
800 //Get IIS config section
801 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_WEBLIMITS_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSection);
802 ExitOnFailure(hr, "Failed get isapiCgiRestriction section");
803 if (!pSection)
804 {
805 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
806 ExitOnFailure(hr, "Failed get isapiCgiRestriction section object");
807 }
808 hr = Iis7PutPropertyInteger(pSection, IIS_CONFIG_WEBLIMITS_MAXBAND, iData);
809
810 break;
811 }
812 case IIS_PROPERTY_LOGUTF8:
813 {
814 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
815 ExitOnFailure(hr, "Failed to read property log");
816 //set value at system.applicationHost/log | logInUTF8
817 //Get IIS config section
818 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_LOG_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSection);
819 ExitOnFailure(hr, "Failed get isapiCgiRestriction section");
820 if (!pSection)
821 {
822 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
823 ExitOnFailure(hr, "Failed get isapiCgiRestriction section object");
824 }
825 hr = Iis7PutPropertyBool(pSection, IIS_CONFIG_LOG_UTF8, iData);
826
827 break;
828 }
829 default:
830 {
831 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for Web Property");
832 break;
833 }
834 }
835
836LExit:
837 ReleaseObject(pSection);
838
839 return hr;
840}
841
842//-------------------------------------------------------------------------------------------------
843// IIS7WebSvcExt
844// Called by WriteIIS7ConfigChanges
845// Processes isapiCgiRestriction
846//
847//-------------------------------------------------------------------------------------------------
848HRESULT IIS7WebSvcExt(
849 __inout LPWSTR *ppwzCustomActionData,
850 __in IAppHostWritableAdminManager *pAdminMgr
851 )
852{
853 HRESULT hr = S_OK;
854
855 int iAction = -1;
856 int iData = 0;
857 BOOL fFound = FALSE;
858 LPWSTR pwzData = NULL;
859 LPWSTR pwzPath = NULL;
860
861 IAppHostElement *pSection = NULL;
862 IAppHostElement *pElement = NULL;
863 IAppHostElementCollection *pCollection = NULL;
864
865 // Get action
866 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
867 ExitOnFailure(hr, "Failed to read WebSvcExt action");
868
869 //get path
870 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzPath);
871 ExitOnFailure(hr, "Failed to read WebSvcExt key");
872
873 //Get IIS config section
874 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_RESTRICTION_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSection);
875 ExitOnFailure(hr, "Failed get isapiCgiRestriction section");
876 if (!pSection)
877 {
878 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
879 ExitOnFailure(hr, "Failed get isapiCgiRestriction section object");
880 }
881 //get collection
882 hr = pSection->get_Collection(&pCollection);
883 ExitOnFailure(hr, "Failed get isapiCgiRestriction collection");
884
885 //find element
886 hr = Iis7FindAppHostElementPath(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_PATH, pwzPath, &pElement, NULL);
887 ExitOnFailure(hr, "Failed get isapiCgiRestriction element");
888 fFound = (NULL != pElement);
889
890 switch (iAction)
891 {
892 case IIS_CREATE:
893 {
894 if (!fFound)
895 {
896 //create a restriction element
897 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pElement);
898 ExitOnFailure(hr, "Failed create isapiCgiRestriction element");
899 //put path
900 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PATH, pwzPath);
901 ExitOnFailure(hr, "Failed set isapiCgiRestriction path property");
902 }
903 //update common properties
904
905 //update allowed
906 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
907 ExitOnFailure(hr, "Failed to read WebSvcExt allowed");
908 hr = Iis7PutPropertyBool(pElement, IIS_CONFIG_ALLOWED, iData);
909 ExitOnFailure(hr, "Failed set isapiCgiRestriction allowed property");
910
911 //update groupId
912 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
913 ExitOnFailure(hr, "Failed to read WebSvcExt group ID");
914 if (*pwzData)
915 {
916 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_GROUPID, pwzData);
917 ExitOnFailure(hr, "Failed set isapiCgiRestriction groupId property");
918 }
919 //update description
920 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
921 ExitOnFailure(hr, "Failed to read WebSvcExt description");
922 if (*pwzData)
923 {
924 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_DESC, pwzData);
925 ExitOnFailure(hr, "Failed set isapiCgiRestriction description property");
926 }
927 // add element if new
928 if (!fFound)
929 {
930 hr = pCollection->AddElement(pElement);
931 ExitOnFailure(hr, "Failed add isapiCgiRestriction element");
932 }
933
934 break;
935 }
936 case IIS_DELETE:
937 {
938 hr = DeleteCollectionElement(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_PATH, pwzPath);
939 ExitOnFailure(hr, "Failed delete isapiCgiRestriction element");
940 break;
941 }
942 default:
943 {
944 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for WebSvcExt");
945 break;
946 }
947 }
948
949LExit:
950 ReleaseStr(pwzPath);
951 ReleaseStr(pwzData);
952 ReleaseObject(pSection);
953 ReleaseObject(pElement);
954 ReleaseObject(pCollection);
955
956 return hr;
957
958}
959
960//-------------------------------------------------------------------------------------------------
961// IIS7WebError
962// Called by WriteIIS7ConfigChanges
963// Processes http header CA Data
964//
965//-------------------------------------------------------------------------------------------------
966
967HRESULT IIS7WebError(
968 __inout LPWSTR *ppwzCustomActionData,
969 __in IAppHostWritableAdminManager *pAdminMgr
970 )
971{
972 HRESULT hr = S_OK;
973 LPWSTR pwzConfigPath = NULL;
974 LPWSTR pwzSiteName = NULL;
975 LPWSTR pwzAppName = NULL;
976
977 IAppHostElement *pElement = NULL;
978 IAppHostElement *pSection = NULL;
979 IAppHostElementCollection *pCollection = NULL;
980
981 SCA_WEB_ERROR_SERVER *psweList = NULL;
982 SCA_WEB_ERROR_SERVER* pswe = NULL;
983 SCA_WEB_ERROR_SERVER we;
984 BOOL fFound = FALSE;
985
986 int iAction = -1;
987 LPWSTR pwzData = NULL;
988
989 //read web site key
990 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
991 ExitOnFailure(hr, "Failed read web error site name");
992
993 //read app key
994 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzAppName);
995 ExitOnFailure(hr, "Failed read web error app name");
996
997 //Construct config root path
998 hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzSiteName);
999 ExitOnFailure(hr, "failed to format web error config path");
1000
1001 if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzAppName, -1, L"/", -1))
1002 {
1003 hr = StrAllocConcat(&pwzConfigPath, L"/", 0);
1004 ExitOnFailure(hr, "failed to copy web error config path delim");
1005 hr = StrAllocConcat(&pwzConfigPath, pwzAppName, 0);
1006 ExitOnFailure(hr, "failed to app name to web error config path");
1007 }
1008
1009 //get httpErrors section at config path location tag
1010 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HTTPERRORS_SECTION), pwzConfigPath, &pSection);
1011 ExitOnFailure(hr, "Failed get httpErrors section");
1012
1013 //get existing httpErrors list & clear collection
1014 hr = PopulateHttpErrors(pSection, &psweList);
1015 ExitOnFailure(hr, "Failed to read httpErrors list");
1016
1017 //get collection
1018 hr = pSection->get_Collection(&pCollection);
1019 ExitOnFailure(hr, "Failed get httpErrors collection");
1020
1021 DWORD cErrors = 0;
1022 hr = pCollection->get_Count(&cErrors);
1023
1024 // Get web error action
1025 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
1026 ExitOnFailure(hr, "Failed to read filter action");
1027 while (IIS_WEBERROR_END != iAction)
1028 {
1029 //Process property action
1030 if (IIS_WEBERROR == iAction)
1031 {
1032 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &(we.iErrorCode));
1033 ExitOnFailure(hr, "failed to get httpErrors ErrorCode");
1034
1035 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &(we.iSubCode));
1036 ExitOnFailure(hr, "failed to get httpErrors SubCode");
1037 //0 is the sub error code wild card for IIS6, change to -1 for IIS7
1038 if (we.iSubCode == 0)
1039 {
1040 we.iSubCode = -1;
1041 }
1042 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
1043 ExitOnFailure(hr, "Failed to get httpErrors File");
1044 hr = ::StringCchCopyW(we.wzFile, countof(we.wzFile), pwzData);
1045 ExitOnFailure(hr, "Failed to copy httpErrors File");
1046
1047 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &(we.iResponseMode));
1048 ExitOnFailure(hr, "Failed to get httpErrors File code");
1049
1050 fFound = FALSE;
1051 hr = GetErrorFromList( we, &psweList, &pswe, &fFound);
1052 if (!fFound)
1053 {
1054 hr = AddWebErrorToList(&psweList);
1055 ExitOnFailure(hr, "failed to add web error to list");
1056 pswe = psweList;
1057 }
1058 else
1059 {
1060 //if overwriting existing http errors element then clear lang path
1061 hr = ::StringCchCopyW(pswe->wzLangPath, countof(pswe->wzLangPath), L"");
1062 ExitOnFailure(hr, "Failed to copy httpErrors lang path value");
1063 }
1064 pswe->iErrorCode = we.iErrorCode;
1065 pswe->iSubCode = we.iSubCode;
1066 hr = ::StringCchCopyW(pswe->wzFile, countof(pswe->wzFile), we.wzFile);
1067 ExitOnFailure(hr, "Failed to copy httpErrors File value");
1068 pswe->iResponseMode = we.iResponseMode;
1069
1070 }
1071 else
1072 {
1073 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for http header");
1074 }
1075
1076 // Get AppExt action
1077 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
1078 ExitOnFailure(hr, "Failed to read filter action");
1079 }
1080
1081 //No inheritance - put a clear in at this loc tag
1082 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_CLEAR), &pElement);
1083 ExitOnFailure(hr, "Failed create httpErrors clear");
1084 hr = pCollection->AddElement(pElement);
1085 ExitOnFailure(hr, "Failed add httpErrors clear");
1086
1087 //now we have merged new, from MSI, http errors with global list
1088 //write this back out at location tag.
1089 // Loop through the HTTP headers
1090 for ( pswe = psweList; pswe; pswe = pswe->psweNext)
1091 {
1092 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ERROR), &pElement);
1093 ExitOnFailure(hr, "Failed create httpErrors element");
1094
1095 // status code
1096 hr = Iis7PutPropertyInteger(pElement, IIS_CONFIG_STATUSCODE, pswe->iErrorCode);
1097 ExitOnFailure(hr, "Failed set httpErrors code value");
1098
1099 //sub status
1100 hr = Iis7PutPropertyInteger(pElement, IIS_CONFIG_SUBSTATUS, pswe->iSubCode);
1101 ExitOnFailure(hr, "Failed set httpErrors sub code value");
1102
1103 //lang path
1104 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_LANGPATH, pswe->wzLangPath);
1105 ExitOnFailure(hr, "Failed set httpErrors lang path value");
1106
1107 //path
1108 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PATH, pswe->wzFile);
1109 ExitOnFailure(hr, "Failed set httpErrors path value");
1110
1111 //response mode
1112 hr = Iis7PutPropertyInteger(pElement, IIS_CONFIG_RESPMODE, pswe->iResponseMode);
1113 ExitOnFailure(hr, "Failed set httpErrors resp mode value");
1114
1115 //add the element
1116 hr = pCollection->AddElement(pElement);
1117 ExitOnFailure(hr, "Failed add httpErrors element");
1118 ReleaseNullObject(pElement);
1119 }
1120
1121LExit:
1122 ScaWebErrorFreeList7(psweList);
1123
1124 ReleaseStr(pwzConfigPath);
1125 ReleaseStr(pwzSiteName);
1126 ReleaseStr(pwzAppName);
1127 ReleaseStr(pwzData);
1128 ReleaseObject(pElement);
1129 ReleaseObject(pSection);
1130 ReleaseObject(pCollection);
1131
1132 return hr;
1133}
1134
1135static HRESULT PopulateHttpErrors(IAppHostElement *pSection, SCA_WEB_ERROR_SERVER **ppsweList)
1136{
1137 HRESULT hr = S_OK;
1138
1139 IAppHostElement *pElement = NULL;
1140 IAppHostElementCollection *pCollection = NULL;
1141 IAppHostProperty *pProperty = NULL;
1142
1143 DWORD cErrors = 0;
1144 SCA_WEB_ERROR_SERVER *pswe = NULL;
1145
1146 VARIANT vPropValue;
1147 VARIANT vtIndex;
1148
1149 VariantInit(&vPropValue);
1150 VariantInit(&vtIndex);
1151
1152 hr = pSection->get_Collection(&pCollection);
1153 ExitOnFailure(hr, "Failed get httpErrors collection");
1154
1155 hr = pCollection->get_Count(&cErrors);
1156 ExitOnFailure(hr, "Failed get sites collection count");
1157
1158 vtIndex.vt = VT_UI4;
1159 for (DWORD i = 0; i < cErrors; ++i)
1160 {
1161 vtIndex.ulVal = i;
1162 hr = pCollection->get_Item(vtIndex , &pElement);
1163 ExitOnFailure(hr, "Failed get httpErrors collection item");
1164
1165 hr = AddWebErrorToList(ppsweList);
1166 ExitOnFailure(hr, "Failed add web error list item");
1167 pswe = *ppsweList;
1168
1169 //get all properties
1170 //
1171 // statusCode UINT
1172 // subStatusCode INT
1173 // prefixLanguageFilePath type="string"
1174 // path type="string"
1175 // responseMode type="enum" defaultValue="File">
1176 // <enum name="File" value="0" />
1177 // <enum name="ExecuteURL" value="1" />
1178 // <enum name="Redirect" value="2" />
1179
1180 // status code
1181 hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_STATUSCODE), &pProperty);
1182 ExitOnFailure(hr, "Failed get httpErrors code property");
1183 hr = pProperty->get_Value(&vPropValue);
1184 ExitOnFailure(hr, "Failed get httpErrors code value");
1185 pswe->iErrorCode = vPropValue.uintVal;
1186 ReleaseVariant(vPropValue);
1187
1188 //sub status
1189 hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_SUBSTATUS), &pProperty);
1190 ExitOnFailure(hr, "Failed get httpErrors sub code property");
1191 hr = pProperty->get_Value(&vPropValue);
1192 ExitOnFailure(hr, "Failed get httpErrors sub code value");
1193 pswe->iSubCode = vPropValue.intVal;
1194 ReleaseVariant(vPropValue);
1195
1196 //lang path
1197 hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_LANGPATH), &pProperty);
1198 ExitOnFailure(hr, "Failed get httpErrors lang path property");
1199 hr = pProperty->get_Value(&vPropValue);
1200 ExitOnFailure(hr, "Failed get httpErrors lang path value");
1201 hr = ::StringCchCopyW(pswe->wzLangPath, countof(pswe->wzLangPath), vPropValue.bstrVal);
1202 ExitOnFailure(hr, "Failed to copy httpErrors lang path");
1203 ReleaseVariant(vPropValue);
1204
1205 //path
1206 hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_PATH), &pProperty);
1207 ExitOnFailure(hr, "Failed get httpErrors path property");
1208 hr = pProperty->get_Value(&vPropValue);
1209 ExitOnFailure(hr, "Failed get httpErrors path value");
1210 hr = ::StringCchCopyW(pswe->wzFile, countof(pswe->wzFile), vPropValue.bstrVal);
1211 ExitOnFailure(hr, "Failed to copy httpErrors File");
1212 ReleaseVariant(vPropValue);
1213
1214 //response mode
1215 hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_RESPMODE), &pProperty);
1216 ExitOnFailure(hr, "Failed get httpErrors resp mode property");
1217 hr = pProperty->get_Value(&vPropValue);
1218 ExitOnFailure(hr, "Failed get httpErrors resp mode value");
1219 pswe->iResponseMode = vPropValue.intVal;
1220 ReleaseVariant(vPropValue);
1221
1222 ReleaseNullObject(pElement);
1223 ReleaseNullObject(pProperty);
1224 }
1225
1226 //remove the elements from connection so we can add back later
1227 hr = pCollection->Clear();
1228 ExitOnFailure(hr, "Failed clear httpErrors collection");
1229
1230LExit:
1231 ReleaseVariant(vPropValue);
1232 ReleaseObject(pProperty);
1233 ReleaseObject(pElement);
1234 ReleaseObject(pCollection);
1235
1236 return hr;
1237}
1238
1239static void ScaWebErrorFreeList7(SCA_WEB_ERROR_SERVER *psweList)
1240{
1241 SCA_WEB_ERROR_SERVER *psweDelete = psweList;
1242 while (psweList)
1243 {
1244 psweDelete = psweList;
1245 psweList = psweList->psweNext;
1246
1247 MemFree(psweDelete);
1248 }
1249}
1250static HRESULT AddWebErrorToList(SCA_WEB_ERROR_SERVER **ppsweList)
1251{
1252 HRESULT hr = S_OK;
1253
1254 SCA_WEB_ERROR_SERVER* pswe = static_cast<SCA_WEB_ERROR_SERVER*>(MemAlloc(sizeof(SCA_WEB_ERROR_SERVER), TRUE));
1255
1256 ExitOnNull(pswe, hr, E_OUTOFMEMORY, "failed to allocate memory for new web error list element");
1257
1258 pswe->psweNext = *ppsweList;
1259 *ppsweList = pswe;
1260
1261LExit:
1262 return hr;
1263}
1264static HRESULT GetErrorFromList( const SCA_WEB_ERROR_SERVER& we,
1265 SCA_WEB_ERROR_SERVER **ppsweList,
1266 SCA_WEB_ERROR_SERVER **ppswe,
1267 BOOL *fFound)
1268{
1269 HRESULT hr = S_OK;
1270
1271 *fFound = FALSE;
1272
1273 SCA_WEB_ERROR_SERVER *pswe;
1274
1275 for ( pswe = *ppsweList; pswe; pswe = pswe->psweNext)
1276 {
1277 if ((pswe->iErrorCode == we.iErrorCode) && (pswe->iSubCode == we.iSubCode))
1278 {
1279 *fFound = TRUE;
1280 *ppswe = pswe;
1281 break;
1282 }
1283 }
1284
1285 return hr;
1286}
1287
1288//-------------------------------------------------------------------------------------------------
1289// IIS7HttpHeader
1290// Called by WriteIIS7ConfigChanges
1291// Processes http header CA Data
1292//
1293//-------------------------------------------------------------------------------------------------
1294
1295HRESULT IIS7HttpHeader(
1296 __inout LPWSTR *ppwzCustomActionData,
1297 __in IAppHostWritableAdminManager *pAdminMgr
1298 )
1299{
1300 HRESULT hr = S_OK;
1301 LPWSTR pwzConfigPath = NULL;
1302 LPWSTR pwzSiteName = NULL;
1303 LPWSTR pwzAppName = NULL;
1304
1305 LPWSTR pwzHeaderName = NULL;
1306 LPWSTR pwzHeaderValue = NULL;
1307
1308 IAppHostElement *pElement = NULL;
1309 IAppHostElement *pSection = NULL;
1310 IAppHostElementCollection *pCollection = NULL;
1311 IAppHostElement *pElementHeaders = NULL;
1312
1313 int iAction = -1;
1314 BOOL fFound = FALSE;
1315
1316 //read web site key
1317 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
1318 ExitOnFailure(hr, "Failed read header web site name");
1319
1320 //read app key
1321 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzAppName);
1322 ExitOnFailure(hr, "Failed read header appkey");
1323
1324 //Construct config root path
1325 hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzSiteName);
1326 ExitOnFailure(hr, "failed to format web error config path");
1327
1328 if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzAppName, -1, L"/", -1))
1329 {
1330 hr = StrAllocConcat(&pwzConfigPath, L"/", 0);
1331 ExitOnFailure(hr, "failed to copy web error config path delim");
1332 hr = StrAllocConcat(&pwzConfigPath, pwzAppName, 0);
1333 ExitOnFailure(hr, "failed to app name to web error config path");
1334 }
1335
1336 //get admin handlers section at config path location tag
1337 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HTTPPROTO_SECTION), pwzConfigPath, &pSection);
1338 ExitOnFailure(hr, "Failed get http protocol section");
1339
1340 hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_HEADERS), &pElementHeaders);
1341 ExitOnFailure(hr, "Failed get http customHeaders section");
1342
1343 hr = pElementHeaders->get_Collection(&pCollection);
1344 ExitOnFailure(hr, "Failed get http customHeaders collection");
1345
1346 // Get filter action
1347 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
1348 ExitOnFailure(hr, "Failed to read filter action");
1349 while (IIS_HTTP_HEADER_END != iAction)
1350 {
1351 //Process property action
1352 if (IIS_HTTP_HEADER == iAction)
1353 {
1354 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzHeaderName);
1355 ExitOnFailure(hr, "Fail to read httpHeader name");
1356
1357 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzHeaderValue);
1358 ExitOnFailure(hr, "Fail to read httpHeader value");
1359
1360 hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_NAME, pwzHeaderName, &pElement, NULL);
1361 ExitOnFailure(hr, "Failed get isapiCgiRestriction element");
1362 fFound = (NULL != pElement);
1363
1364 if (!fFound)
1365 {
1366 //make a new element
1367 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pElement);
1368 ExitOnFailure(hr, "Failed to create filter config element");
1369
1370 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_NAME, pwzHeaderName);
1371 ExitOnFailure(hr, "Failed to set header name");
1372 }
1373
1374 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_VALUE, pwzHeaderValue);
1375 ExitOnFailure(hr, "Failed to set header Value");
1376
1377 if (!fFound)
1378 {
1379 hr = pCollection->AddElement(pElement);
1380 ExitOnFailure(hr, "Failed add http header");
1381 }
1382
1383 }
1384 else
1385 {
1386 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for http header");
1387 }
1388
1389 // Get AppExt action
1390 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
1391 ExitOnFailure(hr, "Failed to read filter action");
1392 }
1393
1394LExit:
1395 ReleaseStr(pwzConfigPath);
1396 ReleaseStr(pwzSiteName);
1397 ReleaseStr(pwzAppName);
1398 ReleaseStr(pwzHeaderName);
1399 ReleaseStr(pwzHeaderValue);
1400 ReleaseObject(pElementHeaders);
1401 ReleaseObject(pElement);
1402 ReleaseObject(pSection);
1403 ReleaseObject(pCollection);
1404
1405 return hr;
1406}
1407
1408//-------------------------------------------------------------------------------------------------
1409// IIS7FilterGlobal
1410// Called by WriteIIS7ConfigChanges
1411// Processes Filter CA Data
1412//
1413//-------------------------------------------------------------------------------------------------
1414HRESULT IIS7FilterGlobal(
1415 __inout LPWSTR *ppwzCustomActionData,
1416 __in IAppHostWritableAdminManager *pAdminMgr
1417 )
1418{
1419 HRESULT hr = S_OK;
1420 int iAction = 0;
1421
1422 IAppHostElement *pSection = NULL;
1423
1424 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_ISAPI_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSection);
1425 ExitOnFailure(hr, "Failed get sites section");
1426
1427 if (!pSection)
1428 {
1429 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
1430 ExitOnFailure(hr, "Failed get isapiFilters section object");
1431 }
1432
1433 // Get filter action
1434 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
1435 ExitOnFailure(hr, "Failed to read filter action");
1436
1437 while (IIS_FILTER_END != iAction)
1438 {
1439 //Process property action
1440 switch (iAction)
1441 {
1442 case IIS_FILTER :
1443 {
1444 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
1445 ExitOnFailure(hr, "Failed to read filter action");
1446
1447 if (iAction == IIS_CREATE)
1448 {
1449 hr = CreateGlobalFilter(ppwzCustomActionData, pSection);
1450 }
1451 else
1452 {
1453 hr = DeleteGlobalFilter(ppwzCustomActionData, pSection);
1454 }
1455 break;
1456 }
1457 default:
1458 {
1459 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for global filter");
1460 break;
1461 }
1462 }
1463 // Get AppExt action
1464 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
1465 ExitOnFailure(hr, "Failed to read filter action");
1466
1467 }
1468
1469LExit:
1470 ReleaseObject(pSection);
1471
1472 return hr;
1473}
1474
1475static HRESULT CreateGlobalFilter( __inout LPWSTR *ppwzCustomActionData, IAppHostElement *pSection)
1476{
1477 HRESULT hr = S_OK;
1478
1479 LPWSTR pwzFilterName = NULL;
1480 LPWSTR pwzSiteName = NULL;
1481 LPWSTR pwzFilterPath = NULL;
1482 int iLoadOrder = 0;
1483 DWORD cFilters = 0;
1484
1485 IAppHostElement *pElement = NULL;
1486 IAppHostElementCollection *pCollection = NULL;
1487
1488 hr = pSection->get_Collection(&pCollection);
1489 ExitOnFailure(hr, "Failed get filter collection");
1490
1491 hr = pCollection->get_Count(&cFilters);
1492 ExitOnFailure(hr, "Failed get filter collection count");
1493
1494 // Attempt to delete, we will we recreate with desired property values and order
1495 hr = DeleteCollectionElement(pCollection, IIS_CONFIG_FILTER, IIS_CONFIG_NAME, pwzFilterName);
1496 ExitOnFailure(hr, "Failed to delete filter");
1497
1498 //make a new element
1499 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_FILTER), &pElement);
1500 ExitOnFailure(hr, "Failed to create filter config element");
1501
1502 //filter Name key
1503 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterName);
1504 ExitOnFailure(hr, "Failed to read filter name");
1505 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_NAME, pwzFilterName);
1506 ExitOnFailure(hr, "Failed to set filter name");
1507
1508 //web site name
1509 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
1510 ExitOnFailure(hr, "Failed to read filter site name");
1511
1512 // filter path
1513 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterPath);
1514 ExitOnFailure(hr, "Failed to read filter path");
1515 hr = Iis7PutPropertyString(pElement,IIS_CONFIG_PATH, pwzFilterPath);
1516 ExitOnFailure(hr, "Failed to set filter path");
1517
1518 //filter load order
1519 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iLoadOrder);
1520 ExitOnFailure(hr, "Failed to read filter load order");
1521
1522 // put element in order in list
1523 int iPosition = -1;
1524 int icFilters = cFilters;
1525 switch (iLoadOrder)
1526 {
1527 case 0 :
1528 {
1529 iPosition = -1;
1530 break;
1531 }
1532 case -1 :
1533 {
1534 iPosition = icFilters;
1535 break;
1536 }
1537 case MSI_NULL_INTEGER :
1538 {
1539 iPosition = icFilters;
1540 break;
1541 }
1542 default:
1543 {
1544 if (iLoadOrder > icFilters)
1545 {
1546 iPosition = icFilters;
1547 }
1548 else
1549 {
1550 iPosition = iLoadOrder;
1551 }
1552 break;
1553 }
1554 }
1555 hr = pCollection->AddElement(pElement, iPosition);
1556 ExitOnFailure(hr, "Failed to add filter element");
1557
1558LExit:
1559 ReleaseStr(pwzFilterName);
1560 ReleaseStr(pwzSiteName);
1561 ReleaseStr(pwzFilterPath);
1562 ReleaseObject(pCollection);
1563 ReleaseObject(pElement);
1564
1565 return hr;
1566}
1567
1568static HRESULT DeleteGlobalFilter( __inout LPWSTR *ppwzCustomActionData, IAppHostElement *pSection)
1569{
1570 HRESULT hr = S_OK;
1571
1572 LPWSTR pwzFilterName = NULL;
1573 LPWSTR pwzSiteName = NULL;
1574
1575 IAppHostElementCollection *pCollection = NULL;
1576
1577 hr = pSection->get_Collection(&pCollection);
1578 ExitOnFailure(hr, "Failed get filter collection");
1579
1580 //filter Name key
1581 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterName);
1582 ExitOnFailure(hr, "Failed to read filter name");
1583
1584 //web site name
1585 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName); // TODO: unused?
1586 ExitOnFailure(hr, "Failed to read filter site name");
1587
1588 DeleteCollectionElement(pCollection, IIS_CONFIG_FILTER, IIS_CONFIG_NAME, pwzFilterName);
1589 ExitOnFailure(hr, "Failed to delete filter %ls", pwzFilterName);
1590
1591LExit:
1592 ReleaseStr(pwzFilterName);
1593 ReleaseStr(pwzSiteName);
1594 ReleaseObject(pCollection);
1595
1596 return hr;
1597}
1598
1599//-------------------------------------------------------------------------------------------------
1600// IIS7FilterSite
1601// Called by WriteIIS7ConfigChanges
1602// Processes Filter CA Data
1603//
1604//-------------------------------------------------------------------------------------------------
1605HRESULT IIS7FilterSite(
1606 __inout LPWSTR *ppwzCustomActionData,
1607 __in IAppHostWritableAdminManager *pAdminMgr
1608 )
1609{
1610 HRESULT hr = S_OK;
1611 int iAction = 0;
1612
1613 // Get filter action
1614 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
1615 ExitOnFailure(hr, "Failed to read filter action");
1616
1617 while (IIS_FILTER_END != iAction)
1618 {
1619 //Process property action
1620 switch (iAction)
1621 {
1622 case IIS_FILTER :
1623 {
1624 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
1625 ExitOnFailure(hr, "Failed to read filter action");
1626
1627 if (iAction == IIS_CREATE)
1628 {
1629 hr = CreateSiteFilter(ppwzCustomActionData, pAdminMgr);
1630 }
1631 else
1632 {
1633 hr = DeleteSiteFilter(ppwzCustomActionData, pAdminMgr);
1634 }
1635 break;
1636 }
1637 default:
1638 {
1639 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for global filter");
1640 break;
1641 }
1642 }
1643
1644 // Get AppExt action
1645 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
1646 ExitOnFailure(hr, "Failed to read filter action");
1647 }
1648
1649LExit:
1650 return hr;
1651
1652}
1653
1654static HRESULT CreateSiteFilter(__inout LPWSTR *ppwzCustomActionData, IAppHostWritableAdminManager *pAdminMgr)
1655{
1656 HRESULT hr = S_OK;
1657 LPWSTR pwzFilterName = NULL;
1658 LPWSTR pwzSiteName = NULL;
1659 LPWSTR pwzFilterPath = NULL;
1660 LPWSTR pwzConfigPath = NULL;
1661 int iLoadOrder = 0;
1662 DWORD cFilters;
1663
1664 IAppHostElement *pElement = NULL;
1665 IAppHostElement *pSection = NULL;
1666 IAppHostElementCollection *pCollection = NULL;
1667
1668 //filter Name key
1669 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterName);
1670 ExitOnFailure(hr, "Failed to read filter name");
1671
1672 //web site name
1673 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
1674 ExitOnFailure(hr, "Failed to read filter site name");
1675
1676 //Construct config root
1677 hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzSiteName);
1678 ExitOnFailure(hr, "failed to format filter config path");
1679
1680 //get admin isapiFilters section at config path location tag
1681 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_ISAPI_SECTION), pwzConfigPath, &pSection);
1682 ExitOnFailure(hr, "Failed get isapiFilters section");
1683
1684 hr = pSection->get_Collection(&pCollection);
1685 ExitOnFailure(hr, "Failed get filter collection");
1686
1687 hr = pCollection->get_Count(&cFilters);
1688 ExitOnFailure(hr, "Failed get filter collection count");
1689
1690 // Attempt to delete, we will we recreate with desired property values and order
1691 hr = DeleteCollectionElement(pCollection, IIS_CONFIG_FILTER, IIS_CONFIG_NAME, pwzFilterName);
1692 ExitOnFailure(hr, "Failed to delete filter");
1693
1694 //make a new element
1695 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_FILTER), &pElement);
1696 ExitOnFailure(hr, "Failed to create filter config element");
1697
1698 hr = Iis7PutPropertyString(pElement,IIS_CONFIG_NAME, pwzFilterName);
1699 ExitOnFailure(hr, "Failed to set filter name");
1700
1701 // filter path
1702 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterPath);
1703 ExitOnFailure(hr, "Failed to read filter path");
1704
1705 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PATH, pwzFilterPath);
1706 ExitOnFailure(hr, "Failed to set filter path");
1707
1708 //filter load order
1709 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iLoadOrder);
1710 ExitOnFailure(hr, "Failed to read filter load order");
1711
1712 // put element in order in list
1713 int iPosition = -1;
1714 int icFilters = cFilters;
1715 switch (iLoadOrder)
1716 {
1717 case 0 :
1718 {
1719 iPosition = -1;
1720 break;
1721 }
1722 case -1 :
1723 {
1724 iPosition = icFilters;
1725 break;
1726 }
1727 case MSI_NULL_INTEGER :
1728 {
1729 iPosition = icFilters;
1730 break;
1731 }
1732 default:
1733 {
1734 if (iLoadOrder > icFilters)
1735 {
1736 iPosition = icFilters;
1737 }
1738 else
1739 {
1740 iPosition = iLoadOrder;
1741 }
1742 break;
1743 }
1744 }
1745
1746 hr = pCollection->AddElement(pElement, iPosition);
1747 ExitOnFailure(hr, "Failed to add filter element");
1748
1749LExit:
1750 ReleaseStr(pwzFilterName);
1751 ReleaseStr(pwzSiteName);
1752 ReleaseStr(pwzFilterPath);
1753 ReleaseStr(pwzConfigPath);
1754 ReleaseObject(pElement);
1755 ReleaseObject(pSection);
1756 ReleaseObject(pCollection);
1757
1758 return hr;
1759}
1760
1761static HRESULT DeleteSiteFilter(__inout LPWSTR *ppwzCustomActionData, IAppHostWritableAdminManager *pAdminMgr)
1762{
1763 HRESULT hr = S_OK;
1764 LPWSTR pwzFilterName = NULL;
1765 LPWSTR pwzSiteName = NULL;
1766 LPWSTR pwzConfigPath = NULL;
1767
1768 IAppHostElement *pSection = NULL;
1769 IAppHostElementCollection *pCollection = NULL;
1770
1771 //filter Name key
1772 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzFilterName);
1773 ExitOnFailure(hr, "Failed to read filter name");
1774
1775 //web site name
1776 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
1777 ExitOnFailure(hr, "Failed to read filter site name");
1778
1779 //Construct config root
1780 hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzSiteName);
1781 ExitOnFailure(hr, "failed to format filter config path");
1782
1783 //get admin isapiFilters section at config path location tag
1784 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_ISAPI_SECTION), pwzConfigPath, &pSection);
1785 ExitOnFailure(hr, "Failed get isapiFilters section");
1786
1787 hr = pSection->get_Collection(&pCollection);
1788 ExitOnFailure(hr, "Failed get filter collection");
1789
1790 DeleteCollectionElement(pCollection, IIS_CONFIG_FILTER, IIS_CONFIG_NAME, pwzFilterName);
1791 ExitOnFailure(hr, "Failed to delete filter %ls", pwzFilterName);
1792
1793LExit:
1794 ReleaseStr(pwzFilterName);
1795 ReleaseStr(pwzSiteName);
1796 ReleaseStr(pwzConfigPath);
1797 ReleaseObject(pSection);
1798 ReleaseObject(pCollection);
1799
1800 return hr;
1801}
1802
1803//-------------------------------------------------------------------------------------------------
1804// IIS7Site
1805// Called by WriteIIS7ConfigChanges
1806// Processes WebSite CA Data
1807//
1808//-------------------------------------------------------------------------------------------------
1809HRESULT IIS7Site(
1810 __inout LPWSTR *ppwzCustomActionData,
1811 __in IAppHostWritableAdminManager *pAdminMgr)
1812{
1813 HRESULT hr = S_OK;
1814 int iAction = -1;
1815 int iData = 0;
1816 BOOL fFound = FALSE;
1817
1818 LPWSTR pwzSiteName = NULL;
1819 IAppHostElement *pSites = NULL;
1820 IAppHostElementCollection *pCollection = NULL;
1821 IAppHostElement *pSiteElem = NULL;
1822 IAppHostElement *pElement = NULL;
1823
1824 // Get site action
1825 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
1826 ExitOnFailure(hr, "Failed to read site action");
1827
1828 //get site name
1829 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
1830 ExitOnFailure(hr, "Failed to read site key");
1831
1832 //Get site if it exists
1833 hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fFound);
1834 ExitOnFailure(hr, "Failed to read sites from config");
1835
1836 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_SITES_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSites);
1837 ExitOnFailure(hr, "Failed get sites section");
1838 ExitOnNull(pSites, hr, ERROR_FILE_NOT_FOUND, "Failed get sites section object");
1839
1840 hr = pSites->get_Collection( &pCollection);
1841 ExitOnFailure(hr, "Failed get site collection");
1842 switch (iAction)
1843 {
1844 case IIS_DELETE :
1845 {
1846 if (fFound)
1847 {
1848 hr = DeleteCollectionElement(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_NAME, pwzSiteName);
1849 ExitOnFailure(hr, "Failed to delete website");
1850 }
1851 ExitFunction();
1852 break;
1853 }
1854 case IIS_CREATE :
1855 {
1856 if (!fFound)
1857 {
1858 //Create the site
1859 hr = CreateSite(pCollection, pwzSiteName, &pSiteElem);
1860 ExitOnFailure(hr, "Failed to create site");
1861
1862 }
1863 }
1864 }
1865 //
1866 //Set other Site properties
1867 //
1868 //set site Id
1869 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
1870 ExitOnFailure(hr, "Failed to read site Id");
1871 if (iData != MSI_NULL_INTEGER && -1 != iData)
1872 {
1873 hr = Iis7PutPropertyInteger(pSiteElem, IIS_CONFIG_SITE_ID, iData);
1874 ExitOnFailure(hr, "Failed set site Id data");
1875 }
1876 //Set Site AutoStart
1877 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
1878 ExitOnFailure(hr, "Failed to read site autostart");
1879 if (MSI_NULL_INTEGER != iData)
1880 {
1881 hr = Iis7PutPropertyBool(pSiteElem, IIS_CONFIG_AUTOSTART, iData);
1882 ExitOnFailure(hr, "Failed set site config data");
1883 }
1884
1885 //Set Site Connection timeout
1886 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
1887 ExitOnFailure(hr, "Failed to read site connection tomeout data");
1888 if (MSI_NULL_INTEGER != iData)
1889 {
1890 // get limits element, get connectionTimeout property
1891 hr = pSiteElem->GetElementByName(ScopeBSTR(IIS_CONFIG_LIMITS), &pElement);
1892 ExitOnFailure(hr, "Failed to read limits from config");
1893 //convert iData in seconds to timeSpan hh:mm:ss
1894 WCHAR wcTime[60];
1895 *wcTime = '\0';
1896 ConvSecToHMS( iData, wcTime, countof( wcTime));
1897
1898 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CONNECTTIMEOUT, wcTime);
1899 ExitOnFailure(hr, "IIS: failed set connection timeout config data");
1900 }
1901
1902LExit:
1903 ReleaseStr(pwzSiteName);
1904 ReleaseObject(pSites);
1905 ReleaseObject(pCollection);
1906 ReleaseObject(pSiteElem);
1907 ReleaseObject(pElement);
1908
1909 return hr;
1910}
1911//-------------------------------------------------------------------------------------------------
1912// IIS7Application
1913// Processes Application CA Data
1914//
1915//
1916//-------------------------------------------------------------------------------------------------
1917
1918HRESULT IIS7Application(
1919 __inout LPWSTR *ppwzCustomActionData,
1920 __in IAppHostWritableAdminManager *pAdminMgr)
1921{
1922 HRESULT hr = S_OK;
1923
1924 int iAction = -1;
1925 BOOL fSiteFound = FALSE;
1926 BOOL fAppFound = FALSE;
1927
1928 LPWSTR pwzSiteName = NULL;
1929 LPWSTR pwzAppPath = NULL;
1930 LPWSTR pwzAppPool = NULL;
1931 LPWSTR pwzLocationPath = NULL;
1932 IAppHostElement *pSiteElem = NULL;
1933 IAppHostElement *pAppElement = NULL;
1934 // Get Application action
1935 hr = WcaReadIntegerFromCaData( ppwzCustomActionData, &iAction);
1936 ExitOnFailure(hr, "Failed to read application action")
1937 //get site key name
1938 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
1939 ExitOnFailure(hr, "Failed to read app site key");
1940 //get application path
1941 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzAppPath);
1942 ExitOnFailure(hr, "Failed to read app path key");
1943 //get application Pool
1944 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzAppPool);
1945 ExitOnFailure(hr, "Failed to read app pool key");
1946
1947 //Get site if it exists
1948 hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fSiteFound);
1949 ExitOnFailure(hr, "Failed to read sites from config");
1950
1951 switch (iAction)
1952 {
1953 case IIS_CREATE :
1954 {
1955 if (fSiteFound)
1956 {
1957 //have site get application collection
1958 hr = GetApplicationElement(pSiteElem,
1959 pwzAppPath,
1960 &pAppElement,
1961 &fAppFound);
1962 ExitOnFailure(hr, "Error reading application from config");
1963
1964 if (!fAppFound)
1965 {
1966 //Create Application
1967 hr = CreateApplication(pSiteElem, pwzAppPath, &pAppElement);
1968 ExitOnFailure(hr, "Error creating application in config");
1969 }
1970 //Update application properties:
1971 //
1972 //Set appPool
1973 hr = SetAppPool(pAppElement, pwzAppPool);
1974 ExitOnFailure(hr, "Unable to set appPool for application");
1975 }
1976 else
1977 {
1978 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
1979 ExitOnFailure(hr, "Site not found for create application");
1980 }
1981 break;
1982 }
1983 case IIS_DELETE :
1984 {
1985 if (fSiteFound)
1986 {
1987 //have site get application collection
1988 hr = GetApplicationElement( pSiteElem,
1989 pwzAppPath,
1990 &pAppElement,
1991 &fAppFound);
1992 ExitOnFailure(hr, "Error reading application from config")
1993 if (fAppFound)
1994 {
1995 //delete Application
1996 hr = DeleteApplication(pSiteElem, pwzAppPath);
1997 ExitOnFailure(hr, "Error deleating application from config")
1998 //Construct Location path
1999 // TODO: it seems odd that these are just
2000 // jammed together, need to determine if this requires a '\'
2001 hr = StrAllocString(&pwzLocationPath, pwzSiteName, 0);
2002 ExitOnFailure(hr, "failed to copy location config path web name");
2003 hr = StrAllocConcat(&pwzLocationPath, pwzAppPath, 0);
2004 ExitOnFailure(hr, "failed to copy location config path appPath ");
2005
2006 // and delete location tag for this application
2007 hr = ClearLocationTag(pAdminMgr, pwzLocationPath);
2008 ExitOnFailure(hr, "failed to clear location tag for %ls", pwzLocationPath);
2009 }
2010 }
2011 break;
2012 }
2013 default:
2014 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for Application");
2015 break;
2016 }
2017
2018LExit:
2019 ReleaseStr(pwzSiteName);
2020 ReleaseStr(pwzAppPath);
2021 ReleaseStr(pwzAppPool);
2022 ReleaseStr(pwzLocationPath);
2023 ReleaseObject(pSiteElem);
2024 ReleaseObject(pAppElement);
2025
2026 return hr;
2027}
2028//-------------------------------------------------------------------------------------------------
2029// IIS7VDir
2030// Processes VDir CA Data
2031//
2032//
2033//-------------------------------------------------------------------------------------------------
2034HRESULT IIS7VDir(
2035 __inout LPWSTR *ppwzCustomActionData,
2036 __in IAppHostWritableAdminManager *pAdminMgr)
2037{
2038 HRESULT hr = S_OK;
2039
2040 int iAction = -1;
2041 BOOL fSiteFound = FALSE;
2042 BOOL fAppFound = FALSE;
2043
2044 LPWSTR pwzSiteName = NULL;
2045 LPWSTR pwzVDirPath = NULL;
2046 LPWSTR pwzVDirPhyDir = NULL;
2047 LPCWSTR pwzVDirSubPath = NULL;
2048
2049 IAppHostElement *pSiteElem = NULL;
2050 IAppHostElement *pAppElement = NULL;
2051 IAppHostElementCollection *pElement = NULL;
2052
2053 // Get Application action
2054 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
2055 ExitOnFailure(hr, "Failed to read VDir action");
2056
2057 //get site key name
2058 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
2059 ExitOnFailure(hr, "Failed to read site key");
2060 //get VDir path
2061 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzVDirPath);
2062 ExitOnFailure(hr, "Failed to read VDir key");
2063 //get physical dir path
2064 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzVDirPhyDir);
2065 ExitOnFailure(hr, "Failed to read VDirPath key");
2066
2067 //Get site if it exists
2068 hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fSiteFound);
2069 ExitOnFailure(hr, "Failed to read sites from config");
2070
2071 if (IIS_CREATE == iAction)
2072 {
2073 if (fSiteFound)
2074 {
2075 //have site get application
2076 hr = GetApplicationElementForVDir( pSiteElem,
2077 pwzVDirPath,
2078 &pAppElement,
2079 &pwzVDirSubPath,
2080 &fAppFound);
2081 ExitOnFailure(hr, "Error reading application element from config");
2082
2083 if (!fAppFound)
2084 {
2085 // need application to add vDir
2086 hr = E_FILENOTFOUND;
2087 ExitOnFailure(hr, "Error application not found for create VDir");
2088 }
2089 //
2090 // create the virDir
2091 //
2092 hr = CreateVdir(pAppElement, pwzVDirSubPath, pwzVDirPhyDir);
2093 ExitOnFailure(hr, "Failed to create vdir for application");
2094 }
2095 else
2096 {
2097 hr = E_FILENOTFOUND;
2098 ExitOnFailure(hr, "IIS: site not found for create VDir");
2099 }
2100 }
2101 else if (IIS_DELETE == iAction)
2102 {
2103 if (fSiteFound)
2104 {
2105 //have site get application
2106 hr = GetApplicationElementForVDir( pSiteElem,
2107 pwzVDirPath,
2108 &pAppElement,
2109 &pwzVDirSubPath,
2110 &fAppFound);
2111 ExitOnFailure(hr, "Error reading application from config")
2112 if (fAppFound)
2113 {
2114 //delete vdir
2115 hr = DeleteVdir(pAppElement, pwzVDirSubPath);
2116 ExitOnFailure(hr, "Unable to delete vdir for application");
2117 }
2118 }
2119 }
2120
2121 LExit:
2122 ReleaseStr(pwzSiteName);
2123 ReleaseStr(pwzVDirPath);
2124 ReleaseStr(pwzVDirPhyDir);
2125 ReleaseObject(pSiteElem);
2126 ReleaseObject(pAppElement);
2127 ReleaseObject(pElement);
2128
2129 return hr;
2130}
2131
2132//-------------------------------------------------------------------------------------------------
2133// IIS7Binding
2134// Processes Bindings CA Data
2135//
2136//
2137//-------------------------------------------------------------------------------------------------
2138HRESULT IIS7Binding(
2139 __inout LPWSTR *ppwzCustomActionData,
2140 __in IAppHostWritableAdminManager *pAdminMgr)
2141{
2142 HRESULT hr = S_OK;
2143
2144 int iAction = -1;
2145 BOOL fSiteFound = FALSE;
2146
2147 LPWSTR pwzSiteName = NULL;
2148 LPWSTR pwzProtocol = NULL;
2149 LPWSTR pwzInfo = NULL;
2150
2151 IAppHostElement *pSiteElem = NULL;
2152
2153 // Get Application action
2154 hr = WcaReadIntegerFromCaData( ppwzCustomActionData, &iAction);
2155 ExitOnFailure(hr, "Failed to read binding action");
2156
2157 //get site key name
2158 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
2159 ExitOnFailure(hr, "Failed to read binding site name key");
2160
2161 //get binding protocol
2162 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzProtocol);
2163 ExitOnFailure(hr, "Failed to read binding protocol");
2164
2165 //get binding info
2166 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzInfo);
2167 ExitOnFailure(hr, "Failed to read binding info");
2168
2169 //Get site if it exists
2170 hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fSiteFound);
2171 ExitOnFailure(hr, "Failed to read sites from config");
2172
2173 if (IIS_CREATE == iAction)
2174 {
2175 if (fSiteFound)
2176 {
2177 //add binding
2178 hr = CreateBinding(pSiteElem, pwzProtocol, pwzInfo);
2179 ExitOnFailure(hr, "Failed to create site binding");
2180 }
2181 else
2182 {
2183 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
2184 ExitOnFailure(hr, "Site not found for create binding");
2185 }
2186 }
2187 else if (IIS_DELETE == iAction)
2188 {
2189 if (fSiteFound)
2190 {
2191 //delete binding
2192 hr = DeleteBinding(pSiteElem, pwzProtocol, pwzInfo);
2193 ExitOnFailure(hr, "Failed to delete binding");
2194 }
2195 }
2196
2197 LExit:
2198 ReleaseStr(pwzSiteName);
2199 ReleaseStr(pwzProtocol);
2200 ReleaseStr(pwzInfo);
2201 ReleaseObject(pSiteElem);
2202
2203 return hr;
2204}
2205//-------------------------------------------------------------------------------------------------
2206// IIS7Binding
2207// Processes WebLog CA Data
2208//
2209//
2210//-------------------------------------------------------------------------------------------------
2211HRESULT IIS7WebLog(
2212 __inout LPWSTR *ppwzCustomActionData,
2213 __in IAppHostWritableAdminManager *pAdminMgr)
2214{
2215 HRESULT hr = S_OK;
2216
2217 BOOL fSiteFound = FALSE;
2218
2219 LPWSTR pwzSiteName = NULL;
2220 LPWSTR pwzLogFormat = NULL;
2221
2222 IAppHostElement *pSiteElem = NULL;
2223
2224 //get site key name
2225 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
2226 ExitOnFailure(hr, "Failed to read web log site name key");
2227
2228 //get log format
2229 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzLogFormat);
2230 ExitOnFailure(hr, "Failed to read web log protocol");
2231
2232 //Get site if it exists
2233 hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fSiteFound);
2234 ExitOnFailure(hr, "Failed to read web log sites from config");
2235
2236 if (fSiteFound)
2237 {
2238 //add log format
2239 hr = CreateWebLog(pSiteElem, pwzLogFormat);
2240 ExitOnFailure(hr, "Failed to create weblog file format");
2241 }
2242 else
2243 {
2244 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
2245 ExitOnFailure(hr, "Site not found for create weblog file format");
2246 }
2247
2248 LExit:
2249 ReleaseStr(pwzSiteName);
2250 ReleaseStr(pwzLogFormat);
2251 ReleaseObject(pSiteElem);
2252
2253 return hr;
2254}
2255//-------------------------------------------------------------------------------------------------
2256// IIS7AppPool
2257// Processes AppPool CA Data
2258//
2259//
2260//-------------------------------------------------------------------------------------------------
2261HRESULT IIS7AppPool(
2262 __inout LPWSTR *ppwzCustomActionData,
2263 __in IAppHostWritableAdminManager *pAdminMgr
2264 )
2265{
2266 HRESULT hr = S_OK;
2267
2268 int iAction = -1;
2269
2270 LPWSTR pwzAppPoolName = NULL;
2271
2272 // Get AppPool action
2273 hr = WcaReadIntegerFromCaData( ppwzCustomActionData, &iAction);
2274 ExitOnFailure(hr, "Failed to read AppPool action");
2275
2276 //get appPool name
2277 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzAppPoolName);
2278 ExitOnFailure(hr, "Failed to read AppPool name key");
2279
2280 switch (iAction)
2281 {
2282 case IIS_CREATE :
2283 {
2284 hr = CreateAppPool(ppwzCustomActionData, pAdminMgr, pwzAppPoolName);
2285 break;
2286 }
2287 case IIS_DELETE:
2288 {
2289 hr = DeleteAppPool(pAdminMgr, pwzAppPoolName);
2290 break;
2291 }
2292 default:
2293 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for appPool");
2294 break;
2295 }
2296
2297LExit:
2298 ReleaseStr(pwzAppPoolName);
2299 return hr;
2300}
2301
2302//-------------------------------------------------------------------------------------------------
2303// IIS7AppExtension
2304// Processes AppExtension (config handlers) CA Data
2305//
2306//
2307//-------------------------------------------------------------------------------------------------
2308HRESULT IIS7AppExtension(
2309 __inout LPWSTR *ppwzCustomActionData,
2310 __in IAppHostWritableAdminManager *pAdminMgr)
2311{
2312 HRESULT hr = S_OK;
2313
2314 LPWSTR pwzWebName = NULL;
2315 LPWSTR pwzWebRoot = NULL;
2316 LPWSTR pwzData = NULL;
2317 LPWSTR pwzConfigPath = NULL;
2318 LPWSTR pwzHandlerName = NULL;
2319 LPWSTR pwzPath = NULL;
2320 int iAction = -1;
2321
2322 IAppHostElement *pSection = NULL;
2323 IAppHostElement *pElement = NULL;
2324 IAppHostElementCollection *pCollection = NULL;
2325
2326 BOOL fFound = FALSE;
2327 DWORD cHandlers = 1000;
2328
2329 //get web name
2330 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebName);
2331 ExitOnFailure(hr, "Failed to read appExt Web name key");
2332
2333 //get root name
2334 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebRoot);
2335 ExitOnFailure(hr, "Failed to read appExt Web name key");
2336
2337 //Construct config root
2338 hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzWebName);
2339 ExitOnFailure(hr, "failed to format appext config path");
2340 //
2341 //Do not append trailing '/' for default vDir
2342 //
2343 if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzWebRoot, -1, L"/", -1))
2344 {
2345 hr = StrAllocConcat(&pwzConfigPath, L"/", 0);
2346 ExitOnFailure(hr, "failed to copy appext config path delim");
2347 hr = StrAllocConcat(&pwzConfigPath, pwzWebRoot, 0);
2348 ExitOnFailure(hr, "failed to copy appext config path root name");
2349 }
2350 //get admin handlers section at config path location tag
2351 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HANDLERS_SECTION), pwzConfigPath, &pSection);
2352 ExitOnFailure(hr, "Failed get appext section");
2353
2354 if (!pSection)
2355 {
2356 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
2357 ExitOnFailure(hr, "Failed get appext section object");
2358 }
2359
2360 // Get AppExt action
2361 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
2362 ExitOnFailure(hr, "Failed to read appExt action");
2363
2364 hr = pSection->get_Collection(&pCollection);
2365 ExitOnFailure(hr, "Failed get handlers collection for appext");
2366
2367 while (IIS_APPEXT_END != iAction)
2368 {
2369 fFound = FALSE;
2370
2371 //Process property action
2372 switch (iAction)
2373 {
2374 case IIS_APPEXT :
2375 {
2376 // These IDs aren't really stable but this is stable enough to support repair since the MSI won't change
2377 hr = StrAllocFormatted(&pwzHandlerName, L"MsiCustom-%u", ++cHandlers);
2378 ExitOnFailure(hr, "Failed increment handler name");
2379
2380 hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_NAME, pwzHandlerName, &pElement, NULL);
2381 ExitOnFailure(hr, "Failed to find mimemap extension");
2382
2383 fFound = (NULL != pElement);
2384 if (!fFound)
2385 {
2386 //create new handler element
2387 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pElement);
2388 ExitOnFailure(hr, "Failed get create handler element for appext");
2389
2390 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_NAME, pwzHandlerName);
2391 ExitOnFailure(hr, "Failed set appext name property");
2392 }
2393
2394 //BUGBUG: For compat we are assuming these are all ISAPI MODULES so we are
2395 //setting the modules property to IsapiModule.
2396 //Currently can't deal with handlers of different module types.
2397 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_MODULES, L"IsapiModule");
2398 ExitOnFailure(hr, "Failed set site appExt path property");
2399
2400 //get extension (path)
2401 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
2402 ExitOnFailure(hr, "Failed to read appExt extension");
2403 hr = StrAllocFormatted(&pwzPath, L"*.%s", pwzData);
2404 ExitOnFailure(hr, "Failed decorate appExt path");
2405 //put property
2406 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PATH, pwzPath);
2407 ExitOnFailure(hr, "Failed set site appExt path property");
2408
2409 //get executable
2410 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
2411 ExitOnFailure(hr, "Failed to read appExt executable");
2412 //put property
2413 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_EXECUTABLE, pwzData);
2414 ExitOnFailure(hr, "Failed set site appExt executable property");
2415
2416 //get verbs
2417 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
2418 ExitOnFailure(hr, "Failed to read appExt verbs");
2419 //put property
2420 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_VERBS, pwzData);
2421 ExitOnFailure(hr, "Failed set site appExt verbs property");
2422
2423 break;
2424 }
2425 default:
2426 {
2427 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for AppExt");
2428 break;
2429 }
2430 }
2431
2432 if (!fFound)
2433 {
2434 // put handler element at beginning of list
2435 hr = pCollection->AddElement(pElement, 0);
2436 ExitOnFailure(hr, "Failed add handler element for appext");
2437 }
2438
2439 ReleaseNullObject(pElement);
2440
2441 // Get AppExt action
2442 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
2443 ExitOnFailure(hr, "Failed to read AppPool Property action");
2444 }
2445
2446LExit:
2447 ReleaseStr(pwzWebName);
2448 ReleaseStr(pwzWebRoot);
2449 ReleaseStr(pwzData);
2450 ReleaseStr(pwzConfigPath);
2451 ReleaseStr(pwzHandlerName);
2452 ReleaseStr(pwzPath);
2453 ReleaseObject(pSection);
2454 ReleaseObject(pElement);
2455 ReleaseObject(pCollection);
2456
2457 return hr;
2458}
2459
2460//-------------------------------------------------------------------------------------------------
2461// IIS7MimeMap
2462// Processes Mime Map (config handlers) CA Data
2463//
2464//
2465//-------------------------------------------------------------------------------------------------
2466 HRESULT IIS7MimeMap(
2467 __inout LPWSTR *ppwzCustomActionData,
2468 __in IAppHostWritableAdminManager *pAdminMgr
2469 )
2470{
2471 HRESULT hr = S_OK;
2472 LPWSTR pwzConfigPath = NULL;
2473 LPWSTR pwzWebName = NULL;
2474 LPWSTR pwzWebRoot = NULL;
2475 LPWSTR pwzData = NULL;
2476 int iAction = -1;
2477
2478 IAppHostElement *pSection = NULL;
2479 IAppHostElement *pElement = NULL;
2480 IAppHostElementCollection *pCollection = NULL;
2481
2482 BOOL fFound = FALSE;
2483
2484 //get web name
2485 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebName);
2486 ExitOnFailure(hr, "Failed to read mime map Web name key");
2487
2488 //get vdir root name
2489 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebRoot);
2490 ExitOnFailure(hr, "Failed to read vdir root name key");
2491
2492 //Construct config root
2493 hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzWebName);
2494 ExitOnFailure(hr, "failed to format mime map config path web name");
2495 //
2496 //Do not append trailing '/' for default vDir
2497 //
2498 if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzWebRoot, -1, L"/", -1))
2499 {
2500 hr = StrAllocConcat(&pwzConfigPath, L"/", 0);
2501 ExitOnFailure(hr, "failed to copy appext config path delim");
2502 hr = StrAllocConcat(&pwzConfigPath, pwzWebRoot, 0);
2503 ExitOnFailure(hr, "failed to copy appext config path root name");
2504 }
2505
2506 //get admin section <staticContent> at config path location tag
2507 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_STATICCONTENT_SECTION), pwzConfigPath, &pSection);
2508 ExitOnFailure(hr, "Failed get staticContent section for mimemap");
2509
2510 if (!pSection)
2511 {
2512 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
2513 ExitOnFailure(hr, "Failed get staticContent section object");
2514 }
2515
2516 // Get mimemap action
2517 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
2518 ExitOnFailure(hr, "Failed to read mimemap action");
2519
2520 hr = pSection->get_Collection(&pCollection);
2521 ExitOnFailure(hr, "Failed get staticContent collection for mimemap");
2522
2523 while (IIS_MIMEMAP_END != iAction)
2524 {
2525 //Process property action
2526 switch (iAction)
2527 {
2528 case IIS_MIMEMAP :
2529 {
2530 //get extension
2531 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
2532 ExitOnFailure(hr, "Failed to read mimemap extension");
2533
2534 hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_MIMEMAP, IIS_CONFIG_FILEEXT, pwzData, &pElement, NULL);
2535 ExitOnFailure(hr, "Failed to find mimemap extension");
2536 fFound = (NULL != pElement);
2537
2538 if (!fFound)
2539 {
2540 //create new mimeMap element
2541 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_MIMEMAP), &pElement);
2542 ExitOnFailure(hr, "Failed get create MimeMap element");
2543 }
2544
2545 //put property
2546 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_FILEEXT, pwzData);
2547 ExitOnFailure(hr, "Failed set mimemap extension property");
2548
2549 //get type
2550 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
2551 ExitOnFailure(hr, "Failed to read mimemap type");
2552 //put property
2553 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_MIMETYPE, pwzData);
2554 ExitOnFailure(hr, "Failed set mimemap type property");
2555
2556 break;
2557 }
2558 default:
2559 {
2560 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for mimeMap");
2561 break;
2562 }
2563 }
2564
2565 if (!fFound)
2566 {
2567 // put mimeMap element at beginning of list
2568 hr = pCollection->AddElement(pElement, -1);
2569 ExitOnFailure(hr, "Failed add mimemap");
2570 }
2571
2572 // Get AppExt action
2573 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
2574 ExitOnFailure(hr, "Failed to read mimemap action");
2575
2576 ReleaseNullObject(pElement);
2577 }
2578
2579LExit:
2580 ReleaseStr(pwzConfigPath);
2581 ReleaseStr(pwzWebName);
2582 ReleaseStr(pwzWebRoot);
2583 ReleaseStr(pwzData);
2584 ReleaseObject(pSection);
2585 ReleaseObject(pElement);
2586 ReleaseObject(pCollection);
2587
2588 return hr;
2589}
2590
2591//-------------------------------------------------------------------------------------------------
2592// IIS7DirProperties
2593// ProcessesVdir Properties CA Data
2594//
2595//
2596//-------------------------------------------------------------------------------------------------
2597HRESULT IIS7DirProperties(
2598 __inout LPWSTR *ppwzCustomActionData,
2599 __in IAppHostWritableAdminManager *pAdminMgr
2600 )
2601{
2602 HRESULT hr = S_OK;
2603 WCHAR wcTime[60];
2604 LPWSTR pwzConfigPath = NULL;
2605 LPWSTR pwzWebName = NULL;
2606 LPWSTR pwzWebRoot = NULL;
2607 LPWSTR pwzData = NULL;
2608 int iAction = -1;
2609 int iData = 0;
2610 DWORD dwData = 0;
2611
2612 IAppHostElement *pSection = NULL;
2613 IAppHostElement *pElement = NULL;
2614 IAppHostElementCollection *pCollection = NULL;
2615
2616 //get web name
2617 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebName);
2618 ExitOnFailure(hr, "Failed to read DirProp Web name key");
2619
2620 //get vdir root name
2621 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzWebRoot);
2622 ExitOnFailure(hr, "Failed to read DirProp Web name key");
2623
2624 //Construct config root
2625 hr = StrAllocFormatted(&pwzConfigPath, L"%s/%s", IIS_CONFIG_APPHOST_ROOT, pwzWebName);
2626 ExitOnFailure(hr, "failed to format mime map config path web name");
2627 //
2628 //Do not append trailing '/' for default vDir
2629 //
2630 if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzWebRoot, -1, L"/", -1))
2631 {
2632 hr = StrAllocConcat(&pwzConfigPath, L"/", 0);
2633 ExitOnFailure(hr, "failed to copy appext config path delim");
2634 hr = StrAllocConcat(&pwzConfigPath, pwzWebRoot, 0);
2635 ExitOnFailure(hr, "failed to copy appext config path root name");
2636 }
2637
2638 // Get DirProps action
2639 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
2640 ExitOnFailure(hr, "Failed to read DirProps action");
2641
2642 while (IIS_DIRPROP_END != iAction)
2643 {
2644 //Process property action
2645 switch (iAction)
2646 {
2647 case IIS_DIRPROP_ACCESS :
2648 {
2649 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
2650 ExitOnFailure(hr, "Failed to read DirProps access");
2651 //iData contains bit flags for <handlers accessPolicy="">
2652 //no translation required
2653 //get admin section at config path location tag
2654 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HANDLERS_SECTION), pwzConfigPath, &pSection);
2655 ExitOnFailure(hr, "Failed get handlers section for DirProp");
2656 if (!pSection)
2657 {
2658 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
2659 ExitOnFailure(hr, "Failed get handlers section object for DirProps");
2660 }
2661 dwData = iData;
2662 hr = Iis7PutPropertyInteger( pSection, L"accessPolicy", dwData);
2663 ExitOnFailure(hr, "Failed set accessPolicy for DirProps");
2664 ReleaseNullObject(pSection);
2665 break;
2666 }
2667 case IIS_DIRPROP_USER :
2668 {
2669 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
2670 ExitOnFailure(hr, "Failed to read DirProps user");
2671 hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/anonymousAuthentication"), pwzConfigPath, &pSection);
2672 ExitOnFailure(hr, "Failed get AnonymousAuthentication section for DirProp");
2673 hr = Iis7PutPropertyString( pSection, IIS_CONFIG_USERNAME, pwzData);
2674 ExitOnFailure(hr, "Failed set accessPolicy for DirProps");
2675 ReleaseNullObject(pSection);
2676 break;
2677 }
2678 case IIS_DIRPROP_PWD :
2679 {
2680 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
2681 ExitOnFailure(hr, "Failed to read DirProps pwd");
2682 hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/anonymousAuthentication"), pwzConfigPath, &pSection);
2683 ExitOnFailure(hr, "Failed get AnonymousAuthentication section for DirProp");
2684 hr = Iis7PutPropertyString( pSection, IIS_CONFIG_PASSWORD, pwzData);
2685 ExitOnFailure(hr, "Failed set accessPolicy for DirProps");
2686 ReleaseNullObject(pSection);
2687 break;
2688 }
2689 case IIS_DIRPROP_DEFDOCS :
2690 {
2691 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
2692 ExitOnFailure(hr, "Failed to read DirProps def doc");
2693 hr = SetDirPropDefDoc(pAdminMgr, pwzConfigPath, pwzData);
2694 ExitOnFailure(hr, "Failed to set DirProps Default Documents");
2695 break;
2696 }
2697 case IIS_DIRPROP_AUTH :
2698 {
2699 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
2700 ExitOnFailure(hr, "Failed to read DirProps auth");
2701 //iData contains bit flags for /security/authentication/<...>
2702 // Anonymous = 1
2703 // Basic = 2
2704 // Windows = 4
2705 // Digest =16
2706 // Passport =64 *not supported
2707 //translation required from bit map to section
2708 // E.G security/authentication/windowsAuthentication [property enabled true|false]
2709 dwData= iData;
2710 hr = SetDirPropAuthentications(pAdminMgr, pwzConfigPath, dwData);
2711 ExitOnFailure(hr, "Failed set Authentication for DirProps");
2712 break;
2713 }
2714 case IIS_DIRPROP_SSLFLAGS :
2715 {
2716 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
2717 ExitOnFailure(hr, "Failed to read DirProps sslFlags");
2718 //iData contains bit flags for /security/access sslFlags
2719 //no translation required
2720 hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/access"), pwzConfigPath, &pSection);
2721 ExitOnFailure(hr, "Failed get security/access section for DirProp");
2722 dwData = iData;
2723 hr = Iis7PutPropertyInteger( pSection, L"sslFlags", dwData);
2724 ExitOnFailure(hr, "Failed set security/access for DirProps");
2725 ReleaseNullObject(pSection);
2726 break;
2727 }
2728 case IIS_DIRPROP_AUTHPROVID :
2729 {
2730 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
2731 ExitOnFailure(hr, "Failed to read DirProps auth provider");
2732 hr = SetDirPropAuthProvider(pAdminMgr, pwzConfigPath, pwzData);
2733 ExitOnFailure(hr, "Failed to set DirProps auth provider");
2734 break;
2735 }
2736 case IIS_DIRPROP_ASPERROR:
2737 {
2738 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
2739 ExitOnFailure(hr, "Failed to read DirProps aspDetailedError");
2740 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_ASP_SECTION), pwzConfigPath, &pSection);
2741 ExitOnFailure(hr, "Failed get asp section for DirProp");
2742 hr = Iis7PutPropertyBool(pSection, IIS_CONFIG_SCRIPTERROR, iData);
2743 ExitOnFailure(hr, "Failed to set DirProps aspDetailedError");
2744 ReleaseNullObject(pSection);
2745 break;
2746 }
2747 case IIS_DIRPROP_HTTPEXPIRES:
2748 {
2749 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
2750 ExitOnFailure(hr, "Failed to read DirProps httpExpires provider");
2751 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_STATICCONTENT_SECTION), pwzConfigPath, &pSection);
2752 ExitOnFailure(hr, "Failed get staticContent section for DirProp");
2753 hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_CLIENTCACHE), &pElement);
2754 ExitOnFailure(hr, "Failed to get clientCache element");
2755 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_HTTPEXPIRES, pwzData);
2756 ExitOnFailure(hr, "Failed to set clientCache httpExpires value");
2757 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CACHECONTROLMODE, IIS_CONFIG_USEEXPIRES);
2758 ExitOnFailure(hr, "Failed to set clientCache cacheControlMode value");
2759 ReleaseNullObject(pSection);
2760 ReleaseNullObject(pElement);
2761 break;
2762 }
2763 case IIS_DIRPROP_MAXAGE:
2764 {
2765 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
2766 ExitOnFailure(hr, "Failed to read DirProps httpExpires provider");
2767 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_STATICCONTENT_SECTION), pwzConfigPath, &pSection);
2768 ExitOnFailure(hr, "Failed get staticContent section for DirProp");
2769 hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_CLIENTCACHE), &pElement);
2770 ExitOnFailure(hr, "Failed to get clientCache element");
2771 *wcTime = '\0';
2772 ConvSecToDHMS(iData, wcTime, countof(wcTime));
2773 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_MAXAGE, wcTime);
2774 ExitOnFailure(hr, "Failed to set clientCache maxAge value");
2775 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CACHECONTROLMODE, IIS_CONFIG_USEMAXAGE);
2776 ExitOnFailure(hr, "Failed to set clientCache cacheControlMode value");
2777 ReleaseNullObject(pSection);
2778 ReleaseNullObject(pElement);
2779 break;
2780 }
2781 case IIS_DIRPROP_CACHECUST:
2782 {
2783 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
2784 ExitOnFailure(hr, "Failed to read DirProps cacheControlCustom");
2785 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_STATICCONTENT_SECTION), pwzConfigPath, &pSection);
2786 ExitOnFailure(hr, "Failed get staticContent section for DirProp");
2787 hr = pSection->GetElementByName(ScopeBSTR(IIS_CONFIG_CLIENTCACHE), &pElement);
2788 ExitOnFailure(hr, "Failed to get clientCache element");
2789 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CACHECUST, pwzData);
2790 ExitOnFailure(hr, "Failed to set clientCache cacheControlCustom value");
2791 ReleaseNullObject(pSection);
2792 ReleaseNullObject(pElement);
2793 break;
2794 }
2795 case IIS_DIRPROP_NOCUSTERROR:
2796 {
2797 //no value, if have ID tag write clear to system.webServer/httpErrors
2798 //error collection
2799 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HTTPERRORS_SECTION), pwzConfigPath, &pSection);
2800 ExitOnFailure(hr, "Failed get httperrors section for DirProp");
2801 hr = pSection->get_Collection(&pCollection);
2802 ExitOnFailure(hr, "Failed get error collection for DirProp");
2803 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_CLEAR), &pElement);
2804 ExitOnFailure(hr, "Failed to create clear element for error collection for DirProp");
2805 hr = pCollection->AddElement(pElement);
2806 ExitOnFailure(hr, "Failed to add lear element for error collection for DirProp");
2807 ReleaseNullObject(pSection);
2808 ReleaseNullObject(pElement);
2809 break;
2810 }
2811 case IIS_DIRPROP_LOGVISITS:
2812 {
2813 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
2814 ExitOnFailure(hr, "Failed to read DirProps logVisits");
2815 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_HTTPLOGGING_SECTION), pwzConfigPath, &pSection);
2816 ExitOnFailure(hr, "Failed get httpLogging section for DirProp");
2817 hr = Iis7PutPropertyBool(pSection, IIS_CONFIG_DONTLOG, iData);
2818 ExitOnFailure(hr, "Failed to set DirProps aspDetailedError");
2819 ReleaseNullObject(pSection);
2820 break;
2821 }
2822 default:
2823 {
2824 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for WebDirProperties");
2825 break;
2826 }
2827 }
2828
2829 // Get AppExt action
2830 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
2831 ExitOnFailure(hr, "Failed to read DirProps Property action");
2832 }
2833LExit:
2834 ReleaseStr(pwzConfigPath);
2835 ReleaseStr(pwzWebName);
2836 ReleaseStr(pwzWebRoot);
2837 ReleaseStr(pwzData);
2838 ReleaseObject(pSection);
2839 ReleaseObject(pElement);
2840 ReleaseObject(pCollection);
2841
2842 return hr;
2843}
2844
2845//-------------------------------------------------------------------------------------------------
2846// IIS7SslBinding
2847// ProcessesVdir Properties CA Data
2848//
2849//
2850//-------------------------------------------------------------------------------------------------
2851HRESULT IIS7SslBinding(
2852 __inout LPWSTR *ppwzCustomActionData,
2853 __in IAppHostWritableAdminManager *pAdminMgr
2854 )
2855{
2856 HRESULT hr = S_OK;
2857 int iAction = -1;
2858 BOOL fSiteFound = FALSE;
2859
2860 LPWSTR pwzSiteName = NULL;
2861 LPWSTR pwzStoreName = NULL;
2862 LPWSTR pwzEncodedCertificateHash = NULL;
2863
2864 IAppHostElement *pSiteElem = NULL;
2865
2866 // Get Application action
2867 hr = WcaReadIntegerFromCaData( ppwzCustomActionData, &iAction);
2868 ExitOnFailure(hr, "Failed to read binding action");
2869
2870 //get site key name
2871 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzSiteName);
2872 ExitOnFailure(hr, "Failed to read binding site name key");
2873
2874 //get binding protocol
2875 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzStoreName);
2876 ExitOnFailure(hr, "Failed to read binding protocol");
2877
2878 //get binding info
2879 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzEncodedCertificateHash);
2880 ExitOnFailure(hr, "Failed to read binding info");
2881
2882 //Get site if it exists
2883 hr = GetSiteElement(pAdminMgr, pwzSiteName, &pSiteElem, &fSiteFound);
2884 ExitOnFailure(hr, "Failed to read sites from config");
2885
2886 if (IIS_CREATE == iAction)
2887 {
2888 if (fSiteFound)
2889 {
2890 //add SSL cert to binding
2891 hr = CreateSslBinding(pSiteElem, pwzStoreName, pwzEncodedCertificateHash);
2892 ExitOnFailure(hr, "Failed to create site binding");
2893 }
2894 else
2895 {
2896 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
2897 ExitOnFailure(hr, "Site not found for create binding");
2898 }
2899 }
2900 else if (IIS_DELETE == iAction)
2901 {
2902 if (fSiteFound)
2903 {
2904 //delete binding
2905 hr = DeleteSslBinding(pSiteElem, pwzStoreName, pwzEncodedCertificateHash);
2906 ExitOnFailure(hr, "Failed to delete binding");
2907 }
2908 }
2909
2910 LExit:
2911 ReleaseStr(pwzSiteName);
2912 ReleaseStr(pwzStoreName);
2913 ReleaseStr(pwzEncodedCertificateHash);
2914 ReleaseObject(pSiteElem);
2915
2916 return hr;
2917}
2918
2919//-------------------------------------------------------------------------------------------------
2920// Helper Functions
2921//
2922//
2923//
2924//-------------------------------------------------------------------------------------------------
2925
2926static HRESULT GetNextAvailableSiteId(
2927 IAppHostElementCollection *pCollection,
2928 DWORD *plSiteId
2929 )
2930{
2931 HRESULT hr = S_OK;
2932 IAppHostElement *pElement = NULL;
2933 IAppHostProperty *pProperty = NULL;
2934
2935 DWORD cSites;
2936 DWORD plNextAvailSite = 0;
2937 VARIANT vPropValue;
2938 VARIANT vtIndex;
2939
2940 VariantInit(&vPropValue);
2941 VariantInit(&vtIndex);
2942
2943 *plSiteId = 0;
2944
2945 hr = pCollection->get_Count(&cSites);
2946 ExitOnFailure(hr, "Failed get sites collection count");
2947
2948 vtIndex.vt = VT_UI4;
2949 for (DWORD i = 0; i < cSites; ++i)
2950 {
2951 vtIndex.ulVal = i;
2952 hr = pCollection->get_Item(vtIndex , &pElement);
2953 ExitOnFailure(hr, "Failed get sites collection item");
2954
2955 hr = pElement->GetPropertyByName(ScopeBSTR(IIS_CONFIG_ID), &pProperty);
2956 ExitOnFailure(hr, "Failed get site property");
2957
2958 hr = pProperty->get_Value(&vPropValue);
2959 ExitOnFailure(hr, "Failed get site property value");
2960
2961 *plSiteId = vPropValue.lVal;
2962 if (*plSiteId > plNextAvailSite)
2963 {
2964 plNextAvailSite = *plSiteId;
2965 }
2966 ReleaseNullObject(pElement);
2967 ReleaseNullObject(pProperty);
2968 }
2969 *plSiteId = ++plNextAvailSite;
2970
2971LExit:
2972 ReleaseVariant(vPropValue);
2973 ReleaseVariant(vtIndex);
2974
2975 ReleaseObject(pElement);
2976 ReleaseObject(pProperty);
2977
2978 return hr;
2979}
2980
2981static HRESULT GetSiteElement(
2982 IAppHostWritableAdminManager *pAdminMgr,
2983 LPCWSTR swSiteName,
2984 IAppHostElement **ppSiteElement,
2985 BOOL* fFound
2986 )
2987{
2988 HRESULT hr = S_OK;
2989 IAppHostElement *pSites = NULL;
2990 IAppHostElementCollection *pCollection = NULL;
2991
2992 *fFound = FALSE;
2993
2994 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_SITES_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pSites);
2995 ExitOnFailure(hr, "Failed get sites section");
2996 ExitOnNull(pSites, hr, ERROR_FILE_NOT_FOUND, "Failed get sites section object");
2997
2998 hr = pSites->get_Collection(&pCollection);
2999 ExitOnFailure(hr, "Failed get sites collection");
3000
3001 hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_NAME, swSiteName, ppSiteElement, NULL);
3002 ExitOnFailure(hr, "Failed to find site %ls", swSiteName);
3003
3004 *fFound = ppSiteElement != NULL && *ppSiteElement != NULL;
3005
3006LExit:
3007 ReleaseObject(pSites);
3008 ReleaseObject(pCollection);
3009
3010 return hr;
3011}
3012
3013static HRESULT GetApplicationElement( IAppHostElement *pSiteElement,
3014 LPCWSTR swAppPath,
3015 IAppHostElement **ppAppElement,
3016 BOOL* fFound)
3017{
3018 HRESULT hr = S_OK;
3019 IAppHostElementCollection *pCollection = NULL;
3020
3021 *fFound = FALSE;
3022
3023 hr = pSiteElement->get_Collection( &pCollection);
3024 ExitOnFailure(hr, "Failed get site app collection");
3025
3026 hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_APPLICATION, IIS_CONFIG_PATH, swAppPath, ppAppElement, NULL);
3027 ExitOnFailure(hr, "Failed to find app %ls", swAppPath);
3028
3029 *fFound = ppAppElement != NULL && *ppAppElement != NULL;
3030
3031LExit:
3032 ReleaseObject(pCollection);
3033
3034 return hr;
3035}
3036
3037static HRESULT GetApplicationElementForVDir( IAppHostElement *pSiteElement,
3038 LPCWSTR pwzVDirPath,
3039 IAppHostElement **ppAppElement,
3040 LPCWSTR *ppwzVDirSubPath,
3041 BOOL* fFound)
3042{
3043 HRESULT hr = S_OK;
3044 IAppHostElementCollection *pCollection = NULL;
3045 LPWSTR pwzAppPath = NULL;
3046 *fFound = FALSE;
3047 *ppwzVDirSubPath = NULL;
3048
3049 hr = pSiteElement->get_Collection( &pCollection);
3050 ExitOnFailure(hr, "Failed get site app collection");
3051
3052 // Start with full path
3053 int iLastPathIndex = lstrlenW(pwzVDirPath) - 1;
3054 hr = StrAllocString(&pwzAppPath, pwzVDirPath, 0);
3055 ExitOnFailure(hr, "Failed allocate application path");
3056
3057 for (int iSubPathIndex = iLastPathIndex; (iSubPathIndex >= 0) && (!*fFound); --iSubPathIndex)
3058 {
3059 // We are looking at the full path, or at a directory boundary, or at the root
3060 if (iSubPathIndex == iLastPathIndex ||
3061 '/' == pwzAppPath[iSubPathIndex] ||
3062 0 == iSubPathIndex)
3063 {
3064 // break the path if needed
3065 if ('/' == pwzAppPath[iSubPathIndex])
3066 {
3067 pwzAppPath[iSubPathIndex] = '\0';
3068 }
3069
3070 // Special case for root path, need an empty app path
3071 LPCWSTR pwzAppSearchPath = 0 == iSubPathIndex ? L"/" : pwzAppPath;
3072
3073 // Try to find an app with the specified path
3074 hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_APPLICATION, IIS_CONFIG_PATH, pwzAppSearchPath, ppAppElement, NULL);
3075 ExitOnFailure(hr, "Failed to search for app %ls", pwzAppSearchPath);
3076 *fFound = ppAppElement != NULL && *ppAppElement != NULL;
3077
3078 if (*fFound)
3079 {
3080 // set return value for sub path
3081 // special case for app path == vdir path, need an empty subpath.
3082 *ppwzVDirSubPath = (iSubPathIndex == iLastPathIndex) ? L"/" : pwzVDirPath + iSubPathIndex;
3083 }
3084 }
3085 }
3086
3087LExit:
3088 ReleaseObject(pCollection);
3089 ReleaseStr(pwzAppPath);
3090
3091 return hr;
3092}
3093
3094static HRESULT CreateSite(
3095 __in IAppHostElementCollection *pCollection,
3096 __in LPCWSTR swSiteName,
3097 __out IAppHostElement **pSiteElement
3098 )
3099{
3100 HRESULT hr = S_OK;
3101 IAppHostElement *pNewElement = NULL;
3102
3103 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_SITE), &pNewElement);
3104 ExitOnFailure(hr, "Failed create site element");
3105
3106 hr = Iis7PutPropertyString(pNewElement, IIS_CONFIG_NAME, swSiteName);
3107 ExitOnFailure(hr, "Failed set site name property");
3108
3109 DWORD lSiteId = 0;
3110 hr = GetNextAvailableSiteId(pCollection, &lSiteId);
3111 ExitOnFailure(hr, "Failed get next site id");
3112
3113 Iis7PutPropertyInteger(pNewElement, IIS_CONFIG_ID, lSiteId);
3114 ExitOnFailure(hr, "Failed set site id property");
3115
3116 hr = pCollection->AddElement(pNewElement);
3117 ExitOnFailure(hr, "Failed add site element");
3118
3119 *pSiteElement = pNewElement;
3120 pNewElement = NULL;
3121
3122LExit:
3123 ReleaseObject(pNewElement);
3124
3125 return hr;
3126}
3127
3128static HRESULT CreateApplication(
3129 IAppHostElement *pSiteElement,
3130 LPCWSTR swAppPath,
3131 IAppHostElement **pAppElement
3132 )
3133{
3134 HRESULT hr = S_OK;
3135 IAppHostElement *pNewElement = NULL;
3136 IAppHostElementCollection *pCollection = NULL;
3137
3138 hr = pSiteElement->get_Collection(&pCollection);
3139 ExitOnFailure(hr, "Failed get application collection");
3140
3141 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_APPLICATION), &pNewElement);
3142 ExitOnFailure(hr, "Failed get application element");
3143
3144 hr = Iis7PutPropertyString(pNewElement, IIS_CONFIG_PATH, swAppPath);
3145 ExitOnFailure(hr, "Failed set application path property");
3146
3147 hr = pCollection->AddElement(pNewElement);
3148 ExitOnFailure(hr, "Failed add application to collection");
3149
3150 *pAppElement = pNewElement;
3151 pNewElement = NULL;
3152
3153LExit:
3154 ReleaseObject(pCollection);
3155 ReleaseObject(pNewElement);
3156
3157 return hr;
3158}
3159
3160static HRESULT DeleteApplication(
3161 IAppHostElement *pSiteElement,
3162 LPCWSTR swAppPath
3163 )
3164{
3165 HRESULT hr = S_OK;
3166 IAppHostElementCollection *pCollection = NULL;
3167
3168 hr = pSiteElement->get_Collection(&pCollection);
3169 ExitOnFailure(hr, "Failed get application collection");
3170
3171 hr = DeleteCollectionElement(pCollection, IIS_CONFIG_APPLICATION, IIS_CONFIG_PATH, swAppPath);
3172 ExitOnFailure(hr, "Failed to delete website");
3173
3174LExit:
3175 ReleaseObject(pCollection);
3176
3177 return hr;
3178}
3179
3180static HRESULT SetAppPool(
3181 IAppHostElement *pAppElement,
3182 LPCWSTR pwzAppPool
3183 )
3184{
3185 HRESULT hr = S_OK;
3186
3187 if (*pwzAppPool != 0)
3188 {
3189 hr = Iis7PutPropertyString(pAppElement, IIS_CONFIG_APPPOOL, pwzAppPool);
3190 ExitOnFailure(hr, "Failed set application appPool property");
3191 }
3192LExit:
3193 return hr;
3194}
3195
3196static HRESULT CreateVdir(
3197 IAppHostElement *pAppElement,
3198 LPCWSTR pwzVDirPath,
3199 LPCWSTR pwzVDirPhyDir
3200 )
3201{
3202 HRESULT hr = S_OK;
3203 IAppHostElement *pElement = NULL;
3204 IAppHostElementCollection *pCollection = NULL;
3205 BOOL fFound;
3206
3207 hr = pAppElement->get_Collection(&pCollection);
3208 ExitOnFailure(hr, "Failed get application VDir collection");
3209
3210 hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_VDIR, IIS_CONFIG_PATH, pwzVDirPath, &pElement, NULL);
3211 ExitOnFailure(hr, "Failed while finding virtualDir");
3212 fFound = (NULL != pElement);
3213
3214 if (!fFound)
3215 {
3216 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_VDIR), &pElement);
3217 ExitOnFailure(hr, "Failed create application VDir collection");
3218
3219 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PATH, pwzVDirPath);
3220 ExitOnFailure(hr, "Failed set VDir path property");
3221 }
3222
3223 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PHYSPATH, pwzVDirPhyDir);
3224 ExitOnFailure(hr, "Failed set VDir phys path property");
3225
3226 if (!fFound)
3227 {
3228 hr = pCollection->AddElement(pElement);
3229 ExitOnFailure(hr, "Failed add application VDir element");
3230 }
3231
3232LExit:
3233 ReleaseObject(pCollection);
3234 ReleaseObject(pElement);
3235
3236 return hr;
3237}
3238
3239static HRESULT DeleteVdir(
3240 IAppHostElement *pAppElement,
3241 LPCWSTR pwzVDirPath
3242 )
3243{
3244 HRESULT hr = S_OK;
3245 IAppHostElementCollection *pCollection = NULL;
3246
3247 hr = pAppElement->get_Collection(&pCollection);
3248 ExitOnFailure(hr, "Failed get application VDir collection");
3249
3250 hr = DeleteCollectionElement(pCollection, IIS_CONFIG_VDIR, IIS_CONFIG_PATH, pwzVDirPath);
3251 ExitOnFailure(hr, "Failed to delete vdir");
3252
3253LExit:
3254 ReleaseObject(pCollection);
3255
3256 return hr;
3257}
3258
3259static HRESULT CreateBinding(
3260 IAppHostElement *pSiteElem,
3261 LPCWSTR pwzProtocol,
3262 LPCWSTR pwzInfo
3263 )
3264{
3265 HRESULT hr = S_OK;
3266 IAppHostChildElementCollection *pChildElems = NULL;
3267 IAppHostElement *pBindings = NULL;
3268 IAppHostElement *pBindingElement = NULL;
3269 IAppHostElementCollection *pCollection = NULL;
3270
3271 VARIANT vtProp;
3272
3273 VariantInit(&vtProp);
3274
3275 hr = pSiteElem->get_ChildElements(&pChildElems);
3276 ExitOnFailure(hr, "Failed get site child elements collection");
3277
3278 vtProp.vt = VT_BSTR;
3279 vtProp.bstrVal = ::SysAllocString(IIS_CONFIG_BINDINGS);
3280 hr = pChildElems->get_Item(vtProp, &pBindings);
3281 ExitOnFailure(hr, "Failed get bindings element");
3282 ReleaseVariant(vtProp);
3283
3284 hr = pBindings->get_Collection(&pCollection);
3285 ExitOnFailure(hr, "Failed get bindings collection");
3286
3287 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_BINDING), &pBindingElement);
3288 ExitOnFailure(hr, "Failed get binding element");
3289
3290 hr = Iis7PutPropertyString(pBindingElement, IIS_CONFIG_PROTOCOL, pwzProtocol);
3291 ExitOnFailure(hr, "Failed set binding protocol property");
3292
3293 hr = Iis7PutPropertyString(pBindingElement, IIS_CONFIG_BINDINGINFO, pwzInfo);
3294 ExitOnFailure(hr, "Failed set binding information property");
3295
3296 hr = pCollection->AddElement(pBindingElement);
3297 if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
3298 {
3299 //Eat this error. Binding is there and nothing to repair since
3300 //identity == protocol + info so all is OK
3301 hr = S_OK;
3302 }
3303 else
3304 {
3305 ExitOnFailure(hr, "Failed add binding to site");
3306 }
3307
3308LExit:
3309 ReleaseVariant(vtProp);
3310
3311 ReleaseObject(pCollection);
3312 ReleaseObject(pChildElems);
3313 ReleaseObject(pBindingElement);
3314 ReleaseObject(pBindings);
3315
3316 return hr;
3317}
3318static HRESULT CreateWebLog(
3319 IAppHostElement *pSiteElem,
3320 LPCWSTR pwzFormat
3321 )
3322{
3323 HRESULT hr = S_OK;
3324 IAppHostChildElementCollection *pChildElems = NULL;
3325 IAppHostElement *pLogFile = NULL;
3326
3327 VARIANT vtProp;
3328
3329 VariantInit(&vtProp);
3330
3331 hr = pSiteElem->get_ChildElements(&pChildElems);
3332 ExitOnFailure(hr, "Failed get site child elements collection");
3333
3334 vtProp.vt = VT_BSTR;
3335 vtProp.bstrVal = ::SysAllocString(IIS_CONFIG_WEBLOG);
3336 hr = pChildElems->get_Item(vtProp, &pLogFile);
3337 ExitOnFailure(hr, "Failed get logfile element");
3338 ReleaseVariant(vtProp);
3339
3340 if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pwzFormat, -1, L"none", -1))
3341 {
3342 hr = Iis7PutPropertyString(pLogFile, IIS_CONFIG_LOGFORMAT, pwzFormat);
3343 ExitOnFailure(hr, "Failed set logfile format property");
3344 hr = Iis7PutPropertyString(pLogFile, IIS_CONFIG_ENABLED, IIS_CONFIG_TRUE);
3345 ExitOnFailure(hr, "Failed set logfile enabled property");
3346 }
3347 else
3348 {
3349 hr = Iis7PutPropertyString(pLogFile, IIS_CONFIG_ENABLED, IIS_CONFIG_FALSE);
3350 ExitOnFailure(hr, "Failed set logfile enabled property");
3351 }
3352
3353LExit:
3354 ReleaseVariant(vtProp);
3355
3356 ReleaseObject(pLogFile);
3357 ReleaseObject(pChildElems);
3358
3359 return hr;
3360}
3361
3362static HRESULT DeleteBinding(
3363 IAppHostElement* /*pSiteElem*/,
3364 LPCWSTR /*pwzProtocol*/,
3365 LPCWSTR /*pwzInfo*/
3366 )
3367{
3368 HRESULT hr = S_OK;
3369 //
3370 //this isn't supported right now, we should support this for the SiteSearch scenario
3371 return hr;
3372}
3373
3374struct SCA_SSLBINDINGINFO
3375{
3376 IIS7_APPHOSTELEMENTCOMPARISON comparison;
3377 LPCWSTR pwzStoreName;
3378 LPCWSTR pwzEncodedCertificateHash;
3379 HRESULT hr;
3380};
3381
3382static BOOL AddSslCertificateToBindingCallback(IAppHostElement *pBindingElement, LPVOID pContext)
3383{
3384 HRESULT hr = S_OK;
3385 VARIANT vtProp;
3386 VariantInit(&vtProp);
3387 SCA_SSLBINDINGINFO* pBindingInfo = (SCA_SSLBINDINGINFO*)pContext;
3388 IAppHostMethodCollection *pAppHostMethodCollection = NULL;
3389 IAppHostMethod *pAddSslMethod = NULL;
3390 IAppHostMethodInstance *pAddSslMethodInstance = NULL;
3391 IAppHostElement *pAddSslInput = NULL;
3392 int iWsaError = 0;
3393 WSADATA wsaData = {};
3394 BOOL fWsaInitialized = FALSE;
3395
3396 // IIS's AddSslCertificate doesn't initialize WinSock on 2008 before using it to parse the IP
3397 // Initialize before calling to workaround the failure.
3398 iWsaError = WSAStartup(MAKEWORD(2, 2), &wsaData);
3399 if (0 != iWsaError)
3400 {
3401 ExitOnWin32Error(iWsaError, hr, "Failed to initialize WinSock");
3402 }
3403
3404 fWsaInitialized = TRUE;
3405
3406 if (Iis7IsMatchingAppHostElement(pBindingElement, &pBindingInfo->comparison))
3407 {
3408 hr = pBindingElement->get_Methods(&pAppHostMethodCollection);
3409 ExitOnFailure(hr, "failed to get binding method collection");
3410
3411 hr = Iis7FindAppHostMethod(pAppHostMethodCollection, L"AddSslCertificate", &pAddSslMethod, NULL);
3412 if (FAILED(hr))
3413 {
3414 WcaLog(LOGMSG_STANDARD, "The AddSslCertificate method is not supported by the binding element, SSL certificate will not be associated with the website");
3415 ExitFunction();
3416 }
3417
3418 pAddSslMethod->CreateInstance(&pAddSslMethodInstance);
3419 ExitOnFailure(hr, "failed to create an instance of AddSslCertificate method");
3420
3421 pAddSslMethodInstance->get_Input(&pAddSslInput);
3422 ExitOnFailure(hr, "failed to get input element of AddSslCertificate method");
3423
3424 Iis7PutPropertyString(pAddSslInput, IIS_CONFIG_CERTIFICATESTORENAME, pBindingInfo->pwzStoreName);
3425 ExitOnFailure(hr, "failed to set certificateStoreName input parameter of AddSslCertificate method");
3426
3427 Iis7PutPropertyString(pAddSslInput, IIS_CONFIG_CERTIFICATEHASH, pBindingInfo->pwzEncodedCertificateHash);
3428 ExitOnFailure(hr, "failed to set certificateHash input parameter of AddSslCertificate method");
3429
3430 hr = pAddSslMethodInstance->Execute();
3431 ExitOnFailure(hr, "failed to execute AddSslCertificate method");
3432 }
3433LExit:
3434 pBindingInfo->hr = hr;
3435 ReleaseObject(pAppHostMethodCollection);
3436 ReleaseObject(pAddSslMethod);
3437 ReleaseObject(pAddSslMethodInstance);
3438 ReleaseObject(pAddSslInput);
3439 if (fWsaInitialized)
3440 {
3441 WSACleanup();
3442 }
3443
3444 return FAILED(hr);
3445}
3446
3447static HRESULT CreateSslBinding( IAppHostElement *pSiteElem, LPCWSTR pwzStoreName, LPCWSTR pwzEncodedCertificateHash)
3448{
3449 HRESULT hr = S_OK;
3450 IAppHostChildElementCollection *pChildElems = NULL;
3451 IAppHostElement *pBindingsElement = NULL;
3452 IAppHostElementCollection *pBindingsCollection = NULL;
3453 SCA_SSLBINDINGINFO bindingInfo = {};
3454 VARIANT vtProp;
3455 VariantInit(&vtProp);
3456
3457 hr = pSiteElem->get_ChildElements(&pChildElems);
3458 ExitOnFailure(hr, "Failed get site child elements collection");
3459
3460 vtProp.vt = VT_BSTR;
3461 vtProp.bstrVal = ::SysAllocString(IIS_CONFIG_BINDINGS);
3462 hr = pChildElems->get_Item(vtProp, &pBindingsElement);
3463 ExitOnFailure(hr, "Failed get bindings element");
3464 ReleaseVariant(vtProp);
3465
3466 hr = pBindingsElement->get_Collection(&pBindingsCollection);
3467 ExitOnFailure(hr, "Failed get bindings collection");
3468
3469 bindingInfo.comparison.sczElementName = IIS_CONFIG_BINDING;
3470 bindingInfo.comparison.sczAttributeName = IIS_CONFIG_PROTOCOL;
3471 vtProp.vt = VT_BSTR;
3472 vtProp.bstrVal = ::SysAllocString(L"https");
3473 bindingInfo.comparison.pvAttributeValue = &vtProp;
3474 bindingInfo.pwzStoreName = pwzStoreName;
3475 bindingInfo.pwzEncodedCertificateHash = pwzEncodedCertificateHash;
3476
3477 // Our current IISWebSiteCertificates schema does not allow specification of the website binding
3478 // to associate the certificate with. For now just associate it with all secure bindings.
3479
3480 hr = Iis7EnumAppHostElements(pBindingsCollection, AddSslCertificateToBindingCallback, &bindingInfo, NULL, NULL);
3481 ExitOnFailure(hr, "Failed to enumerate bindings collection");
3482 hr = bindingInfo.hr;
3483 ExitOnFailure(hr, "Failed to add ssl binding");
3484
3485LExit:
3486 ReleaseVariant(vtProp);
3487
3488 ReleaseObject(pChildElems);
3489 ReleaseObject(pBindingsElement);
3490 ReleaseObject(pBindingsCollection);
3491
3492 return hr;
3493}
3494
3495static HRESULT DeleteSslBinding(
3496 IAppHostElement * /*pSiteElem*/,
3497 LPCWSTR /*pwzStoreName*/,
3498 LPCWSTR /*pwzEncodedCertificateHash*/
3499 )
3500{
3501 HRESULT hr = S_OK;
3502 //
3503 //this isn't supported right now, we should support this for the SiteSearch scenario
3504 return hr;
3505}
3506
3507static HRESULT DeleteAppPool( IAppHostWritableAdminManager *pAdminMgr,
3508 LPCWSTR swAppPoolName)
3509{
3510 HRESULT hr = S_OK;
3511 IAppHostElement *pAppPools = NULL;
3512 IAppHostElementCollection *pCollection = NULL;
3513
3514 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_APPPOOL_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pAppPools);
3515 ExitOnFailure(hr, "Failed get AppPools section");
3516 ExitOnNull(pAppPools, hr, E_UNEXPECTED, "Failed get appPools section object");
3517
3518 hr = pAppPools->get_Collection( &pCollection);
3519 ExitOnFailure(hr, "Failed get AppPools collection");
3520
3521 hr = DeleteCollectionElement(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_NAME, swAppPoolName);
3522 ExitOnFailure(hr, "Failed to delete app pool %ls", swAppPoolName);
3523
3524LExit:
3525 ReleaseObject(pAppPools);
3526 ReleaseObject(pCollection);
3527
3528 return hr;
3529}
3530
3531static HRESULT CreateAppPool(
3532 __inout LPWSTR *ppwzCustomActionData,
3533 IAppHostWritableAdminManager *pAdminMgr,
3534 LPCWSTR swAppPoolName
3535 )
3536{
3537 HRESULT hr = S_OK;
3538 IAppHostElement *pAppPools = NULL;
3539 IAppHostElement *pAppPoolElement = NULL;
3540 IAppHostElement *pElement = NULL;
3541 IAppHostElement *pElement2 = NULL;
3542 IAppHostElement *pElement3 = NULL;
3543 IAppHostElementCollection *pCollection = NULL;
3544 IAppHostElementCollection *pCollection2 = NULL;
3545 int iAction = -1;
3546 int iData = 0;
3547 LPWSTR pwzData = NULL;
3548 WCHAR wcData[512];
3549 WCHAR wcTime[60];
3550 BOOL fFound = FALSE;
3551
3552 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_APPPOOL_SECTION), ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pAppPools);
3553 ExitOnFailure(hr, "Failed get AppPools section");
3554 ExitOnNull(pAppPools, hr, ERROR_FILE_NOT_FOUND, "Failed get AppPools section object");
3555
3556 hr = pAppPools->get_Collection( &pCollection);
3557 ExitOnFailure(hr, "Failed get AppPools collection");
3558
3559 hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_ADD, IIS_CONFIG_NAME, swAppPoolName, &pAppPoolElement, NULL);
3560 ExitOnFailure(hr, "Failed find AppPool element");
3561 fFound = (NULL != pAppPoolElement);
3562
3563 if (!fFound)
3564 {
3565 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pAppPoolElement);
3566 ExitOnFailure(hr, "Failed create AppPool element");
3567 }
3568
3569 hr = Iis7PutPropertyString(pAppPoolElement, IIS_CONFIG_NAME, swAppPoolName);
3570 ExitOnFailure(hr, "Failed set AppPool name property");
3571
3572 //For WiX II6 /ABO compat we will default managedPipelineMode="Classic"
3573 hr = Iis7PutPropertyString(pAppPoolElement, IIS_CONFIG_PIPELINEMODE, L"Classic");
3574 ExitOnFailure(hr, "Failed set AppPool managedPipelineMode property");
3575 //For WiX II6 /ABO compat we will be hardcoding autostart="true"
3576 hr = Iis7PutPropertyString(pAppPoolElement, IIS_CONFIG_APPPOOL_AUTO, L"true");
3577 ExitOnFailure(hr, "Failed set AppPool autoStart property");
3578
3579 if (!fFound)
3580 {
3581 hr = pCollection->AddElement(pAppPoolElement);
3582 ExitOnFailure(hr, "Failed to add appPool element");
3583 }
3584
3585 // Get AppPool Property action
3586 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
3587 ExitOnFailure(hr, "Failed to read AppPool Property action");
3588 while (IIS_APPPOOL_END != iAction)
3589 {
3590 //Process property action
3591 switch (iAction)
3592 {
3593 case IIS_APPPOOL_RECYCLE_MIN :
3594 {
3595 // /recycling / periodicRestart | time
3596 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3597 ExitOnFailure(hr, "Failed to read AppPool recycle min");
3598 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_RECYCLING), &pElement);
3599 ExitOnFailure(hr, "Failed to get AppPool recycling element");
3600 hr = pElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PEROIDRESTART), &pElement2);
3601 ExitOnFailure(hr, "Failed to get AppPool periodicRestart element");
3602 *wcTime = '\0';
3603 ConvSecToHMS(iData * 60, wcTime, countof(wcTime));
3604 hr = Iis7PutPropertyString(pElement2, IIS_CONFIG_TIME, wcTime);
3605 ExitOnFailure(hr, "Failed to set AppPool periodicRestart time value");
3606 ReleaseNullObject(pElement);
3607 ReleaseNullObject(pElement2);
3608 break;
3609 }
3610 case IIS_APPPOOL_RECYCLE_REQ :
3611 {
3612 // /recycling / periodicRestart | requests
3613 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3614 ExitOnFailure(hr, "Failed to read AppPool recycle req");
3615 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_RECYCLING), &pElement);
3616 ExitOnFailure(hr, "Failed to get AppPool recycling element");
3617 hr = pElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PEROIDRESTART), &pElement2);
3618 ExitOnFailure(hr, "Failed to get AppPool periodicRestart element");
3619 hr = Iis7PutPropertyInteger(pElement2, IIS_CONFIG_REQUESTS, iData);
3620 ExitOnFailure(hr, "Failed to set AppPool periodicRestart time value");
3621 ReleaseNullObject(pElement);
3622 ReleaseNullObject(pElement2);
3623 break;
3624 }
3625 case IIS_APPPOOL_RECYCLE_TIMES :
3626 {
3627 // /recycling / periodicRestart | schedule
3628 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
3629 ExitOnFailure(hr, "Failed to read AppPool recycle times");
3630 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_RECYCLING), &pElement);
3631 ExitOnFailure(hr, "Failed to get AppPool recycling element");
3632 hr = pElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PEROIDRESTART), &pElement2);
3633 ExitOnFailure(hr, "Failed to get AppPool periodicRestart element");
3634 hr = pElement2->GetElementByName(ScopeBSTR(IIS_CONFIG_SCHEDULE), &pElement3);
3635 ExitOnFailure(hr, "Failed to get AppPool schedule element");
3636 hr = pElement3->get_Collection(&pCollection2);
3637 ExitOnFailure(hr, "Failed to get AppPool schedule collection");
3638
3639 WCHAR wcDelim[] = L",";
3640 const WCHAR *wszToken = NULL;
3641 WCHAR *wszNextToken = NULL;
3642 wszToken = wcstok_s( pwzData, wcDelim, &wszNextToken);
3643
3644 while (wszToken)
3645 {
3646 *wcData = '\0';
3647 hr = ::StringCchCopyW(wcData, countof(wcData), wszToken);
3648 ExitOnFailure(hr, "failed to copy AppPool schedule");
3649 hr = ::StringCchCatW(wcData, countof(wcData), L":00");
3650 ExitOnFailure(hr, "failed to append AppPool schedule");
3651
3652 hr = pCollection2->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pElement3);
3653 ExitOnFailure(hr, "Failed to create AppPool schedule element");
3654
3655 hr = Iis7PutPropertyString(pElement3, IIS_CONFIG_VALUE, wcData);
3656 ExitOnFailure(hr, "Failed to set AppPool schedule value");
3657
3658 hr = pCollection2->AddElement(pElement3);
3659 if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
3660 {
3661 //Eat this error, recycle time already exists NBD
3662 hr = S_OK;
3663 }
3664 ExitOnFailure(hr, "Failed to add win auth providers element");
3665 ReleaseNullObject(pElement3);
3666 wszToken = wcstok_s( NULL, wcDelim, &wszNextToken);
3667 }
3668 ReleaseNullObject(pElement);
3669 ReleaseNullObject(pElement2);
3670 ReleaseNullObject(pElement3);
3671 ReleaseNullObject(pCollection2);
3672 break;
3673 }
3674 case IIS_APPPOOL_RECYCLE_VIRMEM :
3675 {
3676 // /recycling / periodicRestart | memory
3677 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3678 ExitOnFailure(hr, "Failed to read AppPool recycle vir memory");
3679 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_RECYCLING), &pElement);
3680 ExitOnFailure(hr, "Failed to get AppPool recycling element");
3681 hr = pElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PEROIDRESTART), &pElement2);
3682 ExitOnFailure(hr, "Failed to get AppPool periodicRestart element");
3683 hr = Iis7PutPropertyInteger(pElement2, IIS_CONFIG_MEMORY, iData);
3684 ExitOnFailure(hr, "Failed to set AppPool periodicRestart memory");
3685 ReleaseNullObject(pElement);
3686 ReleaseNullObject(pElement2);
3687 break;
3688 }
3689 case IIS_APPPOOL_RECYCLE_PRIVMEM :
3690 {
3691 // /recycling / periodicRestart | privateMemory
3692 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3693 ExitOnFailure(hr, "Failed to read AppPool recycle priv mem");
3694 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_RECYCLING), &pElement);
3695 ExitOnFailure(hr, "Failed to get AppPool recycling element");
3696 hr = pElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PEROIDRESTART), &pElement2);
3697 ExitOnFailure(hr, "Failed to get AppPool periodicRestart element");
3698 hr = Iis7PutPropertyInteger(pElement2, IIS_CONFIG_PRIVMEMORY, iData);
3699 ExitOnFailure(hr, "Failed to set AppPool periodicRestart private memory");
3700 ReleaseNullObject(pElement);
3701 ReleaseNullObject(pElement2);
3702 break;
3703 }
3704 case IIS_APPPOOL_RECYCLE_IDLTIMEOUT :
3705 {
3706 // /processModel | idleTimeout
3707 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3708 ExitOnFailure(hr, "Failed to read AppPool idle timeout");
3709 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PROCESSMODEL), &pElement);
3710 ExitOnFailure(hr, "Failed to get AppPool processModel element");
3711 *wcTime = '\0';
3712 ConvSecToHMS(iData * 60, wcTime, countof(wcTime));
3713 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDLETIMEOUT, wcTime);
3714 ExitOnFailure(hr, "Failed to set AppPool processModel idle timeout value");
3715 ReleaseNullObject(pElement);
3716 break;
3717 }
3718 case IIS_APPPOOL_RECYCLE_QUEUELIMIT :
3719 {
3720 // /applicationPools | queueLength
3721 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3722 ExitOnFailure(hr, "Failed to read AppPool recycle queue limit");
3723 hr = Iis7PutPropertyInteger(pAppPoolElement, IIS_CONFIG_QUEUELENGTH, iData);
3724 ExitOnFailure(hr, "Failed to set AppPool recycle queue limit value");
3725 break;
3726 }
3727 case IIS_APPPOOL_MAXPROCESS :
3728 {
3729 // /processModel | maxProcesses
3730 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3731 ExitOnFailure(hr, "Failed to read AppPool max processes");
3732 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PROCESSMODEL), &pElement);
3733 ExitOnFailure(hr, "Failed to get AppPool processModel element");
3734 hr = Iis7PutPropertyInteger(pElement, IIS_CONFIG_MAXWRKPROCESSES, iData);
3735 ExitOnFailure(hr, "Failed to set AppPool processModel maxProcesses value");
3736 ReleaseNullObject(pElement);
3737 break;
3738 }
3739 case IIS_APPPOOL_IDENTITY :
3740 {
3741 //"LocalSystem" 0
3742 //"LocalService" 1
3743 //"NetworkService" 2
3744 //"SpecificUser" 3
3745 //"ApplicationPoolIdentity" 4
3746 // /processModel | identityType
3747 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3748 ExitOnFailure(hr, "Failed to read AppPool identity");
3749 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PROCESSMODEL), &pElement);
3750 ExitOnFailure(hr, "Failed to get AppPool processModel element");
3751 if (iData == 0)
3752 {
3753 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDENITITYTYPE, IIS_CONFIG_LOCALSYSTEM);
3754 }
3755 else if (iData == 1)
3756 {
3757 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDENITITYTYPE, IIS_CONFIG_LOCALSERVICE);
3758 }
3759 else if (iData == 2)
3760 {
3761 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDENITITYTYPE, IIS_CONFIG_NETWORKSERVICE);
3762 }
3763 else if (iData == 3)
3764 {
3765 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDENITITYTYPE, IIS_CONFIG_SPECIFICUSER);
3766 }
3767 else if (iData == 4)
3768 {
3769 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_IDENITITYTYPE, IIS_CONFIG_APPLICATIONPOOLIDENTITY);
3770 }
3771 ExitOnFailure(hr, "Failed to set AppPool processModel identityType value");
3772 ReleaseNullObject(pElement);
3773 break;
3774 }
3775 case IIS_APPPOOL_USER :
3776 {
3777 // /processModel | userName
3778 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
3779 ExitOnFailure(hr, "Failed to read AppPool user");
3780 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PROCESSMODEL), &pElement);
3781 ExitOnFailure(hr, "Failed to get AppPool processModel element");
3782 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_USERNAME, pwzData);
3783 ExitOnFailure(hr, "Failed to set AppPool processModel username value");
3784 ReleaseNullObject(pElement);
3785 break;
3786 }
3787 case IIS_APPPOOL_PWD :
3788 {
3789 // /processModel | password
3790 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
3791 ExitOnFailure(hr, "Failed to read AppPool pwd");
3792 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_PROCESSMODEL), &pElement);
3793 ExitOnFailure(hr, "Failed to get AppPool processModel element");
3794 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_PASSWORD, pwzData);
3795 ExitOnFailure(hr, "Failed to set AppPool processModel password value");
3796 ReleaseNullObject(pElement);
3797 break;
3798 }
3799 case IIS_APPPOOL_RECYCLE_CPU_PCT:
3800 {
3801 // /cpu | limit
3802 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3803 ExitOnFailure(hr, "Failed to read cpu pct");
3804 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_CPU), &pElement);
3805 ExitOnFailure(hr, "Failed to get AppPool cpu element");
3806 // limit is maximum percentage of CPU time (in 1/1000ths of one percent)
3807 hr = Iis7PutPropertyInteger(pElement, IIS_CONFIG_LIMIT, iData * 1000);
3808 ExitOnFailure(hr, "Failed to set AppPool cpu limit");
3809 ReleaseNullObject(pElement);
3810 break;
3811 }
3812 case IIS_APPPOOL_RECYCLE_CPU_REFRESH:
3813 {
3814 // /cpu | resetInterval
3815 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3816 ExitOnFailure(hr, "Failed to read cpu refresh pwd");
3817 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_CPU), &pElement);
3818 ExitOnFailure(hr, "Failed to get AppPool cpu element");
3819 *wcTime = '\0';
3820 ConvSecToHMS(iData * 60, wcTime, countof(wcTime));
3821 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_RESETINTERVAL, wcTime);
3822 ExitOnFailure(hr, "Failed to set AppPool cpu resetInterval value");
3823 ReleaseNullObject(pElement);
3824 break;
3825 }
3826 case IIS_APPPOOL_RECYCLE_CPU_ACTION:
3827 {
3828 // /cpu | action
3829 //"NoAction" 0
3830 //"KillW3wp" 1
3831 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3832 ExitOnFailure(hr, "Failed to read cpu action");
3833 hr = pAppPoolElement->GetElementByName(ScopeBSTR(IIS_CONFIG_CPU), &pElement);
3834 ExitOnFailure(hr, "Failed to get AppPool cpu element");
3835 if (iData)
3836 {
3837 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CPU_ACTION, IIS_CONFIG_KILLW3WP);
3838 }
3839 else
3840 {
3841 hr = Iis7PutPropertyString(pElement, IIS_CONFIG_CPU_ACTION, IIS_CONFIG_NOACTION);
3842 }
3843 ExitOnFailure(hr, "Failed to set AppPool cpu action value");
3844 ReleaseNullObject(pElement);
3845 break;
3846 }
3847 case IIS_APPPOOL_32BIT:
3848 {
3849 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iData);
3850 ExitOnFailure(hr, "Failed to read enable32BitAppOnWin64 value");
3851 // enable32BitAppOnWin64
3852 hr = Iis7PutPropertyBool(pAppPoolElement, IIS_CONFIG_ENABLE32, iData ? TRUE : FALSE);
3853 ExitOnFailure(hr, "Failed to set AppPool enable32BitAppOnWin64 value");
3854 break;
3855 }
3856 case IIS_APPPOOL_MANAGED_PIPELINE_MODE:
3857 {
3858 // managedPipelineMode
3859 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
3860 ExitOnFailure(hr, "Failed to read AppPool managedRuntimeVersion");
3861 hr = Iis7PutPropertyString(pAppPoolElement, IIS_CONFIG_PIPELINEMODE, pwzData);
3862 ExitOnFailure(hr, "Failed set AppPool managedPipelineMode property");
3863 break;
3864 }
3865 case IIS_APPPOOL_MANAGED_RUNTIME_VERSION:
3866 {
3867 // managedRuntimeVersion
3868 hr = WcaReadStringFromCaData(ppwzCustomActionData, &pwzData);
3869 ExitOnFailure(hr, "Failed to read AppPool managedRuntimeVersion");
3870 hr = Iis7PutPropertyString(pAppPoolElement, IIS_CONFIG_MANAGEDRUNTIMEVERSION, pwzData);
3871 ExitOnFailure(hr, "Failed set AppPool managedRuntimeVersion property");
3872 break;
3873 }
3874
3875 default:
3876 ExitOnFailure(hr = E_UNEXPECTED, "Unexpected IIS Config action specified for AppPool");
3877 break;
3878
3879 }
3880 // Get AppPool property action
3881 hr = WcaReadIntegerFromCaData(ppwzCustomActionData, &iAction);
3882 ExitOnFailure(hr, "Failed to read AppPool Property action");
3883 }
3884
3885LExit:
3886 ReleaseObject(pAppPools);
3887 ReleaseObject(pCollection);
3888 ReleaseObject(pCollection2);
3889 ReleaseObject(pAppPoolElement);
3890 ReleaseObject(pElement);
3891 ReleaseObject(pElement2);
3892 ReleaseObject(pElement3);
3893
3894 return hr;
3895}
3896
3897static HRESULT SetDirPropAuthentications(IAppHostWritableAdminManager *pAdminMgr,
3898 LPCWSTR wszConfigPath,
3899 DWORD dwData)
3900{
3901 HRESULT hr = S_OK;
3902 IAppHostElement *pSection = NULL;
3903
3904 //dwData contains bit flags for /security/authentication/<...>
3905 // Anonymous = 1
3906 // Basic = 2
3907 // Windows = 4
3908 // Digest =16
3909 // Passport =64 *not supported
3910 //translation required from bit map to section name
3911 // E.G security/authentication/windowsAuthentication [property enabled true|false]
3912
3913 // AnonymousAuthentication = 1
3914 hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/anonymousAuthentication"), ScopeBSTR(wszConfigPath), &pSection);
3915 ExitOnFailure(hr, "Failed get AnonymousAuthentication section for DirProp");
3916 if (!pSection)
3917 {
3918 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
3919 ExitOnFailure(hr, "Failed get AnonymousAuthentication section object for DirProps");
3920 }
3921
3922 hr = Iis7PutPropertyBool(pSection, L"enabled", (BOOL)(dwData & 0x1));
3923 ExitOnFailure(hr, "Failed set AnonymousAuthentication enabled for DirProps");
3924 ReleaseNullObject(pSection);
3925
3926 // basicAuthentication = 2
3927 hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/basicAuthentication"), ScopeBSTR(wszConfigPath), &pSection);
3928 ExitOnFailure(hr, "Failed get basicAuthentication section for DirProp");
3929 if (!pSection)
3930 {
3931 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
3932 ExitOnFailure(hr, "Failed get basicAuthentication section object for DirProps");
3933 }
3934
3935 hr = Iis7PutPropertyBool(pSection, L"enabled", (BOOL)(dwData & 0x2));
3936 ExitOnFailure(hr, "Failed set basicAuthentication enabled for DirProps");
3937 ReleaseNullObject(pSection);
3938
3939 // WindowsAuthentication = 4
3940 hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/windowsAuthentication"), ScopeBSTR(wszConfigPath), &pSection);
3941 ExitOnFailure(hr, "Failed get windowsAuthentication section for DirProp");
3942 if (!pSection)
3943 {
3944 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
3945 ExitOnFailure(hr, "Failed get windowsAuthentication section object for DirProps");
3946 }
3947
3948 hr = Iis7PutPropertyBool(pSection, L"enabled", (BOOL)(dwData & 0x4));
3949 ExitOnFailure(hr, "Failed set windowsAuthentication enabled for DirProps");
3950 ReleaseNullObject(pSection);
3951
3952 // digestAuthentication = 16
3953 hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/digestAuthentication"), ScopeBSTR(wszConfigPath), &pSection);
3954 ExitOnFailure(hr, "Failed get digestAuthentication section for DirProp");
3955 if (!pSection)
3956 {
3957 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
3958 ExitOnFailure(hr, "Failed get digestAuthentication section object for DirProps");
3959 }
3960
3961 hr = Iis7PutPropertyBool(pSection, L"enabled", (BOOL)(dwData & 0x10));
3962 ExitOnFailure(hr, "Failed set digestAuthentication enabled for DirProps");
3963 ReleaseNullObject(pSection);
3964
3965LExit:
3966 ReleaseObject(pSection);
3967
3968 return hr;
3969}
3970
3971static HRESULT SetDirPropAuthProvider(IAppHostWritableAdminManager *pAdminMgr,
3972 LPCWSTR wszConfigPath,
3973 __in LPWSTR wszData)
3974{
3975 HRESULT hr = S_OK;
3976 IAppHostElement *pSection = NULL;
3977 IAppHostElement *pElement = NULL;
3978 IAppHostElement *pNewElement = NULL;
3979 IAppHostElementCollection *pCollection = NULL;
3980
3981 WCHAR wcDelim[] = L",";
3982 const WCHAR *wszToken = NULL;
3983 WCHAR *wszNextToken = NULL;
3984
3985 hr = pAdminMgr->GetAdminSection(ScopeBSTR(L"system.webServer/security/authentication/windowsAuthentication"), ScopeBSTR(wszConfigPath), &pSection);
3986 ExitOnFailure(hr, "Failed get windowsAuthentication section for DirProp providers");
3987
3988 hr = pSection->GetElementByName(ScopeBSTR(L"providers"), &pElement);
3989 ExitOnFailure(hr, "Failed get win auth providers section");
3990
3991 hr = pElement->get_Collection(&pCollection);
3992 ExitOnFailure(hr, "Failed get win auth providers collection");
3993
3994 hr = pCollection->Clear();
3995 ExitOnFailure(hr, "Failed to clear win auth providers collection");
3996
3997 //Clear out inherited items - add clear
3998 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_CLEAR), &pNewElement);
3999 ExitOnFailure(hr, "Failed to create win auth providers clear element");
4000 hr = pCollection->AddElement(pNewElement);
4001 ExitOnFailure(hr, "Failed to add win auth providers clear element");
4002 ReleaseNullObject(pNewElement);
4003
4004 wszToken = wcstok_s( wszData, wcDelim, &wszNextToken);
4005 for (int i = 0; (wszToken); ++i)
4006 {
4007 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pNewElement);
4008 ExitOnFailure(hr, "Failed to create win auth providers element");
4009
4010 hr = Iis7PutPropertyString( pNewElement, IIS_CONFIG_VALUE, wszToken);
4011 ExitOnFailure(hr, "Failed to set win auth providers value");
4012
4013 hr = pCollection->AddElement(pNewElement, i);
4014 ExitOnFailure(hr, "Failed to add win auth providers element");
4015 ReleaseNullObject(pNewElement);
4016
4017 wszToken = wcstok_s( NULL, wcDelim, &wszNextToken);
4018 }
4019
4020LExit:
4021 ReleaseObject(pSection);
4022 ReleaseObject(pCollection);
4023 ReleaseObject(pElement);
4024 ReleaseObject(pNewElement);
4025
4026 return hr;
4027}
4028
4029static HRESULT SetDirPropDefDoc(
4030 IAppHostWritableAdminManager *pAdminMgr,
4031 LPCWSTR wszConfigPath,
4032 __in LPWSTR wszData)
4033{
4034 HRESULT hr = S_OK;
4035 IAppHostElement *pSection = NULL;
4036 IAppHostElement *pElement = NULL;
4037 IAppHostElement *pNewElement = NULL;
4038 IAppHostElementCollection *pCollection = NULL;
4039
4040 WCHAR wcDelim[] = L",";
4041 const WCHAR *wszToken = NULL;
4042 WCHAR *wszNextToken = NULL;
4043
4044 hr = pAdminMgr->GetAdminSection(ScopeBSTR(IIS_CONFIG_DEFAULTDOC_SECTION), ScopeBSTR(wszConfigPath), &pSection);
4045 ExitOnFailure(hr, "Failed get defaultDocument section for DirProp");
4046
4047 hr = pSection->GetElementByName(ScopeBSTR(L"files"), &pElement);
4048 ExitOnFailure(hr, "Failed get win files section");
4049
4050 hr = pElement->get_Collection(&pCollection);
4051 ExitOnFailure(hr, "Failed get files collection");
4052
4053 hr = pCollection->Clear();
4054 ExitOnFailure(hr, "Failed clear files collection");
4055
4056 //Clear out inherited items - add clear
4057 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_CLEAR), &pNewElement);
4058 ExitOnFailure(hr, "Failed to create files clear element");
4059 hr = pCollection->AddElement(pNewElement);
4060 ExitOnFailure(hr, "Failed to add files clear element");
4061
4062 wszToken = wcstok_s( wszData, wcDelim, &wszNextToken);
4063 for (int i = 0; (wszToken); ++i)
4064 {
4065 hr = pCollection->CreateNewElement(ScopeBSTR(IIS_CONFIG_ADD), &pNewElement);
4066 ExitOnFailure(hr, "Failed to create win auth providers element");
4067
4068 hr = Iis7PutPropertyString( pNewElement, IIS_CONFIG_VALUE, wszToken);
4069 ExitOnFailure(hr, "Failed to set win auth providers value");
4070
4071 hr = pCollection->AddElement(pNewElement, i);
4072 ExitOnFailure(hr, "Failed to add defaultDocument Files element");
4073 ReleaseNullObject(pNewElement);
4074
4075 wszToken = wcstok_s( NULL, wcDelim, &wszNextToken);
4076 }
4077
4078LExit:
4079 ReleaseObject(pSection);
4080 ReleaseObject(pCollection);
4081 ReleaseObject(pNewElement);
4082
4083 return hr;
4084}
4085
4086static HRESULT ClearLocationTag(
4087 IAppHostWritableAdminManager *pAdminMgr,
4088 LPCWSTR swLocationPath
4089 )
4090{
4091 HRESULT hr = S_OK;
4092 IAppHostConfigManager *pConfigMgr = NULL;
4093 IAppHostConfigFile *pConfigFile = NULL;
4094 IAppHostConfigLocationCollection *pLocationCollection = NULL;
4095 IAppHostConfigLocation *pLocation = NULL;
4096
4097 DWORD dwCount = 0;
4098 BSTR bstrLocationPath = NULL;
4099
4100 hr = pAdminMgr->get_ConfigManager(&pConfigMgr);
4101 ExitOnFailure(hr, "Failed to get IIS ConfigManager interface");
4102
4103 hr = pConfigMgr->GetConfigFile(ScopeBSTR(IIS_CONFIG_APPHOST_ROOT), &pConfigFile);
4104 ExitOnFailure(hr, "Failed to get IIS ConfigFile interface");
4105
4106 hr = pConfigFile->get_Locations(&pLocationCollection);
4107 ExitOnFailure(hr, "Failed to get IIS location tag collection");
4108
4109 hr = pLocationCollection->get_Count(&dwCount);
4110 ExitOnFailure(hr, "Failed to get IIS location collection count");
4111
4112 VARIANT vtIndex;
4113 vtIndex.vt = VT_UI4;
4114 for (DWORD i = 0; i < dwCount; ++i)
4115 {
4116 vtIndex.ulVal = i;
4117 hr = pLocationCollection->get_Item(vtIndex, &pLocation);
4118 ExitOnFailure(hr, "Failed to get IIS location collection count");
4119
4120 hr = pLocation->get_Path(&bstrLocationPath);
4121 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, swLocationPath, -1, bstrLocationPath, -1))
4122 {
4123 hr = pLocationCollection->DeleteLocation(vtIndex);
4124 ExitOnFailure(hr, "Failed to delete IIS location tag %ls",swLocationPath);
4125 break;
4126 }
4127
4128 ReleaseNullObject(pLocation);
4129 ::SysFreeString(bstrLocationPath);
4130 bstrLocationPath = NULL;
4131 }
4132LExit:
4133 ReleaseObject(pConfigMgr);
4134 ReleaseObject(pConfigFile);
4135 ReleaseObject(pLocationCollection);
4136 ReleaseObject(pLocation);
4137 ReleaseBSTR(bstrLocationPath);
4138
4139 return hr;
4140
4141}
4142
4143static HRESULT DeleteCollectionElement(
4144 __in IAppHostElementCollection *pCollection,
4145 __in LPCWSTR pwzElementName,
4146 __in LPCWSTR pwzAttributeName,
4147 __in LPCWSTR pwzAttributeValue
4148 )
4149{
4150 HRESULT hr = S_OK;
4151
4152 DWORD dwIndex;
4153 VARIANT vtIndex;
4154 VariantInit(&vtIndex);
4155
4156 hr = Iis7FindAppHostElementString(pCollection, pwzElementName, pwzAttributeName, pwzAttributeValue, NULL, &dwIndex);
4157 ExitOnFailure(hr, "Failed while finding IAppHostElement %ls/@%ls=%ls", pwzElementName, pwzAttributeName, pwzAttributeValue);
4158
4159 if (MAXDWORD != dwIndex)
4160 {
4161 vtIndex.vt = VT_UI4;
4162 vtIndex.ulVal = dwIndex;
4163 hr = pCollection->DeleteElement(vtIndex);
4164 ExitOnFailure(hr, "Failed to delete IAppHostElement %ls/@%ls=%ls", pwzElementName, pwzAttributeName, pwzAttributeValue);
4165 }
4166 // else : nothing to do, already deleted
4167LExit:
4168 ReleaseVariant(vtIndex);
4169
4170 return hr;
4171}
4172static void ConvSecToHMS( int Sec, __out_ecount(cchDest) LPWSTR wcTime, size_t cchDest)
4173{
4174 int ZH, ZM, ZS = 0;
4175
4176 ZH = (Sec / 3600);
4177 Sec = Sec - ZH * 3600;
4178 ZM = (Sec / 60) ;
4179 Sec = Sec - ZM * 60;
4180 ZS = Sec ;
4181
4182 HRESULT hr = ::StringCchPrintfW(wcTime, cchDest, L"%02d:%02d:%02d", ZH, ZM, ZS);
4183 if (S_OK != hr)
4184 {
4185 *wcTime = '\0';
4186 }
4187}
4188static void ConvSecToDHMS( unsigned int Sec, __out_ecount(cchDest) LPWSTR wcTime, size_t cchDest)
4189{
4190 int ZD, ZH, ZM, ZS = 0;
4191
4192 ZD = Sec / 86400;
4193 Sec = Sec - ZD * 86400;
4194 ZH = (Sec / 3600);
4195 Sec = Sec - ZH * 3600;
4196 ZM = (Sec / 60) ;
4197 Sec = Sec - ZM * 60;
4198 ZS = Sec ;
4199
4200 HRESULT hr = ::StringCchPrintfW(wcTime, cchDest, L"%d.%02d:%02d:%02d", ZD, ZH, ZM, ZS);
4201 if (S_OK != hr)
4202 {
4203 *wcTime = '\0';
4204 }
4205}
diff --git a/src/ext/Iis/ca/scaexecIIS7.h b/src/ext/Iis/ca/scaexecIIS7.h
new file mode 100644
index 00000000..ec31f202
--- /dev/null
+++ b/src/ext/Iis/ca/scaexecIIS7.h
@@ -0,0 +1,5 @@
1#pragma once
2// 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.
3
4
5HRESULT IIS7ConfigChanges(MSIHANDLE hInstall, __inout LPWSTR pwzData);
diff --git a/src/ext/Iis/ca/scafilter.cpp b/src/ext/Iis/ca/scafilter.cpp
new file mode 100644
index 00000000..9d9014fd
--- /dev/null
+++ b/src/ext/Iis/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}
diff --git a/src/ext/Iis/ca/scafilter.h b/src/ext/Iis/ca/scafilter.h
new file mode 100644
index 00000000..d072bf22
--- /dev/null
+++ b/src/ext/Iis/ca/scafilter.h
@@ -0,0 +1,46 @@
1#pragma once
2// 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.
3
4
5#include "scaweb.h"
6
7enum eFilterQuery { fqWeb = 1, fqFilter, fqComponent , fqPath, fqDescription, fqFlags, fqLoadOrder, fqInstalled, fqAction };
8
9struct SCA_FILTER
10{
11 // darwin information
12 WCHAR wzKey[MAX_DARWIN_KEY + 1];
13 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
14 INSTALLSTATE isInstalled;
15 INSTALLSTATE isAction;
16
17 // metabase information
18 WCHAR wzWebKey[MAX_DARWIN_KEY + 1];
19 WCHAR wzWebBase[METADATA_MAX_NAME_LEN + 1];
20 WCHAR wzFilterRoot[METADATA_MAX_NAME_LEN + 1];
21
22 // iis configuation information
23 WCHAR wzPath[MAX_PATH];
24 WCHAR wzDescription[MAX_DARWIN_COLUMN + 1];
25 int iFlags;
26 int iLoadOrder;
27
28 SCA_FILTER* psfNext;
29};
30
31
32// prototypes
33HRESULT AddFilterToList(
34 __in SCA_FILTER** ppsfList
35 );
36
37UINT __stdcall ScaFiltersRead(IMSAdminBase* piMetabase,
38 SCA_WEB* pswList, __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, SCA_FILTER** ppsfList,
39 __inout LPWSTR *ppwzCustomActionData);
40
41HRESULT ScaFiltersInstall(IMSAdminBase* piMetabase, SCA_FILTER* psfList);
42
43HRESULT ScaFiltersUninstall(IMSAdminBase* piMetabase, SCA_FILTER* psfList);
44
45void ScaFiltersFreeList(SCA_FILTER* psfList);
46
diff --git a/src/ext/Iis/ca/scafilter7.cpp b/src/ext/Iis/ca/scafilter7.cpp
new file mode 100644
index 00000000..dda91c4d
--- /dev/null
+++ b/src/ext/Iis/ca/scafilter7.cpp
@@ -0,0 +1,284 @@
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
5static HRESULT WriteFilter(const SCA_FILTER* psf);
6
7UINT __stdcall ScaFiltersRead7(
8 __in SCA_WEB7* pswList,
9 __in WCA_WRAPQUERY_HANDLE /*hWebBaseQuery*/,
10 __inout SCA_FILTER** ppsfList,
11 __inout LPWSTR *ppwzCustomActionData
12 )
13{
14 HRESULT hr = S_OK;
15 MSIHANDLE hRec;
16 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
17 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
18 SCA_FILTER* psf;
19
20 LPWSTR pwzData = NULL;
21 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
22 hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
23 ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead");
24
25 if (0 == WcaGetQueryRecords(hWrapQuery))
26 {
27 WcaLog(LOGMSG_VERBOSE, "Skipping ScaFiltersRead() - no IIsFilter table");
28 ExitFunction1(hr = S_FALSE);
29 }
30
31 // loop through all the filters
32 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
33 {
34 // Get the Component first. If the component is not being modified during
35 // this transaction, skip processing this whole record.
36 // get the darwin information
37 hr = WcaGetRecordString(hRec, fqComponent, &pwzData);
38 ExitOnFailure(hr, "failed to get IIsFilter.Component");
39
40 hr = WcaGetRecordInteger(hRec, fqInstalled, (int *)&isInstalled);
41 ExitOnFailure(hr, "Failed to get Component installed state for IIs filter");
42
43 hr = WcaGetRecordInteger(hRec, fqAction, (int *)&isAction);
44 ExitOnFailure(hr, "Failed to get Component action state for IIs filter");
45
46 if (!WcaIsInstalling(isInstalled, isAction) &&
47 !WcaIsReInstalling(isInstalled, isAction) &&
48 !WcaIsUninstalling(isInstalled, isAction))
49 {
50 continue; // skip this record.
51 }
52
53 hr = AddFilterToList(ppsfList);
54 ExitOnFailure(hr, "failed to add filter to list");
55
56 psf = *ppsfList;
57
58 hr = ::StringCchCopyW(psf->wzComponent, countof(psf->wzComponent), pwzData);
59 ExitOnFailure(hr, "failed to copy component name: %ls", pwzData);
60
61 psf->isInstalled = isInstalled;
62 psf->isAction = isAction;
63
64 hr = WcaGetRecordString(hRec, fqWeb, &pwzData);
65 ExitOnFailure(hr, "Failed to get Web for VirtualDir");
66
67 if (*pwzData)
68 {
69 hr = ScaWebsGetBase7(pswList, pwzData, psf->wzFilterRoot, countof(psf->wzFilterRoot));
70 if (FAILED(hr))
71 {
72 WcaLog(LOGMSG_VERBOSE, "Could not find site for filter: %ls. Result 0x%x ", psf->wzFilterRoot, hr);
73 hr = S_OK;
74 }
75 }
76 else
77 {
78 hr = ::StringCchCopyW(psf->wzFilterRoot, countof(psf->wzFilterRoot), L"/");
79 ExitOnFailure(hr, "Failed to allocate global filter base string");
80 }
81
82 // filter Name key
83 hr = WcaGetRecordString(hRec, fqFilter, &pwzData);
84 ExitOnFailure(hr, "Failed to get Filter.Filter");
85 hr = ::StringCchCopyW(psf->wzKey, countof(psf->wzKey), pwzData);
86 ExitOnFailure(hr, "Failed to copy key string to filter object");
87
88 // filter path
89 hr = WcaGetRecordString(hRec, fqPath, &pwzData);
90 ExitOnFailure(hr, "Failed to get Filter.Path");
91 hr = ::StringCchCopyW(psf->wzPath, countof(psf->wzPath), pwzData);
92 ExitOnFailure(hr, "Failed to copy path string to filter object");
93
94 // filter description -- not supported in iis 7
95 hr = WcaGetRecordString(hRec, fqDescription, &pwzData);
96 ExitOnFailure(hr, "Failed to get Filter.Description");
97 hr = ::StringCchCopyW(psf->wzDescription, countof(psf->wzDescription), pwzData);
98 ExitOnFailure(hr, "Failed to copy description string to filter object");
99
100 // filter flags
101 //What are these
102 hr = WcaGetRecordInteger(hRec, fqFlags, &psf->iFlags);
103 ExitOnFailure(hr, "Failed to get Filter.Flags");
104
105 // filter load order
106 hr = WcaGetRecordInteger(hRec, fqLoadOrder, &psf->iLoadOrder);
107 ExitOnFailure(hr, "Failed to get Filter.LoadOrder");
108 }
109
110 if (E_NOMOREITEMS == hr)
111 {
112 hr = S_OK;
113 }
114 ExitOnFailure(hr, "Failure while processing filters");
115
116LExit:
117 WcaFinishUnwrapQuery(hWrapQuery);
118
119 ReleaseStr(pwzData);
120
121 return hr;
122}
123
124
125HRESULT ScaFiltersInstall7(
126 __in SCA_FILTER* psfList
127 )
128{
129 HRESULT hr = S_OK;
130 SCA_FILTER* psf = psfList;
131
132 if (!psf)
133 {
134 ExitFunction();
135 }
136 //write global filters
137 hr = ScaWriteConfigID(IIS_FILTER_GLOBAL_BEGIN);
138 ExitOnFailure(hr, "Failed to write filter begin ID");
139 while (psf)
140 {
141 if (WcaIsInstalling(psf->isInstalled, psf->isAction))
142 {
143 if (0 == wcscmp(psf->wzFilterRoot, L"/"))
144 {
145 hr = WriteFilter(psf);
146 }
147 }
148 psf = psf->psfNext;
149 }
150 hr = ScaWriteConfigID(IIS_FILTER_END);
151 ExitOnFailure(hr, "Failed to write filter ID");
152
153 psf = psfList;
154
155 //Write Web Site Filters
156 hr = ScaWriteConfigID(IIS_FILTER_BEGIN);
157 ExitOnFailure(hr, "Failed to write filter begin ID");
158 while (psf)
159 {
160 if (WcaIsInstalling(psf->isInstalled, psf->isAction))
161 {
162 if (0 != wcscmp(psf->wzFilterRoot, L"/"))
163 {
164 hr = WriteFilter(psf);
165 }
166 }
167 psf = psf->psfNext;
168 }
169 hr = ScaWriteConfigID(IIS_FILTER_END);
170 ExitOnFailure(hr, "Failed to write filter ID");
171
172LExit:
173
174 return hr;
175}
176static HRESULT WriteFilter(const SCA_FILTER* psf)
177{
178 HRESULT hr = S_OK;
179
180 hr = ScaWriteConfigID(IIS_FILTER);
181 ExitOnFailure(hr, "Failed to write filter begin ID");
182
183 hr = ScaWriteConfigID(IIS_CREATE);
184 ExitOnFailure(hr, "Failed to write filter create ID");
185
186 //filter Name key
187 hr = ScaWriteConfigString(psf->wzKey);
188 ExitOnFailure(hr, "Failed to write key name for filter '%ls'", psf->wzKey);
189
190 //web site name
191 hr = ScaWriteConfigString(psf->wzFilterRoot);
192 ExitOnFailure(hr, "Failed to write filter web root ");
193
194 // filter path
195 hr = ScaWriteConfigString(psf->wzPath);
196 ExitOnFailure(hr, "Failed to write Path for filter '%ls'", psf->wzKey);
197
198 //filter load order
199 hr = ScaWriteConfigInteger(psf->iLoadOrder);
200 ExitOnFailure(hr, "Failed to write load order for filter '%ls'", psf->wzKey);
201
202LExit:
203 return hr;
204}
205
206
207HRESULT ScaFiltersUninstall7(
208 __in SCA_FILTER* psfList
209 )
210{
211 HRESULT hr = S_OK;
212 SCA_FILTER* psf = psfList;
213
214 if (!psf)
215 {
216 ExitFunction1(hr = S_OK);
217 }
218
219 //Uninstall global filters
220 hr = ScaWriteConfigID(IIS_FILTER_GLOBAL_BEGIN);
221 ExitOnFailure(hr, "Failed to write filter begin ID");
222
223 while (psf)
224 {
225 if (WcaIsUninstalling(psf->isInstalled, psf->isAction))
226 {
227 if (0 == wcscmp(psf->wzFilterRoot, L"/"))
228 {
229 hr = ScaWriteConfigID(IIS_FILTER);
230 ExitOnFailure(hr, "Failed to write filter begin ID");
231
232 hr = ScaWriteConfigID(IIS_DELETE);
233 ExitOnFailure(hr, "Failed to write filter create ID");
234
235 //filter Name key
236 hr = ScaWriteConfigString(psf->wzKey);
237 ExitOnFailure(hr, "Failed to write key name for filter '%ls'", psf->wzKey);
238
239 //web site name
240 hr = ScaWriteConfigString(psf->wzFilterRoot);
241 ExitOnFailure(hr, "Failed to write filter web root ");
242
243 }
244 }
245 psf = psf->psfNext;
246 }
247
248 hr = ScaWriteConfigID(IIS_FILTER_END);
249 ExitOnFailure(hr, "Failed to write filter ID");
250
251 psf = psfList;
252
253 //Uninstall website filters
254 hr = ScaWriteConfigID(IIS_FILTER_BEGIN);
255 ExitOnFailure(hr, "Failed to write filter begin ID");
256 while (psf)
257 {
258 if (WcaIsUninstalling(psf->isInstalled, psf->isAction))
259 {
260 if (0 != wcscmp(psf->wzFilterRoot, L"/"))
261 {
262 hr = ScaWriteConfigID(IIS_FILTER);
263 ExitOnFailure(hr, "Failed to write filter begin ID");
264
265 hr = ScaWriteConfigID(IIS_DELETE);
266 ExitOnFailure(hr, "Failed to write filter create ID");
267
268 //filter Name key
269 hr = ScaWriteConfigString(psf->wzKey);
270 ExitOnFailure(hr, "Failed to write key name for filter '%ls'", psf->wzKey);
271
272 //web site name
273 hr = ScaWriteConfigString(psf->wzFilterRoot);
274 ExitOnFailure(hr, "Failed to write filter web root ");
275 }
276 }
277 psf = psf->psfNext;
278 }
279 hr = ScaWriteConfigID(IIS_FILTER_END);
280 ExitOnFailure(hr, "Failed to write filter ID");
281
282LExit:
283 return hr;
284}
diff --git a/src/ext/Iis/ca/scafilter7.h b/src/ext/Iis/ca/scafilter7.h
new file mode 100644
index 00000000..50ff6652
--- /dev/null
+++ b/src/ext/Iis/ca/scafilter7.h
@@ -0,0 +1,21 @@
1#pragma once
2// 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.
3
4
5#include "scaweb.h"
6
7// prototypes
8UINT __stdcall ScaFiltersRead7(
9 __in SCA_WEB7* pswList,
10 __in WCA_WRAPQUERY_HANDLE hWebBaseQuery,
11 __inout SCA_FILTER** ppsfList,
12 __inout LPWSTR *ppwzCustomActionData
13 );
14
15HRESULT ScaFiltersInstall7(
16 SCA_FILTER* psfList
17 );
18
19HRESULT ScaFiltersUninstall7(
20 SCA_FILTER* psfList
21 );
diff --git a/src/ext/Iis/ca/scahttpheader.cpp b/src/ext/Iis/ca/scahttpheader.cpp
new file mode 100644
index 00000000..1e134cea
--- /dev/null
+++ b/src/ext/Iis/ca/scahttpheader.cpp
@@ -0,0 +1,323 @@
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
5enum eHttpHeaderQuery { hhqName = 1, hhqParentType, hhqParentValue, hhqValue, hhqAttributes};
6
7static HRESULT AddHttpHeaderToList(
8 __in SCA_HTTP_HEADER** ppshhList
9 );
10
11
12void ScaHttpHeaderFreeList(
13 __in SCA_HTTP_HEADER* pshhList
14 )
15{
16 SCA_HTTP_HEADER* pshhDelete = pshhList;
17 while (pshhList)
18 {
19 pshhDelete = pshhList;
20 pshhList = pshhList->pshhNext;
21
22 MemFree(pshhDelete);
23 }
24}
25
26
27HRESULT ScaHttpHeaderRead(
28 __in SCA_HTTP_HEADER** ppshhList,
29 __inout LPWSTR *ppwzCustomActionData
30 )
31{
32 Assert(ppshhList);
33
34 HRESULT hr = S_OK;
35 MSIHANDLE hRec;
36 LPWSTR pwzData = NULL;
37 SCA_HTTP_HEADER* pshh = 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 ScaHttpHeaderRead() - required tables not present.");
46 ExitFunction1(hr = S_FALSE);
47 }
48
49 // loop through all the HTTP headers
50 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
51 {
52 hr = AddHttpHeaderToList(ppshhList);
53 ExitOnFailure(hr, "failed to add http header to list");
54
55 pshh = *ppshhList;
56
57 hr = WcaGetRecordInteger(hRec, hhqParentType, &(pshh->iParentType));
58 ExitOnFailure(hr, "failed to get IIsHttpHeader.ParentType");
59
60 hr = WcaGetRecordString(hRec, hhqParentValue, &pwzData);
61 ExitOnFailure(hr, "Failed to get IIsHttpHeader.ParentValue");
62 hr = ::StringCchCopyW(pshh->wzParentValue, countof(pshh->wzParentValue), pwzData);
63 ExitOnFailure(hr, "Failed to copy IIsHttpHeader.ParentValue");
64
65 hr = WcaGetRecordString(hRec, hhqName, &pwzData);
66 ExitOnFailure(hr, "Failed to get IIsHttpHeader.Name");
67 hr = ::StringCchCopyW(pshh->wzName, countof(pshh->wzName), pwzData);
68 ExitOnFailure(hr, "Failed to copy IIsHttpHeader.Name");
69
70 hr = WcaGetRecordString(hRec, hhqValue, &pwzData);
71 ExitOnFailure(hr, "Failed to get IIsHttpHeader.Value");
72 hr = ::StringCchCopyW(pshh->wzValue, countof(pshh->wzValue), pwzData);
73 ExitOnFailure(hr, "Failed to copy IIsHttpHeader.Value");
74
75 hr = WcaGetRecordInteger(hRec, hhqAttributes, &(pshh->iAttributes));
76 ExitOnFailure(hr, "failed to get IIsHttpHeader.Attributes");
77 }
78
79 if (E_NOMOREITEMS == hr)
80 {
81 hr = S_OK;
82 }
83 ExitOnFailure(hr, "Failure while processing web errors");
84
85LExit:
86 WcaFinishUnwrapQuery(hWrapQuery);
87
88 ReleaseStr(pwzData);
89
90 return hr;
91}
92
93
94HRESULT ScaGetHttpHeader(
95 __in int iParentType,
96 __in LPCWSTR wzParentValue,
97 __in SCA_HTTP_HEADER** ppshhList,
98 __out SCA_HTTP_HEADER** ppshhOut
99 )
100{
101 HRESULT hr = S_OK;
102 SCA_HTTP_HEADER* pshhAdd = NULL;
103 SCA_HTTP_HEADER* pshhLast = NULL;
104
105 *ppshhOut = NULL;
106
107 if (!*ppshhList)
108 {
109 return hr;
110 }
111
112 SCA_HTTP_HEADER* pshh = *ppshhList;
113 while (pshh)
114 {
115 if (iParentType == pshh->iParentType && CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, 0, wzParentValue, -1, pshh->wzParentValue, -1))
116 {
117 // Found a match, take this one out of the list and add it to the matched out list
118 pshhAdd = pshh;
119
120 if (pshhLast)
121 {
122 // If we're not at the beginning of the list tell the last node about it's new next (since we're taking away it's current next)
123 pshhLast->pshhNext = pshhAdd->pshhNext;
124 }
125 else
126 {
127 // If we are at the beginning (no pshhLast) update the beginning (since we're taking it)
128 *ppshhList = pshh->pshhNext;
129 }
130 pshh = pshh->pshhNext; // move on
131
132 // Add the one we've removed to the beginning of the out list
133 pshhAdd->pshhNext = *ppshhOut;
134 *ppshhOut = pshhAdd;
135 }
136 else
137 {
138 pshhLast = pshh; // remember the last we that didn't match
139 pshh = pshh->pshhNext; // move on
140 }
141 }
142
143 return hr;
144}
145
146
147HRESULT ScaWriteHttpHeader(
148 __in IMSAdminBase* piMetabase,
149 __in LPCWSTR wzRoot,
150 __in SCA_HTTP_HEADER* pshhList
151 )
152{
153 Assert(piMetabase && pshhList);
154
155 HRESULT hr = S_OK;
156 METADATA_RECORD mr = { 0 };
157 DWORD cchData = 0;
158 LPWSTR pwzSearchKey = NULL;
159 LPWSTR pwz = NULL;
160 LPWSTR pwzHeaders = NULL;
161 LPWSTR pwzNewHeader = NULL;
162 DWORD_PTR dwFoundHeaderIndex = 0;
163 LPCWSTR wzFoundHeader = NULL;
164 BOOL fOldValueFound = FALSE;
165
166 ExitOnNull(wzRoot, hr, E_INVALIDARG, "Failed to write HTTP header, because no root was provided");
167
168 Assert(*wzRoot);
169
170 // Check if HTTP header already exist here.
171 mr.dwMDIdentifier = MD_HTTP_CUSTOM;
172 mr.dwMDAttributes = METADATA_INHERIT;
173 mr.dwMDUserType = IIS_MD_UT_SERVER;
174 mr.dwMDDataType = ALL_METADATA;
175 mr.dwMDDataLen = cchData = 0;
176 mr.pbMDData = NULL;
177
178 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzRoot, &mr);
179 if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr)
180 {
181 //
182 // If we don't have any HTTP Headers already, move up to get the parent headers.
183 // TODO: Make it configurable to not inherit HTTP Headers
184 //
185 hr = StrAllocConcat(&pwzSearchKey, wzRoot, 0);
186 ExitOnFailure(hr, "Failed to copy root string: %ls", wzRoot);
187
188 pwz = pwzSearchKey + lstrlenW(pwzSearchKey);
189 while (NULL == pwzHeaders)
190 {
191 // find the last slash
192 while (*pwz != '/' && pwz != pwzSearchKey)
193 {
194 --pwz;
195 }
196
197 if (pwz == pwzSearchKey)
198 {
199 break;
200 }
201
202 *pwz = L'\0';
203
204 // Try here. If it's not found, keep walking up the path
205 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, pwzSearchKey, &mr);
206 if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr)
207 {
208 hr = S_FALSE;
209 }
210 ExitOnFailure(hr, "Failed to find search for HTTP headers for web root: %ls while walking up the tree", wzRoot);
211
212 if (S_OK == hr)
213 {
214 hr = StrAllocString(&pwzHeaders, reinterpret_cast<LPWSTR>(mr.pbMDData), 0);
215 ExitOnFailure(hr, "Failed to allocate parent HTTP header string");
216 break;
217 }
218 }
219 }
220 else
221 {
222 hr = StrAllocString(&pwzHeaders, reinterpret_cast<LPWSTR>(mr.pbMDData), 0);
223 ExitOnFailure(hr, "Failed to allocate HTTP header string");
224 }
225 ExitOnFailure(hr, "Failed while searching for default HTTP headers to start with for web root: %ls", wzRoot);
226
227 // Loop through the HTTP headers
228 for (SCA_HTTP_HEADER* pshh = pshhList; pshh; pshh = pshh->pshhNext)
229 {
230 fOldValueFound = FALSE; // assume a HTTP Header match will not be found
231
232 hr = StrAllocFormatted(&pwzNewHeader, L"%s: ", pshh->wzName);
233 ExitOnFailure(hr, "Failed to allocate header name");
234
235 if (NULL != pwzHeaders && *pwzHeaders)
236 {
237 // Try to find a matching header already in the list
238 hr = MultiSzFindSubstring(pwzHeaders, pwzNewHeader, &dwFoundHeaderIndex, &wzFoundHeader);
239 ExitOnFailure(hr, "Failed while searching for existing HTTP header.");
240
241 // If there was a substring HTTP header match, make sure the match was at the beginning
242 // of the string because that is the HTTP header name.
243 if (S_OK == hr)
244 {
245 DWORD cchMatch = lstrlenW(pwzNewHeader);
246 if (CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, pwzNewHeader, cchMatch, wzFoundHeader, cchMatch))
247 {
248 fOldValueFound = TRUE;
249 break;
250 }
251 }
252 }
253
254 // Add the value on to the header name now.
255 hr = StrAllocConcat(&pwzNewHeader, pshh->wzValue, 0);
256 ExitOnFailure(hr, "Failed to add value on to HTTP header name.");
257
258 // If we have something to replace, replace it, otherwise, put it at the beginning (order shouldn't matter)
259 if (fOldValueFound)
260 {
261 if (NULL == pwzHeaders)
262 {
263 ExitOnFailure(hr = E_INVALIDARG, "While attempting to replace old HTTP header with new HTTP header, it was discovered that the old HTTP header was NULL!");
264 }
265 hr = MultiSzReplaceString(&pwzHeaders, dwFoundHeaderIndex, pwzNewHeader);
266 ExitOnFailure(hr, "Failed to replace old HTTP header with new HTTP header");
267 }
268 else
269 {
270 hr = MultiSzPrepend(&pwzHeaders, NULL, pwzNewHeader);
271 ExitOnFailure(hr, "Failed to prepend new HTTP header");
272 }
273 }
274
275 // now write the HttpCustom to the metabase
276 hr = ScaWriteMetabaseValue(piMetabase, wzRoot, NULL, MD_HTTP_CUSTOM, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, pwzHeaders);
277 ExitOnFailure(hr, "Failed to write HTTP Headers to metabase");
278
279LExit:
280 MetaFreeValue(&mr);
281
282 ReleaseStr(pwzNewHeader);
283 ReleaseStr(pwzHeaders);
284 ReleaseStr(pwzSearchKey);
285
286 return hr;
287}
288
289
290HRESULT ScaHttpHeaderCheckList(
291 __in SCA_HTTP_HEADER* pshhList
292 )
293{
294 if (!pshhList)
295 {
296 return S_OK;
297 }
298
299 while (pshhList)
300 {
301 WcaLog(LOGMSG_STANDARD, "Http Header: %ls for parent: %ls not used!", pshhList->wzName, pshhList->wzParentValue);
302 pshhList = pshhList->pshhNext;
303 }
304
305 return E_FAIL;
306}
307
308
309static HRESULT AddHttpHeaderToList(
310 __in SCA_HTTP_HEADER** ppshhList
311 )
312{
313 HRESULT hr = S_OK;
314
315 SCA_HTTP_HEADER* pshh = static_cast<SCA_HTTP_HEADER*>(MemAlloc(sizeof(SCA_HTTP_HEADER), TRUE));
316 ExitOnNull(pshh, hr, E_OUTOFMEMORY, "failed to allocate memory for new http header list element");
317
318 pshh->pshhNext = *ppshhList;
319 *ppshhList = pshh;
320
321LExit:
322 return hr;
323}
diff --git a/src/ext/Iis/ca/scahttpheader.h b/src/ext/Iis/ca/scahttpheader.h
new file mode 100644
index 00000000..a4c407a4
--- /dev/null
+++ b/src/ext/Iis/ca/scahttpheader.h
@@ -0,0 +1,40 @@
1#pragma once
2// 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.
3
4
5enum eHttpHeaderParentType { hhptVDir = 1, hhptWeb };
6
7struct SCA_HTTP_HEADER
8{
9 int iParentType;
10 WCHAR wzParentValue[MAX_DARWIN_KEY + 1];
11
12 WCHAR wzName[MAX_PATH];
13 WCHAR wzValue[MAX_PATH];
14 int iAttributes;
15
16 SCA_HTTP_HEADER* pshhNext;
17};
18
19// prototypes
20HRESULT ScaHttpHeaderRead(
21 __in SCA_HTTP_HEADER **ppshhList,
22 __inout LPWSTR *ppwzCustomActionData
23 );
24void ScaHttpHeaderFreeList(
25 __in SCA_HTTP_HEADER *pshhList
26 );
27HRESULT ScaHttpHeaderCheckList(
28 __in SCA_HTTP_HEADER* pshhList
29 );
30HRESULT ScaGetHttpHeader(
31 __in int iParentType,
32 __in LPCWSTR wzParentValue,
33 __in SCA_HTTP_HEADER** ppshhList,
34 __out SCA_HTTP_HEADER** ppshhOut
35 );
36HRESULT ScaWriteHttpHeader(
37 __in IMSAdminBase* piMetabase,
38 LPCWSTR wzRoot,
39 SCA_HTTP_HEADER* pshhList
40 );
diff --git a/src/ext/Iis/ca/scahttpheader7.cpp b/src/ext/Iis/ca/scahttpheader7.cpp
new file mode 100644
index 00000000..645dd8d4
--- /dev/null
+++ b/src/ext/Iis/ca/scahttpheader7.cpp
@@ -0,0 +1,130 @@
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
5HRESULT ScaGetHttpHeader7(
6 __in int iParentType,
7 __in_z LPCWSTR wzParentValue,
8 __in SCA_HTTP_HEADER** ppshhList,
9 __out SCA_HTTP_HEADER** ppshhOut
10 )
11{
12 HRESULT hr = S_OK;
13 SCA_HTTP_HEADER* pshhAdd = NULL;
14 SCA_HTTP_HEADER* pshhLast = NULL;
15
16 *ppshhOut = NULL;
17
18 if (!*ppshhList)
19 {
20 return hr;
21 }
22
23 SCA_HTTP_HEADER* pshh = *ppshhList;
24 while (pshh)
25 {
26 if (iParentType == pshh->iParentType && 0 == wcscmp(wzParentValue, pshh->wzParentValue))
27 {
28 // Found a match, take this one out of the list and add it to the matched out list
29 pshhAdd = pshh;
30
31 if (pshhLast)
32 {
33 // If we're not at the beginning of the list tell the last node about it's new next (since we're taking away it's current next)
34 pshhLast->pshhNext = pshhAdd->pshhNext;
35 }
36 else
37 {
38 // If we are at the beginning (no pshhLast) update the beginning (since we're taking it)
39 *ppshhList = pshh->pshhNext;
40 }
41 pshh = pshh->pshhNext; // move on
42
43 // Add the one we've removed to the beginning of the out list
44 pshhAdd->pshhNext = *ppshhOut;
45 *ppshhOut = pshhAdd;
46 }
47 else
48 {
49 pshhLast = pshh; // remember the last we that didn't match
50 pshh = pshh->pshhNext; // move on
51 }
52 }
53
54 return hr;
55}
56
57
58HRESULT ScaWriteHttpHeader7(
59 __in_z LPCWSTR wzWebName,
60 __in_z LPCWSTR wzRoot,
61 SCA_HTTP_HEADER* pshhList
62 )
63{
64
65 HRESULT hr = S_OK;
66
67 hr = ScaWriteConfigID(IIS_HTTP_HEADER_BEGIN);
68 ExitOnFailure(hr, "Fail to write httpHeader begin ID");
69
70 hr = ScaWriteConfigString(wzWebName);
71 ExitOnFailure(hr, "Fail to write httpHeader Web Key");
72
73 hr = ScaWriteConfigString(wzRoot);
74 ExitOnFailure(hr, "Fail to write httpHeader Vdir key");
75
76 // Loop through the HTTP headers
77 for (SCA_HTTP_HEADER* pshh = pshhList; pshh; pshh = pshh->pshhNext)
78 {
79 hr = ScaWriteConfigID(IIS_HTTP_HEADER);
80 ExitOnFailure(hr, "Fail to write httpHeader ID");
81
82 hr = ScaWriteConfigString(pshh->wzName);
83 ExitOnFailure(hr, "Fail to write httpHeader name");
84
85 hr = ScaWriteConfigString(pshh->wzValue);
86 ExitOnFailure(hr, "Fail to write httpHeader value");
87 }
88
89 hr = ScaWriteConfigID(IIS_HTTP_HEADER_END);
90 ExitOnFailure(hr, "Fail to write httpHeader end ID");
91
92LExit:
93 return hr;
94}
95
96
97HRESULT ScaHttpHeaderCheckList7(
98 __in SCA_HTTP_HEADER* pshhList
99 )
100{
101 if (!pshhList)
102 {
103 return S_OK;
104 }
105
106 while (pshhList)
107 {
108 WcaLog(LOGMSG_STANDARD, "Http Header: %ls for parent: %ls not used!", pshhList->wzName, pshhList->wzParentValue);
109 pshhList = pshhList->pshhNext;
110 }
111
112 return E_FAIL;
113}
114
115
116//static HRESULT AddHttpHeaderToList(
117// __in SCA_HTTP_HEADER** ppshhList
118// )
119//{
120// HRESULT hr = S_OK;
121//
122// SCA_HTTP_HEADER* pshh = static_cast<SCA_HTTP_HEADER*>(MemAlloc(sizeof(SCA_HTTP_HEADER), TRUE));
123// ExitOnNull(pshh, hr, E_OUTOFMEMORY, "failed to allocate memory for new http header list element");
124//
125// pshh->pshhNext = *ppshhList;
126// *ppshhList = pshh;
127//
128//LExit:
129// return hr;
130//}
diff --git a/src/ext/Iis/ca/scahttpheader7.h b/src/ext/Iis/ca/scahttpheader7.h
new file mode 100644
index 00000000..7a873c16
--- /dev/null
+++ b/src/ext/Iis/ca/scahttpheader7.h
@@ -0,0 +1,15 @@
1#pragma once
2// 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.
3
4
5HRESULT ScaGetHttpHeader7(
6 __in int iParentType,
7 __in_z LPCWSTR wzParentValue,
8 __in SCA_HTTP_HEADER** ppshhList,
9 __out SCA_HTTP_HEADER** ppshhOut
10 );
11HRESULT ScaWriteHttpHeader7(
12 __in_z LPCWSTR wzWebName,
13 __in_z LPCWSTR wzRoot,
14 SCA_HTTP_HEADER* pshhList
15 );
diff --git a/src/ext/Iis/ca/scaiis.cpp b/src/ext/Iis/ca/scaiis.cpp
new file mode 100644
index 00000000..958051ed
--- /dev/null
+++ b/src/ext/Iis/ca/scaiis.cpp
@@ -0,0 +1,481 @@
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// globals
6LPWSTR vpwzCustomActionData = NULL;
7DWORD vdwCustomActionCost = 0;
8
9HRESULT ScaMetabaseTransaction(__in_z LPCWSTR wzBackup)
10{
11 HRESULT hr = S_OK;
12
13 // TODO: These functions have been reported to hang IIS (O11:51709). They may have been fixed in IIS6, but if not, need to be re-written the hard way
14
15 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"StartMetabaseTransaction"), wzBackup, COST_IIS_TRANSACTIONS);
16 ExitOnFailure(hr, "Failed to schedule StartMetabaseTransaction");
17
18 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackMetabaseTransaction"), wzBackup, 0); // rollback cost is irrelevant
19 ExitOnFailure(hr, "Failed to schedule RollbackMetabaseTransaction");
20
21 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CommitMetabaseTransaction"), wzBackup, 0); // commit is free
22 ExitOnFailure(hr, "Failed to schedule StartMetabaseTransaction");
23
24LExit:
25 return hr;
26}
27
28
29HRESULT ScaCreateWeb(IMSAdminBase* piMetabase, LPCWSTR /*wzWeb*/, LPCWSTR wzWebBase)
30{
31 Assert(piMetabase);
32
33 HRESULT hr = S_OK;
34 UINT ui = 0;
35
36 hr = ScaCreateMetabaseKey(piMetabase, wzWebBase, L"");
37 ExitOnFailure(hr, "Failed to create web");
38
39 hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsWebServer");
40 ExitOnFailure(hr, "Failed to set key type for web");
41
42 hr = ScaCreateMetabaseKey(piMetabase, wzWebBase, L"Root");
43 ExitOnFailure(hr, "Failed to create web root");
44
45 hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"Root", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsWebVirtualDir");
46 ExitOnFailure(hr, "Failed to set key type for web root");
47
48 ui = 0x4000003e; // 1073741886; // default directory browsing rights
49 hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"Root", MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui));
50 ExitOnFailure(hr, "Failed to set directory browsing for web");
51
52 hr = ScaCreateMetabaseKey(piMetabase, wzWebBase, L"Filters");
53 ExitOnFailure(hr, "Failed to create web filters root");
54
55 hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"Filters", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsFilters");
56 ExitOnFailure(hr, "Failed to set key for web filters root");
57
58 hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"Filters", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"");
59 ExitOnFailure(hr, "Failed to set empty load order for web");
60
61LExit:
62 return hr;
63}
64
65
66HRESULT ScaDeleteApp(IMSAdminBase* piMetabase, LPCWSTR wzWebRoot)
67{
68 Assert(piMetabase);
69 Unused(piMetabase);
70
71 HRESULT hr = S_OK;
72 WCHAR wzKey[METADATA_MAX_NAME_LEN];
73
74 WCHAR* pwzCustomActionData = NULL;
75
76 hr = WcaWriteIntegerToCaData(MBA_DELETEAPP, &pwzCustomActionData);
77 ExitOnFailure(hr, "Failed to add metabase delete app directive to CustomActionData");
78
79 hr = ::StringCchCopyW(wzKey, countof(wzKey), wzWebRoot);
80 ExitOnFailure(hr, "Failed to copy webroot string to key");
81 hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData);
82 ExitOnFailure(hr, "Failed to add metabase key to CustomActionData");
83
84 hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_DELETEAPP);
85 ExitOnFailure(hr, "Failed to add ScaDeleteApp action data: %ls cost: %d", pwzCustomActionData, COST_IIS_DELETEAPP);
86
87LExit:
88 ReleaseStr(pwzCustomActionData);
89
90 return hr;
91}
92
93
94HRESULT ScaCreateApp(IMSAdminBase* piMetabase, LPCWSTR wzWebRoot,
95 DWORD dwIsolation)
96{
97 Assert(piMetabase);
98 Unused(piMetabase);
99
100 HRESULT hr = S_OK;
101 WCHAR wzKey[METADATA_MAX_NAME_LEN];
102 BOOL fInProc = FALSE;
103
104 WCHAR* pwzCustomActionData = NULL;
105
106 hr = WcaWriteIntegerToCaData(MBA_CREATEAPP, &pwzCustomActionData);
107 ExitOnFailure(hr, "Failed to add metabase create app directive to CustomActionData");
108
109 hr = ::StringCchCopyW(wzKey, countof(wzKey), wzWebRoot);
110 ExitOnFailure(hr, "Failed to copy webroot string to key");
111 hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData);
112 ExitOnFailure(hr, "Failed to add metabase key to CustomActionData");
113
114 if (0 == dwIsolation)
115 fInProc = TRUE;
116 else
117 fInProc = FALSE;
118
119 hr = WcaWriteIntegerToCaData(fInProc, &pwzCustomActionData);
120 ExitOnFailure(hr, "Failed to add isolation value to CustomActionData");
121
122 hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_CREATEAPP);
123 ExitOnFailure(hr, "Failed to add ScaCreateApp action data: %ls cost: %d", pwzCustomActionData, COST_IIS_CREATEAPP);
124
125LExit:
126 ReleaseStr(pwzCustomActionData);
127
128 return hr;
129}
130
131
132HRESULT ScaCreateMetabaseKey(IMSAdminBase* piMetabase, LPCWSTR wzRootKey,
133 LPCWSTR wzSubKey)
134{
135 Assert(piMetabase);
136 Unused(piMetabase);
137
138 HRESULT hr = S_OK;
139 WCHAR wzKey[METADATA_MAX_NAME_LEN];
140 WCHAR* pwzCustomActionData = NULL;
141
142 hr = ::StringCchCopyW(wzKey, countof(wzKey), wzRootKey);
143 ExitOnFailure(hr, "Failed to copy root key string to key");
144 if (L'/' != *(wzKey + lstrlenW(wzRootKey)))
145 {
146 hr = ::StringCchCatW(wzKey, countof(wzKey), L"/");
147 ExitOnFailure(hr, "Failed to concatenate / to key string");
148 }
149 if (wzSubKey && *wzSubKey)
150 {
151 if (L'/' == *wzSubKey)
152 {
153 hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey + 1);
154 ExitOnFailure(hr, "Failed to concatenate subkey (minus slash) to key string");
155 }
156 else
157 {
158 hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey);
159 ExitOnFailure(hr, "Failed to concatenate subkey to key string");
160 }
161 }
162
163 hr = WcaWriteIntegerToCaData(MBA_CREATEKEY, &pwzCustomActionData);
164 ExitOnFailure(hr, "Failed to add metabase delete key directive to CustomActionData");
165
166 hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData);
167 ExitOnFailure(hr, "Failed to add metabase key to CustomActionData");
168
169 hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_CREATEKEY);
170 ExitOnFailure(hr, "Failed to add ScaCreateMetabaseKey action data: %ls cost: %d", pwzCustomActionData, COST_IIS_CREATEKEY);
171
172LExit:
173 ReleaseStr(pwzCustomActionData);
174
175 return hr;
176}
177
178
179HRESULT ScaDeleteMetabaseKey(IMSAdminBase* piMetabase, LPCWSTR wzRootKey,
180 LPCWSTR wzSubKey)
181{
182 Assert(piMetabase);
183 Unused(piMetabase);
184
185 HRESULT hr = S_OK;
186 WCHAR wzKey[METADATA_MAX_NAME_LEN];
187 WCHAR* pwzCustomActionData = NULL;
188
189 hr = ::StringCchCopyW(wzKey, countof(wzKey), wzRootKey);
190 ExitOnFailure(hr, "Failed to copy root key string to key");
191 if (L'/' != *(wzKey + lstrlenW(wzRootKey)))
192 {
193 hr = ::StringCchCatW(wzKey, countof(wzKey), L"/");
194 ExitOnFailure(hr, "Failed to concatenate / to key string");
195 }
196 if (*wzSubKey)
197 {
198 if (L'/' == *wzSubKey)
199 {
200 hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey + 1);
201 ExitOnFailure(hr, "Failed to concatenate subkey (minus slash) to key string");
202 }
203 else
204 {
205 hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey);
206 ExitOnFailure(hr, "Failed to concatenate subkey to key string");
207 }
208 }
209
210 hr = WcaWriteIntegerToCaData(MBA_DELETEKEY, &pwzCustomActionData);
211 ExitOnFailure(hr, "Failed to add metabase delete key directive to CustomActionData");
212
213 hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData);
214 ExitOnFailure(hr, "Failed to add metabase key to CustomActionData");
215
216 hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_DELETEKEY);
217 ExitOnFailure(hr, "Failed to add ScaDeleteMetabaseKey action data: %ls cost: %d", pwzCustomActionData, COST_IIS_DELETEKEY);
218
219LExit:
220 ReleaseStr(pwzCustomActionData);
221
222 return hr;
223}
224
225
226HRESULT ScaDeleteMetabaseValue(IMSAdminBase* piMetabase, LPCWSTR wzRootKey,
227 LPCWSTR wzSubKey, DWORD dwIdentifier,
228 DWORD dwDataType)
229{
230 Assert(piMetabase);
231 Unused(piMetabase);
232
233 HRESULT hr = S_OK;
234 WCHAR wzKey[METADATA_MAX_NAME_LEN];
235 WCHAR* pwzCustomActionData = NULL;
236
237 hr = ::StringCchCopyW(wzKey, countof(wzKey), wzRootKey);
238 ExitOnFailure(hr, "Failed to copy root key string to key");
239 if (L'/' != *(wzKey + lstrlenW(wzRootKey)))
240 {
241 hr = ::StringCchCatW(wzKey, countof(wzKey), L"/");
242 ExitOnFailure(hr, "Failed to concatenate / to key string");
243 }
244
245 if (wzSubKey && *wzSubKey)
246 {
247 if (L'/' == *wzSubKey)
248 {
249 hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey + 1);
250 ExitOnFailure(hr, "Failed to concatenate subkey (minus slash) to key string");
251 }
252 else
253 {
254 hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey);
255 ExitOnFailure(hr, "Failed to concatenate subkey to key string");
256 }
257 }
258
259 hr = WcaWriteIntegerToCaData(MBA_DELETEVALUE, &pwzCustomActionData);
260 ExitOnFailure(hr, "Failed to add metabase write value directive to CustomActionData");
261
262 hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData);
263 ExitOnFailure(hr, "Failed to add metabase key to CustomActionData");
264
265 hr = WcaWriteIntegerToCaData(dwIdentifier, &pwzCustomActionData);
266 ExitOnFailure(hr, "Failed to add metabase identifier to CustomActionData");
267
268 hr = WcaWriteIntegerToCaData(dwDataType, &pwzCustomActionData);
269 ExitOnFailure(hr, "Failed to add metabase data type to CustomActionData");
270
271 hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_DELETEVALUE);
272 ExitOnFailure(hr, "Failed to add ScaDeleteMetabaseValue action data: %ls, cost: %d", pwzCustomActionData, COST_IIS_DELETEVALUE);
273
274LExit:
275 ReleaseStr(pwzCustomActionData);
276
277 return hr;
278}
279
280
281#pragma prefast(push)
282#pragma prefast(disable:25120) // Disable "requires count parameter" warning - we do have a way to distinguish buffer sizes in all situations,
283 // it just depends on the dwDataType, and there's no way to annotate the situation in SAL
284HRESULT ScaWriteMetabaseValue(IMSAdminBase* piMetabase, LPCWSTR wzRootKey,
285 LPCWSTR wzSubKey, DWORD dwIdentifier,
286 DWORD dwAttributes, DWORD dwUserType,
287 DWORD dwDataType, LPVOID pvData)
288#pragma prefast(pop)
289{
290 Assert(piMetabase && (pvData || (DWORD_METADATA == dwDataType))); // pvData may be 0 if it is DWORD data
291 Unused(piMetabase);
292
293 HRESULT hr = S_OK;
294 WCHAR wzKey[METADATA_MAX_NAME_LEN];
295 WCHAR* pwzCustomActionData = NULL;
296
297 if (BINARY_METADATA == dwDataType)
298 {
299 ExitOnNull(pvData, hr, E_INVALIDARG, "Failed to write binary metadata - no data available to write");
300 }
301
302 hr = ::StringCchCopyW(wzKey, countof(wzKey), wzRootKey);
303 ExitOnFailure(hr, "Failed to copy root key string to key");
304 if (L'/' != *(wzKey + lstrlenW(wzRootKey)))
305 {
306 hr = ::StringCchCatW(wzKey, countof(wzKey), L"/");
307 ExitOnFailure(hr, "Failed to concatenate / to key string");
308 }
309 if (wzSubKey && *wzSubKey)
310 {
311 if (L'/' == *wzSubKey)
312 {
313 hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey + 1);
314 ExitOnFailure(hr, "Failed to concatenate subkey (minus slash) to key string");
315 }
316 else
317 {
318 hr = ::StringCchCatW(wzKey, countof(wzKey), wzSubKey);
319 ExitOnFailure(hr, "Failed to concatenate subkey to key string");
320 }
321 }
322
323 hr = WcaWriteIntegerToCaData(MBA_WRITEVALUE, &pwzCustomActionData);
324 ExitOnFailure(hr, "Failed to add metabase write value directive to CustomActionData");
325
326 hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData);
327 ExitOnFailure(hr, "Failed to add metabase key to CustomActionData");
328
329 hr = WcaWriteIntegerToCaData(dwIdentifier, &pwzCustomActionData);
330 ExitOnFailure(hr, "Failed to add metabase identifier to CustomActionData");
331
332 hr = WcaWriteIntegerToCaData(dwAttributes, &pwzCustomActionData);
333 ExitOnFailure(hr, "Failed to add metabase attributes to CustomActionData");
334
335 hr = WcaWriteIntegerToCaData(dwUserType, &pwzCustomActionData);
336 ExitOnFailure(hr, "Failed to add metabase user type to CustomActionData");
337
338 hr = WcaWriteIntegerToCaData(dwDataType, &pwzCustomActionData);
339 ExitOnFailure(hr, "Failed to add metabase data type to CustomActionData");
340
341 switch (dwDataType)
342 {
343 case DWORD_METADATA:
344 hr = WcaWriteIntegerToCaData((DWORD)((DWORD_PTR)pvData), &pwzCustomActionData);
345 break;
346 case STRING_METADATA:
347 hr = WcaWriteStringToCaData((LPCWSTR)pvData, &pwzCustomActionData);
348 break;
349 case MULTISZ_METADATA:
350 {
351 // change NULLs to unprintable character to create a 'safe' MULTISZ string
352 LPWSTR pwz = (LPWSTR)pvData;
353 for (;;)
354 {
355 if ('\0' == *pwz)
356 {
357 *pwz = MAGIC_MULTISZ_CHAR;
358 if ('\0' == *(pwz + 1)) // second null back to back means end of string
359 break;
360 }
361
362 ++pwz;
363 }
364
365 hr = WcaWriteStringToCaData((LPCWSTR)pvData, &pwzCustomActionData);
366 }
367 break;
368 case BINARY_METADATA:
369 hr = WcaWriteStreamToCaData(((BLOB*) pvData)->pBlobData, ((BLOB*) pvData)->cbSize, &pwzCustomActionData);
370 break;
371 default:
372 hr = E_UNEXPECTED;
373 }
374 ExitOnFailure(hr, "Failed to add metabase data to CustomActionData");
375
376 // TODO: maybe look the key up and make sure we're not just writing the same value that already there
377
378 hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_WRITEVALUE);
379 ExitOnFailure(hr, "Failed to add ScaWriteMetabaseValue action data: %ls, cost: %d", pwzCustomActionData, COST_IIS_WRITEVALUE);
380
381LExit:
382 ReleaseStr(pwzCustomActionData);
383
384 return hr;
385}
386
387
388HRESULT ScaAddToIisConfiguration(LPCWSTR pwzData, DWORD dwCost)
389{
390 HRESULT hr = S_OK;
391
392 hr = WcaWriteStringToCaData(pwzData, &vpwzCustomActionData);
393 ExitOnFailure(hr, "failed to add to metabase configuration data string: %ls", pwzData);
394
395 vdwCustomActionCost += dwCost;
396
397LExit:
398 return hr;
399}
400
401
402HRESULT ScaWriteConfigurationScript(__in LPCWSTR pwzCaScriptKey)
403{
404 HRESULT hr = S_OK;
405 WCA_CASCRIPT_HANDLE hScript = NULL;
406 LPWSTR pwzHashString = NULL;
407 BYTE rgbActualHash[SHA1_HASH_LEN] = { };
408 DWORD dwHashedBytes = SHA1_HASH_LEN;
409
410 // Create CaScript for communication with WriteMetabaseChanges
411 hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_SCHEDULED, FALSE, pwzCaScriptKey, FALSE, &hScript);
412 ExitOnFailure(hr, "Failed to write ca script for WriteMetabaseChanges script.");
413
414 if (vpwzCustomActionData && *vpwzCustomActionData)
415 {
416 // Write the actual custom action data to the ca script
417 WcaCaScriptWriteString(hScript, vpwzCustomActionData);
418
419 hr = CrypHashBuffer((BYTE*)vpwzCustomActionData, sizeof(vpwzCustomActionData) * sizeof(WCHAR), PROV_RSA_AES, CALG_SHA1, rgbActualHash, dwHashedBytes);
420 ExitOnFailure(hr, "Failed to calculate hash of CustomAction data.");
421
422 hr = StrAlloc(&pwzHashString, ((dwHashedBytes * 2) + 1));
423 ExitOnFailure(hr, "Failed to allocate string for script hash");
424
425 hr = StrHexEncode(rgbActualHash, dwHashedBytes, pwzHashString, ((dwHashedBytes * 2) + 1));
426 ExitOnFailure(hr, "Failed to convert hash bytes to string.");
427
428 WcaLog(LOGMSG_VERBOSE, "Custom action data hash: %ls", pwzHashString);
429 WcaLog(LOGMSG_TRACEONLY, "Custom action data being written to ca script: %ls", vpwzCustomActionData);
430 }
431 else
432 hr = S_FALSE;
433
434LExit:
435 // Release the string
436 ReleaseStr(vpwzCustomActionData);
437 ReleaseStr(pwzHashString);
438
439 // Flush the ca script to disk as best we can
440 WcaCaScriptFlush(hScript);
441
442 WcaCaScriptClose(hScript, WCA_CASCRIPT_CLOSE_PRESERVE);
443
444 return hr;
445}
446
447
448HRESULT ScaLoadMetabase(IMSAdminBase** ppiMetabase)
449{
450 HRESULT hr = S_OK;
451 UINT er = ERROR_SUCCESS;
452
453 // if IIS was uninstalled (thus no IID_IMSAdminBase) allow the
454 // user to still uninstall this package by clicking "Ignore"
455 do
456 {
457 hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void**)ppiMetabase);
458 if (FAILED(hr))
459 {
460 WcaLog(LOGMSG_STANDARD, "failed to get IID_IMSAdminBase Object");
461 er = WcaErrorMessage(msierrIISCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
462 switch (er)
463 {
464 case IDABORT:
465 ExitFunction(); // bail with the error result from the CoCreate to kick off a rollback
466 case IDRETRY:
467 hr = S_FALSE; // hit me, baby, one more time
468 break;
469 case IDIGNORE:
470 hr = S_OK; // pretend everything is okay and bail
471 break;
472 default: // For failure on uninstall continue
473 hr = S_OK;
474 break;
475 }
476 }
477 } while (S_FALSE == hr);
478
479LExit:
480 return hr;
481}
diff --git a/src/ext/Iis/ca/scaiis.h b/src/ext/Iis/ca/scaiis.h
new file mode 100644
index 00000000..4c743edf
--- /dev/null
+++ b/src/ext/Iis/ca/scaiis.h
@@ -0,0 +1,33 @@
1#pragma once
2// 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.
3
4
5HRESULT ScaMetabaseTransaction(__in_z LPCWSTR wzBackup);
6
7HRESULT ScaCreateWeb(IMSAdminBase* piMetabase, LPCWSTR wzWeb, LPCWSTR wzWebBase);
8
9HRESULT ScaDeleteApp(IMSAdminBase* piMetabase, LPCWSTR wzWebRoot);
10
11HRESULT ScaCreateApp(IMSAdminBase* piMetabase, LPCWSTR wzWebRoot,
12 DWORD dwIsolation);
13
14HRESULT ScaCreateMetabaseKey(IMSAdminBase* piMetabase, LPCWSTR wzRootKey,
15 LPCWSTR wzSubKey);
16
17HRESULT ScaDeleteMetabaseKey(IMSAdminBase* piMetabase, LPCWSTR wzRootKey,
18 LPCWSTR wzSubKey);
19
20HRESULT ScaWriteMetabaseValue(IMSAdminBase* piMetabase, LPCWSTR wzRootKey,
21 LPCWSTR wzSubKey, DWORD dwIdentifier,
22 DWORD dwAttributes, DWORD dwUserType,
23 DWORD dwDataType, LPVOID pvData);
24
25HRESULT ScaDeleteMetabaseValue(IMSAdminBase* piMetabase, LPCWSTR wzRootKey,
26 LPCWSTR wzSubKey, DWORD dwIdentifier,
27 DWORD dwDataType);
28
29HRESULT ScaWriteConfigurationScript(LPCWSTR pwzCaScriptKey);
30
31HRESULT ScaAddToIisConfiguration(LPCWSTR pwzData, DWORD dwCost);
32
33HRESULT ScaLoadMetabase(IMSAdminBase** piMetabase);
diff --git a/src/ext/Iis/ca/scaiis7.cpp b/src/ext/Iis/ca/scaiis7.cpp
new file mode 100644
index 00000000..aaf307d7
--- /dev/null
+++ b/src/ext/Iis/ca/scaiis7.cpp
@@ -0,0 +1,74 @@
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#define COST_IIS_WRITEKEY 10
6
7HRESULT ScaIIS7ConfigTransaction(LPCWSTR wzBackup)
8{
9 HRESULT hr = S_OK;
10
11 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"StartIIS7ConfigTransaction"), wzBackup, COST_IIS_TRANSACTIONS);
12 ExitOnFailure(hr, "Failed to schedule StartIIS7ConfigTransaction");
13
14 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RollbackIIS7ConfigTransaction"), wzBackup, 0); // rollback cost is irrelevant
15 ExitOnFailure(hr, "Failed to schedule RollbackIIS7ConfigTransaction");
16
17 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CommitIIS7ConfigTransaction"), wzBackup, 0); // commit is free
18 ExitOnFailure(hr, "Failed to schedule StartIIS7ConfigTransaction");
19
20LExit:
21 return hr;
22}
23
24HRESULT ScaWriteConfigString(const LPCWSTR wzValue)
25{
26 HRESULT hr = S_OK;
27 WCHAR* pwzCustomActionData = NULL;
28
29 hr = WcaWriteStringToCaData(wzValue, &pwzCustomActionData);
30 ExitOnFailure(hr, "Failed to add metabase delete key directive to CustomActionData");
31
32 hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_WRITEKEY);
33 ExitOnFailure(hr, "Failed to add ScaWriteMetabaseValue action data: %ls, cost: %d", pwzCustomActionData, COST_IIS_WRITEKEY);
34
35LExit:
36 ReleaseStr(pwzCustomActionData);
37
38 return hr;
39}
40
41HRESULT ScaWriteConfigInteger(DWORD dwValue)
42{
43 HRESULT hr = S_OK;
44 WCHAR* pwzCustomActionData = NULL;
45
46 hr = WcaWriteIntegerToCaData(dwValue, &pwzCustomActionData);
47 ExitOnFailure(hr, "Failed to add metabase delete key directive to CustomActionData");
48
49 hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_WRITEKEY);
50 ExitOnFailure(hr, "Failed to add ScaWriteMetabaseValue action data: %ls, cost: %d", pwzCustomActionData, COST_IIS_WRITEKEY);
51
52LExit:
53 ReleaseStr(pwzCustomActionData);
54
55 return hr;
56}
57
58HRESULT ScaWriteConfigID(IIS_CONFIG_ACTION emID)
59{
60 HRESULT hr = S_OK;
61 WCHAR* pwzCustomActionData = NULL;
62
63 hr = WcaWriteIntegerToCaData(emID, &pwzCustomActionData);
64 ExitOnFailure(hr, "Failed to add metabase delete key directive to CustomActionData");
65
66 hr = ScaAddToIisConfiguration(pwzCustomActionData, COST_IIS_WRITEKEY);
67 ExitOnFailure(hr, "Failed to add ScaWriteMetabaseValue action data: %ls, cost: %d", pwzCustomActionData, COST_IIS_WRITEKEY);
68
69LExit:
70 ReleaseStr(pwzCustomActionData);
71
72 return hr;
73}
74
diff --git a/src/ext/Iis/ca/scaiis7.h b/src/ext/Iis/ca/scaiis7.h
new file mode 100644
index 00000000..f398deca
--- /dev/null
+++ b/src/ext/Iis/ca/scaiis7.h
@@ -0,0 +1,17 @@
1#pragma once
2// 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.
3
4
5HRESULT ScaScheduleIIS7Configuration();
6
7HRESULT ScaIIS7ConfigTransaction(__in_z LPCWSTR wzBackup);
8
9HRESULT ScaCreateApp7(__in_z LPCWSTR wzWebRoot, DWORD dwIsolation);
10
11HRESULT ScaDeleteConfigElement(IIS_CONFIG_ACTION emElement, LPCWSTR wzSubKey);
12
13HRESULT ScaWriteConfigString(__in_z const LPCWSTR wzValue);
14
15HRESULT ScaWriteConfigID(IIS_CONFIG_ACTION emID);
16
17HRESULT ScaWriteConfigInteger(DWORD dwValue);
diff --git a/src/ext/Iis/ca/scamimemap.cpp b/src/ext/Iis/ca/scamimemap.cpp
new file mode 100644
index 00000000..8afe99f9
--- /dev/null
+++ b/src/ext/Iis/ca/scamimemap.cpp
@@ -0,0 +1,200 @@
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
5enum eMimeMapQuery { mmqMimeMap = 1, mmqParentType, mmqParentValue,
6 mmqMimeType, mmqExtension};
7
8// prototypes
9static HRESULT AddMimeMapToList(SCA_MIMEMAP** ppsmmList);
10
11
12void ScaMimeMapFreeList(SCA_MIMEMAP* psmmList)
13{
14 SCA_MIMEMAP* psmmDelete = psmmList;
15 while (psmmList)
16 {
17 psmmDelete = psmmList;
18 psmmList = psmmList->psmmNext;
19
20 MemFree(psmmDelete);
21 }
22}
23
24
25HRESULT __stdcall ScaMimeMapRead(
26 SCA_MIMEMAP** ppsmmList,
27 __inout LPWSTR *ppwzCustomActionData
28 )
29{
30 HRESULT hr = S_OK;
31 MSIHANDLE hRec;
32 LPWSTR pwzData = NULL;
33 SCA_MIMEMAP* psmm;
34 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
35
36 hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
37 ExitOnFailure(hr, "Failed to unwrap query for ScaMimeMapRead");
38
39 if (0 == WcaGetQueryRecords(hWrapQuery))
40 {
41 WcaLog(LOGMSG_VERBOSE, "Skipping ScaMimeMapRead() - required table not present");
42 ExitFunction1(hr = S_FALSE);
43 }
44
45 // loop through all the mimemappings
46 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
47 {
48 hr = AddMimeMapToList(ppsmmList);
49 ExitOnFailure(hr, "failed to add mime map to list");
50
51 psmm = *ppsmmList;
52
53 hr = WcaGetRecordString(hRec, mmqMimeMap, &pwzData);
54 ExitOnFailure(hr, "Failed to get MimeMap.MimeMap");
55 hr = ::StringCchCopyW(psmm->wzMimeMap, countof(psmm->wzMimeMap), pwzData);
56 ExitOnFailure(hr, "Failed to copy mimemap string to mimemap object");
57
58 hr = WcaGetRecordInteger(hRec, mmqParentType, &psmm->iParentType);
59 ExitOnFailure(hr, "Failed to get MimeMap.iParentType");
60
61 hr = WcaGetRecordString(hRec, mmqParentValue, &pwzData);
62 ExitOnFailure(hr, "Failed to get MimeMap.ParentValue");
63 hr = ::StringCchCopyW(psmm->wzParentValue, countof(psmm->wzParentValue), pwzData);
64 ExitOnFailure(hr, "Failed to copy parent value string to mimemap object");
65
66 hr = WcaGetRecordString(hRec, mmqExtension, &pwzData);
67 ExitOnFailure(hr, "Failed to get MimeMap.Extension");
68 hr = ::StringCchCopyW(psmm->wzExtension, countof(psmm->wzExtension), pwzData);
69 ExitOnFailure(hr, "Failed to copy extension string to mimemap object");
70
71 hr = WcaGetRecordString(hRec, mmqMimeType, &pwzData);
72 ExitOnFailure(hr, "Failed to get MimeMap.MimeType");
73 hr = ::StringCchCopyW(psmm->wzMimeType, countof(psmm->wzMimeType), pwzData);
74 ExitOnFailure(hr, "Failed to copy mimetype string to mimemap object");
75 }
76
77 if (E_NOMOREITEMS == hr)
78 hr = S_OK;
79 ExitOnFailure(hr, "Failure while processing mimemappings");
80
81LExit:
82 WcaFinishUnwrapQuery(hWrapQuery);
83
84 ReleaseStr(pwzData);
85
86 return hr;
87}
88
89
90HRESULT ScaGetMimeMap(int iParentType, LPCWSTR wzParentValue, SCA_MIMEMAP **ppsmmList, SCA_MIMEMAP **ppsmmOut)
91{
92 HRESULT hr = S_OK;
93 SCA_MIMEMAP* psmmAdd = NULL;
94 SCA_MIMEMAP* psmmLast = NULL;
95
96 *ppsmmOut = NULL;
97
98 if (!*ppsmmList)
99 return hr;
100
101 SCA_MIMEMAP* psmm = *ppsmmList;
102 while (psmm)
103 {
104 if (iParentType == psmm->iParentType && 0 == lstrcmpW(wzParentValue, psmm->wzParentValue))
105 {
106 // Found a match, take this one out of the list and add it to the matched out list
107 psmmAdd = psmm;
108
109 if (psmmLast)
110 {
111 // If we're not at the beginning of the list tell the last node about it's new next (since we're taking away it's current next)
112 psmmLast->psmmNext = psmmAdd->psmmNext;
113 }
114 else
115 {
116 // If we are at the beginning (no psmmLast) update the beginning (since we're taking it)
117 *ppsmmList = psmm->psmmNext;
118 }
119 psmm = psmm->psmmNext; // move on
120
121 // Add the one we've removed to the beginning of the out list
122 psmmAdd->psmmNext = *ppsmmOut;
123 *ppsmmOut = psmmAdd;
124 }
125 else
126 {
127 psmmLast = psmm; // remember the last we that didn't match
128 psmm = psmm->psmmNext; // move on
129 }
130 }
131
132 return hr;
133}
134
135HRESULT ScaMimeMapCheckList(SCA_MIMEMAP* psmmList)
136{
137 if (!psmmList)
138 return S_OK;
139
140 while (psmmList)
141 {
142 WcaLog(LOGMSG_STANDARD, "MimeMapping of %ls with ParentType=%d and ParentValue=%ls not used!", psmmList->wzMimeMap, psmmList->iParentType, psmmList->wzParentValue);
143 psmmList = psmmList->psmmNext;
144 }
145
146 return E_FAIL;
147}
148
149
150HRESULT ScaWriteMimeMap(IMSAdminBase* piMetabase, LPCWSTR wzRootOfWeb,
151 SCA_MIMEMAP* psmmList)
152{
153 HRESULT hr = S_OK;
154
155 WCHAR wzMimeMap[8192];
156 WCHAR *pwzNext = wzMimeMap;
157 const WCHAR *pwzMac = wzMimeMap + countof(wzMimeMap); // used to properly create the MULTI_SZ
158
159 // fill the MULTI_SZ wzMimeMap buffer for the MimeMap attribute
160 ::ZeroMemory(wzMimeMap, sizeof(wzMimeMap));
161
162 for (SCA_MIMEMAP* psmm = psmmList; psmm; psmm = psmm->psmmNext)
163 {
164 hr = ::StringCchPrintfW(pwzNext, max(0, pwzMac - pwzNext), L"%s,%s", psmm->wzExtension, psmm->wzMimeType);
165 ExitOnFailure(hr, "Failed to set MimeMap string");
166
167 pwzNext += lstrlenW(pwzNext) + 1; // reserve space for null
168 Assert(pwzNext <= pwzMac);
169 }
170
171 if (pwzNext != wzMimeMap)
172 {
173 // now write the CustomErrors to the metabase
174 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_MIME_MAP, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, wzMimeMap);
175 ExitOnFailure(hr, "Failed to write MimeMap");
176 }
177 else
178 {
179 WcaLog(LOGMSG_VERBOSE, "Skipping ScaWriteMimeMap() - no mappings found.");
180 ExitFunction1(hr = S_FALSE);
181 }
182
183LExit:
184 return hr;
185}
186
187
188static HRESULT AddMimeMapToList(SCA_MIMEMAP** ppsmmList)
189{
190 HRESULT hr = S_OK;
191
192 SCA_MIMEMAP* psmm = static_cast<SCA_MIMEMAP*>(MemAlloc(sizeof(SCA_MIMEMAP), TRUE));
193 ExitOnNull(psmm, hr, E_OUTOFMEMORY, "failed to allocate memory for new mime map list element");
194
195 psmm->psmmNext = *ppsmmList;
196 *ppsmmList = psmm;
197
198LExit:
199 return hr;
200}
diff --git a/src/ext/Iis/ca/scamimemap.h b/src/ext/Iis/ca/scamimemap.h
new file mode 100644
index 00000000..b50e82e9
--- /dev/null
+++ b/src/ext/Iis/ca/scamimemap.h
@@ -0,0 +1,33 @@
1#pragma once
2// 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.
3
4
5enum eMimeMapParentType { mmptVDir = 1, mmptWeb = 2 };
6
7struct SCA_MIMEMAP
8{
9 // iis configuation information
10 WCHAR wzMimeMap[MAX_DARWIN_KEY + 1];
11 int iParentType;
12 WCHAR wzParentValue[MAX_DARWIN_KEY + 1];
13 WCHAR wzMimeType[MAX_DARWIN_KEY + 1];
14 WCHAR wzExtension[MAX_DARWIN_KEY + 1];
15
16
17 SCA_MIMEMAP* psmmNext;
18};
19
20
21// prototypes
22
23HRESULT __stdcall ScaMimeMapRead(SCA_MIMEMAP** ppsmmList, __inout LPWSTR *ppwzCustomActionData);
24
25HRESULT ScaGetMimeMap(int iParentType, LPCWSTR wzParentValue, SCA_MIMEMAP **psmmList, SCA_MIMEMAP **ppsmmOut);
26
27HRESULT ScaMimeMapCheckList(SCA_MIMEMAP* psmmList);
28
29void ScaMimeMapFreeList(SCA_MIMEMAP* psmmList);
30
31HRESULT ScaWriteMimeMap(IMSAdminBase* piMetabase, LPCWSTR wzRootOfWeb,
32 SCA_MIMEMAP* psmmList);
33
diff --git a/src/ext/Iis/ca/scamimemap7.cpp b/src/ext/Iis/ca/scamimemap7.cpp
new file mode 100644
index 00000000..f6689720
--- /dev/null
+++ b/src/ext/Iis/ca/scamimemap7.cpp
@@ -0,0 +1,68 @@
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
6HRESULT ScaWriteMimeMap7(
7 __in_z LPCWSTR wzWebName,
8 __in_z LPCWSTR wzRootOfWeb,
9 SCA_MIMEMAP* psmmList
10 )
11{
12 HRESULT hr = S_OK;
13 SCA_MIMEMAP* psmm;
14
15 //create the mimemap list for this vdir application
16 //all go to same web/root location tag
17 hr = ScaWriteConfigID(IIS_MIMEMAP_BEGIN);
18 ExitOnFailure(hr, "Failed to write mimemap begin id");
19 hr = ScaWriteConfigString(wzWebName); //site name key
20 ExitOnFailure(hr, "Failed to write mimemap web key");
21 hr = ScaWriteConfigString(wzRootOfWeb); //app path key
22 ExitOnFailure(hr, "Failed to write mimemap app key");
23
24 psmm = psmmList;
25
26 while (psmm)
27 {
28 //create the Extension for this vdir application
29 hr = ScaWriteConfigID(IIS_MIMEMAP);
30 ExitOnFailure(hr, "Failed to write mimemap id");
31
32 if (*psmm->wzExtension)
33 {
34 hr = ScaWriteConfigString(psmm->wzExtension);
35 }
36 else // blank means "*" (all)
37 {
38 hr = ScaWriteConfigString(L"*");
39 }
40 ExitOnFailure(hr, "Failed to write mimemap extension");
41
42 hr = ScaWriteConfigString(psmm->wzMimeType);
43 ExitOnFailure(hr, "Failed to write mimemap type");
44
45 psmm = psmm->psmmNext;
46 }
47
48 hr = ScaWriteConfigID(IIS_MIMEMAP_END);
49 ExitOnFailure(hr, "Failed to write mimemap end id");
50
51LExit:
52 return hr;
53}
54
55
56//static HRESULT AddMimeMapToList(SCA_MIMEMAP** ppsmmList)
57//{
58// HRESULT hr = S_OK;
59//
60// SCA_MIMEMAP* psmm = static_cast<SCA_MIMEMAP*>(MemAlloc(sizeof(SCA_MIMEMAP), TRUE));
61// ExitOnNull(psmm, hr, E_OUTOFMEMORY, "failed to allocate memory for new mime map list element");
62//
63// psmm->psmmNext = *ppsmmList;
64// *ppsmmList = psmm;
65//
66//LExit:
67// return hr;
68//}
diff --git a/src/ext/Iis/ca/scamimemap7.h b/src/ext/Iis/ca/scamimemap7.h
new file mode 100644
index 00000000..88fcdc39
--- /dev/null
+++ b/src/ext/Iis/ca/scamimemap7.h
@@ -0,0 +1,10 @@
1#pragma once
2// 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.
3
4
5HRESULT ScaWriteMimeMap7(
6 __in_z LPCWSTR wzWebName,
7 __in_z LPCWSTR wzRootOfWeb,
8 SCA_MIMEMAP* psmmList
9 );
10
diff --git a/src/ext/Iis/ca/scaproperty.cpp b/src/ext/Iis/ca/scaproperty.cpp
new file mode 100644
index 00000000..d0e0d8a4
--- /dev/null
+++ b/src/ext/Iis/ca/scaproperty.cpp
@@ -0,0 +1,252 @@
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/*------------------------------------------------------------------
6IIsProperty table:
7
8Property Component_ Attributes Value
9s72 s72 i4 s255
10------------------------------------------------------------------*/
11
12// sql queries
13enum ePropertyQuery { pqProperty = 1, pqComponent, pqAttributes, pqValue, pqInstalled, pqAction };
14
15
16// prototypes
17static HRESULT AddPropertyToList(
18 SCA_PROPERTY** ppspList
19 );
20
21
22// functions
23void ScaPropertyFreeList(
24 SCA_PROPERTY* pspList
25 )
26{
27 SCA_PROPERTY* pspDelete = pspList;
28 while (pspList)
29 {
30 pspDelete = pspList;
31 pspList = pspList->pspNext;
32
33 MemFree(pspDelete);
34 }
35}
36
37
38HRESULT ScaPropertyRead(
39 SCA_PROPERTY** ppspList,
40 __inout LPWSTR *ppwzCustomActionData
41 )
42{
43 HRESULT hr = S_OK;
44 MSIHANDLE hRec;
45
46 LPWSTR pwzData = NULL;
47 SCA_PROPERTY* pss;
48
49 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
50
51 ExitOnNull(ppspList, hr, E_INVALIDARG, "Failed to read property, because no property to read was provided");
52
53 hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
54 ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead");
55
56 if (0 == WcaGetQueryRecords(hWrapQuery))
57 {
58 WcaLog(LOGMSG_VERBOSE, "Skipping ScaInstallProperty() - required table not present");
59 ExitFunction1(hr = S_FALSE);
60 }
61
62 // loop through all the Settings
63 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
64 {
65 hr = AddPropertyToList(ppspList);
66 ExitOnFailure(hr, "failed to add property to list");
67
68 pss = *ppspList;
69
70 hr = WcaGetRecordString(hRec, pqProperty, &pwzData);
71 ExitOnFailure(hr, "failed to get IIsProperty.Property");
72 hr = ::StringCchCopyW(pss->wzProperty, countof(pss->wzProperty), pwzData);
73 ExitOnFailure(hr, "failed to copy Property name: %ls", pwzData);
74
75 hr = WcaGetRecordString(hRec, pqValue, &pwzData);
76 ExitOnFailure(hr, "failed to get IIsProperty.Value");
77 hr = ::StringCchCopyW(pss->wzValue, countof(pss->wzValue), pwzData);
78 ExitOnFailure(hr, "failed to copy Property value: %ls", pwzData);
79
80 hr = WcaGetRecordInteger(hRec, pqAttributes, &pss->iAttributes);
81 ExitOnFailure(hr, "failed to get IIsProperty.Attributes");
82
83 hr = WcaGetRecordString(hRec, pqComponent, &pwzData);
84 ExitOnFailure(hr, "failed to get IIsProperty.Component");
85 hr = ::StringCchCopyW(pss->wzComponent, countof(pss->wzComponent), pwzData);
86 ExitOnFailure(hr, "failed to copy component name: %ls", pwzData);
87
88 hr = WcaGetRecordInteger(hRec, pqInstalled, (int *)&pss->isInstalled);
89 ExitOnFailure(hr, "Failed to get Component installed state for filter");
90
91 hr = WcaGetRecordInteger(hRec, pqAction, (int *)&pss->isAction);
92 ExitOnFailure(hr, "Failed to get Component action state for filter");
93 }
94
95 if (E_NOMOREITEMS == hr)
96 {
97 hr = S_OK;
98 }
99 ExitOnFailure(hr, "failure while processing IIsProperty table");
100
101LExit:
102 WcaFinishUnwrapQuery(hWrapQuery);
103
104 ReleaseStr(pwzData);
105
106 return hr;
107}
108
109
110HRESULT ScaPropertyInstall(
111 IMSAdminBase* piMetabase,
112 SCA_PROPERTY* pspList
113 )
114{
115 Assert(piMetabase);
116
117 HRESULT hr = S_OK;
118
119 for (SCA_PROPERTY* psp = pspList; psp; psp = psp->pspNext)
120 {
121 // if we are installing the web site
122 if (WcaIsInstalling(psp->isInstalled, psp->isAction))
123 {
124 hr = ScaWriteProperty(piMetabase, psp);
125 ExitOnFailure(hr, "failed to write Property '%ls' to metabase", psp->wzProperty);
126 }
127 }
128
129LExit:
130 return hr;
131}
132
133
134HRESULT ScaPropertyUninstall(
135 IMSAdminBase* piMetabase,
136 SCA_PROPERTY* pspList
137 )
138{
139 Assert(piMetabase);
140
141 HRESULT hr = S_OK;
142
143 for (SCA_PROPERTY* psp = pspList; psp; psp = psp->pspNext)
144 {
145 // if we are uninstalling the web site
146 if (WcaIsUninstalling(psp->isInstalled, psp->isAction))
147 {
148 hr = ScaRemoveProperty(piMetabase, psp);
149 ExitOnFailure(hr, "Failed to remove Property '%ls' from metabase", psp->wzProperty);
150 }
151 }
152
153LExit:
154 return hr;
155}
156
157
158HRESULT ScaWriteProperty(
159 IMSAdminBase* piMetabase,
160 SCA_PROPERTY* psp
161 )
162{
163 Assert(piMetabase);
164
165 HRESULT hr = S_OK;
166 DWORD dwValue;
167 LPWSTR wz = NULL;
168
169 ExitOnNull(psp, hr, E_INVALIDARG, "Failed to write property because no property to write was given");
170
171 //
172 // Figure out what setting we're writing and write it
173 //
174 if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_IIS5_ISOLATION_MODE))
175 {
176 dwValue = 1;
177 hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_GLOBAL_STANDARD_APP_MODE_ENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue));
178 ExitOnFailure(hr, "failed to set IIs5IsolationMode");
179 }
180 else if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_MAX_GLOBAL_BANDWIDTH))
181 {
182 dwValue = wcstoul(psp->wzValue, &wz, 10) * 1024; // remember, the value shown is in kilobytes, the value saved is in bytes
183 hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_MAX_GLOBAL_BANDWIDTH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue));
184 ExitOnFailure(hr, "failed to set MaxGlobalBandwidth");
185 }
186 else if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_LOG_IN_UTF8))
187 {
188 dwValue = 1;
189 hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_GLOBAL_LOG_IN_UTF_8, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue));
190 ExitOnFailure(hr, "failed to set LogInUTF8");
191 }
192 else if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_ETAG_CHANGENUMBER))
193 {
194 dwValue = wcstoul(psp->wzValue, &wz, 10);
195 hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, /*MD_ETAG_CHANGENUMBER*/ 2039, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue));
196 ExitOnFailure(hr, "failed to set EtagChangenumber");
197 }
198LExit:
199 return hr;
200}
201
202
203HRESULT ScaRemoveProperty(
204 IMSAdminBase* piMetabase,
205 SCA_PROPERTY* psp
206 )
207{
208 Assert(piMetabase);
209
210 HRESULT hr = S_OK;
211 DWORD dwValue;
212
213 ExitOnNull(psp, hr, E_INVALIDARG, "Failed to remove property because no property to remove was given");
214
215 if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_IIS5_ISOLATION_MODE))
216 {
217 dwValue = 0;
218 hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_GLOBAL_STANDARD_APP_MODE_ENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue));
219 ExitOnFailure(hr, "failed to clear IIs5IsolationMode");
220 }
221 else if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_MAX_GLOBAL_BANDWIDTH))
222 {
223 dwValue = 0xFFFFFFFF; // This unchecks the box
224 hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_MAX_GLOBAL_BANDWIDTH, METADATA_NO_ATTRIBUTES , IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue));
225 ExitOnFailure(hr, "failed to clear MaxGlobalBandwidth");
226 }
227 else if (0 == lstrcmpW(psp->wzProperty, wzIISPROPERTY_LOG_IN_UTF8))
228 {
229 dwValue = 0;
230 hr = ScaWriteMetabaseValue(piMetabase, L"/LM/W3SVC", NULL, MD_GLOBAL_LOG_IN_UTF_8, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwValue));
231 ExitOnFailure(hr, "failed to clear LogInUTF8");
232 }
233
234LExit:
235 return hr;
236}
237
238
239static HRESULT AddPropertyToList(
240 SCA_PROPERTY** ppspList
241 )
242{
243 HRESULT hr = S_OK;
244 SCA_PROPERTY* psp = static_cast<SCA_PROPERTY*>(MemAlloc(sizeof(SCA_PROPERTY), TRUE));
245 ExitOnNull(psp, hr, E_OUTOFMEMORY, "failed to allocate memory for new property list element");
246
247 psp->pspNext = *ppspList;
248 *ppspList = psp;
249
250LExit:
251 return hr;
252}
diff --git a/src/ext/Iis/ca/scaproperty.h b/src/ext/Iis/ca/scaproperty.h
new file mode 100644
index 00000000..21e7cfc7
--- /dev/null
+++ b/src/ext/Iis/ca/scaproperty.h
@@ -0,0 +1,54 @@
1#pragma once
2// 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.
3
4
5#define wzIISPROPERTY_IIS5_ISOLATION_MODE L"IIs5IsolationMode"
6#define wzIISPROPERTY_MAX_GLOBAL_BANDWIDTH L"MaxGlobalBandwidth"
7#define wzIISPROPERTY_LOG_IN_UTF8 L"LogInUTF8"
8#define wzIISPROPERTY_ETAG_CHANGENUMBER L"ETagChangeNumber"
9
10struct SCA_PROPERTY
11{
12 // iis configuation information
13 WCHAR wzProperty[MAX_DARWIN_KEY + 1];
14 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
15 INSTALLSTATE isInstalled;
16 INSTALLSTATE isAction;
17 INT iAttributes;
18 WCHAR wzValue[MAX_DARWIN_COLUMN + 1];
19
20 SCA_PROPERTY *pspNext;
21};
22
23
24// prototypes
25
26HRESULT ScaPropertyRead(
27 SCA_PROPERTY** ppspList,
28 __inout LPWSTR *ppwzCustomActionData
29 );
30
31void ScaPropertyFreeList(
32 SCA_PROPERTY* pspList
33 );
34
35HRESULT ScaPropertyInstall(
36 IMSAdminBase* piMetabase,
37 SCA_PROPERTY* pspList
38 );
39
40HRESULT ScaPropertyUninstall(
41 IMSAdminBase* piMetabase,
42 SCA_PROPERTY* pspList
43 );
44
45HRESULT ScaWriteProperty(
46 IMSAdminBase* piMetabase,
47 SCA_PROPERTY* psp
48 );
49
50HRESULT ScaRemoveProperty(
51 IMSAdminBase* piMetabase,
52 SCA_PROPERTY* psp
53 );
54
diff --git a/src/ext/Iis/ca/scaproperty7.cpp b/src/ext/Iis/ca/scaproperty7.cpp
new file mode 100644
index 00000000..d17eeb68
--- /dev/null
+++ b/src/ext/Iis/ca/scaproperty7.cpp
@@ -0,0 +1,108 @@
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
5HRESULT ScaPropertyInstall7(
6 SCA_PROPERTY* pspList
7 )
8{
9 HRESULT hr = S_OK;
10
11 for (SCA_PROPERTY* psp = pspList; psp; psp = psp->pspNext)
12 {
13 // if we are installing the web site
14 if (WcaIsInstalling(psp->isInstalled, psp->isAction))
15 {
16 hr = ScaWriteProperty7(psp);
17 ExitOnFailure(hr, "failed to write Property '%ls' ", psp->wzProperty);
18 }
19 }
20
21LExit:
22 return hr;
23}
24
25
26HRESULT ScaPropertyUninstall7(
27 SCA_PROPERTY* pspList
28 )
29{
30 HRESULT hr = S_OK;
31
32 for (SCA_PROPERTY* psp = pspList; psp; psp = psp->pspNext)
33 {
34 // if we are uninstalling the web site
35 if (WcaIsUninstalling(psp->isInstalled, psp->isAction))
36 {
37 hr = ScaRemoveProperty7(psp);
38 ExitOnFailure(hr, "Failed to remove Property '%ls'", psp->wzProperty);
39 }
40 }
41
42LExit:
43 return hr;
44}
45
46
47HRESULT ScaWriteProperty7(
48 const SCA_PROPERTY* psp
49 )
50{
51 HRESULT hr = S_OK;
52 DWORD dwValue;
53 LPWSTR wz = NULL;
54
55 ExitOnNull(psp, hr, E_INVALIDARG, "Failed to write property because no property to write was given");
56 //
57 // Figure out what setting we're writing and write it
58 //
59 if (0 == wcscmp(psp->wzProperty, wzIISPROPERTY_IIS5_ISOLATION_MODE))
60 {
61 // IIs5IsolationMode not supported
62 WcaLog(LOGMSG_VERBOSE, "Not supported by IIS7: IIs5IsolationMode, ignoring");
63 }
64 else if (0 == wcscmp(psp->wzProperty, wzIISPROPERTY_MAX_GLOBAL_BANDWIDTH))
65 {
66 dwValue = wcstoul(psp->wzValue, &wz, 10) * 1024; // remember, the value shown is in kilobytes, the value saved is in bytes
67 hr = ScaWriteConfigID(IIS_PROPERTY);
68 ExitOnFailure(hr, "failed to set Property ID");
69 hr = ScaWriteConfigID(IIS_PROPERTY_MAXBAND);
70 ExitOnFailure(hr, "failed to set Property MSXBAND ID");
71 hr = ScaWriteConfigInteger(dwValue);
72 ExitOnFailure(hr, "failed to set Property MSXBAND value");
73 }
74 else if (0 == wcscmp(psp->wzProperty, wzIISPROPERTY_LOG_IN_UTF8))
75 {
76 dwValue = 1;
77 hr = ScaWriteConfigID(IIS_PROPERTY);
78 ExitOnFailure(hr, "failed to set Property ID");
79 hr = ScaWriteConfigID(IIS_PROPERTY_LOGUTF8);
80 ExitOnFailure(hr, "failed to set Property LOG ID");
81 hr = ScaWriteConfigInteger(dwValue);
82 ExitOnFailure(hr, "failed to set Property Log value");
83 }
84 else if (0 == wcscmp(psp->wzProperty, wzIISPROPERTY_ETAG_CHANGENUMBER))
85 {
86 //EtagChangenumber not supported
87 WcaLog(LOGMSG_VERBOSE, "Not supported by IIS7: EtagChangenumber, ignoring");
88 }
89
90LExit:
91 return hr;
92}
93
94HRESULT ScaRemoveProperty7(
95 __in SCA_PROPERTY* /*psp*/
96 )
97{
98
99 // NOP function for now
100 //The two global values being set by WebProperty:
101 // <iis:WebProperty Id="MaxGlobalBandwidth" Value="1024" />
102 // <iis:WebProperty Id ="LogInUTF8" />
103 // should should not be removed on uninstall.
104
105 HRESULT hr = S_OK;
106
107 return hr;
108}
diff --git a/src/ext/Iis/ca/scaproperty7.h b/src/ext/Iis/ca/scaproperty7.h
new file mode 100644
index 00000000..bbf811e8
--- /dev/null
+++ b/src/ext/Iis/ca/scaproperty7.h
@@ -0,0 +1,26 @@
1#pragma once
2// 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.
3
4
5#define wzIISPROPERTY_IIS5_ISOLATION_MODE L"IIs5IsolationMode"
6#define wzIISPROPERTY_MAX_GLOBAL_BANDWIDTH L"MaxGlobalBandwidth"
7#define wzIISPROPERTY_LOG_IN_UTF8 L"LogInUTF8"
8#define wzIISPROPERTY_ETAG_CHANGENUMBER L"ETagChangeNumber"
9
10// prototypes
11HRESULT ScaPropertyInstall7(
12 SCA_PROPERTY* pspList
13 );
14
15HRESULT ScaPropertyUninstall7(
16 SCA_PROPERTY* pspList
17 );
18
19HRESULT ScaWriteProperty7(
20 const SCA_PROPERTY* psp
21 );
22
23HRESULT ScaRemoveProperty7(
24 SCA_PROPERTY* psp
25 );
26
diff --git a/src/ext/Iis/ca/scasched.cpp b/src/ext/Iis/ca/scasched.cpp
new file mode 100644
index 00000000..de021275
--- /dev/null
+++ b/src/ext/Iis/ca/scasched.cpp
@@ -0,0 +1,823 @@
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
5const int ConfigureIIsCost = 8;
6const int WriteMetabaseChangesCost = 20;
7const int WriteIIS7ConfigChangesCost = 20;
8
9// sql queries
10LPCWSTR vcsUserDeferredQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Password` FROM `User`";
11
12LPCWSTR vcsWebSvcExtQuery = L"SELECT `Component_`, `File`, `Description`, `Group`, `Attributes` FROM `IIsWebServiceExtension`";
13
14LPCWSTR vcsAppPoolQuery = L"SELECT `AppPool`, `Name`, `Component_`, `Attributes`, `User_`, `RecycleMinutes`, `RecycleRequests`, `RecycleTimes`, `VirtualMemory`, `PrivateMemory`, `IdleTimeout`, `QueueLimit`, `CPUMon`, `MaxProc`, `ManagedRuntimeVersion`, `ManagedPipelineMode` FROM `IIsAppPool`";
15
16LPCWSTR vcsComponentAttrQuery = L"SELECT `Component`,`Attributes` FROM `Component`";
17
18LPCWSTR vcsMimeMapQuery = L"SELECT `MimeMap`, `ParentType`, `ParentValue`, `MimeType`, `Extension` FROM `IIsMimeMap`";
19
20LPCWSTR vcsHttpHeaderQuery = L"SELECT `Name`, `ParentType`, `ParentValue`, `Value`, `Attributes` FROM `IIsHttpHeader` ORDER BY `Sequence`";
21
22LPCWSTR vcsWebErrorQuery =
23 L"SELECT `ErrorCode`, `SubCode`, `ParentType`, `ParentValue`, `File`, `URL` "
24 L"FROM `IIsWebError` ORDER BY `ErrorCode`, `SubCode`";
25
26LPCWSTR vcsWebDirPropertiesQuery = L"SELECT `DirProperties`, `Access`, `Authorization`, `AnonymousUser_`, `IIsControlledPassword`, `LogVisits`, `Index`, `DefaultDoc`, `AspDetailedError`, `HttpExpires`, `CacheControlMaxAge`, `CacheControlCustom`, `NoCustomError`, `AccessSSLFlags`, `AuthenticationProviders` "
27 L"FROM `IIsWebDirProperties`";
28
29LPCWSTR vcsSslCertificateQuery = L"SELECT `Certificate`.`StoreName`, `CertificateHash`.`Hash`, `IIsWebSiteCertificates`.`Web_` FROM `Certificate`, `CertificateHash`, `IIsWebSiteCertificates` WHERE `Certificate`.`Certificate`=`CertificateHash`.`Certificate_` AND `CertificateHash`.`Certificate_`=`IIsWebSiteCertificates`.`Certificate_`";
30
31LPCWSTR vcsWebLogQuery = L"SELECT `Log`, `Format` "
32 L"FROM `IIsWebLog`";
33
34LPCWSTR vcsWebApplicationQuery = L"SELECT `Name`, `Isolation`, `AllowSessions`, `SessionTimeout`, "
35 L"`Buffer`, `ParentPaths`, `DefaultScript`, `ScriptTimeout`, "
36 L"`ServerDebugging`, `ClientDebugging`, `AppPool_`, `Application` "
37 L"FROM `IIsWebApplication`";
38
39LPCWSTR vcsWebAppExtensionQuery = L"SELECT `Extension`, `Verbs`, `Executable`, `Attributes`, `Application_` FROM `IIsWebApplicationExtension`";
40
41LPCWSTR vcsWebQuery = L"SELECT `Web`, `Component_`, `Id`, `Description`, `ConnectionTimeout`, `Directory_`, `State`, `Attributes`, `DirProperties_`, `Application_`, "
42 L"`Address`, `IP`, `Port`, `Header`, `Secure`, `Log_` FROM `IIsWebSite`, `IIsWebAddress` "
43 L"WHERE `KeyAddress_`=`Address` ORDER BY `Sequence`";
44
45LPCWSTR vcsWebAddressQuery = L"SELECT `Address`, `Web_`, `IP`, `Port`, `Header`, `Secure` "
46 L"FROM `IIsWebAddress`";
47
48LPCWSTR vcsWebBaseQuery = L"SELECT `Web`, `Id`, `IP`, `Port`, `Header`, `Secure`, `Description` "
49 L"FROM `IIsWebSite`, `IIsWebAddress` "
50 L"WHERE `KeyAddress_`=`Address`";
51
52LPCWSTR vcsWebDirQuery = L"SELECT `Web_`, `WebDir`, `Component_`, `Path`, `DirProperties_`, `Application_` "
53 L"FROM `IIsWebDir`";
54
55LPCWSTR vcsVDirQuery = L"SELECT `Web_`, `VirtualDir`, `Component_`, `Alias`, `Directory_`, `DirProperties_`, `Application_` "
56 L"FROM `IIsWebVirtualDir`";
57
58LPCWSTR vcsFilterQuery = L"SELECT `Web_`, `Name`, `Component_`, `Path`, `Description`, `Flags`, `LoadOrder` FROM `IIsFilter` ORDER BY `Web_`";
59
60LPCWSTR vcsPropertyQuery = L"SELECT `Property`, `Component_`, `Attributes`, `Value` "
61 L"FROM `IIsProperty`";
62
63#define IIS7CONDITION L"VersionNT >= 600"
64#define USEIIS7CONDITION IIS7CONDITION L"AND NOT UseIis6Compatibility"
65
66/********************************************************************
67ConfigureIIs - CUSTOM ACTION ENTRY POINT for installing IIs settings
68
69********************************************************************/
70extern "C" UINT __stdcall ConfigureIIs(
71 __in MSIHANDLE hInstall
72 )
73{
74 //AssertSz(FALSE, "debug ConfigureIIs here");
75 HRESULT hr = S_OK;
76 UINT er = ERROR_SUCCESS;
77 LPWSTR pwzScriptKey = NULL;
78 LPWSTR pwzBackupId = NULL;
79 LPWSTR pwzCustomActionData = NULL; // CustomActionData for ConfigureIIs custom action
80
81 // initialize
82 hr = WcaInitialize(hInstall, "ConfigureIIs");
83 ExitOnFailure(hr, "Failed to initialize");
84
85 // check for the prerequsite tables
86 if (S_OK != WcaTableExists(L"IIsWebSite") && S_OK != WcaTableExists(L"IIsFilter") && S_OK != WcaTableExists(L"IIsProperty") &&
87 S_OK != WcaTableExists(L"IIsWebServiceExtension") && S_OK != WcaTableExists(L"IIsAppPool"))
88 {
89 WcaLog(LOGMSG_VERBOSE, "skipping IIs CustomAction, no IIsWebSite table, no IIsFilter table, no IIsProperty table, no IIsWebServiceExtension, and no IIsAppPool table");
90 ExitFunction1(hr = S_FALSE);
91 }
92
93 // Get a CaScript key
94 hr = WcaCaScriptCreateKey(&pwzScriptKey);
95 ExitOnFailure(hr, "Failed to get encoding key.");
96
97 // Generate a unique string to be used for this product's transaction
98 // This prevents a name collision when doing a major upgrade
99 hr = WcaGetProperty(L"ProductCode", &pwzBackupId);
100 ExitOnFailure(hr, "failed to get ProductCode");
101
102 hr = StrAllocConcat(&pwzBackupId, L"ScaConfigureIIs", 0);
103 ExitOnFailure(hr, "failed to concat ScaConfigureIIs");
104
105 // make sure the operations below are wrapped in a "transaction"
106 // use IIS7 transaction logic even if using Iis6 compat because Backup/Restore don't work with metabase compatibility
107 if (MSICONDITION_TRUE == ::MsiEvaluateConditionW(hInstall, IIS7CONDITION))
108 {
109 hr = ScaIIS7ConfigTransaction(pwzBackupId);
110 MessageExitOnFailure(hr, msierrIISFailedSchedTransaction, "failed to start IIS7 transaction");
111 }
112 else
113 {
114 hr = ScaMetabaseTransaction(pwzBackupId);
115 MessageExitOnFailure(hr, msierrIISFailedSchedTransaction, "failed to start IIS transaction");
116 }
117
118 // Write the CaScript key to the ConfigureIIS custom action data
119 hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData);
120 ExitOnFailure(hr, "Failed to add encoding key to CustomActionData.");
121
122 // Wrap vcsUserDeferredQuery to send to deferred CA
123 if (S_OK == WcaTableExists(L"User"))
124 {
125 hr = WcaWrapQuery(vcsUserDeferredQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF);
126 ExitOnFailure(hr, "Failed to wrap User query");
127 }
128 else
129 {
130 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
131 ExitOnFailure(hr, "Failed to wrap User empty query");
132 }
133
134 // Wrap vcsWebSvcExtQuery to send to deferred CA
135 if (S_OK == WcaTableExists(L"IIsWebServiceExtension"))
136 {
137 hr = WcaWrapQuery(vcsWebSvcExtQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3 | efmcColumn4, 1, 0xFFFFFFFF);
138 ExitOnFailure(hr, "Failed to wrap IIsWebServiceExtension query");
139 }
140 else
141 {
142 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
143 ExitOnFailure(hr, "Failed to wrap IIsWebServiceExtension empty query");
144 }
145
146 // Wrap vcsAppPoolQuery to send to deferred CA
147 if (S_OK == WcaTableExists(L"IIsAppPool"))
148 {
149 hr = WcaWrapQuery(vcsAppPoolQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn15 | efmcColumn16, 3, 0xFFFFFFFF);
150 ExitOnFailure(hr, "Failed to wrap IIsAppPool query");
151
152 hr = WcaWrapQuery(vcsComponentAttrQuery, &pwzCustomActionData, 0, 0xFFFFFFFF, 0xFFFFFFFF);
153 ExitOnFailure(hr, "Failed to wrap Component query");
154 }
155 else
156 {
157 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
158 ExitOnFailure(hr, "Failed to wrap IIsAppPool empty query");
159 }
160
161 // Wrap vcsMimeMapQuery to send to deferred CA
162 if (S_OK == WcaTableExists(L"IIsMimeMap"))
163 {
164 hr = WcaWrapQuery(vcsMimeMapQuery, &pwzCustomActionData, efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF);
165 ExitOnFailure(hr, "Failed to wrap IIsMimeMap query");
166 }
167 else
168 {
169 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
170 ExitOnFailure(hr, "Failed to wrap IIsMimeMap empty query");
171 }
172
173 // Wrap vcsHttpHeaderQuery to send to deferred CA
174 if (S_OK == WcaTableExists(L"IIsHttpHeader"))
175 {
176 hr = WcaWrapQuery(vcsHttpHeaderQuery, &pwzCustomActionData, efmcColumn1 | efmcColumn4, 0xFFFFFFFF, 0xFFFFFFFF);
177 ExitOnFailure(hr, "Failed to wrap IIsHttpHeader query");
178 }
179 else
180 {
181 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
182 ExitOnFailure(hr, "Failed to wrap IIsHttpHeader empty query");
183 }
184
185 // Wrap vcsWebErrorQuery to send to deferred CA
186 if (S_OK == WcaTableExists(L"IIsWebError"))
187 {
188 hr = WcaWrapQuery(vcsWebErrorQuery, &pwzCustomActionData, efmcColumn5 | efmcColumn6, 0xFFFFFFFF, 0xFFFFFFFF);
189 ExitOnFailure(hr, "Failed to wrap IIsWebError query");
190 }
191 else
192 {
193 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
194 ExitOnFailure(hr, "Failed to wrap IIsWebError empty query");
195 }
196
197 // Wrap vcsWebDirPropertiesQuery to send to deferred CA
198 if (S_OK == WcaTableExists(L"IIsWebDirProperties"))
199 {
200 hr = WcaWrapQuery(vcsWebDirPropertiesQuery, &pwzCustomActionData, efmcColumn8 | efmcColumn10 | efmcColumn12 | efmcColumn15, 0xFFFFFFFF, 0xFFFFFFFF);
201 ExitOnFailure(hr, "Failed to wrap IIsWebDirProperties query");
202 }
203 else
204 {
205 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
206 ExitOnFailure(hr, "Failed to wrap IIsWebDirProperties empty query");
207 }
208
209 // Wrap vcsSslCertificateQuery to send to deferred CA
210 if (S_OK == WcaTableExists(L"Certificate") && S_OK == WcaTableExists(L"CertificateHash") && S_OK == WcaTableExists(L"IIsWebSiteCertificates"))
211 {
212 hr = WcaWrapQuery(vcsSslCertificateQuery, &pwzCustomActionData, 0, 0xFFFFFFFF, 0xFFFFFFFF);
213 ExitOnFailure(hr, "Failed to wrap SslCertificate query");
214 }
215 else
216 {
217 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
218 ExitOnFailure(hr, "Failed to wrap SslCertificate empty query");
219 }
220
221 // Wrap vcsWebLogQuery to send to deferred CA
222 if (S_OK == WcaTableExists(L"IIsWebLog"))
223 {
224 hr = WcaWrapQuery(vcsWebLogQuery, &pwzCustomActionData, efmcColumn2, 0xFFFFFFFF, 0xFFFFFFFF);
225 ExitOnFailure(hr, "Failed to wrap IIsWebLog query");
226 }
227 else
228 {
229 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
230 ExitOnFailure(hr, "Failed to wrap IIsWebLog empty query");
231 }
232
233 // Wrap vcsWebApplicationQuery to send to deferred CA
234 if (S_OK == WcaTableExists(L"IIsWebApplication"))
235 {
236 hr = WcaWrapQuery(vcsWebApplicationQuery, &pwzCustomActionData, efmcColumn1, 0xFFFFFFFF, 0xFFFFFFFF);
237 ExitOnFailure(hr, "Failed to wrap IIsWebApplication query");
238 }
239 else
240 {
241 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
242 ExitOnFailure(hr, "Failed to wrap IIsWebApplication empty query");
243 }
244
245 // Wrap vcsWebAppExtensionQuery to send to deferred CA
246 if (S_OK == WcaTableExists(L"IIsWebApplicationExtension"))
247 {
248 hr = WcaWrapQuery(vcsWebAppExtensionQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3, 0xFFFFFFFF, 0xFFFFFFFF);
249 ExitOnFailure(hr, "Failed to wrap IIsWebApplicationExtension query");
250 }
251 else
252 {
253 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
254 ExitOnFailure(hr, "Failed to wrap IIsWebApplicationExtension empty query");
255 }
256
257 // Wrap vcsWebQuery, vcsWebAddressQuery, and vcsWebBaseQuery to send to deferred CA
258 if (S_OK == WcaTableExists(L"IIsWebAddress") && S_OK == WcaTableExists(L"IIsWebSite"))
259 {
260 hr = WcaWrapQuery(vcsWebQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn12 | efmcColumn13 | efmcColumn14, 2, 6);
261 ExitOnFailure(hr, "Failed to wrap IIsWebSite query");
262
263 hr = WcaWrapQuery(vcsWebAddressQuery, &pwzCustomActionData, efmcColumn3 | efmcColumn4 | efmcColumn5, 0xFFFFFFFF, 0xFFFFFFFF);
264 ExitOnFailure(hr, "Failed to wrap IIsWebAddress query");
265
266 hr = WcaWrapQuery(vcsWebBaseQuery, &pwzCustomActionData, efmcColumn2 | efmcColumn3 | efmcColumn4 | efmcColumn5 | efmcColumn7, 0xFFFFFFFF, 0xFFFFFFFF);
267 ExitOnFailure(hr, "Failed to wrap IIsWebBase query");
268 }
269 else
270 {
271 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
272 ExitOnFailure(hr, "Failed to wrap IIsWebSite empty query");
273
274 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
275 ExitOnFailure(hr, "Failed to wrap IIsWebAddress empty query");
276
277 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
278 ExitOnFailure(hr, "Failed to wrap IIsWebBase empty query");
279 }
280
281 // Wrap vcsWebDirQuery to send to deferred CA
282 if (S_OK == WcaTableExists(L"IIsWebDir"))
283 {
284 hr = WcaWrapQuery(vcsWebDirQuery, &pwzCustomActionData, efmcColumn4, 3, 0xFFFFFFFF);
285 ExitOnFailure(hr, "Failed to wrap IIsWebDir query");
286 }
287 else
288 {
289 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
290 ExitOnFailure(hr, "Failed to wrap IIsWebDir empty query");
291 }
292
293 // Wrap vcsVDirQuery to send to deferred CA
294 if (S_OK == WcaTableExists(L"IIsWebVirtualDir"))
295 {
296 hr = WcaWrapQuery(vcsVDirQuery, &pwzCustomActionData, efmcColumn4, 3, 5);
297 ExitOnFailure(hr, "Failed to wrap IIsWebVirtualDir query");
298 }
299 else
300 {
301 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
302 ExitOnFailure(hr, "Failed to wrap IIsWebVirtualDir empty query");
303 }
304
305 // Wrap vcsFilterQuery to send to deferred CA
306 if (S_OK == WcaTableExists(L"IIsFilter"))
307 {
308 hr = WcaWrapQuery(vcsFilterQuery, &pwzCustomActionData, efmcColumn4 | efmcColumn5, 3, 0xFFFFFFFF);
309 ExitOnFailure(hr, "Failed to wrap IIsFilter query");
310 }
311 else
312 {
313 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
314 ExitOnFailure(hr, "Failed to wrap IIsFilter empty query");
315 }
316
317 // Wrap vcsPropertyQuery to send to deferred CA
318 if (S_OK == WcaTableExists(L"IIsProperty"))
319 {
320 hr = WcaWrapQuery(vcsPropertyQuery, &pwzCustomActionData, efmcColumn4, 2, 0xFFFFFFFF);
321 ExitOnFailure(hr, "Failed to wrap IIsProperty query");
322 }
323 else
324 {
325 hr = WcaWrapEmptyQuery(&pwzCustomActionData);
326 ExitOnFailure(hr, "Failed to wrap IIsProperty empty query");
327 }
328
329 if (MSICONDITION_TRUE == ::MsiEvaluateConditionW(hInstall, USEIIS7CONDITION))
330 {
331 // This must remain trace only, CA data may contain password
332 WcaLog(LOGMSG_TRACEONLY, "Custom Action Data for ConfigureIIS7Exec will be: %ls", pwzCustomActionData);
333
334 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ConfigureIIs7Exec"), pwzCustomActionData, ConfigureIIsCost);
335 ExitOnFailure(hr, "Failed to schedule ConfigureIIs7Exec custom action");
336
337 ReleaseNullStr(pwzCustomActionData);
338
339 // Write the CaScript key to the ConfigureIIS custom action data
340 hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData);
341 ExitOnFailure(hr, "Failed to add script key to CustomActionData.");
342
343 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WriteIIS7ConfigChanges"), pwzCustomActionData, WriteIIS7ConfigChangesCost);
344 ExitOnFailure(hr, "Failed to schedule WriteMetabaseChanges custom action");
345 }
346 else
347 {
348 // This must remain trace only, CA data may contain password
349 WcaLog(LOGMSG_TRACEONLY, "Custom Action Data for ConfigureIISExec will be: %ls", pwzCustomActionData);
350
351 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"ConfigureIIsExec"), pwzCustomActionData, ConfigureIIsCost);
352 ExitOnFailure(hr, "Failed to schedule ConfigureIISExec custom action");
353
354 ReleaseNullStr(pwzCustomActionData);
355
356 // Write the CaScript key to the ConfigureIIS custom action data
357 hr = WcaWriteStringToCaData(pwzScriptKey, &pwzCustomActionData);
358 ExitOnFailure(hr, "Failed to add script key to CustomActionData.");
359
360 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WriteMetabaseChanges"), pwzCustomActionData, WriteMetabaseChangesCost);
361 ExitOnFailure(hr, "Failed to schedule WriteMetabaseChanges custom action");
362 }
363
364LExit:
365 ReleaseStr(pwzScriptKey);
366 ReleaseStr(pwzBackupId);
367 ReleaseStr(pwzCustomActionData);
368
369 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
370 return WcaFinalize(er);
371}
372
373/********************************************************************
374ConfigureIIsExec - custom action for installing IIs settings - table
375data will be wrapped and passed in from immediate CA
376ReadIIsTables
377
378********************************************************************/
379extern "C" UINT __stdcall ConfigureIIsExec(
380 __in MSIHANDLE hInstall
381 )
382{
383 //AssertSz(FALSE, "debug ConfigureIIsExec here");
384 HRESULT hr = S_OK;
385 UINT er = ERROR_SUCCESS;
386
387 BOOL fInitializedCom = FALSE;
388 IMSAdminBase* piMetabase = NULL;
389
390 SCA_WEB* pswList = NULL;
391 SCA_WEBDIR* pswdList = NULL;
392 SCA_VDIR* psvdList = NULL;
393 SCA_FILTER* psfList = NULL;
394 SCA_APPPOOL *psapList = NULL;
395 SCA_MIMEMAP* psmmList = NULL;
396 SCA_HTTP_HEADER* pshhList = NULL;
397 SCA_PROPERTY *pspList = NULL;
398 SCA_WEBSVCEXT* psWseList = NULL;
399 SCA_WEB_ERROR* psweList = NULL;
400
401 LPWSTR pwzScriptKey = NULL;
402 LPWSTR pwzCustomActionData = NULL;
403
404 WCA_WRAPQUERY_HANDLE hUserQuery = NULL;
405 WCA_WRAPQUERY_HANDLE hWebBaseQuery = NULL;
406 WCA_WRAPQUERY_HANDLE hWebDirPropQuery = NULL;
407 WCA_WRAPQUERY_HANDLE hSslCertQuery = NULL;
408 WCA_WRAPQUERY_HANDLE hWebLogQuery = NULL;
409 WCA_WRAPQUERY_HANDLE hWebAppQuery = NULL;
410 WCA_WRAPQUERY_HANDLE hWebAppExtQuery = NULL;
411
412 // initialize
413 hr = WcaInitialize(hInstall, "ConfigureIIsExec");
414 ExitOnFailure(hr, "Failed to initialize");
415
416 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
417 ExitOnFailure(hr, "failed to get CustomActionData");
418
419 // Get the CaScript key
420 hr = WcaReadStringFromCaData(&pwzCustomActionData, &pwzScriptKey);
421 ExitOnFailure(hr, "Failed to get CaScript key from custom action data");
422
423 hr = ::CoInitialize(NULL);
424 ExitOnFailure(hr, "failed to initialize COM");
425 fInitializedCom = TRUE;
426
427 // if IIS was uninstalled (thus no IID_IMSAdminBase) allow the
428 // user to still uninstall this package by clicking "Ignore"
429 do
430 {
431 hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void**)&piMetabase);
432 if (FAILED(hr))
433 {
434 WcaLog(LOGMSG_STANDARD, "failed to get IID_IMSAdminBase Object");
435 er = WcaErrorMessage(msierrIISCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
436 switch (er)
437 {
438 case IDABORT:
439 ExitFunction(); // bail with the error result from the CoCreate to kick off a rollback
440 case IDRETRY:
441 hr = S_FALSE; // hit me, baby, one more time
442 break;
443 case IDIGNORE:
444 __fallthrough;
445 default:
446 WcaLog(LOGMSG_STANDARD, "ignoring absent IIS");
447 // We need to write the empty script to communicate to other deferred CA that there is noting to do.
448 hr = ScaWriteConfigurationScript(pwzScriptKey);
449 ExitOnFailure(hr, "failed to schedule metabase configuration");
450
451 ExitFunction1(hr = S_OK); // pretend everything is okay
452 break;
453 }
454 }
455 } while (S_FALSE == hr);
456
457 // read the msi tables
458 hr = WcaBeginUnwrapQuery(&hUserQuery, &pwzCustomActionData);
459 ExitOnFailure(hr, "Failed to unwrap user query");
460
461 hr = ScaWebSvcExtRead(&psWseList, &pwzCustomActionData);
462 MessageExitOnFailure(hr, msierrIISFailedReadWebSvcExt, "failed while processing WebServiceExtensions");
463
464 hr = ScaAppPoolRead(&psapList, hUserQuery, &pwzCustomActionData);
465 MessageExitOnFailure(hr, msierrIISFailedReadAppPool, "failed while processing WebAppPools");
466
467 // MimeMap, Error and HttpHeader need to be read before the virtual directory and web read
468 hr = ScaMimeMapRead(&psmmList, &pwzCustomActionData);
469 MessageExitOnFailure(hr, msierrIISFailedReadMimeMap, "failed while processing MimeMaps");
470
471 hr = ScaHttpHeaderRead(&pshhList, &pwzCustomActionData);
472 MessageExitOnFailure(hr, msierrIISFailedReadHttpHeader, "failed while processing HttpHeaders");
473
474 hr = ScaWebErrorRead(&psweList, &pwzCustomActionData);
475 MessageExitOnFailure(hr, msierrIISFailedReadWebError, "failed while processing WebErrors");
476
477 hr = WcaBeginUnwrapQuery(&hWebDirPropQuery, &pwzCustomActionData);
478 ExitOnFailure(hr, "Failed to unwrap web dir properties query");
479
480 hr = WcaBeginUnwrapQuery(&hSslCertQuery, &pwzCustomActionData);
481 ExitOnFailure(hr, "Failed to unwrap ssl certificate query");
482
483 hr = WcaBeginUnwrapQuery(&hWebLogQuery, &pwzCustomActionData);
484 ExitOnFailure(hr, "Failed to unwrap web log query");
485
486 hr = WcaBeginUnwrapQuery(&hWebAppQuery, &pwzCustomActionData);
487 ExitOnFailure(hr, "Failed to unwrap web application query");
488
489 hr = WcaBeginUnwrapQuery(&hWebAppExtQuery, &pwzCustomActionData);
490 ExitOnFailure(hr, "Failed to unwrap web application extension query");
491
492 hr = ScaWebsRead(piMetabase, &psmmList, &pswList, &pshhList, &psweList, hUserQuery, hWebDirPropQuery, hSslCertQuery, hWebLogQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData);
493 MessageExitOnFailure(hr, msierrIISFailedReadWebSite, "failed while processing WebSites");
494
495 hr = WcaBeginUnwrapQuery(&hWebBaseQuery, &pwzCustomActionData);
496 ExitOnFailure(hr, "Failed to unwrap web base query");
497
498 hr = ScaWebDirsRead(piMetabase, pswList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData, &pswdList);
499 MessageExitOnFailure(hr, msierrIISFailedReadWebDirs, "failed while processing WebDirs");
500
501 hr = ScaVirtualDirsRead(piMetabase, pswList, &psvdList, &psmmList, &pshhList, &psweList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData);
502 MessageExitOnFailure(hr, msierrIISFailedReadVDirs, "failed while processing WebVirtualDirs");
503
504 hr = ScaFiltersRead(piMetabase, pswList, hWebBaseQuery, &psfList, &pwzCustomActionData);
505 MessageExitOnFailure(hr, msierrIISFailedReadFilters, "failed while processing WebFilters");
506
507 hr = ScaPropertyRead(&pspList, &pwzCustomActionData);
508 MessageExitOnFailure(hr, msierrIISFailedReadProp, "failed while processing WebProperties");
509
510 // do uninstall actions (order is important!)
511 hr = ScaPropertyUninstall(piMetabase, pspList);
512 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallProp, "failed to uninstall IIS properties");
513
514 hr = ScaFiltersUninstall(piMetabase, psfList);
515 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallFilters, "failed to schedule uninstall of filters");
516
517 hr = ScaVirtualDirsUninstall(piMetabase, psvdList);
518 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallVDirs, "failed to schedule uninstall of virtual directories");
519
520 hr = ScaWebDirsUninstall(piMetabase, pswdList);
521 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebDirs, "failed to schedule uninstall of web directories");
522
523 hr = ScaWebsUninstall(piMetabase, pswList);
524 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebs, "failed to schedule uninstall of webs");
525
526 hr = ScaAppPoolUninstall(piMetabase, psapList);
527 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallAppPool, "failed to schedule uninstall of AppPools");
528
529
530 // do install actions (order is important!)
531 // ScaWebSvcExtCommit contains both uninstall and install actions.
532 hr = ScaWebSvcExtCommit(piMetabase, psWseList);
533 MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebSvcExt, "failed to schedule install/uninstall of WebSvcExt");
534
535 hr = ScaAppPoolInstall(piMetabase, psapList);
536 MessageExitOnFailure(hr, msierrIISFailedSchedInstallAppPool, "failed to schedule install of AppPools");
537
538 hr = ScaWebsInstall(piMetabase, pswList, psapList);
539 MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebs, "failed to schedule install of webs");
540
541 hr = ScaWebDirsInstall(piMetabase, pswdList, psapList);
542 MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebDirs, "failed to schedule install of web directories");
543
544 hr = ScaVirtualDirsInstall(piMetabase, psvdList, psapList);
545 MessageExitOnFailure(hr, msierrIISFailedSchedInstallVDirs, "failed to schedule install of virtual directories");
546
547 hr = ScaFiltersInstall(piMetabase, psfList);
548 MessageExitOnFailure(hr, msierrIISFailedSchedInstallFilters, "failed to schedule install of filters");
549
550 hr = ScaPropertyInstall(piMetabase, pspList);
551 MessageExitOnFailure(hr, msierrIISFailedSchedInstallProp, "failed to schedule install of properties");
552
553 hr = ScaWriteConfigurationScript(pwzScriptKey);
554 ExitOnFailure(hr, "failed to schedule metabase configuration");
555
556LExit:
557 ReleaseStr(pwzScriptKey);
558 ReleaseStr(pwzCustomActionData);
559
560 WcaFinishUnwrapQuery(hUserQuery);
561 WcaFinishUnwrapQuery(hWebBaseQuery);
562 WcaFinishUnwrapQuery(hWebDirPropQuery);
563 WcaFinishUnwrapQuery(hSslCertQuery);
564 WcaFinishUnwrapQuery(hWebLogQuery);
565 WcaFinishUnwrapQuery(hWebAppQuery);
566 WcaFinishUnwrapQuery(hWebAppExtQuery);
567
568 if (psWseList)
569 {
570 ScaWebSvcExtFreeList(psWseList);
571 }
572
573 if (psfList)
574 {
575 ScaFiltersFreeList(psfList);
576 }
577
578 if (psvdList)
579 {
580 ScaVirtualDirsFreeList(psvdList);
581 }
582
583 if (pswdList)
584 {
585 ScaWebDirsFreeList(pswdList);
586 }
587
588 if (pswList)
589 {
590 ScaWebsFreeList(pswList);
591 }
592
593 if (psmmList)
594 {
595 ScaMimeMapCheckList(psmmList);
596 ScaMimeMapFreeList(psmmList);
597 }
598
599 if (pshhList)
600 {
601 ScaHttpHeaderCheckList(pshhList);
602 ScaHttpHeaderFreeList(pshhList);
603 }
604
605 if (psweList)
606 {
607 ScaWebErrorCheckList(psweList);
608 ScaWebErrorFreeList(psweList);
609 }
610
611 ReleaseObject(piMetabase);
612
613 if (fInitializedCom)
614 {
615 ::CoUninitialize();
616 }
617
618 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
619 return WcaFinalize(er);
620}
621
622
623/********************************************************************
624ConfigureIIs - CUSTOM ACTION ENTRY POINT for installing IIs settings
625
626********************************************************************/
627extern "C" UINT __stdcall ConfigureIIs7Exec(
628 __in MSIHANDLE hInstall
629 )
630{
631 //AssertSz(FALSE, "debug ConfigureIIs7Exec here");
632 HRESULT hr = S_OK;
633 UINT er = ERROR_SUCCESS;
634
635 LPWSTR pwzScriptKey = NULL;
636 LPWSTR pwzCustomActionData = NULL;
637
638 SCA_WEB7* pswList = NULL;
639 SCA_WEBDIR7* pswdList = NULL;
640 SCA_VDIR7* psvdList = NULL;
641 SCA_FILTER* psfList = NULL;
642 SCA_APPPOOL *psapList = NULL;
643 SCA_MIMEMAP* psmmList = NULL;
644 SCA_HTTP_HEADER* pshhList = NULL;
645 SCA_PROPERTY *pspList = NULL;
646 SCA_WEBSVCEXT* psWseList = NULL;
647 SCA_WEB_ERROR* psweList = NULL;
648
649 WCA_WRAPQUERY_HANDLE hUserQuery = NULL;
650 WCA_WRAPQUERY_HANDLE hWebBaseQuery = NULL;
651 WCA_WRAPQUERY_HANDLE hWebDirPropQuery = NULL;
652 WCA_WRAPQUERY_HANDLE hSslCertQuery = NULL;
653 WCA_WRAPQUERY_HANDLE hWebLogQuery = NULL;
654 WCA_WRAPQUERY_HANDLE hWebAppQuery = NULL;
655 WCA_WRAPQUERY_HANDLE hWebAppExtQuery = NULL;
656
657 // initialize
658 hr = WcaInitialize(hInstall, "ConfigureIIs7Exec");
659 ExitOnFailure(hr, "Failed to initialize");
660
661 hr = WcaGetProperty(L"CustomActionData", &pwzCustomActionData);
662 ExitOnFailure(hr, "failed to get CustomActionData");
663
664 // Get the CaScript key
665 hr = WcaReadStringFromCaData(&pwzCustomActionData, &pwzScriptKey);
666 ExitOnFailure(hr, "Failed to get CaScript key from custom action data");
667
668 // read the msi tables
669 hr = WcaBeginUnwrapQuery(&hUserQuery, &pwzCustomActionData);
670 ExitOnFailure(hr, "Failed to unwrap user query");
671
672 hr = ScaWebSvcExtRead(&psWseList, &pwzCustomActionData);
673 MessageExitOnFailure(hr, msierrIISFailedReadWebSvcExt, "failed while processing WebServiceExtensions");
674
675 hr = ScaAppPoolRead(&psapList, hUserQuery, &pwzCustomActionData);
676 MessageExitOnFailure(hr, msierrIISFailedReadAppPool, "failed while processing WebAppPools");
677
678 // MimeMap, Error and HttpHeader need to be read before the virtual directory and web read
679 hr = ScaMimeMapRead(&psmmList, &pwzCustomActionData);
680 MessageExitOnFailure(hr, msierrIISFailedReadMimeMap, "failed while processing MimeMaps");
681
682 hr = ScaHttpHeaderRead(&pshhList, &pwzCustomActionData);
683 MessageExitOnFailure(hr, msierrIISFailedReadHttpHeader, "failed while processing HttpHeaders");
684
685 hr = ScaWebErrorRead(&psweList, &pwzCustomActionData);
686 MessageExitOnFailure(hr, msierrIISFailedReadWebError, "failed while processing WebErrors");
687
688 hr = WcaBeginUnwrapQuery(&hWebDirPropQuery, &pwzCustomActionData);
689 ExitOnFailure(hr, "Failed to unwrap web dir properties query");
690
691 hr = WcaBeginUnwrapQuery(&hSslCertQuery, &pwzCustomActionData);
692 ExitOnFailure(hr, "Failed to unwrap ssl certificate query");
693
694 hr = WcaBeginUnwrapQuery(&hWebLogQuery, &pwzCustomActionData);
695 ExitOnFailure(hr, "Failed to unwrap web log query");
696
697 hr = WcaBeginUnwrapQuery(&hWebAppQuery, &pwzCustomActionData);
698 ExitOnFailure(hr, "Failed to unwrap web application query");
699
700 hr = WcaBeginUnwrapQuery(&hWebAppExtQuery, &pwzCustomActionData);
701 ExitOnFailure(hr, "Failed to unwrap web application extension query");
702
703 hr = ScaWebsRead7(&pswList, &pshhList, &psweList, hUserQuery, hWebDirPropQuery, hSslCertQuery, hWebLogQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData);
704 MessageExitOnFailure(hr, msierrIISFailedReadWebSite, "failed while processing WebSites");
705
706 hr = WcaBeginUnwrapQuery(&hWebBaseQuery, &pwzCustomActionData);
707 ExitOnFailure(hr, "Failed to unwrap web base query");
708
709 hr = ScaWebDirsRead7(pswList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData, &pswdList);
710 MessageExitOnFailure(hr, msierrIISFailedReadWebDirs, "failed while processing WebDirs");
711
712 hr = ScaVirtualDirsRead7(pswList, &psvdList, &psmmList, &pshhList, &psweList, hUserQuery, hWebBaseQuery, hWebDirPropQuery, hWebAppQuery, hWebAppExtQuery, &pwzCustomActionData);
713 MessageExitOnFailure(hr, msierrIISFailedReadVDirs, "failed while processing WebVirtualDirs");
714
715 hr = ScaFiltersRead7(pswList, hWebBaseQuery, &psfList, &pwzCustomActionData);
716 MessageExitOnFailure(hr, msierrIISFailedReadFilters, "failed while processing WebFilters");
717
718 hr = ScaPropertyRead(&pspList, &pwzCustomActionData);
719 MessageExitOnFailure(hr, msierrIISFailedReadProp, "failed while processing WebProperties");
720
721 // do uninstall actions (order is important!)
722 hr = ScaPropertyUninstall7(pspList);
723 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallProp, "failed to uninstall IIS properties");
724
725 hr = ScaFiltersUninstall7(psfList);
726 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallFilters, "failed to schedule uninstall of filters");
727
728 hr = ScaVirtualDirsUninstall7(psvdList);
729 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallVDirs, "failed to schedule uninstall of virtual directories");
730
731 hr = ScaWebDirsUninstall7(pswdList);
732 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebDirs, "failed to schedule uninstall of web directories");
733
734 hr = ScaWebsUninstall7(pswList);
735 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallWebs, "failed to schedule uninstall of webs");
736
737 hr = ScaAppPoolUninstall7(psapList);
738 MessageExitOnFailure(hr, msierrIISFailedSchedUninstallAppPool, "failed to schedule uninstall of AppPools");
739
740
741 // do install actions (order is important!)
742 // ScaWebSvcExtCommit contains both uninstall and install actions.
743 hr = ScaWebSvcExtCommit7(psWseList);
744 MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebSvcExt, "failed to schedule install/uninstall of WebSvcExt");
745
746 hr = ScaAppPoolInstall7(psapList);
747 MessageExitOnFailure(hr, msierrIISFailedSchedInstallAppPool, "failed to schedule install of AppPools");
748
749 hr = ScaWebsInstall7(pswList, psapList);
750 MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebs, "failed to schedule install of webs");
751
752 hr = ScaWebDirsInstall7(pswdList, psapList);
753 MessageExitOnFailure(hr, msierrIISFailedSchedInstallWebDirs, "failed to schedule install of web directories");
754
755 hr = ScaVirtualDirsInstall7(psvdList, psapList);
756 MessageExitOnFailure(hr, msierrIISFailedSchedInstallVDirs, "failed to schedule install of virtual directories");
757
758 hr = ScaFiltersInstall7(psfList);
759 MessageExitOnFailure(hr, msierrIISFailedSchedInstallFilters, "failed to schedule install of filters");
760
761 hr = ScaPropertyInstall7(pspList);
762 MessageExitOnFailure(hr, msierrIISFailedSchedInstallProp, "failed to schedule install of properties");
763
764 hr = ScaWriteConfigurationScript(pwzScriptKey);
765 ExitOnFailure(hr, "failed to schedule metabase configuration");
766
767LExit:
768 ReleaseNullStr(pwzScriptKey);
769 ReleaseNullStr(pwzCustomActionData);
770
771 WcaFinishUnwrapQuery(hUserQuery);
772 WcaFinishUnwrapQuery(hWebBaseQuery);
773 WcaFinishUnwrapQuery(hWebDirPropQuery);
774 WcaFinishUnwrapQuery(hSslCertQuery);
775 WcaFinishUnwrapQuery(hWebLogQuery);
776 WcaFinishUnwrapQuery(hWebAppQuery);
777 WcaFinishUnwrapQuery(hWebAppExtQuery);
778
779 if (psWseList)
780 {
781 ScaWebSvcExtFreeList(psWseList);
782 }
783
784 if (psfList)
785 {
786 ScaFiltersFreeList(psfList);
787 }
788
789 if (psvdList)
790 {
791 ScaVirtualDirsFreeList7(psvdList);
792 }
793
794 if (pswdList)
795 {
796 ScaWebDirsFreeList7(pswdList);
797 }
798
799 if (pswList)
800 {
801 ScaWebsFreeList7(pswList);
802 }
803
804 if (psmmList)
805 {
806 ScaMimeMapFreeList(psmmList);
807 }
808
809 if (pshhList)
810 {
811 ScaHttpHeaderCheckList(pshhList);
812 ScaHttpHeaderFreeList(pshhList);
813 }
814
815 if (psweList)
816 {
817 ScaWebErrorCheckList(psweList);
818 ScaWebErrorFreeList(psweList);
819 }
820
821 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
822 return WcaFinalize(er);
823}
diff --git a/src/ext/Iis/ca/scassl.cpp b/src/ext/Iis/ca/scassl.cpp
new file mode 100644
index 00000000..4a06b77e
--- /dev/null
+++ b/src/ext/Iis/ca/scassl.cpp
@@ -0,0 +1,115 @@
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
5enum eSslCertificateQuery { scqStoreName = 1, scqHash, scqWeb };
6
7static HRESULT AddSslCertificateToList(
8 __in SCA_WEB_SSL_CERTIFICATE** ppswscList
9 );
10
11
12HRESULT ScaSslCertificateRead(
13 __in LPCWSTR wzWebId,
14 __in WCA_WRAPQUERY_HANDLE hSslCertQuery,
15 __inout SCA_WEB_SSL_CERTIFICATE** ppswscList
16 )
17{
18 HRESULT hr = S_OK;
19
20 MSIHANDLE hRec;
21 SCA_WEB_SSL_CERTIFICATE* pswsc = NULL;
22 LPWSTR pwzData = NULL;
23
24 WcaFetchWrappedReset(hSslCertQuery);
25
26 // Get the certificate information.
27 while (S_OK == (hr = WcaFetchWrappedRecordWhereString(hSslCertQuery, scqWeb, wzWebId, &hRec)))
28 {
29 hr = AddSslCertificateToList(ppswscList);
30 ExitOnFailure(hr, "failed to add ssl certificate to list");
31
32 pswsc = *ppswscList;
33
34 hr = WcaGetRecordString(hRec, scqStoreName, &pwzData);
35 ExitOnFailure(hr, "Failed to get web ssl certificate store name.");
36
37 hr = ::StringCchCopyW(pswsc->wzStoreName, countof(pswsc->wzStoreName), pwzData);
38 ExitOnFailure(hr, "Failed to copy web ssl certificate store name.");
39
40 hr = WcaGetRecordString(hRec, scqHash, &pwzData);
41 ExitOnFailure(hr, "Failed to get hash for web ssl certificate.");
42
43 hr = StrHexDecode(pwzData, pswsc->rgbSHA1Hash, countof(pswsc->rgbSHA1Hash));
44 ExitOnFailure(hr, "Failed to decode certificate hash for web: %ls, data: %ls", wzWebId, pwzData);
45 }
46
47 if (E_NOMOREITEMS == hr)
48 {
49 hr = S_OK;
50 }
51 ExitOnFailure(hr, "Failed to read IIsWebSiteCertificates table.");
52
53LExit:
54 ReleaseStr(pwzData);
55 return hr;
56}
57
58
59HRESULT ScaSslCertificateWriteMetabase(
60 __in IMSAdminBase* piMetabase,
61 __in LPCWSTR wzWebBase,
62 __in SCA_WEB_SSL_CERTIFICATE* pswscList
63 )
64{
65 HRESULT hr = S_OK;
66 BLOB blob;
67
68 for (SCA_WEB_SSL_CERTIFICATE* pswsc = pswscList; pswsc; pswsc = pswsc->pNext)
69 {
70 // Write: /W3SVC/1:SslCertStoreName = "MY", "CA", "Root", etc.
71 hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_SSL_CERT_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, static_cast<LPVOID>(pswsc->wzStoreName));
72 ExitOnFailure(hr, "Failed to write SslCertStoreName");
73
74 // Write: /W3SVC/1:SslCertHash = <blob>
75 blob.pBlobData = pswsc->rgbSHA1Hash;
76 blob.cbSize = countof(pswsc->rgbSHA1Hash);
77 hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_SSL_CERT_HASH, METADATA_INHERIT, IIS_MD_UT_SERVER, BINARY_METADATA, static_cast<LPVOID>(&blob));
78 ExitOnFailure(hr, "Failed to write SslCertHash");
79 }
80
81LExit:
82 return hr;
83}
84
85
86void ScaSslCertificateFreeList(
87 __in SCA_WEB_SSL_CERTIFICATE* pswscList
88 )
89{
90 SCA_WEB_SSL_CERTIFICATE* pswscDelete = pswscList;
91 while (pswscList)
92 {
93 pswscDelete = pswscList;
94 pswscList = pswscList->pNext;
95
96 MemFree(pswscDelete);
97 }
98}
99
100
101static HRESULT AddSslCertificateToList(
102 __in SCA_WEB_SSL_CERTIFICATE** ppswscList
103 )
104{
105 HRESULT hr = S_OK;
106
107 SCA_WEB_SSL_CERTIFICATE* pswsc = static_cast<SCA_WEB_SSL_CERTIFICATE*>(MemAlloc(sizeof(SCA_WEB_SSL_CERTIFICATE), TRUE));
108 ExitOnNull(pswsc, hr, E_OUTOFMEMORY, "failed to allocate memory for new SSL certificate list element");
109
110 pswsc->pNext = *ppswscList;
111 *ppswscList = pswsc;
112
113LExit:
114 return hr;
115}
diff --git a/src/ext/Iis/ca/scassl.h b/src/ext/Iis/ca/scassl.h
new file mode 100644
index 00000000..df7c473d
--- /dev/null
+++ b/src/ext/Iis/ca/scassl.h
@@ -0,0 +1,36 @@
1#pragma once
2// 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.
3
4
5#define MD_SSL_CERT_HASH ( IIS_MD_SSL_BASE+6 )
6#define MD_SSL_CERT_STORE_NAME ( IIS_MD_SSL_BASE+11 )
7//#define WIDE(x) WIDE2(x)
8//#define WIDE2(x) L ## x
9
10
11// structs
12struct SCA_WEB_SSL_CERTIFICATE
13{
14 WCHAR wzStoreName[65];
15 BYTE rgbSHA1Hash[CB_CERTIFICATE_HASH];
16
17 SCA_WEB_SSL_CERTIFICATE* pNext;
18};
19
20
21// prototypes
22HRESULT ScaSslCertificateRead(
23 __in LPCWSTR wzWebId,
24 __in WCA_WRAPQUERY_HANDLE hSslCertQuery,
25 __inout SCA_WEB_SSL_CERTIFICATE** ppswscList
26 );
27
28HRESULT ScaSslCertificateWriteMetabase(
29 __in IMSAdminBase* piMetabase,
30 __in LPCWSTR wzWebBase,
31 __in SCA_WEB_SSL_CERTIFICATE* pswscList
32 );
33
34void ScaSslCertificateFreeList(
35 __in SCA_WEB_SSL_CERTIFICATE* pswscList
36 );
diff --git a/src/ext/Iis/ca/scassl7.cpp b/src/ext/Iis/ca/scassl7.cpp
new file mode 100644
index 00000000..47c16a9d
--- /dev/null
+++ b/src/ext/Iis/ca/scassl7.cpp
@@ -0,0 +1,34 @@
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
5HRESULT ScaSslCertificateWrite7(
6 __in_z LPCWSTR wzWebBase,
7 __in SCA_WEB_SSL_CERTIFICATE* pswscList
8 )
9{
10 HRESULT hr = S_OK;
11 WCHAR wzEncodedCertificateHash[CB_CERTIFICATE_HASH * 2 + 1] = { 0 };
12
13 for (SCA_WEB_SSL_CERTIFICATE* pswsc = pswscList; pswsc; pswsc = pswsc->pNext)
14 {
15 hr = ScaWriteConfigID(IIS_SSL_BINDING);
16 ExitOnFailure(hr, "Failed write SSL binding ID");
17 hr = ScaWriteConfigID(IIS_CREATE); // Need to determine site action
18 ExitOnFailure(hr, "Failed write binding action");
19
20 hr = ScaWriteConfigString(wzWebBase); //site name key
21 ExitOnFailure(hr, "Failed to write SSL website");
22 hr = ScaWriteConfigString(pswsc->wzStoreName); //ssl store name
23 ExitOnFailure(hr, "Failed to write SSL store name");
24
25 hr = StrHexEncode(pswsc->rgbSHA1Hash, countof(pswsc->rgbSHA1Hash), wzEncodedCertificateHash, countof(wzEncodedCertificateHash));
26 ExitOnFailure(hr, "Failed to encode SSL hash");
27
28 hr = ScaWriteConfigString(wzEncodedCertificateHash); //ssl hash
29 ExitOnFailure(hr, "Failed to write SSL hash");
30 }
31LExit:
32
33 return hr;
34}
diff --git a/src/ext/Iis/ca/scassl7.h b/src/ext/Iis/ca/scassl7.h
new file mode 100644
index 00000000..1a4b09af
--- /dev/null
+++ b/src/ext/Iis/ca/scassl7.h
@@ -0,0 +1,8 @@
1#pragma once
2// 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.
3
4
5HRESULT ScaSslCertificateWrite7(
6 __in_z LPCWSTR wzWebBase,
7 __in SCA_WEB_SSL_CERTIFICATE* pswscList
8 );
diff --git a/src/ext/Iis/ca/scauser.cpp b/src/ext/Iis/ca/scauser.cpp
new file mode 100644
index 00000000..0b99edff
--- /dev/null
+++ b/src/ext/Iis/ca/scauser.cpp
@@ -0,0 +1,91 @@
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
5LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Password` FROM `User` WHERE `User`=?";
6enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqPassword };
7
8LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Group` WHERE `Group`=?";
9enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain };
10
11LPCWSTR vcsUserGroupQuery = L"SELECT `User_`, `Group_` FROM `UserGroup` WHERE `User_`=?";
12enum eUserGroupQuery { vugqUser = 1, vugqGroup };
13
14LPCWSTR vActionableQuery = L"SELECT `User`,`Component_`,`Name`,`Domain`,`Password`,`Attributes` FROM `User` WHERE `Component_` IS NOT NULL";
15enum eActionableQuery { vaqUser = 1, vaqComponent, vaqName, vaqDomain, vaqPassword, vaqAttributes };
16
17HRESULT __stdcall ScaGetUserDeferred(
18 __in LPCWSTR wzUser,
19 __in WCA_WRAPQUERY_HANDLE hUserQuery,
20 __out SCA_USER* pscau
21 )
22{
23 if (!wzUser || !pscau)
24 {
25 return E_INVALIDARG;
26 }
27
28 HRESULT hr = S_OK;
29 MSIHANDLE hRec, hRecTest;
30
31 LPWSTR pwzData = NULL;
32
33 // clear struct and bail right away if no user key was passed to search for
34 ::ZeroMemory(pscau, sizeof(*pscau));
35 if (!*wzUser)
36 {
37 ExitFunction1(hr = S_OK);
38 }
39
40 // Reset back to the first record
41 WcaFetchWrappedReset(hUserQuery);
42
43 hr = WcaFetchWrappedRecordWhereString(hUserQuery, vuqUser, wzUser, &hRec);
44 if (S_OK == hr)
45 {
46 hr = WcaFetchWrappedRecordWhereString(hUserQuery, vuqUser, wzUser, &hRecTest);
47 if (S_OK == hr)
48 {
49 AssertSz(FALSE, "Found multiple matching User rows");
50 }
51
52 hr = WcaGetRecordString(hRec, vuqUser, &pwzData);
53 ExitOnFailure(hr, "Failed to get User.User");
54 hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData);
55 ExitOnFailure(hr, "Failed to copy key string to user object (in deferred CA)");
56
57 hr = WcaGetRecordString(hRec, vuqComponent, &pwzData);
58 ExitOnFailure(hr, "Failed to get User.Component_");
59 hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData);
60 ExitOnFailure(hr, "Failed to copy component string to user object (in deferred CA)");
61
62 hr = WcaGetRecordString(hRec, vuqName, &pwzData);
63 ExitOnFailure(hr, "Failed to get User.Name");
64 hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData);
65 ExitOnFailure(hr, "Failed to copy name string to user object (in deferred CA)");
66
67 hr = WcaGetRecordString(hRec, vuqDomain, &pwzData);
68 ExitOnFailure(hr, "Failed to get User.Domain");
69 hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData);
70 ExitOnFailure(hr, "Failed to copy domain string to user object (in deferred CA)");
71
72 hr = WcaGetRecordString(hRec, vuqPassword, &pwzData);
73 ExitOnFailure(hr, "Failed to get User.Password");
74 hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData);
75 ExitOnFailure(hr, "Failed to copy password string to user object (in deferred CA)");
76 }
77 else if (E_NOMOREITEMS == hr)
78 {
79 WcaLog(LOGMSG_STANDARD, "Error: Cannot locate User.User='%ls'", wzUser);
80 hr = E_FAIL;
81 }
82 else
83 {
84 ExitOnFailure(hr, "Error fetching single User row");
85 }
86
87LExit:
88 ReleaseStr(pwzData);
89
90 return hr;
91}
diff --git a/src/ext/Iis/ca/scauser.h b/src/ext/Iis/ca/scauser.h
new file mode 100644
index 00000000..b2b94650
--- /dev/null
+++ b/src/ext/Iis/ca/scauser.h
@@ -0,0 +1,39 @@
1#pragma once
2// 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.
3
4// structs
5struct SCA_GROUP
6{
7 WCHAR wzKey[MAX_DARWIN_KEY + 1];
8 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
9
10 WCHAR wzDomain[MAX_DARWIN_COLUMN + 1];
11 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
12
13 SCA_GROUP *psgNext;
14};
15
16struct SCA_USER
17{
18 WCHAR wzKey[MAX_DARWIN_KEY + 1];
19 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
20 INSTALLSTATE isInstalled;
21 INSTALLSTATE isAction;
22
23 WCHAR wzDomain[MAX_DARWIN_COLUMN + 1];
24 WCHAR wzName[MAX_DARWIN_COLUMN + 1];
25 WCHAR wzPassword[MAX_DARWIN_COLUMN + 1];
26 INT iAttributes;
27
28 SCA_GROUP *psgGroups;
29
30 SCA_USER *psuNext;
31};
32
33
34// prototypes
35HRESULT __stdcall ScaGetUserDeferred(
36 __in LPCWSTR wzUser,
37 __in WCA_WRAPQUERY_HANDLE hUserQuery,
38 __out SCA_USER* pscau
39 );
diff --git a/src/ext/Iis/ca/scavdir.cpp b/src/ext/Iis/ca/scavdir.cpp
new file mode 100644
index 00000000..d388ce97
--- /dev/null
+++ b/src/ext/Iis/ca/scavdir.cpp
@@ -0,0 +1,331 @@
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 AddVirtualDirToList(
7 __in SCA_VDIR** psvdList
8 );
9
10
11HRESULT __stdcall ScaVirtualDirsRead(
12 __in IMSAdminBase* piMetabase,
13 __in SCA_WEB* pswList,
14 __in SCA_VDIR** ppsvdList,
15 __in SCA_MIMEMAP** ppsmmList,
16 __in SCA_HTTP_HEADER** ppshhList,
17 __in SCA_WEB_ERROR** ppsweList,
18 __in WCA_WRAPQUERY_HANDLE hUserQuery,
19 __in WCA_WRAPQUERY_HANDLE hWebBaseQuery,
20 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
21 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
22 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
23 __inout LPWSTR *ppwzCustomActionData
24 )
25{
26 Assert(piMetabase && ppsvdList);
27
28 HRESULT hr = S_OK;
29 MSIHANDLE hRec;
30 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
31 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
32
33 SCA_VDIR* pvdir = NULL;
34 LPWSTR pwzData = NULL;
35
36 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
37
38 hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
39 ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead");
40
41 if (0 == WcaGetQueryRecords(hWrapQuery))
42 {
43 WcaLog(LOGMSG_VERBOSE, "Skipping ScaVirtualDirsRead() because IIsWebVirtualDir table not present");
44 ExitFunction1(hr = S_FALSE);
45 }
46
47 // loop through all the vdirs
48 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
49 {
50 // Get the Component first. If there is a Component and it is not being modified during
51 // this transaction, skip processing this whole record.
52 hr = WcaGetRecordString(hRec, vdqComponent, &pwzData);
53 ExitOnFailure(hr, "failed to get IIsWebVirtualDir.Component");
54
55 hr = WcaGetRecordInteger(hRec, vdqInstalled, (int *)&isInstalled);
56 ExitOnFailure(hr, "Failed to get Component installed state for virtual dir");
57
58 hr = WcaGetRecordInteger(hRec, vdqAction, (int *)&isAction);
59 ExitOnFailure(hr, "Failed to get Component action state for virtual dir");
60
61 if (!WcaIsInstalling(isInstalled, isAction) &&
62 !WcaIsReInstalling(isInstalled, isAction) &&
63 !WcaIsUninstalling(isInstalled, isAction))
64 {
65 continue; // skip this record.
66 }
67
68 hr = AddVirtualDirToList(ppsvdList);
69 ExitOnFailure(hr, "failed to add virtual dir to list");
70
71 pvdir = *ppsvdList;
72
73 hr = ::StringCchCopyW(pvdir->wzComponent, countof(pvdir->wzComponent), pwzData);
74 ExitOnFailure(hr, "failed to copy component name: %ls", pwzData);
75
76 pvdir->isInstalled = isInstalled;
77 pvdir->isAction = isAction;
78
79 // get the web key
80 hr = WcaGetRecordString(hRec, vdqWeb, &pwzData);
81 ExitOnFailure(hr, "Failed to get Web for VirtualDir");
82
83 hr = ScaWebsGetBase(piMetabase, pswList, pwzData, pvdir->wzWebBase, countof(pvdir->wzWebBase), hWebBaseQuery);
84 if (WcaIsUninstalling(isInstalled, isAction))
85 {
86 // If we're uninstalling, ignore any failure to find the existing web
87 hr = S_OK;
88 }
89 ExitOnFailure(hr, "Failed to get base of web: %ls for VirtualDir", pwzData);
90
91 hr = WcaGetRecordString(hRec, vdqAlias, &pwzData);
92 ExitOnFailure(hr, "Failed to get Alias for VirtualDir");
93
94 if (0 != lstrlenW(pvdir->wzWebBase))
95 {
96 hr = ::StringCchPrintfW(pvdir->wzVDirRoot, countof(pvdir->wzVDirRoot), L"%s/Root/%s", pvdir->wzWebBase, pwzData);
97 ExitOnFailure(hr, "Failed to set VDirRoot for VirtualDir");
98 }
99
100 // get the vdir's directory
101 hr = WcaGetRecordString(hRec, vdqDirectory, &pwzData);
102 ExitOnFailure(hr, "Failed to get Directory for VirtualDir");
103
104 // get the web's directory
105 if (INSTALLSTATE_SOURCE == pvdir->isAction)
106 {
107 hr = WcaGetRecordString(hRec, vdqSourcePath, &pwzData);
108 }
109 else
110 {
111 hr = WcaGetRecordString(hRec, vdqTargetPath, &pwzData);
112 }
113 ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory");
114
115 // remove trailing backslash(es)
116 while (lstrlenW(pwzData) > 0 && pwzData[lstrlenW(pwzData)-1] == L'\\')
117 {
118 pwzData[lstrlenW(pwzData)-1] = 0;
119 }
120 hr = ::StringCchCopyW(pvdir->wzDirectory, countof(pvdir->wzDirectory), pwzData);
121 ExitOnFailure(hr, "Failed to copy directory string to vdir object");
122
123 // get the security information for this web
124 hr = WcaGetRecordString(hRec, vdqProperties, &pwzData);
125 ExitOnFailure(hr, "Failed to get web directory identifier for VirtualDir");
126 if (*pwzData)
127 {
128 hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &pvdir->swp);
129 ExitOnFailure(hr, "Failed to get web directory for VirtualDir");
130
131 pvdir->fHasProperties = TRUE;
132 }
133
134 // get the application information for this web
135 hr = WcaGetRecordString(hRec, vdqApplication, &pwzData);
136 ExitOnFailure(hr, "Failed to get application identifier for VirtualDir");
137 if (*pwzData)
138 {
139 hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &pvdir->swapp);
140 ExitOnFailure(hr, "Failed to get application for VirtualDir");
141
142 pvdir->fHasApplication = TRUE;
143 }
144
145 hr = WcaGetRecordString(hRec, vdqVDir, &pwzData);
146 ExitOnFailure(hr, "Failed to get VDir for VirtualDir");
147
148 if (*pwzData && *ppsmmList)
149 {
150 hr = ScaGetMimeMap(mmptVDir, pwzData, ppsmmList, &pvdir->psmm);
151 ExitOnFailure(hr, "Failed to get mimemap for VirtualDir");
152 }
153
154 if (*pwzData && *ppshhList)
155 {
156 hr = ScaGetHttpHeader(hhptVDir, pwzData, ppshhList, &pvdir->pshh);
157 ExitOnFailure(hr, "Failed to get custom HTTP headers for VirtualDir: %ls", pwzData);
158 }
159
160 if (*pwzData && *ppsweList)
161 {
162 hr = ScaGetWebError(weptVDir, pwzData, ppsweList, &pvdir->pswe);
163 ExitOnFailure(hr, "Failed to get custom web errors for VirtualDir: %ls", pwzData);
164 }
165 }
166
167 if (E_NOMOREITEMS == hr)
168 {
169 hr = S_OK;
170 }
171 ExitOnFailure(hr, "Failure while processing VirtualDirs");
172
173LExit:
174 WcaFinishUnwrapQuery(hWrapQuery);
175
176 ReleaseStr(pwzData);
177 return hr;
178}
179
180
181HRESULT ScaVirtualDirsInstall(
182 __in IMSAdminBase* piMetabase,
183 __in SCA_VDIR* psvdList,
184 __in SCA_APPPOOL * psapList
185 )
186{
187 Assert(piMetabase);
188
189 HRESULT hr = S_OK;
190 SCA_VDIR* psvd = psvdList;
191 int i;
192
193 while (psvd)
194 {
195 // On reinstall, we have to uninstall the old application, otherwise a duplicate will be created
196 if (WcaIsReInstalling(psvd->isInstalled, psvd->isAction))
197 {
198 if (psvd->fHasApplication)
199 {
200 hr = ScaDeleteApp(piMetabase, psvd->wzVDirRoot);
201 ExitOnFailure(hr, "Failed to remove application for WebVDir as part of a reinstall");
202 }
203 }
204
205 if (WcaIsInstalling(psvd->isInstalled, psvd->isAction))
206 {
207 hr = ScaCreateMetabaseKey(piMetabase, psvd->wzVDirRoot, L"");
208 ExitOnFailure(hr, "Failed to create key for VirtualDir");
209 hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsWebVirtualDir");
210 ExitOnFailure(hr, "Failed to write key type for for VirtualDir");
211 i = 0x4000003e; // 1073741886; // default directory browsing rights
212 hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)i));
213 ExitOnFailure(hr, "Failed to set directory browsing for VirtualDir");
214
215 hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)psvd->wzDirectory);
216 ExitOnFailure(hr, "Failed to write Directory for VirtualDir");
217
218 if (psvd->fHasProperties)
219 {
220 ScaWriteWebDirProperties(piMetabase, psvd->wzVDirRoot, &psvd->swp);
221 ExitOnFailure(hr, "Failed to write directory properties for VirtualDir");
222 }
223
224 if (psvd->fHasApplication)
225 {
226 hr = ScaWriteWebApplication(piMetabase, psvd->wzVDirRoot, &psvd->swapp, psapList);
227 ExitOnFailure(hr, "Failed to write application for VirtualDir");
228 }
229
230 if (psvd->psmm)
231 {
232 hr = ScaWriteMimeMap(piMetabase, psvd->wzVDirRoot, psvd->psmm);
233 ExitOnFailure(hr, "Failed to write mimemap for VirtualDir");
234 }
235
236 if (psvd->pshh)
237 {
238 hr = ScaWriteHttpHeader(piMetabase, psvd->wzVDirRoot, psvd->pshh);
239 ExitOnFailure(hr, "Failed to write custom HTTP headers for VirtualDir");
240 }
241
242 if (psvd->pswe)
243 {
244 hr = ScaWriteWebError(piMetabase, weptVDir, psvd->wzVDirRoot, psvd->pswe);
245 ExitOnFailure(hr, "Failed to write custom web errors for VirtualDir");
246 }
247 }
248
249 psvd = psvd->psvdNext;
250 }
251
252LExit:
253 return hr;
254}
255
256
257HRESULT ScaVirtualDirsUninstall(
258 __in IMSAdminBase* piMetabase,
259 __in SCA_VDIR* psvdList
260 )
261{
262 Assert(piMetabase);
263
264 HRESULT hr = S_OK;
265 SCA_VDIR* psvd = psvdList;
266
267 while (psvd)
268 {
269 if (WcaIsUninstalling(psvd->isInstalled, psvd->isAction))
270 {
271 // delete the application for this virtual directory
272 if (psvd->fHasApplication)
273 {
274 hr = ScaDeleteApp(piMetabase, psvd->wzVDirRoot);
275 ExitOnFailure(hr, "Failed to remove application for WebVDir");
276 }
277
278 if (0 != lstrlenW(psvd->wzVDirRoot))
279 {
280 hr = ScaDeleteMetabaseKey(piMetabase, psvd->wzVDirRoot, L"");
281 ExitOnFailure(hr, "Failed to remove VirtualDir '%ls' from metabase", psvd->wzKey);
282 }
283 }
284
285 psvd = psvd->psvdNext;
286 }
287
288LExit:
289 return hr;
290}
291
292
293void ScaVirtualDirsFreeList(
294 __in SCA_VDIR* psvdList
295 )
296{
297 SCA_VDIR* psvdDelete = psvdList;
298 while (psvdList)
299 {
300 psvdDelete = psvdList;
301 psvdList = psvdList->psvdNext;
302
303 if (psvdDelete->psmm)
304 {
305 ScaMimeMapFreeList(psvdDelete->psmm);
306 }
307
308 if (psvdDelete->pswe)
309 {
310 ScaWebErrorFreeList(psvdDelete->pswe);
311 }
312
313 MemFree(psvdDelete);
314 }
315}
316
317
318static HRESULT AddVirtualDirToList(
319 __in SCA_VDIR** ppsvdList
320 )
321{
322 HRESULT hr = S_OK;
323 SCA_VDIR* psvd = static_cast<SCA_VDIR*>(MemAlloc(sizeof(SCA_VDIR), TRUE));
324 ExitOnNull(psvd, hr, E_OUTOFMEMORY, "failed to allocate memory for new vdir list element");
325
326 psvd->psvdNext= *ppsvdList;
327 *ppsvdList = psvd;
328
329LExit:
330 return hr;
331}
diff --git a/src/ext/Iis/ca/scavdir.h b/src/ext/Iis/ca/scavdir.h
new file mode 100644
index 00000000..c7e9661b
--- /dev/null
+++ b/src/ext/Iis/ca/scavdir.h
@@ -0,0 +1,71 @@
1#pragma once
2// 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.
3
4
5#include "scawebprop.h"
6#include "scawebapp.h"
7#include "scamimemap.h"
8#include "scaapppool.h"
9
10enum eVDirQuery { vdqWeb = 1, vdqVDir, vdqComponent , vdqAlias, vdqDirectory, vdqProperties, vdqApplication, vdqInstalled, vdqAction, vdqSourcePath, vdqTargetPath };
11
12struct SCA_VDIR
13{
14 // darwin information
15 WCHAR wzKey[MAX_DARWIN_KEY + 1];
16 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
17 INSTALLSTATE isInstalled;
18 INSTALLSTATE isAction;
19
20 // metabase information
21 WCHAR wzWebKey[MAX_DARWIN_KEY + 1];
22 WCHAR wzWebBase[METADATA_MAX_NAME_LEN + 1];
23 WCHAR wzVDirRoot[METADATA_MAX_NAME_LEN + 1];
24
25 // iis configuation information
26 WCHAR wzDirectory[MAX_PATH];
27
28 BOOL fHasProperties;
29 SCA_WEB_PROPERTIES swp;
30
31 BOOL fHasApplication;
32 SCA_WEB_APPLICATION swapp;
33
34 SCA_MIMEMAP* psmm; // mime mappings
35 SCA_HTTP_HEADER* pshh; // custom web errors
36 SCA_WEB_ERROR* pswe; // custom web errors
37
38 SCA_VDIR* psvdNext;
39};
40
41
42// prototypes
43HRESULT __stdcall ScaVirtualDirsRead(
44 __in IMSAdminBase* piMetabase,
45 __in SCA_WEB* pswList,
46 __in SCA_VDIR** ppsvdList,
47 __in SCA_MIMEMAP** ppsmmList,
48 __in SCA_HTTP_HEADER** ppshhList,
49 __in SCA_WEB_ERROR** ppsweList,
50 __in WCA_WRAPQUERY_HANDLE hUserQuery,
51 __in WCA_WRAPQUERY_HANDLE hWebBaseQuery,
52 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
53 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
54 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
55 __inout LPWSTR *ppwzCustomActionData
56 );
57
58HRESULT ScaVirtualDirsInstall(
59 __in IMSAdminBase* piMetabase,
60 __in SCA_VDIR* psvdList,
61 __in SCA_APPPOOL * psapList
62 );
63
64HRESULT ScaVirtualDirsUninstall(
65 __in IMSAdminBase* piMetabase,
66 __in SCA_VDIR* psvdList
67 );
68
69void ScaVirtualDirsFreeList(
70 __in SCA_VDIR* psvdList
71 );
diff --git a/src/ext/Iis/ca/scavdir7.cpp b/src/ext/Iis/ca/scavdir7.cpp
new file mode 100644
index 00000000..3f675357
--- /dev/null
+++ b/src/ext/Iis/ca/scavdir7.cpp
@@ -0,0 +1,380 @@
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 AddVirtualDirToList7(
7 __in SCA_VDIR7** psvdList
8 );
9
10
11HRESULT __stdcall ScaVirtualDirsRead7(
12 __in SCA_WEB7* pswList,
13 __in SCA_VDIR7** ppsvdList,
14 __in SCA_MIMEMAP** ppsmmList,
15 __in SCA_HTTP_HEADER** ppshhList,
16 __in SCA_WEB_ERROR** ppsweList,
17 __in WCA_WRAPQUERY_HANDLE hUserQuery,
18 __in WCA_WRAPQUERY_HANDLE /*hWebBaseQuery*/,
19 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
20 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
21 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
22 __inout LPWSTR *ppwzCustomActionData
23 )
24{
25 Assert(ppsvdList);
26
27 HRESULT hr = S_OK;
28 MSIHANDLE hRec;
29
30 SCA_VDIR7* pvdir = NULL;
31 LPWSTR pwzData = NULL;
32 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
33
34 hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
35 ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead");
36
37 if (0 == WcaGetQueryRecords(hWrapQuery))
38 {
39 WcaLog(LOGMSG_VERBOSE, "Skipping ScaVirtualDirsRead() because IIsWebVirtualDir table not present");
40 ExitFunction1(hr = S_FALSE);
41 }
42
43 // loop through all the vdirs
44 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
45 {
46 // Add this record's information into the list of things to process.
47 hr = AddVirtualDirToList7(ppsvdList);
48 ExitOnFailure(hr, "failed to add vdir to vdir list");
49
50 pvdir = *ppsvdList;
51
52 // get the darwin information
53 hr = WcaGetRecordString(hRec, vdqComponent, &pwzData);
54 ExitOnFailure(hr, "failed to get IIsWebVirtualDir.Component");
55
56 hr = WcaGetRecordInteger(hRec, vdqInstalled, (int *)&pvdir->isInstalled);
57 ExitOnFailure(hr, "Failed to get Component installed state for virtual dir");
58
59 hr = WcaGetRecordInteger(hRec, vdqAction, (int *)&pvdir->isAction);
60 ExitOnFailure(hr, "Failed to get Component action state for virtual dir");
61
62 // get vdir properties
63 hr = ::StringCchCopyW(pvdir->wzComponent, countof(pvdir->wzComponent), pwzData);
64 ExitOnFailure(hr, "failed to copy vdir component name: %ls", pwzData);
65
66 hr = WcaGetRecordString(hRec, vdqWeb, &pwzData);
67 ExitOnFailure(hr, "Failed to get Web for VirtualDir");
68
69 hr = ScaWebsGetBase7(pswList, pwzData, pvdir->wzWebName , countof(pvdir->wzWebName));
70 if (S_FALSE == hr)
71 {
72 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
73 ExitOnFailure(hr, "Failed to get Web Base for VirtualDir");
74 }
75 if (WcaIsUninstalling(pvdir->isInstalled, pvdir->isAction))
76 {
77 // If we're uninstalling, ignore any failure to find the existing web
78 hr = S_OK;
79 }
80
81 hr = WcaGetRecordString(hRec, vdqAlias, &pwzData);
82 ExitOnFailure(hr, "Failed to get Alias for VirtualDir");
83
84 hr = ::StringCchCopyW(pvdir->wzVDirRoot, countof(pvdir->wzVDirRoot), pwzData);
85 ExitOnFailure(hr, "Failed to set VDirRoot for VirtualDir");
86
87 // get the vdir's directory
88 hr = WcaGetRecordString(hRec, vdqDirectory, &pwzData);
89 ExitOnFailure(hr, "Failed to get Directory for VirtualDir");
90
91 // get the web's directory
92 if (INSTALLSTATE_SOURCE == pvdir->isAction)
93 {
94 hr = WcaGetRecordString(hRec, vdqSourcePath, &pwzData);
95 }
96 else
97 {
98 hr = WcaGetRecordString(hRec, vdqTargetPath, &pwzData);
99 }
100 ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory");
101
102 // remove trailing backslash(es)
103 while (lstrlenW(pwzData) > 0 && pwzData[lstrlenW(pwzData)-1] == L'\\')
104 {
105 pwzData[lstrlenW(pwzData)-1] = 0;
106 }
107 hr = ::StringCchCopyW(pvdir->wzDirectory, countof(pvdir->wzDirectory), pwzData);
108 ExitOnFailure(hr, "Failed to copy directory string to vdir object");
109
110 // get the security information for this web
111 hr = WcaGetRecordString(hRec, vdqProperties, &pwzData);
112 ExitOnFailure(hr, "Failed to get web directory identifier for VirtualDir");
113 if (*pwzData)
114 {
115 hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &pvdir->swp);
116 ExitOnFailure(hr, "Failed to get web directory for VirtualDir");
117
118 pvdir->fHasProperties = TRUE;
119 }
120
121 // get the application information for this web
122 hr = WcaGetRecordString(hRec, vdqApplication, &pwzData);
123 ExitOnFailure(hr, "Failed to get application identifier for VirtualDir");
124 if (*pwzData)
125 {
126 hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &pvdir->swapp);
127 ExitOnFailure(hr, "Failed to get application for VirtualDir");
128
129 pvdir->fHasApplication = TRUE;
130 }
131
132 hr = WcaGetRecordString(hRec, vdqVDir, &pwzData);
133 ExitOnFailure(hr, "Failed to get VDir for VirtualDir");
134
135 if (*pwzData && *ppsmmList)
136 {
137 hr = ScaGetMimeMap(mmptVDir, pwzData, ppsmmList, &pvdir->psmm);
138 ExitOnFailure(hr, "Failed to get mimemap for VirtualDir");
139 }
140
141 if (*pwzData && *ppshhList)
142 {
143 hr = ScaGetHttpHeader(hhptVDir, pwzData, ppshhList, &pvdir->pshh);
144 ExitOnFailure(hr, "Failed to get custom HTTP headers for VirtualDir: %ls", pwzData);
145 }
146
147 if (*pwzData && *ppsweList)
148 {
149 hr = ScaGetWebError(weptVDir, pwzData, ppsweList, &pvdir->pswe);
150 ExitOnFailure(hr, "Failed to get custom web errors for VirtualDir: %ls", pwzData);
151 }
152 }
153
154 if (E_NOMOREITEMS == hr)
155 {
156 hr = S_OK;
157 }
158 ExitOnFailure(hr, "Failure while processing VirtualDirs");
159
160LExit:
161 WcaFinishUnwrapQuery(hWrapQuery);
162
163 ReleaseStr(pwzData);
164
165 return hr;
166}
167
168
169HRESULT ScaVirtualDirsInstall7(
170 __in SCA_VDIR7* psvdList,
171 __in SCA_APPPOOL * psapList
172 )
173{
174 HRESULT hr = S_OK;
175 SCA_VDIR7* psvd = psvdList;
176 LPWSTR wzPath = NULL;
177 WCHAR wzAppPoolName[MAX_PATH];
178 while (psvd)
179 {
180 if (WcaIsInstalling(psvd->isInstalled, psvd->isAction))
181 {
182 // First write all applications, this is necessary since vdirs must be nested under the applications.
183 if (psvd->fHasApplication)
184 {
185 //create the application for this vdir application
186 hr = ScaWriteConfigID(IIS_APPLICATION);
187 ExitOnFailure(hr, "Failed to write app ID");
188 hr = ScaWriteConfigID(IIS_CREATE);
189 ExitOnFailure(hr, "Failed to write app action");
190#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
191 hr = ScaWriteConfigString(psvd->wzWebName); //site name key
192 ExitOnFailure(hr, "Failed to write app web key");
193 hr = StrAllocFormatted(&wzPath, L"/%s", psvd->wzVDirRoot);
194 ExitOnFailure(hr, "Failed to create app path");
195 hr = ScaWriteConfigString(wzPath); // App Path
196 ExitOnFailure(hr, "Failed to write app path root ");
197
198 if (!*psvd->swapp.wzAppPool)
199 {
200 //This Application goes in default appPool
201 hr = ScaWriteConfigString(L""); // App Pool
202 }
203 else
204 {
205 //get apppool from WebApplication
206#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
207 hr = ScaFindAppPool7(psvd->swapp.wzAppPool, wzAppPoolName, countof(wzAppPoolName), psapList);
208 ExitOnFailure(hr, "Failed to read app pool from application");
209 hr = ScaWriteConfigString(wzAppPoolName); // App Pool
210 ExitOnFailure(hr, "Failed to write appPool for vdir");
211
212 }
213 }
214 }
215
216 psvd = psvd->psvdNext;
217 }
218
219 // Reset our linked list and write all the VDirs
220 psvd = psvdList;
221 while (psvd)
222 {
223 if (WcaIsInstalling(psvd->isInstalled, psvd->isAction))
224 {
225 //create the Vdir
226 hr = ScaWriteConfigID(IIS_VDIR);
227 ExitOnFailure(hr, "Failed write VirDir ID")
228 hr = ScaWriteConfigID(IIS_CREATE);
229 ExitOnFailure(hr, "Failed write VirDir action")
230#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
231 hr = ScaWriteConfigString(psvd->wzWebName); //site name key
232 ExitOnFailure(hr, "Failed write VirDir web name");
233 hr = StrAllocFormatted(&wzPath, L"/%s", psvd->wzVDirRoot);
234 ExitOnFailure(hr, "Failed to create vdir path");
235 hr = ScaWriteConfigString(wzPath); //vdir path
236 ExitOnFailure(hr, "Failed write VirDir path")
237#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
238 hr = ScaWriteConfigString(psvd->wzDirectory); //physical dir
239 ExitOnFailure(hr, "Failed write VirDir dir");
240
241 if (psvd->fHasProperties)
242 {
243 ScaWriteWebDirProperties7(psvd->wzWebName, psvd->wzVDirRoot, &psvd->swp);
244 ExitOnFailure(hr, "Failed to write directory properties for VirtualDir");
245 }
246
247 if (psvd->fHasApplication)
248 {
249 hr = ScaWriteWebApplication7(psvd->wzWebName, psvd->wzVDirRoot, &psvd->swapp, psapList);
250 ExitOnFailure(hr, "Failed to write application for VirtualDir");
251 }
252
253 if (psvd->psmm)
254 {
255 hr = ScaWriteMimeMap7(psvd->wzWebName, psvd->wzVDirRoot, psvd->psmm);
256 ExitOnFailure(hr, "Failed to write mimemap for VirtualDir");
257 }
258
259 if (psvd->pshh)
260 {
261 hr = ScaWriteHttpHeader7(psvd->wzWebName, psvd->wzVDirRoot, psvd->pshh);
262 ExitOnFailure(hr, "Failed to write custom HTTP headers for VirtualDir");
263 }
264
265 if (psvd->pswe)
266 {
267 hr = ScaWriteWebError7(psvd->wzWebName, psvd->wzVDirRoot, psvd->pswe);
268 ExitOnFailure(hr, "Failed to write custom web errors for VirtualDir");
269 }
270 }
271
272 psvd = psvd->psvdNext;
273 }
274
275LExit:
276 ReleaseStr(wzPath);
277 return hr;
278}
279
280
281HRESULT ScaVirtualDirsUninstall7(
282 __in SCA_VDIR7* psvdList
283 )
284{
285
286 HRESULT hr = S_OK;
287 SCA_VDIR7* psvd = psvdList;
288 LPWSTR wzPath = NULL;
289
290 while (psvd)
291 {
292 if (WcaIsUninstalling(psvd->isInstalled, psvd->isAction))
293 {
294 //init path
295 hr = StrAllocFormatted(&wzPath, L"/%s", psvd->wzVDirRoot);
296 ExitOnFailure(hr, "Failed to create vdir path");
297
298 if (psvd->fHasApplication)
299 {
300 //delete Application
301 hr = ScaWriteConfigID(IIS_APPLICATION);
302 ExitOnFailure(hr, "Failed to write app ID ");
303 hr = ScaWriteConfigID(IIS_DELETE);
304 ExitOnFailure(hr, "Failed to write delete app ID ");
305#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
306 hr = ScaWriteConfigString(psvd->wzWebName); //site name key
307 ExitOnFailure(hr, "Failed to write App site Name");
308#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
309 hr = ScaWriteConfigString(wzPath); // App Path
310 ExitOnFailure(hr, "Failed to write app path root ");
311 hr = ScaWriteConfigString(L"NOP"); // App pool
312 ExitOnFailure(hr, "Failed to write app path app pool ");
313 }
314 else
315 {
316 //delete VDir
317 hr = ScaWriteConfigID(IIS_VDIR);
318 ExitOnFailure(hr, "Failed to write vDir ID ");
319 hr = ScaWriteConfigID(IIS_DELETE);
320#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
321 hr = ScaWriteConfigString(psvd->wzWebName); //site name key
322 ExitOnFailure(hr, "Failed to write App site Name");
323 hr = ScaWriteConfigString(wzPath); // Vdir Path
324 ExitOnFailure(hr, "Failed to write app vdir ");
325 hr = ScaWriteConfigString(L"NOP"); // Phy Path
326 ExitOnFailure(hr, "Failed to write vdir path");
327 }
328
329 ExitOnFailure(hr, "Failed to remove VirtualDir '%ls' from config", psvd->wzKey);
330 }
331
332 psvd = psvd->psvdNext;
333 }
334
335LExit:
336 ReleaseStr(wzPath);
337 return hr;
338}
339
340
341void ScaVirtualDirsFreeList7(
342 __in SCA_VDIR7* psvdList
343 )
344{
345 SCA_VDIR7* psvdDelete = psvdList;
346 while (psvdList)
347 {
348 psvdDelete = psvdList;
349 psvdList = psvdList->psvdNext;
350
351 if (psvdDelete->psmm)
352 {
353 ScaMimeMapFreeList(psvdDelete->psmm);
354 }
355
356 if (psvdDelete->pswe)
357 {
358 ScaWebErrorFreeList(psvdDelete->pswe);
359 }
360
361 MemFree(psvdDelete);
362 }
363}
364
365
366static HRESULT AddVirtualDirToList7(
367 __in SCA_VDIR7** ppsvdList
368 )
369{
370 HRESULT hr = S_OK;
371
372 SCA_VDIR7* psvd = static_cast<SCA_VDIR7*>(MemAlloc(sizeof(SCA_VDIR7), TRUE));
373 ExitOnNull(psvd, hr, E_OUTOFMEMORY, "failed to allocate memory for new vdir list element");
374
375 psvd->psvdNext= *ppsvdList;
376 *ppsvdList = psvd;
377
378LExit:
379 return hr;
380}
diff --git a/src/ext/Iis/ca/scavdir7.h b/src/ext/Iis/ca/scavdir7.h
new file mode 100644
index 00000000..dba25431
--- /dev/null
+++ b/src/ext/Iis/ca/scavdir7.h
@@ -0,0 +1,66 @@
1#pragma once
2// 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.
3
4
5#include "scawebprop.h"
6#include "scawebapp.h"
7#include "scamimemap.h"
8#include "scaapppool.h"
9
10struct SCA_VDIR7
11{
12 // darwin information
13 WCHAR wzKey[MAX_DARWIN_KEY + 1];
14 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
15 INSTALLSTATE isInstalled;
16 INSTALLSTATE isAction;
17
18 // metabase information
19 WCHAR wzWebKey[MAX_DARWIN_KEY + 1];
20 WCHAR wzWebName[METADATA_MAX_NAME_LEN + 1];
21 WCHAR wzVDirRoot[METADATA_MAX_NAME_LEN + 1];
22
23 // iis configuation information
24 WCHAR wzDirectory[MAX_PATH];
25
26 BOOL fHasProperties;
27 SCA_WEB_PROPERTIES swp;
28
29 BOOL fHasApplication;
30 SCA_WEB_APPLICATION swapp;
31
32 SCA_MIMEMAP* psmm; // mime mappings
33 SCA_HTTP_HEADER* pshh; // custom web errors
34 SCA_WEB_ERROR* pswe; // custom web errors
35
36 SCA_VDIR7* psvdNext;
37};
38
39
40// prototypes
41HRESULT __stdcall ScaVirtualDirsRead7(
42 __in SCA_WEB7* pswList,
43 __in SCA_VDIR7** ppsvdList,
44 __in SCA_MIMEMAP** ppsmmList,
45 __in SCA_HTTP_HEADER** ppshhList,
46 __in SCA_WEB_ERROR** ppsweList,
47 __in WCA_WRAPQUERY_HANDLE hUserQuery,
48 __in WCA_WRAPQUERY_HANDLE hWebBaseQuery,
49 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
50 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
51 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
52 __inout LPWSTR *ppwzCustomActionData
53 );
54
55HRESULT ScaVirtualDirsInstall7(
56 __in SCA_VDIR7* psvdList,
57 __in SCA_APPPOOL * psapList
58 );
59
60HRESULT ScaVirtualDirsUninstall7(
61 __in SCA_VDIR7* psvdList
62 );
63
64void ScaVirtualDirsFreeList7(
65 __in SCA_VDIR7* psvdList
66 );
diff --git a/src/ext/Iis/ca/scaweb.cpp b/src/ext/Iis/ca/scaweb.cpp
new file mode 100644
index 00000000..0452fb0b
--- /dev/null
+++ b/src/ext/Iis/ca/scaweb.cpp
@@ -0,0 +1,1187 @@
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//Adding this because delivery doesn't have the updated specstrings.h that windows build does
6#ifndef __in_xcount
7#define __in_xcount(size)
8#endif
9
10// sql queries
11
12enum eWebBaseQuery { wbqWeb = 1, wbqId, wbqIP, wbqPort, wbqHeader, wbqSecure, wbqDescription };
13
14
15// prototypes for private helper functions
16static SCA_WEB* NewWeb();
17static void FreeWeb(SCA_WEB *pswDelete);
18static SCA_WEB* AddWebToList(
19 __in SCA_WEB* pswList,
20 __in SCA_WEB* psw
21 );
22static HRESULT ScaWebFindBase(
23 __in IMSAdminBase* piMetabase,
24 __in SCA_WEB* pswList,
25 __in_z LPCWSTR wzWeb,
26 __in int iSiteId,
27 __in_z LPCWSTR wzIP,
28 __in int iPort,
29 __in_z LPCWSTR wzHeader,
30 __in BOOL fSecure,
31 __in_z LPCWSTR wzDescription,
32 __out_ecount(cchWebBase) LPWSTR wzWebBase,
33 __in DWORD cchWebBase
34 );
35static HRESULT ScaWebFindFreeBase(
36 __in IMSAdminBase* piMetabase,
37 __in_xcount(unknown) SCA_WEB* pswList,
38 __in int iSiteId,
39 __in_z LPCWSTR wzDescription,
40 __out_ecount(cchWebBase) LPWSTR wzWebBase,
41 __in DWORD cchWebBase
42 );
43static HRESULT ScaWebWrite(
44 __in IMSAdminBase* piMetabase,
45 __in SCA_WEB* psw,
46 __in SCA_APPPOOL * psapList
47 );
48static HRESULT ScaWebRemove(
49 __in IMSAdminBase* piMetabase,
50 __in const SCA_WEB* psw);
51static DWORD SiteIdFromDescription(
52 __in_z LPCWSTR wzDescription
53 );
54static void Sort(
55 __in_ecount(cArray) DWORD dwArray[],
56 __in int cArray
57 );
58
59
60HRESULT ScaWebsRead(
61 __in IMSAdminBase* piMetabase,
62 __in SCA_MIMEMAP** ppsmmList,
63 __in SCA_WEB** ppswList,
64 __in SCA_HTTP_HEADER** ppshhList,
65 __in SCA_WEB_ERROR** ppsweList,
66 __in WCA_WRAPQUERY_HANDLE hUserQuery,
67 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
68 __in WCA_WRAPQUERY_HANDLE hSslCertQuery,
69 __in WCA_WRAPQUERY_HANDLE hWebLogQuery,
70 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
71 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
72 __inout LPWSTR *ppwzCustomActionData
73 )
74{
75 Assert(piMetabase && ppswList);
76
77 HRESULT hr = S_OK;
78
79 MSIHANDLE hRec;
80 MSIHANDLE hRecAddresses;
81
82 SCA_WEB* psw = NULL;
83 LPWSTR pwzData = NULL;
84 int iSiteId;
85
86 DWORD dwLen = 0;
87 WCA_WRAPQUERY_HANDLE hQueryWebSite = NULL;
88 WCA_WRAPQUERY_HANDLE hQueryWebAddress = NULL;
89
90 hr = WcaBeginUnwrapQuery(&hQueryWebSite, ppwzCustomActionData);
91 ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead");
92
93 hr = WcaBeginUnwrapQuery(&hQueryWebAddress, ppwzCustomActionData);
94 ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead");
95
96 if (0 == WcaGetQueryRecords(hQueryWebSite))
97 {
98 WcaLog(LOGMSG_VERBOSE, "Required tables not present");
99 ExitFunction1(hr = S_FALSE);
100 }
101
102 // loop through all the webs
103 while (S_OK == (hr = WcaFetchWrappedRecord(hQueryWebSite, &hRec)))
104 {
105 psw = NewWeb();
106 ExitOnNull(psw, hr, E_OUTOFMEMORY, "Failed to allocate memory for web object in memory");
107
108 // get the darwin information
109 hr = WcaGetRecordString(hRec, wqWeb, &pwzData);
110 ExitOnFailure(hr, "Failed to get Web");
111 hr = ::StringCchCopyW(psw->wzKey, countof(psw->wzKey), pwzData);
112 ExitOnFailure(hr, "Failed to copy key string to web object");
113
114 if (*pwzData && *ppsmmList)
115 {
116 hr = ScaGetMimeMap(mmptWeb, pwzData, ppsmmList, &psw->psmm);
117 ExitOnFailure(hr, "Failed to get mimemap for VirtualDir");
118 }
119
120 // get component install state
121 hr = WcaGetRecordString(hRec, wqComponent, &pwzData);
122 ExitOnFailure(hr, "Failed to get Component for Web");
123 hr = ::StringCchCopyW(psw->wzComponent, countof(psw->wzComponent), pwzData);
124 ExitOnFailure(hr, "Failed to copy component string to web object");
125 if (*(psw->wzComponent))
126 {
127 psw->fHasComponent = TRUE;
128
129 hr = WcaGetRecordInteger(hRec, wqInstalled, (int *)&psw->isInstalled);
130 ExitOnFailure(hr, "Failed to get web Component's installed state");
131
132 WcaGetRecordInteger(hRec, wqAction, (int *)&psw->isAction);
133 ExitOnFailure(hr, "Failed to get web Component's action state");
134
135 if (!WcaIsInstalling(psw->isInstalled, psw->isAction) && !WcaIsUninstalling(psw->isInstalled, psw->isAction)
136 && !WcaIsReInstalling(psw->isInstalled, psw->isAction))
137 {
138 FreeWeb(psw);
139 psw = NULL;
140
141 continue; // If we aren't acting on this component, skip it
142 }
143 }
144
145 hr = WcaGetRecordInteger(hRec, wqId, &iSiteId);
146 ExitOnFailure(hr, "Failed to get SiteId for Web");
147
148 // Get the web's key address.
149 hr = WcaGetRecordString(hRec, wqAddress, &pwzData);
150 ExitOnFailure(hr, "Failed to get Address for Web");
151 hr = ::StringCchCopyW(psw->swaKey.wzKey, countof(psw->swaKey.wzKey), pwzData);
152 ExitOnFailure(hr, "Failed to copy key string to web object");
153
154 hr = WcaGetRecordString(hRec, wqIP, &pwzData);
155 ExitOnFailure(hr, "Failed to get IP for Web");
156 hr = ::StringCchCopyW(psw->swaKey.wzIP, countof(psw->swaKey.wzIP), pwzData);
157 ExitOnFailure(hr, "Failed to copy IP string to web object");
158
159 hr = WcaGetRecordString(hRec, wqPort, &pwzData);
160 ExitOnFailure(hr, "Failed to get Web Address port");
161 psw->swaKey.iPort = wcstol(pwzData, NULL, 10);
162
163 hr = WcaGetRecordString(hRec, wqHeader, &pwzData);
164 ExitOnFailure(hr, "Failed to get Header for Web");
165 hr = ::StringCchCopyW(psw->swaKey.wzHeader, countof(psw->swaKey.wzHeader), pwzData);
166 ExitOnFailure(hr, "Failed to copy header string to web object");
167
168 hr = WcaGetRecordInteger(hRec, wqSecure, &psw->swaKey.fSecure);
169 ExitOnFailure(hr, "Failed to get if Web is secure");
170 if (S_FALSE == hr)
171 {
172 psw->swaKey.fSecure = FALSE;
173 }
174
175 // Get the web's description.
176 hr = WcaGetRecordString(hRec, wqDescription, &pwzData);
177 ExitOnFailure(hr, "Failed to get Description for Web");
178 hr = ::StringCchCopyW(psw->wzDescription, countof(psw->wzDescription), pwzData);
179 ExitOnFailure(hr, "Failed to copy description string to web object");
180
181 // Try to find the web root in case it already exists.
182 dwLen = METADATA_MAX_NAME_LEN;
183 hr = ScaWebFindBase(piMetabase, *ppswList,
184 psw->wzKey,
185 iSiteId,
186 psw->swaKey.wzIP,
187 psw->swaKey.iPort,
188 psw->swaKey.wzHeader,
189 psw->swaKey.fSecure,
190 psw->wzDescription,
191 psw->wzWebBase, dwLen);
192 if (S_OK == hr)
193 {
194 psw->fBaseExists = TRUE;
195 }
196 else if (S_FALSE == hr) // didn't find the web site.
197 {
198 psw->fBaseExists = FALSE;
199
200 // If we're actually configuring the web site.
201 if (psw->fHasComponent)
202 {
203 if (WcaIsInstalling(psw->isInstalled, psw->isAction))
204 {
205 hr = ScaWebFindFreeBase(piMetabase, *ppswList, iSiteId, psw->wzDescription, psw->wzWebBase, countof(psw->wzWebBase));
206 ExitOnFailure(hr, "Failed to find free web root.");
207 }
208 else if (WcaIsUninstalling(psw->isInstalled, psw->isAction))
209 {
210 WcaLog(LOGMSG_VERBOSE, "Web site: '%ls' was already removed, skipping.", psw->wzKey);
211
212 hr = S_OK;
213 continue;
214 }
215 }
216 }
217 ExitOnFailure(hr, "Failed to find web root");
218
219 // get any extra web addresses
220 WcaFetchWrappedReset(hQueryWebAddress);
221 while (S_OK == (hr = WcaFetchWrappedRecordWhereString(hQueryWebAddress, 2, psw->wzKey, &hRecAddresses)))
222 {
223 if (MAX_ADDRESSES_PER_WEB <= psw->cExtraAddresses)
224 {
225 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
226 ExitOnFailure(hr, "Failure to get more extra web addresses, max exceeded.");
227 }
228
229 hr = WcaGetRecordString(hRecAddresses, waqAddress, &pwzData);
230 ExitOnFailure(hr, "Failed to get extra web Address");
231
232 // if this isn't the key address add it
233 if (0 != lstrcmpW(pwzData, psw->swaKey.wzKey))
234 {
235 hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey), pwzData);
236 ExitOnFailure(hr, "Failed to copy extra addresses key string to web object");
237
238 hr = WcaGetRecordString(hRecAddresses, waqIP, &pwzData);
239 ExitOnFailure(hr, "Failed to get extra web IP");
240 hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP), pwzData);
241 ExitOnFailure(hr, "Failed to copy extra addresses IP string to web object");
242
243 hr = WcaGetRecordString(hRecAddresses, waqPort, &pwzData);
244 ExitOnFailure(hr, "Failed to get port for extra web IP");
245 psw->swaExtraAddresses[psw->cExtraAddresses].iPort= wcstol(pwzData, NULL, 10);
246
247 hr = WcaGetRecordString(hRecAddresses, waqHeader, &pwzData);
248 ExitOnFailure(hr, "Failed to get header for extra web IP");
249 hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader), pwzData);
250 ExitOnFailure(hr, "Failed to copy extra addresses header string to web object");
251
252 hr = WcaGetRecordInteger(hRecAddresses, waqSecure, &psw->swaExtraAddresses[psw->cExtraAddresses].fSecure);
253 ExitOnFailure(hr, "Failed to get if secure extra web IP");
254 if (S_FALSE == hr)
255 psw->swaExtraAddresses[psw->cExtraAddresses].fSecure = FALSE;
256
257 ++psw->cExtraAddresses;
258 }
259 }
260
261 if (E_NOMOREITEMS == hr)
262 hr = S_OK;
263 ExitOnFailure(hr, "Failure occured while getting extra web addresses");
264
265 hr = WcaGetRecordInteger(hRec, wqConnectionTimeout, &psw->iConnectionTimeout);
266 ExitOnFailure(hr, "Failed to get connection timeout for Web");
267
268 if (psw->fHasComponent) // If we're installing it, it needs a dir
269 {
270 // get the web's directory
271 if (INSTALLSTATE_SOURCE == psw->isAction)
272 {
273 hr = WcaGetRecordString(hRec, wqSourcePath, &pwzData);
274 }
275 else
276 {
277 hr = WcaGetRecordString(hRec, wqTargetPath, &pwzData);
278 }
279 ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory");
280
281 // remove trailing backslashes
282 while (lstrlenW(pwzData) > 0 && pwzData[lstrlenW(pwzData)-1] == L'\\')
283 {
284 pwzData[lstrlenW(pwzData)-1] = 0;
285 }
286 hr = ::StringCchCopyW(psw->wzDirectory, countof(psw->wzDirectory), pwzData);
287 ExitOnFailure(hr, "Failed to copy directory string to web object");
288 }
289
290 hr = WcaGetRecordInteger(hRec, wqState, &psw->iState);
291 ExitOnFailure(hr, "Failed to get state for Web");
292
293 hr = WcaGetRecordInteger(hRec, wqAttributes, &psw->iAttributes);
294 ExitOnFailure(hr, "Failed to get attributes for Web");
295
296 // get the dir properties for this web
297 hr = WcaGetRecordString(hRec, wqProperties, &pwzData);
298 ExitOnFailure(hr, "Failed to get directory property record for Web");
299 if (*pwzData)
300 {
301 hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &psw->swp);
302 ExitOnFailure(hr, "Failed to get directory properties for Web");
303
304 psw->fHasProperties = TRUE;
305 }
306
307 // get the application information for this web
308 hr = WcaGetRecordString(hRec, wqApplication, &pwzData);
309 ExitOnFailure(hr, "Failed to get application identifier for Web");
310 if (*pwzData)
311 {
312 hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &psw->swapp);
313 ExitOnFailure(hr, "Failed to get application for Web");
314
315 psw->fHasApplication = TRUE;
316 }
317
318 // get the SSL certificates
319 hr = ScaSslCertificateRead(psw->wzKey, hSslCertQuery, &(psw->pswscList));
320 ExitOnFailure(hr, "Failed to get SSL Certificates.");
321
322 // get the custom headers
323 if (*ppshhList)
324 {
325 hr = ScaGetHttpHeader(hhptWeb, psw->wzKey, ppshhList, &(psw->pshhList));
326 ExitOnFailure(hr, "Failed to get Custom HTTP Headers");
327 }
328
329 // get the errors
330 if (*ppsweList)
331 {
332 hr = ScaGetWebError(weptWeb, psw->wzKey, ppsweList, &(psw->psweList));
333 ExitOnFailure(hr, "Failed to get Custom Errors");
334 }
335
336 // get the log information for this web
337 hr = WcaGetRecordString(hRec, wqLog, &pwzData);
338 ExitOnFailure(hr, "Failed to get log identifier for Web");
339 if (*pwzData)
340 {
341 hr = ScaGetWebLog(piMetabase, pwzData, hWebLogQuery, &psw->swl);
342 ExitOnFailure(hr, "Failed to get Log for Web.");
343
344 psw->fHasLog = TRUE;
345 }
346
347 *ppswList = AddWebToList(*ppswList, psw);
348 psw = NULL; // set the web NULL so it doesn't accidentally get freed below
349 }
350
351 if (E_NOMOREITEMS == hr)
352 {
353 hr = S_OK;
354 }
355
356LExit:
357 // if anything was left over after an error clean it all up
358 WcaFinishUnwrapQuery(hQueryWebSite);
359 WcaFinishUnwrapQuery(hQueryWebAddress);
360
361 if (psw)
362 {
363 ScaWebsFreeList(psw);
364 }
365
366 ReleaseStr(pwzData);
367
368 return hr;
369}
370
371
372HRESULT ScaWebsGetBase(
373 __in IMSAdminBase* piMetabase,
374 __in SCA_WEB* pswList,
375 __in LPCWSTR wzWeb,
376 __out_ecount(cchWebBase) LPWSTR wzWebBase,
377 __in DWORD cchWebBase,
378 __in WCA_WRAPQUERY_HANDLE hWrapQuery
379 )
380{
381 HRESULT hr = S_OK;
382 MSIHANDLE hRec;
383
384 int iSiteId;
385 WCHAR wzIP[MAX_PATH];
386 int iPort = -1;
387 WCHAR wzHeader[MAX_PATH];
388 BOOL fSecure = FALSE;
389
390 LPWSTR pwzData = NULL;
391
392 // get the web information
393 WcaFetchWrappedReset(hWrapQuery);
394
395 hr = WcaFetchWrappedRecordWhereString(hWrapQuery, 1, wzWeb, &hRec);
396 if (S_OK == hr)
397 {
398 // get the data to search for
399 hr = WcaGetRecordInteger(hRec, wbqId, &iSiteId);
400 ExitOnFailure(hr, "Failed to get SiteId for Web for VirtualDir");
401
402 hr = WcaGetRecordString(hRec, wbqIP, &pwzData);
403 ExitOnFailure(hr, "Failed to get IP for Web for VirtualDir");
404 hr = ::StringCchCopyW(wzIP, countof(wzIP), pwzData);
405 ExitOnFailure(hr, "Failed to copy IP for Web for VirtualDir");
406
407 hr = WcaGetRecordString(hRec, wbqPort, &pwzData);
408 ExitOnFailure(hr, "Failed to get port for extra web IP");
409 iPort = wcstol(pwzData, NULL, 10);
410
411 hr = WcaGetRecordString(hRec, wbqHeader, &pwzData);
412 ExitOnFailure(hr, "Failed to get Header for Web for VirtualDir");
413 hr = ::StringCchCopyW(wzHeader, countof(wzHeader), pwzData);
414 ExitOnFailure(hr, "Failed to copy Header for Web for VirtualDir");
415
416 hr = WcaGetRecordInteger(hRec, wbqSecure, &fSecure);
417 if (S_FALSE == hr)
418 fSecure = FALSE;
419
420 hr = WcaGetRecordString(hRec, wbqDescription, &pwzData);
421 ExitOnFailure(hr, "Failed to get Description for Web");
422
423 // find the web or find the next free web location
424 hr = ScaWebFindBase(piMetabase, pswList, wzWeb, iSiteId, wzIP, iPort, wzHeader, fSecure, pwzData, wzWebBase, cchWebBase);
425 if (S_FALSE == hr)
426 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
427 ExitOnFailure(hr, "Failed to find Web base");
428 }
429 else if (S_FALSE == hr)
430 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
431
432 // Let's check that there isn't more than one record found - if there is, throw an assert like WcaFetchSingleRecord() would
433 HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWrapQuery, 1, wzWeb, &hRec);
434 if (SUCCEEDED(hrTemp))
435 {
436 AssertSz(E_NOMOREITEMS == hrTemp, "ScaWebsGetBase found more than one record");
437 }
438
439LExit:
440 ReleaseStr(pwzData);
441
442 return hr;
443}
444
445
446HRESULT ScaWebsInstall(
447 __in IMSAdminBase* piMetabase,
448 __in SCA_WEB* pswList,
449 __in SCA_APPPOOL * psapList
450 )
451{
452 HRESULT hr = S_OK;
453 SCA_WEB* psw = pswList;
454
455 while (psw)
456 {
457 // if we are installing the web site
458 if (psw->fHasComponent && WcaIsInstalling(psw->isInstalled, psw->isAction))
459 {
460 hr = ScaWebWrite(piMetabase, psw, psapList);
461 ExitOnFailure(hr, "failed to write web '%ls' to metabase", psw->wzKey);
462 }
463
464 psw = psw->pswNext;
465 }
466
467LExit:
468 return hr;
469}
470
471
472HRESULT ScaWebsUninstall(
473 __in IMSAdminBase* piMetabase,
474 __in SCA_WEB* pswList
475 )
476{
477 HRESULT hr = S_OK;
478 SCA_WEB* psw = pswList;
479
480 while (psw)
481 {
482 // if we are uninstalling the web site
483 if (psw->fHasComponent && WcaIsUninstalling(psw->isInstalled, psw->isAction))
484 {
485 hr = ScaWebRemove(piMetabase, psw);
486 ExitOnFailure(hr, "Failed to remove web '%ls' from metabase", psw->wzKey);
487 }
488
489 psw = psw->pswNext;
490 }
491
492LExit:
493 return hr;
494}
495
496
497void ScaWebsFreeList(
498 __in SCA_WEB* pswList
499 )
500{
501 SCA_WEB* pswDelete = pswList;
502 while (pswList)
503 {
504 pswDelete = pswList;
505 pswList = pswList->pswNext;
506
507 // Free the SSL, headers and errors list first
508 FreeWeb(pswDelete);
509 }
510}
511
512
513// private helper functions
514
515static void FreeWeb(SCA_WEB *pswDelete)
516{
517 ScaSslCertificateFreeList(pswDelete->pswscList);
518 ScaHttpHeaderFreeList(pswDelete->pshhList);
519 ScaWebErrorFreeList(pswDelete->psweList);
520 MemFree(pswDelete);
521}
522
523static SCA_WEB* NewWeb()
524{
525 SCA_WEB* psw = static_cast<SCA_WEB*>(MemAlloc(sizeof(SCA_WEB), TRUE));
526 Assert(psw);
527 return psw;
528}
529
530
531static SCA_WEB* AddWebToList(
532 __in SCA_WEB* pswList,
533 __in SCA_WEB* psw
534 )
535{
536 if (pswList)
537 {
538 SCA_WEB* pswTemp = pswList;
539 while (pswTemp->pswNext)
540 {
541 pswTemp = pswTemp->pswNext;
542 }
543
544 pswTemp->pswNext = psw;
545 }
546 else
547 {
548 pswList = psw;
549 }
550
551 return pswList;
552}
553
554
555static HRESULT ScaWebFindBase(
556 __in IMSAdminBase* piMetabase,
557 __in SCA_WEB* pswList,
558 __in_z LPCWSTR wzWeb,
559 __in int iSiteId,
560 __in_z LPCWSTR wzIP,
561 __in int iPort,
562 __in_z LPCWSTR wzHeader,
563 __in BOOL fSecure,
564 __in_z LPCWSTR wzDescription,
565 __out_ecount(cchWebBase) LPWSTR wzWebBase,
566 __in DWORD cchWebBase
567 )
568{
569 Assert(piMetabase);
570
571 HRESULT hr = S_OK;
572
573 WCHAR wzKey[METADATA_MAX_NAME_LEN];
574 WCHAR wzSubkey[METADATA_MAX_NAME_LEN];
575 LPWSTR wzFoundKey = NULL;
576
577 METADATA_RECORD mr;
578 ::ZeroMemory(&mr, sizeof(mr));
579
580 METADATA_RECORD mrCompare;
581 ::ZeroMemory(&mrCompare, sizeof(mrCompare));
582
583 // try to find the web in memory first
584 for (SCA_WEB* psw = pswList; psw; psw = psw->pswNext)
585 {
586 if (0 == lstrcmpW(wzWeb, psw->wzKey))
587 {
588 if ((0 == lstrcmpW(wzIP, psw->swaKey.wzIP) || 0 == lstrcmpW(wzIP, L"*") || 0 == lstrcmpW(psw->swaKey.wzIP, L"*")) &&
589 iPort == psw->swaKey.iPort &&
590 0 == lstrcmpW(wzHeader, psw->swaKey.wzHeader) &&
591 fSecure == psw->swaKey.fSecure)
592 {
593 if (0 == lstrlenW(psw->wzWebBase))
594 {
595 WcaLog(LOGMSG_STANDARD, "A matching web object in memory was found, but the web object in memory has no associated base");
596 ExitFunction1(hr = S_FALSE);
597 }
598
599 hr = ::StringCchCopyW(wzKey, countof(wzKey), psw->wzWebBase);
600 ExitOnFailure(hr, "Failed to copy web base into key.");
601
602 wzFoundKey = wzKey;
603 break;
604 }
605 else
606 {
607 WcaLog(LOGMSG_STANDARD, "Found web `%ls` but data did not match.", wzWeb);
608 hr = E_UNEXPECTED;
609 break;
610 }
611 }
612 }
613 ExitOnFailure(hr, "Failure occured while searching for web in memory");
614
615 // If we didn't find a web in memory matching look in the metabase.
616 if (!wzFoundKey)
617 {
618 mr.dwMDIdentifier = MD_KEY_TYPE;
619 mr.dwMDAttributes = METADATA_INHERIT;
620 mr.dwMDUserType = IIS_MD_UT_SERVER;
621 mr.dwMDDataType = ALL_METADATA;
622 mr.dwMDDataLen = 0;
623 mr.pbMDData = NULL;
624
625 // If we're looking based on the old WebAddress detection (NULL) or the new
626 // Web description detection (-1)
627 if (MSI_NULL_INTEGER == iSiteId || -1 == iSiteId)
628 {
629 if (MSI_NULL_INTEGER == iSiteId)
630 {
631 mrCompare.dwMDIdentifier = (fSecure) ? MD_SECURE_BINDINGS : MD_SERVER_BINDINGS;
632 }
633 else
634 {
635 mrCompare.dwMDIdentifier = MD_SERVER_COMMENT;
636 }
637 mrCompare.dwMDAttributes = METADATA_INHERIT;
638 mrCompare.dwMDUserType = IIS_MD_UT_SERVER;
639 mrCompare.dwMDDataType = ALL_METADATA;
640 mrCompare.dwMDDataLen = 0;
641 mrCompare.pbMDData = NULL;
642
643 // Loop through the "web keys" looking for the "IIsWebServer" key that matches our search criteria.
644 for (DWORD dwIndex = 0; SUCCEEDED(hr); ++dwIndex)
645 {
646 hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC", wzSubkey, dwIndex);
647 if (SUCCEEDED(hr))
648 {
649 hr = ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%s", wzSubkey);
650 ExitOnFailure(hr, "Failed to copy web subkey.");
651
652 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr);
653 if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
654 {
655 hr = S_FALSE; // didn't find anything, try next one
656 continue;
657 }
658 ExitOnFailure(hr, "Failed to get key from metabase while searching for web servers");
659
660 // If we have an IIsWebServer check to see if this is the site we are searching for.
661 if (0 == lstrcmpW(L"IIsWebServer", (LPCWSTR)mr.pbMDData))
662 {
663 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mrCompare);
664 if (MD_ERROR_DATA_NOT_FOUND == hr || NULL == mrCompare.pbMDData)
665 {
666 hr = S_FALSE;
667 continue;
668 }
669 ExitOnFailure(hr, "Failed to get address/description from metabase while searching for web servers");
670
671 LPWSTR pwzExists = (LPWSTR)mrCompare.pbMDData;
672 if (MSI_NULL_INTEGER == iSiteId)
673 {
674 // Break down the address into its constituent parts (IP:Port:Header).
675 while (S_OK == hr && *pwzExists)
676 {
677 LPCWSTR pwzIPExists = pwzExists;
678 pwzExists = const_cast<LPWSTR>(wcsstr(pwzIPExists, L":"));
679 ExitOnNull(pwzExists, hr, E_INVALIDARG, "Invalid web address. IP was not separated by a colon.");
680 *pwzExists = L'\0';
681
682 LPCWSTR pwzPortExists = pwzExists + 1;
683 pwzExists = const_cast<LPWSTR>(wcsstr(pwzPortExists, L":"));
684 ExitOnNull(pwzExists, hr, E_INVALIDARG, "Invalid web address. Port was not separated by a colon.");
685 *pwzExists = L'\0';
686 int iPortExists = wcstol(pwzPortExists, NULL, 10);
687
688 LPCWSTR pwzHeaderExists = pwzExists + 1;
689
690 // compare the passed in address with the address listed for this web
691 if ((0 == lstrcmpW(wzIP, pwzIPExists) || 0 == lstrcmpW(wzIP, L"*")) &&
692 iPort == iPortExists &&
693 0 == lstrcmpW(wzHeader, pwzHeaderExists))
694 {
695 wzFoundKey = wzKey;
696 break;
697 }
698
699 // move to the next block of data, this may move beyond the available
700 // data and exit the while loop above.
701 pwzExists = const_cast<LPWSTR>(pwzHeaderExists + lstrlenW(pwzHeaderExists) + 1);
702 }
703 }
704 else
705 {
706 if (0 == lstrcmpW(wzDescription, pwzExists))
707 {
708 wzFoundKey = wzKey;
709 }
710 }
711
712 // If we found the key we were looking for, no point in continuing to search.
713 if (wzFoundKey)
714 {
715 break;
716 }
717 }
718 }
719 }
720
721 if (E_NOMOREITEMS == hr)
722 {
723 Assert(!wzFoundKey);
724 hr = S_FALSE;
725 }
726 }
727 else // we're looking a specific SiteId
728 {
729 hr = ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%d", iSiteId);
730 ExitOnFailure(hr, "Failed to allocate metabase key string.");
731
732 // if we have an IIsWebServer store the key
733 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr);
734
735 if (SUCCEEDED(hr) && NULL != mr.pbMDData && 0 == lstrcmpW(L"IIsWebServer", (LPCWSTR)mr.pbMDData))
736 {
737 wzFoundKey = wzKey;
738 }
739 else if (MD_ERROR_DATA_NOT_FOUND == hr || NULL == mrCompare.pbMDData || NULL == mr.pbMDData)
740 {
741 hr = S_FALSE;
742 }
743 }
744 }
745
746 if (wzFoundKey)
747 {
748 Assert(S_OK == hr);
749
750 hr = ::StringCchCopyW(wzWebBase, cchWebBase, wzFoundKey);
751 ExitOnFailure(hr, "Buffer not larger enough for found base key.");
752 }
753
754LExit:
755 MetaFreeValue(&mr);
756 MetaFreeValue(&mrCompare);
757
758 if (!wzFoundKey && SUCCEEDED(hr))
759 {
760 hr = S_FALSE;
761 }
762
763 return hr;
764}
765
766
767static HRESULT ScaWebFindFreeBase(
768 __in IMSAdminBase* piMetabase,
769 __in_xcount(unknown) SCA_WEB* pswList,
770 __in int iSiteId,
771 __in_z LPCWSTR wzDescription,
772 __out_ecount(cchWebBase) LPWSTR wzWebBase,
773 __in DWORD cchWebBase
774 )
775{
776 Assert(piMetabase);
777
778 HRESULT hr = S_OK;
779
780 WCHAR wzKey[METADATA_MAX_NAME_LEN];
781 WCHAR wzSubkey[METADATA_MAX_NAME_LEN];
782 DWORD* prgdwSubKeys = NULL;
783 DWORD cSubKeys = 128;
784 DWORD cSubKeysFilled = 0;
785
786 DWORD dwKey;
787
788 METADATA_RECORD mr;
789 ::ZeroMemory(&mr, sizeof(METADATA_RECORD));
790 mr.dwMDIdentifier = MD_KEY_TYPE;
791 mr.dwMDAttributes = 0;
792 mr.dwMDUserType = IIS_MD_UT_SERVER;
793 mr.dwMDDataType = STRING_METADATA;
794 mr.dwMDDataLen = 0;
795 mr.pbMDData = NULL;
796
797 if (MSI_NULL_INTEGER == iSiteId || -1 == iSiteId)
798 {
799 prgdwSubKeys = static_cast<DWORD*>(MemAlloc(cSubKeys * sizeof(DWORD), TRUE));
800 ExitOnNull(prgdwSubKeys, hr, E_OUTOFMEMORY, "failed to allocate space for web site keys");
801
802 // loop through the "web keys" looking for the "IIsWebServer" key that matches wzWeb
803 for (DWORD dwIndex = 0; SUCCEEDED(hr); ++dwIndex)
804 {
805 hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC", wzSubkey, dwIndex);
806 if (SUCCEEDED(hr))
807 {
808 hr = ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%s", wzSubkey);
809 ExitOnFailure(hr, "Failed remember key.");
810
811 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr);
812 if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
813 {
814 hr = S_FALSE; // didn't find anything, try next one
815 continue;
816 }
817 ExitOnFailure(hr, "Failed to get key from metabase while searching for free web root");
818
819 // if we have a IIsWebServer get the address information
820 if (0 == lstrcmpW(L"IIsWebServer", (LPCWSTR)mr.pbMDData))
821 {
822 if (cSubKeysFilled >= cSubKeys)
823 {
824 cSubKeys = cSubKeys * 2;
825 prgdwSubKeys = static_cast<DWORD*>(MemReAlloc(prgdwSubKeys, cSubKeys * sizeof(DWORD), FALSE));
826 ExitOnNull(prgdwSubKeys, hr, E_OUTOFMEMORY, "failed to allocate space for web site keys");
827 }
828
829 prgdwSubKeys[cSubKeysFilled] = wcstol(wzSubkey, NULL, 10);
830 ++cSubKeysFilled;
831 Sort(prgdwSubKeys, cSubKeysFilled);
832 }
833 }
834 }
835
836 if (E_NOMOREITEMS == hr)
837 {
838 hr = S_OK;
839 }
840 ExitOnFailure(hr, "Failed to find free web root");
841
842 // Add all the webs created in memory.
843 CONST WCHAR *pcchSlash;
844 for (SCA_WEB* psw = pswList; psw; psw = psw->pswNext)
845 {
846 // Don't process webs that don't have a base
847 if (!*psw->wzWebBase)
848 {
849 continue;
850 }
851
852 // find the last slash in the web root because the root # is after it
853 pcchSlash = NULL;
854 for (CONST WCHAR *pcch = psw->wzWebBase; pcch && *pcch; ++pcch)
855 {
856 if (L'/' == *pcch)
857 {
858 pcchSlash = pcch;
859 }
860 }
861 // In case we don't find a slash, error out
862 ExitOnNull(pcchSlash, hr, E_INVALIDARG, "Failed to find a slash in the web root: %ls", psw->wzWebBase);
863
864 prgdwSubKeys[cSubKeysFilled] = wcstol(pcchSlash + 1, NULL, 10);
865 ++cSubKeysFilled;
866 Sort(prgdwSubKeys, cSubKeysFilled);
867
868 if (cSubKeysFilled >= cSubKeys)
869 {
870 cSubKeys = cSubKeys * 2;
871 prgdwSubKeys = static_cast<DWORD*>(MemReAlloc(prgdwSubKeys, cSubKeys * sizeof(DWORD), FALSE));
872 ExitOnNull(prgdwSubKeys, hr, E_OUTOFMEMORY, "failed to allocate space for web site keys");
873 }
874 }
875
876 // Find the lowest free web root.
877 dwKey = (-1 == iSiteId) ? SiteIdFromDescription(wzDescription) : 1;
878 for (DWORD i = 0; i < cSubKeysFilled; ++i)
879 {
880 if (dwKey == prgdwSubKeys[i])
881 {
882 ++dwKey;
883 }
884 else if (dwKey < prgdwSubKeys[i])
885 {
886 break;
887 }
888 }
889 }
890 else
891 {
892 dwKey = iSiteId;
893 }
894
895 hr = ::StringCchPrintfW(wzWebBase, cchWebBase, L"/LM/W3SVC/%u", dwKey);
896 ExitOnFailure(hr, "failed to format web base with key: %u", dwKey);
897
898LExit:
899 MetaFreeValue(&mr);
900
901 if (prgdwSubKeys)
902 {
903 MemFree(prgdwSubKeys);
904 }
905
906 return hr;
907}
908
909
910static HRESULT ScaWebWrite(
911 __in IMSAdminBase* piMetabase,
912 __in SCA_WEB* psw,
913 __in SCA_APPPOOL * psapList)
914{
915 HRESULT hr = S_OK;
916
917 UINT ui = 0;
918 WCHAR wzIP[64];
919 WCHAR wzBindings[1024];
920 WCHAR wzSecureBindings[1024];
921 WCHAR* pcchNext; // used to properly create the MULTI_SZ
922 DWORD cchPcchNext;
923 WCHAR* pcchSecureNext ; // used to properly create the MULTI_SZ
924 DWORD cchPcchSecureNext;
925
926 // if the web root doesn't exist create it
927 if (!psw->fBaseExists)
928 {
929 hr = ScaCreateWeb(piMetabase, psw->wzKey, psw->wzWebBase);
930 ExitOnFailure(hr, "Failed to create web");
931 }
932 else if (psw->iAttributes & SWATTRIB_NOCONFIGUREIFEXISTS) // if we're not supposed to configure existing webs, bail
933 {
934 Assert(psw->fBaseExists);
935
936 hr = S_FALSE;
937 WcaLog(LOGMSG_VERBOSE, "Skipping configuration of existing web: %ls", psw->wzKey);
938 ExitFunction();
939 }
940
941 // put the secure and non-secure bindings together as MULTI_SZs
942 ::ZeroMemory(wzBindings, sizeof(wzBindings));
943 pcchNext = wzBindings;
944 cchPcchNext = countof(wzBindings);
945 ::ZeroMemory(wzSecureBindings, sizeof(wzSecureBindings));
946 pcchSecureNext = wzSecureBindings;
947 cchPcchSecureNext = countof(wzSecureBindings);
948
949 // set the IP address appropriately
950 if (0 == lstrcmpW(psw->swaKey.wzIP, L"*"))
951 {
952 ::ZeroMemory(wzIP, sizeof(wzIP));
953 }
954 else
955 {
956 hr = ::StringCchCopyW(wzIP, countof(wzIP), psw->swaKey.wzIP);
957 ExitOnFailure(hr, "Failed to copy IP string");
958 }
959
960 WCHAR wzBinding[256];
961 hr = ::StringCchPrintfW(wzBinding, countof(wzBinding), L"%s:%d:%s", wzIP, psw->swaKey.iPort, psw->swaKey.wzHeader);
962 ExitOnFailure(hr, "Failed to format IP:Port:Header binding string");
963 if (psw->swaKey.fSecure)
964 {
965 hr = ::StringCchCopyW(pcchSecureNext, cchPcchSecureNext, wzBinding);
966 ExitOnFailure(hr, "Failed to copy binding string to securenext string");
967 pcchSecureNext += lstrlenW(wzBinding) + 1;
968 cchPcchSecureNext -= lstrlenW(wzBinding) + 1;
969 }
970 else
971 {
972 hr = ::StringCchCopyW(pcchNext, cchPcchNext, wzBinding);
973 ExitOnFailure(hr, "Failed to copy binding string to next string");
974 pcchNext += lstrlenW(wzBinding) + 1;
975 cchPcchNext -= lstrlenW(wzBinding) + 1;
976 }
977
978 for (ui = 0; ui < psw->cExtraAddresses; ++ui)
979 {
980 // set the IP address appropriately
981 if (0 == lstrcmpW(psw->swaExtraAddresses[ui].wzIP, L"*"))
982 {
983 ::ZeroMemory(wzIP, sizeof(wzIP));
984 }
985 else
986 {
987 hr = ::StringCchCopyW(wzIP, countof(wzIP), psw->swaExtraAddresses[ui].wzIP);
988 ExitOnFailure(hr, "Failed to copy extra addresses IP to IP string");
989 }
990
991 hr = ::StringCchPrintfW(wzBinding, countof(wzBinding), L"%s:%d:%s", wzIP, psw->swaExtraAddresses[ui].iPort, psw->swaExtraAddresses[ui].wzHeader);
992 ExitOnFailure(hr, "Failed to format IP:Port:Header binding string for extra address");
993 if (psw->swaExtraAddresses[ui].fSecure)
994 {
995 hr = ::StringCchCopyW(pcchSecureNext, cchPcchSecureNext, wzBinding);
996 ExitOnFailure(hr, "Failed to copy binding string to securenext string for extra address");
997 pcchSecureNext += lstrlenW(wzBinding) + 1;
998 cchPcchSecureNext -= lstrlenW(wzBinding) + 1;
999 }
1000 else
1001 {
1002 hr = ::StringCchCopyW(pcchNext, cchPcchNext, wzBinding);
1003 ExitOnFailure(hr, "Failed to copy binding string to next string for extra address");
1004 pcchNext += lstrlenW(wzBinding) + 1;
1005 cchPcchNext -= lstrlenW(wzBinding) + 1;
1006 }
1007 }
1008
1009 // Delete the existing secure bindings metabase value, as having one while SSLCertHash and SSLStoreName aren't both set correctly can result in
1010 // 0x80070520 (ERROR_NO_SUCH_LOGON_SESSION) errors in some situations on IIS7. Clearing this value first and then setting it after the install has completed
1011 // allows the two aforementioned properties to exist in an intermediate state without errors
1012 hr = ScaDeleteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SECURE_BINDINGS, MULTISZ_METADATA);
1013 ExitOnFailure(hr, "Failed to temporarily delete secure bindings for Web");
1014
1015 // now write the bindings to the metabase
1016 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, wzBindings);
1017 ExitOnFailure(hr, "Failed to write server bindings for Web");
1018
1019 // write the target path for the web's directory to the metabase
1020 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"/Root", MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, psw->wzDirectory);
1021 ExitOnFailure(hr, "Failed to write virtual root path for Web");
1022
1023 // write the description for the web to the metabase
1024 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_COMMENT, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, psw->wzDescription);
1025 ExitOnFailure(hr, "Failed to write description for Web");
1026
1027 ui = psw->iConnectionTimeout;
1028 if (MSI_NULL_INTEGER != ui)
1029 {
1030 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_CONNECTION_TIMEOUT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui));
1031 ExitOnFailure(hr, "Failed to write connection timeout for Web");
1032 }
1033
1034 ui = psw->iState;
1035 if (MSI_NULL_INTEGER != ui)
1036 {
1037 if (2 == ui)
1038 {
1039 ui = 1;
1040 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_AUTOSTART, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui));
1041 ExitOnFailure(hr, "Failed to write auto start flag for Web");
1042 ui = 2;
1043 }
1044
1045 if (1 == ui || 2 == ui)
1046 {
1047 ui = 1; // start command
1048 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui));
1049 ExitOnFailure(hr, "Failed to start Web");
1050 }
1051 else if (0 == ui)
1052 {
1053 ui = 2; // stop command
1054 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui));
1055 ExitOnFailure(hr, "Failed to stop Web");
1056 }
1057 else
1058 {
1059 hr = E_UNEXPECTED;
1060 ExitOnFailure(hr, "Unexpected value for Web State");
1061 }
1062 }
1063
1064 WCHAR wzRootOfWeb[METADATA_MAX_NAME_LEN];
1065 hr = ::StringCchPrintfW(wzRootOfWeb, countof(wzRootOfWeb), L"%s/Root", psw->wzWebBase);
1066 ExitOnFailure(hr, "Failed to allocate WebBase/Root string for root of web");
1067
1068 // write the web dirproperties information
1069 if (psw->fHasProperties)
1070 {
1071 hr = ScaWriteWebDirProperties(piMetabase, wzRootOfWeb, &psw->swp);
1072 ExitOnFailure(hr, "Failed to write web security information to metabase");
1073 }
1074
1075 // write the application information
1076 if (psw->fHasApplication)
1077 {
1078 // On reinstall, we have to uninstall the old application, otherwise a duplicate will be created
1079 if (WcaIsReInstalling(psw->isInstalled, psw->isAction))
1080 {
1081 hr = ScaDeleteApp(piMetabase, wzRootOfWeb);
1082 ExitOnFailure(hr, "Failed to remove application for WebDir as part of a reinstall");
1083 }
1084
1085 hr = ScaWriteWebApplication(piMetabase, wzRootOfWeb, &psw->swapp, psapList);
1086 ExitOnFailure(hr, "Failed to write web application information to metabase");
1087 }
1088
1089 // write the SSL certificate information
1090 if (psw->pswscList)
1091 {
1092 hr = ScaSslCertificateWriteMetabase(piMetabase, psw->wzWebBase, psw->pswscList);
1093 ExitOnFailure(hr, "Failed to write SSL certificates for Web site: %ls", psw->wzKey);
1094 }
1095
1096 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SECURE_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, wzSecureBindings);
1097 ExitOnFailure(hr, "Failed to write secure bindings for Web");
1098
1099 // write the headers
1100 if (psw->pshhList)
1101 {
1102 hr = ScaWriteHttpHeader(piMetabase, wzRootOfWeb, psw->pshhList);
1103 ExitOnFailure(hr, "Failed to write custom HTTP headers for Web site: %ls", psw->wzKey);
1104 }
1105
1106 // write the errors
1107 if (psw->psweList)
1108 {
1109 hr = ScaWriteWebError(piMetabase, weptWeb, psw->wzWebBase, psw->psweList);
1110 ExitOnFailure(hr, "Failed to write custom web errors for Web site: %ls", psw->wzKey);
1111 }
1112
1113 // write the mimetypes
1114 if (psw->psmm)
1115 {
1116 hr = ScaWriteMimeMap(piMetabase, wzRootOfWeb, psw->psmm);
1117 ExitOnFailure(hr, "Failed to write mimemap for Web site: %ls", psw->wzKey);
1118 }
1119
1120 // write the log information to the metabase
1121 if (psw->fHasLog)
1122 {
1123 hr = ScaWriteWebLog(piMetabase, psw->wzWebBase, &psw->swl);
1124 ExitOnFailure(hr, "Failed to write web log information to metabase");
1125 }
1126
1127LExit:
1128 return hr;
1129}
1130
1131
1132static HRESULT ScaWebRemove(
1133 __in IMSAdminBase* piMetabase,
1134 __in const SCA_WEB* psw
1135 )
1136{
1137 HRESULT hr = S_OK;
1138
1139 // simply remove the root key and everything else is pulled at the same time
1140 hr = ScaDeleteMetabaseKey(piMetabase, psw->wzWebBase, L"");
1141 ExitOnFailure(hr, "Failed to remove web '%ls' from metabase", psw->wzKey);
1142
1143LExit:
1144 return hr;
1145}
1146
1147
1148static DWORD SiteIdFromDescription(
1149 __in_z LPCWSTR wzDescription
1150 )
1151{
1152 LPCWSTR pwz = wzDescription;
1153 DWORD dwSiteId = 0;
1154 while (pwz && *pwz)
1155 {
1156 WCHAR ch = *pwz & 0xdf;
1157 dwSiteId = (dwSiteId * 101) + ch;
1158 ++pwz;
1159 }
1160
1161 return (dwSiteId % INT_MAX) + 1;
1162}
1163
1164
1165// insertion sort
1166static void Sort(
1167 __in_ecount(cArray) DWORD dwArray[],
1168 __in int cArray
1169 )
1170{
1171 int i, j;
1172 DWORD dwData;
1173
1174 for (i = 1; i < cArray; ++i)
1175 {
1176 dwData = dwArray[i];
1177
1178 j = i - 1;
1179 while (0 <= j && dwArray[j] > dwData)
1180 {
1181 dwArray[j + 1] = dwArray[j];
1182 j--;
1183 }
1184
1185 dwArray[j + 1] = dwData;
1186 }
1187}
diff --git a/src/ext/Iis/ca/scaweb.h b/src/ext/Iis/ca/scaweb.h
new file mode 100644
index 00000000..294030b4
--- /dev/null
+++ b/src/ext/Iis/ca/scaweb.h
@@ -0,0 +1,123 @@
1#pragma once
2// 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.
3
4
5#include "scawebapp.h"
6#include "scawebprop.h"
7#include "scahttpheader.h"
8#include "scaweberr.h"
9#include "scassl.h"
10#include "scaapppool.h"
11#include "scaweblog.h"
12#include "scamimemap.h"
13
14// globals
15#define MAX_ADDRESSES_PER_WEB 10
16
17enum eWebQuery { wqWeb = 1, wqComponent, wqId, wqDescription, wqConnectionTimeout, wqDirectory,
18 wqState, wqAttributes, wqProperties, wqApplication, wqAddress, wqIP, wqPort, wqHeader, wqSecure, wqLog, wqInstalled, wqAction, wqSourcePath, wqTargetPath};
19
20enum eWebAddressQuery { waqAddress = 1, waqWeb, waqIP, waqPort, waqHeader, waqSecure };
21
22enum SCA_WEB_ATTRIBUTES
23{
24 SWATTRIB_NOCONFIGUREIFEXISTS = 2
25};
26
27// structs
28struct SCA_WEB_ADDRESS
29{
30 WCHAR wzKey [MAX_DARWIN_KEY + 1];
31
32 WCHAR wzIP[MAX_DARWIN_COLUMN + 1];
33 int iPort;
34 WCHAR wzHeader[MAX_DARWIN_COLUMN + 1];
35 BOOL fSecure;
36};
37
38struct SCA_WEB
39{
40 // darwin information
41 WCHAR wzKey[MAX_DARWIN_KEY + 1];
42 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
43 BOOL fHasComponent;
44 INSTALLSTATE isInstalled;
45 INSTALLSTATE isAction;
46
47 // metabase information
48 WCHAR wzWebBase[METADATA_MAX_NAME_LEN + 1];
49 BOOL fBaseExists;
50
51 // iis configuation information
52 SCA_WEB_ADDRESS swaKey;
53
54 SCA_WEB_ADDRESS swaExtraAddresses[MAX_ADDRESSES_PER_WEB + 1];
55 DWORD cExtraAddresses;
56
57 WCHAR wzDirectory[MAX_PATH];
58 WCHAR wzDescription[MAX_DARWIN_COLUMN + 1];
59
60 int iState;
61 int iAttributes;
62
63 BOOL fHasProperties;
64 SCA_WEB_PROPERTIES swp;
65
66 BOOL fHasApplication;
67 SCA_WEB_APPLICATION swapp;
68
69 BOOL fHasSecurity;
70 int dwAccessPermissions;
71 int iConnectionTimeout;
72
73 SCA_MIMEMAP* psmm; // mime mappings
74 SCA_WEB_SSL_CERTIFICATE* pswscList;
75 SCA_HTTP_HEADER* pshhList;
76 SCA_WEB_ERROR* psweList;
77
78 BOOL fHasLog;
79 SCA_WEB_LOG swl;
80
81 SCA_WEB* pswNext;
82};
83
84
85// prototypes
86HRESULT ScaWebsRead(
87 __in IMSAdminBase* piMetabase,
88 __in SCA_MIMEMAP** ppsmmList,
89 __in SCA_WEB** ppswList,
90 __in SCA_HTTP_HEADER** pshhList,
91 __in SCA_WEB_ERROR** psweList,
92 __in WCA_WRAPQUERY_HANDLE hUserQuery,
93 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
94 __in WCA_WRAPQUERY_HANDLE hSslCertQuery,
95 __in WCA_WRAPQUERY_HANDLE hWebLogQuery,
96 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
97 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
98 __inout LPWSTR *ppwzCustomActionData
99 );
100
101HRESULT ScaWebsGetBase(
102 __in IMSAdminBase* piMetabase,
103 __in SCA_WEB* pswList,
104 __in LPCWSTR wzWeb,
105 __out_ecount(cchWebBase) LPWSTR wzWebBase,
106 __in DWORD cchWebBase,
107 __in WCA_WRAPQUERY_HANDLE hWrapQuery
108 );
109
110HRESULT ScaWebsInstall(
111 __in IMSAdminBase* piMetabase,
112 __in SCA_WEB* pswList,
113 __in SCA_APPPOOL * psapList
114 );
115
116HRESULT ScaWebsUninstall(
117 __in IMSAdminBase* piMetabase,
118 __in SCA_WEB* pswList
119 );
120
121void ScaWebsFreeList(
122 __in SCA_WEB* pswHead
123 );
diff --git a/src/ext/Iis/ca/scaweb7.cpp b/src/ext/Iis/ca/scaweb7.cpp
new file mode 100644
index 00000000..3ee781f2
--- /dev/null
+++ b/src/ext/Iis/ca/scaweb7.cpp
@@ -0,0 +1,953 @@
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//Adding this because delivery doesn't have the updated specstrings.h that windows build does
6#ifndef __in_xcount
7#define __in_xcount(size)
8#endif
9
10// prototypes for private helper functions
11static SCA_WEB7* NewWeb7();
12static SCA_WEB7* AddWebToList7(
13 __in SCA_WEB7* pswList,
14 __in SCA_WEB7* psw
15 );
16
17static HRESULT ScaWebFindBase7(
18 __in SCA_WEB7* pswList,
19 LPCWSTR wzDescription
20 );
21
22static HRESULT ScaWebWrite7(
23 __in SCA_WEB7* psw,
24 __in SCA_APPPOOL * psapList
25 );
26
27static HRESULT ScaWebRemove7(__in const SCA_WEB7* psw);
28
29
30HRESULT ScaWebsRead7(
31 __in SCA_WEB7** ppswList,
32 __in SCA_HTTP_HEADER** ppshhList,
33 __in SCA_WEB_ERROR** ppsweList,
34 __in WCA_WRAPQUERY_HANDLE hUserQuery,
35 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
36 __in WCA_WRAPQUERY_HANDLE hSslCertQuery,
37 __in WCA_WRAPQUERY_HANDLE hWebLogQuery,
38 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
39 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
40 __inout LPWSTR *ppwzCustomActionData
41 )
42{
43 Assert(ppswList);
44 WcaLog(LOGMSG_VERBOSE, "Entering ScaWebsRead7()");
45
46 HRESULT hr = S_OK;
47
48 MSIHANDLE hRec;
49 MSIHANDLE hRecAddresses;
50
51 WCA_WRAPQUERY_HANDLE hQueryWebSite = NULL;
52 WCA_WRAPQUERY_HANDLE hQueryWebAddress = NULL;
53
54 SCA_WEB7* psw = NULL;
55 LPWSTR pwzData = NULL;
56
57 DWORD dwLen = 0;
58 errno_t error = EINVAL;
59
60 // check to see what tables are available
61 hr = WcaBeginUnwrapQuery(&hQueryWebSite, ppwzCustomActionData);
62 ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead");
63
64 hr = WcaBeginUnwrapQuery(&hQueryWebAddress, ppwzCustomActionData);
65 ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead");
66
67
68 if (0 == WcaGetQueryRecords(hQueryWebSite) || 0 == WcaGetQueryRecords(hQueryWebAddress))
69 {
70 WcaLog(LOGMSG_VERBOSE, "Required tables not present");
71 ExitFunction1(hr = S_FALSE);
72 }
73
74 // loop through all the webs
75 while (S_OK == (hr = WcaFetchWrappedRecord(hQueryWebSite, &hRec)))
76 {
77 psw = NewWeb7();
78 if (!psw)
79 {
80 hr = E_OUTOFMEMORY;
81 break;
82 }
83
84 // get the darwin information
85 hr = WcaGetRecordString(hRec, wqWeb, &pwzData);
86 ExitOnFailure(hr, "Failed to get Web");
87 hr = ::StringCchCopyW(psw->wzKey, countof(psw->wzKey), pwzData);
88 ExitOnFailure(hr, "Failed to copy key string to web object");
89
90 // get component install state
91 hr = WcaGetRecordString(hRec, wqComponent, &pwzData);
92 ExitOnFailure(hr, "Failed to get Component for Web");
93 hr = ::StringCchCopyW(psw->wzComponent, countof(psw->wzComponent), pwzData);
94 ExitOnFailure(hr, "Failed to copy component string to web object");
95 if (*(psw->wzComponent))
96 {
97 psw->fHasComponent = TRUE;
98
99 hr = WcaGetRecordInteger(hRec, wqInstalled, (int *)&psw->isInstalled);
100 ExitOnFailure(hr, "Failed to get web Component's installed state");
101
102 WcaGetRecordInteger(hRec, wqAction, (int *)&psw->isAction);
103 ExitOnFailure(hr, "Failed to get web Component's action state");
104 }
105
106 // Get the web's description.
107 hr = WcaGetRecordString(hRec, wqDescription, &pwzData);
108 ExitOnFailure(hr, "Failed to get Description for Web");
109 hr = ::StringCchCopyW(psw->wzDescription, countof(psw->wzDescription), pwzData);
110 ExitOnFailure(hr, "Failed to copy description string to web object");
111
112 //get web's site Id
113 hr = WcaGetRecordInteger(hRec, wqId, &psw->iSiteId);
114 ExitOnFailure(hr, "Failed to get SiteId for Web");
115
116 // get the web's key address (Bindings)
117 hr = WcaGetRecordString(hRec, wqAddress, &pwzData);
118 ExitOnFailure(hr, "Failed to get Address for Web");
119 hr = ::StringCchCopyW(psw->swaBinding.wzKey, countof(psw->swaBinding.wzKey), pwzData);
120 ExitOnFailure(hr, "Failed to copy web binding key");
121
122 hr = WcaGetRecordString(hRec, wqIP, &pwzData);
123 ExitOnFailure(hr, "Failed to get IP for Web");
124 hr = ::StringCchCopyW(psw->swaBinding.wzIP, countof(psw->swaBinding.wzIP), pwzData);
125 ExitOnFailure(hr, "Failed to copy web IP");
126
127 hr = WcaGetRecordString(hRec, wqPort, &pwzData);
128 ExitOnFailure(hr, "Failed to get Web Address port");
129 psw->swaBinding.iPort = wcstol(pwzData, NULL, 10);
130
131 hr = WcaGetRecordString(hRec, wqHeader, &pwzData);
132 ExitOnFailure(hr, "Failed to get Header for Web");
133 hr = ::StringCchCopyW(psw->swaBinding.wzHeader, countof(psw->swaBinding.wzHeader), pwzData);
134 ExitOnFailure(hr, "Failed to copy web header");
135
136 hr = WcaGetRecordInteger(hRec, wqSecure, &psw->swaBinding.fSecure);
137 ExitOnFailure(hr, "Failed to get if Web is secure");
138 if (S_FALSE == hr)
139 {
140 psw->swaBinding.fSecure = FALSE;
141 }
142
143 // look to see if site exists
144 dwLen = METADATA_MAX_NAME_LEN;
145 hr = ScaWebFindBase7(*ppswList, psw->wzDescription);
146
147 // If we didn't find a web in memory, ignore it - during execute CA
148 // if the site truly does not exist then there will be an error.
149 if (S_OK == hr)
150 {
151 // site exists in config
152 psw->fBaseExists = TRUE;
153 }
154 else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
155 {
156 hr = S_OK;
157
158 // site does not exists in config
159 psw->fBaseExists = FALSE;
160 }
161 ExitOnFailure(hr, "Failed to find web site");
162
163 // get any extra web addresses
164 WcaFetchWrappedReset(hQueryWebAddress);
165
166 while (S_OK == (hr = WcaFetchWrappedRecordWhereString(hQueryWebAddress, 2, psw->wzKey, &hRecAddresses)))
167 {
168 if (MAX_ADDRESSES_PER_WEB <= psw->cExtraAddresses)
169 {
170 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
171 ExitOnFailure(hr, "Failure to get more extra web addresses, max exceeded.");
172 }
173
174 hr = WcaGetRecordString(hRecAddresses, waqAddress, &pwzData);
175 ExitOnFailure(hr, "Failed to get extra web Address");
176
177 // if this isn't the key address add it
178 if (0 != lstrcmpW(pwzData, psw->swaBinding.wzKey))
179 {
180 hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey,
181 countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey), pwzData);
182 ExitOnFailure(hr, "Failed to copy web binding key");
183
184 hr = WcaGetRecordString(hRecAddresses, waqIP, &pwzData);
185 ExitOnFailure(hr, "Failed to get extra web IP");
186 hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP), pwzData);
187 ExitOnFailure(hr, "Failed to copy web binding IP");
188
189 hr = WcaGetRecordString(hRecAddresses, waqPort, &pwzData);
190 ExitOnFailure(hr, "Failed to get port for extra web IP");
191 psw->swaExtraAddresses[psw->cExtraAddresses].iPort= wcstol(pwzData, NULL, 10);
192
193 // errno is set to ERANGE if overflow or underflow occurs
194 _get_errno(&error);
195
196 if (ERANGE == error)
197 {
198 hr = E_INVALIDARG;
199 ExitOnFailure(hr, "Failed to convert web Port address");
200 }
201
202 hr = WcaGetRecordString(hRecAddresses, waqHeader, &pwzData);
203 ExitOnFailure(hr, "Failed to get header for extra web IP");
204 hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader), pwzData);
205 ExitOnFailure(hr, "Failed to copy web binding header");
206
207 hr = WcaGetRecordInteger(hRecAddresses, waqSecure, &psw->swaExtraAddresses[psw->cExtraAddresses].fSecure);
208 ExitOnFailure(hr, "Failed to get if secure extra web IP");
209 if (S_FALSE == hr)
210 {
211 psw->swaExtraAddresses[psw->cExtraAddresses].fSecure = FALSE;
212 }
213
214 ++psw->cExtraAddresses;
215 }
216 }
217
218 if (E_NOMOREITEMS == hr)
219 {
220 hr = S_OK;
221 }
222 ExitOnFailure(hr, "Failure occured while getting extra web addresses");
223
224 //
225 // Connection time out
226 //
227 hr = WcaGetRecordInteger(hRec, wqConnectionTimeout, &psw->iConnectionTimeout);
228 ExitOnFailure(hr, "Failed to get connection timeout for Web");
229
230 if (psw->fHasComponent) // If we're installing it, it needs a dir
231 {
232 // get the web's directory
233 if (INSTALLSTATE_SOURCE == psw->isAction)
234 {
235 hr = WcaGetRecordString(hRec, wqSourcePath, &pwzData);
236 }
237 else
238 {
239 hr = WcaGetRecordString(hRec, wqTargetPath, &pwzData);
240 }
241 ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory");
242
243 dwLen = lstrlenW(pwzData);
244 // remove trailing backslash
245 if (dwLen > 0 && pwzData[dwLen-1] == L'\\')
246 {
247 pwzData[dwLen-1] = 0;
248 }
249 hr = ::StringCchCopyW(psw->wzDirectory, countof(psw->wzDirectory), pwzData);
250 ExitOnFailure(hr, "Failed to copy web dir: '%ls'", pwzData);
251
252 }
253
254 hr = WcaGetRecordInteger(hRec, wqState, &psw->iState);
255 ExitOnFailure(hr, "Failed to get state for Web");
256
257 hr = WcaGetRecordInteger(hRec, wqAttributes, &psw->iAttributes);
258 ExitOnFailure(hr, "Failed to get attributes for Web");
259
260 // get the dir properties for this web
261 hr = WcaGetRecordString(hRec, wqProperties, &pwzData);
262 ExitOnFailure(hr, "Failed to get directory properties for Web");
263 if (*pwzData)
264 {
265 hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &psw->swp);
266 ExitOnFailure(hr, "Failed to get directory properties for Web");
267
268 psw->fHasProperties = TRUE;
269 }
270
271 // get the application information for this web
272 hr = WcaGetRecordString(hRec, wqApplication, &pwzData);
273 ExitOnFailure(hr, "Failed to get application identifier for Web");
274 if (*pwzData)
275 {
276 hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &psw->swapp);
277 ExitOnFailure(hr, "Failed to get application for Web");
278
279 psw->fHasApplication = TRUE;
280 }
281
282 // get the SSL certificates
283 hr = ScaSslCertificateRead(psw->wzKey, hSslCertQuery, &(psw->pswscList));
284 ExitOnFailure(hr, "Failed to get SSL Certificates.");
285
286 // get the custom headers
287 if (*ppshhList)
288 {
289 hr = ScaGetHttpHeader(hhptWeb, psw->wzKey, ppshhList, &(psw->pshhList));
290 ExitOnFailure(hr, "Failed to get Custom HTTP Headers");
291 }
292
293 // get the errors
294 if (*ppsweList)
295 {
296 hr = ScaGetWebError(weptWeb, psw->wzKey, ppsweList, &(psw->psweList));
297 ExitOnFailure(hr, "Failed to get Custom Errors");
298 }
299
300 // get the log information for this web
301 hr = WcaGetRecordString(hRec, wqLog, &pwzData);
302 ExitOnFailure(hr, "Failed to get log identifier for Web");
303 if (*pwzData)
304 {
305 hr = ScaGetWebLog7(pwzData, hWebLogQuery, &psw->swl);
306 ExitOnFailure(hr, "Failed to get Log for Web.");
307 psw->fHasLog = TRUE;
308 }
309
310 *ppswList = AddWebToList7(*ppswList, psw);
311 psw = NULL; // set the web NULL so it doesn't accidentally get freed below
312 }
313
314 if (E_NOMOREITEMS == hr)
315 {
316 hr = S_OK;
317 }
318
319LExit:
320 // if anything was left over after an error clean it all up
321 WcaFinishUnwrapQuery(hQueryWebSite);
322 WcaFinishUnwrapQuery(hQueryWebAddress);
323
324 ScaWebsFreeList7(psw);
325
326 ReleaseStr(pwzData);
327 WcaLog(LOGMSG_VERBOSE, "Exiting ScaWebsRead7()");
328
329 return hr;
330}
331
332BOOL CompareBinding(
333 __in IAppHostElement* pBinding,
334 __in LPVOID pContext
335 )
336{
337 BOOL fFound = FALSE;
338 HRESULT hr = S_OK;
339 LPWSTR pwzBindingInfo = NULL;
340 SCA_WEB7* psw = (SCA_WEB7*)pContext;
341
342 hr = Iis7GetPropertyString(pBinding, IIS_CONFIG_BINDINGINFO, &pwzBindingInfo);
343 ExitOnFailure(hr, "Failed to get bindinginfo for binding element");
344
345 LPWSTR pwzExists = pwzBindingInfo;
346 // Break down the address into its constituent parts (IP:Port:Header).
347 // Taken from IIS6 CA code for compatibility
348 while (S_OK == hr && *pwzExists)
349 {
350 LPCWSTR pwzIPExists = pwzExists;
351 pwzExists = const_cast<LPWSTR>(wcsstr(pwzIPExists, L":"));
352 if (NULL == pwzExists)
353 {
354 ExitFunction();
355 }
356 *pwzExists = L'\0';
357
358 LPCWSTR pwzPortExists = pwzExists + 1;
359 pwzExists = const_cast<LPWSTR>(wcsstr(pwzPortExists, L":"));
360 if (NULL == pwzExists)
361 {
362 ExitFunction();
363 }
364 *pwzExists = L'\0';
365 int iPortExists = wcstol(pwzPortExists, NULL, 10);
366
367 LPCWSTR pwzHeaderExists = pwzExists + 1;
368
369 BOOL fIpMatches = (0 == lstrcmpW(psw->swaBinding.wzIP, pwzIPExists)); // Explicit IP match
370 fIpMatches |= (0 == lstrcmpW(psw->swaBinding.wzIP, L"*")); // Authored * matches any IP
371 fIpMatches |= ('\0' != psw->swaBinding.wzIP) && // Unauthored IP
372 (0 == lstrcmpW(pwzIPExists, L"*")); // matches the All Unassigned IP : '*'
373
374 // compare the passed in address with the address listed for this web
375 if (fIpMatches && psw->swaBinding.iPort == iPortExists &&
376 0 == lstrcmpW(psw->swaBinding.wzHeader, pwzHeaderExists))
377 {
378 fFound = TRUE;
379 break;
380 }
381
382 // move to the next block of data, this may move beyond the available
383 // data and exit the while loop above.
384 pwzExists = const_cast<LPWSTR>(pwzHeaderExists + lstrlenW(pwzHeaderExists));
385 }
386
387LExit:
388 WcaLog(LOGMSG_VERBOSE, "Site with binding %ls %s a match", pwzBindingInfo, fFound ? "is" : "is not");
389 ReleaseNullStr(pwzBindingInfo);
390 return fFound;
391}
392
393BOOL EnumSiteCompareBinding(
394 __in IAppHostElement* pSite,
395 __in LPVOID pContext
396 )
397{
398 BOOL fFound = FALSE;
399 HRESULT hr = S_OK;
400 SCA_WEB7* psw = (SCA_WEB7*)pContext;
401 IAppHostChildElementCollection *pSiteChildren = NULL;
402 IAppHostElement *pBindings = NULL;
403 IAppHostElementCollection *pBindingsCollection = NULL;
404 IAppHostElement *pBinding = NULL;
405 VARIANT vtProp;
406 VariantInit(&vtProp);
407
408 hr = pSite->get_ChildElements(&pSiteChildren);
409 ExitOnFailure(hr, "Failed get site child elements collection");
410
411 vtProp.vt = VT_BSTR;
412 vtProp.bstrVal = ::SysAllocString(IIS_CONFIG_BINDINGS);
413 hr = pSiteChildren->get_Item(vtProp, &pBindings);
414 ExitOnFailure(hr, "Failed get bindings element");
415
416 hr = pBindings->get_Collection(&pBindingsCollection);
417 ExitOnFailure(hr, "Failed get bindings collection");
418
419 WcaLog(LOGMSG_VERBOSE, "Searching for site with binding %ls:%d:%ls", psw->swaBinding.wzIP, psw->swaBinding.iPort, psw->swaBinding.wzHeader);
420
421 hr = Iis7EnumAppHostElements(pBindingsCollection, CompareBinding, psw, &pBinding, NULL);
422 ExitOnFailure(hr, "Failed search bindings collection");
423
424 fFound = NULL != pBinding;
425LExit:
426 VariantClear(&vtProp);
427 ReleaseNullObject(pSiteChildren);
428 ReleaseNullObject(pBindings);
429 ReleaseNullObject(pBindingsCollection);
430 ReleaseNullObject(pBinding);
431 return fFound;
432}
433
434HRESULT ScaWebSearch7(
435 __in SCA_WEB7* psw,
436 __deref_out_z_opt LPWSTR* pswWeb,
437 __out_opt BOOL* pfFound
438 )
439{
440 HRESULT hr = S_OK;
441 BOOL fInitializedCom = FALSE;
442 BSTR bstrSites = NULL;
443 BSTR bstrAppHostRoot = NULL;
444 IAppHostAdminManager *pAdminMgr = NULL;
445 IAppHostElement *pSites = NULL;
446 IAppHostElementCollection *pCollection = NULL;
447 IAppHostElement *pSite = NULL;
448
449 if (NULL != pswWeb)
450 {
451 ReleaseNullStr(*pswWeb);
452 }
453
454 if (NULL != pfFound)
455 {
456 *pfFound = FALSE;
457 }
458
459 hr = ::CoInitialize(NULL);
460 ExitOnFailure(hr, "Failed to initialize COM");
461 fInitializedCom = TRUE;
462
463 hr = CoCreateInstance(__uuidof(AppHostAdminManager), NULL, CLSCTX_INPROC_SERVER, __uuidof(IAppHostAdminManager), reinterpret_cast<void**> (&pAdminMgr));
464 if (REGDB_E_CLASSNOTREG == hr)
465 {
466 WcaLog(LOGMSG_VERBOSE, "AppHostAdminManager was not registered, cannot find site.");
467 hr = S_OK;
468 ExitFunction();
469 }
470 ExitOnFailure(hr, "Failed to CoCreate IAppHostAdminManager");
471
472 bstrSites = ::SysAllocString(IIS_CONFIG_SITES_SECTION);
473 ExitOnNull(bstrSites, hr, E_OUTOFMEMORY, "Failed to allocate sites string.");
474
475 bstrAppHostRoot = ::SysAllocString(IIS_CONFIG_APPHOST_ROOT);
476 ExitOnNull(bstrAppHostRoot, hr, E_OUTOFMEMORY, "Failed to allocate host root string.");
477
478 hr = pAdminMgr->GetAdminSection(bstrSites, bstrAppHostRoot, &pSites);
479 ExitOnFailure(hr, "Failed get sites section");
480 ExitOnNull(pSites, hr, ERROR_FILE_NOT_FOUND, "Failed get sites section object");
481
482 hr = pSites->get_Collection(&pCollection);
483 ExitOnFailure(hr, "Failed get sites collection");
484
485 // not explicitly doing a Description search
486 if (-1 != psw->iSiteId)
487 {
488 if (MSI_NULL_INTEGER == psw->iSiteId)
489 {
490 // Enumerate sites & determine if the binding matches
491 hr = Iis7EnumAppHostElements(pCollection, EnumSiteCompareBinding, psw, &pSite, NULL);
492 ExitOnFailure(hr, "Failed locate site by ID");
493 }
494 else
495 {
496 // Find a site with ID matches
497 hr = Iis7FindAppHostElementInteger(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_ID, psw->iSiteId, &pSite, NULL);
498 ExitOnFailure(hr, "Failed locate site by ID");
499 }
500 }
501
502 if (NULL == pSite)
503 {
504 // Find a site with Name that matches
505 hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_NAME, psw->wzDescription, &pSite, NULL);
506 ExitOnFailure(hr, "Failed locate site by ID");
507 }
508
509 if (NULL != pSite)
510 {
511 if (NULL != pfFound)
512 {
513 *pfFound = TRUE;
514 }
515
516 if (NULL != pswWeb)
517 {
518 // We found a site, return its description
519 hr = Iis7GetPropertyString(pSite, IIS_CONFIG_NAME, pswWeb);
520 ExitOnFailure(hr, "Failed get site name");
521 }
522 }
523LExit:
524 ReleaseNullObject(pAdminMgr);
525 ReleaseNullObject(pSites);
526 ReleaseNullObject(pCollection);
527 ReleaseNullObject(pSite);
528 ReleaseBSTR(bstrAppHostRoot);
529 ReleaseBSTR(bstrSites);
530
531 if (fInitializedCom)
532 {
533 ::CoUninitialize();
534 }
535 return hr;
536}
537
538
539HRESULT ScaWebsGetBase7(
540 __in SCA_WEB7* pswList,
541 __in LPCWSTR pswWebKey,
542 __out_ecount(cchDest) LPWSTR pswWeb,
543 __in DWORD_PTR cchDest
544 )
545{
546 HRESULT hr = S_OK;
547 BOOL fFound = FALSE;
548 SCA_WEB7* psw = pswList;
549 LPWSTR wzSiteName = NULL;
550
551 *pswWeb = '/0';
552
553 //looking for psw->wzKey == pswWebKey
554 while(psw)
555 {
556 if (0 == wcscmp(pswWebKey, psw->wzKey))
557 {
558 fFound = TRUE;
559 break;
560 }
561 psw = psw->pswNext;
562 }
563
564 if (!fFound)
565 {
566 ExitFunction1(hr = S_FALSE);
567 }
568
569 // Search if we're not installing the site
570 if (!psw->fHasComponent || (psw->iAttributes & SWATTRIB_NOCONFIGUREIFEXISTS))
571 {
572 // We are not installing this website. Search for it in IIS config
573 hr = ScaWebSearch7(psw, &wzSiteName, NULL);
574 ExitOnFailure(hr, "Failed to search for Website");
575
576 if (NULL != wzSiteName)
577 {
578 hr = ::StringCchCopyW(pswWeb, cchDest, wzSiteName);
579 ExitOnFailure(hr, "Failed to set Website description for located Website");
580 }
581 }
582
583 if ('/0' == *pswWeb)
584 {
585 WcaLog(LOGMSG_VERBOSE, "Could not find Web: %ls, defaulting to %ls", psw->wzKey, psw->wzDescription);
586 // Default to the provided description, the Exec CA will locate by description
587 hr = ::StringCchCopyW(pswWeb, cchDest, psw->wzDescription);
588 ExitOnFailure(hr, "Failed to set Website description to default");
589 }
590LExit:
591 ReleaseNullStr(wzSiteName);
592 return hr;
593}
594
595HRESULT ScaWebsInstall7(
596 __in SCA_WEB7* pswList,
597 __in SCA_APPPOOL * psapList
598 )
599{
600 HRESULT hr = S_OK;
601 SCA_WEB7* psw = pswList;
602
603 while (psw)
604 {
605 // if we are installing the web site
606 if (psw->fHasComponent && WcaIsInstalling(psw->isInstalled, psw->isAction))
607 {
608 hr = ScaWebWrite7(psw, psapList);
609 ExitOnFailure(hr, "failed to write web '%ls' to metabase", psw->wzKey);
610 }
611
612 psw = psw->pswNext;
613 }
614
615LExit:
616 return hr;
617}
618
619
620HRESULT ScaWebsUninstall7(
621 __in SCA_WEB7* pswList
622 )
623{
624 HRESULT hr = S_OK;
625 SCA_WEB7* psw = pswList;
626
627 while (psw)
628 {
629 if (psw->fHasComponent && WcaIsUninstalling(psw->isInstalled, psw->isAction))
630 {
631 // If someone
632 hr = ScaWebRemove7(psw);
633 ExitOnFailure(hr, "Failed to remove web '%ls' ", psw->wzKey);
634 }
635
636 psw = psw->pswNext;
637 }
638
639LExit:
640 return hr;
641}
642
643
644void ScaWebsFreeList7(__in SCA_WEB7* pswList)
645{
646 SCA_WEB7* pswDelete = pswList;
647 while (pswList)
648 {
649 pswDelete = pswList;
650 pswList = pswList->pswNext;
651
652 // Free the SSL, headers and errors list first
653 ScaSslCertificateFreeList(pswDelete->pswscList);
654 ScaHttpHeaderFreeList(pswDelete->pshhList);
655 ScaWebErrorFreeList(pswDelete->psweList);
656
657 MemFree(pswDelete);
658 }
659}
660
661
662// private helper functions
663
664static SCA_WEB7* NewWeb7()
665{
666 SCA_WEB7* psw = (SCA_WEB7*)MemAlloc(sizeof(SCA_WEB7), TRUE);
667 Assert(psw);
668 return psw;
669}
670
671
672static SCA_WEB7* AddWebToList7(
673 __in SCA_WEB7* pswList,
674 __in SCA_WEB7* psw
675 )
676{
677 if (pswList)
678 {
679 SCA_WEB7* pswTemp = pswList;
680 while (pswTemp->pswNext)
681 {
682 pswTemp = pswTemp->pswNext;
683 }
684
685 pswTemp->pswNext = psw;
686 }
687 else
688 {
689 pswList = psw;
690 }
691
692 return pswList;
693}
694
695
696static HRESULT ScaWebFindBase7(
697 __in SCA_WEB7* pswList,
698 __in_z LPCWSTR wzDescription
699 )
700{
701 HRESULT hr = S_OK;
702 BOOL fFound = FALSE;
703
704 // try to find the web in memory first
705 for (SCA_WEB7* psw = pswList; psw; psw = psw->pswNext)
706 {
707 if (0 == wcscmp(wzDescription, psw->wzDescription))
708 {
709 fFound = TRUE;
710 break;
711 }
712 }
713
714 if (!fFound)
715 {
716 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
717 }
718
719 return hr;
720}
721
722
723static HRESULT ScaWebWrite7(
724 __in SCA_WEB7* psw,
725 __in SCA_APPPOOL * psapList
726 )
727{
728 HRESULT hr = S_OK;
729
730 BOOL fExists = FALSE;
731 UINT ui = 0;
732 WCHAR wzIP[64];
733 WCHAR wzBinding[1024];
734 WCHAR wzAppPoolName[MAX_PATH];
735
736 //
737 // determine if site must be new
738 //
739 if (psw->iAttributes & SWATTRIB_NOCONFIGUREIFEXISTS)
740 {
741 // Check if site already exists.
742 hr = ScaWebSearch7(psw, NULL, &fExists);
743 ExitOnFailure(hr, "Failed to search for web: %ls", psw->wzKey);
744
745 if (fExists)
746 {
747 hr = S_FALSE;
748 WcaLog(LOGMSG_VERBOSE, "Skipping configuration of existing web: %ls", psw->wzKey);
749 ExitFunction();
750 }
751 }
752
753 //create a site
754 hr = ScaWriteConfigID(IIS_SITE);
755 ExitOnFailure(hr, "Failed write site ID");
756
757 hr = ScaWriteConfigID(IIS_CREATE);
758 ExitOnFailure(hr, "Failed write site ID create action");
759
760 //Site Name
761 hr = ScaWriteConfigString(psw->wzDescription); //Site Name
762 ExitOnFailure(hr, "Failed write site desc");
763
764 //Site Id -- value is MSI_NULL_INTEGER if not set in WIX
765 hr = ScaWriteConfigInteger(psw->iSiteId); //SiteID
766 ExitOnFailure(hr, "Failed write site id value");
767
768 //Site Auto Start -- value is MSI_NULL_INTEGER if not set in WIX
769 hr = ScaWriteConfigInteger(psw->iState); // serverAutoStart
770 ExitOnFailure(hr, "Failed write site autostart");
771
772 hr = ScaWriteConfigInteger(psw->iConnectionTimeout); //limits/connectionTimeout
773 ExitOnFailure(hr, "Failed write site timeout");
774
775 //create default application
776 hr = ScaWriteConfigID(IIS_APPLICATION);
777 ExitOnFailure(hr, "Failed write app ID");
778 hr = ScaWriteConfigID(IIS_CREATE);
779 ExitOnFailure(hr, "Failed write app action ID");
780 hr = ScaWriteConfigString(psw->wzDescription); //site name key
781 ExitOnFailure(hr, "Failed write app desc");
782 hr = ScaWriteConfigString(L"/"); // App Path (default)
783 ExitOnFailure(hr, "Failed write app def path /");
784
785 if (psw->fHasApplication && *psw->swapp.wzAppPool)
786 {
787 hr = ScaFindAppPool7(psw->swapp.wzAppPool, wzAppPoolName, countof(wzAppPoolName), psapList);
788 ExitOnFailure(hr, "Failed to read app pool from application");
789
790 hr = ScaWriteConfigString(wzAppPoolName);
791 ExitOnFailure(hr, "Failed write app appPool");
792 }
793 else
794 {
795 hr = ScaWriteConfigString(L"");
796 ExitOnFailure(hr, "Failed write app appPool");
797 }
798
799 //create vdir for default application
800 hr = ScaWriteConfigID(IIS_VDIR);
801 ExitOnFailure(hr, "Failed write vdir ID");
802 hr = ScaWriteConfigID(IIS_CREATE);
803 ExitOnFailure(hr, "Failed write vdir action");
804 hr = ScaWriteConfigString(psw->wzDescription); //site name key
805 ExitOnFailure(hr, "Failed write vdir desc");
806 hr = ScaWriteConfigString(L"/"); //vdir path (default)
807 ExitOnFailure(hr, "Failed write vdir app");
808 hr = ScaWriteConfigString(psw->wzDirectory); //physical dir
809 ExitOnFailure(hr, "Failed write vdir dir");
810
811 //create bindings for site
812 hr = ScaWriteConfigID(IIS_BINDING);
813 ExitOnFailure(hr, "Failed write binding ID");
814 hr = ScaWriteConfigID(IIS_CREATE);
815 ExitOnFailure(hr, "Failed write binding action ID");
816 hr = ScaWriteConfigString(psw->wzDescription); //site name key
817 ExitOnFailure(hr, "Failed write binding site key");
818
819 if (psw->swaBinding.fSecure)
820 {
821 hr = ScaWriteConfigString(L"https"); // binding protocol
822 ExitOnFailure(hr, "Failed write binding https");
823 }
824 else
825 {
826 hr = ScaWriteConfigString(L"http"); // binding protocol
827 ExitOnFailure(hr, "Failed write binding http");
828 }
829
830 // set the IP address appropriately
831 if (0 == wcscmp(psw->swaBinding.wzIP, L""))
832 {
833 hr = ::StringCchCopyW(wzIP, countof(wzIP), L"*"); // if no IP specified = add *
834 }
835 else
836 {
837#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
838 hr = ::StringCchCopyW(wzIP, countof(wzIP), psw->swaBinding.wzIP); // else leave untouched
839 }
840 ExitOnFailure(hr, "Failed to copy IP string");
841
842 hr = ::StringCchPrintfW(wzBinding, countof(wzBinding), L"%s:%d:%s", wzIP, psw->swaBinding.iPort, psw->swaBinding.wzHeader);
843 ExitOnFailure(hr, "Failed to format IP:Port:Header binding string");
844
845 // write bindings CAData
846 hr = ScaWriteConfigString(wzBinding) ; //binding info
847 ExitOnFailure(hr, "Failed to create web bindings");
848
849 for (ui = 0; (ui < MAX_ADDRESSES_PER_WEB) && (ui < psw->cExtraAddresses); ++ui)
850 {
851 // set the IP address appropriately
852 if (0 == wcscmp(psw->swaExtraAddresses[ui].wzIP, L""))
853 {
854 hr = ::StringCchCopyW(wzIP, countof(wzIP), L"*"); // if no IP specified = add *
855 }
856 else
857 {
858#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
859 hr = ::StringCchCopyW(wzIP, countof(wzIP), psw->swaExtraAddresses[ui].wzIP); //else leave untouched
860 }
861 ExitOnFailure(hr, "Failed to copy web IP string");
862
863 hr = ::StringCchPrintfW(wzBinding, countof(wzBinding), L"%s:%d:%s", wzIP, psw->swaExtraAddresses[ui].iPort, psw->swaExtraAddresses[ui].wzHeader);
864 ExitOnFailure(hr, "Failed to copy web IP");
865
866 //create bindings for site
867 hr = ScaWriteConfigID(IIS_BINDING);
868 ExitOnFailure(hr, "Failed write binding ID");
869 hr = ScaWriteConfigID(IIS_CREATE);
870 ExitOnFailure(hr, "Failed write binding action");
871 hr = ScaWriteConfigString(psw->wzDescription); //site name key
872 ExitOnFailure(hr, "Failed write binding web name");
873
874 if (psw->swaExtraAddresses[ui].fSecure)
875 {
876 hr = ScaWriteConfigString(L"https"); // binding protocol
877 }
878 else
879 {
880 hr = ScaWriteConfigString(L"http"); // binding protocol
881 }
882 ExitOnFailure(hr, "Failed write binding http(s)");
883
884 // write bindings CAData
885 hr = ScaWriteConfigString(wzBinding) ; //binding info
886 ExitOnFailure(hr, "Failed write binding info");
887 }
888
889 // write the web dirproperties information
890 if (psw->fHasProperties)
891 {
892 // dir properties are for the default application of the web
893 // with location '/'
894 hr = ScaWriteWebDirProperties7(psw->wzDescription, L"/", &psw->swp);
895 ExitOnFailure(hr, "Failed to write web security information to metabase");
896 }
897
898 //// write the application information
899 if (psw->fHasApplication)
900 {
901 hr = ScaWriteWebApplication7(psw->wzDescription, L"/", &psw->swapp, psapList);
902 ExitOnFailure(hr, "Failed to write web application information to metabase");
903 }
904
905 // write the SSL certificate information
906 if (psw->pswscList)
907 {
908 hr = ScaSslCertificateWrite7(psw->wzDescription, psw->pswscList);
909 ExitOnFailure(hr, "Failed to write SSL certificates for Web site: %ls", psw->wzKey);
910 }
911
912 // write the headers
913 if (psw->pshhList)
914 {
915 hr = ScaWriteHttpHeader7(psw->wzDescription, L"/", psw->pshhList);
916 ExitOnFailure(hr, "Failed to write custom HTTP headers for Web site: %ls", psw->wzKey);
917 }
918
919 // write the errors
920 if (psw->psweList)
921 {
922 hr = ScaWriteWebError7(psw->wzDescription, L"/", psw->psweList);
923 ExitOnFailure(hr, "Failed to write custom web errors for Web site: %ls", psw->wzKey);
924 }
925
926 // write the log information to the metabase
927 if (psw->fHasLog)
928 {
929 hr = ScaWriteWebLog7(psw->wzDescription, &psw->swl);
930 ExitOnFailure(hr, "Failed to write web log information to metabase");
931 }
932
933LExit:
934 return hr;
935}
936
937
938static HRESULT ScaWebRemove7(
939 __in const SCA_WEB7* psw
940 )
941{
942 HRESULT hr = S_OK;
943
944 hr = ScaWriteConfigID(IIS_SITE);
945 ExitOnFailure(hr, "Failed write site ID");
946 hr = ScaWriteConfigID(IIS_DELETE);
947 ExitOnFailure(hr, "Failed write site action");
948 hr = ScaWriteConfigString(psw->wzDescription); //Site Name
949 ExitOnFailure(hr, "Failed write site name");
950
951LExit:
952 return hr;
953}
diff --git a/src/ext/Iis/ca/scaweb7.h b/src/ext/Iis/ca/scaweb7.h
new file mode 100644
index 00000000..78946756
--- /dev/null
+++ b/src/ext/Iis/ca/scaweb7.h
@@ -0,0 +1,97 @@
1#pragma once
2// 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.
3
4
5#include "scawebapp.h"
6#include "scawebprop.h"
7#include "scahttpheader.h"
8#include "scaweberr.h"
9#include "scassl.h"
10#include "scaapppool.h"
11#include "scaweblog.h"
12
13// globals
14#define MAX_ADDRESSES_PER_WEB 10
15
16// structs
17struct SCA_WEB7
18{
19 // darwin information
20 WCHAR wzKey[MAX_DARWIN_KEY + 1];
21 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
22 BOOL fHasComponent;
23 INSTALLSTATE isInstalled;
24 INSTALLSTATE isAction;
25
26 int iSiteId;
27
28 // metabase information
29 WCHAR wzWebBase[METADATA_MAX_NAME_LEN + 1];
30 BOOL fBaseExists;
31
32 // iis configuation information
33 SCA_WEB_ADDRESS swaBinding;
34
35 SCA_WEB_ADDRESS swaExtraAddresses[MAX_ADDRESSES_PER_WEB + 1];
36 DWORD cExtraAddresses;
37
38 WCHAR wzDirectory[MAX_PATH];
39 WCHAR wzDescription[MAX_DARWIN_COLUMN + 1];
40
41 int iState;
42 int iAttributes;
43
44 BOOL fHasProperties;
45 SCA_WEB_PROPERTIES swp;
46
47 BOOL fHasApplication;
48 SCA_WEB_APPLICATION swapp;
49
50 BOOL fHasSecurity;
51 int dwAccessPermissions;
52 int iConnectionTimeout;
53
54 SCA_WEB_SSL_CERTIFICATE* pswscList;
55 SCA_HTTP_HEADER* pshhList;
56 SCA_WEB_ERROR* psweList;
57
58 BOOL fHasLog;
59 SCA_WEB_LOG swl;
60
61 SCA_WEB7* pswNext;
62};
63
64
65// prototypes
66HRESULT ScaWebsRead7(
67 __in SCA_WEB7** ppswList,
68 __in SCA_HTTP_HEADER** ppshhList,
69 __in SCA_WEB_ERROR** ppsweList,
70 __in WCA_WRAPQUERY_HANDLE hUserQuery,
71 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
72 __in WCA_WRAPQUERY_HANDLE hSslCertQuery,
73 __in WCA_WRAPQUERY_HANDLE hWebLogQuery,
74 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
75 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
76 __inout LPWSTR *ppwzCustomActionData
77 );
78
79HRESULT ScaWebsGetBase7(
80 __in SCA_WEB7* pswList,
81 __in LPCWSTR pswWebKey,
82 __out_ecount(cchDest) LPWSTR pswWeb,
83 __in DWORD_PTR cchDest
84 );
85
86HRESULT ScaWebsInstall7(
87 __in SCA_WEB7* pswList,
88 __in SCA_APPPOOL * psapList
89 );
90
91HRESULT ScaWebsUninstall7(
92 __in SCA_WEB7* pswList
93 );
94
95void ScaWebsFreeList7(
96 __in SCA_WEB7* pswHead
97 );
diff --git a/src/ext/Iis/ca/scawebapp.cpp b/src/ext/Iis/ca/scawebapp.cpp
new file mode 100644
index 00000000..a7e9cf82
--- /dev/null
+++ b/src/ext/Iis/ca/scawebapp.cpp
@@ -0,0 +1,194 @@
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// sql queries
6enum eWebApplicationQuery { wappqName = 1, wappqIsolation, wappqAllowSession,
7 wappqSessionTimeout, wappqBuffer, wappqParentPaths,
8 wappqDefaultScript, wappqScriptTimeout,
9 wappqServerDebugging, wappqClientDebugging, wappqAppPool, wappqApplication};
10
11
12HRESULT ScaGetWebApplication(MSIHANDLE /*hViewApplications*/,
13 LPCWSTR pwzApplication,
14 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
15 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
16 SCA_WEB_APPLICATION* pswapp)
17{
18 HRESULT hr = S_OK;
19
20 MSIHANDLE hRec;
21 LPWSTR pwzData = NULL;
22
23 // Reset back to the first record
24 WcaFetchWrappedReset(hWebAppQuery);
25
26 // get the application information
27 hr = WcaFetchWrappedRecordWhereString(hWebAppQuery, wappqApplication, pwzApplication, &hRec);
28 if (S_OK == hr)
29 {
30 // application name
31 hr = WcaGetRecordString(hRec, wappqName, &pwzData);
32 ExitOnFailure(hr, "Failed to get Name of App");
33 hr = ::StringCchCopyW(pswapp->wzName, countof(pswapp->wzName), pwzData);
34 if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr)
35 {
36 // The application name is sometimes truncated to IIS's supported length, so ignore insufficient buffer errors here
37 WcaLog(LOGMSG_VERBOSE, "Application name \"%ls\" truncated to fit IIS's supported %d-character length", pwzData, MAX_APP_NAME);
38 hr = S_OK;
39 }
40 ExitOnFailure(hr, "Failed to copy name string to webapp object");
41
42 hr = WcaGetRecordInteger(hRec, wappqIsolation, &pswapp->iIsolation);
43 ExitOnFailure(hr, "Failed to get App isolation: '%ls'", pswapp->wzName);
44
45 hr = WcaGetRecordInteger(hRec, wappqAllowSession, &pswapp->fAllowSessionState);
46
47 hr = WcaGetRecordInteger(hRec, wappqSessionTimeout, &pswapp->iSessionTimeout);
48
49 hr = WcaGetRecordInteger(hRec, wappqBuffer, &pswapp->fBuffer);
50
51 hr = WcaGetRecordInteger(hRec, wappqParentPaths, &pswapp->fParentPaths);
52
53 hr = WcaGetRecordString(hRec, wappqDefaultScript, &pwzData);
54 ExitOnFailure(hr, "Failed to get default scripting language for App: '%ls'", pswapp->wzName);
55 hr = ::StringCchCopyW(pswapp->wzDefaultScript, countof(pswapp->wzDefaultScript), pwzData);
56 ExitOnFailure(hr, "Failed to copy default script string to webapp object");
57
58 // asp script timeout
59 hr = WcaGetRecordInteger(hRec, wappqScriptTimeout, &pswapp->iScriptTimeout);
60 ExitOnFailure(hr, "Failed to get scripting timeout for App: '%ls'", pswapp->wzName);
61
62 // asp server-side script debugging
63 hr = WcaGetRecordInteger(hRec, wappqServerDebugging, &pswapp->fServerDebugging);
64
65 // asp client-side script debugging
66 hr = WcaGetRecordInteger(hRec, wappqClientDebugging, &pswapp->fClientDebugging);
67
68 hr = WcaGetRecordString(hRec, wappqAppPool, &pwzData);
69 ExitOnFailure(hr, "Failed to get AppPool for App: '%ls'", pswapp->wzName);
70 hr = ::StringCchCopyW(pswapp->wzAppPool, countof(pswapp->wzAppPool), pwzData);
71 ExitOnFailure(hr, "failed to copy AppPool: '%ls' for App: '%ls'", pwzData, pswapp->wzName);
72
73 // app extensions
74 hr = ScaWebAppExtensionsRead(pwzApplication, hWebAppExtQuery, &pswapp->pswappextList);
75 ExitOnFailure(hr, "Failed to read AppExtensions for App: '%ls'", pswapp->wzName);
76
77 hr = S_OK;
78 }
79 else if (E_NOMOREITEMS == hr)
80 {
81 WcaLog(LOGMSG_STANDARD, "Error: Cannot locate IIsWebApplication.Application='%ls'", pwzApplication);
82 hr = E_FAIL;
83 }
84 else
85 ExitOnFailure(hr, "Error matching Application rows");
86
87 // Let's check that there isn't more than one record found - if there is, throw an assert like WcaFetchSingleRecord() would
88 HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWebAppQuery, wappqApplication, pwzApplication, &hRec);
89 if (SUCCEEDED(hrTemp))
90 {
91 AssertSz(E_NOMOREITEMS == hrTemp, "ScaGetWebApplication found more than one record");
92 }
93
94LExit:
95 ReleaseStr(pwzData);
96
97 return hr;
98}
99
100
101HRESULT ScaWriteWebApplication(IMSAdminBase* piMetabase, LPCWSTR wzRootOfWeb,
102 SCA_WEB_APPLICATION* pswapp, SCA_APPPOOL * psapList)
103{
104 HRESULT hr = S_OK;
105 WCHAR wzAppPoolName[MAX_PATH];
106
107 hr = ScaCreateApp(piMetabase, wzRootOfWeb, pswapp->iIsolation);
108 ExitOnFailure(hr, "Failed to create ASP App");
109
110 // Medium Isolation seems to have to be set through the metabase
111 if (2 == pswapp->iIsolation)
112 {
113 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_APP_ISOLATED, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->iIsolation));
114 ExitOnFailure(hr, "Failed to write isolation value for App: '%ls'", pswapp->wzName);
115 }
116
117 // application name
118 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_APP_FRIENDLY_NAME, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, pswapp->wzName);
119 ExitOnFailure(hr, "Failed to write Name of App: '%ls'", pswapp->wzName);
120
121 // allow session state
122 if (MSI_NULL_INTEGER != pswapp->fAllowSessionState)
123 {
124 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_ALLOWSESSIONSTATE, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->fAllowSessionState));
125 ExitOnFailure(hr, "Failed to write allow session information for App: '%ls'", pswapp->wzName);
126 }
127
128 // session timeout
129 if (MSI_NULL_INTEGER != pswapp->iSessionTimeout)
130 {
131 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_SESSIONTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->iSessionTimeout));
132 ExitOnFailure(hr, "Failed to write session timeout for App: '%ls'", pswapp->wzName);
133 }
134
135 // asp buffering
136 if (MSI_NULL_INTEGER != pswapp->fBuffer)
137 {
138 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_BUFFERINGON, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->fBuffer));
139 ExitOnFailure(hr, "Failed to write buffering flag for App: '%ls'", pswapp->wzName);
140 }
141
142 // asp parent paths
143 if (MSI_NULL_INTEGER != pswapp->fParentPaths)
144 {
145 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_ENABLEPARENTPATHS, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->fParentPaths));
146 ExitOnFailure(hr, "Failed to write parent paths flag for App: '%ls'", pswapp->wzName);
147 }
148
149 // default scripting language
150 if (*pswapp->wzDefaultScript)
151 {
152 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_SCRIPTLANGUAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, pswapp->wzDefaultScript);
153 ExitOnFailure(hr, "Failed to write default scripting language for App: '%ls'", pswapp->wzName);
154 }
155
156 // asp script timeout
157 if (MSI_NULL_INTEGER != pswapp->iScriptTimeout)
158 {
159 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_SCRIPTTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->iScriptTimeout));
160 ExitOnFailure(hr, "Failed to write script timeout for App: '%ls'", pswapp->wzName);
161 }
162
163 // asp server-side script debugging
164 if (MSI_NULL_INTEGER != pswapp->fServerDebugging)
165 {
166 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_ENABLESERVERDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->fServerDebugging));
167 ExitOnFailure(hr, "Failed to write ASP server-side script debugging flag for App: '%ls'", pswapp->wzName);
168 }
169
170 // asp server-side script debugging
171 if (MSI_NULL_INTEGER != pswapp->fClientDebugging)
172 {
173 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_ENABLECLIENTDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswapp->fClientDebugging));
174 ExitOnFailure(hr, "Failed to write ASP client-side script debugging flag for App: '%ls'", pswapp->wzName);
175 }
176
177 // AppPool
178 if (*pswapp->wzAppPool && NULL != psapList)
179 {
180 hr = ScaFindAppPool(piMetabase, pswapp->wzAppPool, wzAppPoolName, countof(wzAppPoolName), psapList);
181 ExitOnFailure(hr, "failed to find app pool: %ls", pswapp->wzAppPool);
182 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_APP_APPPOOL_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, wzAppPoolName);
183 ExitOnFailure(hr, "Failed to write default AppPool for App: '%ls'", pswapp->wzName);
184 }
185
186 if (pswapp->pswappextList)
187 {
188 hr = ScaWebAppExtensionsWrite(piMetabase, wzRootOfWeb, pswapp->pswappextList);
189 ExitOnFailure(hr, "Failed to write AppExtensions for App: '%ls'", pswapp->wzName);
190 }
191
192LExit:
193 return hr;
194}
diff --git a/src/ext/Iis/ca/scawebapp.h b/src/ext/Iis/ca/scawebapp.h
new file mode 100644
index 00000000..a4152116
--- /dev/null
+++ b/src/ext/Iis/ca/scawebapp.h
@@ -0,0 +1,42 @@
1#pragma once
2// 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.
3
4
5#include "scaapppool.h"
6#include "scawebappext.h"
7
8// global sql queries provided for optimization
9extern LPCWSTR vcsWebApplicationQuery;
10const int MAX_APP_NAME = 255;
11
12// structs
13struct SCA_WEB_APPLICATION
14{
15 WCHAR wzName[MAX_APP_NAME + 1];
16
17 int iIsolation;
18 BOOL fAllowSessionState;
19 int iSessionTimeout;
20 BOOL fBuffer;
21 BOOL fParentPaths;
22
23 WCHAR wzDefaultScript[MAX_DARWIN_COLUMN + 1];
24 int iScriptTimeout;
25 BOOL fServerDebugging;
26 BOOL fClientDebugging;
27 WCHAR wzAppPool[MAX_DARWIN_COLUMN + 1];
28
29 SCA_WEB_APPLICATION_EXTENSION* pswappextList;
30};
31
32
33// prototypes
34HRESULT ScaGetWebApplication(MSIHANDLE hViewApplications,
35 LPCWSTR pwzApplication,
36 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
37 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
38 SCA_WEB_APPLICATION* pswapp);
39
40HRESULT ScaWriteWebApplication(IMSAdminBase* piMetabase, LPCWSTR wzRootOfWeb,
41 SCA_WEB_APPLICATION* pswapp, SCA_APPPOOL * psapList);
42
diff --git a/src/ext/Iis/ca/scawebapp7.cpp b/src/ext/Iis/ca/scawebapp7.cpp
new file mode 100644
index 00000000..94e6bb18
--- /dev/null
+++ b/src/ext/Iis/ca/scawebapp7.cpp
@@ -0,0 +1,120 @@
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"
4HRESULT ScaWriteWebApplication7(
5 __in_z LPCWSTR wzWebName,
6 __in_z LPCWSTR wzRootOfWeb,
7 SCA_WEB_APPLICATION* pswapp,
8 SCA_APPPOOL * /*psapList*/
9 )
10{
11 HRESULT hr = S_OK;
12
13 //all go to same web/root location tag
14 hr = ScaWriteConfigID(IIS_ASP_BEGIN);
15 ExitOnFailure(hr, "Failed to write WebApp ASP begin id");
16 hr = ScaWriteConfigString(wzWebName); //site name key
17 ExitOnFailure(hr, "Failed to write app web key");
18 hr = ScaWriteConfigString(wzRootOfWeb); //app path key
19 ExitOnFailure(hr, "Failed to write app web root");
20
21 // IIS7 Not Supported: Isolation
22 if (MSI_NULL_INTEGER != pswapp->iIsolation)
23 {
24 WcaLog(LOGMSG_TRACEONLY, "Not supported by IIS7: Isolation Mode, ignoring");
25 }
26
27 // allow session state
28 if (MSI_NULL_INTEGER != pswapp->fAllowSessionState)
29 {
30 //system.webServer/asp /session | allowSessionState
31 hr = ScaWriteConfigID(IIS_ASP_SESSIONSTATE);
32 ExitOnFailure(hr, "Failed to write WebApp ASP sessionstate id");
33 hr = ScaWriteConfigInteger(pswapp->fAllowSessionState);
34 ExitOnFailure(hr, "Failed to write allow session information for App: '%ls'", pswapp->wzName);
35 }
36
37 // session timeout
38 if (MSI_NULL_INTEGER != pswapp->iSessionTimeout)
39 {
40 //system.webServer/asp /session | timeout
41 hr = ScaWriteConfigID(IIS_ASP_SESSIONTIMEOUT);
42 ExitOnFailure(hr, "Failed to write WebApp ASP sessiontimepot id");
43 hr = ScaWriteConfigInteger(pswapp->iSessionTimeout);
44 ExitOnFailure(hr, "Failed to write session timeout for App: '%ls'", pswapp->wzName);
45 }
46
47 // asp buffering
48 if (MSI_NULL_INTEGER != pswapp->fBuffer)
49 {
50 //system.webServer/asp | bufferingOn
51 hr = ScaWriteConfigID(IIS_ASP_BUFFER);
52 ExitOnFailure(hr, "Failed to write WebApp ASP buffer id");
53 hr = ScaWriteConfigInteger(pswapp->fBuffer);
54 ExitOnFailure(hr, "Failed to write buffering flag for App: '%ls'", pswapp->wzName);
55 }
56
57 // asp parent paths
58 if (MSI_NULL_INTEGER != pswapp->fParentPaths)
59 {
60 //system.webServer/asp | enableParentPaths
61 hr = ScaWriteConfigID(IIS_ASP_PARENTPATHS);
62 ExitOnFailure(hr, "Failed to write WebApp ASP parentpaths id");
63 hr = ScaWriteConfigInteger(pswapp->fParentPaths);
64 ExitOnFailure(hr, "Failed to write parent paths flag for App: '%ls'", pswapp->wzName);
65 }
66
67 // default scripting language
68 if (*pswapp->wzDefaultScript)
69 {
70 //system.webServer/asp | scriptLanguage
71 hr = ScaWriteConfigID(IIS_ASP_SCRIPTLANG);
72 ExitOnFailure(hr, "Failed to write WebApp ASP script lang id");
73 hr = ScaWriteConfigString(pswapp->wzDefaultScript);
74 ExitOnFailure(hr, "Failed to write default scripting language for App: '%ls'", pswapp->wzName);
75 }
76
77 // asp script timeout
78 if (MSI_NULL_INTEGER != pswapp->iScriptTimeout)
79 {
80 //system.webServer/asp /limits | scriptTimeout
81 hr = ScaWriteConfigID(IIS_ASP_SCRIPTTIMEOUT);
82 ExitOnFailure(hr, "Failed to write WebApp ASP script timeout id");
83 hr = ScaWriteConfigInteger(pswapp->iScriptTimeout);
84 ExitOnFailure(hr, "Failed to write script timeout for App: '%ls'", pswapp->wzName);
85 }
86
87 // asp server-side script debugging
88 if (MSI_NULL_INTEGER != pswapp->fServerDebugging)
89 {
90 //system.webServer/asp | appAllowDebugging
91 hr = ScaWriteConfigID(IIS_ASP_SCRIPTSERVERDEBUG);
92 ExitOnFailure(hr, "Failed to write WebApp ASP script debug id");
93 hr = ScaWriteConfigInteger(pswapp->fServerDebugging);
94 ExitOnFailure(hr, "Failed to write ASP server-side script debugging flag for App: '%ls'", pswapp->wzName);
95 }
96
97 // asp client-side script debugging
98 if (MSI_NULL_INTEGER != pswapp->fClientDebugging)
99 {
100 //system.webServer/asp | appAllowClientDebug
101 hr = ScaWriteConfigID(IIS_ASP_SCRIPTCLIENTDEBUG);
102 ExitOnFailure(hr, "Failed to write WebApp ASP script debug id");
103 hr = ScaWriteConfigInteger(pswapp->fClientDebugging);
104 ExitOnFailure(hr, "Failed to write ASP client-side script debugging flag for App: '%ls'", pswapp->wzName);
105 }
106
107 //done with ASP application properties
108 hr = ScaWriteConfigID(IIS_ASP_END);
109 ExitOnFailure(hr, "Failed to write WebApp ASP begin id");
110
111 //write out app estensions
112 if (pswapp->pswappextList)
113 {
114 hr = ScaWebAppExtensionsWrite7(wzWebName, wzRootOfWeb, pswapp->pswappextList);
115 ExitOnFailure(hr, "Failed to write AppExtensions for App: '%ls'", pswapp->wzName);
116 }
117
118LExit:
119 return hr;
120}
diff --git a/src/ext/Iis/ca/scawebapp7.h b/src/ext/Iis/ca/scawebapp7.h
new file mode 100644
index 00000000..e1d87f53
--- /dev/null
+++ b/src/ext/Iis/ca/scawebapp7.h
@@ -0,0 +1,10 @@
1#pragma once
2// 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.
3
4
5HRESULT ScaWriteWebApplication7(
6 __in_z LPCWSTR wzWebName,
7 __in_z LPCWSTR wzRootOfWeb,
8 SCA_WEB_APPLICATION* pswapp,
9 SCA_APPPOOL * psapList
10 );
diff --git a/src/ext/Iis/ca/scawebappext.cpp b/src/ext/Iis/ca/scawebappext.cpp
new file mode 100644
index 00000000..cf3b9dd3
--- /dev/null
+++ b/src/ext/Iis/ca/scawebappext.cpp
@@ -0,0 +1,207 @@
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
5enum eWebAppExtensionQuery { wappextqExtension = 1, wappextqVerbs, wappextqExecutable, wappextqAttributes, wappextqApplication };
6
7// prototypes for private helper functions
8static HRESULT NewAppExt(
9 __out SCA_WEB_APPLICATION_EXTENSION** ppswappext
10 );
11static SCA_WEB_APPLICATION_EXTENSION* AddAppExtToList(
12 __in SCA_WEB_APPLICATION_EXTENSION* pswappextList,
13 __in SCA_WEB_APPLICATION_EXTENSION* pswappext
14 );
15
16
17
18HRESULT ScaWebAppExtensionsRead(
19 __in LPCWSTR wzApplication,
20 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
21 __inout SCA_WEB_APPLICATION_EXTENSION** ppswappextList
22 )
23{
24 HRESULT hr = S_OK;
25 MSIHANDLE hRec;
26
27 SCA_WEB_APPLICATION_EXTENSION* pswappext = NULL;
28 LPWSTR pwzData = NULL;
29
30 // Reset back to the first record
31 WcaFetchWrappedReset(hWebAppExtQuery);
32
33 // get the application extension information
34 while (S_OK == (hr = WcaFetchWrappedRecordWhereString(hWebAppExtQuery, wappextqApplication, wzApplication, &hRec)))
35 {
36 hr = NewAppExt(&pswappext);
37 ExitOnFailure(hr, "failed to create new web app extension");
38
39 // get the extension
40 hr = WcaGetRecordString(hRec, wappextqExtension, &pwzData);
41 ExitOnFailure(hr, "Failed to get Web Application Extension");
42 hr = ::StringCchCopyW(pswappext->wzExtension, countof(pswappext->wzExtension), pwzData);
43 ExitOnFailure(hr, "Failed to copy extension string to webappext object");
44
45 // application extension verbs
46 hr = WcaGetRecordString(hRec, wappextqVerbs, &pwzData);
47 ExitOnFailure(hr, "Failed to get Verbs for Application: '%ls'", wzApplication);
48 hr = ::StringCchCopyW(pswappext->wzVerbs, countof(pswappext->wzVerbs), pwzData);
49 ExitOnFailure(hr, "Failed to copy verbs string to webappext object");
50
51 // extension executeable
52 hr = WcaGetRecordString(hRec, wappextqExecutable, &pwzData);
53 ExitOnFailure(hr, "Failed to get Executable for Application: '%ls'", wzApplication);
54 hr = ::StringCchCopyW(pswappext->wzExecutable, countof(pswappext->wzExecutable), pwzData);
55 ExitOnFailure(hr, "Failed to copy executable string to webappext object");
56
57 hr = WcaGetRecordInteger(hRec, wappextqAttributes, &pswappext->iAttributes);
58 if (S_FALSE == hr)
59 {
60 pswappext->iAttributes = 0;
61 hr = S_OK;
62 }
63 ExitOnFailure(hr, "Failed to get App isolation");
64
65 *ppswappextList = AddAppExtToList(*ppswappextList, pswappext);
66 pswappext = NULL; // set the appext NULL so it doesn't accidentally get freed below
67 }
68
69 if (E_NOMOREITEMS == hr)
70 {
71 hr = S_OK;
72 }
73
74LExit:
75 // if anything was left over after an error clean it all up
76 if (pswappext)
77 {
78 ScaWebAppExtensionsFreeList(pswappext);
79 }
80
81 ReleaseStr(pwzData);
82
83 return hr;
84}
85
86
87
88HRESULT ScaWebAppExtensionsWrite(
89 __in IMSAdminBase* piMetabase,
90 __in LPCWSTR wzRootOfWeb,
91 __in SCA_WEB_APPLICATION_EXTENSION* pswappextList
92 )
93{
94 HRESULT hr = S_OK;
95
96 LPWSTR wzAppExt = NULL;
97 DWORD cchAppExt;
98 WCHAR wzAppExtension[1024];
99 WCHAR wzAppExtensions[65536];
100 SCA_WEB_APPLICATION_EXTENSION* pswappext = NULL;
101
102 if (!pswappextList)
103 {
104 ExitFunction();
105 }
106
107 ::ZeroMemory(wzAppExtensions, sizeof(wzAppExtensions));
108 wzAppExt = wzAppExtensions;
109 cchAppExt = countof(wzAppExtensions);
110 pswappext = pswappextList;
111
112 while (pswappext)
113 {
114 // if all (represented by "*" or blank)
115 if (0 == lstrcmpW(pswappext->wzExtension, L"*") || 0 == lstrlenW(pswappext->wzExtension))
116 {
117 hr = ::StringCchPrintfW(wzAppExtension, countof(wzAppExtension), L"*,%s,%d", pswappext->wzExecutable, pswappext->iAttributes);
118 ExitOnFailure(hr, "Failed to format *,executable,attributes string");
119 }
120 else
121 {
122 hr = ::StringCchPrintfW(wzAppExtension, countof(wzAppExtension), L".%s,%s,%d", pswappext->wzExtension, pswappext->wzExecutable, pswappext->iAttributes);
123 ExitOnFailure(hr, "Failed to format extension,executable,attributes string");
124 }
125
126 // if verbs were specified and not the keyword "all"
127 if (pswappext->wzVerbs[0] && CSTR_EQUAL != CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pswappext->wzVerbs, -1, L"all", -1))
128 {
129 hr = ::StringCchCatW(wzAppExtension, countof(wzAppExtension), L",");
130 ExitOnFailure(hr, "Failed to concatenate comma to app extension string");
131 hr = ::StringCchCatW(wzAppExtension, countof(wzAppExtension), pswappext->wzVerbs);
132 ExitOnFailure(hr, "Failed to concatenate verb to app extension string");
133 }
134
135 hr = ::StringCchCopyW(wzAppExt, cchAppExt, wzAppExtension);
136 ExitOnFailure(hr, "Failed to copy app extension string");
137 wzAppExt += lstrlenW(wzAppExtension) + 1;
138 cchAppExt -= lstrlenW(wzAppExtension) + 1;
139 pswappext = pswappext->pswappextNext;
140 }
141
142 if (*wzAppExtensions)
143 {
144 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_SCRIPT_MAPS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, wzAppExtensions);
145 ExitOnFailure(hr, "Failed to write AppExtension: '%ls'", wzAppExtension);
146 }
147
148LExit:
149 return hr;
150}
151
152
153void ScaWebAppExtensionsFreeList(
154 __in SCA_WEB_APPLICATION_EXTENSION* pswappextList
155 )
156{
157 SCA_WEB_APPLICATION_EXTENSION* pswappextDelete = pswappextList;
158 while (pswappextList)
159 {
160 pswappextDelete = pswappextList;
161 pswappextList = pswappextList->pswappextNext;
162
163 MemFree(pswappextDelete);
164 }
165}
166
167
168
169// private helper functions
170
171static HRESULT NewAppExt(
172 __out SCA_WEB_APPLICATION_EXTENSION** ppswappext
173 )
174{
175 HRESULT hr = S_OK;
176 SCA_WEB_APPLICATION_EXTENSION* pswappext = static_cast<SCA_WEB_APPLICATION_EXTENSION*>(MemAlloc(sizeof(SCA_WEB_APPLICATION_EXTENSION), TRUE));
177 ExitOnNull(pswappext, hr, E_OUTOFMEMORY, "failed to allocate memory for new web app ext element");
178
179 *ppswappext = pswappext;
180
181LExit:
182 return hr;
183}
184
185
186static SCA_WEB_APPLICATION_EXTENSION* AddAppExtToList(
187 __in SCA_WEB_APPLICATION_EXTENSION* pswappextList,
188 __in SCA_WEB_APPLICATION_EXTENSION* pswappext
189 )
190{
191 if (pswappextList)
192 {
193 SCA_WEB_APPLICATION_EXTENSION* pswappextT = pswappextList;
194 while (pswappextT->pswappextNext)
195 {
196 pswappextT = pswappextT->pswappextNext;
197 }
198
199 pswappextT->pswappextNext = pswappext;
200 }
201 else
202 {
203 pswappextList = pswappext;
204 }
205
206 return pswappextList;
207}
diff --git a/src/ext/Iis/ca/scawebappext.h b/src/ext/Iis/ca/scawebappext.h
new file mode 100644
index 00000000..71adfd00
--- /dev/null
+++ b/src/ext/Iis/ca/scawebappext.h
@@ -0,0 +1,32 @@
1#pragma once
2// 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.
3
4
5struct SCA_WEB_APPLICATION_EXTENSION
6{
7 WCHAR wzExtension[MAX_DARWIN_COLUMN + 1];
8
9 WCHAR wzVerbs[MAX_DARWIN_COLUMN + 1];
10 WCHAR wzExecutable[MAX_DARWIN_COLUMN + 1];
11 int iAttributes;
12
13 SCA_WEB_APPLICATION_EXTENSION* pswappextNext;
14};
15
16
17// prototypes
18HRESULT ScaWebAppExtensionsRead(
19 __in LPCWSTR wzApplication,
20 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
21 __inout SCA_WEB_APPLICATION_EXTENSION** ppswappextList
22 );
23
24HRESULT ScaWebAppExtensionsWrite(
25 __in IMSAdminBase* piMetabase,
26 __in LPCWSTR wzRootOfWeb,
27 __in SCA_WEB_APPLICATION_EXTENSION* pswappextList
28 );
29
30void ScaWebAppExtensionsFreeList(
31 __in SCA_WEB_APPLICATION_EXTENSION* pswappextList
32 );
diff --git a/src/ext/Iis/ca/scawebappext7.cpp b/src/ext/Iis/ca/scawebappext7.cpp
new file mode 100644
index 00000000..50d3172f
--- /dev/null
+++ b/src/ext/Iis/ca/scawebappext7.cpp
@@ -0,0 +1,61 @@
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
5HRESULT ScaWebAppExtensionsWrite7(
6 __in_z LPCWSTR wzWebName,
7 __in_z LPCWSTR wzRootOfWeb,
8 __in SCA_WEB_APPLICATION_EXTENSION* pswappextList
9 )
10{
11 HRESULT hr = S_OK;
12 SCA_WEB_APPLICATION_EXTENSION* pswappext = NULL;
13
14 if (!pswappextList)
15 {
16 ExitFunction1(hr = S_OK);
17 }
18
19 //create the Extension for this vdir application
20 //all go to same web/root location tag
21 hr = ScaWriteConfigID(IIS_APPEXT_BEGIN);
22 ExitOnFailure(hr, "Failed to write webappext begin id");
23 hr = ScaWriteConfigString(wzWebName); //site name key
24 ExitOnFailure(hr, "Failed to write app web key");
25 hr = ScaWriteConfigString(wzRootOfWeb); //app path key
26 ExitOnFailure(hr, "Failed to write app web key");
27
28 pswappext = pswappextList;
29
30 while (pswappext)
31 {
32 //create the Extension for this vdir application
33 hr = ScaWriteConfigID(IIS_APPEXT);
34 ExitOnFailure(hr, "Failed to write webappext begin id");
35
36 if (*pswappext->wzExtension)
37 {
38 hr = ScaWriteConfigString(pswappext->wzExtension);
39 }
40 else // blank means "*" (all)
41 {
42 hr = ScaWriteConfigString(L"*");
43 }
44 ExitOnFailure(hr, "Failed to write extension");
45
46 hr = ScaWriteConfigString(pswappext->wzExecutable);
47 ExitOnFailure(hr, "Failed to write extension executable");
48
49 hr = ScaWriteConfigString(pswappext->wzVerbs);
50 ExitOnFailure(hr, "Failed to write extension verbs");
51
52 pswappext = pswappext->pswappextNext;
53 }
54
55 hr = ScaWriteConfigID(IIS_APPEXT_END);
56 ExitOnFailure(hr, "Failed to write webappext begin id");
57
58LExit:
59 return hr;
60}
61
diff --git a/src/ext/Iis/ca/scawebappext7.h b/src/ext/Iis/ca/scawebappext7.h
new file mode 100644
index 00000000..55c8b5fc
--- /dev/null
+++ b/src/ext/Iis/ca/scawebappext7.h
@@ -0,0 +1,9 @@
1#pragma once
2// 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.
3
4
5HRESULT ScaWebAppExtensionsWrite7(
6 __in_z LPCWSTR wzWebName,
7 __in_z LPCWSTR wzRootOfWeb,
8 __in SCA_WEB_APPLICATION_EXTENSION* pswappextList
9 );
diff --git a/src/ext/Iis/ca/scawebdir.cpp b/src/ext/Iis/ca/scawebdir.cpp
new file mode 100644
index 00000000..26a7b32b
--- /dev/null
+++ b/src/ext/Iis/ca/scawebdir.cpp
@@ -0,0 +1,241 @@
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// sql queries
6enum eWebDirQuery { wdqWeb = 1, wdqWebDir, wdqComponent , wdqPath, wdqProperties, wdqApplication, wdqInstalled, wdqAction };
7
8// prototypes
9static void AddWebDirToList(SCA_WEBDIR** ppswdList, SCA_WEBDIR *pswd);
10
11static SCA_WEBDIR* NewWebDir();
12static void FreeWebDir(SCA_WEBDIR *pswd);
13
14
15UINT __stdcall ScaWebDirsRead(
16 __in IMSAdminBase* piMetabase,
17 __in SCA_WEB* pswList,
18 __in WCA_WRAPQUERY_HANDLE hUserQuery,
19 __in WCA_WRAPQUERY_HANDLE hWebBaseQuery,
20 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
21 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
22 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
23 __inout LPWSTR *ppwzCustomActionData,
24 __out SCA_WEBDIR** ppswdList
25 )
26{
27 Assert(piMetabase && ppswdList);
28
29 HRESULT hr = S_OK;
30 MSIHANDLE hRec;
31
32 LPWSTR pwzData = NULL;
33 SCA_WEBDIR* pswd;
34 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
35
36 hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
37 ExitOnFailure(hr, "Failed to unwrap query for ScaWebDirsRead");
38
39 if (0 == WcaGetQueryRecords(hWrapQuery))
40 {
41 WcaLog(LOGMSG_VERBOSE, "Skipping ScaInstallWebDirs() because IIsWebDir table not present");
42 ExitFunction1(hr = S_FALSE);
43 }
44
45 // loop through all the web directories
46 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
47 {
48 pswd = NewWebDir();
49 ExitOnNull(pswd, hr, E_OUTOFMEMORY, "Failed to allocate memory for web dir object in memory");
50
51 // get component install state
52 hr = WcaGetRecordString(hRec, wdqComponent, &pwzData);
53 ExitOnFailure(hr, "Failed to get Component for WebDirs");
54 hr = ::StringCchCopyW(pswd->wzComponent, countof(pswd->wzComponent), pwzData);
55 ExitOnFailure(hr, "Failed to copy component string to webdir object");
56
57 hr = WcaGetRecordInteger(hRec, wdqInstalled, (int *)&pswd->isInstalled);
58 ExitOnFailure(hr, "Failed to get Component installed state for webdir");
59
60 hr = WcaGetRecordInteger(hRec, wdqAction, (int *)&pswd->isAction);
61 ExitOnFailure(hr, "Failed to get Component action state for webdir");
62
63 // If this record has a component and no action is being taken for it, skip processing it entirely
64 if (0 < lstrlenW(pswd->wzComponent) && !WcaIsInstalling(pswd->isInstalled, pswd->isAction)
65 && !WcaIsUninstalling(pswd->isInstalled, pswd->isAction) && !WcaIsReInstalling(pswd->isInstalled, pswd->isAction))
66 {
67 FreeWebDir(pswd);
68 pswd = NULL;
69 continue;
70 }
71
72 hr = WcaGetRecordString(hRec, wdqWeb, &pwzData);
73 ExitOnFailure(hr, "Failed to get Web for WebDir");
74
75 hr = ScaWebsGetBase(piMetabase, pswList, pwzData, pswd->wzWebBase, countof(pswd->wzWebBase), hWebBaseQuery);
76 if (WcaIsUninstalling(pswd->isInstalled, pswd->isAction))
77 {
78 // If we're uninstalling, ignore any failure to find the existing web
79 hr = S_OK;
80 }
81
82 ExitOnFailure(hr, "Failed to get base of web for WebDir");
83
84 hr = WcaGetRecordString(hRec, wdqPath, &pwzData);
85 ExitOnFailure(hr, "Failed to get Path for WebDir");
86
87 hr = ::StringCchPrintfW(pswd->wzWebDirRoot, countof(pswd->wzWebDirRoot), L"%s/Root/%s", pswd->wzWebBase, pwzData);
88 ExitOnFailure(hr, "Failed to format webdir root string");
89
90 // get the directory properties for this web
91 hr = WcaGetRecordString(hRec, wdqProperties, &pwzData);
92 ExitOnFailure(hr, "Failed to get security identifier for WebDir");
93 if (*pwzData)
94 {
95 hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &pswd->swp);
96 ExitOnFailure(hr, "Failed to get properties for WebDir");
97
98 pswd->fHasProperties = TRUE;
99 }
100
101 // get the application information for this web directory
102 hr = WcaGetRecordString(hRec, wdqApplication, &pwzData);
103 ExitOnFailure(hr, "Failed to get application identifier for WebDir");
104 if (*pwzData)
105 {
106 hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &pswd->swapp);
107 ExitOnFailure(hr, "Failed to get application for WebDir");
108
109 pswd->fHasApplication = TRUE;
110 }
111
112 AddWebDirToList(ppswdList, pswd);
113 }
114
115 if (E_NOMOREITEMS == hr)
116 {
117 hr = S_OK;
118 }
119 ExitOnFailure(hr, "Failure while processing WebDirs");
120
121LExit:
122 WcaFinishUnwrapQuery(hWrapQuery);
123
124 ReleaseStr(pwzData);
125
126 return hr;
127}
128
129
130HRESULT ScaWebDirsInstall(IMSAdminBase* piMetabase, SCA_WEBDIR* pswdList, SCA_APPPOOL * psapList)
131{
132 HRESULT hr = S_OK;
133 SCA_WEBDIR* pswd = pswdList;
134 int i;
135
136 while (pswd)
137 {
138 // On reinstall, we have to uninstall the old application, otherwise a duplicate will be created
139 if (WcaIsReInstalling(pswd->isInstalled, pswd->isAction))
140 {
141 if (pswd->fHasApplication)
142 {
143 hr = ScaDeleteApp(piMetabase, pswd->wzWebDirRoot);
144 ExitOnFailure(hr, "Failed to remove application for WebDir as part of a reinstall");
145 }
146 }
147
148 // if we are installing the web site
149 if (WcaIsInstalling(pswd->isInstalled, pswd->isAction))
150 {
151 hr = ScaCreateMetabaseKey(piMetabase, pswd->wzWebDirRoot, L"");
152 ExitOnFailure(hr, "Failed to create key for WebDir");
153 hr = ScaWriteMetabaseValue(piMetabase, pswd->wzWebDirRoot, L"", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsWebDirectory");
154 ExitOnFailure(hr, "Failed to write key type for for WebDir");
155 i = 0x4000003e; // 1073741886: default directory browsing rights
156 hr = ScaWriteMetabaseValue(piMetabase, pswd->wzWebDirRoot, L"", MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)i));
157 ExitOnFailure(hr, "Failed to set directory browsing for WebDir");
158
159 // get the security information for this web
160 if (pswd->fHasProperties)
161 {
162 ScaWriteWebDirProperties(piMetabase, pswd->wzWebDirRoot, &pswd->swp);
163 ExitOnFailure(hr, "Failed to write properties for WebDir");
164 }
165
166 // get the application information for this web directory
167 if (pswd->fHasApplication)
168 {
169 hr = ScaWriteWebApplication(piMetabase, pswd->wzWebDirRoot, &pswd->swapp, psapList);
170 ExitOnFailure(hr, "Failed to write application for WebDir");
171 }
172 }
173
174 pswd = pswd->pswdNext;
175 }
176
177LExit:
178 return hr;
179}
180
181
182HRESULT ScaWebDirsUninstall(IMSAdminBase* piMetabase, SCA_WEBDIR* pswdList)
183{
184 Assert(piMetabase);
185
186 HRESULT hr = S_OK;
187 SCA_WEBDIR* pswd = pswdList;
188
189 while (pswd)
190 {
191 if (WcaIsUninstalling(pswd->isInstalled, pswd->isAction))
192 {
193 // remove the application from this web directory
194 if (pswd->fHasApplication)
195 {
196 hr = ScaDeleteApp(piMetabase, pswd->wzWebDirRoot);
197 ExitOnFailure(hr, "Failed to remove application for WebDir");
198 }
199
200 hr = ScaDeleteMetabaseKey(piMetabase, pswd->wzWebDirRoot, L"");
201 ExitOnFailure(hr, "Failed to remove WebDir '%ls' from metabase", pswd->wzKey);
202 }
203
204 pswd = pswd->pswdNext;
205 }
206
207LExit:
208 return hr;
209}
210
211
212static SCA_WEBDIR* NewWebDir()
213{
214 SCA_WEBDIR* pswd = static_cast<SCA_WEBDIR*>(MemAlloc(sizeof(SCA_WEBDIR), TRUE));
215 Assert(pswd);
216 return pswd;
217}
218
219static void FreeWebDir(SCA_WEBDIR *pswd)
220{
221 MemFree(pswd);
222}
223
224void ScaWebDirsFreeList(SCA_WEBDIR* pswdList)
225{
226 SCA_WEBDIR* pswdDelete = pswdList;
227 while (pswdList)
228 {
229 pswdDelete = pswdList;
230 pswdList = pswdList->pswdNext;
231
232 FreeWebDir(pswdDelete);
233 }
234}
235
236
237static void AddWebDirToList(SCA_WEBDIR** ppswdList, SCA_WEBDIR *pswd)
238{
239 pswd->pswdNext = *ppswdList;
240 *ppswdList = pswd;
241}
diff --git a/src/ext/Iis/ca/scawebdir.h b/src/ext/Iis/ca/scawebdir.h
new file mode 100644
index 00000000..0b594532
--- /dev/null
+++ b/src/ext/Iis/ca/scawebdir.h
@@ -0,0 +1,57 @@
1#pragma once
2// 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.
3
4
5struct SCA_WEBDIR
6{
7 // darwin information
8 WCHAR wzKey[MAX_DARWIN_KEY + 1];
9 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
10 INSTALLSTATE isInstalled;
11 INSTALLSTATE isAction;
12
13 // metabase information
14 WCHAR wzWebKey[MAX_DARWIN_KEY + 1];
15 WCHAR wzWebBase[METADATA_MAX_NAME_LEN + 1];
16 WCHAR wzWebDirRoot[METADATA_MAX_NAME_LEN + 1];
17
18 // iis configuation information
19 WCHAR wzDirectory[MAX_PATH];
20
21 BOOL fHasProperties;
22 SCA_WEB_PROPERTIES swp;
23
24 BOOL fHasApplication;
25 SCA_WEB_APPLICATION swapp;
26
27 SCA_WEBDIR* pswdNext;
28};
29
30
31// prototypes
32UINT __stdcall ScaWebDirsRead(
33 __in IMSAdminBase* piMetabase,
34 __in SCA_WEB* pswList,
35 __in WCA_WRAPQUERY_HANDLE hUserQuery,
36 __in WCA_WRAPQUERY_HANDLE hWebBaseQuery,
37 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
38 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
39 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
40 __inout LPWSTR *ppwzCustomActionData,
41 __out SCA_WEBDIR** ppswdList
42 );
43
44HRESULT ScaWebDirsInstall(
45 __in IMSAdminBase* piMetabase,
46 __in SCA_WEBDIR* pswdList,
47 __in SCA_APPPOOL* psapList
48 );
49
50HRESULT ScaWebDirsUninstall(
51 __in IMSAdminBase* piMetabase,
52 __in SCA_WEBDIR* pswdList
53 );
54
55void ScaWebDirsFreeList(
56 __in SCA_WEBDIR* pswdList
57 );
diff --git a/src/ext/Iis/ca/scawebdir7.cpp b/src/ext/Iis/ca/scawebdir7.cpp
new file mode 100644
index 00000000..5ead0470
--- /dev/null
+++ b/src/ext/Iis/ca/scawebdir7.cpp
@@ -0,0 +1,219 @@
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// sql queries
6static LPCWSTR vcsWebDirQuery7 = L"SELECT `Web_`, `WebDir`, `Component_`, `Path`, `DirProperties_`, `Application_`"
7 L"FROM `IIsWebDir`";
8
9enum eWebDirQuery { wdqWeb = 1, wdqWebDir, wdqComponent , wdqPath, wdqProperties, wdqApplication, wdqInstalled, wdqAction };
10
11// prototypes
12static HRESULT AddWebDirToList(SCA_WEBDIR7** ppswdList);
13
14
15UINT __stdcall ScaWebDirsRead7(
16 __in SCA_WEB7* pswList,
17 __in WCA_WRAPQUERY_HANDLE hUserQuery,
18 __in WCA_WRAPQUERY_HANDLE /*hWebBaseQuery*/,
19 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
20 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
21 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
22 __inout LPWSTR *ppwzCustomActionData,
23 __out SCA_WEBDIR7** ppswdList
24 )
25{
26 HRESULT hr = S_OK;
27 MSIHANDLE hRec;
28
29 LPWSTR pwzData = NULL;
30 SCA_WEBDIR7* pswd;
31 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
32
33 hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
34 ExitOnFailure(hr, "Failed to unwrap query for ScaWebDirsRead7");
35
36 if (0 == WcaGetQueryRecords(hWrapQuery))
37 {
38 WcaLog(LOGMSG_VERBOSE, "Skipping ScaInstallWebDirs7() because IIsWebDir table not present");
39 ExitFunction1(hr = S_FALSE);
40 }
41
42 // loop through all the web directories
43 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
44 {
45 hr = AddWebDirToList(ppswdList);
46 ExitOnFailure(hr, "failed to add web dir to list");
47
48 pswd = *ppswdList;
49 ExitOnNull(pswd, hr, E_INVALIDARG, "No web dir provided");
50
51 // get component install state
52 hr = WcaGetRecordString(hRec, wdqComponent, &pwzData);
53 ExitOnFailure(hr, "Failed to get Component for WebDirs");
54 hr = ::StringCchCopyW(pswd->wzComponent, countof(pswd->wzComponent), pwzData);
55 ExitOnFailure(hr, "Failed to copy component string to webdir object");
56
57 hr = WcaGetRecordInteger(hRec, wdqInstalled, (int *)&pswd->isInstalled);
58 ExitOnFailure(hr, "Failed to get Component installed state for webdir");
59
60 hr = WcaGetRecordInteger(hRec, wdqAction, (int *)&pswd->isAction);
61 ExitOnFailure(hr, "Failed to get Component action state for webdir");
62
63 hr = WcaGetRecordString(hRec, wdqWeb, &pwzData);
64 ExitOnFailure(hr, "Failed to get Web for WebDir");
65
66 // get the web key
67 hr = ScaWebsGetBase7(pswList, pwzData, pswd->wzWebSite, countof(pswd->wzWebSite));
68 if (S_FALSE == hr)
69 {
70 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
71 ExitOnFailure(hr, "Failed to get base of web for WebDir");
72 }
73 ExitOnFailure(hr, "Failed to format webdir root string");
74
75 hr = WcaGetRecordString(hRec, wdqPath, &pwzData);
76 ExitOnFailure(hr, "Failed to get Path for WebDir");
77
78 hr = ::StringCchCopyW(pswd->wzPath, countof(pswd->wzPath), pwzData);
79 ExitOnFailure(hr, "Failed to copy path for WebDir");
80
81 // get the directory properties for this web
82 hr = WcaGetRecordString(hRec, wdqProperties, &pwzData);
83 ExitOnFailure(hr, "Failed to get security identifier for WebDir");
84 if (*pwzData)
85 {
86 hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &pswd->swp);
87 ExitOnFailure(hr, "Failed to get properties for WebDir");
88
89 pswd->fHasProperties = TRUE;
90 }
91
92 // get the application information for this web directory
93 hr = WcaGetRecordString(hRec, wdqApplication, &pwzData);
94 ExitOnFailure(hr, "Failed to get application identifier for WebDir");
95 if (*pwzData)
96 {
97 hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &pswd->swapp);
98 ExitOnFailure(hr, "Failed to get application for WebDir");
99
100 pswd->fHasApplication = TRUE;
101 }
102 }
103
104 if (E_NOMOREITEMS == hr)
105 {
106 hr = S_OK;
107 }
108 ExitOnFailure(hr, "Failure while processing WebDirs");
109
110LExit:
111 WcaFinishUnwrapQuery(hWrapQuery);
112
113 ReleaseStr(pwzData);
114
115 return hr;
116}
117
118
119HRESULT ScaWebDirsInstall7(SCA_WEBDIR7* pswdList, SCA_APPPOOL * psapList)
120{
121 HRESULT hr = S_OK;
122 SCA_WEBDIR7* pswd = pswdList;
123
124 while (pswd)
125 {
126 // if we are installing the web site
127 if (WcaIsInstalling(pswd->isInstalled, pswd->isAction))
128 {
129 hr = ScaWriteConfigID(IIS_WEBDIR);
130 ExitOnFailure(hr, "Failed to write WebDir ID");
131
132 hr = ScaWriteConfigID(IIS_CREATE);
133 ExitOnFailure(hr, "Failed to write WebDir action ID");
134
135 hr = ScaWriteConfigString(pswd->wzWebSite);
136 ExitOnFailure(hr, "Failed to write WebDir site");
137
138 hr = ScaWriteConfigString(pswd->wzPath);
139 ExitOnFailure(hr, "Failed to write WebDir path");
140
141 // get the security information for this web
142 if (pswd->fHasProperties)
143 {
144 ScaWriteWebDirProperties7(pswd->wzWebSite, pswd->wzPath, &pswd->swp);
145 ExitOnFailure(hr, "Failed to write properties for WebDir");
146 }
147
148 // get the application information for this web directory
149 if (pswd->fHasApplication)
150 {
151 hr = ScaWriteWebApplication7(pswd->wzWebSite, pswd->wzPath, &pswd->swapp, psapList);
152 ExitOnFailure(hr, "Failed to write application for WebDir");
153 }
154 }
155
156 pswd = pswd->pswdNext;
157 }
158
159LExit:
160 return hr;
161}
162
163
164HRESULT ScaWebDirsUninstall7(SCA_WEBDIR7* pswdList)
165{
166 HRESULT hr = S_OK;
167 SCA_WEBDIR7* pswd = pswdList;
168
169 while (pswd)
170 {
171 if (WcaIsUninstalling(pswd->isInstalled, pswd->isAction))
172 {
173 hr = ScaWriteConfigID(IIS_WEBDIR);
174 ExitOnFailure(hr, "Failed to write WebDir ID");
175
176 hr = ScaWriteConfigID(IIS_DELETE);
177 ExitOnFailure(hr, "Failed to write WebDir action ID");
178
179 hr = ScaWriteConfigString(pswd->wzWebSite);
180 ExitOnFailure(hr, "Failed to write WebDir site");
181
182 hr = ScaWriteConfigString(pswd->wzPath);
183 ExitOnFailure(hr, "Failed to write WebDir path");
184 }
185
186 pswd = pswd->pswdNext;
187 }
188
189LExit:
190 return hr;
191}
192
193
194void ScaWebDirsFreeList7(SCA_WEBDIR7* pswdList)
195{
196 SCA_WEBDIR7* pswdDelete = pswdList;
197 while (pswdList)
198 {
199 pswdDelete = pswdList;
200 pswdList = pswdList->pswdNext;
201
202 MemFree(pswdDelete);
203 }
204}
205
206
207static HRESULT AddWebDirToList(SCA_WEBDIR7** ppswdList)
208{
209 HRESULT hr = S_OK;
210
211 SCA_WEBDIR7* pswd = static_cast<SCA_WEBDIR7*>(MemAlloc(sizeof(SCA_WEBDIR7), TRUE));
212 ExitOnNull(pswd, hr, E_OUTOFMEMORY, "failed to allocate element for web dir list");
213
214 pswd->pswdNext = *ppswdList;
215 *ppswdList = pswd;
216
217LExit:
218 return hr;
219}
diff --git a/src/ext/Iis/ca/scawebdir7.h b/src/ext/Iis/ca/scawebdir7.h
new file mode 100644
index 00000000..c5c87e17
--- /dev/null
+++ b/src/ext/Iis/ca/scawebdir7.h
@@ -0,0 +1,51 @@
1#pragma once
2// 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.
3
4
5struct SCA_WEBDIR7
6{
7 // darwin information
8 WCHAR wzKey[MAX_DARWIN_KEY + 1];
9 WCHAR wzComponent[MAX_DARWIN_KEY + 1];
10 INSTALLSTATE isInstalled;
11 INSTALLSTATE isAction;
12
13
14 // iis configuation information
15 WCHAR wzPath[MAX_PATH];
16 WCHAR wzWebSite[MAX_PATH];
17
18 BOOL fHasProperties;
19 SCA_WEB_PROPERTIES swp;
20
21 BOOL fHasApplication;
22 SCA_WEB_APPLICATION swapp;
23
24 SCA_WEBDIR7* pswdNext;
25};
26
27
28// prototypes
29UINT __stdcall ScaWebDirsRead7(
30 __in SCA_WEB7* pswList,
31 __in WCA_WRAPQUERY_HANDLE hUserQuery,
32 __in WCA_WRAPQUERY_HANDLE hWebBaseQuery,
33 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
34 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
35 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
36 __inout LPWSTR *ppwzCustomActionData,
37 __out SCA_WEBDIR7** ppswdList
38 );
39
40HRESULT ScaWebDirsInstall7(
41 __in SCA_WEBDIR7* pswdList,
42 __in SCA_APPPOOL* psapList
43 );
44
45HRESULT ScaWebDirsUninstall7(
46 __in SCA_WEBDIR7* pswdList
47 );
48
49void ScaWebDirsFreeList7(
50 __in SCA_WEBDIR7* pswdList
51 );
diff --git a/src/ext/Iis/ca/scaweberr.cpp b/src/ext/Iis/ca/scaweberr.cpp
new file mode 100644
index 00000000..2441f006
--- /dev/null
+++ b/src/ext/Iis/ca/scaweberr.cpp
@@ -0,0 +1,371 @@
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
5enum eWebErrorQuery { weqErrorCode = 1, weqSubCode, weqParentType, weqParentValue, weqFile, weqURL };
6
7static HRESULT AddWebErrorToList(SCA_WEB_ERROR** ppsweList);
8
9void ScaWebErrorFreeList(SCA_WEB_ERROR *psweList)
10{
11 SCA_WEB_ERROR *psweDelete = psweList;
12 while (psweList)
13 {
14 psweDelete = psweList;
15 psweList = psweList->psweNext;
16
17 MemFree(psweDelete);
18 }
19}
20
21HRESULT ScaWebErrorRead(
22 SCA_WEB_ERROR **ppsweList,
23 __inout LPWSTR *ppwzCustomActionData
24 )
25{
26// AssertSz(0, "Debug ScaWebErrorRead here");
27 HRESULT hr = S_OK;
28 MSIHANDLE hRec;
29 LPWSTR pwzData = NULL;
30 SCA_WEB_ERROR* pswe;
31 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
32
33 ExitOnNull(ppsweList, hr, E_INVALIDARG, "Failed to read web error, because no web error was provided to read");
34
35 hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
36 ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead");
37
38 if (0 == WcaGetQueryRecords(hWrapQuery))
39 {
40 WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebErrorRead() - required tables not present.");
41 ExitFunction1(hr = S_FALSE);
42 }
43
44 // loop through all the web errors
45 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
46 {
47 hr = AddWebErrorToList(ppsweList);
48 ExitOnFailure(hr, "failed to add web error to list");
49
50 pswe = *ppsweList;
51
52 hr = WcaGetRecordInteger(hRec, weqErrorCode, &(pswe->iErrorCode));
53 ExitOnFailure(hr, "failed to get IIsWebError.ErrorCode");
54
55 hr = WcaGetRecordInteger(hRec, weqSubCode, &(pswe->iSubCode));
56 ExitOnFailure(hr, "failed to get IIsWebError.SubCode");
57
58 hr = WcaGetRecordInteger(hRec, weqParentType, &(pswe->iParentType));
59 ExitOnFailure(hr, "failed to get IIsWebError.ParentType");
60
61 hr = WcaGetRecordString(hRec, weqParentValue, &pwzData);
62 ExitOnFailure(hr, "Failed to get IIsWebError.ParentValue");
63 hr = ::StringCchCopyW(pswe->wzParentValue, countof(pswe->wzParentValue), pwzData);
64 ExitOnFailure(hr, "Failed to copy IIsWebError.ParentValue");
65
66 hr = WcaGetRecordString(hRec, weqFile, &pwzData);
67 ExitOnFailure(hr, "Failed to get IIsWebError.File");
68 hr = ::StringCchCopyW(pswe->wzFile, countof(pswe->wzFile), pwzData);
69 ExitOnFailure(hr, "Failed to copy IIsWebError.File");
70
71 hr = WcaGetRecordString(hRec, weqURL, &pwzData);
72 ExitOnFailure(hr, "Failed to get IIsWebError.URL");
73 hr = ::StringCchCopyW(pswe->wzURL, countof(pswe->wzURL), pwzData);
74 ExitOnFailure(hr, "Failed to copy IIsWebError.URL");
75
76 // If they've specified both a file and a URL, that's invalid
77 if (*(pswe->wzFile) && *(pswe->wzURL))
78 ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA), "Both File and URL specified for web error. File: %ls, URL: %ls", pswe->wzFile, pswe->wzURL);
79 }
80
81 if (E_NOMOREITEMS == hr)
82 {
83 hr = S_OK;
84 }
85 ExitOnFailure(hr, "Failure while processing web errors");
86
87LExit:
88 WcaFinishUnwrapQuery(hWrapQuery);
89
90 ReleaseStr(pwzData);
91
92 return hr;
93}
94
95HRESULT ScaGetWebError(int iParentType, LPCWSTR wzParentValue, SCA_WEB_ERROR **ppsweList, SCA_WEB_ERROR **ppsweOut)
96{
97 HRESULT hr = S_OK;
98 SCA_WEB_ERROR* psweAdd = NULL;
99 SCA_WEB_ERROR* psweLast = NULL;
100
101 *ppsweOut = NULL;
102
103 if (!*ppsweList)
104 return hr;
105
106 SCA_WEB_ERROR* pswe = *ppsweList;
107 while (pswe)
108 {
109 if (iParentType == pswe->iParentType && 0 == lstrcmpW(wzParentValue, pswe->wzParentValue))
110 {
111 // Found a match, take this one out of the list and add it to the matched out list
112 psweAdd = pswe;
113
114 if (psweLast)
115 {
116 // If we're not at the beginning of the list tell the last node about it's new next (since we're taking away it's current next)
117 psweLast->psweNext = psweAdd->psweNext;
118 }
119 else
120 {
121 // If we are at the beginning (no psweLast) update the beginning (since we're taking it)
122 *ppsweList = pswe->psweNext;
123 }
124 pswe = pswe->psweNext; // move on
125
126 // Add the one we've removed to the beginning of the out list
127 psweAdd->psweNext = *ppsweOut;
128 *ppsweOut = psweAdd;
129 }
130 else
131 {
132 psweLast = pswe; // remember the last we that didn't match
133 pswe = pswe->psweNext; // move on
134 }
135 }
136
137 return hr;
138}
139
140HRESULT ScaWriteWebError(IMSAdminBase* piMetabase, int iParentType, LPCWSTR wzRoot, SCA_WEB_ERROR* psweList)
141{
142// AssertSz(0, "Debug ScaWriteWebError here");
143 Assert(*wzRoot && psweList);
144
145 HRESULT hr = S_OK;
146
147 DWORD cchData = 0;
148 LPWSTR pwzSearchKey = NULL;
149 LPWSTR pwz = NULL;
150 LPWSTR pwzErrors = NULL;
151
152 LPWSTR pwzCodeSubCode = NULL;
153 LPWSTR pwzAcceptableCodeSubCode = NULL;
154 LPCWSTR wzFoundCodeSubCode = NULL;
155 DWORD_PTR dwFoundCodeSubCodeIndex = 0xFFFFFFFF;
156 BOOL fOldValueFound = FALSE;
157 LPWSTR pwzAcceptableErrors = NULL;
158
159 LPWSTR pwzNewError = NULL;
160
161 METADATA_RECORD mr;
162 ::ZeroMemory(&mr, sizeof(mr));
163
164 ExitOnNull(piMetabase, hr, E_INVALIDARG, "Failed to write web error, because no metabase was provided");
165 ExitOnNull(wzRoot, hr, E_INVALIDARG, "Failed to write web error, because no root was provided");
166
167 // get the set of all valid custom errors from the metabase
168 mr.dwMDIdentifier = MD_CUSTOM_ERROR_DESC;
169 mr.dwMDAttributes = METADATA_INHERIT;
170 mr.dwMDUserType = IIS_MD_UT_SERVER;
171 mr.dwMDDataType = ALL_METADATA;
172 mr.dwMDDataLen = cchData = 0;
173 mr.pbMDData = NULL;
174
175 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/Info", &mr);
176 ExitOnFailure(hr, "Unable to get set of acceptable error codes for this server.");
177
178 pwzAcceptableErrors = reinterpret_cast<LPWSTR>(mr.pbMDData);
179
180 // Check if web errors already exist here
181 mr.dwMDIdentifier = MD_CUSTOM_ERROR;
182 mr.dwMDAttributes = METADATA_INHERIT;
183 mr.dwMDUserType = IIS_MD_UT_SERVER;
184 mr.dwMDDataType = ALL_METADATA;
185 mr.dwMDDataLen = cchData = 0;
186 mr.pbMDData = NULL;
187
188 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzRoot, &mr);
189 if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr)
190 {
191 //
192 // If we don't have one already, find an appropriate one to start with
193 //
194
195 // we can walk up key by key and look for custom errors to inherit
196
197 hr = StrAllocConcat(&pwzSearchKey, wzRoot, 0);
198 ExitOnFailure(hr, "Failed to copy root string: %ls", wzRoot);
199
200 pwz = pwzSearchKey + lstrlenW(pwzSearchKey);
201
202 while (NULL == pwzErrors)
203 {
204 // find the last slash
205 while (*pwz != '/' && pwz != pwzSearchKey)
206 pwz --;
207
208 if (pwz == pwzSearchKey)
209 break;
210
211 *pwz = L'\0';
212
213 // Try here. If it's not found, keep walking up the path
214 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, pwzSearchKey, &mr);
215 if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr)
216 hr = S_FALSE;
217 ExitOnFailure(hr, "failed to discover default error values to start with for web root: %ls while walking up the tree", wzRoot);
218
219 if (S_OK == hr)
220 {
221 pwzErrors = reinterpret_cast<LPWSTR>(mr.pbMDData);
222 break;
223 }
224
225 // Don't keep going if we're at the root
226 if (0 == lstrcmpW(pwz + 1, L"W3SVC"))
227 break;
228 }
229 }
230 else
231 {
232 pwzErrors = reinterpret_cast<LPWSTR>(mr.pbMDData);
233 }
234 ExitOnFailure(hr, "failed to discover default error values to start with for web root: %ls", wzRoot);
235
236 // The above code should have come up with some value to start pwzErrors off with. Make sure it did.
237 if (NULL == pwzErrors)
238 {
239 ExitOnFailure(hr = E_UNEXPECTED, "failed to discover default error values to start with for web root: %ls", wzRoot);
240 }
241
242 // Loop through the web errors
243 for (SCA_WEB_ERROR* pswe = psweList; pswe; pswe = pswe->psweNext)
244 {
245 // Assume that we will have to replace
246 fOldValueFound = TRUE;
247
248 // If the subcode is 0, that means "*" in MD_CUSTOM_ERROR (thus the special formatting logic)
249 if (0 == pswe->iSubCode)
250 {
251 hr = StrAllocFormatted(&pwzCodeSubCode, L"%d,*", pswe->iErrorCode);
252 ExitOnFailure(hr, "failed to create error code string while installing web error");
253 }
254 else
255 {
256 hr = StrAllocFormatted(&pwzCodeSubCode, L"%d,%d", pswe->iErrorCode, pswe->iSubCode);
257 ExitOnFailure(hr, "failed to create error code,subcode string while installing web error");
258 }
259
260 hr = MultiSzFindSubstring(pwzErrors, pwzCodeSubCode, &dwFoundCodeSubCodeIndex, &wzFoundCodeSubCode);
261 ExitOnFailure(hr, "failed to find existing error code,subcode: %ls", pwzCodeSubCode);
262
263 // If we didn't find this error code/sub code pair in the list already, make sure it's acceptable to add
264 if (S_FALSE == hr)
265 {
266 //
267 // Make sure this error code/sub code pair is in the "acceptable" list
268 //
269
270 // If the subcode is 0, that means "0" in MD_CUSTOM_ERROR_DESC (no special formatting logic needed)
271 hr = StrAllocFormatted(&pwzAcceptableCodeSubCode, L"%d,%d", pswe->iErrorCode, pswe->iSubCode);
272 ExitOnFailure(hr, "failed to create error code,subcode string while installing web error");
273
274 // We don't care where it is, just whether it's there or not
275 hr = MultiSzFindSubstring(pwzAcceptableErrors, pwzAcceptableCodeSubCode, NULL, NULL);
276 ExitOnFailure(hr, "failed to find whether or not error code, subcode: %ls is supported", pwzCodeSubCode);
277
278 if (S_FALSE == hr)
279 {
280 WcaLog(LOGMSG_VERBOSE, "Skipping error code, subcode: %ls because it is not supported by the server.", pwzCodeSubCode);
281 continue;
282 }
283
284 // If we didn't find it (and its an acceptable error) then we have nothing to replace
285 fOldValueFound = FALSE;
286 }
287
288 // Set up the new error string if needed
289 if (*(pswe->wzFile))
290 {
291 hr = StrAllocFormatted(&pwzNewError, L"%s,FILE,%s", pwzCodeSubCode, pswe->wzFile);
292 ExitOnFailure(hr, "failed to create new error code string with code,subcode: %ls, file: %ls", pwzCodeSubCode, pswe->wzFile);
293 }
294 else if (*(pswe->wzURL))
295 {
296 hr = StrAllocFormatted(&pwzNewError, L"%s,URL,%s", pwzCodeSubCode, pswe->wzURL);
297 ExitOnFailure(hr, "failed to create new error code string with code,subcode: %ls, file: %ls", pwzCodeSubCode, pswe->wzFile);
298 }
299 else if (fOldValueFound)
300 {
301 // If no File or URL was specified, they want a default error so remove the old value from the MULTISZ and move on
302 hr = MultiSzRemoveString(&pwzErrors, dwFoundCodeSubCodeIndex);
303 ExitOnFailure(hr, "failed to remove string for error code sub code: %ls in order to make it 'default'", pwzCodeSubCode);
304 continue;
305 }
306
307 // If we have something to replace, replace it, otherwise, put it at the beginning (order shouldn't matter)
308 if (fOldValueFound)
309 {
310 hr = MultiSzReplaceString(&pwzErrors, dwFoundCodeSubCodeIndex, pwzNewError);
311 ExitOnFailure(hr, "failed to replace old error string with new error string for error code,subcode: %ls", pwzCodeSubCode);
312 }
313 else
314 {
315 hr = MultiSzPrepend(&pwzErrors, NULL, pwzNewError);
316 ExitOnFailure(hr, "failed to prepend new error string for error code,subcode: %ls", pwzCodeSubCode);
317 }
318 }
319
320 // now write the CustomErrors to the metabase
321 if (weptWeb == iParentType)
322 {
323 hr = ScaWriteMetabaseValue(piMetabase, wzRoot, L"/Root", MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, pwzErrors);
324 ExitOnFailure(hr, "Failed to write Web Error to /Root");
325 }
326 else
327 {
328 hr = ScaWriteMetabaseValue(piMetabase, wzRoot, NULL, MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, pwzErrors);
329 ExitOnFailure(hr, "Failed to write Web Error");
330 }
331
332LExit:
333 ReleaseStr(pwzErrors);
334 ReleaseStr(pwzSearchKey);
335 ReleaseStr(pwzCodeSubCode);
336 ReleaseStr(pwzAcceptableCodeSubCode);
337 ReleaseStr(pwzAcceptableErrors);
338
339 return hr;
340}
341
342static HRESULT AddWebErrorToList(SCA_WEB_ERROR** ppsweList)
343{
344 HRESULT hr = S_OK;
345
346 SCA_WEB_ERROR* pswe = static_cast<SCA_WEB_ERROR*>(MemAlloc(sizeof(SCA_WEB_ERROR), TRUE));
347 ExitOnNull(pswe, hr, E_OUTOFMEMORY, "failed to allocate memory for new web error list element");
348
349 pswe->psweNext = *ppsweList;
350 *ppsweList = pswe;
351
352LExit:
353 return hr;
354}
355
356HRESULT ScaWebErrorCheckList(SCA_WEB_ERROR* psweList)
357{
358 if (!psweList)
359 {
360 return S_OK;
361 }
362
363 while (psweList)
364 {
365 WcaLog(LOGMSG_STANDARD, "WebError code: %d subcode: %d for parent: %ls not used!", psweList->iErrorCode, psweList->iSubCode, psweList->wzParentValue);
366 psweList = psweList->psweNext;
367 }
368
369 return E_FAIL;
370}
371
diff --git a/src/ext/Iis/ca/scaweberr.h b/src/ext/Iis/ca/scaweberr.h
new file mode 100644
index 00000000..ad8ff4f5
--- /dev/null
+++ b/src/ext/Iis/ca/scaweberr.h
@@ -0,0 +1,30 @@
1#pragma once
2// 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.
3
4
5enum eWebErrorParentType { weptVDir = 1, weptWeb };
6
7struct SCA_WEB_ERROR
8{
9 int iErrorCode;
10 int iSubCode;
11
12 int iParentType;
13 WCHAR wzParentValue[MAX_DARWIN_KEY + 1];
14
15 WCHAR wzFile[MAX_PATH];
16 WCHAR wzURL[MAX_PATH]; // TODO: this needs to be bigger than MAX_PATH
17
18 SCA_WEB_ERROR *psweNext;
19};
20
21// prototypes
22HRESULT ScaWebErrorRead(
23 SCA_WEB_ERROR **ppsweList,
24 __inout LPWSTR *ppwzCustomActionData
25 );
26void ScaWebErrorFreeList(SCA_WEB_ERROR *psweList);
27HRESULT ScaWebErrorCheckList(SCA_WEB_ERROR* psweList);
28HRESULT ScaGetWebError(int iParentType, LPCWSTR wzParentValue, SCA_WEB_ERROR **ppsweList, SCA_WEB_ERROR **ppsweOut);
29HRESULT ScaWriteWebError(IMSAdminBase* piMetabase, int iParentType, LPCWSTR wzRoot, SCA_WEB_ERROR* psweList);
30
diff --git a/src/ext/Iis/ca/scaweberr7.cpp b/src/ext/Iis/ca/scaweberr7.cpp
new file mode 100644
index 00000000..33c2f1bd
--- /dev/null
+++ b/src/ext/Iis/ca/scaweberr7.cpp
@@ -0,0 +1,88 @@
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
5HRESULT ScaWriteWebError7(
6 __in_z LPCWSTR wzWebName,
7 __in_z LPCWSTR wzRoot,
8 SCA_WEB_ERROR* psweList
9 )
10{
11 HRESULT hr = S_OK;
12
13 hr = ScaWriteConfigID(IIS_WEBERROR_BEGIN);
14 ExitOnFailure(hr, "Fail to write webError begin ID");
15
16 hr = ScaWriteConfigString(wzWebName);
17 ExitOnFailure(hr, "Fail to write webError Web Key");
18
19 hr = ScaWriteConfigString(wzRoot);
20 ExitOnFailure(hr, "Fail to write webError Vdir key");
21
22 // Loop through the HTTP headers
23 for (SCA_WEB_ERROR* pswe = psweList; pswe; pswe = pswe->psweNext)
24 {
25 hr = ScaWriteConfigID(IIS_WEBERROR);
26 ExitOnFailure(hr, "Fail to write webError ID");
27
28 hr = ScaWriteConfigInteger(pswe->iErrorCode);
29 ExitOnFailure(hr, "Fail to write webError code");
30
31 hr = ScaWriteConfigInteger(pswe->iSubCode);
32 ExitOnFailure(hr, "Fail to write webError subcode");
33
34 //just write one
35 if (*(pswe->wzFile))
36 {
37 hr = ScaWriteConfigString(pswe->wzFile);
38 ExitOnFailure(hr, "Fail to write webError file");
39 hr = ScaWriteConfigInteger(0);
40 ExitOnFailure(hr, "Fail to write webError file code");
41 }
42 else if (*(pswe->wzURL))
43 {
44 hr = ScaWriteConfigString(pswe->wzURL);
45 ExitOnFailure(hr, "Fail to write webError URL");
46 hr = ScaWriteConfigInteger(1);
47 ExitOnFailure(hr, "Fail to write webError URL code");
48 }
49 }
50
51 hr = ScaWriteConfigID(IIS_WEBERROR_END);
52 ExitOnFailure(hr, "Fail to write httpHeader end ID");
53
54LExit:
55 return hr;
56
57}
58
59//static HRESULT AddWebErrorToList(SCA_WEB_ERROR** ppsweList)
60//{
61// HRESULT hr = S_OK;
62//
63// SCA_WEB_ERROR* pswe = static_cast<SCA_WEB_ERROR*>(MemAlloc(sizeof(SCA_WEB_ERROR), TRUE));
64// ExitOnNull(pswe, hr, E_OUTOFMEMORY, "failed to allocate memory for new web error list element");
65//
66// pswe->psweNext = *ppsweList;
67// *ppsweList = pswe;
68//
69//LExit:
70// return hr;
71//}
72
73HRESULT ScaWebErrorCheckList7(SCA_WEB_ERROR* psweList)
74{
75 if (!psweList)
76 {
77 return S_OK;
78 }
79
80 while (psweList)
81 {
82 WcaLog(LOGMSG_STANDARD, "WebError code: %d subcode: %d for parent: %ls not used!", psweList->iErrorCode, psweList->iSubCode, psweList->wzParentValue);
83 psweList = psweList->psweNext;
84 }
85
86 return E_FAIL;
87}
88
diff --git a/src/ext/Iis/ca/scaweberr7.h b/src/ext/Iis/ca/scaweberr7.h
new file mode 100644
index 00000000..62448211
--- /dev/null
+++ b/src/ext/Iis/ca/scaweberr7.h
@@ -0,0 +1,10 @@
1#pragma once
2// 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.
3
4
5HRESULT ScaWriteWebError7(
6 __in_z LPCWSTR wzWebName,
7 __in_z LPCWSTR wzRoot,
8 SCA_WEB_ERROR* psweList
9 );
10
diff --git a/src/ext/Iis/ca/scaweblog.cpp b/src/ext/Iis/ca/scaweblog.cpp
new file mode 100644
index 00000000..01147848
--- /dev/null
+++ b/src/ext/Iis/ca/scaweblog.cpp
@@ -0,0 +1,177 @@
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
5enum eWebLogQuery { wlqLog = 1, wlqFormat };
6
7/* ****************************************************************
8 * LookupLogFormatGUID -Looks up a given IIS Log format type in
9 * the metabase and returns the GUID for it.
10 * ****************************************************************/
11static HRESULT LookupLogFormatGUID(
12 __in IMSAdminBase* piMetabase,
13 __in LPCWSTR wzLogFormat,
14 __out_ecount(cchGUID) LPWSTR wzGUID,
15 __in int cchGUID
16 )
17{
18 WCHAR wzKey[METADATA_MAX_NAME_LEN];
19 HRESULT hr = S_OK;
20
21 METADATA_RECORD mrKeyType;
22 ::ZeroMemory(&mrKeyType, sizeof(mrKeyType));
23
24 mrKeyType.dwMDIdentifier = MD_KEY_TYPE;
25 mrKeyType.dwMDAttributes = METADATA_NO_ATTRIBUTES;
26 mrKeyType.dwMDUserType = IIS_MD_UT_SERVER;
27 mrKeyType.dwMDDataType = ALL_METADATA;
28 mrKeyType.dwMDDataLen = 0;
29 mrKeyType.pbMDData = NULL;
30
31 METADATA_RECORD mrPluginId;
32 ::ZeroMemory(&mrPluginId, sizeof(mrPluginId));
33
34 mrPluginId.dwMDIdentifier = MD_LOG_PLUGIN_MOD_ID;
35 mrPluginId.dwMDAttributes = METADATA_INHERIT;
36 mrPluginId.dwMDUserType = IIS_MD_UT_SERVER;
37 mrPluginId.dwMDDataType = ALL_METADATA;
38 mrPluginId.dwMDDataLen = 0;
39 mrPluginId.pbMDData = NULL;
40
41 hr = ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/Logging/%s", wzLogFormat);
42 ExitOnFailure(hr, "failed to format logging metabase key name");
43
44 // verify that we have this log format available in IIS
45 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mrKeyType);
46 ExitOnFailure(hr, "Failed to find specified Log format key in IIS for log format: %ls", wzLogFormat);
47 ExitOnNull(mrKeyType.pbMDData, hr, E_POINTER, "Request for Log format key in IIS for log format returned success, but value was NULL");
48
49 if (0 != lstrcmpW(L"IIsLogModule", (LPCWSTR)mrKeyType.pbMDData))
50 {
51 ExitOnFailure(hr = E_UNEXPECTED, "Found invalid log format in IIS: %ls", (LPCWSTR)mrKeyType.pbMDData);
52 }
53
54 // find the GUID for that log format
55 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mrPluginId);
56 ExitOnFailure(hr, "Failed to retrieve IISLog format GUID. Key: %ls", wzKey);
57 ExitOnNull(mrPluginId.pbMDData, hr, E_POINTER, "Retrieval of IISLog format GUID returned success, but value was NULL");
58
59 hr = ::StringCchCopyW(wzGUID, cchGUID, (LPCWSTR)mrPluginId.pbMDData);
60 ExitOnFailure(hr, "failed to copy metabase value: %ls", (LPCWSTR)mrPluginId.pbMDData);
61
62LExit:
63
64 if (mrKeyType.pbMDData)
65 {
66 MetaFreeValue(&mrKeyType);
67 }
68
69 if (mrPluginId.pbMDData)
70 {
71 MetaFreeValue(&mrPluginId);
72 }
73
74 return hr;
75}
76
77
78/* ****************************************************************
79 * ScaGetWebLog -Retrieves Log table data for the specified Log key
80 *
81 * ****************************************************************/
82HRESULT ScaGetWebLog(
83 IMSAdminBase* piMetabase,
84 LPCWSTR wzLog,
85 __in WCA_WRAPQUERY_HANDLE hWebLogQuery,
86 SCA_WEB_LOG* pswl
87 )
88{
89 HRESULT hr = S_OK;
90 LPWSTR pwzData = NULL;
91 MSIHANDLE hRec;
92
93 if (0 == WcaGetQueryRecords(hWebLogQuery))
94 {
95 WcaLog(LOGMSG_VERBOSE, "Skipping ScaGetWebLog() - no records to process");
96 ExitFunction1(hr = S_FALSE);
97 }
98
99 WcaFetchWrappedReset(hWebLogQuery);
100
101 hr = WcaFetchWrappedRecordWhereString(hWebLogQuery, wlqLog, wzLog, &hRec);
102 if (E_NOMOREITEMS == hr)
103 {
104 ExitOnFailure(hr, "cannot locate IIsWebLog.Log='%ls'", wzLog);
105 }
106 HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWebLogQuery, wlqLog, wzLog, &hRec);
107
108 if (SUCCEEDED(hrTemp))
109 {
110 ExitOnFailure(hr, "error - found multiple matching IIsWebLog rows");
111 }
112
113 ::ZeroMemory(pswl, sizeof(SCA_WEB_LOG));
114
115 // check that log key matches
116 hr = WcaGetRecordString(hRec, wlqLog, &pwzData);
117 ExitOnFailure(hr, "failed to get IIsWebLog.Log for Log: %ls", wzLog);
118 hr = ::StringCchCopyW(pswl->wzLog, countof(pswl->wzLog), pwzData);
119 ExitOnFailure(hr, "failed to copy log name: %ls", pwzData);
120
121 hr = WcaGetRecordString(hRec, wlqFormat, &pwzData);
122 ExitOnFailure(hr, "failed to get IIsWebLog.Format for Log:", wzLog);
123 hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), pwzData);
124 ExitOnFailure(hr, "failed to copy log format: %ls", pwzData);
125
126 // if they specified a log format, look up its GUID in the metabase
127 if (*pswl->wzFormat && 0 != lstrcmpW(pswl->wzFormat, L"none"))
128 {
129 hr = LookupLogFormatGUID(piMetabase, pswl->wzFormat, pswl->wzFormatGUID, countof(pswl->wzFormatGUID));
130 ExitOnFailure(hr, "Failed to get Log Format GUID for Log: %ls", wzLog);
131 }
132
133LExit:
134 ReleaseStr(pwzData);
135
136 return hr;
137}
138
139
140/* ****************************************************************
141 * ScaWriteWebLog -Writes the IIS log values to the metabase.
142 *
143 * ****************************************************************/
144HRESULT ScaWriteWebLog(
145 IMSAdminBase* piMetabase,
146 LPCWSTR wzWebBase,
147 SCA_WEB_LOG *pswl
148 )
149{
150 HRESULT hr = S_OK;
151
152 if (*pswl->wzFormat)
153 {
154 if (0 == lstrcmpW(pswl->wzFormat, L"none"))
155 {
156 // user wishes for Logging to be turned 'off'
157 hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_LOG_TYPE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)0));
158 ExitOnFailure(hr, "Failed to write Log Type for Web: %ls", wzWebBase);
159 }
160 else
161 {
162 Assert(*pswl->wzFormatGUID);
163
164 // write the GUID for the log format for the web to the metabase
165 hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_LOG_PLUGIN_ORDER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, pswl->wzFormatGUID);
166 ExitOnFailure(hr, "Failed to write Log GUID for Web: %ls", wzWebBase);
167
168 hr = ScaWriteMetabaseValue(piMetabase, wzWebBase, L"", MD_LOG_TYPE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)1));
169 ExitOnFailure(hr, "Failed to write Log Type for Web: %ls", wzWebBase);
170 }
171 }
172
173LExit:
174 return hr;
175}
176
177
diff --git a/src/ext/Iis/ca/scaweblog.h b/src/ext/Iis/ca/scaweblog.h
new file mode 100644
index 00000000..1a690cce
--- /dev/null
+++ b/src/ext/Iis/ca/scaweblog.h
@@ -0,0 +1,27 @@
1#pragma once
2// 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.
3
4
5struct SCA_WEB_LOG
6{
7 // iis configuation information
8 WCHAR wzLog[MAX_DARWIN_KEY + 1];
9
10 // for specifying the log format
11 WCHAR wzFormat[MAX_DARWIN_KEY + 1];
12 WCHAR wzFormatGUID[MAX_DARWIN_KEY + 1];
13};
14
15
16// prototypes
17HRESULT ScaGetWebLog(
18 IMSAdminBase* piMetabase,
19 LPCWSTR wzLog,
20 __in WCA_WRAPQUERY_HANDLE hWebLogQuery,
21 SCA_WEB_LOG* pswl
22 );
23HRESULT ScaWriteWebLog(
24 IMSAdminBase* piMetabase,
25 LPCWSTR wzRootOfWeb,
26 SCA_WEB_LOG *pswl
27 );
diff --git a/src/ext/Iis/ca/scaweblog7.cpp b/src/ext/Iis/ca/scaweblog7.cpp
new file mode 100644
index 00000000..c857c46f
--- /dev/null
+++ b/src/ext/Iis/ca/scaweblog7.cpp
@@ -0,0 +1,120 @@
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// sql queries
5LPCWSTR vcsWebLogQuery7 = L"SELECT `Log`, `Format` "
6 L"FROM `IIsWebLog` WHERE `Log`=?";
7
8enum eWebLogQuery { wlqLog = 1, wlqFormat };
9
10/* ****************************************************************
11 * ScaGetWebLog7 -Retrieves Log table data for the specified Log key
12 *
13 * ****************************************************************/
14HRESULT ScaGetWebLog7(
15 __in_z LPCWSTR wzLog,
16 __in WCA_WRAPQUERY_HANDLE hWebLogQuery,
17 __out SCA_WEB_LOG* pswl
18 )
19{
20 HRESULT hr = S_OK;
21 LPWSTR pwzData = NULL;
22 MSIHANDLE hRec;
23
24 if (0 == WcaGetQueryRecords(hWebLogQuery))
25 {
26 WcaLog(LOGMSG_VERBOSE, "Skipping ScaGetWebLog() - no records to process");
27 ExitFunction1(hr = S_FALSE);
28 }
29
30 WcaFetchWrappedReset(hWebLogQuery);
31
32 hr = WcaFetchWrappedRecordWhereString(hWebLogQuery, wlqLog, wzLog, &hRec);
33 if (E_NOMOREITEMS == hr)
34 {
35 ExitOnFailure(hr, "cannot locate IIsWebLog.Log='%ls'", wzLog);
36 }
37 HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWebLogQuery, wlqLog, wzLog, &hRec);
38
39 if (SUCCEEDED(hrTemp))
40 {
41 ExitOnFailure(hr, "error - found multiple matching IIsWebLog rows");
42 }
43
44 ::ZeroMemory(pswl, sizeof(SCA_WEB_LOG));
45
46 // check that log key matches
47 hr = WcaGetRecordString(hRec, wlqLog, &pwzData);
48 ExitOnFailure(hr, "failed to get IIsWebLog.Log for Log: %ls", wzLog);
49 hr = ::StringCchCopyW(pswl->wzLog, countof(pswl->wzLog), pwzData);
50 ExitOnFailure(hr, "failed to copy log name: %ls", pwzData);
51
52 hr = WcaGetRecordString(hRec, wlqFormat, &pwzData);
53 ExitOnFailure(hr, "failed to get IIsWebLog.Format for Log:", wzLog);
54
55 //translate WIX log format name strings to IIS7
56 if (0 == lstrcmpW(pwzData, L"Microsoft IIS Log File Format"))
57 {
58 hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), L"IIS");
59 ExitOnFailure(hr, "failed to copy log format: %ls", pwzData);
60 }
61 else if (0 == lstrcmpW(pwzData, L"NCSA Common Log File Format"))
62 {
63 hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), L"NCSA");
64 ExitOnFailure(hr, "failed to copy log format: %ls", pwzData);
65 }
66 else if (0 == lstrcmpW(pwzData, L"none"))
67 {
68 hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), L"none");
69 ExitOnFailure(hr, "failed to copy log format: %ls", pwzData);
70 }
71 else if (0 == lstrcmpW(pwzData, L"ODBC Logging"))
72 {
73 hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), L"W3C");
74 ExitOnFailure(hr, "failed to copy log format: %ls", pwzData);
75 }
76 else if (0 == lstrcmpW(pwzData, L"W3C Extended Log File Format"))
77 {
78 hr = ::StringCchCopyW(pswl->wzFormat, countof(pswl->wzFormat), L"W3C");
79 ExitOnFailure(hr, "failed to copy log format: %ls", pwzData);
80 }
81 else
82 {
83 hr = HRESULT_FROM_WIN32(ERROR_INVALID_INDEX);
84 ExitOnFailure(hr, "Invalid log file format: %ls", pwzData);
85 }
86
87LExit:
88 ReleaseStr(pwzData);
89
90 return hr;
91}
92
93
94/* ****************************************************************
95 * ScaWriteWebLog -Writes the IIS log values to the metabase.
96 *
97 * ****************************************************************/
98HRESULT ScaWriteWebLog7(
99 LPCWSTR wzWebBase,
100 const SCA_WEB_LOG *pswl
101 )
102{
103 HRESULT hr = S_OK;
104
105 if (*pswl->wzFormat)
106 {
107 //write pswl->wzFormat
108 hr = ScaWriteConfigID(IIS_WEBLOG);
109 ExitOnFailure(hr, "Failed to write log format id");
110 hr = ScaWriteConfigString(wzWebBase);
111 ExitOnFailure(hr, "Failed to write log web key");
112 hr = ScaWriteConfigString(pswl->wzFormat);
113 ExitOnFailure(hr, "Failed to write log format string");
114 }
115
116LExit:
117 return hr;
118}
119
120
diff --git a/src/ext/Iis/ca/scaweblog7.h b/src/ext/Iis/ca/scaweblog7.h
new file mode 100644
index 00000000..f2bb60d7
--- /dev/null
+++ b/src/ext/Iis/ca/scaweblog7.h
@@ -0,0 +1,14 @@
1#pragma once
2// 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.
3
4
5HRESULT ScaGetWebLog7(
6 __in_z LPCWSTR wzLog,
7 __in WCA_WRAPQUERY_HANDLE hWebLogQuery,
8 __out SCA_WEB_LOG* pswl
9 );
10
11HRESULT ScaWriteWebLog7(
12 __in_z LPCWSTR wzRootOfWeb,
13 const SCA_WEB_LOG *pswl
14 );
diff --git a/src/ext/Iis/ca/scawebprop.cpp b/src/ext/Iis/ca/scawebprop.cpp
new file mode 100644
index 00000000..b5e38467
--- /dev/null
+++ b/src/ext/Iis/ca/scawebprop.cpp
@@ -0,0 +1,301 @@
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// sql queries
6enum eWebDirPropertiesQuery { wpqProperties = 1, wpqAccess, wpqAuthorization, wpqUser, wpqControlledPassword, wpqLogVisits, wpqIndex, wpqDefaultDoc, wpqAspDetailedError, wpqHttpExp, wpqCCMaxAge, wpqCCCustom, wpqNoCustomError, wpqAccessSSLFlags, wpqAuthenticationProviders };
7
8HRESULT ScaGetWebDirProperties(
9 __in LPCWSTR wzProperties,
10 __in WCA_WRAPQUERY_HANDLE hUserQuery,
11 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
12 __inout SCA_WEB_PROPERTIES* pswp
13 )
14{
15 Assert(*wzProperties && pswp);
16
17 HRESULT hr = S_OK;
18 MSIHANDLE hRec;
19 LPWSTR pwzData = NULL;
20
21 ExitOnNull(wzProperties, hr, E_INVALIDARG, "Failed to get web directory properties because no properties were provided to get");
22
23 WcaFetchWrappedReset(hWebDirPropQuery);
24
25 hr = WcaFetchWrappedRecordWhereString(hWebDirPropQuery, 1, wzProperties, &hRec);
26 if (S_OK == hr)
27 {
28 hr = WcaGetRecordString(hRec, wpqProperties, &pwzData);
29 ExitOnFailure(hr, "Failed to get IIsWebDirProperties.DirProperties");
30 hr = ::StringCchCopyW(pswp->wzKey, countof(pswp->wzKey), pwzData);
31 ExitOnFailure(hr, "Failed to copy key string to webdirproperties object");
32
33 Assert(0 == lstrcmpW(pswp->wzKey, wzProperties));
34
35 hr = WcaGetRecordInteger(hRec, wpqAccess, &pswp->iAccess);
36 ExitOnFailure(hr, "Failed to get access value");
37
38 hr = WcaGetRecordInteger(hRec, wpqAuthorization, &pswp->iAuthorization);
39 ExitOnFailure(hr, "Failed to get authorization value");
40
41 // if allow anonymous users
42 if (S_OK == hr && pswp->iAuthorization & 1)
43 {
44 // if there is an anonymous user specified
45 hr = WcaGetRecordString(hRec, wpqUser, &pwzData);
46 ExitOnFailure(hr, "Failed to get AnonymousUser_");
47 if (pwzData && *pwzData)
48 {
49 hr = WcaGetRecordInteger(hRec, wpqControlledPassword, &pswp->fIIsControlledPassword);
50 ExitOnFailure(hr, "Failed to get IIsControlledPassword");
51 if (S_FALSE == hr)
52 {
53 pswp->fIIsControlledPassword = FALSE;
54 hr = S_OK;
55 }
56
57 hr = ScaGetUserDeferred(pwzData, hUserQuery, &pswp->scau);
58 ExitOnFailure(hr, "Failed to get User information for Web");
59
60 pswp->fHasUser = TRUE;
61 }
62 else
63 pswp->fHasUser = FALSE;
64 }
65
66 hr = WcaGetRecordInteger(hRec, wpqLogVisits, &pswp->fLogVisits);
67 ExitOnFailure(hr, "Failed to get IIsWebDirProperties.LogVisits");
68
69 hr = WcaGetRecordInteger(hRec, wpqIndex, &pswp->fIndex);
70 ExitOnFailure(hr, "Failed to get IIsWebDirProperties.Index");
71
72 hr = WcaGetRecordString(hRec, wpqDefaultDoc, &pwzData);
73 ExitOnFailure(hr, "Failed to get IIsWebDirProperties.DefaultDoc");
74 if (pwzData && *pwzData)
75 {
76 pswp->fHasDefaultDoc = TRUE;
77 if (0 == lstrcmpW(L"-", pwzData)) // remove any existing default documents by setting them blank
78 {
79 pswp->wzDefaultDoc[0] = L'\0';
80 }
81 else // set the default documents
82 {
83 hr = ::StringCchCopyW(pswp->wzDefaultDoc, countof(pswp->wzDefaultDoc), pwzData);
84 ExitOnFailure(hr, "Failed to copy default document string to webdirproperties object");
85 }
86 }
87 else
88 {
89 pswp->fHasDefaultDoc = FALSE;
90 }
91
92 hr = WcaGetRecordInteger(hRec, wpqAspDetailedError, &pswp->fAspDetailedError);
93 ExitOnFailure(hr, "Failed to get IIsWebDirProperties.AspDetailedError");
94
95 hr = WcaGetRecordString(hRec, wpqHttpExp, &pwzData);
96 ExitOnFailure(hr, "Failed to get IIsWebDirProperties.HttpExp");
97 if (pwzData && *pwzData)
98 {
99 pswp->fHasHttpExp = TRUE;
100 if (0 == lstrcmpW(L"-", pwzData)) // remove any existing default expiration settings by setting them blank
101 {
102 pswp->wzHttpExp[0] = L'\0';
103 }
104 else // set the expiration setting
105 {
106 hr = ::StringCchCopyW(pswp->wzHttpExp, countof(pswp->wzHttpExp), pwzData);
107 ExitOnFailure(hr, "Failed to copy http expiration string to webdirproperties object");
108 }
109 }
110 else
111 {
112 pswp->fHasHttpExp = FALSE;
113 }
114
115 hr = WcaGetRecordInteger(hRec, wpqCCMaxAge, &pswp->iCacheControlMaxAge);
116 ExitOnFailure(hr, "failed to get IIsWebDirProperties.CacheControlMaxAge");
117
118 hr = WcaGetRecordString(hRec, wpqCCCustom, &pwzData);
119 ExitOnFailure(hr, "Failed to get IIsWebDirProperties.CacheControlCustom");
120 if (pwzData && *pwzData)
121 {
122 pswp->fHasCacheControlCustom = TRUE;
123 if (0 == lstrcmpW(L"-", pwzData)) // remove any existing default cache control custom settings by setting them blank
124 {
125 pswp->wzCacheControlCustom[0] = L'\0';
126 }
127 else // set the custom cache control setting
128 {
129 hr = ::StringCchCopyW(pswp->wzCacheControlCustom, countof(pswp->wzCacheControlCustom), pwzData);
130 ExitOnFailure(hr, "Failed to copy cache control custom settings to webdirproperites object");
131 }
132 }
133 else
134 {
135 pswp->fHasCacheControlCustom = FALSE;
136 }
137
138 hr = WcaGetRecordInteger(hRec, wpqNoCustomError, &pswp->fNoCustomError);
139 ExitOnFailure(hr, "failed to get IIsWebDirProperties.NoCustomError");
140 if (MSI_NULL_INTEGER == pswp->fNoCustomError)
141 pswp->fNoCustomError = FALSE;
142
143 hr = WcaGetRecordInteger(hRec, wpqAccessSSLFlags, &pswp->iAccessSSLFlags);
144 ExitOnFailure(hr, "failed to get IIsWebDirProperties.AccessSSLFlags");
145
146 hr = WcaGetRecordString(hRec, wpqAuthenticationProviders, &pwzData);
147 ExitOnFailure(hr, "Failed to get IIsWebDirProperties.AuthenticationProviders");
148 if (pwzData && *pwzData)
149 {
150 hr = ::StringCchCopyW(pswp->wzAuthenticationProviders, countof(pswp->wzAuthenticationProviders), pwzData);
151 ExitOnFailure(hr, "Failed to copy authentication providers string to webdirproperties object");
152 }
153 else
154 {
155 pswp->wzAuthenticationProviders[0] = L'\0';
156 }
157 }
158 else if (E_NOMOREITEMS == hr)
159 {
160 WcaLog(LOGMSG_STANDARD, "Error: Cannot locate IIsWebDirProperties.DirProperties='%ls'", wzProperties);
161 hr = E_FAIL;
162 }
163 else
164 {
165 ExitOnFailure(hr, "Error getting appropriate webdirproperty");
166 }
167
168 // Let's check that there isn't more than one record found - if there is, throw an assert like WcaFetchSingleRecord() would
169 HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWebDirPropQuery, 1, wzProperties, &hRec);
170 if (SUCCEEDED(hrTemp))
171 {
172 AssertSz(E_NOMOREITEMS == hrTemp, "ScaGetWebDirProperties found more than one record");
173 }
174
175LExit:
176 ReleaseStr(pwzData);
177
178 return hr;
179}
180
181
182HRESULT ScaWriteWebDirProperties(
183 __in IMSAdminBase* piMetabase,
184 __in LPCWSTR wzRootOfWeb,
185 __inout SCA_WEB_PROPERTIES* pswp
186 )
187{
188 HRESULT hr = S_OK;
189 DWORD dw = 0;
190 WCHAR wz[METADATA_MAX_NAME_LEN + 1];
191
192 // write the access permissions to the metabase
193 if (MSI_NULL_INTEGER != pswp->iAccess)
194 {
195 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iAccess));
196 ExitOnFailure(hr, "Failed to write access permissions for Web");
197 }
198
199 if (MSI_NULL_INTEGER != pswp->iAuthorization)
200 {
201 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_AUTHORIZATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iAuthorization));
202 ExitOnFailure(hr, "Failed to write authorization for Web");
203 }
204
205 if (pswp->fHasUser)
206 {
207 Assert(pswp->scau.wzName);
208 // write the user name
209 if (*pswp->scau.wzDomain)
210 {
211 hr = ::StringCchPrintfW(wz, countof(wz), L"%s\\%s", pswp->scau.wzDomain, pswp->scau.wzName);
212 ExitOnFailure(hr, "Failed to format domain\\username string");
213 }
214 else
215 {
216 hr = ::StringCchCopyW(wz, countof(wz), pswp->scau.wzName);
217 ExitOnFailure(hr, "Failed to copy user name");
218 }
219 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ANONYMOUS_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)wz);
220 ExitOnFailure(hr, "Failed to write anonymous user name for Web");
221
222 // write the password
223 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ANONYMOUS_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->scau.wzPassword);
224 ExitOnFailure(hr, "Failed to write anonymous user password for Web");
225
226 // store whether IIs controls password
227 dw = (pswp->fIIsControlledPassword) ? TRUE : FALSE;
228 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ANONYMOUS_USE_SUBAUTH, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw));
229 ExitOnFailure(hr, "Failed to write if IIs controls user password for Web");
230 }
231
232 if (MSI_NULL_INTEGER != pswp->fLogVisits)
233 {
234 // The sense of this boolean value is reversed - it is "don't log", not "log visits."
235 dw = (pswp->fLogVisits) ? FALSE : TRUE;
236 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_DONT_LOG, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw));
237 ExitOnFailure(hr, "Failed to write authorization for Web");
238 }
239
240 if (MSI_NULL_INTEGER != pswp->fIndex)
241 {
242 dw = (pswp->fIndex) ? TRUE : FALSE;
243 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_IS_CONTENT_INDEXED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw));
244 ExitOnFailure(hr, "Failed to write authorization for Web");
245 }
246
247 if (pswp->fHasDefaultDoc)
248 {
249 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_DEFAULT_LOAD_FILE, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->wzDefaultDoc);
250 ExitOnFailure(hr, "Failed to write default documents for Web");
251 }
252
253 if (MSI_NULL_INTEGER != pswp->fAspDetailedError)
254 {
255 dw = (pswp->fAspDetailedError) ? TRUE : FALSE;
256 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_SCRIPTERRORSSENTTOBROWSER, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw));
257 ExitOnFailure(hr, "Failed to write ASP script error for Web");
258 }
259
260 if (pswp->fHasHttpExp)
261 {
262 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_HTTP_EXPIRES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->wzHttpExp);
263 ExitOnFailure(hr, "Failed to write HTTP Expiration for Web");
264 }
265
266 if (MSI_NULL_INTEGER != pswp->iCacheControlMaxAge)
267 {
268 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_CC_MAX_AGE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iCacheControlMaxAge));
269 ExitOnFailure(hr, "Failed to write Cache Control Max Age for Web");
270 }
271
272 if (pswp->fHasCacheControlCustom)
273 {
274 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_CC_OTHER, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->wzCacheControlCustom);
275 ExitOnFailure(hr, "Failed to write Cache Control Custom for Web");
276 }
277
278 if (pswp->fNoCustomError)
279 {
280 memset(wz, 0, sizeof(wz));
281 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, wz);
282 ExitOnFailure(hr, "Failed to write Custom Error for Web");
283 }
284
285 if (MSI_NULL_INTEGER != pswp->iAccessSSLFlags)
286 {
287 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_SSL_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iAccessSSLFlags));
288 ExitOnFailure(hr, "Failed to write AccessSSLFlags for Web");
289 }
290
291 if (*pswp->wzAuthenticationProviders)
292 {
293 hr = ::StringCchCopyW(wz, countof(wz), pswp->wzAuthenticationProviders);
294 ExitOnFailure(hr, "Failed to copy authentication providers string");
295 hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_NTAUTHENTICATION_PROVIDERS, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)wz);
296 ExitOnFailure(hr, "Failed to write AuthenticationProviders for Web");
297 }
298
299LExit:
300 return hr;
301}
diff --git a/src/ext/Iis/ca/scawebprop.h b/src/ext/Iis/ca/scawebprop.h
new file mode 100644
index 00000000..7a3ae5c9
--- /dev/null
+++ b/src/ext/Iis/ca/scawebprop.h
@@ -0,0 +1,60 @@
1#pragma once
2// 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.
3
4
5#include "scauser.h"
6
7// global sql queries provided for optimization
8extern LPCWSTR vcsWebDirPropertiesQuery;
9
10
11// structs
12struct SCA_WEB_PROPERTIES
13{
14 WCHAR wzKey[MAX_DARWIN_KEY + 1];
15
16 int iAccess;
17
18 int iAuthorization;
19 BOOL fHasUser;
20 SCA_USER scau;
21 BOOL fIIsControlledPassword;
22
23 BOOL fLogVisits;
24 BOOL fIndex;
25
26 BOOL fHasDefaultDoc;
27 WCHAR wzDefaultDoc[MAX_DARWIN_COLUMN + 1];
28
29 BOOL fHasHttpExp;
30 WCHAR wzHttpExp[MAX_DARWIN_COLUMN + 1];
31
32 BOOL fAspDetailedError;
33
34 int iCacheControlMaxAge;
35
36 BOOL fHasCacheControlCustom;
37 WCHAR wzCacheControlCustom[MAX_DARWIN_COLUMN + 1];
38
39 BOOL fNoCustomError;
40
41 int iAccessSSLFlags;
42
43 WCHAR wzAuthenticationProviders[MAX_DARWIN_COLUMN + 1];
44};
45
46
47// prototypes
48HRESULT ScaGetWebDirProperties(
49 __in LPCWSTR pwzProperties,
50 __in WCA_WRAPQUERY_HANDLE hUserQuery,
51 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
52 __inout SCA_WEB_PROPERTIES* pswp
53 );
54
55HRESULT ScaWriteWebDirProperties(
56 __in IMSAdminBase* piMetabase,
57 __in LPCWSTR wzRootOfWeb,
58 __inout SCA_WEB_PROPERTIES* pswp
59 );
60
diff --git a/src/ext/Iis/ca/scawebprop7.cpp b/src/ext/Iis/ca/scawebprop7.cpp
new file mode 100644
index 00000000..b8d99b0a
--- /dev/null
+++ b/src/ext/Iis/ca/scawebprop7.cpp
@@ -0,0 +1,155 @@
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
5HRESULT ScaWriteWebDirProperties7(
6 __in_z LPCWSTR wzWebName,
7 __in_z LPCWSTR wzRootOfWeb,
8 __in const SCA_WEB_PROPERTIES* pswp
9 )
10{
11 HRESULT hr = S_OK;
12 WCHAR wz[METADATA_MAX_NAME_LEN + 1];
13
14 //all go to same web/root location tag
15 hr = ScaWriteConfigID(IIS_DIRPROP_BEGIN);
16 ExitOnFailure(hr, "Failed to write DirProp begin id");
17 hr = ScaWriteConfigString(wzWebName); //site name key
18 ExitOnFailure(hr, "Failed to write DirProp web key");
19 hr = ScaWriteConfigString(wzRootOfWeb); //app path key
20 ExitOnFailure(hr, "Failed to write DirProp app key");
21
22 // write the access permissions to the metabase
23 if (MSI_NULL_INTEGER != pswp->iAccess)
24 {
25 hr = ScaWriteConfigID(IIS_DIRPROP_ACCESS);
26 ExitOnFailure(hr, "Failed to write DirProp access id");
27 hr = ScaWriteConfigInteger(pswp->iAccess);
28 ExitOnFailure(hr, "Failed to write access permissions for Web");
29 }
30
31 if (MSI_NULL_INTEGER != pswp->iAuthorization)
32 {
33 hr = ScaWriteConfigID(IIS_DIRPROP_AUTH);
34 ExitOnFailure(hr, "Failed to write DirProp auth id");
35 hr = ScaWriteConfigInteger(pswp->iAuthorization);
36 ExitOnFailure(hr, "Failed to write authorization for Web");
37 }
38
39 if (pswp->fHasUser)
40 {
41 Assert(pswp->scau.wzName);
42 // write the user name
43 if (*pswp->scau.wzDomain)
44 {
45 hr = ::StringCchPrintfW(wz, countof(wz), L"%s\\%s", pswp->scau.wzDomain, pswp->scau.wzName);
46 ExitOnFailure(hr, "Failed to format domain\\username string");
47 }
48 else
49 {
50#pragma prefast(suppress:26037, "Source string is null terminated - it is populated as target of ::StringCchCopyW")
51 hr = ::StringCchCopyW(wz, countof(wz), pswp->scau.wzName);
52 ExitOnFailure(hr, "Failed to copy user name");
53 }
54 hr = ScaWriteConfigID(IIS_DIRPROP_USER);
55 ExitOnFailure(hr, "Failed to write DirProp user id");
56 hr = ScaWriteConfigString(wz);
57 ExitOnFailure(hr, "Failed to write anonymous user name for Web");
58
59 // write the password
60 hr = ScaWriteConfigID(IIS_DIRPROP_PWD);
61 ExitOnFailure(hr, "Failed to write DirProp pwd id");
62 hr = ScaWriteConfigString(pswp->scau.wzPassword);
63 ExitOnFailure(hr, "Failed to write anonymous user password for Web");
64
65 if (pswp->fIIsControlledPassword)
66 {
67 //Not Supported by IIS7 : pswp->fIIsControlledPassword
68 WcaLog(LOGMSG_VERBOSE, "Not supported by IIS7: WebDirProperties.IIsControlledPassword, ignoring");
69 }
70 }
71
72 if (MSI_NULL_INTEGER != pswp->fLogVisits)
73 {
74 hr = ScaWriteConfigID(IIS_DIRPROP_LOGVISITS);
75 ExitOnFailure(hr, "Failed to write DirProp logVisits id");
76 hr = ScaWriteConfigInteger(pswp->fLogVisits ? FALSE : TRUE); // we capture "should log" but IIS7 wants "should not log"
77 ExitOnFailure(hr, "Failed to write DirProp logVisits");
78 }
79
80 if (MSI_NULL_INTEGER != pswp->fIndex)
81 {
82 //Not Supported by IIS7 : pswp->fIndex
83 WcaLog(LOGMSG_VERBOSE, "Not supported by IIS7: WebDirProperties.Index, ignoring");
84 }
85
86 if (pswp->fHasDefaultDoc)
87 {
88 hr = ScaWriteConfigID(IIS_DIRPROP_DEFDOCS);
89 ExitOnFailure(hr, "Failed to write DirProp defdocs id");
90 hr = ScaWriteConfigString(pswp->wzDefaultDoc);
91 ExitOnFailure(hr, "Failed to write default documents for Web");
92 }
93
94 if (MSI_NULL_INTEGER != pswp->fAspDetailedError)
95 {
96 hr = ScaWriteConfigID(IIS_DIRPROP_ASPERROR);
97 ExitOnFailure(hr, "Failed to write ASP script error id");
98 hr = ScaWriteConfigInteger(pswp->fAspDetailedError);
99 ExitOnFailure(hr, "Failed to write ASP script error for Web");
100 }
101
102 if (pswp->fHasHttpExp)
103 {
104 hr = ScaWriteConfigID(IIS_DIRPROP_HTTPEXPIRES);
105 ExitOnFailure(hr, "Failed to write DirProp HttpExpires id");
106 hr = ScaWriteConfigString(pswp->wzHttpExp);
107 ExitOnFailure(hr, "Failed to write DirProp HttpExpires value");
108 }
109
110 if (MSI_NULL_INTEGER != pswp->iCacheControlMaxAge)
111 {
112 hr = ScaWriteConfigID(IIS_DIRPROP_MAXAGE);
113 ExitOnFailure(hr, "Failed to write DirProp MaxAge id");
114 hr = ScaWriteConfigInteger(pswp->iCacheControlMaxAge);
115 ExitOnFailure(hr, "Failed to write DirProp MaxAge value");
116 }
117
118 if (pswp->fHasCacheControlCustom)
119 {
120 hr = ScaWriteConfigID(IIS_DIRPROP_CACHECUST);
121 ExitOnFailure(hr, "Failed to write DirProp Cache Control Custom id");
122 hr = ScaWriteConfigString(pswp->wzCacheControlCustom);
123 ExitOnFailure(hr, "Failed to write Cache Control Custom for Web");
124 }
125
126 if (pswp->fNoCustomError)
127 {
128 hr = ScaWriteConfigID(IIS_DIRPROP_NOCUSTERROR);
129 ExitOnFailure(hr, "Failed to write DirProp clear Cust Errors id");
130 }
131
132 if (MSI_NULL_INTEGER != pswp->iAccessSSLFlags)
133 {
134 hr = ScaWriteConfigID(IIS_DIRPROP_SSLFLAGS);
135 ExitOnFailure(hr, "Failed to write DirProp sslFlags id");
136 hr = ScaWriteConfigInteger(pswp->iAccessSSLFlags);
137 ExitOnFailure(hr, "Failed to write AccessSSLFlags for Web");
138 }
139
140 if (*pswp->wzAuthenticationProviders)
141 {
142 hr = ::StringCchCopyW(wz, countof(wz), pswp->wzAuthenticationProviders);
143 ExitOnFailure(hr, "Failed to copy authentication providers string");
144 hr = ScaWriteConfigID(IIS_DIRPROP_AUTHPROVID);
145 ExitOnFailure(hr, "Failed to write DirProp AuthProvid id");
146 hr = ScaWriteConfigString(wz);
147 ExitOnFailure(hr, "Failed to write AuthenticationProviders for Web");
148 }
149 //End of Dir Properties
150 hr = ScaWriteConfigID(IIS_DIRPROP_END);
151 ExitOnFailure(hr, "Failed to write DirProp end id");
152
153LExit:
154 return hr;
155}
diff --git a/src/ext/Iis/ca/scawebprop7.h b/src/ext/Iis/ca/scawebprop7.h
new file mode 100644
index 00000000..a97e8679
--- /dev/null
+++ b/src/ext/Iis/ca/scawebprop7.h
@@ -0,0 +1,12 @@
1#pragma once
2// 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.
3
4
5#include "scauser.h"
6
7HRESULT ScaWriteWebDirProperties7(
8 __in_z LPCWSTR wzwWebName,
9 __in_z LPCWSTR wzRootOfWeb,
10 const SCA_WEB_PROPERTIES* pswp
11 );
12
diff --git a/src/ext/Iis/ca/scawebsvcext.cpp b/src/ext/Iis/ca/scawebsvcext.cpp
new file mode 100644
index 00000000..369e951b
--- /dev/null
+++ b/src/ext/Iis/ca/scawebsvcext.cpp
@@ -0,0 +1,343 @@
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// sql queries
6enum eWebSvcExtQuery { ldqComponent=1 , ldqFile, ldqDescription, ldqGroup, ldqAttributes, ldqInstalled, ldqAction };
7
8
9LPCWSTR vcsWebSvcExtRoot = L"/LM/W3SVC";
10
11// prototypes for private helper functions
12static HRESULT AddWebSvcExtToList(
13 __in SCA_WEBSVCEXT** ppsWseList
14 );
15
16//static HRESULT ScaCheckWebSvcExtValue(
17// __in IMSAdminBase* piMetabase,
18// __in DWORD dwMDIdentifier
19// );
20
21static HRESULT ScaWebSvcExtInstall(
22 __in LPWSTR *pwzWebSvcExtList,
23 __in DWORD_PTR *pcchWebSvcExtList,
24 __in SCA_WEBSVCEXT* psWseList
25 );
26
27static HRESULT ScaWebSvcExtUninstall(
28 __in LPWSTR *pwzWebSvcExtList,
29 __in const DWORD *pcchWebSvcExtList,
30 __in SCA_WEBSVCEXT* psWseList
31 );
32
33// functions
34
35HRESULT __stdcall ScaWebSvcExtRead(
36 __in SCA_WEBSVCEXT** ppsWseList,
37 __inout LPWSTR *ppwzCustomActionData
38 )
39{
40 Assert(ppsWseList);
41
42 HRESULT hr = S_OK;
43 MSIHANDLE hRec;
44 LPWSTR pwzData = NULL;
45 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
46 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
47 SCA_WEBSVCEXT* psWebSvcExt = NULL;
48 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
49
50 hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
51 ExitOnFailure(hr, "Failed to unwrap query for ScaWebSvcExtRead");
52
53 if (0 == WcaGetQueryRecords(hWrapQuery))
54 {
55 WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebSvcExtRead() because IIsWebServiceExtension data not present");
56 ExitFunction1(hr = S_FALSE);
57 }
58
59 // loop through all the web service extensions
60 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
61 {
62 // Get the Component first. If the Component is not being modified during
63 // this transaction, skip processing this whole record.
64 hr = WcaGetRecordString(hRec, ldqComponent, &pwzData);
65 ExitOnFailure(hr, "Failed to get Component for WebSvcExt");
66
67 hr = WcaGetRecordInteger(hRec, ldqInstalled, (int *)&isInstalled);
68 ExitOnFailure(hr, "Failed to get Component installed state for WebSvcExt");
69
70 hr = WcaGetRecordInteger(hRec, ldqAction, (int *)&isAction);
71 ExitOnFailure(hr, "Failed to get Component action state for WebSvcExt");
72
73 if (!WcaIsInstalling(isInstalled, isAction) &&
74 !WcaIsReInstalling(isInstalled, isAction) &&
75 !WcaIsUninstalling(isInstalled, isAction))
76 {
77 continue; // skip this record.
78 }
79
80 hr = AddWebSvcExtToList(ppsWseList);
81 ExitOnFailure(hr, "failed to add element to web svc ext list");
82
83 psWebSvcExt = *ppsWseList;
84 Assert(psWebSvcExt);
85
86 psWebSvcExt->isInstalled = isInstalled;
87 psWebSvcExt->isAction = isAction;
88
89 hr = WcaGetRecordString(hRec, ldqFile, &pwzData);
90 ExitOnFailure(hr, "Failed to get File for WebSvcExt");
91 hr = ::StringCchCopyW(psWebSvcExt->wzFile, countof(psWebSvcExt->wzFile), pwzData);
92 ExitOnFailure(hr, "Failed to copy File for WebSvcExt");
93
94 hr = WcaGetRecordString(hRec, ldqDescription, &pwzData);
95 ExitOnFailure(hr, "Failed to get Description for WebSvcExt");
96 hr = ::StringCchCopyW(psWebSvcExt->wzDescription, countof(psWebSvcExt->wzDescription), pwzData);
97 ExitOnFailure(hr, "Failed to copy Description for WebSvcExt");
98
99 hr = WcaGetRecordString(hRec, ldqGroup, &pwzData);
100 ExitOnFailure(hr, "Failed to get Group for WebSvcExt");
101 hr = ::StringCchCopyW(psWebSvcExt->wzGroup, countof(psWebSvcExt->wzGroup), pwzData);
102 ExitOnFailure(hr, "Failed to copy Group for WebSvcExt");
103
104 hr = WcaGetRecordInteger(hRec, ldqAttributes, &psWebSvcExt->iAttributes);
105 ExitOnFailure(hr, "Failed to get Attributes for WebSvcExt");
106 }
107
108 if (E_NOMOREITEMS == hr)
109 hr = S_OK;
110 ExitOnFailure(hr, "Failure while processing WebSvcExt");
111
112LExit:
113 WcaFinishUnwrapQuery(hWrapQuery);
114
115 ReleaseStr(pwzData);
116
117 return hr;
118}
119
120
121// Commit does both install and uninstall
122HRESULT __stdcall ScaWebSvcExtCommit(
123 __in IMSAdminBase* piMetabase,
124 __in SCA_WEBSVCEXT* psWseList
125 )
126{
127 Assert(piMetabase);
128
129 HRESULT hr = S_OK;
130 METADATA_RECORD mr;
131
132 LPWSTR wzWebSvcExtList = NULL;
133 DWORD cbWebSvcExtList = 0;
134 DWORD_PTR cchWebSvcExtList = 0;
135
136 if (!psWseList)
137 {
138 WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebSvcExtCommit() because there are no web service extensions in the list");
139 ExitFunction();
140 }
141
142 // Get current set of web service extensions.
143 ::ZeroMemory(&mr, sizeof(mr));
144 mr.dwMDIdentifier = MD_WEB_SVC_EXT_RESTRICTION_LIST;
145 mr.dwMDAttributes = 0;
146 mr.dwMDUserType = IIS_MD_UT_SERVER;
147 mr.dwMDDataType = ALL_METADATA;
148 mr.pbMDData = NULL;
149 mr.dwMDDataLen = 0;
150
151 hr = piMetabase->GetData(METADATA_MASTER_ROOT_HANDLE, vcsWebSvcExtRoot, &mr, &cbWebSvcExtList);
152 if (MD_ERROR_DATA_NOT_FOUND == hr)
153 {
154 WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebSvcExtCommit() because WebSvcExtRestrictionList value is not present");
155 ExitFunction1(hr = S_FALSE);
156 }
157 else if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr)
158 {
159 // cchWebSvcExtList is returned in bytes. Convert to WCHAR size to call StrAlloc
160 cchWebSvcExtList = cbWebSvcExtList / sizeof(WCHAR);
161 hr = StrAlloc(&wzWebSvcExtList, cchWebSvcExtList);
162 ExitOnFailure(hr, "Failed allocating space for web service extensions");
163 }
164 else
165 {
166 ExitOnFailure(hr, "Failed retrieving web service extensions");
167 }
168
169 mr.pbMDData = (unsigned char*)wzWebSvcExtList;
170 mr.dwMDDataLen = cbWebSvcExtList;
171
172 hr = piMetabase->GetData(METADATA_MASTER_ROOT_HANDLE, vcsWebSvcExtRoot, &mr, &cbWebSvcExtList);
173 ExitOnFailure(hr, "Failed retrieving web service extensions");
174
175 // Make changes to local copy of metabase
176 while (psWseList)
177 {
178 if (WcaIsInstalling(psWseList->isInstalled, psWseList->isAction))
179 {
180 hr = ScaWebSvcExtInstall(&wzWebSvcExtList, &cchWebSvcExtList, psWseList);
181 ExitOnFailure(hr, "Failed to install Web Service extension");
182 }
183 else if (WcaIsUninstalling(psWseList->isInstalled, psWseList->isAction))
184 {
185 hr = ScaWebSvcExtUninstall(&wzWebSvcExtList, (DWORD *)&cchWebSvcExtList, psWseList);
186 ExitOnFailure(hr, "Failed to uninstall Web Service extension");
187 }
188
189 psWseList = psWseList->psWseNext;
190 }
191
192 // Write Metabase
193 hr = ScaWriteMetabaseValue(piMetabase, vcsWebSvcExtRoot, NULL, MD_WEB_SVC_EXT_RESTRICTION_LIST, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, wzWebSvcExtList);
194 ExitOnFailure(hr, "Failed to write WebServiceExtensions: '%ls'", wzWebSvcExtList);
195
196LExit:
197 ReleaseStr(wzWebSvcExtList);
198
199 return hr;
200}
201
202
203static HRESULT ScaWebSvcExtInstall(
204 __in LPWSTR *ppwzWebSvcExtList,
205 __in DWORD_PTR *pcchWebSvcExtList,
206 __in SCA_WEBSVCEXT* psWseList
207 )
208{
209 Assert( ppwzWebSvcExtList && pcchWebSvcExtList && psWseList);
210 Assert(*ppwzWebSvcExtList);
211
212 HRESULT hr = S_OK;
213
214 LPWSTR pwzWebSvcExt = NULL;
215 int iAllow;
216 int iUiDeletable;
217
218 BOOL fAlreadyExists = FALSE;
219 DWORD_PTR dwIndex = 0xFFFFFFFF;
220 LPCWSTR wzFoundString = NULL;
221
222 // Check if it's already in there
223 hr = MultiSzFindSubstring(*ppwzWebSvcExtList, psWseList->wzFile, &dwIndex, &wzFoundString);
224 ExitOnFailure(hr, "failed to search for string:%ls in web service extension MULTISZ", psWseList->wzFile);
225
226 if (S_FALSE != hr && NULL != wcsstr(wzFoundString, psWseList->wzGroup) && NULL != wcsstr(wzFoundString, psWseList->wzDescription))
227 {
228 fAlreadyExists = TRUE;
229 }
230
231 // Construct the single string in the format required for the WebSvc Ext list in metabase
232 iAllow = (psWseList->iAttributes & 1);
233 iUiDeletable = ((psWseList->iAttributes >> 1) & 1);
234 hr = StrAllocFormatted(&pwzWebSvcExt, L"%d,%s,%d,%s,%s", iAllow, psWseList->wzFile, iUiDeletable, psWseList->wzGroup, psWseList->wzDescription);
235 ExitOnFailure(hr, "Failure allocating space for web service extensions");
236
237 if (fAlreadyExists)
238 {
239 hr = MultiSzReplaceString(ppwzWebSvcExtList, dwIndex, pwzWebSvcExt);
240 ExitOnFailure(hr, "failed to update web service extension string: %ls", pwzWebSvcExt);
241 }
242 else
243 {
244 hr = MultiSzPrepend(ppwzWebSvcExtList, pcchWebSvcExtList, pwzWebSvcExt);
245 ExitOnFailure(hr, "failed to prepend web service extension string: %ls", pwzWebSvcExt);
246 }
247
248LExit:
249 ReleaseStr(pwzWebSvcExt);
250
251 return hr;
252}
253
254
255static HRESULT ScaWebSvcExtUninstall(
256 __in LPWSTR *ppwzWebSvcExtList,
257 __in const DWORD* /*pcchWebSvcExtList*/,
258 __in SCA_WEBSVCEXT* psWseList
259 )
260{
261 Assert(ppwzWebSvcExtList && *ppwzWebSvcExtList && psWseList);
262 Assert(*ppwzWebSvcExtList);
263
264 HRESULT hr = S_OK;
265 DWORD_PTR dwIndex = 0xFFFFFFFF;
266 LPCWSTR wzFoundString = NULL;
267
268 // Find the string to remove
269 hr = MultiSzFindSubstring(*ppwzWebSvcExtList, psWseList->wzFile, &dwIndex, &wzFoundString);
270 ExitOnFailure(hr, "failed to search for string:%ls in web service extension MULTISZ", psWseList->wzFile);
271
272 // If we found a match (ignoring the Allow and Deletable flags)
273 if (S_FALSE != hr && NULL != wcsstr(wzFoundString, psWseList->wzGroup) && NULL != wcsstr(wzFoundString, psWseList->wzDescription))
274 {
275 hr = MultiSzRemoveString(ppwzWebSvcExtList, dwIndex);
276 ExitOnFailure(hr, "failed to remove string: %d from web service extension MULTISZ", dwIndex);
277 }
278
279LExit:
280 return hr;
281}
282
283
284//static HRESULT ScaCheckWebSvcExtValue(
285// __in IMSAdminBase* piMetabase,
286// __in DWORD dwMDIdentifier
287// )
288//{
289// if (!piMetabase)
290// {
291// return E_INVALIDARG;
292// }
293//
294// HRESULT hr = S_OK;
295// METADATA_RECORD mr = { 0 };
296// DWORD cch = 0;
297//
298// mr.dwMDIdentifier = dwMDIdentifier;
299// mr.dwMDUserType = IIS_MD_UT_SERVER;
300//
301// hr = piMetabase->GetData(METADATA_MASTER_ROOT_HANDLE, vcsWebSvcExtRoot, &mr, &cch);
302// if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr)
303// {
304// hr = S_OK;
305// }
306// else if (MD_ERROR_DATA_NOT_FOUND == hr)
307// {
308// hr = S_FALSE;
309// }
310//
311// return hr;
312//}
313
314
315void ScaWebSvcExtFreeList(
316 __in SCA_WEBSVCEXT* psWseList
317 )
318{
319 SCA_WEBSVCEXT* psWseDelete = psWseList;
320 while (psWseList)
321 {
322 psWseDelete = psWseList;
323 psWseList = psWseList->psWseNext;
324 MemFree(psWseDelete);
325 }
326}
327
328
329static HRESULT AddWebSvcExtToList(
330 __in SCA_WEBSVCEXT** ppsWseList
331 )
332{
333 HRESULT hr = S_OK;
334
335 SCA_WEBSVCEXT* psWse = static_cast<SCA_WEBSVCEXT*>(MemAlloc(sizeof(SCA_WEBSVCEXT), TRUE));
336 ExitOnNull(psWse, hr, E_OUTOFMEMORY, "failed to allocate element for web svc ext list");
337
338 psWse->psWseNext = *ppsWseList;
339 *ppsWseList = psWse;
340
341LExit:
342 return hr;
343}
diff --git a/src/ext/Iis/ca/scawebsvcext.h b/src/ext/Iis/ca/scawebsvcext.h
new file mode 100644
index 00000000..4d225b09
--- /dev/null
+++ b/src/ext/Iis/ca/scawebsvcext.h
@@ -0,0 +1,35 @@
1#pragma once
2// 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.
3
4
5enum SCA_WEBSVCEXT_ATTRIBUTES { SWSEATTRIB_ALLOW = 1, SWSEATTRIB_UIDELETABLE = 2 };
6
7struct SCA_WEBSVCEXT
8{
9 // darwin information
10 INSTALLSTATE isInstalled;
11 INSTALLSTATE isAction;
12
13 // iis configuation information
14 WCHAR wzFile[MAX_PATH + 1];
15 WCHAR wzDescription[MAX_DARWIN_COLUMN + 1];
16 WCHAR wzGroup[MAX_DARWIN_COLUMN + 1];
17
18 int iAttributes;
19
20 SCA_WEBSVCEXT* psWseNext;
21};
22
23HRESULT __stdcall ScaWebSvcExtRead(
24 __in SCA_WEBSVCEXT** ppsWseList,
25 __inout LPWSTR *ppwzCustomActionData
26 );
27
28HRESULT ScaWebSvcExtCommit(
29 __in IMSAdminBase* piMetabase,
30 __in SCA_WEBSVCEXT* psWseList
31 );
32
33void ScaWebSvcExtFreeList(
34 __in SCA_WEBSVCEXT* psWseList
35 );
diff --git a/src/ext/Iis/ca/scawebsvcext7.cpp b/src/ext/Iis/ca/scawebsvcext7.cpp
new file mode 100644
index 00000000..dcf2f7f8
--- /dev/null
+++ b/src/ext/Iis/ca/scawebsvcext7.cpp
@@ -0,0 +1,106 @@
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
5static HRESULT ScaWebSvcExtInstall(
6 const SCA_WEBSVCEXT* psWseList
7 );
8
9static HRESULT ScaWebSvcExtUninstall(
10 const SCA_WEBSVCEXT* psWseList
11 );
12
13// functions
14// Commit does both install and uninstall
15HRESULT __stdcall ScaWebSvcExtCommit7(
16 __in SCA_WEBSVCEXT* psWseList
17 )
18{
19 HRESULT hr = S_OK;
20
21 if (!psWseList)
22 {
23 WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebSvcExtCommit() because there are no web service extensions in the list");
24 ExitFunction();
25 }
26
27 // Make changes to local copy of metabase
28 while (psWseList)
29 {
30 if (WcaIsInstalling(psWseList->isInstalled, psWseList->isAction))
31 {
32 hr = ScaWebSvcExtInstall(psWseList);
33 ExitOnFailure(hr, "Failed to install Web Service extension");
34 }
35 else if (WcaIsUninstalling(psWseList->isInstalled, psWseList->isAction))
36 {
37 hr = ScaWebSvcExtUninstall(psWseList);
38 ExitOnFailure(hr, "Failed to uninstall Web Service extension");
39 }
40
41 psWseList = psWseList->psWseNext;
42 }
43
44
45LExit:
46
47 return hr;
48}
49
50
51static HRESULT ScaWebSvcExtInstall(
52 const SCA_WEBSVCEXT* psWseList
53 )
54{
55 HRESULT hr = S_OK;
56 int iAllow;
57
58 //Write CAData actions
59 hr = ScaWriteConfigID(IIS_WEB_SVC_EXT);
60 ExitOnFailure(hr, "failed add web svc ext ID");
61 hr = ScaWriteConfigID(IIS_CREATE);
62 ExitOnFailure(hr, "failed add web svc ext action");
63
64 // write File path
65 hr = ScaWriteConfigString(psWseList->wzFile);
66 ExitOnFailure(hr, "failed add web svc ext file path");
67
68 // write allowed
69 // unDeleatable n/a in IIS7
70 iAllow = (psWseList->iAttributes & 1);
71 hr = ScaWriteConfigInteger(iAllow);
72 ExitOnFailure(hr, "failed add web svc ext Allowed");
73
74 //write group
75 hr = ScaWriteConfigString(psWseList->wzGroup);
76 ExitOnFailure(hr, "failed add web svc ext group");
77
78 //write description
79 hr = ScaWriteConfigString(psWseList->wzDescription);
80 ExitOnFailure(hr, "failed add web svc ext description");
81
82LExit:
83
84 return hr;
85}
86
87
88static HRESULT ScaWebSvcExtUninstall(
89 const SCA_WEBSVCEXT* psWseList
90 )
91{
92 HRESULT hr = S_OK;
93
94 //Write CAData actions
95 hr = ScaWriteConfigID(IIS_WEB_SVC_EXT);
96 ExitOnFailure(hr, "failed add web svc ext ID");
97 hr = ScaWriteConfigID(IIS_DELETE);
98 ExitOnFailure(hr, "failed add web svc ext action");
99
100 // write File path (Key)
101 hr = ScaWriteConfigString(psWseList->wzFile);
102 ExitOnFailure(hr, "failed add web svc ext file path");
103
104LExit:
105 return hr;
106}
diff --git a/src/ext/Iis/ca/scawebsvcext7.h b/src/ext/Iis/ca/scawebsvcext7.h
new file mode 100644
index 00000000..1a686aed
--- /dev/null
+++ b/src/ext/Iis/ca/scawebsvcext7.h
@@ -0,0 +1,8 @@
1#pragma once
2// 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.
3
4
5HRESULT ScaWebSvcExtCommit7(
6 __in SCA_WEBSVCEXT* psWseList
7 );
8
diff --git a/src/ext/Iis/nuget.config b/src/ext/Iis/nuget.config
new file mode 100644
index 00000000..db7aba29
--- /dev/null
+++ b/src/ext/Iis/nuget.config
@@ -0,0 +1,17 @@
1<?xml version="1.0" encoding="utf-8"?>
2<configuration>
3 <packageSources>
4 <clear />
5 <add key="wixtoolset-burn" value="https://ci.appveyor.com/nuget/wixtoolset-burn" />
6 <add key="wixtoolset-data" value="https://ci.appveyor.com/nuget/wixtoolset-data" />
7 <add key="wixtoolset-extensibility" value="https://ci.appveyor.com/nuget/wixtoolset-extensibility" />
8 <add key="wixtoolset-core" value="https://ci.appveyor.com/nuget/wixtoolset-core" />
9 <add key="wixtoolset-core-native" value="https://ci.appveyor.com/nuget/wixtoolset-core-native" />
10 <add key="wixtoolset-dtf" value="https://ci.appveyor.com/nuget/wixtoolset-dtf" />
11 <add key="wixtoolset-dutil" value="https://ci.appveyor.com/nuget/wixtoolset-dutil" />
12 <add key="wixtoolset-wcautil" value="https://ci.appveyor.com/nuget/wixtoolset-wcautil" />
13 <add key="wixtoolset-tools" value="https://ci.appveyor.com/nuget/wixtoolset-tools" />
14 <add key="wixbuildtools" value="https://ci.appveyor.com/nuget/wixbuildtools" />
15 <add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
16 </packageSources>
17</configuration> \ No newline at end of file
diff --git a/src/ext/Iis/test/WixToolsetTest.Iis/IisExtensionFixture.cs b/src/ext/Iis/test/WixToolsetTest.Iis/IisExtensionFixture.cs
new file mode 100644
index 00000000..685e7126
--- /dev/null
+++ b/src/ext/Iis/test/WixToolsetTest.Iis/IisExtensionFixture.cs
@@ -0,0 +1,32 @@
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
3namespace WixToolsetTest.Iis
4{
5 using System.Linq;
6 using WixBuildTools.TestSupport;
7 using WixToolset.Core.TestPackage;
8 using WixToolset.Iis;
9 using Xunit;
10
11 public class IisExtensionFixture
12 {
13 [Fact]
14 public void CanBuildUsingIIsWebAddress()
15 {
16 var folder = TestData.Get(@"TestData\UsingIis");
17 var build = new Builder(folder, typeof(IisExtensionFactory), new[] { folder });
18
19 var results = build.BuildAndQuery(Build, "IIsWebAddress");
20 Assert.Equal(new[]
21 {
22 "IIsWebAddress:TestAddress\tTest\t\t[PORT]\t\t0",
23 }, results);
24 }
25
26 private static void Build(string[] args)
27 {
28 var result = WixRunner.Execute(args)
29 .AssertSuccess();
30 }
31 }
32}
diff --git a/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/Package.en-us.wxl b/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/Package.en-us.wxl
new file mode 100644
index 00000000..38c12ac1
--- /dev/null
+++ b/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/Package.en-us.wxl
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2
3<!--
4This file contains the declaration of all the localizable strings.
5-->
6<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
7
8 <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
9 <String Id="FeatureTitle">MsiPackage</String>
10
11</WixLocalization>
diff --git a/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/Package.wxs b/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/Package.wxs
new file mode 100644
index 00000000..f36aafef
--- /dev/null
+++ b/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/Package.wxs
@@ -0,0 +1,17 @@
1<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" InstallerVersion="200">
3 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
5 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
6 <ComponentGroupRef Id="ProductComponents" />
7 </Feature>
8 </Package>
9
10 <Fragment>
11 <StandardDirectory Id="ProgramFilesFolder">
12 <Directory Id="INSTALLFOLDER" Name="MsiPackage">
13 <Directory Id="TestWebSiteProductDirectory" />
14 </Directory>
15 </StandardDirectory>
16 </Fragment>
17</Wix>
diff --git a/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/PackageComponents.wxs b/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/PackageComponents.wxs
new file mode 100644
index 00000000..03203b50
--- /dev/null
+++ b/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/PackageComponents.wxs
@@ -0,0 +1,16 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 xmlns:iis="http://wixtoolset.org/schemas/v4/wxs/iis">
4 <Fragment>
5 <Property Id="PORT" Value="3062" />
6 <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
7 <Component>
8 <File Source="example.txt" />
9 <iis:WebSite Id="Test" Description="Test web server" Directory="TestWebSiteProductDirectory" AutoStart="yes" DirProperties="ReadAndExecute" ConfigureIfExists="no" >
10 <iis:WebAddress Id="TestAddress" Port="[PORT]" Secure="no" />
11 </iis:WebSite>
12 </Component>
13 </ComponentGroup>
14 <iis:WebDirProperties Id="ReadAndExecute" />
15 </Fragment>
16</Wix>
diff --git a/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/example.txt b/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/example.txt
new file mode 100644
index 00000000..1b4ffe8a
--- /dev/null
+++ b/src/ext/Iis/test/WixToolsetTest.Iis/TestData/UsingIis/example.txt
@@ -0,0 +1 @@
This is example.txt. \ No newline at end of file
diff --git a/src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.csproj b/src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.csproj
new file mode 100644
index 00000000..49ed89bc
--- /dev/null
+++ b/src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.csproj
@@ -0,0 +1,41 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netcoreapp3.1</TargetFramework>
7 <IsPackable>false</IsPackable>
8 </PropertyGroup>
9
10 <PropertyGroup>
11 <NoWarn>NU1701</NoWarn>
12 </PropertyGroup>
13
14 <ItemGroup>
15 <Content Include="TestData\UsingIis\example.txt" CopyToOutputDirectory="PreserveNewest" />
16 <Content Include="TestData\UsingIis\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
17 <Content Include="TestData\UsingIis\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
18 <Content Include="TestData\UsingIis\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
19 </ItemGroup>
20
21 <ItemGroup>
22 <ProjectReference Include="..\..\wixext\WixToolset.Iis.wixext.csproj" />
23 </ItemGroup>
24
25 <ItemGroup>
26 <PackageReference Include="WixToolset.Core" Version="4.0.*" />
27 <PackageReference Include="WixToolset.Core.Burn" Version="4.0.*" />
28 <PackageReference Include="WixToolset.Core.WindowsInstaller" Version="4.0.*" />
29 <PackageReference Include="WixToolset.Core.TestPackage" Version="4.0.*" />
30 </ItemGroup>
31
32 <ItemGroup>
33 <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.*" />
34 </ItemGroup>
35
36 <ItemGroup>
37 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
38 <PackageReference Include="xunit" Version="2.4.1" />
39 <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="All" />
40 </ItemGroup>
41</Project>
diff --git a/src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.v3.ncrunchproject b/src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.v3.ncrunchproject
new file mode 100644
index 00000000..7b5b2139
--- /dev/null
+++ b/src/ext/Iis/test/WixToolsetTest.Iis/WixToolsetTest.Iis.v3.ncrunchproject
@@ -0,0 +1,5 @@
1<ProjectConfiguration>
2 <Settings>
3 <CopyReferencedAssembliesToWorkspace>True</CopyReferencedAssembliesToWorkspace>
4 </Settings>
5</ProjectConfiguration> \ No newline at end of file
diff --git a/src/ext/Iis/wix.snk b/src/ext/Iis/wix.snk
new file mode 100644
index 00000000..3908a66a
--- /dev/null
+++ b/src/ext/Iis/wix.snk
Binary files differ
diff --git a/src/ext/Iis/wixext/IIsCompiler.cs b/src/ext/Iis/wixext/IIsCompiler.cs
new file mode 100644
index 00000000..cb573ad1
--- /dev/null
+++ b/src/ext/Iis/wixext/IIsCompiler.cs
@@ -0,0 +1,2620 @@
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
3namespace WixToolset.Iis
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Globalization;
8 using System.Xml.Linq;
9 using WixToolset.Data;
10 using WixToolset.Extensibility;
11 using WixToolset.Extensibility.Data;
12 using WixToolset.Iis.Symbols;
13
14 /// <summary>
15 /// The compiler for the WiX Toolset Internet Information Services Extension.
16 /// </summary>
17 public sealed class IIsCompiler : BaseCompilerExtension
18 {
19 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/iis";
20
21 /// <summary>
22 /// Types of objects that custom HTTP Headers can be applied to.
23 /// </summary>
24 /// <remarks>Note that this must be kept in sync with the eHttpHeaderParentType in scahttpheader.h.</remarks>
25 private enum HttpHeaderParentType
26 {
27 /// <summary>Custom HTTP Header is to be applied to a Web Virtual Directory.</summary>
28 WebVirtualDir = 1,
29 /// <summary>Custom HTTP Header is to be applied to a Web Site.</summary>
30 WebSite = 2,
31 }
32
33 /// <summary>
34 /// Types of objects that MimeMaps can be applied to.
35 /// </summary>
36 /// <remarks>Note that this must be kept in sync with the eMimeMapParentType in scamimemap.h.</remarks>
37 private enum MimeMapParentType
38 {
39 /// <summary>MimeMap is to be applied to a Web Virtual Directory.</summary>
40 WebVirtualDir = 1,
41 WebSite = 2,
42 }
43
44 /// <summary>
45 /// Types of objects that custom WebErrors can be applied to.
46 /// </summary>
47 /// <remarks>Note that this must be kept in sync with the eWebErrorParentType in scaweberror.h.</remarks>
48 private enum WebErrorParentType
49 {
50 /// <summary>Custom WebError is to be applied to a Web Virtual Directory.</summary>
51 WebVirtualDir = 1,
52
53 /// <summary>Custom WebError is to be applied to a Web Site.</summary>
54 WebSite = 2,
55 }
56
57 /// <summary>
58 /// Processes an element for the Compiler.
59 /// </summary>
60 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
61 /// <param name="parentElement">Parent element of element to process.</param>
62 /// <param name="element">Element to process.</param>
63 /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
64 public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
65 {
66 switch (parentElement.Name.LocalName)
67 {
68 case "Component":
69 var componentId = context["ComponentId"];
70 var directoryId = context["DirectoryId"];
71
72 switch (element.Name.LocalName)
73 {
74 case "Certificate":
75 this.ParseCertificateElement(intermediate, section, element, componentId);
76 break;
77 case "WebAppPool":
78 this.ParseWebAppPoolElement(intermediate, section, element, componentId);
79 break;
80 case "WebDir":
81 this.ParseWebDirElement(intermediate, section, element, componentId, null);
82 break;
83 case "WebFilter":
84 this.ParseWebFilterElement(intermediate, section, element, componentId, null);
85 break;
86 case "WebProperty":
87 this.ParseWebPropertyElement(intermediate, section, element, componentId);
88 break;
89 case "WebServiceExtension":
90 this.ParseWebServiceExtensionElement(intermediate, section, element, componentId);
91 break;
92 case "WebSite":
93 this.ParseWebSiteElement(intermediate, section, element, componentId);
94 break;
95 case "WebVirtualDir":
96 this.ParseWebVirtualDirElement(intermediate, section, element, componentId, null, null);
97 break;
98 default:
99 this.ParseHelper.UnexpectedElement(parentElement, element);
100 break;
101 }
102 break;
103 case "Fragment":
104 case "Module":
105 case "Package":
106 switch (element.Name.LocalName)
107 {
108 case "WebApplication":
109 this.ParseWebApplicationElement(intermediate, section, element);
110 break;
111 case "WebAppPool":
112 this.ParseWebAppPoolElement(intermediate, section, element, null);
113 break;
114 case "WebDirProperties":
115 this.ParseWebDirPropertiesElement(intermediate, section, element, null);
116 break;
117 case "WebLog":
118 this.ParseWebLogElement(intermediate, section, element);
119 break;
120 case "WebSite":
121 this.ParseWebSiteElement(intermediate, section, element, null);
122 break;
123 default:
124 this.ParseHelper.UnexpectedElement(parentElement, element);
125 break;
126 }
127 break;
128 default:
129 this.ParseHelper.UnexpectedElement(parentElement, element);
130 break;
131 }
132 }
133
134 /// <summary>
135 /// Parses a certificate element.
136 /// </summary>
137 /// <param name="element">Element to parse.</param>
138 /// <param name="componentId">Identifier for parent component.</param>
139 private void ParseCertificateElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
140 {
141 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
142 Identifier id = null;
143 int attributes = 8; // SCA_CERT_ATTRIBUTE_VITAL
144 string binaryRef = null;
145 string certificatePath = null;
146 string name = null;
147 string pfxPassword = null;
148 int storeLocation = 0;
149 string storeName = null;
150
151 foreach (var attrib in element.Attributes())
152 {
153 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
154 {
155 switch (attrib.Name.LocalName)
156 {
157 case "Id":
158 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
159 break;
160 case "BinaryRef":
161 attributes |= 2; // SCA_CERT_ATTRIBUTE_BINARYDATA
162 binaryRef = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
163 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Binary, binaryRef);
164 break;
165 case "CertificatePath":
166 certificatePath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
167 break;
168 case "Name":
169 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
170 break;
171 case "Overwrite":
172 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
173 {
174 attributes |= 4; // SCA_CERT_ATTRIBUTE_OVERWRITE
175 }
176 else
177 {
178 attributes &= ~4; // SCA_CERT_ATTRIBUTE_OVERWRITE
179 }
180 break;
181 case "PFXPassword":
182 pfxPassword = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
183 break;
184 case "Request":
185 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
186 {
187 attributes |= 1; // SCA_CERT_ATTRIBUTE_REQUEST
188 }
189 else
190 {
191 attributes &= ~1; // SCA_CERT_ATTRIBUTE_REQUEST
192 }
193 break;
194 case "StoreLocation":
195 var storeLocationValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
196 if (0 < storeLocationValue.Length)
197 {
198 switch (storeLocationValue)
199 {
200 case "currentUser":
201 storeLocation = 1; // SCA_CERTSYSTEMSTORE_CURRENTUSER
202 break;
203 case "localMachine":
204 storeLocation = 2; // SCA_CERTSYSTEMSTORE_LOCALMACHINE
205 break;
206 default:
207 storeLocation = -1;
208 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "StoreLocation", storeLocationValue, "currentUser", "localMachine"));
209 break;
210 }
211 }
212 break;
213 case "StoreName":
214 var storeNameValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
215 if (0 < storeNameValue.Length)
216 {
217 switch (storeNameValue)
218 {
219 case "ca":
220 storeName = "CA";
221 break;
222 case "my":
223 case "personal":
224 storeName = "MY";
225 break;
226 case "request":
227 storeName = "REQUEST";
228 break;
229 case "root":
230 storeName = "Root";
231 break;
232 case "otherPeople":
233 storeName = "AddressBook";
234 break;
235 case "trustedPeople":
236 storeName = "TrustedPeople";
237 break;
238 case "trustedPublisher":
239 storeName = "TrustedPublisher";
240 break;
241 default:
242 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "StoreName", storeNameValue, "ca", "my", "request", "root", "otherPeople", "trustedPeople", "trustedPublisher"));
243 break;
244 }
245 }
246 break;
247 case "Vital":
248 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
249 {
250 attributes |= 8; // SCA_CERT_ATTRIBUTE_VITAL
251 }
252 else
253 {
254 attributes &= ~8; // SCA_CERT_ATTRIBUTE_VITAL
255 }
256 break;
257 default:
258 this.ParseHelper.UnexpectedAttribute(element, attrib);
259 break;
260 }
261 }
262 else
263 {
264 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
265 }
266 }
267
268
269 if (null == id)
270 {
271 id = this.ParseHelper.CreateIdentifier("crt", componentId, binaryRef, certificatePath);
272 }
273
274 if (null == name)
275 {
276 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
277 }
278
279 if (0 == storeLocation)
280 {
281 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "StoreLocation"));
282 }
283
284 if (null == storeName)
285 {
286 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "StoreName"));
287 }
288
289 if (null != binaryRef && null != certificatePath)
290 {
291 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "BinaryRef", "CertificatePath", certificatePath));
292 }
293 else if (null == binaryRef && null == certificatePath)
294 {
295 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "BinaryRef", "CertificatePath"));
296 }
297
298 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
299
300 // Reference InstallCertificates and UninstallCertificates since nothing will happen without them
301 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4InstallCertificates", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
302 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4UninstallCertificates", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
303 this.ParseHelper.EnsureTable(section, sourceLineNumbers, IisTableDefinitions.CertificateHash); // Certificate CustomActions require the CertificateHash table
304
305 if (!this.Messaging.EncounteredError)
306 {
307 section.AddSymbol(new CertificateSymbol(sourceLineNumbers, id)
308 {
309 ComponentRef = componentId,
310 Name = name,
311 StoreLocation = storeLocation,
312 StoreName = storeName,
313 Attributes = attributes,
314 BinaryRef = binaryRef,
315 CertificatePath = certificatePath,
316 PFXPassword = pfxPassword,
317 });
318 }
319 }
320
321 /// <summary>
322 /// Parses a CertificateRef extension element.
323 /// </summary>
324 /// <param name="element">Element to parse.</param>
325 /// <param name="webId">Identifier for parent web site.</param>
326 private void ParseCertificateRefElement(Intermediate intermediate, IntermediateSection section, XElement element, string webId)
327 {
328 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
329 Identifier id = null;
330
331 foreach (var attrib in element.Attributes())
332 {
333 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
334 {
335 switch (attrib.Name.LocalName)
336 {
337 case "Id":
338 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
339 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.Certificate, id.Id);
340 break;
341 default:
342 this.ParseHelper.UnexpectedAttribute(element, attrib);
343 break;
344 }
345 }
346 else
347 {
348 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
349 }
350 }
351
352 if (null == id)
353 {
354 id = this.ParseHelper.CreateIdentifier("wsc", webId);
355 }
356
357 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
358
359 if (!this.Messaging.EncounteredError)
360 {
361 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.Certificate, id.Id);
362
363 section.AddSymbol(new IIsWebSiteCertificatesSymbol(sourceLineNumbers)
364 {
365 WebRef = webId,
366 CertificateRef = id.Id,
367 });
368 }
369 }
370
371 /// <summary>
372 /// Parses a mime map element.
373 /// </summary>
374 /// <param name="element">Element to parse.</param>
375 /// <param name="parentId">Identifier for parent symbol.</param>
376 /// <param name="parentType">Type that parentId refers to.</param>
377 private void ParseMimeMapElement(Intermediate intermediate, IntermediateSection section, XElement element, string parentId, MimeMapParentType parentType)
378 {
379 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
380 Identifier id = null;
381 string extension = null;
382 string type = null;
383
384 foreach (var attrib in element.Attributes())
385 {
386 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
387 {
388 switch (attrib.Name.LocalName)
389 {
390 case "Id":
391 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
392 break;
393 case "Extension":
394 extension = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
395 break;
396 case "Type":
397 type = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
398 break;
399 default:
400 this.ParseHelper.UnexpectedAttribute(element, attrib);
401 break;
402 }
403 }
404 else
405 {
406 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
407 }
408 }
409
410 if (null == id)
411 {
412 id = this.ParseHelper.CreateIdentifier("imm", parentId, type, extension);
413 }
414
415 if (null == extension)
416 {
417 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Extension"));
418 }
419 else if (0 < extension.Length)
420 {
421 if (!extension.StartsWith(".", StringComparison.Ordinal))
422 {
423 this.Messaging.Write(IIsErrors.MimeMapExtensionMissingPeriod(sourceLineNumbers, element.Name.LocalName, "Extension", extension));
424 }
425 }
426
427 if (null == type)
428 {
429 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Type"));
430 }
431
432 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
433
434 if (!this.Messaging.EncounteredError)
435 {
436 section.AddSymbol(new IIsMimeMapSymbol(sourceLineNumbers, id)
437 {
438 ParentType = (int)parentType,
439 ParentValue = parentId,
440 MimeType = type,
441 Extension = extension,
442 });
443 }
444 }
445
446 /// <summary>
447 /// Parses a recycle time element.
448 /// </summary>
449 /// <param name="element">Element to parse.</param>
450 /// <returns>Recycle time value.</returns>
451 private string ParseRecycleTimeElement(Intermediate intermediate, IntermediateSection section, XElement element)
452 {
453 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
454 string value = null;
455
456 foreach (var attrib in element.Attributes())
457 {
458 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
459 {
460 switch (attrib.Name.LocalName)
461 {
462 case "Value":
463 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
464 break;
465 default:
466 this.ParseHelper.UnexpectedAttribute(element, attrib);
467 break;
468 }
469 }
470 else
471 {
472 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
473 }
474 }
475
476 if (null == value)
477 {
478 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Value"));
479 }
480
481 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
482
483 return value;
484 }
485
486 /// <summary>
487 /// Parses a web address element.
488 /// </summary>
489 /// <param name="element">Element to parse.</param>
490 /// <param name="parentWeb">Identifier of parent web site.</param>
491 /// <returns>Identifier for web address.</returns>
492 private string ParseWebAddressElement(Intermediate intermediate, IntermediateSection section, XElement element, string parentWeb)
493 {
494 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
495 Identifier id = null;
496 string header = null;
497 string ip = null;
498 string port = null;
499 var secure = false;
500
501 foreach (var attrib in element.Attributes())
502 {
503 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
504 {
505 switch (attrib.Name.LocalName)
506 {
507 case "Id":
508 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
509 break;
510 case "Header":
511 header = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
512 break;
513 case "IP":
514 ip = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
515 break;
516 case "Port":
517 port = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
518 break;
519 case "Secure":
520 secure = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
521 break;
522 default:
523 this.ParseHelper.UnexpectedAttribute(element, attrib);
524 break;
525 }
526 }
527 else
528 {
529 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
530 }
531 }
532
533 if (null == id)
534 {
535 id = this.ParseHelper.CreateIdentifier("iwa", parentWeb, ip, port);
536 }
537
538 if (null == port)
539 {
540 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Port"));
541 }
542
543 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
544
545 if (!this.Messaging.EncounteredError)
546 {
547 section.AddSymbol(new IIsWebAddressSymbol(sourceLineNumbers, id)
548 {
549 WebRef = parentWeb,
550 IP = ip,
551 Port = port,
552 Header = header,
553 Secure = secure ? 1 : 0,
554 });
555 }
556
557 return id?.Id;
558 }
559
560 /// <summary>
561 /// Parses a web application element.
562 /// </summary>
563 /// <param name="element">Element to parse.</param>
564 /// <returns>Identifier for web application.</returns>
565 private string ParseWebApplicationElement(Intermediate intermediate, IntermediateSection section, XElement element)
566 {
567 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
568 Identifier id = null;
569 var allowSessions = YesNoDefaultType.Default;
570 string appPool = null;
571 var buffer = YesNoDefaultType.Default;
572 var clientDebugging = YesNoDefaultType.Default;
573 string defaultScript = null;
574 int isolation = 0;
575 string name = null;
576 var parentPaths = YesNoDefaultType.Default;
577 var scriptTimeout = CompilerConstants.IntegerNotSet;
578 var sessionTimeout = CompilerConstants.IntegerNotSet;
579 var serverDebugging = YesNoDefaultType.Default;
580
581 foreach (var attrib in element.Attributes())
582 {
583 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
584 {
585 switch (attrib.Name.LocalName)
586 {
587 case "Id":
588 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
589 break;
590 case "AllowSessions":
591 allowSessions = this.ParseHelper.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
592 break;
593 case "Buffer":
594 buffer = this.ParseHelper.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
595 break;
596 case "ClientDebugging":
597 clientDebugging = this.ParseHelper.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
598 break;
599 case "DefaultScript":
600 defaultScript = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
601 if (0 < defaultScript.Length)
602 {
603 switch (defaultScript)
604 {
605 case "JScript":
606 case "VBScript":
607 // these are valid values
608 break;
609 default:
610 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, defaultScript, "JScript", "VBScript"));
611 break;
612 }
613 }
614 break;
615 case "Isolation":
616 string isolationValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
617 if (0 < isolationValue.Length)
618 {
619 switch (isolationValue)
620 {
621 case "low":
622 isolation = 0;
623 break;
624 case "medium":
625 isolation = 2;
626 break;
627 case "high":
628 isolation = 1;
629 break;
630 default:
631 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, isolationValue, "low", "medium", "high"));
632 break;
633 }
634 }
635 break;
636 case "Name":
637 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
638 break;
639 case "ParentPaths":
640 parentPaths = this.ParseHelper.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
641 break;
642 case "ScriptTimeout":
643 scriptTimeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
644 break;
645 case "ServerDebugging":
646 serverDebugging = this.ParseHelper.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
647 break;
648 case "SessionTimeout":
649 sessionTimeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
650 break;
651 case "WebAppPool":
652 appPool = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
653 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsAppPool, appPool);
654 break;
655 default:
656 this.ParseHelper.UnexpectedAttribute(element, attrib);
657 break;
658 }
659 }
660 else
661 {
662 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
663 }
664 }
665
666 if (null == id)
667 {
668 id = this.ParseHelper.CreateIdentifier("wap", name, appPool);
669 }
670
671 if (null == name)
672 {
673 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
674 }
675 else if (-1 != name.IndexOf("\\", StringComparison.Ordinal))
676 {
677 this.Messaging.Write(IIsErrors.IllegalCharacterInAttributeValue(sourceLineNumbers, element.Name.LocalName, "Name", name, '\\'));
678 }
679
680 foreach (var child in element.Elements())
681 {
682 if (this.Namespace == child.Name.Namespace)
683 {
684 switch (child.Name.LocalName)
685 {
686 case "WebApplicationExtension":
687 this.ParseWebApplicationExtensionElement(intermediate, section, child, id?.Id);
688 break;
689 default:
690 this.ParseHelper.UnexpectedElement(element, child);
691 break;
692 }
693 }
694 else
695 {
696 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
697 }
698 }
699
700 if (!this.Messaging.EncounteredError)
701 {
702 var symbol = section.AddSymbol(new IIsWebApplicationSymbol(sourceLineNumbers, id)
703 {
704 Name = name,
705 Isolation = isolation,
706 DefaultScript = defaultScript,
707 AppPoolRef = appPool,
708 });
709
710 if (YesNoDefaultType.Default != allowSessions)
711 {
712 symbol.AllowSessions = YesNoDefaultType.Yes == allowSessions ? 1 : 0;
713 }
714
715 if (CompilerConstants.IntegerNotSet != sessionTimeout)
716 {
717 symbol.SessionTimeout = sessionTimeout;
718 }
719
720 if (YesNoDefaultType.Default != buffer)
721 {
722 symbol.Buffer = YesNoDefaultType.Yes == buffer ? 1 : 0;
723 }
724
725 if (YesNoDefaultType.Default != parentPaths)
726 {
727 symbol.ParentPaths = YesNoDefaultType.Yes == parentPaths ? 1 : 0;
728 }
729
730 if (CompilerConstants.IntegerNotSet != scriptTimeout)
731 {
732 symbol.ScriptTimeout = scriptTimeout;
733 }
734
735 if (YesNoDefaultType.Default != serverDebugging)
736 {
737 symbol.ServerDebugging = YesNoDefaultType.Yes == serverDebugging ? 1 : 0;
738 }
739
740 if (YesNoDefaultType.Default != clientDebugging)
741 {
742 symbol.ClientDebugging = YesNoDefaultType.Yes == clientDebugging ? 1 : 0;
743 }
744 }
745
746 return id?.Id;
747 }
748
749 /// <summary>
750 /// Parses a web application extension element.
751 /// </summary>
752 /// <param name="element">Element to parse.</param>
753 /// <param name="application">Identifier for parent web application.</param>
754 private void ParseWebApplicationExtensionElement(Intermediate intermediate, IntermediateSection section, XElement element, string application)
755 {
756 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
757 int attributes = 0;
758 string executable = null;
759 string extension = null;
760 string verbs = null;
761
762 foreach (var attrib in element.Attributes())
763 {
764 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
765 {
766 switch (attrib.Name.LocalName)
767 {
768 case "CheckPath":
769 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
770 {
771 attributes |= 4;
772 }
773 else
774 {
775 attributes &= ~4;
776 }
777 break;
778 case "Executable":
779 executable = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
780 break;
781 case "Extension":
782 extension = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
783 break;
784 case "Script":
785 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
786 {
787 attributes |= 1;
788 }
789 else
790 {
791 attributes &= ~1;
792 }
793 break;
794 case "Verbs":
795 verbs = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
796 break;
797 default:
798 this.ParseHelper.UnexpectedAttribute(element, attrib);
799 break;
800 }
801 }
802 else
803 {
804 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
805 }
806 }
807
808 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
809
810 if (!this.Messaging.EncounteredError)
811 {
812 var symbol = section.AddSymbol(new IIsWebApplicationExtensionSymbol(sourceLineNumbers)
813 {
814 ApplicationRef = application,
815 Extension = extension,
816 Verbs = verbs,
817 Executable = executable,
818 });
819
820 if (0 < attributes)
821 {
822 symbol.Attributes = attributes;
823 }
824 }
825 }
826
827 /// <summary>
828 /// Parses web application pool element.
829 /// </summary>
830 /// <param name="element">Element to parse.</param>
831 /// <param name="componentId">Optional identifier of parent component.</param>
832 private void ParseWebAppPoolElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
833 {
834 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
835 Identifier id = null;
836 int attributes = 0;
837 var cpuAction = CompilerConstants.IntegerNotSet;
838 string cpuMon = null;
839 var idleTimeout = CompilerConstants.IntegerNotSet;
840 int maxCpuUsage = 0;
841 var maxWorkerProcs = CompilerConstants.IntegerNotSet;
842 string managedRuntimeVersion = null;
843 string managedPipelineMode = null;
844 string name = null;
845 var privateMemory = CompilerConstants.IntegerNotSet;
846 var queueLimit = CompilerConstants.IntegerNotSet;
847 var recycleMinutes = CompilerConstants.IntegerNotSet;
848 var recycleRequests = CompilerConstants.IntegerNotSet;
849 string recycleTimes = null;
850 var refreshCpu = CompilerConstants.IntegerNotSet;
851 string user = null;
852 var virtualMemory = CompilerConstants.IntegerNotSet;
853
854 foreach (var attrib in element.Attributes())
855 {
856 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
857 {
858 switch (attrib.Name.LocalName)
859 {
860 case "Id":
861 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
862 break;
863 case "CpuAction":
864 if (null == componentId)
865 {
866 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
867 }
868
869 var cpuActionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
870 if (0 < cpuActionValue.Length)
871 {
872 switch (cpuActionValue)
873 {
874 case "shutdown":
875 cpuAction = 1;
876 break;
877 case "none":
878 cpuAction = 0;
879 break;
880 default:
881 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, cpuActionValue, "shutdown", "none"));
882 break;
883 }
884 }
885 break;
886 case "Identity":
887 if (null == componentId)
888 {
889 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
890 }
891
892 var identityValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
893 if (0 < identityValue.Length)
894 {
895 switch (identityValue)
896 {
897 case "networkService":
898 attributes |= 1;
899 break;
900 case "localService":
901 attributes |= 2;
902 break;
903 case "localSystem":
904 attributes |= 4;
905 break;
906 case "other":
907 attributes |= 8;
908 break;
909 case "applicationPoolIdentity":
910 attributes |= 0x10;
911 break;
912 default:
913 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, identityValue, "networkService", "localService", "localSystem", "other", "applicationPoolIdentity"));
914 break;
915 }
916 }
917 break;
918 case "IdleTimeout":
919 if (null == componentId)
920 {
921 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
922 }
923
924 idleTimeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
925 break;
926 case "ManagedPipelineMode":
927 if (null == componentId)
928 {
929 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
930 }
931
932 managedPipelineMode = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
933
934
935 if (!String.IsNullOrEmpty(managedPipelineMode))
936 {
937 switch (managedPipelineMode)
938 {
939 // In 3.5 we allowed lower case values (per camel case enum style), we now use formatted fields,
940 // so the value needs to match exactly what we pass in to IIS which uses pascal case.
941 case "classic":
942 managedPipelineMode = "Classic";
943 break;
944 case "integrated":
945 managedPipelineMode = "Integrated";
946 break;
947 case "Classic":
948 break;
949 case "Integrated":
950 break;
951 default:
952 if (!this.ParseHelper.ContainsProperty(managedPipelineMode))
953 {
954 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, managedPipelineMode, "Classic", "Integrated"));
955 }
956 break;
957 }
958 }
959
960 break;
961 case "ManagedRuntimeVersion":
962 if (null == componentId)
963 {
964 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
965 }
966
967 managedRuntimeVersion = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
968 break;
969 case "MaxCpuUsage":
970 if (null == componentId)
971 {
972 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
973 }
974
975 maxCpuUsage = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 100);
976 break;
977 case "MaxWorkerProcesses":
978 if (null == componentId)
979 {
980 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
981 }
982
983 maxWorkerProcs = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
984 break;
985 case "Name":
986 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
987 break;
988 case "PrivateMemory":
989 if (null == componentId)
990 {
991 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
992 }
993
994 privateMemory = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 4294967);
995 break;
996 case "QueueLimit":
997 if (null == componentId)
998 {
999 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
1000 }
1001
1002 queueLimit = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
1003 break;
1004 case "RecycleMinutes":
1005 if (null == componentId)
1006 {
1007 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
1008 }
1009
1010 recycleMinutes = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
1011 break;
1012 case "RecycleRequests":
1013 if (null == componentId)
1014 {
1015 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
1016 }
1017
1018 recycleRequests = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
1019 break;
1020 case "RefreshCpu":
1021 if (null == componentId)
1022 {
1023 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
1024 }
1025
1026 refreshCpu = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
1027 break;
1028 case "User":
1029 if (null == componentId)
1030 {
1031 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
1032 }
1033
1034 user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1035 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user);
1036 break;
1037 case "VirtualMemory":
1038 if (null == componentId)
1039 {
1040 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
1041 }
1042
1043 virtualMemory = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 4294967);
1044 break;
1045 default:
1046 this.ParseHelper.UnexpectedAttribute(element, attrib);
1047 break;
1048 }
1049 }
1050 else
1051 {
1052 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1053 }
1054 }
1055
1056 if (null == id)
1057 {
1058 id = this.ParseHelper.CreateIdentifier("iap", name, componentId, user);
1059 }
1060
1061 if (null == name)
1062 {
1063 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
1064 }
1065
1066 if (null == user && 8 == (attributes & 0x1F))
1067 {
1068 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User", "Identity", "other"));
1069 }
1070
1071 if (null != user && 8 != (attributes & 0x1F))
1072 {
1073 this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, element.Name.LocalName, "User", user, "Identity", "other"));
1074 }
1075
1076 cpuMon = maxCpuUsage.ToString(CultureInfo.InvariantCulture.NumberFormat);
1077 if (CompilerConstants.IntegerNotSet != refreshCpu)
1078 {
1079 cpuMon = String.Concat(cpuMon, ",", refreshCpu.ToString(CultureInfo.InvariantCulture.NumberFormat));
1080 if (CompilerConstants.IntegerNotSet != cpuAction)
1081 {
1082 cpuMon = String.Concat(cpuMon, ",", cpuAction.ToString(CultureInfo.InvariantCulture.NumberFormat));
1083 }
1084 }
1085
1086 foreach (var child in element.Elements())
1087 {
1088 if (this.Namespace == child.Name.Namespace)
1089 {
1090 switch (child.Name.LocalName)
1091 {
1092 case "RecycleTime":
1093 if (null == componentId)
1094 {
1095 var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
1096 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, element.Name.LocalName));
1097 }
1098
1099 if (null == recycleTimes)
1100 {
1101 recycleTimes = this.ParseRecycleTimeElement(intermediate, section, child);
1102 }
1103 else
1104 {
1105 recycleTimes = String.Concat(recycleTimes, ",", this.ParseRecycleTimeElement(intermediate, section, child));
1106 }
1107 break;
1108 default:
1109 this.ParseHelper.UnexpectedElement(element, child);
1110 break;
1111 }
1112 }
1113 else
1114 {
1115 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
1116 }
1117 }
1118
1119 if (null != componentId)
1120 {
1121 // Reference ConfigureIIs since nothing will happen without it
1122 this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
1123 }
1124
1125 if (!this.Messaging.EncounteredError)
1126 {
1127 var symbol = section.AddSymbol(new IIsAppPoolSymbol(sourceLineNumbers, id)
1128 {
1129 Name = name,
1130 ComponentRef = componentId,
1131 Attributes = attributes,
1132 UserRef = user,
1133 RecycleTimes = recycleTimes,
1134 CPUMon = cpuMon,
1135 ManagedRuntimeVersion = managedRuntimeVersion,
1136 ManagedPipelineMode = managedPipelineMode,
1137 });
1138
1139 if (CompilerConstants.IntegerNotSet != recycleMinutes)
1140 {
1141 symbol.RecycleMinutes = recycleMinutes;
1142 }
1143
1144 if (CompilerConstants.IntegerNotSet != recycleRequests)
1145 {
1146 symbol.RecycleRequests = recycleRequests;
1147 }
1148
1149 if (CompilerConstants.IntegerNotSet != idleTimeout)
1150 {
1151 symbol.IdleTimeout = idleTimeout;
1152 }
1153
1154 if (CompilerConstants.IntegerNotSet != queueLimit)
1155 {
1156 symbol.QueueLimit = queueLimit;
1157 }
1158
1159 if (CompilerConstants.IntegerNotSet != maxWorkerProcs)
1160 {
1161 symbol.MaxProc = maxWorkerProcs;
1162 }
1163
1164 if (CompilerConstants.IntegerNotSet != virtualMemory)
1165 {
1166 symbol.VirtualMemory = virtualMemory;
1167 }
1168
1169 if (CompilerConstants.IntegerNotSet != privateMemory)
1170 {
1171 symbol.PrivateMemory = privateMemory;
1172 }
1173 }
1174 }
1175
1176 /// <summary>
1177 /// Parses a web directory element.
1178 /// </summary>
1179 /// <param name="element">Element to parse.</param>
1180 /// <param name="componentId">Identifier for parent component.</param>
1181 /// <param name="parentWeb">Optional identifier for parent web site.</param>
1182 private void ParseWebDirElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentWeb)
1183 {
1184 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1185 Identifier id = null;
1186 string dirProperties = null;
1187 string path = null;
1188 string application = null;
1189
1190 foreach (var attrib in element.Attributes())
1191 {
1192 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1193 {
1194 switch (attrib.Name.LocalName)
1195 {
1196 case "Id":
1197 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1198 break;
1199 case "DirProperties":
1200 dirProperties = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1201 break;
1202 case "Path":
1203 path = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1204 break;
1205 case "WebApplication":
1206 application = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1207 break;
1208 case "WebSite":
1209 if (null != parentWeb)
1210 {
1211 this.Messaging.Write(IIsErrors.WebSiteAttributeUnderWebSite(sourceLineNumbers, element.Name.LocalName));
1212 }
1213
1214 parentWeb = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1215 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebSite, parentWeb);
1216 break;
1217 default:
1218 this.ParseHelper.UnexpectedAttribute(element, attrib);
1219 break;
1220 }
1221 }
1222 else
1223 {
1224 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1225 }
1226 }
1227
1228 if (null == id)
1229 {
1230 id = this.ParseHelper.CreateIdentifier("iwd", componentId, parentWeb, dirProperties, application);
1231 }
1232
1233 if (null == path)
1234 {
1235 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
1236 }
1237
1238 if (null == parentWeb)
1239 {
1240 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "WebSite"));
1241 }
1242
1243 foreach (var child in element.Elements())
1244 {
1245 if (this.Namespace == child.Name.Namespace)
1246 {
1247 var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
1248 switch (child.Name.LocalName)
1249 {
1250 case "WebApplication":
1251 if (null != application)
1252 {
1253 this.Messaging.Write(IIsErrors.WebApplicationAlreadySpecified(childSourceLineNumbers, element.Name.LocalName));
1254 }
1255
1256 application = this.ParseWebApplicationElement(intermediate, section, child);
1257 break;
1258 case "WebDirProperties":
1259 if (null == componentId)
1260 {
1261 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
1262 }
1263
1264 string childWebDirProperties = this.ParseWebDirPropertiesElement(intermediate, section, child, componentId);
1265 if (null == dirProperties)
1266 {
1267 dirProperties = childWebDirProperties;
1268 }
1269 else
1270 {
1271 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, child.Name.LocalName, "DirProperties", child.Name.LocalName));
1272 }
1273 break;
1274 default:
1275 this.ParseHelper.UnexpectedElement(element, child);
1276 break;
1277 }
1278 }
1279 else
1280 {
1281 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
1282 }
1283 }
1284
1285 if (null == dirProperties)
1286 {
1287 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "DirProperties"));
1288 }
1289
1290 if (null != application)
1291 {
1292 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebApplication, application);
1293 }
1294
1295 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebDirProperties, dirProperties);
1296
1297 // Reference ConfigureIIs since nothing will happen without it
1298 this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
1299
1300 if (!this.Messaging.EncounteredError)
1301 {
1302 section.AddSymbol(new IIsWebDirSymbol(sourceLineNumbers, id)
1303 {
1304 ComponentRef = componentId,
1305 WebRef = parentWeb,
1306 Path = path,
1307 DirPropertiesRef = dirProperties,
1308 ApplicationRef = application,
1309 });
1310 }
1311 }
1312
1313 /// <summary>
1314 /// Parses a web directory properties element.
1315 /// </summary>
1316 /// <param name="element">Element to parse.</param>
1317 /// <returns>The identifier for this WebDirProperties.</returns>
1318 private string ParseWebDirPropertiesElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
1319 {
1320 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1321 Identifier id = null;
1322 int access = 0;
1323 var accessSet = false;
1324 int accessSSLFlags = 0;
1325 var accessSSLFlagsSet = false;
1326 string anonymousUser = null;
1327 var aspDetailedError = YesNoType.NotSet;
1328 string authenticationProviders = null;
1329 int authorization = 0;
1330 var authorizationSet = false;
1331 string cacheControlCustom = null;
1332 var cacheControlMaxAge = CompilerConstants.LongNotSet;
1333 string defaultDocuments = null;
1334 string httpExpires = null;
1335 var iisControlledPassword = false;
1336 var index = YesNoType.NotSet;
1337 var logVisits = YesNoType.NotSet;
1338 var notCustomError = YesNoType.NotSet;
1339
1340 foreach (var attrib in element.Attributes())
1341 {
1342 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1343 {
1344 switch (attrib.Name.LocalName)
1345 {
1346 case "Id":
1347 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1348 break;
1349 case "AnonymousUser":
1350 anonymousUser = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1351 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", anonymousUser);
1352 break;
1353 case "AspDetailedError":
1354 aspDetailedError = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1355 break;
1356 case "AuthenticationProviders":
1357 authenticationProviders = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1358 break;
1359 case "CacheControlCustom":
1360 cacheControlCustom = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1361 break;
1362 case "CacheControlMaxAge":
1363 cacheControlMaxAge = this.ParseHelper.GetAttributeLongValue(sourceLineNumbers, attrib, 0, uint.MaxValue); // 4294967295 (uint.MaxValue) represents unlimited
1364 break;
1365 case "ClearCustomError":
1366 notCustomError = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1367 break;
1368 case "DefaultDocuments":
1369 defaultDocuments = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1370 break;
1371 case "HttpExpires":
1372 httpExpires = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1373 break;
1374 case "IIsControlledPassword":
1375 iisControlledPassword = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1376 break;
1377 case "Index":
1378 index = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1379 break;
1380 case "LogVisits":
1381 logVisits = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1382 break;
1383
1384 // Access attributes
1385 case "Execute":
1386 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1387 {
1388 access |= 4;
1389 }
1390 else
1391 {
1392 access &= ~4;
1393 }
1394 accessSet = true;
1395 break;
1396 case "Read":
1397 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1398 {
1399 access |= 1;
1400 }
1401 else
1402 {
1403 access &= ~1;
1404 }
1405 accessSet = true;
1406 break;
1407 case "Script":
1408 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1409 {
1410 access |= 512;
1411 }
1412 else
1413 {
1414 access &= ~512;
1415 }
1416 accessSet = true;
1417 break;
1418 case "Write":
1419 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1420 {
1421 access |= 2;
1422 }
1423 else
1424 {
1425 access &= ~2;
1426 }
1427 accessSet = true;
1428 break;
1429
1430 // AccessSSL Attributes
1431 case "AccessSSL":
1432 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1433 {
1434 accessSSLFlags |= 8;
1435 }
1436 else
1437 {
1438 accessSSLFlags &= ~8;
1439 }
1440 accessSSLFlagsSet = true;
1441 break;
1442 case "AccessSSL128":
1443 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1444 {
1445 accessSSLFlags |= 256;
1446 }
1447 else
1448 {
1449 accessSSLFlags &= ~256;
1450 }
1451 accessSSLFlagsSet = true;
1452 break;
1453 case "AccessSSLMapCert":
1454 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1455 {
1456 accessSSLFlags |= 128;
1457 }
1458 else
1459 {
1460 accessSSLFlags &= ~128;
1461 }
1462 accessSSLFlagsSet = true;
1463 break;
1464 case "AccessSSLNegotiateCert":
1465 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1466 {
1467 accessSSLFlags |= 32;
1468 }
1469 else
1470 {
1471 accessSSLFlags &= ~32;
1472 }
1473 accessSSLFlagsSet = true;
1474 break;
1475 case "AccessSSLRequireCert":
1476 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1477 {
1478 accessSSLFlags |= 64;
1479 }
1480 else
1481 {
1482 accessSSLFlags &= ~64;
1483 }
1484 accessSSLFlagsSet = true;
1485 break;
1486
1487 // Authorization attributes
1488 case "AnonymousAccess":
1489 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1490 {
1491 authorization |= 1;
1492 }
1493 else
1494 {
1495 authorization &= ~1;
1496 }
1497 authorizationSet = true;
1498 break;
1499 case "BasicAuthentication":
1500 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1501 {
1502 authorization |= 2;
1503 }
1504 else
1505 {
1506 authorization &= ~2;
1507 }
1508 authorizationSet = true;
1509 break;
1510 case "DigestAuthentication":
1511 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1512 {
1513 authorization |= 16;
1514 }
1515 else
1516 {
1517 authorization &= ~16;
1518 }
1519 authorizationSet = true;
1520 break;
1521 case "PassportAuthentication":
1522 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1523 {
1524 authorization |= 64;
1525 }
1526 else
1527 {
1528 authorization &= ~64;
1529 }
1530 authorizationSet = true;
1531 break;
1532 case "WindowsAuthentication":
1533 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1534 {
1535 authorization |= 4;
1536 }
1537 else
1538 {
1539 authorization &= ~4;
1540 }
1541 authorizationSet = true;
1542 break;
1543 default:
1544 this.ParseHelper.UnexpectedAttribute(element, attrib);
1545 break;
1546 }
1547 }
1548 else
1549 {
1550 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1551 }
1552 }
1553
1554 if (null == id)
1555 {
1556 if (null == componentId)
1557 {
1558 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
1559 id = Identifier.Invalid;
1560 }
1561 else
1562 {
1563 id = this.ParseHelper.CreateIdentifier("wdp", componentId);
1564 }
1565 }
1566
1567 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1568
1569 if (!this.Messaging.EncounteredError)
1570 {
1571 var symbol = section.AddSymbol(new IIsWebDirPropertiesSymbol(sourceLineNumbers, id)
1572 {
1573 AnonymousUserRef = anonymousUser,
1574 IIsControlledPassword = iisControlledPassword ? 1 : 0,
1575 DefaultDoc = defaultDocuments,
1576 HttpExpires = httpExpires,
1577 CacheControlCustom = cacheControlCustom,
1578 });
1579
1580 if (accessSet)
1581 {
1582 symbol.Access = access;
1583 }
1584
1585 if (authorizationSet)
1586 {
1587 symbol.Authorization = authorization;
1588 }
1589
1590 if (YesNoType.NotSet != logVisits)
1591 {
1592 symbol.LogVisits = YesNoType.Yes == logVisits ? 1 : 0;
1593 }
1594
1595 if (YesNoType.NotSet != index)
1596 {
1597 symbol.Index = YesNoType.Yes == index ? 1 : 0;
1598 }
1599
1600 if (YesNoType.NotSet != aspDetailedError)
1601 {
1602 symbol.AspDetailedError = YesNoType.Yes == aspDetailedError ? 1 : 0;
1603 }
1604
1605 if (CompilerConstants.LongNotSet != cacheControlMaxAge)
1606 {
1607 symbol.CacheControlMaxAge = unchecked((int)cacheControlMaxAge);
1608 }
1609
1610 if (YesNoType.NotSet != notCustomError)
1611 {
1612 symbol.NoCustomError = YesNoType.Yes == notCustomError ? 1 : 0;
1613 }
1614
1615 if (accessSSLFlagsSet)
1616 {
1617 symbol.AccessSSLFlags = accessSSLFlags;
1618 }
1619
1620 if (null != authenticationProviders)
1621 {
1622 symbol.AuthenticationProviders = authenticationProviders;
1623 }
1624 }
1625
1626 return id?.Id;
1627 }
1628
1629 /// <summary>
1630 /// Parses a web error element.
1631 /// </summary>
1632 /// <param name="element">Element to parse.</param>
1633 /// <param name="parentType">Type of the parent.</param>
1634 /// <param name="parent">Id of the parent.</param>
1635 private void ParseWebErrorElement(Intermediate intermediate, IntermediateSection section, XElement element, WebErrorParentType parentType, string parent)
1636 {
1637 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1638 var errorCode = CompilerConstants.IntegerNotSet;
1639 string file = null;
1640 string url = null;
1641 var subCode = CompilerConstants.IntegerNotSet;
1642
1643 foreach (var attrib in element.Attributes())
1644 {
1645 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1646 {
1647 switch (attrib.Name.LocalName)
1648 {
1649 case "ErrorCode":
1650 errorCode = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 400, 599);
1651 break;
1652 case "File":
1653 file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1654 break;
1655 case "SubCode":
1656 subCode = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
1657 break;
1658 case "URL":
1659 url = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1660 break;
1661 default:
1662 this.ParseHelper.UnexpectedAttribute(element, attrib);
1663 break;
1664 }
1665 }
1666 else
1667 {
1668 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1669 }
1670 }
1671
1672 if (CompilerConstants.IntegerNotSet == errorCode)
1673 {
1674 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ErrorCode"));
1675 errorCode = CompilerConstants.IllegalInteger;
1676 }
1677
1678 if (CompilerConstants.IntegerNotSet == subCode)
1679 {
1680 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "SubCode"));
1681 subCode = CompilerConstants.IllegalInteger;
1682 }
1683
1684 if (String.IsNullOrEmpty(file) && String.IsNullOrEmpty(url))
1685 {
1686 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "File", "URL"));
1687 }
1688
1689 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1690
1691 // Reference ConfigureIIs since nothing will happen without it
1692 this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
1693
1694 if (!this.Messaging.EncounteredError)
1695 {
1696 section.AddSymbol(new IIsWebErrorSymbol(sourceLineNumbers)
1697 {
1698 ErrorCode = errorCode,
1699 SubCode = subCode,
1700 ParentType = (int)parentType,
1701 ParentValue = parent,
1702 File = file,
1703 URL = url,
1704 });
1705 }
1706 }
1707
1708 /// <summary>
1709 /// Parses a web filter element.
1710 /// </summary>
1711 /// <param name="element">Element to parse.</param>
1712 /// <param name="componentId">Identifier of parent component.</param>
1713 /// <param name="parentWeb">Optional identifier of parent web site.</param>
1714 private void ParseWebFilterElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentWeb)
1715 {
1716 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1717 Identifier id = null;
1718 string description = null;
1719 int flags = 0;
1720 var loadOrder = CompilerConstants.IntegerNotSet;
1721 string name = null;
1722 string path = null;
1723
1724 foreach (var attrib in element.Attributes())
1725 {
1726 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1727 {
1728 switch (attrib.Name.LocalName)
1729 {
1730 case "Id":
1731 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1732 break;
1733 case "Description":
1734 description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1735 break;
1736 case "Flags":
1737 flags = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
1738 break;
1739 case "LoadOrder":
1740 string loadOrderValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1741 if (0 < loadOrderValue.Length)
1742 {
1743 switch (loadOrderValue)
1744 {
1745 case "first":
1746 loadOrder = 0;
1747 break;
1748 case "last":
1749 loadOrder = -1;
1750 break;
1751 default:
1752 loadOrder = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue);
1753 break;
1754 }
1755 }
1756 break;
1757 case "Name":
1758 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1759 break;
1760 case "Path":
1761 path = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1762 break;
1763 case "WebSite":
1764 if (null != parentWeb)
1765 {
1766 this.Messaging.Write(IIsErrors.WebSiteAttributeUnderWebSite(sourceLineNumbers, element.Name.LocalName));
1767 }
1768
1769 parentWeb = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1770 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebSite, parentWeb);
1771 break;
1772 default:
1773 this.ParseHelper.UnexpectedAttribute(element, attrib);
1774 break;
1775 }
1776 }
1777 else
1778 {
1779 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1780 }
1781 }
1782
1783 if (null == id)
1784 {
1785 id = this.ParseHelper.CreateIdentifier("ifl", name, componentId, path, parentWeb);
1786 }
1787
1788 if (null == name)
1789 {
1790 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
1791 }
1792
1793 if (null == path)
1794 {
1795 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
1796 }
1797
1798 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1799
1800 // Reference ConfigureIIs since nothing will happen without it
1801 this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
1802
1803 if (!this.Messaging.EncounteredError)
1804 {
1805 var symbol = section.AddSymbol(new IIsFilterSymbol(sourceLineNumbers, id)
1806 {
1807 Name = name,
1808 ComponentRef = componentId,
1809 Path = path,
1810 WebRef = parentWeb,
1811 Description = description,
1812 Flags = flags,
1813 });
1814
1815 if (CompilerConstants.IntegerNotSet != loadOrder)
1816 {
1817 symbol.LoadOrder = loadOrder;
1818 }
1819 }
1820 }
1821
1822 /// <summary>
1823 /// Parses web log element.
1824 /// </summary>
1825 /// <param name="element">Node to be parsed.</param>
1826 private void ParseWebLogElement(Intermediate intermediate, IntermediateSection section, XElement element)
1827 {
1828 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1829 Identifier id = null;
1830 string type = null;
1831
1832 foreach (var attrib in element.Attributes())
1833 {
1834 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1835 {
1836 switch (attrib.Name.LocalName)
1837 {
1838 case "Id":
1839 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1840 break;
1841 case "Type":
1842 var typeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1843 if (0 < typeValue.Length)
1844 {
1845 switch (typeValue)
1846 {
1847 case "IIS":
1848 type = "Microsoft IIS Log File Format";
1849 break;
1850 case "NCSA":
1851 type = "NCSA Common Log File Format";
1852 break;
1853 case "none":
1854 type = "none";
1855 break;
1856 case "ODBC":
1857 type = "ODBC Logging";
1858 break;
1859 case "W3C":
1860 type = "W3C Extended Log File Format";
1861 break;
1862 default:
1863 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Type", typeValue, "IIS", "NCSA", "none", "ODBC", "W3C"));
1864 break;
1865 }
1866 }
1867 break;
1868 default:
1869 this.ParseHelper.UnexpectedAttribute(element, attrib);
1870 break;
1871 }
1872 }
1873 else
1874 {
1875 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1876 }
1877 }
1878
1879 if (null == id)
1880 {
1881 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
1882 }
1883
1884 if (null == type)
1885 {
1886 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Type"));
1887 }
1888
1889 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1890
1891 if (!this.Messaging.EncounteredError)
1892 {
1893 section.AddSymbol(new IIsWebLogSymbol(sourceLineNumbers, id)
1894 {
1895 Format = type,
1896 });
1897 }
1898 }
1899
1900 /// <summary>
1901 /// Parses a web property element.
1902 /// </summary>
1903 /// <param name="element">Element to parse.</param>
1904 /// <param name="componentId">Identifier for parent component.</param>
1905 private void ParseWebPropertyElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
1906 {
1907 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1908 Identifier id = null;
1909 string value = null;
1910
1911 foreach (var attrib in element.Attributes())
1912 {
1913 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1914 {
1915 switch (attrib.Name.LocalName)
1916 {
1917 case "Id":
1918 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1919 break;
1920 case "Value":
1921 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1922 break;
1923 default:
1924 this.ParseHelper.UnexpectedAttribute(element, attrib);
1925 break;
1926 }
1927 }
1928 else
1929 {
1930 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1931 }
1932 }
1933
1934 switch (id?.Id)
1935 {
1936 case "ETagChangeNumber":
1937 case "MaxGlobalBandwidth":
1938 // Must specify a value for these
1939 if (null == value)
1940 {
1941 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Value", "Id", id.Id));
1942 }
1943 break;
1944 case "IIs5IsolationMode":
1945 case "LogInUTF8":
1946 // Can't specify a value for these
1947 if (null != value)
1948 {
1949 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Value", "Id", id.Id));
1950 }
1951 break;
1952 default:
1953 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Id", id?.Id, "ETagChangeNumber", "IIs5IsolationMode", "LogInUTF8", "MaxGlobalBandwidth"));
1954 break;
1955 }
1956
1957 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1958
1959 // Reference ConfigureIIs since nothing will happen without it
1960 this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
1961
1962 if (!this.Messaging.EncounteredError)
1963 {
1964 section.AddSymbol(new IIsPropertySymbol(sourceLineNumbers, id)
1965 {
1966 ComponentRef = componentId,
1967 Attributes = 0,
1968 Value = value,
1969 });
1970 }
1971 }
1972
1973 /// <summary>
1974 /// Parses a web service extension element.
1975 /// </summary>
1976 /// <param name="element">Element to parse.</param>
1977 /// <param name="componentId">Identifier for parent component.</param>
1978 private void ParseWebServiceExtensionElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
1979 {
1980 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1981 Identifier id = null;
1982 int attributes = 0;
1983 string description = null;
1984 string file = null;
1985 string group = null;
1986
1987 foreach (XAttribute attrib in element.Attributes())
1988 {
1989 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1990 {
1991 switch (attrib.Name.LocalName)
1992 {
1993 case "Id":
1994 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
1995 break;
1996 case "Allow":
1997 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
1998 {
1999 attributes |= 1;
2000 }
2001 else
2002 {
2003 attributes &= ~1;
2004 }
2005 break;
2006 case "Description":
2007 description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2008 break;
2009 case "File":
2010 file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2011 break;
2012 case "Group":
2013 group = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2014 break;
2015 case "UIDeletable":
2016 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
2017 {
2018 attributes |= 2;
2019 }
2020 else
2021 {
2022 attributes &= ~2;
2023 }
2024 break;
2025 default:
2026 this.ParseHelper.UnexpectedAttribute(element, attrib);
2027 break;
2028 }
2029 }
2030 else
2031 {
2032 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2033 }
2034 }
2035
2036 if (null == id)
2037 {
2038 id = this.ParseHelper.CreateIdentifier("iwe", componentId, file);
2039 }
2040
2041 if (null == file)
2042 {
2043 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File"));
2044 }
2045
2046 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2047
2048 // Reference ConfigureIIs since nothing will happen without it
2049 this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
2050
2051 if (!this.Messaging.EncounteredError)
2052 {
2053 section.AddSymbol(new IIsWebServiceExtensionSymbol(sourceLineNumbers, id)
2054 {
2055 ComponentRef = componentId,
2056 File = file,
2057 Description = description,
2058 Group = group,
2059 Attributes = attributes,
2060 });
2061 }
2062 }
2063
2064 /// <summary>
2065 /// Parses a web site element.
2066 /// </summary>
2067 /// <param name="element">Element to parse.</param>
2068 /// <param name="componentId">Optional identifier of parent component.</param>
2069 private void ParseWebSiteElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
2070 {
2071 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2072 Identifier id = null;
2073 string application = null;
2074 int attributes = 0;
2075 var connectionTimeout = CompilerConstants.IntegerNotSet;
2076 string description = null;
2077 string directory = null;
2078 string dirProperties = null;
2079 string keyAddress = null;
2080 string log = null;
2081 string siteId = null;
2082 var sequence = CompilerConstants.IntegerNotSet;
2083 var state = CompilerConstants.IntegerNotSet;
2084
2085 foreach (var attrib in element.Attributes())
2086 {
2087 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2088 {
2089 switch (attrib.Name.LocalName)
2090 {
2091 case "Id":
2092 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
2093 break;
2094 case "AutoStart":
2095 if (null == componentId)
2096 {
2097 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
2098 }
2099
2100 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
2101 {
2102 state = 2;
2103 }
2104 else if (state != 1)
2105 {
2106 state = 0;
2107 }
2108 break;
2109 case "ConfigureIfExists":
2110 if (null == componentId)
2111 {
2112 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
2113 }
2114
2115 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
2116 {
2117 attributes &= ~2;
2118 }
2119 else
2120 {
2121 attributes |= 2;
2122 }
2123 break;
2124 case "ConnectionTimeout":
2125 connectionTimeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
2126 break;
2127 case "Description":
2128 description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2129 break;
2130 case "Directory":
2131 directory = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2132 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, directory);
2133 break;
2134 case "DirProperties":
2135 if (null == componentId)
2136 {
2137 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
2138 }
2139
2140 dirProperties = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2141 break;
2142 case "SiteId":
2143 siteId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2144 if ("*" == siteId)
2145 {
2146 siteId = "-1";
2147 }
2148 break;
2149 case "Sequence":
2150 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue);
2151 break;
2152 case "StartOnInstall":
2153 if (null == componentId)
2154 {
2155 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
2156 }
2157
2158 // when state is set to 2 it implies 1, so don't set it to 1
2159 if (2 != state && YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
2160 {
2161 state = 1;
2162 }
2163 else if (2 != state)
2164 {
2165 state = 0;
2166 }
2167 break;
2168 case "WebApplication":
2169 if (null == componentId)
2170 {
2171 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
2172 }
2173
2174 application = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2175 break;
2176 case "WebLog":
2177 if (null == componentId)
2178 {
2179 this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
2180 }
2181
2182 log = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2183 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebLog, log);
2184 break;
2185 default:
2186 this.ParseHelper.UnexpectedAttribute(element, attrib);
2187 break;
2188 }
2189 }
2190 else
2191 {
2192 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2193 }
2194 }
2195
2196 if (null == id)
2197 {
2198 id = this.ParseHelper.CreateIdentifier("iws", description, componentId, siteId, application);
2199 }
2200
2201 if (null == description)
2202 {
2203 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Description"));
2204 }
2205
2206 if (null == directory && null != componentId)
2207 {
2208 this.Messaging.Write(IIsErrors.RequiredAttributeUnderComponent(sourceLineNumbers, element.Name.LocalName, "Directory"));
2209 }
2210
2211 foreach (var child in element.Elements())
2212 {
2213 if (this.Namespace == child.Name.Namespace)
2214 {
2215 var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
2216 switch (child.Name.LocalName)
2217 {
2218 case "CertificateRef":
2219 if (null == componentId)
2220 {
2221 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
2222 }
2223
2224 this.ParseCertificateRefElement(intermediate, section, child, id?.Id);
2225 break;
2226 case "HttpHeader":
2227 if (null == componentId)
2228 {
2229 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
2230 }
2231
2232 this.ParseHttpHeaderElement(intermediate, section, child, HttpHeaderParentType.WebSite, id?.Id);
2233 break;
2234 case "WebAddress":
2235 string address = this.ParseWebAddressElement(intermediate, section, child, id?.Id);
2236 if (null == keyAddress)
2237 {
2238 keyAddress = address;
2239 }
2240 break;
2241 case "WebApplication":
2242 if (null == componentId)
2243 {
2244 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
2245 }
2246
2247 if (null != application)
2248 {
2249 this.Messaging.Write(IIsErrors.WebApplicationAlreadySpecified(childSourceLineNumbers, element.Name.LocalName));
2250 }
2251
2252 application = this.ParseWebApplicationElement(intermediate, section, child);
2253 break;
2254 case "WebDir":
2255 if (null == componentId)
2256 {
2257 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
2258 }
2259
2260 this.ParseWebDirElement(intermediate, section, child, componentId, id?.Id);
2261 break;
2262 case "WebDirProperties":
2263 if (null == componentId)
2264 {
2265 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
2266 }
2267
2268 string childWebDirProperties = this.ParseWebDirPropertiesElement(intermediate, section, child, componentId);
2269 if (null == dirProperties)
2270 {
2271 dirProperties = childWebDirProperties;
2272 }
2273 else
2274 {
2275 this.Messaging.Write(ErrorMessages.IllegalParentAttributeWhenNested(sourceLineNumbers, "WebSite", "DirProperties", child.Name.LocalName));
2276 }
2277 break;
2278 case "WebError":
2279 if (null == componentId)
2280 {
2281 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
2282 }
2283
2284 this.ParseWebErrorElement(intermediate, section, child, WebErrorParentType.WebSite, id?.Id);
2285 break;
2286 case "WebFilter":
2287 if (null == componentId)
2288 {
2289 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
2290 }
2291
2292 this.ParseWebFilterElement(intermediate, section, child, componentId, id?.Id);
2293 break;
2294 case "WebVirtualDir":
2295 if (null == componentId)
2296 {
2297 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
2298 }
2299
2300 this.ParseWebVirtualDirElement(intermediate, section, child, componentId, id?.Id, null);
2301 break;
2302 case "MimeMap":
2303 this.ParseMimeMapElement(intermediate, section, child, id?.Id, MimeMapParentType.WebSite);
2304 break;
2305 default:
2306 this.ParseHelper.UnexpectedElement(element, child);
2307 break;
2308 }
2309 }
2310 else
2311 {
2312 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
2313 }
2314 }
2315
2316
2317 if (null == keyAddress)
2318 {
2319 this.Messaging.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, element.Name.LocalName, "WebAddress"));
2320 }
2321
2322 if (null != application)
2323 {
2324 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebApplication, application);
2325 }
2326
2327 if (null != dirProperties)
2328 {
2329 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebDirProperties, dirProperties);
2330 }
2331
2332 if (null != componentId)
2333 {
2334 // Reference ConfigureIIs since nothing will happen without it
2335 this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
2336 }
2337
2338 if (!this.Messaging.EncounteredError)
2339 {
2340 var symbol = section.AddSymbol(new IIsWebSiteSymbol(sourceLineNumbers, id)
2341 {
2342 ComponentRef = componentId,
2343 Description = description,
2344 DirectoryRef = directory,
2345 KeyAddressRef = keyAddress,
2346 DirPropertiesRef = dirProperties,
2347 ApplicationRef = application,
2348 LogRef = log,
2349 WebsiteId = siteId,
2350 });
2351
2352 if (CompilerConstants.IntegerNotSet != connectionTimeout)
2353 {
2354 symbol.ConnectionTimeout = connectionTimeout;
2355 }
2356
2357 if (CompilerConstants.IntegerNotSet != state)
2358 {
2359 symbol.State = state;
2360 }
2361
2362 if (0 != attributes)
2363 {
2364 symbol.Attributes = attributes;
2365 }
2366
2367 if (CompilerConstants.IntegerNotSet != sequence)
2368 {
2369 symbol.Sequence = sequence;
2370 }
2371 }
2372 }
2373
2374 /// <summary>
2375 /// Parses a HTTP Header element.
2376 /// </summary>
2377 /// <param name="element">Element to parse.</param>
2378 /// <param name="parentType">Type of the parent.</param>
2379 /// <param name="parent">Id of the parent.</param>
2380 private void ParseHttpHeaderElement(Intermediate intermediate, IntermediateSection section, XElement element, HttpHeaderParentType parentType, string parent)
2381 {
2382 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2383 Identifier id = null;
2384 string headerName = null;
2385 string headerValue = null;
2386
2387 foreach (var attrib in element.Attributes())
2388 {
2389 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2390 {
2391 switch (attrib.Name.LocalName)
2392 {
2393 case "Id":
2394 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
2395 break;
2396 case "Name":
2397 headerName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2398 break;
2399 case "Value":
2400 headerValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2401 break;
2402 default:
2403 this.ParseHelper.UnexpectedAttribute(element, attrib);
2404 break;
2405 }
2406 }
2407 else
2408 {
2409 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2410 }
2411 }
2412
2413 if (null == headerName)
2414 {
2415 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
2416 }
2417 else if (null == id)
2418 {
2419 id = this.ParseHelper.CreateIdentifierFromFilename(headerName);
2420 }
2421
2422 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2423
2424 // Reference ConfigureIIs since nothing will happen without it
2425 this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
2426
2427 if (!this.Messaging.EncounteredError)
2428 {
2429 section.AddSymbol(new IIsHttpHeaderSymbol(sourceLineNumbers, id)
2430 {
2431 HttpHeader = id.Id,
2432 ParentType = (int)parentType,
2433 ParentValue = parent,
2434 Name = headerName,
2435 Value = headerValue,
2436 Attributes = 0,
2437 });
2438 }
2439 }
2440
2441 /// <summary>
2442 /// Parses a virtual directory element.
2443 /// </summary>
2444 /// <param name="element">Element to parse.</param>
2445 /// <param name="componentId">Identifier of parent component.</param>
2446 /// <param name="parentWeb">Identifier of parent web site.</param>
2447 /// <param name="parentAlias">Alias of the parent web site.</param>
2448 private void ParseWebVirtualDirElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentWeb, string parentAlias)
2449 {
2450 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2451 Identifier id = null;
2452 string alias = null;
2453 string application = null;
2454 string directory = null;
2455 string dirProperties = null;
2456
2457 foreach (var attrib in element.Attributes())
2458 {
2459 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2460 {
2461 switch (attrib.Name.LocalName)
2462 {
2463 case "Id":
2464 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
2465 break;
2466 case "Alias":
2467 alias = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2468 break;
2469 case "Directory":
2470 directory = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2471 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, directory);
2472 break;
2473 case "DirProperties":
2474 dirProperties = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2475 break;
2476 case "WebApplication":
2477 application = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2478 break;
2479 case "WebSite":
2480 if (null != parentWeb)
2481 {
2482 this.Messaging.Write(IIsErrors.WebSiteAttributeUnderWebSite(sourceLineNumbers, element.Name.LocalName));
2483 }
2484
2485 parentWeb = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
2486 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebSite, parentWeb);
2487 break;
2488 default:
2489 this.ParseHelper.UnexpectedAttribute(element, attrib);
2490 break;
2491 }
2492 }
2493 else
2494 {
2495 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2496 }
2497 }
2498
2499 if (null == id)
2500 {
2501 id = this.ParseHelper.CreateIdentifier("wvd", alias, directory, dirProperties, application, parentWeb);
2502 }
2503
2504 if (null == alias)
2505 {
2506 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Alias"));
2507 }
2508 else if (-1 != alias.IndexOf("\\", StringComparison.Ordinal))
2509 {
2510 this.Messaging.Write(IIsErrors.IllegalCharacterInAttributeValue(sourceLineNumbers, element.Name.LocalName, "Alias", alias, '\\'));
2511 }
2512
2513 if (null == directory)
2514 {
2515 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Directory"));
2516 }
2517
2518 if (null == parentWeb)
2519 {
2520 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "WebSite"));
2521 }
2522
2523 if (null == componentId)
2524 {
2525 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(sourceLineNumbers, element.Name.LocalName));
2526 }
2527
2528 if (null != parentAlias)
2529 {
2530 alias = String.Concat(parentAlias, "/", alias);
2531 }
2532
2533 foreach (var child in element.Elements())
2534 {
2535 if (this.Namespace == child.Name.Namespace)
2536 {
2537 var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
2538 switch (child.Name.LocalName)
2539 {
2540 case "WebApplication":
2541 if (null != application)
2542 {
2543 this.Messaging.Write(IIsErrors.WebApplicationAlreadySpecified(childSourceLineNumbers, element.Name.LocalName));
2544 }
2545
2546 application = this.ParseWebApplicationElement(intermediate, section, child);
2547 break;
2548 case "WebDirProperties":
2549 if (null == componentId)
2550 {
2551 this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
2552 }
2553
2554 string childWebDirProperties = this.ParseWebDirPropertiesElement(intermediate, section, child, componentId);
2555 if (null == dirProperties)
2556 {
2557 dirProperties = childWebDirProperties;
2558 }
2559 else
2560 {
2561 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, child.Name.LocalName, "DirProperties", child.Name.LocalName));
2562 }
2563 break;
2564
2565 case "WebError":
2566 this.ParseWebErrorElement(intermediate, section, child, WebErrorParentType.WebVirtualDir, id?.Id);
2567 break;
2568 case "WebVirtualDir":
2569 this.ParseWebVirtualDirElement(intermediate, section, child, componentId, parentWeb, alias);
2570 break;
2571 case "HttpHeader":
2572 this.ParseHttpHeaderElement(intermediate, section, child, HttpHeaderParentType.WebVirtualDir, id?.Id);
2573 break;
2574 case "MimeMap":
2575 this.ParseMimeMapElement(intermediate, section, child, id?.Id, MimeMapParentType.WebVirtualDir);
2576 break;
2577 default:
2578 this.ParseHelper.UnexpectedElement(element, child);
2579 break;
2580 }
2581 }
2582 else
2583 {
2584 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
2585 }
2586 }
2587
2588 if (null != dirProperties)
2589 {
2590 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebDirProperties, dirProperties);
2591 }
2592
2593 if (null != application)
2594 {
2595 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebApplication, application);
2596 }
2597
2598 // Reference ConfigureIIs since nothing will happen without it
2599 this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
2600
2601 if (!this.Messaging.EncounteredError)
2602 {
2603 section.AddSymbol(new IIsWebVirtualDirSymbol(sourceLineNumbers, id)
2604 {
2605 ComponentRef = componentId,
2606 WebRef = parentWeb,
2607 Alias = alias,
2608 DirectoryRef = directory,
2609 DirPropertiesRef = dirProperties,
2610 ApplicationRef = application,
2611 });
2612 }
2613 }
2614
2615 private void AddReferenceToConfigureIIs(IntermediateSection section, SourceLineNumber sourceLineNumbers)
2616 {
2617 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureIIs", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
2618 }
2619 }
2620}
diff --git a/src/ext/Iis/wixext/IIsDecompiler.cs b/src/ext/Iis/wixext/IIsDecompiler.cs
new file mode 100644
index 00000000..17e15348
--- /dev/null
+++ b/src/ext/Iis/wixext/IIsDecompiler.cs
@@ -0,0 +1,1549 @@
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
3namespace WixToolset.Iis
4{
5#if TODO_CONSIDER_DECOMPILER
6 using System;
7 using System.Collections;
8 using System.Globalization;
9 using WixToolset.Data;
10 using WixToolset.Extensibility;
11 using IIs = WixToolset.Extensions.Serialize.IIs;
12 using Wix = WixToolset.Data.Serialize;
13
14 /// <summary>
15 /// The decompiler for the WiX Toolset Internet Information Services Extension.
16 /// </summary>
17 public sealed class IIsDecompiler : DecompilerExtension
18 {
19 /// <summary>
20 /// Creates a decompiler for IIs Extension.
21 /// </summary>
22 public IIsDecompiler()
23 {
24 this.TableDefinitions = IIsExtensionData.GetExtensionTableDefinitions();
25 }
26
27 /// <summary>
28 /// Get the extensions library to be removed.
29 /// </summary>
30 /// <param name="tableDefinitions">Table definitions for library.</param>
31 /// <returns>Library to remove from decompiled output.</returns>
32 public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions)
33 {
34 return IIsExtensionData.GetExtensionLibrary(tableDefinitions);
35 }
36
37 /// <summary>
38 /// Decompiles an extension table.
39 /// </summary>
40 /// <param name="table">The table to decompile.</param>
41 public override void DecompileTable(Table table)
42 {
43 switch (table.Name)
44 {
45 case "Certificate":
46 this.DecompileCertificateTable(table);
47 break;
48 case "CertificateHash":
49 // There is nothing to do for this table, it contains no authored data
50 // to be decompiled.
51 break;
52 case "IIsAppPool":
53 this.DecompileIIsAppPoolTable(table);
54 break;
55 case "IIsFilter":
56 this.DecompileIIsFilterTable(table);
57 break;
58 case "IIsProperty":
59 this.DecompileIIsPropertyTable(table);
60 break;
61 case "IIsHttpHeader":
62 this.DecompileIIsHttpHeaderTable(table);
63 break;
64 case "IIsMimeMap":
65 this.DecompileIIsMimeMapTable(table);
66 break;
67 case "IIsWebAddress":
68 this.DecompileIIsWebAddressTable(table);
69 break;
70 case "IIsWebApplication":
71 this.DecompileIIsWebApplicationTable(table);
72 break;
73 case "IIsWebDirProperties":
74 this.DecompileIIsWebDirPropertiesTable(table);
75 break;
76 case "IIsWebError":
77 this.DecompileIIsWebErrorTable(table);
78 break;
79 case "IIsWebLog":
80 this.DecompileIIsWebLogTable(table);
81 break;
82 case "IIsWebServiceExtension":
83 this.DecompileIIsWebServiceExtensionTable(table);
84 break;
85 case "IIsWebSite":
86 this.DecompileIIsWebSiteTable(table);
87 break;
88 case "IIsWebVirtualDir":
89 this.DecompileIIsWebVirtualDirTable(table);
90 break;
91 case "IIsWebSiteCertificates":
92 this.DecompileIIsWebSiteCertificatesTable(table);
93 break;
94 default:
95 base.DecompileTable(table);
96 break;
97 }
98 }
99
100 /// <summary>
101 /// Finalize decompilation.
102 /// </summary>
103 /// <param name="tables">The collection of all tables.</param>
104 public override void Finish(TableIndexedCollection tables)
105 {
106 this.FinalizeIIsMimeMapTable(tables);
107 this.FinalizeIIsHttpHeaderTable(tables);
108 this.FinalizeIIsWebApplicationTable(tables);
109 this.FinalizeIIsWebErrorTable(tables);
110 this.FinalizeIIsWebVirtualDirTable(tables);
111 this.FinalizeIIsWebSiteCertificatesTable(tables);
112 this.FinalizeWebAddressTable(tables);
113 }
114
115 /// <summary>
116 /// Decompile the Certificate table.
117 /// </summary>
118 /// <param name="table">The table to decompile.</param>
119 private void DecompileCertificateTable(Table table)
120 {
121 foreach (Row row in table.Rows)
122 {
123 IIs.Certificate certificate = new IIs.Certificate();
124
125 certificate.Id = (string)row[0];
126 certificate.Name = (string)row[2];
127
128 switch ((int)row[3])
129 {
130 case 1:
131 certificate.StoreLocation = IIs.Certificate.StoreLocationType.currentUser;
132 break;
133 case 2:
134 certificate.StoreLocation = IIs.Certificate.StoreLocationType.localMachine;
135 break;
136 default:
137 // TODO: warn
138 break;
139 }
140
141 switch ((string)row[4])
142 {
143 case "CA":
144 certificate.StoreName = IIs.Certificate.StoreNameType.ca;
145 break;
146 case "MY":
147 certificate.StoreName = IIs.Certificate.StoreNameType.my;
148 break;
149 case "REQUEST":
150 certificate.StoreName = IIs.Certificate.StoreNameType.request;
151 break;
152 case "Root":
153 certificate.StoreName = IIs.Certificate.StoreNameType.root;
154 break;
155 case "AddressBook":
156 certificate.StoreName = IIs.Certificate.StoreNameType.otherPeople;
157 break;
158 case "TrustedPeople":
159 certificate.StoreName = IIs.Certificate.StoreNameType.trustedPeople;
160 break;
161 case "TrustedPublisher":
162 certificate.StoreName = IIs.Certificate.StoreNameType.trustedPublisher;
163 break;
164 default:
165 // TODO: warn
166 break;
167 }
168
169 int attribute = (int)row[5];
170
171 if (0x1 == (attribute & 0x1))
172 {
173 certificate.Request = IIs.YesNoType.yes;
174 }
175
176 if (0x2 == (attribute & 0x2))
177 {
178 if (null != row[6])
179 {
180 certificate.BinaryKey = (string)row[6];
181 }
182 else
183 {
184 // TODO: warn about expected value in row 5
185 }
186 }
187 else if (null != row[7])
188 {
189 certificate.CertificatePath = (string)row[7];
190 }
191
192 if (0x4 == (attribute & 0x4))
193 {
194 certificate.Overwrite = IIs.YesNoType.yes;
195 }
196
197 if (null != row[8])
198 {
199 certificate.PFXPassword = (string)row[8];
200 }
201
202 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
203 if (null != component)
204 {
205 component.AddChild(certificate);
206 }
207 else
208 {
209 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
210 }
211 }
212 }
213
214 /// <summary>
215 /// Decompile the IIsAppPool table.
216 /// </summary>
217 /// <param name="table">The table to decompile.</param>
218 private void DecompileIIsAppPoolTable(Table table)
219 {
220 foreach (Row row in table.Rows)
221 {
222 IIs.WebAppPool webAppPool = new IIs.WebAppPool();
223
224 webAppPool.Id = (string)row[0];
225
226 webAppPool.Name = (string)row[1];
227
228 switch ((int)row[3] & 0x1F)
229 {
230 case 1:
231 webAppPool.Identity = IIs.WebAppPool.IdentityType.networkService;
232 break;
233 case 2:
234 webAppPool.Identity = IIs.WebAppPool.IdentityType.localService;
235 break;
236 case 4:
237 webAppPool.Identity = IIs.WebAppPool.IdentityType.localSystem;
238 break;
239 case 8:
240 webAppPool.Identity = IIs.WebAppPool.IdentityType.other;
241 break;
242 case 0x10:
243 webAppPool.Identity = IIs.WebAppPool.IdentityType.applicationPoolIdentity;
244 break;
245 default:
246 // TODO: warn
247 break;
248 }
249
250 if (null != row[4])
251 {
252 webAppPool.User = (string)row[4];
253 }
254
255 if (null != row[5])
256 {
257 webAppPool.RecycleMinutes = (int)row[5];
258 }
259
260 if (null != row[6])
261 {
262 webAppPool.RecycleRequests = (int)row[6];
263 }
264
265 if (null != row[7])
266 {
267 string[] recycleTimeValues = ((string)row[7]).Split(',');
268
269 foreach (string recycleTimeValue in recycleTimeValues)
270 {
271 IIs.RecycleTime recycleTime = new IIs.RecycleTime();
272
273 recycleTime.Value = recycleTimeValue;
274
275 webAppPool.AddChild(recycleTime);
276 }
277 }
278
279 if (null != row[8])
280 {
281 webAppPool.IdleTimeout = (int)row[8];
282 }
283
284 if (null != row[9])
285 {
286 webAppPool.QueueLimit = (int)row[9];
287 }
288
289 if (null != row[10])
290 {
291 string[] cpuMon = ((string)row[10]).Split(',');
292
293 if (0 < cpuMon.Length && "0" != cpuMon[0])
294 {
295 webAppPool.MaxCpuUsage = Convert.ToInt32(cpuMon[0], CultureInfo.InvariantCulture);
296 }
297
298 if (1 < cpuMon.Length)
299 {
300 webAppPool.RefreshCpu = Convert.ToInt32(cpuMon[1], CultureInfo.InvariantCulture);
301 }
302
303 if (2 < cpuMon.Length)
304 {
305 switch (Convert.ToInt32(cpuMon[2], CultureInfo.InvariantCulture))
306 {
307 case 0:
308 webAppPool.CpuAction = IIs.WebAppPool.CpuActionType.none;
309 break;
310 case 1:
311 webAppPool.CpuAction = IIs.WebAppPool.CpuActionType.shutdown;
312 break;
313 default:
314 // TODO: warn
315 break;
316 }
317 }
318
319 if (3 < cpuMon.Length)
320 {
321 // TODO: warn
322 }
323 }
324
325 if (null != row[11])
326 {
327 webAppPool.MaxWorkerProcesses = (int)row[11];
328 }
329
330 if (null != row[12])
331 {
332 webAppPool.VirtualMemory = (int)row[12];
333 }
334
335 if (null != row[13])
336 {
337 webAppPool.PrivateMemory = (int)row[13];
338 }
339
340 if (null != row[14])
341 {
342 webAppPool.ManagedRuntimeVersion = (string)row[14];
343 }
344
345 if (null != row[15])
346 {
347 webAppPool.ManagedPipelineMode = (string)row[15];
348 }
349
350 if (null != row[2])
351 {
352 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]);
353
354 if (null != component)
355 {
356 component.AddChild(webAppPool);
357 }
358 else
359 {
360 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component"));
361 }
362 }
363 else
364 {
365 this.Core.RootElement.AddChild(webAppPool);
366 }
367 }
368 }
369
370 /// <summary>
371 /// Decompile the IIsProperty table.
372 /// </summary>
373 /// <param name="table">The table to decompile.</param>
374 private void DecompileIIsPropertyTable(Table table)
375 {
376 foreach (Row row in table.Rows)
377 {
378 IIs.WebProperty webProperty = new IIs.WebProperty();
379
380 switch ((string)row[0])
381 {
382 case "ETagChangeNumber":
383 webProperty.Id = IIs.WebProperty.IdType.ETagChangeNumber;
384 break;
385 case "IIs5IsolationMode":
386 webProperty.Id = IIs.WebProperty.IdType.IIs5IsolationMode;
387 break;
388 case "LogInUTF8":
389 webProperty.Id = IIs.WebProperty.IdType.LogInUTF8;
390 break;
391 case "MaxGlobalBandwidth":
392 webProperty.Id = IIs.WebProperty.IdType.MaxGlobalBandwidth;
393 break;
394 }
395
396 if (0 != (int)row[2])
397 {
398 // TODO: warn about value in unused column
399 }
400
401 if (null != row[3])
402 {
403 webProperty.Value = (string)row[3];
404 }
405
406 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
407 if (null != component)
408 {
409 component.AddChild(webProperty);
410 }
411 else
412 {
413 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
414 }
415 }
416 }
417
418 /// <summary>
419 /// Decompile the IIsHttpHeader table.
420 /// </summary>
421 /// <param name="table">The table to decompile.</param>
422 private void DecompileIIsHttpHeaderTable(Table table)
423 {
424 foreach (Row row in table.Rows)
425 {
426 IIs.HttpHeader httpHeader = new IIs.HttpHeader();
427
428 httpHeader.Name = (string)row[3];
429
430 // the ParentType and Parent columns are handled in FinalizeIIsHttpHeaderTable
431
432 httpHeader.Value = (string)row[4];
433
434 this.Core.IndexElement(row, httpHeader);
435 }
436 }
437
438 /// <summary>
439 /// Decompile the IIsMimeMap table.
440 /// </summary>
441 /// <param name="table">The table to decompile.</param>
442 private void DecompileIIsMimeMapTable(Table table)
443 {
444 foreach (Row row in table.Rows)
445 {
446 IIs.MimeMap mimeMap = new IIs.MimeMap();
447
448 mimeMap.Id = (string)row[0];
449
450 // the ParentType and ParentValue columns are handled in FinalizeIIsMimeMapTable
451
452 mimeMap.Type = (string)row[3];
453
454 mimeMap.Extension = (string)row[4];
455
456 this.Core.IndexElement(row, mimeMap);
457 }
458 }
459
460 /// <summary>
461 /// Decompile the IIsWebAddress table.
462 /// </summary>
463 /// <param name="table">The table to decompile.</param>
464 private void DecompileIIsWebAddressTable(Table table)
465 {
466 foreach (Row row in table.Rows)
467 {
468 IIs.WebAddress webAddress = new IIs.WebAddress();
469
470 webAddress.Id = (string)row[0];
471
472 if (null != row[2])
473 {
474 webAddress.IP = (string)row[2];
475 }
476
477 webAddress.Port = (string)row[3];
478
479 if (null != row[4])
480 {
481 webAddress.Header = (string)row[4];
482 }
483
484 if (null != row[5] && 1 == (int)row[5])
485 {
486 webAddress.Secure = IIs.YesNoType.yes;
487 }
488
489 this.Core.IndexElement(row, webAddress);
490 }
491 }
492
493 /// <summary>
494 /// Decompile the IIsWebApplication table.
495 /// </summary>
496 /// <param name="table">The table to decompile.</param>
497 private void DecompileIIsWebApplicationTable(Table table)
498 {
499 foreach (Row row in table.Rows)
500 {
501 IIs.WebApplication webApplication = new IIs.WebApplication();
502
503 webApplication.Id = (string)row[0];
504
505 webApplication.Name = (string)row[1];
506
507 // these are not listed incorrectly - the order is low, high, medium
508 switch ((int)row[2])
509 {
510 case 0:
511 webApplication.Isolation = IIs.WebApplication.IsolationType.low;
512 break;
513 case 1:
514 webApplication.Isolation = IIs.WebApplication.IsolationType.high;
515 break;
516 case 2:
517 webApplication.Isolation = IIs.WebApplication.IsolationType.medium;
518 break;
519 default:
520 // TODO: warn
521 break;
522 }
523
524 if (null != row[3])
525 {
526 switch ((int)row[3])
527 {
528 case 0:
529 webApplication.AllowSessions = IIs.YesNoDefaultType.no;
530 break;
531 case 1:
532 webApplication.AllowSessions = IIs.YesNoDefaultType.yes;
533 break;
534 default:
535 // TODO: warn
536 break;
537 }
538 }
539
540 if (null != row[4])
541 {
542 webApplication.SessionTimeout = (int)row[4];
543 }
544
545 if (null != row[5])
546 {
547 switch ((int)row[5])
548 {
549 case 0:
550 webApplication.Buffer = IIs.YesNoDefaultType.no;
551 break;
552 case 1:
553 webApplication.Buffer = IIs.YesNoDefaultType.yes;
554 break;
555 default:
556 // TODO: warn
557 break;
558 }
559 }
560
561 if (null != row[6])
562 {
563 switch ((int)row[6])
564 {
565 case 0:
566 webApplication.ParentPaths = IIs.YesNoDefaultType.no;
567 break;
568 case 1:
569 webApplication.ParentPaths = IIs.YesNoDefaultType.yes;
570 break;
571 default:
572 // TODO: warn
573 break;
574 }
575 }
576
577 if (null != row[7])
578 {
579 switch ((string)row[7])
580 {
581 case "JScript":
582 webApplication.DefaultScript = IIs.WebApplication.DefaultScriptType.JScript;
583 break;
584 case "VBScript":
585 webApplication.DefaultScript = IIs.WebApplication.DefaultScriptType.VBScript;
586 break;
587 default:
588 // TODO: warn
589 break;
590 }
591 }
592
593 if (null != row[8])
594 {
595 webApplication.ScriptTimeout = (int)row[8];
596 }
597
598 if (null != row[9])
599 {
600 switch ((int)row[9])
601 {
602 case 0:
603 webApplication.ServerDebugging = IIs.YesNoDefaultType.no;
604 break;
605 case 1:
606 webApplication.ServerDebugging = IIs.YesNoDefaultType.yes;
607 break;
608 default:
609 // TODO: warn
610 break;
611 }
612 }
613
614 if (null != row[10])
615 {
616 switch ((int)row[10])
617 {
618 case 0:
619 webApplication.ClientDebugging = IIs.YesNoDefaultType.no;
620 break;
621 case 1:
622 webApplication.ClientDebugging = IIs.YesNoDefaultType.yes;
623 break;
624 default:
625 // TODO: warn
626 break;
627 }
628 }
629
630 if (null != row[11])
631 {
632 webApplication.WebAppPool = (string)row[11];
633 }
634
635 this.Core.IndexElement(row, webApplication);
636 }
637 }
638
639 /// <summary>
640 /// Decompile the IIsWebDirProperties table.
641 /// </summary>
642 /// <param name="table">The table to decompile.</param>
643 private void DecompileIIsWebDirPropertiesTable(Table table)
644 {
645 foreach (Row row in table.Rows)
646 {
647 IIs.WebDirProperties webDirProperties = new IIs.WebDirProperties();
648
649 webDirProperties.Id = (string)row[0];
650
651 if (null != row[1])
652 {
653 int access = (int)row[1];
654
655 if (0x1 == (access & 0x1))
656 {
657 webDirProperties.Read = IIs.YesNoType.yes;
658 }
659
660 if (0x2 == (access & 0x2))
661 {
662 webDirProperties.Write = IIs.YesNoType.yes;
663 }
664
665 if (0x4 == (access & 0x4))
666 {
667 webDirProperties.Execute = IIs.YesNoType.yes;
668 }
669
670 if (0x200 == (access & 0x200))
671 {
672 webDirProperties.Script = IIs.YesNoType.yes;
673 }
674 }
675
676 if (null != row[2])
677 {
678 int authorization = (int)row[2];
679
680 if (0x1 == (authorization & 0x1))
681 {
682 webDirProperties.AnonymousAccess = IIs.YesNoType.yes;
683 }
684 else // set one of the properties to 'no' to force the output value to be '0' if not other attributes are set
685 {
686 webDirProperties.AnonymousAccess = IIs.YesNoType.no;
687 }
688
689 if (0x2 == (authorization & 0x2))
690 {
691 webDirProperties.BasicAuthentication = IIs.YesNoType.yes;
692 }
693
694 if (0x4 == (authorization & 0x4))
695 {
696 webDirProperties.WindowsAuthentication = IIs.YesNoType.yes;
697 }
698
699 if (0x10 == (authorization & 0x10))
700 {
701 webDirProperties.DigestAuthentication = IIs.YesNoType.yes;
702 }
703
704 if (0x40 == (authorization & 0x40))
705 {
706 webDirProperties.PassportAuthentication = IIs.YesNoType.yes;
707 }
708 }
709
710 if (null != row[3])
711 {
712 webDirProperties.AnonymousUser = (string)row[3];
713 }
714
715 if (null != row[4] && 1 == (int)row[4])
716 {
717 webDirProperties.IIsControlledPassword = IIs.YesNoType.yes;
718 }
719
720 if (null != row[5])
721 {
722 switch ((int)row[5])
723 {
724 case 0:
725 webDirProperties.LogVisits = IIs.YesNoType.no;
726 break;
727 case 1:
728 webDirProperties.LogVisits = IIs.YesNoType.yes;
729 break;
730 default:
731 // TODO: warn
732 break;
733 }
734 }
735
736 if (null != row[6])
737 {
738 switch ((int)row[6])
739 {
740 case 0:
741 webDirProperties.Index = IIs.YesNoType.no;
742 break;
743 case 1:
744 webDirProperties.Index = IIs.YesNoType.yes;
745 break;
746 default:
747 // TODO: warn
748 break;
749 }
750 }
751
752 if (null != row[7])
753 {
754 webDirProperties.DefaultDocuments = (string)row[7];
755 }
756
757 if (null != row[8])
758 {
759 switch ((int)row[8])
760 {
761 case 0:
762 webDirProperties.AspDetailedError = IIs.YesNoType.no;
763 break;
764 case 1:
765 webDirProperties.AspDetailedError = IIs.YesNoType.yes;
766 break;
767 default:
768 // TODO: warn
769 break;
770 }
771 }
772
773 if (null != row[9])
774 {
775 webDirProperties.HttpExpires = (string)row[9];
776 }
777
778 if (null != row[10])
779 {
780 // force the value to be a positive number
781 webDirProperties.CacheControlMaxAge = unchecked((uint)(int)row[10]);
782 }
783
784 if (null != row[11])
785 {
786 webDirProperties.CacheControlCustom = (string)row[11];
787 }
788
789 if (null != row[12])
790 {
791 switch ((int)row[8])
792 {
793 case 0:
794 webDirProperties.ClearCustomError = IIs.YesNoType.no;
795 break;
796 case 1:
797 webDirProperties.ClearCustomError = IIs.YesNoType.yes;
798 break;
799 default:
800 // TODO: warn
801 break;
802 }
803 }
804
805 if (null != row[13])
806 {
807 int accessSSLFlags = (int)row[13];
808
809 if (0x8 == (accessSSLFlags & 0x8))
810 {
811 webDirProperties.AccessSSL = IIs.YesNoType.yes;
812 }
813
814 if (0x20 == (accessSSLFlags & 0x20))
815 {
816 webDirProperties.AccessSSLNegotiateCert = IIs.YesNoType.yes;
817 }
818
819 if (0x40 == (accessSSLFlags & 0x40))
820 {
821 webDirProperties.AccessSSLRequireCert = IIs.YesNoType.yes;
822 }
823
824 if (0x80 == (accessSSLFlags & 0x80))
825 {
826 webDirProperties.AccessSSLMapCert = IIs.YesNoType.yes;
827 }
828
829 if (0x100 == (accessSSLFlags & 0x100))
830 {
831 webDirProperties.AccessSSL128 = IIs.YesNoType.yes;
832 }
833 }
834
835 if (null != row[14])
836 {
837 webDirProperties.AuthenticationProviders = (string)row[14];
838 }
839
840 this.Core.RootElement.AddChild(webDirProperties);
841 }
842 }
843
844 /// <summary>
845 /// Decompile the IIsWebError table.
846 /// </summary>
847 /// <param name="table">The table to decompile.</param>
848 private void DecompileIIsWebErrorTable(Table table)
849 {
850 foreach (Row row in table.Rows)
851 {
852 IIs.WebError webError = new IIs.WebError();
853
854 webError.ErrorCode = (int)row[0];
855
856 webError.SubCode = (int)row[1];
857
858 // the ParentType and ParentValue columns are handled in FinalizeIIsWebErrorTable
859
860 if (null != row[4])
861 {
862 webError.File = (string)row[4];
863 }
864
865 if (null != row[5])
866 {
867 webError.URL = (string)row[5];
868 }
869
870 this.Core.IndexElement(row, webError);
871 }
872 }
873
874 /// <summary>
875 /// Decompile the IIsFilter table.
876 /// </summary>
877 /// <param name="table">The table to decompile.</param>
878 private void DecompileIIsFilterTable(Table table)
879 {
880 foreach (Row row in table.Rows)
881 {
882 IIs.WebFilter webFilter = new IIs.WebFilter();
883
884 webFilter.Id = (string)row[0];
885
886 webFilter.Name = (string)row[1];
887
888 if (null != row[3])
889 {
890 webFilter.Path = (string)row[3];
891 }
892
893 if (null != row[5])
894 {
895 webFilter.Description = (string)row[5];
896 }
897
898 webFilter.Flags = (int)row[6];
899
900 if (null != row[7])
901 {
902 switch ((int)row[7])
903 {
904 case (-1):
905 webFilter.LoadOrder = "last";
906 break;
907 case 0:
908 webFilter.LoadOrder = "first";
909 break;
910 default:
911 webFilter.LoadOrder = Convert.ToString((int)row[7], CultureInfo.InvariantCulture);
912 break;
913 }
914 }
915
916 if (null != row[4])
917 {
918 IIs.WebSite webSite = (IIs.WebSite)this.Core.GetIndexedElement("IIsWebSite", (string)row[4]);
919
920 if (null != webSite)
921 {
922 webSite.AddChild(webFilter);
923 }
924 else
925 {
926 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Web_", (string)row[4], "IIsWebSite"));
927 }
928 }
929 else // Component parent
930 {
931 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[2]);
932
933 if (null != component)
934 {
935 component.AddChild(webFilter);
936 }
937 else
938 {
939 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component"));
940 }
941 }
942 }
943 }
944
945 /// <summary>
946 /// Decompile the IIsWebLog table.
947 /// </summary>
948 /// <param name="table">The table to decompile.</param>
949 private void DecompileIIsWebLogTable(Table table)
950 {
951 foreach (Row row in table.Rows)
952 {
953 IIs.WebLog webLog = new IIs.WebLog();
954
955 webLog.Id = (string)row[0];
956
957 switch ((string)row[1])
958 {
959 case "Microsoft IIS Log File Format":
960 webLog.Type = IIs.WebLog.TypeType.IIS;
961 break;
962 case "NCSA Common Log File Format":
963 webLog.Type = IIs.WebLog.TypeType.NCSA;
964 break;
965 case "none":
966 webLog.Type = IIs.WebLog.TypeType.none;
967 break;
968 case "ODBC Logging":
969 webLog.Type = IIs.WebLog.TypeType.ODBC;
970 break;
971 case "W3C Extended Log File Format":
972 webLog.Type = IIs.WebLog.TypeType.W3C;
973 break;
974 default:
975 // TODO: warn
976 break;
977 }
978
979 this.Core.RootElement.AddChild(webLog);
980 }
981 }
982
983 /// <summary>
984 /// Decompile the IIsWebServiceExtension table.
985 /// </summary>
986 /// <param name="table">The table to decompile.</param>
987 private void DecompileIIsWebServiceExtensionTable(Table table)
988 {
989 foreach (Row row in table.Rows)
990 {
991 IIs.WebServiceExtension webServiceExtension = new IIs.WebServiceExtension();
992
993 webServiceExtension.Id = (string)row[0];
994
995 webServiceExtension.File = (string)row[2];
996
997 if (null != row[3])
998 {
999 webServiceExtension.Description = (string)row[3];
1000 }
1001
1002 if (null != row[4])
1003 {
1004 webServiceExtension.Group = (string)row[4];
1005 }
1006
1007 int attributes = (int)row[5];
1008
1009 if (0x1 == (attributes & 0x1))
1010 {
1011 webServiceExtension.Allow = IIs.YesNoType.yes;
1012 }
1013 else
1014 {
1015 webServiceExtension.Allow = IIs.YesNoType.no;
1016 }
1017
1018 if (0x2 == (attributes & 0x2))
1019 {
1020 webServiceExtension.UIDeletable = IIs.YesNoType.yes;
1021 }
1022
1023 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
1024 if (null != component)
1025 {
1026 component.AddChild(webServiceExtension);
1027 }
1028 else
1029 {
1030 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
1031 }
1032 }
1033 }
1034
1035 /// <summary>
1036 /// Decompile the IIsWebSite table.
1037 /// </summary>
1038 /// <param name="table">The table to decompile.</param>
1039 private void DecompileIIsWebSiteTable(Table table)
1040 {
1041 foreach (Row row in table.Rows)
1042 {
1043 IIs.WebSite webSite = new IIs.WebSite();
1044
1045 webSite.Id = (string)row[0];
1046
1047 if (null != row[2])
1048 {
1049 webSite.Description = (string)row[2];
1050 }
1051
1052 if (null != row[3])
1053 {
1054 webSite.ConnectionTimeout = (int)row[3];
1055 }
1056
1057 if (null != row[4])
1058 {
1059 webSite.Directory = (string)row[4];
1060 }
1061
1062 if (null != row[5])
1063 {
1064 switch ((int)row[5])
1065 {
1066 case 0:
1067 // this is the default
1068 break;
1069 case 1:
1070 webSite.StartOnInstall = IIs.YesNoType.yes;
1071 break;
1072 case 2:
1073 webSite.AutoStart = IIs.YesNoType.yes;
1074 break;
1075 default:
1076 // TODO: warn
1077 break;
1078 }
1079 }
1080
1081 if (null != row[6])
1082 {
1083 int attributes = (int)row[6];
1084
1085 if (0x2 == (attributes & 0x2))
1086 {
1087 webSite.ConfigureIfExists = IIs.YesNoType.no;
1088 }
1089 }
1090
1091 // the KeyAddress_ column is handled in FinalizeWebAddressTable
1092
1093 if (null != row[8])
1094 {
1095 webSite.DirProperties = (string)row[8];
1096 }
1097
1098 // the Application_ column is handled in FinalizeIIsWebApplicationTable
1099
1100 if (null != row[10])
1101 {
1102 if (-1 != (int)row[10])
1103 {
1104 webSite.Sequence = (int)row[10];
1105 }
1106 }
1107
1108 if (null != row[11])
1109 {
1110 webSite.WebLog = (string)row[11];
1111 }
1112
1113 if (null != row[12])
1114 {
1115 webSite.SiteId = (string)row[12];
1116 }
1117
1118 if (null != row[1])
1119 {
1120 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
1121
1122 if (null != component)
1123 {
1124 component.AddChild(webSite);
1125 }
1126 else
1127 {
1128 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
1129 }
1130 }
1131 else
1132 {
1133 this.Core.RootElement.AddChild(webSite);
1134 }
1135 this.Core.IndexElement(row, webSite);
1136 }
1137 }
1138
1139 /// <summary>
1140 /// Decompile the IIsWebVirtualDir table.
1141 /// </summary>
1142 /// <param name="table">The table to decompile.</param>
1143 private void DecompileIIsWebVirtualDirTable(Table table)
1144 {
1145 foreach (Row row in table.Rows)
1146 {
1147 IIs.WebVirtualDir webVirtualDir = new IIs.WebVirtualDir();
1148
1149 webVirtualDir.Id = (string)row[0];
1150
1151 // the Component_ and Web_ columns are handled in FinalizeIIsWebVirtualDirTable
1152
1153 webVirtualDir.Alias = (string)row[3];
1154
1155 webVirtualDir.Directory = (string)row[4];
1156
1157 if (null != row[5])
1158 {
1159 webVirtualDir.DirProperties = (string)row[5];
1160 }
1161
1162 // the Application_ column is handled in FinalizeIIsWebApplicationTable
1163
1164 this.Core.IndexElement(row, webVirtualDir);
1165 }
1166 }
1167
1168 /// <summary>
1169 /// Decompile the IIsWebSiteCertificates table.
1170 /// </summary>
1171 /// <param name="table">The table to decompile.</param>
1172 private void DecompileIIsWebSiteCertificatesTable(Table table)
1173 {
1174 foreach (Row row in table.Rows)
1175 {
1176 IIs.CertificateRef certificateRef = new IIs.CertificateRef();
1177
1178 certificateRef.Id = (string)row[1];
1179
1180 this.Core.IndexElement(row, certificateRef);
1181 }
1182 }
1183
1184 /// <summary>
1185 /// Finalize the IIsHttpHeader table.
1186 /// </summary>
1187 /// <param name="tables">The collection of all tables.</param>
1188 /// <remarks>
1189 /// The IIsHttpHeader table supports multiple parent types so no foreign key
1190 /// is declared and thus nesting must be done late.
1191 /// </remarks>
1192 private void FinalizeIIsHttpHeaderTable(TableIndexedCollection tables)
1193 {
1194 Table iisHttpHeaderTable = tables["IIsHttpHeader"];
1195
1196 if (null != iisHttpHeaderTable)
1197 {
1198 foreach (Row row in iisHttpHeaderTable.Rows)
1199 {
1200 IIs.HttpHeader httpHeader = (IIs.HttpHeader)this.Core.GetIndexedElement(row);
1201
1202 if (1 == (int)row[1])
1203 {
1204 IIs.WebVirtualDir webVirtualDir = (IIs.WebVirtualDir)this.Core.GetIndexedElement("IIsWebVirtualDir", (string)row[2]);
1205 if (null != webVirtualDir)
1206 {
1207 webVirtualDir.AddChild(httpHeader);
1208 }
1209 else
1210 {
1211 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, iisHttpHeaderTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ParentValue", (string)row[2], "IIsWebVirtualDir"));
1212 }
1213 }
1214 else if (2 == (int)row[1])
1215 {
1216 IIs.WebSite webSite = (IIs.WebSite)this.Core.GetIndexedElement("IIsWebSite", (string)row[2]);
1217 if (null != webSite)
1218 {
1219 webSite.AddChild(httpHeader);
1220 }
1221 else
1222 {
1223 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, iisHttpHeaderTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ParentValue", (string)row[2], "IIsWebSite"));
1224 }
1225 }
1226 }
1227 }
1228 }
1229
1230 /// <summary>
1231 /// Finalize the IIsMimeMap table.
1232 /// </summary>
1233 /// <param name="tables">The collection of all tables.</param>
1234 /// <remarks>
1235 /// The IIsMimeMap table supports multiple parent types so no foreign key
1236 /// is declared and thus nesting must be done late.
1237 /// </remarks>
1238 private void FinalizeIIsMimeMapTable(TableIndexedCollection tables)
1239 {
1240 Table iisMimeMapTable = tables["IIsMimeMap"];
1241
1242 if (null != iisMimeMapTable)
1243 {
1244 foreach (Row row in iisMimeMapTable.Rows)
1245 {
1246 IIs.MimeMap mimeMap = (IIs.MimeMap)this.Core.GetIndexedElement(row);
1247
1248 if (2 < (int)row[1] || 0 >= (int)row[1])
1249 {
1250 // TODO: warn about unknown parent type
1251 }
1252
1253 IIs.WebVirtualDir webVirtualDir = (IIs.WebVirtualDir)this.Core.GetIndexedElement("IIsWebVirtualDir", (string)row[2]);
1254 IIs.WebSite webSite = (IIs.WebSite)this.Core.GetIndexedElement("IIsWebSite", (string)row[2]);
1255 if (null != webVirtualDir)
1256 {
1257 webVirtualDir.AddChild(mimeMap);
1258 }
1259 else if (null != webSite)
1260 {
1261 webSite.AddChild(mimeMap);
1262 }
1263 else
1264 {
1265 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, iisMimeMapTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ParentValue", (string)row[2], "IIsWebVirtualDir"));
1266 }
1267 }
1268 }
1269 }
1270
1271 /// <summary>
1272 /// Finalize the IIsWebApplication table.
1273 /// </summary>
1274 /// <param name="tables">The collection of all tables.</param>
1275 /// <remarks>
1276 /// Since WebApplication elements may nest under a specific WebSite or
1277 /// WebVirtualDir (or just the root element), the nesting must be done late.
1278 /// </remarks>
1279 private void FinalizeIIsWebApplicationTable(TableIndexedCollection tables)
1280 {
1281 Table iisWebApplicationTable = tables["IIsWebApplication"];
1282 Table iisWebSiteTable = tables["IIsWebSite"];
1283 Table iisWebVirtualDirTable = tables["IIsWebVirtualDir"];
1284
1285 Hashtable addedWebApplications = new Hashtable();
1286
1287 if (null != iisWebSiteTable)
1288 {
1289 foreach (Row row in iisWebSiteTable.Rows)
1290 {
1291 if (null != row[9])
1292 {
1293 IIs.WebSite webSite = (IIs.WebSite)this.Core.GetIndexedElement(row);
1294
1295 IIs.WebApplication webApplication = (IIs.WebApplication)this.Core.GetIndexedElement("IIsWebApplication", (string)row[9]);
1296 if (null != webApplication)
1297 {
1298 webSite.AddChild(webApplication);
1299 addedWebApplications[webApplication] = null;
1300 }
1301 else
1302 {
1303 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, iisWebSiteTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Application_", (string)row[9], "IIsWebApplication"));
1304 }
1305 }
1306 }
1307 }
1308
1309 if (null != iisWebVirtualDirTable)
1310 {
1311 foreach (Row row in iisWebVirtualDirTable.Rows)
1312 {
1313 if (null != row[6])
1314 {
1315 IIs.WebVirtualDir webVirtualDir = (IIs.WebVirtualDir)this.Core.GetIndexedElement(row);
1316
1317 IIs.WebApplication webApplication = (IIs.WebApplication)this.Core.GetIndexedElement("IIsWebApplication", (string)row[6]);
1318 if (null != webApplication)
1319 {
1320 webVirtualDir.AddChild(webApplication);
1321 addedWebApplications[webApplication] = null;
1322 }
1323 else
1324 {
1325 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, iisWebVirtualDirTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Application_", (string)row[6], "IIsWebApplication"));
1326 }
1327 }
1328 }
1329 }
1330
1331 if (null != iisWebApplicationTable)
1332 {
1333 foreach (Row row in iisWebApplicationTable.Rows)
1334 {
1335 IIs.WebApplication webApplication = (IIs.WebApplication)this.Core.GetIndexedElement(row);
1336
1337 if (!addedWebApplications.Contains(webApplication))
1338 {
1339 this.Core.RootElement.AddChild(webApplication);
1340 }
1341 }
1342 }
1343 }
1344
1345 /// <summary>
1346 /// Finalize the IIsWebError table.
1347 /// </summary>
1348 /// <param name="tables">The collection of all tables.</param>
1349 /// <remarks>
1350 /// Since there is no foreign key relationship declared for this table
1351 /// (because it takes various parent types), it must be nested late.
1352 /// </remarks>
1353 private void FinalizeIIsWebErrorTable(TableIndexedCollection tables)
1354 {
1355 Table iisWebErrorTable = tables["IIsWebError"];
1356
1357 if (null != iisWebErrorTable)
1358 {
1359 foreach (Row row in iisWebErrorTable.Rows)
1360 {
1361 IIs.WebError webError = (IIs.WebError)this.Core.GetIndexedElement(row);
1362
1363 if (1 == (int)row[2]) // WebVirtualDir parent
1364 {
1365 IIs.WebVirtualDir webVirtualDir = (IIs.WebVirtualDir)this.Core.GetIndexedElement("IIsWebVirtualDir", (string)row[3]);
1366
1367 if (null != webVirtualDir)
1368 {
1369 webVirtualDir.AddChild(webError);
1370 }
1371 else
1372 {
1373 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, iisWebErrorTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ParentValue", (string)row[3], "IIsWebVirtualDir"));
1374 }
1375 }
1376 else if (2 == (int)row[2]) // WebSite parent
1377 {
1378 IIs.WebSite webSite = (IIs.WebSite)this.Core.GetIndexedElement("IIsWebSite", (string)row[3]);
1379
1380 if (null != webSite)
1381 {
1382 webSite.AddChild(webError);
1383 }
1384 else
1385 {
1386 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, iisWebErrorTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "ParentValue", (string)row[3], "IIsWebSite"));
1387 }
1388 }
1389 else
1390 {
1391 // TODO: warn unknown parent type
1392 }
1393 }
1394 }
1395 }
1396
1397 /// <summary>
1398 /// Finalize the IIsWebVirtualDir table.
1399 /// </summary>
1400 /// <param name="tables">The collection of all tables.</param>
1401 /// <remarks>
1402 /// WebVirtualDir elements nest under either a WebSite or component
1403 /// depending upon whether the component in the IIsWebVirtualDir row
1404 /// is the same as the one in the parent IIsWebSite row.
1405 /// </remarks>
1406 private void FinalizeIIsWebVirtualDirTable(TableIndexedCollection tables)
1407 {
1408 Table iisWebSiteTable = tables["IIsWebSite"];
1409 Table iisWebVirtualDirTable = tables["IIsWebVirtualDir"];
1410
1411 Hashtable iisWebSiteRows = new Hashtable();
1412
1413 // index the IIsWebSite rows by their primary keys
1414 if (null != iisWebSiteTable)
1415 {
1416 foreach (Row row in iisWebSiteTable.Rows)
1417 {
1418 iisWebSiteRows.Add(row[0], row);
1419 }
1420 }
1421
1422 if (null != iisWebVirtualDirTable)
1423 {
1424 foreach (Row row in iisWebVirtualDirTable.Rows)
1425 {
1426 IIs.WebVirtualDir webVirtualDir = (IIs.WebVirtualDir)this.Core.GetIndexedElement(row);
1427 Row iisWebSiteRow = (Row)iisWebSiteRows[row[2]];
1428
1429 if (null != iisWebSiteRow)
1430 {
1431 if ((string)iisWebSiteRow[1] == (string)row[1])
1432 {
1433 IIs.WebSite webSite = (IIs.WebSite)this.Core.GetIndexedElement(iisWebSiteRow);
1434
1435 webSite.AddChild(webVirtualDir);
1436 }
1437 else
1438 {
1439 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[1]);
1440
1441 if (null != component)
1442 {
1443 webVirtualDir.WebSite = (string)row[2];
1444 component.AddChild(webVirtualDir);
1445 }
1446 else
1447 {
1448 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, iisWebVirtualDirTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component"));
1449 }
1450 }
1451 }
1452 else
1453 {
1454 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, iisWebVirtualDirTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Web_", (string)row[2], "IIsWebSite"));
1455 }
1456 }
1457 }
1458 }
1459
1460 /// <summary>
1461 /// Finalize the IIsWebSiteCertificates table.
1462 /// </summary>
1463 /// <param name="tables">The collection of all tables.</param>
1464 /// <remarks>
1465 /// This table creates CertificateRef elements which nest under WebSite
1466 /// elements.
1467 /// </remarks>
1468 private void FinalizeIIsWebSiteCertificatesTable(TableIndexedCollection tables)
1469 {
1470 Table IIsWebSiteCertificatesTable = tables["IIsWebSiteCertificates"];
1471
1472 if (null != IIsWebSiteCertificatesTable)
1473 {
1474 foreach (Row row in IIsWebSiteCertificatesTable.Rows)
1475 {
1476 IIs.CertificateRef certificateRef = (IIs.CertificateRef)this.Core.GetIndexedElement(row);
1477 IIs.WebSite webSite = (IIs.WebSite)this.Core.GetIndexedElement("IIsWebSite", (string)row[0]);
1478
1479 if (null != webSite)
1480 {
1481 webSite.AddChild(certificateRef);
1482 }
1483 else
1484 {
1485 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, IIsWebSiteCertificatesTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Web_", (string)row[0], "IIsWebSite"));
1486 }
1487 }
1488 }
1489 }
1490
1491 /// <summary>
1492 /// Finalize the WebAddress table.
1493 /// </summary>
1494 /// <param name="tables">The collection of all tables.</param>
1495 /// <remarks>
1496 /// There is a circular dependency between the WebAddress and WebSite
1497 /// tables, so nesting must be handled here.
1498 /// </remarks>
1499 private void FinalizeWebAddressTable(TableIndexedCollection tables)
1500 {
1501 Table iisWebAddressTable = tables["IIsWebAddress"];
1502 Table iisWebSiteTable = tables["IIsWebSite"];
1503
1504 Hashtable addedWebAddresses = new Hashtable();
1505
1506 if (null != iisWebSiteTable)
1507 {
1508 foreach (Row row in iisWebSiteTable.Rows)
1509 {
1510 IIs.WebSite webSite = (IIs.WebSite)this.Core.GetIndexedElement(row);
1511
1512 IIs.WebAddress webAddress = (IIs.WebAddress)this.Core.GetIndexedElement("IIsWebAddress", (string)row[7]);
1513 if (null != webAddress)
1514 {
1515 webSite.AddChild(webAddress);
1516 addedWebAddresses[webAddress] = null;
1517 }
1518 else
1519 {
1520 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, iisWebSiteTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "KeyAddress_", (string)row[7], "IIsWebAddress"));
1521 }
1522 }
1523 }
1524
1525 if (null != iisWebAddressTable)
1526 {
1527 foreach (Row row in iisWebAddressTable.Rows)
1528 {
1529 IIs.WebAddress webAddress = (IIs.WebAddress)this.Core.GetIndexedElement(row);
1530
1531 if (!addedWebAddresses.Contains(webAddress))
1532 {
1533 IIs.WebSite webSite = (IIs.WebSite)this.Core.GetIndexedElement("IIsWebSite", (string)row[1]);
1534
1535 if (null != webSite)
1536 {
1537 webSite.AddChild(webAddress);
1538 }
1539 else
1540 {
1541 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, iisWebAddressTable.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Web_", (string)row[1], "IIsWebSite"));
1542 }
1543 }
1544 }
1545 }
1546 }
1547 }
1548#endif
1549}
diff --git a/src/ext/Iis/wixext/IIsExtensionData.cs b/src/ext/Iis/wixext/IIsExtensionData.cs
new file mode 100644
index 00000000..6a0e1f09
--- /dev/null
+++ b/src/ext/Iis/wixext/IIsExtensionData.cs
@@ -0,0 +1,30 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Extensibility;
7
8 /// <summary>
9 /// The WiX Toolset Internet Information Services Extension.
10 /// </summary>
11 public sealed class IIsExtensionData : BaseExtensionData
12 {
13 /// <summary>
14 /// Gets the default culture.
15 /// </summary>
16 /// <value>The default culture.</value>
17 public override string DefaultCulture => "en-US";
18
19 public override bool TryGetSymbolDefinitionByName(string name, out IntermediateSymbolDefinition symbolDefinition)
20 {
21 symbolDefinition = IisSymbolDefinitions.ByName(name);
22 return symbolDefinition != null;
23 }
24
25 public override Intermediate GetLibrary(ISymbolDefinitionCreator symbolDefinitions)
26 {
27 return Intermediate.Load(typeof(IIsExtensionData).Assembly, "WixToolset.Iis.iis.wixlib", symbolDefinitions);
28 }
29 }
30}
diff --git a/src/ext/Iis/wixext/IisErrors.cs b/src/ext/Iis/wixext/IisErrors.cs
new file mode 100644
index 00000000..2f226217
--- /dev/null
+++ b/src/ext/Iis/wixext/IisErrors.cs
@@ -0,0 +1,78 @@
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
3namespace WixToolset.Data
4{
5 using System;
6 using System.Resources;
7
8 public static class IIsErrors
9 {
10 public static Message DeprecatedBinaryChildElement(SourceLineNumber sourceLineNumbers, string elementName)
11 {
12 return Message(sourceLineNumbers, Ids.DeprecatedBinaryChildElement, "The {0} element contains a deprecated child Binary element. Please move the Binary element under a Fragment, Module, or Product element and set the {0}/@BinaryKey attribute to the value of the Binary/@Id attribute.", elementName);
13 }
14
15 public static Message IllegalAttributeWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName)
16 {
17 return Message(sourceLineNumbers, Ids.IllegalAttributeWithoutComponent, "The {0}/@{1} attribute cannot be specified unless the element has a Component as an ancestor. A {0} that does not have a Component ancestor is not installed.", elementName, attributeName);
18 }
19
20 public static Message IllegalCharacterInAttributeValue(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string value, Char illegalCharacter)
21 {
22 return Message(sourceLineNumbers, Ids.IllegalCharacterInAttributeValue, "The {0}/@{1} attribute's value, '{2}', is invalid. It cannot contain the character '{3}'.", elementName, attributeName, value, illegalCharacter);
23 }
24
25 public static Message IllegalElementWithoutComponent(SourceLineNumber sourceLineNumbers, string elementName)
26 {
27 return Message(sourceLineNumbers, Ids.IllegalElementWithoutComponent, "The {0} element cannot be specified unless the element has a Component as an ancestor. A {0} that does not have a Component ancestor is not installed.", elementName);
28 }
29
30 public static Message MimeMapExtensionMissingPeriod(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string attributeValue)
31 {
32 return Message(sourceLineNumbers, Ids.MimeMapExtensionMissingPeriod, "The {0}/@{1} attribute's value, '{2}', is not a valid mime map extension. It must begin with a period.", elementName, attributeName, attributeValue);
33 }
34
35 public static Message OneOfAttributesRequiredUnderComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName1, string attributeName2, string attributeName3, string attributeName4)
36 {
37 return Message(sourceLineNumbers, Ids.OneOfAttributesRequiredUnderComponent, "When nested under a Component, the {0} element must have one of the following attributes specified: {1}, {2}, {3} or {4}.", elementName, attributeName1, attributeName2, attributeName3, attributeName4);
38 }
39
40 public static Message RequiredAttributeUnderComponent(SourceLineNumber sourceLineNumbers, string elementName, string attributeName)
41 {
42 return Message(sourceLineNumbers, Ids.RequiredAttributeUnderComponent, "The {0}/@{1} attribute must be specified when the element has a Component as an ancestor.", elementName, attributeName);
43 }
44
45 public static Message WebApplicationAlreadySpecified(SourceLineNumber sourceLineNumbers, string elementName)
46 {
47 return Message(sourceLineNumbers, Ids.WebApplicationAlreadySpecified, "The {0} element can have at most a single WebApplication specified. This can be either through the WebApplication attribute, or through a nested WebApplication element, but not both.", elementName);
48 }
49
50 public static Message WebSiteAttributeUnderWebSite(SourceLineNumber sourceLineNumbers, string elementName)
51 {
52 return Message(sourceLineNumbers, Ids.WebSiteAttributeUnderWebSite, "The {0}/@WebSite attribute cannot be specified when the {0} element is nested under a WebSite element.", elementName);
53 }
54
55 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
56 {
57 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args);
58 }
59
60 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)
61 {
62 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, resourceManager, resourceName, args);
63 }
64
65 public enum Ids
66 {
67 MimeMapExtensionMissingPeriod = 5150,
68 IllegalAttributeWithoutComponent = 5151,
69 IllegalElementWithoutComponent = 5152,
70 OneOfAttributesRequiredUnderComponent = 5153,
71 WebSiteAttributeUnderWebSite = 5154,
72 WebApplicationAlreadySpecified = 5155,
73 IllegalCharacterInAttributeValue = 5156,
74 DeprecatedBinaryChildElement = 5157,
75 RequiredAttributeUnderComponent = 5161,
76 }
77 }
78}
diff --git a/src/ext/Iis/wixext/IisExtensionFactory.cs b/src/ext/Iis/wixext/IisExtensionFactory.cs
new file mode 100644
index 00000000..2fb7e682
--- /dev/null
+++ b/src/ext/Iis/wixext/IisExtensionFactory.cs
@@ -0,0 +1,18 @@
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
3namespace WixToolset.Iis
4{
5 using System;
6 using System.Collections.Generic;
7 using WixToolset.Extensibility;
8
9 public class IisExtensionFactory : BaseExtensionFactory
10 {
11 protected override IReadOnlyCollection<Type> ExtensionTypes => new[]
12 {
13 typeof(IIsCompiler),
14 typeof(IIsExtensionData),
15 typeof(IisWindowsInstallerBackendBinderExtension),
16 };
17 }
18}
diff --git a/src/ext/Iis/wixext/IisTableDefinitions.cs b/src/ext/Iis/wixext/IisTableDefinitions.cs
new file mode 100644
index 00000000..f513152e
--- /dev/null
+++ b/src/ext/Iis/wixext/IisTableDefinitions.cs
@@ -0,0 +1,324 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data.WindowsInstaller;
6
7 public static class IisTableDefinitions
8 {
9 public static readonly TableDefinition Certificate = new TableDefinition(
10 "Certificate",
11 IisSymbolDefinitions.Certificate,
12 new[]
13 {
14 new ColumnDefinition("Certificate", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyColumn: 1, description: "Identifier for the certificate in the package.", modularizeType: ColumnModularizeType.Column),
15 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, description: "Foreign key into the Component table used to determine install state", modularizeType: ColumnModularizeType.Column),
16 new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Name to be used for the Certificate."),
17 new ColumnDefinition("StoreLocation", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 1, maxValue: 2, description: "Location of the target certificate store (CurrentUser == 1, LocalMachine == 2)"),
18 new ColumnDefinition("StoreName", ColumnType.String, 64, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Name of the target certificate store"),
19 new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 2147483647, description: "Attributes of the certificate"),
20 new ColumnDefinition("Binary_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "Binary", keyColumn: 1, description: "Identifier to Binary table containing certificate.", modularizeType: ColumnModularizeType.Column),
21 new ColumnDefinition("CertificatePath", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Property to path of certificate.", modularizeType: ColumnModularizeType.Property),
22 new ColumnDefinition("PFXPassword", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Hidden property to a pfx password", modularizeType: ColumnModularizeType.Property),
23 },
24 symbolIdIsPrimaryKey: true
25 );
26
27 public static readonly TableDefinition CertificateHash = new TableDefinition(
28 "CertificateHash",
29 IisSymbolDefinitions.CertificateHash,
30 new[]
31 {
32 new ColumnDefinition("Certificate_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyColumn: 1, description: "Foreign key to certificate in Certificate table.", modularizeType: ColumnModularizeType.Column),
33 new ColumnDefinition("Hash", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Text, description: "Base64 encoded SHA1 hash of certificate populated at run-time."),
34 },
35 symbolIdIsPrimaryKey: false
36 );
37
38 public static readonly TableDefinition IIsWebSiteCertificates = new TableDefinition(
39 "IIsWebSiteCertificates",
40 IisSymbolDefinitions.IIsWebSiteCertificates,
41 new[]
42 {
43 new ColumnDefinition("Web_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "IIsWebSite", keyColumn: 1, description: "The index into the IIsWebSite table.", modularizeType: ColumnModularizeType.Column),
44 new ColumnDefinition("Certificate_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Text, keyTable: "Certificate", keyColumn: 1, description: "The index into the Certificate table.", modularizeType: ColumnModularizeType.Column),
45 },
46 symbolIdIsPrimaryKey: false
47 );
48
49 public static readonly TableDefinition IIsAppPool = new TableDefinition(
50 "IIsAppPool",
51 IisSymbolDefinitions.IIsAppPool,
52 new[]
53 {
54 new ColumnDefinition("AppPool", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token for apppool", modularizeType: ColumnModularizeType.Column),
55 new ColumnDefinition("Name", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Name to be used for the IIs AppPool.", modularizeType: ColumnModularizeType.Property),
56 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key referencing Component that controls the app pool", modularizeType: ColumnModularizeType.Column),
57 new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, description: "Attributes of the AppPool"),
58 new ColumnDefinition("User_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "User", keyColumn: 1, description: "User account to run the app pool as", modularizeType: ColumnModularizeType.Column),
59 new ColumnDefinition("RecycleMinutes", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Number of minutes between recycling app pool"),
60 new ColumnDefinition("RecycleRequests", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Number of requests between recycling app pool"),
61 new ColumnDefinition("RecycleTimes", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Times to recycle app pool (comma delimited - i.e. 1:45,13:30)"),
62 new ColumnDefinition("IdleTimeout", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Amount of idle time before shutting down"),
63 new ColumnDefinition("QueueLimit", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Reject requests after queue gets how large"),
64 new ColumnDefinition("CPUMon", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "CPUMon is a comma delimeted list of the following format: <percent CPU usage>,<refress minutes>,<Action>. The values for Action are 1 (Shutdown) and 0 (No Action)."),
65 new ColumnDefinition("MaxProc", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Maximum number of processes to use"),
66 new ColumnDefinition("VirtualMemory", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Amount of virtual memory (in KB) that a worker process can use before the worker process recycles. The maximum value supported for this field is 4,294,967 KB."),
67 new ColumnDefinition("PrivateMemory", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Amount of private memory (in KB) that a worker process can use before the worker process recycles. The maximum value supported for this field is 4,294,967 KB."),
68 new ColumnDefinition("ManagedRuntimeVersion", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Specifies the .NET Framework version to be used by the application pool."),
69 new ColumnDefinition("ManagedPipelineMode", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Specifies the request-processing mode that is used to process requests for managed content."),
70 },
71 symbolIdIsPrimaryKey: true
72 );
73
74 public static readonly TableDefinition IIsMimeMap = new TableDefinition(
75 "IIsMimeMap",
76 IisSymbolDefinitions.IIsMimeMap,
77 new[]
78 {
79 new ColumnDefinition("MimeMap", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token for Mime Map definitions", modularizeType: ColumnModularizeType.Column),
80 new ColumnDefinition("ParentType", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, possibilities: "1;2", description: "Type of parent: 1=vdir 2=website"),
81 new ColumnDefinition("ParentValue", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, description: "Name of the parent value.", modularizeType: ColumnModularizeType.Column),
82 new ColumnDefinition("MimeType", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Mime-type covered by the MimeMap."),
83 new ColumnDefinition("Extension", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Extension covered by the MimeMap."),
84 },
85 symbolIdIsPrimaryKey: true
86 );
87
88 public static readonly TableDefinition IIsProperty = new TableDefinition(
89 "IIsProperty",
90 IisSymbolDefinitions.IIsProperty,
91 new[]
92 {
93 new ColumnDefinition("Property", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Unique name of the IIsProperty"),
94 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Component that the property is linked to", modularizeType: ColumnModularizeType.Column),
95 new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, description: "Attributes of the IIsProperty (unused)"),
96 new ColumnDefinition("Value", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Value of the IIsProperty"),
97 },
98 symbolIdIsPrimaryKey: true
99 );
100
101 public static readonly TableDefinition IIsWebDirProperties = new TableDefinition(
102 "IIsWebDirProperties",
103 IisSymbolDefinitions.IIsWebDirProperties,
104 new[]
105 {
106 new ColumnDefinition("DirProperties", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token for Web Properties", modularizeType: ColumnModularizeType.Column),
107 new ColumnDefinition("Access", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Access rights to the web server"),
108 new ColumnDefinition("Authorization", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Authorization policy to web server (anonymous access, NTLM, etc)"),
109 new ColumnDefinition("AnonymousUser_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "User", keyColumn: 1, description: "Foreign key, User used to log into database", modularizeType: ColumnModularizeType.Column),
110 new ColumnDefinition("IIsControlledPassword", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1", description: "Specifies whether IIs is allowed to set the AnonymousUser_ password"),
111 new ColumnDefinition("LogVisits", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1", description: "Specifies whether IIs tracks all access to the directory"),
112 new ColumnDefinition("Index", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1", description: "Specifies whether IIs searches the directory"),
113 new ColumnDefinition("DefaultDoc", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Text, description: "Comma delimited list of file names to act as a default document"),
114 new ColumnDefinition("AspDetailedError", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1", description: "Specifies whether detailed ASP errors are sent to browser"),
115 new ColumnDefinition("HttpExpires", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Text, description: "Value to set the HttpExpires attribute to for a Web Dir in the metabase"),
116 new ColumnDefinition("CacheControlMaxAge", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Integer value specifying the cache control maximum age value."),
117 new ColumnDefinition("CacheControlCustom", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Text, description: "Custom HTTP 1.1 cache control directives."),
118 new ColumnDefinition("NoCustomError", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1", description: "Specifies whether IIs will return custom errors for this directory."),
119 new ColumnDefinition("AccessSSLFlags", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Specifies AccessSSLFlags IIS metabase property."),
120 new ColumnDefinition("AuthenticationProviders", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Text, description: "Comma delimited list, in order of precedence, of Windows authentication providers that IIS will attempt to use: NTLM, Kerberos, Negotiate, and others."),
121 },
122 symbolIdIsPrimaryKey: true
123 );
124
125 public static readonly TableDefinition IIsWebAddress = new TableDefinition(
126 "IIsWebAddress",
127 IisSymbolDefinitions.IIsWebAddress,
128 new[]
129 {
130 new ColumnDefinition("Address", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
131 new ColumnDefinition("Web_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "IIsWebSite", keyColumn: 1, description: "Foreign key referencing Web that uses the address.", modularizeType: ColumnModularizeType.Column),
132 new ColumnDefinition("IP", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Text, description: "String representing IP address (#.#.#.#) or NT machine name (fooserver)", modularizeType: ColumnModularizeType.Property),
133 new ColumnDefinition("Port", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Port web site listens on", modularizeType: ColumnModularizeType.Property),
134 new ColumnDefinition("Header", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Text, description: "Special header information for the web site"),
135 new ColumnDefinition("Secure", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1", description: "Specifies whether SSL is used to communicate with web site"),
136 },
137 symbolIdIsPrimaryKey: true
138 );
139
140 public static readonly TableDefinition IIsWebSite = new TableDefinition(
141 "IIsWebSite",
142 IisSymbolDefinitions.IIsWebSite,
143 new[]
144 {
145 new ColumnDefinition("Web", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
146 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key referencing Component that controls the web site", modularizeType: ColumnModularizeType.Column),
147 new ColumnDefinition("Description", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Description displayed in IIS MMC applet"),
148 new ColumnDefinition("ConnectionTimeout", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Time connection is maintained without activity (in seconds)"),
149 new ColumnDefinition("Directory_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "Directory", keyColumn: 1, description: "Foreign key referencing directory that the web site points at", modularizeType: ColumnModularizeType.Column),
150 new ColumnDefinition("State", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1;2", description: "Sets intial state of web site"),
151 new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "2", description: "Control the install behavior of web site"),
152 new ColumnDefinition("KeyAddress_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "IIsWebAddress", keyColumn: 1, description: "Foreign key referencing primary address for the web site", modularizeType: ColumnModularizeType.Column),
153 new ColumnDefinition("DirProperties_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "IIsWebDirProperties", keyColumn: 1, description: "Foreign key referencing possible security information for the web site", modularizeType: ColumnModularizeType.Column),
154 new ColumnDefinition("Application_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "IIsWebApplication", keyColumn: 1, description: "Foreign key referencing possible ASP application for the web site.", modularizeType: ColumnModularizeType.Column),
155 new ColumnDefinition("Sequence", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Allows ordering of web site install"),
156 new ColumnDefinition("Log_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Unknown, keyTable: "IIsWebLog", keyColumn: 1, description: "Foreign key reference to IIsWebLog data", modularizeType: ColumnModularizeType.Column),
157 new ColumnDefinition("Id", ColumnType.String, 74, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Optional number or formatted value that resolves to number that acts as the WebSite Id."),
158 },
159 symbolIdIsPrimaryKey: true
160 );
161
162 public static readonly TableDefinition IIsWebApplication = new TableDefinition(
163 "IIsWebApplication",
164 IisSymbolDefinitions.IIsWebApplication,
165 new[]
166 {
167 new ColumnDefinition("Application", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token for ASP Application", modularizeType: ColumnModularizeType.Column),
168 new ColumnDefinition("Name", ColumnType.Localized, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Name of application in IIS MMC applet", modularizeType: ColumnModularizeType.Property),
169 new ColumnDefinition("Isolation", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, possibilities: "0;1;2", description: "Isolation level for ASP Application: 0 == Low, 2 == Medium, 1 == High"),
170 new ColumnDefinition("AllowSessions", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1", description: "Specifies whether application may maintain session state"),
171 new ColumnDefinition("SessionTimeout", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Time session state is maintained without user interaction"),
172 new ColumnDefinition("Buffer", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1", description: "Specifies whether application buffers its output"),
173 new ColumnDefinition("ParentPaths", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1", description: "What is this for anyway?"),
174 new ColumnDefinition("DefaultScript", ColumnType.String, 26, primaryKey: false, nullable: true, ColumnCategory.Text, possibilities: "VBScript;JScript", description: "Default scripting language for ASP applications"),
175 new ColumnDefinition("ScriptTimeout", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Time ASP application page is permitted to process"),
176 new ColumnDefinition("ServerDebugging", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1", description: "Specifies whether to allow ASP server-side script debugging"),
177 new ColumnDefinition("ClientDebugging", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "0;1", description: "Specifies whether to allow ASP client-side script debugging"),
178 new ColumnDefinition("AppPool_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "IIsAppPool", keyColumn: 1, description: "App Pool this application should run under", modularizeType: ColumnModularizeType.Column),
179 },
180 symbolIdIsPrimaryKey: true
181 );
182
183 public static readonly TableDefinition IIsWebApplicationExtension = new TableDefinition(
184 "IIsWebApplicationExtension",
185 IisSymbolDefinitions.IIsWebApplicationExtension,
186 new[]
187 {
188 new ColumnDefinition("Application_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "IIsWebApplication", keyColumn: 1, description: "Foreign key referencing possible ASP application for the web site", modularizeType: ColumnModularizeType.Column),
189 new ColumnDefinition("Extension", ColumnType.String, 255, primaryKey: true, nullable: true, ColumnCategory.Text, description: "Primary key, Extension that should be registered for this ASP application"),
190 new ColumnDefinition("Verbs", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Text, description: "Comma delimited list of HTTP verbs the extension should be registered with"),
191 new ColumnDefinition("Executable", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Path to extension (usually file property: [#file])", modularizeType: ColumnModularizeType.Property),
192 new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, possibilities: "1;4;5", description: "Attributes for extension: 1 == Script, 4 == Check Path Info"),
193 },
194 symbolIdIsPrimaryKey: false
195 );
196
197 public static readonly TableDefinition IIsFilter = new TableDefinition(
198 "IIsFilter",
199 IisSymbolDefinitions.IIsFilter,
200 new[]
201 {
202 new ColumnDefinition("Filter", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
203 new ColumnDefinition("Name", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Unknown, description: "Name of the ISAPI Filter in IIS"),
204 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key referencing Component that controls the filter", modularizeType: ColumnModularizeType.Column),
205 new ColumnDefinition("Path", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Path to filter (usually file property: [#file])", modularizeType: ColumnModularizeType.Property),
206 new ColumnDefinition("Web_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "IIsWebSite", keyColumn: 1, description: "Foreign key referencing web site that loads the filter (NULL == global filter", modularizeType: ColumnModularizeType.Column),
207 new ColumnDefinition("Description", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Description displayed in IIS MMC applet"),
208 new ColumnDefinition("Flags", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 2147483647, description: "What do all these numbers mean?"),
209 new ColumnDefinition("LoadOrder", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "-1 == last in order, 0 == first in order, # == place in order"),
210 },
211 symbolIdIsPrimaryKey: true
212 );
213
214 public static readonly TableDefinition IIsWebDir = new TableDefinition(
215 "IIsWebDir",
216 IisSymbolDefinitions.IIsWebDir,
217 new[]
218 {
219 new ColumnDefinition("WebDir", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
220 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key referencing Component that controls the virtual directory", modularizeType: ColumnModularizeType.Column),
221 new ColumnDefinition("Web_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "IIsWebSite", keyColumn: 1, description: "Foreign key referencing web site that controls the virtual directory", modularizeType: ColumnModularizeType.Column),
222 new ColumnDefinition("Path", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Name of web directory displayed in IIS MMC applet", modularizeType: ColumnModularizeType.Property),
223 new ColumnDefinition("DirProperties_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "IIsWebDirProperties", keyColumn: 1, description: "Foreign key referencing possible security information for the virtual directory", modularizeType: ColumnModularizeType.Column),
224 new ColumnDefinition("Application_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "IIsWebApplication", keyColumn: 1, description: "Foreign key referencing possible ASP application for the virtual directory. This column is currently unused, but maintained for compatibility reasons.", modularizeType: ColumnModularizeType.Column),
225 },
226 symbolIdIsPrimaryKey: true
227 );
228
229 public static readonly TableDefinition IIsWebError = new TableDefinition(
230 "IIsWebError",
231 IisSymbolDefinitions.IIsWebError,
232 new[]
233 {
234 new ColumnDefinition("ErrorCode", ColumnType.Number, 2, primaryKey: true, nullable: false, ColumnCategory.Unknown, minValue: 400, maxValue: 599, description: "HTTP status code indicating error."),
235 new ColumnDefinition("SubCode", ColumnType.Number, 4, primaryKey: true, nullable: false, ColumnCategory.Unknown, description: "HTTP sub-status code indicating error."),
236 new ColumnDefinition("ParentType", ColumnType.Number, 2, primaryKey: true, nullable: false, ColumnCategory.Unknown, possibilities: "1;2", description: "Type of parent: 1=vdir, 2=web"),
237 new ColumnDefinition("ParentValue", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Name of the parent value.", modularizeType: ColumnModularizeType.Column),
238 new ColumnDefinition("File", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Path to file for this custom error (usually file property: [#file]). Must be null if URL is not null."),
239 new ColumnDefinition("URL", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "URL for this custom error. Must be null if File is not null."),
240 },
241 symbolIdIsPrimaryKey: false
242 );
243
244 public static readonly TableDefinition IIsHttpHeader = new TableDefinition(
245 "IIsHttpHeader",
246 IisSymbolDefinitions.IIsHttpHeader,
247 new[]
248 {
249 new ColumnDefinition("HttpHeader", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
250 new ColumnDefinition("ParentType", ColumnType.Number, 2, primaryKey: true, nullable: false, ColumnCategory.Unknown, possibilities: "1;2", description: "Type of parent: 1=vdir, 2=web"),
251 new ColumnDefinition("ParentValue", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Name of the parent value.", modularizeType: ColumnModularizeType.Column),
252 new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Name of the HTTP Header"),
253 new ColumnDefinition("Value", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "URL for this custom error. Must be null if File is not null."),
254 new ColumnDefinition("Attributes", ColumnType.Number, 2, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 0, description: "Attributes for HTTP Header: none"),
255 new ColumnDefinition("Sequence", ColumnType.Number, 2, primaryKey: false, nullable: true, ColumnCategory.Unknown, description: "Order to add the HTTP Headers."),
256 },
257 symbolIdIsPrimaryKey: false
258 );
259
260 public static readonly TableDefinition IIsWebServiceExtension = new TableDefinition(
261 "IIsWebServiceExtension",
262 IisSymbolDefinitions.IIsWebServiceExtension,
263 new[]
264 {
265 new ColumnDefinition("WebServiceExtension", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
266 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key referencing Component that controls the WebServiceExtension handler", modularizeType: ColumnModularizeType.Column),
267 new ColumnDefinition("File", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Path to handler (usually file property: [#file])", modularizeType: ColumnModularizeType.Property),
268 new ColumnDefinition("Description", ColumnType.Localized, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Description displayed in WebServiceExtension Wizard", modularizeType: ColumnModularizeType.Property),
269 new ColumnDefinition("Group", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "String used to identify groups of extensions.", modularizeType: ColumnModularizeType.Property),
270 new ColumnDefinition("Attributes", ColumnType.Number, 1, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 3, description: "Attributes for WebServiceExtension: 1 = Allow, 2 = UIDeletable"),
271 },
272 symbolIdIsPrimaryKey: true
273 );
274
275 public static readonly TableDefinition IIsWebVirtualDir = new TableDefinition(
276 "IIsWebVirtualDir",
277 IisSymbolDefinitions.IIsWebVirtualDir,
278 new[]
279 {
280 new ColumnDefinition("VirtualDir", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
281 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key referencing Component that controls the virtual directory", modularizeType: ColumnModularizeType.Column),
282 new ColumnDefinition("Web_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "IIsWebSite", keyColumn: 1, description: "Foreign key referencing web site that controls the virtual directory", modularizeType: ColumnModularizeType.Column),
283 new ColumnDefinition("Alias", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Name of virtual directory displayed in IIS MMC applet", modularizeType: ColumnModularizeType.Property),
284 new ColumnDefinition("Directory_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Directory", keyColumn: 1, description: "Foreign key referencing directory that the virtual directory points at", modularizeType: ColumnModularizeType.Column),
285 new ColumnDefinition("DirProperties_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "IIsWebDirProperties", keyColumn: 1, description: "Foreign key referencing possible security information for the virtual directory", modularizeType: ColumnModularizeType.Column),
286 new ColumnDefinition("Application_", ColumnType.String, 72, primaryKey: false, nullable: true, ColumnCategory.Identifier, keyTable: "IIsWebApplication", keyColumn: 1, description: "Foreign key referencing possible ASP application for the virtual directory", modularizeType: ColumnModularizeType.Column),
287 },
288 symbolIdIsPrimaryKey: true
289 );
290
291 public static readonly TableDefinition IIsWebLog = new TableDefinition(
292 "IIsWebLog",
293 IisSymbolDefinitions.IIsWebLog,
294 new[]
295 {
296 new ColumnDefinition("Log", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column),
297 new ColumnDefinition("Format", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Text, description: "Type of log format"),
298 },
299 symbolIdIsPrimaryKey: true
300 );
301
302 public static readonly TableDefinition[] All = new[]
303 {
304 Certificate,
305 CertificateHash,
306 IIsWebSiteCertificates,
307 IIsAppPool,
308 IIsMimeMap,
309 IIsProperty,
310 IIsWebDirProperties,
311 IIsWebAddress,
312 IIsWebSite,
313 IIsWebApplication,
314 IIsWebApplicationExtension,
315 IIsFilter,
316 IIsWebDir,
317 IIsWebError,
318 IIsHttpHeader,
319 IIsWebServiceExtension,
320 IIsWebVirtualDir,
321 IIsWebLog,
322 };
323 }
324}
diff --git a/src/ext/Iis/wixext/IisWindowsInstallerBackendBinderExtension.cs b/src/ext/Iis/wixext/IisWindowsInstallerBackendBinderExtension.cs
new file mode 100644
index 00000000..a61cbad6
--- /dev/null
+++ b/src/ext/Iis/wixext/IisWindowsInstallerBackendBinderExtension.cs
@@ -0,0 +1,13 @@
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
3namespace WixToolset.Iis
4{
5 using System.Collections.Generic;
6 using WixToolset.Data.WindowsInstaller;
7 using WixToolset.Extensibility;
8
9 public class IisWindowsInstallerBackendBinderExtension : BaseWindowsInstallerBackendBinderExtension
10 {
11 public override IReadOnlyCollection<TableDefinition> TableDefinitions => IisTableDefinitions.All;
12 }
13}
diff --git a/src/ext/Iis/wixext/Symbols/CertificateHashSymbol.cs b/src/ext/Iis/wixext/Symbols/CertificateHashSymbol.cs
new file mode 100644
index 00000000..866d474c
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/CertificateHashSymbol.cs
@@ -0,0 +1,55 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition CertificateHash = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.CertificateHash.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(CertificateHashSymbolFields.CertificateRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(CertificateHashSymbolFields.Hash), IntermediateFieldType.String),
16 },
17 typeof(CertificateHashSymbol));
18 }
19}
20
21namespace WixToolset.Iis.Symbols
22{
23 using WixToolset.Data;
24
25 public enum CertificateHashSymbolFields
26 {
27 CertificateRef,
28 Hash,
29 }
30
31 public class CertificateHashSymbol : IntermediateSymbol
32 {
33 public CertificateHashSymbol() : base(IisSymbolDefinitions.CertificateHash, null, null)
34 {
35 }
36
37 public CertificateHashSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.CertificateHash, sourceLineNumber, id)
38 {
39 }
40
41 public IntermediateField this[CertificateHashSymbolFields index] => this.Fields[(int)index];
42
43 public string CertificateRef
44 {
45 get => this.Fields[(int)CertificateHashSymbolFields.CertificateRef].AsString();
46 set => this.Set((int)CertificateHashSymbolFields.CertificateRef, value);
47 }
48
49 public string Hash
50 {
51 get => this.Fields[(int)CertificateHashSymbolFields.Hash].AsString();
52 set => this.Set((int)CertificateHashSymbolFields.Hash, value);
53 }
54 }
55} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/CertificateSymbol.cs b/src/ext/Iis/wixext/Symbols/CertificateSymbol.cs
new file mode 100644
index 00000000..b80b6ba4
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/CertificateSymbol.cs
@@ -0,0 +1,103 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition Certificate = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.Certificate.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(CertificateSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(CertificateSymbolFields.Name), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(CertificateSymbolFields.StoreLocation), IntermediateFieldType.Number),
17 new IntermediateFieldDefinition(nameof(CertificateSymbolFields.StoreName), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(CertificateSymbolFields.Attributes), IntermediateFieldType.Number),
19 new IntermediateFieldDefinition(nameof(CertificateSymbolFields.BinaryRef), IntermediateFieldType.String),
20 new IntermediateFieldDefinition(nameof(CertificateSymbolFields.CertificatePath), IntermediateFieldType.String),
21 new IntermediateFieldDefinition(nameof(CertificateSymbolFields.PFXPassword), IntermediateFieldType.String),
22 },
23 typeof(CertificateSymbol));
24 }
25}
26
27namespace WixToolset.Iis.Symbols
28{
29 using WixToolset.Data;
30
31 public enum CertificateSymbolFields
32 {
33 ComponentRef,
34 Name,
35 StoreLocation,
36 StoreName,
37 Attributes,
38 BinaryRef,
39 CertificatePath,
40 PFXPassword,
41 }
42
43 public class CertificateSymbol : IntermediateSymbol
44 {
45 public CertificateSymbol() : base(IisSymbolDefinitions.Certificate, null, null)
46 {
47 }
48
49 public CertificateSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.Certificate, sourceLineNumber, id)
50 {
51 }
52
53 public IntermediateField this[CertificateSymbolFields index] => this.Fields[(int)index];
54
55 public string ComponentRef
56 {
57 get => this.Fields[(int)CertificateSymbolFields.ComponentRef].AsString();
58 set => this.Set((int)CertificateSymbolFields.ComponentRef, value);
59 }
60
61 public string Name
62 {
63 get => this.Fields[(int)CertificateSymbolFields.Name].AsString();
64 set => this.Set((int)CertificateSymbolFields.Name, value);
65 }
66
67 public int StoreLocation
68 {
69 get => this.Fields[(int)CertificateSymbolFields.StoreLocation].AsNumber();
70 set => this.Set((int)CertificateSymbolFields.StoreLocation, value);
71 }
72
73 public string StoreName
74 {
75 get => this.Fields[(int)CertificateSymbolFields.StoreName].AsString();
76 set => this.Set((int)CertificateSymbolFields.StoreName, value);
77 }
78
79 public int Attributes
80 {
81 get => this.Fields[(int)CertificateSymbolFields.Attributes].AsNumber();
82 set => this.Set((int)CertificateSymbolFields.Attributes, value);
83 }
84
85 public string BinaryRef
86 {
87 get => this.Fields[(int)CertificateSymbolFields.BinaryRef].AsString();
88 set => this.Set((int)CertificateSymbolFields.BinaryRef, value);
89 }
90
91 public string CertificatePath
92 {
93 get => this.Fields[(int)CertificateSymbolFields.CertificatePath].AsString();
94 set => this.Set((int)CertificateSymbolFields.CertificatePath, value);
95 }
96
97 public string PFXPassword
98 {
99 get => this.Fields[(int)CertificateSymbolFields.PFXPassword].AsString();
100 set => this.Set((int)CertificateSymbolFields.PFXPassword, value);
101 }
102 }
103} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsAppPoolSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsAppPoolSymbol.cs
new file mode 100644
index 00000000..a6fab136
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsAppPoolSymbol.cs
@@ -0,0 +1,159 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsAppPool = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsAppPool.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.Name), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.ComponentRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.Attributes), IntermediateFieldType.Number),
17 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.UserRef), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.RecycleMinutes), IntermediateFieldType.Number),
19 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.RecycleRequests), IntermediateFieldType.Number),
20 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.RecycleTimes), IntermediateFieldType.String),
21 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.IdleTimeout), IntermediateFieldType.Number),
22 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.QueueLimit), IntermediateFieldType.Number),
23 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.CPUMon), IntermediateFieldType.String),
24 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.MaxProc), IntermediateFieldType.Number),
25 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.VirtualMemory), IntermediateFieldType.Number),
26 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.PrivateMemory), IntermediateFieldType.Number),
27 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.ManagedRuntimeVersion), IntermediateFieldType.String),
28 new IntermediateFieldDefinition(nameof(IIsAppPoolSymbolFields.ManagedPipelineMode), IntermediateFieldType.String),
29 },
30 typeof(IIsAppPoolSymbol));
31 }
32}
33
34namespace WixToolset.Iis.Symbols
35{
36 using WixToolset.Data;
37
38 public enum IIsAppPoolSymbolFields
39 {
40 Name,
41 ComponentRef,
42 Attributes,
43 UserRef,
44 RecycleMinutes,
45 RecycleRequests,
46 RecycleTimes,
47 IdleTimeout,
48 QueueLimit,
49 CPUMon,
50 MaxProc,
51 VirtualMemory,
52 PrivateMemory,
53 ManagedRuntimeVersion,
54 ManagedPipelineMode,
55 }
56
57 public class IIsAppPoolSymbol : IntermediateSymbol
58 {
59 public IIsAppPoolSymbol() : base(IisSymbolDefinitions.IIsAppPool, null, null)
60 {
61 }
62
63 public IIsAppPoolSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsAppPool, sourceLineNumber, id)
64 {
65 }
66
67 public IntermediateField this[IIsAppPoolSymbolFields index] => this.Fields[(int)index];
68
69 public string Name
70 {
71 get => this.Fields[(int)IIsAppPoolSymbolFields.Name].AsString();
72 set => this.Set((int)IIsAppPoolSymbolFields.Name, value);
73 }
74
75 public string ComponentRef
76 {
77 get => this.Fields[(int)IIsAppPoolSymbolFields.ComponentRef].AsString();
78 set => this.Set((int)IIsAppPoolSymbolFields.ComponentRef, value);
79 }
80
81 public int Attributes
82 {
83 get => this.Fields[(int)IIsAppPoolSymbolFields.Attributes].AsNumber();
84 set => this.Set((int)IIsAppPoolSymbolFields.Attributes, value);
85 }
86
87 public string UserRef
88 {
89 get => this.Fields[(int)IIsAppPoolSymbolFields.UserRef].AsString();
90 set => this.Set((int)IIsAppPoolSymbolFields.UserRef, value);
91 }
92
93 public int? RecycleMinutes
94 {
95 get => this.Fields[(int)IIsAppPoolSymbolFields.RecycleMinutes].AsNullableNumber();
96 set => this.Set((int)IIsAppPoolSymbolFields.RecycleMinutes, value);
97 }
98
99 public int? RecycleRequests
100 {
101 get => this.Fields[(int)IIsAppPoolSymbolFields.RecycleRequests].AsNullableNumber();
102 set => this.Set((int)IIsAppPoolSymbolFields.RecycleRequests, value);
103 }
104
105 public string RecycleTimes
106 {
107 get => this.Fields[(int)IIsAppPoolSymbolFields.RecycleTimes].AsString();
108 set => this.Set((int)IIsAppPoolSymbolFields.RecycleTimes, value);
109 }
110
111 public int? IdleTimeout
112 {
113 get => this.Fields[(int)IIsAppPoolSymbolFields.IdleTimeout].AsNullableNumber();
114 set => this.Set((int)IIsAppPoolSymbolFields.IdleTimeout, value);
115 }
116
117 public int? QueueLimit
118 {
119 get => this.Fields[(int)IIsAppPoolSymbolFields.QueueLimit].AsNullableNumber();
120 set => this.Set((int)IIsAppPoolSymbolFields.QueueLimit, value);
121 }
122
123 public string CPUMon
124 {
125 get => this.Fields[(int)IIsAppPoolSymbolFields.CPUMon].AsString();
126 set => this.Set((int)IIsAppPoolSymbolFields.CPUMon, value);
127 }
128
129 public int? MaxProc
130 {
131 get => this.Fields[(int)IIsAppPoolSymbolFields.MaxProc].AsNullableNumber();
132 set => this.Set((int)IIsAppPoolSymbolFields.MaxProc, value);
133 }
134
135 public int? VirtualMemory
136 {
137 get => this.Fields[(int)IIsAppPoolSymbolFields.VirtualMemory].AsNullableNumber();
138 set => this.Set((int)IIsAppPoolSymbolFields.VirtualMemory, value);
139 }
140
141 public int? PrivateMemory
142 {
143 get => this.Fields[(int)IIsAppPoolSymbolFields.PrivateMemory].AsNullableNumber();
144 set => this.Set((int)IIsAppPoolSymbolFields.PrivateMemory, value);
145 }
146
147 public string ManagedRuntimeVersion
148 {
149 get => this.Fields[(int)IIsAppPoolSymbolFields.ManagedRuntimeVersion].AsString();
150 set => this.Set((int)IIsAppPoolSymbolFields.ManagedRuntimeVersion, value);
151 }
152
153 public string ManagedPipelineMode
154 {
155 get => this.Fields[(int)IIsAppPoolSymbolFields.ManagedPipelineMode].AsString();
156 set => this.Set((int)IIsAppPoolSymbolFields.ManagedPipelineMode, value);
157 }
158 }
159} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsFilterSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsFilterSymbol.cs
new file mode 100644
index 00000000..618730bf
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsFilterSymbol.cs
@@ -0,0 +1,95 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsFilter = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsFilter.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsFilterSymbolFields.Name), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsFilterSymbolFields.ComponentRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(IIsFilterSymbolFields.Path), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(IIsFilterSymbolFields.WebRef), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(IIsFilterSymbolFields.Description), IntermediateFieldType.String),
19 new IntermediateFieldDefinition(nameof(IIsFilterSymbolFields.Flags), IntermediateFieldType.Number),
20 new IntermediateFieldDefinition(nameof(IIsFilterSymbolFields.LoadOrder), IntermediateFieldType.Number),
21 },
22 typeof(IIsFilterSymbol));
23 }
24}
25
26namespace WixToolset.Iis.Symbols
27{
28 using WixToolset.Data;
29
30 public enum IIsFilterSymbolFields
31 {
32 Name,
33 ComponentRef,
34 Path,
35 WebRef,
36 Description,
37 Flags,
38 LoadOrder,
39 }
40
41 public class IIsFilterSymbol : IntermediateSymbol
42 {
43 public IIsFilterSymbol() : base(IisSymbolDefinitions.IIsFilter, null, null)
44 {
45 }
46
47 public IIsFilterSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsFilter, sourceLineNumber, id)
48 {
49 }
50
51 public IntermediateField this[IIsFilterSymbolFields index] => this.Fields[(int)index];
52
53 public string Name
54 {
55 get => this.Fields[(int)IIsFilterSymbolFields.Name].AsString();
56 set => this.Set((int)IIsFilterSymbolFields.Name, value);
57 }
58
59 public string ComponentRef
60 {
61 get => this.Fields[(int)IIsFilterSymbolFields.ComponentRef].AsString();
62 set => this.Set((int)IIsFilterSymbolFields.ComponentRef, value);
63 }
64
65 public string Path
66 {
67 get => this.Fields[(int)IIsFilterSymbolFields.Path].AsString();
68 set => this.Set((int)IIsFilterSymbolFields.Path, value);
69 }
70
71 public string WebRef
72 {
73 get => this.Fields[(int)IIsFilterSymbolFields.WebRef].AsString();
74 set => this.Set((int)IIsFilterSymbolFields.WebRef, value);
75 }
76
77 public string Description
78 {
79 get => this.Fields[(int)IIsFilterSymbolFields.Description].AsString();
80 set => this.Set((int)IIsFilterSymbolFields.Description, value);
81 }
82
83 public int Flags
84 {
85 get => this.Fields[(int)IIsFilterSymbolFields.Flags].AsNumber();
86 set => this.Set((int)IIsFilterSymbolFields.Flags, value);
87 }
88
89 public int? LoadOrder
90 {
91 get => this.Fields[(int)IIsFilterSymbolFields.LoadOrder].AsNullableNumber();
92 set => this.Set((int)IIsFilterSymbolFields.LoadOrder, value);
93 }
94 }
95} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsHttpHeaderSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsHttpHeaderSymbol.cs
new file mode 100644
index 00000000..3ab2bf59
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsHttpHeaderSymbol.cs
@@ -0,0 +1,95 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsHttpHeader = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsHttpHeader.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsHttpHeaderSymbolFields.HttpHeader), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsHttpHeaderSymbolFields.ParentType), IntermediateFieldType.Number),
16 new IntermediateFieldDefinition(nameof(IIsHttpHeaderSymbolFields.ParentValue), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(IIsHttpHeaderSymbolFields.Name), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(IIsHttpHeaderSymbolFields.Value), IntermediateFieldType.String),
19 new IntermediateFieldDefinition(nameof(IIsHttpHeaderSymbolFields.Attributes), IntermediateFieldType.Number),
20 new IntermediateFieldDefinition(nameof(IIsHttpHeaderSymbolFields.Sequence), IntermediateFieldType.Number),
21 },
22 typeof(IIsHttpHeaderSymbol));
23 }
24}
25
26namespace WixToolset.Iis.Symbols
27{
28 using WixToolset.Data;
29
30 public enum IIsHttpHeaderSymbolFields
31 {
32 HttpHeader,
33 ParentType,
34 ParentValue,
35 Name,
36 Value,
37 Attributes,
38 Sequence,
39 }
40
41 public class IIsHttpHeaderSymbol : IntermediateSymbol
42 {
43 public IIsHttpHeaderSymbol() : base(IisSymbolDefinitions.IIsHttpHeader, null, null)
44 {
45 }
46
47 public IIsHttpHeaderSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsHttpHeader, sourceLineNumber, id)
48 {
49 }
50
51 public IntermediateField this[IIsHttpHeaderSymbolFields index] => this.Fields[(int)index];
52
53 public string HttpHeader
54 {
55 get => this.Fields[(int)IIsHttpHeaderSymbolFields.HttpHeader].AsString();
56 set => this.Set((int)IIsHttpHeaderSymbolFields.HttpHeader, value);
57 }
58
59 public int ParentType
60 {
61 get => this.Fields[(int)IIsHttpHeaderSymbolFields.ParentType].AsNumber();
62 set => this.Set((int)IIsHttpHeaderSymbolFields.ParentType, value);
63 }
64
65 public string ParentValue
66 {
67 get => this.Fields[(int)IIsHttpHeaderSymbolFields.ParentValue].AsString();
68 set => this.Set((int)IIsHttpHeaderSymbolFields.ParentValue, value);
69 }
70
71 public string Name
72 {
73 get => this.Fields[(int)IIsHttpHeaderSymbolFields.Name].AsString();
74 set => this.Set((int)IIsHttpHeaderSymbolFields.Name, value);
75 }
76
77 public string Value
78 {
79 get => this.Fields[(int)IIsHttpHeaderSymbolFields.Value].AsString();
80 set => this.Set((int)IIsHttpHeaderSymbolFields.Value, value);
81 }
82
83 public int Attributes
84 {
85 get => this.Fields[(int)IIsHttpHeaderSymbolFields.Attributes].AsNumber();
86 set => this.Set((int)IIsHttpHeaderSymbolFields.Attributes, value);
87 }
88
89 public int? Sequence
90 {
91 get => this.Fields[(int)IIsHttpHeaderSymbolFields.Sequence].AsNullableNumber();
92 set => this.Set((int)IIsHttpHeaderSymbolFields.Sequence, value);
93 }
94 }
95} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsMimeMapSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsMimeMapSymbol.cs
new file mode 100644
index 00000000..4af6f81c
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsMimeMapSymbol.cs
@@ -0,0 +1,71 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsMimeMap = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsMimeMap.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsMimeMapSymbolFields.ParentType), IntermediateFieldType.Number),
15 new IntermediateFieldDefinition(nameof(IIsMimeMapSymbolFields.ParentValue), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(IIsMimeMapSymbolFields.MimeType), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(IIsMimeMapSymbolFields.Extension), IntermediateFieldType.String),
18 },
19 typeof(IIsMimeMapSymbol));
20 }
21}
22
23namespace WixToolset.Iis.Symbols
24{
25 using WixToolset.Data;
26
27 public enum IIsMimeMapSymbolFields
28 {
29 ParentType,
30 ParentValue,
31 MimeType,
32 Extension,
33 }
34
35 public class IIsMimeMapSymbol : IntermediateSymbol
36 {
37 public IIsMimeMapSymbol() : base(IisSymbolDefinitions.IIsMimeMap, null, null)
38 {
39 }
40
41 public IIsMimeMapSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsMimeMap, sourceLineNumber, id)
42 {
43 }
44
45 public IntermediateField this[IIsMimeMapSymbolFields index] => this.Fields[(int)index];
46
47 public int ParentType
48 {
49 get => this.Fields[(int)IIsMimeMapSymbolFields.ParentType].AsNumber();
50 set => this.Set((int)IIsMimeMapSymbolFields.ParentType, value);
51 }
52
53 public string ParentValue
54 {
55 get => this.Fields[(int)IIsMimeMapSymbolFields.ParentValue].AsString();
56 set => this.Set((int)IIsMimeMapSymbolFields.ParentValue, value);
57 }
58
59 public string MimeType
60 {
61 get => this.Fields[(int)IIsMimeMapSymbolFields.MimeType].AsString();
62 set => this.Set((int)IIsMimeMapSymbolFields.MimeType, value);
63 }
64
65 public string Extension
66 {
67 get => this.Fields[(int)IIsMimeMapSymbolFields.Extension].AsString();
68 set => this.Set((int)IIsMimeMapSymbolFields.Extension, value);
69 }
70 }
71} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsPropertySymbol.cs b/src/ext/Iis/wixext/Symbols/IIsPropertySymbol.cs
new file mode 100644
index 00000000..9cf67014
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsPropertySymbol.cs
@@ -0,0 +1,63 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsProperty = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsProperty.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsPropertySymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsPropertySymbolFields.Attributes), IntermediateFieldType.Number),
16 new IntermediateFieldDefinition(nameof(IIsPropertySymbolFields.Value), IntermediateFieldType.String),
17 },
18 typeof(IIsPropertySymbol));
19 }
20}
21
22namespace WixToolset.Iis.Symbols
23{
24 using WixToolset.Data;
25
26 public enum IIsPropertySymbolFields
27 {
28 ComponentRef,
29 Attributes,
30 Value,
31 }
32
33 public class IIsPropertySymbol : IntermediateSymbol
34 {
35 public IIsPropertySymbol() : base(IisSymbolDefinitions.IIsProperty, null, null)
36 {
37 }
38
39 public IIsPropertySymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsProperty, sourceLineNumber, id)
40 {
41 }
42
43 public IntermediateField this[IIsPropertySymbolFields index] => this.Fields[(int)index];
44
45 public string ComponentRef
46 {
47 get => this.Fields[(int)IIsPropertySymbolFields.ComponentRef].AsString();
48 set => this.Set((int)IIsPropertySymbolFields.ComponentRef, value);
49 }
50
51 public int Attributes
52 {
53 get => this.Fields[(int)IIsPropertySymbolFields.Attributes].AsNumber();
54 set => this.Set((int)IIsPropertySymbolFields.Attributes, value);
55 }
56
57 public string Value
58 {
59 get => this.Fields[(int)IIsPropertySymbolFields.Value].AsString();
60 set => this.Set((int)IIsPropertySymbolFields.Value, value);
61 }
62 }
63} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsWebAddressSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsWebAddressSymbol.cs
new file mode 100644
index 00000000..7111718a
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsWebAddressSymbol.cs
@@ -0,0 +1,79 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsWebAddress = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsWebAddress.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsWebAddressSymbolFields.WebRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsWebAddressSymbolFields.IP), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(IIsWebAddressSymbolFields.Port), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(IIsWebAddressSymbolFields.Header), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(IIsWebAddressSymbolFields.Secure), IntermediateFieldType.Number),
19 },
20 typeof(IIsWebAddressSymbol));
21 }
22}
23
24namespace WixToolset.Iis.Symbols
25{
26 using WixToolset.Data;
27
28 public enum IIsWebAddressSymbolFields
29 {
30 WebRef,
31 IP,
32 Port,
33 Header,
34 Secure,
35 }
36
37 public class IIsWebAddressSymbol : IntermediateSymbol
38 {
39 public IIsWebAddressSymbol() : base(IisSymbolDefinitions.IIsWebAddress, null, null)
40 {
41 }
42
43 public IIsWebAddressSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsWebAddress, sourceLineNumber, id)
44 {
45 }
46
47 public IntermediateField this[IIsWebAddressSymbolFields index] => this.Fields[(int)index];
48
49 public string WebRef
50 {
51 get => this.Fields[(int)IIsWebAddressSymbolFields.WebRef].AsString();
52 set => this.Set((int)IIsWebAddressSymbolFields.WebRef, value);
53 }
54
55 public string IP
56 {
57 get => this.Fields[(int)IIsWebAddressSymbolFields.IP].AsString();
58 set => this.Set((int)IIsWebAddressSymbolFields.IP, value);
59 }
60
61 public string Port
62 {
63 get => this.Fields[(int)IIsWebAddressSymbolFields.Port].AsString();
64 set => this.Set((int)IIsWebAddressSymbolFields.Port, value);
65 }
66
67 public string Header
68 {
69 get => this.Fields[(int)IIsWebAddressSymbolFields.Header].AsString();
70 set => this.Set((int)IIsWebAddressSymbolFields.Header, value);
71 }
72
73 public int? Secure
74 {
75 get => this.Fields[(int)IIsWebAddressSymbolFields.Secure].AsNullableNumber();
76 set => this.Set((int)IIsWebAddressSymbolFields.Secure, value);
77 }
78 }
79} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsWebApplicationExtensionSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsWebApplicationExtensionSymbol.cs
new file mode 100644
index 00000000..4283d702
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsWebApplicationExtensionSymbol.cs
@@ -0,0 +1,79 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsWebApplicationExtension = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsWebApplicationExtension.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsWebApplicationExtensionSymbolFields.ApplicationRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsWebApplicationExtensionSymbolFields.Extension), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(IIsWebApplicationExtensionSymbolFields.Verbs), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(IIsWebApplicationExtensionSymbolFields.Executable), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(IIsWebApplicationExtensionSymbolFields.Attributes), IntermediateFieldType.Number),
19 },
20 typeof(IIsWebApplicationExtensionSymbol));
21 }
22}
23
24namespace WixToolset.Iis.Symbols
25{
26 using WixToolset.Data;
27
28 public enum IIsWebApplicationExtensionSymbolFields
29 {
30 ApplicationRef,
31 Extension,
32 Verbs,
33 Executable,
34 Attributes,
35 }
36
37 public class IIsWebApplicationExtensionSymbol : IntermediateSymbol
38 {
39 public IIsWebApplicationExtensionSymbol() : base(IisSymbolDefinitions.IIsWebApplicationExtension, null, null)
40 {
41 }
42
43 public IIsWebApplicationExtensionSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsWebApplicationExtension, sourceLineNumber, id)
44 {
45 }
46
47 public IntermediateField this[IIsWebApplicationExtensionSymbolFields index] => this.Fields[(int)index];
48
49 public string ApplicationRef
50 {
51 get => this.Fields[(int)IIsWebApplicationExtensionSymbolFields.ApplicationRef].AsString();
52 set => this.Set((int)IIsWebApplicationExtensionSymbolFields.ApplicationRef, value);
53 }
54
55 public string Extension
56 {
57 get => this.Fields[(int)IIsWebApplicationExtensionSymbolFields.Extension].AsString();
58 set => this.Set((int)IIsWebApplicationExtensionSymbolFields.Extension, value);
59 }
60
61 public string Verbs
62 {
63 get => this.Fields[(int)IIsWebApplicationExtensionSymbolFields.Verbs].AsString();
64 set => this.Set((int)IIsWebApplicationExtensionSymbolFields.Verbs, value);
65 }
66
67 public string Executable
68 {
69 get => this.Fields[(int)IIsWebApplicationExtensionSymbolFields.Executable].AsString();
70 set => this.Set((int)IIsWebApplicationExtensionSymbolFields.Executable, value);
71 }
72
73 public int Attributes
74 {
75 get => this.Fields[(int)IIsWebApplicationExtensionSymbolFields.Attributes].AsNumber();
76 set => this.Set((int)IIsWebApplicationExtensionSymbolFields.Attributes, value);
77 }
78 }
79} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsWebApplicationSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsWebApplicationSymbol.cs
new file mode 100644
index 00000000..2f6f87de
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsWebApplicationSymbol.cs
@@ -0,0 +1,127 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsWebApplication = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsWebApplication.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsWebApplicationSymbolFields.Name), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsWebApplicationSymbolFields.Isolation), IntermediateFieldType.Number),
16 new IntermediateFieldDefinition(nameof(IIsWebApplicationSymbolFields.AllowSessions), IntermediateFieldType.Number),
17 new IntermediateFieldDefinition(nameof(IIsWebApplicationSymbolFields.SessionTimeout), IntermediateFieldType.Number),
18 new IntermediateFieldDefinition(nameof(IIsWebApplicationSymbolFields.Buffer), IntermediateFieldType.Number),
19 new IntermediateFieldDefinition(nameof(IIsWebApplicationSymbolFields.ParentPaths), IntermediateFieldType.Number),
20 new IntermediateFieldDefinition(nameof(IIsWebApplicationSymbolFields.DefaultScript), IntermediateFieldType.String),
21 new IntermediateFieldDefinition(nameof(IIsWebApplicationSymbolFields.ScriptTimeout), IntermediateFieldType.Number),
22 new IntermediateFieldDefinition(nameof(IIsWebApplicationSymbolFields.ServerDebugging), IntermediateFieldType.Number),
23 new IntermediateFieldDefinition(nameof(IIsWebApplicationSymbolFields.ClientDebugging), IntermediateFieldType.Number),
24 new IntermediateFieldDefinition(nameof(IIsWebApplicationSymbolFields.AppPoolRef), IntermediateFieldType.String),
25 },
26 typeof(IIsWebApplicationSymbol));
27 }
28}
29
30namespace WixToolset.Iis.Symbols
31{
32 using WixToolset.Data;
33
34 public enum IIsWebApplicationSymbolFields
35 {
36 Name,
37 Isolation,
38 AllowSessions,
39 SessionTimeout,
40 Buffer,
41 ParentPaths,
42 DefaultScript,
43 ScriptTimeout,
44 ServerDebugging,
45 ClientDebugging,
46 AppPoolRef,
47 }
48
49 public class IIsWebApplicationSymbol : IntermediateSymbol
50 {
51 public IIsWebApplicationSymbol() : base(IisSymbolDefinitions.IIsWebApplication, null, null)
52 {
53 }
54
55 public IIsWebApplicationSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsWebApplication, sourceLineNumber, id)
56 {
57 }
58
59 public IntermediateField this[IIsWebApplicationSymbolFields index] => this.Fields[(int)index];
60
61 public string Name
62 {
63 get => this.Fields[(int)IIsWebApplicationSymbolFields.Name].AsString();
64 set => this.Set((int)IIsWebApplicationSymbolFields.Name, value);
65 }
66
67 public int Isolation
68 {
69 get => this.Fields[(int)IIsWebApplicationSymbolFields.Isolation].AsNumber();
70 set => this.Set((int)IIsWebApplicationSymbolFields.Isolation, value);
71 }
72
73 public int? AllowSessions
74 {
75 get => this.Fields[(int)IIsWebApplicationSymbolFields.AllowSessions].AsNullableNumber();
76 set => this.Set((int)IIsWebApplicationSymbolFields.AllowSessions, value);
77 }
78
79 public int? SessionTimeout
80 {
81 get => this.Fields[(int)IIsWebApplicationSymbolFields.SessionTimeout].AsNullableNumber();
82 set => this.Set((int)IIsWebApplicationSymbolFields.SessionTimeout, value);
83 }
84
85 public int? Buffer
86 {
87 get => this.Fields[(int)IIsWebApplicationSymbolFields.Buffer].AsNullableNumber();
88 set => this.Set((int)IIsWebApplicationSymbolFields.Buffer, value);
89 }
90
91 public int? ParentPaths
92 {
93 get => this.Fields[(int)IIsWebApplicationSymbolFields.ParentPaths].AsNullableNumber();
94 set => this.Set((int)IIsWebApplicationSymbolFields.ParentPaths, value);
95 }
96
97 public string DefaultScript
98 {
99 get => this.Fields[(int)IIsWebApplicationSymbolFields.DefaultScript].AsString();
100 set => this.Set((int)IIsWebApplicationSymbolFields.DefaultScript, value);
101 }
102
103 public int? ScriptTimeout
104 {
105 get => this.Fields[(int)IIsWebApplicationSymbolFields.ScriptTimeout].AsNullableNumber();
106 set => this.Set((int)IIsWebApplicationSymbolFields.ScriptTimeout, value);
107 }
108
109 public int? ServerDebugging
110 {
111 get => this.Fields[(int)IIsWebApplicationSymbolFields.ServerDebugging].AsNullableNumber();
112 set => this.Set((int)IIsWebApplicationSymbolFields.ServerDebugging, value);
113 }
114
115 public int? ClientDebugging
116 {
117 get => this.Fields[(int)IIsWebApplicationSymbolFields.ClientDebugging].AsNullableNumber();
118 set => this.Set((int)IIsWebApplicationSymbolFields.ClientDebugging, value);
119 }
120
121 public string AppPoolRef
122 {
123 get => this.Fields[(int)IIsWebApplicationSymbolFields.AppPoolRef].AsString();
124 set => this.Set((int)IIsWebApplicationSymbolFields.AppPoolRef, value);
125 }
126 }
127} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsWebDirPropertiesSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsWebDirPropertiesSymbol.cs
new file mode 100644
index 00000000..42d2dead
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsWebDirPropertiesSymbol.cs
@@ -0,0 +1,151 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsWebDirProperties = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsWebDirProperties.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.Access), IntermediateFieldType.Number),
15 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.Authorization), IntermediateFieldType.Number),
16 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.AnonymousUserRef), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.IIsControlledPassword), IntermediateFieldType.Number),
18 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.LogVisits), IntermediateFieldType.Number),
19 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.Index), IntermediateFieldType.Number),
20 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.DefaultDoc), IntermediateFieldType.String),
21 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.AspDetailedError), IntermediateFieldType.Number),
22 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.HttpExpires), IntermediateFieldType.String),
23 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.CacheControlMaxAge), IntermediateFieldType.Number),
24 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.CacheControlCustom), IntermediateFieldType.String),
25 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.NoCustomError), IntermediateFieldType.Number),
26 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.AccessSSLFlags), IntermediateFieldType.Number),
27 new IntermediateFieldDefinition(nameof(IIsWebDirPropertiesSymbolFields.AuthenticationProviders), IntermediateFieldType.String),
28 },
29 typeof(IIsWebDirPropertiesSymbol));
30 }
31}
32
33namespace WixToolset.Iis.Symbols
34{
35 using WixToolset.Data;
36
37 public enum IIsWebDirPropertiesSymbolFields
38 {
39 Access,
40 Authorization,
41 AnonymousUserRef,
42 IIsControlledPassword,
43 LogVisits,
44 Index,
45 DefaultDoc,
46 AspDetailedError,
47 HttpExpires,
48 CacheControlMaxAge,
49 CacheControlCustom,
50 NoCustomError,
51 AccessSSLFlags,
52 AuthenticationProviders,
53 }
54
55 public class IIsWebDirPropertiesSymbol : IntermediateSymbol
56 {
57 public IIsWebDirPropertiesSymbol() : base(IisSymbolDefinitions.IIsWebDirProperties, null, null)
58 {
59 }
60
61 public IIsWebDirPropertiesSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsWebDirProperties, sourceLineNumber, id)
62 {
63 }
64
65 public IntermediateField this[IIsWebDirPropertiesSymbolFields index] => this.Fields[(int)index];
66
67 public int? Access
68 {
69 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.Access].AsNullableNumber();
70 set => this.Set((int)IIsWebDirPropertiesSymbolFields.Access, value);
71 }
72
73 public int? Authorization
74 {
75 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.Authorization].AsNullableNumber();
76 set => this.Set((int)IIsWebDirPropertiesSymbolFields.Authorization, value);
77 }
78
79 public string AnonymousUserRef
80 {
81 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.AnonymousUserRef].AsString();
82 set => this.Set((int)IIsWebDirPropertiesSymbolFields.AnonymousUserRef, value);
83 }
84
85 public int? IIsControlledPassword
86 {
87 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.IIsControlledPassword].AsNullableNumber();
88 set => this.Set((int)IIsWebDirPropertiesSymbolFields.IIsControlledPassword, value);
89 }
90
91 public int? LogVisits
92 {
93 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.LogVisits].AsNullableNumber();
94 set => this.Set((int)IIsWebDirPropertiesSymbolFields.LogVisits, value);
95 }
96
97 public int? Index
98 {
99 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.Index].AsNullableNumber();
100 set => this.Set((int)IIsWebDirPropertiesSymbolFields.Index, value);
101 }
102
103 public string DefaultDoc
104 {
105 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.DefaultDoc].AsString();
106 set => this.Set((int)IIsWebDirPropertiesSymbolFields.DefaultDoc, value);
107 }
108
109 public int? AspDetailedError
110 {
111 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.AspDetailedError].AsNullableNumber();
112 set => this.Set((int)IIsWebDirPropertiesSymbolFields.AspDetailedError, value);
113 }
114
115 public string HttpExpires
116 {
117 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.HttpExpires].AsString();
118 set => this.Set((int)IIsWebDirPropertiesSymbolFields.HttpExpires, value);
119 }
120
121 public int? CacheControlMaxAge
122 {
123 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.CacheControlMaxAge].AsNullableNumber();
124 set => this.Set((int)IIsWebDirPropertiesSymbolFields.CacheControlMaxAge, value);
125 }
126
127 public string CacheControlCustom
128 {
129 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.CacheControlCustom].AsString();
130 set => this.Set((int)IIsWebDirPropertiesSymbolFields.CacheControlCustom, value);
131 }
132
133 public int? NoCustomError
134 {
135 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.NoCustomError].AsNullableNumber();
136 set => this.Set((int)IIsWebDirPropertiesSymbolFields.NoCustomError, value);
137 }
138
139 public int? AccessSSLFlags
140 {
141 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.AccessSSLFlags].AsNullableNumber();
142 set => this.Set((int)IIsWebDirPropertiesSymbolFields.AccessSSLFlags, value);
143 }
144
145 public string AuthenticationProviders
146 {
147 get => this.Fields[(int)IIsWebDirPropertiesSymbolFields.AuthenticationProviders].AsString();
148 set => this.Set((int)IIsWebDirPropertiesSymbolFields.AuthenticationProviders, value);
149 }
150 }
151} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsWebDirSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsWebDirSymbol.cs
new file mode 100644
index 00000000..7f257f14
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsWebDirSymbol.cs
@@ -0,0 +1,79 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsWebDir = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsWebDir.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsWebDirSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsWebDirSymbolFields.WebRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(IIsWebDirSymbolFields.Path), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(IIsWebDirSymbolFields.DirPropertiesRef), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(IIsWebDirSymbolFields.ApplicationRef), IntermediateFieldType.String),
19 },
20 typeof(IIsWebDirSymbol));
21 }
22}
23
24namespace WixToolset.Iis.Symbols
25{
26 using WixToolset.Data;
27
28 public enum IIsWebDirSymbolFields
29 {
30 ComponentRef,
31 WebRef,
32 Path,
33 DirPropertiesRef,
34 ApplicationRef,
35 }
36
37 public class IIsWebDirSymbol : IntermediateSymbol
38 {
39 public IIsWebDirSymbol() : base(IisSymbolDefinitions.IIsWebDir, null, null)
40 {
41 }
42
43 public IIsWebDirSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsWebDir, sourceLineNumber, id)
44 {
45 }
46
47 public IntermediateField this[IIsWebDirSymbolFields index] => this.Fields[(int)index];
48
49 public string ComponentRef
50 {
51 get => this.Fields[(int)IIsWebDirSymbolFields.ComponentRef].AsString();
52 set => this.Set((int)IIsWebDirSymbolFields.ComponentRef, value);
53 }
54
55 public string WebRef
56 {
57 get => this.Fields[(int)IIsWebDirSymbolFields.WebRef].AsString();
58 set => this.Set((int)IIsWebDirSymbolFields.WebRef, value);
59 }
60
61 public string Path
62 {
63 get => this.Fields[(int)IIsWebDirSymbolFields.Path].AsString();
64 set => this.Set((int)IIsWebDirSymbolFields.Path, value);
65 }
66
67 public string DirPropertiesRef
68 {
69 get => this.Fields[(int)IIsWebDirSymbolFields.DirPropertiesRef].AsString();
70 set => this.Set((int)IIsWebDirSymbolFields.DirPropertiesRef, value);
71 }
72
73 public string ApplicationRef
74 {
75 get => this.Fields[(int)IIsWebDirSymbolFields.ApplicationRef].AsString();
76 set => this.Set((int)IIsWebDirSymbolFields.ApplicationRef, value);
77 }
78 }
79} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsWebErrorSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsWebErrorSymbol.cs
new file mode 100644
index 00000000..f8488fed
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsWebErrorSymbol.cs
@@ -0,0 +1,87 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsWebError = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsWebError.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsWebErrorSymbolFields.ErrorCode), IntermediateFieldType.Number),
15 new IntermediateFieldDefinition(nameof(IIsWebErrorSymbolFields.SubCode), IntermediateFieldType.Number),
16 new IntermediateFieldDefinition(nameof(IIsWebErrorSymbolFields.ParentType), IntermediateFieldType.Number),
17 new IntermediateFieldDefinition(nameof(IIsWebErrorSymbolFields.ParentValue), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(IIsWebErrorSymbolFields.File), IntermediateFieldType.String),
19 new IntermediateFieldDefinition(nameof(IIsWebErrorSymbolFields.URL), IntermediateFieldType.String),
20 },
21 typeof(IIsWebErrorSymbol));
22 }
23}
24
25namespace WixToolset.Iis.Symbols
26{
27 using WixToolset.Data;
28
29 public enum IIsWebErrorSymbolFields
30 {
31 ErrorCode,
32 SubCode,
33 ParentType,
34 ParentValue,
35 File,
36 URL,
37 }
38
39 public class IIsWebErrorSymbol : IntermediateSymbol
40 {
41 public IIsWebErrorSymbol() : base(IisSymbolDefinitions.IIsWebError, null, null)
42 {
43 }
44
45 public IIsWebErrorSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsWebError, sourceLineNumber, id)
46 {
47 }
48
49 public IntermediateField this[IIsWebErrorSymbolFields index] => this.Fields[(int)index];
50
51 public int ErrorCode
52 {
53 get => this.Fields[(int)IIsWebErrorSymbolFields.ErrorCode].AsNumber();
54 set => this.Set((int)IIsWebErrorSymbolFields.ErrorCode, value);
55 }
56
57 public int SubCode
58 {
59 get => this.Fields[(int)IIsWebErrorSymbolFields.SubCode].AsNumber();
60 set => this.Set((int)IIsWebErrorSymbolFields.SubCode, value);
61 }
62
63 public int ParentType
64 {
65 get => this.Fields[(int)IIsWebErrorSymbolFields.ParentType].AsNumber();
66 set => this.Set((int)IIsWebErrorSymbolFields.ParentType, value);
67 }
68
69 public string ParentValue
70 {
71 get => this.Fields[(int)IIsWebErrorSymbolFields.ParentValue].AsString();
72 set => this.Set((int)IIsWebErrorSymbolFields.ParentValue, value);
73 }
74
75 public string File
76 {
77 get => this.Fields[(int)IIsWebErrorSymbolFields.File].AsString();
78 set => this.Set((int)IIsWebErrorSymbolFields.File, value);
79 }
80
81 public string URL
82 {
83 get => this.Fields[(int)IIsWebErrorSymbolFields.URL].AsString();
84 set => this.Set((int)IIsWebErrorSymbolFields.URL, value);
85 }
86 }
87} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsWebLogSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsWebLogSymbol.cs
new file mode 100644
index 00000000..409dc673
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsWebLogSymbol.cs
@@ -0,0 +1,47 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsWebLog = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsWebLog.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsWebLogSymbolFields.Format), IntermediateFieldType.String),
15 },
16 typeof(IIsWebLogSymbol));
17 }
18}
19
20namespace WixToolset.Iis.Symbols
21{
22 using WixToolset.Data;
23
24 public enum IIsWebLogSymbolFields
25 {
26 Format,
27 }
28
29 public class IIsWebLogSymbol : IntermediateSymbol
30 {
31 public IIsWebLogSymbol() : base(IisSymbolDefinitions.IIsWebLog, null, null)
32 {
33 }
34
35 public IIsWebLogSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsWebLog, sourceLineNumber, id)
36 {
37 }
38
39 public IntermediateField this[IIsWebLogSymbolFields index] => this.Fields[(int)index];
40
41 public string Format
42 {
43 get => this.Fields[(int)IIsWebLogSymbolFields.Format].AsString();
44 set => this.Set((int)IIsWebLogSymbolFields.Format, value);
45 }
46 }
47} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsWebServiceExtensionSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsWebServiceExtensionSymbol.cs
new file mode 100644
index 00000000..44922357
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsWebServiceExtensionSymbol.cs
@@ -0,0 +1,79 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsWebServiceExtension = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsWebServiceExtension.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsWebServiceExtensionSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsWebServiceExtensionSymbolFields.File), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(IIsWebServiceExtensionSymbolFields.Description), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(IIsWebServiceExtensionSymbolFields.Group), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(IIsWebServiceExtensionSymbolFields.Attributes), IntermediateFieldType.Number),
19 },
20 typeof(IIsWebServiceExtensionSymbol));
21 }
22}
23
24namespace WixToolset.Iis.Symbols
25{
26 using WixToolset.Data;
27
28 public enum IIsWebServiceExtensionSymbolFields
29 {
30 ComponentRef,
31 File,
32 Description,
33 Group,
34 Attributes,
35 }
36
37 public class IIsWebServiceExtensionSymbol : IntermediateSymbol
38 {
39 public IIsWebServiceExtensionSymbol() : base(IisSymbolDefinitions.IIsWebServiceExtension, null, null)
40 {
41 }
42
43 public IIsWebServiceExtensionSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsWebServiceExtension, sourceLineNumber, id)
44 {
45 }
46
47 public IntermediateField this[IIsWebServiceExtensionSymbolFields index] => this.Fields[(int)index];
48
49 public string ComponentRef
50 {
51 get => this.Fields[(int)IIsWebServiceExtensionSymbolFields.ComponentRef].AsString();
52 set => this.Set((int)IIsWebServiceExtensionSymbolFields.ComponentRef, value);
53 }
54
55 public string File
56 {
57 get => this.Fields[(int)IIsWebServiceExtensionSymbolFields.File].AsString();
58 set => this.Set((int)IIsWebServiceExtensionSymbolFields.File, value);
59 }
60
61 public string Description
62 {
63 get => this.Fields[(int)IIsWebServiceExtensionSymbolFields.Description].AsString();
64 set => this.Set((int)IIsWebServiceExtensionSymbolFields.Description, value);
65 }
66
67 public string Group
68 {
69 get => this.Fields[(int)IIsWebServiceExtensionSymbolFields.Group].AsString();
70 set => this.Set((int)IIsWebServiceExtensionSymbolFields.Group, value);
71 }
72
73 public int Attributes
74 {
75 get => this.Fields[(int)IIsWebServiceExtensionSymbolFields.Attributes].AsNumber();
76 set => this.Set((int)IIsWebServiceExtensionSymbolFields.Attributes, value);
77 }
78 }
79} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsWebSiteCertificatesSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsWebSiteCertificatesSymbol.cs
new file mode 100644
index 00000000..851ce556
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsWebSiteCertificatesSymbol.cs
@@ -0,0 +1,55 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsWebSiteCertificates = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsWebSiteCertificates.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsWebSiteCertificatesSymbolFields.WebRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsWebSiteCertificatesSymbolFields.CertificateRef), IntermediateFieldType.String),
16 },
17 typeof(IIsWebSiteCertificatesSymbol));
18 }
19}
20
21namespace WixToolset.Iis.Symbols
22{
23 using WixToolset.Data;
24
25 public enum IIsWebSiteCertificatesSymbolFields
26 {
27 WebRef,
28 CertificateRef,
29 }
30
31 public class IIsWebSiteCertificatesSymbol : IntermediateSymbol
32 {
33 public IIsWebSiteCertificatesSymbol() : base(IisSymbolDefinitions.IIsWebSiteCertificates, null, null)
34 {
35 }
36
37 public IIsWebSiteCertificatesSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsWebSiteCertificates, sourceLineNumber, id)
38 {
39 }
40
41 public IntermediateField this[IIsWebSiteCertificatesSymbolFields index] => this.Fields[(int)index];
42
43 public string WebRef
44 {
45 get => this.Fields[(int)IIsWebSiteCertificatesSymbolFields.WebRef].AsString();
46 set => this.Set((int)IIsWebSiteCertificatesSymbolFields.WebRef, value);
47 }
48
49 public string CertificateRef
50 {
51 get => this.Fields[(int)IIsWebSiteCertificatesSymbolFields.CertificateRef].AsString();
52 set => this.Set((int)IIsWebSiteCertificatesSymbolFields.CertificateRef, value);
53 }
54 }
55} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsWebSiteSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsWebSiteSymbol.cs
new file mode 100644
index 00000000..ceba2ea0
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsWebSiteSymbol.cs
@@ -0,0 +1,135 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsWebSite = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsWebSite.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.Description), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.ConnectionTimeout), IntermediateFieldType.Number),
17 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.DirectoryRef), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.State), IntermediateFieldType.Number),
19 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.Attributes), IntermediateFieldType.Number),
20 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.KeyAddressRef), IntermediateFieldType.String),
21 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.DirPropertiesRef), IntermediateFieldType.String),
22 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.ApplicationRef), IntermediateFieldType.String),
23 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.Sequence), IntermediateFieldType.Number),
24 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.LogRef), IntermediateFieldType.String),
25 new IntermediateFieldDefinition(nameof(IIsWebSiteSymbolFields.WebsiteId), IntermediateFieldType.String),
26 },
27 typeof(IIsWebSiteSymbol));
28 }
29}
30
31namespace WixToolset.Iis.Symbols
32{
33 using WixToolset.Data;
34
35 public enum IIsWebSiteSymbolFields
36 {
37 ComponentRef,
38 Description,
39 ConnectionTimeout,
40 DirectoryRef,
41 State,
42 Attributes,
43 KeyAddressRef,
44 DirPropertiesRef,
45 ApplicationRef,
46 Sequence,
47 LogRef,
48 WebsiteId,
49 }
50
51 public class IIsWebSiteSymbol : IntermediateSymbol
52 {
53 public IIsWebSiteSymbol() : base(IisSymbolDefinitions.IIsWebSite, null, null)
54 {
55 }
56
57 public IIsWebSiteSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsWebSite, sourceLineNumber, id)
58 {
59 }
60
61 public IntermediateField this[IIsWebSiteSymbolFields index] => this.Fields[(int)index];
62
63 public string ComponentRef
64 {
65 get => this.Fields[(int)IIsWebSiteSymbolFields.ComponentRef].AsString();
66 set => this.Set((int)IIsWebSiteSymbolFields.ComponentRef, value);
67 }
68
69 public string Description
70 {
71 get => this.Fields[(int)IIsWebSiteSymbolFields.Description].AsString();
72 set => this.Set((int)IIsWebSiteSymbolFields.Description, value);
73 }
74
75 public int? ConnectionTimeout
76 {
77 get => this.Fields[(int)IIsWebSiteSymbolFields.ConnectionTimeout].AsNullableNumber();
78 set => this.Set((int)IIsWebSiteSymbolFields.ConnectionTimeout, value);
79 }
80
81 public string DirectoryRef
82 {
83 get => this.Fields[(int)IIsWebSiteSymbolFields.DirectoryRef].AsString();
84 set => this.Set((int)IIsWebSiteSymbolFields.DirectoryRef, value);
85 }
86
87 public int? State
88 {
89 get => this.Fields[(int)IIsWebSiteSymbolFields.State].AsNullableNumber();
90 set => this.Set((int)IIsWebSiteSymbolFields.State, value);
91 }
92
93 public int Attributes
94 {
95 get => this.Fields[(int)IIsWebSiteSymbolFields.Attributes].AsNumber();
96 set => this.Set((int)IIsWebSiteSymbolFields.Attributes, value);
97 }
98
99 public string KeyAddressRef
100 {
101 get => this.Fields[(int)IIsWebSiteSymbolFields.KeyAddressRef].AsString();
102 set => this.Set((int)IIsWebSiteSymbolFields.KeyAddressRef, value);
103 }
104
105 public string DirPropertiesRef
106 {
107 get => this.Fields[(int)IIsWebSiteSymbolFields.DirPropertiesRef].AsString();
108 set => this.Set((int)IIsWebSiteSymbolFields.DirPropertiesRef, value);
109 }
110
111 public string ApplicationRef
112 {
113 get => this.Fields[(int)IIsWebSiteSymbolFields.ApplicationRef].AsString();
114 set => this.Set((int)IIsWebSiteSymbolFields.ApplicationRef, value);
115 }
116
117 public int? Sequence
118 {
119 get => this.Fields[(int)IIsWebSiteSymbolFields.Sequence].AsNullableNumber();
120 set => this.Set((int)IIsWebSiteSymbolFields.Sequence, value);
121 }
122
123 public string LogRef
124 {
125 get => this.Fields[(int)IIsWebSiteSymbolFields.LogRef].AsString();
126 set => this.Set((int)IIsWebSiteSymbolFields.LogRef, value);
127 }
128
129 public string WebsiteId
130 {
131 get => this.Fields[(int)IIsWebSiteSymbolFields.WebsiteId].AsString();
132 set => this.Set((int)IIsWebSiteSymbolFields.WebsiteId, value);
133 }
134 }
135} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IIsWebVirtualDirSymbol.cs b/src/ext/Iis/wixext/Symbols/IIsWebVirtualDirSymbol.cs
new file mode 100644
index 00000000..bfc29e84
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IIsWebVirtualDirSymbol.cs
@@ -0,0 +1,87 @@
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
3namespace WixToolset.Iis
4{
5 using WixToolset.Data;
6 using WixToolset.Iis.Symbols;
7
8 public static partial class IisSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition IIsWebVirtualDir = new IntermediateSymbolDefinition(
11 IisSymbolDefinitionType.IIsWebVirtualDir.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(IIsWebVirtualDirSymbolFields.ComponentRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(IIsWebVirtualDirSymbolFields.WebRef), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(IIsWebVirtualDirSymbolFields.Alias), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(IIsWebVirtualDirSymbolFields.DirectoryRef), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(IIsWebVirtualDirSymbolFields.DirPropertiesRef), IntermediateFieldType.String),
19 new IntermediateFieldDefinition(nameof(IIsWebVirtualDirSymbolFields.ApplicationRef), IntermediateFieldType.String),
20 },
21 typeof(IIsWebVirtualDirSymbol));
22 }
23}
24
25namespace WixToolset.Iis.Symbols
26{
27 using WixToolset.Data;
28
29 public enum IIsWebVirtualDirSymbolFields
30 {
31 ComponentRef,
32 WebRef,
33 Alias,
34 DirectoryRef,
35 DirPropertiesRef,
36 ApplicationRef,
37 }
38
39 public class IIsWebVirtualDirSymbol : IntermediateSymbol
40 {
41 public IIsWebVirtualDirSymbol() : base(IisSymbolDefinitions.IIsWebVirtualDir, null, null)
42 {
43 }
44
45 public IIsWebVirtualDirSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(IisSymbolDefinitions.IIsWebVirtualDir, sourceLineNumber, id)
46 {
47 }
48
49 public IntermediateField this[IIsWebVirtualDirSymbolFields index] => this.Fields[(int)index];
50
51 public string ComponentRef
52 {
53 get => this.Fields[(int)IIsWebVirtualDirSymbolFields.ComponentRef].AsString();
54 set => this.Set((int)IIsWebVirtualDirSymbolFields.ComponentRef, value);
55 }
56
57 public string WebRef
58 {
59 get => this.Fields[(int)IIsWebVirtualDirSymbolFields.WebRef].AsString();
60 set => this.Set((int)IIsWebVirtualDirSymbolFields.WebRef, value);
61 }
62
63 public string Alias
64 {
65 get => this.Fields[(int)IIsWebVirtualDirSymbolFields.Alias].AsString();
66 set => this.Set((int)IIsWebVirtualDirSymbolFields.Alias, value);
67 }
68
69 public string DirectoryRef
70 {
71 get => this.Fields[(int)IIsWebVirtualDirSymbolFields.DirectoryRef].AsString();
72 set => this.Set((int)IIsWebVirtualDirSymbolFields.DirectoryRef, value);
73 }
74
75 public string DirPropertiesRef
76 {
77 get => this.Fields[(int)IIsWebVirtualDirSymbolFields.DirPropertiesRef].AsString();
78 set => this.Set((int)IIsWebVirtualDirSymbolFields.DirPropertiesRef, value);
79 }
80
81 public string ApplicationRef
82 {
83 get => this.Fields[(int)IIsWebVirtualDirSymbolFields.ApplicationRef].AsString();
84 set => this.Set((int)IIsWebVirtualDirSymbolFields.ApplicationRef, value);
85 }
86 }
87} \ No newline at end of file
diff --git a/src/ext/Iis/wixext/Symbols/IisSymbolDefinitions.cs b/src/ext/Iis/wixext/Symbols/IisSymbolDefinitions.cs
new file mode 100644
index 00000000..d6ed80a2
--- /dev/null
+++ b/src/ext/Iis/wixext/Symbols/IisSymbolDefinitions.cs
@@ -0,0 +1,107 @@
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
3namespace WixToolset.Iis
4{
5 using System;
6 using WixToolset.Data;
7
8 public enum IisSymbolDefinitionType
9 {
10 Certificate,
11 CertificateHash,
12 IIsAppPool,
13 IIsFilter,
14 IIsHttpHeader,
15 IIsMimeMap,
16 IIsProperty,
17 IIsWebAddress,
18 IIsWebApplication,
19 IIsWebApplicationExtension,
20 IIsWebDir,
21 IIsWebDirProperties,
22 IIsWebError,
23 IIsWebLog,
24 IIsWebServiceExtension,
25 IIsWebSite,
26 IIsWebSiteCertificates,
27 IIsWebVirtualDir,
28 }
29
30 public static partial class IisSymbolDefinitions
31 {
32 public static readonly Version Version = new Version("4.0.0");
33
34 public static IntermediateSymbolDefinition ByName(string name)
35 {
36 if (!Enum.TryParse(name, out IisSymbolDefinitionType type))
37 {
38 return null;
39 }
40
41 return ByType(type);
42 }
43
44 public static IntermediateSymbolDefinition ByType(IisSymbolDefinitionType type)
45 {
46 switch (type)
47 {
48 case IisSymbolDefinitionType.Certificate:
49 return IisSymbolDefinitions.Certificate;
50
51 case IisSymbolDefinitionType.CertificateHash:
52 return IisSymbolDefinitions.CertificateHash;
53
54 case IisSymbolDefinitionType.IIsAppPool:
55 return IisSymbolDefinitions.IIsAppPool;
56
57 case IisSymbolDefinitionType.IIsFilter:
58 return IisSymbolDefinitions.IIsFilter;
59
60 case IisSymbolDefinitionType.IIsHttpHeader:
61 return IisSymbolDefinitions.IIsHttpHeader;
62
63 case IisSymbolDefinitionType.IIsMimeMap:
64 return IisSymbolDefinitions.IIsMimeMap;
65
66 case IisSymbolDefinitionType.IIsProperty:
67 return IisSymbolDefinitions.IIsProperty;
68
69 case IisSymbolDefinitionType.IIsWebAddress:
70 return IisSymbolDefinitions.IIsWebAddress;
71
72 case IisSymbolDefinitionType.IIsWebApplication:
73 return IisSymbolDefinitions.IIsWebApplication;
74
75 case IisSymbolDefinitionType.IIsWebApplicationExtension:
76 return IisSymbolDefinitions.IIsWebApplicationExtension;
77
78 case IisSymbolDefinitionType.IIsWebDir:
79 return IisSymbolDefinitions.IIsWebDir;
80
81 case IisSymbolDefinitionType.IIsWebDirProperties:
82 return IisSymbolDefinitions.IIsWebDirProperties;
83
84 case IisSymbolDefinitionType.IIsWebError:
85 return IisSymbolDefinitions.IIsWebError;
86
87 case IisSymbolDefinitionType.IIsWebLog:
88 return IisSymbolDefinitions.IIsWebLog;
89
90 case IisSymbolDefinitionType.IIsWebServiceExtension:
91 return IisSymbolDefinitions.IIsWebServiceExtension;
92
93 case IisSymbolDefinitionType.IIsWebSite:
94 return IisSymbolDefinitions.IIsWebSite;
95
96 case IisSymbolDefinitionType.IIsWebSiteCertificates:
97 return IisSymbolDefinitions.IIsWebSiteCertificates;
98
99 case IisSymbolDefinitionType.IIsWebVirtualDir:
100 return IisSymbolDefinitions.IIsWebVirtualDir;
101
102 default:
103 throw new ArgumentOutOfRangeException(nameof(type));
104 }
105 }
106 }
107}
diff --git a/src/ext/Iis/wixext/WixToolset.Iis.wixext.csproj b/src/ext/Iis/wixext/WixToolset.Iis.wixext.csproj
new file mode 100644
index 00000000..81d41e77
--- /dev/null
+++ b/src/ext/Iis/wixext/WixToolset.Iis.wixext.csproj
@@ -0,0 +1,31 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netstandard2.0</TargetFramework>
7 <RootNamespace>WixToolset.Iis</RootNamespace>
8 <Description>WiX Toolset Iis Extension</Description>
9 <Title>WiX Toolset Iis Extension</Title>
10 <IsTool>true</IsTool>
11 <ContentTargetFolders>build</ContentTargetFolders>
12 </PropertyGroup>
13
14 <ItemGroup>
15 <Content Include="$(MSBuildThisFileName).targets" />
16 <EmbeddedResource Include="$(OutputPath)..\iis.wixlib" />
17 </ItemGroup>
18
19 <ItemGroup>
20 <PackageReference Include="WixToolset.Data" Version="4.0.*" PrivateAssets="all" />
21 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" PrivateAssets="all" />
22 </ItemGroup>
23
24 <ItemGroup>
25 <ProjectReference Include="..\wixlib\iis.wixproj" ReferenceOutputAssembly="false" Condition=" '$(NCrunch)'=='' " />
26 </ItemGroup>
27
28 <ItemGroup>
29 <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="all" />
30 </ItemGroup>
31</Project>
diff --git a/src/ext/Iis/wixext/WixToolset.Iis.wixext.targets b/src/ext/Iis/wixext/WixToolset.Iis.wixext.targets
new file mode 100644
index 00000000..6398fce1
--- /dev/null
+++ b/src/ext/Iis/wixext/WixToolset.Iis.wixext.targets
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
5 <PropertyGroup>
6 <WixToolsetIisWixextPath Condition=" '$(WixToolsetIisWixextPath)' == '' ">$(MSBuildThisFileDirectory)..\tools\WixToolset.Iis.wixext.dll</WixToolsetIisWixextPath>
7 </PropertyGroup>
8 <ItemGroup>
9 <WixExtension Include="$(WixToolsetIisWixextPath)" />
10 </ItemGroup>
11</Project>
diff --git a/src/ext/Iis/wixlib/IIsExtension.wxs b/src/ext/Iis/wixlib/IIsExtension.wxs
new file mode 100644
index 00000000..18fc34ff
--- /dev/null
+++ b/src/ext/Iis/wixlib/IIsExtension.wxs
@@ -0,0 +1,58 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?include caerr.wxi ?>
6
7 <Fragment>
8 <Property Id="IISMAJORVERSION">
9 <RegistrySearch Id="IIsMajorVersionSearch" Root="HKLM" Key="SOFTWARE\Microsoft\InetStp" Name="MajorVersion" Type="raw" />
10 </Property>
11
12 <Property Id="IISMINORVERSION">
13 <RegistrySearch Id="IIsMinorVersionSearch" Root="HKLM" Key="SOFTWARE\Microsoft\InetStp" Name="MinorVersion" Type="raw" />
14 </Property>
15 </Fragment>
16
17 <Fragment>
18 <UI Id="WixIIsErrors">
19 <Error Id="$(var.msierrIISCannotConnect)" Message="!(loc.msierrIISCannotConnect)" />
20 <Error Id="$(var.msierrIISFailedReadWebSite)" Message="!(loc.msierrIISFailedReadWebSite)" />
21 <Error Id="$(var.msierrIISFailedReadWebDirs)" Message="!(loc.msierrIISFailedReadWebDirs)" />
22 <Error Id="$(var.msierrIISFailedReadVDirs)" Message="!(loc.msierrIISFailedReadVDirs)" />
23 <Error Id="$(var.msierrIISFailedReadFilters)" Message="!(loc.msierrIISFailedReadFilters)" />
24 <Error Id="$(var.msierrIISFailedReadMimeMap)" Message="!(loc.msierrIISFailedReadMimeMap)" />
25 <Error Id="$(var.msierrIISFailedReadAppPool)" Message="!(loc.msierrIISFailedReadAppPool)" />
26 <Error Id="$(var.msierrIISFailedReadProp)" Message="!(loc.msierrIISFailedReadProp)" />
27 <Error Id="$(var.msierrIISFailedReadWebSvcExt)" Message="!(loc.msierrIISFailedReadWebSvcExt)" />
28 <Error Id="$(var.msierrIISFailedReadWebError)" Message="!(loc.msierrIISFailedReadWebError)" />
29 <Error Id="$(var.msierrIISFailedReadHttpHeader)" Message="!(loc.msierrIISFailedReadHttpHeader)" />
30
31 <Error Id="$(var.msierrIISFailedSchedTransaction)" Message="!(loc.msierrIISFailedSchedTransaction)" />
32 <Error Id="$(var.msierrIISFailedSchedInstallWebs)" Message="!(loc.msierrIISFailedSchedInstallWebs)" />
33 <Error Id="$(var.msierrIISFailedSchedInstallWebDirs)" Message="!(loc.msierrIISFailedSchedInstallWebDirs)" />
34 <Error Id="$(var.msierrIISFailedSchedInstallVDirs)" Message="!(loc.msierrIISFailedSchedInstallVDirs)" />
35 <Error Id="$(var.msierrIISFailedSchedInstallFilters)" Message="!(loc.msierrIISFailedSchedInstallFilters)" />
36 <Error Id="$(var.msierrIISFailedSchedInstallAppPool)" Message="!(loc.msierrIISFailedSchedInstallAppPool)" />
37 <Error Id="$(var.msierrIISFailedSchedInstallProp)" Message="!(loc.msierrIISFailedSchedInstallProp)" />
38 <Error Id="$(var.msierrIISFailedSchedInstallWebSvcExt)" Message="!(loc.msierrIISFailedSchedInstallWebSvcExt)" />
39
40 <Error Id="$(var.msierrIISFailedSchedUninstallWebs)" Message="!(loc.msierrIISFailedSchedUninstallWebs)" />
41 <Error Id="$(var.msierrIISFailedSchedUninstallWebDirs)" Message="!(loc.msierrIISFailedSchedUninstallWebDirs)" />
42 <Error Id="$(var.msierrIISFailedSchedUninstallVDirs)" Message="!(loc.msierrIISFailedSchedUninstallVDirs)" />
43 <Error Id="$(var.msierrIISFailedSchedUninstallFilters)" Message="!(loc.msierrIISFailedSchedUninstallFilters)" />
44 <Error Id="$(var.msierrIISFailedSchedUninstallAppPool)" Message="!(loc.msierrIISFailedSchedUninstallAppPool)" />
45 <Error Id="$(var.msierrIISFailedSchedUninstallProp)" Message="!(loc.msierrIISFailedSchedUninstallProp)" />
46 <Error Id="$(var.msierrIISFailedSchedUninstallWebSvcExt)" Message="!(loc.msierrIISFailedSchedUninstallWebSvcExt)" />
47
48 <Error Id="$(var.msierrIISFailedStartTransaction)" Message="!(loc.msierrIISFailedStartTransaction)" />
49 <Error Id="$(var.msierrIISFailedOpenKey)" Message="!(loc.msierrIISFailedOpenKey)" />
50 <Error Id="$(var.msierrIISFailedCreateKey)" Message="!(loc.msierrIISFailedCreateKey)" />
51 <Error Id="$(var.msierrIISFailedWriteData)" Message="!(loc.msierrIISFailedWriteData)" />
52 <Error Id="$(var.msierrIISFailedCreateApp)" Message="!(loc.msierrIISFailedCreateApp)" />
53 <Error Id="$(var.msierrIISFailedDeleteKey)" Message="!(loc.msierrIISFailedDeleteKey)" />
54 <Error Id="$(var.msierrIISFailedDeleteValue)" Message="!(loc.msierrIISFailedDeleteValue)" />
55 <Error Id="$(var.msierrIISFailedCommitInUse)" Message="!(loc.msierrIISFailedCommitInUse)" />
56 </UI>
57 </Fragment>
58</Wix>
diff --git a/src/ext/Iis/wixlib/IIsExtension_Platform.wxi b/src/ext/Iis/wixlib/IIsExtension_Platform.wxi
new file mode 100644
index 00000000..09562a69
--- /dev/null
+++ b/src/ext/Iis/wixlib/IIsExtension_Platform.wxi
@@ -0,0 +1,66 @@
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
4<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?include caDecor.wxi ?>
6
7 <Fragment>
8 <UIRef Id="WixIIsErrors" />
9 <UI>
10 <ProgressText Action="$(var.Prefix)ConfigureIIs$(var.Suffix)" Message="!(loc.ConfigureIIs)" />
11 <ProgressText Action="$(var.Prefix)ConfigureIIsExec$(var.Suffix)" Message="!(loc.ConfigureIIsExec)" />
12 <ProgressText Action="$(var.Prefix)StartMetabaseTransaction$(var.Suffix)" Message="!(loc.StartMetabaseTransaction)" />
13 <ProgressText Action="$(var.Prefix)RollbackMetabaseTransaction$(var.Suffix)" Message="!(loc.RollbackMetabaseTransaction)" />
14 <ProgressText Action="$(var.Prefix)CommitMetabaseTransaction$(var.Suffix)" Message="!(loc.CommitMetabaseTransaction)" />
15 <ProgressText Action="$(var.Prefix)WriteMetabaseChanges$(var.Suffix)" Message="!(loc.WriteMetabaseChanges)" />
16
17 <ProgressText Action="$(var.Prefix)ConfigureIIs7Exec$(var.Suffix)" Message="!(loc.ConfigureIIs7Exec)" />
18 <ProgressText Action="$(var.Prefix)StartIIS7ConfigTransaction$(var.Suffix)" Message="!(loc.StartIIS7ConfigTransaction)" />
19 <ProgressText Action="$(var.Prefix)RollbackIIS7ConfigTransaction$(var.Suffix)" Message="!(loc.RollbackIIS7ConfigTransaction)" />
20 <ProgressText Action="$(var.Prefix)CommitIIS7ConfigTransaction$(var.Suffix)" Message="!(loc.CommitIIS7ConfigTransaction)" />
21 <ProgressText Action="$(var.Prefix)WriteIIS7ConfigChanges$(var.Suffix)" Message="!(loc.WriteIIS7ConfigChanges)" />
22 </UI>
23
24 <CustomAction Id="$(var.Prefix)ConfigureIIs$(var.Suffix)" DllEntry="ConfigureIIs" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
25 <CustomAction Id="$(var.Prefix)ConfigureIIsExec$(var.Suffix)" DllEntry="ConfigureIIsExec" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
26 <CustomAction Id="$(var.Prefix)StartMetabaseTransaction$(var.Suffix)" DllEntry="StartMetabaseTransaction" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
27 <CustomAction Id="$(var.Prefix)RollbackMetabaseTransaction$(var.Suffix)" DllEntry="RollbackMetabaseTransaction" Impersonate="no" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
28 <CustomAction Id="$(var.Prefix)CommitMetabaseTransaction$(var.Suffix)" DllEntry="CommitMetabaseTransaction" Impersonate="no" Execute="commit" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
29 <CustomAction Id="$(var.Prefix)WriteMetabaseChanges$(var.Suffix)" DllEntry="WriteMetabaseChanges" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
30
31 <CustomAction Id="$(var.Prefix)ConfigureIIs7Exec$(var.Suffix)" DllEntry="ConfigureIIs7Exec" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
32 <CustomAction Id="$(var.Prefix)StartIIS7ConfigTransaction$(var.Suffix)" DllEntry="StartIIS7ConfigTransaction" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
33 <CustomAction Id="$(var.Prefix)RollbackIIS7ConfigTransaction$(var.Suffix)" DllEntry="RollbackIIS7ConfigTransaction" Impersonate="no" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
34 <CustomAction Id="$(var.Prefix)CommitIIS7ConfigTransaction$(var.Suffix)" DllEntry="CommitIIS7ConfigTransaction" Impersonate="no" Execute="commit" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
35 <CustomAction Id="$(var.Prefix)WriteIIS7ConfigChanges$(var.Suffix)" DllEntry="WriteIIS7ConfigChanges" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
36
37 <InstallExecuteSequence>
38 <Custom Action="$(var.Prefix)ConfigureIIs$(var.Suffix)" Before="RegisterUser" Overridable="yes" Condition="NOT SKIPCONFIGUREIIS AND VersionNT &gt; 400" />
39 </InstallExecuteSequence>
40 </Fragment>
41
42 <Fragment>
43 <Binary Id="IisCA$(var.Suffix)" SourceFile="!(bindpath.$(var.platform))iisca.dll" />
44 </Fragment>
45
46 <Fragment>
47 <CustomAction Id="$(var.Prefix)InstallCertificates$(var.Suffix)" DllEntry="InstallCertificates" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
48 <CustomAction Id="$(var.Prefix)UninstallCertificates$(var.Suffix)" DllEntry="UninstallCertificates" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
49
50 <CustomAction Id="$(var.Prefix)AddUserCertificate$(var.Suffix)" DllEntry="AddUserCertificate" Impersonate="yes" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" TerminalServerAware="yes" BinaryRef="IisCA$(var.Suffix)" />
51 <CustomAction Id="$(var.Prefix)AddMachineCertificate$(var.Suffix)" DllEntry="AddMachineCertificate" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
52 <CustomAction Id="$(var.Prefix)DeleteUserCertificate$(var.Suffix)" DllEntry="DeleteUserCertificate" Impersonate="yes" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" TerminalServerAware="yes" BinaryRef="IisCA$(var.Suffix)" />
53 <CustomAction Id="$(var.Prefix)DeleteMachineCertificate$(var.Suffix)" DllEntry="DeleteMachineCertificate" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
54
55 <CustomAction Id="$(var.Prefix)RollbackAddUserCertificate$(var.Suffix)" DllEntry="DeleteUserCertificate" Impersonate="yes" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" TerminalServerAware="yes" BinaryRef="IisCA$(var.Suffix)" />
56 <CustomAction Id="$(var.Prefix)RollbackAddMachineCertificate$(var.Suffix)" DllEntry="DeleteMachineCertificate" Impersonate="no" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
57 <CustomAction Id="$(var.Prefix)RollbackDeleteUserCertificate$(var.Suffix)" DllEntry="AddUserCertificate" Impersonate="yes" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" TerminalServerAware="yes" BinaryRef="IisCA$(var.Suffix)" />
58 <CustomAction Id="$(var.Prefix)RollbackDeleteMachineCertificate$(var.Suffix)" DllEntry="AddMachineCertificate" Impersonate="no" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="IisCA$(var.Suffix)" />
59
60 <InstallExecuteSequence>
61 <Custom Action="UninstallCertificates$(var.Suffix)" Before="RemoveFiles" Overridable="yes" Condition="VersionNT &gt; 400" />
62 <Custom Action="InstallCertificates$(var.Suffix)" After="InstallFiles" Overridable="yes" Condition="VersionNT &gt; 400" />
63 </InstallExecuteSequence>
64 </Fragment>
65
66</Include>
diff --git a/src/ext/Iis/wixlib/IIsExtension_arm64.wxs b/src/ext/Iis/wixlib/IIsExtension_arm64.wxs
new file mode 100644
index 00000000..39ac048f
--- /dev/null
+++ b/src/ext/Iis/wixlib/IIsExtension_arm64.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=arm64 ?>
6 <?include IIsExtension_Platform.wxi ?>
7</Wix>
diff --git a/src/ext/Iis/wixlib/IIsExtension_x64.wxs b/src/ext/Iis/wixlib/IIsExtension_x64.wxs
new file mode 100644
index 00000000..553953b3
--- /dev/null
+++ b/src/ext/Iis/wixlib/IIsExtension_x64.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=x64 ?>
6 <?include IIsExtension_Platform.wxi ?>
7</Wix>
diff --git a/src/ext/Iis/wixlib/IIsExtension_x86.wxs b/src/ext/Iis/wixlib/IIsExtension_x86.wxs
new file mode 100644
index 00000000..c99a243b
--- /dev/null
+++ b/src/ext/Iis/wixlib/IIsExtension_x86.wxs
@@ -0,0 +1,7 @@
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
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?define platform=x86 ?>
6 <?include IIsExtension_Platform.wxi ?>
7</Wix>
diff --git a/src/ext/Iis/wixlib/caDecor.wxi b/src/ext/Iis/wixlib/caDecor.wxi
new file mode 100644
index 00000000..b1711518
--- /dev/null
+++ b/src/ext/Iis/wixlib/caDecor.wxi
@@ -0,0 +1,39 @@
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
4<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <?ifdef Prefix ?>
6 <?undef Prefix ?>
7 <?endif?>
8
9 <?define Prefix="Wix4" ?>
10
11 <?ifndef platform ?>
12 <?define platform="x86" ?>
13 <?endif?>
14
15 <?if $(var.platform)="" ?>
16 <?undef platform ?>
17 <?define platform="x86" ?>
18 <?endif?>
19
20 <?ifdef Suffix ?>
21 <?undef Suffix ?>
22 <?endif?>
23
24 <?if $(var.platform)~="x86" ?>
25 <?define Suffix="_X86" ?>
26 <?endif?>
27
28 <?if $(var.platform)~="x64" ?>
29 <?define Suffix="_X64" ?>
30 <?endif?>
31
32 <?if $(var.platform)~="arm" ?>
33 <?define Suffix="_A32" ?>
34 <?endif?>
35
36 <?if $(var.platform)~="arm64" ?>
37 <?define Suffix="_A64" ?>
38 <?endif?>
39</Include>
diff --git a/src/ext/Iis/wixlib/caerr.wxi b/src/ext/Iis/wixlib/caerr.wxi
new file mode 100644
index 00000000..ff7ec121
--- /dev/null
+++ b/src/ext/Iis/wixlib/caerr.wxi
@@ -0,0 +1,96 @@
1<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 <?define msierrSecureObjectsFailedCreateSD = 25520?>
3 <?define msierrSecureObjectsFailedSet = 25521?>
4 <?define msierrSecureObjectsUnknownType = 25522?>
5 <?define msierrXmlFileFailedRead = 25530?>
6 <?define msierrXmlFileFailedOpen = 25531?>
7 <?define msierrXmlFileFailedSelect = 25532?>
8 <?define msierrXmlFileFailedSave = 25533?>
9 <?define msierrXmlConfigFailedRead = 25540?>
10 <?define msierrXmlConfigFailedOpen = 25541?>
11 <?define msierrXmlConfigFailedSelect = 25542?>
12 <?define msierrXmlConfigFailedSave = 25543?>
13 <?define msierrFirewallCannotConnect = 25580?>
14 <?define msierrIISCannotConnect = 26001?>
15 <?define msierrIISFailedReadWebSite = 26002?>
16 <?define msierrIISFailedReadWebDirs = 26003?>
17 <?define msierrIISFailedReadVDirs = 26004?>
18 <?define msierrIISFailedReadFilters = 26005?>
19 <?define msierrIISFailedReadAppPool = 26006?>
20 <?define msierrIISFailedReadMimeMap = 26007?>
21 <?define msierrIISFailedReadProp = 26008?>
22 <?define msierrIISFailedReadWebSvcExt = 26009?>
23 <?define msierrIISFailedReadWebError = 26010?>
24 <?define msierrIISFailedReadHttpHeader = 26011?>
25 <?define msierrIISFailedSchedTransaction = 26031?>
26 <?define msierrIISFailedSchedInstallWebs = 26032?>
27 <?define msierrIISFailedSchedInstallWebDirs = 26033?>
28 <?define msierrIISFailedSchedInstallVDirs = 26034?>
29 <?define msierrIISFailedSchedInstallFilters = 26035?>
30 <?define msierrIISFailedSchedInstallAppPool = 26036?>
31 <?define msierrIISFailedSchedInstallProp = 26037?>
32 <?define msierrIISFailedSchedInstallWebSvcExt = 26038?>
33 <?define msierrIISFailedSchedUninstallWebs = 26051?>
34 <?define msierrIISFailedSchedUninstallWebDirs = 26052?>
35 <?define msierrIISFailedSchedUninstallVDirs = 26053?>
36 <?define msierrIISFailedSchedUninstallFilters = 26054?>
37 <?define msierrIISFailedSchedUninstallAppPool = 26055?>
38 <?define msierrIISFailedSchedUninstallProp = 26056?>
39 <?define msierrIISFailedSchedUninstallWebSvcExt = 26057?>
40 <?define msierrIISFailedStartTransaction = 26101?>
41 <?define msierrIISFailedOpenKey = 26102?>
42 <?define msierrIISFailedCreateKey = 26103?>
43 <?define msierrIISFailedWriteData = 26104?>
44 <?define msierrIISFailedCreateApp = 26105?>
45 <?define msierrIISFailedDeleteKey = 26106?>
46 <?define msierrIISFailedDeleteApp = 26107?>
47 <?define msierrIISFailedDeleteValue = 26108?>
48 <?define msierrIISFailedCommitInUse = 26109?>
49 <?define msierrSQLFailedCreateDatabase = 26201?>
50 <?define msierrSQLFailedDropDatabase = 26202?>
51 <?define msierrSQLFailedConnectDatabase = 26203?>
52 <?define msierrSQLFailedExecString = 26204?>
53 <?define msierrSQLDatabaseAlreadyExists = 26205?>
54 <?define msierrPERFMONFailedRegisterDLL = 26251?>
55 <?define msierrPERFMONFailedUnregisterDLL = 26252?>
56 <?define msierrInstallPerfCounterData = 26253?>
57 <?define msierrUninstallPerfCounterData = 26254?>
58 <?define msierrSMBFailedCreate = 26301?>
59 <?define msierrSMBFailedDrop = 26302?>
60 <?define msierrCERTFailedOpen = 26351?>
61 <?define msierrCERTFailedAdd = 26352?>
62 <?define msierrUSRFailedUserCreate = 26401?>
63 <?define msierrUSRFailedUserCreatePswd = 26402?>
64 <?define msierrUSRFailedUserGroupAdd = 26403?>
65 <?define msierrUSRFailedUserCreateExists = 26404?>
66 <?define msierrUSRFailedGrantLogonAsService = 26405?>
67 <?define msierrDependencyMissingDependencies = 26451?>
68 <?define msierrDependencyHasDependents = 26452?>
69 <?define msierrDotNetRuntimeRequired = 27000?>
70 <?define msierrComPlusCannotConnect = 28001?>
71 <?define msierrComPlusPartitionReadFailed = 28002?>
72 <?define msierrComPlusPartitionRoleReadFailed = 28003?>
73 <?define msierrComPlusUserInPartitionRoleReadFailed = 28004?>
74 <?define msierrComPlusPartitionUserReadFailed = 28005?>
75 <?define msierrComPlusApplicationReadFailed = 28006?>
76 <?define msierrComPlusApplicationRoleReadFailed = 28007?>
77 <?define msierrComPlusUserInApplicationRoleReadFailed = 28008?>
78 <?define msierrComPlusAssembliesReadFailed = 28009?>
79 <?define msierrComPlusSubscriptionReadFailed = 28010?>
80 <?define msierrComPlusPartitionDependency = 28011?>
81 <?define msierrComPlusPartitionNotFound = 28012?>
82 <?define msierrComPlusPartitionIdConflict = 28013?>
83 <?define msierrComPlusPartitionNameConflict = 28014?>
84 <?define msierrComPlusApplicationDependency = 28015?>
85 <?define msierrComPlusApplicationNotFound = 28016?>
86 <?define msierrComPlusApplicationIdConflict = 28017?>
87 <?define msierrComPlusApplicationNameConflict = 28018?>
88 <?define msierrComPlusApplicationRoleDependency = 28019?>
89 <?define msierrComPlusApplicationRoleNotFound = 28020?>
90 <?define msierrComPlusApplicationRoleConflict = 28021?>
91 <?define msierrComPlusAssemblyDependency = 28022?>
92 <?define msierrComPlusSubscriptionIdConflict = 28023?>
93 <?define msierrComPlusSubscriptionNameConflict = 28024?>
94 <?define msierrComPlusFailedLookupNames = 28025?>
95 <?define msierrMsmqCannotConnect = 28101?>
96</Include> \ No newline at end of file
diff --git a/src/ext/Iis/wixlib/de-de.wxl b/src/ext/Iis/wixlib/de-de.wxl
new file mode 100644
index 00000000..5929f258
--- /dev/null
+++ b/src/ext/Iis/wixlib/de-de.wxl
@@ -0,0 +1,55 @@
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
4<WixLocalization Culture="de-de" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrIISCannotConnect" Overridable="yes">Konnte keine Verbindung mit dem Internet Information Server herstellen. ([2] [3] [4] [5])</String>
6 <String Id="msierrIISFailedReadWebSite" Overridable="yes">Fehler bei der Verarbeitung der WebSites. ([2] [3] [4] [5])</String>
7 <String Id="msierrIISFailedReadWebDirs" Overridable="yes">Fehler bei der Verarbeitung der WebDirs. ([2] [3] [4] [5])</String>
8 <String Id="msierrIISFailedReadVDirs" Overridable="yes">Fehler bei der Verarbeitung der WebVirtualDirs. ([2] [3] [4] [5])</String>
9 <String Id="msierrIISFailedReadFilters" Overridable="yes">Fehler bei der Verarbeitung der WebFilters. ([2] [3] [4] [5])</String>
10 <String Id="msierrIISFailedReadMimeMap" Overridable="yes">Fehler bei der Verarbeitung der MimeMaps. ([2] [3] [4] [5])</String>
11 <String Id="msierrIISFailedReadAppPool" Overridable="yes">Fehler bei der Verarbeitung der WebAppPools. ([2] [3] [4] [5])</String>
12 <String Id="msierrIISFailedReadProp" Overridable="yes">Fehler bei der Verarbeitung der WebProperties. ([2] [3] [4] [5])</String>
13 <String Id="msierrIISFailedReadWebSvcExt" Overridable="yes">Fehler bei der Verarbeitung der WebServiceExtensions. ([2] [3] [4] [5])</String>
14 <String Id="msierrIISFailedReadWebError" Overridable="yes">Fehler bei der Verarbeitung der WebErrors. ([2] [3] [4] [5])</String>
15 <String Id="msierrIISFailedReadHttpHeader" Overridable="yes">Fehler bei der Verarbeitung der HttpHeader. ([2] [3] [4] [5])</String>
16
17 <String Id="msierrIISFailedSchedTransaction" Overridable="yes">Die Transaktion für Änderungen am IIS konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
18 <String Id="msierrIISFailedSchedInstallWebs" Overridable="yes">Die Installation von IIS-Websites konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
19 <String Id="msierrIISFailedSchedInstallWebDirs" Overridable="yes">Die Installation von IIS Web Directories konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
20 <String Id="msierrIISFailedSchedInstallVDirs" Overridable="yes">Die Installation von IIS Virtual Directories konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
21 <String Id="msierrIISFailedSchedInstallFilters" Overridable="yes">Die Installation von IIS Filters konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
22 <String Id="msierrIISFailedSchedInstallAppPool" Overridable="yes">Die Installation von IIS AppPools konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
23 <String Id="msierrIISFailedSchedInstallProp" Overridable="yes">Die Installation von IIS Properties konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
24 <String Id="msierrIISFailedSchedInstallWebSvcExt" Overridable="yes">Die Installation von IIS Web Service Extensions konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
25
26 <String Id="msierrIISFailedSchedUninstallWebs" Overridable="yes">Die Deinstallation von IIS Web Sites konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
27 <String Id="msierrIISFailedSchedUninstallWebDirs" Overridable="yes">Die Deinstallation von IIS Web Directories konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
28 <String Id="msierrIISFailedSchedUninstallVDirs" Overridable="yes">Die Deinstallation von IIS Virtual Directories konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
29 <String Id="msierrIISFailedSchedUninstallFilters" Overridable="yes">Die Deinstallation von IIS Filters konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
30 <String Id="msierrIISFailedSchedUninstallAppPool" Overridable="yes">Die Deinstallation von IIS AppPools konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
31 <String Id="msierrIISFailedSchedUninstallProp" Overridable="yes">Die Deinstallation der IIS Properties konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
32 <String Id="msierrIISFailedSchedUninstallWebSvcExt" Overridable="yes">Die Deinstallation von IIS Web Service Extensions konnte nicht geschedulded werden. ([2] [3] [4] [5])</String>
33
34 <String Id="msierrIISFailedStartTransaction" Overridable="yes">Die IIS-Transaktion konnte nicht gestartet werden. ([2] [3] [4] [5])</String>
35 <String Id="msierrIISFailedOpenKey" Overridable="yes">Der Metabase Key konnte nicht geöffnet werden. ([2] [3] [4] [5])</String>
36 <String Id="msierrIISFailedCreateKey" Overridable="yes">Der Metabase Key konnte nicht erstellt werden. ([2] [3] [4] [5])</String>
37 <String Id="msierrIISFailedWriteData" Overridable="yes">Daten konnten nicht in den Metabase Key geschrieben werden. ([2] [3] [4] [5])</String>
38 <String Id="msierrIISFailedCreateApp" Overridable="yes">Webanwendung konnte nicht erstellt werden. ([2] [3] [4] [5])</String>
39 <String Id="msierrIISFailedDeleteKey" Overridable="yes">Der Metabase Key konnte nicht gelöscht werden. ([2] [3] [4] [5])</String>
40 <String Id="msierrIISFailedDeleteValue" Overridable="yes">Der Metabase Value konnte nicht gelöscht werden. ([2] [3] [4] [5])</String>
41 <String Id="msierrIISFailedCommitInUse" Overridable="yes">Die IIS Transaktion konnte aufgrund einer Freigabeverletzung nicht committed werden. Möglicherweise konfiguriert eine andere Anwendung derzeit IIS.</String>
42
43 <String Id="ConfigureIIs" Overridable="yes">Konfiguriere IIS</String>
44 <String Id="ConfigureIIsExec" Overridable="yes">Führe IIS Konfiguration aus</String>
45 <String Id="StartMetabaseTransaction" Overridable="yes">Starte IIS Metabase Transaktion</String>
46 <String Id="RollbackMetabaseTransaction" Overridable="yes">Mache IIS Metabase Transaktion rückgängig</String>
47 <String Id="CommitMetabaseTransaction" Overridable="yes">Committe IIS Metabase Transaktion</String>
48 <String Id="WriteMetabaseChanges" Overridable="yes">Installiere Metabase Keys und Values</String>
49
50 <String Id="ConfigureIIs7Exec" Overridable="yes">Konfiguriere IIS</String>
51 <String Id="StartIIS7ConfigTransaction" Overridable="yes">Starte IIS Konfigurationstransaktion</String>
52 <String Id="RollbackIIS7ConfigTransaction" Overridable="yes">Mache IIS Konfigurationstransaktion rückgängig</String>
53 <String Id="CommitIIS7ConfigTransaction" Overridable="yes">Committe IIS Konfigurationstransaktion</String>
54 <String Id="WriteIIS7ConfigChanges" Overridable="yes">Installiere Konfigurationskeys and -values</String>
55</WixLocalization>
diff --git a/src/ext/Iis/wixlib/en-us.wxl b/src/ext/Iis/wixlib/en-us.wxl
new file mode 100644
index 00000000..44949095
--- /dev/null
+++ b/src/ext/Iis/wixlib/en-us.wxl
@@ -0,0 +1,55 @@
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
4<WixLocalization Culture="en-us" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrIISCannotConnect" Overridable="yes">Cannot connect to Internet Information Server. ([2] [3] [4] [5])</String>
6 <String Id="msierrIISFailedReadWebSite" Overridable="yes">Failed while processing WebSites. ([2] [3] [4] [5])</String>
7 <String Id="msierrIISFailedReadWebDirs" Overridable="yes">Failed while processing WebDirs. ([2] [3] [4] [5])</String>
8 <String Id="msierrIISFailedReadVDirs" Overridable="yes">Failed while processing WebVirtualDirs. ([2] [3] [4] [5])</String>
9 <String Id="msierrIISFailedReadFilters" Overridable="yes">Failed while processing WebFilters. ([2] [3] [4] [5])</String>
10 <String Id="msierrIISFailedReadMimeMap" Overridable="yes">Failed while processing MimeMaps. ([2] [3] [4] [5])</String>
11 <String Id="msierrIISFailedReadAppPool" Overridable="yes">Failed while processing WebAppPools. ([2] [3] [4] [5])</String>
12 <String Id="msierrIISFailedReadProp" Overridable="yes">Failed while processing WebProperties. ([2] [3] [4] [5])</String>
13 <String Id="msierrIISFailedReadWebSvcExt" Overridable="yes">Failed while processing WebServiceExtensions. ([2] [3] [4] [5])</String>
14 <String Id="msierrIISFailedReadWebError" Overridable="yes">Failed while processing WebErrors. ([2] [3] [4] [5])</String>
15 <String Id="msierrIISFailedReadHttpHeader" Overridable="yes">Failed while processing HttpHeaders. ([2] [3] [4] [5])</String>
16
17 <String Id="msierrIISFailedSchedTransaction" Overridable="yes">Failed to schedule transaction for changes to IIS. ([2] [3] [4] [5])</String>
18 <String Id="msierrIISFailedSchedInstallWebs" Overridable="yes">Failed to schedule install of IIS Web Sites. ([2] [3] [4] [5])</String>
19 <String Id="msierrIISFailedSchedInstallWebDirs" Overridable="yes">Failed to schedule install of IIS Web Directories. ([2] [3] [4] [5])</String>
20 <String Id="msierrIISFailedSchedInstallVDirs" Overridable="yes">Failed to schedule install of IIS Virtual Directories. ([2] [3] [4] [5])</String>
21 <String Id="msierrIISFailedSchedInstallFilters" Overridable="yes">Failed to schedule install of IIS Filters. ([2] [3] [4] [5])</String>
22 <String Id="msierrIISFailedSchedInstallAppPool" Overridable="yes">Failed to schedule install of IIS AppPools. ([2] [3] [4] [5])</String>
23 <String Id="msierrIISFailedSchedInstallProp" Overridable="yes">Failed to schedule install of IIS Properties. ([2] [3] [4] [5])</String>
24 <String Id="msierrIISFailedSchedInstallWebSvcExt" Overridable="yes">Failed to schedule install of IIS Web Service Extensions. ([2] [3] [4] [5])</String>
25
26 <String Id="msierrIISFailedSchedUninstallWebs" Overridable="yes">Failed to schedule uninstall of IIS Web Sites. ([2] [3] [4] [5])</String>
27 <String Id="msierrIISFailedSchedUninstallWebDirs" Overridable="yes">Failed to schedule uninstall of IIS Web Directories. ([2] [3] [4] [5])</String>
28 <String Id="msierrIISFailedSchedUninstallVDirs" Overridable="yes">Failed to schedule uninstall of IIS Virtual Directories. ([2] [3] [4] [5])</String>
29 <String Id="msierrIISFailedSchedUninstallFilters" Overridable="yes">Failed to schedule uninstall of IIS Filters. ([2] [3] [4] [5])</String>
30 <String Id="msierrIISFailedSchedUninstallAppPool" Overridable="yes">Failed to schedule uninstall of IIS AppPools. ([2] [3] [4] [5])</String>
31 <String Id="msierrIISFailedSchedUninstallProp" Overridable="yes">Failed to schedule uninstall of IIS Properties. ([2] [3] [4] [5])</String>
32 <String Id="msierrIISFailedSchedUninstallWebSvcExt" Overridable="yes">Failed to schedule uninstall of IIS Web Service Extensions. ([2] [3] [4] [5])</String>
33
34 <String Id="msierrIISFailedStartTransaction" Overridable="yes">Failed to start IIS transaction. ([2] [3] [4] [5])</String>
35 <String Id="msierrIISFailedOpenKey" Overridable="yes">Failed to open metabase key. ([2] [3] [4] [5])</String>
36 <String Id="msierrIISFailedCreateKey" Overridable="yes">Failed to create metabase key. ([2] [3] [4] [5])</String>
37 <String Id="msierrIISFailedWriteData" Overridable="yes">Failed to write data to metabase key. ([2] [3] [4] [5])</String>
38 <String Id="msierrIISFailedCreateApp" Overridable="yes">Failed to create web application. ([2] [3] [4] [5])</String>
39 <String Id="msierrIISFailedDeleteKey" Overridable="yes">Failed to delete metabase key. ([2] [3] [4] [5])</String>
40 <String Id="msierrIISFailedDeleteValue" Overridable="yes">Failed to delete metabase value. ([2] [3] [4] [5])</String>
41 <String Id="msierrIISFailedCommitInUse" Overridable="yes">Failed to commit IIS transaction due to a sharing violation. Some other application may be configuring IIS.</String>
42
43 <String Id="ConfigureIIs" Overridable="yes">Configuring IIS</String>
44 <String Id="ConfigureIIsExec" Overridable="yes">Executing IIS Configuration</String>
45 <String Id="StartMetabaseTransaction" Overridable="yes">Starting IIS Metabase Transaction</String>
46 <String Id="RollbackMetabaseTransaction" Overridable="yes">Rolling back IIS Metabase Transaction</String>
47 <String Id="CommitMetabaseTransaction" Overridable="yes">Committing IIS Metabase Transaction</String>
48 <String Id="WriteMetabaseChanges" Overridable="yes">Installing Metabase Keys and Values</String>
49
50 <String Id="ConfigureIIs7Exec" Overridable="yes">Configuring IIS</String>
51 <String Id="StartIIS7ConfigTransaction" Overridable="yes">Starting IIS Config Transaction</String>
52 <String Id="RollbackIIS7ConfigTransaction" Overridable="yes">Rolling back IIS Config Transaction</String>
53 <String Id="CommitIIS7ConfigTransaction" Overridable="yes">Committing IIS Config Transaction</String>
54 <String Id="WriteIIS7ConfigChanges" Overridable="yes">Installing Config Keys and Values</String>
55</WixLocalization>
diff --git a/src/ext/Iis/wixlib/iis.v3.ncrunchproject b/src/ext/Iis/wixlib/iis.v3.ncrunchproject
new file mode 100644
index 00000000..319cd523
--- /dev/null
+++ b/src/ext/Iis/wixlib/iis.v3.ncrunchproject
@@ -0,0 +1,5 @@
1<ProjectConfiguration>
2 <Settings>
3 <IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
4 </Settings>
5</ProjectConfiguration> \ No newline at end of file
diff --git a/src/ext/Iis/wixlib/iis.wixproj b/src/ext/Iis/wixlib/iis.wixproj
new file mode 100644
index 00000000..89f9608f
--- /dev/null
+++ b/src/ext/Iis/wixlib/iis.wixproj
@@ -0,0 +1,26 @@
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<Project Sdk="WixToolset.Sdk">
3
4 <PropertyGroup>
5 <OutputType>Library</OutputType>
6 <BindFiles>true</BindFiles>
7 <Cultures>en-us</Cultures>
8 </PropertyGroup>
9
10 <ItemGroup>
11 <BindInputPaths Include="$(OutputPath)x86" BindName='x86' />
12 <BindInputPaths Include="$(OutputPath)x64" BindName='x64' />
13 <BindInputPaths Include="$(OutputPath)arm64" BindName='arm64' />
14 </ItemGroup>
15
16 <ItemGroup>
17 <ProjectReference Include="..\ca\iisca.vcxproj" Properties="Platform=ARM64" />
18 <ProjectReference Include="..\ca\iisca.vcxproj" Properties="Platform=x86" />
19 <ProjectReference Include="..\ca\iisca.vcxproj" Properties="Platform=x64" />
20 </ItemGroup>
21
22 <ItemGroup>
23 <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="All" />
24 </ItemGroup>
25
26</Project>
diff --git a/src/ext/Iis/wixlib/ja-jp.wxl b/src/ext/Iis/wixlib/ja-jp.wxl
new file mode 100644
index 00000000..7fd6978a
--- /dev/null
+++ b/src/ext/Iis/wixlib/ja-jp.wxl
@@ -0,0 +1,47 @@
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
4<WixLocalization Culture="ja-jp" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrIISCannotConnect" Overridable="yes">IISへ接続できません。 ([2] [3] [4] [5])</String>
6 <String Id="msierrIISFailedReadWebSite" Overridable="yes">ウェブ サイト処理中に失敗しました。 ([2] [3] [4] [5])</String>
7 <String Id="msierrIISFailedReadWebDirs" Overridable="yes">ウェブ ディレクトリ処理中に失敗しました。 ([2] [3] [4] [5])</String>
8 <String Id="msierrIISFailedReadVDirs" Overridable="yes">ウェブ仮想ディレクトリ処理中に失敗しました。 ([2] [3] [4] [5])</String>
9 <String Id="msierrIISFailedReadFilters" Overridable="yes">ウェブ フィルタ処理中に失敗しました。 ([2] [3] [4] [5])</String>
10 <String Id="msierrIISFailedReadMimeMap" Overridable="yes">MIME マップ処理中に失敗しました。 ([2] [3] [4] [5])</String>
11 <String Id="msierrIISFailedReadAppPool" Overridable="yes">ウェブ アプリケーション プール処理中に失敗しました。 ([2] [3] [4] [5])</String>
12 <String Id="msierrIISFailedReadProp" Overridable="yes">ウェブ プロパティ処理中に失敗しました。 ([2] [3] [4] [5])</String>
13 <String Id="msierrIISFailedReadWebSvcExt" Overridable="yes">ウェブ サービス拡張処理中に失敗しました。 ([2] [3] [4] [5])</String>
14 <String Id="msierrIISFailedReadWebError" Overridable="yes">ウェブ エラー処理中に失敗しました。 ([2] [3] [4] [5])</String>
15 <String Id="msierrIISFailedReadHttpHeader" Overridable="yes">HTTP ヘッダ処理中に失敗しました。 ([2] [3] [4] [5])</String>
16
17 <String Id="msierrIISFailedSchedTransaction" Overridable="yes">IIS 変更トランザクションのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
18 <String Id="msierrIISFailedSchedInstallWebs" Overridable="yes">IIS ウェブ サイト インストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
19 <String Id="msierrIISFailedSchedInstallWebDirs" Overridable="yes">IIS ウェブ ディレクトリ インストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
20 <String Id="msierrIISFailedSchedInstallVDirs" Overridable="yes">IIS 仮想ディレクトリ インストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
21 <String Id="msierrIISFailedSchedInstallFilters" Overridable="yes">IIS フィルタ インストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
22 <String Id="msierrIISFailedSchedInstallAppPool" Overridable="yes">IIS アプリケーション プール インストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
23 <String Id="msierrIISFailedSchedInstallProp" Overridable="yes">IIS プロパティ インストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
24 <String Id="msierrIISFailedSchedInstallWebSvcExt" Overridable="yes">IIS ウェブ サービス拡張インストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
25
26 <String Id="msierrIISFailedSchedUninstallWebs" Overridable="yes">IISウェブ サイト アンインストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
27 <String Id="msierrIISFailedSchedUninstallWebDirs" Overridable="yes">IIS ウェブ ディレクトリ アンインストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
28 <String Id="msierrIISFailedSchedUninstallVDirs" Overridable="yes">IIS 仮想ディレクトリ アンインストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
29 <String Id="msierrIISFailedSchedUninstallFilters" Overridable="yes">IIS フィルタ アンインストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
30 <String Id="msierrIISFailedSchedUninstallAppPool" Overridable="yes">IIS アプリケーション プール アンインストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
31 <String Id="msierrIISFailedSchedUninstallProp" Overridable="yes">IIS プロパティ アンインストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
32 <String Id="msierrIISFailedSchedUninstallWebSvcExt" Overridable="yes">IIS ウェブ サービス拡張アンインストールのスケジューリングに失敗しました。 ([2] [3] [4] [5])</String>
33
34 <String Id="msierrIISFailedStartTransaction" Overridable="yes">IIS トランザクション開始に失敗しました。 ([2] [3] [4] [5])</String>
35 <String Id="msierrIISFailedOpenKey" Overridable="yes">メタベース キーのオープンに失敗しました。 ([2] [3] [4] [5])</String>
36 <String Id="msierrIISFailedCreateKey" Overridable="yes">メタベース キーの作成に失敗しました。 ([2] [3] [4] [5])</String>
37 <String Id="msierrIISFailedWriteData" Overridable="yes">メタベース キーの書き込みに失敗しました。 ([2] [3] [4] [5])</String>
38 <String Id="msierrIISFailedCreateApp" Overridable="yes">ウェブ アプリケーションの作成に失敗しました。 ([2] [3] [4] [5])</String>
39 <String Id="msierrIISFailedDeleteKey" Overridable="yes">メタベース キーの削除に失敗しました。 ([2] [3] [4] [5])</String>
40 <String Id="msierrIISFailedDeleteValue" Overridable="yes">メタベース値の削除に失敗しました。 ([2] [3] [4] [5])</String>
41
42 <String Id="ConfigureIIs" Overridable="yes">IIS を構成しています</String>
43 <String Id="StartMetabaseTransaction" Overridable="yes">IIS メタベース トランザクションを開始しています</String>
44 <String Id="RollbackMetabaseTransaction" Overridable="yes">IIS メタベース トランザクションをロールバックしています</String>
45 <String Id="CommitMetabaseTransaction" Overridable="yes">IIS メタベース トランザクションを確定しています</String>
46 <String Id="WriteMetabaseChanges" Overridable="yes">IIS メタベース キーと値をインストールしています</String>
47</WixLocalization>
diff --git a/src/ext/Iis/wixlib/pt-br.wxl b/src/ext/Iis/wixlib/pt-br.wxl
new file mode 100644
index 00000000..1fc0d768
--- /dev/null
+++ b/src/ext/Iis/wixlib/pt-br.wxl
@@ -0,0 +1,50 @@
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
4<WixLocalization Culture="pt-br" xmlns="http://wixtoolset.org/schemas/v4/wxl">
5 <String Id="msierrIISCannotConnect" Overridable="yes">Não foi possível conectar no Internet Information Server. ([2] [3] [4] [5])</String>
6 <String Id="msierrIISFailedReadWebSite" Overridable="yes">Erro ao processar WebSites. ([2] [3] [4] [5])</String>
7 <String Id="msierrIISFailedReadWebDirs" Overridable="yes">Erro ao processar WebDirs. ([2] [3] [4] [5])</String>
8 <String Id="msierrIISFailedReadVDirs" Overridable="yes">Erro ao processar WebVirtualDirs. ([2] [3] [4] [5])</String>
9 <String Id="msierrIISFailedReadFilters" Overridable="yes">Erro ao processar WebFilters. ([2] [3] [4] [5])</String>
10 <String Id="msierrIISFailedReadMimeMap" Overridable="yes">Erro ao processar MimeMaps. ([2] [3] [4] [5])</String>
11 <String Id="msierrIISFailedReadAppPool" Overridable="yes">Erro ao processar WebAppPools. ([2] [3] [4] [5])</String>
12 <String Id="msierrIISFailedReadProp" Overridable="yes">Erro ao processar WebProperties. ([2] [3] [4] [5])</String>
13 <String Id="msierrIISFailedReadWebSvcExt" Overridable="yes">Erro ao processar WebServiceExtensions. ([2] [3] [4] [5])</String>
14 <String Id="msierrIISFailedReadWebError" Overridable="yes">Erro ao processar WebErrors. ([2] [3] [4] [5])</String>
15 <String Id="msierrIISFailedReadHttpHeader" Overridable="yes">Erro ao processar HttpHeaders. ([2] [3] [4] [5])</String>
16 <String Id="msierrIISFailedSchedTransaction" Overridable="yes">Erro ao agendar transação para alterações no IIS. ([2] [3] [4] [5])</String>
17 <String Id="msierrIISFailedSchedInstallWebs" Overridable="yes">Erro ao agendar instalação de IIS Web Sites. ([2] [3] [4] [5])</String>
18 <String Id="msierrIISFailedSchedInstallWebDirs" Overridable="yes">Erro ao agendar instalação de IIS Web Directories. ([2] [3] [4] [5])</String>
19 <String Id="msierrIISFailedSchedInstallVDirs" Overridable="yes">Erro ao agendar instalação de IIS Virtual Directories. ([2] [3] [4] [5])</String>
20 <String Id="msierrIISFailedSchedInstallFilters" Overridable="yes">Erro ao agendar instalação de IIS Filters. ([2] [3] [4] [5])</String>
21 <String Id="msierrIISFailedSchedInstallAppPool" Overridable="yes">Erro ao agendar instalação de IIS AppPools. ([2] [3] [4] [5])</String>
22 <String Id="msierrIISFailedSchedInstallProp" Overridable="yes">Erro ao agendar instalação de IIS Properties. ([2] [3] [4] [5])</String>
23 <String Id="msierrIISFailedSchedInstallWebSvcExt" Overridable="yes">Erro ao agendar instalação de IIS Web Service Extensions. ([2] [3] [4] [5])</String>
24 <String Id="msierrIISFailedSchedUninstallWebs" Overridable="yes">Erro ao agendar desinstalação de IIS Web Sites. ([2] [3] [4] [5])</String>
25 <String Id="msierrIISFailedSchedUninstallWebDirs" Overridable="yes">Erro ao agendar desinstalação de IIS Web Directories. ([2] [3] [4] [5])</String>
26 <String Id="msierrIISFailedSchedUninstallVDirs" Overridable="yes">Erro ao agendar desinstalação de IIS Virtual Directories. ([2] [3] [4] [5])</String>
27 <String Id="msierrIISFailedSchedUninstallFilters" Overridable="yes">Erro ao agendar desinstalação de IIS Filters. ([2] [3] [4] [5])</String>
28 <String Id="msierrIISFailedSchedUninstallAppPool" Overridable="yes">Erro ao agendar desinstalação de IIS AppPools. ([2] [3] [4] [5])</String>
29 <String Id="msierrIISFailedSchedUninstallProp" Overridable="yes">Erro ao agendar desinstalação de IIS Properties. ([2] [3] [4] [5])</String>
30 <String Id="msierrIISFailedSchedUninstallWebSvcExt" Overridable="yes">Erro ao agendar desinstalação de IIS Web Service Extensions. ([2] [3] [4] [5])</String>
31 <String Id="msierrIISFailedStartTransaction" Overridable="yes">Erro ao iniciar transação do IIS . ([2] [3] [4] [5])</String>
32 <String Id="msierrIISFailedOpenKey" Overridable="yes">Erro ao abrir metabase key. ([2] [3] [4] [5])</String>
33 <String Id="msierrIISFailedCreateKey" Overridable="yes">Erro ao criar metabase key. ([2] [3] [4] [5])</String>
34 <String Id="msierrIISFailedWriteData" Overridable="yes">Erro ao escrever dados na metabase key. ([2] [3] [4] [5])</String>
35 <String Id="msierrIISFailedCreateApp" Overridable="yes">Erro ao criar aplicação Web. ([2] [3] [4] [5])</String>
36 <String Id="msierrIISFailedDeleteKey" Overridable="yes">Erro ao excluir metabase key. ([2] [3] [4] [5])</String>
37 <String Id="msierrIISFailedDeleteValue" Overridable="yes">Erro ao excluir valor da metabase. ([2] [3] [4] [5])</String>
38 <String Id="msierrIISFailedCommitInUse" Overridable="yes">Erro ao fazer commit de transação IIS por violação de compartilhamento. Alguma outra aplicação pode estar tentando configurar o ISS ao mesmo tempo.</String>
39 <String Id="ConfigureIIs" Overridable="yes">Configurando IIS</String>
40 <String Id="ConfigureIIsExec" Overridable="yes">Executando Configurações do IIS</String>
41 <String Id="StartMetabaseTransaction" Overridable="yes">Iniciando Transação de Metabase do IIS</String>
42 <String Id="RollbackMetabaseTransaction" Overridable="yes">Cancelando Transação de Metabase do IIS</String>
43 <String Id="CommitMetabaseTransaction" Overridable="yes">Efetivando Transação de Metabase do IIS</String>
44 <String Id="WriteMetabaseChanges" Overridable="yes">Instalando Chaves e Valores de Metabase do IIS</String>
45 <String Id="ConfigureIIs7Exec" Overridable="yes">Configurando IIS</String>
46 <String Id="StartIIS7ConfigTransaction" Overridable="yes">Iniciando Transação de Configuração do IIS</String>
47 <String Id="RollbackIIS7ConfigTransaction" Overridable="yes">Cancelando Transação de Configuração do IIS</String>
48 <String Id="CommitIIS7ConfigTransaction" Overridable="yes">Efetivando Transação de Configuração do IIS</String>
49 <String Id="WriteIIS7ConfigChanges" Overridable="yes">Instalando Chaves e Valores de Configurações do IIS</String>
50</WixLocalization>