network_configuration_handler.cc revision c2db58bd994c04d98e4ee2cd7565b71548655fe3
1// Copyright (c) 2012 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/network_configuration_handler.h" 6 7#include <string> 8#include <vector> 9 10#include "base/bind.h" 11#include "base/format_macros.h" 12#include "base/json/json_writer.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/strings/stringprintf.h" 18#include "base/values.h" 19#include "chromeos/dbus/dbus_thread_manager.h" 20#include "chromeos/dbus/shill_manager_client.h" 21#include "chromeos/dbus/shill_profile_client.h" 22#include "chromeos/dbus/shill_service_client.h" 23#include "chromeos/network/network_event_log.h" 24#include "chromeos/network/network_state.h" 25#include "chromeos/network/network_state_handler.h" 26#include "dbus/object_path.h" 27#include "third_party/cros_system_api/dbus/service_constants.h" 28 29namespace chromeos { 30 31namespace { 32 33// Strip surrounding "" from keys (if present). 34std::string StripQuotations(const std::string& in_str) { 35 size_t len = in_str.length(); 36 if (len >= 2 && in_str[0] == '"' && in_str[len-1] == '"') 37 return in_str.substr(1, len-2); 38 return in_str; 39} 40 41void InvokeErrorCallback(const std::string& error, 42 const std::string& path, 43 const network_handler::ErrorCallback& error_callback) { 44 NET_LOG_ERROR(error, path); 45 if (error_callback.is_null()) 46 return; 47 scoped_ptr<base::DictionaryValue> error_data( 48 network_handler::CreateErrorData(path, error, "")); 49 error_callback.Run(error, error_data.Pass()); 50} 51 52void GetPropertiesCallback( 53 const network_handler::DictionaryResultCallback& callback, 54 const network_handler::ErrorCallback& error_callback, 55 const std::string& service_path, 56 DBusMethodCallStatus call_status, 57 const base::DictionaryValue& properties) { 58 // Get the correct name from WifiHex if necessary. 59 scoped_ptr<base::DictionaryValue> properties_copy(properties.DeepCopy()); 60 std::string name = NetworkState::GetNameFromProperties( 61 service_path, properties); 62 if (!name.empty()) { 63 properties_copy->SetStringWithoutPathExpansion( 64 flimflam::kNameProperty, name); 65 } 66 network_handler::GetPropertiesCallback( 67 callback, error_callback, service_path, call_status, 68 *properties_copy.get()); 69} 70 71void SetNetworkProfileErrorCallback( 72 const std::string& service_path, 73 const std::string& profile_path, 74 const network_handler::ErrorCallback& error_callback, 75 const std::string& dbus_error_name, 76 const std::string& dbus_error_message) { 77 network_handler::ShillErrorCallbackFunction( 78 "Config.SetNetworkProfile Failed: " + profile_path, 79 service_path, error_callback, 80 dbus_error_name, dbus_error_message); 81} 82 83bool IsPassphrase(const std::string& key) { 84 return key == flimflam::kEapPrivateKeyPasswordProperty || 85 key == flimflam::kEapPasswordProperty || 86 key == flimflam::kL2tpIpsecPasswordProperty || 87 key == flimflam::kOpenVPNPasswordProperty || 88 key == flimflam::kPassphraseProperty || 89 key == flimflam::kOpenVPNOTPProperty || 90 key == flimflam::kEapPrivateKeyProperty || 91 key == flimflam::kEapPrivateKeyPasswordProperty || 92 key == flimflam::kEapPinProperty || 93 key == flimflam::kApnPasswordProperty; 94} 95 96void LogConfigProperties(const std::string& desc, 97 const std::string& path, 98 const base::DictionaryValue& properties) { 99 for (base::DictionaryValue::Iterator iter(properties); 100 !iter.IsAtEnd(); iter.Advance()) { 101 std::string v = "******"; 102 if (!IsPassphrase(iter.key())) 103 base::JSONWriter::Write(&iter.value(), &v); 104 NET_LOG_DEBUG(desc, path + "." + iter.key() + "=" + v); 105 } 106} 107 108} // namespace 109 110// Helper class to request from Shill the profile entries associated with a 111// Service and delete the service from each profile. Triggers either 112// |callback| on success or |error_callback| on failure, and calls 113// |handler|->ProfileEntryDeleterCompleted() on completion to delete itself. 114class NetworkConfigurationHandler::ProfileEntryDeleter 115 : public base::SupportsWeakPtr<ProfileEntryDeleter> { 116 public: 117 ProfileEntryDeleter(NetworkConfigurationHandler* handler, 118 const std::string& service_path, 119 const base::Closure& callback, 120 const network_handler::ErrorCallback& error_callback) 121 : owner_(handler), 122 service_path_(service_path), 123 callback_(callback), 124 error_callback_(error_callback) { 125 } 126 127 void Run() { 128 DBusThreadManager::Get()->GetShillServiceClient()-> 129 GetLoadableProfileEntries( 130 dbus::ObjectPath(service_path_), 131 base::Bind(&ProfileEntryDeleter::GetProfileEntriesToDeleteCallback, 132 AsWeakPtr())); 133 } 134 135 private: 136 void GetProfileEntriesToDeleteCallback( 137 DBusMethodCallStatus call_status, 138 const base::DictionaryValue& profile_entries) { 139 if (call_status != DBUS_METHOD_CALL_SUCCESS) { 140 InvokeErrorCallback( 141 "GetLoadableProfileEntries Failed", service_path_, error_callback_); 142 owner_->ProfileEntryDeleterCompleted(service_path_); // Deletes this. 143 return; 144 } 145 146 for (base::DictionaryValue::Iterator iter(profile_entries); 147 !iter.IsAtEnd(); iter.Advance()) { 148 std::string profile_path = StripQuotations(iter.key()); 149 std::string entry_path; 150 iter.value().GetAsString(&entry_path); 151 if (profile_path.empty() || entry_path.empty()) { 152 NET_LOG_ERROR("Failed to parse Profile Entry", base::StringPrintf( 153 "%s: %s", profile_path.c_str(), entry_path.c_str())); 154 continue; 155 } 156 if (profile_delete_entries_.count(profile_path) != 0) { 157 NET_LOG_ERROR("Multiple Profile Entries", base::StringPrintf( 158 "%s: %s", profile_path.c_str(), entry_path.c_str())); 159 continue; 160 } 161 NET_LOG_DEBUG("Delete Profile Entry", base::StringPrintf( 162 "%s: %s", profile_path.c_str(), entry_path.c_str())); 163 profile_delete_entries_[profile_path] = entry_path; 164 DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry( 165 dbus::ObjectPath(profile_path), 166 entry_path, 167 base::Bind(&ProfileEntryDeleter::ProfileEntryDeletedCallback, 168 AsWeakPtr(), profile_path, entry_path), 169 base::Bind(&ProfileEntryDeleter::ShillErrorCallback, 170 AsWeakPtr(), profile_path, entry_path)); 171 } 172 } 173 174 void ProfileEntryDeletedCallback(const std::string& profile_path, 175 const std::string& entry) { 176 NET_LOG_DEBUG("Profile Entry Deleted", base::StringPrintf( 177 "%s: %s", profile_path.c_str(), entry.c_str())); 178 profile_delete_entries_.erase(profile_path); 179 if (!profile_delete_entries_.empty()) 180 return; 181 // Run the callback if this is the last pending deletion. 182 if (!callback_.is_null()) 183 callback_.Run(); 184 // Request NetworkStateHandler manager update to update ServiceCompleteList. 185 owner_->network_state_handler_->UpdateManagerProperties(); 186 owner_->ProfileEntryDeleterCompleted(service_path_); // Deletes this. 187 } 188 189 void ShillErrorCallback(const std::string& profile_path, 190 const std::string& entry, 191 const std::string& dbus_error_name, 192 const std::string& dbus_error_message) { 193 // Any Shill Error triggers a failure / error. 194 network_handler::ShillErrorCallbackFunction( 195 "GetLoadableProfileEntries Failed", profile_path, error_callback_, 196 dbus_error_name, dbus_error_message); 197 // Delete this even if there are pending deletions; any callbacks will 198 // safely become no-ops (by invalidating the WeakPtrs). 199 owner_->ProfileEntryDeleterCompleted(service_path_); // Deletes this. 200 } 201 202 NetworkConfigurationHandler* owner_; // Unowned 203 std::string service_path_; 204 base::Closure callback_; 205 network_handler::ErrorCallback error_callback_; 206 207 // Map of pending profile entry deletions, indexed by profile path. 208 std::map<std::string, std::string> profile_delete_entries_; 209 210 DISALLOW_COPY_AND_ASSIGN(ProfileEntryDeleter); 211}; 212 213// NetworkConfigurationHandler 214 215void NetworkConfigurationHandler::GetProperties( 216 const std::string& service_path, 217 const network_handler::DictionaryResultCallback& callback, 218 const network_handler::ErrorCallback& error_callback) const { 219 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties( 220 dbus::ObjectPath(service_path), 221 base::Bind(&GetPropertiesCallback, 222 callback, error_callback, service_path)); 223} 224 225void NetworkConfigurationHandler::SetProperties( 226 const std::string& service_path, 227 const base::DictionaryValue& properties, 228 const base::Closure& callback, 229 const network_handler::ErrorCallback& error_callback) { 230 if (properties.empty()) { 231 if (!callback.is_null()) 232 callback.Run(); 233 return; 234 } 235 NET_LOG_USER("SetProperties", service_path); 236 LogConfigProperties("SetProperty", service_path, properties); 237 238 DBusThreadManager::Get()->GetShillServiceClient()->SetProperties( 239 dbus::ObjectPath(service_path), 240 properties, 241 base::Bind(&NetworkConfigurationHandler::SetPropertiesSuccessCallback, 242 AsWeakPtr(), service_path, callback), 243 base::Bind(&NetworkConfigurationHandler::SetPropertiesErrorCallback, 244 AsWeakPtr(), service_path, error_callback)); 245} 246 247void NetworkConfigurationHandler::ClearProperties( 248 const std::string& service_path, 249 const std::vector<std::string>& names, 250 const base::Closure& callback, 251 const network_handler::ErrorCallback& error_callback) { 252 if (names.empty()) { 253 if (!callback.is_null()) 254 callback.Run(); 255 return; 256 } 257 NET_LOG_USER("ClearProperties", service_path); 258 for (std::vector<std::string>::const_iterator iter = names.begin(); 259 iter != names.end(); ++iter) { 260 NET_LOG_DEBUG("ClearProperty", service_path + "." + *iter); 261 } 262 DBusThreadManager::Get()->GetShillServiceClient()->ClearProperties( 263 dbus::ObjectPath(service_path), 264 names, 265 base::Bind(&NetworkConfigurationHandler::ClearPropertiesSuccessCallback, 266 AsWeakPtr(), service_path, names, callback, error_callback), 267 base::Bind(&NetworkConfigurationHandler::ClearPropertiesErrorCallback, 268 AsWeakPtr(), service_path, error_callback)); 269} 270 271void NetworkConfigurationHandler::CreateConfiguration( 272 const base::DictionaryValue& properties, 273 const network_handler::StringResultCallback& callback, 274 const network_handler::ErrorCallback& error_callback) { 275 ShillManagerClient* manager = 276 DBusThreadManager::Get()->GetShillManagerClient(); 277 std::string type; 278 properties.GetStringWithoutPathExpansion(flimflam::kTypeProperty, &type); 279 280 NET_LOG_USER("CreateConfiguration", type); 281 LogConfigProperties("Configure", type, properties); 282 283 std::string profile; 284 properties.GetStringWithoutPathExpansion(flimflam::kProfileProperty, 285 &profile); 286 DCHECK(!profile.empty()); 287 manager->ConfigureServiceForProfile( 288 dbus::ObjectPath(profile), 289 properties, 290 base::Bind(&NetworkConfigurationHandler::RunCreateNetworkCallback, 291 AsWeakPtr(), 292 callback), 293 base::Bind(&network_handler::ShillErrorCallbackFunction, 294 "Config.CreateConfiguration Failed", 295 "", 296 error_callback)); 297} 298 299void NetworkConfigurationHandler::RemoveConfiguration( 300 const std::string& service_path, 301 const base::Closure& callback, 302 const network_handler::ErrorCallback& error_callback) { 303 // Service.Remove is not reliable. Instead, request the profile entries 304 // for the service and remove each entry. 305 if (profile_entry_deleters_.count(service_path)) { 306 InvokeErrorCallback( 307 "RemoveConfiguration In-Progress", service_path, error_callback); 308 return; 309 } 310 NET_LOG_USER("Remove Configuration", service_path); 311 ProfileEntryDeleter* deleter = 312 new ProfileEntryDeleter(this, service_path, callback, error_callback); 313 profile_entry_deleters_[service_path] = deleter; 314 deleter->Run(); 315} 316 317void NetworkConfigurationHandler::SetNetworkProfile( 318 const std::string& service_path, 319 const std::string& profile_path, 320 const base::Closure& callback, 321 const network_handler::ErrorCallback& error_callback) { 322 NET_LOG_USER("SetNetworkProfile", service_path + ": " + profile_path); 323 base::StringValue profile_path_value(profile_path); 324 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( 325 dbus::ObjectPath(service_path), 326 flimflam::kProfileProperty, 327 profile_path_value, 328 callback, 329 base::Bind(&SetNetworkProfileErrorCallback, 330 service_path, profile_path, error_callback)); 331} 332 333// NetworkConfigurationHandler Private methods 334 335NetworkConfigurationHandler::NetworkConfigurationHandler() 336 : network_state_handler_(NULL) { 337} 338 339NetworkConfigurationHandler::~NetworkConfigurationHandler() { 340 STLDeleteContainerPairSecondPointers( 341 profile_entry_deleters_.begin(), profile_entry_deleters_.end()); 342} 343 344void NetworkConfigurationHandler::Init( 345 NetworkStateHandler* network_state_handler) { 346 network_state_handler_ = network_state_handler; 347} 348 349void NetworkConfigurationHandler::RunCreateNetworkCallback( 350 const network_handler::StringResultCallback& callback, 351 const dbus::ObjectPath& service_path) { 352 if (!callback.is_null()) 353 callback.Run(service_path.value()); 354 // This may also get called when CreateConfiguration is used to update an 355 // existing configuration, so request a service update just in case. 356 // TODO(pneubeck): Separate 'Create' and 'Update' calls and only trigger 357 // this on an update. 358 network_state_handler_->RequestUpdateForNetwork(service_path.value()); 359} 360 361void NetworkConfigurationHandler::ProfileEntryDeleterCompleted( 362 const std::string& service_path) { 363 std::map<std::string, ProfileEntryDeleter*>::iterator iter = 364 profile_entry_deleters_.find(service_path); 365 DCHECK(iter != profile_entry_deleters_.end()); 366 delete iter->second; 367 profile_entry_deleters_.erase(iter); 368} 369 370void NetworkConfigurationHandler::SetPropertiesSuccessCallback( 371 const std::string& service_path, 372 const base::Closure& callback) { 373 if (!callback.is_null()) 374 callback.Run(); 375 network_state_handler_->RequestUpdateForNetwork(service_path); 376} 377 378void NetworkConfigurationHandler::SetPropertiesErrorCallback( 379 const std::string& service_path, 380 const network_handler::ErrorCallback& error_callback, 381 const std::string& dbus_error_name, 382 const std::string& dbus_error_message) { 383 network_handler::ShillErrorCallbackFunction( 384 "Config.SetProperties Failed", 385 service_path, error_callback, 386 dbus_error_name, dbus_error_message); 387 // Some properties may have changed so request an update regardless. 388 network_state_handler_->RequestUpdateForNetwork(service_path); 389} 390 391void NetworkConfigurationHandler::ClearPropertiesSuccessCallback( 392 const std::string& service_path, 393 const std::vector<std::string>& names, 394 const base::Closure& callback, 395 const network_handler::ErrorCallback& error_callback, 396 const base::ListValue& result) { 397 const std::string kClearPropertiesFailedError("Error.ClearPropertiesFailed"); 398 DCHECK(names.size() == result.GetSize()) 399 << "Incorrect result size from ClearProperties."; 400 401 bool some_failed = false; 402 for (size_t i = 0; i < result.GetSize(); ++i) { 403 bool success = false; 404 result.GetBoolean(i, &success); 405 if (!success) { 406 NET_LOG_ERROR("ClearProperties Failed: " + names[i], service_path); 407 some_failed = true; 408 } 409 } 410 411 if (some_failed) { 412 if (!error_callback.is_null()) { 413 scoped_ptr<base::DictionaryValue> error_data( 414 network_handler::CreateErrorData( 415 service_path, kClearPropertiesFailedError, 416 base::StringPrintf("Errors: %" PRIuS, result.GetSize()))); 417 error_data->Set("errors", result.DeepCopy()); 418 scoped_ptr<base::ListValue> name_list(new base::ListValue); 419 name_list->AppendStrings(names); 420 error_data->Set("names", name_list.release()); 421 error_callback.Run(kClearPropertiesFailedError, error_data.Pass()); 422 } 423 } else if (!callback.is_null()) { 424 callback.Run(); 425 } 426 network_state_handler_->RequestUpdateForNetwork(service_path); 427} 428 429void NetworkConfigurationHandler::ClearPropertiesErrorCallback( 430 const std::string& service_path, 431 const network_handler::ErrorCallback& error_callback, 432 const std::string& dbus_error_name, 433 const std::string& dbus_error_message) { 434 network_handler::ShillErrorCallbackFunction( 435 "Config.ClearProperties Failed", 436 service_path, error_callback, 437 dbus_error_name, dbus_error_message); 438 // Some properties may have changed so request an update regardless. 439 network_state_handler_->RequestUpdateForNetwork(service_path); 440} 441 442// static 443NetworkConfigurationHandler* NetworkConfigurationHandler::InitializeForTest( 444 NetworkStateHandler* network_state_handler) { 445 NetworkConfigurationHandler* handler = new NetworkConfigurationHandler(); 446 handler->Init(network_state_handler); 447 return handler; 448} 449 450} // namespace chromeos 451