Index: chromeos/network/policy_util.cc |
diff --git a/chromeos/network/policy_util.cc b/chromeos/network/policy_util.cc |
index 7e27d97d64961e30e45ecdbdd677794ab363c68e..33fc05a1053aeeb9d62e4820982bf8edea9891e4 100644 |
--- a/chromeos/network/policy_util.cc |
+++ b/chromeos/network/policy_util.cc |
@@ -125,26 +125,172 @@ bool IsPolicyMatching(const base::DictionaryValue& policy, |
return false; |
} |
+base::DictionaryValue* GetOrCreateDictionary(const std::string& key, |
+ base::DictionaryValue* dict) { |
+ base::DictionaryValue* inner_dict = NULL; |
+ if (!dict->GetDictionaryWithoutPathExpansion(key, &inner_dict)) { |
+ inner_dict = new base::DictionaryValue; |
+ dict->SetWithoutPathExpansion(key, inner_dict); |
+ } |
+ return inner_dict; |
+} |
+ |
+base::DictionaryValue* GetOrCreateNestedDictionary( |
+ const std::string& key1, |
+ const std::string& key2, |
+ base::DictionaryValue* dict) { |
+ base::DictionaryValue* inner_dict = GetOrCreateDictionary(key1, dict); |
+ return GetOrCreateDictionary(key2, inner_dict); |
+} |
+ |
+void ApplyGlobalAutoconnectPolicy( |
+ NetworkProfile::Type profile_type, |
+ base::DictionaryValue* augmented_onc_network) { |
+ base::DictionaryValue* type_dictionary = NULL; |
+ augmented_onc_network->GetDictionaryWithoutPathExpansion( |
+ ::onc::network_config::kType, &type_dictionary); |
+ std::string type; |
+ if (!type_dictionary || |
+ !type_dictionary->GetStringWithoutPathExpansion( |
+ ::onc::kAugmentationActiveSetting, &type) || |
+ type.empty()) { |
+ LOG(ERROR) << "ONC dictionary with no Type."; |
+ return; |
+ } |
+ |
+ // Managed dictionaries don't contain empty dictionaries (see onc_merger.cc), |
+ // so add the Autoconnect dictionary in case Shill didn't report a value. |
+ base::DictionaryValue* auto_connect_dictionary = NULL; |
+ if (type == ::onc::network_type::kWiFi) { |
+ auto_connect_dictionary = |
+ GetOrCreateNestedDictionary(::onc::network_config::kWiFi, |
+ ::onc::wifi::kAutoConnect, |
+ augmented_onc_network); |
+ } else if (type == ::onc::network_type::kVPN) { |
+ auto_connect_dictionary = |
+ GetOrCreateNestedDictionary(::onc::network_config::kVPN, |
+ ::onc::vpn::kAutoConnect, |
+ augmented_onc_network); |
+ } else { |
+ return; // Network type without auto-connect property. |
+ } |
+ |
+ std::string policy_source; |
+ if (profile_type == NetworkProfile::TYPE_USER) |
+ policy_source = ::onc::kAugmentationUserPolicy; |
+ else if(profile_type == NetworkProfile::TYPE_SHARED) |
+ policy_source = ::onc::kAugmentationDevicePolicy; |
+ else |
+ NOTREACHED(); |
+ |
+ auto_connect_dictionary->SetBooleanWithoutPathExpansion(policy_source, false); |
+ auto_connect_dictionary->SetStringWithoutPathExpansion( |
+ ::onc::kAugmentationEffectiveSetting, policy_source); |
+} |
+ |
} // namespace |
+scoped_ptr<base::DictionaryValue> CreateManagedONC( |
+ const base::DictionaryValue* global_policy, |
+ const base::DictionaryValue* network_policy, |
+ const base::DictionaryValue* user_settings, |
+ const base::DictionaryValue* active_settings, |
+ const NetworkProfile* profile) { |
+ const base::DictionaryValue* user_policy = NULL; |
+ const base::DictionaryValue* device_policy = NULL; |
+ const base::DictionaryValue* nonshared_user_settings = NULL; |
+ const base::DictionaryValue* shared_user_settings = NULL; |
+ |
+ if (profile) { |
+ if (profile->type() == NetworkProfile::TYPE_SHARED) { |
+ device_policy = network_policy; |
+ shared_user_settings = user_settings; |
+ } else if (profile->type() == NetworkProfile::TYPE_USER) { |
+ user_policy = network_policy; |
+ nonshared_user_settings = user_settings; |
+ } else { |
+ NOTREACHED(); |
+ } |
+ } |
+ |
+ // This call also removes credentials from policies. |
+ scoped_ptr<base::DictionaryValue> augmented_onc_network = |
+ onc::MergeSettingsAndPoliciesToAugmented( |
+ onc::kNetworkConfigurationSignature, |
+ user_policy, |
+ device_policy, |
+ nonshared_user_settings, |
+ shared_user_settings, |
+ active_settings); |
+ |
+ // If present, apply the Autoconnect policy only to networks that are not |
+ // managed by policy. |
+ if (!network_policy && global_policy && profile) { |
+ bool allow_only_policy_autoconnect = false; |
+ global_policy->GetBooleanWithoutPathExpansion( |
+ ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect, |
+ &allow_only_policy_autoconnect); |
+ if (allow_only_policy_autoconnect) { |
+ ApplyGlobalAutoconnectPolicy(profile->type(), |
+ augmented_onc_network.get()); |
+ } |
+ } |
+ |
+ return augmented_onc_network.Pass(); |
+} |
+ |
+void SetShillPropertiesForGlobalPolicy( |
+ const base::DictionaryValue& shill_dictionary, |
+ const base::DictionaryValue& global_network_policy, |
+ base::DictionaryValue* shill_properties_to_update) { |
+ // kAllowOnlyPolicyNetworksToAutoconnect is currently the only global config. |
+ |
+ std::string type; |
+ shill_dictionary.GetStringWithoutPathExpansion(shill::kTypeProperty, &type); |
+ if (NetworkTypePattern::Ethernet().MatchesType(type)) |
+ return; // Autoconnect for Ethernet cannot be configured. |
+ |
+ // By default all networks are allowed to autoconnect. |
+ bool only_policy_autoconnect = false; |
+ global_network_policy.GetBooleanWithoutPathExpansion( |
+ ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect, |
+ &only_policy_autoconnect); |
+ if (!only_policy_autoconnect) |
+ return; |
+ |
+ bool old_autoconnect = false; |
+ if (shill_dictionary.GetBooleanWithoutPathExpansion( |
+ shill::kAutoConnectProperty, &old_autoconnect) && |
+ !old_autoconnect) { |
+ // Autoconnect is already explictly disabled. No need to set it again. |
+ return; |
+ } |
+ |
+ // If autconnect is not explicitly set yet, it might automatically be enabled |
+ // by Shill. To prevent that, disable it explicitly. |
+ shill_properties_to_update->SetBooleanWithoutPathExpansion( |
+ shill::kAutoConnectProperty, false); |
+} |
+ |
scoped_ptr<base::DictionaryValue> CreateShillConfiguration( |
const NetworkProfile& profile, |
const std::string& guid, |
- const base::DictionaryValue* policy, |
+ const base::DictionaryValue* global_policy, |
+ const base::DictionaryValue* network_policy, |
const base::DictionaryValue* user_settings) { |
scoped_ptr<base::DictionaryValue> effective; |
::onc::ONCSource onc_source = ::onc::ONC_SOURCE_NONE; |
- if (policy) { |
+ if (network_policy) { |
if (profile.type() == NetworkProfile::TYPE_SHARED) { |
effective = onc::MergeSettingsAndPoliciesToEffective( |
NULL, // no user policy |
- policy, // device policy |
+ network_policy, // device policy |
NULL, // no user settings |
user_settings); // shared settings |
onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY; |
} else if (profile.type() == NetworkProfile::TYPE_USER) { |
effective = onc::MergeSettingsAndPoliciesToEffective( |
- policy, // user policy |
+ network_policy, // user policy |
NULL, // no device policy |
user_settings, // user settings |
NULL); // no shared settings |
@@ -178,6 +324,12 @@ scoped_ptr<base::DictionaryValue> CreateShillConfiguration( |
shill_dictionary->SetStringWithoutPathExpansion(shill::kProfileProperty, |
profile.path); |
+ if (!network_policy && global_policy) { |
+ // The network isn't managed. Global network policies have to be applied. |
+ SetShillPropertiesForGlobalPolicy( |
+ *shill_dictionary, *global_policy, shill_dictionary.get()); |
+ } |
+ |
scoped_ptr<NetworkUIData> ui_data(NetworkUIData::CreateFromONC(onc_source)); |
if (user_settings) { |