aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Http/ca
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Http/ca')
-rw-r--r--src/ext/Http/ca/caDecor.h13
-rw-r--r--src/ext/Http/ca/cost.h6
-rw-r--r--src/ext/Http/ca/dllmain.cpp26
-rw-r--r--src/ext/Http/ca/httpca.vcxproj72
-rw-r--r--src/ext/Http/ca/httpca.vcxproj.filters42
-rw-r--r--src/ext/Http/ca/packages.config5
-rw-r--r--src/ext/Http/ca/precomp.h25
-rw-r--r--src/ext/Http/ca/snisslcert.cpp704
-rw-r--r--src/ext/Http/ca/wixhttpca.cpp530
-rw-r--r--src/ext/Http/ca/wixhttpca.def12
10 files changed, 1435 insertions, 0 deletions
diff --git a/src/ext/Http/ca/caDecor.h b/src/ext/Http/ca/caDecor.h
new file mode 100644
index 00000000..da274650
--- /dev/null
+++ b/src/ext/Http/ca/caDecor.h
@@ -0,0 +1,13 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5#if defined(_M_ARM64)
6#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_A64"
7#elif defined(_M_AMD64)
8#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X64"
9#elif defined(_M_ARM)
10#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_ARM"
11#else
12#define CUSTOM_ACTION_DECORATION(f) L"Wix4" f L"_X86"
13#endif
diff --git a/src/ext/Http/ca/cost.h b/src/ext/Http/ca/cost.h
new file mode 100644
index 00000000..9677e7e8
--- /dev/null
+++ b/src/ext/Http/ca/cost.h
@@ -0,0 +1,6 @@
1#pragma once
2// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3
4
5const UINT COST_HTTP_URL_ACL = 2000;
6const UINT COST_HTTP_SNI_SSL = 2000;
diff --git a/src/ext/Http/ca/dllmain.cpp b/src/ext/Http/ca/dllmain.cpp
new file mode 100644
index 00000000..b4c8c037
--- /dev/null
+++ b/src/ext/Http/ca/dllmain.cpp
@@ -0,0 +1,26 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5/********************************************************************
6DllMain - standard entry point for all WiX CustomActions
7
8********************************************************************/
9extern "C" BOOL WINAPI DllMain(
10 IN HINSTANCE hInstance,
11 IN ULONG ulReason,
12 IN LPVOID)
13{
14 switch(ulReason)
15 {
16 case DLL_PROCESS_ATTACH:
17 WcaGlobalInitialize(hInstance);
18 break;
19
20 case DLL_PROCESS_DETACH:
21 WcaGlobalFinalize();
22 break;
23 }
24
25 return TRUE;
26}
diff --git a/src/ext/Http/ca/httpca.vcxproj b/src/ext/Http/ca/httpca.vcxproj
new file mode 100644
index 00000000..fde00ff4
--- /dev/null
+++ b/src/ext/Http/ca/httpca.vcxproj
@@ -0,0 +1,72 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
4 <Import Project="..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props')" />
5 <Import Project="..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props" Condition="Exists('..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props')" />
6
7 <ItemGroup Label="ProjectConfigurations">
8 <ProjectConfiguration Include="Debug|Win32">
9 <Configuration>Debug</Configuration>
10 <Platform>Win32</Platform>
11 </ProjectConfiguration>
12 <ProjectConfiguration Include="Release|Win32">
13 <Configuration>Release</Configuration>
14 <Platform>Win32</Platform>
15 </ProjectConfiguration>
16 <ProjectConfiguration Include="Debug|x64">
17 <Configuration>Debug</Configuration>
18 <Platform>x64</Platform>
19 </ProjectConfiguration>
20 <ProjectConfiguration Include="Release|x64">
21 <Configuration>Release</Configuration>
22 <Platform>x64</Platform>
23 </ProjectConfiguration>
24 <ProjectConfiguration Include="Debug|ARM64">
25 <Configuration>Debug</Configuration>
26 <Platform>ARM64</Platform>
27 </ProjectConfiguration>
28 <ProjectConfiguration Include="Release|ARM64">
29 <Configuration>Release</Configuration>
30 <Platform>ARM64</Platform>
31 </ProjectConfiguration>
32 </ItemGroup>
33
34 <PropertyGroup Label="Globals">
35 <ProjectGuid>{90743805-C043-47C7-B5FF-8F5EE5C8A2DE}</ProjectGuid>
36 <ConfigurationType>DynamicLibrary</ConfigurationType>
37 <PlatformToolset>v142</PlatformToolset>
38 <CharacterSet>Unicode</CharacterSet>
39 <TargetName>httpca</TargetName>
40 <ProjectModuleDefinitionFile>wixhttpca.def</ProjectModuleDefinitionFile>
41 <Description>WiX Toolset Http CustomAction</Description>
42 </PropertyGroup>
43
44 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
45 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
46
47 <PropertyGroup>
48 <ProjectAdditionalLinkLibraries>crypt32.lib;httpapi.lib;msi.lib;rpcrt4.lib;ws2_32.lib</ProjectAdditionalLinkLibraries>
49 </PropertyGroup>
50
51 <ItemGroup>
52 <ClCompile Include="dllmain.cpp">
53 <PrecompiledHeader>Create</PrecompiledHeader>
54 </ClCompile>
55 <ClCompile Include="snisslcert.cpp" />
56 <ClCompile Include="wixhttpca.cpp" />
57 <ClInclude Include="cost.h" />
58 <ClInclude Include="precomp.h" />
59 <None Include="packages.config" />
60 <None Include="wixhttpca.def" />
61 </ItemGroup>
62
63 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
64
65 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
66 <PropertyGroup>
67 <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
68 </PropertyGroup>
69 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.56\build\WixToolset.DUtil.props'))" />
70 <Error Condition="!Exists('..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.WcaUtil.4.0.17\build\WixToolset.WcaUtil.props'))" />
71 </Target>
72</Project>
diff --git a/src/ext/Http/ca/httpca.vcxproj.filters b/src/ext/Http/ca/httpca.vcxproj.filters
new file mode 100644
index 00000000..2ccd604d
--- /dev/null
+++ b/src/ext/Http/ca/httpca.vcxproj.filters
@@ -0,0 +1,42 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ItemGroup>
4 <Filter Include="Source Files">
5 <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
6 <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
7 </Filter>
8 <Filter Include="Header Files">
9 <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
10 <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
11 </Filter>
12 <Filter Include="Resource Files">
13 <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
14 <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
15 </Filter>
16 </ItemGroup>
17 <ItemGroup>
18 <ClCompile Include="wixhttpca.cpp">
19 <Filter>Source Files</Filter>
20 </ClCompile>
21 <ClCompile Include="dllmain.cpp">
22 <Filter>Source Files</Filter>
23 </ClCompile>
24 <ClCompile Include="snisslcert.cpp">
25 <Filter>Source Files</Filter>
26 </ClCompile>
27 </ItemGroup>
28 <ItemGroup>
29 <ClInclude Include="precomp.h">
30 <Filter>Header Files</Filter>
31 </ClInclude>
32 <ClInclude Include="cost.h">
33 <Filter>Header Files</Filter>
34 </ClInclude>
35 </ItemGroup>
36 <ItemGroup>
37 <None Include="wixhttpca.def">
38 <Filter>Source Files</Filter>
39 </None>
40 <None Include="packages.config" />
41 </ItemGroup>
42</Project> \ No newline at end of file
diff --git a/src/ext/Http/ca/packages.config b/src/ext/Http/ca/packages.config
new file mode 100644
index 00000000..9d88f529
--- /dev/null
+++ b/src/ext/Http/ca/packages.config
@@ -0,0 +1,5 @@
1<?xml version="1.0" encoding="utf-8"?>
2<packages>
3 <package id="WixToolset.DUtil" version="4.0.56" targetFramework="native" />
4 <package id="WixToolset.WcaUtil" version="4.0.17" targetFramework="native" />
5</packages> \ No newline at end of file
diff --git a/src/ext/Http/ca/precomp.h b/src/ext/Http/ca/precomp.h
new file mode 100644
index 00000000..c78d78c1
--- /dev/null
+++ b/src/ext/Http/ca/precomp.h
@@ -0,0 +1,25 @@
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 <http.h>
6#include <msiquery.h>
7#include <strsafe.h>
8
9#include "wcautil.h"
10#include "cryputil.h"
11#include "dutil.h"
12#include "memutil.h"
13#include "strutil.h"
14#include "aclutil.h"
15
16#include "cost.h"
17
18#include "caDecor.h"
19
20enum eHandleExisting
21{
22 heReplace = 0,
23 heIgnore = 1,
24 heFail = 2
25};
diff --git a/src/ext/Http/ca/snisslcert.cpp b/src/ext/Http/ca/snisslcert.cpp
new file mode 100644
index 00000000..3a7336af
--- /dev/null
+++ b/src/ext/Http/ca/snisslcert.cpp
@@ -0,0 +1,704 @@
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#if _WIN32_WINNT < 0x0602
6
7typedef struct _HTTP_SERVICE_CONFIG_SSL_SNI_KEY
8{
9 SOCKADDR_STORAGE IpPort;
10 PWSTR Host;
11} HTTP_SERVICE_CONFIG_SSL_SNI_KEY, * PHTTP_SERVICE_CONFIG_SSL_SNI_KEY;
12
13typedef struct _HTTP_SERVICE_CONFIG_SSL_SNI_SET
14{
15 HTTP_SERVICE_CONFIG_SSL_SNI_KEY KeyDesc;
16 HTTP_SERVICE_CONFIG_SSL_PARAM ParamDesc;
17} HTTP_SERVICE_CONFIG_SSL_SNI_SET, * PHTTP_SERVICE_CONFIG_SSL_SNI_SET;
18
19typedef struct _HTTP_SERVICE_CONFIG_SSL_SNI_QUERY
20{
21 HTTP_SERVICE_CONFIG_QUERY_TYPE QueryDesc;
22 HTTP_SERVICE_CONFIG_SSL_SNI_KEY KeyDesc;
23 DWORD dwToken;
24} HTTP_SERVICE_CONFIG_SSL_SNI_QUERY, * PHTTP_SERVICE_CONFIG_SSL_SNI_QUERY;
25
26#define HttpServiceConfigSslSniCertInfo static_cast<HTTP_SERVICE_CONFIG_ID>(HttpServiceConfigCache + 1)
27
28#endif
29
30static UINT SchedHttpSniSslCerts(
31 __in WCA_TODO todoSched
32);
33static HRESULT WriteExistingSniSslCert(
34 __in WCA_TODO action,
35 __in_z LPCWSTR wzId,
36 __in_z LPCWSTR wzHost,
37 __in int iPort,
38 __in int iHandleExisting,
39 __in HTTP_SERVICE_CONFIG_SSL_SNI_SET* pSniSslSet,
40 __inout_z LPWSTR* psczCustomActionData
41);
42static HRESULT WriteSniSslCert(
43 __in WCA_TODO action,
44 __in_z LPCWSTR wzId,
45 __in_z LPCWSTR wzHost,
46 __in int iPort,
47 __in int iHandleExisting,
48 __in_z LPCWSTR wzCertificateThumbprint,
49 __in_z LPCWSTR wzAppId,
50 __in_z_opt LPCWSTR wzCertificateStore,
51 __inout_z LPWSTR* psczCustomActionData
52);
53static HRESULT EnsureAppId(
54 __inout_z LPWSTR* psczAppId,
55 __in_opt HTTP_SERVICE_CONFIG_SSL_SNI_SET* pExistingSniSslSet
56);
57static HRESULT StringFromGuid(
58 __in REFGUID rguid,
59 __inout_z LPWSTR* psczGuid
60);
61static HRESULT AddSniSslCert(
62 __in_z LPCWSTR wzId,
63 __in_z LPWSTR wzHost,
64 __in int iPort,
65 __in BYTE rgbCertificateThumbprint[],
66 __in DWORD cbCertificateThumbprint,
67 __in GUID* pAppId,
68 __in_z LPWSTR wzSslCertStore
69);
70static HRESULT GetSniSslCert(
71 __in_z LPWSTR wzHost,
72 __in int nPort,
73 __out HTTP_SERVICE_CONFIG_SSL_SNI_SET** ppSet
74);
75static HRESULT RemoveSniSslCert(
76 __in_z LPCWSTR wzId,
77 __in_z LPWSTR wzHost,
78 __in int iPort
79);
80static void SetSniSslCertSetKey(
81 __in HTTP_SERVICE_CONFIG_SSL_SNI_KEY* pKey,
82 __in_z LPWSTR wzHost,
83 __in int iPort
84);
85
86
87LPCWSTR vcsWixHttpSniSslCertQuery =
88L"SELECT `Wix4HttpSniSslCert`.`Wix4HttpSniSslCert`, `Wix4HttpSniSslCert`.`Host`, `Wix4HttpSniSslCert`.`Port`, `Wix4HttpSniSslCert`.`Thumbprint`, `Wix4HttpSniSslCert`.`AppId`, `Wix4HttpSniSslCert`.`Store`, `Wix4HttpSniSslCert`.`HandleExisting`, `Wix4HttpSniSslCert`.`Component_` "
89L"FROM `Wix4HttpSniSslCert`";
90enum eWixHttpSniSslCertQuery { hurqId = 1, hurqHost, hurqPort, hurqCertificateThumbprint, hurqAppId, hurqCertificateStore, hurqHandleExisting, hurqComponent };
91
92/******************************************************************
93 SchedWixHttpSniSslCertsInstall - immediate custom action entry
94 point to prepare adding URL reservations.
95
96********************************************************************/
97extern "C" UINT __stdcall SchedHttpSniSslCertsInstall(
98 __in MSIHANDLE hInstall
99)
100{
101 HRESULT hr = S_OK;
102
103 hr = WcaInitialize(hInstall, "SchedHttpSniSslCertsInstall");
104 ExitOnFailure(hr, "Failed to initialize");
105
106 hr = SchedHttpSniSslCerts(WCA_TODO_INSTALL);
107
108LExit:
109 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
110}
111
112/******************************************************************
113 SchedWixHttpSniSslCertsUninstall - immediate custom action entry
114 point to prepare removing URL reservations.
115
116********************************************************************/
117extern "C" UINT __stdcall SchedHttpSniSslCertsUninstall(
118 __in MSIHANDLE hInstall
119)
120{
121 HRESULT hr = S_OK;
122
123 hr = WcaInitialize(hInstall, "SchedHttpSniSslCertsUninstall");
124 ExitOnFailure(hr, "Failed to initialize");
125
126 hr = SchedHttpSniSslCerts(WCA_TODO_UNINSTALL);
127
128LExit:
129 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
130}
131
132/******************************************************************
133 ExecHttpSniSslCerts - deferred custom action entry point to
134 register and remove URL reservations.
135
136********************************************************************/
137extern "C" UINT __stdcall ExecHttpSniSslCerts(
138 __in MSIHANDLE hInstall
139)
140{
141 HRESULT hr = S_OK;
142 BOOL fHttpInitialized = FALSE;
143 LPWSTR sczCustomActionData = NULL;
144 LPWSTR wz = NULL;
145 int iTodo = WCA_TODO_UNKNOWN;
146 LPWSTR sczId = NULL;
147 LPWSTR sczHost = NULL;
148 int iPort = 0;
149 eHandleExisting handleExisting = heIgnore;
150 LPWSTR sczCertificateThumbprint = NULL;
151 LPWSTR sczAppId = NULL;
152 LPWSTR sczCertificateStore = NULL;
153
154 BOOL fRollback = ::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK);
155 BOOL fRemove = FALSE;
156 BOOL fAdd = FALSE;
157 BOOL fFailOnExisting = FALSE;
158
159 GUID guidAppId = { };
160 BYTE* pbCertificateThumbprint = NULL;
161 DWORD cbCertificateThumbprint = 0;
162
163 // Initialize.
164 hr = WcaInitialize(hInstall, "ExecHttpSniSslCerts");
165 ExitOnFailure(hr, "Failed to initialize");
166
167 hr = HRESULT_FROM_WIN32(::HttpInitialize(HTTPAPI_VERSION_1, HTTP_INITIALIZE_CONFIG, NULL));
168 ExitOnFailure(hr, "Failed to initialize HTTP Server configuration");
169
170 fHttpInitialized = TRUE;
171
172 hr = WcaGetProperty(L"CustomActionData", &sczCustomActionData);
173 ExitOnFailure(hr, "Failed to get CustomActionData");
174 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", sczCustomActionData);
175
176 wz = sczCustomActionData;
177 while (wz && *wz)
178 {
179 // Extract the custom action data and if rolling back, swap INSTALL and UNINSTALL.
180 hr = WcaReadIntegerFromCaData(&wz, &iTodo);
181 ExitOnFailure(hr, "Failed to read todo from custom action data");
182
183 hr = WcaReadStringFromCaData(&wz, &sczId);
184 ExitOnFailure(hr, "Failed to read Id from custom action data");
185
186 hr = WcaReadStringFromCaData(&wz, &sczHost);
187 ExitOnFailure(hr, "Failed to read Host from custom action data");
188
189 hr = WcaReadIntegerFromCaData(&wz, &iPort);
190 ExitOnFailure(hr, "Failed to read Port from custom action data");
191
192 hr = WcaReadIntegerFromCaData(&wz, reinterpret_cast<int*>(&handleExisting));
193 ExitOnFailure(hr, "Failed to read HandleExisting from custom action data");
194
195 hr = WcaReadStringFromCaData(&wz, &sczCertificateThumbprint);
196 ExitOnFailure(hr, "Failed to read CertificateThumbprint from custom action data");
197
198 hr = WcaReadStringFromCaData(&wz, &sczAppId);
199 ExitOnFailure(hr, "Failed to read AppId from custom action data");
200
201 hr = WcaReadStringFromCaData(&wz, &sczCertificateStore);
202 ExitOnFailure(hr, "Failed to read CertificateStore from custom action data");
203
204 switch (iTodo)
205 {
206 case WCA_TODO_INSTALL:
207 case WCA_TODO_REINSTALL:
208 fRemove = heReplace == handleExisting || fRollback;
209 fAdd = !fRollback || *sczCertificateThumbprint;
210 fFailOnExisting = heFail == handleExisting && !fRollback;
211 break;
212
213 case WCA_TODO_UNINSTALL:
214 fRemove = !fRollback;
215 fAdd = fRollback && *sczCertificateThumbprint;
216 fFailOnExisting = FALSE;
217 break;
218 }
219
220 if (fRemove)
221 {
222 hr = RemoveSniSslCert(sczId, sczHost, iPort);
223 if (S_OK == hr)
224 {
225 WcaLog(LOGMSG_STANDARD, "Removed SNI SSL certificate '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
226 }
227 else if (FAILED(hr))
228 {
229 if (fRollback)
230 {
231 WcaLogError(hr, "Failed to remove SNI SSL certificate to rollback '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
232 }
233 else
234 {
235 ExitOnFailure(hr, "Failed to remove SNI SSL certificate '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
236 }
237 }
238 }
239
240 if (fAdd)
241 {
242 WcaLog(LOGMSG_STANDARD, "Adding SNI SSL certificate '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
243
244 hr = StrAllocHexDecode(sczCertificateThumbprint, &pbCertificateThumbprint, &cbCertificateThumbprint);
245 ExitOnFailure(hr, "Failed to convert thumbprint to bytes for SNI SSL certificate '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
246
247 hr = ::IIDFromString(sczAppId, &guidAppId);
248 ExitOnFailure(hr, "Failed to convert AppId '%ls' back to GUID for SNI SSL certificate '%ls' for hostname: %ls:%d", sczAppId, sczId, sczHost, iPort);
249
250 hr = AddSniSslCert(sczId, sczHost, iPort, pbCertificateThumbprint, cbCertificateThumbprint, &guidAppId, sczCertificateStore && *sczCertificateStore ? sczCertificateStore : L"MY");
251 if (S_FALSE == hr && fFailOnExisting)
252 {
253 hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
254 }
255
256 if (S_OK == hr)
257 {
258 WcaLog(LOGMSG_STANDARD, "Added SNI SSL certificate '%ls' for hostname: %ls:%d with thumbprint: %ls", sczId, sczHost, iPort, sczCertificateThumbprint);
259 }
260 else if (FAILED(hr))
261 {
262 if (fRollback)
263 {
264 WcaLogError(hr, "Failed to add SNI SSL certificate to rollback '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
265 }
266 else
267 {
268 ExitOnFailure(hr, "Failed to add SNI SSL certificate '%ls' for hostname: %ls:%d", sczId, sczHost, iPort);
269 }
270 }
271
272 ReleaseNullMem(pbCertificateThumbprint);
273 }
274 }
275
276LExit:
277 ReleaseMem(pbCertificateThumbprint);
278 ReleaseStr(sczCertificateStore);
279 ReleaseStr(sczAppId);
280 ReleaseStr(sczCertificateThumbprint);
281 ReleaseStr(sczHost);
282 ReleaseStr(sczId);
283 ReleaseStr(sczCustomActionData);
284
285 if (fHttpInitialized)
286 {
287 ::HttpTerminate(HTTP_INITIALIZE_CONFIG, NULL);
288 }
289
290 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
291}
292
293static UINT SchedHttpSniSslCerts(
294 __in WCA_TODO todoSched
295)
296{
297 HRESULT hr = S_OK;
298 UINT er = ERROR_SUCCESS;
299 BOOL fHttpInitialized = FALSE;
300 DWORD cCertificates = 0;
301
302 PMSIHANDLE hView = NULL;
303 PMSIHANDLE hRec = NULL;
304 PMSIHANDLE hQueryReq = NULL;
305 PMSIHANDLE hAceView = NULL;
306
307 LPWSTR sczCustomActionData = NULL;
308 LPWSTR sczRollbackCustomActionData = NULL;
309
310 LPWSTR sczId = NULL;
311 LPWSTR sczComponent = NULL;
312 WCA_TODO todoComponent = WCA_TODO_UNKNOWN;
313 LPWSTR sczHost = NULL;
314 int iPort = 0;
315 LPWSTR sczCertificateThumbprint = NULL;
316 LPWSTR sczAppId = NULL;
317 LPWSTR sczCertificateStore = NULL;
318 int iHandleExisting = 0;
319
320 HTTP_SERVICE_CONFIG_SSL_SNI_SET* pExistingSniSslSet = NULL;
321
322 // Anything to do?
323 hr = WcaTableExists(L"Wix4HttpSniSslCert");
324 ExitOnFailure(hr, "Failed to check if the Wix4HttpSniSslCert table exists");
325 if (S_FALSE == hr)
326 {
327 WcaLog(LOGMSG_STANDARD, "Wix4HttpSniSslCert table doesn't exist, so there are no URL reservations to configure");
328 ExitFunction();
329 }
330
331 // Query and loop through all the SNI SSL certificates.
332 hr = WcaOpenExecuteView(vcsWixHttpSniSslCertQuery, &hView);
333 ExitOnFailure(hr, "Failed to open view on the Wix4HttpSniSslCert table");
334
335 hr = HRESULT_FROM_WIN32(::HttpInitialize(HTTPAPI_VERSION_1, HTTP_INITIALIZE_CONFIG, NULL));
336 ExitOnFailure(hr, "Failed to initialize HTTP Server configuration");
337
338 fHttpInitialized = TRUE;
339
340 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
341 {
342 hr = WcaGetRecordString(hRec, hurqId, &sczId);
343 ExitOnFailure(hr, "Failed to get Wix4HttpSniSslCert.Wix4HttpSniSslCert");
344
345 hr = WcaGetRecordString(hRec, hurqComponent, &sczComponent);
346 ExitOnFailure(hr, "Failed to get Wix4HttpSniSslCert.Component_");
347
348 // Figure out what we're doing for this reservation, treating reinstall the same as install.
349 todoComponent = WcaGetComponentToDo(sczComponent);
350 if ((WCA_TODO_REINSTALL == todoComponent ? WCA_TODO_INSTALL : todoComponent) != todoSched)
351 {
352 WcaLog(LOGMSG_STANDARD, "Component '%ls' action state (%d) doesn't match request (%d) for Wix4HttpSniSslCert '%ls'", sczComponent, todoComponent, todoSched, sczId);
353 continue;
354 }
355
356 hr = WcaGetRecordFormattedString(hRec, hurqHost, &sczHost);
357 ExitOnFailure(hr, "Failed to get Wix4HttpSniSslCert.Host");
358
359 hr = WcaGetRecordFormattedInteger(hRec, hurqPort, &iPort);
360 ExitOnFailure(hr, "Failed to get Wix4HttpSniSslCert.Port");
361
362 hr = WcaGetRecordFormattedString(hRec, hurqCertificateThumbprint, &sczCertificateThumbprint);
363 ExitOnFailure(hr, "Failed to get Wix4HttpSniSslCert.CertificateThumbprint");
364
365 if (!sczHost || !*sczHost)
366 {
367 hr = E_INVALIDARG;
368 ExitOnFailure(hr, "Require a Host value for Wix4HttpSniSslCert '%ls'", sczId);
369 }
370
371 if (!iPort)
372 {
373 hr = E_INVALIDARG;
374 ExitOnFailure(hr, "Require a Port value for Wix4HttpSniSslCert '%ls'", sczId);
375 }
376
377 if (!sczCertificateThumbprint || !*sczCertificateThumbprint)
378 {
379 hr = E_INVALIDARG;
380 ExitOnFailure(hr, "Require a CertificateThumbprint value for Wix4HttpSniSslCert '%ls'", sczId);
381 }
382
383 hr = WcaGetRecordFormattedString(hRec, hurqAppId, &sczAppId);
384 ExitOnFailure(hr, "Failed to get AppId for Wix4HttpSniSslCert '%ls'", sczId);
385
386 hr = WcaGetRecordFormattedString(hRec, hurqCertificateStore, &sczCertificateStore);
387 ExitOnFailure(hr, "Failed to get CertificateStore for Wix4HttpSniSslCert '%ls'", sczId);
388
389 hr = WcaGetRecordInteger(hRec, hurqHandleExisting, &iHandleExisting);
390 ExitOnFailure(hr, "Failed to get HandleExisting for Wix4HttpSniSslCert '%ls'", sczId);
391
392 hr = GetSniSslCert(sczHost, iPort, &pExistingSniSslSet);
393 ExitOnFailure(hr, "Failed to get the existing SNI SSL certificate for Wix4HttpSniSslCert '%ls'", sczId);
394
395 hr = EnsureAppId(&sczAppId, pExistingSniSslSet);
396 ExitOnFailure(hr, "Failed to ensure AppId for Wix4HttpSniSslCert '%ls'", sczId);
397
398 hr = WriteExistingSniSslCert(todoComponent, sczId, sczHost, iPort, iHandleExisting, pExistingSniSslSet, &sczRollbackCustomActionData);
399 ExitOnFailure(hr, "Failed to write rollback custom action data for Wix4HttpSniSslCert '%ls'", sczId);
400
401 hr = WriteSniSslCert(todoComponent, sczId, sczHost, iPort, iHandleExisting, sczCertificateThumbprint, sczAppId, sczCertificateStore, &sczCustomActionData);
402 ExitOnFailure(hr, "Failed to write custom action data for Wix4HttpSniSslCert '%ls'", sczId);
403 ++cCertificates;
404
405 ReleaseNullMem(pExistingSniSslSet);
406 }
407
408 // Reaching the end of the list is not an error.
409 if (E_NOMOREITEMS == hr)
410 {
411 hr = S_OK;
412 }
413 ExitOnFailure(hr, "Failure occurred while processing Wix4HttpSniSslCert table");
414
415 // Schedule ExecHttpSniSslCerts if there's anything to do.
416 if (cCertificates)
417 {
418 WcaLog(LOGMSG_STANDARD, "Scheduling SNI SSL certificate (%ls)", sczCustomActionData);
419 WcaLog(LOGMSG_STANDARD, "Scheduling rollback SNI SSL certificate (%ls)", sczRollbackCustomActionData);
420
421 if (WCA_TODO_INSTALL == todoSched)
422 {
423 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixRollbackHttpSniSslCertsInstall"), sczRollbackCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
424 ExitOnFailure(hr, "Failed to schedule install SNI SSL certificate rollback");
425 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixExecHttpSniSslCertsInstall"), sczCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
426 ExitOnFailure(hr, "Failed to schedule install SNI SSL certificate execution");
427 }
428 else
429 {
430 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixRollbackHttpSniSslCertsUninstall"), sczRollbackCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
431 ExitOnFailure(hr, "Failed to schedule uninstall SNI SSL certificate rollback");
432 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixExecHttpSniSslCertsUninstall"), sczCustomActionData, cCertificates * COST_HTTP_SNI_SSL);
433 ExitOnFailure(hr, "Failed to schedule uninstall SNI SSL certificate execution");
434 }
435 }
436 else
437 {
438 WcaLog(LOGMSG_STANDARD, "No SNI SSL certificates scheduled");
439 }
440
441LExit:
442 ReleaseMem(pExistingSniSslSet);
443 ReleaseStr(sczCertificateStore);
444 ReleaseStr(sczAppId);
445 ReleaseStr(sczCertificateThumbprint);
446 ReleaseStr(sczHost);
447 ReleaseStr(sczComponent);
448 ReleaseStr(sczId);
449 ReleaseStr(sczRollbackCustomActionData);
450 ReleaseStr(sczCustomActionData);
451
452 if (fHttpInitialized)
453 {
454 ::HttpTerminate(HTTP_INITIALIZE_CONFIG, NULL);
455 }
456
457 return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
458}
459
460static HRESULT WriteExistingSniSslCert(
461 __in WCA_TODO action,
462 __in_z LPCWSTR wzId,
463 __in_z LPCWSTR wzHost,
464 __in int iPort,
465 __in int iHandleExisting,
466 __in HTTP_SERVICE_CONFIG_SSL_SNI_SET* pSniSslSet,
467 __inout_z LPWSTR* psczCustomActionData
468)
469{
470 HRESULT hr = S_OK;
471 LPWSTR sczCertificateThumbprint = NULL;
472 LPWSTR sczAppId = NULL;
473 LPCWSTR wzCertificateStore = NULL;
474
475 if (pSniSslSet)
476 {
477 hr = StrAllocHexEncode(reinterpret_cast<BYTE*>(pSniSslSet->ParamDesc.pSslHash), pSniSslSet->ParamDesc.SslHashLength, &sczCertificateThumbprint);
478 ExitOnFailure(hr, "Failed to convert existing certificate thumbprint to hex for Wix4HttpSniSslCert '%ls'", wzId);
479
480 hr = StringFromGuid(pSniSslSet->ParamDesc.AppId, &sczAppId);
481 ExitOnFailure(hr, "Failed to copy existing AppId for Wix4HttpSniSslCert '%ls'", wzId);
482
483 wzCertificateStore = pSniSslSet->ParamDesc.pSslCertStoreName;
484 }
485
486 hr = WriteSniSslCert(action, wzId, wzHost, iPort, iHandleExisting, sczCertificateThumbprint ? sczCertificateThumbprint : L"", sczAppId ? sczAppId : L"", wzCertificateStore ? wzCertificateStore : L"", psczCustomActionData);
487 ExitOnFailure(hr, "Failed to write custom action data for Wix4HttpSniSslCert '%ls'", wzId);
488
489LExit:
490 ReleaseStr(sczAppId);
491 ReleaseStr(sczCertificateThumbprint);
492
493 return hr;
494}
495
496static HRESULT WriteSniSslCert(
497 __in WCA_TODO action,
498 __in_z LPCWSTR wzId,
499 __in_z LPCWSTR wzHost,
500 __in int iPort,
501 __in int iHandleExisting,
502 __in_z LPCWSTR wzCertificateThumbprint,
503 __in_z LPCWSTR wzAppId,
504 __in_z_opt LPCWSTR wzCertificateStore,
505 __inout_z LPWSTR* psczCustomActionData
506)
507{
508 HRESULT hr = S_OK;
509
510 hr = WcaWriteIntegerToCaData(action, psczCustomActionData);
511 ExitOnFailure(hr, "Failed to write action to custom action data");
512
513 hr = WcaWriteStringToCaData(wzId, psczCustomActionData);
514 ExitOnFailure(hr, "Failed to write id to custom action data");
515
516 hr = WcaWriteStringToCaData(wzHost, psczCustomActionData);
517 ExitOnFailure(hr, "Failed to write Host to custom action data");
518
519 hr = WcaWriteIntegerToCaData(iPort, psczCustomActionData);
520 ExitOnFailure(hr, "Failed to write Port to custom action data");
521
522 hr = WcaWriteIntegerToCaData(iHandleExisting, psczCustomActionData);
523 ExitOnFailure(hr, "Failed to write HandleExisting to custom action data");
524
525 hr = WcaWriteStringToCaData(wzCertificateThumbprint, psczCustomActionData);
526 ExitOnFailure(hr, "Failed to write CertificateThumbprint to custom action data");
527
528 hr = WcaWriteStringToCaData(wzAppId, psczCustomActionData);
529 ExitOnFailure(hr, "Failed to write AppId to custom action data");
530
531 hr = WcaWriteStringToCaData(wzCertificateStore ? wzCertificateStore : L"", psczCustomActionData);
532 ExitOnFailure(hr, "Failed to write CertificateStore to custom action data");
533
534LExit:
535 return hr;
536}
537
538static HRESULT EnsureAppId(
539 __inout_z LPWSTR* psczAppId,
540 __in_opt HTTP_SERVICE_CONFIG_SSL_SNI_SET* pExistingSniSslSet
541)
542{
543 HRESULT hr = S_OK;
544 RPC_STATUS rs = RPC_S_OK;
545 GUID guid = { };
546
547 if (!psczAppId || !*psczAppId || !**psczAppId)
548 {
549 if (pExistingSniSslSet)
550 {
551 hr = StringFromGuid(pExistingSniSslSet->ParamDesc.AppId, psczAppId);
552 ExitOnFailure(hr, "Failed to ensure AppId guid");
553 }
554 else
555 {
556 rs = ::UuidCreate(&guid);
557 hr = HRESULT_FROM_RPC(rs);
558 ExitOnRootFailure(hr, "Failed to create guid for AppId");
559
560 hr = StringFromGuid(guid, psczAppId);
561 ExitOnFailure(hr, "Failed to ensure AppId guid");
562 }
563 }
564
565LExit:
566 return hr;
567}
568
569static HRESULT StringFromGuid(
570 __in REFGUID rguid,
571 __inout_z LPWSTR* psczGuid
572)
573{
574 HRESULT hr = S_OK;
575 WCHAR wzGuid[39];
576
577 if (!::StringFromGUID2(rguid, wzGuid, countof(wzGuid)))
578 {
579 hr = E_OUTOFMEMORY;
580 ExitOnRootFailure(hr, "Failed to convert guid into string");
581 }
582
583 hr = StrAllocString(psczGuid, wzGuid, 0);
584 ExitOnFailure(hr, "Failed to copy guid");
585
586LExit:
587 return hr;
588}
589
590static HRESULT AddSniSslCert(
591 __in_z LPCWSTR /*wzId*/,
592 __in_z LPWSTR wzHost,
593 __in int iPort,
594 __in BYTE rgbCertificateThumbprint[],
595 __in DWORD cbCertificateThumbprint,
596 __in GUID* pAppId,
597 __in_z LPWSTR wzSslCertStore
598)
599{
600 HRESULT hr = S_OK;
601 DWORD er = ERROR_SUCCESS;
602 HTTP_SERVICE_CONFIG_SSL_SNI_SET set = { };
603
604 SetSniSslCertSetKey(&set.KeyDesc, wzHost, iPort);
605 set.ParamDesc.SslHashLength = cbCertificateThumbprint;
606 set.ParamDesc.pSslHash = rgbCertificateThumbprint;
607 set.ParamDesc.AppId = *pAppId;
608 set.ParamDesc.pSslCertStoreName = wzSslCertStore;
609
610 er = ::HttpSetServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &set, sizeof(set), NULL);
611 if (ERROR_ALREADY_EXISTS == er)
612 {
613 hr = S_FALSE;
614 }
615 else
616 {
617 hr = HRESULT_FROM_WIN32(er);
618 }
619
620 return hr;
621}
622
623static HRESULT GetSniSslCert(
624 __in_z LPWSTR wzHost,
625 __in int nPort,
626 __out HTTP_SERVICE_CONFIG_SSL_SNI_SET** ppSet
627)
628{
629 HRESULT hr = S_OK;
630 DWORD er = ERROR_SUCCESS;
631 HTTP_SERVICE_CONFIG_SSL_SNI_QUERY query = { };
632 HTTP_SERVICE_CONFIG_SSL_SNI_SET* pSet = NULL;
633 ULONG cbSet = 0;
634
635 *ppSet = NULL;
636
637 query.QueryDesc = HttpServiceConfigQueryExact;
638 SetSniSslCertSetKey(&query.KeyDesc, wzHost, nPort);
639
640 er = ::HttpQueryServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &query, sizeof(query), pSet, cbSet, &cbSet, NULL);
641 if (ERROR_INSUFFICIENT_BUFFER == er)
642 {
643 pSet = reinterpret_cast<HTTP_SERVICE_CONFIG_SSL_SNI_SET*>(MemAlloc(cbSet, TRUE));
644 ExitOnNull(pSet, hr, E_OUTOFMEMORY, "Failed to allocate query SN SSL certificate buffer");
645
646 er = ::HttpQueryServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &query, sizeof(query), pSet, cbSet, &cbSet, NULL);
647 }
648
649 if (ERROR_SUCCESS == er)
650 {
651 *ppSet = pSet;
652 pSet = NULL;
653 }
654 else if (ERROR_FILE_NOT_FOUND == er)
655 {
656 hr = S_FALSE;
657 }
658 else
659 {
660 hr = HRESULT_FROM_WIN32(er);
661 }
662
663LExit:
664 ReleaseMem(pSet);
665
666 return hr;
667}
668
669static HRESULT RemoveSniSslCert(
670 __in_z LPCWSTR /*wzId*/,
671 __in_z LPWSTR wzHost,
672 __in int iPort
673)
674{
675 HRESULT hr = S_OK;
676 DWORD er = ERROR_SUCCESS;
677 HTTP_SERVICE_CONFIG_SSL_SNI_SET set = { };
678
679 SetSniSslCertSetKey(&set.KeyDesc, wzHost, iPort);
680
681 er = ::HttpDeleteServiceConfiguration(NULL, HttpServiceConfigSslSniCertInfo, &set, sizeof(set), NULL);
682 if (ERROR_FILE_NOT_FOUND == er)
683 {
684 hr = S_FALSE;
685 }
686 else
687 {
688 hr = HRESULT_FROM_WIN32(er);
689 }
690
691 return hr;
692}
693
694static void SetSniSslCertSetKey(
695 __in HTTP_SERVICE_CONFIG_SSL_SNI_KEY* pKey,
696 __in_z LPWSTR wzHost,
697 __in int iPort
698)
699{
700 pKey->Host = wzHost;
701 SOCKADDR_IN* pss = reinterpret_cast<SOCKADDR_IN*>(&pKey->IpPort);
702 pss->sin_family = AF_INET;
703 pss->sin_port = htons(static_cast<USHORT>(iPort));
704}
diff --git a/src/ext/Http/ca/wixhttpca.cpp b/src/ext/Http/ca/wixhttpca.cpp
new file mode 100644
index 00000000..8c846ffc
--- /dev/null
+++ b/src/ext/Http/ca/wixhttpca.cpp
@@ -0,0 +1,530 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5static HRESULT AppendUrlAce(
6 __in LPWSTR wzSecurityPrincipal,
7 __in int iRights,
8 __in LPWSTR* psczSDDL
9 );
10static HRESULT WriteHttpUrlReservation(
11 __in WCA_TODO action,
12 __in LPWSTR wzUrl,
13 __in LPWSTR wzSDDL,
14 __in int iHandleExisting,
15 __in LPWSTR* psczCustomActionData
16 );
17static HRESULT AddUrlReservation(
18 __in LPWSTR wzUrl,
19 __in LPWSTR wzSddl
20 );
21static HRESULT GetUrlReservation(
22 __in LPWSTR wzUrl,
23 __deref_out_z LPWSTR* psczSddl
24 );
25static HRESULT RemoveUrlReservation(
26 __in LPWSTR wzUrl
27 );
28
29HTTPAPI_VERSION vcHttpVersion = HTTPAPI_VERSION_1;
30ULONG vcHttpFlags = HTTP_INITIALIZE_CONFIG;
31
32LPCWSTR vcsHttpUrlReservationQuery =
33 L"SELECT `Wix4HttpUrlReservation`.`Wix4HttpUrlReservation`, `Wix4HttpUrlReservation`.`HandleExisting`, `Wix4HttpUrlReservation`.`Sddl`, `Wix4HttpUrlReservation`.`Url`, `Wix4HttpUrlReservation`.`Component_` "
34 L"FROM `Wix4HttpUrlReservation`";
35enum eHttpUrlReservationQuery { hurqId = 1, hurqHandleExisting, hurqSDDL, hurqUrl, hurqComponent };
36
37LPCWSTR vcsHttpUrlAceQuery =
38 L"SELECT `Wix4HttpUrlAce`.`SecurityPrincipal`, `Wix4HttpUrlAce`.`Rights` "
39 L"FROM `Wix4HttpUrlAce` "
40 L"WHERE `Wix4HttpUrlAce`.`Wix4HttpUrlReservation_`=?";
41enum eHttpUrlAceQuery { huaqSecurityPrincipal = 1, huaqRights };
42
43/******************************************************************
44 SchedHttpUrlReservations - immediate custom action worker to
45 prepare configuring URL reservations.
46
47********************************************************************/
48static UINT SchedHttpUrlReservations(
49 __in MSIHANDLE hInstall,
50 __in WCA_TODO todoSched
51 )
52{
53 HRESULT hr = S_OK;
54 UINT er = ERROR_SUCCESS;
55 BOOL fAceTableExists = FALSE;
56 BOOL fHttpInitialized = FALSE;
57 DWORD cUrlReservations = 0;
58
59 PMSIHANDLE hView = NULL;
60 PMSIHANDLE hRec = NULL;
61 PMSIHANDLE hQueryReq = NULL;
62 PMSIHANDLE hAceView = NULL;
63
64 LPWSTR sczCustomActionData = NULL;
65 LPWSTR sczRollbackCustomActionData = NULL;
66
67 LPWSTR sczId = NULL;
68 LPWSTR sczComponent = NULL;
69 WCA_TODO todoComponent = WCA_TODO_UNKNOWN;
70 LPWSTR sczUrl = NULL;
71 LPWSTR sczSecurityPrincipal = NULL;
72 int iRights = 0;
73 int iHandleExisting = 0;
74
75 LPWSTR sczExistingSDDL = NULL;
76 LPWSTR sczSDDL = NULL;
77
78 // Initialize.
79 hr = WcaInitialize(hInstall, "SchedHttpUrlReservations");
80 ExitOnFailure(hr, "Failed to initialize.");
81
82 // Anything to do?
83 hr = WcaTableExists(L"Wix4HttpUrlReservation");
84 ExitOnFailure(hr, "Failed to check if the Wix4HttpUrlReservation table exists.");
85 if (S_FALSE == hr)
86 {
87 WcaLog(LOGMSG_STANDARD, "Wix4HttpUrlReservation table doesn't exist, so there are no URL reservations to configure.");
88 ExitFunction();
89 }
90
91 hr = WcaTableExists(L"Wix4HttpUrlAce");
92 ExitOnFailure(hr, "Failed to check if the Wix4HttpUrlAce table exists.");
93 fAceTableExists = S_OK == hr;
94
95 // Query and loop through all the URL reservations.
96 hr = WcaOpenExecuteView(vcsHttpUrlReservationQuery, &hView);
97 ExitOnFailure(hr, "Failed to open view on the Wix4HttpUrlReservation table.");
98
99 hr = HRESULT_FROM_WIN32(::HttpInitialize(vcHttpVersion, vcHttpFlags, NULL));
100 ExitOnFailure(hr, "Failed to initialize HTTP Server configuration.");
101
102 fHttpInitialized = TRUE;
103
104 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
105 {
106 hr = WcaGetRecordString(hRec, hurqId, &sczId);
107 ExitOnFailure(hr, "Failed to get Wix4HttpUrlReservation.Wix4HttpUrlReservation");
108
109 hr = WcaGetRecordString(hRec, hurqComponent, &sczComponent);
110 ExitOnFailure(hr, "Failed to get Wix4HttpUrlReservation.Component_");
111
112 // Figure out what we're doing for this reservation, treating reinstall the same as install.
113 todoComponent = WcaGetComponentToDo(sczComponent);
114 if ((WCA_TODO_REINSTALL == todoComponent ? WCA_TODO_INSTALL : todoComponent) != todoSched)
115 {
116 WcaLog(LOGMSG_STANDARD, "Component '%ls' action state (%d) doesn't match request (%d) for UrlReservation '%ls'.", sczComponent, todoComponent, todoSched, sczId);
117 continue;
118 }
119
120 hr = WcaGetRecordFormattedString(hRec, hurqUrl, &sczUrl);
121 ExitOnFailure(hr, "Failed to get Wix4HttpUrlReservation.Url");
122
123 hr = WcaGetRecordInteger(hRec, hurqHandleExisting, &iHandleExisting);
124 ExitOnFailure(hr, "Failed to get Wix4HttpUrlReservation.HandleExisting");
125
126 if (::MsiRecordIsNull(hRec, hurqSDDL))
127 {
128 hr = StrAllocString(&sczSDDL, L"D:", 2);
129 ExitOnFailure(hr, "Failed to allocate SDDL string.");
130
131 // Skip creating the SDDL on uninstall, since it's never used and the lookup(s) could fail.
132 if (fAceTableExists && WCA_TODO_UNINSTALL != todoComponent)
133 {
134 hQueryReq = ::MsiCreateRecord(1);
135 hr = WcaSetRecordString(hQueryReq, 1, sczId);
136 ExitOnFailure(hr, "Failed to create record for querying Wix4HttpUrlAce table for reservation %ls", sczId);
137
138 hr = WcaOpenView(vcsHttpUrlAceQuery, &hAceView);
139 ExitOnFailure(hr, "Failed to open view on Wix4HttpUrlAce table for reservation %ls", sczId);
140 hr = WcaExecuteView(hAceView, hQueryReq);
141 ExitOnFailure(hr, "Failed to execute view on Wix4HttpUrlAce table for reservation %ls", sczId);
142
143 while (S_OK == (hr = WcaFetchRecord(hAceView, &hRec)))
144 {
145 hr = WcaGetRecordFormattedString(hRec, huaqSecurityPrincipal, &sczSecurityPrincipal);
146 ExitOnFailure(hr, "Failed to get Wix4HttpUrlAce.SecurityPrincipal");
147
148 hr = WcaGetRecordInteger(hRec, huaqRights, &iRights);
149 ExitOnFailure(hr, "Failed to get Wix4HttpUrlAce.Rights");
150
151 hr = AppendUrlAce(sczSecurityPrincipal, iRights, &sczSDDL);
152 ExitOnFailure(hr, "Failed to append URL ACE.");
153 }
154
155 if (E_NOMOREITEMS == hr)
156 {
157 hr = S_OK;
158 }
159 ExitOnFailure(hr, "Failed to enumerate selected rows from Wix4HttpUrlAce table.");
160 }
161 }
162 else
163 {
164 hr = WcaGetRecordFormattedString(hRec, hurqSDDL, &sczSDDL);
165 ExitOnFailure(hr, "Failed to get Wix4HttpUrlReservation.SDDL");
166 }
167
168 hr = GetUrlReservation(sczUrl, &sczExistingSDDL);
169 ExitOnFailure(hr, "Failed to get the existing SDDL for %ls", sczUrl);
170
171 hr = WriteHttpUrlReservation(todoComponent, sczUrl, sczExistingSDDL ? sczExistingSDDL : L"", iHandleExisting, &sczRollbackCustomActionData);
172 ExitOnFailure(hr, "Failed to write URL Reservation to rollback custom action data.");
173
174 hr = WriteHttpUrlReservation(todoComponent, sczUrl, sczSDDL, iHandleExisting, &sczCustomActionData);
175 ExitOnFailure(hr, "Failed to write URL reservation to custom action data.");
176 ++cUrlReservations;
177 }
178
179 // Reaching the end of the list is not an error.
180 if (E_NOMOREITEMS == hr)
181 {
182 hr = S_OK;
183 }
184 ExitOnFailure(hr, "Failure occurred while processing Wix4HttpUrlReservation table.");
185
186 // Schedule ExecHttpUrlReservations if there's anything to do.
187 if (cUrlReservations)
188 {
189 WcaLog(LOGMSG_STANDARD, "Scheduling URL reservations (%ls)", sczCustomActionData);
190 WcaLog(LOGMSG_STANDARD, "Scheduling rollback URL reservations (%ls)", sczRollbackCustomActionData);
191
192 if (WCA_TODO_INSTALL == todoSched)
193 {
194 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixRollbackHttpUrlReservationsInstall"), sczRollbackCustomActionData, cUrlReservations * COST_HTTP_URL_ACL);
195 ExitOnFailure(hr, "Failed to schedule install URL reservations rollback.");
196 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixExecHttpUrlReservationsInstall"), sczCustomActionData, cUrlReservations * COST_HTTP_URL_ACL);
197 ExitOnFailure(hr, "Failed to schedule install URL reservations execution.");
198 }
199 else
200 {
201 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixRollbackHttpUrlReservationsUninstall"), sczRollbackCustomActionData, cUrlReservations * COST_HTTP_URL_ACL);
202 ExitOnFailure(hr, "Failed to schedule uninstall URL reservations rollback.");
203 hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"WixExecHttpUrlReservationsUninstall"), sczCustomActionData, cUrlReservations * COST_HTTP_URL_ACL);
204 ExitOnFailure(hr, "Failed to schedule uninstall URL reservations execution.");
205 }
206 }
207 else
208 {
209 WcaLog(LOGMSG_STANDARD, "No URL reservations scheduled.");
210 }
211
212LExit:
213 ReleaseStr(sczSDDL);
214 ReleaseStr(sczExistingSDDL);
215 ReleaseStr(sczSecurityPrincipal);
216 ReleaseStr(sczUrl)
217 ReleaseStr(sczComponent);
218 ReleaseStr(sczId);
219 ReleaseStr(sczRollbackCustomActionData);
220 ReleaseStr(sczCustomActionData);
221
222 if (fHttpInitialized)
223 {
224 ::HttpTerminate(vcHttpFlags, NULL);
225 }
226
227 return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
228}
229
230static HRESULT AppendUrlAce(
231 __in LPWSTR wzSecurityPrincipal,
232 __in int iRights,
233 __in LPWSTR* psczSDDL
234 )
235{
236 HRESULT hr = S_OK;
237 LPCWSTR wzSid = NULL;
238 LPWSTR sczSid = NULL;
239
240 Assert(wzSecurityPrincipal && *wzSecurityPrincipal);
241 Assert(psczSDDL && *psczSDDL);
242
243 // As documented in the xsd, if the first char is '*', then the rest of the string is a SID string, e.g. *S-1-5-18.
244 if (L'*' == wzSecurityPrincipal[0])
245 {
246 wzSid = &wzSecurityPrincipal[1];
247 }
248 else
249 {
250 hr = AclGetAccountSidStringEx(NULL, wzSecurityPrincipal, &sczSid);
251 ExitOnFailure(hr, "Failed to lookup the SID for account %ls", wzSecurityPrincipal);
252
253 wzSid = sczSid;
254 }
255
256 hr = StrAllocFormatted(psczSDDL, L"%ls(A;;%#x;;;%ls)", *psczSDDL, iRights, wzSid);
257
258LExit:
259 ReleaseStr(sczSid);
260
261 return hr;
262}
263
264static HRESULT WriteHttpUrlReservation(
265 __in WCA_TODO action,
266 __in LPWSTR wzUrl,
267 __in LPWSTR wzSDDL,
268 __in int iHandleExisting,
269 __in LPWSTR* psczCustomActionData
270 )
271{
272 HRESULT hr = S_OK;
273
274 hr = WcaWriteIntegerToCaData(action, psczCustomActionData);
275 ExitOnFailure(hr, "Failed to write action to custom action data.");
276
277 hr = WcaWriteStringToCaData(wzUrl, psczCustomActionData);
278 ExitOnFailure(hr, "Failed to write URL to custom action data.");
279
280 hr = WcaWriteStringToCaData(wzSDDL, psczCustomActionData);
281 ExitOnFailure(hr, "Failed to write SDDL to custom action data.");
282
283 hr = WcaWriteIntegerToCaData(iHandleExisting, psczCustomActionData);
284 ExitOnFailure(hr, "Failed to write HandleExisting to custom action data.")
285
286LExit:
287 return hr;
288}
289
290/******************************************************************
291 SchedHttpUrlReservationsInstall - immediate custom action entry
292 point to prepare adding URL reservations.
293
294********************************************************************/
295extern "C" UINT __stdcall SchedHttpUrlReservationsInstall(
296 __in MSIHANDLE hInstall
297 )
298{
299 return SchedHttpUrlReservations(hInstall, WCA_TODO_INSTALL);
300}
301
302/******************************************************************
303 SchedHttpUrlReservationsUninstall - immediate custom action entry
304 point to prepare removing URL reservations.
305
306********************************************************************/
307extern "C" UINT __stdcall SchedHttpUrlReservationsUninstall(
308 __in MSIHANDLE hInstall
309 )
310{
311 return SchedHttpUrlReservations(hInstall, WCA_TODO_UNINSTALL);
312}
313
314/******************************************************************
315 ExecHttpUrlReservations - deferred custom action entry point to
316 register and remove URL reservations.
317
318********************************************************************/
319extern "C" UINT __stdcall ExecHttpUrlReservations(
320 __in MSIHANDLE hInstall
321 )
322{
323 HRESULT hr = S_OK;
324 BOOL fHttpInitialized = FALSE;
325 LPWSTR sczCustomActionData = NULL;
326 LPWSTR wz = NULL;
327 int iTodo = WCA_TODO_UNKNOWN;
328 LPWSTR sczUrl = NULL;
329 LPWSTR sczSDDL = NULL;
330 eHandleExisting handleExisting = heIgnore;
331 BOOL fRollback = ::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK);
332 BOOL fRemove = FALSE;
333 BOOL fAdd = FALSE;
334 BOOL fFailOnExisting = FALSE;
335
336 // Initialize.
337 hr = WcaInitialize(hInstall, "ExecHttpUrlReservations");
338 ExitOnFailure(hr, "Failed to initialize.");
339
340 hr = HRESULT_FROM_WIN32(::HttpInitialize(vcHttpVersion, vcHttpFlags, NULL));
341 ExitOnFailure(hr, "Failed to initialize HTTP Server configuration.");
342
343 fHttpInitialized = TRUE;
344
345 hr = WcaGetProperty(L"CustomActionData", &sczCustomActionData);
346 ExitOnFailure(hr, "Failed to get CustomActionData.");
347 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", sczCustomActionData);
348
349 if (!sczCustomActionData || !*sczCustomActionData)
350 {
351 WcaLog(LOGMSG_STANDARD, "No URL reservations to be executed.");
352 }
353
354 wz = sczCustomActionData;
355 while (wz && *wz)
356 {
357 // Extract the custom action data and if rolling back, swap INSTALL and UNINSTALL.
358 hr = WcaReadIntegerFromCaData(&wz, &iTodo);
359 ExitOnFailure(hr, "Failed to read todo from custom action data.");
360
361 hr = WcaReadStringFromCaData(&wz, &sczUrl);
362 ExitOnFailure(hr, "Failed to read Url from custom action data.");
363
364 hr = WcaReadStringFromCaData(&wz, &sczSDDL);
365 ExitOnFailure(hr, "Failed to read SDDL from custom action data.");
366
367 hr = WcaReadIntegerFromCaData(&wz, reinterpret_cast<int*>(&handleExisting));
368 ExitOnFailure(hr, "Failed to read HandleExisting from custom action data.");
369
370 switch (iTodo)
371 {
372 case WCA_TODO_INSTALL:
373 case WCA_TODO_REINSTALL:
374 fRemove = heReplace == handleExisting || fRollback;
375 fAdd = !fRollback || *sczSDDL;
376 fFailOnExisting = heFail == handleExisting && !fRollback;
377 break;
378
379 case WCA_TODO_UNINSTALL:
380 fRemove = !fRollback;
381 fAdd = fRollback && *sczSDDL;
382 fFailOnExisting = FALSE;
383 break;
384 }
385
386 if (fRemove)
387 {
388 WcaLog(LOGMSG_STANDARD, "Removing reservation for URL '%ls'", sczUrl);
389 hr = RemoveUrlReservation(sczUrl);
390 if (FAILED(hr))
391 {
392 if (fRollback)
393 {
394 WcaLogError(hr, "Failed to remove reservation for rollback for URL '%ls'", sczUrl);
395 }
396 else
397 {
398 ExitOnFailure(hr, "Failed to remove reservation for URL '%ls'", sczUrl);
399 }
400 }
401 }
402
403 if (fAdd)
404 {
405 WcaLog(LOGMSG_STANDARD, "Adding reservation for URL '%ls' with SDDL '%ls'", sczUrl, sczSDDL);
406 hr = AddUrlReservation(sczUrl, sczSDDL);
407 if (S_FALSE == hr && fFailOnExisting)
408 {
409 hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
410 }
411 if (FAILED(hr))
412 {
413 if (fRollback)
414 {
415 WcaLogError(hr, "Failed to add reservation for rollback for URL '%ls' with SDDL '%ls'", sczUrl, sczSDDL);
416 }
417 else
418 {
419 ExitOnFailure(hr, "Failed to add reservation for URL '%ls' with SDDL '%ls'", sczUrl, sczSDDL);
420 }
421 }
422 }
423 }
424
425LExit:
426 ReleaseStr(sczSDDL);
427 ReleaseStr(sczUrl);
428 ReleaseStr(sczCustomActionData);
429
430 if (fHttpInitialized)
431 {
432 ::HttpTerminate(vcHttpFlags, NULL);
433 }
434
435 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
436}
437
438static HRESULT AddUrlReservation(
439 __in LPWSTR wzUrl,
440 __in LPWSTR wzSddl
441 )
442{
443 HRESULT hr = S_OK;
444 DWORD er = ERROR_SUCCESS;
445 HTTP_SERVICE_CONFIG_URLACL_SET set = { };
446
447 set.KeyDesc.pUrlPrefix = wzUrl;
448 set.ParamDesc.pStringSecurityDescriptor = wzSddl;
449
450 er = ::HttpSetServiceConfiguration(NULL, HttpServiceConfigUrlAclInfo, &set, sizeof(set), NULL);
451 if (ERROR_ALREADY_EXISTS == er)
452 {
453 hr = S_FALSE;
454 }
455 else
456 {
457 hr = HRESULT_FROM_WIN32(er);
458 }
459 ExitOnFailure(hr, "Failed to add URL reservation: %ls, ACL: %ls", wzUrl, wzSddl);
460
461LExit:
462 return hr;
463}
464
465static HRESULT GetUrlReservation(
466 __in LPWSTR wzUrl,
467 __deref_out_z LPWSTR* psczSddl
468 )
469{
470 HRESULT hr = S_OK;
471 DWORD er = ERROR_SUCCESS;
472 HTTP_SERVICE_CONFIG_URLACL_QUERY query = { };
473 HTTP_SERVICE_CONFIG_URLACL_SET* pSet = NULL;
474 ULONG cbSet = 0;
475
476 query.QueryDesc = HttpServiceConfigQueryExact;
477 query.KeyDesc.pUrlPrefix = wzUrl;
478
479 er = ::HttpQueryServiceConfiguration(NULL, HttpServiceConfigUrlAclInfo, &query, sizeof(query), pSet, cbSet, &cbSet, NULL);
480 if (ERROR_INSUFFICIENT_BUFFER == er)
481 {
482 pSet = reinterpret_cast<HTTP_SERVICE_CONFIG_URLACL_SET*>(MemAlloc(cbSet, TRUE));
483 ExitOnNull(pSet, hr, E_OUTOFMEMORY, "Failed to allocate query URLACL buffer.");
484
485 er = ::HttpQueryServiceConfiguration(NULL, HttpServiceConfigUrlAclInfo, &query, sizeof(query), pSet, cbSet, &cbSet, NULL);
486 }
487
488 if (ERROR_SUCCESS == er)
489 {
490 hr = StrAllocString(psczSddl, pSet->ParamDesc.pStringSecurityDescriptor, 0);
491 }
492 else if (ERROR_FILE_NOT_FOUND == er)
493 {
494 hr = S_FALSE;
495 }
496 else
497 {
498 hr = HRESULT_FROM_WIN32(er);
499 }
500
501LExit:
502 ReleaseMem(pSet);
503
504 return hr;
505}
506
507static HRESULT RemoveUrlReservation(
508 __in LPWSTR wzUrl
509 )
510{
511 HRESULT hr = S_OK;
512 DWORD er = ERROR_SUCCESS;
513 HTTP_SERVICE_CONFIG_URLACL_SET set = { };
514
515 set.KeyDesc.pUrlPrefix = wzUrl;
516
517 er = ::HttpDeleteServiceConfiguration(NULL, HttpServiceConfigUrlAclInfo, &set, sizeof(set), NULL);
518 if (ERROR_FILE_NOT_FOUND == er)
519 {
520 hr = S_FALSE;
521 }
522 else
523 {
524 hr = HRESULT_FROM_WIN32(er);
525 }
526 ExitOnFailure(hr, "Failed to remove URL reservation: %ls", wzUrl);
527
528LExit:
529 return hr;
530}
diff --git a/src/ext/Http/ca/wixhttpca.def b/src/ext/Http/ca/wixhttpca.def
new file mode 100644
index 00000000..281c5631
--- /dev/null
+++ b/src/ext/Http/ca/wixhttpca.def
@@ -0,0 +1,12 @@
1; Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3
4LIBRARY "httpca"
5
6EXPORTS
7 SchedHttpUrlReservationsInstall
8 SchedHttpUrlReservationsUninstall
9 ExecHttpUrlReservations
10 SchedHttpSniSslCertsInstall
11 SchedHttpSniSslCertsUninstall
12 ExecHttpSniSslCerts