1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/network/managed_network_configuration_handler_impl.h"
10 #include "base/bind.h"
11 #include "base/guid.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/stl_util.h"
17 #include "base/values.h"
18 #include "chromeos/dbus/shill_manager_client.h"
19 #include "chromeos/dbus/shill_profile_client.h"
20 #include "chromeos/dbus/shill_service_client.h"
21 #include "chromeos/network/device_state.h"
22 #include "chromeos/network/network_configuration_handler.h"
23 #include "chromeos/network/network_event_log.h"
24 #include "chromeos/network/network_policy_observer.h"
25 #include "chromeos/network/network_profile.h"
26 #include "chromeos/network/network_profile_handler.h"
27 #include "chromeos/network/network_state.h"
28 #include "chromeos/network/network_state_handler.h"
29 #include "chromeos/network/network_ui_data.h"
30 #include "chromeos/network/onc/onc_merger.h"
31 #include "chromeos/network/onc/onc_signature.h"
32 #include "chromeos/network/onc/onc_translator.h"
33 #include "chromeos/network/onc/onc_validator.h"
34 #include "chromeos/network/policy_util.h"
35 #include "chromeos/network/shill_property_util.h"
36 #include "components/onc/onc_constants.h"
37 #include "third_party/cros_system_api/dbus/service_constants.h"
43 typedef std::map<std::string, const base::DictionaryValue*> GuidToPolicyMap;
45 // These are error strings used for error callbacks. None of these error
46 // messages are user-facing: they should only appear in logs.
47 const char kInvalidUserSettings[] = "InvalidUserSettings";
48 const char kNetworkAlreadyConfigured[] = "NetworkAlreadyConfigured";
49 const char kPoliciesNotInitialized[] = "PoliciesNotInitialized";
50 const char kProfileNotInitialized[] = "ProflieNotInitialized";
51 const char kSetOnUnconfiguredNetwork[] = "SetCalledOnUnconfiguredNetwork";
52 const char kUnknownProfilePath[] = "UnknownProfilePath";
53 const char kUnknownServicePath[] = "UnknownServicePath";
55 std::string ToDebugString(::onc::ONCSource source,
56 const std::string& userhash) {
57 return source == ::onc::ONC_SOURCE_USER_POLICY ?
58 ("user policy of " + userhash) : "device policy";
61 void InvokeErrorCallback(const std::string& service_path,
62 const network_handler::ErrorCallback& error_callback,
63 const std::string& error_name) {
64 std::string error_msg = "ManagedConfig Error: " + error_name;
65 NET_LOG_ERROR(error_msg, service_path);
66 network_handler::RunErrorCallback(
67 error_callback, service_path, error_name, error_msg);
70 void LogErrorWithDict(const tracked_objects::Location& from_where,
71 const std::string& error_name,
72 scoped_ptr<base::DictionaryValue> error_data) {
73 network_event_log::internal::AddEntry(
74 from_where.file_name(), from_where.line_number(),
75 network_event_log::LOG_LEVEL_ERROR,
79 const base::DictionaryValue* GetByGUID(const GuidToPolicyMap& policies,
80 const std::string& guid) {
81 GuidToPolicyMap::const_iterator it = policies.find(guid);
82 if (it == policies.end())
89 struct ManagedNetworkConfigurationHandlerImpl::Policies {
92 GuidToPolicyMap per_network_config;
93 base::DictionaryValue global_network_config;
96 ManagedNetworkConfigurationHandlerImpl::Policies::~Policies() {
97 STLDeleteValues(&per_network_config);
100 void ManagedNetworkConfigurationHandlerImpl::AddObserver(
101 NetworkPolicyObserver* observer) {
102 observers_.AddObserver(observer);
105 void ManagedNetworkConfigurationHandlerImpl::RemoveObserver(
106 NetworkPolicyObserver* observer) {
107 observers_.RemoveObserver(observer);
110 void ManagedNetworkConfigurationHandlerImpl::GetManagedProperties(
111 const std::string& userhash,
112 const std::string& service_path,
113 const network_handler::DictionaryResultCallback& callback,
114 const network_handler::ErrorCallback& error_callback) {
115 if (!GetPoliciesForUser(userhash) || !GetPoliciesForUser(std::string())) {
116 InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
119 network_configuration_handler_->GetProperties(
122 &ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback,
123 weak_ptr_factory_.GetWeakPtr(),
129 void ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback(
130 const network_handler::DictionaryResultCallback& callback,
131 const network_handler::ErrorCallback& error_callback,
132 const std::string& service_path,
133 const base::DictionaryValue& shill_properties) {
134 std::string profile_path;
135 shill_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
137 const NetworkProfile* profile =
138 network_profile_handler_->GetProfileForPath(profile_path);
140 NET_LOG_ERROR("No profile for service: " + profile_path, service_path);
142 scoped_ptr<NetworkUIData> ui_data =
143 shill_property_util::GetUIDataFromProperties(shill_properties);
145 const base::DictionaryValue* user_settings = NULL;
146 const base::DictionaryValue* shared_settings = NULL;
148 if (ui_data && profile) {
149 if (profile->type() == NetworkProfile::TYPE_SHARED)
150 shared_settings = ui_data->user_settings();
151 else if (profile->type() == NetworkProfile::TYPE_USER)
152 user_settings = ui_data->user_settings();
155 } else if (profile) {
156 NET_LOG_ERROR("Service contains empty or invalid UIData", service_path);
157 // TODO(pneubeck): add a conversion of user configured entries of old
158 // ChromeOS versions. We will have to use a heuristic to determine which
159 // properties _might_ be user configured.
162 scoped_ptr<base::DictionaryValue> properties_copy(
163 shill_properties.DeepCopy());
164 // Add the IPConfigs to the dictionary before the ONC translation.
165 GetIPConfigs(service_path, properties_copy.get());
167 scoped_ptr<base::DictionaryValue> active_settings(
168 onc::TranslateShillServiceToONCPart(
170 &onc::kNetworkWithStateSignature));
173 active_settings->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
176 const base::DictionaryValue* user_policy = NULL;
177 const base::DictionaryValue* device_policy = NULL;
178 if (!guid.empty() && profile) {
179 const Policies* policies = GetPoliciesForProfile(*profile);
182 service_path, error_callback, kPoliciesNotInitialized);
185 const base::DictionaryValue* policy =
186 GetByGUID(policies->per_network_config, guid);
187 if (profile->type() == NetworkProfile::TYPE_SHARED)
188 device_policy = policy;
189 else if (profile->type() == NetworkProfile::TYPE_USER)
190 user_policy = policy;
195 // This call also removes credentials from policies.
196 scoped_ptr<base::DictionaryValue> augmented_properties =
197 onc::MergeSettingsAndPoliciesToAugmented(
198 onc::kNetworkConfigurationSignature,
203 active_settings.get());
204 callback.Run(service_path, *augmented_properties);
207 void ManagedNetworkConfigurationHandlerImpl::GetProperties(
208 const std::string& service_path,
209 const network_handler::DictionaryResultCallback& callback,
210 const network_handler::ErrorCallback& error_callback) {
211 network_configuration_handler_->GetProperties(
213 base::Bind(&ManagedNetworkConfigurationHandlerImpl::GetPropertiesCallback,
214 weak_ptr_factory_.GetWeakPtr(),
219 void ManagedNetworkConfigurationHandlerImpl::GetPropertiesCallback(
220 const network_handler::DictionaryResultCallback& callback,
221 const std::string& service_path,
222 const base::DictionaryValue& shill_properties) {
223 scoped_ptr<base::DictionaryValue> properties_copy(
224 shill_properties.DeepCopy());
225 // Add the IPConfigs to the dictionary before the ONC translation.
226 GetIPConfigs(service_path, properties_copy.get());
228 scoped_ptr<base::DictionaryValue> onc_network(
229 onc::TranslateShillServiceToONCPart(
231 &onc::kNetworkWithStateSignature));
232 callback.Run(service_path, *onc_network);
235 void ManagedNetworkConfigurationHandlerImpl::SetProperties(
236 const std::string& service_path,
237 const base::DictionaryValue& user_settings,
238 const base::Closure& callback,
239 const network_handler::ErrorCallback& error_callback) const {
240 const NetworkState* state =
241 network_state_handler_->GetNetworkState(service_path);
244 InvokeErrorCallback(service_path, error_callback, kUnknownServicePath);
248 std::string guid = state->guid();
250 // TODO(pneubeck): create an initial configuration in this case. As for
251 // CreateConfiguration, user settings from older ChromeOS versions have to
254 service_path, error_callback, kSetOnUnconfiguredNetwork);
258 const std::string& profile_path = state->profile_path();
259 const NetworkProfile *profile =
260 network_profile_handler_->GetProfileForPath(profile_path);
262 InvokeErrorCallback(service_path, error_callback, kUnknownProfilePath);
266 VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
267 << profile->ToDebugString();
269 const Policies* policies = GetPoliciesForProfile(*profile);
271 InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
275 // Validate the ONC dictionary. We are liberal and ignore unknown field
276 // names. User settings are only partial ONC, thus we ignore missing fields.
277 onc::Validator validator(false, // Ignore unknown fields.
278 false, // Ignore invalid recommended field names.
279 false, // Ignore missing fields.
280 false); // This ONC does not come from policy.
282 onc::Validator::Result validation_result;
283 scoped_ptr<base::DictionaryValue> validated_user_settings =
284 validator.ValidateAndRepairObject(
285 &onc::kNetworkConfigurationSignature,
289 if (validation_result == onc::Validator::INVALID) {
290 InvokeErrorCallback(service_path, error_callback, kInvalidUserSettings);
293 if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
294 LOG(WARNING) << "Validation of ONC user settings produced warnings.";
296 const base::DictionaryValue* policy =
297 GetByGUID(policies->per_network_config, guid);
298 VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
300 scoped_ptr<base::DictionaryValue> shill_dictionary(
301 policy_util::CreateShillConfiguration(
302 *profile, guid, policy, validated_user_settings.get()));
304 network_configuration_handler_->SetProperties(
305 service_path, *shill_dictionary, callback, error_callback);
308 void ManagedNetworkConfigurationHandlerImpl::CreateConfiguration(
309 const std::string& userhash,
310 const base::DictionaryValue& properties,
311 const network_handler::StringResultCallback& callback,
312 const network_handler::ErrorCallback& error_callback) const {
313 const Policies* policies = GetPoliciesForUser(userhash);
315 InvokeErrorCallback("", error_callback, kPoliciesNotInitialized);
319 if (policy_util::FindMatchingPolicy(policies->per_network_config,
321 InvokeErrorCallback("", error_callback, kNetworkAlreadyConfigured);
325 const NetworkProfile* profile =
326 network_profile_handler_->GetProfileForUserhash(userhash);
328 InvokeErrorCallback("", error_callback, kProfileNotInitialized);
332 // TODO(pneubeck): In case of WiFi, check that no other configuration for the
333 // same {SSID, mode, security} exists. We don't support such multiple
334 // configurations, yet.
336 // Generate a new GUID for this configuration. Ignore the maybe provided GUID
337 // in |properties| as it is not our own and from an untrusted source.
338 std::string guid = base::GenerateGUID();
339 scoped_ptr<base::DictionaryValue> shill_dictionary(
340 policy_util::CreateShillConfiguration(
341 *profile, guid, NULL /*no policy*/, &properties));
343 network_configuration_handler_->CreateConfiguration(
344 *shill_dictionary, callback, error_callback);
347 void ManagedNetworkConfigurationHandlerImpl::RemoveConfiguration(
348 const std::string& service_path,
349 const base::Closure& callback,
350 const network_handler::ErrorCallback& error_callback) const {
351 network_configuration_handler_->RemoveConfiguration(
352 service_path, callback, error_callback);
355 void ManagedNetworkConfigurationHandlerImpl::SetPolicy(
356 ::onc::ONCSource onc_source,
357 const std::string& userhash,
358 const base::ListValue& network_configs_onc,
359 const base::DictionaryValue& global_network_config) {
360 VLOG(1) << "Setting policies from " << ToDebugString(onc_source, userhash)
363 // |userhash| must be empty for device policies.
364 DCHECK(onc_source != ::onc::ONC_SOURCE_DEVICE_POLICY ||
366 Policies* policies = NULL;
367 if (ContainsKey(policies_by_user_, userhash)) {
368 policies = policies_by_user_[userhash].get();
370 policies = new Policies;
371 policies_by_user_[userhash] = make_linked_ptr(policies);
374 policies->global_network_config.MergeDictionary(&global_network_config);
376 GuidToPolicyMap old_per_network_config;
377 policies->per_network_config.swap(old_per_network_config);
379 // This stores all GUIDs of policies that have changed or are new.
380 std::set<std::string> modified_policies;
382 for (base::ListValue::const_iterator it = network_configs_onc.begin();
383 it != network_configs_onc.end(); ++it) {
384 const base::DictionaryValue* network = NULL;
385 (*it)->GetAsDictionary(&network);
389 network->GetStringWithoutPathExpansion(::onc::network_config::kGUID, &guid);
390 DCHECK(!guid.empty());
392 if (policies->per_network_config.count(guid) > 0) {
393 NET_LOG_ERROR("ONC from " + ToDebugString(onc_source, userhash) +
394 " contains several entries for the same GUID ", guid);
395 delete policies->per_network_config[guid];
397 const base::DictionaryValue* new_entry = network->DeepCopy();
398 policies->per_network_config[guid] = new_entry;
400 const base::DictionaryValue* old_entry = old_per_network_config[guid];
401 if (!old_entry || !old_entry->Equals(new_entry))
402 modified_policies.insert(guid);
405 STLDeleteValues(&old_per_network_config);
407 const NetworkProfile* profile =
408 network_profile_handler_->GetProfileForUserhash(userhash);
410 VLOG(1) << "The relevant Shill profile isn't initialized yet, postponing "
411 << "policy application.";
415 scoped_refptr<PolicyApplicator> applicator =
416 new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
418 policies->per_network_config,
419 policies->global_network_config,
424 void ManagedNetworkConfigurationHandlerImpl::OnProfileAdded(
425 const NetworkProfile& profile) {
426 VLOG(1) << "Adding profile " << profile.ToDebugString() << "'.";
428 const Policies* policies = GetPoliciesForProfile(profile);
430 VLOG(1) << "The relevant policy is not initialized, "
431 << "postponing policy application.";
435 std::set<std::string> policy_guids;
436 for (GuidToPolicyMap::const_iterator it =
437 policies->per_network_config.begin();
438 it != policies->per_network_config.end(); ++it) {
439 policy_guids.insert(it->first);
442 scoped_refptr<PolicyApplicator> applicator =
443 new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
445 policies->per_network_config,
446 policies->global_network_config,
451 void ManagedNetworkConfigurationHandlerImpl::OnProfileRemoved(
452 const NetworkProfile& profile) {
453 // Nothing to do in this case.
456 void ManagedNetworkConfigurationHandlerImpl::CreateConfigurationFromPolicy(
457 const base::DictionaryValue& shill_properties) {
458 network_configuration_handler_->CreateConfiguration(
461 &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork,
462 weak_ptr_factory_.GetWeakPtr()),
463 base::Bind(&LogErrorWithDict, FROM_HERE));
466 void ManagedNetworkConfigurationHandlerImpl::
467 UpdateExistingConfigurationWithPropertiesFromPolicy(
468 const base::DictionaryValue& existing_properties,
469 const base::DictionaryValue& new_properties) {
470 base::DictionaryValue shill_properties;
473 existing_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
475 if (profile.empty()) {
476 NET_LOG_ERROR("Missing profile property",
477 shill_property_util::GetNetworkIdFromProperties(
478 existing_properties));
481 shill_properties.SetStringWithoutPathExpansion(shill::kProfileProperty,
484 if (!shill_property_util::CopyIdentifyingProperties(existing_properties,
485 &shill_properties)) {
486 NET_LOG_ERROR("Missing identifying properties",
487 shill_property_util::GetNetworkIdFromProperties(
488 existing_properties));
491 shill_properties.MergeDictionary(&new_properties);
493 network_configuration_handler_->CreateConfiguration(
496 &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork,
497 weak_ptr_factory_.GetWeakPtr()),
498 base::Bind(&LogErrorWithDict, FROM_HERE));
501 void ManagedNetworkConfigurationHandlerImpl::OnPoliciesApplied() {
502 // After all policies were applied, trigger an update of the network lists.
503 if (network_state_handler_)
504 network_state_handler_->UpdateManagerProperties();
507 const base::DictionaryValue*
508 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGUID(
509 const std::string userhash,
510 const std::string& guid,
511 ::onc::ONCSource* onc_source) const {
512 *onc_source = ::onc::ONC_SOURCE_NONE;
514 if (!userhash.empty()) {
515 const Policies* user_policies = GetPoliciesForUser(userhash);
517 const base::DictionaryValue* policy =
518 GetByGUID(user_policies->per_network_config, guid);
520 *onc_source = ::onc::ONC_SOURCE_USER_POLICY;
526 const Policies* device_policies = GetPoliciesForUser(std::string());
527 if (device_policies) {
528 const base::DictionaryValue* policy =
529 GetByGUID(device_policies->per_network_config, guid);
531 *onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
539 const base::DictionaryValue*
540 ManagedNetworkConfigurationHandlerImpl::GetGlobalConfigFromPolicy(
541 const std::string userhash) const {
542 const Policies* policies = GetPoliciesForUser(userhash);
546 return &policies->global_network_config;
548 const base::DictionaryValue*
549 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGuidAndProfile(
550 const std::string& guid,
551 const std::string& profile_path) const {
552 const NetworkProfile* profile =
553 network_profile_handler_->GetProfileForPath(profile_path);
555 NET_LOG_ERROR("Profile path unknown:" + profile_path, guid);
559 const Policies* policies = GetPoliciesForProfile(*profile);
563 return GetByGUID(policies->per_network_config, guid);
566 const ManagedNetworkConfigurationHandlerImpl::Policies*
567 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForUser(
568 const std::string& userhash) const {
569 UserToPoliciesMap::const_iterator it = policies_by_user_.find(userhash);
570 if (it == policies_by_user_.end())
572 return it->second.get();
575 const ManagedNetworkConfigurationHandlerImpl::Policies*
576 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForProfile(
577 const NetworkProfile& profile) const {
578 DCHECK(profile.type() != NetworkProfile::TYPE_SHARED ||
579 profile.userhash.empty());
580 return GetPoliciesForUser(profile.userhash);
583 ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
584 : network_state_handler_(NULL),
585 network_profile_handler_(NULL),
586 network_configuration_handler_(NULL),
587 weak_ptr_factory_(this) {}
589 ManagedNetworkConfigurationHandlerImpl::
590 ~ManagedNetworkConfigurationHandlerImpl() {
591 network_profile_handler_->RemoveObserver(this);
594 void ManagedNetworkConfigurationHandlerImpl::Init(
595 NetworkStateHandler* network_state_handler,
596 NetworkProfileHandler* network_profile_handler,
597 NetworkConfigurationHandler* network_configuration_handler) {
598 network_state_handler_ = network_state_handler;
599 network_profile_handler_ = network_profile_handler;
600 network_configuration_handler_ = network_configuration_handler;
601 network_profile_handler_->AddObserver(this);
604 void ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork(
605 const std::string& service_path) {
606 if (service_path.empty())
609 NetworkPolicyObserver, observers_, PolicyApplied(service_path));
612 void ManagedNetworkConfigurationHandlerImpl::GetIPConfigs(
613 const std::string& service_path,
614 base::DictionaryValue* properties) {
615 std::string connection_state;
616 properties->GetStringWithoutPathExpansion(
617 shill::kStateProperty, &connection_state);
618 if (!NetworkState::StateIsConnected(connection_state))
621 // Get the IPConfig properties from the device and store them in "IPConfigs"
622 // (plural) in the properties dictionary. (Note: Shill only provides a single
623 // "IPConfig" property for a network service, but a consumer of this API may
624 // want information about all ipv4 and ipv6 IPConfig properties.
626 properties->GetStringWithoutPathExpansion(shill::kDeviceProperty, &device);
627 const DeviceState* device_state =
628 network_state_handler_->GetDeviceState(device);
630 NET_LOG_ERROR("GetIPConfigs: no device: " + device, service_path);
633 // Convert IPConfig dictionary to a ListValue.
634 base::ListValue* ip_configs = new base::ListValue;
635 for (base::DictionaryValue::Iterator iter(device_state->ip_configs());
636 !iter.IsAtEnd(); iter.Advance()) {
637 ip_configs->Append(iter.value().DeepCopy());
639 properties->SetWithoutPathExpansion(shill::kIPConfigsProperty, ip_configs);
642 } // namespace chromeos