network_connection_handler.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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 3// found in the LICENSE file. 4 5#include "chromeos/network/network_connection_handler.h" 6 7#include "base/bind.h" 8#include "base/command_line.h" 9#include "base/json/json_reader.h" 10#include "chromeos/chromeos_switches.h" 11#include "chromeos/dbus/dbus_thread_manager.h" 12#include "chromeos/dbus/shill_manager_client.h" 13#include "chromeos/dbus/shill_service_client.h" 14#include "chromeos/network/cert_loader.h" 15#include "chromeos/network/certificate_pattern_matcher.h" 16#include "chromeos/network/managed_network_configuration_handler.h" 17#include "chromeos/network/network_configuration_handler.h" 18#include "chromeos/network/network_event_log.h" 19#include "chromeos/network/network_handler_callbacks.h" 20#include "chromeos/network/network_state.h" 21#include "chromeos/network/network_state_handler.h" 22#include "chromeos/network/network_ui_data.h" 23#include "dbus/object_path.h" 24#include "net/cert/x509_certificate.h" 25#include "third_party/cros_system_api/dbus/service_constants.h" 26 27namespace chromeos { 28 29namespace { 30 31void InvokeErrorCallback(const std::string& service_path, 32 const network_handler::ErrorCallback& error_callback, 33 const std::string& error_name) { 34 std::string error_msg = "Connect Error: " + error_name; 35 NET_LOG_ERROR(error_msg, service_path); 36 if (error_callback.is_null()) 37 return; 38 scoped_ptr<base::DictionaryValue> error_data( 39 network_handler::CreateErrorData(service_path, error_name, error_msg)); 40 error_callback.Run(error_name, error_data.Pass()); 41} 42 43bool NetworkMayNeedCredentials(const NetworkState* network) { 44 if (network->type() == flimflam::kTypeWifi && 45 (network->security() == flimflam::kSecurity8021x || 46 network->security() == flimflam::kSecurityWep /* For dynamic WEP*/)) 47 return true; 48 if (network->type() == flimflam::kTypeVPN) 49 return true; 50 return false; 51} 52 53bool NetworkRequiresActivation(const NetworkState* network) { 54 return (network->type() == flimflam::kTypeCellular && 55 (network->activation_state() != flimflam::kActivationStateActivated || 56 network->cellular_out_of_credits())); 57} 58 59bool VPNIsConfigured(const base::DictionaryValue& properties) { 60 std::string provider_type; 61 // Note: we use Value path expansion to extract Provider.Type. 62 properties.GetString(flimflam::kProviderTypeProperty, &provider_type); 63 if (provider_type == flimflam::kProviderOpenVpn) { 64 std::string hostname; 65 properties.GetString(flimflam::kProviderHostProperty, &hostname); 66 if (hostname.empty()) 67 return false; 68 std::string username; 69 properties.GetStringWithoutPathExpansion( 70 flimflam::kOpenVPNUserProperty, &username); 71 if (username.empty()) 72 return false; 73 std::string client_cert_id; 74 properties.GetStringWithoutPathExpansion( 75 flimflam::kOpenVPNClientCertIdProperty, &client_cert_id); 76 if (client_cert_id.empty()) 77 return false; 78 } else { 79 bool passphrase_required = false; 80 std::string passphrase; 81 properties.GetBooleanWithoutPathExpansion( 82 flimflam::kL2tpIpsecPskRequiredProperty, &passphrase_required); 83 properties.GetStringWithoutPathExpansion( 84 flimflam::kL2tpIpsecPskProperty, &passphrase); 85 if (passphrase_required && passphrase.empty()) 86 return false; 87 } 88 return true; 89} 90 91bool CertificateIsConfigured(NetworkUIData* ui_data) { 92 if (ui_data->certificate_type() != CLIENT_CERT_TYPE_PATTERN) 93 return true; // No certificate or a reference. 94 if (ui_data->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY) { 95 // We skip checking certificate patterns for device policy ONC so that an 96 // unmanaged user can't get to the place where a cert is presented for them 97 // involuntarily. 98 return true; 99 } 100 if (ui_data->certificate_pattern().Empty()) 101 return false; 102 103 // Find the matching certificate. 104 scoped_refptr<net::X509Certificate> matching_cert = 105 certificate_pattern::GetCertificateMatch( 106 ui_data->certificate_pattern()); 107 if (!matching_cert.get()) 108 return false; 109 return true; 110} 111 112} // namespace 113 114const char NetworkConnectionHandler::kErrorNotFound[] = "not-found"; 115const char NetworkConnectionHandler::kErrorConnected[] = "connected"; 116const char NetworkConnectionHandler::kErrorConnecting[] = "connecting"; 117const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected"; 118const char NetworkConnectionHandler::kErrorPassphraseRequired[] = 119 "passphrase-required"; 120const char NetworkConnectionHandler::kErrorActivationRequired[] = 121 "activation-required"; 122const char NetworkConnectionHandler::kErrorCertificateRequired[] = 123 "certificate-required"; 124const char NetworkConnectionHandler::kErrorConfigurationRequired[] = 125 "configuration-required"; 126const char NetworkConnectionHandler::kErrorShillError[] = "shill-error"; 127 128NetworkConnectionHandler::NetworkConnectionHandler() 129 : network_state_handler_(NULL), 130 network_configuration_handler_(NULL) { 131 const char* new_handlers_enabled = 132 CommandLine::ForCurrentProcess()->HasSwitch( 133 chromeos::switches::kUseNewNetworkConfigurationHandlers) ? 134 "enabled" : "disabled"; 135 NET_LOG_EVENT("NewNetworkConfigurationHandlers", new_handlers_enabled); 136} 137 138NetworkConnectionHandler::~NetworkConnectionHandler() { 139} 140 141void NetworkConnectionHandler::Init( 142 NetworkStateHandler* network_state_handler, 143 NetworkConfigurationHandler* network_configuration_handler) { 144 network_state_handler_ = network_state_handler; 145 network_configuration_handler_ = network_configuration_handler; 146} 147 148void NetworkConnectionHandler::ConnectToNetwork( 149 const std::string& service_path, 150 const base::Closure& success_callback, 151 const network_handler::ErrorCallback& error_callback, 152 bool ignore_error_state) { 153 const NetworkState* network = 154 network_state_handler_->GetNetworkState(service_path); 155 if (!network) { 156 InvokeErrorCallback(service_path, error_callback, kErrorNotFound); 157 return; 158 } 159 if (network->IsConnectedState()) { 160 InvokeErrorCallback(service_path, error_callback, kErrorConnected); 161 return; 162 } 163 if (network->IsConnectingState() || 164 pending_requests_.find(service_path) != pending_requests_.end()) { 165 InvokeErrorCallback(service_path, error_callback, kErrorConnecting); 166 return; 167 } 168 if (NetworkRequiresActivation(network)) { 169 InvokeErrorCallback(service_path, error_callback, kErrorActivationRequired); 170 return; 171 } 172 if (!ignore_error_state) { 173 if (network->passphrase_required()) { 174 InvokeErrorCallback(service_path, error_callback, 175 kErrorPassphraseRequired); 176 return; 177 } 178 if (network->error() == flimflam::kErrorConnectFailed) { 179 InvokeErrorCallback(service_path, error_callback, 180 kErrorPassphraseRequired); 181 return; 182 } 183 if (network->error() == flimflam::kErrorBadPassphrase) { 184 InvokeErrorCallback(service_path, error_callback, 185 kErrorPassphraseRequired); 186 return; 187 } 188 if (network->HasAuthenticationError()) { 189 InvokeErrorCallback(service_path, error_callback, 190 kErrorConfigurationRequired); 191 return; 192 } 193 } 194 195 // All synchronous checks passed, add |service_path| to connecting list. 196 pending_requests_.insert(service_path); 197 198 if (!network->connectable() && NetworkMayNeedCredentials(network)) { 199 // Request additional properties to check. 200 network_configuration_handler_->GetProperties( 201 network->path(), 202 base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect, 203 AsWeakPtr(), success_callback, error_callback), 204 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure, 205 AsWeakPtr(), network->path(), error_callback)); 206 return; 207 } 208 // All checks passed, send connect request. 209 CallShillConnect(service_path, success_callback, error_callback); 210} 211 212void NetworkConnectionHandler::DisconnectNetwork( 213 const std::string& service_path, 214 const base::Closure& success_callback, 215 const network_handler::ErrorCallback& error_callback) { 216 const NetworkState* network = 217 network_state_handler_->GetNetworkState(service_path); 218 if (!network) { 219 InvokeErrorCallback(service_path, error_callback, kErrorNotFound); 220 return; 221 } 222 if (!network->IsConnectedState()) { 223 InvokeErrorCallback(service_path, error_callback, kErrorNotConnected); 224 return; 225 } 226 CallShillDisconnect(service_path, success_callback, error_callback); 227} 228 229void NetworkConnectionHandler::CallShillConnect( 230 const std::string& service_path, 231 const base::Closure& success_callback, 232 const network_handler::ErrorCallback& error_callback) { 233 // TODO(stevenjb): Remove SetConnectingNetwork and use this class to maintain 234 // the connecting network(s) once NetworkLibrary path is eliminated. 235 network_state_handler_->SetConnectingNetwork(service_path); 236 NET_LOG_EVENT("Connect Request", service_path); 237 DBusThreadManager::Get()->GetShillServiceClient()->Connect( 238 dbus::ObjectPath(service_path), 239 base::Bind(&NetworkConnectionHandler::HandleShillSuccess, 240 AsWeakPtr(), service_path, success_callback), 241 base::Bind(&NetworkConnectionHandler::HandleShillFailure, 242 AsWeakPtr(), service_path, error_callback)); 243} 244 245void NetworkConnectionHandler::CallShillDisconnect( 246 const std::string& service_path, 247 const base::Closure& success_callback, 248 const network_handler::ErrorCallback& error_callback) { 249 NET_LOG_EVENT("Disconnect Request", service_path); 250 DBusThreadManager::Get()->GetShillServiceClient()->Disconnect( 251 dbus::ObjectPath(service_path), 252 base::Bind(&NetworkConnectionHandler::HandleShillSuccess, 253 AsWeakPtr(), service_path, success_callback), 254 base::Bind(&NetworkConnectionHandler::HandleShillFailure, 255 AsWeakPtr(), service_path, error_callback)); 256} 257 258void NetworkConnectionHandler::VerifyConfiguredAndConnect( 259 const base::Closure& success_callback, 260 const network_handler::ErrorCallback& error_callback, 261 const std::string& service_path, 262 const base::DictionaryValue& properties) { 263 const NetworkState* network = 264 network_state_handler_->GetNetworkState(service_path); 265 if (!network) { 266 InvokeErrorCallback(service_path, error_callback, kErrorNotFound); 267 return; 268 } 269 270 // VPN requires a host and username to be set. 271 if (network->type() == flimflam::kTypeVPN && 272 !VPNIsConfigured(properties)) { 273 InvokeErrorCallback(service_path, error_callback, 274 kErrorConfigurationRequired); 275 return; 276 } 277 278 // Check certificate properties in kUIDataProperty. 279 scoped_ptr<NetworkUIData> ui_data = 280 ManagedNetworkConfigurationHandler::GetUIData(properties); 281 if (ui_data && !CertificateIsConfigured(ui_data.get())) { 282 InvokeErrorCallback(service_path, error_callback, 283 kErrorCertificateRequired); 284 return; 285 } 286 287 CallShillConnect(service_path, success_callback, error_callback); 288} 289 290void NetworkConnectionHandler::HandleConfigurationFailure( 291 const std::string& service_path, 292 const network_handler::ErrorCallback& error_callback, 293 const std::string& error_name, 294 scoped_ptr<base::DictionaryValue> error_data) { 295 pending_requests_.erase(service_path); 296 if (!error_callback.is_null()) 297 error_callback.Run(error_name, error_data.Pass()); 298} 299 300void NetworkConnectionHandler::HandleShillSuccess( 301 const std::string& service_path, 302 const base::Closure& success_callback) { 303 // TODO(stevenjb): Currently, this only indicates that the connect request 304 // succeeded. It might be preferable to wait for the actually connect 305 // attempt to succeed or fail here and only call |success_callback| at that 306 // point (or maybe call it twice, once indicating in-progress, then success 307 // or failure). 308 pending_requests_.erase(service_path); 309 NET_LOG_EVENT("Connect Request Sent", service_path); 310 success_callback.Run(); 311} 312 313void NetworkConnectionHandler::HandleShillFailure( 314 const std::string& service_path, 315 const network_handler::ErrorCallback& error_callback, 316 const std::string& error_name, 317 const std::string& error_message) { 318 pending_requests_.erase(service_path); 319 std::string error = "Connect Failure: " + error_name + ": " + error_message; 320 network_handler::ShillErrorCallbackFunction( 321 service_path, error_callback, error_name, error_message); 322} 323 324} // namespace chromeos 325