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