Home | History | Annotate | Download | only in network
      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.
      4 
      5 #include "chromeos/network/managed_network_configuration_handler_impl.h"
      6 
      7 #include <set>
      8 #include <vector>
      9 
     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_device_handler.h"
     24 #include "chromeos/network/network_event_log.h"
     25 #include "chromeos/network/network_policy_observer.h"
     26 #include "chromeos/network/network_profile.h"
     27 #include "chromeos/network/network_profile_handler.h"
     28 #include "chromeos/network/network_state.h"
     29 #include "chromeos/network/network_state_handler.h"
     30 #include "chromeos/network/network_ui_data.h"
     31 #include "chromeos/network/onc/onc_merger.h"
     32 #include "chromeos/network/onc/onc_signature.h"
     33 #include "chromeos/network/onc/onc_translator.h"
     34 #include "chromeos/network/onc/onc_validator.h"
     35 #include "chromeos/network/policy_util.h"
     36 #include "chromeos/network/shill_property_util.h"
     37 #include "components/onc/onc_constants.h"
     38 #include "third_party/cros_system_api/dbus/service_constants.h"
     39 
     40 namespace chromeos {
     41 
     42 namespace {
     43 
     44 typedef std::map<std::string, const base::DictionaryValue*> GuidToPolicyMap;
     45 
     46 // These are error strings used for error callbacks. None of these error
     47 // messages are user-facing: they should only appear in logs.
     48 const char kInvalidUserSettings[] = "InvalidUserSettings";
     49 const char kNetworkAlreadyConfigured[] = "NetworkAlreadyConfigured";
     50 const char kPoliciesNotInitialized[] = "PoliciesNotInitialized";
     51 const char kProfileNotInitialized[] = "ProflieNotInitialized";
     52 const char kSetOnUnconfiguredNetwork[] = "SetCalledOnUnconfiguredNetwork";
     53 const char kUnknownProfilePath[] = "UnknownProfilePath";
     54 const char kUnknownNetwork[] = "UnknownNetwork";
     55 
     56 std::string ToDebugString(::onc::ONCSource source,
     57                           const std::string& userhash) {
     58   return source == ::onc::ONC_SOURCE_USER_POLICY ?
     59       ("user policy of " + userhash) : "device policy";
     60 }
     61 
     62 void InvokeErrorCallback(const std::string& service_path,
     63                          const network_handler::ErrorCallback& error_callback,
     64                          const std::string& error_name) {
     65   std::string error_msg = "ManagedConfig Error: " + error_name;
     66   NET_LOG_ERROR(error_msg, service_path);
     67   network_handler::RunErrorCallback(
     68       error_callback, service_path, error_name, error_msg);
     69 }
     70 
     71 void LogErrorWithDict(const tracked_objects::Location& from_where,
     72                       const std::string& error_name,
     73                       scoped_ptr<base::DictionaryValue> error_data) {
     74   network_event_log::internal::AddEntry(
     75        from_where.file_name(), from_where.line_number(),
     76        network_event_log::LOG_LEVEL_ERROR,
     77        error_name, "");
     78 }
     79 
     80 const base::DictionaryValue* GetByGUID(const GuidToPolicyMap& policies,
     81                                        const std::string& guid) {
     82   GuidToPolicyMap::const_iterator it = policies.find(guid);
     83   if (it == policies.end())
     84     return NULL;
     85   return it->second;
     86 }
     87 
     88 }  // namespace
     89 
     90 struct ManagedNetworkConfigurationHandlerImpl::Policies {
     91   ~Policies();
     92 
     93   GuidToPolicyMap per_network_config;
     94   base::DictionaryValue global_network_config;
     95 };
     96 
     97 ManagedNetworkConfigurationHandlerImpl::Policies::~Policies() {
     98   STLDeleteValues(&per_network_config);
     99 }
    100 
    101 void ManagedNetworkConfigurationHandlerImpl::AddObserver(
    102     NetworkPolicyObserver* observer) {
    103   observers_.AddObserver(observer);
    104 }
    105 
    106 void ManagedNetworkConfigurationHandlerImpl::RemoveObserver(
    107     NetworkPolicyObserver* observer) {
    108   observers_.RemoveObserver(observer);
    109 }
    110 
    111 // GetManagedProperties
    112 
    113 void ManagedNetworkConfigurationHandlerImpl::GetManagedProperties(
    114     const std::string& userhash,
    115     const std::string& service_path,
    116     const network_handler::DictionaryResultCallback& callback,
    117     const network_handler::ErrorCallback& error_callback) {
    118   if (!GetPoliciesForUser(userhash) || !GetPoliciesForUser(std::string())) {
    119     InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
    120     return;
    121   }
    122   network_configuration_handler_->GetProperties(
    123       service_path,
    124       base::Bind(
    125           &ManagedNetworkConfigurationHandlerImpl::GetPropertiesCallback,
    126           weak_ptr_factory_.GetWeakPtr(),
    127           base::Bind(
    128               &ManagedNetworkConfigurationHandlerImpl::SendManagedProperties,
    129               weak_ptr_factory_.GetWeakPtr(),
    130               callback,
    131               error_callback)),
    132       error_callback);
    133 }
    134 
    135 void ManagedNetworkConfigurationHandlerImpl::SendManagedProperties(
    136     const network_handler::DictionaryResultCallback& callback,
    137     const network_handler::ErrorCallback& error_callback,
    138     const std::string& service_path,
    139     scoped_ptr<base::DictionaryValue> shill_properties) {
    140   std::string profile_path;
    141   shill_properties->GetStringWithoutPathExpansion(shill::kProfileProperty,
    142                                                   &profile_path);
    143   const NetworkProfile* profile =
    144       network_profile_handler_->GetProfileForPath(profile_path);
    145   if (!profile)
    146     NET_LOG_ERROR("No profile for service: " + profile_path, service_path);
    147 
    148   scoped_ptr<NetworkUIData> ui_data =
    149       shill_property_util::GetUIDataFromProperties(*shill_properties);
    150 
    151   const base::DictionaryValue* user_settings = NULL;
    152   const base::DictionaryValue* shared_settings = NULL;
    153 
    154   if (ui_data && profile) {
    155     if (profile->type() == NetworkProfile::TYPE_SHARED)
    156       shared_settings = ui_data->user_settings();
    157     else if (profile->type() == NetworkProfile::TYPE_USER)
    158       user_settings = ui_data->user_settings();
    159     else
    160       NOTREACHED();
    161   } else if (profile) {
    162     NET_LOG_ERROR("Service contains empty or invalid UIData", service_path);
    163     // TODO(pneubeck): add a conversion of user configured entries of old
    164     // ChromeOS versions. We will have to use a heuristic to determine which
    165     // properties _might_ be user configured.
    166   }
    167 
    168   scoped_ptr<base::DictionaryValue> active_settings(
    169       onc::TranslateShillServiceToONCPart(
    170           *shill_properties,
    171           &onc::kNetworkWithStateSignature));
    172 
    173   std::string guid;
    174   active_settings->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
    175                                                  &guid);
    176 
    177   const base::DictionaryValue* user_policy = NULL;
    178   const base::DictionaryValue* device_policy = NULL;
    179   if (!guid.empty() && profile) {
    180     const Policies* policies = GetPoliciesForProfile(*profile);
    181     if (!policies) {
    182       InvokeErrorCallback(
    183           service_path, error_callback, kPoliciesNotInitialized);
    184       return;
    185     }
    186     const base::DictionaryValue* policy =
    187         GetByGUID(policies->per_network_config, guid);
    188     if (profile->type() == NetworkProfile::TYPE_SHARED)
    189       device_policy = policy;
    190     else if (profile->type() == NetworkProfile::TYPE_USER)
    191       user_policy = policy;
    192     else
    193       NOTREACHED();
    194   }
    195 
    196   // This call also removes credentials from policies.
    197   scoped_ptr<base::DictionaryValue> augmented_properties =
    198       onc::MergeSettingsAndPoliciesToAugmented(
    199           onc::kNetworkConfigurationSignature,
    200           user_policy,
    201           device_policy,
    202           user_settings,
    203           shared_settings,
    204           active_settings.get());
    205   callback.Run(service_path, *augmented_properties);
    206 }
    207 
    208 // GetProperties
    209 
    210 void ManagedNetworkConfigurationHandlerImpl::GetProperties(
    211     const std::string& service_path,
    212     const network_handler::DictionaryResultCallback& callback,
    213     const network_handler::ErrorCallback& error_callback) {
    214   network_configuration_handler_->GetProperties(
    215       service_path,
    216       base::Bind(
    217           &ManagedNetworkConfigurationHandlerImpl::GetPropertiesCallback,
    218           weak_ptr_factory_.GetWeakPtr(),
    219           base::Bind(&ManagedNetworkConfigurationHandlerImpl::SendProperties,
    220                      weak_ptr_factory_.GetWeakPtr(),
    221                      callback,
    222                      error_callback)),
    223       error_callback);
    224 }
    225 
    226 void ManagedNetworkConfigurationHandlerImpl::SendProperties(
    227     const network_handler::DictionaryResultCallback& callback,
    228     const network_handler::ErrorCallback& error_callback,
    229     const std::string& service_path,
    230     scoped_ptr<base::DictionaryValue> shill_properties) {
    231   scoped_ptr<base::DictionaryValue> onc_network(
    232       onc::TranslateShillServiceToONCPart(*shill_properties,
    233                                           &onc::kNetworkWithStateSignature));
    234   callback.Run(service_path, *onc_network);
    235 }
    236 
    237 // SetProperties
    238 
    239 void ManagedNetworkConfigurationHandlerImpl::SetProperties(
    240     const std::string& service_path,
    241     const base::DictionaryValue& user_settings,
    242     const base::Closure& callback,
    243     const network_handler::ErrorCallback& error_callback) const {
    244   const NetworkState* state =
    245       network_state_handler_->GetNetworkStateFromServicePath(
    246           service_path, true /* configured_only */);
    247   if (!state) {
    248     InvokeErrorCallback(service_path, error_callback, kUnknownNetwork);
    249     return;
    250   }
    251 
    252   std::string guid = state->guid();
    253   if (guid.empty()) {
    254     // TODO(pneubeck): create an initial configuration in this case. As for
    255     // CreateConfiguration, user settings from older ChromeOS versions have to
    256     // determined here.
    257     InvokeErrorCallback(
    258         service_path, error_callback, kSetOnUnconfiguredNetwork);
    259     return;
    260   }
    261 
    262   const std::string& profile_path = state->profile_path();
    263   const NetworkProfile *profile =
    264       network_profile_handler_->GetProfileForPath(profile_path);
    265   if (!profile) {
    266     InvokeErrorCallback(service_path, error_callback, kUnknownProfilePath);
    267     return;
    268   }
    269 
    270   VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
    271           << profile->ToDebugString();
    272 
    273   const Policies* policies = GetPoliciesForProfile(*profile);
    274   if (!policies) {
    275     InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
    276     return;
    277   }
    278 
    279   // Validate the ONC dictionary. We are liberal and ignore unknown field
    280   // names. User settings are only partial ONC, thus we ignore missing fields.
    281   onc::Validator validator(false,  // Ignore unknown fields.
    282                            false,  // Ignore invalid recommended field names.
    283                            false,  // Ignore missing fields.
    284                            false);  // This ONC does not come from policy.
    285 
    286   onc::Validator::Result validation_result;
    287   scoped_ptr<base::DictionaryValue> validated_user_settings =
    288       validator.ValidateAndRepairObject(
    289           &onc::kNetworkConfigurationSignature,
    290           user_settings,
    291           &validation_result);
    292 
    293   if (validation_result == onc::Validator::INVALID) {
    294     InvokeErrorCallback(service_path, error_callback, kInvalidUserSettings);
    295     return;
    296   }
    297   if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
    298     LOG(WARNING) << "Validation of ONC user settings produced warnings.";
    299 
    300   const base::DictionaryValue* policy =
    301       GetByGUID(policies->per_network_config, guid);
    302   VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
    303 
    304   scoped_ptr<base::DictionaryValue> shill_dictionary(
    305       policy_util::CreateShillConfiguration(
    306           *profile, guid, policy, validated_user_settings.get()));
    307 
    308   network_configuration_handler_->SetProperties(
    309       service_path, *shill_dictionary, callback, error_callback);
    310 }
    311 
    312 void ManagedNetworkConfigurationHandlerImpl::CreateConfiguration(
    313     const std::string& userhash,
    314     const base::DictionaryValue& properties,
    315     const network_handler::StringResultCallback& callback,
    316     const network_handler::ErrorCallback& error_callback) const {
    317   const Policies* policies = GetPoliciesForUser(userhash);
    318   if (!policies) {
    319     InvokeErrorCallback("", error_callback, kPoliciesNotInitialized);
    320     return;
    321   }
    322 
    323   if (policy_util::FindMatchingPolicy(policies->per_network_config,
    324                                       properties)) {
    325     InvokeErrorCallback("", error_callback, kNetworkAlreadyConfigured);
    326     return;
    327   }
    328 
    329   const NetworkProfile* profile =
    330       network_profile_handler_->GetProfileForUserhash(userhash);
    331   if (!profile) {
    332     InvokeErrorCallback("", error_callback, kProfileNotInitialized);
    333     return;
    334   }
    335 
    336   // TODO(pneubeck): In case of WiFi, check that no other configuration for the
    337   // same {SSID, mode, security} exists. We don't support such multiple
    338   // configurations, yet.
    339 
    340   // Generate a new GUID for this configuration. Ignore the maybe provided GUID
    341   // in |properties| as it is not our own and from an untrusted source.
    342   std::string guid = base::GenerateGUID();
    343   scoped_ptr<base::DictionaryValue> shill_dictionary(
    344       policy_util::CreateShillConfiguration(
    345           *profile, guid, NULL /*no policy*/, &properties));
    346 
    347   network_configuration_handler_->CreateConfiguration(
    348       *shill_dictionary, callback, error_callback);
    349 }
    350 
    351 void ManagedNetworkConfigurationHandlerImpl::RemoveConfiguration(
    352     const std::string& service_path,
    353     const base::Closure& callback,
    354     const network_handler::ErrorCallback& error_callback) const {
    355   network_configuration_handler_->RemoveConfiguration(
    356       service_path, callback, error_callback);
    357 }
    358 
    359 void ManagedNetworkConfigurationHandlerImpl::SetPolicy(
    360     ::onc::ONCSource onc_source,
    361     const std::string& userhash,
    362     const base::ListValue& network_configs_onc,
    363     const base::DictionaryValue& global_network_config) {
    364   VLOG(1) << "Setting policies from " << ToDebugString(onc_source, userhash)
    365           << ".";
    366 
    367   // |userhash| must be empty for device policies.
    368   DCHECK(onc_source != ::onc::ONC_SOURCE_DEVICE_POLICY ||
    369          userhash.empty());
    370   Policies* policies = NULL;
    371   if (ContainsKey(policies_by_user_, userhash)) {
    372     policies = policies_by_user_[userhash].get();
    373   } else {
    374     policies = new Policies;
    375     policies_by_user_[userhash] = make_linked_ptr(policies);
    376   }
    377 
    378   policies->global_network_config.MergeDictionary(&global_network_config);
    379 
    380   GuidToPolicyMap old_per_network_config;
    381   policies->per_network_config.swap(old_per_network_config);
    382 
    383   // This stores all GUIDs of policies that have changed or are new.
    384   std::set<std::string> modified_policies;
    385 
    386   for (base::ListValue::const_iterator it = network_configs_onc.begin();
    387        it != network_configs_onc.end(); ++it) {
    388     const base::DictionaryValue* network = NULL;
    389     (*it)->GetAsDictionary(&network);
    390     DCHECK(network);
    391 
    392     std::string guid;
    393     network->GetStringWithoutPathExpansion(::onc::network_config::kGUID, &guid);
    394     DCHECK(!guid.empty());
    395 
    396     if (policies->per_network_config.count(guid) > 0) {
    397       NET_LOG_ERROR("ONC from " + ToDebugString(onc_source, userhash) +
    398                     " contains several entries for the same GUID ", guid);
    399       delete policies->per_network_config[guid];
    400     }
    401     const base::DictionaryValue* new_entry = network->DeepCopy();
    402     policies->per_network_config[guid] = new_entry;
    403 
    404     const base::DictionaryValue* old_entry = old_per_network_config[guid];
    405     if (!old_entry || !old_entry->Equals(new_entry))
    406       modified_policies.insert(guid);
    407   }
    408 
    409   STLDeleteValues(&old_per_network_config);
    410 
    411   const NetworkProfile* profile =
    412       network_profile_handler_->GetProfileForUserhash(userhash);
    413   if (profile) {
    414     scoped_refptr<PolicyApplicator> applicator =
    415         new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
    416                              *profile,
    417                              policies->per_network_config,
    418                              policies->global_network_config,
    419                              &modified_policies);
    420     applicator->Run();
    421   } else {
    422     VLOG(1) << "The relevant Shill profile isn't initialized yet, postponing "
    423             << "policy application.";
    424     // See OnProfileAdded.
    425   }
    426 
    427   FOR_EACH_OBSERVER(NetworkPolicyObserver, observers_, PolicyChanged(userhash));
    428 }
    429 
    430 void ManagedNetworkConfigurationHandlerImpl::OnProfileAdded(
    431     const NetworkProfile& profile) {
    432   VLOG(1) << "Adding profile " << profile.ToDebugString() << "'.";
    433 
    434   const Policies* policies = GetPoliciesForProfile(profile);
    435   if (!policies) {
    436     VLOG(1) << "The relevant policy is not initialized, "
    437             << "postponing policy application.";
    438     // See SetPolicy.
    439     return;
    440   }
    441 
    442   std::set<std::string> policy_guids;
    443   for (GuidToPolicyMap::const_iterator it =
    444            policies->per_network_config.begin();
    445        it != policies->per_network_config.end(); ++it) {
    446     policy_guids.insert(it->first);
    447   }
    448 
    449   scoped_refptr<PolicyApplicator> applicator =
    450       new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
    451                            profile,
    452                            policies->per_network_config,
    453                            policies->global_network_config,
    454                            &policy_guids);
    455   applicator->Run();
    456 }
    457 
    458 void ManagedNetworkConfigurationHandlerImpl::OnProfileRemoved(
    459     const NetworkProfile& profile) {
    460   // Nothing to do in this case.
    461 }
    462 
    463 void ManagedNetworkConfigurationHandlerImpl::CreateConfigurationFromPolicy(
    464     const base::DictionaryValue& shill_properties) {
    465   network_configuration_handler_->CreateConfiguration(
    466       shill_properties,
    467       base::Bind(
    468           &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork,
    469           weak_ptr_factory_.GetWeakPtr()),
    470       base::Bind(&LogErrorWithDict, FROM_HERE));
    471 }
    472 
    473 void ManagedNetworkConfigurationHandlerImpl::
    474     UpdateExistingConfigurationWithPropertiesFromPolicy(
    475         const base::DictionaryValue& existing_properties,
    476         const base::DictionaryValue& new_properties) {
    477   base::DictionaryValue shill_properties;
    478 
    479   std::string profile;
    480   existing_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
    481                                                     &profile);
    482   if (profile.empty()) {
    483     NET_LOG_ERROR("Missing profile property",
    484                   shill_property_util::GetNetworkIdFromProperties(
    485                       existing_properties));
    486     return;
    487   }
    488   shill_properties.SetStringWithoutPathExpansion(shill::kProfileProperty,
    489                                                  profile);
    490 
    491   if (!shill_property_util::CopyIdentifyingProperties(
    492           existing_properties,
    493           true /* properties were read from Shill */,
    494           &shill_properties)) {
    495     NET_LOG_ERROR("Missing identifying properties",
    496                   shill_property_util::GetNetworkIdFromProperties(
    497                       existing_properties));
    498   }
    499 
    500   shill_properties.MergeDictionary(&new_properties);
    501 
    502   network_configuration_handler_->CreateConfiguration(
    503       shill_properties,
    504       base::Bind(
    505           &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork,
    506           weak_ptr_factory_.GetWeakPtr()),
    507       base::Bind(&LogErrorWithDict, FROM_HERE));
    508 }
    509 
    510 void ManagedNetworkConfigurationHandlerImpl::OnPoliciesApplied() {
    511 }
    512 
    513 const base::DictionaryValue*
    514 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGUID(
    515     const std::string userhash,
    516     const std::string& guid,
    517     ::onc::ONCSource* onc_source) const {
    518   *onc_source = ::onc::ONC_SOURCE_NONE;
    519 
    520   if (!userhash.empty()) {
    521     const Policies* user_policies = GetPoliciesForUser(userhash);
    522     if (user_policies) {
    523       const base::DictionaryValue* policy =
    524           GetByGUID(user_policies->per_network_config, guid);
    525       if (policy) {
    526         *onc_source = ::onc::ONC_SOURCE_USER_POLICY;
    527         return policy;
    528       }
    529     }
    530   }
    531 
    532   const Policies* device_policies = GetPoliciesForUser(std::string());
    533   if (device_policies) {
    534     const base::DictionaryValue* policy =
    535         GetByGUID(device_policies->per_network_config, guid);
    536     if (policy) {
    537       *onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
    538       return policy;
    539     }
    540   }
    541 
    542   return NULL;
    543 }
    544 
    545 const base::DictionaryValue*
    546 ManagedNetworkConfigurationHandlerImpl::GetGlobalConfigFromPolicy(
    547     const std::string userhash) const {
    548   const Policies* policies = GetPoliciesForUser(userhash);
    549   if (!policies)
    550     return NULL;
    551 
    552   return &policies->global_network_config;
    553 }
    554 const base::DictionaryValue*
    555 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGuidAndProfile(
    556     const std::string& guid,
    557     const std::string& profile_path) const {
    558   const NetworkProfile* profile =
    559       network_profile_handler_->GetProfileForPath(profile_path);
    560   if (!profile) {
    561     NET_LOG_ERROR("Profile path unknown:" + profile_path, guid);
    562     return NULL;
    563   }
    564 
    565   const Policies* policies = GetPoliciesForProfile(*profile);
    566   if (!policies)
    567     return NULL;
    568 
    569   return GetByGUID(policies->per_network_config, guid);
    570 }
    571 
    572 const ManagedNetworkConfigurationHandlerImpl::Policies*
    573 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForUser(
    574     const std::string& userhash) const {
    575   UserToPoliciesMap::const_iterator it = policies_by_user_.find(userhash);
    576   if (it == policies_by_user_.end())
    577     return NULL;
    578   return it->second.get();
    579 }
    580 
    581 const ManagedNetworkConfigurationHandlerImpl::Policies*
    582 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForProfile(
    583     const NetworkProfile& profile) const {
    584   DCHECK(profile.type() != NetworkProfile::TYPE_SHARED ||
    585          profile.userhash.empty());
    586   return GetPoliciesForUser(profile.userhash);
    587 }
    588 
    589 ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
    590     : network_state_handler_(NULL),
    591       network_profile_handler_(NULL),
    592       network_configuration_handler_(NULL),
    593       network_device_handler_(NULL),
    594       weak_ptr_factory_(this) {}
    595 
    596 ManagedNetworkConfigurationHandlerImpl::
    597     ~ManagedNetworkConfigurationHandlerImpl() {
    598   network_profile_handler_->RemoveObserver(this);
    599 }
    600 
    601 void ManagedNetworkConfigurationHandlerImpl::Init(
    602     NetworkStateHandler* network_state_handler,
    603     NetworkProfileHandler* network_profile_handler,
    604     NetworkConfigurationHandler* network_configuration_handler,
    605     NetworkDeviceHandler* network_device_handler) {
    606   network_state_handler_ = network_state_handler;
    607   network_profile_handler_ = network_profile_handler;
    608   network_configuration_handler_ = network_configuration_handler;
    609   network_device_handler_ = network_device_handler;
    610   network_profile_handler_->AddObserver(this);
    611 }
    612 
    613 void ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork(
    614     const std::string& service_path) {
    615   if (service_path.empty())
    616     return;
    617   FOR_EACH_OBSERVER(
    618       NetworkPolicyObserver, observers_, PolicyApplied(service_path));
    619 }
    620 
    621 // Get{Managed}Properties helpers
    622 
    623 void ManagedNetworkConfigurationHandlerImpl::GetDeviceStateProperties(
    624     const std::string& service_path,
    625     base::DictionaryValue* properties) {
    626   std::string connection_state;
    627   properties->GetStringWithoutPathExpansion(
    628       shill::kStateProperty, &connection_state);
    629   if (!NetworkState::StateIsConnected(connection_state))
    630     return;
    631 
    632   // Get the IPConfig properties from the device and store them in "IPConfigs"
    633   // (plural) in the properties dictionary. (Note: Shill only provides a single
    634   // "IPConfig" property for a network service, but a consumer of this API may
    635   // want information about all ipv4 and ipv6 IPConfig properties.
    636   std::string device;
    637   properties->GetStringWithoutPathExpansion(shill::kDeviceProperty, &device);
    638   const DeviceState* device_state =
    639       network_state_handler_->GetDeviceState(device);
    640   if (!device_state) {
    641     NET_LOG_ERROR("GetDeviceProperties: no device: " + device, service_path);
    642     return;
    643   }
    644 
    645   // Get the hardware MAC address from the DeviceState.
    646   if (!device_state->mac_address().empty()) {
    647     properties->SetStringWithoutPathExpansion(
    648         shill::kAddressProperty, device_state->mac_address());
    649   }
    650 
    651   // Convert IPConfig dictionary to a ListValue.
    652   base::ListValue* ip_configs = new base::ListValue;
    653   for (base::DictionaryValue::Iterator iter(device_state->ip_configs());
    654        !iter.IsAtEnd(); iter.Advance()) {
    655     ip_configs->Append(iter.value().DeepCopy());
    656   }
    657   properties->SetWithoutPathExpansion(shill::kIPConfigsProperty, ip_configs);
    658 }
    659 
    660 void ManagedNetworkConfigurationHandlerImpl::GetPropertiesCallback(
    661     GetDevicePropertiesCallback send_callback,
    662     const std::string& service_path,
    663     const base::DictionaryValue& shill_properties) {
    664   scoped_ptr<base::DictionaryValue> shill_properties_copy(
    665       shill_properties.DeepCopy());
    666 
    667   // Add associated Device properties before the ONC translation.
    668   GetDeviceStateProperties(service_path, shill_properties_copy.get());
    669 
    670   // Only request Device properties for Cellular networks with a valid device.
    671   std::string type, device_path;
    672   if (!network_device_handler_ ||
    673       !shill_properties_copy->GetStringWithoutPathExpansion(
    674           shill::kTypeProperty, &type) ||
    675       type != shill::kTypeCellular ||
    676       !shill_properties_copy->GetStringWithoutPathExpansion(
    677           shill::kDeviceProperty, &device_path) ||
    678       device_path.empty()) {
    679     send_callback.Run(service_path, shill_properties_copy.Pass());
    680     return;
    681   }
    682 
    683   // Request the device properties. On success or failure pass (a possibly
    684   // modified) |shill_properties| to |send_callback|.
    685   scoped_ptr<base::DictionaryValue> shill_properties_copy_error_copy(
    686       shill_properties_copy->DeepCopy());
    687   network_device_handler_->GetDeviceProperties(
    688       device_path,
    689       base::Bind(&ManagedNetworkConfigurationHandlerImpl::
    690                      GetDevicePropertiesSuccess,
    691                  weak_ptr_factory_.GetWeakPtr(),
    692                  service_path,
    693                  base::Passed(&shill_properties_copy),
    694                  send_callback),
    695       base::Bind(&ManagedNetworkConfigurationHandlerImpl::
    696                      GetDevicePropertiesFailure,
    697                  weak_ptr_factory_.GetWeakPtr(),
    698                  service_path,
    699                  base::Passed(&shill_properties_copy_error_copy),
    700                  send_callback));
    701 }
    702 
    703 void ManagedNetworkConfigurationHandlerImpl::GetDevicePropertiesSuccess(
    704     const std::string& service_path,
    705     scoped_ptr<base::DictionaryValue> network_properties,
    706     GetDevicePropertiesCallback send_callback,
    707     const std::string& device_path,
    708     const base::DictionaryValue& device_properties) {
    709   // Create a "Device" dictionary in |network_properties|.
    710   network_properties->SetWithoutPathExpansion(
    711       shill::kDeviceProperty, device_properties.DeepCopy());
    712   send_callback.Run(service_path, network_properties.Pass());
    713 }
    714 
    715 void ManagedNetworkConfigurationHandlerImpl::GetDevicePropertiesFailure(
    716     const std::string& service_path,
    717     scoped_ptr<base::DictionaryValue> network_properties,
    718     GetDevicePropertiesCallback send_callback,
    719     const std::string& error_name,
    720     scoped_ptr<base::DictionaryValue> error_data) {
    721   NET_LOG_ERROR("Error getting device properties", service_path);
    722   send_callback.Run(service_path, network_properties.Pass());
    723 }
    724 
    725 
    726 }  // namespace chromeos
    727