blob: 214ba25802272f9cb9c433ecd6ed76f00c0cec17 [file] [log] [blame]
// Copyright 2019 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 "chromeos/services/network_config/cros_network_config.h"
#include <vector>
#include "base/optional.h"
#include "base/strings/string_util.h"
#include "chromeos/components/sync_wifi/network_eligibility_checker.h"
#include "chromeos/login/login_state/login_state.h"
#include "chromeos/network/device_state.h"
#include "chromeos/network/managed_network_configuration_handler.h"
#include "chromeos/network/network_connection_handler.h"
#include "chromeos/network/network_device_handler.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_metadata_store.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/network_type_pattern.h"
#include "chromeos/network/network_util.h"
#include "chromeos/network/onc/onc_translation_tables.h"
#include "chromeos/network/prohibited_technologies_handler.h"
#include "chromeos/network/proxy/ui_proxy_config_service.h"
#include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config_mojom_traits.h"
#include "components/device_event_log/device_event_log.h"
#include "components/onc/onc_constants.h"
#include "components/user_manager/user_manager.h"
#include "net/base/ip_address.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
using user_manager::UserManager;
namespace chromeos {
namespace network_config {
namespace {
// Error strings from networking_private_api.cc. TODO(1004434): Enumerate
// these in mojo.
const char kErrorAccessToSharedConfig[] = "Error.CannotChangeSharedConfig";
const char kErrorInvalidONCConfiguration[] = "Error.InvalidONCConfiguration";
const char kErrorNetworkUnavailable[] = "Error.NetworkUnavailable";
const char kErrorNotReady[] = "Error.NotReady";
std::string ShillToOnc(const std::string& shill_string,
const onc::StringTranslationEntry table[]) {
std::string onc_string;
if (!shill_string.empty())
onc::TranslateStringToONC(table, shill_string, &onc_string);
return onc_string;
}
mojom::NetworkType NetworkPatternToMojo(NetworkTypePattern type) {
if (type.Equals(NetworkTypePattern::Cellular()))
return mojom::NetworkType::kCellular;
if (type.MatchesPattern(NetworkTypePattern::EthernetOrEthernetEAP()))
return mojom::NetworkType::kEthernet;
if (type.Equals(NetworkTypePattern::Tether()))
return mojom::NetworkType::kTether;
if (type.Equals(NetworkTypePattern::VPN()))
return mojom::NetworkType::kVPN;
if (type.Equals(NetworkTypePattern::WiFi()))
return mojom::NetworkType::kWiFi;
NOTREACHED() << "Unsupported network type: " << type.ToDebugString();
return mojom::NetworkType::kAll; // Unsupported
}
mojom::NetworkType ShillTypeToMojo(const std::string& shill_type) {
return NetworkPatternToMojo(NetworkTypePattern::Primitive(shill_type));
}
mojom::NetworkType OncTypeToMojo(const std::string& onc_type) {
return NetworkPatternToMojo(NetworkTypePattern::Primitive(
network_util::TranslateONCTypeToShill(onc_type)));
}
NetworkTypePattern MojoTypeToPattern(mojom::NetworkType type) {
switch (type) {
case mojom::NetworkType::kAll:
return NetworkTypePattern::Default();
case mojom::NetworkType::kCellular:
return NetworkTypePattern::Cellular();
case mojom::NetworkType::kEthernet:
return NetworkTypePattern::Ethernet();
case mojom::NetworkType::kMobile:
return NetworkTypePattern::Mobile();
case mojom::NetworkType::kTether:
return NetworkTypePattern::Tether();
case mojom::NetworkType::kVPN:
return NetworkTypePattern::VPN();
case mojom::NetworkType::kWireless:
return NetworkTypePattern::Wireless();
case mojom::NetworkType::kWiFi:
return NetworkTypePattern::WiFi();
}
NOTREACHED();
return NetworkTypePattern::Default();
}
std::string MojoNetworkTypeToOnc(mojom::NetworkType type) {
switch (type) {
case mojom::NetworkType::kAll:
case mojom::NetworkType::kMobile:
case mojom::NetworkType::kWireless:
break; // Not supported
case mojom::NetworkType::kCellular:
return ::onc::network_type::kCellular;
case mojom::NetworkType::kEthernet:
return ::onc::network_type::kEthernet;
case mojom::NetworkType::kTether:
return ::onc::network_type::kTether;
case mojom::NetworkType::kVPN:
return ::onc::network_type::kVPN;
case mojom::NetworkType::kWiFi:
return ::onc::network_type::kWiFi;
}
NOTREACHED() << "Unsupported mojo to ONC type: " << type;
return std::string();
}
mojom::ConnectionStateType GetMojoConnectionStateType(
const NetworkState* network) {
if (network->IsConnectedState()) {
if (network->IsCaptivePortal())
return mojom::ConnectionStateType::kPortal;
if (network->IsOnline())
return mojom::ConnectionStateType::kOnline;
return mojom::ConnectionStateType::kConnected;
}
if (network->IsConnectingState())
return mojom::ConnectionStateType::kConnecting;
return mojom::ConnectionStateType::kNotConnected;
}
mojom::ConnectionStateType GetConnectionState(const NetworkState* network,
bool technology_enabled) {
// If a network technology is not enabled, always use NotConnected as the
// connection state to avoid any edge cases during device enable/disable.
return technology_enabled ? GetMojoConnectionStateType(network)
: mojom::ConnectionStateType::kNotConnected;
}
std::string MojoSecurityTypeToOnc(mojom::SecurityType security_type) {
switch (security_type) {
case mojom::SecurityType::kNone:
return ::onc::wifi::kSecurityNone;
case mojom::SecurityType::kWep8021x:
return ::onc::wifi::kWEP_8021X;
case mojom::SecurityType::kWepPsk:
return ::onc::wifi::kWEP_PSK;
case mojom::SecurityType::kWpaEap:
return ::onc::wifi::kWPA_EAP;
case mojom::SecurityType::kWpaPsk:
return ::onc::wifi::kWPA_PSK;
}
NOTREACHED() << "Unsupported mojo to ONC type: " << security_type;
return std::string();
}
mojom::VpnType OncVpnTypeToMojo(const std::string& onc_vpn_type) {
if (onc_vpn_type == ::onc::vpn::kTypeL2TP_IPsec)
return mojom::VpnType::kL2TPIPsec;
if (onc_vpn_type == ::onc::vpn::kOpenVPN)
return mojom::VpnType::kOpenVPN;
if (onc_vpn_type == ::onc::vpn::kThirdPartyVpn)
return mojom::VpnType::kExtension;
if (onc_vpn_type == ::onc::vpn::kArcVpn)
return mojom::VpnType::kArc;
NOTREACHED() << "Unsupported ONC VPN type: " << onc_vpn_type;
return mojom::VpnType::kOpenVPN;
}
std::string MojoVpnTypeToOnc(mojom::VpnType mojo_vpn_type) {
switch (mojo_vpn_type) {
case mojom::VpnType::kL2TPIPsec:
return ::onc::vpn::kTypeL2TP_IPsec;
case mojom::VpnType::kOpenVPN:
return ::onc::vpn::kOpenVPN;
case mojom::VpnType::kExtension:
return ::onc::vpn::kThirdPartyVpn;
case mojom::VpnType::kArc:
return ::onc::vpn::kArcVpn;
}
NOTREACHED();
return ::onc::vpn::kOpenVPN;
}
bool GetIsConfiguredByUser(const std::string& network_guid) {
if (!NetworkHandler::IsInitialized())
return false;
NetworkMetadataStore* network_metadata_store =
NetworkHandler::Get()->network_metadata_store();
if (!network_metadata_store)
return false;
return network_metadata_store->GetIsCreatedByUser(network_guid);
}
mojom::DeviceStateType GetMojoDeviceStateType(
NetworkStateHandler::TechnologyState technology_state) {
switch (technology_state) {
case NetworkStateHandler::TECHNOLOGY_UNAVAILABLE:
return mojom::DeviceStateType::kUnavailable;
case NetworkStateHandler::TECHNOLOGY_UNINITIALIZED:
return mojom::DeviceStateType::kUninitialized;
case NetworkStateHandler::TECHNOLOGY_AVAILABLE:
return mojom::DeviceStateType::kDisabled;
case NetworkStateHandler::TECHNOLOGY_DISABLING:
return mojom::DeviceStateType::kDisabling;
case NetworkStateHandler::TECHNOLOGY_ENABLING:
return mojom::DeviceStateType::kEnabling;
case NetworkStateHandler::TECHNOLOGY_ENABLED:
return mojom::DeviceStateType::kEnabled;
case NetworkStateHandler::TECHNOLOGY_PROHIBITED:
return mojom::DeviceStateType::kProhibited;
}
NOTREACHED();
return mojom::DeviceStateType::kUnavailable;
}
mojom::PortalState GetMojoPortalState(
const NetworkState::PortalState portal_state) {
switch (portal_state) {
case NetworkState::PortalState::kUnknown:
return mojom::PortalState::kUnknown;
case NetworkState::PortalState::kOnline:
return mojom::PortalState::kOnline;
case NetworkState::PortalState::kPortalSuspected:
return mojom::PortalState::kPortalSuspected;
case NetworkState::PortalState::kPortal:
return mojom::PortalState::kPortal;
case NetworkState::PortalState::kProxyAuthRequired:
return mojom::PortalState::kProxyAuthRequired;
case NetworkState::PortalState::kNoInternet:
return mojom::PortalState::kNoInternet;
}
NOTREACHED();
return mojom::PortalState::kUnknown;
}
mojom::OncSource GetMojoOncSource(const NetworkState* network) {
::onc::ONCSource source = network->onc_source();
switch (source) {
case ::onc::ONC_SOURCE_UNKNOWN:
case ::onc::ONC_SOURCE_NONE:
if (!network->IsInProfile())
return mojom::OncSource::kNone;
return network->IsPrivate() ? mojom::OncSource::kUser
: mojom::OncSource::kDevice;
case ::onc::ONC_SOURCE_USER_IMPORT:
return mojom::OncSource::kUser;
case ::onc::ONC_SOURCE_DEVICE_POLICY:
return mojom::OncSource::kDevicePolicy;
case ::onc::ONC_SOURCE_USER_POLICY:
return mojom::OncSource::kUserPolicy;
}
NOTREACHED();
return mojom::OncSource::kNone;
}
const std::string& GetVpnProviderName(
const std::vector<mojom::VpnProviderPtr>& vpn_providers,
const std::string& provider_id) {
for (const mojom::VpnProviderPtr& provider : vpn_providers) {
if (provider->provider_id == provider_id)
return provider->provider_name;
}
return base::EmptyString();
}
bool IsVpnProhibited() {
bool vpn_prohibited = false;
if (NetworkHandler::IsInitialized()) {
std::vector<std::string> prohibited_technologies =
NetworkHandler::Get()
->prohibited_technologies_handler()
->GetCurrentlyProhibitedTechnologies();
vpn_prohibited = base::Contains(prohibited_technologies, shill::kTypeVPN);
}
return vpn_prohibited;
}
mojom::DeviceStatePropertiesPtr GetVpnState() {
auto result = mojom::DeviceStateProperties::New();
result->type = mojom::NetworkType::kVPN;
result->device_state = IsVpnProhibited() ? mojom::DeviceStateType::kProhibited
: mojom::DeviceStateType::kEnabled;
return result;
}
mojom::NetworkStatePropertiesPtr NetworkStateToMojo(
NetworkStateHandler* network_state_handler,
const std::vector<mojom::VpnProviderPtr>& vpn_providers,
const NetworkState* network) {
mojom::NetworkType type = ShillTypeToMojo(network->type());
if (type == mojom::NetworkType::kAll) {
NET_LOG(ERROR) << "Unexpected network type: " << network->type()
<< " GUID: " << network->guid();
return nullptr;
}
auto result = mojom::NetworkStateProperties::New();
result->type = type;
result->connectable = network->connectable();
if (type == mojom::NetworkType::kCellular) {
// Ensure that a cellular network that has a locked sim state or is scanning
// is not connectable.
const DeviceState* device =
network_state_handler->GetDeviceState(network->device_path());
if (!device) {
// When a device is removed or SIM is replaced, the Shill Service may
// outlive the Device. Such services are not connectable.
NET_LOG(DEBUG) << "Cellular device is not available: "
<< network->device_path();
result->connectable = false;
} else if (device->IsSimLocked() || device->scanning()) {
result->connectable = false;
}
}
result->connect_requested = network->connect_requested();
bool technology_enabled = network->Matches(NetworkTypePattern::VPN()) ||
network_state_handler->IsTechnologyEnabled(
NetworkTypePattern::Primitive(network->type()));
result->connection_state = GetConnectionState(network, technology_enabled);
if (!network->GetError().empty())
result->error_state = network->GetError();
result->guid = network->guid();
result->name = network->name();
result->portal_state = GetMojoPortalState(network->portal_state());
result->priority = network->priority();
result->prohibited_by_policy = network->blocked_by_policy();
result->source = GetMojoOncSource(network);
result->proxy_mode =
NetworkHandler::HasUiProxyConfigService()
? mojom::ProxyMode(
NetworkHandler::GetUiProxyConfigService()->ProxyModeForNetwork(
network))
: mojom::ProxyMode::kDirect;
switch (type) {
case mojom::NetworkType::kCellular: {
auto cellular = mojom::CellularStateProperties::New();
cellular->activation_state = network->GetMojoActivationState();
cellular->network_technology = ShillToOnc(network->network_technology(),
onc::kNetworkTechnologyTable);
cellular->roaming = network->IndicateRoaming();
cellular->signal_strength = network->signal_strength();
const DeviceState* cellular_device =
network_state_handler->GetDeviceState(network->device_path());
cellular->sim_locked = cellular_device && cellular_device->IsSimLocked();
result->type_state =
mojom::NetworkTypeStateProperties::NewCellular(std::move(cellular));
break;
}
case mojom::NetworkType::kEthernet: {
auto ethernet = mojom::EthernetStateProperties::New();
ethernet->authentication = network->type() == shill::kTypeEthernetEap
? mojom::AuthenticationType::k8021x
: mojom::AuthenticationType::kNone;
result->type_state =
mojom::NetworkTypeStateProperties::NewEthernet(std::move(ethernet));
break;
}
case mojom::NetworkType::kTether: {
auto tether = mojom::TetherStateProperties::New();
tether->battery_percentage = network->battery_percentage();
tether->carrier = network->tether_carrier();
tether->has_connected_to_host = network->tether_has_connected_to_host();
tether->signal_strength = network->signal_strength();
result->type_state =
mojom::NetworkTypeStateProperties::NewTether(std::move(tether));
break;
}
case mojom::NetworkType::kVPN: {
auto vpn = mojom::VPNStateProperties::New();
const NetworkState::VpnProviderInfo* vpn_provider =
network->vpn_provider();
if (vpn_provider) {
vpn->type = OncVpnTypeToMojo(
ShillToOnc(vpn_provider->type, onc::kVPNTypeTable));
vpn->provider_id = vpn_provider->id;
vpn->provider_name =
GetVpnProviderName(vpn_providers, vpn_provider->id);
}
result->type_state =
mojom::NetworkTypeStateProperties::NewVpn(std::move(vpn));
break;
}
case mojom::NetworkType::kWiFi: {
auto wifi = mojom::WiFiStateProperties::New();
wifi->bssid = network->bssid();
wifi->frequency = network->frequency();
wifi->hex_ssid = network->GetHexSsid();
wifi->security = network->GetMojoSecurity();
wifi->signal_strength = network->signal_strength();
wifi->ssid = network->name();
result->type_state =
mojom::NetworkTypeStateProperties::NewWifi(std::move(wifi));
break;
}
case mojom::NetworkType::kAll:
case mojom::NetworkType::kMobile:
case mojom::NetworkType::kWireless:
NOTREACHED() << "NetworkStateProperties can not be of type: " << type;
break;
}
return result;
}
mojom::DeviceStatePropertiesPtr DeviceStateToMojo(
const DeviceState* device,
mojom::DeviceStateType technology_state) {
mojom::NetworkType type = ShillTypeToMojo(device->type());
if (type == mojom::NetworkType::kAll) {
NET_LOG(ERROR) << "Unexpected device type: " << device->type()
<< " path: " << device->path();
return nullptr;
}
auto result = mojom::DeviceStateProperties::New();
result->type = type;
net::IPAddress ipv4_address;
if (ipv4_address.AssignFromIPLiteral(
device->GetIpAddressByType(shill::kTypeIPv4))) {
result->ipv4_address = ipv4_address;
}
net::IPAddress ipv6_address;
if (ipv6_address.AssignFromIPLiteral(
device->GetIpAddressByType(shill::kTypeIPv6))) {
result->ipv6_address = ipv6_address;
}
result->mac_address =
network_util::FormattedMacAddress(device->mac_address());
result->scanning = device->scanning();
result->device_state = technology_state;
result->managed_network_available =
!device->available_managed_network_path().empty();
result->sim_absent = device->IsSimAbsent();
if (device->sim_present()) {
auto sim_lock_status = mojom::SIMLockStatus::New();
sim_lock_status->lock_type = device->sim_lock_type();
sim_lock_status->lock_enabled = device->sim_lock_enabled();
sim_lock_status->retries_left = device->sim_retries_left();
result->sim_lock_status = std::move(sim_lock_status);
}
return result;
}
void SetValueIfKeyPresent(const base::Value* dict,
const char* key,
base::Value* out) {
const base::Value* v = dict->FindKey(key);
if (v)
*out = v->Clone();
}
base::Optional<std::string> GetString(const base::Value* dict,
const char* key) {
const base::Value* v = dict->FindKey(key);
if (v && !v->is_string()) {
NET_LOG(ERROR) << "Expected string, found: " << *v;
return base::nullopt;
}
return v ? base::make_optional<std::string>(v->GetString()) : base::nullopt;
}
std::string GetRequiredString(const base::Value* dict, const char* key) {
const base::Value* v = dict->FindKey(key);
if (!v) {
NOTREACHED() << "Required key missing: " << key;
return std::string();
}
if (!v->is_string()) {
NET_LOG(ERROR) << "Expected string, found: " << *v;
return std::string();
}
return v->GetString();
}
bool GetBoolean(const base::Value* dict, const char* key) {
const base::Value* v = dict->FindKey(key);
if (v && !v->is_bool()) {
NET_LOG(ERROR) << "Expected bool, found: " << *v;
return false;
}
return v ? v->GetBool() : false;
}
int32_t GetInt32(const base::Value* dict, const char* key) {
const base::Value* v = dict->FindKey(key);
if (v && !v->is_int()) {
NET_LOG(ERROR) << "Expected int, found: " << *v;
return false;
}
return v ? v->GetInt() : false;
}
std::vector<int32_t> GetInt32List(const base::Value* dict, const char* key) {
std::vector<int32_t> result;
const base::Value* v = dict->FindKey(key);
if (v && !v->is_list()) {
NET_LOG(ERROR) << "Expected list, found: " << *v;
return result;
}
if (v) {
for (const base::Value& e : v->GetList())
result.push_back(e.GetInt());
}
return result;
}
const base::Value* GetDictionary(const base::Value* dict, const char* key) {
const base::Value* v = dict->FindKey(key);
if (v && !v->is_dict()) {
NET_LOG(ERROR) << "Expected dictionary, found: " << *v;
return nullptr;
}
return v;
}
base::Optional<std::vector<std::string>> GetStringList(const base::Value* dict,
const char* key) {
const base::Value* v = dict->FindKey(key);
if (!v)
return base::nullopt;
if (!v->is_list()) {
NET_LOG(ERROR) << "Expected list, found: " << *v;
return base::nullopt;
}
std::vector<std::string> result;
for (const base::Value& e : v->GetList())
result.push_back(e.GetString());
return result;
}
void SetString(const char* key,
const base::Optional<std::string>& property,
base::Value* dict) {
if (!property)
return;
dict->SetStringKey(key, *property);
}
void SetStringIfNotEmpty(const char* key,
const base::Optional<std::string>& property,
base::Value* dict) {
if (!property || property->empty())
return;
dict->SetStringKey(key, *property);
}
void SetStringList(const char* key,
const base::Optional<std::vector<std::string>>& property,
base::Value* dict) {
if (!property)
return;
base::Value list(base::Value::Type::LIST);
for (const std::string& s : *property)
list.Append(base::Value(s));
dict->SetKey(key, std::move(list));
}
// GetManagedDictionary() returns a ManagedDictionary representing the active
// and policy values for a managed property. The types of |active_value| and
// |policy_value| are expected to match the ONC signature for the property type.
struct ManagedDictionary {
base::Value active_value;
mojom::PolicySource policy_source = mojom::PolicySource::kNone;
base::Value policy_value;
};
ManagedDictionary GetManagedDictionary(const base::Value* onc_dict) {
ManagedDictionary result;
// When available, the active value (i.e. the value from Shill) is used.
SetValueIfKeyPresent(onc_dict, ::onc::kAugmentationActiveSetting,
&result.active_value);
base::Optional<std::string> effective =
GetString(onc_dict, ::onc::kAugmentationEffectiveSetting);
if (!effective)
return result;
// If no active value is set (e.g. the network is not visible), use the
// effective value.
if (result.active_value.is_none())
SetValueIfKeyPresent(onc_dict, effective->c_str(), &result.active_value);
if (result.active_value.is_none()) {
// No active or effective value, return a default dictionary.
return result;
}
// If the effective value is set by an extension, use kActiveExtension.
if (effective == ::onc::kAugmentationActiveExtension) {
result.policy_source = mojom::PolicySource::kActiveExtension;
result.policy_value = result.active_value.Clone();
return result;
}
// Set policy properties based on the effective source and policies.
// NOTE: This does not enforce valid ONC. See onc_merger.cc for details.
const base::Value* user_policy =
onc_dict->FindKey(::onc::kAugmentationUserPolicy);
const base::Value* device_policy =
onc_dict->FindKey(::onc::kAugmentationDevicePolicy);
bool user_enforced = !GetBoolean(onc_dict, ::onc::kAugmentationUserEditable);
bool device_enforced =
!GetBoolean(onc_dict, ::onc::kAugmentationDeviceEditable);
if (effective == ::onc::kAugmentationUserPolicy ||
(user_policy && effective != ::onc::kAugmentationDevicePolicy)) {
// Set the policy source to "User" when:
// * The effective value is set to "UserPolicy" OR
// * A User policy exists and the effective value is not "DevicePolicy",
// i.e. no enforced device policy is overriding a recommended user policy.
result.policy_source = user_enforced
? mojom::PolicySource::kUserPolicyEnforced
: mojom::PolicySource::kUserPolicyRecommended;
if (user_policy)
result.policy_value = user_policy->Clone();
} else if (effective == ::onc::kAugmentationDevicePolicy || device_policy) {
// Set the policy source to "Device" when:
// * The effective value is set to "DevicePolicy" OR
// * A Device policy exists (since we checked for a user policy first).
result.policy_source = device_enforced
? mojom::PolicySource::kDevicePolicyEnforced
: mojom::PolicySource::kDevicePolicyRecommended;
if (device_policy)
result.policy_value = device_policy->Clone();
} else if (effective == ::onc::kAugmentationUserSetting ||
effective == ::onc::kAugmentationSharedSetting) {
// User or shared setting, no policy source.
} else {
// Unexpected ONC. No policy source or value will be set.
NET_LOG(ERROR) << "Unexpected ONC property: " << *onc_dict;
}
DCHECK(result.policy_value.is_none() ||
result.policy_value.type() == result.active_value.type());
return result;
}
mojom::ManagedStringPtr GetManagedString(const base::Value* dict,
const char* key) {
const base::Value* v = dict->FindKey(key);
if (!v)
return nullptr;
if (v->is_string()) {
auto result = mojom::ManagedString::New();
result->active_value = v->GetString();
return result;
}
if (v->is_dict()) {
ManagedDictionary managed_dict = GetManagedDictionary(v);
if (!managed_dict.active_value.is_string()) {
NET_LOG(ERROR) << "No active or effective value for: " << key;
return nullptr;
}
auto result = mojom::ManagedString::New();
result->active_value = managed_dict.active_value.GetString();
result->policy_source = managed_dict.policy_source;
if (!managed_dict.policy_value.is_none())
result->policy_value = managed_dict.policy_value.GetString();
return result;
}
NET_LOG(ERROR) << "Expected string or dictionary, found: " << *v;
return nullptr;
}
mojom::ManagedStringPtr GetRequiredManagedString(const base::Value* dict,
const char* key) {
mojom::ManagedStringPtr result = GetManagedString(dict, key);
if (!result) {
// Return an empty string with no policy source.
result = mojom::ManagedString::New();
}
return result;
}
mojom::ManagedStringListPtr GetManagedStringList(const base::Value* dict,
const char* key) {
const base::Value* v = dict->FindKey(key);
if (!v)
return nullptr;
if (v->is_list()) {
auto result = mojom::ManagedStringList::New();
std::vector<std::string> active;
for (const base::Value& e : v->GetList())
active.push_back(e.GetString());
result->active_value = std::move(active);
return result;
}
if (v->is_dict()) {
ManagedDictionary managed_dict = GetManagedDictionary(v);
if (!managed_dict.active_value.is_list()) {
NET_LOG(ERROR) << "No active or effective value for: " << key;
return nullptr;
}
auto result = mojom::ManagedStringList::New();
for (const base::Value& e : managed_dict.active_value.GetList())
result->active_value.push_back(e.GetString());
result->policy_source = managed_dict.policy_source;
if (!managed_dict.policy_value.is_none()) {
result->policy_value = std::vector<std::string>();
for (const base::Value& e : managed_dict.policy_value.GetList())
result->policy_value->push_back(e.GetString());
}
return result;
}
NET_LOG(ERROR) << "Expected list or dictionary, found: " << *v;
return nullptr;
}
mojom::ManagedBooleanPtr GetManagedBoolean(const base::Value* dict,
const char* key) {
const base::Value* v = dict->FindKey(key);
if (!v)
return nullptr;
if (v->is_bool()) {
auto result = mojom::ManagedBoolean::New();
result->active_value = v->GetBool();
return result;
}
if (v->is_dict()) {
ManagedDictionary managed_dict = GetManagedDictionary(v);
if (!managed_dict.active_value.is_bool()) {
NET_LOG(ERROR) << "No active or effective value for: " << key;
return nullptr;
}
auto result = mojom::ManagedBoolean::New();
result->active_value = managed_dict.active_value.GetBool();
result->policy_source = managed_dict.policy_source;
if (!managed_dict.policy_value.is_none())
result->policy_value = managed_dict.policy_value.GetBool();
return result;
}
NET_LOG(ERROR) << "Expected bool or dictionary, found: " << *v;
return nullptr;
}
mojom::ManagedInt32Ptr GetManagedInt32(const base::Value* dict,
const char* key) {
const base::Value* v = dict->FindKey(key);
if (!v)
return nullptr;
if (v->is_int()) {
auto result = mojom::ManagedInt32::New();
result->active_value = v->GetInt();
return result;
}
if (v->is_dict()) {
ManagedDictionary managed_dict = GetManagedDictionary(v);
if (!managed_dict.active_value.is_int()) {
NET_LOG(ERROR) << "No active or effective value for: " << key;
return nullptr;
}
auto result = mojom::ManagedInt32::New();
result->active_value = managed_dict.active_value.GetInt();
result->policy_source = managed_dict.policy_source;
if (!managed_dict.policy_value.is_none())
result->policy_value = managed_dict.policy_value.GetInt();
return result;
}
NET_LOG(ERROR) << "Expected int or dictionary, found: " << *v;
return nullptr;
}
mojom::IPConfigPropertiesPtr GetIPConfig(const base::Value* dict) {
auto ip_config = mojom::IPConfigProperties::New();
ip_config->gateway = GetString(dict, ::onc::ipconfig::kGateway);
ip_config->ip_address = GetString(dict, ::onc::ipconfig::kIPAddress);
ip_config->excluded_routes =
GetStringList(dict, ::onc::ipconfig::kExcludedRoutes);
ip_config->included_routes =
GetStringList(dict, ::onc::ipconfig::kIncludedRoutes);
ip_config->name_servers = GetStringList(dict, ::onc::ipconfig::kNameServers);
ip_config->search_domains =
GetStringList(dict, ::onc::ipconfig::kSearchDomains);
ip_config->routing_prefix = GetInt32(dict, ::onc::ipconfig::kRoutingPrefix);
ip_config->type = GetString(dict, ::onc::ipconfig::kType);
// Shill may omit the IP Config type for VPNs. The type should be IPv4.
if (!ip_config->type || ip_config->type->empty())
ip_config->type = ::onc::ipconfig::kIPv4;
ip_config->web_proxy_auto_discovery_url =
GetString(dict, ::onc::ipconfig::kWebProxyAutoDiscoveryUrl);
return ip_config;
}
mojom::ManagedIPConfigPropertiesPtr GetManagedIPConfig(
const base::Value* dict) {
auto ip_config = mojom::ManagedIPConfigProperties::New();
ip_config->gateway = GetManagedString(dict, ::onc::ipconfig::kGateway);
ip_config->ip_address = GetManagedString(dict, ::onc::ipconfig::kIPAddress);
ip_config->name_servers =
GetManagedStringList(dict, ::onc::ipconfig::kNameServers);
ip_config->routing_prefix =
GetManagedInt32(dict, ::onc::ipconfig::kRoutingPrefix);
ip_config->type = GetManagedString(dict, ::onc::ipconfig::kType);
ip_config->web_proxy_auto_discovery_url =
GetManagedString(dict, ::onc::ipconfig::kWebProxyAutoDiscoveryUrl);
return ip_config;
}
mojom::ManagedProxyLocationPtr GetManagedProxyLocation(const base::Value* dict,
const char* key) {
const base::Value* location_dict = GetDictionary(dict, key);
if (!location_dict)
return nullptr;
auto proxy_location = mojom::ManagedProxyLocation::New();
proxy_location->host =
GetRequiredManagedString(location_dict, ::onc::proxy::kHost);
proxy_location->port = GetManagedInt32(location_dict, ::onc::proxy::kPort);
if (!proxy_location->port) {
NET_LOG(ERROR) << "ProxyLocation: No port: " << *location_dict;
return nullptr;
}
return proxy_location;
}
void SetProxyLocation(const char* key,
const mojom::ProxyLocationPtr& location,
base::Value* dict) {
if (location.is_null())
return;
base::Value location_dict(base::Value::Type::DICTIONARY);
location_dict.SetStringKey(::onc::proxy::kHost, location->host);
location_dict.SetIntKey(::onc::proxy::kPort, location->port);
dict->SetKey(key, std::move(location_dict));
}
mojom::ManagedProxySettingsPtr GetManagedProxySettings(
const base::Value* dict) {
auto proxy_settings = mojom::ManagedProxySettings::New();
proxy_settings->type = GetRequiredManagedString(dict, ::onc::proxy::kType);
const base::Value* manual_dict = GetDictionary(dict, ::onc::proxy::kManual);
if (manual_dict) {
auto manual_proxy_settings = mojom::ManagedManualProxySettings::New();
manual_proxy_settings->http_proxy =
GetManagedProxyLocation(manual_dict, ::onc::proxy::kHttp);
manual_proxy_settings->secure_http_proxy =
GetManagedProxyLocation(manual_dict, ::onc::proxy::kHttps);
manual_proxy_settings->ftp_proxy =
GetManagedProxyLocation(manual_dict, ::onc::proxy::kFtp);
manual_proxy_settings->socks =
GetManagedProxyLocation(manual_dict, ::onc::proxy::kSocks);
proxy_settings->manual = std::move(manual_proxy_settings);
}
proxy_settings->exclude_domains =
GetManagedStringList(dict, ::onc::proxy::kExcludeDomains);
proxy_settings->pac = GetManagedString(dict, ::onc::proxy::kPAC);
return proxy_settings;
}
mojom::ApnPropertiesPtr GetApnProperties(const base::Value* dict) {
auto apn = mojom::ApnProperties::New();
apn->access_point_name =
GetRequiredString(dict, ::onc::cellular_apn::kAccessPointName);
apn->authentication = GetString(dict, ::onc::cellular_apn::kAuthentication);
apn->language = GetString(dict, ::onc::cellular_apn::kLanguage);
apn->localized_name = GetString(dict, ::onc::cellular_apn::kLocalizedName);
apn->name = GetString(dict, ::onc::cellular_apn::kName);
apn->password = GetString(dict, ::onc::cellular_apn::kPassword);
apn->username = GetString(dict, ::onc::cellular_apn::kUsername);
return apn;
}
mojom::ManagedApnPropertiesPtr GetManagedApnProperties(const base::Value* dict,
const char* key) {
const base::Value* apn_dict = dict->FindKey(key);
if (!apn_dict)
return nullptr;
if (!apn_dict->is_dict()) {
NET_LOG(ERROR) << "Expected dictionary, found: " << *apn_dict;
return nullptr;
}
auto apn = mojom::ManagedApnProperties::New();
apn->access_point_name =
GetRequiredManagedString(apn_dict, ::onc::cellular_apn::kAccessPointName);
CHECK(apn->access_point_name);
apn->authentication =
GetManagedString(apn_dict, ::onc::cellular_apn::kAuthentication);
apn->language = GetManagedString(apn_dict, ::onc::cellular_apn::kLanguage);
apn->localized_name =
GetManagedString(apn_dict, ::onc::cellular_apn::kLocalizedName);
apn->name = GetManagedString(apn_dict, ::onc::cellular_apn::kName);
apn->password = GetManagedString(apn_dict, ::onc::cellular_apn::kPassword);
apn->username = GetManagedString(apn_dict, ::onc::cellular_apn::kUsername);
return apn;
}
mojom::ManagedApnListPtr GetManagedApnList(const base::Value* value) {
if (!value)
return nullptr;
if (value->is_list()) {
auto result = mojom::ManagedApnList::New();
std::vector<mojom::ApnPropertiesPtr> active;
for (const base::Value& value : value->GetList())
active.push_back(GetApnProperties(&value));
result->active_value = std::move(active);
return result;
} else if (value->is_dict()) {
ManagedDictionary managed_dict = GetManagedDictionary(value);
if (!managed_dict.active_value.is_list()) {
NET_LOG(ERROR) << "No active or effective value for APNList";
return nullptr;
}
auto result = mojom::ManagedApnList::New();
for (const base::Value& e : managed_dict.active_value.GetList())
result->active_value.push_back(GetApnProperties(&e));
result->policy_source = managed_dict.policy_source;
if (!managed_dict.policy_value.is_none()) {
result->policy_value = std::vector<mojom::ApnPropertiesPtr>();
for (const base::Value& e : managed_dict.policy_value.GetList())
result->policy_value->push_back(GetApnProperties(&e));
}
return result;
}
NET_LOG(ERROR) << "Expected list or dictionary, found: " << *value;
return nullptr;
}
std::vector<mojom::FoundNetworkPropertiesPtr> GetFoundNetworksList(
const base::Value* dict,
const char* key) {
std::vector<mojom::FoundNetworkPropertiesPtr> result;
const base::Value* v = dict->FindKey(key);
if (!v)
return result;
if (!v->is_list()) {
NET_LOG(ERROR) << "Expected list, found: " << *v;
return result;
}
for (const base::Value& e : v->GetList()) {
auto found_network = mojom::FoundNetworkProperties::New();
found_network->status =
GetRequiredString(&e, ::onc::cellular_found_network::kStatus);
found_network->network_id =
GetRequiredString(&e, ::onc::cellular_found_network::kNetworkId);
found_network->technology =
GetRequiredString(&e, ::onc::cellular_found_network::kTechnology);
found_network->short_name =
GetString(&e, ::onc::cellular_found_network::kShortName);
found_network->long_name =
GetString(&e, ::onc::cellular_found_network::kLongName);
result.push_back(std::move(found_network));
}
return result;
}
mojom::CellularProviderPropertiesPtr GetCellularProviderProperties(
const base::Value* dict,
const char* key) {
const base::Value* provider_dict = dict->FindKey(key);
if (!provider_dict)
return nullptr;
auto provider = mojom::CellularProviderProperties::New();
provider->name =
GetRequiredString(provider_dict, ::onc::cellular_provider::kName);
provider->code =
GetRequiredString(provider_dict, ::onc::cellular_provider::kCode);
provider->country =
GetString(provider_dict, ::onc::cellular_provider::kCountry);
return provider;
}
mojom::ManagedIssuerSubjectPatternPtr GetManagedIssuerSubjectPattern(
const base::Value* dict,
const char* key) {
const base::Value* pattern_dict = dict->FindKey(key);
if (!pattern_dict)
return nullptr;
if (!pattern_dict->is_dict()) {
NET_LOG(ERROR) << "Expected dictionary, found: " << *pattern_dict;
return nullptr;
}
auto pattern = mojom::ManagedIssuerSubjectPattern::New();
pattern->common_name =
GetManagedString(pattern_dict, ::onc::client_cert::kCommonName);
pattern->locality =
GetManagedString(pattern_dict, ::onc::client_cert::kLocality);
pattern->organization =
GetManagedString(pattern_dict, ::onc::client_cert::kOrganization);
pattern->organizational_unit =
GetManagedString(pattern_dict, ::onc::client_cert::kOrganizationalUnit);
return pattern;
}
mojom::ManagedCertificatePatternPtr GetManagedCertificatePattern(
const base::Value* dict,
const char* key) {
const base::Value* pattern_dict = dict->FindKey(key);
if (!pattern_dict)
return nullptr;
if (!pattern_dict->is_dict()) {
NET_LOG(ERROR) << "Expected dictionary, found: " << *pattern_dict;
return nullptr;
}
auto pattern = mojom::ManagedCertificatePattern::New();
pattern->enrollment_uri =
GetManagedStringList(pattern_dict, ::onc::client_cert::kEnrollmentURI);
pattern->issuer =
GetManagedIssuerSubjectPattern(pattern_dict, ::onc::client_cert::kIssuer);
pattern->issuer_ca_ref =
GetManagedStringList(pattern_dict, ::onc::client_cert::kIssuerCARef);
pattern->subject = GetManagedIssuerSubjectPattern(
pattern_dict, ::onc::client_cert::kSubject);
return pattern;
}
mojom::ManagedEAPPropertiesPtr GetManagedEAPProperties(const base::Value* dict,
const char* key) {
auto eap = mojom::ManagedEAPProperties::New();
const base::Value* eap_dict = dict->FindKey(key);
if (!eap_dict)
return eap;
if (!eap_dict->is_dict()) {
NET_LOG(ERROR) << "Expected dictionary, found: " << *eap_dict;
return eap;
}
eap->anonymous_identity =
GetManagedString(eap_dict, ::onc::eap::kAnonymousIdentity);
eap->client_cert_pattern = GetManagedCertificatePattern(
eap_dict, ::onc::client_cert::kClientCertPattern);
eap->client_cert_pkcs11_id =
GetManagedString(eap_dict, ::onc::client_cert::kClientCertPKCS11Id);
eap->client_cert_ref =
GetManagedString(eap_dict, ::onc::client_cert::kClientCertRef);
eap->client_cert_type =
GetManagedString(eap_dict, ::onc::client_cert::kClientCertType);
eap->identity = GetManagedString(eap_dict, ::onc::eap::kIdentity);
eap->inner = GetManagedString(eap_dict, ::onc::eap::kInner);
eap->outer = GetManagedString(eap_dict, ::onc::eap::kOuter);
eap->password = GetManagedString(eap_dict, ::onc::eap::kPassword);
eap->save_credentials =
GetManagedBoolean(eap_dict, ::onc::eap::kSaveCredentials);
eap->server_ca_pems =
GetManagedStringList(eap_dict, ::onc::eap::kServerCAPEMs);
eap->server_ca_refs =
GetManagedStringList(eap_dict, ::onc::eap::kServerCARefs);
eap->subject_match = GetManagedString(eap_dict, ::onc::eap::kSubjectMatch);
eap->tls_version_max = GetManagedString(eap_dict, ::onc::eap::kTLSVersionMax);
eap->use_proactive_key_caching =
GetManagedBoolean(eap_dict, ::onc::eap::kUseProactiveKeyCaching);
eap->use_system_cas = GetManagedBoolean(eap_dict, ::onc::eap::kUseSystemCAs);
return eap;
}
mojom::ManagedIPSecPropertiesPtr GetManagedIPSecProperties(
const base::Value* dict,
const char* key) {
auto ipsec = mojom::ManagedIPSecProperties::New();
const base::Value* ipsec_dict = dict->FindKey(key);
if (!ipsec_dict)
return ipsec;
if (!ipsec_dict->is_dict()) {
NET_LOG(ERROR) << "Expected dictionary, found: " << *ipsec_dict;
return ipsec;
}
ipsec->authentication_type =
GetRequiredManagedString(ipsec_dict, ::onc::ipsec::kAuthenticationType);
ipsec->client_cert_pattern = GetManagedCertificatePattern(
ipsec_dict, ::onc::client_cert::kClientCertPattern);
ipsec->client_cert_pkcs11_id =
GetManagedString(ipsec_dict, ::onc::client_cert::kClientCertPKCS11Id);
ipsec->client_cert_ref =
GetManagedString(ipsec_dict, ::onc::client_cert::kClientCertRef);
ipsec->client_cert_type =
GetManagedString(ipsec_dict, ::onc::client_cert::kClientCertType);
ipsec->eap = GetManagedEAPProperties(ipsec_dict, ::onc::ipsec::kEAP);
ipsec->group = GetManagedString(ipsec_dict, ::onc::ipsec::kGroup);
ipsec->ike_version = GetManagedInt32(ipsec_dict, ::onc::ipsec::kIKEVersion);
ipsec->psk = GetManagedString(ipsec_dict, ::onc::ipsec::kPSK);
ipsec->save_credentials =
GetManagedBoolean(ipsec_dict, ::onc::vpn::kSaveCredentials);
ipsec->server_ca_pems =
GetManagedStringList(ipsec_dict, ::onc::ipsec::kServerCAPEMs);
ipsec->server_ca_refs =
GetManagedStringList(ipsec_dict, ::onc::ipsec::kServerCARefs);
return ipsec;
}
mojom::ManagedL2TPPropertiesPtr GetManagedL2TPProperties(
const base::Value* dict,
const char* key) {
auto l2tp = mojom::ManagedL2TPProperties::New();
const base::Value* l2tp_dict = dict->FindKey(key);
if (!l2tp_dict)
return l2tp;
if (!l2tp_dict->is_dict()) {
NET_LOG(ERROR) << "Expected dictionary, found: " << *l2tp_dict;
return l2tp;
}
l2tp->lcp_echo_disabled =
GetManagedBoolean(l2tp_dict, ::onc::l2tp::kLcpEchoDisabled);
l2tp->password = GetManagedString(l2tp_dict, ::onc::l2tp::kPassword);
l2tp->save_credentials =
GetManagedBoolean(l2tp_dict, ::onc::l2tp::kSaveCredentials);
l2tp->username = GetManagedString(l2tp_dict, ::onc::l2tp::kUsername);
return l2tp;
}
mojom::ManagedOpenVPNPropertiesPtr GetManagedOpenVPNProperties(
const base::Value* dict,
const char* key) {
auto openvpn = mojom::ManagedOpenVPNProperties::New();
const base::Value* openvpn_dict = dict->FindKey(key);
if (!openvpn_dict)
return openvpn;
if (!openvpn_dict->is_dict()) {
NET_LOG(ERROR) << "Expected dictionary, found: " << *openvpn_dict;
return openvpn;
}
openvpn->auth = GetManagedString(openvpn_dict, ::onc::openvpn::kAuth);
openvpn->auth_retry =
GetManagedString(openvpn_dict, ::onc::openvpn::kAuthRetry);
openvpn->auth_no_cache =
GetManagedBoolean(openvpn_dict, ::onc::openvpn::kAuthNoCache);
openvpn->cipher = GetManagedString(openvpn_dict, ::onc::openvpn::kCipher);
openvpn->client_cert_pkcs11_id =
GetManagedString(openvpn_dict, ::onc::client_cert::kClientCertPKCS11Id);
openvpn->client_cert_pattern = GetManagedCertificatePattern(
openvpn_dict, ::onc::client_cert::kClientCertPattern);
openvpn->client_cert_ref =
GetManagedString(openvpn_dict, ::onc::client_cert::kClientCertRef);
openvpn->client_cert_type =
GetManagedString(openvpn_dict, ::onc::client_cert::kClientCertType);
openvpn->compression_algorithm =
GetManagedString(openvpn_dict, ::onc::openvpn::kCompressionAlgorithm);
openvpn->extra_hosts =
GetManagedStringList(openvpn_dict, ::onc::openvpn::kExtraHosts);
openvpn->ignore_default_route =
GetManagedBoolean(openvpn_dict, ::onc::openvpn::kIgnoreDefaultRoute);
openvpn->key_direction =
GetManagedString(openvpn_dict, ::onc::openvpn::kKeyDirection);
openvpn->ns_cert_type =
GetManagedString(openvpn_dict, ::onc::openvpn::kNsCertType);
openvpn->password = GetManagedString(openvpn_dict, ::onc::openvpn::kPassword);
openvpn->port = GetManagedInt32(openvpn_dict, ::onc::openvpn::kPort);
openvpn->proto = GetManagedString(openvpn_dict, ::onc::openvpn::kProto);
openvpn->push_peer_info =
GetManagedBoolean(openvpn_dict, ::onc::openvpn::kPushPeerInfo);
openvpn->remote_cert_eku =
GetManagedString(openvpn_dict, ::onc::openvpn::kRemoteCertEKU);
openvpn->remote_cert_ku =
GetManagedStringList(openvpn_dict, ::onc::openvpn::kRemoteCertKU);
openvpn->remote_cert_tls =
GetManagedString(openvpn_dict, ::onc::openvpn::kRemoteCertTLS);
openvpn->reneg_sec = GetManagedInt32(openvpn_dict, ::onc::openvpn::kRenegSec);
openvpn->save_credentials =
GetManagedBoolean(openvpn_dict, ::onc::vpn::kSaveCredentials);
openvpn->server_ca_pems =
GetManagedStringList(openvpn_dict, ::onc::openvpn::kServerCAPEMs);
openvpn->server_ca_refs =
GetManagedStringList(openvpn_dict, ::onc::openvpn::kServerCARefs);
openvpn->server_cert_ref =
GetManagedString(openvpn_dict, ::onc::openvpn::kServerCertRef);
openvpn->server_poll_timeout =
GetManagedInt32(openvpn_dict, ::onc::openvpn::kServerPollTimeout);
openvpn->shaper = GetManagedInt32(openvpn_dict, ::onc::openvpn::kShaper);
openvpn->static_challenge =
GetManagedString(openvpn_dict, ::onc::openvpn::kStaticChallenge);
openvpn->tls_auth_contents =
GetManagedString(openvpn_dict, ::onc::openvpn::kTLSAuthContents);
openvpn->tls_remote =
GetManagedString(openvpn_dict, ::onc::openvpn::kTLSRemote);
openvpn->tls_version_min =
GetManagedString(openvpn_dict, ::onc::openvpn::kTLSVersionMin);
openvpn->user_authentication_type =
GetManagedString(openvpn_dict, ::onc::openvpn::kUserAuthenticationType);
openvpn->username = GetManagedString(openvpn_dict, ::onc::vpn::kUsername);
openvpn->verb = GetManagedString(openvpn_dict, ::onc::openvpn::kVerb);
openvpn->verify_hash =
GetManagedString(openvpn_dict, ::onc::openvpn::kVerifyHash);
const base::Value* verify_x509_dict =
openvpn_dict->FindKey(::onc::openvpn::kVerifyX509);
if (verify_x509_dict) {
auto verify_x509 = mojom::ManagedVerifyX509Properties::New();
verify_x509->name =
GetManagedString(verify_x509_dict, ::onc::verify_x509::kName);
verify_x509->type =
GetManagedString(verify_x509_dict, ::onc::verify_x509::kType);
openvpn->verify_x509 = std::move(verify_x509);
}
return openvpn;
}
mojom::ManagedPropertiesPtr ManagedPropertiesToMojo(
const NetworkState* network_state,
const std::vector<mojom::VpnProviderPtr>& vpn_providers,
const base::Value* properties) {
DCHECK(network_state);
DCHECK(properties);
base::Optional<std::string> onc_type =
GetString(properties, ::onc::network_config::kType);
if (!onc_type) {
NET_LOG(ERROR) << "Malformed ONC dictionary: missing 'Type'";
return nullptr;
}
mojom::NetworkType type = OncTypeToMojo(*onc_type);
if (type == mojom::NetworkType::kAll) {
NET_LOG(ERROR) << "Unexpected network type: " << *onc_type;
return nullptr;
}
auto result = mojom::ManagedProperties::New();
// |network_state| and |properties| guid should be the same.
base::Optional<std::string> guid =
GetString(properties, ::onc::network_config::kGUID);
if (!guid) {
NET_LOG(ERROR) << "Malformed ONC dictionary: missing 'GUID'";
return nullptr;
}
DCHECK_EQ(network_state->guid(), *guid);
result->guid = network_state->guid();
// Typed properties (compatible with NetworkStateProperties):
result->connection_state =
GetConnectionState(network_state, /*technology_enabled=*/true);
result->source = GetMojoOncSource(network_state);
result->type = type;
// Unmanaged properties
result->connectable =
GetBoolean(properties, ::onc::network_config::kConnectable);
result->error_state =
GetString(properties, ::onc::network_config::kErrorState);
const base::Value* ip_configs_list =
properties->FindKey(::onc::network_config::kIPConfigs);
if (ip_configs_list) {
std::vector<mojom::IPConfigPropertiesPtr> ip_configs;
for (const base::Value& ip_config_value : ip_configs_list->GetList())
ip_configs.push_back(GetIPConfig(&ip_config_value));
result->ip_configs = std::move(ip_configs);
}
result->portal_state = GetMojoPortalState(network_state->portal_state());
const base::Value* saved_ip_config =
GetDictionary(properties, ::onc::network_config::kSavedIPConfig);
if (saved_ip_config)
result->saved_ip_config = GetIPConfig(saved_ip_config);
// Managed properties
result->ip_address_config_type = GetRequiredManagedString(
properties, ::onc::network_config::kIPAddressConfigType);
result->metered =
GetManagedBoolean(properties, ::onc::network_config::kMetered);
result->name = GetManagedString(properties, ::onc::network_config::kName);
result->name_servers_config_type = GetRequiredManagedString(
properties, ::onc::network_config::kNameServersConfigType);
result->priority =
GetManagedInt32(properties, ::onc::network_config::kPriority);
// Managed dictionaries (not type specific)
const base::Value* proxy_settings =
GetDictionary(properties, ::onc::network_config::kProxySettings);
if (proxy_settings)
result->proxy_settings = GetManagedProxySettings(proxy_settings);
const base::Value* static_ip_config =
GetDictionary(properties, ::onc::network_config::kStaticIPConfig);
if (static_ip_config)
result->static_ip_config = GetManagedIPConfig(static_ip_config);
// Type specific dictionaries
switch (type) {
case mojom::NetworkType::kCellular: {
auto cellular = mojom::ManagedCellularProperties::New();
cellular->activation_state = network_state->GetMojoActivationState();
const base::Value* cellular_dict =
GetDictionary(properties, ::onc::network_config::kCellular);
if (!cellular_dict) {
result->type_properties =
mojom::NetworkTypeManagedProperties::NewCellular(
std::move(cellular));
break;
}
cellular->auto_connect =
GetManagedBoolean(cellular_dict, ::onc::cellular::kAutoConnect);
cellular->selected_apn =
GetManagedApnProperties(cellular_dict, ::onc::cellular::kAPN);
cellular->apn_list =
GetManagedApnList(cellular_dict->FindKey(::onc::cellular::kAPNList));
cellular->allow_roaming =
GetBoolean(cellular_dict, ::onc::cellular::kAllowRoaming);
cellular->esn = GetString(cellular_dict, ::onc::cellular::kESN);
cellular->family = GetString(cellular_dict, ::onc::cellular::kFamily);
cellular->firmware_revision =
GetString(cellular_dict, ::onc::cellular::kFirmwareRevision);
cellular->found_networks =
GetFoundNetworksList(cellular_dict, ::onc::cellular::kFoundNetworks);
cellular->hardware_revision =
GetString(cellular_dict, ::onc::cellular::kHardwareRevision);
cellular->home_provider = GetCellularProviderProperties(
cellular_dict, ::onc::cellular::kHomeProvider);
cellular->eid = GetString(cellular_dict, ::onc::cellular::kEID);
cellular->iccid = GetString(cellular_dict, ::onc::cellular::kICCID);
cellular->imei = GetString(cellular_dict, ::onc::cellular::kIMEI);
const base::Value* apn_dict =
GetDictionary(cellular_dict, ::onc::cellular::kLastGoodAPN);
if (apn_dict)
cellular->last_good_apn = GetApnProperties(apn_dict);
cellular->manufacturer =
GetString(cellular_dict, ::onc::cellular::kManufacturer);
cellular->mdn = GetString(cellular_dict, ::onc::cellular::kMDN);
cellular->meid = GetString(cellular_dict, ::onc::cellular::kMEID);
cellular->min = GetString(cellular_dict, ::onc::cellular::kMIN);
cellular->model_id = GetString(cellular_dict, ::onc::cellular::kModelID);
cellular->network_technology =
GetString(cellular_dict, ::onc::cellular::kNetworkTechnology);
const base::Value* payment_portal_dict =
cellular_dict->FindKey(::onc::cellular::kPaymentPortal);
if (payment_portal_dict) {
auto payment_portal = mojom::PaymentPortalProperties::New();
payment_portal->method = GetRequiredString(
payment_portal_dict, ::onc::cellular_payment_portal::kMethod);
payment_portal->post_data = GetRequiredString(
payment_portal_dict, ::onc::cellular_payment_portal::kPostData);
payment_portal->url = GetString(payment_portal_dict,
::onc::cellular_payment_portal::kUrl);
cellular->payment_portal = std::move(payment_portal);
}
cellular->roaming_state =
GetString(cellular_dict, ::onc::cellular::kRoamingState);
cellular->serving_operator = GetCellularProviderProperties(
cellular_dict, ::onc::cellular::kServingOperator);
cellular->signal_strength =
GetInt32(cellular_dict, ::onc::cellular::kSignalStrength);
cellular->support_network_scan =
GetBoolean(cellular_dict, ::onc::cellular::kSupportNetworkScan);
result->type_properties =
mojom::NetworkTypeManagedProperties::NewCellular(std::move(cellular));
break;
}
case mojom::NetworkType::kEthernet: {
auto ethernet = mojom::ManagedEthernetProperties::New();
const base::Value* ethernet_dict =
GetDictionary(properties, ::onc::network_config::kEthernet);
if (ethernet_dict) {
ethernet->authentication =
GetManagedString(ethernet_dict, ::onc::ethernet::kAuthentication);
ethernet->eap =
GetManagedEAPProperties(ethernet_dict, ::onc::ethernet::kEAP);
}
result->type_properties =
mojom::NetworkTypeManagedProperties::NewEthernet(std::move(ethernet));
break;
}
case mojom::NetworkType::kTether: {
// Tether has no managed properties, provide the state properties.
auto tether = mojom::TetherStateProperties::New();
tether->battery_percentage = network_state->battery_percentage();
tether->carrier = network_state->tether_carrier();
tether->has_connected_to_host =
network_state->tether_has_connected_to_host();
tether->signal_strength = network_state->signal_strength();
result->type_properties =
mojom::NetworkTypeManagedProperties::NewTether(std::move(tether));
break;
}
case mojom::NetworkType::kVPN: {
auto vpn = mojom::ManagedVPNProperties::New();
const base::Value* vpn_dict =
GetDictionary(properties, ::onc::network_config::kVPN);
if (!vpn_dict) {
result->type_properties =
mojom::NetworkTypeManagedProperties::NewVpn(std::move(vpn));
break;
}
mojom::ManagedStringPtr managed_type =
GetManagedString(vpn_dict, ::onc::vpn::kType);
CHECK(managed_type);
vpn->type = OncVpnTypeToMojo(managed_type->active_value);
vpn->auto_connect = GetManagedBoolean(vpn_dict, ::onc::vpn::kAutoConnect);
vpn->host = GetManagedString(vpn_dict, ::onc::vpn::kHost);
switch (vpn->type) {
case mojom::VpnType::kL2TPIPsec:
vpn->ip_sec = GetManagedIPSecProperties(vpn_dict, ::onc::vpn::kIPsec);
vpn->l2tp = GetManagedL2TPProperties(vpn_dict, ::onc::vpn::kL2TP);
break;
case mojom::VpnType::kOpenVPN:
vpn->open_vpn =
GetManagedOpenVPNProperties(vpn_dict, ::onc::vpn::kOpenVPN);
break;
case mojom::VpnType::kExtension:
case mojom::VpnType::kArc:
const base::Value* third_party_dict =
vpn_dict->FindKey(::onc::vpn::kThirdPartyVpn);
if (third_party_dict) {
vpn->provider_id = GetManagedString(
third_party_dict, ::onc::third_party_vpn::kExtensionID);
base::Optional<std::string> provider_name = GetString(
third_party_dict, ::onc::third_party_vpn::kProviderName);
if (provider_name)
vpn->provider_name = *provider_name;
if (vpn->provider_id && vpn->provider_name.empty()) {
vpn->provider_name = GetVpnProviderName(
vpn_providers, vpn->provider_id->active_value);
}
} else {
// Lookup VPN provider details from the NetworkState.
const NetworkState::VpnProviderInfo* vpn_provider =
network_state->vpn_provider();
if (vpn_provider) {
vpn->provider_id = mojom::ManagedString::New();
vpn->provider_id->active_value = vpn_provider->id;
vpn->provider_name =
GetVpnProviderName(vpn_providers, vpn_provider->id);
}
}
break;
}
result->type_properties =
mojom::NetworkTypeManagedProperties::NewVpn(std::move(vpn));
break;
}
case mojom::NetworkType::kWiFi: {
auto wifi = mojom::ManagedWiFiProperties::New();
wifi->security = network_state->GetMojoSecurity();
const base::Value* wifi_dict =
GetDictionary(properties, ::onc::network_config::kWiFi);
if (!wifi_dict) {
result->type_properties =
mojom::NetworkTypeManagedProperties::NewWifi(std::move(wifi));
break;
}
wifi->allow_gateway_arp_polling =
GetManagedBoolean(wifi_dict, ::onc::wifi::kAllowGatewayARPPolling);
wifi->auto_connect =
GetManagedBoolean(wifi_dict, ::onc::wifi::kAutoConnect);
wifi->bssid = GetString(wifi_dict, ::onc::wifi::kBSSID);
wifi->eap = GetManagedEAPProperties(wifi_dict, ::onc::wifi::kEAP);
wifi->frequency = GetInt32(wifi_dict, ::onc::wifi::kFrequency);
wifi->frequency_list =
GetInt32List(wifi_dict, ::onc::wifi::kFrequencyList);
wifi->hex_ssid = GetManagedString(wifi_dict, ::onc::wifi::kHexSSID);
wifi->hidden_ssid =
GetManagedBoolean(wifi_dict, ::onc::wifi::kHiddenSSID);
wifi->passphrase = GetManagedString(wifi_dict, ::onc::wifi::kPassphrase);
wifi->ssid = GetRequiredManagedString(wifi_dict, ::onc::wifi::kSSID);
CHECK(wifi->ssid);
wifi->signal_strength = GetInt32(wifi_dict, ::onc::wifi::kSignalStrength);
wifi->tethering_state =
GetString(wifi_dict, ::onc::wifi::kTetheringState);
wifi->is_syncable = sync_wifi::IsEligibleForSync(
result->guid, result->connectable, wifi->security, result->source,
/*log_result=*/false);
wifi->is_configured_by_active_user = GetIsConfiguredByUser(result->guid);
result->type_properties =
mojom::NetworkTypeManagedProperties::NewWifi(std::move(wifi));
break;
}
case mojom::NetworkType::kAll:
case mojom::NetworkType::kMobile:
case mojom::NetworkType::kWireless:
NOTREACHED() << "NetworkStateProperties can not be of type: " << type;
break;
}
return result;
}
bool NetworkTypeCanBeDisabled(mojom::NetworkType type) {
switch (type) {
case mojom::NetworkType::kCellular:
case mojom::NetworkType::kTether:
case mojom::NetworkType::kWiFi:
return true;
case mojom::NetworkType::kAll:
case mojom::NetworkType::kEthernet:
case mojom::NetworkType::kMobile:
case mojom::NetworkType::kVPN:
case mojom::NetworkType::kWireless:
return false;
}
NOTREACHED();
return false;
}
base::Value GetEAPProperties(const mojom::EAPConfigProperties& eap) {
base::Value eap_dict(base::Value::Type::DICTIONARY);
SetString(::onc::eap::kAnonymousIdentity, eap.anonymous_identity, &eap_dict);
SetString(::onc::client_cert::kClientCertPKCS11Id, eap.client_cert_pkcs11_id,
&eap_dict);
SetString(::onc::client_cert::kClientCertType, eap.client_cert_type,
&eap_dict);
SetString(::onc::eap::kIdentity, eap.identity, &eap_dict);
SetString(::onc::eap::kInner, eap.inner, &eap_dict);
SetString(::onc::eap::kOuter, eap.outer, &eap_dict);
SetString(::onc::eap::kPassword, eap.password, &eap_dict);
eap_dict.SetBoolKey(::onc::eap::kSaveCredentials, eap.save_credentials);
SetStringList(::onc::eap::kServerCAPEMs, eap.server_ca_pems, &eap_dict);
SetString(::onc::eap::kSubjectMatch, eap.subject_match, &eap_dict);
eap_dict.SetBoolKey(::onc::eap::kUseSystemCAs, eap.use_system_cas);
return eap_dict;
}
std::unique_ptr<base::DictionaryValue> GetOncFromConfigProperties(
const mojom::ConfigProperties* properties,
base::Optional<std::string> guid) {
auto onc = std::make_unique<base::DictionaryValue>();
// Process |properties->network_type| and set |type|. Configurations have only
// one type dictionary.
mojom::NetworkType type = mojom::NetworkType::kAll; // Invalid type
base::Value type_dict(base::Value::Type::DICTIONARY);
if (properties->guid && !properties->guid->empty()) {
if (guid && *guid != *properties->guid) {
NET_LOG(ERROR) << "GUID does not match: " << *guid
<< " != " << *properties->guid;
return nullptr;
}
SetString(::onc::network_config::kGUID, *properties->guid, onc.get());
}
if (properties->type_config->is_cellular()) {
type = mojom::NetworkType::kCellular;
const mojom::CellularConfigProperties& cellular =
*properties->type_config->get_cellular();
if (cellular.apn) {
const mojom::ApnProperties& apn = *cellular.apn;
base::Value apn_dict(base::Value::Type::DICTIONARY);
apn_dict.SetStringKey(::onc::cellular_apn::kAccessPointName,
apn.access_point_name);
SetString(::onc::cellular_apn::kAuthentication, apn.authentication,
&apn_dict);
SetString(::onc::cellular_apn::kLanguage, apn.language, &apn_dict);
SetString(::onc::cellular_apn::kLocalizedName, apn.localized_name,
&apn_dict);
SetString(::onc::cellular_apn::kName, apn.name, &apn_dict);
SetString(::onc::cellular_apn::kPassword, apn.password, &apn_dict);
SetString(::onc::cellular_apn::kUsername, apn.username, &apn_dict);
type_dict.SetKey(::onc::cellular::kAPN, std::move(apn_dict));
}
} else if (properties->type_config->is_ethernet()) {
type = mojom::NetworkType::kEthernet;
const mojom::EthernetConfigProperties& ethernet =
*properties->type_config->get_ethernet();
SetString(::onc::ethernet::kAuthentication, ethernet.authentication,
&type_dict);
if (ethernet.eap) {
type_dict.SetKey(::onc::ethernet::kEAP,
GetEAPProperties(*ethernet.eap.get()));
}
} else if (properties->type_config->is_vpn()) {
type = mojom::NetworkType::kVPN;
const mojom::VPNConfigProperties& vpn = *properties->type_config->get_vpn();
SetString(::onc::vpn::kHost, vpn.host, &type_dict);
if (vpn.ip_sec) {
const mojom::IPSecConfigProperties& ip_sec = *vpn.ip_sec;
base::Value ip_sec_dict(base::Value::Type::DICTIONARY);
SetString(::onc::ipsec::kAuthenticationType, ip_sec.authentication_type,
&ip_sec_dict);
SetString(::onc::client_cert::kClientCertPKCS11Id,
ip_sec.client_cert_pkcs11_id, &ip_sec_dict);
SetString(::onc::client_cert::kClientCertType, ip_sec.client_cert_type,
&ip_sec_dict);
SetString(::onc::ipsec::kGroup, ip_sec.group, &ip_sec_dict);
ip_sec_dict.SetIntKey(::onc::ipsec::kIKEVersion, ip_sec.ike_version);
SetString(::onc::ipsec::kPSK, ip_sec.psk, &ip_sec_dict);
ip_sec_dict.SetBoolKey(::onc::l2tp::kSaveCredentials,
ip_sec.save_credentials);
SetStringList(::onc::ipsec::kServerCAPEMs, ip_sec.server_ca_pems,
&ip_sec_dict);
SetStringList(::onc::ipsec::kServerCARefs, ip_sec.server_ca_refs,
&ip_sec_dict);
type_dict.SetKey(::onc::vpn::kIPsec, std::move(ip_sec_dict));
}
if (vpn.l2tp) {
const mojom::L2TPConfigProperties& l2tp = *vpn.l2tp;
base::Value l2tp_dict(base::Value::Type::DICTIONARY);
l2tp_dict.SetBoolKey(::onc::l2tp::kLcpEchoDisabled,
l2tp.lcp_echo_disabled);
SetString(::onc::l2tp::kPassword, l2tp.password, &l2tp_dict);
l2tp_dict.SetBoolKey(::onc::l2tp::kSaveCredentials,
l2tp.save_credentials);
SetString(::onc::l2tp::kUsername, l2tp.username, &l2tp_dict);
type_dict.SetKey(::onc::vpn::kL2TP, std::move(l2tp_dict));
}
if (vpn.open_vpn) {
const mojom::OpenVPNConfigProperties& open_vpn = *vpn.open_vpn;
base::Value open_vpn_dict(base::Value::Type::DICTIONARY);
SetString(::onc::client_cert::kClientCertPKCS11Id,
open_vpn.client_cert_pkcs11_id, &open_vpn_dict);
SetString(::onc::client_cert::kClientCertType, open_vpn.client_cert_type,
&open_vpn_dict);
SetStringList(::onc::openvpn::kExtraHosts, open_vpn.extra_hosts,
&open_vpn_dict);
SetString(::onc::openvpn::kOTP, open_vpn.otp, &open_vpn_dict);
SetString(::onc::openvpn::kPassword, open_vpn.password, &open_vpn_dict);
open_vpn_dict.SetBoolKey(::onc::l2tp::kSaveCredentials,
open_vpn.save_credentials);
SetStringList(::onc::openvpn::kServerCAPEMs, open_vpn.server_ca_pems,
&open_vpn_dict);
SetStringList(::onc::openvpn::kServerCARefs, open_vpn.server_ca_refs,
&open_vpn_dict);
SetString(::onc::vpn::kUsername, open_vpn.username, &open_vpn_dict);
SetString(::onc::openvpn::kUserAuthenticationType,
open_vpn.user_authentication_type, &open_vpn_dict);
type_dict.SetKey(::onc::vpn::kOpenVPN, std::move(open_vpn_dict));
}
if (vpn.type) {
SetString(::onc::vpn::kType, MojoVpnTypeToOnc(vpn.type->value),
&type_dict);
}
} else if (properties->type_config->is_wifi()) {
type = mojom::NetworkType::kWiFi;
const mojom::WiFiConfigProperties& wifi =
*properties->type_config->get_wifi();
SetString(::onc::wifi::kPassphrase, wifi.passphrase, &type_dict);
SetStringIfNotEmpty(::onc::wifi::kSSID, wifi.ssid, &type_dict);
SetString(::onc::wifi::kPassphrase, wifi.passphrase, &type_dict);
SetString(::onc::wifi::kSecurity, MojoSecurityTypeToOnc(wifi.security),
&type_dict);
if (wifi.eap) {
type_dict.SetKey(::onc::wifi::kEAP, GetEAPProperties(*wifi.eap.get()));
}
}
std::string onc_type = MojoNetworkTypeToOnc(type);
if (onc_type.empty()) {
NET_LOG(ERROR) << "Invalid NetworkConfig properties";
return nullptr;
}
SetString(::onc::network_config::kType, onc_type, onc.get());
// Process other |properties| members. Order matches the mojo struct.
if (properties->ip_address_config_type) {
onc->SetStringKey(::onc::network_config::kIPAddressConfigType,
*properties->ip_address_config_type);
}
if (properties->metered) {
onc->SetBoolKey(::onc::network_config::kMetered,
properties->metered->value);
}
SetString(::onc::network_config::kName, properties->name, onc.get());
SetString(::onc::network_config::kNameServersConfigType,
properties->name_servers_config_type, onc.get());
if (properties->priority) {
onc->SetIntKey(::onc::network_config::kPriority,
properties->priority->value);
}
if (properties->proxy_settings) {
const mojom::ProxySettings& proxy = *properties->proxy_settings;
base::Value proxy_dict(base::Value::Type::DICTIONARY);
proxy_dict.SetStringKey(::onc::proxy::kType, proxy.type);
if (proxy.manual) {
const mojom::ManualProxySettings& manual = *proxy.manual;
base::Value manual_dict(base::Value::Type::DICTIONARY);
SetProxyLocation(::onc::proxy::kHttp, manual.http_proxy, &manual_dict);
SetProxyLocation(::onc::proxy::kHttps, manual.secure_http_proxy,
&manual_dict);
SetProxyLocation(::onc::proxy::kFtp, manual.ftp_proxy, &manual_dict);
SetProxyLocation(::onc::proxy::kSocks, manual.socks, &manual_dict);
proxy_dict.SetKey(::onc::proxy::kManual, std::move(manual_dict));
}
SetStringList(::onc::proxy::kExcludeDomains, proxy.exclude_domains,
&proxy_dict);
SetString(::onc::proxy::kPAC, proxy.pac, &proxy_dict);
onc->SetKey(::onc::network_config::kProxySettings, std::move(proxy_dict));
}
if (properties->static_ip_config) {
const mojom::IPConfigProperties& ip_config = *properties->static_ip_config;
base::Value ip_config_dict(base::Value::Type::DICTIONARY);
SetString(::onc::ipconfig::kGateway, ip_config.gateway, &ip_config_dict);
SetString(::onc::ipconfig::kIPAddress, ip_config.ip_address,
&ip_config_dict);
SetStringList(::onc::ipconfig::kNameServers, ip_config.name_servers,
&ip_config_dict);
ip_config_dict.SetIntKey(::onc::ipconfig::kRoutingPrefix,
ip_config.routing_prefix);
SetString(::onc::ipconfig::kType, ip_config.type, &ip_config_dict);
SetString(::onc::ipconfig::kWebProxyAutoDiscoveryUrl,
ip_config.web_proxy_auto_discovery_url, &ip_config_dict);
onc->SetKey(::onc::network_config::kStaticIPConfig,
std::move(ip_config_dict));
}
if (properties->auto_connect) {
NetworkTypePattern type_pattern = MojoTypeToPattern(type);
if (type_pattern.Equals(NetworkTypePattern::Cellular()) ||
type_pattern.Equals(NetworkTypePattern::VPN()) ||
type_pattern.Equals(NetworkTypePattern::WiFi())) {
// Note: All type dicts use the same kAutoConnect key.
type_dict.SetBoolKey(::onc::wifi::kAutoConnect,
properties->auto_connect->value);
}
}
if (!type_dict.DictEmpty()) {
onc->SetKey(onc_type, std::move(type_dict));
}
return onc;
}
mojom::NetworkCertificatePtr GetMojoCert(
const NetworkCertificateHandler::Certificate& cert,
mojom::CertificateType type) {
auto result = mojom::NetworkCertificate::New();
result->type = type;
result->hash = cert.hash;
result->issued_by = cert.issued_by;
result->issued_to = cert.issued_to;
result->hardware_backed = cert.hardware_backed;
result->device_wide = cert.device_wide;
if (type == mojom::CertificateType::kServerCA)
result->pem_or_id = cert.pem;
if (type == mojom::CertificateType::kUserCert)
result->pem_or_id = cert.pkcs11_id;
return result;
}
} // namespace
CrosNetworkConfig::CrosNetworkConfig()
: CrosNetworkConfig(
NetworkHandler::Get()->network_state_handler(),
NetworkHandler::Get()->network_device_handler(),
NetworkHandler::Get()->managed_network_configuration_handler(),
NetworkHandler::Get()->network_connection_handler(),
NetworkHandler::Get()->network_certificate_handler()) {}
CrosNetworkConfig::CrosNetworkConfig(
NetworkStateHandler* network_state_handler,
NetworkDeviceHandler* network_device_handler,
ManagedNetworkConfigurationHandler* network_configuration_handler,
NetworkConnectionHandler* network_connection_handler,
NetworkCertificateHandler* network_certificate_handler)
: network_state_handler_(network_state_handler),
network_device_handler_(network_device_handler),
network_configuration_handler_(network_configuration_handler),
network_connection_handler_(network_connection_handler),
network_certificate_handler_(network_certificate_handler) {
CHECK(network_state_handler);
}
CrosNetworkConfig::~CrosNetworkConfig() {
if (network_state_handler_->HasObserver(this))
network_state_handler_->RemoveObserver(this, FROM_HERE);
if (network_certificate_handler_ &&
network_certificate_handler_->HasObserver(this)) {
network_certificate_handler_->RemoveObserver(this);
}
}
void CrosNetworkConfig::BindReceiver(
mojo::PendingReceiver<mojom::CrosNetworkConfig> receiver) {
NET_LOG(EVENT) << "CrosNetworkConfig::BindReceiver()";
receivers_.Add(this, std::move(receiver));
}
void CrosNetworkConfig::AddObserver(
mojo::PendingRemote<mojom::CrosNetworkConfigObserver> observer) {
if (!network_state_handler_->HasObserver(this))
network_state_handler_->AddObserver(this, FROM_HERE);
if (network_certificate_handler_ &&
!network_certificate_handler_->HasObserver(this)) {
network_certificate_handler_->AddObserver(this);
}
observers_.Add(std::move(observer));
}
void CrosNetworkConfig::GetNetworkState(const std::string& guid,
GetNetworkStateCallback callback) {
const NetworkState* network =
network_state_handler_->GetNetworkStateFromGuid(guid);
if (!network) {
NET_LOG(ERROR) << "Network not found: " << guid;
std::move(callback).Run(nullptr);
return;
}
if (network->type() == shill::kTypeEthernetEap) {
NET_LOG(ERROR) << "EthernetEap not supported for GetNetworkState";
std::move(callback).Run(nullptr);
return;
}
std::move(callback).Run(
NetworkStateToMojo(network_state_handler_, vpn_providers_, network));
}
void CrosNetworkConfig::GetNetworkStateList(
mojom::NetworkFilterPtr filter,
GetNetworkStateListCallback callback) {
NetworkStateHandler::NetworkStateList networks;
NetworkTypePattern pattern = MojoTypeToPattern(filter->network_type);
switch (filter->filter) {
case mojom::FilterType::kActive:
network_state_handler_->GetActiveNetworkListByType(pattern, &networks);
if (filter->limit > 0 &&
static_cast<int>(networks.size()) > filter->limit)
networks.resize(filter->limit);
break;
case mojom::FilterType::kVisible:
network_state_handler_->GetNetworkListByType(
pattern, /*configured_only=*/false, /*visible_only=*/true,
filter->limit, &networks);
break;
case mojom::FilterType::kConfigured:
network_state_handler_->GetNetworkListByType(
pattern, /*configured_only=*/true, /*visible_only=*/false,
filter->limit, &networks);
break;
case mojom::FilterType::kAll:
network_state_handler_->GetNetworkListByType(
pattern, /*configured_only=*/false, /*visible_only=*/false,
filter->limit, &networks);
break;
}
std::vector<mojom::NetworkStatePropertiesPtr> result;
for (const NetworkState* network : networks) {
if (network->type() == shill::kTypeEthernetEap) {
// EthernetEap is used by Shill to store EAP properties and does not
// represent a separate network service.
continue;
}
mojom::NetworkStatePropertiesPtr mojo_network =
NetworkStateToMojo(network_state_handler_, vpn_providers_, network);
if (mojo_network)
result.emplace_back(std::move(mojo_network));
}
std::move(callback).Run(std::move(result));
}
void CrosNetworkConfig::GetDeviceStateList(
GetDeviceStateListCallback callback) {
NetworkStateHandler::DeviceStateList devices;
network_state_handler_->GetDeviceList(&devices);
std::vector<mojom::DeviceStatePropertiesPtr> result;
for (const DeviceState* device : devices) {
mojom::DeviceStateType technology_state =
GetMojoDeviceStateType(network_state_handler_->GetTechnologyState(
NetworkTypePattern::Primitive(device->type())));
if (technology_state == mojom::DeviceStateType::kUnavailable) {
NET_LOG(ERROR) << "Device state unavailable: " << device->name();
continue;
}
if (technology_state == mojom::DeviceStateType::kEnabled &&
device->inhibited()) {
technology_state = mojom::DeviceStateType::kInhibited;
}
mojom::DeviceStatePropertiesPtr mojo_device =
DeviceStateToMojo(device, technology_state);
if (mojo_device)
result.emplace_back(std::move(mojo_device));
}
// Handle VPN state separately because VPN is not considered a device by shill
// and thus will not be included in the |devices| list returned by network
// state handler. In the UI code, it is treated as a "device" for consistency.
// In the UI code, knowing whether a device is prohibited or not is done by
// checking |device_state| field of the DeviceStateProperties of the
// corresponding device. A VPN device state is returned if built-in VPN
// services are prohibited by policy even if no VPN services exist in order to
// indicate that adding a VPN is prohibited in the UI.
if (network_state_handler_->FirstNetworkByType(NetworkTypePattern::VPN()) ||
IsVpnProhibited()) {
result.emplace_back(GetVpnState());
}
std::move(callback).Run(std::move(result));
}
void CrosNetworkConfig::GetManagedProperties(
const std::string& guid,
GetManagedPropertiesCallback callback) {
if (!network_configuration_handler_) {
NET_LOG(ERROR) << "GetManagedProperties called with no handler";
std::move(callback).Run(nullptr);
return;
}
const NetworkState* network =
network_state_handler_->GetNetworkStateFromGuid(guid);
if (!network) {
NET_LOG(ERROR) << "Network not found: " << guid;
std::move(callback).Run(nullptr);
return;
}
network_configuration_handler_->GetManagedProperties(
chromeos::LoginState::Get()->primary_user_hash(), network->path(),
base::BindOnce(&CrosNetworkConfig::OnGetManagedProperties,
weak_factory_.GetWeakPtr(), std::move(callback), guid));
}
void CrosNetworkConfig::OnGetManagedProperties(
GetManagedPropertiesCallback callback,
std::string guid,
const std::string& service_path,
base::Optional<base::Value> properties,
base::Optional<std::string> error) {
if (!properties) {
NET_LOG(ERROR) << "GetManagedProperties failed for: " << guid
<< " Error: " << error.value_or("Failed");
std::move(callback).Run(nullptr);
return;
}
const NetworkState* network_state =
network_state_handler_->GetNetworkState(service_path);
if (!network_state) {
NET_LOG(ERROR) << "Network not found: " << service_path;
std::move(callback).Run(nullptr);
return;
}
mojom::ManagedPropertiesPtr managed_properties = ManagedPropertiesToMojo(
network_state, vpn_providers_, &properties.value());
if (managed_properties->type == mojom::NetworkType::kCellular) {
std::vector<mojom::ApnPropertiesPtr> custom_apn_list =
GetCustomAPNList(guid);
if (!custom_apn_list.empty()) {
managed_properties->type_properties->get_cellular()->custom_apn_list =
std::move(custom_apn_list);
}
}
// For Ethernet networks with no authentication, check for a separate
// EthernetEAP configuration.
const NetworkState* eap_state = nullptr;
if (managed_properties->type == mojom::NetworkType::kEthernet) {
mojom::ManagedEthernetPropertiesPtr& ethernet =
managed_properties->type_properties->get_ethernet();
if (!ethernet->authentication || ethernet->authentication->active_value ==
::onc::ethernet::kAuthenticationNone) {
eap_state = network_state_handler_->GetEAPForEthernet(
network_state->path(), /*connected_only=*/false);
}
}
if (!eap_state) {
// No EAP properties, return the managed properties as-is.
std::move(callback).Run(std::move(managed_properties));
return;
}
// Request the EAP state. On success the EAP state will be applied to
// |managed_properties| and returned. On failure |managed_properties| will
// be returned as-is.
NET_LOG(DEBUG) << "Requesting EAP state for: " + service_path
<< " from: " << eap_state->path();
network_configuration_handler_->GetManagedProperties(
chromeos::LoginState::Get()->primary_user_hash(), eap_state->path(),
base::BindOnce(&CrosNetworkConfig::OnGetManagedPropertiesEap,
weak_factory_.GetWeakPtr(), std::move(callback),
std::move(managed_properties)));
}
void CrosNetworkConfig::OnGetManagedPropertiesEap(
GetManagedPropertiesCallback callback,
mojom::ManagedPropertiesPtr managed_properties,
const std::string& service_path,
base::Optional<base::Value> eap_properties,
base::Optional<std::string> error) {
if (eap_properties) {
// Copy the EAP properties to |managed_properties| before sending.
const base::Value* ethernet_dict =
eap_properties->FindDictKey(::onc::network_config::kEthernet);
if (ethernet_dict) {
auto ethernet = mojom::ManagedEthernetProperties::New();
ethernet->authentication =
GetManagedString(ethernet_dict, ::onc::ethernet::kAuthentication);
ethernet->eap =
GetManagedEAPProperties(ethernet_dict, ::onc::ethernet::kEAP);
managed_properties->type_properties =
mojom::NetworkTypeManagedProperties::NewEthernet(std::move(ethernet));
}
}
std::move(callback).Run(std::move(managed_properties));
}
void CrosNetworkConfig::SetProperties(const std::string& guid,
mojom::ConfigPropertiesPtr properties,
SetPropertiesCallback callback) {
if (!network_configuration_handler_) {
NET_LOG(ERROR) << "SetProperties called with no handler";
std::move(callback).Run(false, kErrorNotReady);
return;
}
const NetworkState* network =
network_state_handler_->GetNetworkStateFromGuid(guid);
if (!network || network->profile_path().empty()) {
NET_LOG(ERROR) << "SetProperties called with unconfigured network: "
<< guid;
std::move(callback).Run(false, kErrorNetworkUnavailable);
return;
}
// If EthernetEAP properties exist, and properties.ethernet.eap is provided,
// apply the configuration to the EthernetEAP service. Currently we only
// support configuration of EAP properties or other properties (e.g IP
// Config), not both.
if (network->type() == shill::kTypeEthernet &&
properties->type_config->is_ethernet() &&
properties->type_config->get_ethernet()->eap) {
const NetworkState* eap_state = network_state_handler_->GetEAPForEthernet(
network->path(), /*connected_only=*/false);
if (!eap_state) {
NET_LOG(ERROR)
<< "SetProperties called with ethernet.eap but no EAP config: "
<< guid;
std::move(callback).Run(false, kErrorNetworkUnavailable);
return;
}
network = eap_state;
}
if (network->type() == shill::kTypeCellular &&
properties->type_config->is_cellular()) {
UpdateCustomAPNList(network, properties.get());
}
std::unique_ptr<base::DictionaryValue> onc =
GetOncFromConfigProperties(properties.get(), guid);
if (!onc) {
NET_LOG(ERROR) << "Bad ONC Configuration for " << guid;
std::move(callback).Run(false, kErrorInvalidONCConfiguration);
return;
}
NET_LOG(DEBUG) << "Configuring properties for " << guid << ": " << *onc;
int callback_id = callback_id_++;
set_properties_callbacks_[callback_id] = std::move(callback);
// If the profile path is empty the network is not saved, so we need to call
// CreateConfiguration(). This can happen for EthernetEAP where a default
// service is generated by Shill but may not be saved.
if (network->profile_path().empty()) {
NET_LOG(USER) << "Configuring properties for " << guid
<< " (no profile entry set)";
std::string user_id_hash = LoginState::Get()->primary_user_hash();
network_configuration_handler_->CreateConfiguration(
user_id_hash, *onc,
base::BindOnce(&CrosNetworkConfig::SetPropertiesConfigureSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::SetPropertiesFailure,
weak_factory_.GetWeakPtr(), guid, callback_id));
return;
}
network_configuration_handler_->SetProperties(
network->path(), *onc,
base::BindOnce(&CrosNetworkConfig::SetPropertiesSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::SetPropertiesFailure,
weak_factory_.GetWeakPtr(), guid, callback_id));
}
void CrosNetworkConfig::SetPropertiesSuccess(int callback_id) {
auto iter = set_properties_callbacks_.find(callback_id);
DCHECK(iter != set_properties_callbacks_.end());
std::move(iter->second).Run(/*success=*/true, /*message=*/"");
set_properties_callbacks_.erase(iter);
}
void CrosNetworkConfig::SetPropertiesConfigureSuccess(
int callback_id,
const std::string& service_path,
const std::string& guid) {
auto iter = set_properties_callbacks_.find(callback_id);
DCHECK(iter != set_properties_callbacks_.end());
std::move(iter->second).Run(/*success=*/true, /*message=*/"");
set_properties_callbacks_.erase(iter);
}
void CrosNetworkConfig::SetPropertiesFailure(
const std::string& guid,
int callback_id,
const std::string& error_name,
std::unique_ptr<base::DictionaryValue> error_data) {
auto iter = set_properties_callbacks_.find(callback_id);
DCHECK(iter != set_properties_callbacks_.end());
NET_LOG(ERROR) << "Failed to set network properties: " << guid
<< " Error: " << error_name;
std::move(iter->second).Run(/*success=*/false, error_name);
set_properties_callbacks_.erase(iter);
}
void CrosNetworkConfig::ConfigureNetwork(mojom::ConfigPropertiesPtr properties,
bool shared,
ConfigureNetworkCallback callback) {
if (!network_configuration_handler_) {
NET_LOG(ERROR) << "Configure called with no handler";
std::move(callback).Run(/*guid=*/base::nullopt, kErrorNotReady);
return;
}
if (!shared && UserManager::Get()->GetPrimaryUser() !=
UserManager::Get()->GetActiveUser()) {
NET_LOG(ERROR)
<< "Attempt to set unshared configuration from non primary user";
std::move(callback).Run(/*guid=*/base::nullopt, kErrorAccessToSharedConfig);
return;
}
std::unique_ptr<base::DictionaryValue> onc =
GetOncFromConfigProperties(properties.get(), /*guid=*/base::nullopt);
if (!onc) {
std::move(callback).Run(/*guid=*/base::nullopt,
kErrorInvalidONCConfiguration);
return;
}
std::string user_id_hash =
shared ? "" : LoginState::Get()->primary_user_hash();
int callback_id = callback_id_++;
configure_network_callbacks_[callback_id] = std::move(callback);
network_configuration_handler_->CreateConfiguration(
user_id_hash, *onc,
base::BindOnce(&CrosNetworkConfig::ConfigureNetworkSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::ConfigureNetworkFailure,
weak_factory_.GetWeakPtr(), callback_id));
}
void CrosNetworkConfig::ConfigureNetworkSuccess(int callback_id,
const std::string& service_path,
const std::string& guid) {
auto iter = configure_network_callbacks_.find(callback_id);
DCHECK(iter != configure_network_callbacks_.end());
std::move(iter->second).Run(guid, /*message=*/"");
configure_network_callbacks_.erase(iter);
}
void CrosNetworkConfig::ConfigureNetworkFailure(
int callback_id,
const std::string& error_name,
std::unique_ptr<base::DictionaryValue> error_data) {
auto iter = configure_network_callbacks_.find(callback_id);
DCHECK(iter != configure_network_callbacks_.end());
DCHECK(iter->second);
NET_LOG(ERROR) << "Failed to configure network. Error: " << error_name;
std::move(iter->second).Run(/*guid=*/base::nullopt, error_name);
configure_network_callbacks_.erase(iter);
}
void CrosNetworkConfig::ForgetNetwork(const std::string& guid,
ForgetNetworkCallback callback) {
if (!network_configuration_handler_) {
NET_LOG(ERROR) << "ForgetNetwork called with no handler";
std::move(callback).Run(false);
return;
}
const NetworkState* network =
network_state_handler_->GetNetworkStateFromGuid(guid);
if (!network || network->profile_path().empty()) {
NET_LOG(ERROR) << "ForgetNetwork called with unconfigured network: "
<< guid;
std::move(callback).Run(false);
return;
}
bool allow_forget_shared_config = true;
::onc::ONCSource onc_source = ::onc::ONC_SOURCE_UNKNOWN;
std::string user_id_hash = LoginState::Get()->primary_user_hash();
if (network_configuration_handler_->FindPolicyByGUID(user_id_hash, guid,
&onc_source)) {
if (onc_source == ::onc::ONC_SOURCE_USER_POLICY) {
// Prevent a policy controlled configuration removal.
std::move(callback).Run(false);
return;
}
if (onc_source == ::onc::ONC_SOURCE_DEVICE_POLICY)
allow_forget_shared_config = false;
}
int callback_id = callback_id_++;
forget_network_callbacks_[callback_id] = std::move(callback);
if (allow_forget_shared_config) {
network_configuration_handler_->RemoveConfiguration(
network->path(),
base::BindOnce(&CrosNetworkConfig::ForgetNetworkSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::ForgetNetworkFailure,
weak_factory_.GetWeakPtr(), guid, callback_id));
} else {
network_configuration_handler_->RemoveConfigurationFromCurrentProfile(
network->path(),
base::BindOnce(&CrosNetworkConfig::ForgetNetworkSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::ForgetNetworkFailure,
weak_factory_.GetWeakPtr(), guid, callback_id));
}
}
void CrosNetworkConfig::ForgetNetworkSuccess(int callback_id) {
auto iter = forget_network_callbacks_.find(callback_id);
DCHECK(iter != forget_network_callbacks_.end());
std::move(iter->second).Run(/*success=*/true);
forget_network_callbacks_.erase(iter);
}
void CrosNetworkConfig::ForgetNetworkFailure(
const std::string& guid,
int callback_id,
const std::string& error_name,
std::unique_ptr<base::DictionaryValue> error_data) {
auto iter = forget_network_callbacks_.find(callback_id);
DCHECK(iter != forget_network_callbacks_.end());
NET_LOG(ERROR) << "Failed to forget network: " << guid
<< " Error: " << error_name;
std::move(iter->second).Run(/*success=*/false);
forget_network_callbacks_.erase(iter);
}
void CrosNetworkConfig::SetNetworkTypeEnabledState(
mojom::NetworkType type,
bool enabled,
SetNetworkTypeEnabledStateCallback callback) {
if (!NetworkTypeCanBeDisabled(type)) {
std::move(callback).Run(false);
return;
}
NetworkTypePattern pattern = MojoTypeToPattern(type);
if (!network_state_handler_->IsTechnologyAvailable(pattern)) {
NET_LOG(ERROR) << "Technology unavailable: " << type;
std::move(callback).Run(false);
return;
}
if (network_state_handler_->IsTechnologyProhibited(pattern)) {
NET_LOG(ERROR) << "Technology prohibited: " << type;
std::move(callback).Run(false);
return;
}
// Set the technology enabled state and return true. The call to Shill does
// not have a 'success' callback (and errors are already logged).
network_state_handler_->SetTechnologyEnabled(
pattern, enabled, chromeos::network_handler::ErrorCallback());
std::move(callback).Run(true);
}
void CrosNetworkConfig::SetCellularSimState(
mojom::CellularSimStatePtr sim_state,
SetCellularSimStateCallback callback) {
const DeviceState* device_state =
network_state_handler_->GetDeviceStateByType(
NetworkTypePattern::Cellular());
if (!device_state || device_state->IsSimAbsent()) {
std::move(callback).Run(false);
return;
}
const std::string& lock_type = device_state->sim_lock_type();
// When unblocking a PUK locked SIM, a new PIN must be provided.
if (lock_type == shill::kSIMLockPuk && !sim_state->new_pin) {
NET_LOG(ERROR) << "SetCellularSimState: PUK locked and no pin provided.";
std::move(callback).Run(false);
return;
}
int callback_id = callback_id_++;
set_cellular_sim_state_callbacks_[callback_id] = std::move(callback);
if (lock_type == shill::kSIMLockPuk) {
// Unblock a PUK locked SIM.
network_device_handler_->UnblockPin(
device_state->path(), sim_state->current_pin_or_puk,
*sim_state->new_pin,
base::BindOnce(&CrosNetworkConfig::SetCellularSimStateSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::SetCellularSimStateFailure,
weak_factory_.GetWeakPtr(), callback_id));
return;
}
if (lock_type == shill::kSIMLockPin) {
// Unlock locked SIM.
network_device_handler_->EnterPin(
device_state->path(), sim_state->current_pin_or_puk,
base::BindOnce(&CrosNetworkConfig::SetCellularSimStateSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::SetCellularSimStateFailure,
weak_factory_.GetWeakPtr(), callback_id));
return;
}
if (sim_state->new_pin) {
// Change the SIM PIN.
network_device_handler_->ChangePin(
device_state->path(), sim_state->current_pin_or_puk,
*sim_state->new_pin,
base::BindOnce(&CrosNetworkConfig::SetCellularSimStateSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::SetCellularSimStateFailure,
weak_factory_.GetWeakPtr(), callback_id));
return;
}
// Enable or disable SIM locking.
network_device_handler_->RequirePin(
device_state->path(), sim_state->require_pin,
sim_state->current_pin_or_puk,
base::BindOnce(&CrosNetworkConfig::SetCellularSimStateSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::SetCellularSimStateFailure,
weak_factory_.GetWeakPtr(), callback_id));
}
void CrosNetworkConfig::SetCellularSimStateSuccess(int callback_id) {
auto iter = set_cellular_sim_state_callbacks_.find(callback_id);
DCHECK(iter != set_cellular_sim_state_callbacks_.end());
std::move(iter->second).Run(true);
set_cellular_sim_state_callbacks_.erase(iter);
}
void CrosNetworkConfig::SetCellularSimStateFailure(
int callback_id,
const std::string& error_name,
std::unique_ptr<base::DictionaryValue> error_data) {
auto iter = set_cellular_sim_state_callbacks_.find(callback_id);
DCHECK(iter != set_cellular_sim_state_callbacks_.end());
std::move(iter->second).Run(false);
set_cellular_sim_state_callbacks_.erase(iter);
}
void CrosNetworkConfig::SelectCellularMobileNetwork(
const std::string& guid,
const std::string& network_id,
SelectCellularMobileNetworkCallback callback) {
const DeviceState* device_state = nullptr;
const NetworkState* network_state =
network_state_handler_->GetNetworkStateFromGuid(guid);
if (network_state) {
device_state =
network_state_handler_->GetDeviceState(network_state->device_path());
}
if (!device_state) {
std::move(callback).Run(false);
return;
}
int callback_id = callback_id_++;
select_cellular_mobile_network_callbacks_[callback_id] = std::move(callback);
network_device_handler_->RegisterCellularNetwork(
device_state->path(), network_id,
base::BindOnce(&CrosNetworkConfig::SelectCellularMobileNetworkSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::SelectCellularMobileNetworkFailure,
weak_factory_.GetWeakPtr(), callback_id));
}
void CrosNetworkConfig::SelectCellularMobileNetworkSuccess(int callback_id) {
auto iter = select_cellular_mobile_network_callbacks_.find(callback_id);
DCHECK(iter != select_cellular_mobile_network_callbacks_.end());
std::move(iter->second).Run(true);
select_cellular_mobile_network_callbacks_.erase(iter);
}
void CrosNetworkConfig::SelectCellularMobileNetworkFailure(
int callback_id,
const std::string& error_name,
std::unique_ptr<base::DictionaryValue> error_data) {
auto iter = select_cellular_mobile_network_callbacks_.find(callback_id);
DCHECK(iter != select_cellular_mobile_network_callbacks_.end());
std::move(iter->second).Run(false);
select_cellular_mobile_network_callbacks_.erase(iter);
}
void CrosNetworkConfig::UpdateCustomAPNList(
const NetworkState* network,
const mojom::ConfigProperties* properties) {
const mojom::CellularConfigProperties& cellular_config =
*properties->type_config->get_cellular();
if (!cellular_config.apn) {
return;
}
const DeviceState* device =
network_state_handler_->GetDeviceState(network->device_path());
DCHECK(device);
// Do not update custom APN list if APN is in device APN list.
if (device->HasAPN(cellular_config.apn->access_point_name)) {
return;
}
base::Value custom_apn(base::Value::Type::DICTIONARY);
custom_apn.SetStringKey(::onc::cellular_apn::kAccessPointName,
cellular_config.apn->access_point_name);
SetString(::onc::cellular_apn::kName, cellular_config.apn->name, &custom_apn);
SetString(::onc::cellular_apn::kUsername, cellular_config.apn->username,
&custom_apn);
SetString(::onc::cellular_apn::kPassword, cellular_config.apn->password,
&custom_apn);
SetString(::onc::cellular_apn::kAuthentication,
cellular_config.apn->authentication, &custom_apn);
SetString(::onc::cellular_apn::kLocalizedName,
cellular_config.apn->localized_name, &custom_apn);
SetString(::onc::cellular_apn::kLanguage, cellular_config.apn->language,
&custom_apn);
// The UI currently only supports setting a single custom apn.
base::Value custom_apn_list(base::Value::Type::LIST);
custom_apn_list.Append(std::move(custom_apn));
NET_LOG(DEBUG) << "Saving Custom APN entry for " << network->guid();
NetworkMetadataStore* network_metadata_store =
NetworkHandler::Get()->network_metadata_store();
network_metadata_store->SetCustomAPNList(network->guid(),
std::move(custom_apn_list));
}
std::vector<mojom::ApnPropertiesPtr> CrosNetworkConfig::GetCustomAPNList(
const std::string& guid) {
NetworkMetadataStore* network_metadata_store =
NetworkHandler::Get()->network_metadata_store();
std::vector<mojom::ApnPropertiesPtr> mojo_custom_apns;
const base::Value* custom_apn_list =
network_metadata_store->GetCustomAPNList(guid);
if (!custom_apn_list) {
return mojo_custom_apns;
}
DCHECK(custom_apn_list->is_list());
for (const auto& apn : custom_apn_list->GetList()) {
DCHECK(apn.is_dict());
mojom::ApnPropertiesPtr mojo_apn = mojom::ApnProperties::New();
mojo_apn->access_point_name =
GetRequiredString(&apn, ::onc::cellular_apn::kAccessPointName);
mojo_apn->name = GetString(&apn, ::onc::cellular_apn::kName);
mojo_apn->username = GetString(&apn, ::onc::cellular_apn::kUsername);
mojo_apn->password = GetString(&apn, ::onc::cellular_apn::kPassword);
mojo_apn->authentication =
GetString(&apn, ::onc::cellular_apn::kAuthentication);
mojo_apn->localized_name =
GetString(&apn, ::onc::cellular_apn::kLocalizedName);
mojo_apn->language = GetString(&apn, ::onc::cellular_apn::kLanguage);
mojo_custom_apns.push_back(std::move(mojo_apn));
}
return mojo_custom_apns;
}
void CrosNetworkConfig::RequestNetworkScan(mojom::NetworkType type) {
network_state_handler_->RequestScan(MojoTypeToPattern(type));
}
void CrosNetworkConfig::GetGlobalPolicy(GetGlobalPolicyCallback callback) {
auto result = mojom::GlobalPolicy::New();
// Global network configuration policy values come from the device policy.
const base::DictionaryValue* global_policy_dict =
network_configuration_handler_->GetGlobalConfigFromPolicy(
/*userhash=*/std::string());
if (global_policy_dict) {
result->allow_only_policy_networks_to_autoconnect = GetBoolean(
global_policy_dict,
::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect);
result->allow_only_policy_networks_to_connect = GetBoolean(
global_policy_dict,
::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect);
result->allow_only_policy_networks_to_connect_if_available = GetBoolean(
global_policy_dict, ::onc::global_network_config::
kAllowOnlyPolicyNetworksToConnectIfAvailable);
base::Optional<std::vector<std::string>> blocked_hex_ssids = GetStringList(
global_policy_dict, ::onc::global_network_config::kBlockedHexSSIDs);
if (blocked_hex_ssids)
result->blocked_hex_ssids = std::move(*blocked_hex_ssids);
}
std::move(callback).Run(std::move(result));
}
void CrosNetworkConfig::StartConnect(const std::string& guid,
StartConnectCallback callback) {
std::string service_path = GetServicePathFromGuid(guid);
if (service_path.empty()) {
std::move(callback).Run(mojom::StartConnectResult::kInvalidGuid,
NetworkConnectionHandler::kErrorNotFound);
return;
}
int callback_id = callback_id_++;
start_connect_callbacks_[callback_id] = std::move(callback);
network_connection_handler_->ConnectToNetwork(
service_path,
base::BindOnce(&CrosNetworkConfig::StartConnectSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::StartConnectFailure,
weak_factory_.GetWeakPtr(), callback_id),
true /* check_error_state */, chromeos::ConnectCallbackMode::ON_STARTED);
}
void CrosNetworkConfig::StartConnectSuccess(int callback_id) {
auto iter = start_connect_callbacks_.find(callback_id);
DCHECK(iter != start_connect_callbacks_.end());
std::move(iter->second)
.Run(mojom::StartConnectResult::kSuccess, std::string());
start_connect_callbacks_.erase(iter);
}
void CrosNetworkConfig::StartConnectFailure(
int callback_id,
const std::string& error_name,
std::unique_ptr<base::DictionaryValue> error_data) {
auto iter = start_connect_callbacks_.find(callback_id);
DCHECK(iter != start_connect_callbacks_.end());
mojom::StartConnectResult result;
if (error_name == NetworkConnectionHandler::kErrorNotFound) {
result = mojom::StartConnectResult::kInvalidGuid;
} else if (error_name == NetworkConnectionHandler::kErrorConnected ||
error_name == NetworkConnectionHandler::kErrorConnecting) {
result = mojom::StartConnectResult::kInvalidState;
} else if (error_name == NetworkConnectionHandler::kErrorConnectCanceled) {
result = mojom::StartConnectResult::kCanceled;
} else if (error_name == NetworkConnectionHandler::kErrorPassphraseRequired ||
error_name == NetworkConnectionHandler::kErrorBadPassphrase ||
error_name ==
NetworkConnectionHandler::kErrorCertificateRequired ||
error_name ==
NetworkConnectionHandler::kErrorConfigurationRequired ||
error_name ==
NetworkConnectionHandler::kErrorAuthenticationRequired ||
error_name == NetworkConnectionHandler::kErrorCertLoadTimeout ||
error_name == NetworkConnectionHandler::kErrorConfigureFailed) {
result = mojom::StartConnectResult::kNotConfigured;
} else if (error_name == NetworkConnectionHandler::kErrorBlockedByPolicy) {
result = mojom::StartConnectResult::kBlocked;
} else {
result = mojom::StartConnectResult::kUnknown;
}
std::move(iter->second).Run(result, error_name);
start_connect_callbacks_.erase(iter);
}
void CrosNetworkConfig::StartDisconnect(const std::string& guid,
StartDisconnectCallback callback) {
std::string service_path = GetServicePathFromGuid(guid);
if (service_path.empty()) {
std::move(callback).Run(false);
return;
}
int callback_id = callback_id_++;
start_disconnect_callbacks_[callback_id] = std::move(callback);
network_connection_handler_->DisconnectNetwork(
service_path,
base::BindOnce(&CrosNetworkConfig::StartDisconnectSuccess,
weak_factory_.GetWeakPtr(), callback_id),
base::BindOnce(&CrosNetworkConfig::StartDisconnectFailure,
weak_factory_.GetWeakPtr(), callback_id));
}
void CrosNetworkConfig::StartDisconnectSuccess(int callback_id) {
auto iter = start_disconnect_callbacks_.find(callback_id);
DCHECK(iter != start_disconnect_callbacks_.end());
std::move(iter->second).Run(true);
start_disconnect_callbacks_.erase(iter);
}
void CrosNetworkConfig::StartDisconnectFailure(
int callback_id,
const std::string& error_name,
std::unique_ptr<base::DictionaryValue> error_data) {
auto iter = start_disconnect_callbacks_.find(callback_id);
DCHECK(iter != start_disconnect_callbacks_.end());
std::move(iter->second).Run(false);
start_disconnect_callbacks_.erase(iter);
}
void CrosNetworkConfig::SetVpnProviders(
std::vector<mojom::VpnProviderPtr> providers) {
vpn_providers_ = std::move(providers);
for (auto& observer : observers_)
observer->OnVpnProvidersChanged();
}
void CrosNetworkConfig::GetVpnProviders(GetVpnProvidersCallback callback) {
std::move(callback).Run(mojo::Clone(vpn_providers_));
}
void CrosNetworkConfig::GetNetworkCertificates(
GetNetworkCertificatesCallback callback) {
const std::vector<NetworkCertificateHandler::Certificate>&
handler_server_cas =
network_certificate_handler_->server_ca_certificates();
std::vector<mojom::NetworkCertificatePtr> server_cas;
for (const auto& cert : handler_server_cas)
server_cas.push_back(GetMojoCert(cert, mojom::CertificateType::kServerCA));
std::vector<mojom::NetworkCertificatePtr> user_certs;
const std::vector<NetworkCertificateHandler::Certificate>&
handler_user_certs = network_certificate_handler_->client_certificates();
for (const auto& cert : handler_user_certs)
user_certs.push_back(GetMojoCert(cert, mojom::CertificateType::kUserCert));
std::move(callback).Run(std::move(server_cas), std::move(user_certs));
}
// NetworkStateHandlerObserver
void CrosNetworkConfig::NetworkListChanged() {
for (auto& observer : observers_)
observer->OnNetworkStateListChanged();
}
void CrosNetworkConfig::DeviceListChanged() {
for (auto& observer : observers_)
observer->OnDeviceStateListChanged();
}
void CrosNetworkConfig::ActiveNetworksChanged(
const std::vector<const NetworkState*>& active_networks) {
std::vector<mojom::NetworkStatePropertiesPtr> result;
for (const NetworkState* network : active_networks) {
mojom::NetworkStatePropertiesPtr mojo_network =
NetworkStateToMojo(network_state_handler_, vpn_providers_, network);
if (mojo_network)
result.emplace_back(std::move(mojo_network));
}
for (auto& observer : observers_)
observer->OnActiveNetworksChanged(mojo::Clone(result));
}
void CrosNetworkConfig::NetworkPropertiesUpdated(const NetworkState* network) {
if (network->type() == shill::kTypeEthernetEap)
return;
mojom::NetworkStatePropertiesPtr mojo_network =
NetworkStateToMojo(network_state_handler_, vpn_providers_, network);
if (!mojo_network)
return;
for (auto& observer : observers_)
observer->OnNetworkStateChanged(mojo_network.Clone());
}
void CrosNetworkConfig::DevicePropertiesUpdated(const DeviceState* device) {
DeviceListChanged();
}
void CrosNetworkConfig::ScanCompleted(const DeviceState* device) {
DeviceListChanged();
}
void CrosNetworkConfig::ScanStarted(const DeviceState* device) {
DeviceListChanged();
}
void CrosNetworkConfig::OnShuttingDown() {
if (network_state_handler_->HasObserver(this))
network_state_handler_->RemoveObserver(this, FROM_HERE);
network_state_handler_ = nullptr;
}
void CrosNetworkConfig::OnCertificatesChanged() {
for (auto& observer : observers_)
observer->OnNetworkCertificatesChanged();
}
const std::string& CrosNetworkConfig::GetServicePathFromGuid(
const std::string& guid) {
const chromeos::NetworkState* network =
network_state_handler_->GetNetworkStateFromGuid(guid);
return network ? network->path() : base::EmptyString();
}
} // namespace network_config
} // namespace chromeos