10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
20529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
30529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// found in the LICENSE file.
40529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/installer/util/advanced_firewall_manager_win.h"
60529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
70529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/guid.h"
80529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/logging.h"
90529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/strings/stringprintf.h"
100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/strings/utf_string_conversions.h"
110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/win/scoped_bstr.h"
120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/win/scoped_variant.h"
130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnamespace installer {
150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
160529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochAdvancedFirewallManager::AdvancedFirewallManager() {}
170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
180529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochAdvancedFirewallManager::~AdvancedFirewallManager() {}
190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool AdvancedFirewallManager::Init(const base::string16& app_name,
210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                   const base::FilePath& app_path) {
220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  firewall_rules_ = NULL;
230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  HRESULT hr = firewall_policy_.CreateInstance(CLSID_NetFwPolicy2);
240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (FAILED(hr)) {
250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    firewall_policy_ = NULL;
270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  hr = firewall_policy_->get_Rules(firewall_rules_.Receive());
300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (FAILED(hr)) {
310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    firewall_rules_ = NULL;
330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  app_name_ = app_name;
360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  app_path_ = app_path;
370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return true;
380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool AdvancedFirewallManager::IsFirewallEnabled() {
410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  long profile_types = 0;
420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  HRESULT hr = firewall_policy_->get_CurrentProfileTypes(&profile_types);
430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (FAILED(hr))
440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // The most-restrictive active profile takes precedence.
460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const NET_FW_PROFILE_TYPE2 kProfileTypes[] = {
470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    NET_FW_PROFILE2_PUBLIC,
480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    NET_FW_PROFILE2_PRIVATE,
490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    NET_FW_PROFILE2_DOMAIN
500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  };
510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (size_t i = 0; i < arraysize(kProfileTypes); ++i) {
520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if ((profile_types & kProfileTypes[i]) != 0) {
530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      VARIANT_BOOL enabled = VARIANT_TRUE;
540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      hr = firewall_policy_->get_FirewallEnabled(kProfileTypes[i], &enabled);
550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // Assume the firewall is enabled if we can't determine.
560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (FAILED(hr) || enabled != VARIANT_FALSE)
570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        return true;
580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return false;
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool AdvancedFirewallManager::HasAnyRule() {
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<base::win::ScopedComPtr<INetFwRule> > rules;
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  GetAllRules(&rules);
660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return !rules.empty();
670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool AdvancedFirewallManager::AddUDPRule(const base::string16& rule_name,
700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                         const base::string16& description,
710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                         uint16_t port) {
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Delete the rule. According MDSN |INetFwRules::Add| should replace rule with
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // same "rule identifier". It's not clear what is "rule identifier", but it
740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // can successfully create many rule with same name.
750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DeleteRuleByName(rule_name);
760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Create the rule and add it to the rule set (only succeeds if elevated).
780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::win::ScopedComPtr<INetFwRule> udp_rule =
790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      CreateUDPRule(rule_name, description, port);
800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!udp_rule.get())
810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  HRESULT hr = firewall_rules_->Add(udp_rule);
840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DLOG_IF(ERROR, FAILED(hr)) << logging::SystemErrorCodeToString(hr);
850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return SUCCEEDED(hr);
860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid AdvancedFirewallManager::DeleteRuleByName(
890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const base::string16& rule_name) {
900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<base::win::ScopedComPtr<INetFwRule> > rules;
910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  GetAllRules(&rules);
920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (size_t i = 0; i < rules.size(); ++i) {
930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::win::ScopedBstr name;
940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    HRESULT hr = rules[i]->get_Name(name.Receive());
950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (SUCCEEDED(hr) && name && base::string16(name) == rule_name) {
960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      DeleteRule(rules[i]);
970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid AdvancedFirewallManager::DeleteRule(
1020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::win::ScopedComPtr<INetFwRule> rule) {
1030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Rename rule to unique name and delete by unique name. We can't just delete
1040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // rule by name. Multiple rules with the same name and different app are
1050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // possible.
1060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::win::ScopedBstr unique_name(
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::UTF8ToUTF16(base::GenerateGUID()).c_str());
1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  rule->put_Name(unique_name);
1090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  firewall_rules_->Remove(unique_name);
1100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid AdvancedFirewallManager::DeleteAllRules() {
1130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<base::win::ScopedComPtr<INetFwRule> > rules;
1140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  GetAllRules(&rules);
1150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (size_t i = 0; i < rules.size(); ++i) {
1160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DeleteRule(rules[i]);
1170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbase::win::ScopedComPtr<INetFwRule> AdvancedFirewallManager::CreateUDPRule(
1210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const base::string16& rule_name,
1220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const base::string16& description,
1230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    uint16_t port) {
1240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::win::ScopedComPtr<INetFwRule> udp_rule;
1250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  HRESULT hr = udp_rule.CreateInstance(CLSID_NetFwRule);
1270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (FAILED(hr)) {
1280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
1290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return base::win::ScopedComPtr<INetFwRule>();
1300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  udp_rule->put_Name(base::win::ScopedBstr(rule_name.c_str()));
1330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  udp_rule->put_Description(base::win::ScopedBstr(description.c_str()));
1340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  udp_rule->put_ApplicationName(
1350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::win::ScopedBstr(app_path_.value().c_str()));
1360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  udp_rule->put_Protocol(NET_FW_IP_PROTOCOL_UDP);
1370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  udp_rule->put_Direction(NET_FW_RULE_DIR_IN);
1380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  udp_rule->put_Enabled(VARIANT_TRUE);
1390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  udp_rule->put_LocalPorts(
1400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::win::ScopedBstr(base::StringPrintf(L"%u", port).c_str()));
1410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  udp_rule->put_Grouping(base::win::ScopedBstr(app_name_.c_str()));
1420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  udp_rule->put_Profiles(NET_FW_PROFILE2_ALL);
1430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  udp_rule->put_Action(NET_FW_ACTION_ALLOW);
1440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return udp_rule;
1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid AdvancedFirewallManager::GetAllRules(
1490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<base::win::ScopedComPtr<INetFwRule> >* rules) {
1500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::win::ScopedComPtr<IUnknown> rules_enum_unknown;
1510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  HRESULT hr = firewall_rules_->get__NewEnum(rules_enum_unknown.Receive());
1520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (FAILED(hr)) {
1530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
1540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
1550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::win::ScopedComPtr<IEnumVARIANT> rules_enum;
1580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  hr = rules_enum.QueryFrom(rules_enum_unknown);
1590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (FAILED(hr)) {
1600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
1610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
1620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (;;) {
1650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::win::ScopedVariant rule_var;
1660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    hr = rules_enum->Next(1, rule_var.Receive(), NULL);
1670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DLOG_IF(ERROR, FAILED(hr)) << logging::SystemErrorCodeToString(hr);
1680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (hr != S_OK)
1690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      break;
1700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DCHECK_EQ(VT_DISPATCH, rule_var.type());
1710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (VT_DISPATCH != rule_var.type()) {
1720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      DLOG(ERROR) << "Unexpected type";
1730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      continue;
1740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
1750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::win::ScopedComPtr<INetFwRule> rule;
1760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    hr = rule.QueryFrom(V_DISPATCH(&rule_var));
1770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (FAILED(hr)) {
1780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      continue;
1800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::win::ScopedBstr path;
1830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    hr = rule->get_ApplicationName(path.Receive());
1840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (FAILED(hr)) {
1850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
1860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      continue;
1870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
1880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (!path ||
1900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        !base::FilePath::CompareEqualIgnoreCase(static_cast<BSTR>(path),
1910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                app_path_.value())) {
1920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      continue;
1930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
1940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    rules->push_back(rule);
1960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}  // namespace installer
200