source: nscp/helpers/installer_dll_fw/firewall.cpp @ 8170e81

0.4.00.4.10.4.2stable
Last change on this file since 8170e81 was 8170e81, checked in by Michael Medin <michael@…>, 4 years ago

added some missing modules...

  • Property mode set to 100644
File size: 18.8 KB
Line 
1//-------------------------------------------------------------------------------------------------
2// <copyright file="firewall.cpp" company="Microsoft">
3//    Copyright (c) Microsoft Corporation.  All rights reserved.
4//   
5//    The use and distribution terms for this software are covered by the
6//    Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
7//    which can be found in the file CPL.TXT at the root of this distribution.
8//    By using this software in any fashion, you are agreeing to be bound by
9//    the terms of this license.
10//   
11//    You must not remove this notice, or any other, from this software.
12// </copyright>
13//
14// <summary>
15//    Firewall custom action code.
16// </summary>
17//-------------------------------------------------------------------------------------------------
18
19#include "precomp.h"
20#include "../installer_dll/installer_helper.hpp"
21#include <atlbase.h>
22
23LPCWSTR vcsFirewallExceptionQuery =
24    L"SELECT `Name`, `RemoteAddresses`, `Port`, `Protocol`, `Program`, `Attributes`, `Component_` FROM `WixFirewallException`";
25enum eFirewallExceptionQuery { feqName = 1, feqRemoteAddresses, feqPort, feqProtocol, feqProgram, feqAttributes, feqComponent };
26enum eFirewallExceptionTarget { fetPort = 1, fetApplication, fetUnknown };
27enum eFirewallExceptionAttributes { feaIgnoreFailures = 1 };
28
29
30
31/******************************************************************
32 SchedFirewallExceptions - immediate custom action worker to
33   register and remove firewall exceptions.
34
35********************************************************************/
36static UINT SchedFirewallExceptions(__in MSIHANDLE hInstall, msi_helper::WCA_TODO todoSched)
37{
38        msi_helper h(hInstall, _T("SchedFirewallExceptions"));
39        try {
40                int cFirewallExceptions = 0;
41                h.logMessage(_T("SchedFirewallExceptions: ") + strEx::itos(todoSched));
42
43                // anything to do?
44                if (!h.table_exists(L"WixFirewallException")) {
45                        h.logMessage(_T("WixFirewallException table doesn't exist, so there are no firewall exceptions to configure."));
46                        return ERROR_SUCCESS;
47                }
48
49                // query and loop through all the firewall exceptions
50                PMSIHANDLE hView = h.open_execute_view(vcsFirewallExceptionQuery);
51                if (h.isNull(hView)) {
52                        h.logMessage(_T("WixFirewallException!"));
53                        return ERROR_INSTALL_FAILURE;
54                }
55
56                msi_helper::custom_action_data_w custom_data;
57                PMSIHANDLE hRec = h.fetch_record(hView);
58                while (hRec != NULL)
59                {
60                        std::wstring name = h.get_record_formatted_string(hRec, feqName);
61                        std::wstring remoteAddress = h.get_record_formatted_string(hRec, feqRemoteAddresses);
62                        int port = h.get_record_formatted_integer(hRec, feqPort);
63                        int protocol = h.get_record_integer(hRec, feqProtocol);
64                        std::wstring program = h.get_record_formatted_string(hRec, feqProgram);
65                        int attributes = h.get_record_integer(hRec, feqAttributes);
66                        std::wstring component = h.get_record_string(hRec, feqComponent);
67
68                        // figure out what we're doing for this exception, treating reinstall the same as install
69                        msi_helper::WCA_TODO todoComponent = h.get_component_todo(component);
70                        if ((msi_helper::WCA_TODO_REINSTALL == todoComponent ? msi_helper::WCA_TODO_INSTALL : todoComponent) != todoSched) {
71                                h.logMessage(_T("Component '") + component + _T("' action state (") + strEx::itos(todoComponent) + _T(") doesn't match request (") + strEx::itos(todoSched) + _T(")"));
72                                hRec = h.fetch_record(hView);
73                                continue;
74                        }
75                        h.logMessage(_T("Adding data to CA chunk... "));
76                        // action :: name :: remoteaddresses :: attributes :: target :: {port::protocol | path}
77                        ++cFirewallExceptions;
78                        custom_data.write_int(todoComponent);
79                        custom_data.write_string(name);
80                        custom_data.write_string(remoteAddress);
81                        custom_data.write_int(attributes);
82                        if (MSI_NULL_INTEGER == port || MSI_NULL_INTEGER == protocol) {
83                                // without port and protocol, we have an application exception.
84                                custom_data.write_int(fetApplication);
85                                custom_data.write_string(program);
86                        } else {
87                                // we have a port-based exception
88                                custom_data.write_int(fetPort);
89                                custom_data.write_int(port);
90                                custom_data.write_int(protocol);
91                        }
92                        h.logMessage(_T("Adding data to CA chunk... DONE"));
93                        h.logMessage(_T("CA chunk: ") + custom_data.to_string());
94                        hRec = h.fetch_record(hView);
95                }
96                // schedule ExecFirewallExceptions if there's anything to do
97                if (custom_data.has_data()) {
98                        h.logMessage(_T("Scheduling (WixExecFirewallExceptionsInstall) firewall exception: ") + custom_data.to_string());
99                        if (msi_helper::WCA_TODO_INSTALL == todoSched) {
100                                HRESULT hr = h.do_deferred_action(L"WixRollbackFirewallExceptionsInstall", custom_data, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
101                                if (FAILED(hr)) {
102                                        h.errorMessage(_T("failed to schedule firewall install exceptions rollback"));
103                                        return hr;
104                                }
105                                hr = h.do_deferred_action(L"WixExecFirewallExceptionsInstall", custom_data, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
106                                if (FAILED(hr)) {
107                                        h.errorMessage(_T("failed to schedule firewall install exceptions execution"));
108                                        return hr;
109                                }
110                        }
111                        else
112                        {
113                                h.logMessage(_T("Scheduling (WixExecFirewallExceptionsUninstall) firewall exception: ") + custom_data.to_string());
114                                HRESULT hr = h.do_deferred_action(L"WixRollbackFirewallExceptionsUninstall", custom_data, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
115                                if (FAILED(hr)) {
116                                        h.errorMessage(_T("failed to schedule firewall install exceptions rollback"));
117                                        return hr;
118                                }
119                                hr = h.do_deferred_action(L"WixExecFirewallExceptionsUninstall", custom_data, cFirewallExceptions * COST_FIREWALL_EXCEPTION);
120                                if (FAILED(hr)) {
121                                        h.errorMessage(_T("failed to schedule firewall install exceptions execution"));
122                                        return hr;
123                                }
124                        }
125                } else
126                        h.logMessage(_T("No firewall exceptions scheduled"));
127        } catch (installer_exception e) {
128                h.errorMessage(_T("Failed to install firewall exception: ") + e.what());
129                return ERROR_INSTALL_FAILURE;
130        } catch (...) {
131                h.errorMessage(_T("Failed to install firewall exception: <UNKNOWN EXCEPTION>"));
132                return ERROR_INSTALL_FAILURE;
133        }
134        return ERROR_SUCCESS;
135}
136
137/******************************************************************
138 SchedFirewallExceptionsInstall - immediate custom action entry
139   point to register firewall exceptions.
140
141********************************************************************/
142
143extern "C" UINT __stdcall SchedFirewallExceptionsInstall(__in MSIHANDLE hInstall)
144{
145        return SchedFirewallExceptions(hInstall, msi_helper::WCA_TODO_INSTALL);
146}
147
148
149/******************************************************************
150 SchedFirewallExceptionsUninstall - immediate custom action entry
151   point to remove firewall exceptions.
152
153********************************************************************/
154
155extern "C" UINT __stdcall SchedFirewallExceptionsUninstall(__in MSIHANDLE hInstall)
156{
157    return SchedFirewallExceptions(hInstall, msi_helper::WCA_TODO_UNINSTALL);
158}
159
160
161#define ReleaseNullObject(x) if (x) { (x)->Release(); x = NULL; }
162
163
164/******************************************************************
165 GetFirewallProfile - get the active firewall profile as an
166   INetFwProfile, which owns the lists of exceptions we're
167   updating.
168********************************************************************/
169HRESULT GetFirewallProfile(__in BOOL fIgnoreFailures, CComPtr<INetFwProfile> &pfwProfile)
170{
171        CComPtr< INetFwMgr > pfwMgr = NULL;
172        CComPtr< INetFwPolicy > pfwPolicy = NULL;
173        HRESULT hr = CoCreateInstance(__uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), reinterpret_cast< void** >( &pfwMgr ) );
174        if (FAILED(hr))
175                throw installer_exception(_T("CoCreateInstance for NetFwMgr failed!") + error::format::from_system(hr));
176        hr = pfwMgr->get_LocalPolicy(&pfwPolicy);
177        if (FAILED(hr))
178                throw installer_exception(_T("get_LocalPolicy failed: ") + error::format::from_system(hr));
179        hr = pfwPolicy->get_CurrentProfile(&pfwProfile);
180        if (FAILED(hr))
181                throw installer_exception(_T("get_LocalPolicy failed: ") + error::format::from_system(hr));
182}
183
184/******************************************************************
185 AddApplicationException
186
187********************************************************************/
188
189void AddApplicationException(std::wstring file, std::wstring name, std::wstring remoteAddresses, BOOL fIgnoreFailures) {
190    HRESULT hr = S_OK;
191    CComBSTR bstrFile(file.c_str());
192    CComBSTR bstrName(name.c_str());
193    CComBSTR bstrRemoteAddresses(remoteAddresses.c_str());
194    CComPtr<INetFwProfile> pfwProfile;
195    CComPtr<INetFwAuthorizedApplications> pfwApps;
196
197    // get the firewall profile, which is our entry point for adding exceptions
198    GetFirewallProfile(fIgnoreFailures, pfwProfile);
199
200    // first, let's see if the app is already on the exception list
201    hr = pfwProfile->get_AuthorizedApplications(&pfwApps);
202        if (FAILED(hr))
203                throw installer_exception(_T("get_AuthorizedApplications failed: ") + error::format::from_system(hr));
204
205    // try to find it (i.e., support reinstall)
206        CComPtr<INetFwAuthorizedApplication> pfwApp;
207    hr = pfwApps->Item(bstrFile, &pfwApp);
208    if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
209    {
210        // not found, so we get to add it
211        hr = ::CoCreateInstance(__uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), reinterpret_cast<void**>(&pfwApp));
212                if (FAILED(hr))
213                        throw installer_exception(_T("NetFwAuthorizedApplication failed: ") + error::format::from_system(hr));
214
215        // set the display name
216        hr = pfwApp->put_Name(bstrName);
217                if (FAILED(hr))
218                        throw installer_exception(_T("put_Name failed: ") + error::format::from_system(hr));
219
220        // set path
221        hr = pfwApp->put_ProcessImageFileName(bstrFile);
222                if (FAILED(hr))
223                        throw installer_exception(_T("put_ProcessImageFileName failed: ") + error::format::from_system(hr));
224
225        // set the allowed remote addresses
226        if (remoteAddresses.length() > 0)
227        {
228            hr = pfwApp->put_RemoteAddresses(bstrRemoteAddresses);
229                        if (FAILED(hr))
230                                throw installer_exception(_T("put_RemoteAddresses failed: ") + error::format::from_system(hr) + _T(" '") + remoteAddresses + _T("'"));
231        }
232
233        // add it to the list of authorized apps
234        hr = pfwApps->Add(pfwApp);
235                if (FAILED(hr))
236                        throw installer_exception(_T("Failed to add authorized application: ") + error::format::from_system(hr));
237        } else if (SUCCEEDED(hr)) {
238                // we found an existing app exception (if we succeeded, that is)
239                // enable it (just in case it was disabled)
240                pfwApp->put_Enabled(VARIANT_TRUE);
241        } else {
242                throw installer_exception(_T("Item error: ") + error::format::from_system(hr));
243    }
244}
245
246/******************************************************************
247 RemoveApplicationException
248
249********************************************************************/
250static HRESULT RemoveApplicationException( std::wstring file, BOOL fIgnoreFailures) {
251        CComBSTR bstrFile(file.c_str());
252        CComPtr<INetFwProfile> pfwProfile;
253        CComPtr<INetFwAuthorizedApplications> pfwApps;
254
255        // get the firewall profile, which is our entry point for adding exceptions
256        GetFirewallProfile(fIgnoreFailures, pfwProfile);
257
258       
259    // now get the list of app exceptions and remove the one
260        HRESULT hr = pfwProfile->get_AuthorizedApplications(&pfwApps);
261        if (FAILED(hr))
262                throw installer_exception(_T("get_AuthorizedApplications failed: ") + error::format::from_system(hr));
263
264    pfwApps->Remove(bstrFile);
265}
266
267/******************************************************************
268 AddPortException
269
270********************************************************************/
271/*
272static HRESULT AddPortException(
273    __in LPCWSTR wzName,
274    __in_opt LPCWSTR wzRemoteAddresses,
275    __in BOOL fIgnoreFailures,
276    __in int iPort,
277    __in int iProtocol
278    )
279{
280    HRESULT hr = S_OK;
281    BSTR bstrName = NULL;
282    BSTR bstrRemoteAddresses = NULL;
283    INetFwProfile* pfwProfile = NULL;
284    INetFwOpenPorts* pfwPorts = NULL;
285    INetFwOpenPort* pfwPort = NULL;
286
287    // convert to BSTRs to make COM happy
288    bstrName = ::SysAllocString(wzName);
289    ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString for name");
290    bstrRemoteAddresses = ::SysAllocString(wzRemoteAddresses);
291    ExitOnNull(bstrRemoteAddresses, hr, E_OUTOFMEMORY, "failed SysAllocString for remote addresses");
292
293    // create and initialize a new open port object
294    hr = ::CoCreateInstance(__uuidof(NetFwOpenPort), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwOpenPort), reinterpret_cast<void**>(&pfwPort));
295    ExitOnFailure(hr, "failed to create new open port");
296
297    hr = pfwPort->put_Port(iPort);
298    ExitOnFailure(hr, "failed to set exception port");
299
300    hr = pfwPort->put_Protocol(static_cast<NET_FW_IP_PROTOCOL>(iProtocol));
301    ExitOnFailure(hr, "failed to set exception protocol");
302
303    if (bstrRemoteAddresses && *bstrRemoteAddresses)
304    {
305        hr = pfwPort->put_RemoteAddresses(bstrRemoteAddresses);
306        ExitOnFailure1(hr, "failed to set exception remote addresses '%S'", bstrRemoteAddresses);
307    }
308
309    hr = pfwPort->put_Name(bstrName);
310    ExitOnFailure(hr, "failed to set exception name");
311
312    // get the firewall profile, its current list of open ports, and add ours
313    hr = GetFirewallProfile(fIgnoreFailures, &pfwProfile);
314    ExitOnFailure(hr, "failed to get firewall profile");
315    if (S_FALSE == hr) // user or package author chose to ignore missing firewall
316    {
317        ExitFunction();
318    }
319
320    hr = pfwProfile->get_GloballyOpenPorts(&pfwPorts);
321    ExitOnFailure(hr, "failed to get open ports");
322
323    hr = pfwPorts->Add(pfwPort);
324    ExitOnFailure(hr, "failed to add exception to global list");
325
326LExit:
327    ReleaseBSTR(bstrRemoteAddresses);
328    ReleaseBSTR(bstrName);
329    ReleaseObject(pfwProfile);
330    ReleaseObject(pfwPorts);
331    ReleaseObject(pfwPort);
332
333    return fIgnoreFailures ? S_OK : hr;
334}*/
335
336/******************************************************************
337 RemovePortException
338
339********************************************************************/
340/*
341static HRESULT RemovePortException(
342    __in int iPort,
343    __in int iProtocol,
344    __in BOOL fIgnoreFailures
345    )
346{
347    HRESULT hr = S_OK;
348    INetFwProfile* pfwProfile = NULL;
349    INetFwOpenPorts* pfwPorts = NULL;
350
351    // get the firewall profile, which is our entry point for adding exceptions
352    hr = GetFirewallProfile(fIgnoreFailures, &pfwProfile);
353    ExitOnFailure(hr, "failed to get firewall profile");
354    if (S_FALSE == hr) // user or package author chose to ignore missing firewall
355    {
356        ExitFunction();
357    }
358
359    hr = pfwProfile->get_GloballyOpenPorts(&pfwPorts);
360    ExitOnFailure(hr, "failed to get open ports");
361
362    hr = pfwPorts->Remove(iPort, static_cast<NET_FW_IP_PROTOCOL>(iProtocol));
363    ExitOnFailure2(hr, "failed to remove open port %d, protocol %d", iPort, iProtocol);
364
365LExit:
366    return fIgnoreFailures ? S_OK : hr;
367}
368*/
369
370
371/******************************************************************
372 ExecFirewallExceptions - deferred custom action entry point to
373   register and remove firewall exceptions.
374
375********************************************************************/
376extern "C" UINT __stdcall ExecFirewallExceptions(__in MSIHANDLE hInstall)
377{
378    HRESULT hr = S_OK;
379    // initialize
380        msi_helper h(hInstall, _T("ExecFirewallExceptions"));
381        try {
382
383        msi_helper::custom_action_data_r data(h.getPropery(L"CustomActionData"));
384
385    hr = ::CoInitialize(NULL);
386        if (FAILED(hr)) {
387                h.errorMessage(_T("Failed to initialize COM"));
388                return ERROR_INSTALL_FAILURE;
389        }
390
391    // loop through all the passed in data
392    while (data.has_more()) {
393        // extract the custom action data and if rolling back, swap INSTALL and UNINSTALL
394                int iTodo = data.get_next_int();
395        if (::MsiGetMode(hInstall, MSIRUNMODE_ROLLBACK))
396        {
397                        if (msi_helper::WCA_TODO_INSTALL == iTodo)
398            {
399                iTodo = msi_helper::WCA_TODO_UNINSTALL;
400            }
401            else if (msi_helper::WCA_TODO_UNINSTALL == iTodo)
402            {
403                iTodo = msi_helper::WCA_TODO_INSTALL;
404            }
405        }
406
407                std::wstring name = data.get_next_string();
408                std::wstring remote_addr = data.get_next_string();
409                int attr = data.get_next_int();
410        BOOL fIgnoreFailures = feaIgnoreFailures == (attr & feaIgnoreFailures);
411
412        int target = data.get_next_int();
413        switch (target) {
414                        /*
415        case fetPort:
416            hr = WcaReadIntegerFromCaData(&pwz, &iPort);
417            ExitOnFailure(hr, "failed to read port from custom action data");
418            hr = WcaReadIntegerFromCaData(&pwz, &iProtocol);
419            ExitOnFailure(hr, "failed to read protocol from custom action data");
420
421            switch (iTodo)
422            {
423            case WCA_TODO_INSTALL:
424            case WCA_TODO_REINSTALL:
425                WcaLog(LOGMSG_STANDARD, "Installing firewall exception %S on port %d, protocol %d", pwzName, iPort, iProtocol);
426                hr = AddPortException(pwzName, pwzRemoteAddresses, fIgnoreFailures, iPort, iProtocol);
427                ExitOnFailure3(hr, "failed to add/update port exception for name '%S' on port %d, protocol %d", pwzName, iPort, iProtocol);
428                break;
429
430            case WCA_TODO_UNINSTALL:
431                WcaLog(LOGMSG_STANDARD, "Uninstalling firewall exception %S on port %d, protocol %d", pwzName, iPort, iProtocol);
432                hr = RemovePortException(iPort, iProtocol, fIgnoreFailures);
433                ExitOnFailure3(hr, "failed to remove port exception for name '%S' on port %d, protocol %d", pwzName, iPort, iProtocol);
434                break;
435            }
436            break;
437*/
438        case fetApplication:
439                        {
440                                std::wstring file = data.get_next_string();
441                                switch (iTodo)
442                                {
443                                case msi_helper::WCA_TODO_INSTALL:
444                                case msi_helper::WCA_TODO_REINSTALL:
445                                        h.logMessage(_T("Installing firewall exception: ") + name + _T(", ") + file);
446                                        AddApplicationException(file, name, remote_addr, fIgnoreFailures);
447                                        break;
448
449                                case msi_helper::WCA_TODO_UNINSTALL:
450                                        h.logMessage(_T("Uninstalling firewall exception: ") + name + _T(", ") + file);
451                                        RemoveApplicationException(file, fIgnoreFailures);
452                                        break;
453                                default:
454                                        h.logMessage(_T("IGNORING firewall exception: ") + name + _T(", ") + file);
455                                }
456                        }
457            break;
458                default:
459                        h.logMessage(_T("IGNORING (target) firewall exception: ") + name + _T(" Target is: ") + strEx::itos(target));
460        }
461    }
462    ::CoUninitialize();
463        } catch (installer_exception e) {
464                h.errorMessage(_T("Failed to install firewall exception: ") + e.what());
465                return ERROR_SUCCESS;
466        } catch (...) {
467                h.errorMessage(_T("Failed to install firewall exception: <UNKNOWN EXCEPTION>"));
468                return ERROR_INSTALL_FAILURE;
469        }
470        return ERROR_SUCCESS;
471}
Note: See TracBrowser for help on using the repository browser.