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/network_configuration_handler.h"
22 #include "chromeos/network/network_event_log.h"
23 #include "chromeos/network/network_policy_observer.h"
24 #include "chromeos/network/network_profile.h"
25 #include "chromeos/network/network_profile_handler.h"
26 #include "chromeos/network/network_state.h"
27 #include "chromeos/network/network_state_handler.h"
28 #include "chromeos/network/network_ui_data.h"
29 #include "chromeos/network/onc/onc_merger.h"
30 #include "chromeos/network/onc/onc_signature.h"
31 #include "chromeos/network/onc/onc_translator.h"
32 #include "chromeos/network/onc/onc_validator.h"
33 #include "chromeos/network/policy_util.h"
34 #include "chromeos/network/shill_property_util.h"
35 #include "components/onc/onc_constants.h"
36 #include "third_party/cros_system_api/dbus/service_constants.h"
42 typedef std::map<std::string, const base::DictionaryValue*> GuidToPolicyMap;
44 // These are error strings used for error callbacks. None of these error
45 // messages are user-facing: they should only appear in logs.
46 const char kInvalidUserSettings[] = "InvalidUserSettings";
47 const char kNetworkAlreadyConfigured[] = "NetworkAlreadyConfigured";
48 const char kPoliciesNotInitialized[] = "PoliciesNotInitialized";
49 const char kProfileNotInitialized[] = "ProflieNotInitialized";
50 const char kSetOnUnconfiguredNetwork[] = "SetCalledOnUnconfiguredNetwork";
51 const char kUnknownProfilePath[] = "UnknownProfilePath";
52 const char kUnknownServicePath[] = "UnknownServicePath";
54 std::string ToDebugString(::onc::ONCSource source,
55 const std::string& userhash) {
56 return source == ::onc::ONC_SOURCE_USER_POLICY ?
57 ("user policy of " + userhash) : "device policy";
60 void InvokeErrorCallback(const std::string& service_path,
61 const network_handler::ErrorCallback& error_callback,
62 const std::string& error_name) {
63 std::string error_msg = "ManagedConfig Error: " + error_name;
64 NET_LOG_ERROR(error_msg, service_path);
65 network_handler::RunErrorCallback(
66 error_callback, service_path, error_name, error_msg);
69 void LogErrorWithDict(const tracked_objects::Location& from_where,
70 const std::string& error_name,
71 scoped_ptr<base::DictionaryValue> error_data) {
72 LOG(ERROR) << from_where.ToString() << ": " << error_name;
75 const base::DictionaryValue* GetByGUID(const GuidToPolicyMap& policies,
76 const std::string& guid) {
77 GuidToPolicyMap::const_iterator it = policies.find(guid);
78 if (it == policies.end())
83 void TranslatePropertiesToOncAndRunCallback(
84 const network_handler::DictionaryResultCallback& callback,
85 const std::string& service_path,
86 const base::DictionaryValue& shill_properties) {
87 scoped_ptr<base::DictionaryValue> onc_network(
88 onc::TranslateShillServiceToONCPart(
90 &onc::kNetworkWithStateSignature));
91 callback.Run(service_path, *onc_network);
96 struct ManagedNetworkConfigurationHandlerImpl::Policies {
99 GuidToPolicyMap per_network_config;
100 base::DictionaryValue global_network_config;
103 ManagedNetworkConfigurationHandlerImpl::Policies::~Policies() {
104 STLDeleteValues(&per_network_config);
107 void ManagedNetworkConfigurationHandlerImpl::AddObserver(
108 NetworkPolicyObserver* observer) {
109 observers_.AddObserver(observer);
112 void ManagedNetworkConfigurationHandlerImpl::RemoveObserver(
113 NetworkPolicyObserver* observer) {
114 observers_.RemoveObserver(observer);
117 void ManagedNetworkConfigurationHandlerImpl::GetManagedProperties(
118 const std::string& userhash,
119 const std::string& service_path,
120 const network_handler::DictionaryResultCallback& callback,
121 const network_handler::ErrorCallback& error_callback) {
122 if (!GetPoliciesForUser(userhash) || !GetPoliciesForUser(std::string())) {
123 InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
126 network_configuration_handler_->GetProperties(
129 &ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback,
130 weak_ptr_factory_.GetWeakPtr(),
136 void ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback(
137 const network_handler::DictionaryResultCallback& callback,
138 const network_handler::ErrorCallback& error_callback,
139 const std::string& service_path,
140 const base::DictionaryValue& shill_properties) {
141 std::string profile_path;
142 shill_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
144 const NetworkProfile* profile =
145 network_profile_handler_->GetProfileForPath(profile_path);
147 LOG(ERROR) << "No or no known profile received for service "
148 << service_path << ".";
151 scoped_ptr<NetworkUIData> ui_data =
152 shill_property_util::GetUIDataFromProperties(shill_properties);
154 const base::DictionaryValue* user_settings = NULL;
155 const base::DictionaryValue* shared_settings = NULL;
157 if (ui_data && profile) {
158 if (profile->type() == NetworkProfile::TYPE_SHARED)
159 shared_settings = ui_data->user_settings();
160 else if (profile->type() == NetworkProfile::TYPE_USER)
161 user_settings = ui_data->user_settings();
164 } else if (profile) {
165 LOG(WARNING) << "Service " << service_path << " of profile "
166 << profile_path << " contains no or no valid UIData.";
167 // TODO(pneubeck): add a conversion of user configured entries of old
168 // ChromeOS versions. We will have to use a heuristic to determine which
169 // properties _might_ be user configured.
172 scoped_ptr<base::DictionaryValue> active_settings(
173 onc::TranslateShillServiceToONCPart(
175 &onc::kNetworkWithStateSignature));
178 active_settings->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
181 const base::DictionaryValue* user_policy = NULL;
182 const base::DictionaryValue* device_policy = NULL;
183 if (!guid.empty() && profile) {
184 const Policies* policies = GetPoliciesForProfile(*profile);
187 service_path, error_callback, kPoliciesNotInitialized);
190 const base::DictionaryValue* policy =
191 GetByGUID(policies->per_network_config, guid);
192 if (profile->type() == NetworkProfile::TYPE_SHARED)
193 device_policy = policy;
194 else if (profile->type() == NetworkProfile::TYPE_USER)
195 user_policy = policy;
200 // This call also removes credentials from policies.
201 scoped_ptr<base::DictionaryValue> augmented_properties =
202 onc::MergeSettingsAndPoliciesToAugmented(
203 onc::kNetworkConfigurationSignature,
208 active_settings.get());
209 callback.Run(service_path, *augmented_properties);
212 void ManagedNetworkConfigurationHandlerImpl::GetProperties(
213 const std::string& service_path,
214 const network_handler::DictionaryResultCallback& callback,
215 const network_handler::ErrorCallback& error_callback) const {
216 network_configuration_handler_->GetProperties(
218 base::Bind(&TranslatePropertiesToOncAndRunCallback, callback),
222 void ManagedNetworkConfigurationHandlerImpl::SetProperties(
223 const std::string& service_path,
224 const base::DictionaryValue& user_settings,
225 const base::Closure& callback,
226 const network_handler::ErrorCallback& error_callback) const {
227 const NetworkState* state =
228 network_state_handler_->GetNetworkState(service_path);
231 InvokeErrorCallback(service_path, error_callback, kUnknownServicePath);
235 std::string guid = state->guid();
237 // TODO(pneubeck): create an initial configuration in this case. As for
238 // CreateConfiguration, user settings from older ChromeOS versions have to
241 service_path, error_callback, kSetOnUnconfiguredNetwork);
245 const std::string& profile_path = state->profile_path();
246 const NetworkProfile *profile =
247 network_profile_handler_->GetProfileForPath(profile_path);
249 InvokeErrorCallback(service_path, error_callback, kUnknownProfilePath);
253 VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
254 << profile->ToDebugString();
256 const Policies* policies = GetPoliciesForProfile(*profile);
258 InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
262 // Validate the ONC dictionary. We are liberal and ignore unknown field
263 // names. User settings are only partial ONC, thus we ignore missing fields.
264 onc::Validator validator(false, // Ignore unknown fields.
265 false, // Ignore invalid recommended field names.
266 false, // Ignore missing fields.
267 false); // This ONC does not come from policy.
269 onc::Validator::Result validation_result;
270 scoped_ptr<base::DictionaryValue> validated_user_settings =
271 validator.ValidateAndRepairObject(
272 &onc::kNetworkConfigurationSignature,
276 if (validation_result == onc::Validator::INVALID) {
277 InvokeErrorCallback(service_path, error_callback, kInvalidUserSettings);
280 if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
281 LOG(WARNING) << "Validation of ONC user settings produced warnings.";
283 const base::DictionaryValue* policy =
284 GetByGUID(policies->per_network_config, guid);
285 VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
287 scoped_ptr<base::DictionaryValue> shill_dictionary(
288 policy_util::CreateShillConfiguration(
289 *profile, guid, policy, validated_user_settings.get()));
291 network_configuration_handler_->SetProperties(
292 service_path, *shill_dictionary, callback, error_callback);
295 void ManagedNetworkConfigurationHandlerImpl::CreateConfiguration(
296 const std::string& userhash,
297 const base::DictionaryValue& properties,
298 const network_handler::StringResultCallback& callback,
299 const network_handler::ErrorCallback& error_callback) const {
300 const Policies* policies = GetPoliciesForUser(userhash);
302 InvokeErrorCallback("", error_callback, kPoliciesNotInitialized);
306 if (policy_util::FindMatchingPolicy(policies->per_network_config,
308 InvokeErrorCallback("", error_callback, kNetworkAlreadyConfigured);
312 const NetworkProfile* profile =
313 network_profile_handler_->GetProfileForUserhash(userhash);
315 InvokeErrorCallback("", error_callback, kProfileNotInitialized);
319 // TODO(pneubeck): In case of WiFi, check that no other configuration for the
320 // same {SSID, mode, security} exists. We don't support such multiple
321 // configurations, yet.
323 // Generate a new GUID for this configuration. Ignore the maybe provided GUID
324 // in |properties| as it is not our own and from an untrusted source.
325 std::string guid = base::GenerateGUID();
326 scoped_ptr<base::DictionaryValue> shill_dictionary(
327 policy_util::CreateShillConfiguration(
328 *profile, guid, NULL /*no policy*/, &properties));
330 network_configuration_handler_->CreateConfiguration(
331 *shill_dictionary, callback, error_callback);
334 void ManagedNetworkConfigurationHandlerImpl::RemoveConfiguration(
335 const std::string& service_path,
336 const base::Closure& callback,
337 const network_handler::ErrorCallback& error_callback) const {
338 network_configuration_handler_->RemoveConfiguration(
339 service_path, callback, error_callback);
342 void ManagedNetworkConfigurationHandlerImpl::SetPolicy(
343 ::onc::ONCSource onc_source,
344 const std::string& userhash,
345 const base::ListValue& network_configs_onc,
346 const base::DictionaryValue& global_network_config) {
347 VLOG(1) << "Setting policies from " << ToDebugString(onc_source, userhash)
350 // |userhash| must be empty for device policies.
351 DCHECK(onc_source != ::onc::ONC_SOURCE_DEVICE_POLICY ||
353 Policies* policies = NULL;
354 if (ContainsKey(policies_by_user_, userhash)) {
355 policies = policies_by_user_[userhash].get();
357 policies = new Policies;
358 policies_by_user_[userhash] = make_linked_ptr(policies);
361 policies->global_network_config.MergeDictionary(&global_network_config);
363 GuidToPolicyMap old_per_network_config;
364 policies->per_network_config.swap(old_per_network_config);
366 // This stores all GUIDs of policies that have changed or are new.
367 std::set<std::string> modified_policies;
369 for (base::ListValue::const_iterator it = network_configs_onc.begin();
370 it != network_configs_onc.end(); ++it) {
371 const base::DictionaryValue* network = NULL;
372 (*it)->GetAsDictionary(&network);
376 network->GetStringWithoutPathExpansion(::onc::network_config::kGUID, &guid);
377 DCHECK(!guid.empty());
379 if (policies->per_network_config.count(guid) > 0) {
380 LOG(ERROR) << "ONC from " << ToDebugString(onc_source, userhash)
381 << " contains several entries for the same GUID "
383 delete policies->per_network_config[guid];
385 const base::DictionaryValue* new_entry = network->DeepCopy();
386 policies->per_network_config[guid] = new_entry;
388 const base::DictionaryValue* old_entry = old_per_network_config[guid];
389 if (!old_entry || !old_entry->Equals(new_entry))
390 modified_policies.insert(guid);
393 STLDeleteValues(&old_per_network_config);
395 const NetworkProfile* profile =
396 network_profile_handler_->GetProfileForUserhash(userhash);
398 VLOG(1) << "The relevant Shill profile isn't initialized yet, postponing "
399 << "policy application.";
403 scoped_refptr<PolicyApplicator> applicator =
404 new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
406 policies->per_network_config,
407 policies->global_network_config,
412 void ManagedNetworkConfigurationHandlerImpl::OnProfileAdded(
413 const NetworkProfile& profile) {
414 VLOG(1) << "Adding profile " << profile.ToDebugString() << "'.";
416 const Policies* policies = GetPoliciesForProfile(profile);
418 VLOG(1) << "The relevant policy is not initialized, "
419 << "postponing policy application.";
423 std::set<std::string> policy_guids;
424 for (GuidToPolicyMap::const_iterator it =
425 policies->per_network_config.begin();
426 it != policies->per_network_config.end(); ++it) {
427 policy_guids.insert(it->first);
430 scoped_refptr<PolicyApplicator> applicator =
431 new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
433 policies->per_network_config,
434 policies->global_network_config,
439 void ManagedNetworkConfigurationHandlerImpl::OnProfileRemoved(
440 const NetworkProfile& profile) {
441 // Nothing to do in this case.
444 void ManagedNetworkConfigurationHandlerImpl::CreateConfigurationFromPolicy(
445 const base::DictionaryValue& shill_properties) {
446 network_configuration_handler_->CreateConfiguration(
448 base::Bind(&ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied,
449 weak_ptr_factory_.GetWeakPtr()),
450 base::Bind(&LogErrorWithDict, FROM_HERE));
453 void ManagedNetworkConfigurationHandlerImpl::
454 UpdateExistingConfigurationWithPropertiesFromPolicy(
455 const base::DictionaryValue& existing_properties,
456 const base::DictionaryValue& new_properties) {
457 base::DictionaryValue shill_properties;
460 existing_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
462 if (profile.empty()) {
463 LOG(ERROR) << "Missing profile property.";
466 shill_properties.SetStringWithoutPathExpansion(shill::kProfileProperty,
469 if (!shill_property_util::CopyIdentifyingProperties(existing_properties,
470 &shill_properties)) {
471 LOG(ERROR) << "Missing identifying properties.";
474 shill_properties.MergeDictionary(&new_properties);
476 network_configuration_handler_->CreateConfiguration(
478 base::Bind(&ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied,
479 weak_ptr_factory_.GetWeakPtr()),
480 base::Bind(&LogErrorWithDict, FROM_HERE));
483 const base::DictionaryValue*
484 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGUID(
485 const std::string userhash,
486 const std::string& guid,
487 ::onc::ONCSource* onc_source) const {
488 *onc_source = ::onc::ONC_SOURCE_NONE;
490 if (!userhash.empty()) {
491 const Policies* user_policies = GetPoliciesForUser(userhash);
493 const base::DictionaryValue* policy =
494 GetByGUID(user_policies->per_network_config, guid);
496 *onc_source = ::onc::ONC_SOURCE_USER_POLICY;
502 const Policies* device_policies = GetPoliciesForUser(std::string());
503 if (device_policies) {
504 const base::DictionaryValue* policy =
505 GetByGUID(device_policies->per_network_config, guid);
507 *onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
515 const base::DictionaryValue*
516 ManagedNetworkConfigurationHandlerImpl::GetGlobalConfigFromPolicy(
517 const std::string userhash) const {
518 const Policies* policies = GetPoliciesForUser(userhash);
522 return &policies->global_network_config;
524 const base::DictionaryValue*
525 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGuidAndProfile(
526 const std::string& guid,
527 const std::string& profile_path) const {
528 const NetworkProfile* profile =
529 network_profile_handler_->GetProfileForPath(profile_path);
531 LOG(ERROR) << "Profile path unknown: " << profile_path;
535 const Policies* policies = GetPoliciesForProfile(*profile);
539 return GetByGUID(policies->per_network_config, guid);
542 const ManagedNetworkConfigurationHandlerImpl::Policies*
543 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForUser(
544 const std::string& userhash) const {
545 UserToPoliciesMap::const_iterator it = policies_by_user_.find(userhash);
546 if (it == policies_by_user_.end())
548 return it->second.get();
551 const ManagedNetworkConfigurationHandlerImpl::Policies*
552 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForProfile(
553 const NetworkProfile& profile) const {
554 DCHECK(profile.type() != NetworkProfile::TYPE_SHARED ||
555 profile.userhash.empty());
556 return GetPoliciesForUser(profile.userhash);
559 ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
560 : network_state_handler_(NULL),
561 network_profile_handler_(NULL),
562 network_configuration_handler_(NULL),
563 weak_ptr_factory_(this) {}
565 ManagedNetworkConfigurationHandlerImpl::
566 ~ManagedNetworkConfigurationHandlerImpl() {
567 network_profile_handler_->RemoveObserver(this);
570 void ManagedNetworkConfigurationHandlerImpl::Init(
571 NetworkStateHandler* network_state_handler,
572 NetworkProfileHandler* network_profile_handler,
573 NetworkConfigurationHandler* network_configuration_handler) {
574 network_state_handler_ = network_state_handler;
575 network_profile_handler_ = network_profile_handler;
576 network_configuration_handler_ = network_configuration_handler;
577 network_profile_handler_->AddObserver(this);
580 void ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied(
581 const std::string& service_path) {
582 if (service_path.empty())
585 NetworkPolicyObserver, observers_, PolicyApplied(service_path));
588 } // namespace chromeos