1/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/base/winfirewall.h"
29
30#include "talk/base/win32.h"
31
32#include <comdef.h>
33#include <netfw.h>
34
35#define RELEASE(lpUnk) do { \
36  if ((lpUnk) != NULL) { \
37    (lpUnk)->Release(); \
38    (lpUnk) = NULL; \
39  } \
40} while (0)
41
42namespace talk_base {
43
44//////////////////////////////////////////////////////////////////////
45// WinFirewall
46//////////////////////////////////////////////////////////////////////
47
48WinFirewall::WinFirewall() : mgr_(NULL), policy_(NULL), profile_(NULL) {
49}
50
51WinFirewall::~WinFirewall() {
52  Shutdown();
53}
54
55bool WinFirewall::Initialize(HRESULT* result) {
56  if (mgr_) {
57    if (result) {
58      *result = S_OK;
59    }
60    return true;
61  }
62
63  HRESULT hr = CoCreateInstance(__uuidof(NetFwMgr),
64                                0, CLSCTX_INPROC_SERVER,
65                                __uuidof(INetFwMgr),
66                                reinterpret_cast<void **>(&mgr_));
67  if (SUCCEEDED(hr) && (mgr_ != NULL))
68    hr = mgr_->get_LocalPolicy(&policy_);
69  if (SUCCEEDED(hr) && (policy_ != NULL))
70    hr = policy_->get_CurrentProfile(&profile_);
71
72  if (result)
73    *result = hr;
74  return SUCCEEDED(hr) && (profile_ != NULL);
75}
76
77void WinFirewall::Shutdown() {
78  RELEASE(profile_);
79  RELEASE(policy_);
80  RELEASE(mgr_);
81}
82
83bool WinFirewall::Enabled() const {
84  if (!profile_)
85    return false;
86
87  VARIANT_BOOL fwEnabled = VARIANT_FALSE;
88  profile_->get_FirewallEnabled(&fwEnabled);
89  return (fwEnabled != VARIANT_FALSE);
90}
91
92bool WinFirewall::QueryAuthorized(const char* filename, bool* authorized)
93    const {
94  return QueryAuthorizedW(ToUtf16(filename).c_str(), authorized);
95}
96
97bool WinFirewall::QueryAuthorizedW(const wchar_t* filename, bool* authorized)
98    const {
99  *authorized = false;
100  bool success = false;
101
102  if (!profile_)
103    return false;
104
105  _bstr_t bfilename = filename;
106
107  INetFwAuthorizedApplications* apps = NULL;
108  HRESULT hr = profile_->get_AuthorizedApplications(&apps);
109  if (SUCCEEDED(hr) && (apps != NULL)) {
110    INetFwAuthorizedApplication* app = NULL;
111    hr = apps->Item(bfilename, &app);
112    if (SUCCEEDED(hr) && (app != NULL)) {
113      VARIANT_BOOL fwEnabled = VARIANT_FALSE;
114      hr = app->get_Enabled(&fwEnabled);
115      app->Release();
116
117      if (SUCCEEDED(hr)) {
118        success = true;
119        *authorized = (fwEnabled != VARIANT_FALSE);
120      }
121    } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) {
122      // No entry in list of authorized apps
123      success = true;
124    } else {
125      // Unexpected error
126    }
127    apps->Release();
128  }
129
130  return success;
131}
132
133bool WinFirewall::AddApplication(const char* filename,
134                                 const char* friendly_name,
135                                 bool authorized,
136                                 HRESULT* result) {
137  return AddApplicationW(ToUtf16(filename).c_str(),
138      ToUtf16(friendly_name).c_str(), authorized, result);
139}
140
141bool WinFirewall::AddApplicationW(const wchar_t* filename,
142                                  const wchar_t* friendly_name,
143                                  bool authorized,
144                                  HRESULT* result) {
145  INetFwAuthorizedApplications* apps = NULL;
146  HRESULT hr = profile_->get_AuthorizedApplications(&apps);
147  if (SUCCEEDED(hr) && (apps != NULL)) {
148    INetFwAuthorizedApplication* app = NULL;
149    hr = CoCreateInstance(__uuidof(NetFwAuthorizedApplication),
150                          0, CLSCTX_INPROC_SERVER,
151                          __uuidof(INetFwAuthorizedApplication),
152                          reinterpret_cast<void **>(&app));
153    if (SUCCEEDED(hr) && (app != NULL)) {
154      _bstr_t bstr = filename;
155      hr = app->put_ProcessImageFileName(bstr);
156      bstr = friendly_name;
157      if (SUCCEEDED(hr))
158        hr = app->put_Name(bstr);
159      if (SUCCEEDED(hr))
160        hr = app->put_Enabled(authorized ? VARIANT_TRUE : VARIANT_FALSE);
161      if (SUCCEEDED(hr))
162        hr = apps->Add(app);
163      app->Release();
164    }
165    apps->Release();
166  }
167  if (result)
168    *result = hr;
169  return SUCCEEDED(hr);
170}
171
172}  // namespace talk_base
173