network_connection_handler.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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
31namespace chromeos {
32
33namespace {
34
35void 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
43bool 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
51bool 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
89std::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
105const char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
106const char NetworkConnectionHandler::kErrorConnected[] = "connected";
107const char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
108const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
109const char NetworkConnectionHandler::kErrorPassphraseRequired[] =
110    "passphrase-required";
111const char NetworkConnectionHandler::kErrorActivationRequired[] =
112    "activation-required";
113const char NetworkConnectionHandler::kErrorCertificateRequired[] =
114    "certificate-required";
115const char NetworkConnectionHandler::kErrorConfigurationRequired[] =
116    "configuration-required";
117const char NetworkConnectionHandler::kErrorAuthenticationRequired[] =
118    "authentication-required";
119const char NetworkConnectionHandler::kErrorShillError[] = "shill-error";
120const char NetworkConnectionHandler::kErrorConfigureFailed[] =
121    "configure-failed";
122const char NetworkConnectionHandler::kErrorConnectCanceled[] =
123    "connect-canceled";
124const char NetworkConnectionHandler::kErrorCertLoadTimeout[] =
125    "cert-load-timeout";
126
127struct 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
150NetworkConnectionHandler::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
160NetworkConnectionHandler::~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
169void 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
207void 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
219void 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
233void NetworkConnectionHandler::PolicyChanged(const std::string& userhash) {
234  // Ignore user policies.
235  if (!userhash.empty())
236    return;
237  DisconnectIfPolicyRequires();
238}
239
240void 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
322void 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
340bool NetworkConnectionHandler::HasConnectingNetwork(
341    const std::string& service_path) {
342  return pending_requests_.count(service_path) != 0;
343}
344
345bool NetworkConnectionHandler::HasPendingConnectRequest() {
346  return pending_requests_.size() > 0;
347}
348
349void NetworkConnectionHandler::NetworkListChanged() {
350  CheckAllPendingRequests();
351}
352
353void NetworkConnectionHandler::NetworkPropertiesUpdated(
354    const NetworkState* network) {
355  if (HasConnectingNetwork(network->path()))
356    CheckPendingRequest(network->path());
357}
358
359NetworkConnectionHandler::ConnectRequest*
360NetworkConnectionHandler::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
368void 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
544void 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
578void 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
593void 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
608void 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
620void 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
636void 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
653void 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
670void 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
729void 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
736std::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
749void 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
766void 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
779void 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
787void 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
797void 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