managed_network_configuration_handler_impl.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
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  network_event_log::internal::AddEntry(
73       from_where.file_name(), from_where.line_number(),
74       network_event_log::LOG_LEVEL_ERROR,
75       error_name, "");
76}
77
78const base::DictionaryValue* GetByGUID(const GuidToPolicyMap& policies,
79                                       const std::string& guid) {
80  GuidToPolicyMap::const_iterator it = policies.find(guid);
81  if (it == policies.end())
82    return NULL;
83  return it->second;
84}
85
86void TranslatePropertiesToOncAndRunCallback(
87    const network_handler::DictionaryResultCallback& callback,
88    const std::string& service_path,
89    const base::DictionaryValue& shill_properties) {
90  scoped_ptr<base::DictionaryValue> onc_network(
91      onc::TranslateShillServiceToONCPart(
92          shill_properties,
93          &onc::kNetworkWithStateSignature));
94  callback.Run(service_path, *onc_network);
95}
96
97}  // namespace
98
99struct ManagedNetworkConfigurationHandlerImpl::Policies {
100  ~Policies();
101
102  GuidToPolicyMap per_network_config;
103  base::DictionaryValue global_network_config;
104};
105
106ManagedNetworkConfigurationHandlerImpl::Policies::~Policies() {
107  STLDeleteValues(&per_network_config);
108}
109
110void ManagedNetworkConfigurationHandlerImpl::AddObserver(
111    NetworkPolicyObserver* observer) {
112  observers_.AddObserver(observer);
113}
114
115void ManagedNetworkConfigurationHandlerImpl::RemoveObserver(
116    NetworkPolicyObserver* observer) {
117  observers_.RemoveObserver(observer);
118}
119
120void ManagedNetworkConfigurationHandlerImpl::GetManagedProperties(
121    const std::string& userhash,
122    const std::string& service_path,
123    const network_handler::DictionaryResultCallback& callback,
124    const network_handler::ErrorCallback& error_callback) {
125  if (!GetPoliciesForUser(userhash) || !GetPoliciesForUser(std::string())) {
126    InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
127    return;
128  }
129  network_configuration_handler_->GetProperties(
130      service_path,
131      base::Bind(
132          &ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback,
133          weak_ptr_factory_.GetWeakPtr(),
134          callback,
135          error_callback),
136      error_callback);
137}
138
139void ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback(
140    const network_handler::DictionaryResultCallback& callback,
141    const network_handler::ErrorCallback& error_callback,
142    const std::string& service_path,
143    const base::DictionaryValue& shill_properties) {
144  std::string profile_path;
145  shill_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
146                                                 &profile_path);
147  const NetworkProfile* profile =
148      network_profile_handler_->GetProfileForPath(profile_path);
149  if (!profile)
150    NET_LOG_ERROR("No profile for service: " + profile_path, service_path);
151
152  scoped_ptr<NetworkUIData> ui_data =
153      shill_property_util::GetUIDataFromProperties(shill_properties);
154
155  const base::DictionaryValue* user_settings = NULL;
156  const base::DictionaryValue* shared_settings = NULL;
157
158  if (ui_data && profile) {
159    if (profile->type() == NetworkProfile::TYPE_SHARED)
160      shared_settings = ui_data->user_settings();
161    else if (profile->type() == NetworkProfile::TYPE_USER)
162      user_settings = ui_data->user_settings();
163    else
164      NOTREACHED();
165  } else if (profile) {
166    NET_LOG_ERROR("Service contains empty or invalid UIData", service_path);
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      NET_LOG_ERROR("ONC from " + ToDebugString(onc_source, userhash) +
381                    " contains several entries for the same GUID ", guid);
382      delete policies->per_network_config[guid];
383    }
384    const base::DictionaryValue* new_entry = network->DeepCopy();
385    policies->per_network_config[guid] = new_entry;
386
387    const base::DictionaryValue* old_entry = old_per_network_config[guid];
388    if (!old_entry || !old_entry->Equals(new_entry))
389      modified_policies.insert(guid);
390  }
391
392  STLDeleteValues(&old_per_network_config);
393
394  const NetworkProfile* profile =
395      network_profile_handler_->GetProfileForUserhash(userhash);
396  if (!profile) {
397    VLOG(1) << "The relevant Shill profile isn't initialized yet, postponing "
398            << "policy application.";
399    return;
400  }
401
402  scoped_refptr<PolicyApplicator> applicator =
403      new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
404                           *profile,
405                           policies->per_network_config,
406                           policies->global_network_config,
407                           &modified_policies);
408  applicator->Run();
409}
410
411void ManagedNetworkConfigurationHandlerImpl::OnProfileAdded(
412    const NetworkProfile& profile) {
413  VLOG(1) << "Adding profile " << profile.ToDebugString() << "'.";
414
415  const Policies* policies = GetPoliciesForProfile(profile);
416  if (!policies) {
417    VLOG(1) << "The relevant policy is not initialized, "
418            << "postponing policy application.";
419    return;
420  }
421
422  std::set<std::string> policy_guids;
423  for (GuidToPolicyMap::const_iterator it =
424           policies->per_network_config.begin();
425       it != policies->per_network_config.end(); ++it) {
426    policy_guids.insert(it->first);
427  }
428
429  scoped_refptr<PolicyApplicator> applicator =
430      new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
431                           profile,
432                           policies->per_network_config,
433                           policies->global_network_config,
434                           &policy_guids);
435  applicator->Run();
436}
437
438void ManagedNetworkConfigurationHandlerImpl::OnProfileRemoved(
439    const NetworkProfile& profile) {
440  // Nothing to do in this case.
441}
442
443void ManagedNetworkConfigurationHandlerImpl::CreateConfigurationFromPolicy(
444    const base::DictionaryValue& shill_properties) {
445  network_configuration_handler_->CreateConfiguration(
446      shill_properties,
447      base::Bind(
448          &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork,
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    NET_LOG_ERROR("Missing profile property",
464                  shill_property_util::GetNetworkIdFromProperties(
465                      existing_properties));
466    return;
467  }
468  shill_properties.SetStringWithoutPathExpansion(shill::kProfileProperty,
469                                                 profile);
470
471  if (!shill_property_util::CopyIdentifyingProperties(existing_properties,
472                                                      &shill_properties)) {
473    NET_LOG_ERROR("Missing identifying properties",
474                  shill_property_util::GetNetworkIdFromProperties(
475                      existing_properties));
476  }
477
478  shill_properties.MergeDictionary(&new_properties);
479
480  network_configuration_handler_->CreateConfiguration(
481      shill_properties,
482      base::Bind(
483          &ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork,
484          weak_ptr_factory_.GetWeakPtr()),
485      base::Bind(&LogErrorWithDict, FROM_HERE));
486}
487
488void ManagedNetworkConfigurationHandlerImpl::OnPoliciesApplied() {
489  // After all policies were applied, trigger an update of the network lists.
490  if (network_state_handler_)
491    network_state_handler_->UpdateManagerProperties();
492}
493
494const base::DictionaryValue*
495ManagedNetworkConfigurationHandlerImpl::FindPolicyByGUID(
496    const std::string userhash,
497    const std::string& guid,
498    ::onc::ONCSource* onc_source) const {
499  *onc_source = ::onc::ONC_SOURCE_NONE;
500
501  if (!userhash.empty()) {
502    const Policies* user_policies = GetPoliciesForUser(userhash);
503    if (user_policies) {
504      const base::DictionaryValue* policy =
505          GetByGUID(user_policies->per_network_config, guid);
506      if (policy) {
507        *onc_source = ::onc::ONC_SOURCE_USER_POLICY;
508        return policy;
509      }
510    }
511  }
512
513  const Policies* device_policies = GetPoliciesForUser(std::string());
514  if (device_policies) {
515    const base::DictionaryValue* policy =
516        GetByGUID(device_policies->per_network_config, guid);
517    if (policy) {
518      *onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
519      return policy;
520    }
521  }
522
523  return NULL;
524}
525
526const base::DictionaryValue*
527ManagedNetworkConfigurationHandlerImpl::GetGlobalConfigFromPolicy(
528    const std::string userhash) const {
529  const Policies* policies = GetPoliciesForUser(userhash);
530  if (!policies)
531    return NULL;
532
533  return &policies->global_network_config;
534}
535const base::DictionaryValue*
536ManagedNetworkConfigurationHandlerImpl::FindPolicyByGuidAndProfile(
537    const std::string& guid,
538    const std::string& profile_path) const {
539  const NetworkProfile* profile =
540      network_profile_handler_->GetProfileForPath(profile_path);
541  if (!profile) {
542    NET_LOG_ERROR("Profile path unknown:" + profile_path, guid);
543    return NULL;
544  }
545
546  const Policies* policies = GetPoliciesForProfile(*profile);
547  if (!policies)
548    return NULL;
549
550  return GetByGUID(policies->per_network_config, guid);
551}
552
553const ManagedNetworkConfigurationHandlerImpl::Policies*
554ManagedNetworkConfigurationHandlerImpl::GetPoliciesForUser(
555    const std::string& userhash) const {
556  UserToPoliciesMap::const_iterator it = policies_by_user_.find(userhash);
557  if (it == policies_by_user_.end())
558    return NULL;
559  return it->second.get();
560}
561
562const ManagedNetworkConfigurationHandlerImpl::Policies*
563ManagedNetworkConfigurationHandlerImpl::GetPoliciesForProfile(
564    const NetworkProfile& profile) const {
565  DCHECK(profile.type() != NetworkProfile::TYPE_SHARED ||
566         profile.userhash.empty());
567  return GetPoliciesForUser(profile.userhash);
568}
569
570ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
571    : network_state_handler_(NULL),
572      network_profile_handler_(NULL),
573      network_configuration_handler_(NULL),
574      weak_ptr_factory_(this) {}
575
576ManagedNetworkConfigurationHandlerImpl::
577    ~ManagedNetworkConfigurationHandlerImpl() {
578  network_profile_handler_->RemoveObserver(this);
579}
580
581void ManagedNetworkConfigurationHandlerImpl::Init(
582    NetworkStateHandler* network_state_handler,
583    NetworkProfileHandler* network_profile_handler,
584    NetworkConfigurationHandler* network_configuration_handler) {
585  network_state_handler_ = network_state_handler;
586  network_profile_handler_ = network_profile_handler;
587  network_configuration_handler_ = network_configuration_handler;
588  network_profile_handler_->AddObserver(this);
589}
590
591void ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork(
592    const std::string& service_path) {
593  if (service_path.empty())
594    return;
595  FOR_EACH_OBSERVER(
596      NetworkPolicyObserver, observers_, PolicyApplied(service_path));
597}
598
599}  // namespace chromeos
600