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