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