Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Side by Side Diff: chromeos/network/managed_network_configuration_handler.cc

Issue 12676017: Adding policy support to the new network configuration stack. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed clang errors. Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chromeos/network/managed_network_configuration_handler.h" 5 #include "chromeos/network/managed_network_configuration_handler.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/guid.h" 11 #include "base/guid.h"
12 #include "base/json/json_writer.h"
13 #include "base/location.h"
12 #include "base/logging.h" 14 #include "base/logging.h"
13 #include "base/memory/ref_counted.h" 15 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_ptr.h" 16 #include "base/memory/scoped_ptr.h"
17 #include "base/stl_util.h"
15 #include "base/values.h" 18 #include "base/values.h"
16 #include "chromeos/dbus/dbus_method_call_status.h" 19 #include "chromeos/dbus/dbus_method_call_status.h"
17 #include "chromeos/dbus/dbus_thread_manager.h" 20 #include "chromeos/dbus/dbus_thread_manager.h"
18 #include "chromeos/dbus/shill_manager_client.h" 21 #include "chromeos/dbus/shill_manager_client.h"
22 #include "chromeos/dbus/shill_profile_client.h"
19 #include "chromeos/dbus/shill_service_client.h" 23 #include "chromeos/dbus/shill_service_client.h"
20 #include "chromeos/network/network_configuration_handler.h" 24 #include "chromeos/network/network_configuration_handler.h"
21 #include "chromeos/network/network_event_log.h" 25 #include "chromeos/network/network_event_log.h"
26 #include "chromeos/network/network_handler_callbacks.h"
22 #include "chromeos/network/network_state.h" 27 #include "chromeos/network/network_state.h"
23 #include "chromeos/network/network_state_handler.h" 28 #include "chromeos/network/network_state_handler.h"
29 #include "chromeos/network/network_ui_data.h"
24 #include "chromeos/network/onc/onc_constants.h" 30 #include "chromeos/network/onc/onc_constants.h"
31 #include "chromeos/network/onc/onc_merger.h"
25 #include "chromeos/network/onc/onc_signature.h" 32 #include "chromeos/network/onc/onc_signature.h"
26 #include "chromeos/network/onc/onc_translator.h" 33 #include "chromeos/network/onc/onc_translator.h"
34 #include "chromeos/network/onc/onc_utils.h"
35 #include "chromeos/network/onc/onc_validator.h"
27 #include "dbus/object_path.h" 36 #include "dbus/object_path.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h" 37 #include "third_party/cros_system_api/dbus/service_constants.h"
29 38
30 namespace chromeos { 39 namespace chromeos {
31 40
32 namespace { 41 namespace {
33 42
34 ManagedNetworkConfigurationHandler* g_configuration_handler_instance = NULL; 43 ManagedNetworkConfigurationHandler* g_configuration_handler_instance = NULL;
35 44
36 const char kLogModule[] = "ManagedNetworkConfigurationHandler"; 45 const char kLogModule[] = "ManagedNetworkConfigurationHandler";
37 46
38 // These are error strings used for error callbacks. None of these error 47 // These are error strings used for error callbacks. None of these error
39 // messages are user-facing: they should only appear in logs. 48 // messages are user-facing: they should only appear in logs.
49 const char kInvalidUserSettingsMessage[] = "User settings are invalid.";
50 const char kInvalidUserSettings[] = "Error.InvalidUserSettings";
51 const char kNetworkAlreadyConfiguredMessage[] =
52 "Network is already configured.";
53 const char kNetworkAlreadyConfigured[] = "Error.NetworkAlreadyConfigured";
54 const char kPoliciesNotInitializedMessage[] = "Policies not initialized.";
55 const char kPoliciesNotInitialized[] = "Error.PoliciesNotInitialized";
40 const char kServicePath[] = "servicePath"; 56 const char kServicePath[] = "servicePath";
41 const char kSetOnUnconfiguredNetworkMessage[] = 57 const char kSetOnUnconfiguredNetworkMessage[] =
42 "Unable to modify properties of an unconfigured network."; 58 "Unable to modify properties of an unconfigured network.";
43 const char kSetOnUnconfiguredNetwork[] = "Error.SetCalledOnUnconfiguredNetwork"; 59 const char kSetOnUnconfiguredNetwork[] = "Error.SetCalledOnUnconfiguredNetwork";
60 const char kUIDataErrorMessage[] = "UI data contains errors.";
61 const char kUIDataError[] = "Error.UIData";
44 const char kUnknownServicePathMessage[] = "Service path is unknown."; 62 const char kUnknownServicePathMessage[] = "Service path is unknown.";
45 const char kUnknownServicePath[] = "Error.UnknownServicePath"; 63 const char kUnknownServicePath[] = "Error.UnknownServicePath";
46 64
65 enum ProfileType {
66 PROFILE_NONE, // Not in any profile.
67 PROFILE_SHARED, // In the shared profile, shared by all users on device.
68 PROFILE_USER // In the user profile, not visible to other users.
69 };
70
71 const char kSharedProfilePath[] = "/profile/default";
72 const char kUserProfilePath[] = "/profile/chronos/shill";
73
74 // This fake credential contains a random postfix which is extremly unlikely to
75 // be used by any user.
76 const char kFakeCredential[] = "FAKE_CREDENTIAL_VPaJDV9x";
77
47 void RunErrorCallback(const std::string& service_path, 78 void RunErrorCallback(const std::string& service_path,
48 const std::string& error_name, 79 const std::string& error_name,
49 const std::string& error_message, 80 const std::string& error_message,
50 const network_handler::ErrorCallback& error_callback) { 81 const network_handler::ErrorCallback& error_callback) {
51 network_event_log::AddEntry(kLogModule, error_name, error_message); 82 network_event_log::AddEntry(kLogModule, error_name, error_message);
52 error_callback.Run( 83 error_callback.Run(
53 error_name, 84 error_name,
54 make_scoped_ptr( 85 make_scoped_ptr(
55 network_handler::CreateErrorData(service_path, 86 network_handler::CreateErrorData(service_path,
56 error_name, 87 error_name,
57 error_message))); 88 error_message)));
58 } 89 }
59 90
60 void TranslatePropertiesAndRunCallback( 91 // Returns the NetworkUIData parsed from the UIData property of
92 // |shill_dictionary|. If parsing fails or the field doesn't exist, returns
93 // NULL.
94 scoped_ptr<NetworkUIData> GetUIData(
95 const base::DictionaryValue& shill_dictionary) {
96 std::string ui_data_blob;
97 if (shill_dictionary.GetStringWithoutPathExpansion(
98 flimflam::kUIDataProperty,
99 &ui_data_blob) &&
100 !ui_data_blob.empty()) {
101 scoped_ptr<base::DictionaryValue> ui_data_dict =
102 onc::ReadDictionaryFromJson(ui_data_blob);
103 if (ui_data_dict)
104 return make_scoped_ptr(new NetworkUIData(*ui_data_dict));
105 else
106 LOG(ERROR) << "UIData is not a valid JSON dictionary.";
107 }
108 return scoped_ptr<NetworkUIData>();
109 }
110
111 // Sets the UIData property in |shill_dictionary| to the serialization of
112 // |ui_data|.
113 void SetUIData(const NetworkUIData& ui_data,
114 base::DictionaryValue* shill_dictionary) {
115 base::DictionaryValue ui_data_dict;
116 ui_data.FillDictionary(&ui_data_dict);
117 std::string ui_data_blob;
118 base::JSONWriter::Write(&ui_data_dict, &ui_data_blob);
119 shill_dictionary->SetStringWithoutPathExpansion(flimflam::kUIDataProperty,
120 ui_data_blob);
121 }
122
123 // A dummy callback to ignore the result of Shill calls.
124 void IgnoreString(const std::string& str) {
125 }
126
127 void LogErrorWithDict(const tracked_objects::Location& from_where,
128 const std::string& error_name,
129 const scoped_ptr<base::DictionaryValue> error_data) {
130 LOG(ERROR) << from_where.ToString() << ": " << error_name;
131 }
132
133 void LogErrorMessage(const tracked_objects::Location& from_where,
134 const std::string& error_name,
135 const std::string& error_message) {
136 LOG(ERROR) << from_where.ToString() << ": " << error_message;
137 }
138
139 // Removes all kFakeCredential values from sensitive fields (determined by
140 // onc::FieldIsCredential) of |onc_object|.
141 void RemoveFakeCredentials(
142 const onc::OncValueSignature& signature,
143 base::DictionaryValue* onc_object) {
144 base::DictionaryValue::Iterator it(*onc_object);
145 while (!it.IsAtEnd()) {
146 base::Value* value = NULL;
147 std::string field_name = it.key();
148 // We need the non-const entry to remove nested values but DictionaryValue
149 // has no non-const iterator.
150 onc_object->GetWithoutPathExpansion(field_name, &value);
151 // Advance before delete.
152 it.Advance();
153
154 // If |value| is a dictionary, recurse.
155 base::DictionaryValue* nested_object = NULL;
156 if (value->GetAsDictionary(&nested_object)) {
157 const onc::OncFieldSignature* field_signature =
158 onc::GetFieldSignature(signature, field_name);
159
160 RemoveFakeCredentials(*field_signature->value_signature,
161 nested_object);
162 continue;
163 }
164
165 // If |value| is a string, check if it is a fake credential.
166 std::string string_value;
167 if (value->GetAsString(&string_value) &&
168 onc::FieldIsCredential(signature, field_name)) {
169 if (string_value == kFakeCredential) {
170 // The value wasn't modified by the UI, thus we remove the field to keep
171 // the existing value that is stored in Shill.
172 onc_object->RemoveWithoutPathExpansion(field_name, NULL);
173 }
174 // Otherwise, the value is set and modified by the UI, thus we keep that
175 // value to overwrite whatever is stored in Shill.
176 }
177 }
178 }
179
180 // Creates a Shill property dictionary from the given arguments. The resulting
181 // dictionary will be sent to Shill by the caller. Depending on the profile
182 // path, |policy| is interpreted as the user or device policy and |settings| as
183 // the user or shared settings.
184 scoped_ptr<base::DictionaryValue> CreateShillConfiguration(
185 const std::string& profile_path,
186 const std::string& guid,
187 const base::DictionaryValue* policy,
188 const base::DictionaryValue* settings) {
189 scoped_ptr<base::DictionaryValue> effective;
190
191 onc::ONCSource onc_source;
192 if (policy) {
193 if (profile_path == kSharedProfilePath) {
194 effective = onc::MergeSettingsAndPoliciesToEffective(
195 NULL, // no user policy
196 policy, // device policy
197 NULL, // no user settings
198 settings); // shared settings
199 onc_source = onc::ONC_SOURCE_DEVICE_POLICY;
200 } else {
201 effective = onc::MergeSettingsAndPoliciesToEffective(
202 policy, // user policy
203 NULL, // no device policy
204 settings, // user settings
205 NULL); // no shared settings
206 onc_source = onc::ONC_SOURCE_USER_POLICY;
207 }
208 } else if (settings) {
209 effective.reset(settings->DeepCopy());
210 // TODO(pneubeck): change to source ONC_SOURCE_USER
211 onc_source = onc::ONC_SOURCE_NONE;
212 } else {
213 NOTREACHED();
214 onc_source = onc::ONC_SOURCE_NONE;
215 }
216
217 RemoveFakeCredentials(onc::kNetworkConfigurationSignature,
218 effective.get());
219
220 effective->SetStringWithoutPathExpansion(onc::network_config::kGUID, guid);
221
222 scoped_ptr<base::DictionaryValue> shill_dictionary(
223 onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
224 *effective));
225
226 shill_dictionary->SetStringWithoutPathExpansion(flimflam::kProfileProperty,
227 profile_path);
228
229 scoped_ptr<NetworkUIData> ui_data;
230 if (policy)
231 ui_data = CreateUIDataFromONC(onc_source, *policy);
232 else
233 ui_data.reset(new NetworkUIData());
234
235 if (settings) {
236 // Shill doesn't know that sensitive data is contained in the UIData
237 // property and might write it into logs or other insecure places. Thus, we
238 // have to remove or mask credentials.
239 //
240 // Shill's GetProperties doesn't return credentials. Masking credentials
241 // instead of just removing them, allows remembering if a credential is set
242 // or not.
243 scoped_ptr<base::DictionaryValue> sanitized_settings(
244 onc::MaskCredentialsInOncObject(onc::kNetworkConfigurationSignature,
245 *settings,
246 kFakeCredential));
247 ui_data->set_user_settings(sanitized_settings.Pass());
248 }
249
250 SetUIData(*ui_data, shill_dictionary.get());
251
252 VLOG(2) << "Created Shill properties: " << *shill_dictionary;
253
254 return shill_dictionary.Pass();
255 }
256
257 // Returns true if |policy| matches |onc_network_part|. This is should be the
258 // only such matching function within Chrome. Shill does such matching in
259 // several functions for network identification. For compatibility, we currently
260 // should stick to Shill's matching behavior.
261 bool IsPolicyMatching(const base::DictionaryValue& policy,
262 const base::DictionaryValue& onc_network_part) {
263 std::string policy_type;
264 policy.GetStringWithoutPathExpansion(onc::network_config::kType,
265 &policy_type);
266 std::string network_type;
267 onc_network_part.GetStringWithoutPathExpansion(onc::network_config::kType,
268 &network_type);
269 if (policy_type != network_type)
270 return false;
271
272 if (network_type != onc::network_type::kWiFi)
273 return false;
274
275 std::string policy_ssid;
276 policy.GetStringWithoutPathExpansion(onc::wifi::kSSID, &policy_ssid);
277 std::string network_ssid;
278 onc_network_part.GetStringWithoutPathExpansion(onc::wifi::kSSID,
279 &network_ssid);
280 return (policy_ssid == network_ssid);
281 }
282
283 // Returns the policy of |policies| matching |onc_network_part|, if any
284 // exists. Returns NULL otherwise.
285 const base::DictionaryValue* FindMatchingPolicy(
286 const ManagedNetworkConfigurationHandler::PolicyMap &policies,
287 const base::DictionaryValue& onc_network_part) {
288 for (ManagedNetworkConfigurationHandler::PolicyMap::const_iterator it =
289 policies.begin(); it != policies.end(); ++it) {
290 if (IsPolicyMatching(*it->second, onc_network_part))
291 return it->second;
292 }
293 return NULL;
294 }
295
296 void TranslatePropertiesToOncAndRunCallback(
61 const network_handler::DictionaryResultCallback& callback, 297 const network_handler::DictionaryResultCallback& callback,
62 const std::string& service_path, 298 const std::string& service_path,
63 const base::DictionaryValue& shill_properties) { 299 const base::DictionaryValue& shill_properties) {
64 scoped_ptr<base::DictionaryValue> onc_network( 300 scoped_ptr<base::DictionaryValue> onc_network(
65 onc::TranslateShillServiceToONCPart( 301 onc::TranslateShillServiceToONCPart(
66 shill_properties, 302 shill_properties,
67 &onc::kNetworkWithStateSignature)); 303 &onc::kNetworkWithStateSignature));
68 callback.Run(service_path, *onc_network); 304 callback.Run(service_path, *onc_network);
69 } 305 }
70 306
(...skipping 16 matching lines...) Expand all
87 delete g_configuration_handler_instance; 323 delete g_configuration_handler_instance;
88 g_configuration_handler_instance = NULL; 324 g_configuration_handler_instance = NULL;
89 } 325 }
90 326
91 // static 327 // static
92 ManagedNetworkConfigurationHandler* ManagedNetworkConfigurationHandler::Get() { 328 ManagedNetworkConfigurationHandler* ManagedNetworkConfigurationHandler::Get() {
93 CHECK(g_configuration_handler_instance); 329 CHECK(g_configuration_handler_instance);
94 return g_configuration_handler_instance; 330 return g_configuration_handler_instance;
95 } 331 }
96 332
333 void ManagedNetworkConfigurationHandler::GetManagedProperties(
334 const std::string& service_path,
335 const network_handler::DictionaryResultCallback& callback,
336 const network_handler::ErrorCallback& error_callback) {
337 if (!user_policies_initialized_ || !device_policies_initialized_) {
338 RunErrorCallback(service_path,
339 kPoliciesNotInitialized,
340 kPoliciesNotInitializedMessage,
341 error_callback);
342 return;
343 }
344 NetworkConfigurationHandler::Get()->GetProperties(
345 service_path,
346 base::Bind(
347 &ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback,
348 weak_ptr_factory_.GetWeakPtr(),
349 callback,
350 error_callback),
351 error_callback);
352 }
353
354 void ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback(
355 const network_handler::DictionaryResultCallback& callback,
356 const network_handler::ErrorCallback& error_callback,
357 const std::string& service_path,
358 const base::DictionaryValue& shill_properties) {
359 std::string profile_path;
360 ProfileType profile_type = PROFILE_NONE;
361 if (shill_properties.GetStringWithoutPathExpansion(
362 flimflam::kProfileProperty, &profile_path)) {
363 if (profile_path == kSharedProfilePath)
364 profile_type = PROFILE_SHARED;
365 else if (!profile_path.empty())
366 profile_type = PROFILE_USER;
367 } else {
368 VLOG(1) << "No profile path for service " << service_path << ".";
369 }
370
371 scoped_ptr<NetworkUIData> ui_data = GetUIData(shill_properties);
372
373 const base::DictionaryValue* user_settings = NULL;
374 const base::DictionaryValue* shared_settings = NULL;
375
376 if (ui_data) {
377 if (profile_type == PROFILE_SHARED)
378 shared_settings = ui_data->user_settings();
379 else if (profile_type == PROFILE_USER)
380 user_settings = ui_data->user_settings();
381 } else if (profile_type != PROFILE_NONE) {
382 LOG(WARNING) << "Service " << service_path << " of profile "
383 << profile_path << " contains no or no valid UIData.";
384 // TODO(pneubeck): add a conversion of user configured entries of old
385 // ChromeOS versions. We will have to use a heuristic to determine which
386 // properties _might_ be user configured.
387 }
388
389 scoped_ptr<base::DictionaryValue> active_settings(
390 onc::TranslateShillServiceToONCPart(
391 shill_properties,
392 &onc::kNetworkWithStateSignature));
393
394 std::string guid;
395 active_settings->GetStringWithoutPathExpansion(onc::network_config::kGUID,
396 &guid);
397
398 const base::DictionaryValue* user_policy = NULL;
399 const base::DictionaryValue* device_policy = NULL;
400 if (!guid.empty()) {
401 // We already checked that the policies were initialized. No need to do that
402 // again.
403 if (profile_type == PROFILE_SHARED)
404 device_policy = device_policies_by_guid_[guid];
405 else if (profile_type == PROFILE_USER)
406 user_policy = user_policies_by_guid_[guid];
407 }
408
409 // This call also removes credentials from policies.
410 scoped_ptr<base::DictionaryValue> augmented_properties =
411 onc::MergeSettingsAndPoliciesToAugmented(
412 onc::kNetworkConfigurationSignature,
413 user_policy,
414 device_policy,
415 user_settings,
416 shared_settings,
417 active_settings.get());
418 callback.Run(service_path, *augmented_properties);
419 }
420
97 void ManagedNetworkConfigurationHandler::GetProperties( 421 void ManagedNetworkConfigurationHandler::GetProperties(
98 const std::string& service_path, 422 const std::string& service_path,
99 const network_handler::DictionaryResultCallback& callback, 423 const network_handler::DictionaryResultCallback& callback,
100 const network_handler::ErrorCallback& error_callback) const { 424 const network_handler::ErrorCallback& error_callback) const {
101 // TODO(pneubeck): Merge with policies.
102 NetworkConfigurationHandler::Get()->GetProperties( 425 NetworkConfigurationHandler::Get()->GetProperties(
103 service_path, 426 service_path,
104 base::Bind(&TranslatePropertiesAndRunCallback, callback), 427 base::Bind(&TranslatePropertiesToOncAndRunCallback, callback),
105 error_callback); 428 error_callback);
106 } 429 }
107 430
108 void ManagedNetworkConfigurationHandler::SetProperties( 431 void ManagedNetworkConfigurationHandler::SetProperties(
109 const std::string& service_path, 432 const std::string& service_path,
110 const base::DictionaryValue& properties, 433 const base::DictionaryValue& user_settings,
111 const base::Closure& callback, 434 const base::Closure& callback,
112 const network_handler::ErrorCallback& error_callback) const { 435 const network_handler::ErrorCallback& error_callback) const {
113 const NetworkState* state = 436 const NetworkState* state =
114 NetworkStateHandler::Get()->GetNetworkState(service_path); 437 NetworkStateHandler::Get()->GetNetworkState(service_path);
115 438
116 if (!state) { 439 if (!state) {
117 RunErrorCallback(service_path, 440 RunErrorCallback(service_path,
118 kUnknownServicePath, 441 kUnknownServicePath,
119 kUnknownServicePathMessage, 442 kUnknownServicePathMessage,
120 error_callback); 443 error_callback);
444 return;
121 } 445 }
446
122 std::string guid = state->guid(); 447 std::string guid = state->guid();
123 if (guid.empty()) { 448 if (guid.empty()) {
449 // TODO(pneubeck): create an initial configuration in this case. As for
450 // CreateConfiguration, user settings from older ChromeOS versions have to
451 // determined here.
124 RunErrorCallback(service_path, 452 RunErrorCallback(service_path,
125 kSetOnUnconfiguredNetwork, 453 kSetOnUnconfiguredNetwork,
126 kSetOnUnconfiguredNetworkMessage, 454 kSetOnUnconfiguredNetworkMessage,
127 error_callback); 455 error_callback);
456 return;
128 } 457 }
129 458
130 // TODO(pneubeck): Enforce policies. 459 // Validate the ONC dictionary. We are liberal and ignore unknown field
460 // names. User settings are only partial ONC, thus we ignore missing fields.
461 onc::Validator validator(false, // Ignore unknown fields.
462 false, // Ignore invalid recommended field names.
463 false, // Ignore missing fields.
464 false); // This ONC does not comes from policy.
465
466 onc::Validator::Result validation_result;
467 scoped_ptr<base::DictionaryValue> validated_user_settings =
468 validator.ValidateAndRepairObject(
469 &onc::kNetworkConfigurationSignature,
470 user_settings,
471 &validation_result);
472
473 if (validation_result == onc::Validator::INVALID) {
474 LOG(ERROR) << "ONC user settings are invalid and couldn't be repaired.";
475 RunErrorCallback(service_path,
476 kInvalidUserSettings,
477 kInvalidUserSettingsMessage,
478 error_callback);
479 return;
480 }
481 if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
482 LOG(WARNING) << "Validation of ONC user settings produced warnings.";
483
484 VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
485 << state->profile_path();
486
487 const PolicyMap* policies_by_guid =
488 GetPoliciesForProfile(state->profile_path());
489
490 if (!policies_by_guid) {
491 RunErrorCallback(service_path,
492 kPoliciesNotInitialized,
493 kPoliciesNotInitializedMessage,
494 error_callback);
495 return;
496 }
497
498 const base::DictionaryValue* policy = NULL;
499 PolicyMap::const_iterator it = policies_by_guid->find(guid);
500 if (it != policies_by_guid->end())
501 policy = it->second;
502
503 VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
131 504
132 scoped_ptr<base::DictionaryValue> shill_dictionary( 505 scoped_ptr<base::DictionaryValue> shill_dictionary(
133 onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature, 506 CreateShillConfiguration(state->profile_path(), guid, policy,
134 properties)); 507 &user_settings));
135 508
136 NetworkConfigurationHandler::Get()->SetProperties(service_path, 509 NetworkConfigurationHandler::Get()->SetProperties(service_path,
137 *shill_dictionary, 510 *shill_dictionary,
138 callback, 511 callback,
139 error_callback); 512 error_callback);
140 } 513 }
141 514
142 void ManagedNetworkConfigurationHandler::Connect( 515 void ManagedNetworkConfigurationHandler::Connect(
143 const std::string& service_path, 516 const std::string& service_path,
144 const base::Closure& callback, 517 const base::Closure& callback,
145 const network_handler::ErrorCallback& error_callback) const { 518 const network_handler::ErrorCallback& error_callback) const {
146 // TODO(pneubeck): Update the user profile with tracked/followed settings of
147 // the shared profile.
148 NetworkConfigurationHandler::Get()->Connect(service_path, 519 NetworkConfigurationHandler::Get()->Connect(service_path,
149 callback, 520 callback,
150 error_callback); 521 error_callback);
151 } 522 }
152 523
153 void ManagedNetworkConfigurationHandler::Disconnect( 524 void ManagedNetworkConfigurationHandler::Disconnect(
154 const std::string& service_path, 525 const std::string& service_path,
155 const base::Closure& callback, 526 const base::Closure& callback,
156 const network_handler::ErrorCallback& error_callback) const { 527 const network_handler::ErrorCallback& error_callback) const {
157 NetworkConfigurationHandler::Get()->Disconnect(service_path, 528 NetworkConfigurationHandler::Get()->Disconnect(service_path,
158 callback, 529 callback,
159 error_callback); 530 error_callback);
160 } 531 }
161 532
162 void ManagedNetworkConfigurationHandler::CreateConfiguration( 533 void ManagedNetworkConfigurationHandler::CreateConfiguration(
163 const base::DictionaryValue& properties, 534 const base::DictionaryValue& properties,
164 const network_handler::StringResultCallback& callback, 535 const network_handler::StringResultCallback& callback,
165 const network_handler::ErrorCallback& error_callback) const { 536 const network_handler::ErrorCallback& error_callback) const {
166 scoped_ptr<base::DictionaryValue> modified_properties( 537 std::string profile_path = kUserProfilePath;
167 properties.DeepCopy()); 538 const PolicyMap* policies_by_guid = GetPoliciesForProfile(profile_path);
168 539
169 // If there isn't already a GUID attached to these properties, then 540 if (!policies_by_guid) {
170 // generate one and add it. 541 RunErrorCallback("",
171 std::string guid; 542 kPoliciesNotInitialized,
172 if (!properties.GetString(onc::network_config::kGUID, &guid)) { 543 kPoliciesNotInitializedMessage,
173 guid = base::GenerateGUID(); 544 error_callback);
174 modified_properties->SetStringWithoutPathExpansion( 545 return;
175 onc::network_config::kGUID, guid);
176 } else {
177 NOTREACHED(); // TODO(pneubeck): Return an error using error_callback.
178 } 546 }
179 547
180 // TODO(pneubeck): Enforce policies. 548 if (FindMatchingPolicy(*policies_by_guid, properties)) {
549 RunErrorCallback("",
550 kNetworkAlreadyConfigured,
551 kNetworkAlreadyConfiguredMessage,
552 error_callback);
553 }
554
555 // TODO(pneubeck): In case of WiFi, check that no other configuration for the
556 // same {SSID, mode, security} exists. We don't support such multiple
557 // configurations, yet.
558
559 // Generate a new GUID for this configuration. Ignore the maybe provided GUID
560 // in |properties| as it is not our own and from an untrusted source.
561 std::string guid = base::GenerateGUID();
181 562
182 scoped_ptr<base::DictionaryValue> shill_dictionary( 563 scoped_ptr<base::DictionaryValue> shill_dictionary(
183 onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature, 564 CreateShillConfiguration(profile_path, guid, NULL /*no policy*/,
184 properties)); 565 &properties));
185 566
186 NetworkConfigurationHandler::Get()->CreateConfiguration(*shill_dictionary, 567 NetworkConfigurationHandler::Get()->CreateConfiguration(*shill_dictionary,
187 callback, 568 callback,
188 error_callback); 569 error_callback);
189 } 570 }
190 571
191 void ManagedNetworkConfigurationHandler::RemoveConfiguration( 572 void ManagedNetworkConfigurationHandler::RemoveConfiguration(
192 const std::string& service_path, 573 const std::string& service_path,
193 const base::Closure& callback, 574 const base::Closure& callback,
194 const network_handler::ErrorCallback& error_callback) const { 575 const network_handler::ErrorCallback& error_callback) const {
195 NetworkConfigurationHandler::Get()->RemoveConfiguration(service_path, 576 NetworkConfigurationHandler::Get()->RemoveConfiguration(service_path,
196 callback, 577 callback,
197 error_callback); 578 error_callback);
198 } 579 }
199 580
200 ManagedNetworkConfigurationHandler::ManagedNetworkConfigurationHandler() { 581 // This class compares (entry point is Run()) |modified_policies| with the
582 // existing entries in the provided Shill profile |profile|. It fetches all
583 // entries in parallel (GetProfileProperties), compares each entry with the
584 // current policies (GetEntry) and adds all missing policies
585 // (~PolicyApplicator).
586 class ManagedNetworkConfigurationHandler::PolicyApplicator
587 : public base::RefCounted<PolicyApplicator> {
588 public:
589 typedef ManagedNetworkConfigurationHandler::PolicyMap PolicyMap;
590
591 // |modified_policies| must not be NULL and will be empty afterwards.
592 PolicyApplicator(base::WeakPtr<ManagedNetworkConfigurationHandler> handler,
593 const std::string& profile,
594 std::set<std::string>* modified_policies)
595 : handler_(handler),
596 profile_path_(profile) {
597 remaining_policies_.swap(*modified_policies);
598 }
599
600 void Run() {
601 DBusThreadManager::Get()->GetShillProfileClient()->GetProperties(
602 dbus::ObjectPath(profile_path_),
603 base::Bind(&PolicyApplicator::GetProfileProperties, this),
604 base::Bind(&LogErrorMessage, FROM_HERE));
605 }
606
607 private:
608 friend class base::RefCounted<PolicyApplicator>;
609
610 void GetProfileProperties(const base::DictionaryValue& profile_properties) {
611 if (!handler_) {
612 LOG(WARNING) << "Handler destructed during policy application to profile "
613 << profile_path_;
614 return;
615 }
616
617 VLOG(2) << "Received properties for profile " << profile_path_;
618 const base::ListValue* entries = NULL;
619 if (!profile_properties.GetListWithoutPathExpansion(
620 flimflam::kEntriesProperty, &entries)) {
621 LOG(ERROR) << "Profile " << profile_path_
622 << " doesn't contain the property "
623 << flimflam::kEntriesProperty;
624 return;
625 }
626
627 for (base::ListValue::const_iterator it = entries->begin();
628 it != entries->end(); ++it) {
629 std::string entry;
630 (*it)->GetAsString(&entry);
631
632 std::ostringstream entry_failure;
633 DBusThreadManager::Get()->GetShillProfileClient()->GetEntry(
634 dbus::ObjectPath(profile_path_),
635 entry,
636 base::Bind(&PolicyApplicator::GetEntry, this, entry),
637 base::Bind(&LogErrorMessage, FROM_HERE));
638 }
639 }
640
641 void GetEntry(const std::string& entry,
642 const base::DictionaryValue& entry_properties) {
643 if (!handler_) {
644 LOG(WARNING) << "Handler destructed during policy application to profile "
645 << profile_path_;
646 return;
647 }
648
649 VLOG(2) << "Received properties for entry " << entry << " of profile "
650 << profile_path_;
651
652 scoped_ptr<base::DictionaryValue> onc_part(
653 onc::TranslateShillServiceToONCPart(
654 entry_properties,
655 &onc::kNetworkWithStateSignature));
656
657 std::string old_guid;
658 if (!onc_part->GetStringWithoutPathExpansion(onc::network_config::kGUID,
659 &old_guid)) {
660 LOG(WARNING) << "Entry " << entry << " of profile " << profile_path_
661 << " doesn't contain a GUID.";
662 // This might be an entry of an older ChromeOS version. Assume it to be
663 // unmanaged.
664 return;
665 }
666
667 scoped_ptr<NetworkUIData> ui_data = GetUIData(entry_properties);
668 if (!ui_data) {
669 VLOG(1) << "Entry " << entry << " of profile " << profile_path_
670 << " contains no or no valid UIData.";
671 // This might be an entry of an older ChromeOS version. Assume it to be
672 // unmanaged.
673 return;
674 }
675
676 bool was_managed =
677 (ui_data->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY ||
678 ui_data->onc_source() == onc::ONC_SOURCE_USER_POLICY);
679
680 // The relevant policy must have been initialized, otherwise we hadn't Run
681 // this PolicyApplicator.
682 const PolicyMap& policies_by_guid =
683 *handler_->GetPoliciesForProfile(profile_path_);
684
685 const base::DictionaryValue* new_policy = NULL;
686 if (was_managed) {
687 // If we have a GUID that might match a current policy, do a lookup using
688 // that GUID at first. In particular this is necessary, as some networks
689 // can't be matched to policies by properties (e.g. VPN).
690 PolicyMap::const_iterator it = policies_by_guid.find(old_guid);
691 if (it != policies_by_guid.end())
692 new_policy = it->second;
693 }
694
695 if (!new_policy) {
696 // If we didn't find a policy by GUID, still a new policy might match.
697 new_policy = FindMatchingPolicy(policies_by_guid, *onc_part);
698 }
699
700 if (new_policy) {
701 std::string new_guid;
702 new_policy->GetStringWithoutPathExpansion(onc::network_config::kGUID,
703 &new_guid);
704
705 VLOG_IF(1, was_managed && old_guid != new_guid)
706 << "Updating configuration previously managed by policy " << old_guid
707 << " with new policy " << new_guid << ".";
708 VLOG_IF(1, !was_managed)
709 << "Applying policy " << new_guid << " to previously unmanaged "
710 << "configuration.";
711
712 if (old_guid == new_guid &&
713 remaining_policies_.find(new_guid) == remaining_policies_.end()) {
714 VLOG(1) << "Not updating existing managed configuration with guid "
715 << new_guid << " because the policy didn't change.";
716 } else {
717 VLOG_IF(1, old_guid == new_guid)
718 << "Updating previously managed configuration with the updated "
719 << "policy " << new_guid << ".";
720
721 // Update the existing configuration with the maybe changed
722 // policy. Thereby the GUID might change.
723 scoped_ptr<base::DictionaryValue> shill_dictionary =
724 CreateShillConfiguration(profile_path_, new_guid, new_policy,
725 ui_data->user_settings());
726 NetworkConfigurationHandler::Get()->CreateConfiguration(
727 *shill_dictionary,
728 base::Bind(&IgnoreString),
729 base::Bind(&LogErrorWithDict, FROM_HERE));
730 remaining_policies_.erase(new_guid);
731 }
732 } else if (was_managed) {
733 VLOG(1) << "Removing configuration previously managed by policy "
734 << old_guid << ", because the policy was removed.";
735
736 // Remove the entry, because the network was managed but isn't anymore.
737 // Note: An alternative might be to preserve the user settings, but it's
738 // unclear which values originating the policy should be removed.
739 DeleteEntry(entry);
740 } else {
741 VLOG(2) << "Ignore unmanaged entry.";
742
743 // The entry wasn't managed and doesn't match any current policy. Thus
744 // leave it as it is.
745 }
746 }
747
748 void DeleteEntry(const std::string& entry) {
749 DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry(
750 dbus::ObjectPath(profile_path_),
751 entry,
752 base::Bind(&base::DoNothing),
753 base::Bind(&LogErrorMessage, FROM_HERE));
754 }
755
756 virtual ~PolicyApplicator() {
757 if (remaining_policies_.empty())
758 return;
759
760 VLOG(2) << "Create new managed network configurations in profile"
761 << profile_path_ << ".";
762 // All profile entries were compared to policies. |configureGUIDs_| contains
763 // all matched policies. From the remainder of policies, new configurations
764 // have to be created.
765
766 // The relevant policy must have been initialized, otherwise we hadn't Run
767 // this PolicyApplicator.
768 const PolicyMap& policies_by_guid =
769 *handler_->GetPoliciesForProfile(profile_path_);
770
771 for (std::set<std::string>::iterator it = remaining_policies_.begin();
772 it != remaining_policies_.end(); ++it) {
773 PolicyMap::const_iterator policy_it = policies_by_guid.find(*it);
774 if (policy_it == policies_by_guid.end()) {
775 LOG(ERROR) << "Policy " << *it << " doesn't exist anymore.";
776 continue;
777 }
778
779 const base::DictionaryValue* policy = policy_it->second;
780
781 VLOG(1) << "Creating new configuration managed by policy " << *it
782 << " in profile " << profile_path_ << ".";
783
784 scoped_ptr<base::DictionaryValue> shill_dictionary =
785 CreateShillConfiguration(profile_path_, *it, policy, NULL);
786 NetworkConfigurationHandler::Get()->CreateConfiguration(
787 *shill_dictionary,
788 base::Bind(&IgnoreString),
789 base::Bind(&LogErrorWithDict, FROM_HERE));
790 }
791 }
792
793 std::set<std::string> remaining_policies_;
794 base::WeakPtr<ManagedNetworkConfigurationHandler> handler_;
795 std::string profile_path_;
796
797 DISALLOW_COPY_AND_ASSIGN(PolicyApplicator);
798 };
799
800 void ManagedNetworkConfigurationHandler::SetPolicy(
801 onc::ONCSource onc_source,
802 const base::DictionaryValue& toplevel_onc) {
803 VLOG(1) << "Setting policies for ONC source "
804 << onc::GetSourceAsString(onc_source) << ".";
805
806 // Validate the ONC dictionary. We are liberal and ignore unknown field
807 // names and ignore invalid field names in kRecommended arrays.
808 onc::Validator validator(false, // Ignore unknown fields.
809 false, // Ignore invalid recommended field names.
810 true, // Fail on missing fields.
811 true); // This ONC comes from policy.
812 validator.SetOncSource(onc_source);
813
814 onc::Validator::Result validation_result;
815 scoped_ptr<base::DictionaryValue> onc_validated =
816 validator.ValidateAndRepairObject(
817 &onc::kToplevelConfigurationSignature,
818 toplevel_onc,
819 &validation_result);
820
821 if (validation_result == onc::Validator::VALID_WITH_WARNINGS) {
822 LOG(WARNING) << "ONC from " << onc::GetSourceAsString(onc_source)
823 << " produced warnings.";
824 } else if (validation_result == onc::Validator::INVALID ||
825 onc_validated == NULL) {
826 LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
827 << " is invalid and couldn't be repaired.";
828 return;
829 }
830
831 PolicyMap* policies;
832 std::string profile;
833 if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY) {
834 policies = &user_policies_by_guid_;
835 profile = kUserProfilePath;
836 user_policies_initialized_ = true;
837 } else {
838 policies = &device_policies_by_guid_;
839 profile = kSharedProfilePath;
840 device_policies_initialized_ = true;
841 }
842
843 PolicyMap old_policies;
844 policies->swap(old_policies);
845
846 // This stores all GUIDs of policies that have changed or are new.
847 std::set<std::string> modified_policies;
848
849 base::ListValue* network_configurations = NULL;
850 onc_validated->GetListWithoutPathExpansion(
851 onc::toplevel_config::kNetworkConfigurations,
852 &network_configurations);
853
854 if (network_configurations) {
855 while (!network_configurations->empty()) {
856 base::Value* network_value = NULL;
857 // Passes ownership of network_value.
858 network_configurations->Remove(network_configurations->GetSize() - 1,
859 &network_value);
860 const base::DictionaryValue* network = NULL;
861 network_value->GetAsDictionary(&network);
862 std::string guid;
863 network->GetStringWithoutPathExpansion(onc::network_config::kGUID,
864 &guid);
865
866 const base::DictionaryValue* old_entry = old_policies[guid];
867 const base::DictionaryValue*& new_entry = (*policies)[guid];
868 if (new_entry) {
869 LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
870 << " contains several entries for the same GUID "
871 << guid << ".";
872 delete new_entry;
873 }
874 new_entry = network;
875
876 if (!old_entry || !old_entry->Equals(new_entry)) {
877 modified_policies.insert(guid);
878 }
879 }
880 }
881
882 STLDeleteValues(&old_policies);
883
884 scoped_refptr<PolicyApplicator> applicator = new PolicyApplicator(
885 weak_ptr_factory_.GetWeakPtr(),
886 profile,
887 &modified_policies);
888 applicator->Run();
889 }
890
891 const ManagedNetworkConfigurationHandler::PolicyMap*
892 ManagedNetworkConfigurationHandler::GetPoliciesForProfile(
893 const std::string& profile) const {
894 if (profile == kSharedProfilePath) {
895 if (device_policies_initialized_)
896 return &device_policies_by_guid_;
897 } else if (user_policies_initialized_) {
898 return &user_policies_by_guid_;
899 }
900 return NULL;
901 }
902
903 ManagedNetworkConfigurationHandler::ManagedNetworkConfigurationHandler()
904 : user_policies_initialized_(false),
905 device_policies_initialized_(false),
906 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
201 } 907 }
202 908
203 ManagedNetworkConfigurationHandler::~ManagedNetworkConfigurationHandler() { 909 ManagedNetworkConfigurationHandler::~ManagedNetworkConfigurationHandler() {
910 STLDeleteValues(&user_policies_by_guid_);
911 STLDeleteValues(&device_policies_by_guid_);
204 } 912 }
205 913
206 } // namespace chromeos 914 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698