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