diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2018-12-16 21:19:24 -0600 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2018-12-16 21:20:40 -0600 |
commit | 95a5a8f9efef02ddcec5b3f69be99a00d71a802a (patch) | |
tree | f0a92b8e8e37e17af6053db11f1b8a7a532cd12c | |
parent | aec6e9a4b21accd2e8aeb2cb36ad1cdc8f308f79 (diff) | |
download | wix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.tar.gz wix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.tar.bz2 wix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.zip |
Import implementation of IisCA from old repo's scasched/scaexec.
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 | ||
6 | msbuild -p:Configuration=Release -t:Restore | 6 | msbuild -p:Configuration=Release -t:Restore |
7 | 7 | ||
8 | rem msbuild -p:Configuration=Release src\test\WixToolsetTest.Iis\WixToolsetTest.Iis.csproj | 8 | msbuild -p:Configuration=Release src\test\WixToolsetTest.Iis\WixToolsetTest.Iis.csproj |
9 | 9 | ||
10 | msbuild -p:Configuration=Release -t:Pack src\wixext\WixToolset.Iis.wixext.csproj | 10 | msbuild -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 @@ | |||
4 | LIBRARY "iisca" | 4 | LIBRARY "iisca" |
5 | 5 | ||
6 | EXPORTS | 6 | EXPORTS |
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. | ||
8 | enum SCA_ACTION | ||
9 | { | ||
10 | SCA_ACTION_NONE, | ||
11 | SCA_ACTION_INSTALL, | ||
12 | SCA_ACTION_UNINSTALL | ||
13 | }; | ||
14 | |||
15 | |||
16 | // IIS Metabase actions | ||
17 | enum 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 | ||
29 | enum 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 | ||
110 | enum 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 | /*------------------------------------------------------------------ | ||
6 | AppPool table: | ||
7 | |||
8 | Column Type Nullable Example Value | ||
9 | AppPool s72 No TestPool | ||
10 | Name s72 No "TestPool" | ||
11 | Component_ s72 No ComponentName | ||
12 | Attributes i2 No 8 (APATTR_OTHERUSER) | ||
13 | User_ s72 Yes UserKey | ||
14 | RecycleMinutes i2 Yes 500 | ||
15 | RecycleRequests i2 Yes 5000 | ||
16 | RecycleTimes s72 Yes "1:45,13:30,22:00" | ||
17 | IdleTimeout i2 Yes 15 | ||
18 | QueueLimit i2 Yes 500 | ||
19 | CPUMon s72 Yes "65,500,1" (65% CPU usage, 500 minutes, Shutdown Action) | ||
20 | MaxProc i2 Yes 5 | ||
21 | ManagedRuntimeVersion s72 Yes "v2.0" | ||
22 | ManagedPipelineMode s72 Yes "Integrated" | ||
23 | |||
24 | Notes: | ||
25 | RecycleTimes is a comma delimeted list of times. CPUMon is a | ||
26 | comma delimeted list of the following format: | ||
27 | <percent CPU usage>,<refress minutes>,<Action>. The values for | ||
28 | Action are 1 (Shutdown) and 0 (No Action). | ||
29 | |||
30 | ------------------------------------------------------------------*/ | ||
31 | |||
32 | enum eAppPoolQuery { apqAppPool = 1, apqName, apqComponent, apqAttributes, apqUser, apqRecycleMinutes, apqRecycleRequests, apqRecycleTimes, apqVirtualMemory, apqPrivateMemory, apqIdleTimeout, apqQueueLimit, apqCpuMon, apqMaxProc, apqManagedRuntimeVersion, apqManagedPipelineMode, apqInstalled, apqAction }; | ||
33 | |||
34 | enum eComponentAttrQuery { caqComponent = 1, caqAttributes }; | ||
35 | |||
36 | // prototypes | ||
37 | static HRESULT AppPoolExists( | ||
38 | __in IMSAdminBase* piMetabase, | ||
39 | __in LPCWSTR wzAppPool | ||
40 | ); | ||
41 | |||
42 | // functions | ||
43 | |||
44 | void 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 | |||
59 | HRESULT 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 | |||
189 | LExit: | ||
190 | WcaFinishUnwrapQuery(hAppPoolQuery); | ||
191 | WcaFinishUnwrapQuery(hComponentQuery); | ||
192 | |||
193 | ReleaseStr(pwzData); | ||
194 | return hr; | ||
195 | } | ||
196 | |||
197 | |||
198 | HRESULT 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 | |||
232 | LExit: | ||
233 | return hr; | ||
234 | } | ||
235 | |||
236 | |||
237 | static 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 | |||
266 | HRESULT 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 | |||
285 | LExit: | ||
286 | return hr; | ||
287 | } | ||
288 | |||
289 | |||
290 | HRESULT 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 | |||
309 | LExit: | ||
310 | return hr; | ||
311 | } | ||
312 | |||
313 | |||
314 | HRESULT 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 | |||
551 | LExit: | ||
552 | ReleaseStr(pwzValue); | ||
553 | |||
554 | return hr; | ||
555 | } | ||
556 | |||
557 | |||
558 | HRESULT 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 | |||
576 | LExit: | ||
577 | return hr; | ||
578 | } | ||
579 | |||
580 | |||
581 | HRESULT 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 | |||
592 | LExit: | ||
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 | |||
13 | struct 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 | |||
48 | HRESULT ScaAppPoolRead( | ||
49 | __inout SCA_APPPOOL** ppsapList, | ||
50 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | ||
51 | __inout LPWSTR *ppwzCustomActionData | ||
52 | ); | ||
53 | |||
54 | void ScaAppPoolFreeList( | ||
55 | __in SCA_APPPOOL* psapList | ||
56 | ); | ||
57 | |||
58 | HRESULT 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 | |||
66 | HRESULT ScaAppPoolInstall( | ||
67 | __in IMSAdminBase* piMetabase, | ||
68 | __in SCA_APPPOOL* psapList | ||
69 | ); | ||
70 | |||
71 | HRESULT ScaAppPoolUninstall( | ||
72 | __in IMSAdminBase* piMetabase, | ||
73 | __in SCA_APPPOOL* psapList | ||
74 | ); | ||
75 | |||
76 | HRESULT ScaWriteAppPool( | ||
77 | __in IMSAdminBase* piMetabase, | ||
78 | __in SCA_APPPOOL* psap | ||
79 | ); | ||
80 | |||
81 | HRESULT ScaRemoveAppPool( | ||
82 | __in IMSAdminBase* piMetabase, | ||
83 | __in SCA_APPPOOL* psap | ||
84 | ); | ||
85 | |||
86 | HRESULT 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 | ||
6 | static HRESULT AppPoolExists( | ||
7 | __in LPCWSTR wzAppPool | ||
8 | ); | ||
9 | |||
10 | // functions | ||
11 | HRESULT 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 | |||
45 | LExit: | ||
46 | return hr; | ||
47 | } | ||
48 | |||
49 | |||
50 | static 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 | |||
63 | HRESULT 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 | |||
79 | LExit: | ||
80 | return hr; | ||
81 | } | ||
82 | |||
83 | |||
84 | HRESULT 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 | |||
101 | LExit: | ||
102 | return hr; | ||
103 | } | ||
104 | |||
105 | |||
106 | HRESULT 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 | |||
370 | LExit: | ||
371 | ReleaseStr(pwzValue); | ||
372 | |||
373 | return hr; | ||
374 | } | ||
375 | |||
376 | |||
377 | HRESULT 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 | |||
399 | LExit: | ||
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 | ||
15 | HRESULT ScaFindAppPool7( | ||
16 | __in LPCWSTR wzAppPool, | ||
17 | __out_ecount(cchName) LPWSTR wzName, | ||
18 | __in DWORD cchName, | ||
19 | __in SCA_APPPOOL *psapList | ||
20 | ); | ||
21 | |||
22 | HRESULT ScaAppPoolInstall7( | ||
23 | __in SCA_APPPOOL* psapList | ||
24 | ); | ||
25 | |||
26 | HRESULT ScaAppPoolUninstall7( | ||
27 | __in SCA_APPPOOL* psapList | ||
28 | ); | ||
29 | |||
30 | HRESULT ScaWriteAppPool7( | ||
31 | __in const SCA_APPPOOL* psap | ||
32 | ); | ||
33 | |||
34 | HRESULT 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 | ||
6 | static HRESULT ConfigureCertificates( | ||
7 | __in SCA_ACTION saAction | ||
8 | ); | ||
9 | |||
10 | static LPCWSTR StoreMapping( | ||
11 | __in int iStore | ||
12 | ); | ||
13 | |||
14 | static HRESULT FindExistingCertificate( | ||
15 | __in LPCWSTR wzName, | ||
16 | __in DWORD dwStoreLocation, | ||
17 | __in LPCWSTR wzStore, | ||
18 | __out BYTE** prgbCertificate, | ||
19 | __out DWORD* pcbCertificate | ||
20 | ); | ||
21 | |||
22 | static 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 | |||
34 | static HRESULT ReadCertificateFile( | ||
35 | __in LPCWSTR wzPath, | ||
36 | __out BYTE** prgbData, | ||
37 | __out DWORD* pcbData | ||
38 | ); | ||
39 | |||
40 | static 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 | /* | ||
50 | HRESULT 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 | |||
56 | HRESULT 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 | |||
62 | HRESULT ScaSslNewCertificate(LPCWSTR pwzName, INT iStore, | ||
63 | INT iStoreLocation, LPCWSTR wzComputerName, | ||
64 | LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthorityOrig, | ||
65 | BSTR* pbstrCertificate, DWORD* pcbCertificate, | ||
66 | BYTE* pbaHashBuffer); | ||
67 | |||
68 | HRESULT ScaSslExistingCertificateByName(LPCWSTR pwzName, INT iStore, | ||
69 | INT iStoreLocation, BSTR* pbstrCertificate, | ||
70 | DWORD* pcbCertificate, BYTE* pbaHashBuffer); | ||
71 | |||
72 | HRESULT ScaSslExistingCertificateByBinaryData(INT iStore, INT iStoreLocation, | ||
73 | BYTE* pwzData, DWORD cchData); | ||
74 | |||
75 | HRESULT CreateEnroll(ICEnroll2 **hEnroll, INT iStore, | ||
76 | INT iStoreLocation); | ||
77 | |||
78 | HRESULT RequestCertificate(LPCWSTR pwzName, INT iStore, | ||
79 | INT iStoreLocation, LPCWSTR wzComputerName, | ||
80 | LPCWSTR wzDistinguishedName, LPCWSTR wzCertificateAuthority, | ||
81 | BSTR *pbstrCertificate); | ||
82 | |||
83 | VOID ParseCertificateAuthority(__in LPCWSTR wzCertificateAuthorityOrig, __out LPWSTR *pwzBuffer, | ||
84 | __out LPWSTR **hwzCAArray, __out int *piCAArray); | ||
85 | */ | ||
86 | |||
87 | |||
88 | LPCWSTR vcsCertQuery = L"SELECT `Certificate`, `Name`, `Component_`, `StoreLocation`, `StoreName`, `Attributes`, `Binary_`, `CertificatePath`, `PFXPassword` FROM `Certificate`"; | ||
89 | enum eCertQuery { cqCertificate = 1, cqName, cqComponent, cqStoreLocation, cqStoreName, cqAttributes, cqCertificateBinary, cqCertificatePath, cqPFXPassword }; | ||
90 | |||
91 | |||
92 | /******************************************************************** | ||
93 | InstallCertificates - CUSTOM ACTION ENTRY POINT for installing | ||
94 | certificates | ||
95 | |||
96 | ********************************************************************/ | ||
97 | extern "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 | |||
110 | LExit: | ||
111 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
112 | return WcaFinalize(er); | ||
113 | } | ||
114 | |||
115 | |||
116 | /******************************************************************** | ||
117 | UninstallCertificates - CUSTOM ACTION ENTRY POINT for uninstalling | ||
118 | certificates | ||
119 | |||
120 | ********************************************************************/ | ||
121 | extern "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 | |||
134 | LExit: | ||
135 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
136 | return WcaFinalize(er); | ||
137 | } | ||
138 | |||
139 | |||
140 | static 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 | |||
336 | LExit: | ||
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 | |||
355 | static 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 | |||
501 | LExit: | ||
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 | |||
521 | static 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 | |||
566 | LExit: | ||
567 | ReleaseMem(pbData); | ||
568 | return hr; | ||
569 | } | ||
570 | |||
571 | |||
572 | static 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 | |||
646 | LExit: | ||
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 | |||
669 | static 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 | |||
719 | LExit: | ||
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 | /* | ||
736 | HRESULT 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 | |||
796 | HRESULT 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 | |||
851 | LExit: | ||
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 | |||
863 | VOID 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 | |||
909 | HRESULT 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 | |||
942 | LExit: | ||
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 | |||
963 | HRESULT 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 | |||
1051 | LExit: | ||
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 | |||
1068 | HRESULT 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 | |||
1149 | LExit: | ||
1150 | if (wzCABuffer) | ||
1151 | { | ||
1152 | delete wzCABuffer; | ||
1153 | } | ||
1154 | if (wzCAArray) | ||
1155 | { | ||
1156 | delete wzCAArray; | ||
1157 | } | ||
1158 | |||
1159 | return hr; | ||
1160 | } | ||
1161 | |||
1162 | |||
1163 | HRESULT 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 | |||
1206 | LExit: | ||
1207 | ReleaseStr(pwzData); | ||
1208 | |||
1209 | return hr; | ||
1210 | } | ||
1211 | |||
1212 | |||
1213 | HRESULT 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 | |||
1243 | LExit: | ||
1244 | if (hCertStore) | ||
1245 | { | ||
1246 | CertCloseStore(hCertStore, 0); | ||
1247 | hCertStore = NULL; | ||
1248 | } | ||
1249 | |||
1250 | return hr; | ||
1251 | } | ||
1252 | |||
1253 | |||
1254 | HRESULT 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 | |||
1359 | LExit: | ||
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 | |||
1381 | HRESULT 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 | |||
1454 | LExit: | ||
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 | ||
8 | enum 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 | ||
18 | enum 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 | ||
8 | static HRESULT ExecuteCertificateOperation( | ||
9 | __in MSIHANDLE hInstall, | ||
10 | __in SCA_ACTION saAction, | ||
11 | __in DWORD dwStoreRoot | ||
12 | ); | ||
13 | |||
14 | static HRESULT ReadCertificateFile( | ||
15 | __in LPCWSTR wzPath, | ||
16 | __out BYTE** prgbData, | ||
17 | __out DWORD* pcbData | ||
18 | ); | ||
19 | |||
20 | static 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 | |||
29 | static 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 | * ***************************************************************/ | ||
41 | extern "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 | |||
54 | LExit: | ||
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 | * ***************************************************************/ | ||
65 | extern "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 | |||
78 | LExit: | ||
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 | * ***************************************************************/ | ||
89 | extern "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 | |||
102 | LExit: | ||
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 | * ***************************************************************/ | ||
113 | extern "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 | |||
126 | LExit: | ||
127 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
128 | return WcaFinalize(er); | ||
129 | } | ||
130 | |||
131 | |||
132 | static 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 | |||
199 | LExit: | ||
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 | |||
223 | static 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 | |||
300 | LExit: | ||
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 | |||
321 | static 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 | |||
395 | LExit: | ||
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 | |||
5 | const UINT COST_IIS_TRANSACTIONS = 10000; | ||
6 | |||
7 | const UINT COST_IIS_CREATEKEY = 5000; | ||
8 | const UINT COST_IIS_DELETEKEY = 5000; | ||
9 | const UINT COST_IIS_WRITEVALUE = 5000; | ||
10 | const UINT COST_IIS_DELETEVALUE = 5000; | ||
11 | const UINT COST_IIS_CREATEAPP = 5000; | ||
12 | const UINT COST_IIS_DELETEAPP = 5000; | ||
13 | |||
14 | const UINT COST_CERT_ADD = 5000; | ||
15 | const 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 | ********************************************************************/ | ||
11 | extern "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); | ||
54 | LExit: | ||
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 | ********************************************************************/ | ||
74 | extern "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 | |||
109 | LExit: | ||
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 | * *****************************************************************/ | ||
131 | extern "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 | |||
161 | LExit: | ||
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 | * *****************************************************************/ | ||
183 | static 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 | |||
219 | LExit: | ||
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 | * *****************************************************************/ | ||
234 | static 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 | |||
363 | LExit: | ||
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 | * *****************************************************************/ | ||
386 | static 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); | ||
431 | LExit: | ||
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 | * *****************************************************************/ | ||
446 | static 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); | ||
566 | LExit: | ||
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 | * ****************************************************************/ | ||
583 | static 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); | ||
601 | LExit: | ||
602 | return hr; | ||
603 | } | ||
604 | |||
605 | |||
606 | /******************************************************************** | ||
607 | DeleteMetabaseKey - Deletes metabase keys | ||
608 | |||
609 | Input: deferred CustomActionData - Key | ||
610 | ******************************************************************/ | ||
611 | static 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); | ||
647 | LExit: | ||
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 | *******************************************************************/ | ||
661 | extern "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 | |||
816 | LExit: | ||
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 | *******************************************************************/ | ||
842 | extern "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 | |||
884 | LExit: | ||
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 | * *****************************************************************/ | ||
904 | extern "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 | |||
970 | LExit: | ||
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 | ********************************************************************/ | ||
993 | extern "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 | |||
1069 | LExit: | ||
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 | ********************************************************************/ | ||
1092 | extern "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 | |||
1168 | LExit: | ||
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 | ||
8 | HRESULT IIS7Site( | ||
9 | __inout LPWSTR *ppwzCustomActionData, | ||
10 | __in IAppHostWritableAdminManager *pAdminMgr | ||
11 | ); | ||
12 | |||
13 | HRESULT IIS7Application( | ||
14 | __inout LPWSTR *ppwzCustomActionData, | ||
15 | __in IAppHostWritableAdminManager *pAdminMgr | ||
16 | ); | ||
17 | HRESULT IIS7VDir( | ||
18 | __inout LPWSTR *ppwzCustomActionData, | ||
19 | __in IAppHostWritableAdminManager *pAdminMgr | ||
20 | ); | ||
21 | HRESULT IIS7Binding( | ||
22 | __inout LPWSTR *ppwzCustomActionData, | ||
23 | __in IAppHostWritableAdminManager *pAdminMgr | ||
24 | ); | ||
25 | HRESULT IIS7AppPool( | ||
26 | __inout LPWSTR *ppwzCustomActionData, | ||
27 | __in IAppHostWritableAdminManager *pAdminMgr | ||
28 | ); | ||
29 | HRESULT IIS7AppExtension( | ||
30 | __inout LPWSTR *ppwzCustomActionData, | ||
31 | __in IAppHostWritableAdminManager *pAdminMgr | ||
32 | ); | ||
33 | HRESULT IIS7MimeMap( | ||
34 | __inout LPWSTR *ppwzCustomActionData, | ||
35 | __in IAppHostWritableAdminManager *pAdminMgr | ||
36 | ); | ||
37 | HRESULT IIS7DirProperties( | ||
38 | __inout LPWSTR *ppwzCustomActionData, | ||
39 | __in IAppHostWritableAdminManager *pAdminMgr | ||
40 | ); | ||
41 | HRESULT IIS7WebLog( | ||
42 | __inout LPWSTR *ppwzCustomActionData, | ||
43 | __in IAppHostWritableAdminManager *pAdminMgr | ||
44 | ); | ||
45 | HRESULT IIS7FilterGlobal( | ||
46 | __inout LPWSTR *ppwzCustomActionData, | ||
47 | __in IAppHostWritableAdminManager *pAdminMgr | ||
48 | ); | ||
49 | HRESULT IIS7FilterSite( | ||
50 | __inout LPWSTR *ppwzCustomActionData, | ||
51 | __in IAppHostWritableAdminManager *pAdminMgr | ||
52 | ); | ||
53 | HRESULT IIS7HttpHeader( | ||
54 | __inout LPWSTR *ppwzCustomActionData, | ||
55 | __in IAppHostWritableAdminManager *pAdminMgr | ||
56 | ); | ||
57 | HRESULT IIS7WebError( | ||
58 | __inout LPWSTR *ppwzCustomActionData, | ||
59 | __in IAppHostWritableAdminManager *pAdminMgr | ||
60 | ); | ||
61 | HRESULT IIS7WebSvcExt( | ||
62 | __inout LPWSTR *ppwzCustomActionData, | ||
63 | __in IAppHostWritableAdminManager *pAdminMgr | ||
64 | ); | ||
65 | HRESULT IIS7WebProperty( | ||
66 | __inout LPWSTR *ppwzCustomActionData, | ||
67 | __in IAppHostWritableAdminManager *pAdminMgr | ||
68 | ); | ||
69 | HRESULT IIS7WebDir( | ||
70 | __inout LPWSTR *ppwzCustomActionData, | ||
71 | __in IAppHostWritableAdminManager *pAdminMgr | ||
72 | ); | ||
73 | HRESULT IIS7AspProperty( | ||
74 | __inout LPWSTR *ppwzCustomActionData, | ||
75 | __in IAppHostWritableAdminManager *pAdminMgr | ||
76 | ); | ||
77 | HRESULT IIS7SslBinding( | ||
78 | __inout LPWSTR *ppwzCustomActionData, | ||
79 | __in IAppHostWritableAdminManager *pAdminMgr | ||
80 | ); | ||
81 | //local helper functions | ||
82 | |||
83 | static HRESULT GetNextAvailableSiteId( | ||
84 | IAppHostWritableAdminManager *pAdminMgr, | ||
85 | DWORD *plSiteId | ||
86 | ); | ||
87 | static HRESULT GetSiteElement( | ||
88 | IAppHostWritableAdminManager *pAdminMgr, | ||
89 | LPCWSTR swSiteName, | ||
90 | IAppHostElement **pSiteElement, | ||
91 | BOOL* fFound | ||
92 | ); | ||
93 | static HRESULT GetApplicationElement( | ||
94 | IAppHostElement *pSiteElement, | ||
95 | LPCWSTR swAppPath, | ||
96 | IAppHostElement **pAppElement, | ||
97 | BOOL* fFound | ||
98 | ); | ||
99 | static HRESULT GetApplicationElementForVDir( | ||
100 | IAppHostElement *pSiteElement, | ||
101 | LPCWSTR swVDirPath, | ||
102 | IAppHostElement **ppAppElement, | ||
103 | LPCWSTR *ppwzVDirSubPath, | ||
104 | BOOL* fFound | ||
105 | ); | ||
106 | |||
107 | static HRESULT CreateApplication( | ||
108 | IAppHostElement *pSiteElement, | ||
109 | LPCWSTR swAppPath, | ||
110 | IAppHostElement **pAppElement | ||
111 | ); | ||
112 | static HRESULT DeleteApplication( | ||
113 | IAppHostElement *pSiteElement, | ||
114 | LPCWSTR swAppPath | ||
115 | ); | ||
116 | |||
117 | static HRESULT SetAppPool( | ||
118 | IAppHostElement *pAppElementpAppElement, | ||
119 | LPCWSTR pwzAppPool | ||
120 | ); | ||
121 | static HRESULT CreateVdir( | ||
122 | IAppHostElement *pAppElement, | ||
123 | LPCWSTR pwzVDirPath, | ||
124 | LPCWSTR pwzVDirPhyDir | ||
125 | ); | ||
126 | static HRESULT DeleteVdir( | ||
127 | IAppHostElement *pAppElement, | ||
128 | LPCWSTR pwzVDirPath | ||
129 | ); | ||
130 | |||
131 | static HRESULT CreateBinding( | ||
132 | IAppHostElement *pSiteElem, | ||
133 | LPCWSTR pwzProtocol, | ||
134 | LPCWSTR pwzInfo | ||
135 | ); | ||
136 | static HRESULT DeleteBinding( | ||
137 | IAppHostElement *pSiteElem, | ||
138 | LPCWSTR pwzProtocol, | ||
139 | LPCWSTR pwzInfo | ||
140 | ); | ||
141 | |||
142 | static HRESULT CreateSslBinding( | ||
143 | IAppHostElement *pSiteElem, | ||
144 | LPCWSTR pwzStoreName, | ||
145 | LPCWSTR pwzEncodedCertificateHash | ||
146 | ); | ||
147 | static HRESULT DeleteSslBinding( | ||
148 | IAppHostElement *pSiteElem, | ||
149 | LPCWSTR pwzStoreName, | ||
150 | LPCWSTR pwzEncodedCertificateHash | ||
151 | ); | ||
152 | |||
153 | static HRESULT CreateSite( | ||
154 | IAppHostElementCollection *pAdminMgr, | ||
155 | LPCWSTR swSiteName, | ||
156 | IAppHostElement **pSiteElement | ||
157 | ); | ||
158 | |||
159 | static HRESULT DeleteAppPool( | ||
160 | IAppHostWritableAdminManager *pAdminMgr, | ||
161 | LPCWSTR swAppPoolName | ||
162 | ); | ||
163 | static HRESULT CreateAppPool( | ||
164 | __inout LPWSTR *ppwzCustomActionData, | ||
165 | IAppHostWritableAdminManager *pAdminMgr, | ||
166 | LPCWSTR swAppPoolName | ||
167 | ); | ||
168 | |||
169 | static HRESULT SetDirPropAuthentications( | ||
170 | IAppHostWritableAdminManager *pAdminMgr, | ||
171 | LPCWSTR wcConfigPath, | ||
172 | DWORD dwData | ||
173 | ); | ||
174 | static HRESULT SetDirPropAuthProvider( | ||
175 | IAppHostWritableAdminManager *pAdminMgr, | ||
176 | LPCWSTR wszConfigPath, | ||
177 | __in LPWSTR wszData | ||
178 | ); | ||
179 | static HRESULT SetDirPropDefDoc( | ||
180 | IAppHostWritableAdminManager *pAdminMgr, | ||
181 | LPCWSTR wszConfigPath, | ||
182 | __in LPWSTR wszData | ||
183 | ); | ||
184 | |||
185 | static HRESULT ClearLocationTag( | ||
186 | IAppHostWritableAdminManager *pAdminMgr, | ||
187 | LPCWSTR swLocationPath | ||
188 | ); | ||
189 | |||
190 | static HRESULT CreateWebLog( | ||
191 | IAppHostElement *pSiteElem, | ||
192 | LPCWSTR pwzFormat | ||
193 | ); | ||
194 | |||
195 | static HRESULT CreateGlobalFilter( | ||
196 | __inout LPWSTR *ppwzCustomActionData, | ||
197 | IAppHostElement *pSection | ||
198 | ); | ||
199 | static HRESULT DeleteGlobalFilter( | ||
200 | __inout LPWSTR *ppwzCustomActionData, | ||
201 | IAppHostElement *pSection | ||
202 | ); | ||
203 | |||
204 | static HRESULT CreateSiteFilter( | ||
205 | __inout LPWSTR *ppwzCustomActionData, | ||
206 | IAppHostWritableAdminManager *pAdminMgr | ||
207 | ); | ||
208 | static HRESULT DeleteSiteFilter( | ||
209 | __inout LPWSTR *ppwzCustomActionData, | ||
210 | IAppHostWritableAdminManager *pAdminMgr | ||
211 | ); | ||
212 | |||
213 | static HRESULT DeleteCollectionElement( | ||
214 | __in IAppHostElementCollection *pCollection, | ||
215 | __in LPCWSTR pwzElementName, | ||
216 | __in LPCWSTR pwzAttributeName, | ||
217 | __in LPCWSTR pwzAttributeValue | ||
218 | ); | ||
219 | |||
220 | struct 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 | }; | ||
229 | static HRESULT AddWebErrorToList( | ||
230 | SCA_WEB_ERROR_SERVER** ppsweList | ||
231 | ); | ||
232 | static void ScaWebErrorFreeList7( | ||
233 | SCA_WEB_ERROR_SERVER *psweList | ||
234 | ); | ||
235 | static HRESULT PopulateHttpErrors( | ||
236 | IAppHostElement *pSection, | ||
237 | SCA_WEB_ERROR_SERVER **psweList | ||
238 | ); | ||
239 | static 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 | |||
246 | static void ConvSecToHMS( | ||
247 | int Sec, | ||
248 | __out_ecount(cchDest) LPWSTR wcTime, | ||
249 | size_t cchDest | ||
250 | ); | ||
251 | static 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 | ///////////////////////////////////////////////////////////////////// | ||
261 | class ScopeBSTR | ||
262 | { | ||
263 | public: | ||
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 | *******************************************************************/ | ||
300 | HRESULT 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 | } | ||
518 | LExit: | ||
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 | |||
536 | HRESULT 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 | |||
686 | LExit: | ||
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 | //------------------------------------------------------------------------------------------------- | ||
703 | HRESULT 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 | } | ||
763 | LExit: | ||
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 | //------------------------------------------------------------------------------------------------- | ||
777 | HRESULT 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 | |||
836 | LExit: | ||
837 | ReleaseObject(pSection); | ||
838 | |||
839 | return hr; | ||
840 | } | ||
841 | |||
842 | //------------------------------------------------------------------------------------------------- | ||
843 | // IIS7WebSvcExt | ||
844 | // Called by WriteIIS7ConfigChanges | ||
845 | // Processes isapiCgiRestriction | ||
846 | // | ||
847 | //------------------------------------------------------------------------------------------------- | ||
848 | HRESULT 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 | |||
949 | LExit: | ||
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 | |||
967 | HRESULT 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 | |||
1121 | LExit: | ||
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 | |||
1135 | static 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 | |||
1230 | LExit: | ||
1231 | ReleaseVariant(vPropValue); | ||
1232 | ReleaseObject(pProperty); | ||
1233 | ReleaseObject(pElement); | ||
1234 | ReleaseObject(pCollection); | ||
1235 | |||
1236 | return hr; | ||
1237 | } | ||
1238 | |||
1239 | static 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 | } | ||
1250 | static 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 | |||
1261 | LExit: | ||
1262 | return hr; | ||
1263 | } | ||
1264 | static 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 | |||
1295 | HRESULT 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 | |||
1394 | LExit: | ||
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 | //------------------------------------------------------------------------------------------------- | ||
1414 | HRESULT 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 | |||
1469 | LExit: | ||
1470 | ReleaseObject(pSection); | ||
1471 | |||
1472 | return hr; | ||
1473 | } | ||
1474 | |||
1475 | static 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 | |||
1558 | LExit: | ||
1559 | ReleaseStr(pwzFilterName); | ||
1560 | ReleaseStr(pwzSiteName); | ||
1561 | ReleaseStr(pwzFilterPath); | ||
1562 | ReleaseObject(pCollection); | ||
1563 | ReleaseObject(pElement); | ||
1564 | |||
1565 | return hr; | ||
1566 | } | ||
1567 | |||
1568 | static 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 | |||
1591 | LExit: | ||
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 | //------------------------------------------------------------------------------------------------- | ||
1605 | HRESULT 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 | |||
1649 | LExit: | ||
1650 | return hr; | ||
1651 | |||
1652 | } | ||
1653 | |||
1654 | static 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 | |||
1749 | LExit: | ||
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 | |||
1761 | static 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 | |||
1793 | LExit: | ||
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 | //------------------------------------------------------------------------------------------------- | ||
1809 | HRESULT 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 | |||
1902 | LExit: | ||
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 | |||
1918 | HRESULT 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 | |||
2018 | LExit: | ||
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 | //------------------------------------------------------------------------------------------------- | ||
2034 | HRESULT 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 | //------------------------------------------------------------------------------------------------- | ||
2138 | HRESULT 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 | //------------------------------------------------------------------------------------------------- | ||
2211 | HRESULT 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 | //------------------------------------------------------------------------------------------------- | ||
2261 | HRESULT 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 | |||
2297 | LExit: | ||
2298 | ReleaseStr(pwzAppPoolName); | ||
2299 | return hr; | ||
2300 | } | ||
2301 | |||
2302 | //------------------------------------------------------------------------------------------------- | ||
2303 | // IIS7AppExtension | ||
2304 | // Processes AppExtension (config handlers) CA Data | ||
2305 | // | ||
2306 | // | ||
2307 | //------------------------------------------------------------------------------------------------- | ||
2308 | HRESULT 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 | |||
2446 | LExit: | ||
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 | |||
2579 | LExit: | ||
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 | //------------------------------------------------------------------------------------------------- | ||
2597 | HRESULT 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 | } | ||
2833 | LExit: | ||
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 | //------------------------------------------------------------------------------------------------- | ||
2851 | HRESULT 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 | |||
2926 | static 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 | |||
2971 | LExit: | ||
2972 | ReleaseVariant(vPropValue); | ||
2973 | ReleaseVariant(vtIndex); | ||
2974 | |||
2975 | ReleaseObject(pElement); | ||
2976 | ReleaseObject(pProperty); | ||
2977 | |||
2978 | return hr; | ||
2979 | } | ||
2980 | |||
2981 | static 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 | |||
3006 | LExit: | ||
3007 | ReleaseObject(pSites); | ||
3008 | ReleaseObject(pCollection); | ||
3009 | |||
3010 | return hr; | ||
3011 | } | ||
3012 | |||
3013 | static 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 | |||
3031 | LExit: | ||
3032 | ReleaseObject(pCollection); | ||
3033 | |||
3034 | return hr; | ||
3035 | } | ||
3036 | |||
3037 | static 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 | |||
3087 | LExit: | ||
3088 | ReleaseObject(pCollection); | ||
3089 | ReleaseStr(pwzAppPath); | ||
3090 | |||
3091 | return hr; | ||
3092 | } | ||
3093 | |||
3094 | static 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 | |||
3122 | LExit: | ||
3123 | ReleaseObject(pNewElement); | ||
3124 | |||
3125 | return hr; | ||
3126 | } | ||
3127 | |||
3128 | static 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 | |||
3153 | LExit: | ||
3154 | ReleaseObject(pCollection); | ||
3155 | ReleaseObject(pNewElement); | ||
3156 | |||
3157 | return hr; | ||
3158 | } | ||
3159 | |||
3160 | static 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 | |||
3174 | LExit: | ||
3175 | ReleaseObject(pCollection); | ||
3176 | |||
3177 | return hr; | ||
3178 | } | ||
3179 | |||
3180 | static 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 | } | ||
3192 | LExit: | ||
3193 | return hr; | ||
3194 | } | ||
3195 | |||
3196 | static 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 | |||
3232 | LExit: | ||
3233 | ReleaseObject(pCollection); | ||
3234 | ReleaseObject(pElement); | ||
3235 | |||
3236 | return hr; | ||
3237 | } | ||
3238 | |||
3239 | static 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 | |||
3253 | LExit: | ||
3254 | ReleaseObject(pCollection); | ||
3255 | |||
3256 | return hr; | ||
3257 | } | ||
3258 | |||
3259 | static 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 | |||
3308 | LExit: | ||
3309 | ReleaseVariant(vtProp); | ||
3310 | |||
3311 | ReleaseObject(pCollection); | ||
3312 | ReleaseObject(pChildElems); | ||
3313 | ReleaseObject(pBindingElement); | ||
3314 | ReleaseObject(pBindings); | ||
3315 | |||
3316 | return hr; | ||
3317 | } | ||
3318 | static 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 | |||
3353 | LExit: | ||
3354 | ReleaseVariant(vtProp); | ||
3355 | |||
3356 | ReleaseObject(pLogFile); | ||
3357 | ReleaseObject(pChildElems); | ||
3358 | |||
3359 | return hr; | ||
3360 | } | ||
3361 | |||
3362 | static 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 | |||
3374 | struct SCA_SSLBINDINGINFO | ||
3375 | { | ||
3376 | IIS7_APPHOSTELEMENTCOMPARISON comparison; | ||
3377 | LPCWSTR pwzStoreName; | ||
3378 | LPCWSTR pwzEncodedCertificateHash; | ||
3379 | HRESULT hr; | ||
3380 | }; | ||
3381 | |||
3382 | static 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 | } | ||
3433 | LExit: | ||
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 | |||
3447 | static 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 | |||
3485 | LExit: | ||
3486 | ReleaseVariant(vtProp); | ||
3487 | |||
3488 | ReleaseObject(pChildElems); | ||
3489 | ReleaseObject(pBindingsElement); | ||
3490 | ReleaseObject(pBindingsCollection); | ||
3491 | |||
3492 | return hr; | ||
3493 | } | ||
3494 | |||
3495 | static 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 | |||
3507 | static 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 | |||
3524 | LExit: | ||
3525 | ReleaseObject(pAppPools); | ||
3526 | ReleaseObject(pCollection); | ||
3527 | |||
3528 | return hr; | ||
3529 | } | ||
3530 | |||
3531 | static 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 | |||
3885 | LExit: | ||
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 | |||
3897 | static 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 | |||
3965 | LExit: | ||
3966 | ReleaseObject(pSection); | ||
3967 | |||
3968 | return hr; | ||
3969 | } | ||
3970 | |||
3971 | static 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 | |||
4020 | LExit: | ||
4021 | ReleaseObject(pSection); | ||
4022 | ReleaseObject(pCollection); | ||
4023 | ReleaseObject(pElement); | ||
4024 | ReleaseObject(pNewElement); | ||
4025 | |||
4026 | return hr; | ||
4027 | } | ||
4028 | |||
4029 | static 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 | |||
4078 | LExit: | ||
4079 | ReleaseObject(pSection); | ||
4080 | ReleaseObject(pCollection); | ||
4081 | ReleaseObject(pNewElement); | ||
4082 | |||
4083 | return hr; | ||
4084 | } | ||
4085 | |||
4086 | static 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 | } | ||
4132 | LExit: | ||
4133 | ReleaseObject(pConfigMgr); | ||
4134 | ReleaseObject(pConfigFile); | ||
4135 | ReleaseObject(pLocationCollection); | ||
4136 | ReleaseObject(pLocation); | ||
4137 | ReleaseBSTR(bstrLocationPath); | ||
4138 | |||
4139 | return hr; | ||
4140 | |||
4141 | } | ||
4142 | |||
4143 | static 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 | ||
4167 | LExit: | ||
4168 | ReleaseVariant(vtIndex); | ||
4169 | |||
4170 | return hr; | ||
4171 | } | ||
4172 | static 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 | } | ||
4188 | static 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 | |||
5 | HRESULT 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 | ||
6 | static HRESULT ReadFilterLoadOrder( | ||
7 | __in IMSAdminBase* piMetabase, | ||
8 | __in LPCWSTR wzFilterRoot, | ||
9 | __out LPWSTR *ppwzLoadOrder | ||
10 | ); | ||
11 | static HRESULT AddFilterToLoadOrder( | ||
12 | __in LPCWSTR wzFilter, | ||
13 | __in int iLoadOrder, | ||
14 | __inout LPWSTR *ppwzLoadOrder | ||
15 | ); | ||
16 | static HRESULT RemoveFilterFromLoadOrder( | ||
17 | __in LPCWSTR wzFilter, | ||
18 | __inout LPWSTR *ppwzLoadOrder | ||
19 | ); | ||
20 | |||
21 | |||
22 | UINT __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 | |||
139 | LExit: | ||
140 | WcaFinishUnwrapQuery(hWrapQuery); | ||
141 | |||
142 | ReleaseStr(pwzData); | ||
143 | return hr; | ||
144 | } | ||
145 | |||
146 | |||
147 | HRESULT 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 | |||
217 | LExit: | ||
218 | ReleaseStr(pwzLoadOrder); | ||
219 | return hr; | ||
220 | } | ||
221 | |||
222 | |||
223 | HRESULT 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 | |||
275 | LExit: | ||
276 | return hr; | ||
277 | } | ||
278 | |||
279 | |||
280 | void 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 | |||
294 | HRESULT 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 | |||
304 | LExit: | ||
305 | return hr; | ||
306 | } | ||
307 | |||
308 | // private helper functions | ||
309 | |||
310 | |||
311 | static 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 | |||
366 | LExit: | ||
367 | ReleaseMem(mr.pbMDData); | ||
368 | |||
369 | if (mhRoot) | ||
370 | { | ||
371 | piMetabase->CloseKey(mhRoot); | ||
372 | } | ||
373 | |||
374 | return hr; | ||
375 | } | ||
376 | |||
377 | |||
378 | static 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 | |||
457 | LExit: | ||
458 | ReleaseStr(pwzTemp); | ||
459 | return hr; | ||
460 | } | ||
461 | |||
462 | |||
463 | static 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 | |||
7 | enum eFilterQuery { fqWeb = 1, fqFilter, fqComponent , fqPath, fqDescription, fqFlags, fqLoadOrder, fqInstalled, fqAction }; | ||
8 | |||
9 | struct 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 | ||
33 | HRESULT AddFilterToList( | ||
34 | __in SCA_FILTER** ppsfList | ||
35 | ); | ||
36 | |||
37 | UINT __stdcall ScaFiltersRead(IMSAdminBase* piMetabase, | ||
38 | SCA_WEB* pswList, __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, SCA_FILTER** ppsfList, | ||
39 | __inout LPWSTR *ppwzCustomActionData); | ||
40 | |||
41 | HRESULT ScaFiltersInstall(IMSAdminBase* piMetabase, SCA_FILTER* psfList); | ||
42 | |||
43 | HRESULT ScaFiltersUninstall(IMSAdminBase* piMetabase, SCA_FILTER* psfList); | ||
44 | |||
45 | void 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 | |||
5 | static HRESULT WriteFilter(const SCA_FILTER* psf); | ||
6 | |||
7 | UINT __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 | |||
116 | LExit: | ||
117 | WcaFinishUnwrapQuery(hWrapQuery); | ||
118 | |||
119 | ReleaseStr(pwzData); | ||
120 | |||
121 | return hr; | ||
122 | } | ||
123 | |||
124 | |||
125 | HRESULT 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 | |||
172 | LExit: | ||
173 | |||
174 | return hr; | ||
175 | } | ||
176 | static 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 | |||
202 | LExit: | ||
203 | return hr; | ||
204 | } | ||
205 | |||
206 | |||
207 | HRESULT 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 | |||
282 | LExit: | ||
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 | ||
8 | UINT __stdcall ScaFiltersRead7( | ||
9 | __in SCA_WEB7* pswList, | ||
10 | __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, | ||
11 | __inout SCA_FILTER** ppsfList, | ||
12 | __inout LPWSTR *ppwzCustomActionData | ||
13 | ); | ||
14 | |||
15 | HRESULT ScaFiltersInstall7( | ||
16 | SCA_FILTER* psfList | ||
17 | ); | ||
18 | |||
19 | HRESULT 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 | |||
5 | enum eHttpHeaderQuery { hhqName = 1, hhqParentType, hhqParentValue, hhqValue, hhqAttributes}; | ||
6 | |||
7 | static HRESULT AddHttpHeaderToList( | ||
8 | __in SCA_HTTP_HEADER** ppshhList | ||
9 | ); | ||
10 | |||
11 | |||
12 | void 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 | |||
27 | HRESULT 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 | |||
85 | LExit: | ||
86 | WcaFinishUnwrapQuery(hWrapQuery); | ||
87 | |||
88 | ReleaseStr(pwzData); | ||
89 | |||
90 | return hr; | ||
91 | } | ||
92 | |||
93 | |||
94 | HRESULT 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 | |||
147 | HRESULT 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 | |||
279 | LExit: | ||
280 | MetaFreeValue(&mr); | ||
281 | |||
282 | ReleaseStr(pwzNewHeader); | ||
283 | ReleaseStr(pwzHeaders); | ||
284 | ReleaseStr(pwzSearchKey); | ||
285 | |||
286 | return hr; | ||
287 | } | ||
288 | |||
289 | |||
290 | HRESULT 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 | |||
309 | static 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 | |||
321 | LExit: | ||
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 | |||
5 | enum eHttpHeaderParentType { hhptVDir = 1, hhptWeb }; | ||
6 | |||
7 | struct 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 | ||
20 | HRESULT ScaHttpHeaderRead( | ||
21 | __in SCA_HTTP_HEADER **ppshhList, | ||
22 | __inout LPWSTR *ppwzCustomActionData | ||
23 | ); | ||
24 | void ScaHttpHeaderFreeList( | ||
25 | __in SCA_HTTP_HEADER *pshhList | ||
26 | ); | ||
27 | HRESULT ScaHttpHeaderCheckList( | ||
28 | __in SCA_HTTP_HEADER* pshhList | ||
29 | ); | ||
30 | HRESULT ScaGetHttpHeader( | ||
31 | __in int iParentType, | ||
32 | __in LPCWSTR wzParentValue, | ||
33 | __in SCA_HTTP_HEADER** ppshhList, | ||
34 | __out SCA_HTTP_HEADER** ppshhOut | ||
35 | ); | ||
36 | HRESULT 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 | |||
5 | HRESULT 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 | |||
58 | HRESULT 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 | |||
92 | LExit: | ||
93 | return hr; | ||
94 | } | ||
95 | |||
96 | |||
97 | HRESULT 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 | |||
5 | HRESULT ScaGetHttpHeader7( | ||
6 | __in int iParentType, | ||
7 | __in_z LPCWSTR wzParentValue, | ||
8 | __in SCA_HTTP_HEADER** ppshhList, | ||
9 | __out SCA_HTTP_HEADER** ppshhOut | ||
10 | ); | ||
11 | HRESULT 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 | ||
6 | LPWSTR vpwzCustomActionData = NULL; | ||
7 | DWORD vdwCustomActionCost = 0; | ||
8 | |||
9 | HRESULT 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 | |||
24 | LExit: | ||
25 | return hr; | ||
26 | } | ||
27 | |||
28 | |||
29 | HRESULT 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 | |||
61 | LExit: | ||
62 | return hr; | ||
63 | } | ||
64 | |||
65 | |||
66 | HRESULT 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 | |||
87 | LExit: | ||
88 | ReleaseStr(pwzCustomActionData); | ||
89 | |||
90 | return hr; | ||
91 | } | ||
92 | |||
93 | |||
94 | HRESULT 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 | |||
125 | LExit: | ||
126 | ReleaseStr(pwzCustomActionData); | ||
127 | |||
128 | return hr; | ||
129 | } | ||
130 | |||
131 | |||
132 | HRESULT 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 | |||
172 | LExit: | ||
173 | ReleaseStr(pwzCustomActionData); | ||
174 | |||
175 | return hr; | ||
176 | } | ||
177 | |||
178 | |||
179 | HRESULT 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 | |||
219 | LExit: | ||
220 | ReleaseStr(pwzCustomActionData); | ||
221 | |||
222 | return hr; | ||
223 | } | ||
224 | |||
225 | |||
226 | HRESULT 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 | |||
274 | LExit: | ||
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 | ||
284 | HRESULT 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 | |||
381 | LExit: | ||
382 | ReleaseStr(pwzCustomActionData); | ||
383 | |||
384 | return hr; | ||
385 | } | ||
386 | |||
387 | |||
388 | HRESULT 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 | |||
397 | LExit: | ||
398 | return hr; | ||
399 | } | ||
400 | |||
401 | |||
402 | HRESULT 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 | |||
434 | LExit: | ||
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 | |||
448 | HRESULT 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 | |||
479 | LExit: | ||
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 | |||
5 | HRESULT ScaMetabaseTransaction(__in_z LPCWSTR wzBackup); | ||
6 | |||
7 | HRESULT ScaCreateWeb(IMSAdminBase* piMetabase, LPCWSTR wzWeb, LPCWSTR wzWebBase); | ||
8 | |||
9 | HRESULT ScaDeleteApp(IMSAdminBase* piMetabase, LPCWSTR wzWebRoot); | ||
10 | |||
11 | HRESULT ScaCreateApp(IMSAdminBase* piMetabase, LPCWSTR wzWebRoot, | ||
12 | DWORD dwIsolation); | ||
13 | |||
14 | HRESULT ScaCreateMetabaseKey(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
15 | LPCWSTR wzSubKey); | ||
16 | |||
17 | HRESULT ScaDeleteMetabaseKey(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
18 | LPCWSTR wzSubKey); | ||
19 | |||
20 | HRESULT ScaWriteMetabaseValue(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
21 | LPCWSTR wzSubKey, DWORD dwIdentifier, | ||
22 | DWORD dwAttributes, DWORD dwUserType, | ||
23 | DWORD dwDataType, LPVOID pvData); | ||
24 | |||
25 | HRESULT ScaDeleteMetabaseValue(IMSAdminBase* piMetabase, LPCWSTR wzRootKey, | ||
26 | LPCWSTR wzSubKey, DWORD dwIdentifier, | ||
27 | DWORD dwDataType); | ||
28 | |||
29 | HRESULT ScaWriteConfigurationScript(LPCWSTR pwzCaScriptKey); | ||
30 | |||
31 | HRESULT ScaAddToIisConfiguration(LPCWSTR pwzData, DWORD dwCost); | ||
32 | |||
33 | HRESULT 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 | |||
7 | HRESULT 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 | |||
20 | LExit: | ||
21 | return hr; | ||
22 | } | ||
23 | |||
24 | HRESULT 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 | |||
35 | LExit: | ||
36 | ReleaseStr(pwzCustomActionData); | ||
37 | |||
38 | return hr; | ||
39 | } | ||
40 | |||
41 | HRESULT 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 | |||
52 | LExit: | ||
53 | ReleaseStr(pwzCustomActionData); | ||
54 | |||
55 | return hr; | ||
56 | } | ||
57 | |||
58 | HRESULT 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 | |||
69 | LExit: | ||
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 | |||
5 | HRESULT ScaScheduleIIS7Configuration(); | ||
6 | |||
7 | HRESULT ScaIIS7ConfigTransaction(__in_z LPCWSTR wzBackup); | ||
8 | |||
9 | HRESULT ScaCreateApp7(__in_z LPCWSTR wzWebRoot, DWORD dwIsolation); | ||
10 | |||
11 | HRESULT ScaDeleteConfigElement(IIS_CONFIG_ACTION emElement, LPCWSTR wzSubKey); | ||
12 | |||
13 | HRESULT ScaWriteConfigString(__in_z const LPCWSTR wzValue); | ||
14 | |||
15 | HRESULT ScaWriteConfigID(IIS_CONFIG_ACTION emID); | ||
16 | |||
17 | HRESULT 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 | |||
5 | enum eMimeMapQuery { mmqMimeMap = 1, mmqParentType, mmqParentValue, | ||
6 | mmqMimeType, mmqExtension}; | ||
7 | |||
8 | // prototypes | ||
9 | static HRESULT AddMimeMapToList(SCA_MIMEMAP** ppsmmList); | ||
10 | |||
11 | |||
12 | void 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 | |||
25 | HRESULT __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 | |||
81 | LExit: | ||
82 | WcaFinishUnwrapQuery(hWrapQuery); | ||
83 | |||
84 | ReleaseStr(pwzData); | ||
85 | |||
86 | return hr; | ||
87 | } | ||
88 | |||
89 | |||
90 | HRESULT 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 | |||
135 | HRESULT 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 | |||
150 | HRESULT 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 | |||
183 | LExit: | ||
184 | return hr; | ||
185 | } | ||
186 | |||
187 | |||
188 | static 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 | |||
198 | LExit: | ||
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 | |||
5 | enum eMimeMapParentType { mmptVDir = 1, mmptWeb = 2 }; | ||
6 | |||
7 | struct 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 | |||
23 | HRESULT __stdcall ScaMimeMapRead(SCA_MIMEMAP** ppsmmList, __inout LPWSTR *ppwzCustomActionData); | ||
24 | |||
25 | HRESULT ScaGetMimeMap(int iParentType, LPCWSTR wzParentValue, SCA_MIMEMAP **psmmList, SCA_MIMEMAP **ppsmmOut); | ||
26 | |||
27 | HRESULT ScaMimeMapCheckList(SCA_MIMEMAP* psmmList); | ||
28 | |||
29 | void ScaMimeMapFreeList(SCA_MIMEMAP* psmmList); | ||
30 | |||
31 | HRESULT 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 | ||
6 | HRESULT 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 | |||
51 | LExit: | ||
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 | |||
5 | HRESULT 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 | /*------------------------------------------------------------------ | ||
6 | IIsProperty table: | ||
7 | |||
8 | Property Component_ Attributes Value | ||
9 | s72 s72 i4 s255 | ||
10 | ------------------------------------------------------------------*/ | ||
11 | |||
12 | // sql queries | ||
13 | enum ePropertyQuery { pqProperty = 1, pqComponent, pqAttributes, pqValue, pqInstalled, pqAction }; | ||
14 | |||
15 | |||
16 | // prototypes | ||
17 | static HRESULT AddPropertyToList( | ||
18 | SCA_PROPERTY** ppspList | ||
19 | ); | ||
20 | |||
21 | |||
22 | // functions | ||
23 | void 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 | |||
38 | HRESULT 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 | |||
101 | LExit: | ||
102 | WcaFinishUnwrapQuery(hWrapQuery); | ||
103 | |||
104 | ReleaseStr(pwzData); | ||
105 | |||
106 | return hr; | ||
107 | } | ||
108 | |||
109 | |||
110 | HRESULT 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 | |||
129 | LExit: | ||
130 | return hr; | ||
131 | } | ||
132 | |||
133 | |||
134 | HRESULT 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 | |||
153 | LExit: | ||
154 | return hr; | ||
155 | } | ||
156 | |||
157 | |||
158 | HRESULT 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 | } | ||
198 | LExit: | ||
199 | return hr; | ||
200 | } | ||
201 | |||
202 | |||
203 | HRESULT 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 | |||
234 | LExit: | ||
235 | return hr; | ||
236 | } | ||
237 | |||
238 | |||
239 | static 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 | |||
250 | LExit: | ||
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 | |||
10 | struct 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 | |||
26 | HRESULT ScaPropertyRead( | ||
27 | SCA_PROPERTY** ppspList, | ||
28 | __inout LPWSTR *ppwzCustomActionData | ||
29 | ); | ||
30 | |||
31 | void ScaPropertyFreeList( | ||
32 | SCA_PROPERTY* pspList | ||
33 | ); | ||
34 | |||
35 | HRESULT ScaPropertyInstall( | ||
36 | IMSAdminBase* piMetabase, | ||
37 | SCA_PROPERTY* pspList | ||
38 | ); | ||
39 | |||
40 | HRESULT ScaPropertyUninstall( | ||
41 | IMSAdminBase* piMetabase, | ||
42 | SCA_PROPERTY* pspList | ||
43 | ); | ||
44 | |||
45 | HRESULT ScaWriteProperty( | ||
46 | IMSAdminBase* piMetabase, | ||
47 | SCA_PROPERTY* psp | ||
48 | ); | ||
49 | |||
50 | HRESULT 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 | |||
5 | HRESULT 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 | |||
21 | LExit: | ||
22 | return hr; | ||
23 | } | ||
24 | |||
25 | |||
26 | HRESULT 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 | |||
42 | LExit: | ||
43 | return hr; | ||
44 | } | ||
45 | |||
46 | |||
47 | HRESULT 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 | |||
90 | LExit: | ||
91 | return hr; | ||
92 | } | ||
93 | |||
94 | HRESULT 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 | ||
11 | HRESULT ScaPropertyInstall7( | ||
12 | SCA_PROPERTY* pspList | ||
13 | ); | ||
14 | |||
15 | HRESULT ScaPropertyUninstall7( | ||
16 | SCA_PROPERTY* pspList | ||
17 | ); | ||
18 | |||
19 | HRESULT ScaWriteProperty7( | ||
20 | const SCA_PROPERTY* psp | ||
21 | ); | ||
22 | |||
23 | HRESULT 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 | |||
5 | const int ConfigureIIsCost = 8; | ||
6 | const int WriteMetabaseChangesCost = 20; | ||
7 | const int WriteIIS7ConfigChangesCost = 20; | ||
8 | |||
9 | // sql queries | ||
10 | LPCWSTR vcsUserDeferredQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Password` FROM `User`"; | ||
11 | |||
12 | LPCWSTR vcsWebSvcExtQuery = L"SELECT `Component_`, `File`, `Description`, `Group`, `Attributes` FROM `IIsWebServiceExtension`"; | ||
13 | |||
14 | LPCWSTR vcsAppPoolQuery = L"SELECT `AppPool`, `Name`, `Component_`, `Attributes`, `User_`, `RecycleMinutes`, `RecycleRequests`, `RecycleTimes`, `VirtualMemory`, `PrivateMemory`, `IdleTimeout`, `QueueLimit`, `CPUMon`, `MaxProc`, `ManagedRuntimeVersion`, `ManagedPipelineMode` FROM `IIsAppPool`"; | ||
15 | |||
16 | LPCWSTR vcsComponentAttrQuery = L"SELECT `Component`,`Attributes` FROM `Component`"; | ||
17 | |||
18 | LPCWSTR vcsMimeMapQuery = L"SELECT `MimeMap`, `ParentType`, `ParentValue`, `MimeType`, `Extension` FROM `IIsMimeMap`"; | ||
19 | |||
20 | LPCWSTR vcsHttpHeaderQuery = L"SELECT `Name`, `ParentType`, `ParentValue`, `Value`, `Attributes` FROM `IIsHttpHeader` ORDER BY `Sequence`"; | ||
21 | |||
22 | LPCWSTR vcsWebErrorQuery = | ||
23 | L"SELECT `ErrorCode`, `SubCode`, `ParentType`, `ParentValue`, `File`, `URL` " | ||
24 | L"FROM `IIsWebError` ORDER BY `ErrorCode`, `SubCode`"; | ||
25 | |||
26 | LPCWSTR vcsWebDirPropertiesQuery = L"SELECT `DirProperties`, `Access`, `Authorization`, `AnonymousUser_`, `IIsControlledPassword`, `LogVisits`, `Index`, `DefaultDoc`, `AspDetailedError`, `HttpExpires`, `CacheControlMaxAge`, `CacheControlCustom`, `NoCustomError`, `AccessSSLFlags`, `AuthenticationProviders` " | ||
27 | L"FROM `IIsWebDirProperties`"; | ||
28 | |||
29 | LPCWSTR vcsSslCertificateQuery = L"SELECT `Certificate`.`StoreName`, `CertificateHash`.`Hash`, `IIsWebSiteCertificates`.`Web_` FROM `Certificate`, `CertificateHash`, `IIsWebSiteCertificates` WHERE `Certificate`.`Certificate`=`CertificateHash`.`Certificate_` AND `CertificateHash`.`Certificate_`=`IIsWebSiteCertificates`.`Certificate_`"; | ||
30 | |||
31 | LPCWSTR vcsWebLogQuery = L"SELECT `Log`, `Format` " | ||
32 | L"FROM `IIsWebLog`"; | ||
33 | |||
34 | LPCWSTR vcsWebApplicationQuery = L"SELECT `Name`, `Isolation`, `AllowSessions`, `SessionTimeout`, " | ||
35 | L"`Buffer`, `ParentPaths`, `DefaultScript`, `ScriptTimeout`, " | ||
36 | L"`ServerDebugging`, `ClientDebugging`, `AppPool_`, `Application` " | ||
37 | L"FROM `IIsWebApplication`"; | ||
38 | |||
39 | LPCWSTR vcsWebAppExtensionQuery = L"SELECT `Extension`, `Verbs`, `Executable`, `Attributes`, `Application_` FROM `IIsWebApplicationExtension`"; | ||
40 | |||
41 | LPCWSTR 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 | |||
45 | LPCWSTR vcsWebAddressQuery = L"SELECT `Address`, `Web_`, `IP`, `Port`, `Header`, `Secure` " | ||
46 | L"FROM `IIsWebAddress`"; | ||
47 | |||
48 | LPCWSTR vcsWebBaseQuery = L"SELECT `Web`, `Id`, `IP`, `Port`, `Header`, `Secure`, `Description` " | ||
49 | L"FROM `IIsWebSite`, `IIsWebAddress` " | ||
50 | L"WHERE `KeyAddress_`=`Address`"; | ||
51 | |||
52 | LPCWSTR vcsWebDirQuery = L"SELECT `Web_`, `WebDir`, `Component_`, `Path`, `DirProperties_`, `Application_` " | ||
53 | L"FROM `IIsWebDir`"; | ||
54 | |||
55 | LPCWSTR vcsVDirQuery = L"SELECT `Web_`, `VirtualDir`, `Component_`, `Alias`, `Directory_`, `DirProperties_`, `Application_` " | ||
56 | L"FROM `IIsWebVirtualDir`"; | ||
57 | |||
58 | LPCWSTR vcsFilterQuery = L"SELECT `Web_`, `Name`, `Component_`, `Path`, `Description`, `Flags`, `LoadOrder` FROM `IIsFilter` ORDER BY `Web_`"; | ||
59 | |||
60 | LPCWSTR 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 | /******************************************************************** | ||
67 | ConfigureIIs - CUSTOM ACTION ENTRY POINT for installing IIs settings | ||
68 | |||
69 | ********************************************************************/ | ||
70 | extern "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 | |||
364 | LExit: | ||
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 | /******************************************************************** | ||
374 | ConfigureIIsExec - custom action for installing IIs settings - table | ||
375 | data will be wrapped and passed in from immediate CA | ||
376 | ReadIIsTables | ||
377 | |||
378 | ********************************************************************/ | ||
379 | extern "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 | |||
556 | LExit: | ||
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 | /******************************************************************** | ||
624 | ConfigureIIs - CUSTOM ACTION ENTRY POINT for installing IIs settings | ||
625 | |||
626 | ********************************************************************/ | ||
627 | extern "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 | |||
767 | LExit: | ||
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 | |||
5 | enum eSslCertificateQuery { scqStoreName = 1, scqHash, scqWeb }; | ||
6 | |||
7 | static HRESULT AddSslCertificateToList( | ||
8 | __in SCA_WEB_SSL_CERTIFICATE** ppswscList | ||
9 | ); | ||
10 | |||
11 | |||
12 | HRESULT 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 | |||
53 | LExit: | ||
54 | ReleaseStr(pwzData); | ||
55 | return hr; | ||
56 | } | ||
57 | |||
58 | |||
59 | HRESULT 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 | |||
81 | LExit: | ||
82 | return hr; | ||
83 | } | ||
84 | |||
85 | |||
86 | void 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 | |||
101 | static 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 | |||
113 | LExit: | ||
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 | ||
12 | struct 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 | ||
22 | HRESULT ScaSslCertificateRead( | ||
23 | __in LPCWSTR wzWebId, | ||
24 | __in WCA_WRAPQUERY_HANDLE hSslCertQuery, | ||
25 | __inout SCA_WEB_SSL_CERTIFICATE** ppswscList | ||
26 | ); | ||
27 | |||
28 | HRESULT ScaSslCertificateWriteMetabase( | ||
29 | __in IMSAdminBase* piMetabase, | ||
30 | __in LPCWSTR wzWebBase, | ||
31 | __in SCA_WEB_SSL_CERTIFICATE* pswscList | ||
32 | ); | ||
33 | |||
34 | void 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 | |||
5 | HRESULT 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 | } | ||
31 | LExit: | ||
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 | |||
5 | HRESULT 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 | |||
5 | LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Password` FROM `User` WHERE `User`=?"; | ||
6 | enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqPassword }; | ||
7 | |||
8 | LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Group` WHERE `Group`=?"; | ||
9 | enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; | ||
10 | |||
11 | LPCWSTR vcsUserGroupQuery = L"SELECT `User_`, `Group_` FROM `UserGroup` WHERE `User_`=?"; | ||
12 | enum eUserGroupQuery { vugqUser = 1, vugqGroup }; | ||
13 | |||
14 | LPCWSTR vActionableQuery = L"SELECT `User`,`Component_`,`Name`,`Domain`,`Password`,`Attributes` FROM `User` WHERE `Component_` IS NOT NULL"; | ||
15 | enum eActionableQuery { vaqUser = 1, vaqComponent, vaqName, vaqDomain, vaqPassword, vaqAttributes }; | ||
16 | |||
17 | HRESULT __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 | |||
87 | LExit: | ||
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 | ||
5 | struct 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 | |||
16 | struct 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 | ||
35 | HRESULT __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 | ||
6 | static HRESULT AddVirtualDirToList( | ||
7 | __in SCA_VDIR** psvdList | ||
8 | ); | ||
9 | |||
10 | |||
11 | HRESULT __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 | |||
173 | LExit: | ||
174 | WcaFinishUnwrapQuery(hWrapQuery); | ||
175 | |||
176 | ReleaseStr(pwzData); | ||
177 | return hr; | ||
178 | } | ||
179 | |||
180 | |||
181 | HRESULT 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 | |||
252 | LExit: | ||
253 | return hr; | ||
254 | } | ||
255 | |||
256 | |||
257 | HRESULT 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 | |||
288 | LExit: | ||
289 | return hr; | ||
290 | } | ||
291 | |||
292 | |||
293 | void 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 | |||
318 | static 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 | |||
329 | LExit: | ||
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 | |||
10 | enum eVDirQuery { vdqWeb = 1, vdqVDir, vdqComponent , vdqAlias, vdqDirectory, vdqProperties, vdqApplication, vdqInstalled, vdqAction, vdqSourcePath, vdqTargetPath }; | ||
11 | |||
12 | struct 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 | ||
43 | HRESULT __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 | |||
58 | HRESULT ScaVirtualDirsInstall( | ||
59 | __in IMSAdminBase* piMetabase, | ||
60 | __in SCA_VDIR* psvdList, | ||
61 | __in SCA_APPPOOL * psapList | ||
62 | ); | ||
63 | |||
64 | HRESULT ScaVirtualDirsUninstall( | ||
65 | __in IMSAdminBase* piMetabase, | ||
66 | __in SCA_VDIR* psvdList | ||
67 | ); | ||
68 | |||
69 | void 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 | ||
6 | static HRESULT AddVirtualDirToList7( | ||
7 | __in SCA_VDIR7** psvdList | ||
8 | ); | ||
9 | |||
10 | |||
11 | HRESULT __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 | |||
160 | LExit: | ||
161 | WcaFinishUnwrapQuery(hWrapQuery); | ||
162 | |||
163 | ReleaseStr(pwzData); | ||
164 | |||
165 | return hr; | ||
166 | } | ||
167 | |||
168 | |||
169 | HRESULT 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 | |||
275 | LExit: | ||
276 | ReleaseStr(wzPath); | ||
277 | return hr; | ||
278 | } | ||
279 | |||
280 | |||
281 | HRESULT 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 | |||
335 | LExit: | ||
336 | ReleaseStr(wzPath); | ||
337 | return hr; | ||
338 | } | ||
339 | |||
340 | |||
341 | void 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 | |||
366 | static 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 | |||
378 | LExit: | ||
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 | |||
10 | struct 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 | ||
41 | HRESULT __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 | |||
55 | HRESULT ScaVirtualDirsInstall7( | ||
56 | __in SCA_VDIR7* psvdList, | ||
57 | __in SCA_APPPOOL * psapList | ||
58 | ); | ||
59 | |||
60 | HRESULT ScaVirtualDirsUninstall7( | ||
61 | __in SCA_VDIR7* psvdList | ||
62 | ); | ||
63 | |||
64 | void 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 | |||
12 | enum eWebBaseQuery { wbqWeb = 1, wbqId, wbqIP, wbqPort, wbqHeader, wbqSecure, wbqDescription }; | ||
13 | |||
14 | |||
15 | // prototypes for private helper functions | ||
16 | static SCA_WEB* NewWeb(); | ||
17 | static void FreeWeb(SCA_WEB *pswDelete); | ||
18 | static SCA_WEB* AddWebToList( | ||
19 | __in SCA_WEB* pswList, | ||
20 | __in SCA_WEB* psw | ||
21 | ); | ||
22 | static 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 | ); | ||
35 | static 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 | ); | ||
43 | static HRESULT ScaWebWrite( | ||
44 | __in IMSAdminBase* piMetabase, | ||
45 | __in SCA_WEB* psw, | ||
46 | __in SCA_APPPOOL * psapList | ||
47 | ); | ||
48 | static HRESULT ScaWebRemove( | ||
49 | __in IMSAdminBase* piMetabase, | ||
50 | __in const SCA_WEB* psw); | ||
51 | static DWORD SiteIdFromDescription( | ||
52 | __in_z LPCWSTR wzDescription | ||
53 | ); | ||
54 | static void Sort( | ||
55 | __in_ecount(cArray) DWORD dwArray[], | ||
56 | __in int cArray | ||
57 | ); | ||
58 | |||
59 | |||
60 | HRESULT 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 | |||
356 | LExit: | ||
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 | |||
372 | HRESULT 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 | |||
439 | LExit: | ||
440 | ReleaseStr(pwzData); | ||
441 | |||
442 | return hr; | ||
443 | } | ||
444 | |||
445 | |||
446 | HRESULT 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 | |||
467 | LExit: | ||
468 | return hr; | ||
469 | } | ||
470 | |||
471 | |||
472 | HRESULT 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 | |||
492 | LExit: | ||
493 | return hr; | ||
494 | } | ||
495 | |||
496 | |||
497 | void 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 | |||
515 | static void FreeWeb(SCA_WEB *pswDelete) | ||
516 | { | ||
517 | ScaSslCertificateFreeList(pswDelete->pswscList); | ||
518 | ScaHttpHeaderFreeList(pswDelete->pshhList); | ||
519 | ScaWebErrorFreeList(pswDelete->psweList); | ||
520 | MemFree(pswDelete); | ||
521 | } | ||
522 | |||
523 | static 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 | |||
531 | static 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 | |||
555 | static 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 | |||
754 | LExit: | ||
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 | |||
767 | static 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 | |||
898 | LExit: | ||
899 | MetaFreeValue(&mr); | ||
900 | |||
901 | if (prgdwSubKeys) | ||
902 | { | ||
903 | MemFree(prgdwSubKeys); | ||
904 | } | ||
905 | |||
906 | return hr; | ||
907 | } | ||
908 | |||
909 | |||
910 | static 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 | |||
1127 | LExit: | ||
1128 | return hr; | ||
1129 | } | ||
1130 | |||
1131 | |||
1132 | static 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 | |||
1143 | LExit: | ||
1144 | return hr; | ||
1145 | } | ||
1146 | |||
1147 | |||
1148 | static 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 | ||
1166 | static 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 | |||
17 | enum eWebQuery { wqWeb = 1, wqComponent, wqId, wqDescription, wqConnectionTimeout, wqDirectory, | ||
18 | wqState, wqAttributes, wqProperties, wqApplication, wqAddress, wqIP, wqPort, wqHeader, wqSecure, wqLog, wqInstalled, wqAction, wqSourcePath, wqTargetPath}; | ||
19 | |||
20 | enum eWebAddressQuery { waqAddress = 1, waqWeb, waqIP, waqPort, waqHeader, waqSecure }; | ||
21 | |||
22 | enum SCA_WEB_ATTRIBUTES | ||
23 | { | ||
24 | SWATTRIB_NOCONFIGUREIFEXISTS = 2 | ||
25 | }; | ||
26 | |||
27 | // structs | ||
28 | struct 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 | |||
38 | struct 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 | ||
86 | HRESULT 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 | |||
101 | HRESULT 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 | |||
110 | HRESULT ScaWebsInstall( | ||
111 | __in IMSAdminBase* piMetabase, | ||
112 | __in SCA_WEB* pswList, | ||
113 | __in SCA_APPPOOL * psapList | ||
114 | ); | ||
115 | |||
116 | HRESULT ScaWebsUninstall( | ||
117 | __in IMSAdminBase* piMetabase, | ||
118 | __in SCA_WEB* pswList | ||
119 | ); | ||
120 | |||
121 | void 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 | ||
11 | static SCA_WEB7* NewWeb7(); | ||
12 | static SCA_WEB7* AddWebToList7( | ||
13 | __in SCA_WEB7* pswList, | ||
14 | __in SCA_WEB7* psw | ||
15 | ); | ||
16 | |||
17 | static HRESULT ScaWebFindBase7( | ||
18 | __in SCA_WEB7* pswList, | ||
19 | LPCWSTR wzDescription | ||
20 | ); | ||
21 | |||
22 | static HRESULT ScaWebWrite7( | ||
23 | __in SCA_WEB7* psw, | ||
24 | __in SCA_APPPOOL * psapList | ||
25 | ); | ||
26 | |||
27 | static HRESULT ScaWebRemove7(__in const SCA_WEB7* psw); | ||
28 | |||
29 | |||
30 | HRESULT 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 | |||
319 | LExit: | ||
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 | |||
332 | BOOL 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 | |||
387 | LExit: | ||
388 | WcaLog(LOGMSG_VERBOSE, "Site with binding %ls %s a match", pwzBindingInfo, fFound ? "is" : "is not"); | ||
389 | ReleaseNullStr(pwzBindingInfo); | ||
390 | return fFound; | ||
391 | } | ||
392 | |||
393 | BOOL 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; | ||
425 | LExit: | ||
426 | VariantClear(&vtProp); | ||
427 | ReleaseNullObject(pSiteChildren); | ||
428 | ReleaseNullObject(pBindings); | ||
429 | ReleaseNullObject(pBindingsCollection); | ||
430 | ReleaseNullObject(pBinding); | ||
431 | return fFound; | ||
432 | } | ||
433 | |||
434 | HRESULT 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 | } | ||
523 | LExit: | ||
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 | |||
539 | HRESULT 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 | } | ||
590 | LExit: | ||
591 | ReleaseNullStr(wzSiteName); | ||
592 | return hr; | ||
593 | } | ||
594 | |||
595 | HRESULT 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 | |||
615 | LExit: | ||
616 | return hr; | ||
617 | } | ||
618 | |||
619 | |||
620 | HRESULT 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 | |||
639 | LExit: | ||
640 | return hr; | ||
641 | } | ||
642 | |||
643 | |||
644 | void 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 | |||
664 | static SCA_WEB7* NewWeb7() | ||
665 | { | ||
666 | SCA_WEB7* psw = (SCA_WEB7*)MemAlloc(sizeof(SCA_WEB7), TRUE); | ||
667 | Assert(psw); | ||
668 | return psw; | ||
669 | } | ||
670 | |||
671 | |||
672 | static 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 | |||
696 | static 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 | |||
723 | static 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 | |||
932 | LExit: | ||
933 | return hr; | ||
934 | } | ||
935 | |||
936 | |||
937 | static 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 | |||
950 | LExit: | ||
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 | ||
17 | struct 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 | ||
66 | HRESULT 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 | |||
79 | HRESULT ScaWebsGetBase7( | ||
80 | __in SCA_WEB7* pswList, | ||
81 | __in LPCWSTR pswWebKey, | ||
82 | __out_ecount(cchDest) LPWSTR pswWeb, | ||
83 | __in DWORD_PTR cchDest | ||
84 | ); | ||
85 | |||
86 | HRESULT ScaWebsInstall7( | ||
87 | __in SCA_WEB7* pswList, | ||
88 | __in SCA_APPPOOL * psapList | ||
89 | ); | ||
90 | |||
91 | HRESULT ScaWebsUninstall7( | ||
92 | __in SCA_WEB7* pswList | ||
93 | ); | ||
94 | |||
95 | void 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 | ||
6 | enum eWebApplicationQuery { wappqName = 1, wappqIsolation, wappqAllowSession, | ||
7 | wappqSessionTimeout, wappqBuffer, wappqParentPaths, | ||
8 | wappqDefaultScript, wappqScriptTimeout, | ||
9 | wappqServerDebugging, wappqClientDebugging, wappqAppPool, wappqApplication}; | ||
10 | |||
11 | |||
12 | HRESULT 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 | |||
94 | LExit: | ||
95 | ReleaseStr(pwzData); | ||
96 | |||
97 | return hr; | ||
98 | } | ||
99 | |||
100 | |||
101 | HRESULT 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 | |||
192 | LExit: | ||
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 | ||
9 | extern LPCWSTR vcsWebApplicationQuery; | ||
10 | const int MAX_APP_NAME = 255; | ||
11 | |||
12 | // structs | ||
13 | struct 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 | ||
34 | HRESULT ScaGetWebApplication(MSIHANDLE hViewApplications, | ||
35 | LPCWSTR pwzApplication, | ||
36 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, | ||
37 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
38 | SCA_WEB_APPLICATION* pswapp); | ||
39 | |||
40 | HRESULT 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" | ||
4 | HRESULT 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 | |||
118 | LExit: | ||
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 | |||
5 | HRESULT 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 | |||
5 | enum eWebAppExtensionQuery { wappextqExtension = 1, wappextqVerbs, wappextqExecutable, wappextqAttributes, wappextqApplication }; | ||
6 | |||
7 | // prototypes for private helper functions | ||
8 | static HRESULT NewAppExt( | ||
9 | __out SCA_WEB_APPLICATION_EXTENSION** ppswappext | ||
10 | ); | ||
11 | static SCA_WEB_APPLICATION_EXTENSION* AddAppExtToList( | ||
12 | __in SCA_WEB_APPLICATION_EXTENSION* pswappextList, | ||
13 | __in SCA_WEB_APPLICATION_EXTENSION* pswappext | ||
14 | ); | ||
15 | |||
16 | |||
17 | |||
18 | HRESULT 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 | |||
74 | LExit: | ||
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 | |||
88 | HRESULT 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 | |||
148 | LExit: | ||
149 | return hr; | ||
150 | } | ||
151 | |||
152 | |||
153 | void 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 | |||
171 | static 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 | |||
181 | LExit: | ||
182 | return hr; | ||
183 | } | ||
184 | |||
185 | |||
186 | static 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 | |||
5 | struct 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 | ||
18 | HRESULT ScaWebAppExtensionsRead( | ||
19 | __in LPCWSTR wzApplication, | ||
20 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, | ||
21 | __inout SCA_WEB_APPLICATION_EXTENSION** ppswappextList | ||
22 | ); | ||
23 | |||
24 | HRESULT ScaWebAppExtensionsWrite( | ||
25 | __in IMSAdminBase* piMetabase, | ||
26 | __in LPCWSTR wzRootOfWeb, | ||
27 | __in SCA_WEB_APPLICATION_EXTENSION* pswappextList | ||
28 | ); | ||
29 | |||
30 | void 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 | |||
5 | HRESULT 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 | |||
58 | LExit: | ||
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 | |||
5 | HRESULT 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 | ||
6 | enum eWebDirQuery { wdqWeb = 1, wdqWebDir, wdqComponent , wdqPath, wdqProperties, wdqApplication, wdqInstalled, wdqAction }; | ||
7 | |||
8 | // prototypes | ||
9 | static void AddWebDirToList(SCA_WEBDIR** ppswdList, SCA_WEBDIR *pswd); | ||
10 | |||
11 | static SCA_WEBDIR* NewWebDir(); | ||
12 | static void FreeWebDir(SCA_WEBDIR *pswd); | ||
13 | |||
14 | |||
15 | UINT __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 | |||
121 | LExit: | ||
122 | WcaFinishUnwrapQuery(hWrapQuery); | ||
123 | |||
124 | ReleaseStr(pwzData); | ||
125 | |||
126 | return hr; | ||
127 | } | ||
128 | |||
129 | |||
130 | HRESULT 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 | |||
177 | LExit: | ||
178 | return hr; | ||
179 | } | ||
180 | |||
181 | |||
182 | HRESULT 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 | |||
207 | LExit: | ||
208 | return hr; | ||
209 | } | ||
210 | |||
211 | |||
212 | static 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 | |||
219 | static void FreeWebDir(SCA_WEBDIR *pswd) | ||
220 | { | ||
221 | MemFree(pswd); | ||
222 | } | ||
223 | |||
224 | void 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 | |||
237 | static 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 | |||
5 | struct 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 | ||
32 | UINT __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 | |||
44 | HRESULT ScaWebDirsInstall( | ||
45 | __in IMSAdminBase* piMetabase, | ||
46 | __in SCA_WEBDIR* pswdList, | ||
47 | __in SCA_APPPOOL* psapList | ||
48 | ); | ||
49 | |||
50 | HRESULT ScaWebDirsUninstall( | ||
51 | __in IMSAdminBase* piMetabase, | ||
52 | __in SCA_WEBDIR* pswdList | ||
53 | ); | ||
54 | |||
55 | void 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 | ||
6 | static LPCWSTR vcsWebDirQuery7 = L"SELECT `Web_`, `WebDir`, `Component_`, `Path`, `DirProperties_`, `Application_`" | ||
7 | L"FROM `IIsWebDir`"; | ||
8 | |||
9 | enum eWebDirQuery { wdqWeb = 1, wdqWebDir, wdqComponent , wdqPath, wdqProperties, wdqApplication, wdqInstalled, wdqAction }; | ||
10 | |||
11 | // prototypes | ||
12 | static HRESULT AddWebDirToList(SCA_WEBDIR7** ppswdList); | ||
13 | |||
14 | |||
15 | UINT __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 | |||
110 | LExit: | ||
111 | WcaFinishUnwrapQuery(hWrapQuery); | ||
112 | |||
113 | ReleaseStr(pwzData); | ||
114 | |||
115 | return hr; | ||
116 | } | ||
117 | |||
118 | |||
119 | HRESULT 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 | |||
159 | LExit: | ||
160 | return hr; | ||
161 | } | ||
162 | |||
163 | |||
164 | HRESULT 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 | |||
189 | LExit: | ||
190 | return hr; | ||
191 | } | ||
192 | |||
193 | |||
194 | void 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 | |||
207 | static 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 | |||
217 | LExit: | ||
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 | |||
5 | struct 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 | ||
29 | UINT __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 | |||
40 | HRESULT ScaWebDirsInstall7( | ||
41 | __in SCA_WEBDIR7* pswdList, | ||
42 | __in SCA_APPPOOL* psapList | ||
43 | ); | ||
44 | |||
45 | HRESULT ScaWebDirsUninstall7( | ||
46 | __in SCA_WEBDIR7* pswdList | ||
47 | ); | ||
48 | |||
49 | void 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 | |||
5 | enum eWebErrorQuery { weqErrorCode = 1, weqSubCode, weqParentType, weqParentValue, weqFile, weqURL }; | ||
6 | |||
7 | static HRESULT AddWebErrorToList(SCA_WEB_ERROR** ppsweList); | ||
8 | |||
9 | void 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 | |||
21 | HRESULT 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 | |||
87 | LExit: | ||
88 | WcaFinishUnwrapQuery(hWrapQuery); | ||
89 | |||
90 | ReleaseStr(pwzData); | ||
91 | |||
92 | return hr; | ||
93 | } | ||
94 | |||
95 | HRESULT 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 | |||
140 | HRESULT 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 | |||
332 | LExit: | ||
333 | ReleaseStr(pwzErrors); | ||
334 | ReleaseStr(pwzSearchKey); | ||
335 | ReleaseStr(pwzCodeSubCode); | ||
336 | ReleaseStr(pwzAcceptableCodeSubCode); | ||
337 | ReleaseStr(pwzAcceptableErrors); | ||
338 | |||
339 | return hr; | ||
340 | } | ||
341 | |||
342 | static 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 | |||
352 | LExit: | ||
353 | return hr; | ||
354 | } | ||
355 | |||
356 | HRESULT 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 | |||
5 | enum eWebErrorParentType { weptVDir = 1, weptWeb }; | ||
6 | |||
7 | struct 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 | ||
22 | HRESULT ScaWebErrorRead( | ||
23 | SCA_WEB_ERROR **ppsweList, | ||
24 | __inout LPWSTR *ppwzCustomActionData | ||
25 | ); | ||
26 | void ScaWebErrorFreeList(SCA_WEB_ERROR *psweList); | ||
27 | HRESULT ScaWebErrorCheckList(SCA_WEB_ERROR* psweList); | ||
28 | HRESULT ScaGetWebError(int iParentType, LPCWSTR wzParentValue, SCA_WEB_ERROR **ppsweList, SCA_WEB_ERROR **ppsweOut); | ||
29 | HRESULT 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 | |||
5 | HRESULT 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 | |||
54 | LExit: | ||
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 | |||
73 | HRESULT 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 | |||
5 | HRESULT 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 | |||
5 | enum 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 | * ****************************************************************/ | ||
11 | static 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 | |||
62 | LExit: | ||
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 | * ****************************************************************/ | ||
82 | HRESULT 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 | |||
133 | LExit: | ||
134 | ReleaseStr(pwzData); | ||
135 | |||
136 | return hr; | ||
137 | } | ||
138 | |||
139 | |||
140 | /* **************************************************************** | ||
141 | * ScaWriteWebLog -Writes the IIS log values to the metabase. | ||
142 | * | ||
143 | * ****************************************************************/ | ||
144 | HRESULT 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 | |||
173 | LExit: | ||
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 | |||
5 | struct 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 | ||
17 | HRESULT ScaGetWebLog( | ||
18 | IMSAdminBase* piMetabase, | ||
19 | LPCWSTR wzLog, | ||
20 | __in WCA_WRAPQUERY_HANDLE hWebLogQuery, | ||
21 | SCA_WEB_LOG* pswl | ||
22 | ); | ||
23 | HRESULT 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 | ||
5 | LPCWSTR vcsWebLogQuery7 = L"SELECT `Log`, `Format` " | ||
6 | L"FROM `IIsWebLog` WHERE `Log`=?"; | ||
7 | |||
8 | enum eWebLogQuery { wlqLog = 1, wlqFormat }; | ||
9 | |||
10 | /* **************************************************************** | ||
11 | * ScaGetWebLog7 -Retrieves Log table data for the specified Log key | ||
12 | * | ||
13 | * ****************************************************************/ | ||
14 | HRESULT 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 | |||
87 | LExit: | ||
88 | ReleaseStr(pwzData); | ||
89 | |||
90 | return hr; | ||
91 | } | ||
92 | |||
93 | |||
94 | /* **************************************************************** | ||
95 | * ScaWriteWebLog -Writes the IIS log values to the metabase. | ||
96 | * | ||
97 | * ****************************************************************/ | ||
98 | HRESULT 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 | |||
116 | LExit: | ||
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 | |||
5 | HRESULT ScaGetWebLog7( | ||
6 | __in_z LPCWSTR wzLog, | ||
7 | __in WCA_WRAPQUERY_HANDLE hWebLogQuery, | ||
8 | __out SCA_WEB_LOG* pswl | ||
9 | ); | ||
10 | |||
11 | HRESULT 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 | ||
6 | enum eWebDirPropertiesQuery { wpqProperties = 1, wpqAccess, wpqAuthorization, wpqUser, wpqControlledPassword, wpqLogVisits, wpqIndex, wpqDefaultDoc, wpqAspDetailedError, wpqHttpExp, wpqCCMaxAge, wpqCCCustom, wpqNoCustomError, wpqAccessSSLFlags, wpqAuthenticationProviders }; | ||
7 | |||
8 | HRESULT 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 | |||
175 | LExit: | ||
176 | ReleaseStr(pwzData); | ||
177 | |||
178 | return hr; | ||
179 | } | ||
180 | |||
181 | |||
182 | HRESULT 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 | |||
299 | LExit: | ||
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 | ||
8 | extern LPCWSTR vcsWebDirPropertiesQuery; | ||
9 | |||
10 | |||
11 | // structs | ||
12 | struct 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 | ||
48 | HRESULT 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 | |||
55 | HRESULT 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 | |||
5 | HRESULT 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 | |||
153 | LExit: | ||
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 | |||
7 | HRESULT 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 | ||
6 | enum eWebSvcExtQuery { ldqComponent=1 , ldqFile, ldqDescription, ldqGroup, ldqAttributes, ldqInstalled, ldqAction }; | ||
7 | |||
8 | |||
9 | LPCWSTR vcsWebSvcExtRoot = L"/LM/W3SVC"; | ||
10 | |||
11 | // prototypes for private helper functions | ||
12 | static HRESULT AddWebSvcExtToList( | ||
13 | __in SCA_WEBSVCEXT** ppsWseList | ||
14 | ); | ||
15 | |||
16 | //static HRESULT ScaCheckWebSvcExtValue( | ||
17 | // __in IMSAdminBase* piMetabase, | ||
18 | // __in DWORD dwMDIdentifier | ||
19 | // ); | ||
20 | |||
21 | static HRESULT ScaWebSvcExtInstall( | ||
22 | __in LPWSTR *pwzWebSvcExtList, | ||
23 | __in DWORD_PTR *pcchWebSvcExtList, | ||
24 | __in SCA_WEBSVCEXT* psWseList | ||
25 | ); | ||
26 | |||
27 | static HRESULT ScaWebSvcExtUninstall( | ||
28 | __in LPWSTR *pwzWebSvcExtList, | ||
29 | __in const DWORD *pcchWebSvcExtList, | ||
30 | __in SCA_WEBSVCEXT* psWseList | ||
31 | ); | ||
32 | |||
33 | // functions | ||
34 | |||
35 | HRESULT __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 | |||
112 | LExit: | ||
113 | WcaFinishUnwrapQuery(hWrapQuery); | ||
114 | |||
115 | ReleaseStr(pwzData); | ||
116 | |||
117 | return hr; | ||
118 | } | ||
119 | |||
120 | |||
121 | // Commit does both install and uninstall | ||
122 | HRESULT __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 | |||
196 | LExit: | ||
197 | ReleaseStr(wzWebSvcExtList); | ||
198 | |||
199 | return hr; | ||
200 | } | ||
201 | |||
202 | |||
203 | static 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 | |||
248 | LExit: | ||
249 | ReleaseStr(pwzWebSvcExt); | ||
250 | |||
251 | return hr; | ||
252 | } | ||
253 | |||
254 | |||
255 | static 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 | |||
279 | LExit: | ||
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 | |||
315 | void 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 | |||
329 | static 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 | |||
341 | LExit: | ||
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 | |||
5 | enum SCA_WEBSVCEXT_ATTRIBUTES { SWSEATTRIB_ALLOW = 1, SWSEATTRIB_UIDELETABLE = 2 }; | ||
6 | |||
7 | struct 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 | |||
23 | HRESULT __stdcall ScaWebSvcExtRead( | ||
24 | __in SCA_WEBSVCEXT** ppsWseList, | ||
25 | __inout LPWSTR *ppwzCustomActionData | ||
26 | ); | ||
27 | |||
28 | HRESULT ScaWebSvcExtCommit( | ||
29 | __in IMSAdminBase* piMetabase, | ||
30 | __in SCA_WEBSVCEXT* psWseList | ||
31 | ); | ||
32 | |||
33 | void 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 | |||
5 | static HRESULT ScaWebSvcExtInstall( | ||
6 | const SCA_WEBSVCEXT* psWseList | ||
7 | ); | ||
8 | |||
9 | static HRESULT ScaWebSvcExtUninstall( | ||
10 | const SCA_WEBSVCEXT* psWseList | ||
11 | ); | ||
12 | |||
13 | // functions | ||
14 | // Commit does both install and uninstall | ||
15 | HRESULT __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 | |||
45 | LExit: | ||
46 | |||
47 | return hr; | ||
48 | } | ||
49 | |||
50 | |||
51 | static 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 | |||
82 | LExit: | ||
83 | |||
84 | return hr; | ||
85 | } | ||
86 | |||
87 | |||
88 | static 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 | |||
104 | LExit: | ||
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 | |||
5 | HRESULT ScaWebSvcExtCommit7( | ||
6 | __in SCA_WEBSVCEXT* psWseList | ||
7 | ); | ||
8 | |||