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