aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2018-12-16 21:19:24 -0600
committerSean Hall <r.sean.hall@gmail.com>2018-12-16 21:20:40 -0600
commit95a5a8f9efef02ddcec5b3f69be99a00d71a802a (patch)
treef0a92b8e8e37e17af6053db11f1b8a7a532cd12c
parentaec6e9a4b21accd2e8aeb2cb36ad1cdc8f308f79 (diff)
downloadwix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.tar.gz
wix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.tar.bz2
wix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.zip
Import implementation of IisCA from old repo's scasched/scaexec.
-rw-r--r--appveyor.cmd2
-rw-r--r--src/ca/CustomMsiErrors.h48
-rw-r--r--src/ca/caSuffix.h11
-rw-r--r--src/ca/iisca.def25
-rw-r--r--src/ca/iisca.vcxproj79
-rw-r--r--src/ca/precomp.h54
-rw-r--r--src/ca/sca.h124
-rw-r--r--src/ca/scaapppool.cpp594
-rw-r--r--src/ca/scaapppool.h88
-rw-r--r--src/ca/scaapppool7.cpp401
-rw-r--r--src/ca/scaapppool7.h36
-rw-r--r--src/ca/scacert.cpp1479
-rw-r--r--src/ca/scacert.h22
-rw-r--r--src/ca/scacertexec.cpp404
-rw-r--r--src/ca/scacost.h15
-rw-r--r--src/ca/scaexec.cpp1184
-rw-r--r--src/ca/scaexecIIS7.cpp4205
-rw-r--r--src/ca/scaexecIIS7.h5
-rw-r--r--src/ca/scafilter.cpp510
-rw-r--r--src/ca/scafilter.h46
-rw-r--r--src/ca/scafilter7.cpp284
-rw-r--r--src/ca/scafilter7.h21
-rw-r--r--src/ca/scahttpheader.cpp323
-rw-r--r--src/ca/scahttpheader.h40
-rw-r--r--src/ca/scahttpheader7.cpp130
-rw-r--r--src/ca/scahttpheader7.h15
-rw-r--r--src/ca/scaiis.cpp481
-rw-r--r--src/ca/scaiis.h33
-rw-r--r--src/ca/scaiis7.cpp74
-rw-r--r--src/ca/scaiis7.h17
-rw-r--r--src/ca/scamimemap.cpp200
-rw-r--r--src/ca/scamimemap.h33
-rw-r--r--src/ca/scamimemap7.cpp68
-rw-r--r--src/ca/scamimemap7.h10
-rw-r--r--src/ca/scaproperty.cpp252
-rw-r--r--src/ca/scaproperty.h54
-rw-r--r--src/ca/scaproperty7.cpp108
-rw-r--r--src/ca/scaproperty7.h26
-rw-r--r--src/ca/scasched.cpp823
-rw-r--r--src/ca/scassl.cpp115
-rw-r--r--src/ca/scassl.h36
-rw-r--r--src/ca/scassl7.cpp34
-rw-r--r--src/ca/scassl7.h8
-rw-r--r--src/ca/scauser.cpp91
-rw-r--r--src/ca/scauser.h39
-rw-r--r--src/ca/scavdir.cpp331
-rw-r--r--src/ca/scavdir.h71
-rw-r--r--src/ca/scavdir7.cpp380
-rw-r--r--src/ca/scavdir7.h66
-rw-r--r--src/ca/scaweb.cpp1187
-rw-r--r--src/ca/scaweb.h123
-rw-r--r--src/ca/scaweb7.cpp952
-rw-r--r--src/ca/scaweb7.h97
-rw-r--r--src/ca/scawebapp.cpp194
-rw-r--r--src/ca/scawebapp.h42
-rw-r--r--src/ca/scawebapp7.cpp120
-rw-r--r--src/ca/scawebapp7.h10
-rw-r--r--src/ca/scawebappext.cpp207
-rw-r--r--src/ca/scawebappext.h32
-rw-r--r--src/ca/scawebappext7.cpp61
-rw-r--r--src/ca/scawebappext7.h9
-rw-r--r--src/ca/scawebdir.cpp241
-rw-r--r--src/ca/scawebdir.h57
-rw-r--r--src/ca/scawebdir7.cpp219
-rw-r--r--src/ca/scawebdir7.h51
-rw-r--r--src/ca/scaweberr.cpp371
-rw-r--r--src/ca/scaweberr.h30
-rw-r--r--src/ca/scaweberr7.cpp88
-rw-r--r--src/ca/scaweberr7.h10
-rw-r--r--src/ca/scaweblog.cpp177
-rw-r--r--src/ca/scaweblog.h27
-rw-r--r--src/ca/scaweblog7.cpp120
-rw-r--r--src/ca/scaweblog7.h14
-rw-r--r--src/ca/scawebprop.cpp301
-rw-r--r--src/ca/scawebprop.h60
-rw-r--r--src/ca/scawebprop7.cpp155
-rw-r--r--src/ca/scawebprop7.h12
-rw-r--r--src/ca/scawebsvcext.cpp343
-rw-r--r--src/ca/scawebsvcext.h35
-rw-r--r--src/ca/scawebsvcext7.cpp106
-rw-r--r--src/ca/scawebsvcext7.h8
81 files changed, 18951 insertions, 3 deletions
diff --git a/appveyor.cmd b/appveyor.cmd
index 9b376415..3a8bbfae 100644
--- a/appveyor.cmd
+++ b/appveyor.cmd
@@ -5,7 +5,7 @@ nuget restore
5 5
6msbuild -p:Configuration=Release -t:Restore 6msbuild -p:Configuration=Release -t:Restore
7 7
8rem msbuild -p:Configuration=Release src\test\WixToolsetTest.Iis\WixToolsetTest.Iis.csproj 8msbuild -p:Configuration=Release src\test\WixToolsetTest.Iis\WixToolsetTest.Iis.csproj
9 9
10msbuild -p:Configuration=Release -t:Pack src\wixext\WixToolset.Iis.wixext.csproj 10msbuild -p:Configuration=Release -t:Pack src\wixext\WixToolset.Iis.wixext.csproj
11 11
diff --git a/src/ca/CustomMsiErrors.h b/src/ca/CustomMsiErrors.h
new file mode 100644
index 00000000..1fd8d050
--- /dev/null
+++ b/src/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/ca/caSuffix.h b/src/ca/caSuffix.h
new file mode 100644
index 00000000..303a99e9
--- /dev/null
+++ b/src/ca/caSuffix.h
@@ -0,0 +1,11 @@
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 _WIN64
6#define PLATFORM_DECORATION(f) f L"_64"
7#elif defined ARM
8#define PLATFORM_DECORATION(f) f L"_ARM"
9#else
10#define PLATFORM_DECORATION(f) f
11#endif
diff --git a/src/ca/iisca.def b/src/ca/iisca.def
index 187269e1..b9127da6 100644
--- a/src/ca/iisca.def
+++ b/src/ca/iisca.def
@@ -4,4 +4,27 @@
4LIBRARY "iisca" 4LIBRARY "iisca"
5 5
6EXPORTS 6EXPORTS
7 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/ca/iisca.vcxproj b/src/ca/iisca.vcxproj
index f83268b2..08ac4444 100644
--- a/src/ca/iisca.vcxproj
+++ b/src/ca/iisca.vcxproj
@@ -38,7 +38,7 @@
38 </ImportGroup> 38 </ImportGroup>
39 39
40 <PropertyGroup> 40 <PropertyGroup>
41 <ProjectAdditionalLinkLibraries>msi.lib</ProjectAdditionalLinkLibraries> 41 <ProjectAdditionalLinkLibraries>crypt32.lib;msi.lib;Ws2_32.lib</ProjectAdditionalLinkLibraries>
42 </PropertyGroup> 42 </PropertyGroup>
43 43
44 <ItemGroup> 44 <ItemGroup>
@@ -46,10 +46,87 @@
46 <PrecompiledHeader>Create</PrecompiledHeader> 46 <PrecompiledHeader>Create</PrecompiledHeader>
47 </ClCompile> 47 </ClCompile>
48 <ClCompile Include="iisca.cpp" /> 48 <ClCompile Include="iisca.cpp" />
49 <ClCompile Include="scaapppool.cpp" />
50 <ClCompile Include="scaapppool7.cpp" />
51 <ClCompile Include="scacert.cpp" />
52 <ClCompile Include="scacertexec.cpp" />
53 <ClCompile Include="scaexec.cpp" />
54 <ClCompile Include="scaexecIIS7.cpp" />
55 <ClCompile Include="scafilter.cpp" />
56 <ClCompile Include="scafilter7.cpp" />
57 <ClCompile Include="scahttpheader.cpp" />
58 <ClCompile Include="scahttpheader7.cpp" />
59 <ClCompile Include="scaiis.cpp" />
60 <ClCompile Include="scaiis7.cpp" />
61 <ClCompile Include="scamimemap.cpp" />
62 <ClCompile Include="scamimemap7.cpp" />
63 <ClCompile Include="scaproperty.cpp" />
64 <ClCompile Include="scaproperty7.cpp" />
65 <ClCompile Include="scasched.cpp" />
66 <ClCompile Include="scassl.cpp" />
67 <ClCompile Include="scassl7.cpp" />
68 <ClCompile Include="scauser.cpp" />
69 <ClCompile Include="scavdir.cpp" />
70 <ClCompile Include="scavdir7.cpp" />
71 <ClCompile Include="scaweb.cpp" />
72 <ClCompile Include="scaweb7.cpp" />
73 <ClCompile Include="scawebapp.cpp" />
74 <ClCompile Include="scawebapp7.cpp" />
75 <ClCompile Include="scawebappext.cpp" />
76 <ClCompile Include="scawebappext7.cpp" />
77 <ClCompile Include="scawebdir.cpp" />
78 <ClCompile Include="scawebdir7.cpp" />
79 <ClCompile Include="scaweberr.cpp" />
80 <ClCompile Include="scaweberr7.cpp" />
81 <ClCompile Include="scaweblog.cpp" />
82 <ClCompile Include="scaweblog7.cpp" />
83 <ClCompile Include="scawebprop.cpp" />
84 <ClCompile Include="scawebprop7.cpp" />
85 <ClCompile Include="scawebsvcext.cpp" />
86 <ClCompile Include="scawebsvcext7.cpp" />
49 </ItemGroup> 87 </ItemGroup>
50 88
51 <ItemGroup> 89 <ItemGroup>
90 <ClInclude Include="caSuffix.h" />
91 <ClInclude Include="CustomMsiErrors.h" />
52 <ClInclude Include="precomp.h" /> 92 <ClInclude Include="precomp.h" />
93 <ClInclude Include="sca.h" />
94 <ClInclude Include="scaapppool.h" />
95 <ClInclude Include="scaapppool7.h" />
96 <ClInclude Include="scacert.h" />
97 <ClInclude Include="scacost.h" />
98 <ClInclude Include="scaexecIIS7.h" />
99 <ClInclude Include="scafilter.h" />
100 <ClInclude Include="scafilter7.h" />
101 <ClInclude Include="scahttpheader.h" />
102 <ClInclude Include="scahttpheader7.h" />
103 <ClInclude Include="scaiis.h" />
104 <ClInclude Include="scaiis7.h" />
105 <ClInclude Include="scamimemap.h" />
106 <ClInclude Include="scamimemap7.h" />
107 <ClInclude Include="scaproperty.h" />
108 <ClInclude Include="scaproperty7.h" />
109 <ClInclude Include="scassl.h" />
110 <ClInclude Include="scassl7.h" />
111 <ClInclude Include="scauser.h" />
112 <ClInclude Include="scavdir.h" />
113 <ClInclude Include="scavdir7.h" />
114 <ClInclude Include="scaweb.h" />
115 <ClInclude Include="scaweb7.h" />
116 <ClInclude Include="scawebapp.h" />
117 <ClInclude Include="scawebapp7.h" />
118 <ClInclude Include="scawebappext.h" />
119 <ClInclude Include="scawebappext7.h" />
120 <ClInclude Include="scawebdir.h" />
121 <ClInclude Include="scawebdir7.h" />
122 <ClInclude Include="scaweberr.h" />
123 <ClInclude Include="scaweberr7.h" />
124 <ClInclude Include="scaweblog.h" />
125 <ClInclude Include="scaweblog7.h" />
126 <ClInclude Include="scawebprop.h" />
127 <ClInclude Include="scawebprop7.h" />
128 <ClInclude Include="scawebsvcext.h" />
129 <ClInclude Include="scawebsvcext7.h" />
53 </ItemGroup> 130 </ItemGroup>
54 131
55 <ItemGroup> 132 <ItemGroup>
diff --git a/src/ca/precomp.h b/src/ca/precomp.h
index 3edad7ed..efddb5f2 100644
--- a/src/ca/precomp.h
+++ b/src/ca/precomp.h
@@ -2,12 +2,66 @@
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. 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 3
4 4
5#if _WIN32_MSI < 150
6#define _WIN32_MSI 150
7#endif
8
5#include <windows.h> 9#include <windows.h>
6#include <msiquery.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
7 19
8#define MAXUINT USHRT_MAX 20#define MAXUINT USHRT_MAX
9#include <Setup.Configuration.h> 21#include <Setup.Configuration.h>
10 22
11#include "wcautil.h" 23#include "wcautil.h"
24#include "wcawow64.h"
25#include "wcawrapquery.h"
26
27#include "certutil.h"
28#include "cryputil.h"
12#include "fileutil.h" 29#include "fileutil.h"
30#include "iis7util.h"
31#include "memutil.h"
32#include "metautil.h"
13#include "strutil.h" 33#include "strutil.h"
34#include "userutil.h"
35#include "wiutil.h"
36
37#include "CustomMsiErrors.h"
38#include "sca.h"
39#include "scacost.h"
40#include "scacert.h"
41#include "scafilter.h"
42
43#include "scaiis.h"
44#include "scaiis7.h"
45#include "scaproperty.h"
46#include "scaweb.h"
47#include "scawebdir.h"
48#include "scawebsvcext.h"
49#include "scavdir.h"
50#include "scaweb7.h"
51#include "scaapppool7.h"
52#include "scavdir7.h"
53#include "scawebapp7.h"
54#include "scawebappext7.h"
55#include "scamimemap7.h"
56#include "scawebprop7.h"
57#include "scaweblog7.h"
58#include "scafilter7.h"
59#include "scahttpheader7.h"
60#include "scaweberr7.h"
61#include "scawebsvcext7.h"
62#include "scaproperty7.h"
63#include "scawebdir7.h"
64#include "scassl7.h"
65#include "scaexecIIS7.h"
66
67#include "caSuffix.h"
diff --git a/src/ca/sca.h b/src/ca/sca.h
new file mode 100644
index 00000000..64567dcb
--- /dev/null
+++ b/src/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/ca/scaapppool.cpp b/src/ca/scaapppool.cpp
new file mode 100644
index 00000000..781c55ca
--- /dev/null
+++ b/src/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/ca/scaapppool.h b/src/ca/scaapppool.h
new file mode 100644
index 00000000..68575fcb
--- /dev/null
+++ b/src/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/ca/scaapppool7.cpp b/src/ca/scaapppool7.cpp
new file mode 100644
index 00000000..0fac4346
--- /dev/null
+++ b/src/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/ca/scaapppool7.h b/src/ca/scaapppool7.h
new file mode 100644
index 00000000..1f49d899
--- /dev/null
+++ b/src/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/ca/scacert.cpp b/src/ca/scacert.cpp
new file mode 100644
index 00000000..90db6375
--- /dev/null
+++ b/src/ca/scacert.cpp
@@ -0,0 +1,1479 @@
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 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(SCA_CERT_ATTRIBUTE_BINARYDATA, &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
273 // Pick the right action to run based on what store we're uninstalling from.
274 if (CERT_SYSTEM_STORE_LOCAL_MACHINE == dwStoreLocation)
275 {
276 wzAction = L"DeleteMachineCertificate";
277 if (pbCertificate)
278 {
279 wzRollbackAction = L"RollbackDeleteMachineCertificate";
280 }
281 }
282 else
283 {
284 wzAction = L"DeleteUserCertificate";
285 if (pbCertificate)
286 {
287 wzRollbackAction = L"RollbackDeleteUserCertificate";
288 }
289 }
290 dwCost = COST_CERT_DELETE;
291 }
292 else
293 {
294 // Actually get the certificate, resolve it to a blob, and get the blob's hash.
295 hr = ResolveCertificate(pwzId, pwzName, dwStoreLocation, pwzStoreName, dwAttributes, pwzData, pwzPFXPassword, &pbCertificate, &cbCertificate);
296 ExitOnFailure(hr, "Failed to resolve certificate: %ls", pwzId);
297
298 hr = WcaWriteStreamToCaData(pbCertificate, cbCertificate, &pwzCaData);
299 ExitOnFailure(hr, "Failed to pass Certificate.Data to deferred CustomAction.");
300
301 hr = WcaWriteStringToCaData(pwzPFXPassword, &pwzCaData);
302 ExitOnFailure(hr, "Failed to pass Certificate.PFXPassword to deferred CustomAction.");
303
304 // Pick the right action to run based on what store we're installing into.
305 if (CERT_SYSTEM_STORE_LOCAL_MACHINE == dwStoreLocation)
306 {
307 wzAction = L"AddMachineCertificate";
308 wzRollbackAction = L"RollbackAddMachineCertificate";
309 }
310 else
311 {
312 wzAction = L"AddUserCertificate";
313 wzRollbackAction = L"RollbackAddUserCertificate";
314 }
315 dwCost = COST_CERT_ADD;
316 }
317
318 if (wzRollbackAction)
319 {
320 hr = WcaDoDeferredAction(wzRollbackAction, pwzRollbackCaData, dwCost);
321 ExitOnFailure(hr, "Failed to schedule rollback certificate action '%ls' for: %ls", wzRollbackAction, pwzId);
322 }
323
324 hr = WcaDoDeferredAction(wzAction, pwzCaData, dwCost);
325 ExitOnFailure(hr, "Failed to schedule certificate action '%ls' for: %ls", wzAction, pwzId);
326
327 // Clean up for the next certificate.
328 ReleaseNullMem(pbCertificate);
329 }
330
331 if (E_NOMOREITEMS == hr)
332 {
333 hr = S_OK;
334 }
335
336LExit:
337 if (NULL != pwzPFXPassword && SUCCEEDED(StrSize(pwzPFXPassword, &cbPFXPassword)))
338 {
339 SecureZeroMemory(pwzPFXPassword, cbPFXPassword);
340 }
341
342 ReleaseMem(pbCertificate);
343 ReleaseStr(pwzCaData);
344 ReleaseStr(pwzPFXPassword);
345 ReleaseStr(pwzData);
346 ReleaseStr(pwzName);
347 ReleaseStr(pwzStoreName);
348 ReleaseStr(pwzComponent);
349 ReleaseStr(pwzId);
350
351 return hr;
352}
353
354
355static HRESULT ResolveCertificate(
356 __in LPCWSTR wzId,
357 __in LPCWSTR /*wzName*/,
358 __in DWORD dwStoreLocation,
359 __in LPCWSTR /*wzStoreName*/,
360 __in DWORD dwAttributes,
361 __in LPCWSTR wzData,
362 __in LPCWSTR wzPFXPassword,
363 __out BYTE** ppbCertificate,
364 __out DWORD* pcbCertificate
365 )
366{
367 HRESULT hr = S_OK;
368
369 LPWSTR pwzSql = NULL;
370 PMSIHANDLE hView;
371 PMSIHANDLE hRec;
372 MSIHANDLE hCertificateHashView = NULL;
373 MSIHANDLE hCertificateHashColumns = NULL;
374
375 BYTE rgbCertificateHash[CB_CERTIFICATE_HASH] = { 0 };
376 WCHAR wzEncodedCertificateHash[CB_CERTIFICATE_HASH * 2 + 1] = { 0 };
377
378 PMSIHANDLE hViewCertificateRequest, hRecCertificateRequest;
379
380 WCHAR* pwzDistinguishedName = NULL;
381 WCHAR* pwzCA = NULL;
382
383 BYTE* pbData = NULL;
384 DWORD cbData = 0;
385
386 if (dwAttributes & SCA_CERT_ATTRIBUTE_REQUEST)
387 {
388 hr = E_NOTIMPL;
389 ExitOnFailure(hr, "Installing certificates by requesting them from a certificate authority is not currently supported");
390 //if (dwAttributes & SCA_CERT_ATTRIBUTE_OVERWRITE)
391 //{
392 // // try to overwrite with the patch to a cert file
393 // WcaLog(LOGMSG_VERBOSE, "ConfigureCertificates - Overwrite with SSLCERTIFICATE");
394 // hr = ScaGetCertificateByPath(pwzName, fIsInstalling, fIsUninstalling,
395 // iStore, iStoreLocation, pwzData, wzPFXPassword, pbstrCertificate, pcbCertificate, pbaHashBuffer);
396 //}
397 //if (hr != S_OK)
398 //{
399 // if (fIsUninstalling && !fIsInstalling)
400 // {
401 // // for uninstall, we just want to find the existing certificate
402 // hr = ScaSslExistingCertificateByName(pwzName, iStore, iStoreLocation, pbstrCertificate, pcbCertificate, pbaHashBuffer);
403 // ExitOnFailure(hr, "Failed Retrieving existing certificate during uninstall");
404 // // ok if no existing cert
405 // if (S_OK != hr)
406 // hr = S_OK;
407 // }
408 // else
409 // {
410 // // still no certificate
411 // // user has request this certificate, try to locate DistinguishedName and CA
412 // hr = WcaTableExists(L"CertificateRequest");
413 // ExitOnFailure(hr, "CertificateRequest is referenced but not found");
414 // WcaLog(LOGMSG_VERBOSE, "ConfigureCertificates - CertificateRequest table present");
415 // cchSQLView = 255 + lstrlenW(pwzName);
416 // pwzSQLView = new WCHAR[cchSQLView];
417 // if (pwzSQLView)
418 // {
419 // hr = ::StringCchPrintfW(pwzSQLView, cchSQLView, L"SELECT `DistinguishedName`, `CA` FROM `CertificateRequest` WHERE `Certificate_`=\'%s\'", pwzName);
420 // ExitOnFailure(hr, "::StringCchPrintfW failed");
421 // hr = WcaOpenExecuteView(pwzSQLView, &hViewCertificateRequest);
422 // ExitOnFailure(hr, "failed to open view on CertificateRequest table");
423 // hr = WcaFetchSingleRecord(hViewCertificateRequest, &hRecCertificateRequest);
424 // ExitOnFailure(hr, "failed to retrieve request from CertificateRequest table");
425 // hr = WcaGetRecordString(hRecCertificateRequest, 1, &pwzDistinguishedName);
426 // ExitOnFailure(hr, "failed to get DistinguishedName");
427 // hr = WcaGetRecordString(hRecCertificateRequest, 2, &pwzCA);
428 // ExitOnFailure(hr, "failed to get CA");
429 // if (pwzDistinguishedName && pwzCA && *pwzDistinguishedName && *pwzCA)
430 // {
431 // hr = ScaGetCertificateByRequest(pwzName, fIsInstalling, fIsUninstalling, iStore, iStoreLocation, pwzDistinguishedName, pwzCA, pbstrCertificate, pcbCertificate, pbaHashBuffer);
432 // }
433 // else
434 // {
435 // hr = E_FAIL;
436 // ExitOnFailure(hr, "CertificateRequest entry is empty");
437 // }
438 // }
439 // else
440 // {
441 // hr = E_FAIL;
442 // ExitOnFailure(hr, "Out of memory");
443 // }
444 // }
445 //}
446 }
447 else if (dwAttributes & SCA_CERT_ATTRIBUTE_BINARYDATA)
448 {
449 // get the binary stream in Binary
450 hr = WcaTableExists(L"Binary");
451 if (S_OK != hr)
452 {
453 if (SUCCEEDED(hr))
454 {
455 hr = E_UNEXPECTED;
456 }
457 ExitOnFailure(hr, "Binary was referenced but there is no Binary table.");
458 }
459
460 hr = StrAllocFormatted(&pwzSql, L"SELECT `Data` FROM `Binary` WHERE `Name`=\'%s\'", wzData);
461 ExitOnFailure(hr, "Failed to allocate Binary table query.");
462
463 hr = WcaOpenExecuteView(pwzSql, &hView);
464 ExitOnFailure(hr, "Failed to open view on Binary table");
465
466 hr = WcaFetchSingleRecord(hView, &hRec);
467 ExitOnFailure(hr, "Failed to retrieve request from Binary table");
468
469 hr = WcaGetRecordStream(hRec, 1, &pbData, &cbData);
470 ExitOnFailure(hr, "Failed to ready Binary.Data for certificate.");
471 }
472 else if (dwAttributes == SCA_CERT_ATTRIBUTE_DEFAULT)
473 {
474 hr = ReadCertificateFile(wzData, &pbData, &cbData);
475 ExitOnFailure(hr, "Failed to read certificate from file path.");
476 }
477 else
478 {
479 hr = E_INVALIDARG;
480 ExitOnFailure(hr, "Invalid Certificate.Attributes.");
481 }
482
483 // If we have loaded a certificate, update the Certificate.Hash column.
484 if (pbData)
485 {
486 hr = CertificateToHash(pbData, cbData, dwStoreLocation, wzPFXPassword, rgbCertificateHash, countof(rgbCertificateHash));
487 ExitOnFailure(hr, "Failed to get SHA1 hash of certificate.");
488
489 hr = StrHexEncode(rgbCertificateHash, countof(rgbCertificateHash), wzEncodedCertificateHash, countof(wzEncodedCertificateHash));
490 ExitOnFailure(hr, "Failed to hex encode SHA1 hash of certificate.");
491
492 // Update the CertificateHash table.
493 hr = WcaAddTempRecord(&hCertificateHashView, &hCertificateHashColumns, L"CertificateHash", NULL, 0, 2, wzId, wzEncodedCertificateHash);
494 ExitOnFailure(hr, "Failed to add encoded has for certificate: %ls", wzId);
495 }
496
497 *ppbCertificate = pbData;
498 *pcbCertificate = cbData;
499 pbData = NULL;
500
501LExit:
502 if (hCertificateHashColumns)
503 {
504 ::MsiCloseHandle(hCertificateHashColumns);
505 }
506
507 if (hCertificateHashView)
508 {
509 ::MsiCloseHandle(hCertificateHashView);
510 }
511
512 ReleaseStr(pwzDistinguishedName);
513 ReleaseStr(pwzCA);
514 ReleaseMem(pbData);
515 ReleaseStr(pwzSql);
516
517 return hr;
518}
519
520
521static HRESULT ReadCertificateFile(
522 __in LPCWSTR wzPath,
523 __out BYTE** prgbData,
524 __out DWORD* pcbData
525 )
526{
527 HRESULT hr = S_OK;
528
529 PCCERT_CONTEXT pCertContext = NULL;
530 DWORD dwContentType;
531 BYTE* pbData = NULL;
532 DWORD cbData = 0;
533
534 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))
535 {
536 ExitOnFailure(hr, "Failed to read certificate from file: %ls", wzPath);
537 }
538
539 if (pCertContext)
540 {
541 cbData = pCertContext->cbCertEncoded;
542 pbData = static_cast<BYTE*>(MemAlloc(cbData, FALSE));
543 ExitOnNull(pbData, hr, E_OUTOFMEMORY, "Failed to allocate memory to read certificate from file: %ls", wzPath);
544
545 CopyMemory(pbData, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
546 }
547 else
548 {
549 // If we have a PFX blob, get the first certificate out of the PFX and use that instead of the PFX.
550 if (dwContentType & CERT_QUERY_CONTENT_PFX)
551 {
552 hr = FileRead(&pbData, &cbData, wzPath);
553 ExitOnFailure(hr, "Failed to read PFX file: %ls", wzPath);
554 }
555 else
556 {
557 hr = E_UNEXPECTED;
558 ExitOnFailure(hr, "Unexpected certificate type read from disk.");
559 }
560 }
561
562 *pcbData = cbData;
563 *prgbData = pbData;
564 pbData = NULL;
565
566LExit:
567 ReleaseMem(pbData);
568 return hr;
569}
570
571
572static HRESULT CertificateToHash(
573 __in BYTE* pbCertificate,
574 __in DWORD cbCertificate,
575 __in DWORD dwStoreLocation,
576 __in LPCWSTR wzPFXPassword,
577 __in BYTE rgbHash[],
578 __in DWORD cbHash
579 )
580{
581 HRESULT hr = S_OK;
582
583 HCERTSTORE hPfxCertStore = NULL;
584 PCCERT_CONTEXT pCertContext = NULL;
585 PCCERT_CONTEXT pCertContextEnum = NULL;
586 CRYPT_DATA_BLOB blob = { 0 };
587 CRYPT_KEY_PROV_INFO* pPfxInfo = NULL;
588 DWORD dwKeyset = (CERT_SYSTEM_STORE_CURRENT_USER == dwStoreLocation) ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET;
589 DWORD dwEncodingType;
590 DWORD dwContentType;
591 DWORD dwFormatType;
592
593 blob.pbData = pbCertificate;
594 blob.cbData = cbCertificate;
595
596 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))
597 {
598 ExitWithLastError(hr, "Failed to process certificate as a valid certificate.");
599 }
600
601 if (!pCertContext)
602 {
603 // If we have a PFX blob, get the first certificate out of the PFX and use that instead of the PFX.
604 if (dwContentType & CERT_QUERY_CONTENT_PFX)
605 {
606 // If we fail and our password is blank, also try passing in NULL for the password (according to the docs)
607 hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, wzPFXPassword, dwKeyset);
608 if (NULL == hPfxCertStore && !*wzPFXPassword)
609 {
610 hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, NULL, dwKeyset);
611 }
612 ExitOnNullWithLastError(hPfxCertStore, hr, "Failed to open PFX file.");
613
614 // Find the first cert with a private key, or just use the last one
615 for (pCertContextEnum = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContextEnum);
616 pCertContextEnum;
617 pCertContextEnum = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContextEnum))
618 {
619 pCertContext = pCertContextEnum;
620
621 if (pCertContext && CertHasPrivateKey(pCertContext, NULL))
622 {
623 break;
624 }
625 }
626
627 ExitOnNullWithLastError(pCertContext, hr, "Failed to read first certificate out of PFX file.");
628
629 // Ignore failures, the worst that happens is some parts of the PFX get left behind.
630 CertReadProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, &pPfxInfo, NULL);
631 }
632 else
633 {
634 hr = E_UNEXPECTED;
635 ExitOnFailure(hr, "Unexpected certificate type processed.");
636 }
637 }
638
639 DWORD cb = cbHash;
640 if (!::CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, static_cast<LPVOID>(rgbHash), &cb))
641 {
642 ExitWithLastError(hr, "Failed to get certificate SHA1 hash property.");
643 }
644 AssertSz(cb == cbHash, "Did not correctly read certificate SHA1 hash.");
645
646LExit:
647 if (pCertContext)
648 {
649 ::CertFreeCertificateContext(pCertContext);
650 }
651
652 if (hPfxCertStore)
653 {
654 ::CertCloseStore(hPfxCertStore, 0);
655 }
656
657 if (pPfxInfo)
658 {
659 HCRYPTPROV hProvIgnored = NULL; // ignored on deletes.
660 ::CryptAcquireContextW(&hProvIgnored, pPfxInfo->pwszContainerName, pPfxInfo->pwszProvName, pPfxInfo->dwProvType, dwKeyset | CRYPT_DELETEKEYSET | CRYPT_SILENT);
661
662 MemFree(pPfxInfo);
663 }
664
665 return hr;
666}
667
668
669static HRESULT FindExistingCertificate(
670 __in LPCWSTR wzName,
671 __in DWORD dwStoreLocation,
672 __in LPCWSTR wzStore,
673 __out BYTE** prgbCertificate,
674 __out DWORD* pcbCertificate
675 )
676{
677 HRESULT hr = S_OK;
678 HCERTSTORE hCertStore = NULL;
679 PCCERT_CONTEXT pCertContext = NULL;
680 BYTE* pbCertificate = NULL;
681 DWORD cbCertificate = 0;
682
683 hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwStoreLocation | CERT_STORE_READONLY_FLAG, wzStore);
684 MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "Failed to open certificate store.");
685
686 // Loop through the certificate, looking for certificates that match our friendly name.
687 pCertContext = CertFindCertificateInStore(hCertStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL);
688 while (pCertContext)
689 {
690 WCHAR wzFriendlyName[256] = { 0 };
691 DWORD cbFriendlyName = sizeof(wzFriendlyName);
692
693 if (::CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, reinterpret_cast<BYTE*>(wzFriendlyName), &cbFriendlyName) &&
694 CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, 0, wzName, -1, wzFriendlyName, -1))
695 {
696 // If the certificate with matching friendly name is valid, let's use that.
697 long lVerify = ::CertVerifyTimeValidity(NULL, pCertContext->pCertInfo);
698 if (0 == lVerify)
699 {
700 cbCertificate = pCertContext->cbCertEncoded;
701 pbCertificate = static_cast<BYTE*>(MemAlloc(cbCertificate, FALSE));
702 ExitOnNull(pbCertificate, hr, E_OUTOFMEMORY, "Failed to allocate memory to copy out exist certificate.");
703
704 CopyMemory(pbCertificate, pCertContext->pbCertEncoded, cbCertificate);
705 break; // found a matching certificate, no more searching necessary
706 }
707 }
708
709 // Next certificate in the store.
710 PCCERT_CONTEXT pNext = ::CertFindCertificateInStore(hCertStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, pCertContext);
711 // old pCertContext is freed by CertFindCertificateInStore
712 pCertContext = pNext;
713 }
714
715 *prgbCertificate = pbCertificate;
716 *pcbCertificate = cbCertificate;
717 pbCertificate = NULL;
718
719LExit:
720 ReleaseMem(pbCertificate);
721
722 if (pCertContext)
723 {
724 ::CertFreeCertificateContext(pCertContext);
725 }
726
727 if (hCertStore)
728 {
729 ::CertCloseStore(hCertStore, 0);
730 }
731
732 return hr;
733}
734
735/*
736HRESULT CreateEnroll(ICEnroll2 **hEnroll, INT iStore, INT iStoreLocation)
737{
738 ICEnroll2 *pEnroll = NULL;
739 HRESULT hr = S_OK;
740 LONG lFlags;
741 DWORD dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT;
742
743 // create IEntroll
744 hr = CoCreateInstance( CLSID_CEnroll, NULL, CLSCTX_INPROC_SERVER, IID_ICEnroll2, (void **)&pEnroll );
745 if (FAILED(hr))
746 return hr;
747
748 switch (iStore)
749 {
750 case SCA_CERT_STORENAME_MY:
751 pEnroll->get_MyStoreFlags(&lFlags);
752 lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
753 lFlags |= dwFlags;
754 // following call will change Request store flags also
755 pEnroll->put_MyStoreFlags(lFlags);
756 break;
757 case SCA_CERT_STORENAME_CA:
758 pEnroll->get_CAStoreFlags(&lFlags);
759 lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
760 lFlags |= dwFlags;
761 // following call will change Request store flags also
762 pEnroll->put_CAStoreFlags(lFlags);
763 break;
764 case SCA_CERT_STORENAME_REQUEST:
765 pEnroll->get_RequestStoreFlags(&lFlags);
766 lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
767 lFlags |= dwFlags;
768 // following call will change Request store flags also
769 pEnroll->put_RequestStoreFlags(lFlags);
770 break;
771 case SCA_CERT_STORENAME_ROOT:
772 pEnroll->get_RootStoreFlags(&lFlags);
773 lFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
774 lFlags |= dwFlags;
775 // following call will change Request store flags also
776 pEnroll->put_RootStoreFlags(lFlags);
777 break;
778 default:
779 hr = E_FAIL;
780 return hr;
781 }
782
783 pEnroll->get_GenKeyFlags(&lFlags);
784 lFlags |= CRYPT_EXPORTABLE;
785 pEnroll->put_GenKeyFlags(lFlags);
786
787 pEnroll->put_KeySpec(AT_KEYEXCHANGE);
788 pEnroll->put_ProviderType(PROV_RSA_SCHANNEL);
789 pEnroll->put_DeleteRequestCert(TRUE);
790
791 *hEnroll = pEnroll;
792 return hr;
793}
794
795
796HRESULT RequestCertificate(LPCWSTR pwzName, INT iStore, INT iStoreLocation,
797 LPCWSTR wzComputerName, LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthority,
798 BSTR *pbstrCertificate)
799{
800 if (pbstrCertificate == NULL)
801 return E_INVALIDARG;
802
803 HRESULT hr;
804 ICEnroll2 *pEnroll = NULL;
805 ICertRequest *pCertRequest = NULL;
806 BSTR bstrRequest = NULL;
807 LONG nDisposition;
808
809 BSTR bstrCertificateUsage = NULL;
810 BSTR bstrCertificateAttributes = NULL;
811 BSTR bstrCertificateAuthority = NULL;
812
813 // equivalent to: sprintf(bstrDistinguishedName, L"%s,CN=%s", wzDistinguishedName, wzComputerName);
814 DWORD cchComputerName = lstrlenW(wzComputerName);
815 DWORD cchDistinguishedName = lstrlenW(wzDistinguishedName);
816 CONST DWORD cchbstrDistinguishedName = 5 + cchComputerName + cchDistinguishedName;
817 BSTR bstrDistinguishedName = SysAllocStringLen(NULL, cchbstrDistinguishedName);
818 ExitOnNull(bstrDistinguishedName, hr, E_OUTOFMEMORY, "Failed to allocate space for distinguished name.");
819 ::StringCchCopyW((WCHAR*) bstrDistinguishedName, cchbstrDistinguishedName, wzDistinguishedName);
820 ::StringCchCatW((WCHAR*) bstrDistinguishedName, cchbstrDistinguishedName, L",CN=");
821 ::StringCchCatW((WCHAR*) bstrDistinguishedName, cchbstrDistinguishedName, wzComputerName);
822
823 bstrCertificateUsage = SysAllocString(WIDE(szOID_PKIX_KP_SERVER_AUTH));
824 ExitOnNull(bstrCertificateUsage, hr, E_OUTOFMEMORY, "Failed to allocate space for Certificate Usage.");
825 bstrCertificateAttributes = SysAllocString(L"CertificateTemplate:WebServer");
826 bstrCertificateAuthority = SysAllocString(wzCertificateAuthority);
827 ExitOnNull(bstrCertificateAuthority, hr, E_OUTOFMEMORY, "Failed to allocate space for Certificate Authority.");
828
829 hr = CreateEnroll(&pEnroll, iStore, iStoreLocation);
830 ExitOnFailure(hr, "failed CoCreateInstance IEnroll");
831
832 hr = pEnroll->createPKCS10(bstrDistinguishedName, bstrCertificateUsage, &bstrRequest);
833 ExitOnFailure(hr, "failed createPKCS10");
834
835 hr = CoCreateInstance(CLSID_CCertRequest, NULL, CLSCTX_INPROC_SERVER, IID_ICertRequest, (void **)&pCertRequest);
836 ExitOnFailure(hr, "failed CoCreateInstance ICertRequest");
837
838 hr = pCertRequest->Submit(CR_IN_BASE64 | CR_IN_PKCS10, bstrRequest, bstrCertificateAttributes, bstrCertificateAuthority, &nDisposition);
839 ExitOnFailure(hr, "failed ICertRequest.Submit");
840
841 hr = (nDisposition == CR_DISP_ISSUED) ? S_OK : E_FAIL;
842 ExitOnFailure(hr, "failed CR_DISP_ISSUED");
843
844 hr = pCertRequest->GetCertificate(CR_OUT_BASE64, pbstrCertificate);
845 ExitOnFailure(hr, "failed ICertRequest.GetCertificate");
846
847 // save the certificate in place, cannot be passed to a deferred custom action
848 hr = pEnroll->acceptPKCS7(*pbstrCertificate);
849 ExitOnFailure(hr, "failed accept certificate into MY store");
850
851LExit:
852 ReleaseObject(pCertRequest);
853 ReleaseBSTR(bstrRequest);
854 ReleaseObject(pEnroll);
855 ReleaseBSTR(bstrCertificateAuthority);
856 ReleaseBSTR(bstrCertificateAttributes);
857 ReleaseBSTR(bstrDistinguishedName);
858
859 return hr;
860}
861
862
863VOID ParseCertificateAuthority(__in LPCWSTR wzCertificateAuthorityOrig, __out LPWSTR *pwzBuffer, __out LPWSTR **hwzCAArray, __out int *piCAArray)
864{
865 // @asAuthorities = split /;/, $sAuthority;
866 CONST WCHAR wchDelimiter = L';';
867
868 // copy constant into a buffer
869 Assert(wzCertificateAuthorityOrig);
870
871 INT cchCA = lstrlenW(wzCertificateAuthorityOrig) + 1;
872 WCHAR* wzBuffer = new WCHAR[cchCA];
873 if (!wzBuffer)
874 return;
875
876 ::StringCchCopyW(wzBuffer, cchCA, wzCertificateAuthorityOrig);
877
878 // determine the number of strings in the field
879 int iCAArray = 1;
880 int i;
881 for (i = 0; i < cchCA; ++i)
882 {
883 if (wzBuffer[i] == wchDelimiter)
884 ++iCAArray;
885 }
886 LPWSTR *pwzCAArray = (LPWSTR*) new BYTE[iCAArray * sizeof(LPWSTR)];
887 if (!pwzCAArray)
888 {
889 return;
890 }
891
892 pwzCAArray[0] = wzBuffer;
893 iCAArray = 0;
894 for (i = 0; i < cchCA; ++i)
895 {
896 if (wzBuffer[i] != wchDelimiter)
897 continue;
898 wzBuffer[i] = 0; // convert buffer into MULTISZ
899 pwzCAArray[iCAArray] = &wzBuffer[i+1];
900 ++iCAArray;
901 }
902
903 *pwzBuffer = wzBuffer;
904 *hwzCAArray = pwzCAArray;
905 *piCAArray = iCAArray;
906}
907
908
909HRESULT ScaSslExistingCertificateByBinaryData(INT iStore, INT iStoreLocation, BYTE* pwzData, DWORD cchData)
910{
911 HRESULT hr = S_FALSE;
912 HCERTSTORE hCertStore = NULL;
913 PCCERT_CONTEXT pCertCtx = NULL, pCertCtxExisting = NULL;
914 DWORD dwFlags = 0;
915 LPCWSTR wzStore = StoreMapping(iStore);
916 CERT_BLOB blob;
917
918 dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT;
919 hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwFlags, wzStore);
920 MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "failed to open certificate store, OK on uninstall");
921
922 blob.pbData = pwzData;
923 blob.cbData = cchData;
924
925 if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL,
926 0, NULL, NULL, NULL, NULL, NULL, (LPCVOID*)&pCertCtx))
927 ExitOnLastError(hr, "failed to parse the certificate blob, OK on uninstall");
928
929 pCertCtxExisting = CertFindCertificateInStore(
930 hCertStore,
931 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
932 0,
933 CERT_FIND_EXISTING,
934 pCertCtx,
935 NULL);
936
937 if (pCertCtxExisting)
938 {
939 hr = S_OK;
940 }
941
942LExit:
943 if (pCertCtx)
944 {
945 CertFreeCertificateContext(pCertCtx);
946 pCertCtx = NULL;
947 }
948 if (pCertCtxExisting)
949 {
950 CertFreeCertificateContext(pCertCtxExisting);
951 pCertCtxExisting = NULL;
952 }
953 if (hCertStore)
954 {
955 CertCloseStore(hCertStore, 0);
956 hCertStore = NULL;
957 }
958
959 return hr;
960}
961
962
963HRESULT ScaSslExistingCertificateByName(LPCWSTR pwzName, INT iStore, INT iStoreLocation,
964 BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer)
965{
966 HRESULT hr = S_FALSE;
967 HCERTSTORE hSystemStore = NULL;
968 PCCERT_CONTEXT pTargetCert = NULL;
969 WCHAR wzFriendlyName[MAX_PATH] = {0};
970 DWORD dwFriendlyNameLen = sizeof(wzFriendlyName);
971
972 // Call CertOpenStore to open the CA store.
973 hSystemStore = CertOpenStore(
974 CERT_STORE_PROV_SYSTEM_REGISTRY,
975 0,
976 NULL,
977 (iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT) | CERT_STORE_OPEN_EXISTING_FLAG,
978 StoreMapping(iStore));
979 if (hSystemStore == NULL)
980 ExitFunction();
981
982 // Get a particular certificate using CertFindCertificateInStore.
983 pTargetCert = CertFindCertificateInStore(
984 hSystemStore,
985 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
986 0,
987 CERT_FIND_ANY,
988 NULL,
989 NULL);
990 while (pTargetCert != NULL)
991 {
992 if ((CertGetCertificateContextProperty(pTargetCert, CERT_FRIENDLY_NAME_PROP_ID,
993 (BYTE*)wzFriendlyName, &dwFriendlyNameLen)) &&
994 lstrcmpW(wzFriendlyName, pwzName) == 0)
995 {
996 // pTargetCert is a pointer to the desired certificate.
997 // Check the certificate's validity.
998 switch (CertVerifyTimeValidity(
999 NULL,
1000 pTargetCert->pCertInfo))
1001 {
1002 case 1:
1003 // Certificate is expired
1004 WcaLog(LOGMSG_STANDARD, "The SSL certificate has expired");
1005 // always remove it
1006 {
1007 PCCERT_CONTEXT pDupCertContext = CertDuplicateCertificateContext(pTargetCert);
1008 if (pDupCertContext && CertDeleteCertificateFromStore(pDupCertContext))
1009 {
1010 WcaLog(LOGMSG_STANDARD, "A SSL certificate has removed");
1011 }
1012 }
1013 break;
1014 case 0:
1015 // Certificate is valid
1016 WcaLog(LOGMSG_STANDARD, "The SSL certificate is valid");
1017 hr = S_OK;
1018 if (pbaHashBuffer)
1019 {
1020 // if the certificate already exists and is valid, use that one
1021 DWORD dwHashSize = CB_CERTIFICATE_HASH;
1022 hr = CertGetCertificateContextProperty(pTargetCert, CERT_SHA1_HASH_PROP_ID, (VOID*)pbaHashBuffer, &dwHashSize)
1023 ? S_OK : E_FAIL;
1024 ExitOnFailure(hr, "failed CertGetCertificateContextProperty CERT_SHA1_HASH_PROP_ID");
1025 Assert(pbstrCertificate);
1026 Assert(pcbCertificate);
1027 ReleaseBSTR(*pbstrCertificate);
1028
1029 *pbstrCertificate = SysAllocStringByteLen((LPCSTR)(pTargetCert->pbCertEncoded), pTargetCert->cbCertEncoded);
1030 *pcbCertificate = pTargetCert->cbCertEncoded;
1031 }
1032 ExitFunction();
1033 break;
1034 default:
1035 // Certificate not valid yet, ignore it
1036 WcaLog(LOGMSG_STANDARD, "The SSL certificate is not valid");
1037 break;
1038 }
1039 }
1040 pTargetCert = CertFindCertificateInStore(
1041 hSystemStore,
1042 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1043 0,
1044 CERT_FIND_ANY,
1045 NULL,
1046 pTargetCert);
1047 wzFriendlyName[0] = 0;
1048 dwFriendlyNameLen = sizeof(wzFriendlyName);
1049 }
1050
1051LExit:
1052 // Clean up memory and quit.
1053 if (pTargetCert)
1054 {
1055 CertFreeCertificateContext(pTargetCert);
1056 pTargetCert = NULL;
1057 }
1058 if (hSystemStore)
1059 {
1060 CertCloseStore(hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG);
1061 hSystemStore = NULL;
1062 }
1063
1064 return hr;
1065}
1066
1067
1068HRESULT ScaSslNewCertificate(LPCWSTR pwzName, INT iStore, INT iStoreLocation, LPCWSTR wzComputerName, LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthorityOrig,
1069 BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer)
1070{
1071
1072 if (pbstrCertificate == NULL)
1073 return E_INVALIDARG;
1074
1075 HRESULT hr = S_OK;
1076 LPWSTR wzCABuffer = NULL;
1077 LPWSTR *wzCAArray = NULL;
1078 int iCAArray = 0;
1079
1080 // otherwise call the CA for one
1081 ParseCertificateAuthority(wzCertificateAuthorityOrig, &wzCABuffer, &wzCAArray, &iCAArray);
1082
1083 // try each authority three times
1084 for (int i = 0; i < 3 * iCAArray; ++i)
1085 {
1086 LPCWSTR wzCA = wzCAArray[i % iCAArray];
1087 if (NULL == wzCA || NULL == wzCA[0]) continue;
1088 WcaLog(LOGMSG_STANDARD, "Requesting SSL certificate from %ls", wzCA);
1089 hr = RequestCertificate(pwzName, iStore, iStoreLocation, wzComputerName, wzDistinguishedName, wzCA, pbstrCertificate);
1090 if (hr == S_OK && pbstrCertificate)
1091 {
1092 // set the friendly name
1093 CRYPT_HASH_BLOB hblob;
1094 CERT_BLOB blob;
1095 HCERTSTORE hCertStore = NULL;
1096 PCCERT_CONTEXT pCertCtxExisting = NULL;
1097
1098 blob.pbData = (BYTE*)pwzName;
1099 blob.cbData = (lstrlenW(pwzName) + 1) * sizeof(pwzName[0]); // including terminating null
1100
1101 *pcbCertificate = SysStringByteLen(*pbstrCertificate);
1102 hr = CertificateToHash(*pbstrCertificate, pbaHashBuffer);
1103 ExitOnFailure(hr, "failed to CertificateToHash for an existing certificate");
1104
1105 hblob.pbData = pbaHashBuffer;
1106 hblob.cbData = CB_CERTIFICATE_HASH;
1107
1108 hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, (iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT), StoreMapping(iStore));
1109 MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "failed to open certificate store");
1110
1111 pCertCtxExisting = CertFindCertificateInStore(
1112 hCertStore,
1113 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1114 0,
1115 CERT_FIND_HASH,
1116 &hblob,
1117 NULL);
1118
1119 if (pCertCtxExisting)
1120 {
1121 CertSetCertificateContextProperty(
1122 pCertCtxExisting,
1123 CERT_FRIENDLY_NAME_PROP_ID,
1124 0,
1125 &blob);
1126 }
1127
1128 if (pCertCtxExisting)
1129 {
1130 CertFreeCertificateContext(pCertCtxExisting);
1131 pCertCtxExisting = NULL;
1132 }
1133 if (hCertStore)
1134 {
1135 CertCloseStore(hCertStore, 0);
1136 hCertStore = NULL;
1137 }
1138 ExitFunction();
1139 }
1140 if (pbstrCertificate && *pbstrCertificate)
1141 {
1142 SysFreeString(*pbstrCertificate);
1143 pbstrCertificate = NULL;
1144 }
1145 }
1146 hr = E_FAIL;
1147 ExitOnFailure(hr, "failed to RequestCertificate");
1148
1149LExit:
1150 if (wzCABuffer)
1151 {
1152 delete wzCABuffer;
1153 }
1154 if (wzCAArray)
1155 {
1156 delete wzCAArray;
1157 }
1158
1159 return hr;
1160}
1161
1162
1163HRESULT ScaGetCertificateByRequest(LPCWSTR pwzName, BOOL fIsInstalling, BOOL fIsUninstalling,
1164 INT iStore, INT iStoreLocation,
1165 LPCWSTR wzDistinguishedName, LPCWSTR wzCA,
1166 BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer)
1167{
1168 HRESULT hr = S_OK;
1169 WCHAR wzComputerName[MAX_COMPUTER_NAME] = {0};
1170 WCHAR* pwzData = NULL;
1171 DWORD cchData = 0;
1172
1173 // override %COMPUTERNAME% with DOMAINNAME property
1174 hr = WcaGetProperty( L"DOMAINNAME", &pwzData);
1175 ExitOnFailure(hr, "Failed to get Property DOMAINNAME");
1176 if (*pwzData)
1177 {
1178 // if DOMAINNAME is set, use it
1179 ::StringCchCopyW(wzComputerName, MAX_COMPUTER_NAME, pwzData);
1180 }
1181 else
1182 {
1183 // otherwise get the intranet name given by %COMPUTERNAME%
1184 GetEnvironmentVariableW(L"COMPUTERNAME", wzComputerName, MAX_COMPUTER_NAME);
1185 }
1186
1187 hr = ScaSslExistingCertificateByName(pwzName, iStore, iStoreLocation, pbstrCertificate, pcbCertificate, pbaHashBuffer);
1188 ExitOnFailure(hr, "Failed ScaSslExistingCertificateByName");
1189 if (S_OK != hr)
1190 {
1191 if (!fIsUninstalling && fIsInstalling)
1192 {
1193 // if no existing cert and not on uninstall, hit the authority
1194 WcaLog(LOGMSG_STANDARD, "Adding certificate: requested, %ls", wzDistinguishedName);
1195 hr = ScaSslNewCertificate(pwzName, iStore, iStoreLocation, wzComputerName, wzDistinguishedName, wzCA,
1196 pbstrCertificate, pcbCertificate, pbaHashBuffer);
1197 ExitOnFailure(hr, "Failed ScaSslNewCertificate");
1198 }
1199 else
1200 {
1201 // if no existing cert and uninstall
1202 hr = S_OK;
1203 }
1204 }
1205
1206LExit:
1207 ReleaseStr(pwzData);
1208
1209 return hr;
1210}
1211
1212
1213HRESULT ScaInstallCertificateByContext(LPCWSTR pwzName, INT iStore, INT iStoreLocation,
1214 PCCERT_CONTEXT pCertContext)
1215{
1216 HRESULT hr = S_OK;
1217 HCERTSTORE hCertStore = NULL;
1218 DWORD dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT;
1219 CERT_BLOB blob;
1220
1221 hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwFlags, StoreMapping(iStore));
1222 if (hCertStore == NULL)
1223 MessageExitOnLastError(hr, msierrCERTFailedOpen, "failed to open certificate store");
1224
1225 blob.pbData = (BYTE*)pwzName;
1226 blob.cbData = (lstrlenW(pwzName) + 1) * sizeof(pwzName[0]); // including terminating null
1227 CertSetCertificateContextProperty(
1228 pCertContext,
1229 CERT_FRIENDLY_NAME_PROP_ID,
1230 0,
1231 &blob);
1232
1233 if (!CertAddCertificateContextToStore(
1234 hCertStore,
1235 pCertContext,
1236 CERT_STORE_ADD_REPLACE_EXISTING,
1237 NULL))
1238 {
1239 hr = E_FAIL;
1240 MessageExitOnLastError(hr, msierrCERTFailedAdd, "failed to add certificate to the store");
1241 }
1242
1243LExit:
1244 if (hCertStore)
1245 {
1246 CertCloseStore(hCertStore, 0);
1247 hCertStore = NULL;
1248 }
1249
1250 return hr;
1251}
1252
1253
1254HRESULT ScaGetCertificateByPath(LPCWSTR pwzName, BOOL fIsInstalling, BOOL fIsUninstalling,
1255 INT iStore, INT iStoreLocation, LPCWSTR wzSslCertificate, LPCWSTR wzPFXPassword,
1256 BSTR* pbstrCertificate, DWORD* pcbCertificate, BYTE* pbaHashBuffer)
1257{
1258 Assert(wzSslCertificate);
1259 HRESULT hr = S_OK;
1260 PCCERT_CONTEXT pCertContext = NULL;
1261 DWORD dwEncodingType = 0;
1262 DWORD dwContentType = 0;
1263 DWORD dwFormatType = 0;
1264 DWORD dwHashSize = CB_CERTIFICATE_HASH;
1265 HANDLE hPfxFile = INVALID_HANDLE_VALUE;
1266 CRYPT_DATA_BLOB blob;
1267
1268 blob.pbData = NULL;
1269 blob.cbData = 0;
1270
1271 if (wzSslCertificate && wzSslCertificate[0] != 0)
1272 {
1273 if (!::CryptQueryObject(CERT_QUERY_OBJECT_FILE, (LPVOID)wzSslCertificate, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL,
1274 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertContext))
1275 hr = fIsUninstalling ? S_FALSE : HRESULT_FROM_WIN32(::GetLastError()); // don't fail on uninstall
1276 ExitOnFailure(hr, "failed CryptQueryObject");
1277 }
1278 else
1279 {
1280 hr = S_FALSE;
1281 ExitFunction();
1282 }
1283
1284 if (!pCertContext)
1285 {
1286 // this is a pfx?
1287 // make sure to exit this block of code properly for clean up blob.pbData
1288 if (dwContentType & CERT_QUERY_CONTENT_PFX)
1289 {
1290 DWORD iSize = 0, iReadSize = 0;
1291 HCERTSTORE hPfxCertStore = NULL;
1292
1293 hPfxFile = ::CreateFileW(wzSslCertificate, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1294 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1295 hr = (hPfxFile != INVALID_HANDLE_VALUE) ? S_OK : E_FAIL;
1296 ExitOnFailure(hr, "failed CryptQueryObject, file handle is null");
1297 iSize = ::GetFileSize(hPfxFile, NULL);
1298 hr = (iSize > 0) ? S_OK : E_FAIL;
1299 ExitOnFailure(hr, "failed CryptQueryObject, file size is 0");
1300 blob.pbData = new BYTE[iSize];
1301 blob.cbData = iSize;
1302 hr = (blob.pbData) ? S_OK : E_FAIL;
1303 ExitOnFailure(hr, "out of memory for blob");
1304
1305 if (::ReadFile(hPfxFile, (LPVOID)blob.pbData, iSize, &iReadSize, NULL))
1306 {
1307 hPfxCertStore = PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, wzPFXPassword,
1308 (iStoreLocation == SCA_CERTSYSTEMSTORE_CURRENTUSER) ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET);
1309 if (hPfxCertStore)
1310 {
1311 pCertContext = CertEnumCertificatesInStore(hPfxCertStore, NULL);
1312 // work only with the first certificate in pfx
1313 if (pCertContext)
1314 {
1315 hr = CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, (VOID*)pbaHashBuffer, &dwHashSize)
1316 ? S_OK : E_FAIL;
1317 ExitOnFailure(hr, "failed CertGetCertificateContextProperty CERT_SHA1_HASH_PROP_ID");
1318 ReleaseBSTR(*pbstrCertificate);
1319
1320 *pbstrCertificate = SysAllocStringByteLen((LPCSTR)(pCertContext->pbCertEncoded), pCertContext->cbCertEncoded);
1321 *pcbCertificate = pCertContext->cbCertEncoded;
1322 if (fIsInstalling)
1323 {
1324 // install the certificate, cannot defer because the data required cannot be passed
1325 hr = ScaInstallCertificateByContext(pwzName, iStore, iStoreLocation, pCertContext);
1326 }
1327 }
1328 else
1329 hr = E_FAIL;
1330 }
1331 else
1332 hr = E_FAIL;
1333 }
1334 else
1335 hr = E_FAIL;
1336 }
1337 else
1338 {
1339 ExitOnFailure(hr = E_FAIL, "failed CryptQueryObject, unknown data");
1340 }
1341 }
1342 else
1343 {
1344 // return cert and its hash
1345 hr = CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, (VOID*)pbaHashBuffer, &dwHashSize)
1346 ? S_OK : E_FAIL;
1347 ExitOnFailure(hr, "failed CertGetCertificateContextProperty CERT_SHA1_HASH_PROP_ID");
1348 ReleaseBSTR(*pbstrCertificate);
1349
1350 *pbstrCertificate = SysAllocStringByteLen((LPCSTR)(pCertContext->pbCertEncoded), pCertContext->cbCertEncoded);
1351 *pcbCertificate = pCertContext->cbCertEncoded;
1352 if (fIsInstalling)
1353 {
1354 // install the certificate, cannot defer because the data required cannot be passed
1355 hr = ScaInstallCertificateByContext(pwzName, iStore, iStoreLocation, pCertContext);
1356 }
1357 }
1358
1359LExit:
1360 if (pCertContext)
1361 {
1362 CertFreeCertificateContext(pCertContext);
1363 pCertContext = NULL;
1364 }
1365 if (hPfxFile != INVALID_HANDLE_VALUE)
1366 {
1367 CloseHandle(hPfxFile);
1368 hPfxFile = INVALID_HANDLE_VALUE;
1369 }
1370 if (blob.pbData)
1371 {
1372 delete [] blob.pbData;
1373 blob.pbData = NULL;
1374 blob.cbData = 0;
1375 }
1376
1377 return hr;
1378}
1379
1380
1381HRESULT ScaInstallCertificateByBinaryData(BOOL fAddCert, INT iStore, INT iStoreLocation, LPCWSTR wzName, BYTE* pwzData, DWORD cchData,
1382 LPCWSTR wzPFXPassword)
1383{
1384 Assert(wzName);
1385 Assert(pwzData);
1386 Assert(cchData);
1387 HRESULT hr = S_OK;
1388 HCERTSTORE hCertStore = NULL, hPfxCertStore = NULL;
1389 PCCERT_CONTEXT pCertCtx = NULL, pCertCtxExisting = NULL;
1390 DWORD dwFlags, dwEncodingType, dwContentType, dwFormatType;
1391 CERT_BLOB blob;
1392 LPCWSTR wzStore = StoreMapping(iStore);
1393
1394 dwFlags = iStoreLocation << CERT_SYSTEM_STORE_LOCATION_SHIFT;
1395 hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwFlags, wzStore);
1396 MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "failed to open certificate store");
1397
1398 blob.pbData = pwzData;
1399 blob.cbData = cchData;
1400
1401 if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, CERT_QUERY_CONTENT_FLAG_ALL, CERT_QUERY_FORMAT_FLAG_ALL,
1402 0, &dwEncodingType, &dwContentType, &dwFormatType, NULL, NULL, (LPCVOID*)&pCertCtx))
1403 ExitOnLastError(hr, "failed to parse the certificate blob");
1404 ExitOnNull(pCertCtx, hr, E_UNEXPECTED, "failed to parse the certificate blob");
1405
1406 blob.pbData = (BYTE*)wzName;
1407 blob.cbData = (lstrlenW(wzName) + 1) * sizeof(wzName[0]); // including terminating null
1408
1409 CertSetCertificateContextProperty(
1410 pCertCtx,
1411 CERT_FRIENDLY_NAME_PROP_ID,
1412 0,
1413 &blob);
1414
1415 if (fAddCert)
1416 {
1417 // Add
1418 WcaLog(LOGMSG_STANDARD, "Adding certificate: binary name, %ls", wzName);
1419 if (!CertAddCertificateContextToStore(
1420 hCertStore,
1421 pCertCtx,
1422 CERT_STORE_ADD_REPLACE_EXISTING,
1423 NULL))
1424 {
1425 hr = E_FAIL;
1426 MessageExitOnLastError(hr, msierrCERTFailedAdd, "failed to add certificate to the store");
1427 }
1428 }
1429 else
1430 {
1431 // Delete
1432 WcaLog(LOGMSG_STANDARD, "Deleting certificate provided: binary name, %ls", wzName);
1433 pCertCtxExisting = CertFindCertificateInStore(
1434 hCertStore,
1435 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1436 0,
1437 CERT_FIND_EXISTING,
1438 pCertCtx,
1439 NULL);
1440
1441 if (pCertCtxExisting)
1442 {
1443 if (!CertDeleteCertificateFromStore(pCertCtxExisting))
1444 {
1445 ExitOnLastError(hr, "failed to delete certificate");
1446 }
1447 else
1448 {
1449 pCertCtxExisting = NULL;
1450 }
1451 }
1452 }
1453
1454LExit:
1455 if (pCertCtx)
1456 {
1457 CertFreeCertificateContext(pCertCtx);
1458 pCertCtx = NULL;
1459 }
1460 if (pCertCtxExisting)
1461 {
1462 CertFreeCertificateContext(pCertCtxExisting);
1463 pCertCtxExisting = NULL;
1464 }
1465 // order is important for store
1466 if (hCertStore)
1467 {
1468 CertCloseStore(hCertStore, 0);
1469 hCertStore = NULL;
1470 }
1471 if (hPfxCertStore)
1472 {
1473 CertCloseStore(hPfxCertStore, 0);
1474 hPfxCertStore = NULL;
1475 }
1476
1477 return hr;
1478}
1479*/
diff --git a/src/ca/scacert.h b/src/ca/scacert.h
new file mode 100644
index 00000000..baa6fb8e
--- /dev/null
+++ b/src/ca/scacert.h
@@ -0,0 +1,22 @@
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};
15
16
17// Certificate.StoreLocation
18enum SCA_CERTSYSTEMSTORE
19{
20 SCA_CERTSYSTEMSTORE_CURRENTUSER = 1,
21 SCA_CERTSYSTEMSTORE_LOCALMACHINE = 2,
22};
diff --git a/src/ca/scacertexec.cpp b/src/ca/scacertexec.cpp
new file mode 100644
index 00000000..3864659f
--- /dev/null
+++ b/src/ca/scacertexec.cpp
@@ -0,0 +1,404 @@
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_opt LPCWSTR wzPFXPassword
27 );
28
29static HRESULT UninstallCertificatePackage(
30 __in HCERTSTORE hStore,
31 __in BOOL fUserCertificateStore,
32 __in LPCWSTR wzName
33 );
34
35
36/* ****************************************************************
37 AddUserCertificate - CUSTOM ACTION ENTRY POINT for adding per-user
38 certificates
39
40 * ***************************************************************/
41extern "C" UINT __stdcall AddUserCertificate(
42 __in MSIHANDLE hInstall
43 )
44{
45 HRESULT hr = S_OK;
46 DWORD er = ERROR_SUCCESS;
47
48 hr = WcaInitialize(hInstall, "AddUserCertificate");
49 ExitOnFailure(hr, "Failed to initialize AddUserCertificate.");
50
51 hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_INSTALL, CERT_SYSTEM_STORE_CURRENT_USER);
52 ExitOnFailure(hr, "Failed to install per-user certificate.");
53
54LExit:
55 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
56 return WcaFinalize(er);
57}
58
59
60/* ****************************************************************
61 AddMachineCertificate - CUSTOM ACTION ENTRY POINT for adding
62 per-machine certificates
63
64 * ***************************************************************/
65extern "C" UINT __stdcall AddMachineCertificate(
66 __in MSIHANDLE hInstall
67 )
68{
69 HRESULT hr = S_OK;
70 DWORD er = ERROR_SUCCESS;
71
72 hr = WcaInitialize(hInstall, "AddMachineCertificate");
73 ExitOnFailure(hr, "Failed to initialize AddMachineCertificate.");
74
75 hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_INSTALL, CERT_SYSTEM_STORE_LOCAL_MACHINE);
76 ExitOnFailure(hr, "Failed to install per-machine certificate.");
77
78LExit:
79 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
80 return WcaFinalize(er);
81}
82
83
84/* ****************************************************************
85 DeleteUserCertificate - CUSTOM ACTION ENTRY POINT for deleting
86 per-user certificates
87
88 * ***************************************************************/
89extern "C" UINT __stdcall DeleteUserCertificate(
90 __in MSIHANDLE hInstall
91 )
92{
93 HRESULT hr = S_OK;
94 DWORD er = ERROR_SUCCESS;
95
96 hr = WcaInitialize(hInstall, "DeleteUserCertificate");
97 ExitOnFailure(hr, "Failed to initialize DeleteUserCertificate.");
98
99 hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_UNINSTALL, CERT_SYSTEM_STORE_CURRENT_USER);
100 ExitOnFailure(hr, "Failed to uninstall per-user certificate.");
101
102LExit:
103 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
104 return WcaFinalize(er);
105}
106
107
108/* ****************************************************************
109 DeleteMachineCertificate - CUSTOM ACTION ENTRY POINT for deleting
110 per-machine certificates
111
112 * ***************************************************************/
113extern "C" UINT __stdcall DeleteMachineCertificate(
114 __in MSIHANDLE hInstall
115 )
116{
117 HRESULT hr = S_OK;
118 DWORD er = ERROR_SUCCESS;
119
120 hr = WcaInitialize(hInstall, "DeleteMachineCertificate");
121 ExitOnFailure(hr, "Failed to initialize DeleteMachineCertificate.");
122
123 hr = ExecuteCertificateOperation(hInstall, SCA_ACTION_UNINSTALL, CERT_SYSTEM_STORE_LOCAL_MACHINE);
124 ExitOnFailure(hr, "Failed to uninstall per-machine certificate.");
125
126LExit:
127 er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
128 return WcaFinalize(er);
129}
130
131
132static HRESULT ExecuteCertificateOperation(
133 __in MSIHANDLE /*hInstall*/,
134 __in SCA_ACTION saAction,
135 __in DWORD dwStoreLocation
136 )
137{
138 //AssertSz(FALSE, "Debug ExecuteCertificateOperation() here.");
139 Assert(saAction & SCA_ACTION_INSTALL || saAction & SCA_ACTION_UNINSTALL);
140
141 HRESULT hr = S_OK;
142 LPWSTR pwzCaData = NULL;
143 LPWSTR pwz;
144 LPWSTR pwzName = NULL;
145 LPWSTR pwzStore = NULL;
146 int iAttributes = 0;
147 LPWSTR pwzPFXPassword = NULL;
148 LPWSTR pwzFilePath = NULL;
149 BYTE* pbData = NULL;
150 DWORD cbData = 0;
151 DWORD cbPFXPassword = 0;
152
153 BOOL fUserStoreLocation = (CERT_SYSTEM_STORE_CURRENT_USER == dwStoreLocation);
154 HCERTSTORE hCertStore = NULL;
155
156 hr = WcaGetProperty(L"CustomActionData", &pwzCaData);
157 ExitOnFailure(hr, "Failed to get CustomActionData");
158
159 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCaData);
160
161 pwz = pwzCaData;
162 hr = WcaReadStringFromCaData(&pwz, &pwzName);
163 ExitOnFailure(hr, "Failed to parse certificate name.");
164 hr = WcaReadStringFromCaData(&pwz, &pwzStore);
165 ExitOnFailure(hr, "Failed to parse CustomActionData, StoreName");
166 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
167 ExitOnFailure(hr, "Failed to parse certificate attribute");
168 if (SCA_ACTION_INSTALL == saAction) // install operations need more data
169 {
170 hr = WcaReadStreamFromCaData(&pwz, &pbData, (DWORD_PTR*)&cbData);
171 ExitOnFailure(hr, "Failed to parse certificate stream.");
172
173 hr = WcaReadStringFromCaData(&pwz, &pwzPFXPassword);
174 ExitOnFailure(hr, "Failed to parse certificate password.");
175 }
176
177 // Open the right store.
178 hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, dwStoreLocation, pwzStore);
179 MessageExitOnNullWithLastError(hCertStore, hr, msierrCERTFailedOpen, "Failed to open certificate store: %ls", pwzStore);
180
181 if (SCA_ACTION_INSTALL == saAction) // install operations need more data
182 {
183 // Uninstall existing versions of this package. Ignore any failures
184 // This is needed to clean up the private key of a cert when we replace an existing cert
185 // CertAddCertificateContextToStore(CERT_STORE_ADD_REPLACE_EXISTING) does not remove the private key if the cert is replaced
186 UninstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName);
187
188 hr = InstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName, pbData, cbData, pwzPFXPassword);
189 ExitOnFailure(hr, "Failed to install certificate.");
190 }
191 else
192 {
193 Assert(SCA_ACTION_UNINSTALL == saAction);
194
195 hr = UninstallCertificatePackage(hCertStore, fUserStoreLocation, pwzName);
196 ExitOnFailure(hr, "Failed to uninstall certificate.");
197 }
198
199LExit:
200 if (NULL != pwzPFXPassword && SUCCEEDED(StrSize(pwzPFXPassword, &cbPFXPassword)))
201 {
202 SecureZeroMemory(pwzPFXPassword, cbPFXPassword);
203 }
204
205 if (hCertStore)
206 {
207 if (!::CertCloseStore(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG))
208 {
209 WcaLog(LOGMSG_VERBOSE, "Cert store was closed but not all resources were freed. Error 0x%x", GetLastError());
210 }
211 }
212
213 ReleaseMem(pbData);
214 ReleaseStr(pwzFilePath);
215 ReleaseStr(pwzPFXPassword);
216 ReleaseStr(pwzStore);
217 ReleaseStr(pwzName);
218 ReleaseStr(pwzCaData);
219 return hr;
220}
221
222
223static HRESULT InstallCertificatePackage(
224 __in HCERTSTORE hStore,
225 __in BOOL fUserCertificateStore,
226 __in LPCWSTR wzName,
227 __in_opt BYTE* rgbData,
228 __in DWORD cbData,
229 __in_opt LPCWSTR wzPFXPassword
230 )
231{
232 HRESULT hr = S_OK;
233
234 HCERTSTORE hPfxCertStore = NULL;
235 PCCERT_CONTEXT pCertContext = NULL;
236 CERT_BLOB blob = { 0 };
237 DWORD dwKeyset = fUserCertificateStore ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET;
238 DWORD dwEncodingType;
239 DWORD dwContentType;
240 DWORD dwFormatType;
241 LPWSTR pwzUniqueName = NULL;
242 int iUniqueId = 0;
243
244 // Figure out what type of blob (certificate or PFX) we're dealing with here.
245 blob.pbData = rgbData;
246 blob.cbData = cbData;
247
248 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))
249 {
250 ExitWithLastError(hr, "Failed to parse the certificate blob: %ls", wzName);
251 }
252
253 hr = StrAllocFormatted(&pwzUniqueName, L"%s_wixCert_%d", wzName, ++iUniqueId);
254 ExitOnFailure(hr, "Failed to format unique name");
255
256 if (!pCertContext)
257 {
258 // If we have a PFX blob, get the first certificate out of the PFX and use that instead of the PFX.
259 if (dwContentType & CERT_QUERY_CONTENT_PFX)
260 {
261 ExitOnNull(wzPFXPassword, hr, E_INVALIDARG, "Failed to import PFX blob because no password was provided");
262
263 // If we fail and our password is blank, also try passing in NULL for the password (according to the docs)
264 hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, wzPFXPassword, dwKeyset);
265 if (NULL == hPfxCertStore && !*wzPFXPassword)
266 {
267 hPfxCertStore = ::PFXImportCertStore((CRYPT_DATA_BLOB*)&blob, NULL, dwKeyset);
268 }
269 ExitOnNullWithLastError(hPfxCertStore, hr, "Failed to open PFX file.");
270
271 // Install all certificates in the PFX
272 for (pCertContext = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContext);
273 pCertContext;
274 pCertContext = ::CertEnumCertificatesInStore(hPfxCertStore, pCertContext))
275 {
276 WcaLog(LOGMSG_STANDARD, "Adding certificate: %ls", pwzUniqueName);
277 hr = CertInstallSingleCertificate(hStore, pCertContext, pwzUniqueName);
278 MessageExitOnFailure(hr, msierrCERTFailedAdd, "Failed to add certificate to the store.");
279
280 hr = StrAllocFormatted(&pwzUniqueName, L"%s_wixCert_%d", wzName, ++iUniqueId);
281 ExitOnFailure(hr, "Failed to format unique name");
282 }
283 }
284 else
285 {
286 hr = E_UNEXPECTED;
287 ExitOnFailure(hr, "Unexpected certificate type processed.");
288 }
289 }
290 else
291 {
292 WcaLog(LOGMSG_STANDARD, "Adding certificate: %ls", pwzUniqueName);
293 hr = CertInstallSingleCertificate(hStore, pCertContext, pwzUniqueName);
294 MessageExitOnFailure(hr, msierrCERTFailedAdd, "Failed to add certificate to the store.");
295 }
296
297 hr = WcaProgressMessage(COST_CERT_ADD, FALSE);
298 ExitOnFailure(hr, "Failed to send install progress message.");
299
300LExit:
301 ReleaseStr(pwzUniqueName);
302
303 if (pCertContext)
304 {
305 ::CertFreeCertificateContext(pCertContext);
306 }
307
308 // Close the stores after the context's are released.
309 if (hPfxCertStore)
310 {
311 if (!::CertCloseStore(hPfxCertStore, CERT_CLOSE_STORE_CHECK_FLAG))
312 {
313 WcaLog(LOGMSG_VERBOSE, "PFX cert store was closed but not all resources were freed. Error 0x%x", GetLastError());
314 }
315 }
316
317 return hr;
318}
319
320
321static HRESULT UninstallCertificatePackage(
322 __in HCERTSTORE hStore,
323 __in BOOL fUserCertificateStore,
324 __in LPCWSTR wzName
325 )
326{
327 HRESULT hr = S_OK;
328 DWORD er = ERROR_SUCCESS;
329 PCCERT_CONTEXT pCertContext = NULL;
330 CRYPT_KEY_PROV_INFO* pPrivateKeyInfo = NULL;
331 LPWSTR pwzUniquePrefix = NULL;
332 int ccUniquePrefix = 0;
333
334 hr = StrAllocFormatted(&pwzUniquePrefix, L"%s_wixCert_", wzName);
335 ExitOnFailure(hr, "Failed to format unique name");
336 ccUniquePrefix = ::lstrlenW(pwzUniquePrefix);
337
338 WcaLog(LOGMSG_STANDARD, "Deleting certificate that begin with friendly name: %ls", pwzUniquePrefix);
339
340 // Loop through all certificates in the store, deleting the ones that begin with our prefix.
341 while (NULL != (pCertContext = ::CertFindCertificateInStore(hStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, pCertContext)))
342 {
343 WCHAR wzFriendlyName[256] = { 0 };
344 DWORD cbFriendlyName = sizeof(wzFriendlyName);
345
346 if (::CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, reinterpret_cast<BYTE*>(wzFriendlyName), &cbFriendlyName) &&
347 lstrlenW(wzFriendlyName) >= ccUniquePrefix &&
348 CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, 0, pwzUniquePrefix, ccUniquePrefix, wzFriendlyName, ccUniquePrefix))
349 {
350 PCCERT_CONTEXT pCertContextDelete = ::CertDuplicateCertificateContext(pCertContext); // duplicate the context so we can delete it with out disrupting the looping
351 if(pCertContextDelete)
352 {
353 // Delete the certificate and if successful delete the matching private key as well.
354 if (::CertDeleteCertificateFromStore(pCertContextDelete))
355 {
356 // If we found private key info, delete it.
357 hr = CertReadProperty(pCertContextDelete, CERT_KEY_PROV_INFO_PROP_ID, &pPrivateKeyInfo, NULL);
358 if (SUCCEEDED(hr))
359 {
360 HCRYPTPROV hProvIgnored = NULL; // ignored on deletes.
361 DWORD dwKeyset = fUserCertificateStore ? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET;
362
363 if (!::CryptAcquireContextW(&hProvIgnored, pPrivateKeyInfo->pwszContainerName, pPrivateKeyInfo->pwszProvName, pPrivateKeyInfo->dwProvType, dwKeyset | CRYPT_DELETEKEYSET | CRYPT_SILENT))
364 {
365 er = ::GetLastError();
366 hr = HRESULT_FROM_WIN32(er);
367 }
368
369 ReleaseNullMem(pPrivateKeyInfo);
370 }
371 else // don't worry about failures to delete private keys.
372 {
373 hr = S_OK;
374 }
375 }
376 else
377 {
378 er = ::GetLastError();
379 hr = HRESULT_FROM_WIN32(er);
380 }
381
382 if (FAILED(hr))
383 {
384 WcaLog(LOGMSG_STANDARD, "Failed to delete certificate with friendly name: %ls, continuing anyway. Error: 0x%x", wzFriendlyName, hr);
385 }
386
387 pCertContextDelete = NULL;
388 }
389 }
390 }
391
392 hr = WcaProgressMessage(COST_CERT_DELETE, FALSE);
393 ExitOnFailure(hr, "Failed to send uninstall progress message.");
394
395LExit:
396 ReleaseStr(pwzUniquePrefix);
397 ReleaseMem(pPrivateKeyInfo);
398 if(pCertContext)
399 {
400 ::CertFreeCertificateContext(pCertContext);
401 }
402
403 return hr;
404}
diff --git a/src/ca/scacost.h b/src/ca/scacost.h
new file mode 100644
index 00000000..be92cf26
--- /dev/null
+++ b/src/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/ca/scaexec.cpp b/src/ca/scaexec.cpp
new file mode 100644
index 00000000..df25e8db
--- /dev/null
+++ b/src/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/ca/scaexecIIS7.cpp b/src/ca/scaexecIIS7.cpp
new file mode 100644
index 00000000..108007a1
--- /dev/null
+++ b/src/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/ca/scaexecIIS7.h b/src/ca/scaexecIIS7.h
new file mode 100644
index 00000000..ec31f202
--- /dev/null
+++ b/src/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/ca/scafilter.cpp b/src/ca/scafilter.cpp
new file mode 100644
index 00000000..9d9014fd
--- /dev/null
+++ b/src/ca/scafilter.cpp
@@ -0,0 +1,510 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5// prototypes
6static HRESULT ReadFilterLoadOrder(
7 __in IMSAdminBase* piMetabase,
8 __in LPCWSTR wzFilterRoot,
9 __out LPWSTR *ppwzLoadOrder
10 );
11static HRESULT AddFilterToLoadOrder(
12 __in LPCWSTR wzFilter,
13 __in int iLoadOrder,
14 __inout LPWSTR *ppwzLoadOrder
15 );
16static HRESULT RemoveFilterFromLoadOrder(
17 __in LPCWSTR wzFilter,
18 __inout LPWSTR *ppwzLoadOrder
19 );
20
21
22UINT __stdcall ScaFiltersRead(
23 __in IMSAdminBase* piMetabase,
24 __in SCA_WEB* pswList,
25 __in WCA_WRAPQUERY_HANDLE hWebBaseQuery,
26 __inout SCA_FILTER** ppsfList,
27 __inout LPWSTR *ppwzCustomActionData
28 )
29{
30 HRESULT hr = S_OK;
31 MSIHANDLE hRec;
32 INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN;
33 INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN;
34
35 LPWSTR pwzData = NULL;
36
37 SCA_FILTER* psf = NULL;
38 WCA_WRAPQUERY_HANDLE hWrapQuery = NULL;
39
40 hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData);
41 ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead");
42
43 if (0 == WcaGetQueryRecords(hWrapQuery))
44 {
45 WcaLog(LOGMSG_VERBOSE, "Skipping ScaFiltersRead() - no IIsFilter table");
46 ExitFunction1(hr = S_FALSE);
47 }
48
49 // loop through all the filters
50 while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec)))
51 {
52 // Get the Component first. If the component is not being modified during
53 // this transaction, skip processing this whole record.
54 hr = WcaGetRecordString(hRec, fqComponent, &pwzData);
55 ExitOnFailure(hr, "failed to get IIsFilter.Component");
56
57 hr = WcaGetRecordInteger(hRec, fqInstalled, (int *)&isInstalled);
58 ExitOnFailure(hr, "Failed to get Component installed state for IIs filter");
59
60 hr = WcaGetRecordInteger(hRec, fqAction, (int *)&isAction);
61 ExitOnFailure(hr, "Failed to get Component action state for IIs filter");
62
63 if (!WcaIsInstalling(isInstalled, isAction) &&
64 !WcaIsReInstalling(isInstalled, isAction) &&
65 !WcaIsUninstalling(isInstalled, isAction))
66 {
67 continue; // skip this record.
68 }
69
70 hr = AddFilterToList(ppsfList);
71 ExitOnFailure(hr, "failed to add filter to list");
72
73 psf = *ppsfList;
74
75 hr = ::StringCchCopyW(psf->wzComponent, countof(psf->wzComponent), pwzData);
76 ExitOnFailure(hr, "failed to copy component name: %ls", pwzData);
77
78 psf->isInstalled = isInstalled;
79 psf->isAction = isAction;
80
81 hr = WcaGetRecordString(hRec, fqWeb, &pwzData);
82 ExitOnFailure(hr, "Failed to get Web for VirtualDir");
83
84 if (*pwzData)
85 {
86 hr = ScaWebsGetBase(piMetabase, pswList, pwzData, psf->wzWebBase, countof(psf->wzWebBase), hWebBaseQuery);
87 if (FAILED(hr) && WcaIsUninstalling(isInstalled, isAction))
88 {
89 // If we're uninstalling, don't bother finding the existing web, just leave the filter root empty
90 hr = S_OK;
91 }
92 ExitOnFailure(hr, "Failed to get base of web for Filter");
93
94 if (0 != lstrlenW(psf->wzWebBase))
95 {
96 hr = ::StringCchPrintfW(psf->wzFilterRoot, countof(psf->wzFilterRoot), L"%s/Filters", psf->wzWebBase);
97 ExitOnFailure(hr, "Failed to allocate filter base string");
98 }
99 }
100 else
101 {
102 hr = ::StringCchCopyW(psf->wzFilterRoot, countof(psf->wzFilterRoot), L"/LM/W3SVC/Filters");
103 ExitOnFailure(hr, "Failed to allocate global filter base string");
104 }
105
106 // filter key
107 hr = WcaGetRecordString(hRec, fqFilter, &pwzData);
108 ExitOnFailure(hr, "Failed to get Filter.Filter");
109 hr = ::StringCchCopyW(psf->wzKey, countof(psf->wzKey), pwzData);
110 ExitOnFailure(hr, "Failed to copy key string to filter object");
111
112 // filter path
113 hr = WcaGetRecordString(hRec, fqPath, &pwzData);
114 ExitOnFailure(hr, "Failed to get Filter.Path");
115 hr = ::StringCchCopyW(psf->wzPath, countof(psf->wzPath), pwzData);
116 ExitOnFailure(hr, "Failed to copy path string to filter object");
117
118 // filter description
119 hr = WcaGetRecordString(hRec, fqDescription, &pwzData);
120 ExitOnFailure(hr, "Failed to get Filter.Description");
121 hr = ::StringCchCopyW(psf->wzDescription, countof(psf->wzDescription), pwzData);
122 ExitOnFailure(hr, "Failed to copy description string to filter object");
123
124 // filter flags
125 hr = WcaGetRecordInteger(hRec, fqFlags, &psf->iFlags);
126 ExitOnFailure(hr, "Failed to get Filter.Flags");
127
128 // filter load order
129 hr = WcaGetRecordInteger(hRec, fqLoadOrder, &psf->iLoadOrder);
130 ExitOnFailure(hr, "Failed to get Filter.LoadOrder");
131 }
132
133 if (E_NOMOREITEMS == hr)
134 {
135 hr = S_OK;
136 }
137 ExitOnFailure(hr, "Failure while processing filters");
138
139LExit:
140 WcaFinishUnwrapQuery(hWrapQuery);
141
142 ReleaseStr(pwzData);
143 return hr;
144}
145
146
147HRESULT ScaFiltersInstall(
148 __in IMSAdminBase* piMetabase,
149 __in SCA_FILTER* psfList
150 )
151{
152 HRESULT hr = S_OK;
153 SCA_FILTER* psf = psfList;
154 LPCWSTR wzPreviousFilterRoot = NULL;
155 LPWSTR pwzLoadOrder = NULL;
156
157 while (psf)
158 {
159 if (WcaIsInstalling(psf->isInstalled, psf->isAction))
160 {
161 if (!wzPreviousFilterRoot || CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, 0, wzPreviousFilterRoot, -1, psf->wzFilterRoot, -1))
162 {
163 if (pwzLoadOrder)
164 {
165 hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder);
166 ExitOnFailure(hr, "Failed to write filter load order to metabase");
167
168 ReleaseNullStr(pwzLoadOrder);
169 }
170
171 hr = ReadFilterLoadOrder(piMetabase, psf->wzFilterRoot, &pwzLoadOrder);
172 ExitOnFailure(hr, "Failed to read filter load order.");
173
174 wzPreviousFilterRoot = psf->wzFilterRoot;
175 }
176
177 hr = ScaCreateMetabaseKey(piMetabase, psf->wzFilterRoot, psf->wzKey);
178 ExitOnFailure(hr, "Failed to create key for filter '%ls'", psf->wzKey);
179
180 hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsFilter");
181 ExitOnFailure(hr, "Failed to write key type for filter '%ls'", psf->wzKey);
182
183 // filter path
184 hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_IMAGE_PATH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)psf->wzPath);
185 ExitOnFailure(hr, "Failed to write Path for filter '%ls'", psf->wzKey);
186
187 // filter description
188 hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_DESCRIPTION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)psf->wzDescription);
189 ExitOnFailure(hr, "Failed to write Description for filter '%ls'", psf->wzKey);
190
191 // filter flags
192 if (MSI_NULL_INTEGER != psf->iFlags)
193 {
194 hr = ScaWriteMetabaseValue(piMetabase, psf->wzFilterRoot, psf->wzKey, MD_FILTER_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psf->iFlags));
195 ExitOnFailure(hr, "Failed to write Flags for filter '%ls'", psf->wzKey);
196 }
197
198 // filter load order
199 if (MSI_NULL_INTEGER != psf->iLoadOrder)
200 {
201 hr = AddFilterToLoadOrder(psf->wzKey, psf->iLoadOrder, &pwzLoadOrder);
202 ExitOnFailure(hr, "Failed to add filter '%ls' to load order.", psf->wzKey);
203 }
204 }
205
206 psf = psf->psfNext;
207 }
208
209 if (pwzLoadOrder)
210 {
211 Assert(wzPreviousFilterRoot && *wzPreviousFilterRoot);
212
213 hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder);
214 ExitOnFailure(hr, "Failed to write filter load order to metabase");
215 }
216
217LExit:
218 ReleaseStr(pwzLoadOrder);
219 return hr;
220}
221
222
223HRESULT ScaFiltersUninstall(
224 __in IMSAdminBase* piMetabase,
225 __in SCA_FILTER* psfList
226 )
227{
228 HRESULT hr = S_OK;
229 SCA_FILTER* psf = psfList;
230 LPCWSTR wzPreviousFilterRoot = NULL;
231 LPWSTR pwzLoadOrder = NULL;
232
233 while (psf)
234 {
235 if (WcaIsUninstalling(psf->isInstalled, psf->isAction))
236 {
237 if (!wzPreviousFilterRoot || CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, 0, wzPreviousFilterRoot, -1, psf->wzFilterRoot, -1))
238 {
239 if (pwzLoadOrder)
240 {
241 hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder);
242 ExitOnFailure(hr, "Failed to write filter load order to metabase");
243
244 ReleaseNullStr(pwzLoadOrder);
245 }
246
247 hr = ReadFilterLoadOrder(piMetabase, psf->wzFilterRoot, &pwzLoadOrder);
248 ExitOnFailure(hr, "Failed to read filter load order.");
249
250 wzPreviousFilterRoot = psf->wzFilterRoot;
251 }
252
253 hr = RemoveFilterFromLoadOrder(psf->wzKey, &pwzLoadOrder);
254 ExitOnFailure(hr, "Failed to remove filter '%ls' from load order", psf->wzKey);
255
256 // remove the filter from the load order and remove the filter's key
257 if (0 != lstrlenW(psf->wzFilterRoot))
258 {
259 hr = ScaDeleteMetabaseKey(piMetabase, psf->wzFilterRoot, psf->wzKey);
260 ExitOnFailure(hr, "Failed to remove web '%ls' from metabase", psf->wzKey);
261 }
262 }
263
264 psf = psf->psfNext;
265 }
266
267 if (pwzLoadOrder)
268 {
269 Assert(wzPreviousFilterRoot && *wzPreviousFilterRoot);
270
271 hr = ScaWriteMetabaseValue(piMetabase, wzPreviousFilterRoot, L"", MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)pwzLoadOrder);
272 ExitOnFailure(hr, "Failed to write filter load order to metabase");
273 }
274
275LExit:
276 return hr;
277}
278
279
280void ScaFiltersFreeList(
281 __in SCA_FILTER* psfList
282 )
283{
284 SCA_FILTER* psfDelete = psfList;
285 while (psfList)
286 {
287 psfDelete = psfList;
288 psfList = psfList->psfNext;
289
290 MemFree(psfDelete);
291 }
292}
293
294HRESULT AddFilterToList(
295 __inout SCA_FILTER** ppsfList)
296{
297 HRESULT hr = S_OK;
298 SCA_FILTER* psf = static_cast<SCA_FILTER*>(MemAlloc(sizeof(SCA_FILTER), TRUE));
299 ExitOnNull(psf, hr, E_OUTOFMEMORY, "failed to add filter to filter list");
300
301 psf->psfNext = *ppsfList;
302 *ppsfList = psf;
303
304LExit:
305 return hr;
306}
307
308// private helper functions
309
310
311static HRESULT ReadFilterLoadOrder(
312 __in IMSAdminBase* piMetabase,
313 __in LPCWSTR wzFilterRoot,
314 __out LPWSTR *ppwzLoadOrder
315 )
316{
317 HRESULT hr = S_OK;
318 METADATA_HANDLE mhRoot = NULL;
319
320 METADATA_RECORD mr;
321 DWORD dwRequired = 0;
322 DWORD cchData = 255;
323
324 ::ZeroMemory(&mr, sizeof(mr));
325 mr.dwMDIdentifier = MD_FILTER_LOAD_ORDER;
326 mr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
327 mr.dwMDUserType = IIS_MD_UT_SERVER;
328 mr.dwMDDataType = ALL_METADATA;
329 mr.dwMDDataLen = cchData;
330 mr.pbMDData = static_cast<BYTE*>(MemAlloc(mr.dwMDDataLen * sizeof(WCHAR), TRUE));
331 ExitOnNull(mr.pbMDData, hr, E_OUTOFMEMORY, "failed to allocate memory for MDData in metadata record");
332
333 hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, wzFilterRoot, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 10, &mhRoot);
334 for (int i = 30; i > 0 && HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr; i--)
335 {
336 ::Sleep(1000);
337 WcaLog(LOGMSG_STANDARD, "Failed to open root key, retrying %d time(s)...", i);
338 hr = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, wzFilterRoot, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 10, &mhRoot);
339 }
340
341 if (SUCCEEDED(hr))
342 {
343 hr = piMetabase->GetData(mhRoot, L"", &mr, &dwRequired);
344 if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr)
345 {
346 mr.dwMDDataLen = cchData = dwRequired;
347
348 LPVOID pv = MemReAlloc(mr.pbMDData, mr.dwMDDataLen * sizeof(WCHAR), TRUE);
349 ExitOnNull(pv, hr, E_OUTOFMEMORY, "failed to allocate memory for MDData in metadata record");
350 mr.pbMDData = static_cast<BYTE*>(pv);
351
352 hr = piMetabase->GetData(mhRoot, L"", &mr, &dwRequired);
353 }
354 }
355
356 // The /Filters node or /Filters/FilterLoadOrder property might not exist (yet).
357 if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr)
358 {
359 hr = S_OK;
360 }
361 ExitOnFailure(hr, "Failed to get filter load order.");
362
363 hr = StrAllocString(ppwzLoadOrder, reinterpret_cast<LPCWSTR>(mr.pbMDData), 0);
364 ExitOnFailure(hr, "Failed to allocate string for filter load order.");
365
366LExit:
367 ReleaseMem(mr.pbMDData);
368
369 if (mhRoot)
370 {
371 piMetabase->CloseKey(mhRoot);
372 }
373
374 return hr;
375}
376
377
378static HRESULT AddFilterToLoadOrder(
379 __in LPCWSTR wzFilter,
380 __in int iLoadOrder,
381 __inout LPWSTR *ppwzLoadOrder
382 )
383{
384 HRESULT hr = S_OK;
385 LPCWSTR wzLoadOrder = *ppwzLoadOrder;
386 int cchFilter = lstrlenW(wzFilter);
387 LPWSTR pwzTemp = NULL;
388
389 // If the filter name ends with '\0' or ',' and
390 // the filter name begins at the beginning of the list or with ','
391 // Then we've found the exact filter by name.
392 //
393 // If the filter isn't already in the load order, add it
394 if (wzLoadOrder && *wzLoadOrder)
395 {
396 LPCWSTR pwz = wcsstr(wzLoadOrder, wzFilter);
397
398 if (NULL != pwz &&
399 (L'\0' == *(pwz + cchFilter) || L',' == *(pwz + cchFilter)) &&
400 (pwz == wzLoadOrder || L',' == *(pwz - 1)))
401 {
402 // Filter already in the load order, no work to do.
403 }
404 else
405 {
406 pwz = NULL;
407 if (0 <= iLoadOrder)
408 {
409 pwz = wzLoadOrder;
410 for (int i = 0; i < iLoadOrder && pwz; ++i)
411 {
412 pwz = wcsstr(pwz, L",");
413 }
414 }
415
416 if (NULL == pwz) // put the filter at the end of the order
417 {
418 Assert(wzLoadOrder && *wzLoadOrder);
419
420 // tack on a comma since there are other filters in the order
421 hr = StrAllocConcat(ppwzLoadOrder, L",", 1);
422 ExitOnFailure(hr, "Failed to append a comma to filter load order.");
423
424 hr = StrAllocConcat(ppwzLoadOrder, wzFilter, cchFilter);
425 ExitOnFailure(hr, "Failed to append the filter on to the load order.");
426 }
427 else if (L',' == *pwz) // put the filter in the middle of the order
428 {
429 hr = StrAllocString(&pwzTemp, wzLoadOrder, pwz - wzLoadOrder + 1);
430 ExitOnFailure(hr, "Failed to copy first half of filter load order to temp string.");
431
432 hr = StrAllocConcat(&pwzTemp, wzFilter, 0);
433 ExitOnFailure(hr, "Failed to copy filter into load order.");
434
435 hr = StrAllocConcat(&pwzTemp, pwz, 0);
436 ExitOnFailure(hr, "Failed to copy remaining filter load order back onto load order.");
437
438 hr = StrAllocString(ppwzLoadOrder, pwzTemp, 0);
439 ExitOnFailure(hr, "Failed to copy temp string to load order string.");
440 }
441 else // put the filter at the beginning of the order
442 {
443 hr = StrAllocPrefix(ppwzLoadOrder, L",", 1);
444 ExitOnFailure(hr, "Failed to prepend a comma to filter load order.");
445
446 hr = StrAllocPrefix(ppwzLoadOrder, wzFilter, cchFilter);
447 ExitOnFailure(hr, "Failed to prepend the filter on to the load order.");
448 }
449 }
450 }
451 else
452 {
453 hr = StrAllocString(ppwzLoadOrder, wzFilter, cchFilter);
454 ExitOnFailure(hr, "Failed to add filter to load order.");
455 }
456
457LExit:
458 ReleaseStr(pwzTemp);
459 return hr;
460}
461
462
463static HRESULT RemoveFilterFromLoadOrder(
464 __in LPCWSTR wzFilter,
465 __inout LPWSTR *ppwzLoadOrder
466 )
467{
468 HRESULT hr = S_OK;
469 int cchFilter = lstrlenW(wzFilter);
470
471 LPCWSTR pwzStart = NULL;
472 LPWSTR pwzFind = NULL;
473
474 pwzStart = pwzFind = *ppwzLoadOrder;
475 while (NULL != (pwzFind = wcsstr(pwzFind, wzFilter)))
476 {
477 // Make sure to only match [wzFilter] and NOT foo[wzFilter]bar
478 if (pwzFind == pwzStart || L',' == *(pwzFind - 1))
479 {
480 int cchRemainder = lstrlenW(pwzFind) - cchFilter + 1; // add one to include the null terminator
481
482 if (L'\0' == *(pwzFind + cchFilter))
483 {
484 if (pwzFind == pwzStart)
485 {
486 memmove(pwzFind, pwzFind + cchFilter, cchRemainder * sizeof(WCHAR)); // copy down the null terminator
487 }
488 else
489 {
490 memmove(pwzFind - 1, pwzFind + cchFilter, cchRemainder * sizeof(WCHAR)); // copy down the null terminator over top the trailing ","
491 }
492 }
493 else if (L',' == *(pwzFind + cchFilter))
494 {
495 memmove(pwzFind, pwzFind + cchFilter + 1, (cchRemainder - 1) * sizeof(WCHAR)); // skip copying the ","
496 }
497 else // skip past the partial match
498 {
499 pwzFind = pwzFind + cchFilter;
500 }
501 }
502 else // skip past the partial match
503 {
504 pwzFind = pwzFind + cchFilter;
505 }
506 }
507
508//LExit:
509 return hr;
510}
diff --git a/src/ca/scafilter.h b/src/ca/scafilter.h
new file mode 100644
index 00000000..d072bf22
--- /dev/null
+++ b/src/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/ca/scafilter7.cpp b/src/ca/scafilter7.cpp
new file mode 100644
index 00000000..dda91c4d
--- /dev/null
+++ b/src/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/ca/scafilter7.h b/src/ca/scafilter7.h
new file mode 100644
index 00000000..50ff6652
--- /dev/null
+++ b/src/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/ca/scahttpheader.cpp b/src/ca/scahttpheader.cpp
new file mode 100644
index 00000000..a8fea796
--- /dev/null
+++ b/src/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 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/ca/scahttpheader.h b/src/ca/scahttpheader.h
new file mode 100644
index 00000000..a4c407a4
--- /dev/null
+++ b/src/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/ca/scahttpheader7.cpp b/src/ca/scahttpheader7.cpp
new file mode 100644
index 00000000..645dd8d4
--- /dev/null
+++ b/src/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/ca/scahttpheader7.h b/src/ca/scahttpheader7.h
new file mode 100644
index 00000000..7a873c16
--- /dev/null
+++ b/src/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/ca/scaiis.cpp b/src/ca/scaiis.cpp
new file mode 100644
index 00000000..a29af1db
--- /dev/null
+++ b/src/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(L"StartMetabaseTransaction", wzBackup, COST_IIS_TRANSACTIONS);
16 ExitOnFailure(hr, "Failed to schedule StartMetabaseTransaction");
17
18 hr = WcaDoDeferredAction(L"RollbackMetabaseTransaction", wzBackup, 0); // rollback cost is irrelevant
19 ExitOnFailure(hr, "Failed to schedule RollbackMetabaseTransaction");
20
21 hr = WcaDoDeferredAction(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/ca/scaiis.h b/src/ca/scaiis.h
new file mode 100644
index 00000000..4c743edf
--- /dev/null
+++ b/src/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/ca/scaiis7.cpp b/src/ca/scaiis7.cpp
new file mode 100644
index 00000000..f0f4a629
--- /dev/null
+++ b/src/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(L"StartIIS7ConfigTransaction", wzBackup, COST_IIS_TRANSACTIONS);
12 ExitOnFailure(hr, "Failed to schedule StartIIS7ConfigTransaction");
13
14 hr = WcaDoDeferredAction(L"RollbackIIS7ConfigTransaction", wzBackup, 0); // rollback cost is irrelevant
15 ExitOnFailure(hr, "Failed to schedule RollbackIIS7ConfigTransaction");
16
17 hr = WcaDoDeferredAction(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/ca/scaiis7.h b/src/ca/scaiis7.h
new file mode 100644
index 00000000..f398deca
--- /dev/null
+++ b/src/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/ca/scamimemap.cpp b/src/ca/scamimemap.cpp
new file mode 100644
index 00000000..8afe99f9
--- /dev/null
+++ b/src/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/ca/scamimemap.h b/src/ca/scamimemap.h
new file mode 100644
index 00000000..b50e82e9
--- /dev/null
+++ b/src/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/ca/scamimemap7.cpp b/src/ca/scamimemap7.cpp
new file mode 100644
index 00000000..f6689720
--- /dev/null
+++ b/src/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/ca/scamimemap7.h b/src/ca/scamimemap7.h
new file mode 100644
index 00000000..88fcdc39
--- /dev/null
+++ b/src/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/ca/scaproperty.cpp b/src/ca/scaproperty.cpp
new file mode 100644
index 00000000..d0e0d8a4
--- /dev/null
+++ b/src/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/ca/scaproperty.h b/src/ca/scaproperty.h
new file mode 100644
index 00000000..21e7cfc7
--- /dev/null
+++ b/src/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/ca/scaproperty7.cpp b/src/ca/scaproperty7.cpp
new file mode 100644
index 00000000..d17eeb68
--- /dev/null
+++ b/src/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/ca/scaproperty7.h b/src/ca/scaproperty7.h
new file mode 100644
index 00000000..bbf811e8
--- /dev/null
+++ b/src/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/ca/scasched.cpp b/src/ca/scasched.cpp
new file mode 100644
index 00000000..cdece45d
--- /dev/null
+++ b/src/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(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(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(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(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/ca/scassl.cpp b/src/ca/scassl.cpp
new file mode 100644
index 00000000..4a06b77e
--- /dev/null
+++ b/src/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/ca/scassl.h b/src/ca/scassl.h
new file mode 100644
index 00000000..df7c473d
--- /dev/null
+++ b/src/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/ca/scassl7.cpp b/src/ca/scassl7.cpp
new file mode 100644
index 00000000..47c16a9d
--- /dev/null
+++ b/src/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/ca/scassl7.h b/src/ca/scassl7.h
new file mode 100644
index 00000000..1a4b09af
--- /dev/null
+++ b/src/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/ca/scauser.cpp b/src/ca/scauser.cpp
new file mode 100644
index 00000000..0b99edff
--- /dev/null
+++ b/src/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/ca/scauser.h b/src/ca/scauser.h
new file mode 100644
index 00000000..b2b94650
--- /dev/null
+++ b/src/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/ca/scavdir.cpp b/src/ca/scavdir.cpp
new file mode 100644
index 00000000..d388ce97
--- /dev/null
+++ b/src/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/ca/scavdir.h b/src/ca/scavdir.h
new file mode 100644
index 00000000..c7e9661b
--- /dev/null
+++ b/src/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/ca/scavdir7.cpp b/src/ca/scavdir7.cpp
new file mode 100644
index 00000000..3f675357
--- /dev/null
+++ b/src/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/ca/scavdir7.h b/src/ca/scavdir7.h
new file mode 100644
index 00000000..dba25431
--- /dev/null
+++ b/src/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/ca/scaweb.cpp b/src/ca/scaweb.cpp
new file mode 100644
index 00000000..0452fb0b
--- /dev/null
+++ b/src/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/ca/scaweb.h b/src/ca/scaweb.h
new file mode 100644
index 00000000..294030b4
--- /dev/null
+++ b/src/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/ca/scaweb7.cpp b/src/ca/scaweb7.cpp
new file mode 100644
index 00000000..e1893782
--- /dev/null
+++ b/src/ca/scaweb7.cpp
@@ -0,0 +1,952 @@
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 ::ZeroMemory(wzIP, sizeof(wzIP));
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);
839 ExitOnFailure(hr, "Failed to copy IP string");
840 }
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 ::ZeroMemory(wzIP, sizeof(wzIP));
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);
860 ExitOnFailure(hr, "Failed to copy web IP");
861 }
862 hr = ::StringCchPrintfW(wzBinding, countof(wzBinding), L"%s:%d:%s", wzIP, psw->swaExtraAddresses[ui].iPort, psw->swaExtraAddresses[ui].wzHeader);
863 ExitOnFailure(hr, "Failed to copy web IP");
864
865 //create bindings for site
866 hr = ScaWriteConfigID(IIS_BINDING);
867 ExitOnFailure(hr, "Failed write binding ID");
868 hr = ScaWriteConfigID(IIS_CREATE);
869 ExitOnFailure(hr, "Failed write binding action");
870 hr = ScaWriteConfigString(psw->wzDescription); //site name key
871 ExitOnFailure(hr, "Failed write binding web name");
872
873 if (psw->swaExtraAddresses[ui].fSecure)
874 {
875 hr = ScaWriteConfigString(L"https"); // binding protocol
876 }
877 else
878 {
879 hr = ScaWriteConfigString(L"http"); // binding protocol
880 }
881 ExitOnFailure(hr, "Failed write binding http(s)");
882
883 // write bindings CAData
884 hr = ScaWriteConfigString(wzBinding) ; //binding info
885 ExitOnFailure(hr, "Failed write binding info");
886 }
887
888 // write the web dirproperties information
889 if (psw->fHasProperties)
890 {
891 // dir properties are for the default application of the web
892 // with location '/'
893 hr = ScaWriteWebDirProperties7(psw->wzDescription, L"/", &psw->swp);
894 ExitOnFailure(hr, "Failed to write web security information to metabase");
895 }
896
897 //// write the application information
898 if (psw->fHasApplication)
899 {
900 hr = ScaWriteWebApplication7(psw->wzDescription, L"/", &psw->swapp, psapList);
901 ExitOnFailure(hr, "Failed to write web application information to metabase");
902 }
903
904 // write the SSL certificate information
905 if (psw->pswscList)
906 {
907 hr = ScaSslCertificateWrite7(psw->wzDescription, psw->pswscList);
908 ExitOnFailure(hr, "Failed to write SSL certificates for Web site: %ls", psw->wzKey);
909 }
910
911 // write the headers
912 if (psw->pshhList)
913 {
914 hr = ScaWriteHttpHeader7(psw->wzDescription, L"/", psw->pshhList);
915 ExitOnFailure(hr, "Failed to write custom HTTP headers for Web site: %ls", psw->wzKey);
916 }
917
918 // write the errors
919 if (psw->psweList)
920 {
921 hr = ScaWriteWebError7(psw->wzDescription, L"/", psw->psweList);
922 ExitOnFailure(hr, "Failed to write custom web errors for Web site: %ls", psw->wzKey);
923 }
924
925 // write the log information to the metabase
926 if (psw->fHasLog)
927 {
928 hr = ScaWriteWebLog7(psw->wzDescription, &psw->swl);
929 ExitOnFailure(hr, "Failed to write web log information to metabase");
930 }
931
932LExit:
933 return hr;
934}
935
936
937static HRESULT ScaWebRemove7(
938 __in const SCA_WEB7* psw
939 )
940{
941 HRESULT hr = S_OK;
942
943 hr = ScaWriteConfigID(IIS_SITE);
944 ExitOnFailure(hr, "Failed write site ID");
945 hr = ScaWriteConfigID(IIS_DELETE);
946 ExitOnFailure(hr, "Failed write site action");
947 hr = ScaWriteConfigString(psw->wzDescription); //Site Name
948 ExitOnFailure(hr, "Failed write site name");
949
950LExit:
951 return hr;
952}
diff --git a/src/ca/scaweb7.h b/src/ca/scaweb7.h
new file mode 100644
index 00000000..78946756
--- /dev/null
+++ b/src/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/ca/scawebapp.cpp b/src/ca/scawebapp.cpp
new file mode 100644
index 00000000..a7e9cf82
--- /dev/null
+++ b/src/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/ca/scawebapp.h b/src/ca/scawebapp.h
new file mode 100644
index 00000000..a4152116
--- /dev/null
+++ b/src/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/ca/scawebapp7.cpp b/src/ca/scawebapp7.cpp
new file mode 100644
index 00000000..94e6bb18
--- /dev/null
+++ b/src/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/ca/scawebapp7.h b/src/ca/scawebapp7.h
new file mode 100644
index 00000000..e1d87f53
--- /dev/null
+++ b/src/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/ca/scawebappext.cpp b/src/ca/scawebappext.cpp
new file mode 100644
index 00000000..cf3b9dd3
--- /dev/null
+++ b/src/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/ca/scawebappext.h b/src/ca/scawebappext.h
new file mode 100644
index 00000000..71adfd00
--- /dev/null
+++ b/src/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/ca/scawebappext7.cpp b/src/ca/scawebappext7.cpp
new file mode 100644
index 00000000..50d3172f
--- /dev/null
+++ b/src/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/ca/scawebappext7.h b/src/ca/scawebappext7.h
new file mode 100644
index 00000000..55c8b5fc
--- /dev/null
+++ b/src/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/ca/scawebdir.cpp b/src/ca/scawebdir.cpp
new file mode 100644
index 00000000..26a7b32b
--- /dev/null
+++ b/src/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/ca/scawebdir.h b/src/ca/scawebdir.h
new file mode 100644
index 00000000..0b594532
--- /dev/null
+++ b/src/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/ca/scawebdir7.cpp b/src/ca/scawebdir7.cpp
new file mode 100644
index 00000000..5ead0470
--- /dev/null
+++ b/src/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/ca/scawebdir7.h b/src/ca/scawebdir7.h
new file mode 100644
index 00000000..c5c87e17
--- /dev/null
+++ b/src/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/ca/scaweberr.cpp b/src/ca/scaweberr.cpp
new file mode 100644
index 00000000..2441f006
--- /dev/null
+++ b/src/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/ca/scaweberr.h b/src/ca/scaweberr.h
new file mode 100644
index 00000000..ad8ff4f5
--- /dev/null
+++ b/src/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/ca/scaweberr7.cpp b/src/ca/scaweberr7.cpp
new file mode 100644
index 00000000..33c2f1bd
--- /dev/null
+++ b/src/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/ca/scaweberr7.h b/src/ca/scaweberr7.h
new file mode 100644
index 00000000..62448211
--- /dev/null
+++ b/src/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/ca/scaweblog.cpp b/src/ca/scaweblog.cpp
new file mode 100644
index 00000000..01147848
--- /dev/null
+++ b/src/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/ca/scaweblog.h b/src/ca/scaweblog.h
new file mode 100644
index 00000000..1a690cce
--- /dev/null
+++ b/src/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/ca/scaweblog7.cpp b/src/ca/scaweblog7.cpp
new file mode 100644
index 00000000..c857c46f
--- /dev/null
+++ b/src/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/ca/scaweblog7.h b/src/ca/scaweblog7.h
new file mode 100644
index 00000000..f2bb60d7
--- /dev/null
+++ b/src/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/ca/scawebprop.cpp b/src/ca/scawebprop.cpp
new file mode 100644
index 00000000..b5e38467
--- /dev/null
+++ b/src/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/ca/scawebprop.h b/src/ca/scawebprop.h
new file mode 100644
index 00000000..7a3ae5c9
--- /dev/null
+++ b/src/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/ca/scawebprop7.cpp b/src/ca/scawebprop7.cpp
new file mode 100644
index 00000000..b8d99b0a
--- /dev/null
+++ b/src/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/ca/scawebprop7.h b/src/ca/scawebprop7.h
new file mode 100644
index 00000000..a97e8679
--- /dev/null
+++ b/src/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/ca/scawebsvcext.cpp b/src/ca/scawebsvcext.cpp
new file mode 100644
index 00000000..369e951b
--- /dev/null
+++ b/src/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/ca/scawebsvcext.h b/src/ca/scawebsvcext.h
new file mode 100644
index 00000000..4d225b09
--- /dev/null
+++ b/src/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/ca/scawebsvcext7.cpp b/src/ca/scawebsvcext7.cpp
new file mode 100644
index 00000000..dcf2f7f8
--- /dev/null
+++ b/src/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/ca/scawebsvcext7.h b/src/ca/scawebsvcext7.h
new file mode 100644
index 00000000..1a686aed
--- /dev/null
+++ b/src/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