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(
449 &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork
,
450 weak_ptr_factory_
.GetWeakPtr()),
451 base::Bind(&LogErrorWithDict
, FROM_HERE
));
454 void ManagedNetworkConfigurationHandlerImpl::
455 UpdateExistingConfigurationWithPropertiesFromPolicy(
456 const base::DictionaryValue
& existing_properties
,
457 const base::DictionaryValue
& new_properties
) {
458 base::DictionaryValue shill_properties
;
461 existing_properties
.GetStringWithoutPathExpansion(shill::kProfileProperty
,
463 if (profile
.empty()) {
464 LOG(ERROR
) << "Missing profile property.";
467 shill_properties
.SetStringWithoutPathExpansion(shill::kProfileProperty
,
470 if (!shill_property_util::CopyIdentifyingProperties(existing_properties
,
471 &shill_properties
)) {
472 LOG(ERROR
) << "Missing identifying properties.";
475 shill_properties
.MergeDictionary(&new_properties
);
477 network_configuration_handler_
->CreateConfiguration(
480 &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork
,
481 weak_ptr_factory_
.GetWeakPtr()),
482 base::Bind(&LogErrorWithDict
, FROM_HERE
));
485 void ManagedNetworkConfigurationHandlerImpl::OnPoliciesApplied() {
486 // After all policies were applied, trigger an update of the network lists.
487 if (network_state_handler_
)
488 network_state_handler_
->UpdateManagerProperties();
491 const base::DictionaryValue
*
492 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGUID(
493 const std::string userhash
,
494 const std::string
& guid
,
495 ::onc::ONCSource
* onc_source
) const {
496 *onc_source
= ::onc::ONC_SOURCE_NONE
;
498 if (!userhash
.empty()) {
499 const Policies
* user_policies
= GetPoliciesForUser(userhash
);
501 const base::DictionaryValue
* policy
=
502 GetByGUID(user_policies
->per_network_config
, guid
);
504 *onc_source
= ::onc::ONC_SOURCE_USER_POLICY
;
510 const Policies
* device_policies
= GetPoliciesForUser(std::string());
511 if (device_policies
) {
512 const base::DictionaryValue
* policy
=
513 GetByGUID(device_policies
->per_network_config
, guid
);
515 *onc_source
= ::onc::ONC_SOURCE_DEVICE_POLICY
;
523 const base::DictionaryValue
*
524 ManagedNetworkConfigurationHandlerImpl::GetGlobalConfigFromPolicy(
525 const std::string userhash
) const {
526 const Policies
* policies
= GetPoliciesForUser(userhash
);
530 return &policies
->global_network_config
;
532 const base::DictionaryValue
*
533 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGuidAndProfile(
534 const std::string
& guid
,
535 const std::string
& profile_path
) const {
536 const NetworkProfile
* profile
=
537 network_profile_handler_
->GetProfileForPath(profile_path
);
539 LOG(ERROR
) << "Profile path unknown: " << profile_path
;
543 const Policies
* policies
= GetPoliciesForProfile(*profile
);
547 return GetByGUID(policies
->per_network_config
, guid
);
550 const ManagedNetworkConfigurationHandlerImpl::Policies
*
551 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForUser(
552 const std::string
& userhash
) const {
553 UserToPoliciesMap::const_iterator it
= policies_by_user_
.find(userhash
);
554 if (it
== policies_by_user_
.end())
556 return it
->second
.get();
559 const ManagedNetworkConfigurationHandlerImpl::Policies
*
560 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForProfile(
561 const NetworkProfile
& profile
) const {
562 DCHECK(profile
.type() != NetworkProfile::TYPE_SHARED
||
563 profile
.userhash
.empty());
564 return GetPoliciesForUser(profile
.userhash
);
567 ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
568 : network_state_handler_(NULL
),
569 network_profile_handler_(NULL
),
570 network_configuration_handler_(NULL
),
571 weak_ptr_factory_(this) {}
573 ManagedNetworkConfigurationHandlerImpl::
574 ~ManagedNetworkConfigurationHandlerImpl() {
575 network_profile_handler_
->RemoveObserver(this);
578 void ManagedNetworkConfigurationHandlerImpl::Init(
579 NetworkStateHandler
* network_state_handler
,
580 NetworkProfileHandler
* network_profile_handler
,
581 NetworkConfigurationHandler
* network_configuration_handler
) {
582 network_state_handler_
= network_state_handler
;
583 network_profile_handler_
= network_profile_handler
;
584 network_configuration_handler_
= network_configuration_handler
;
585 network_profile_handler_
->AddObserver(this);
588 void ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork(
589 const std::string
& service_path
) {
590 if (service_path
.empty())
593 NetworkPolicyObserver
, observers_
, PolicyApplied(service_path
));
596 } // namespace chromeos