Home | History | Annotate | Download | only in network
      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 "base/location.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "chromeos/cert_loader.h"
     13 #include "chromeos/dbus/dbus_thread_manager.h"
     14 #include "chromeos/dbus/shill_manager_client.h"
     15 #include "chromeos/dbus/shill_service_client.h"
     16 #include "chromeos/network/client_cert_util.h"
     17 #include "chromeos/network/managed_network_configuration_handler.h"
     18 #include "chromeos/network/network_configuration_handler.h"
     19 #include "chromeos/network/network_event_log.h"
     20 #include "chromeos/network/network_handler_callbacks.h"
     21 #include "chromeos/network/network_profile_handler.h"
     22 #include "chromeos/network/network_state.h"
     23 #include "chromeos/network/network_state_handler.h"
     24 #include "chromeos/network/network_ui_data.h"
     25 #include "chromeos/network/shill_property_util.h"
     26 #include "chromeos/tpm_token_loader.h"
     27 #include "dbus/object_path.h"
     28 #include "net/cert/x509_certificate.h"
     29 #include "third_party/cros_system_api/dbus/service_constants.h"
     30 
     31 namespace chromeos {
     32 
     33 namespace {
     34 
     35 void InvokeErrorCallback(const std::string& service_path,
     36                          const network_handler::ErrorCallback& error_callback,
     37                          const std::string& error_name) {
     38   NET_LOG_ERROR("Connect Error: " + error_name, service_path);
     39   network_handler::RunErrorCallback(
     40       error_callback, service_path, error_name, "");
     41 }
     42 
     43 bool IsAuthenticationError(const std::string& error) {
     44   return (error == shill::kErrorBadWEPKey ||
     45           error == shill::kErrorPppAuthFailed ||
     46           error == shill::kErrorEapLocalTlsFailed ||
     47           error == shill::kErrorEapRemoteTlsFailed ||
     48           error == shill::kErrorEapAuthenticationFailed);
     49 }
     50 
     51 bool VPNRequiresCredentials(const std::string& service_path,
     52                            const std::string& provider_type,
     53                            const base::DictionaryValue& provider_properties) {
     54   if (provider_type == shill::kProviderOpenVpn) {
     55     std::string username;
     56     provider_properties.GetStringWithoutPathExpansion(
     57         shill::kOpenVPNUserProperty, &username);
     58     if (username.empty()) {
     59       NET_LOG_EVENT("OpenVPN: No username", service_path);
     60       return true;
     61     }
     62     bool passphrase_required = false;
     63     provider_properties.GetBooleanWithoutPathExpansion(
     64         shill::kPassphraseRequiredProperty, &passphrase_required);
     65     if (passphrase_required) {
     66       NET_LOG_EVENT("OpenVPN: Passphrase Required", service_path);
     67       return true;
     68     }
     69     NET_LOG_EVENT("OpenVPN Is Configured", service_path);
     70   } else {
     71     bool passphrase_required = false;
     72     provider_properties.GetBooleanWithoutPathExpansion(
     73         shill::kL2tpIpsecPskRequiredProperty, &passphrase_required);
     74     if (passphrase_required) {
     75       NET_LOG_EVENT("VPN: PSK Required", service_path);
     76       return true;
     77     }
     78     provider_properties.GetBooleanWithoutPathExpansion(
     79         shill::kPassphraseRequiredProperty, &passphrase_required);
     80     if (passphrase_required) {
     81       NET_LOG_EVENT("VPN: Passphrase Required", service_path);
     82       return true;
     83     }
     84     NET_LOG_EVENT("VPN Is Configured", service_path);
     85   }
     86   return false;
     87 }
     88 
     89 std::string GetDefaultUserProfilePath(const NetworkState* network) {
     90   if (!NetworkHandler::IsInitialized() ||
     91       (LoginState::IsInitialized() &&
     92        !LoginState::Get()->UserHasNetworkProfile()) ||
     93       (network && network->type() == shill::kTypeWifi &&
     94        network->security() == shill::kSecurityNone)) {
     95     return NetworkProfileHandler::GetSharedProfilePath();
     96   }
     97   const NetworkProfile* profile  =
     98       NetworkHandler::Get()->network_profile_handler()->GetDefaultUserProfile();
     99   return profile ? profile->path
    100                  : NetworkProfileHandler::GetSharedProfilePath();
    101 }
    102 
    103 }  // namespace
    104 
    105 const char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
    106 const char NetworkConnectionHandler::kErrorConnected[] = "connected";
    107 const char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
    108 const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
    109 const char NetworkConnectionHandler::kErrorPassphraseRequired[] =
    110     "passphrase-required";
    111 const char NetworkConnectionHandler::kErrorActivationRequired[] =
    112     "activation-required";
    113 const char NetworkConnectionHandler::kErrorCertificateRequired[] =
    114     "certificate-required";
    115 const char NetworkConnectionHandler::kErrorConfigurationRequired[] =
    116     "configuration-required";
    117 const char NetworkConnectionHandler::kErrorAuthenticationRequired[] =
    118     "authentication-required";
    119 const char NetworkConnectionHandler::kErrorShillError[] = "shill-error";
    120 const char NetworkConnectionHandler::kErrorConfigureFailed[] =
    121     "configure-failed";
    122 const char NetworkConnectionHandler::kErrorConnectCanceled[] =
    123     "connect-canceled";
    124 const char NetworkConnectionHandler::kErrorCertLoadTimeout[] =
    125     "cert-load-timeout";
    126 
    127 struct NetworkConnectionHandler::ConnectRequest {
    128   ConnectRequest(const std::string& service_path,
    129                  const std::string& profile_path,
    130                  const base::Closure& success,
    131                  const network_handler::ErrorCallback& error)
    132       : service_path(service_path),
    133         profile_path(profile_path),
    134         connect_state(CONNECT_REQUESTED),
    135         success_callback(success),
    136         error_callback(error) {
    137   }
    138   enum ConnectState {
    139     CONNECT_REQUESTED = 0,
    140     CONNECT_STARTED = 1,
    141     CONNECT_CONNECTING = 2
    142   };
    143   std::string service_path;
    144   std::string profile_path;
    145   ConnectState connect_state;
    146   base::Closure success_callback;
    147   network_handler::ErrorCallback error_callback;
    148 };
    149 
    150 NetworkConnectionHandler::NetworkConnectionHandler()
    151     : cert_loader_(NULL),
    152       network_state_handler_(NULL),
    153       configuration_handler_(NULL),
    154       logged_in_(false),
    155       certificates_loaded_(false),
    156       applied_autoconnect_policy_(false),
    157       requested_connect_to_best_network_(false) {
    158 }
    159 
    160 NetworkConnectionHandler::~NetworkConnectionHandler() {
    161   if (network_state_handler_)
    162     network_state_handler_->RemoveObserver(this, FROM_HERE);
    163   if (cert_loader_)
    164     cert_loader_->RemoveObserver(this);
    165   if (LoginState::IsInitialized())
    166     LoginState::Get()->RemoveObserver(this);
    167 }
    168 
    169 void NetworkConnectionHandler::Init(
    170     NetworkStateHandler* network_state_handler,
    171     NetworkConfigurationHandler* network_configuration_handler,
    172     ManagedNetworkConfigurationHandler* managed_network_configuration_handler) {
    173   if (LoginState::IsInitialized())
    174     LoginState::Get()->AddObserver(this);
    175 
    176   if (CertLoader::IsInitialized()) {
    177     cert_loader_ = CertLoader::Get();
    178     cert_loader_->AddObserver(this);
    179     if (cert_loader_->certificates_loaded()) {
    180       NET_LOG_EVENT("Certificates Loaded", "");
    181       certificates_loaded_ = true;
    182     }
    183   } else {
    184     // TODO(tbarzic): Require a mock or stub cert_loader in tests.
    185     NET_LOG_EVENT("Certificate Loader not initialized", "");
    186     certificates_loaded_ = true;
    187   }
    188 
    189   if (network_state_handler) {
    190     network_state_handler_ = network_state_handler;
    191     network_state_handler_->AddObserver(this, FROM_HERE);
    192   }
    193   configuration_handler_ = network_configuration_handler;
    194 
    195   if (managed_network_configuration_handler) {
    196     managed_configuration_handler_ = managed_network_configuration_handler;
    197     managed_configuration_handler_->AddObserver(this);
    198   }
    199 
    200   // After this point, the NetworkConnectionHandler is fully initialized (all
    201   // handler references set, observers registered, ...).
    202 
    203   if (LoginState::IsInitialized())
    204     LoggedInStateChanged();
    205 }
    206 
    207 void NetworkConnectionHandler::LoggedInStateChanged() {
    208   LoginState* login_state = LoginState::Get();
    209   if (logged_in_ || !login_state->IsUserLoggedIn())
    210     return;
    211 
    212   NET_LOG_EVENT("Logged In", "");
    213   logged_in_ = true;
    214   logged_in_time_ = base::TimeTicks::Now();
    215 
    216   DisconnectIfPolicyRequires();
    217 }
    218 
    219 void NetworkConnectionHandler::OnCertificatesLoaded(
    220     const net::CertificateList& cert_list,
    221     bool initial_load) {
    222   certificates_loaded_ = true;
    223   NET_LOG_EVENT("Certificates Loaded", "");
    224   if (queued_connect_) {
    225     ConnectToQueuedNetwork();
    226   } else if (initial_load) {
    227     // Connecting to the "best" available network requires certificates to be
    228     // loaded. Try to connect now.
    229     ConnectToBestNetworkAfterLogin();
    230   }
    231 }
    232 
    233 void NetworkConnectionHandler::PolicyChanged(const std::string& userhash) {
    234   // Ignore user policies.
    235   if (!userhash.empty())
    236     return;
    237   DisconnectIfPolicyRequires();
    238 }
    239 
    240 void NetworkConnectionHandler::ConnectToNetwork(
    241     const std::string& service_path,
    242     const base::Closure& success_callback,
    243     const network_handler::ErrorCallback& error_callback,
    244     bool check_error_state) {
    245   NET_LOG_USER("ConnectToNetwork", service_path);
    246   // Clear any existing queued connect request.
    247   queued_connect_.reset();
    248   if (HasConnectingNetwork(service_path)) {
    249     NET_LOG_USER("Connect Request While Pending", service_path);
    250     InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
    251     return;
    252   }
    253 
    254   // Check cached network state for connected, connecting, or unactivated
    255   // networks. These states will not be affected by a recent configuration.
    256   // Note: NetworkState may not exist for a network that was recently
    257   // configured, in which case these checks do not apply anyway.
    258   const NetworkState* network =
    259       network_state_handler_->GetNetworkState(service_path);
    260 
    261   if (network) {
    262     // For existing networks, perform some immediate consistency checks.
    263     if (network->IsConnectedState()) {
    264       InvokeErrorCallback(service_path, error_callback, kErrorConnected);
    265       return;
    266     }
    267     if (network->IsConnectingState()) {
    268       InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
    269       return;
    270     }
    271     if (network->RequiresActivation()) {
    272       InvokeErrorCallback(service_path, error_callback,
    273                           kErrorActivationRequired);
    274       return;
    275     }
    276 
    277     if (check_error_state) {
    278       const std::string& error = network->last_error();
    279       if (error == shill::kErrorBadPassphrase) {
    280         InvokeErrorCallback(service_path, error_callback, error);
    281         return;
    282       }
    283       if (IsAuthenticationError(error)) {
    284         InvokeErrorCallback(
    285             service_path, error_callback, kErrorAuthenticationRequired);
    286         return;
    287       }
    288     }
    289   }
    290 
    291   // If the network does not have a profile path, specify the correct default
    292   // profile here and set it once connected. Otherwise leave it empty to
    293   // indicate that it does not need to be set.
    294   std::string profile_path;
    295   if (!network || network->profile_path().empty())
    296     profile_path = GetDefaultUserProfilePath(network);
    297 
    298   // All synchronous checks passed, add |service_path| to connecting list.
    299   pending_requests_.insert(std::make_pair(
    300       service_path,
    301       ConnectRequest(service_path, profile_path,
    302                      success_callback, error_callback)));
    303 
    304   // Connect immediately to 'connectable' networks.
    305   // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
    306   if (network && network->connectable() && network->type() != shill::kTypeVPN) {
    307     CallShillConnect(service_path);
    308     return;
    309   }
    310 
    311   // Request additional properties to check. VerifyConfiguredAndConnect will
    312   // use only these properties, not cached properties, to ensure that they
    313   // are up to date after any recent configuration.
    314   configuration_handler_->GetProperties(
    315       service_path,
    316       base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect,
    317                  AsWeakPtr(), check_error_state),
    318       base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
    319                  AsWeakPtr(), service_path));
    320 }
    321 
    322 void NetworkConnectionHandler::DisconnectNetwork(
    323     const std::string& service_path,
    324     const base::Closure& success_callback,
    325     const network_handler::ErrorCallback& error_callback) {
    326   NET_LOG_USER("DisconnectNetwork", service_path);
    327   const NetworkState* network =
    328       network_state_handler_->GetNetworkState(service_path);
    329   if (!network) {
    330     InvokeErrorCallback(service_path, error_callback, kErrorNotFound);
    331     return;
    332   }
    333   if (!network->IsConnectedState()) {
    334     InvokeErrorCallback(service_path, error_callback, kErrorNotConnected);
    335     return;
    336   }
    337   CallShillDisconnect(service_path, success_callback, error_callback);
    338 }
    339 
    340 bool NetworkConnectionHandler::HasConnectingNetwork(
    341     const std::string& service_path) {
    342   return pending_requests_.count(service_path) != 0;
    343 }
    344 
    345 bool NetworkConnectionHandler::HasPendingConnectRequest() {
    346   return pending_requests_.size() > 0;
    347 }
    348 
    349 void NetworkConnectionHandler::NetworkListChanged() {
    350   CheckAllPendingRequests();
    351 }
    352 
    353 void NetworkConnectionHandler::NetworkPropertiesUpdated(
    354     const NetworkState* network) {
    355   if (HasConnectingNetwork(network->path()))
    356     CheckPendingRequest(network->path());
    357 }
    358 
    359 NetworkConnectionHandler::ConnectRequest*
    360 NetworkConnectionHandler::GetPendingRequest(const std::string& service_path) {
    361   std::map<std::string, ConnectRequest>::iterator iter =
    362       pending_requests_.find(service_path);
    363   return iter != pending_requests_.end() ? &(iter->second) : NULL;
    364 }
    365 
    366 // ConnectToNetwork implementation
    367 
    368 void NetworkConnectionHandler::VerifyConfiguredAndConnect(
    369     bool check_error_state,
    370     const std::string& service_path,
    371     const base::DictionaryValue& service_properties) {
    372   NET_LOG_EVENT("VerifyConfiguredAndConnect", service_path);
    373 
    374   // If 'passphrase_required' is still true, then the 'Passphrase' property
    375   // has not been set to a minimum length value.
    376   bool passphrase_required = false;
    377   service_properties.GetBooleanWithoutPathExpansion(
    378       shill::kPassphraseRequiredProperty, &passphrase_required);
    379   if (passphrase_required) {
    380     ErrorCallbackForPendingRequest(service_path, kErrorPassphraseRequired);
    381     return;
    382   }
    383 
    384   std::string type, security;
    385   service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
    386   service_properties.GetStringWithoutPathExpansion(
    387       shill::kSecurityProperty, &security);
    388   bool connectable = false;
    389   service_properties.GetBooleanWithoutPathExpansion(
    390       shill::kConnectableProperty, &connectable);
    391 
    392   // In case NetworkState was not available in ConnectToNetwork (e.g. it had
    393   // been recently configured), we need to check Connectable again.
    394   if (connectable && type != shill::kTypeVPN) {
    395     // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
    396     CallShillConnect(service_path);
    397     return;
    398   }
    399 
    400   // Get VPN provider type and host (required for configuration) and ensure
    401   // that required VPN non-cert properties are set.
    402   const base::DictionaryValue* provider_properties = NULL;
    403   std::string vpn_provider_type, vpn_provider_host, vpn_client_cert_id;
    404   if (type == shill::kTypeVPN) {
    405     // VPN Provider values are read from the "Provider" dictionary, not the
    406     // "Provider.Type", etc keys (which are used only to set the values).
    407     if (service_properties.GetDictionaryWithoutPathExpansion(
    408             shill::kProviderProperty, &provider_properties)) {
    409       provider_properties->GetStringWithoutPathExpansion(
    410           shill::kTypeProperty, &vpn_provider_type);
    411       provider_properties->GetStringWithoutPathExpansion(
    412           shill::kHostProperty, &vpn_provider_host);
    413       provider_properties->GetStringWithoutPathExpansion(
    414           shill::kL2tpIpsecClientCertIdProperty, &vpn_client_cert_id);
    415     }
    416     if (vpn_provider_type.empty() || vpn_provider_host.empty()) {
    417       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    418       return;
    419     }
    420   }
    421 
    422   scoped_ptr<NetworkUIData> ui_data =
    423       shill_property_util::GetUIDataFromProperties(service_properties);
    424 
    425   client_cert::ConfigType client_cert_type = client_cert::CONFIG_TYPE_NONE;
    426   if (type == shill::kTypeVPN) {
    427     if (vpn_provider_type == shill::kProviderOpenVpn) {
    428       client_cert_type = client_cert::CONFIG_TYPE_OPENVPN;
    429     } else {
    430       // L2TP/IPSec only requires a certificate if one is specified in ONC
    431       // or one was configured by the UI. Otherwise it is L2TP/IPSec with
    432       // PSK and doesn't require a certificate.
    433       //
    434       // TODO(benchan): Modify shill to specify the authentication type via
    435       // the kL2tpIpsecAuthenticationType property, so that Chrome doesn't need
    436       // to deduce the authentication type based on the
    437       // kL2tpIpsecClientCertIdProperty here (and also in VPNConfigView).
    438       if (!vpn_client_cert_id.empty() ||
    439           (ui_data && ui_data->certificate_type() != CLIENT_CERT_TYPE_NONE))
    440         client_cert_type = client_cert::CONFIG_TYPE_IPSEC;
    441     }
    442   } else if (type == shill::kTypeWifi && security == shill::kSecurity8021x) {
    443     client_cert_type = client_cert::CONFIG_TYPE_EAP;
    444   }
    445 
    446   base::DictionaryValue config_properties;
    447   if (client_cert_type != client_cert::CONFIG_TYPE_NONE) {
    448     // Note: if we get here then a certificate *may* be required, so we want
    449     // to ensure that certificates have loaded successfully before attempting
    450     // to connect.
    451 
    452     // User must be logged in to connect to a network requiring a certificate.
    453     if (!logged_in_ || !cert_loader_) {
    454       NET_LOG_ERROR("User not logged in", "");
    455       ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
    456       return;
    457     }
    458     // If certificates have not been loaded yet, queue the connect request.
    459     if (!certificates_loaded_) {
    460       NET_LOG_EVENT("Certificates not loaded", "");
    461       QueueConnectRequest(service_path);
    462       return;
    463     }
    464 
    465     // If the client certificate must be configured, this will be set to a
    466     // non-empty string.
    467     std::string pkcs11_id;
    468 
    469     // Check certificate properties in kUIDataProperty if configured.
    470     // Note: Wifi/VPNConfigView set these properties explicitly, in which case
    471     // only the TPM must be configured.
    472     if (ui_data && ui_data->certificate_type() == CLIENT_CERT_TYPE_PATTERN) {
    473       pkcs11_id = CertificateIsConfigured(ui_data.get());
    474       // Ensure the certificate is available and configured.
    475       if (!cert_loader_->IsHardwareBacked() || pkcs11_id.empty()) {
    476         ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
    477         return;
    478       }
    479     } else if (check_error_state &&
    480                !client_cert::IsCertificateConfigured(client_cert_type,
    481                                                      service_properties)) {
    482       // Network may not be configured.
    483       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    484       return;
    485     }
    486 
    487     // The network may not be 'Connectable' because the TPM properties are not
    488     // set up, so configure tpm slot/pin before connecting.
    489     if (cert_loader_ && cert_loader_->IsHardwareBacked()) {
    490       // Pass NULL if pkcs11_id is empty, so that it doesn't clear any
    491       // previously configured client cert.
    492       client_cert::SetShillProperties(
    493           client_cert_type,
    494           base::IntToString(cert_loader_->TPMTokenSlotID()),
    495           TPMTokenLoader::Get()->tpm_user_pin(),
    496           pkcs11_id.empty() ? NULL : &pkcs11_id,
    497           &config_properties);
    498     }
    499   }
    500 
    501   if (type == shill::kTypeVPN) {
    502     // VPN may require a username, and/or passphrase to be set. (Check after
    503     // ensuring that any required certificates are configured).
    504     DCHECK(provider_properties);
    505     if (VPNRequiresCredentials(
    506             service_path, vpn_provider_type, *provider_properties)) {
    507       NET_LOG_USER("VPN Requires Credentials", service_path);
    508       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    509       return;
    510     }
    511 
    512     // If it's L2TP/IPsec PSK, there is no properties to configure, so proceed
    513     // to connect.
    514     if (client_cert_type == client_cert::CONFIG_TYPE_NONE) {
    515       CallShillConnect(service_path);
    516       return;
    517     }
    518   }
    519 
    520   if (!config_properties.empty()) {
    521     NET_LOG_EVENT("Configuring Network", service_path);
    522     configuration_handler_->SetProperties(
    523         service_path,
    524         config_properties,
    525         base::Bind(&NetworkConnectionHandler::CallShillConnect,
    526                    AsWeakPtr(),
    527                    service_path),
    528         base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
    529                    AsWeakPtr(),
    530                    service_path));
    531     return;
    532   }
    533 
    534   // Otherwise, we probably still need to configure the network since
    535   // 'Connectable' is false. If |check_error_state| is true, signal an
    536   // error, otherwise attempt to connect to possibly gain additional error
    537   // state from Shill (or in case 'Connectable' is improperly unset).
    538   if (check_error_state)
    539     ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
    540   else
    541     CallShillConnect(service_path);
    542 }
    543 
    544 void NetworkConnectionHandler::QueueConnectRequest(
    545     const std::string& service_path) {
    546   ConnectRequest* request = GetPendingRequest(service_path);
    547   if (!request) {
    548     NET_LOG_ERROR("No pending request to queue", service_path);
    549     return;
    550   }
    551 
    552   const int kMaxCertLoadTimeSeconds = 15;
    553   base::TimeDelta dtime = base::TimeTicks::Now() - logged_in_time_;
    554   if (dtime > base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds)) {
    555     NET_LOG_ERROR("Certificate load timeout", service_path);
    556     InvokeErrorCallback(service_path,
    557                         request->error_callback,
    558                         kErrorCertLoadTimeout);
    559     return;
    560   }
    561 
    562   NET_LOG_EVENT("Connect Request Queued", service_path);
    563   queued_connect_.reset(new ConnectRequest(
    564       service_path, request->profile_path,
    565       request->success_callback, request->error_callback));
    566   pending_requests_.erase(service_path);
    567 
    568   // Post a delayed task to check to see if certificates have loaded. If they
    569   // haven't, and queued_connect_ has not been cleared (e.g. by a successful
    570   // connect request), cancel the request and notify the user.
    571   base::MessageLoopProxy::current()->PostDelayedTask(
    572       FROM_HERE,
    573       base::Bind(&NetworkConnectionHandler::CheckCertificatesLoaded,
    574                  AsWeakPtr()),
    575       base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds) - dtime);
    576 }
    577 
    578 void NetworkConnectionHandler::CheckCertificatesLoaded() {
    579   if (certificates_loaded_)
    580     return;
    581   // If queued_connect_ has been cleared (e.g. another connect request occurred
    582   // and wasn't queued), do nothing here.
    583   if (!queued_connect_)
    584     return;
    585   // Otherwise, notify the user.
    586   NET_LOG_ERROR("Certificate load timeout", queued_connect_->service_path);
    587   InvokeErrorCallback(queued_connect_->service_path,
    588                       queued_connect_->error_callback,
    589                       kErrorCertLoadTimeout);
    590   queued_connect_.reset();
    591 }
    592 
    593 void NetworkConnectionHandler::ConnectToQueuedNetwork() {
    594   DCHECK(queued_connect_);
    595 
    596   // Make a copy of |queued_connect_| parameters, because |queued_connect_|
    597   // will get reset at the beginning of |ConnectToNetwork|.
    598   std::string service_path = queued_connect_->service_path;
    599   base::Closure success_callback = queued_connect_->success_callback;
    600   network_handler::ErrorCallback error_callback =
    601       queued_connect_->error_callback;
    602 
    603   NET_LOG_EVENT("Connecting to Queued Network", service_path);
    604   ConnectToNetwork(service_path, success_callback, error_callback,
    605                    false /* check_error_state */);
    606 }
    607 
    608 void NetworkConnectionHandler::CallShillConnect(
    609     const std::string& service_path) {
    610   NET_LOG_EVENT("Sending Connect Request to Shill", service_path);
    611   network_state_handler_->ClearLastErrorForNetwork(service_path);
    612   DBusThreadManager::Get()->GetShillServiceClient()->Connect(
    613       dbus::ObjectPath(service_path),
    614       base::Bind(&NetworkConnectionHandler::HandleShillConnectSuccess,
    615                  AsWeakPtr(), service_path),
    616       base::Bind(&NetworkConnectionHandler::HandleShillConnectFailure,
    617                  AsWeakPtr(), service_path));
    618 }
    619 
    620 void NetworkConnectionHandler::HandleConfigurationFailure(
    621     const std::string& service_path,
    622     const std::string& error_name,
    623     scoped_ptr<base::DictionaryValue> error_data) {
    624   ConnectRequest* request = GetPendingRequest(service_path);
    625   if (!request) {
    626     NET_LOG_ERROR("HandleConfigurationFailure called with no pending request.",
    627                   service_path);
    628     return;
    629   }
    630   network_handler::ErrorCallback error_callback = request->error_callback;
    631   pending_requests_.erase(service_path);
    632   if (!error_callback.is_null())
    633     error_callback.Run(kErrorConfigureFailed, error_data.Pass());
    634 }
    635 
    636 void NetworkConnectionHandler::HandleShillConnectSuccess(
    637     const std::string& service_path) {
    638   ConnectRequest* request = GetPendingRequest(service_path);
    639   if (!request) {
    640     NET_LOG_ERROR("HandleShillConnectSuccess called with no pending request.",
    641                   service_path);
    642     return;
    643   }
    644   request->connect_state = ConnectRequest::CONNECT_STARTED;
    645   NET_LOG_EVENT("Connect Request Acknowledged", service_path);
    646   // Do not call success_callback here, wait for one of the following
    647   // conditions:
    648   // * State transitions to a non connecting state indicating success or failure
    649   // * Network is no longer in the visible list, indicating failure
    650   CheckPendingRequest(service_path);
    651 }
    652 
    653 void NetworkConnectionHandler::HandleShillConnectFailure(
    654     const std::string& service_path,
    655     const std::string& dbus_error_name,
    656     const std::string& dbus_error_message) {
    657   ConnectRequest* request = GetPendingRequest(service_path);
    658   if (!request) {
    659     NET_LOG_ERROR("HandleShillConnectFailure called with no pending request.",
    660                   service_path);
    661     return;
    662   }
    663   network_handler::ErrorCallback error_callback = request->error_callback;
    664   pending_requests_.erase(service_path);
    665   network_handler::ShillErrorCallbackFunction(
    666       shill::kErrorConnectFailed, service_path, error_callback,
    667       dbus_error_name, dbus_error_message);
    668 }
    669 
    670 void NetworkConnectionHandler::CheckPendingRequest(
    671     const std::string service_path) {
    672   ConnectRequest* request = GetPendingRequest(service_path);
    673   DCHECK(request);
    674   if (request->connect_state == ConnectRequest::CONNECT_REQUESTED)
    675     return;  // Request has not started, ignore update
    676   const NetworkState* network =
    677       network_state_handler_->GetNetworkState(service_path);
    678   if (!network)
    679     return;  // NetworkState may not be be updated yet.
    680 
    681   if (network->IsConnectingState()) {
    682     request->connect_state = ConnectRequest::CONNECT_CONNECTING;
    683     return;
    684   }
    685   if (network->IsConnectedState()) {
    686     NET_LOG_EVENT("Connect Request Succeeded", service_path);
    687     if (!request->profile_path.empty()) {
    688       // If a profile path was specified, set it on a successful connection.
    689       configuration_handler_->SetNetworkProfile(
    690           service_path,
    691           request->profile_path,
    692           base::Bind(&base::DoNothing),
    693           chromeos::network_handler::ErrorCallback());
    694     }
    695     if (!request->success_callback.is_null())
    696       request->success_callback.Run();
    697     pending_requests_.erase(service_path);
    698     return;
    699   }
    700   if (network->connection_state() == shill::kStateIdle &&
    701       request->connect_state != ConnectRequest::CONNECT_CONNECTING) {
    702     // Connection hasn't started yet, keep waiting.
    703     return;
    704   }
    705 
    706   // Network is neither connecting or connected; an error occurred.
    707   std::string error_name;  // 'Canceled' or 'Failed'
    708   if (network->connection_state() == shill::kStateIdle &&
    709       pending_requests_.size() > 1) {
    710     // Another connect request canceled this one.
    711     error_name = kErrorConnectCanceled;
    712   } else {
    713     error_name = shill::kErrorConnectFailed;
    714     if (network->connection_state() != shill::kStateFailure) {
    715       NET_LOG_ERROR("Unexpected State: " + network->connection_state(),
    716                     service_path);
    717     }
    718   }
    719 
    720   network_handler::ErrorCallback error_callback = request->error_callback;
    721   pending_requests_.erase(service_path);
    722   if (error_callback.is_null()) {
    723     NET_LOG_ERROR("Connect Error, no callback: " + error_name, service_path);
    724     return;
    725   }
    726   InvokeErrorCallback(service_path, error_callback, error_name);
    727 }
    728 
    729 void NetworkConnectionHandler::CheckAllPendingRequests() {
    730   for (std::map<std::string, ConnectRequest>::iterator iter =
    731            pending_requests_.begin(); iter != pending_requests_.end(); ++iter) {
    732     CheckPendingRequest(iter->first);
    733   }
    734 }
    735 
    736 std::string NetworkConnectionHandler::CertificateIsConfigured(
    737     NetworkUIData* ui_data) {
    738   if (ui_data->certificate_pattern().Empty())
    739     return std::string();
    740   // Find the matching certificate.
    741   scoped_refptr<net::X509Certificate> matching_cert =
    742       client_cert::GetCertificateMatch(ui_data->certificate_pattern(),
    743                                        cert_loader_->cert_list());
    744   if (!matching_cert.get())
    745     return std::string();
    746   return CertLoader::GetPkcs11IdForCert(*matching_cert.get());
    747 }
    748 
    749 void NetworkConnectionHandler::ErrorCallbackForPendingRequest(
    750     const std::string& service_path,
    751     const std::string& error_name) {
    752   ConnectRequest* request = GetPendingRequest(service_path);
    753   if (!request) {
    754     NET_LOG_ERROR("ErrorCallbackForPendingRequest with no pending request.",
    755                   service_path);
    756     return;
    757   }
    758   // Remove the entry before invoking the callback in case it triggers a retry.
    759   network_handler::ErrorCallback error_callback = request->error_callback;
    760   pending_requests_.erase(service_path);
    761   InvokeErrorCallback(service_path, error_callback, error_name);
    762 }
    763 
    764 // Disconnect
    765 
    766 void NetworkConnectionHandler::CallShillDisconnect(
    767     const std::string& service_path,
    768     const base::Closure& success_callback,
    769     const network_handler::ErrorCallback& error_callback) {
    770   NET_LOG_USER("Disconnect Request", service_path);
    771   DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
    772       dbus::ObjectPath(service_path),
    773       base::Bind(&NetworkConnectionHandler::HandleShillDisconnectSuccess,
    774                  AsWeakPtr(), service_path, success_callback),
    775       base::Bind(&network_handler::ShillErrorCallbackFunction,
    776                  kErrorShillError, service_path, error_callback));
    777 }
    778 
    779 void NetworkConnectionHandler::HandleShillDisconnectSuccess(
    780     const std::string& service_path,
    781     const base::Closure& success_callback) {
    782   NET_LOG_EVENT("Disconnect Request Sent", service_path);
    783   if (!success_callback.is_null())
    784     success_callback.Run();
    785 }
    786 
    787 void NetworkConnectionHandler::ConnectToBestNetworkAfterLogin() {
    788   if (requested_connect_to_best_network_ || !applied_autoconnect_policy_ ||
    789       !certificates_loaded_) {
    790     return;
    791   }
    792 
    793   requested_connect_to_best_network_ = true;
    794   network_state_handler_->ConnectToBestWifiNetwork();
    795 }
    796 
    797 void NetworkConnectionHandler::DisconnectIfPolicyRequires() {
    798   if (applied_autoconnect_policy_ || !LoginState::Get()->IsUserLoggedIn())
    799     return;
    800 
    801   const base::DictionaryValue* global_network_config =
    802       managed_configuration_handler_->GetGlobalConfigFromPolicy(std::string());
    803   if (!global_network_config)
    804     return;
    805 
    806   applied_autoconnect_policy_ = true;
    807 
    808   bool only_policy_autoconnect = false;
    809   global_network_config->GetBooleanWithoutPathExpansion(
    810       ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
    811       &only_policy_autoconnect);
    812 
    813   if (!only_policy_autoconnect)
    814     return;
    815 
    816   NET_LOG_DEBUG("DisconnectIfPolicyRequires",
    817                 "Disconnecting unmanaged and shared networks if any exist.");
    818 
    819   // Get the list of unmanaged & shared networks that are connected or
    820   // connecting.
    821   NetworkStateHandler::NetworkStateList networks;
    822   network_state_handler_->GetVisibleNetworkListByType(
    823       NetworkTypePattern::Wireless(), &networks);
    824   for (NetworkStateHandler::NetworkStateList::const_iterator it =
    825            networks.begin();
    826        it != networks.end();
    827        ++it) {
    828     const NetworkState* network = *it;
    829     if (!(network->IsConnectingState() || network->IsConnectedState()))
    830       break;  // Connected and connecting networks are listed first.
    831 
    832     if (network->IsPrivate())
    833       continue;
    834 
    835     const bool network_is_policy_managed =
    836         !network->profile_path().empty() && !network->guid().empty() &&
    837         managed_configuration_handler_->FindPolicyByGuidAndProfile(
    838             network->guid(), network->profile_path());
    839     if (network_is_policy_managed)
    840       continue;
    841 
    842     NET_LOG_EVENT("Disconnect Forced by Policy", network->path());
    843     CallShillDisconnect(
    844         network->path(), base::Closure(), network_handler::ErrorCallback());
    845   }
    846 
    847   ConnectToBestNetworkAfterLogin();
    848 }
    849 
    850 }  // namespace chromeos
    851