Home | History | Annotate | Download | only in util
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/installer/util/advanced_firewall_manager_win.h"
      6 
      7 #include "base/guid.h"
      8 #include "base/logging.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "base/win/scoped_bstr.h"
     12 #include "base/win/scoped_variant.h"
     13 
     14 namespace installer {
     15 
     16 AdvancedFirewallManager::AdvancedFirewallManager() {}
     17 
     18 AdvancedFirewallManager::~AdvancedFirewallManager() {}
     19 
     20 bool AdvancedFirewallManager::Init(const base::string16& app_name,
     21                                    const base::FilePath& app_path) {
     22   firewall_rules_ = NULL;
     23   HRESULT hr = firewall_policy_.CreateInstance(CLSID_NetFwPolicy2);
     24   if (FAILED(hr)) {
     25     DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
     26     firewall_policy_ = NULL;
     27     return false;
     28   }
     29   hr = firewall_policy_->get_Rules(firewall_rules_.Receive());
     30   if (FAILED(hr)) {
     31     DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
     32     firewall_rules_ = NULL;
     33     return false;
     34   }
     35   app_name_ = app_name;
     36   app_path_ = app_path;
     37   return true;
     38 }
     39 
     40 bool AdvancedFirewallManager::IsFirewallEnabled() {
     41   long profile_types = 0;
     42   HRESULT hr = firewall_policy_->get_CurrentProfileTypes(&profile_types);
     43   if (FAILED(hr))
     44     return false;
     45   // The most-restrictive active profile takes precedence.
     46   const NET_FW_PROFILE_TYPE2 kProfileTypes[] = {
     47     NET_FW_PROFILE2_PUBLIC,
     48     NET_FW_PROFILE2_PRIVATE,
     49     NET_FW_PROFILE2_DOMAIN
     50   };
     51   for (size_t i = 0; i < arraysize(kProfileTypes); ++i) {
     52     if ((profile_types & kProfileTypes[i]) != 0) {
     53       VARIANT_BOOL enabled = VARIANT_TRUE;
     54       hr = firewall_policy_->get_FirewallEnabled(kProfileTypes[i], &enabled);
     55       // Assume the firewall is enabled if we can't determine.
     56       if (FAILED(hr) || enabled != VARIANT_FALSE)
     57         return true;
     58     }
     59   }
     60   return false;
     61 }
     62 
     63 bool AdvancedFirewallManager::HasAnyRule() {
     64   std::vector<base::win::ScopedComPtr<INetFwRule> > rules;
     65   GetAllRules(&rules);
     66   return !rules.empty();
     67 }
     68 
     69 bool AdvancedFirewallManager::AddUDPRule(const base::string16& rule_name,
     70                                          const base::string16& description,
     71                                          uint16_t port) {
     72   // Delete the rule. According MDSN |INetFwRules::Add| should replace rule with
     73   // same "rule identifier". It's not clear what is "rule identifier", but it
     74   // can successfully create many rule with same name.
     75   DeleteRuleByName(rule_name);
     76 
     77   // Create the rule and add it to the rule set (only succeeds if elevated).
     78   base::win::ScopedComPtr<INetFwRule> udp_rule =
     79       CreateUDPRule(rule_name, description, port);
     80   if (!udp_rule.get())
     81     return false;
     82 
     83   HRESULT hr = firewall_rules_->Add(udp_rule);
     84   DLOG_IF(ERROR, FAILED(hr)) << logging::SystemErrorCodeToString(hr);
     85   return SUCCEEDED(hr);
     86 }
     87 
     88 void AdvancedFirewallManager::DeleteRuleByName(
     89     const base::string16& rule_name) {
     90   std::vector<base::win::ScopedComPtr<INetFwRule> > rules;
     91   GetAllRules(&rules);
     92   for (size_t i = 0; i < rules.size(); ++i) {
     93     base::win::ScopedBstr name;
     94     HRESULT hr = rules[i]->get_Name(name.Receive());
     95     if (SUCCEEDED(hr) && name && base::string16(name) == rule_name) {
     96       DeleteRule(rules[i]);
     97     }
     98   }
     99 }
    100 
    101 void AdvancedFirewallManager::DeleteRule(
    102     base::win::ScopedComPtr<INetFwRule> rule) {
    103   // Rename rule to unique name and delete by unique name. We can't just delete
    104   // rule by name. Multiple rules with the same name and different app are
    105   // possible.
    106   base::win::ScopedBstr unique_name(
    107       base::UTF8ToUTF16(base::GenerateGUID()).c_str());
    108   rule->put_Name(unique_name);
    109   firewall_rules_->Remove(unique_name);
    110 }
    111 
    112 void AdvancedFirewallManager::DeleteAllRules() {
    113   std::vector<base::win::ScopedComPtr<INetFwRule> > rules;
    114   GetAllRules(&rules);
    115   for (size_t i = 0; i < rules.size(); ++i) {
    116     DeleteRule(rules[i]);
    117   }
    118 }
    119 
    120 base::win::ScopedComPtr<INetFwRule> AdvancedFirewallManager::CreateUDPRule(
    121     const base::string16& rule_name,
    122     const base::string16& description,
    123     uint16_t port) {
    124   base::win::ScopedComPtr<INetFwRule> udp_rule;
    125 
    126   HRESULT hr = udp_rule.CreateInstance(CLSID_NetFwRule);
    127   if (FAILED(hr)) {
    128     DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
    129     return base::win::ScopedComPtr<INetFwRule>();
    130   }
    131 
    132   udp_rule->put_Name(base::win::ScopedBstr(rule_name.c_str()));
    133   udp_rule->put_Description(base::win::ScopedBstr(description.c_str()));
    134   udp_rule->put_ApplicationName(
    135       base::win::ScopedBstr(app_path_.value().c_str()));
    136   udp_rule->put_Protocol(NET_FW_IP_PROTOCOL_UDP);
    137   udp_rule->put_Direction(NET_FW_RULE_DIR_IN);
    138   udp_rule->put_Enabled(VARIANT_TRUE);
    139   udp_rule->put_LocalPorts(
    140       base::win::ScopedBstr(base::StringPrintf(L"%u", port).c_str()));
    141   udp_rule->put_Grouping(base::win::ScopedBstr(app_name_.c_str()));
    142   udp_rule->put_Profiles(NET_FW_PROFILE2_ALL);
    143   udp_rule->put_Action(NET_FW_ACTION_ALLOW);
    144 
    145   return udp_rule;
    146 }
    147 
    148 void AdvancedFirewallManager::GetAllRules(
    149     std::vector<base::win::ScopedComPtr<INetFwRule> >* rules) {
    150   base::win::ScopedComPtr<IUnknown> rules_enum_unknown;
    151   HRESULT hr = firewall_rules_->get__NewEnum(rules_enum_unknown.Receive());
    152   if (FAILED(hr)) {
    153     DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
    154     return;
    155   }
    156 
    157   base::win::ScopedComPtr<IEnumVARIANT> rules_enum;
    158   hr = rules_enum.QueryFrom(rules_enum_unknown);
    159   if (FAILED(hr)) {
    160     DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
    161     return;
    162   }
    163 
    164   for (;;) {
    165     base::win::ScopedVariant rule_var;
    166     hr = rules_enum->Next(1, rule_var.Receive(), NULL);
    167     DLOG_IF(ERROR, FAILED(hr)) << logging::SystemErrorCodeToString(hr);
    168     if (hr != S_OK)
    169       break;
    170     DCHECK_EQ(VT_DISPATCH, rule_var.type());
    171     if (VT_DISPATCH != rule_var.type()) {
    172       DLOG(ERROR) << "Unexpected type";
    173       continue;
    174     }
    175     base::win::ScopedComPtr<INetFwRule> rule;
    176     hr = rule.QueryFrom(V_DISPATCH(&rule_var));
    177     if (FAILED(hr)) {
    178       DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
    179       continue;
    180     }
    181 
    182     base::win::ScopedBstr path;
    183     hr = rule->get_ApplicationName(path.Receive());
    184     if (FAILED(hr)) {
    185       DLOG(ERROR) << logging::SystemErrorCodeToString(hr);
    186       continue;
    187     }
    188 
    189     if (!path ||
    190         !base::FilePath::CompareEqualIgnoreCase(static_cast<BSTR>(path),
    191                                                 app_path_.value())) {
    192       continue;
    193     }
    194 
    195     rules->push_back(rule);
    196   }
    197 }
    198 
    199 }  // namespace installer
    200