managed_network_configuration_handler_impl.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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/network_configuration_handler.h"
22#include "chromeos/network/network_event_log.h"
23#include "chromeos/network/network_policy_observer.h"
24#include "chromeos/network/network_profile.h"
25#include "chromeos/network/network_profile_handler.h"
26#include "chromeos/network/network_state.h"
27#include "chromeos/network/network_state_handler.h"
28#include "chromeos/network/network_ui_data.h"
29#include "chromeos/network/onc/onc_merger.h"
30#include "chromeos/network/onc/onc_signature.h"
31#include "chromeos/network/onc/onc_translator.h"
32#include "chromeos/network/onc/onc_validator.h"
33#include "chromeos/network/policy_util.h"
34#include "chromeos/network/shill_property_util.h"
35#include "components/onc/onc_constants.h"
36#include "third_party/cros_system_api/dbus/service_constants.h"
37
38namespace chromeos {
39
40namespace {
41
42typedef std::map<std::string, const base::DictionaryValue*> GuidToPolicyMap;
43
44// These are error strings used for error callbacks. None of these error
45// messages are user-facing: they should only appear in logs.
46const char kInvalidUserSettings[] = "InvalidUserSettings";
47const char kNetworkAlreadyConfigured[] = "NetworkAlreadyConfigured";
48const char kPoliciesNotInitialized[] = "PoliciesNotInitialized";
49const char kProfileNotInitialized[] = "ProflieNotInitialized";
50const char kSetOnUnconfiguredNetwork[] = "SetCalledOnUnconfiguredNetwork";
51const char kUnknownProfilePath[] = "UnknownProfilePath";
52const char kUnknownServicePath[] = "UnknownServicePath";
53
54std::string ToDebugString(::onc::ONCSource source,
55                          const std::string& userhash) {
56  return source == ::onc::ONC_SOURCE_USER_POLICY ?
57      ("user policy of " + userhash) : "device policy";
58}
59
60void InvokeErrorCallback(const std::string& service_path,
61                         const network_handler::ErrorCallback& error_callback,
62                         const std::string& error_name) {
63  std::string error_msg = "ManagedConfig Error: " + error_name;
64  NET_LOG_ERROR(error_msg, service_path);
65  network_handler::RunErrorCallback(
66      error_callback, service_path, error_name, error_msg);
67}
68
69void LogErrorWithDict(const tracked_objects::Location& from_where,
70                      const std::string& error_name,
71                      scoped_ptr<base::DictionaryValue> error_data) {
72  LOG(ERROR) << from_where.ToString() << ": " << error_name;
73}
74
75const base::DictionaryValue* GetByGUID(const GuidToPolicyMap& policies,
76                                       const std::string& guid) {
77  GuidToPolicyMap::const_iterator it = policies.find(guid);
78  if (it == policies.end())
79    return NULL;
80  return it->second;
81}
82
83void TranslatePropertiesToOncAndRunCallback(
84    const network_handler::DictionaryResultCallback& callback,
85    const std::string& service_path,
86    const base::DictionaryValue& shill_properties) {
87  scoped_ptr<base::DictionaryValue> onc_network(
88      onc::TranslateShillServiceToONCPart(
89          shill_properties,
90          &onc::kNetworkWithStateSignature));
91  callback.Run(service_path, *onc_network);
92}
93
94}  // namespace
95
96struct ManagedNetworkConfigurationHandlerImpl::Policies {
97  ~Policies();
98
99  GuidToPolicyMap per_network_config;
100  base::DictionaryValue global_network_config;
101};
102
103ManagedNetworkConfigurationHandlerImpl::Policies::~Policies() {
104  STLDeleteValues(&per_network_config);
105}
106
107void ManagedNetworkConfigurationHandlerImpl::AddObserver(
108    NetworkPolicyObserver* observer) {
109  observers_.AddObserver(observer);
110}
111
112void ManagedNetworkConfigurationHandlerImpl::RemoveObserver(
113    NetworkPolicyObserver* observer) {
114  observers_.RemoveObserver(observer);
115}
116
117void ManagedNetworkConfigurationHandlerImpl::GetManagedProperties(
118    const std::string& userhash,
119    const std::string& service_path,
120    const network_handler::DictionaryResultCallback& callback,
121    const network_handler::ErrorCallback& error_callback) {
122  if (!GetPoliciesForUser(userhash) || !GetPoliciesForUser(std::string())) {
123    InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
124    return;
125  }
126  network_configuration_handler_->GetProperties(
127      service_path,
128      base::Bind(
129          &ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback,
130          weak_ptr_factory_.GetWeakPtr(),
131          callback,
132          error_callback),
133      error_callback);
134}
135
136void ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback(
137    const network_handler::DictionaryResultCallback& callback,
138    const network_handler::ErrorCallback& error_callback,
139    const std::string& service_path,
140    const base::DictionaryValue& shill_properties) {
141  std::string profile_path;
142  shill_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
143                                                 &profile_path);
144  const NetworkProfile* profile =
145      network_profile_handler_->GetProfileForPath(profile_path);
146  if (!profile) {
147    LOG(ERROR) << "No or no known profile received for service "
148            << service_path << ".";
149  }
150
151  scoped_ptr<NetworkUIData> ui_data =
152      shill_property_util::GetUIDataFromProperties(shill_properties);
153
154  const base::DictionaryValue* user_settings = NULL;
155  const base::DictionaryValue* shared_settings = NULL;
156
157  if (ui_data && profile) {
158    if (profile->type() == NetworkProfile::TYPE_SHARED)
159      shared_settings = ui_data->user_settings();
160    else if (profile->type() == NetworkProfile::TYPE_USER)
161      user_settings = ui_data->user_settings();
162    else
163      NOTREACHED();
164  } else if (profile) {
165    LOG(WARNING) << "Service " << service_path << " of profile "
166                 << profile_path << " contains no or no valid UIData.";
167    // TODO(pneubeck): add a conversion of user configured entries of old
168    // ChromeOS versions. We will have to use a heuristic to determine which
169    // properties _might_ be user configured.
170  }
171
172  scoped_ptr<base::DictionaryValue> active_settings(
173      onc::TranslateShillServiceToONCPart(
174          shill_properties,
175          &onc::kNetworkWithStateSignature));
176
177  std::string guid;
178  active_settings->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
179                                                 &guid);
180
181  const base::DictionaryValue* user_policy = NULL;
182  const base::DictionaryValue* device_policy = NULL;
183  if (!guid.empty() && profile) {
184    const Policies* policies = GetPoliciesForProfile(*profile);
185    if (!policies) {
186      InvokeErrorCallback(
187          service_path, error_callback, kPoliciesNotInitialized);
188      return;
189    }
190    const base::DictionaryValue* policy =
191        GetByGUID(policies->per_network_config, guid);
192    if (profile->type() == NetworkProfile::TYPE_SHARED)
193      device_policy = policy;
194    else if (profile->type() == NetworkProfile::TYPE_USER)
195      user_policy = policy;
196    else
197      NOTREACHED();
198  }
199
200  // This call also removes credentials from policies.
201  scoped_ptr<base::DictionaryValue> augmented_properties =
202      onc::MergeSettingsAndPoliciesToAugmented(
203          onc::kNetworkConfigurationSignature,
204          user_policy,
205          device_policy,
206          user_settings,
207          shared_settings,
208          active_settings.get());
209  callback.Run(service_path, *augmented_properties);
210}
211
212void ManagedNetworkConfigurationHandlerImpl::GetProperties(
213    const std::string& service_path,
214    const network_handler::DictionaryResultCallback& callback,
215    const network_handler::ErrorCallback& error_callback) const {
216  network_configuration_handler_->GetProperties(
217      service_path,
218      base::Bind(&TranslatePropertiesToOncAndRunCallback, callback),
219      error_callback);
220}
221
222void ManagedNetworkConfigurationHandlerImpl::SetProperties(
223    const std::string& service_path,
224    const base::DictionaryValue& user_settings,
225    const base::Closure& callback,
226    const network_handler::ErrorCallback& error_callback) const {
227  const NetworkState* state =
228      network_state_handler_->GetNetworkState(service_path);
229
230  if (!state) {
231    InvokeErrorCallback(service_path, error_callback, kUnknownServicePath);
232    return;
233  }
234
235  std::string guid = state->guid();
236  if (guid.empty()) {
237    // TODO(pneubeck): create an initial configuration in this case. As for
238    // CreateConfiguration, user settings from older ChromeOS versions have to
239    // determined here.
240    InvokeErrorCallback(
241        service_path, error_callback, kSetOnUnconfiguredNetwork);
242    return;
243  }
244
245  const std::string& profile_path = state->profile_path();
246  const NetworkProfile *profile =
247      network_profile_handler_->GetProfileForPath(profile_path);
248  if (!profile) {
249    InvokeErrorCallback(service_path, error_callback, kUnknownProfilePath);
250    return;
251  }
252
253  VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
254          << profile->ToDebugString();
255
256  const Policies* policies = GetPoliciesForProfile(*profile);
257  if (!policies) {
258    InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
259    return;
260  }
261
262  // Validate the ONC dictionary. We are liberal and ignore unknown field
263  // names. User settings are only partial ONC, thus we ignore missing fields.
264  onc::Validator validator(false,  // Ignore unknown fields.
265                           false,  // Ignore invalid recommended field names.
266                           false,  // Ignore missing fields.
267                           false);  // This ONC does not come from policy.
268
269  onc::Validator::Result validation_result;
270  scoped_ptr<base::DictionaryValue> validated_user_settings =
271      validator.ValidateAndRepairObject(
272          &onc::kNetworkConfigurationSignature,
273          user_settings,
274          &validation_result);
275
276  if (validation_result == onc::Validator::INVALID) {
277    InvokeErrorCallback(service_path, error_callback, kInvalidUserSettings);
278    return;
279  }
280  if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
281    LOG(WARNING) << "Validation of ONC user settings produced warnings.";
282
283  const base::DictionaryValue* policy =
284      GetByGUID(policies->per_network_config, guid);
285  VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
286
287  scoped_ptr<base::DictionaryValue> shill_dictionary(
288      policy_util::CreateShillConfiguration(
289          *profile, guid, policy, validated_user_settings.get()));
290
291  network_configuration_handler_->SetProperties(
292      service_path, *shill_dictionary, callback, error_callback);
293}
294
295void ManagedNetworkConfigurationHandlerImpl::CreateConfiguration(
296    const std::string& userhash,
297    const base::DictionaryValue& properties,
298    const network_handler::StringResultCallback& callback,
299    const network_handler::ErrorCallback& error_callback) const {
300  const Policies* policies = GetPoliciesForUser(userhash);
301  if (!policies) {
302    InvokeErrorCallback("", error_callback, kPoliciesNotInitialized);
303    return;
304  }
305
306  if (policy_util::FindMatchingPolicy(policies->per_network_config,
307                                      properties)) {
308    InvokeErrorCallback("", error_callback, kNetworkAlreadyConfigured);
309    return;
310  }
311
312  const NetworkProfile* profile =
313      network_profile_handler_->GetProfileForUserhash(userhash);
314  if (!profile) {
315    InvokeErrorCallback("", error_callback, kProfileNotInitialized);
316    return;
317  }
318
319  // TODO(pneubeck): In case of WiFi, check that no other configuration for the
320  // same {SSID, mode, security} exists. We don't support such multiple
321  // configurations, yet.
322
323  // Generate a new GUID for this configuration. Ignore the maybe provided GUID
324  // in |properties| as it is not our own and from an untrusted source.
325  std::string guid = base::GenerateGUID();
326  scoped_ptr<base::DictionaryValue> shill_dictionary(
327      policy_util::CreateShillConfiguration(
328          *profile, guid, NULL /*no policy*/, &properties));
329
330  network_configuration_handler_->CreateConfiguration(
331      *shill_dictionary, callback, error_callback);
332}
333
334void ManagedNetworkConfigurationHandlerImpl::RemoveConfiguration(
335    const std::string& service_path,
336    const base::Closure& callback,
337    const network_handler::ErrorCallback& error_callback) const {
338  network_configuration_handler_->RemoveConfiguration(
339      service_path, callback, error_callback);
340}
341
342void ManagedNetworkConfigurationHandlerImpl::SetPolicy(
343    ::onc::ONCSource onc_source,
344    const std::string& userhash,
345    const base::ListValue& network_configs_onc,
346    const base::DictionaryValue& global_network_config) {
347  VLOG(1) << "Setting policies from " << ToDebugString(onc_source, userhash)
348          << ".";
349
350  // |userhash| must be empty for device policies.
351  DCHECK(onc_source != ::onc::ONC_SOURCE_DEVICE_POLICY ||
352         userhash.empty());
353  Policies* policies = NULL;
354  if (ContainsKey(policies_by_user_, userhash)) {
355    policies = policies_by_user_[userhash].get();
356  } else {
357    policies = new Policies;
358    policies_by_user_[userhash] = make_linked_ptr(policies);
359  }
360
361  policies->global_network_config.MergeDictionary(&global_network_config);
362
363  GuidToPolicyMap old_per_network_config;
364  policies->per_network_config.swap(old_per_network_config);
365
366  // This stores all GUIDs of policies that have changed or are new.
367  std::set<std::string> modified_policies;
368
369  for (base::ListValue::const_iterator it = network_configs_onc.begin();
370       it != network_configs_onc.end(); ++it) {
371    const base::DictionaryValue* network = NULL;
372    (*it)->GetAsDictionary(&network);
373    DCHECK(network);
374
375    std::string guid;
376    network->GetStringWithoutPathExpansion(::onc::network_config::kGUID, &guid);
377    DCHECK(!guid.empty());
378
379    if (policies->per_network_config.count(guid) > 0) {
380      LOG(ERROR) << "ONC from " << ToDebugString(onc_source, userhash)
381                 << " contains several entries for the same GUID "
382                 << guid << ".";
383      delete policies->per_network_config[guid];
384    }
385    const base::DictionaryValue* new_entry = network->DeepCopy();
386    policies->per_network_config[guid] = new_entry;
387
388    const base::DictionaryValue* old_entry = old_per_network_config[guid];
389    if (!old_entry || !old_entry->Equals(new_entry))
390      modified_policies.insert(guid);
391  }
392
393  STLDeleteValues(&old_per_network_config);
394
395  const NetworkProfile* profile =
396      network_profile_handler_->GetProfileForUserhash(userhash);
397  if (!profile) {
398    VLOG(1) << "The relevant Shill profile isn't initialized yet, postponing "
399            << "policy application.";
400    return;
401  }
402
403  scoped_refptr<PolicyApplicator> applicator =
404      new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
405                           *profile,
406                           policies->per_network_config,
407                           policies->global_network_config,
408                           &modified_policies);
409  applicator->Run();
410}
411
412void ManagedNetworkConfigurationHandlerImpl::OnProfileAdded(
413    const NetworkProfile& profile) {
414  VLOG(1) << "Adding profile " << profile.ToDebugString() << "'.";
415
416  const Policies* policies = GetPoliciesForProfile(profile);
417  if (!policies) {
418    VLOG(1) << "The relevant policy is not initialized, "
419            << "postponing policy application.";
420    return;
421  }
422
423  std::set<std::string> policy_guids;
424  for (GuidToPolicyMap::const_iterator it =
425           policies->per_network_config.begin();
426       it != policies->per_network_config.end(); ++it) {
427    policy_guids.insert(it->first);
428  }
429
430  scoped_refptr<PolicyApplicator> applicator =
431      new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
432                           profile,
433                           policies->per_network_config,
434                           policies->global_network_config,
435                           &policy_guids);
436  applicator->Run();
437}
438
439void ManagedNetworkConfigurationHandlerImpl::OnProfileRemoved(
440    const NetworkProfile& profile) {
441  // Nothing to do in this case.
442}
443
444void ManagedNetworkConfigurationHandlerImpl::CreateConfigurationFromPolicy(
445    const base::DictionaryValue& shill_properties) {
446  network_configuration_handler_->CreateConfiguration(
447      shill_properties,
448      base::Bind(&ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied,
449                 weak_ptr_factory_.GetWeakPtr()),
450      base::Bind(&LogErrorWithDict, FROM_HERE));
451}
452
453void ManagedNetworkConfigurationHandlerImpl::
454    UpdateExistingConfigurationWithPropertiesFromPolicy(
455        const base::DictionaryValue& existing_properties,
456        const base::DictionaryValue& new_properties) {
457  base::DictionaryValue shill_properties;
458
459  std::string profile;
460  existing_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
461                                                    &profile);
462  if (profile.empty()) {
463    LOG(ERROR) << "Missing profile property.";
464    return;
465  }
466  shill_properties.SetStringWithoutPathExpansion(shill::kProfileProperty,
467                                                 profile);
468
469  if (!shill_property_util::CopyIdentifyingProperties(existing_properties,
470                                                      &shill_properties)) {
471    LOG(ERROR) << "Missing identifying properties.";
472  }
473
474  shill_properties.MergeDictionary(&new_properties);
475
476  network_configuration_handler_->CreateConfiguration(
477      shill_properties,
478      base::Bind(&ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied,
479                 weak_ptr_factory_.GetWeakPtr()),
480      base::Bind(&LogErrorWithDict, FROM_HERE));
481}
482
483const base::DictionaryValue*
484ManagedNetworkConfigurationHandlerImpl::FindPolicyByGUID(
485    const std::string userhash,
486    const std::string& guid,
487    ::onc::ONCSource* onc_source) const {
488  *onc_source = ::onc::ONC_SOURCE_NONE;
489
490  if (!userhash.empty()) {
491    const Policies* user_policies = GetPoliciesForUser(userhash);
492    if (user_policies) {
493      const base::DictionaryValue* policy =
494          GetByGUID(user_policies->per_network_config, guid);
495      if (policy) {
496        *onc_source = ::onc::ONC_SOURCE_USER_POLICY;
497        return policy;
498      }
499    }
500  }
501
502  const Policies* device_policies = GetPoliciesForUser(std::string());
503  if (device_policies) {
504    const base::DictionaryValue* policy =
505        GetByGUID(device_policies->per_network_config, guid);
506    if (policy) {
507      *onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
508      return policy;
509    }
510  }
511
512  return NULL;
513}
514
515const base::DictionaryValue*
516ManagedNetworkConfigurationHandlerImpl::GetGlobalConfigFromPolicy(
517    const std::string userhash) const {
518  const Policies* policies = GetPoliciesForUser(userhash);
519  if (!policies)
520    return NULL;
521
522  return &policies->global_network_config;
523}
524const base::DictionaryValue*
525ManagedNetworkConfigurationHandlerImpl::FindPolicyByGuidAndProfile(
526    const std::string& guid,
527    const std::string& profile_path) const {
528  const NetworkProfile* profile =
529      network_profile_handler_->GetProfileForPath(profile_path);
530  if (!profile) {
531    LOG(ERROR) << "Profile path unknown: " << profile_path;
532    return NULL;
533  }
534
535  const Policies* policies = GetPoliciesForProfile(*profile);
536  if (!policies)
537    return NULL;
538
539  return GetByGUID(policies->per_network_config, guid);
540}
541
542const ManagedNetworkConfigurationHandlerImpl::Policies*
543ManagedNetworkConfigurationHandlerImpl::GetPoliciesForUser(
544    const std::string& userhash) const {
545  UserToPoliciesMap::const_iterator it = policies_by_user_.find(userhash);
546  if (it == policies_by_user_.end())
547    return NULL;
548  return it->second.get();
549}
550
551const ManagedNetworkConfigurationHandlerImpl::Policies*
552ManagedNetworkConfigurationHandlerImpl::GetPoliciesForProfile(
553    const NetworkProfile& profile) const {
554  DCHECK(profile.type() != NetworkProfile::TYPE_SHARED ||
555         profile.userhash.empty());
556  return GetPoliciesForUser(profile.userhash);
557}
558
559ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
560    : network_state_handler_(NULL),
561      network_profile_handler_(NULL),
562      network_configuration_handler_(NULL),
563      weak_ptr_factory_(this) {}
564
565ManagedNetworkConfigurationHandlerImpl::
566    ~ManagedNetworkConfigurationHandlerImpl() {
567  network_profile_handler_->RemoveObserver(this);
568}
569
570void ManagedNetworkConfigurationHandlerImpl::Init(
571    NetworkStateHandler* network_state_handler,
572    NetworkProfileHandler* network_profile_handler,
573    NetworkConfigurationHandler* network_configuration_handler) {
574  network_state_handler_ = network_state_handler;
575  network_profile_handler_ = network_profile_handler;
576  network_configuration_handler_ = network_configuration_handler;
577  network_profile_handler_->AddObserver(this);
578}
579
580void ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied(
581    const std::string& service_path) {
582  if (service_path.empty())
583    return;
584  FOR_EACH_OBSERVER(
585      NetworkPolicyObserver, observers_, PolicyApplied(service_path));
586}
587
588}  // namespace chromeos
589