1 // Copyright (c) 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.h"
10 #include "base/bind.h"
11 #include "base/guid.h"
12 #include "base/json/json_writer.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/stl_util.h"
18 #include "base/string_util.h"
19 #include "base/values.h"
20 #include "chromeos/dbus/dbus_method_call_status.h"
21 #include "chromeos/dbus/dbus_thread_manager.h"
22 #include "chromeos/dbus/shill_manager_client.h"
23 #include "chromeos/dbus/shill_profile_client.h"
24 #include "chromeos/dbus/shill_service_client.h"
25 #include "chromeos/network/network_configuration_handler.h"
26 #include "chromeos/network/network_event_log.h"
27 #include "chromeos/network/network_handler_callbacks.h"
28 #include "chromeos/network/network_profile.h"
29 #include "chromeos/network/network_profile_handler.h"
30 #include "chromeos/network/network_state.h"
31 #include "chromeos/network/network_state_handler.h"
32 #include "chromeos/network/network_ui_data.h"
33 #include "chromeos/network/onc/onc_constants.h"
34 #include "chromeos/network/onc/onc_merger.h"
35 #include "chromeos/network/onc/onc_signature.h"
36 #include "chromeos/network/onc/onc_translator.h"
37 #include "chromeos/network/onc/onc_utils.h"
38 #include "chromeos/network/onc/onc_validator.h"
39 #include "dbus/object_path.h"
40 #include "third_party/cros_system_api/dbus/service_constants.h"
46 const char kLogModule
[] = "ManagedNetworkConfigurationHandler";
48 // These are error strings used for error callbacks. None of these error
49 // messages are user-facing: they should only appear in logs.
50 const char kInvalidUserSettingsMessage
[] = "User settings are invalid.";
51 const char kInvalidUserSettings
[] = "Error.InvalidUserSettings";
52 const char kNetworkAlreadyConfiguredMessage
[] =
53 "Network is already configured.";
54 const char kNetworkAlreadyConfigured
[] = "Error.NetworkAlreadyConfigured";
55 const char kPoliciesNotInitializedMessage
[] = "Policies not initialized.";
56 const char kPoliciesNotInitialized
[] = "Error.PoliciesNotInitialized";
57 const char kProfileNotInitializedMessage
[] = "Profile not initialized.";
58 const char kProfileNotInitialized
[] = "Error.ProflieNotInitialized";
59 const char kSetOnUnconfiguredNetworkMessage
[] =
60 "Unable to modify properties of an unconfigured network.";
61 const char kSetOnUnconfiguredNetwork
[] = "Error.SetCalledOnUnconfiguredNetwork";
62 const char kUnknownProfilePathMessage
[] = "Profile path is unknown.";
63 const char kUnknownProfilePath
[] = "Error.UnknownProfilePath";
64 const char kUnknownServicePathMessage
[] = "Service path is unknown.";
65 const char kUnknownServicePath
[] = "Error.UnknownServicePath";
67 // This fake credential contains a random postfix which is extremly unlikely to
68 // be used by any user.
69 const char kFakeCredential
[] = "FAKE_CREDENTIAL_VPaJDV9x";
71 std::string
ToDebugString(onc::ONCSource source
,
72 const std::string
& userhash
) {
73 return source
== onc::ONC_SOURCE_USER_POLICY
?
74 ("user policy of " + userhash
) : "device policy";
77 void RunErrorCallback(const std::string
& service_path
,
78 const std::string
& error_name
,
79 const std::string
& error_message
,
80 const network_handler::ErrorCallback
& error_callback
) {
81 network_event_log::AddEntry(kLogModule
, error_name
, error_message
);
85 network_handler::CreateErrorData(service_path
,
90 // Sets the UIData property in |shill_dictionary| to the serialization of
92 void SetUIData(const NetworkUIData
& ui_data
,
93 base::DictionaryValue
* shill_dictionary
) {
94 base::DictionaryValue ui_data_dict
;
95 ui_data
.FillDictionary(&ui_data_dict
);
96 std::string ui_data_blob
;
97 base::JSONWriter::Write(&ui_data_dict
, &ui_data_blob
);
98 shill_dictionary
->SetStringWithoutPathExpansion(flimflam::kUIDataProperty
,
102 // A dummy callback to ignore the result of Shill calls.
103 void IgnoreString(const std::string
& str
) {
106 void LogErrorWithDict(const tracked_objects::Location
& from_where
,
107 const std::string
& error_name
,
108 scoped_ptr
<base::DictionaryValue
> error_data
) {
109 LOG(ERROR
) << from_where
.ToString() << ": " << error_name
;
112 void LogErrorMessage(const tracked_objects::Location
& from_where
,
113 const std::string
& error_name
,
114 const std::string
& error_message
) {
115 LOG(ERROR
) << from_where
.ToString() << ": " << error_message
;
118 // Removes all kFakeCredential values from sensitive fields (determined by
119 // onc::FieldIsCredential) of |onc_object|.
120 void RemoveFakeCredentials(
121 const onc::OncValueSignature
& signature
,
122 base::DictionaryValue
* onc_object
) {
123 base::DictionaryValue::Iterator
it(*onc_object
);
124 while (!it
.IsAtEnd()) {
125 base::Value
* value
= NULL
;
126 std::string field_name
= it
.key();
127 // We need the non-const entry to remove nested values but DictionaryValue
128 // has no non-const iterator.
129 onc_object
->GetWithoutPathExpansion(field_name
, &value
);
130 // Advance before delete.
133 // If |value| is a dictionary, recurse.
134 base::DictionaryValue
* nested_object
= NULL
;
135 if (value
->GetAsDictionary(&nested_object
)) {
136 const onc::OncFieldSignature
* field_signature
=
137 onc::GetFieldSignature(signature
, field_name
);
139 RemoveFakeCredentials(*field_signature
->value_signature
,
144 // If |value| is a string, check if it is a fake credential.
145 std::string string_value
;
146 if (value
->GetAsString(&string_value
) &&
147 onc::FieldIsCredential(signature
, field_name
)) {
148 if (string_value
== kFakeCredential
) {
149 // The value wasn't modified by the UI, thus we remove the field to keep
150 // the existing value that is stored in Shill.
151 onc_object
->RemoveWithoutPathExpansion(field_name
, NULL
);
153 // Otherwise, the value is set and modified by the UI, thus we keep that
154 // value to overwrite whatever is stored in Shill.
159 // Creates a Shill property dictionary from the given arguments. The resulting
160 // dictionary will be sent to Shill by the caller. Depending on the profile
161 // path, |policy| is interpreted as the user or device policy and |settings| as
162 // the user or shared settings.
163 scoped_ptr
<base::DictionaryValue
> CreateShillConfiguration(
164 const NetworkProfile
& profile
,
165 const std::string
& guid
,
166 const base::DictionaryValue
* policy
,
167 const base::DictionaryValue
* settings
) {
168 scoped_ptr
<base::DictionaryValue
> effective
;
169 onc::ONCSource onc_source
;
171 if (profile
.type() == NetworkProfile::TYPE_SHARED
) {
172 effective
= onc::MergeSettingsAndPoliciesToEffective(
173 NULL
, // no user policy
174 policy
, // device policy
175 NULL
, // no user settings
176 settings
); // shared settings
177 onc_source
= onc::ONC_SOURCE_DEVICE_POLICY
;
178 } else if (profile
.type() == NetworkProfile::TYPE_USER
) {
179 effective
= onc::MergeSettingsAndPoliciesToEffective(
180 policy
, // user policy
181 NULL
, // no device policy
182 settings
, // user settings
183 NULL
); // no shared settings
184 onc_source
= onc::ONC_SOURCE_USER_POLICY
;
188 } else if (settings
) {
189 effective
.reset(settings
->DeepCopy());
190 // TODO(pneubeck): change to source ONC_SOURCE_USER
191 onc_source
= onc::ONC_SOURCE_NONE
;
194 onc_source
= onc::ONC_SOURCE_NONE
;
197 RemoveFakeCredentials(onc::kNetworkConfigurationSignature
,
200 effective
->SetStringWithoutPathExpansion(onc::network_config::kGUID
, guid
);
202 scoped_ptr
<base::DictionaryValue
> shill_dictionary(
203 onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature
,
206 shill_dictionary
->SetStringWithoutPathExpansion(flimflam::kProfileProperty
,
209 scoped_ptr
<NetworkUIData
> ui_data
;
211 ui_data
= NetworkUIData::CreateFromONC(onc_source
, *policy
);
213 ui_data
.reset(new NetworkUIData());
216 // Shill doesn't know that sensitive data is contained in the UIData
217 // property and might write it into logs or other insecure places. Thus, we
218 // have to remove or mask credentials.
220 // Shill's GetProperties doesn't return credentials. Masking credentials
221 // instead of just removing them, allows remembering if a credential is set
223 scoped_ptr
<base::DictionaryValue
> sanitized_settings(
224 onc::MaskCredentialsInOncObject(onc::kNetworkConfigurationSignature
,
227 ui_data
->set_user_settings(sanitized_settings
.Pass());
230 SetUIData(*ui_data
, shill_dictionary
.get());
232 VLOG(2) << "Created Shill properties: " << *shill_dictionary
;
234 return shill_dictionary
.Pass();
237 // Returns true if |policy| matches |onc_network_part|. This is should be the
238 // only such matching function within Chrome. Shill does such matching in
239 // several functions for network identification. For compatibility, we currently
240 // should stick to Shill's matching behavior.
241 bool IsPolicyMatching(const base::DictionaryValue
& policy
,
242 const base::DictionaryValue
& onc_network_part
) {
243 std::string policy_type
;
244 policy
.GetStringWithoutPathExpansion(onc::network_config::kType
,
246 std::string network_type
;
247 onc_network_part
.GetStringWithoutPathExpansion(onc::network_config::kType
,
249 if (policy_type
!= network_type
)
252 if (network_type
!= onc::network_type::kWiFi
)
255 std::string policy_ssid
;
256 policy
.GetStringWithoutPathExpansion(onc::wifi::kSSID
, &policy_ssid
);
257 std::string network_ssid
;
258 onc_network_part
.GetStringWithoutPathExpansion(onc::wifi::kSSID
,
260 return (policy_ssid
== network_ssid
);
263 // Returns the policy of |policies| matching |onc_network_part|, if any
264 // exists. Returns NULL otherwise.
265 const base::DictionaryValue
* FindMatchingPolicy(
266 const ManagedNetworkConfigurationHandler::GuidToPolicyMap
&policies
,
267 const base::DictionaryValue
& onc_network_part
) {
268 for (ManagedNetworkConfigurationHandler::GuidToPolicyMap::const_iterator it
=
269 policies
.begin(); it
!= policies
.end(); ++it
) {
270 if (IsPolicyMatching(*it
->second
, onc_network_part
))
276 const base::DictionaryValue
* GetByGUID(
277 const ManagedNetworkConfigurationHandler::GuidToPolicyMap
&policies
,
278 const std::string
& guid
) {
279 ManagedNetworkConfigurationHandler::GuidToPolicyMap::const_iterator it
=
281 if (it
== policies
.end())
286 void TranslatePropertiesToOncAndRunCallback(
287 const network_handler::DictionaryResultCallback
& callback
,
288 const std::string
& service_path
,
289 const base::DictionaryValue
& shill_properties
) {
290 scoped_ptr
<base::DictionaryValue
> onc_network(
291 onc::TranslateShillServiceToONCPart(
293 &onc::kNetworkWithStateSignature
));
294 callback
.Run(service_path
, *onc_network
);
299 static ManagedNetworkConfigurationHandler
*
300 g_configuration_handler_instance
= NULL
;
303 void ManagedNetworkConfigurationHandler::Initialize(
304 NetworkProfileHandler
* profile_handler
) {
305 CHECK(!g_configuration_handler_instance
);
306 g_configuration_handler_instance
=
307 new ManagedNetworkConfigurationHandler(profile_handler
);
311 bool ManagedNetworkConfigurationHandler::IsInitialized() {
312 return g_configuration_handler_instance
;
316 void ManagedNetworkConfigurationHandler::Shutdown() {
317 CHECK(g_configuration_handler_instance
);
318 delete g_configuration_handler_instance
;
319 g_configuration_handler_instance
= NULL
;
323 ManagedNetworkConfigurationHandler
* ManagedNetworkConfigurationHandler::Get() {
324 CHECK(g_configuration_handler_instance
);
325 return g_configuration_handler_instance
;
329 scoped_ptr
<NetworkUIData
> ManagedNetworkConfigurationHandler::GetUIData(
330 const base::DictionaryValue
& shill_dictionary
) {
331 std::string ui_data_blob
;
332 if (shill_dictionary
.GetStringWithoutPathExpansion(
333 flimflam::kUIDataProperty
,
335 !ui_data_blob
.empty()) {
336 scoped_ptr
<base::DictionaryValue
> ui_data_dict
=
337 onc::ReadDictionaryFromJson(ui_data_blob
);
339 return make_scoped_ptr(new NetworkUIData(*ui_data_dict
));
341 LOG(ERROR
) << "UIData is not a valid JSON dictionary.";
343 VLOG(2) << "JSON dictionary has no UIData blob: " << shill_dictionary
;
344 return scoped_ptr
<NetworkUIData
>();
347 void ManagedNetworkConfigurationHandler::GetManagedProperties(
348 const std::string
& userhash
,
349 const std::string
& service_path
,
350 const network_handler::DictionaryResultCallback
& callback
,
351 const network_handler::ErrorCallback
& error_callback
) {
352 if (!GetPoliciesForUser(userhash
) || !GetPoliciesForUser(std::string())) {
353 RunErrorCallback(service_path
,
354 kPoliciesNotInitialized
,
355 kPoliciesNotInitializedMessage
,
359 NetworkConfigurationHandler::Get()->GetProperties(
362 &ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback
,
363 weak_ptr_factory_
.GetWeakPtr(),
369 void ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback(
370 const network_handler::DictionaryResultCallback
& callback
,
371 const network_handler::ErrorCallback
& error_callback
,
372 const std::string
& service_path
,
373 const base::DictionaryValue
& shill_properties
) {
374 std::string profile_path
;
375 shill_properties
.GetStringWithoutPathExpansion(flimflam::kProfileProperty
,
377 const NetworkProfile
* profile
=
378 profile_handler_
->GetProfileForPath(profile_path
);
380 VLOG(1) << "No or no known profile received for service "
381 << service_path
<< ".";
384 scoped_ptr
<NetworkUIData
> ui_data
= GetUIData(shill_properties
);
386 const base::DictionaryValue
* user_settings
= NULL
;
387 const base::DictionaryValue
* shared_settings
= NULL
;
389 if (ui_data
&& profile
) {
390 if (profile
->type() == NetworkProfile::TYPE_SHARED
)
391 shared_settings
= ui_data
->user_settings();
392 else if (profile
->type() == NetworkProfile::TYPE_USER
)
393 user_settings
= ui_data
->user_settings();
396 } else if (profile
) {
397 LOG(WARNING
) << "Service " << service_path
<< " of profile "
398 << profile_path
<< " contains no or no valid UIData.";
399 // TODO(pneubeck): add a conversion of user configured entries of old
400 // ChromeOS versions. We will have to use a heuristic to determine which
401 // properties _might_ be user configured.
404 scoped_ptr
<base::DictionaryValue
> active_settings(
405 onc::TranslateShillServiceToONCPart(
407 &onc::kNetworkWithStateSignature
));
410 active_settings
->GetStringWithoutPathExpansion(onc::network_config::kGUID
,
413 const base::DictionaryValue
* user_policy
= NULL
;
414 const base::DictionaryValue
* device_policy
= NULL
;
415 if (!guid
.empty() && profile
) {
416 const GuidToPolicyMap
* policies
= GetPoliciesForProfile(*profile
);
418 RunErrorCallback(service_path
,
419 kPoliciesNotInitialized
,
420 kPoliciesNotInitializedMessage
,
424 const base::DictionaryValue
* policy
= GetByGUID(*policies
, guid
);
425 if (profile
->type() == NetworkProfile::TYPE_SHARED
)
426 device_policy
= policy
;
427 else if (profile
->type() == NetworkProfile::TYPE_USER
)
428 user_policy
= policy
;
433 // This call also removes credentials from policies.
434 scoped_ptr
<base::DictionaryValue
> augmented_properties
=
435 onc::MergeSettingsAndPoliciesToAugmented(
436 onc::kNetworkConfigurationSignature
,
441 active_settings
.get());
442 callback
.Run(service_path
, *augmented_properties
);
445 void ManagedNetworkConfigurationHandler::GetProperties(
446 const std::string
& service_path
,
447 const network_handler::DictionaryResultCallback
& callback
,
448 const network_handler::ErrorCallback
& error_callback
) const {
449 NetworkConfigurationHandler::Get()->GetProperties(
451 base::Bind(&TranslatePropertiesToOncAndRunCallback
, callback
),
455 void ManagedNetworkConfigurationHandler::SetProperties(
456 const std::string
& service_path
,
457 const base::DictionaryValue
& user_settings
,
458 const base::Closure
& callback
,
459 const network_handler::ErrorCallback
& error_callback
) const {
460 const NetworkState
* state
=
461 NetworkStateHandler::Get()->GetNetworkState(service_path
);
464 RunErrorCallback(service_path
,
466 kUnknownServicePathMessage
,
471 std::string guid
= state
->guid();
473 // TODO(pneubeck): create an initial configuration in this case. As for
474 // CreateConfiguration, user settings from older ChromeOS versions have to
476 RunErrorCallback(service_path
,
477 kSetOnUnconfiguredNetwork
,
478 kSetOnUnconfiguredNetworkMessage
,
483 const std::string
& profile_path
= state
->profile_path();
484 const NetworkProfile
*profile
=
485 profile_handler_
->GetProfileForPath(profile_path
);
487 RunErrorCallback(service_path
,
489 kUnknownProfilePathMessage
,
494 VLOG(2) << "SetProperties: Found GUID " << guid
<< " and profile "
495 << profile
->ToDebugString();
497 const GuidToPolicyMap
* policies
= GetPoliciesForProfile(*profile
);
499 RunErrorCallback(service_path
,
500 kPoliciesNotInitialized
,
501 kPoliciesNotInitializedMessage
,
506 // Validate the ONC dictionary. We are liberal and ignore unknown field
507 // names. User settings are only partial ONC, thus we ignore missing fields.
508 onc::Validator
validator(false, // Ignore unknown fields.
509 false, // Ignore invalid recommended field names.
510 false, // Ignore missing fields.
511 false); // This ONC does not comes from policy.
513 onc::Validator::Result validation_result
;
514 scoped_ptr
<base::DictionaryValue
> validated_user_settings
=
515 validator
.ValidateAndRepairObject(
516 &onc::kNetworkConfigurationSignature
,
520 if (validation_result
== onc::Validator::INVALID
) {
521 RunErrorCallback(service_path
,
522 kInvalidUserSettings
,
523 kInvalidUserSettingsMessage
,
527 if (validation_result
== onc::Validator::VALID_WITH_WARNINGS
)
528 LOG(WARNING
) << "Validation of ONC user settings produced warnings.";
530 const base::DictionaryValue
* policy
= GetByGUID(*policies
, guid
);
531 VLOG(2) << "This configuration is " << (policy
? "" : "not ") << "managed.";
533 scoped_ptr
<base::DictionaryValue
> shill_dictionary(
534 CreateShillConfiguration(*profile
, guid
, policy
, &user_settings
));
536 NetworkConfigurationHandler::Get()->SetProperties(service_path
,
542 void ManagedNetworkConfigurationHandler::CreateConfiguration(
543 const std::string
& userhash
,
544 const base::DictionaryValue
& properties
,
545 const network_handler::StringResultCallback
& callback
,
546 const network_handler::ErrorCallback
& error_callback
) const {
547 const GuidToPolicyMap
* policies
= GetPoliciesForUser(userhash
);
550 kPoliciesNotInitialized
,
551 kPoliciesNotInitializedMessage
,
556 if (FindMatchingPolicy(*policies
, properties
)) {
558 kNetworkAlreadyConfigured
,
559 kNetworkAlreadyConfiguredMessage
,
563 const NetworkProfile
* profile
=
564 profile_handler_
->GetProfileForUserhash(userhash
);
567 kProfileNotInitialized
,
568 kProfileNotInitializedMessage
,
572 // TODO(pneubeck): In case of WiFi, check that no other configuration for the
573 // same {SSID, mode, security} exists. We don't support such multiple
574 // configurations, yet.
576 // Generate a new GUID for this configuration. Ignore the maybe provided GUID
577 // in |properties| as it is not our own and from an untrusted source.
578 std::string guid
= base::GenerateGUID();
579 scoped_ptr
<base::DictionaryValue
> shill_dictionary(
580 CreateShillConfiguration(*profile
, guid
, NULL
/*no policy*/,
583 NetworkConfigurationHandler::Get()->CreateConfiguration(*shill_dictionary
,
588 void ManagedNetworkConfigurationHandler::RemoveConfiguration(
589 const std::string
& service_path
,
590 const base::Closure
& callback
,
591 const network_handler::ErrorCallback
& error_callback
) const {
592 NetworkConfigurationHandler::Get()->RemoveConfiguration(service_path
,
597 // This class compares (entry point is Run()) |modified_policies| with the
598 // existing entries in the provided Shill profile |profile|. It fetches all
599 // entries in parallel (GetProfileProperties), compares each entry with the
600 // current policies (GetEntry) and adds all missing policies
601 // (~PolicyApplicator).
602 class ManagedNetworkConfigurationHandler::PolicyApplicator
603 : public base::RefCounted
<PolicyApplicator
> {
605 typedef ManagedNetworkConfigurationHandler::GuidToPolicyMap GuidToPolicyMap
;
607 // |modified_policies| must not be NULL and will be empty afterwards.
608 PolicyApplicator(base::WeakPtr
<ManagedNetworkConfigurationHandler
> handler
,
609 const NetworkProfile
& profile
,
610 std::set
<std::string
>* modified_policies
)
613 remaining_policies_
.swap(*modified_policies
);
617 DBusThreadManager::Get()->GetShillProfileClient()->GetProperties(
618 dbus::ObjectPath(profile_
.path
),
619 base::Bind(&PolicyApplicator::GetProfileProperties
, this),
620 base::Bind(&LogErrorMessage
, FROM_HERE
));
624 friend class base::RefCounted
<PolicyApplicator
>;
626 void GetProfileProperties(const base::DictionaryValue
& profile_properties
) {
628 LOG(WARNING
) << "Handler destructed during policy application to profile "
629 << profile_
.ToDebugString();
633 VLOG(2) << "Received properties for profile " << profile_
.ToDebugString();
634 const base::ListValue
* entries
= NULL
;
635 if (!profile_properties
.GetListWithoutPathExpansion(
636 flimflam::kEntriesProperty
, &entries
)) {
637 LOG(ERROR
) << "Profile " << profile_
.ToDebugString()
638 << " doesn't contain the property "
639 << flimflam::kEntriesProperty
;
643 for (base::ListValue::const_iterator it
= entries
->begin();
644 it
!= entries
->end(); ++it
) {
646 (*it
)->GetAsString(&entry
);
648 std::ostringstream entry_failure
;
649 DBusThreadManager::Get()->GetShillProfileClient()->GetEntry(
650 dbus::ObjectPath(profile_
.path
),
652 base::Bind(&PolicyApplicator::GetEntry
, this, entry
),
653 base::Bind(&LogErrorMessage
, FROM_HERE
));
657 void GetEntry(const std::string
& entry
,
658 const base::DictionaryValue
& entry_properties
) {
660 LOG(WARNING
) << "Handler destructed during policy application to profile "
661 << profile_
.ToDebugString();
665 VLOG(2) << "Received properties for entry " << entry
<< " of profile "
666 << profile_
.ToDebugString();
668 scoped_ptr
<base::DictionaryValue
> onc_part(
669 onc::TranslateShillServiceToONCPart(
671 &onc::kNetworkWithStateSignature
));
673 std::string old_guid
;
674 if (!onc_part
->GetStringWithoutPathExpansion(onc::network_config::kGUID
,
676 LOG(WARNING
) << "Entry " << entry
<< " of profile "
677 << profile_
.ToDebugString() << " doesn't contain a GUID.";
678 // This might be an entry of an older ChromeOS version. Assume it to be
683 scoped_ptr
<NetworkUIData
> ui_data
= GetUIData(entry_properties
);
685 VLOG(1) << "Entry " << entry
<< " of profile "
686 << profile_
.ToDebugString()
687 << " contains no or no valid UIData.";
688 // This might be an entry of an older ChromeOS version. Assume it to be
694 (ui_data
->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY
||
695 ui_data
->onc_source() == onc::ONC_SOURCE_USER_POLICY
);
697 // The relevant policy must have been initialized, otherwise we hadn't Run
698 // this PolicyApplicator.
699 const GuidToPolicyMap
& policies
=
700 *handler_
->GetPoliciesForProfile(profile_
);
702 const base::DictionaryValue
* new_policy
= NULL
;
704 // If we have a GUID that might match a current policy, do a lookup using
705 // that GUID at first. In particular this is necessary, as some networks
706 // can't be matched to policies by properties (e.g. VPN).
707 new_policy
= GetByGUID(policies
, old_guid
);
711 // If we didn't find a policy by GUID, still a new policy might match.
712 new_policy
= FindMatchingPolicy(policies
, *onc_part
);
716 std::string new_guid
;
717 new_policy
->GetStringWithoutPathExpansion(onc::network_config::kGUID
,
720 VLOG_IF(1, was_managed
&& old_guid
!= new_guid
)
721 << "Updating configuration previously managed by policy " << old_guid
722 << " with new policy " << new_guid
<< ".";
723 VLOG_IF(1, !was_managed
)
724 << "Applying policy " << new_guid
<< " to previously unmanaged "
727 if (old_guid
== new_guid
&&
728 remaining_policies_
.find(new_guid
) == remaining_policies_
.end()) {
729 VLOG(1) << "Not updating existing managed configuration with guid "
730 << new_guid
<< " because the policy didn't change.";
732 VLOG_IF(1, old_guid
== new_guid
)
733 << "Updating previously managed configuration with the updated "
734 << "policy " << new_guid
<< ".";
736 // Update the existing configuration with the maybe changed
737 // policy. Thereby the GUID might change.
738 scoped_ptr
<base::DictionaryValue
> shill_dictionary
=
739 CreateShillConfiguration(profile_
, new_guid
, new_policy
,
740 ui_data
->user_settings());
741 NetworkConfigurationHandler::Get()->CreateConfiguration(
743 base::Bind(&IgnoreString
),
744 base::Bind(&LogErrorWithDict
, FROM_HERE
));
745 remaining_policies_
.erase(new_guid
);
747 } else if (was_managed
) {
748 VLOG(1) << "Removing configuration previously managed by policy "
749 << old_guid
<< ", because the policy was removed.";
751 // Remove the entry, because the network was managed but isn't anymore.
752 // Note: An alternative might be to preserve the user settings, but it's
753 // unclear which values originating the policy should be removed.
756 VLOG(2) << "Ignore unmanaged entry.";
758 // The entry wasn't managed and doesn't match any current policy. Thus
759 // leave it as it is.
763 void DeleteEntry(const std::string
& entry
) {
764 DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry(
765 dbus::ObjectPath(profile_
.path
),
767 base::Bind(&base::DoNothing
),
768 base::Bind(&LogErrorMessage
, FROM_HERE
));
771 virtual ~PolicyApplicator() {
773 LOG(WARNING
) << "Handler destructed during policy application to profile "
774 << profile_
.ToDebugString();
778 if (remaining_policies_
.empty())
781 VLOG(2) << "Create new managed network configurations in profile"
782 << profile_
.ToDebugString() << ".";
783 // All profile entries were compared to policies. |configureGUIDs_| contains
784 // all matched policies. From the remainder of policies, new configurations
785 // have to be created.
787 // The relevant policy must have been initialized, otherwise we hadn't Run
788 // this PolicyApplicator.
789 const GuidToPolicyMap
& policies
=
790 *handler_
->GetPoliciesForProfile(profile_
);
792 for (std::set
<std::string
>::iterator it
= remaining_policies_
.begin();
793 it
!= remaining_policies_
.end(); ++it
) {
794 const base::DictionaryValue
* policy
= GetByGUID(policies
, *it
);
796 LOG(ERROR
) << "Policy " << *it
<< " doesn't exist anymore.";
800 VLOG(1) << "Creating new configuration managed by policy " << *it
801 << " in profile " << profile_
.ToDebugString() << ".";
803 scoped_ptr
<base::DictionaryValue
> shill_dictionary
=
804 CreateShillConfiguration(profile_
, *it
, policy
,
805 NULL
/* no user settings */);
806 NetworkConfigurationHandler::Get()->CreateConfiguration(
808 base::Bind(&IgnoreString
),
809 base::Bind(&LogErrorWithDict
, FROM_HERE
));
813 std::set
<std::string
> remaining_policies_
;
814 base::WeakPtr
<ManagedNetworkConfigurationHandler
> handler_
;
815 NetworkProfile profile_
;
817 DISALLOW_COPY_AND_ASSIGN(PolicyApplicator
);
820 void ManagedNetworkConfigurationHandler::SetPolicy(
821 onc::ONCSource onc_source
,
822 const std::string
& userhash
,
823 const base::ListValue
& network_configs_onc
) {
824 VLOG(1) << "Setting policies from " << ToDebugString(onc_source
, userhash
)
827 // |userhash| must be empty for device policies.
828 DCHECK(onc_source
!= chromeos::onc::ONC_SOURCE_DEVICE_POLICY
||
830 GuidToPolicyMap
& policies
= policies_by_user_
[userhash
];
832 GuidToPolicyMap old_policies
;
833 policies
.swap(old_policies
);
835 // This stores all GUIDs of policies that have changed or are new.
836 std::set
<std::string
> modified_policies
;
838 for (base::ListValue::const_iterator it
= network_configs_onc
.begin();
839 it
!= network_configs_onc
.end(); ++it
) {
840 const base::DictionaryValue
* network
= NULL
;
841 (*it
)->GetAsDictionary(&network
);
845 network
->GetStringWithoutPathExpansion(onc::network_config::kGUID
, &guid
);
846 DCHECK(!guid
.empty());
848 if (policies
.count(guid
) > 0) {
849 LOG(ERROR
) << "ONC from " << ToDebugString(onc_source
, userhash
)
850 << " contains several entries for the same GUID "
852 delete policies
[guid
];
854 const base::DictionaryValue
* new_entry
= network
->DeepCopy();
855 policies
[guid
] = new_entry
;
857 const base::DictionaryValue
* old_entry
= old_policies
[guid
];
858 if (!old_entry
|| !old_entry
->Equals(new_entry
))
859 modified_policies
.insert(guid
);
862 STLDeleteValues(&old_policies
);
864 const NetworkProfile
* profile
=
865 profile_handler_
->GetProfileForUserhash(userhash
);
867 VLOG(1) << "The relevant Shill profile isn't initialized yet, postponing "
868 << "policy application.";
872 scoped_refptr
<PolicyApplicator
> applicator
= new PolicyApplicator(
873 weak_ptr_factory_
.GetWeakPtr(),
879 void ManagedNetworkConfigurationHandler::OnProfileAdded(
880 const NetworkProfile
& profile
) {
881 VLOG(1) << "Adding profile " << profile
.ToDebugString() << "'.";
883 const GuidToPolicyMap
* policies
= GetPoliciesForProfile(profile
);
885 VLOG(1) << "The relevant policy is not initialized, "
886 << "postponing policy application.";
890 std::set
<std::string
> policy_guids
;
891 for (GuidToPolicyMap::const_iterator it
= policies
->begin();
892 it
!= policies
->end(); ++it
) {
893 policy_guids
.insert(it
->first
);
896 scoped_refptr
<PolicyApplicator
> applicator
= new PolicyApplicator(
897 weak_ptr_factory_
.GetWeakPtr(),
903 void ManagedNetworkConfigurationHandler::OnProfileRemoved(
904 const NetworkProfile
& profile
) {
905 // Nothing to do in this case.
908 const ManagedNetworkConfigurationHandler::GuidToPolicyMap
*
909 ManagedNetworkConfigurationHandler::GetPoliciesForUser(
910 const std::string
& userhash
) const {
911 UserToPoliciesMap::const_iterator it
= policies_by_user_
.find(userhash
);
912 if (it
== policies_by_user_
.end())
917 const ManagedNetworkConfigurationHandler::GuidToPolicyMap
*
918 ManagedNetworkConfigurationHandler::GetPoliciesForProfile(
919 const NetworkProfile
& profile
) const {
920 DCHECK(profile
.type() != NetworkProfile::TYPE_SHARED
||
921 profile
.userhash
.empty());
922 return GetPoliciesForUser(profile
.userhash
);
925 ManagedNetworkConfigurationHandler::ManagedNetworkConfigurationHandler(
926 NetworkProfileHandler
* profile_handler
)
927 : profile_handler_(profile_handler
),
928 weak_ptr_factory_(this) {
929 profile_handler_
->AddObserver(this);
932 ManagedNetworkConfigurationHandler::~ManagedNetworkConfigurationHandler() {
933 profile_handler_
->RemoveObserver(this);
934 for (UserToPoliciesMap::iterator it
= policies_by_user_
.begin();
935 it
!= policies_by_user_
.end(); ++it
) {
936 STLDeleteValues(&it
->second
);
940 } // namespace chromeos