| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/installer/util/advanced_firewall_manager_win.h" |
| |
| #include <objbase.h> |
| #include <stddef.h> |
| |
| #include "base/guid.h" |
| #include "base/logging.h" |
| #include "base/stl_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/win/scoped_bstr.h" |
| #include "base/win/scoped_variant.h" |
| |
| namespace installer { |
| |
| AdvancedFirewallManager::AdvancedFirewallManager() {} |
| |
| AdvancedFirewallManager::~AdvancedFirewallManager() {} |
| |
| bool AdvancedFirewallManager::Init(const base::string16& app_name, |
| const base::FilePath& app_path) { |
| firewall_rules_ = nullptr; |
| HRESULT hr = ::CoCreateInstance(CLSID_NetFwPolicy2, nullptr, CLSCTX_ALL, |
| IID_PPV_ARGS(&firewall_policy_)); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << logging::SystemErrorCodeToString(hr); |
| firewall_policy_ = nullptr; |
| return false; |
| } |
| hr = firewall_policy_->get_Rules(firewall_rules_.GetAddressOf()); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << logging::SystemErrorCodeToString(hr); |
| firewall_rules_ = nullptr; |
| return false; |
| } |
| app_name_ = app_name; |
| app_path_ = app_path; |
| return true; |
| } |
| |
| bool AdvancedFirewallManager::IsFirewallEnabled() { |
| long profile_types = 0; |
| HRESULT hr = firewall_policy_->get_CurrentProfileTypes(&profile_types); |
| if (FAILED(hr)) |
| return false; |
| // The most-restrictive active profile takes precedence. |
| const NET_FW_PROFILE_TYPE2 kProfileTypes[] = { |
| NET_FW_PROFILE2_PUBLIC, |
| NET_FW_PROFILE2_PRIVATE, |
| NET_FW_PROFILE2_DOMAIN |
| }; |
| for (size_t i = 0; i < base::size(kProfileTypes); ++i) { |
| if ((profile_types & kProfileTypes[i]) != 0) { |
| VARIANT_BOOL enabled = VARIANT_TRUE; |
| hr = firewall_policy_->get_FirewallEnabled(kProfileTypes[i], &enabled); |
| // Assume the firewall is enabled if we can't determine. |
| if (FAILED(hr) || enabled != VARIANT_FALSE) |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool AdvancedFirewallManager::HasAnyRule() { |
| std::vector<Microsoft::WRL::ComPtr<INetFwRule>> rules; |
| GetAllRules(&rules); |
| return !rules.empty(); |
| } |
| |
| bool AdvancedFirewallManager::AddUDPRule(const base::string16& rule_name, |
| const base::string16& description, |
| uint16_t port) { |
| // Delete the rule. According MDSN |INetFwRules::Add| should replace rule with |
| // same "rule identifier". It's not clear what is "rule identifier", but it |
| // can successfully create many rule with same name. |
| DeleteRuleByName(rule_name); |
| |
| // Create the rule and add it to the rule set (only succeeds if elevated). |
| Microsoft::WRL::ComPtr<INetFwRule> udp_rule = |
| CreateUDPRule(rule_name, description, port); |
| if (!udp_rule.Get()) |
| return false; |
| |
| HRESULT hr = firewall_rules_->Add(udp_rule.Get()); |
| DLOG_IF(ERROR, FAILED(hr)) << logging::SystemErrorCodeToString(hr); |
| return SUCCEEDED(hr); |
| } |
| |
| void AdvancedFirewallManager::DeleteRuleByName( |
| const base::string16& rule_name) { |
| std::vector<Microsoft::WRL::ComPtr<INetFwRule>> rules; |
| GetAllRules(&rules); |
| for (size_t i = 0; i < rules.size(); ++i) { |
| base::win::ScopedBstr name; |
| HRESULT hr = rules[i]->get_Name(name.Receive()); |
| if (SUCCEEDED(hr) && name && base::string16(name) == rule_name) { |
| DeleteRule(rules[i]); |
| } |
| } |
| } |
| |
| void AdvancedFirewallManager::DeleteRule( |
| Microsoft::WRL::ComPtr<INetFwRule> rule) { |
| // Rename rule to unique name and delete by unique name. We can't just delete |
| // rule by name. Multiple rules with the same name and different app are |
| // possible. |
| base::win::ScopedBstr unique_name(base::UTF8ToUTF16(base::GenerateGUID())); |
| rule->put_Name(unique_name); |
| firewall_rules_->Remove(unique_name); |
| } |
| |
| void AdvancedFirewallManager::DeleteAllRules() { |
| std::vector<Microsoft::WRL::ComPtr<INetFwRule>> rules; |
| GetAllRules(&rules); |
| for (size_t i = 0; i < rules.size(); ++i) { |
| DeleteRule(rules[i]); |
| } |
| } |
| |
| Microsoft::WRL::ComPtr<INetFwRule> AdvancedFirewallManager::CreateUDPRule( |
| const base::string16& rule_name, |
| const base::string16& description, |
| uint16_t port) { |
| Microsoft::WRL::ComPtr<INetFwRule> udp_rule; |
| |
| HRESULT hr = ::CoCreateInstance(CLSID_NetFwRule, nullptr, CLSCTX_ALL, |
| IID_PPV_ARGS(&udp_rule)); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << logging::SystemErrorCodeToString(hr); |
| return Microsoft::WRL::ComPtr<INetFwRule>(); |
| } |
| |
| udp_rule->put_Name(base::win::ScopedBstr(rule_name)); |
| udp_rule->put_Description(base::win::ScopedBstr(description)); |
| udp_rule->put_ApplicationName(base::win::ScopedBstr(app_path_.value())); |
| udp_rule->put_Protocol(NET_FW_IP_PROTOCOL_UDP); |
| udp_rule->put_Direction(NET_FW_RULE_DIR_IN); |
| udp_rule->put_Enabled(VARIANT_TRUE); |
| udp_rule->put_LocalPorts( |
| base::win::ScopedBstr(base::StringPrintf(L"%u", port))); |
| udp_rule->put_Grouping(base::win::ScopedBstr(app_name_)); |
| udp_rule->put_Profiles(NET_FW_PROFILE2_ALL); |
| udp_rule->put_Action(NET_FW_ACTION_ALLOW); |
| |
| return udp_rule; |
| } |
| |
| void AdvancedFirewallManager::GetAllRules( |
| std::vector<Microsoft::WRL::ComPtr<INetFwRule>>* rules) { |
| Microsoft::WRL::ComPtr<IUnknown> rules_enum_unknown; |
| HRESULT hr = firewall_rules_->get__NewEnum(rules_enum_unknown.GetAddressOf()); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << logging::SystemErrorCodeToString(hr); |
| return; |
| } |
| |
| Microsoft::WRL::ComPtr<IEnumVARIANT> rules_enum; |
| hr = rules_enum_unknown.CopyTo(rules_enum.GetAddressOf()); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << logging::SystemErrorCodeToString(hr); |
| return; |
| } |
| |
| for (;;) { |
| base::win::ScopedVariant rule_var; |
| hr = rules_enum->Next(1, rule_var.Receive(), NULL); |
| DLOG_IF(ERROR, FAILED(hr)) << logging::SystemErrorCodeToString(hr); |
| if (hr != S_OK) |
| break; |
| DCHECK_EQ(VT_DISPATCH, rule_var.type()); |
| if (VT_DISPATCH != rule_var.type()) { |
| DLOG(ERROR) << "Unexpected type"; |
| continue; |
| } |
| Microsoft::WRL::ComPtr<INetFwRule> rule; |
| hr = V_DISPATCH(rule_var.ptr())->QueryInterface(IID_PPV_ARGS(&rule)); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << logging::SystemErrorCodeToString(hr); |
| continue; |
| } |
| |
| base::win::ScopedBstr path; |
| hr = rule->get_ApplicationName(path.Receive()); |
| if (FAILED(hr)) { |
| DLOG(ERROR) << logging::SystemErrorCodeToString(hr); |
| continue; |
| } |
| |
| if (!path || |
| !base::FilePath::CompareEqualIgnoreCase(static_cast<BSTR>(path), |
| app_path_.value())) { |
| continue; |
| } |
| |
| rules->push_back(rule); |
| } |
| } |
| |
| } // namespace installer |