aboutsummaryrefslogtreecommitdiff
path: root/src/ca
diff options
context:
space:
mode:
Diffstat (limited to 'src/ca')
-rw-r--r--src/ca/CustomMsiErrors.h130
-rw-r--r--src/ca/cost.h5
-rw-r--r--src/ca/dllmain.cpp26
-rw-r--r--src/ca/firewall.cpp1067
-rw-r--r--src/ca/fwca.def9
-rw-r--r--src/ca/fwca.vcxproj72
-rw-r--r--src/ca/packages.config6
-rw-r--r--src/ca/precomp.h17
8 files changed, 1332 insertions, 0 deletions
diff --git a/src/ca/CustomMsiErrors.h b/src/ca/CustomMsiErrors.h
new file mode 100644
index 00000000..f149fb31
--- /dev/null
+++ b/src/ca/CustomMsiErrors.h
@@ -0,0 +1,130 @@
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 GLOBAL_ERROR_BASE 25501
6
7#define msierrSecureObjectsFailedCreateSD 25520
8#define msierrSecureObjectsFailedSet 25521
9#define msierrSecureObjectsUnknownType 25522
10
11#define msierrXmlFileFailedRead 25530
12#define msierrXmlFileFailedOpen 25531
13#define msierrXmlFileFailedSelect 25532
14#define msierrXmlFileFailedSave 25533
15
16#define msierrXmlConfigFailedRead 25540
17#define msierrXmlConfigFailedOpen 25541
18#define msierrXmlConfigFailedSelect 25542
19#define msierrXmlConfigFailedSave 25543
20
21#define msierrFirewallCannotConnect 25580
22
23//---------------------------------------------------------------------------
24// Server CustomAction Errors
25// SERVER range: 26001-26100
26#define SERVER_ERROR_BASE 26000
27
28#define msierrIISCannotConnect 26001
29#define msierrIISFailedReadWebSite 26002
30#define msierrIISFailedReadWebDirs 26003
31#define msierrIISFailedReadVDirs 26004
32#define msierrIISFailedReadFilters 26005
33#define msierrIISFailedReadAppPool 26006
34#define msierrIISFailedReadMimeMap 26007
35#define msierrIISFailedReadProp 26008
36#define msierrIISFailedReadWebSvcExt 26009
37#define msierrIISFailedReadWebError 26010
38#define msierrIISFailedReadHttpHeader 26011
39
40#define msierrIISFailedSchedTransaction 26031
41#define msierrIISFailedSchedInstallWebs 26032
42#define msierrIISFailedSchedInstallWebDirs 26033
43#define msierrIISFailedSchedInstallVDirs 26034
44#define msierrIISFailedSchedInstallFilters 26035
45#define msierrIISFailedSchedInstallAppPool 26036
46#define msierrIISFailedSchedInstallProp 26037
47#define msierrIISFailedSchedInstallWebSvcExt 26038
48
49#define msierrIISFailedSchedUninstallWebs 26051
50#define msierrIISFailedSchedUninstallWebDirs 26052
51#define msierrIISFailedSchedUninstallVDirs 26053
52#define msierrIISFailedSchedUninstallFilters 26054
53#define msierrIISFailedSchedUninstallAppPool 26055
54#define msierrIISFailedSchedUninstallProp 26056
55#define msierrIISFailedSchedUninstallWebSvcExt 26057
56
57#define msierrIISFailedStartTransaction 26101
58#define msierrIISFailedOpenKey 26102
59#define msierrIISFailedCreateKey 26103
60#define msierrIISFailedWriteData 26104
61#define msierrIISFailedCreateApp 26105
62#define msierrIISFailedDeleteKey 26106
63#define msierrIISFailedDeleteApp 26107
64#define msierrIISFailedDeleteValue 26108
65#define msierrIISFailedCommitInUse 26109
66
67#define msierrSQLFailedCreateDatabase 26201
68#define msierrSQLFailedDropDatabase 26202
69#define msierrSQLFailedConnectDatabase 26203
70#define msierrSQLFailedExecString 26204
71#define msierrSQLDatabaseAlreadyExists 26205
72
73#define msierrPERFMONFailedRegisterDLL 26251
74#define msierrPERFMONFailedUnregisterDLL 26252
75#define msierrInstallPerfCounterData 26253
76#define msierrUninstallPerfCounterData 26254
77
78#define msierrSMBFailedCreate 26301
79#define msierrSMBFailedDrop 26302
80
81#define msierrCERTFailedOpen 26351
82#define msierrCERTFailedAdd 26352
83
84#define msierrUSRFailedUserCreate 26401
85#define msierrUSRFailedUserCreatePswd 26402
86#define msierrUSRFailedUserGroupAdd 26403
87#define msierrUSRFailedUserCreateExists 26404
88#define msierrUSRFailedGrantLogonAsService 26405
89
90#define msierrDependencyMissingDependencies 26451
91#define msierrDependencyHasDependents 26452
92
93//--------------------------------------------------------------------------
94// Managed code CustomAction Errors
95// MANAGED range: 27000-27100
96#define MANAGED_ERROR_BASE 27000
97
98#define msierrDotNetRuntimeRequired 27000
99//---------------------------------------------------------------------------
100// Public CustomAction Errors
101// PUBLIC range: 28001-28100
102#define PUBLIC_ERROR_BASE 28000
103
104#define msierrComPlusCannotConnect 28001
105#define msierrComPlusPartitionReadFailed 28002
106#define msierrComPlusPartitionRoleReadFailed 28003
107#define msierrComPlusUserInPartitionRoleReadFailed 28004
108#define msierrComPlusPartitionUserReadFailed 28005
109#define msierrComPlusApplicationReadFailed 28006
110#define msierrComPlusApplicationRoleReadFailed 28007
111#define msierrComPlusUserInApplicationRoleReadFailed 28008
112#define msierrComPlusAssembliesReadFailed 28009
113#define msierrComPlusSubscriptionReadFailed 28010
114#define msierrComPlusPartitionDependency 28011
115#define msierrComPlusPartitionNotFound 28012
116#define msierrComPlusPartitionIdConflict 28013
117#define msierrComPlusPartitionNameConflict 28014
118#define msierrComPlusApplicationDependency 28015
119#define msierrComPlusApplicationNotFound 28016
120#define msierrComPlusApplicationIdConflict 28017
121#define msierrComPlusApplicationNameConflict 28018
122#define msierrComPlusApplicationRoleDependency 28019
123#define msierrComPlusApplicationRoleNotFound 28020
124#define msierrComPlusApplicationRoleConflict 28021
125#define msierrComPlusAssemblyDependency 28022
126#define msierrComPlusSubscriptionIdConflict 28023
127#define msierrComPlusSubscriptionNameConflict 28024
128#define msierrComPlusFailedLookupNames 28025
129
130#define msierrMsmqCannotConnect 28101
diff --git a/src/ca/cost.h b/src/ca/cost.h
new file mode 100644
index 00000000..da68c667
--- /dev/null
+++ b/src/ca/cost.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
5const UINT COST_FIREWALL_EXCEPTION = 2000;
diff --git a/src/ca/dllmain.cpp b/src/ca/dllmain.cpp
new file mode 100644
index 00000000..df53f872
--- /dev/null
+++ b/src/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 hInst,
11 IN ULONG ulReason,
12 IN LPVOID)
13{
14 switch(ulReason)
15 {
16 case DLL_PROCESS_ATTACH:
17 WcaGlobalInitialize(hInst);
18 break;
19
20 case DLL_PROCESS_DETACH:
21 WcaGlobalFinalize();
22 break;
23 }
24
25 return TRUE;
26}
diff --git a/src/ca/firewall.cpp b/src/ca/firewall.cpp
new file mode 100644
index 00000000..62a5b454
--- /dev/null
+++ b/src/ca/firewall.cpp
@@ -0,0 +1,1067 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5LPCWSTR vcsFirewallExceptionQuery =
6 L"SELECT `Name`, `RemoteAddresses`, `Port`, `Protocol`, `Program`, `Attributes`, `Profile`, `Component_`, `Description` FROM `WixFirewallException`";
7enum eFirewallExceptionQuery { feqName = 1, feqRemoteAddresses, feqPort, feqProtocol, feqProgram, feqAttributes, feqProfile, feqComponent, feqDescription };
8enum eFirewallExceptionTarget { fetPort = 1, fetApplication, fetUnknown };
9enum eFirewallExceptionAttributes { feaIgnoreFailures = 1 };
10
11/******************************************************************
12 SchedFirewallExceptions - immediate custom action worker to
13 register and remove firewall exceptions.
14
15********************************************************************/
16static UINT SchedFirewallExceptions(
17 __in MSIHANDLE hInstall,
18 WCA_TODO todoSched
19 )
20{
21 HRESULT hr = S_OK;
22 UINT er = ERROR_SUCCESS;
23 int cFirewallExceptions = 0;
24
25 PMSIHANDLE hView = NULL;
26 PMSIHANDLE hRec = NULL;
27
28 LPWSTR pwzCustomActionData = NULL;
29 LPWSTR pwzName = NULL;
30 LPWSTR pwzRemoteAddresses = NULL;
31 LPWSTR pwzPort = NULL;
32 int iProtocol = 0;
33 int iAttributes = 0;
34 int iProfile = 0;
35 LPWSTR pwzProgram = NULL;
36 LPWSTR pwzComponent = NULL;
37 LPWSTR pwzFormattedFile = NULL;
38 LPWSTR pwzDescription = NULL;
39
40 // initialize
41 hr = WcaInitialize(hInstall, "SchedFirewallExceptions");
42 ExitOnFailure(hr, "failed to initialize");
43
44 // anything to do?
45 if (S_OK != WcaTableExists(L"WixFirewallException"))
46 {
47 WcaLog(LOGMSG_STANDARD, "WixFirewallException table doesn't exist, so there are no firewall exceptions to configure.");
48 ExitFunction();
49 }
50
51 // query and loop through all the firewall exceptions
52 hr = WcaOpenExecuteView(vcsFirewallExceptionQuery, &hView);
53 ExitOnFailure(hr, "failed to open view on WixFirewallException table");
54
55 while (S_OK == (hr = WcaFetchRecord(hView, &hRec)))
56 {
57 hr = WcaGetRecordFormattedString(hRec, feqName, &pwzName);
58 ExitOnFailure(hr, "failed to get firewall exception name");
59
60 hr = WcaGetRecordFormattedString(hRec, feqRemoteAddresses, &pwzRemoteAddresses);
61 ExitOnFailure(hr, "failed to get firewall exception remote addresses");
62
63 hr = WcaGetRecordFormattedString(hRec, feqPort, &pwzPort);
64 ExitOnFailure(hr, "failed to get firewall exception port");
65
66 hr = WcaGetRecordInteger(hRec, feqProtocol, &iProtocol);
67 ExitOnFailure(hr, "failed to get firewall exception protocol");
68
69 hr = WcaGetRecordFormattedString(hRec, feqProgram, &pwzProgram);
70 ExitOnFailure(hr, "failed to get firewall exception program");
71
72 hr = WcaGetRecordInteger(hRec, feqAttributes, &iAttributes);
73 ExitOnFailure(hr, "failed to get firewall exception attributes");
74
75 hr = WcaGetRecordInteger(hRec, feqProfile, &iProfile);
76 ExitOnFailure(hr, "failed to get firewall exception profile");
77
78 hr = WcaGetRecordString(hRec, feqComponent, &pwzComponent);
79 ExitOnFailure(hr, "failed to get firewall exception component");
80
81 hr = WcaGetRecordString(hRec, feqDescription, &pwzDescription);
82 ExitOnFailure(hr, "failed to get firewall description");
83
84 // figure out what we're doing for this exception, treating reinstall the same as install
85 WCA_TODO todoComponent = WcaGetComponentToDo(pwzComponent);
86 if ((WCA_TODO_REINSTALL == todoComponent ? WCA_TODO_INSTALL : todoComponent) != todoSched)
87 {
88 WcaLog(LOGMSG_STANDARD, "Component '%ls' action state (%d) doesn't match request (%d)", pwzComponent, todoComponent, todoSched);
89 continue;
90 }
91
92 // action :: name :: profile :: remoteaddresses :: attributes :: target :: {port::protocol | path}
93 ++cFirewallExceptions;
94 hr = WcaWriteIntegerToCaData(todoComponent, &pwzCustomActionData);
95 ExitOnFailure(hr, "failed to write exception action to custom action data");
96
97 hr = WcaWriteStringToCaData(pwzName, &pwzCustomActionData);
98 ExitOnFailure(hr, "failed to write exception name to custom action data");
99
100 hr = WcaWriteIntegerToCaData(iProfile, &pwzCustomActionData);
101 ExitOnFailure(hr, "failed to write exception profile to custom action data");
102
103 hr = WcaWriteStringToCaData(pwzRemoteAddresses, &pwzCustomActionData);
104 ExitOnFailure(hr, "failed to write exception remote addresses to custom action data");
105
106 hr = WcaWriteIntegerToCaData(iAttributes, &pwzCustomActionData);
107 ExitOnFailure(hr, "failed to write exception attributes to custom action data");
108
109 if (*pwzProgram)
110 {
111 // If program is defined, we have an application exception.
112 hr = WcaWriteIntegerToCaData(fetApplication, &pwzCustomActionData);
113 ExitOnFailure(hr, "failed to write exception target (application) to custom action data");
114
115 hr = WcaWriteStringToCaData(pwzProgram, &pwzCustomActionData);
116 ExitOnFailure(hr, "failed to write application path to custom action data");
117 }
118 else
119 {
120 // we have a port-only exception
121 hr = WcaWriteIntegerToCaData(fetPort, &pwzCustomActionData);
122 ExitOnFailure(hr, "failed to write exception target (port) to custom action data");
123 }
124
125 hr = WcaWriteStringToCaData(pwzPort, &pwzCustomActionData);
126 ExitOnFailure(hr, "failed to write application path to custom action data");
127
128 hr = WcaWriteIntegerToCaData(iProtocol, &pwzCustomActionData);
129 ExitOnFailure(hr, "failed to write exception protocol to custom action data");
130
131 hr = WcaWriteStringToCaData(pwzDescription, &pwzCustomActionData);
132 ExitOnFailure(hr, "failed to write firewall rule description to custom action data");
133 }
134
135 // reaching the end of the list is actually a good thing, not an error
136 if (E_NOMOREITEMS == hr)
137 {
138 hr = S_OK;
139 }
140 ExitOnFailure(hr, "failure occured while processing WixFirewallException table");
141
142 // schedule ExecFirewallExceptions if there's anything to do
143 if (pwzCustomActionData && *pwzCustomActionData)
144 {
145 WcaLog(LOGMSG_STANDARD, "Scheduling firewall exception (%ls)", pwzCustomActionData);
146
147 if (WCA_TODO_INSTALL == todoSched)
148 {
149 hr = WcaDoDeferredAction(L"WixRollbackFirewallExceptionsInstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
150 ExitOnFailure(hr, "failed to schedule firewall install exceptions rollback");
151 hr = WcaDoDeferredAction(L"WixExecFirewallExceptionsInstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
152 ExitOnFailure(hr, "failed to schedule firewall install exceptions execution");
153 }
154 else
155 {
156 hr = WcaDoDeferredAction(L"WixRollbackFirewallExceptionsUninstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
157 ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions rollback");
158 hr = WcaDoDeferredAction(L"WixExecFirewallExceptionsUninstall", pwzCustomActionData, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
159 ExitOnFailure(hr, "failed to schedule firewall uninstall exceptions execution");
160 }
161 }
162 else
163 {
164 WcaLog(LOGMSG_STANDARD, "No firewall exceptions scheduled");
165 }
166
167LExit:
168 ReleaseStr(pwzCustomActionData);
169 ReleaseStr(pwzName);
170 ReleaseStr(pwzRemoteAddresses);
171 ReleaseStr(pwzPort);
172 ReleaseStr(pwzProgram);
173 ReleaseStr(pwzComponent);
174 ReleaseStr(pwzDescription);
175 ReleaseStr(pwzFormattedFile);
176
177 return WcaFinalize(er = FAILED(hr) ? ERROR_INSTALL_FAILURE : er);
178}
179
180/******************************************************************
181 SchedFirewallExceptionsInstall - immediate custom action entry
182 point to register firewall exceptions.
183
184********************************************************************/
185extern "C" UINT __stdcall SchedFirewallExceptionsInstall(
186 __in MSIHANDLE hInstall
187 )
188{
189 return SchedFirewallExceptions(hInstall, WCA_TODO_INSTALL);
190}
191
192/******************************************************************
193 SchedFirewallExceptionsUninstall - immediate custom action entry
194 point to remove firewall exceptions.
195
196********************************************************************/
197extern "C" UINT __stdcall SchedFirewallExceptionsUninstall(
198 __in MSIHANDLE hInstall
199 )
200{
201 return SchedFirewallExceptions(hInstall, WCA_TODO_UNINSTALL);
202}
203
204/******************************************************************
205 GetFirewallRules - Get the collection of firewall rules.
206
207********************************************************************/
208static HRESULT GetFirewallRules(
209 __in BOOL fIgnoreFailures,
210 __out INetFwRules** ppNetFwRules
211 )
212{
213 HRESULT hr = S_OK;
214 INetFwPolicy2* pNetFwPolicy2 = NULL;
215 INetFwRules* pNetFwRules = NULL;
216 *ppNetFwRules = NULL;
217
218 do
219 {
220 ReleaseNullObject(pNetFwPolicy2);
221 ReleaseNullObject(pNetFwRules);
222
223 if (SUCCEEDED(hr = ::CoCreateInstance(__uuidof(NetFwPolicy2), NULL, CLSCTX_ALL, __uuidof(INetFwPolicy2), (void**)&pNetFwPolicy2)) &&
224 SUCCEEDED(hr = pNetFwPolicy2->get_Rules(&pNetFwRules)))
225 {
226 break;
227 }
228 else if (fIgnoreFailures)
229 {
230 ExitFunction1(hr = S_FALSE);
231 }
232 else
233 {
234 WcaLog(LOGMSG_STANDARD, "Failed to connect to Windows Firewall");
235 UINT er = WcaErrorMessage(msierrFirewallCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
236 switch (er)
237 {
238 case IDABORT: // exit with the current HRESULT
239 ExitFunction();
240 case IDRETRY: // clean up and retry the loop
241 hr = S_FALSE;
242 break;
243 case IDIGNORE: // pass S_FALSE back to the caller, who knows how to ignore the failure
244 ExitFunction1(hr = S_FALSE);
245 default: // No UI, so default is to fail.
246 ExitFunction();
247 }
248 }
249 } while (S_FALSE == hr);
250
251 *ppNetFwRules = pNetFwRules;
252 pNetFwRules = NULL;
253
254LExit:
255 ReleaseObject(pNetFwPolicy2);
256 ReleaseObject(pNetFwRules);
257
258 return hr;
259}
260
261/******************************************************************
262 CreateFwRuleObject - CoCreate a firewall rule, and set the common set of properties which are shared
263 between port and application firewall rules
264
265********************************************************************/
266static HRESULT CreateFwRuleObject(
267 __in BSTR bstrName,
268 __in int iProfile,
269 __in_opt LPCWSTR wzRemoteAddresses,
270 __in LPCWSTR wzPort,
271 __in int iProtocol,
272 __in LPCWSTR wzDescription,
273 __out INetFwRule** ppNetFwRule
274 )
275{
276 HRESULT hr = S_OK;
277 BSTR bstrRemoteAddresses = NULL;
278 BSTR bstrPort = NULL;
279 BSTR bstrDescription = NULL;
280 INetFwRule* pNetFwRule = NULL;
281 *ppNetFwRule = NULL;
282
283 // convert to BSTRs to make COM happy
284 bstrRemoteAddresses = ::SysAllocString(wzRemoteAddresses);
285 ExitOnNull(bstrRemoteAddresses, hr, E_OUTOFMEMORY, "failed SysAllocString for remote addresses");
286 bstrPort = ::SysAllocString(wzPort);
287 ExitOnNull(bstrPort, hr, E_OUTOFMEMORY, "failed SysAllocString for port");
288 bstrDescription = ::SysAllocString(wzDescription);
289 ExitOnNull(bstrDescription, hr, E_OUTOFMEMORY, "failed SysAllocString for description");
290
291 hr = ::CoCreateInstance(__uuidof(NetFwRule), NULL, CLSCTX_ALL, __uuidof(INetFwRule), (void**)&pNetFwRule);
292 ExitOnFailure(hr, "failed to create NetFwRule object");
293
294 hr = pNetFwRule->put_Name(bstrName);
295 ExitOnFailure(hr, "failed to set exception name");
296
297 hr = pNetFwRule->put_Profiles(static_cast<NET_FW_PROFILE_TYPE2>(iProfile));
298 ExitOnFailure(hr, "failed to set exception profile");
299
300 if (MSI_NULL_INTEGER != iProtocol)
301 {
302 hr = pNetFwRule->put_Protocol(static_cast<NET_FW_IP_PROTOCOL>(iProtocol));
303 ExitOnFailure(hr, "failed to set exception protocol");
304 }
305
306 if (bstrPort && *bstrPort)
307 {
308 hr = pNetFwRule->put_LocalPorts(bstrPort);
309 ExitOnFailure(hr, "failed to set exception port");
310 }
311
312 if (bstrRemoteAddresses && *bstrRemoteAddresses)
313 {
314 hr = pNetFwRule->put_RemoteAddresses(bstrRemoteAddresses);
315 ExitOnFailure(hr, "failed to set exception remote addresses '%ls'", bstrRemoteAddresses);
316 }
317
318 if (bstrDescription && *bstrDescription)
319 {
320 hr = pNetFwRule->put_Description(bstrDescription);
321 ExitOnFailure(hr, "failed to set exception description '%ls'", bstrDescription);
322 }
323
324 *ppNetFwRule = pNetFwRule;
325 pNetFwRule = NULL;
326
327LExit:
328 ReleaseBSTR(bstrRemoteAddresses);
329 ReleaseBSTR(bstrPort);
330 ReleaseBSTR(bstrDescription);
331 ReleaseObject(pNetFwRule);
332
333 return hr;
334}
335
336/******************************************************************
337 FSupportProfiles - Returns true if we support profiles on this machine.
338 (Only on Vista or later)
339
340********************************************************************/
341static BOOL FSupportProfiles()
342{
343 BOOL fSupportProfiles = FALSE;
344 INetFwRules* pNetFwRules = NULL;
345
346 // We only support profiles if we can co-create an instance of NetFwPolicy2.
347 // This will not work on pre-vista machines.
348 if (SUCCEEDED(GetFirewallRules(TRUE, &pNetFwRules)) && pNetFwRules != NULL)
349 {
350 fSupportProfiles = TRUE;
351 ReleaseObject(pNetFwRules);
352 }
353
354 return fSupportProfiles;
355}
356
357/******************************************************************
358 GetCurrentFirewallProfile - get the active firewall profile as an
359 INetFwProfile, which owns the lists of exceptions we're
360 updating.
361
362********************************************************************/
363static HRESULT GetCurrentFirewallProfile(
364 __in BOOL fIgnoreFailures,
365 __out INetFwProfile** ppfwProfile
366 )
367{
368 HRESULT hr = S_OK;
369 INetFwMgr* pfwMgr = NULL;
370 INetFwPolicy* pfwPolicy = NULL;
371 INetFwProfile* pfwProfile = NULL;
372 *ppfwProfile = NULL;
373
374 do
375 {
376 ReleaseNullObject(pfwPolicy);
377 ReleaseNullObject(pfwMgr);
378 ReleaseNullObject(pfwProfile);
379
380 if (SUCCEEDED(hr = ::CoCreateInstance(__uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&pfwMgr)) &&
381 SUCCEEDED(hr = pfwMgr->get_LocalPolicy(&pfwPolicy)) &&
382 SUCCEEDED(hr = pfwPolicy->get_CurrentProfile(&pfwProfile)))
383 {
384 break;
385 }
386 else if (fIgnoreFailures)
387 {
388 ExitFunction1(hr = S_FALSE);
389 }
390 else
391 {
392 WcaLog(LOGMSG_STANDARD, "Failed to connect to Windows Firewall");
393 UINT er = WcaErrorMessage(msierrFirewallCannotConnect, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0);
394 switch (er)
395 {
396 case IDABORT: // exit with the current HRESULT
397 ExitFunction();
398 case IDRETRY: // clean up and retry the loop
399 hr = S_FALSE;
400 break;
401 case IDIGNORE: // pass S_FALSE back to the caller, who knows how to ignore the failure
402 ExitFunction1(hr = S_FALSE);
403 default: // No UI, so default is to fail.
404 ExitFunction();
405 }
406 }
407 } while (S_FALSE == hr);
408
409 *ppfwProfile = pfwProfile;
410 pfwProfile = NULL;
411
412LExit:
413 ReleaseObject(pfwPolicy);
414 ReleaseObject(pfwMgr);
415 ReleaseObject(pfwProfile);
416
417 return hr;
418}
419
420/******************************************************************
421 AddApplicationException
422
423********************************************************************/
424static HRESULT AddApplicationException(
425 __in LPCWSTR wzFile,
426 __in LPCWSTR wzName,
427 __in int iProfile,
428 __in_opt LPCWSTR wzRemoteAddresses,
429 __in BOOL fIgnoreFailures,
430 __in LPCWSTR wzPort,
431 __in int iProtocol,
432 __in LPCWSTR wzDescription
433 )
434{
435 HRESULT hr = S_OK;
436 BSTR bstrFile = NULL;
437 BSTR bstrName = NULL;
438 INetFwRules* pNetFwRules = NULL;
439 INetFwRule* pNetFwRule = NULL;
440
441 // convert to BSTRs to make COM happy
442 bstrFile = ::SysAllocString(wzFile);
443 ExitOnNull(bstrFile, hr, E_OUTOFMEMORY, "failed SysAllocString for path");
444 bstrName = ::SysAllocString(wzName);
445 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name");
446
447 // get the collection of firewall rules
448 hr = GetFirewallRules(fIgnoreFailures, &pNetFwRules);
449 ExitOnFailure(hr, "failed to get firewall rules object");
450 if (S_FALSE == hr) // user or package author chose to ignore missing firewall
451 {
452 ExitFunction();
453 }
454
455 // try to find it (i.e., support reinstall)
456 hr = pNetFwRules->Item(bstrName, &pNetFwRule);
457 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
458 {
459 hr = CreateFwRuleObject(bstrName, iProfile, wzRemoteAddresses, wzPort, iProtocol, wzDescription, &pNetFwRule);
460 ExitOnFailure(hr, "failed to create FwRule object");
461
462 // set edge traversal to true
463 hr = pNetFwRule->put_EdgeTraversal(VARIANT_TRUE);
464 ExitOnFailure(hr, "failed to set application exception edgetraversal property");
465
466 // set path
467 hr = pNetFwRule->put_ApplicationName(bstrFile);
468 ExitOnFailure(hr, "failed to set application name");
469
470 // enable it
471 hr = pNetFwRule->put_Enabled(VARIANT_TRUE);
472 ExitOnFailure(hr, "failed to to enable application exception");
473
474 // add it to the list of authorized apps
475 hr = pNetFwRules->Add(pNetFwRule);
476 ExitOnFailure(hr, "failed to add app to the authorized apps list");
477 }
478 else
479 {
480 // we found an existing app exception (if we succeeded, that is)
481 ExitOnFailure(hr, "failed trying to find existing app");
482
483 // enable it (just in case it was disabled)
484 pNetFwRule->put_Enabled(VARIANT_TRUE);
485 }
486
487LExit:
488 ReleaseBSTR(bstrName);
489 ReleaseBSTR(bstrFile);
490 ReleaseObject(pNetFwRules);
491 ReleaseObject(pNetFwRule);
492
493 return fIgnoreFailures ? S_OK : hr;
494}
495
496/******************************************************************
497 AddApplicationExceptionOnCurrentProfile
498
499********************************************************************/
500static HRESULT AddApplicationExceptionOnCurrentProfile(
501 __in LPCWSTR wzFile,
502 __in LPCWSTR wzName,
503 __in_opt LPCWSTR wzRemoteAddresses,
504 __in BOOL fIgnoreFailures
505 )
506{
507 HRESULT hr = S_OK;
508 BSTR bstrFile = NULL;
509 BSTR bstrName = NULL;
510 BSTR bstrRemoteAddresses = NULL;
511 INetFwProfile* pfwProfile = NULL;
512 INetFwAuthorizedApplications* pfwApps = NULL;
513 INetFwAuthorizedApplication* pfwApp = NULL;
514
515 // convert to BSTRs to make COM happy
516 bstrFile = ::SysAllocString(wzFile);
517 ExitOnNull(bstrFile, hr, E_OUTOFMEMORY, "failed SysAllocString for path");
518 bstrName = ::SysAllocString(wzName);
519 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name");
520 bstrRemoteAddresses = ::SysAllocString(wzRemoteAddresses);
521 ExitOnNull(bstrRemoteAddresses, hr, E_OUTOFMEMORY, "failed SysAllocString for remote addresses");
522
523 // get the firewall profile, which is our entry point for adding exceptions
524 hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile);
525 ExitOnFailure(hr, "failed to get firewall profile");
526 if (S_FALSE == hr) // user or package author chose to ignore missing firewall
527 {
528 ExitFunction();
529 }
530
531 // first, let's see if the app is already on the exception list
532 hr = pfwProfile->get_AuthorizedApplications(&pfwApps);
533 ExitOnFailure(hr, "failed to get list of authorized apps");
534
535 // try to find it (i.e., support reinstall)
536 hr = pfwApps->Item(bstrFile, &pfwApp);
537 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
538 {
539 // not found, so we get to add it
540 hr = ::CoCreateInstance(__uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), reinterpret_cast<void**>(&pfwApp));
541 ExitOnFailure(hr, "failed to create authorized app");
542
543 // set the display name
544 hr = pfwApp->put_Name(bstrName);
545 ExitOnFailure(hr, "failed to set authorized app name");
546
547 // set path
548 hr = pfwApp->put_ProcessImageFileName(bstrFile);
549 ExitOnFailure(hr, "failed to set authorized app path");
550
551 // set the allowed remote addresses
552 if (bstrRemoteAddresses && *bstrRemoteAddresses)
553 {
554 hr = pfwApp->put_RemoteAddresses(bstrRemoteAddresses);
555 ExitOnFailure(hr, "failed to set authorized app remote addresses");
556 }
557
558 // add it to the list of authorized apps
559 hr = pfwApps->Add(pfwApp);
560 ExitOnFailure(hr, "failed to add app to the authorized apps list");
561 }
562 else
563 {
564 // we found an existing app exception (if we succeeded, that is)
565 ExitOnFailure(hr, "failed trying to find existing app");
566
567 // enable it (just in case it was disabled)
568 pfwApp->put_Enabled(VARIANT_TRUE);
569 }
570
571LExit:
572 ReleaseBSTR(bstrRemoteAddresses);
573 ReleaseBSTR(bstrName);
574 ReleaseBSTR(bstrFile);
575 ReleaseObject(pfwApp);
576 ReleaseObject(pfwApps);
577 ReleaseObject(pfwProfile);
578
579 return fIgnoreFailures ? S_OK : hr;
580}
581
582/******************************************************************
583 AddPortException
584
585********************************************************************/
586static HRESULT AddPortException(
587 __in LPCWSTR wzName,
588 __in int iProfile,
589 __in_opt LPCWSTR wzRemoteAddresses,
590 __in BOOL fIgnoreFailures,
591 __in LPCWSTR wzPort,
592 __in int iProtocol,
593 __in LPCWSTR wzDescription
594 )
595{
596 HRESULT hr = S_OK;
597 BSTR bstrName = NULL;
598 INetFwRules* pNetFwRules = NULL;
599 INetFwRule* pNetFwRule = NULL;
600
601 // convert to BSTRs to make COM happy
602 bstrName = ::SysAllocString(wzName);
603 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name");
604
605 // get the collection of firewall rules
606 hr = GetFirewallRules(fIgnoreFailures, &pNetFwRules);
607 ExitOnFailure(hr, "failed to get firewall rules object");
608 if (S_FALSE == hr) // user or package author chose to ignore missing firewall
609 {
610 ExitFunction();
611 }
612
613 // try to find it (i.e., support reinstall)
614 hr = pNetFwRules->Item(bstrName, &pNetFwRule);
615 if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
616 {
617 hr = CreateFwRuleObject(bstrName, iProfile, wzRemoteAddresses, wzPort, iProtocol, wzDescription, &pNetFwRule);
618 ExitOnFailure(hr, "failed to create FwRule object");
619
620 // enable it
621 hr = pNetFwRule->put_Enabled(VARIANT_TRUE);
622 ExitOnFailure(hr, "failed to to enable port exception");
623
624 // add it to the list of authorized ports
625 hr = pNetFwRules->Add(pNetFwRule);
626 ExitOnFailure(hr, "failed to add app to the authorized ports list");
627 }
628 else
629 {
630 // we found an existing port exception (if we succeeded, that is)
631 ExitOnFailure(hr, "failed trying to find existing port rule");
632
633 // enable it (just in case it was disabled)
634 pNetFwRule->put_Enabled(VARIANT_TRUE);
635 }
636
637LExit:
638 ReleaseBSTR(bstrName);
639 ReleaseObject(pNetFwRules);
640 ReleaseObject(pNetFwRule);
641
642 return fIgnoreFailures ? S_OK : hr;
643}
644
645/******************************************************************
646 AddPortExceptionOnCurrentProfile
647
648********************************************************************/
649static HRESULT AddPortExceptionOnCurrentProfile(
650 __in LPCWSTR wzName,
651 __in_opt LPCWSTR wzRemoteAddresses,
652 __in BOOL fIgnoreFailures,
653 __in int iPort,
654 __in int iProtocol
655 )
656{
657 HRESULT hr = S_OK;
658 BSTR bstrName = NULL;
659 BSTR bstrRemoteAddresses = NULL;
660 INetFwProfile* pfwProfile = NULL;
661 INetFwOpenPorts* pfwPorts = NULL;
662 INetFwOpenPort* pfwPort = NULL;
663
664 // convert to BSTRs to make COM happy
665 bstrName = ::SysAllocString(wzName);
666 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name");
667 bstrRemoteAddresses = ::SysAllocString(wzRemoteAddresses);
668 ExitOnNull(bstrRemoteAddresses, hr, E_OUTOFMEMORY, "failed SysAllocString for remote addresses");
669
670 // create and initialize a new open port object
671 hr = ::CoCreateInstance(__uuidof(NetFwOpenPort), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwOpenPort), reinterpret_cast<void**>(&pfwPort));
672 ExitOnFailure(hr, "failed to create new open port");
673
674 hr = pfwPort->put_Port(iPort);
675 ExitOnFailure(hr, "failed to set exception port");
676
677 hr = pfwPort->put_Protocol(static_cast<NET_FW_IP_PROTOCOL>(iProtocol));
678 ExitOnFailure(hr, "failed to set exception protocol");
679
680 if (bstrRemoteAddresses && *bstrRemoteAddresses)
681 {
682 hr = pfwPort->put_RemoteAddresses(bstrRemoteAddresses);
683 ExitOnFailure(hr, "failed to set exception remote addresses '%ls'", bstrRemoteAddresses);
684 }
685
686 hr = pfwPort->put_Name(bstrName);
687 ExitOnFailure(hr, "failed to set exception name");
688
689 // get the firewall profile, its current list of open ports, and add ours
690 hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile);
691 ExitOnFailure(hr, "failed to get firewall profile");
692 if (S_FALSE == hr) // user or package author chose to ignore missing firewall
693 {
694 ExitFunction();
695 }
696
697 hr = pfwProfile->get_GloballyOpenPorts(&pfwPorts);
698 ExitOnFailure(hr, "failed to get open ports");
699
700 hr = pfwPorts->Add(pfwPort);
701 ExitOnFailure(hr, "failed to add exception to global list");
702
703LExit:
704 ReleaseBSTR(bstrRemoteAddresses);
705 ReleaseBSTR(bstrName);
706 ReleaseObject(pfwProfile);
707 ReleaseObject(pfwPorts);
708 ReleaseObject(pfwPort);
709
710 return fIgnoreFailures ? S_OK : hr;
711}
712
713/******************************************************************
714 RemoveException - Removes the exception rule with the given name.
715
716********************************************************************/
717static HRESULT RemoveException(
718 __in LPCWSTR wzName,
719 __in BOOL fIgnoreFailures
720 )
721{
722 HRESULT hr = S_OK;;
723 INetFwRules* pNetFwRules = NULL;
724
725 // convert to BSTRs to make COM happy
726 BSTR bstrName = ::SysAllocString(wzName);
727 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for path");
728
729 // get the collection of firewall rules
730 hr = GetFirewallRules(fIgnoreFailures, &pNetFwRules);
731 ExitOnFailure(hr, "failed to get firewall rules object");
732 if (S_FALSE == hr) // user or package author chose to ignore missing firewall
733 {
734 ExitFunction();
735 }
736
737 hr = pNetFwRules->Remove(bstrName);
738 ExitOnFailure(hr, "failed to remove authorized app");
739
740LExit:
741 ReleaseBSTR(bstrName);
742 ReleaseObject(pNetFwRules);
743
744 return fIgnoreFailures ? S_OK : hr;
745}
746
747/******************************************************************
748 RemoveApplicationExceptionFromCurrentProfile
749
750********************************************************************/
751static HRESULT RemoveApplicationExceptionFromCurrentProfile(
752 __in LPCWSTR wzFile,
753 __in BOOL fIgnoreFailures
754 )
755{
756 HRESULT hr = S_OK;
757 INetFwProfile* pfwProfile = NULL;
758 INetFwAuthorizedApplications* pfwApps = NULL;
759
760 // convert to BSTRs to make COM happy
761 BSTR bstrFile = ::SysAllocString(wzFile);
762 ExitOnNull(bstrFile, hr, E_OUTOFMEMORY, "failed SysAllocString for path");
763
764 // get the firewall profile, which is our entry point for removing exceptions
765 hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile);
766 ExitOnFailure(hr, "failed to get firewall profile");
767 if (S_FALSE == hr) // user or package author chose to ignore missing firewall
768 {
769 ExitFunction();
770 }
771
772 // now get the list of app exceptions and remove the one
773 hr = pfwProfile->get_AuthorizedApplications(&pfwApps);
774 ExitOnFailure(hr, "failed to get list of authorized apps");
775
776 hr = pfwApps->Remove(bstrFile);
777 ExitOnFailure(hr, "failed to remove authorized app");
778
779LExit:
780 ReleaseBSTR(bstrFile);
781 ReleaseObject(pfwApps);
782 ReleaseObject(pfwProfile);
783
784 return fIgnoreFailures ? S_OK : hr;
785}
786
787/******************************************************************
788 RemovePortExceptionFromCurrentProfile
789
790********************************************************************/
791static HRESULT RemovePortExceptionFromCurrentProfile(
792 __in int iPort,
793 __in int iProtocol,
794 __in BOOL fIgnoreFailures
795 )
796{
797 HRESULT hr = S_OK;
798 INetFwProfile* pfwProfile = NULL;
799 INetFwOpenPorts* pfwPorts = NULL;
800
801 // get the firewall profile, which is our entry point for adding exceptions
802 hr = GetCurrentFirewallProfile(fIgnoreFailures, &pfwProfile);
803 ExitOnFailure(hr, "failed to get firewall profile");
804 if (S_FALSE == hr) // user or package author chose to ignore missing firewall
805 {
806 ExitFunction();
807 }
808
809 hr = pfwProfile->get_GloballyOpenPorts(&pfwPorts);
810 ExitOnFailure(hr, "failed to get open ports");
811
812 hr = pfwPorts->Remove(iPort, static_cast<NET_FW_IP_PROTOCOL>(iProtocol));
813 ExitOnFailure(hr, "failed to remove open port %d, protocol %d", iPort, iProtocol);
814
815LExit:
816 return fIgnoreFailures ? S_OK : hr;
817}
818
819static HRESULT AddApplicationException(
820 __in BOOL fSupportProfiles,
821 __in LPCWSTR wzFile,
822 __in LPCWSTR wzName,
823 __in int iProfile,
824 __in_opt LPCWSTR wzRemoteAddresses,
825 __in BOOL fIgnoreFailures,
826 __in LPCWSTR wzPort,
827 __in int iProtocol,
828 __in LPCWSTR wzDescription
829 )
830{
831 HRESULT hr = S_OK;
832
833 if (fSupportProfiles)
834 {
835 hr = AddApplicationException(wzFile, wzName, iProfile, wzRemoteAddresses, fIgnoreFailures, wzPort, iProtocol, wzDescription);
836 }
837 else
838 {
839 if (0 != *wzPort || MSI_NULL_INTEGER != iProtocol)
840 {
841 // NOTE: This is treated as an error rather than either creating a rule based on just the application (no port), or
842 // just the port because it is unclear what is the proper fall back. For example, suppose that you have code that
843 // runs in dllhost.exe. Clearly falling back to opening all of dllhost is wrong. Because the firewall is a security
844 // feature, it seems better to require the MSI author to indicate the behavior that they want.
845 WcaLog(LOGMSG_STANDARD, "FirewallExtension: Cannot add firewall rule '%ls', which defines both an application and a port or protocol. Such a rule requires Microsoft Windows Vista or later.", wzName);
846 return fIgnoreFailures ? S_OK : E_NOTIMPL;
847 }
848
849 hr = AddApplicationExceptionOnCurrentProfile(wzFile, wzName, wzRemoteAddresses, fIgnoreFailures);
850 }
851
852 return hr;
853}
854
855static HRESULT AddPortException(
856 __in BOOL fSupportProfiles,
857 __in LPCWSTR wzName,
858 __in int iProfile,
859 __in_opt LPCWSTR wzRemoteAddresses,
860 __in BOOL fIgnoreFailures,
861 __in LPCWSTR wzPort,
862 __in int iProtocol,
863 __in LPCWSTR wzDescription
864 )
865{
866 HRESULT hr = S_OK;
867
868 if (fSupportProfiles)
869 {
870 hr = AddPortException(wzName, iProfile, wzRemoteAddresses, fIgnoreFailures, wzPort, iProtocol, wzDescription);
871 }
872 else
873 {
874 hr = AddPortExceptionOnCurrentProfile(wzName, wzRemoteAddresses, fIgnoreFailures, wcstol(wzPort, NULL, 10), iProtocol);
875 }
876
877 return hr;
878}
879
880static HRESULT RemoveApplicationException(
881 __in BOOL fSupportProfiles,
882 __in LPCWSTR wzName,
883 __in LPCWSTR wzFile,
884 __in BOOL fIgnoreFailures,
885 __in LPCWSTR wzPort,
886 __in int iProtocol
887 )
888{
889 HRESULT hr = S_OK;
890
891 if (fSupportProfiles)
892 {
893 hr = RemoveException(wzName, fIgnoreFailures);
894 }
895 else
896 {
897 if (0 != *wzPort || MSI_NULL_INTEGER != iProtocol)
898 {
899 WcaLog(LOGMSG_STANDARD, "FirewallExtension: Cannot remove firewall rule '%ls', which defines both an application and a port or protocol. Such a rule requires Microsoft Windows Vista or later.", wzName);
900 return S_OK;
901 }
902
903 hr = RemoveApplicationExceptionFromCurrentProfile(wzFile, fIgnoreFailures);
904 }
905
906 return hr;
907}
908
909static HRESULT RemovePortException(
910 __in BOOL fSupportProfiles,
911 __in LPCWSTR wzName,
912 __in LPCWSTR wzPort,
913 __in int iProtocol,
914 __in BOOL fIgnoreFailures
915 )
916{
917 HRESULT hr = S_OK;
918
919 if (fSupportProfiles)
920 {
921 hr = RemoveException(wzName, fIgnoreFailures);
922 }
923 else
924 {
925 hr = RemovePortExceptionFromCurrentProfile(wcstol(wzPort, NULL, 10), iProtocol, fIgnoreFailures);
926 }
927
928 return hr;
929}
930
931/******************************************************************
932 ExecFirewallExceptions - deferred custom action entry point to
933 register and remove firewall exceptions.
934
935********************************************************************/
936extern "C" UINT __stdcall ExecFirewallExceptions(
937 __in MSIHANDLE hInstall
938 )
939{
940 HRESULT hr = S_OK;
941 BOOL fSupportProfiles = FALSE;
942 LPWSTR pwz = NULL;
943 LPWSTR pwzCustomActionData = NULL;
944 int iTodo = WCA_TODO_UNKNOWN;
945 LPWSTR pwzName = NULL;
946 LPWSTR pwzRemoteAddresses = NULL;
947 int iAttributes = 0;
948 int iTarget = fetUnknown;
949 LPWSTR pwzFile = NULL;
950 LPWSTR pwzPort = NULL;
951 LPWSTR pwzDescription = NULL;
952 int iProtocol = 0;
953 int iProfile = 0;
954
955 // initialize
956 hr = WcaInitialize(hInstall, "ExecFirewallExceptions");
957 ExitOnFailure(hr, "failed to initialize");
958
959 hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData);
960 ExitOnFailure(hr, "failed to get CustomActionData");
961 WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData);
962
963 hr = ::CoInitialize(NULL);
964 ExitOnFailure(hr, "failed to initialize COM");
965
966 // Find out if we support profiles (only on Vista or later)
967 fSupportProfiles = FSupportProfiles();
968
969 // loop through all the passed in data
970 pwz = pwzCustomActionData;
971 while (pwz && *pwz)
972 {
973 // extract the custom action data and if rolling back, swap INSTALL and UNINSTALL
974 hr = WcaReadIntegerFromCaData(&pwz, &iTodo);
975 ExitOnFailure(hr, "failed to read todo from custom action data");
976 if (::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK))
977 {
978 if (WCA_TODO_INSTALL == iTodo)
979 {
980 iTodo = WCA_TODO_UNINSTALL;
981 }
982 else if (WCA_TODO_UNINSTALL == iTodo)
983 {
984 iTodo = WCA_TODO_INSTALL;
985 }
986 }
987
988 hr = WcaReadStringFromCaData(&pwz, &pwzName);
989 ExitOnFailure(hr, "failed to read name from custom action data");
990
991 hr = WcaReadIntegerFromCaData(&pwz, &iProfile);
992 ExitOnFailure(hr, "failed to read profile from custom action data");
993
994 hr = WcaReadStringFromCaData(&pwz, &pwzRemoteAddresses);
995 ExitOnFailure(hr, "failed to read remote addresses from custom action data");
996
997 hr = WcaReadIntegerFromCaData(&pwz, &iAttributes);
998 ExitOnFailure(hr, "failed to read attributes from custom action data");
999 BOOL fIgnoreFailures = feaIgnoreFailures == (iAttributes & feaIgnoreFailures);
1000
1001 hr = WcaReadIntegerFromCaData(&pwz, &iTarget);
1002 ExitOnFailure(hr, "failed to read target from custom action data");
1003
1004 if (iTarget == fetApplication)
1005 {
1006 hr = WcaReadStringFromCaData(&pwz, &pwzFile);
1007 ExitOnFailure(hr, "failed to read file path from custom action data");
1008 }
1009
1010 hr = WcaReadStringFromCaData(&pwz, &pwzPort);
1011 ExitOnFailure(hr, "failed to read port from custom action data");
1012 hr = WcaReadIntegerFromCaData(&pwz, &iProtocol);
1013 ExitOnFailure(hr, "failed to read protocol from custom action data");
1014 hr = WcaReadStringFromCaData(&pwz, &pwzDescription);
1015 ExitOnFailure(hr, "failed to read protocol from custom action data");
1016
1017 switch (iTarget)
1018 {
1019 case fetPort:
1020 switch (iTodo)
1021 {
1022 case WCA_TODO_INSTALL:
1023 case WCA_TODO_REINSTALL:
1024 WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol);
1025 hr = AddPortException(fSupportProfiles, pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription);
1026 ExitOnFailure(hr, "failed to add/update port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol);
1027 break;
1028
1029 case WCA_TODO_UNINSTALL:
1030 WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls on port %ls, protocol %d", pwzName, pwzPort, iProtocol);
1031 hr = RemovePortException(fSupportProfiles, pwzName, pwzPort, iProtocol, fIgnoreFailures);
1032 ExitOnFailure(hr, "failed to remove port exception for name '%ls' on port %ls, protocol %d", pwzName, pwzPort, iProtocol);
1033 break;
1034 }
1035 break;
1036
1037 case fetApplication:
1038 switch (iTodo)
1039 {
1040 case WCA_TODO_INSTALL:
1041 case WCA_TODO_REINSTALL:
1042 WcaLog(LOGMSG_STANDARD, "Installing firewall exception2 %ls (%ls)", pwzName, pwzFile);
1043 hr = AddApplicationException(fSupportProfiles, pwzFile, pwzName, iProfile, pwzRemoteAddresses, fIgnoreFailures, pwzPort, iProtocol, pwzDescription);
1044 ExitOnFailure(hr, "failed to add/update application exception for name '%ls', file '%ls'", pwzName, pwzFile);
1045 break;
1046
1047 case WCA_TODO_UNINSTALL:
1048 WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception2 %ls (%ls)", pwzName, pwzFile);
1049 hr = RemoveApplicationException(fSupportProfiles, pwzName, pwzFile, fIgnoreFailures, pwzPort, iProtocol);
1050 ExitOnFailure(hr, "failed to remove application exception for name '%ls', file '%ls'", pwzName, pwzFile);
1051 break;
1052 }
1053 break;
1054 }
1055 }
1056
1057LExit:
1058 ReleaseStr(pwzCustomActionData);
1059 ReleaseStr(pwzName);
1060 ReleaseStr(pwzRemoteAddresses);
1061 ReleaseStr(pwzFile);
1062 ReleaseStr(pwzPort);
1063 ReleaseStr(pwzDescription);
1064 ::CoUninitialize();
1065
1066 return WcaFinalize(FAILED(hr) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS);
1067}
diff --git a/src/ca/fwca.def b/src/ca/fwca.def
new file mode 100644
index 00000000..d32c5379
--- /dev/null
+++ b/src/ca/fwca.def
@@ -0,0 +1,9 @@
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 "fwca"
5
6EXPORTS
7 SchedFirewallExceptionsInstall
8 SchedFirewallExceptionsUninstall
9 ExecFirewallExceptions
diff --git a/src/ca/fwca.vcxproj b/src/ca/fwca.vcxproj
new file mode 100644
index 00000000..b6075790
--- /dev/null
+++ b/src/ca/fwca.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
4<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
5 <Import Project="..\..\packages\WixToolset.DUtil.4.0.6\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.6\build\WixToolset.DUtil.props')" />
6 <Import Project="..\..\packages\WixToolset.WcaUtil.4.0.2\build\WixToolset.WcaUtil.props" Condition="Exists('..\..\packages\WixToolset.WcaUtil.4.0.2\build\WixToolset.WcaUtil.props')" />
7
8 <ItemGroup Label="ProjectConfigurations">
9 <ProjectConfiguration Include="Debug|Win32">
10 <Configuration>Debug</Configuration>
11 <Platform>Win32</Platform>
12 </ProjectConfiguration>
13 <ProjectConfiguration Include="Release|Win32">
14 <Configuration>Release</Configuration>
15 <Platform>Win32</Platform>
16 </ProjectConfiguration>
17 </ItemGroup>
18
19 <PropertyGroup Label="Globals">
20 <ProjectGuid>{F72D34CA-48DA-4DFD-91A9-A0C78BEF6981}</ProjectGuid>
21 <ConfigurationType>DynamicLibrary</ConfigurationType>
22 <TargetName>fwca</TargetName>
23 <PlatformToolset>v141</PlatformToolset>
24 <CharacterSet>Unicode</CharacterSet>
25 <ProjectModuleDefinitionFile>fwca.def</ProjectModuleDefinitionFile>
26 <Description>WiX Toolset Firewall CustomAction</Description>
27 </PropertyGroup>
28
29 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
30 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
31
32 <ImportGroup Label="ExtensionSettings">
33 </ImportGroup>
34
35 <ImportGroup Label="Shared">
36 <Import Project="..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.1.14.114\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets" Condition="Exists('..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.1.14.114\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" />
37 </ImportGroup>
38
39 <PropertyGroup>
40 <ProjectAdditionalLinkLibraries>msi.lib</ProjectAdditionalLinkLibraries>
41 </PropertyGroup>
42
43 <ItemGroup>
44 <ClCompile Include="dllmain.cpp">
45 <PrecompiledHeader>Create</PrecompiledHeader>
46 </ClCompile>
47 <ClCompile Include="firewall.cpp" />
48 </ItemGroup>
49
50 <ItemGroup>
51 <ClInclude Include="cost.h" />
52 <ClInclude Include="CustomMsiErrors.h" />
53 <ClInclude Include="precomp.h" />
54 </ItemGroup>
55
56 <ItemGroup>
57 <None Include="packages.config" />
58 <None Include="fwca.def" />
59 </ItemGroup>
60
61 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
62
63 <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
64 <PropertyGroup>
65 <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>
66 </PropertyGroup>
67 <Error Condition="!Exists('..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.1.14.114\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.1.14.114\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets'))" />
68 <Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.6\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.6\build\WixToolset.DUtil.props'))" />
69 <Error Condition="!Exists('..\..\packages\WixToolset.WcaUtil.4.0.2\build\WixToolset.WcaUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.WcaUtil.4.0.2\build\WixToolset.WcaUtil.props'))" />
70 </Target>
71</Project>
72
diff --git a/src/ca/packages.config b/src/ca/packages.config
new file mode 100644
index 00000000..b74ff5d0
--- /dev/null
+++ b/src/ca/packages.config
@@ -0,0 +1,6 @@
1<?xml version="1.0" encoding="utf-8"?>
2<packages>
3 <package id="Microsoft.VisualStudio.Setup.Configuration.Native" version="1.14.114" targetFramework="native" developmentDependency="true" />
4 <package id="WixToolset.DUtil" version="4.0.6" targetFramework="native" />
5 <package id="WixToolset.WcaUtil" version="4.0.2" targetFramework="native" />
6</packages> \ No newline at end of file
diff --git a/src/ca/precomp.h b/src/ca/precomp.h
new file mode 100644
index 00000000..a84bacff
--- /dev/null
+++ b/src/ca/precomp.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#include <windows.h>
6#include <msidefs.h>
7#include <msiquery.h>
8#include <strsafe.h>
9#include <netfw.h>
10
11#include "wcautil.h"
12#include "fileutil.h"
13#include "pathutil.h"
14#include "strutil.h"
15
16#include "CustomMsiErrors.h"
17#include "cost.h"