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

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

Powered by Google App Engine
This is Rietveld 408576698