- add sources.
[platform/framework/web/crosswalk.git] / src / chromeos / network / managed_network_configuration_handler_impl.cc
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
38 namespace chromeos {
39
40 namespace {
41
42 typedef 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.
46 const char kInvalidUserSettings[] = "InvalidUserSettings";
47 const char kNetworkAlreadyConfigured[] = "NetworkAlreadyConfigured";
48 const char kPoliciesNotInitialized[] = "PoliciesNotInitialized";
49 const char kProfileNotInitialized[] = "ProflieNotInitialized";
50 const char kSetOnUnconfiguredNetwork[] = "SetCalledOnUnconfiguredNetwork";
51 const char kUnknownProfilePath[] = "UnknownProfilePath";
52 const char kUnknownServicePath[] = "UnknownServicePath";
53
54 std::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
60 void 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
69 void 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
75 const 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
83 void 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
96 struct ManagedNetworkConfigurationHandlerImpl::Policies {
97   ~Policies();
98
99   GuidToPolicyMap per_network_config;
100   base::DictionaryValue global_network_config;
101 };
102
103 ManagedNetworkConfigurationHandlerImpl::Policies::~Policies() {
104   STLDeleteValues(&per_network_config);
105 }
106
107 void ManagedNetworkConfigurationHandlerImpl::AddObserver(
108     NetworkPolicyObserver* observer) {
109   observers_.AddObserver(observer);
110 }
111
112 void ManagedNetworkConfigurationHandlerImpl::RemoveObserver(
113     NetworkPolicyObserver* observer) {
114   observers_.RemoveObserver(observer);
115 }
116
117 void 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
136 void 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
212 void 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
222 void 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
295 void 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
334 void 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
342 void 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
412 void 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
439 void ManagedNetworkConfigurationHandlerImpl::OnProfileRemoved(
440     const NetworkProfile& profile) {
441   // Nothing to do in this case.
442 }
443
444 void 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
453 void 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
483 const base::DictionaryValue*
484 ManagedNetworkConfigurationHandlerImpl::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
515 const base::DictionaryValue*
516 ManagedNetworkConfigurationHandlerImpl::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 }
524 const base::DictionaryValue*
525 ManagedNetworkConfigurationHandlerImpl::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
542 const ManagedNetworkConfigurationHandlerImpl::Policies*
543 ManagedNetworkConfigurationHandlerImpl::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
551 const ManagedNetworkConfigurationHandlerImpl::Policies*
552 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForProfile(
553     const NetworkProfile& profile) const {
554   DCHECK(profile.type() != NetworkProfile::TYPE_SHARED ||
555          profile.userhash.empty());
556   return GetPoliciesForUser(profile.userhash);
557 }
558
559 ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
560     : network_state_handler_(NULL),
561       network_profile_handler_(NULL),
562       network_configuration_handler_(NULL),
563       weak_ptr_factory_(this) {}
564
565 ManagedNetworkConfigurationHandlerImpl::
566     ~ManagedNetworkConfigurationHandlerImpl() {
567   network_profile_handler_->RemoveObserver(this);
568 }
569
570 void 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
580 void 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