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

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: Addressed Julian's comments. Reuploaded with rebase. 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 and a credential, ...
stevenjb 2013/04/16 16:02:40 Maybe 'If |value| is a string, check if it is a fa
166 std::string string_value;
167 if (value->GetAsString(&string_value) &&
168 onc::FieldIsCredential(signature, field_name) &&
169 string_value == kFakeCredential) {
170 if (string_value == kFakeCredential) {
stevenjb 2013/04/16 16:02:40 redundant
171 // The value wasn't modified by the UI, thus we remove the field to keep
172 // the existing value that is stored in Shill.
173 onc_object->RemoveWithoutPathExpansion(field_name, NULL);
174 }
175 // Otherwise, the value is set and modified by the UI, thus we keep that
176 // value to overwrite whatever is stored in Shill.
177 }
178 }
179 }
180
181 // Creates a Shill property dictionary from the given arguments. The resulting
182 // dictionary will be sent to Shill by the caller. Depending on the profile
183 // path, |policy| is interpreted as the user or device policy and |settings| as
184 // the user or shared settings.
185 scoped_ptr<base::DictionaryValue> CreateShillConfiguration(
186 const std::string& profile_path,
187 const std::string& guid,
188 const base::DictionaryValue* policy,
189 const base::DictionaryValue* settings) {
190 scoped_ptr<base::DictionaryValue> effective;
191
192 onc::ONCSource onc_source;
193 if (policy) {
194 if (profile_path == kSharedProfilePath) {
195 effective = onc::MergeSettingsAndPoliciesToEffective(
196 NULL, // no user policy
197 policy, // device policy
198 NULL, // no user settings
199 settings); // shared settings
200 onc_source = onc::ONC_SOURCE_DEVICE_POLICY;
201 } else {
202 effective = onc::MergeSettingsAndPoliciesToEffective(
203 policy, // user policy
204 NULL, // no device policy
205 settings, // user settings
206 NULL); // no shared settings
207 onc_source = onc::ONC_SOURCE_USER_POLICY;
208 }
209 } else if (settings) {
210 effective.reset(settings->DeepCopy());
211 // TODO(pneubeck): change to source ONC_SOURCE_USER
212 onc_source = onc::ONC_SOURCE_NONE;
213 } else {
214 NOTREACHED();
215 onc_source = onc::ONC_SOURCE_NONE;
216 }
217
218 RemoveFakeCredentials(onc::kNetworkConfigurationSignature,
219 effective.get());
220
221 effective->SetStringWithoutPathExpansion(onc::network_config::kGUID, guid);
222
223 scoped_ptr<base::DictionaryValue> shill_dictionary(
224 onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
225 *effective));
226
227 shill_dictionary->SetStringWithoutPathExpansion(flimflam::kProfileProperty,
228 profile_path);
229
230 scoped_ptr<NetworkUIData> ui_data;
231 if (policy)
232 ui_data = CreateUIDataFromONC(onc_source, *policy);
233 else
234 ui_data.reset(new NetworkUIData());
235
236 if (settings) {
237 // Shill doesn't know that sensitive data is contained in the UIData
238 // property and might write it into logs or other insecure places. Thus, we
239 // have to remove or mask credentials.
240 //
241 // Shill's GetProperties doesn't return credentials. Masking credentials
242 // instead of just removing them, allows remembering if a credential is set
243 // or not.
244 scoped_ptr<base::DictionaryValue> sanitized_settings(
245 onc::MaskCredentialsInOncObject(onc::kNetworkConfigurationSignature,
246 *settings,
247 kFakeCredential));
248 ui_data->set_user_settings(sanitized_settings.Pass());
249 }
250
251 SetUIData(*ui_data, shill_dictionary.get());
252
253 VLOG(2) << "Created Shill properties: " << *shill_dictionary;
254
255 return shill_dictionary.Pass();
256 }
257
258 // Returns true if |policy| matches |onc_network_part|. This is should be the
259 // only such matching function within Chrome. Shill does such matching in
260 // several functions for network identification. For compatibility, we currently
261 // should stick to Shill's matching behavior.
262 bool IsPolicyMatching(const base::DictionaryValue& policy,
263 const base::DictionaryValue& onc_network_part) {
264 std::string policy_type;
265 policy.GetStringWithoutPathExpansion(onc::network_config::kType,
266 &policy_type);
267 std::string network_type;
268 onc_network_part.GetStringWithoutPathExpansion(onc::network_config::kType,
269 &network_type);
270 if (policy_type != network_type)
271 return false;
272
273 if (network_type != onc::network_type::kWiFi)
274 return false;
275
276 std::string policy_ssid;
277 policy.GetStringWithoutPathExpansion(onc::wifi::kSSID, &policy_ssid);
278 std::string network_ssid;
279 onc_network_part.GetStringWithoutPathExpansion(onc::wifi::kSSID,
280 &network_ssid);
281 return (policy_ssid == network_ssid);
282 }
283
284 // Returns the policy of |policies| matching |onc_network_part|, if any
285 // exists. Returns NULL otherwise.
286 const base::DictionaryValue* FindMatchingPolicy(
287 const ManagedNetworkConfigurationHandler::PolicyMap &policies,
288 const base::DictionaryValue& onc_network_part) {
289 for (ManagedNetworkConfigurationHandler::PolicyMap::const_iterator it =
290 policies.begin(); it != policies.end(); ++it) {
291 if (IsPolicyMatching(*it->second, onc_network_part))
292 return it->second;
293 }
294 return NULL;
295 }
296
297 void TranslatePropertiesToOncAndRunCallback(
61 const network_handler::DictionaryResultCallback& callback, 298 const network_handler::DictionaryResultCallback& callback,
62 const std::string& service_path, 299 const std::string& service_path,
63 const base::DictionaryValue& shill_properties) { 300 const base::DictionaryValue& shill_properties) {
64 scoped_ptr<base::DictionaryValue> onc_network( 301 scoped_ptr<base::DictionaryValue> onc_network(
65 onc::TranslateShillServiceToONCPart( 302 onc::TranslateShillServiceToONCPart(
66 shill_properties, 303 shill_properties,
67 &onc::kNetworkWithStateSignature)); 304 &onc::kNetworkWithStateSignature));
68 callback.Run(service_path, *onc_network); 305 callback.Run(service_path, *onc_network);
69 } 306 }
70 307
(...skipping 16 matching lines...) Expand all
87 delete g_configuration_handler_instance; 324 delete g_configuration_handler_instance;
88 g_configuration_handler_instance = NULL; 325 g_configuration_handler_instance = NULL;
89 } 326 }
90 327
91 // static 328 // static
92 ManagedNetworkConfigurationHandler* ManagedNetworkConfigurationHandler::Get() { 329 ManagedNetworkConfigurationHandler* ManagedNetworkConfigurationHandler::Get() {
93 CHECK(g_configuration_handler_instance); 330 CHECK(g_configuration_handler_instance);
94 return g_configuration_handler_instance; 331 return g_configuration_handler_instance;
95 } 332 }
96 333
334 void ManagedNetworkConfigurationHandler::GetManagedProperties(
335 const std::string& service_path,
336 const network_handler::DictionaryResultCallback& callback,
337 const network_handler::ErrorCallback& error_callback) {
338 if (!user_policies_initialized_ || !device_policies_initialized_) {
339 RunErrorCallback(service_path,
340 kPoliciesNotInitialized,
341 kPoliciesNotInitializedMessage,
342 error_callback);
343 return;
344 }
345 NetworkConfigurationHandler::Get()->GetProperties(
346 service_path,
347 base::Bind(
348 &ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback,
349 weak_ptr_factory_.GetWeakPtr(),
350 callback,
351 error_callback),
352 error_callback);
353 }
354
355 void ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback(
356 const network_handler::DictionaryResultCallback& callback,
357 const network_handler::ErrorCallback& error_callback,
358 const std::string& service_path,
359 const base::DictionaryValue& shill_properties) {
360 std::string profile_path;
361 ProfileType profile_type = PROFILE_NONE;
362 if (shill_properties.GetStringWithoutPathExpansion(
363 flimflam::kProfileProperty, &profile_path)) {
364 if (profile_path == kSharedProfilePath)
365 profile_type = PROFILE_SHARED;
366 else if (!profile_path.empty())
367 profile_type = PROFILE_USER;
368 } else {
369 VLOG(1) << "No profile path for service " << service_path << ".";
370 }
371
372 scoped_ptr<NetworkUIData> ui_data = GetUIData(shill_properties);
373
374 const base::DictionaryValue* user_settings = NULL;
375 const base::DictionaryValue* shared_settings = NULL;
376
377 if (ui_data) {
378 if (profile_type == PROFILE_SHARED)
379 shared_settings = ui_data->user_settings();
380 else if (profile_type == PROFILE_USER)
381 user_settings = ui_data->user_settings();
382 } else if (profile_type != PROFILE_NONE) {
383 LOG(WARNING) << "Service " << service_path << " of profile "
384 << profile_path << " contains no or no valid UIData.";
385 // TODO(pneubeck): add a conversion of user configured entries of old
386 // ChromeOS versions. We will have to use a heuristic to determine which
387 // properties _might_ be user configured.
388 }
389
390 scoped_ptr<base::DictionaryValue> active_settings(
391 onc::TranslateShillServiceToONCPart(
392 shill_properties,
393 &onc::kNetworkWithStateSignature));
394
395 std::string guid;
396 active_settings->GetStringWithoutPathExpansion(onc::network_config::kGUID,
397 &guid);
398
399 const base::DictionaryValue* user_policy = NULL;
400 const base::DictionaryValue* device_policy = NULL;
401 if (!guid.empty()) {
402 // We already checked that the policies were initialized. No need to do that
403 // again.
404 if (profile_type == PROFILE_SHARED)
405 device_policy = device_policies_by_guid_[guid];
406 else if (profile_type == PROFILE_USER)
407 user_policy = user_policies_by_guid_[guid];
408 }
409
410 // This call also removes credentials from policies.
411 scoped_ptr<base::DictionaryValue> augmented_properties =
412 onc::MergeSettingsAndPoliciesToAugmented(
413 onc::kNetworkConfigurationSignature,
414 user_policy,
415 device_policy,
416 user_settings,
417 shared_settings,
418 active_settings.get());
419 callback.Run(service_path, *augmented_properties);
420 }
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(&TranslatePropertiesToOncAndRunCallback, 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::INVALID) {
475 LOG(ERROR) << "ONC user settings are invalid and couldn't be repaired.";
476 RunErrorCallback(service_path,
477 kInvalidUserSettings,
478 kInvalidUserSettingsMessage,
479 error_callback);
480 return;
481 }
482 if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
483 LOG(WARNING) << "Validation of ONC user settings produced warnings.";
484
485 VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
486 << state->profile_path();
487
488 const PolicyMap* policies_by_guid =
489 GetPoliciesForProfile(state->profile_path());
490
491 if (!policies_by_guid) {
492 RunErrorCallback(service_path,
493 kPoliciesNotInitialized,
494 kPoliciesNotInitializedMessage,
495 error_callback);
496 return;
497 }
498
499 const base::DictionaryValue* policy = NULL;
500 PolicyMap::const_iterator it = policies_by_guid->find(guid);
501 if (it != policies_by_guid->end())
502 policy = it->second;
503
504 VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
131 505
132 scoped_ptr<base::DictionaryValue> shill_dictionary( 506 scoped_ptr<base::DictionaryValue> shill_dictionary(
133 onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature, 507 CreateShillConfiguration(state->profile_path(), guid, policy,
134 properties)); 508 &user_settings));
135 509
136 NetworkConfigurationHandler::Get()->SetProperties(service_path, 510 NetworkConfigurationHandler::Get()->SetProperties(service_path,
137 *shill_dictionary, 511 *shill_dictionary,
138 callback, 512 callback,
139 error_callback); 513 error_callback);
140 } 514 }
141 515
142 void ManagedNetworkConfigurationHandler::Connect( 516 void ManagedNetworkConfigurationHandler::Connect(
143 const std::string& service_path, 517 const std::string& service_path,
144 const base::Closure& callback, 518 const base::Closure& callback,
145 const network_handler::ErrorCallback& error_callback) const { 519 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, 520 NetworkConfigurationHandler::Get()->Connect(service_path,
149 callback, 521 callback,
150 error_callback); 522 error_callback);
151 } 523 }
152 524
153 void ManagedNetworkConfigurationHandler::Disconnect( 525 void ManagedNetworkConfigurationHandler::Disconnect(
154 const std::string& service_path, 526 const std::string& service_path,
155 const base::Closure& callback, 527 const base::Closure& callback,
156 const network_handler::ErrorCallback& error_callback) const { 528 const network_handler::ErrorCallback& error_callback) const {
157 NetworkConfigurationHandler::Get()->Disconnect(service_path, 529 NetworkConfigurationHandler::Get()->Disconnect(service_path,
158 callback, 530 callback,
159 error_callback); 531 error_callback);
160 } 532 }
161 533
162 void ManagedNetworkConfigurationHandler::CreateConfiguration( 534 void ManagedNetworkConfigurationHandler::CreateConfiguration(
163 const base::DictionaryValue& properties, 535 const base::DictionaryValue& properties,
164 const network_handler::StringResultCallback& callback, 536 const network_handler::StringResultCallback& callback,
165 const network_handler::ErrorCallback& error_callback) const { 537 const network_handler::ErrorCallback& error_callback) const {
166 scoped_ptr<base::DictionaryValue> modified_properties( 538 std::string profile_path = kUserProfilePath;
167 properties.DeepCopy()); 539 const PolicyMap* policies_by_guid = GetPoliciesForProfile(profile_path);
168 540
169 // If there isn't already a GUID attached to these properties, then 541 if (!policies_by_guid) {
170 // generate one and add it. 542 RunErrorCallback("",
171 std::string guid; 543 kPoliciesNotInitialized,
172 if (!properties.GetString(onc::network_config::kGUID, &guid)) { 544 kPoliciesNotInitializedMessage,
173 guid = base::GenerateGUID(); 545 error_callback);
174 modified_properties->SetStringWithoutPathExpansion( 546 return;
175 onc::network_config::kGUID, guid);
176 } else {
177 NOTREACHED(); // TODO(pneubeck): Return an error using error_callback.
178 } 547 }
179 548
180 // TODO(pneubeck): Enforce policies. 549 if (FindMatchingPolicy(*policies_by_guid, properties)) {
550 RunErrorCallback("",
551 kNetworkAlreadyConfigured,
552 kNetworkAlreadyConfiguredMessage,
553 error_callback);
554 }
555
556 // TODO(pneubeck): In case of WiFi, check that no other configuration for the
557 // same {SSID, mode, security} exists. We don't support such multiple
558 // configurations, yet.
559
560 // Generate a new GUID for this configuration. Ignore the maybe provided GUID
561 // in |properties| as it is not our own and from an untrusted source.
562 std::string guid = base::GenerateGUID();
181 563
182 scoped_ptr<base::DictionaryValue> shill_dictionary( 564 scoped_ptr<base::DictionaryValue> shill_dictionary(
183 onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature, 565 CreateShillConfiguration(profile_path, guid, NULL /*no policy*/,
184 properties)); 566 &properties));
185 567
186 NetworkConfigurationHandler::Get()->CreateConfiguration(*shill_dictionary, 568 NetworkConfigurationHandler::Get()->CreateConfiguration(*shill_dictionary,
187 callback, 569 callback,
188 error_callback); 570 error_callback);
189 } 571 }
190 572
191 void ManagedNetworkConfigurationHandler::RemoveConfiguration( 573 void ManagedNetworkConfigurationHandler::RemoveConfiguration(
192 const std::string& service_path, 574 const std::string& service_path,
193 const base::Closure& callback, 575 const base::Closure& callback,
194 const network_handler::ErrorCallback& error_callback) const { 576 const network_handler::ErrorCallback& error_callback) const {
195 NetworkConfigurationHandler::Get()->RemoveConfiguration(service_path, 577 NetworkConfigurationHandler::Get()->RemoveConfiguration(service_path,
196 callback, 578 callback,
197 error_callback); 579 error_callback);
198 } 580 }
199 581
200 ManagedNetworkConfigurationHandler::ManagedNetworkConfigurationHandler() { 582 // This class compares (entry point is Run()) |modified_policies| with the
583 // existing entries in the provided Shill profile |profile|. It fetches all
584 // entries in parallel (GetProfileProperties), compares each entry with the
585 // current policies (GetEntry) and adds all missing policies
586 // (~PolicyApplicator).
587 class ManagedNetworkConfigurationHandler::PolicyApplicator
588 : public base::RefCounted<PolicyApplicator> {
589 public:
590 typedef ManagedNetworkConfigurationHandler::PolicyMap PolicyMap;
591
592 // |modified_policies| must not be NULL and will be empty afterwards.
593 PolicyApplicator(base::WeakPtr<ManagedNetworkConfigurationHandler> handler,
594 const std::string& profile,
595 std::set<std::string>* modified_policies)
596 : handler_(handler),
597 profile_path_(profile) {
598 remaining_policies_.swap(*modified_policies);
599 }
600
601 void Run() {
602 DBusThreadManager::Get()->GetShillProfileClient()->GetProperties(
603 dbus::ObjectPath(profile_path_),
604 base::Bind(&PolicyApplicator::GetProfileProperties, this),
605 base::Bind(&LogErrorMessage, FROM_HERE));
606 }
607
608 private:
609 friend class base::RefCounted<PolicyApplicator>;
610
611 void GetProfileProperties(const base::DictionaryValue& profile_properties) {
612 if (!handler_) {
613 LOG(WARNING) << "Handler destructed during policy application to profile "
614 << profile_path_;
615 return;
616 }
617
618 VLOG(2) << "Received properties for profile " << profile_path_;
619 const base::ListValue* entries = NULL;
620 if (!profile_properties.GetListWithoutPathExpansion(
621 flimflam::kEntriesProperty, &entries)) {
622 LOG(ERROR) << "Profile " << profile_path_
623 << " doesn't contain the property "
624 << flimflam::kEntriesProperty;
625 return;
626 }
627
628 for (base::ListValue::const_iterator it = entries->begin();
629 it != entries->end(); ++it) {
630 std::string entry;
631 (*it)->GetAsString(&entry);
632
633 std::ostringstream entry_failure;
634 DBusThreadManager::Get()->GetShillProfileClient()->GetEntry(
635 dbus::ObjectPath(profile_path_),
636 entry,
637 base::Bind(&PolicyApplicator::GetEntry, this, entry),
638 base::Bind(&LogErrorMessage, FROM_HERE));
639 }
640 }
641
642 void GetEntry(const std::string& entry,
643 const base::DictionaryValue& entry_properties) {
644 if (!handler_) {
645 LOG(WARNING) << "Handler destructed during policy application to profile "
646 << profile_path_;
647 return;
648 }
649
650 VLOG(2) << "Received properties for entry " << entry << " of profile "
651 << profile_path_;
652
653 scoped_ptr<base::DictionaryValue> onc_part(
654 onc::TranslateShillServiceToONCPart(
655 entry_properties,
656 &onc::kNetworkWithStateSignature));
657
658 std::string old_guid;
659 if (!onc_part->GetStringWithoutPathExpansion(onc::network_config::kGUID,
660 &old_guid)) {
661 LOG(WARNING) << "Entry " << entry << " of profile " << profile_path_
662 << " doesn't contain a GUID.";
663 // This might be an entry of an older ChromeOS version. Assume it to be
664 // unmanaged.
665 return;
666 }
667
668 scoped_ptr<NetworkUIData> ui_data = GetUIData(entry_properties);
669 if (!ui_data) {
670 VLOG(1) << "Entry " << entry << " of profile " << profile_path_
671 << " contains no or no valid UIData.";
672 // This might be an entry of an older ChromeOS version. Assume it to be
673 // unmanaged.
674 return;
675 }
676
677 bool was_managed =
678 (ui_data->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY ||
679 ui_data->onc_source() == onc::ONC_SOURCE_USER_POLICY);
680
681 // The relevant policy must have been initialized, otherwise we hadn't Run
682 // this PolicyApplicator.
683 const PolicyMap& policies_by_guid =
684 *handler_->GetPoliciesForProfile(profile_path_);
685
686 const base::DictionaryValue* new_policy = NULL;
687 if (was_managed) {
688 // If we have a GUID that might match a current policy, do a lookup using
689 // that GUID at first. In particular this is necessary, as some networks
690 // can't be matched to policies by properties (e.g. VPN).
691 PolicyMap::const_iterator it = policies_by_guid.find(old_guid);
692 if (it != policies_by_guid.end())
693 new_policy = it->second;
694 }
695
696 if (!new_policy) {
697 // If we didn't find a policy by GUID, still a new policy might match.
698 new_policy = FindMatchingPolicy(policies_by_guid, *onc_part);
699 }
700
701 if (new_policy) {
702 std::string new_guid;
703 new_policy->GetStringWithoutPathExpansion(onc::network_config::kGUID,
704 &new_guid);
705
706 VLOG_IF(1, was_managed && old_guid != new_guid)
707 << "Updating configuration previously managed by policy " << old_guid
708 << " with new policy " << new_guid << ".";
709 VLOG_IF(1, !was_managed)
710 << "Applying policy " << new_guid << " to previously unmanaged "
711 << "configuration.";
712
713 if (old_guid == new_guid &&
714 remaining_policies_.find(new_guid) == remaining_policies_.end()) {
715 VLOG(1) << "Not updating existing managed configuration with guid "
716 << new_guid << " because the policy didn't change.";
717 } else {
718 VLOG_IF(1, old_guid == new_guid)
719 << "Updating previously managed configuration with the updated "
720 << "policy " << new_guid << ".";
721
722 // Update the existing configuration with the maybe changed
723 // policy. Thereby the GUID might change.
724 scoped_ptr<base::DictionaryValue> shill_dictionary =
725 CreateShillConfiguration(profile_path_, new_guid, new_policy,
726 ui_data->user_settings());
727 NetworkConfigurationHandler::Get()->CreateConfiguration(
728 *shill_dictionary,
729 base::Bind(&IgnoreString),
730 base::Bind(&LogErrorWithDict, FROM_HERE));
731 remaining_policies_.erase(new_guid);
732 }
733 } else if (was_managed) {
734 VLOG(1) << "Removing configuration previously managed by policy "
735 << old_guid << ", because the policy was removed.";
736
737 // Remove the entry, because the network was managed but isn't anymore.
738 // Note: An alternative might be to preserve the user settings, but it's
739 // unclear which values originating the policy should be removed.
740 DeleteEntry(entry);
741 } else {
742 VLOG(2) << "Ignore unmanaged entry.";
743
744 // The entry wasn't managed and doesn't match any current policy. Thus
745 // leave it as it is.
746 }
747 }
748
749 void DeleteEntry(const std::string& entry) {
750 DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry(
751 dbus::ObjectPath(profile_path_),
752 entry,
753 base::Bind(&base::DoNothing),
754 base::Bind(&LogErrorMessage, FROM_HERE));
755 }
756
757 virtual ~PolicyApplicator() {
758 if (remaining_policies_.empty())
759 return;
760
761 VLOG(2) << "Create new managed network configurations in profile"
762 << profile_path_ << ".";
763 // All profile entries were compared to policies. |configureGUIDs_| contains
764 // all matched policies. From the remainder of policies, new configurations
765 // have to be created.
766
767 // The relevant policy must have been initialized, otherwise we hadn't Run
768 // this PolicyApplicator.
769 const PolicyMap& policies_by_guid =
770 *handler_->GetPoliciesForProfile(profile_path_);
771
772 for (std::set<std::string>::iterator it = remaining_policies_.begin();
773 it != remaining_policies_.end(); ++it) {
774 PolicyMap::const_iterator policy_it = policies_by_guid.find(*it);
775 if (policy_it == policies_by_guid.end()) {
776 LOG(ERROR) << "Policy " << *it << " doesn't exist anymore.";
777 continue;
778 }
779
780 const base::DictionaryValue* policy = policy_it->second;
781
782 VLOG(1) << "Creating new configuration managed by policy " << *it
783 << " in profile " << profile_path_ << ".";
784
785 scoped_ptr<base::DictionaryValue> shill_dictionary =
786 CreateShillConfiguration(profile_path_, *it, policy, NULL);
787 NetworkConfigurationHandler::Get()->CreateConfiguration(
788 *shill_dictionary,
789 base::Bind(&IgnoreString),
790 base::Bind(&LogErrorWithDict, FROM_HERE));
791 }
792 }
793
794 std::set<std::string> remaining_policies_;
795 base::WeakPtr<ManagedNetworkConfigurationHandler> handler_;
796 std::string profile_path_;
797
798 DISALLOW_COPY_AND_ASSIGN(PolicyApplicator);
799 };
800
801 void ManagedNetworkConfigurationHandler::SetPolicy(
802 onc::ONCSource onc_source,
803 const base::DictionaryValue& toplevel_onc) {
804 VLOG(1) << "Setting policies for ONC source "
805 << onc::GetSourceAsString(onc_source) << ".";
806
807 // Validate the ONC dictionary. We are liberal and ignore unknown field
808 // names and ignore invalid field names in kRecommended arrays.
809 onc::Validator validator(false, // Ignore unknown fields.
810 false, // Ignore invalid recommended field names.
811 true, // Fail on missing fields.
812 true); // This ONC comes from policy.
813 validator.SetOncSource(onc_source);
814
815 onc::Validator::Result validation_result;
816 scoped_ptr<base::DictionaryValue> onc_validated =
817 validator.ValidateAndRepairObject(
818 &onc::kToplevelConfigurationSignature,
819 toplevel_onc,
820 &validation_result);
821
822 if (validation_result == onc::Validator::VALID_WITH_WARNINGS) {
823 LOG(WARNING) << "ONC from " << onc::GetSourceAsString(onc_source)
824 << " produced warnings.";
825 } else if (validation_result == onc::Validator::INVALID ||
826 onc_validated == NULL) {
827 LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
828 << " is invalid and couldn't be repaired.";
829 return;
830 }
831
832 PolicyMap* policies;
833 std::string profile;
834 if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY) {
835 policies = &user_policies_by_guid_;
836 profile = kUserProfilePath;
837 user_policies_initialized_ = true;
838 } else {
839 policies = &device_policies_by_guid_;
840 profile = kSharedProfilePath;
841 device_policies_initialized_ = true;
842 }
843
844 PolicyMap old_policies;
845 policies->swap(old_policies);
846
847 // This stores all GUIDs of policies that have changed or are new.
848 std::set<std::string> modified_policies;
849
850 base::ListValue* network_configurations = NULL;
851 onc_validated->GetListWithoutPathExpansion(
852 onc::toplevel_config::kNetworkConfigurations,
853 &network_configurations);
854
855 if (network_configurations) {
856 while (!network_configurations->empty()) {
857 base::Value* network_value = NULL;
858 // Passes ownership of network_value.
859 network_configurations->Remove(network_configurations->GetSize() - 1,
860 &network_value);
861 const base::DictionaryValue* network = NULL;
862 network_value->GetAsDictionary(&network);
863 std::string guid;
864 network->GetStringWithoutPathExpansion(onc::network_config::kGUID,
865 &guid);
866
867 const base::DictionaryValue* old_entry = old_policies[guid];
868 const base::DictionaryValue*& new_entry = (*policies)[guid];
869 if (new_entry) {
870 LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
871 << " contains several entries for the same GUID "
872 << guid << ".";
873 delete new_entry;
874 }
875 new_entry = network;
876
877 if (!old_entry || !old_entry->Equals(new_entry)) {
878 modified_policies.insert(guid);
879 }
880 }
881 }
882
883 STLDeleteValues(&old_policies);
884
885 scoped_refptr<PolicyApplicator> applicator = new PolicyApplicator(
886 weak_ptr_factory_.GetWeakPtr(),
887 profile,
888 &modified_policies);
889 applicator->Run();
890 }
891
892 const ManagedNetworkConfigurationHandler::PolicyMap*
893 ManagedNetworkConfigurationHandler::GetPoliciesForProfile(
894 const std::string& profile) const {
895 if (profile == kSharedProfilePath) {
896 if (device_policies_initialized_)
897 return &device_policies_by_guid_;
898 } else if (user_policies_initialized_) {
899 return &user_policies_by_guid_;
900 }
901 return NULL;
902 }
903
904 ManagedNetworkConfigurationHandler::ManagedNetworkConfigurationHandler()
905 : user_policies_initialized_(false),
906 device_policies_initialized_(false),
907 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
201 } 908 }
202 909
203 ManagedNetworkConfigurationHandler::~ManagedNetworkConfigurationHandler() { 910 ManagedNetworkConfigurationHandler::~ManagedNetworkConfigurationHandler() {
911 STLDeleteValues(&user_policies_by_guid_);
912 STLDeleteValues(&device_policies_by_guid_);
204 } 913 }
205 914
206 } // namespace chromeos 915 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698