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