network_connection_handler.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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 "base/strings/string_number_conversions.h"
11#include "chromeos/chromeos_switches.h"
12#include "chromeos/dbus/dbus_thread_manager.h"
13#include "chromeos/dbus/shill_manager_client.h"
14#include "chromeos/dbus/shill_service_client.h"
15#include "chromeos/network/client_cert_util.h"
16#include "chromeos/network/network_configuration_handler.h"
17#include "chromeos/network/network_event_log.h"
18#include "chromeos/network/network_handler_callbacks.h"
19#include "chromeos/network/network_profile_handler.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 "chromeos/network/shill_property_util.h"
24#include "dbus/object_path.h"
25#include "net/cert/x509_certificate.h"
26#include "third_party/cros_system_api/dbus/service_constants.h"
27
28namespace chromeos {
29
30namespace {
31
32void InvokeErrorCallback(const std::string& service_path,
33                         const network_handler::ErrorCallback& error_callback,
34                         const std::string& error_name) {
35  std::string error_msg = "Connect Error: " + error_name;
36  NET_LOG_ERROR(error_msg, service_path);
37  network_handler::RunErrorCallback(
38      error_callback, service_path, error_name, error_msg);
39}
40
41bool IsAuthenticationError(const std::string& error) {
42  return (error == shill::kErrorBadWEPKey ||
43          error == shill::kErrorPppAuthFailed ||
44          error == shill::kErrorEapLocalTlsFailed ||
45          error == shill::kErrorEapRemoteTlsFailed ||
46          error == shill::kErrorEapAuthenticationFailed);
47}
48
49bool VPNRequiresCredentials(const std::string& service_path,
50                           const std::string& provider_type,
51                           const base::DictionaryValue& provider_properties) {
52  if (provider_type == shill::kProviderOpenVpn) {
53    std::string username;
54    provider_properties.GetStringWithoutPathExpansion(
55        shill::kOpenVPNUserProperty, &username);
56    if (username.empty()) {
57      NET_LOG_EVENT("OpenVPN: No username", service_path);
58      return true;
59    }
60    bool passphrase_required = false;
61    provider_properties.GetBooleanWithoutPathExpansion(
62        shill::kPassphraseRequiredProperty, &passphrase_required);
63    if (passphrase_required) {
64      NET_LOG_EVENT("OpenVPN: Passphrase Required", service_path);
65      return true;
66    }
67    NET_LOG_EVENT("OpenVPN Is Configured", service_path);
68  } else {
69    bool passphrase_required = false;
70    std::string passphrase;
71    provider_properties.GetBooleanWithoutPathExpansion(
72        shill::kL2tpIpsecPskRequiredProperty, &passphrase_required);
73    if (passphrase_required) {
74      NET_LOG_EVENT("VPN: PSK Required", service_path);
75      return true;
76    }
77    NET_LOG_EVENT("VPN Is Configured", service_path);
78  }
79  return false;
80}
81
82std::string GetDefaultProfilePath(const NetworkState* network) {
83  if (!NetworkHandler::IsInitialized() ||
84      !LoginState::Get()->IsUserAuthenticated() ||
85      (network && network->type() == shill::kTypeWifi &&
86       network->security() == shill::kSecurityNone)) {
87    return NetworkProfileHandler::kSharedProfilePath;
88  }
89  const NetworkProfile* profile  =
90      NetworkHandler::Get()->network_profile_handler()->GetDefaultUserProfile();
91  return profile ? profile->path : NetworkProfileHandler::kSharedProfilePath;
92}
93
94}  // namespace
95
96const char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
97const char NetworkConnectionHandler::kErrorConnected[] = "connected";
98const char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
99const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
100const char NetworkConnectionHandler::kErrorPassphraseRequired[] =
101    "passphrase-required";
102const char NetworkConnectionHandler::kErrorActivationRequired[] =
103    "activation-required";
104const char NetworkConnectionHandler::kErrorCertificateRequired[] =
105    "certificate-required";
106const char NetworkConnectionHandler::kErrorConfigurationRequired[] =
107    "configuration-required";
108const char NetworkConnectionHandler::kErrorAuthenticationRequired[] =
109    "authentication-required";
110const char NetworkConnectionHandler::kErrorShillError[] = "shill-error";
111const char NetworkConnectionHandler::kErrorConfigureFailed[] =
112    "configure-failed";
113const char NetworkConnectionHandler::kErrorConnectCanceled[] =
114    "connect-canceled";
115
116struct NetworkConnectionHandler::ConnectRequest {
117  ConnectRequest(const std::string& service_path,
118                 const std::string& profile_path,
119                 const base::Closure& success,
120                 const network_handler::ErrorCallback& error)
121      : service_path(service_path),
122        profile_path(profile_path),
123        connect_state(CONNECT_REQUESTED),
124        success_callback(success),
125        error_callback(error) {
126  }
127  enum ConnectState {
128    CONNECT_REQUESTED = 0,
129    CONNECT_STARTED = 1,
130    CONNECT_CONNECTING = 2
131  };
132  std::string service_path;
133  std::string profile_path;
134  ConnectState connect_state;
135  base::Closure success_callback;
136  network_handler::ErrorCallback error_callback;
137};
138
139NetworkConnectionHandler::NetworkConnectionHandler()
140    : cert_loader_(NULL),
141      network_state_handler_(NULL),
142      network_configuration_handler_(NULL),
143      logged_in_(false),
144      certificates_loaded_(false) {
145}
146
147NetworkConnectionHandler::~NetworkConnectionHandler() {
148  if (network_state_handler_)
149    network_state_handler_->RemoveObserver(this, FROM_HERE);
150  if (cert_loader_)
151    cert_loader_->RemoveObserver(this);
152  if (LoginState::IsInitialized())
153    LoginState::Get()->RemoveObserver(this);
154}
155
156void NetworkConnectionHandler::Init(
157    NetworkStateHandler* network_state_handler,
158    NetworkConfigurationHandler* network_configuration_handler) {
159  if (LoginState::IsInitialized()) {
160    LoginState::Get()->AddObserver(this);
161    logged_in_ = LoginState::Get()->IsUserLoggedIn();
162  }
163  if (CertLoader::IsInitialized()) {
164    cert_loader_ = CertLoader::Get();
165    cert_loader_->AddObserver(this);
166    certificates_loaded_ = cert_loader_->certificates_loaded();
167  } else {
168    // TODO(stevenjb): Require a mock or stub cert_loader in tests.
169    certificates_loaded_ = true;
170  }
171  if (network_state_handler) {
172    network_state_handler_ = network_state_handler;
173    network_state_handler_->AddObserver(this, FROM_HERE);
174  }
175  network_configuration_handler_ = network_configuration_handler;
176}
177
178void NetworkConnectionHandler::LoggedInStateChanged() {
179  if (LoginState::Get()->IsUserLoggedIn()) {
180    logged_in_ = true;
181    NET_LOG_EVENT("Logged In", "");
182  }
183}
184
185void NetworkConnectionHandler::OnCertificatesLoaded(
186    const net::CertificateList& cert_list,
187    bool initial_load) {
188  certificates_loaded_ = true;
189  NET_LOG_EVENT("Certificates Loaded", "");
190  if (queued_connect_) {
191    NET_LOG_EVENT("Connecting to Queued Network",
192                  queued_connect_->service_path);
193    ConnectToNetwork(queued_connect_->service_path,
194                     queued_connect_->success_callback,
195                     queued_connect_->error_callback,
196                     false /* check_error_state */);
197  } else if (initial_load) {
198    // Once certificates have loaded, connect to the "best" available network.
199    network_state_handler_->ConnectToBestWifiNetwork();
200  }
201}
202
203void NetworkConnectionHandler::ConnectToNetwork(
204    const std::string& service_path,
205    const base::Closure& success_callback,
206    const network_handler::ErrorCallback& error_callback,
207    bool check_error_state) {
208  NET_LOG_USER("ConnectToNetwork", service_path);
209  // Clear any existing queued connect request.
210  queued_connect_.reset();
211  if (HasConnectingNetwork(service_path)) {
212    NET_LOG_USER("Connect Request While Pending", service_path);
213    InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
214    return;
215  }
216
217  // Check cached network state for connected, connecting, or unactivated
218  // networks. These states will not be affected by a recent configuration.
219  // Note: NetworkState may not exist for a network that was recently
220  // configured, in which case these checks do not apply anyway.
221  const NetworkState* network =
222      network_state_handler_->GetNetworkState(service_path);
223
224  if (network) {
225    // For existing networks, perform some immediate consistency checks.
226    if (network->IsConnectedState()) {
227      InvokeErrorCallback(service_path, error_callback, kErrorConnected);
228      return;
229    }
230    if (network->IsConnectingState()) {
231      InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
232      return;
233    }
234    if (network->RequiresActivation()) {
235      InvokeErrorCallback(service_path, error_callback,
236                          kErrorActivationRequired);
237      return;
238    }
239
240    if (check_error_state) {
241      const std::string& error = network->error();
242      if (error == shill::kErrorBadPassphrase) {
243        InvokeErrorCallback(service_path, error_callback, error);
244        return;
245      }
246      if (IsAuthenticationError(error)) {
247        InvokeErrorCallback(
248            service_path, error_callback, kErrorAuthenticationRequired);
249        return;
250      }
251    }
252  }
253
254  // If the network does not have a profile path, specify the correct default
255  // profile here and set it once connected. Otherwise leave it empty to
256  // indicate that it does not need to be set.
257  std::string profile_path;
258  if (!network || network->profile_path().empty())
259    profile_path = GetDefaultProfilePath(network);
260
261  // All synchronous checks passed, add |service_path| to connecting list.
262  pending_requests_.insert(std::make_pair(
263      service_path,
264      ConnectRequest(service_path, profile_path,
265                     success_callback, error_callback)));
266
267  // Connect immediately to 'connectable' networks.
268  // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
269  if (network && network->connectable() && network->type() != shill::kTypeVPN) {
270    CallShillConnect(service_path);
271    return;
272  }
273
274  // Request additional properties to check. VerifyConfiguredAndConnect will
275  // use only these properties, not cached properties, to ensure that they
276  // are up to date after any recent configuration.
277  network_configuration_handler_->GetProperties(
278      service_path,
279      base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect,
280                 AsWeakPtr(), check_error_state),
281      base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
282                 AsWeakPtr(), service_path));
283}
284
285void NetworkConnectionHandler::DisconnectNetwork(
286    const std::string& service_path,
287    const base::Closure& success_callback,
288    const network_handler::ErrorCallback& error_callback) {
289  NET_LOG_USER("DisconnectNetwork", service_path);
290  const NetworkState* network =
291      network_state_handler_->GetNetworkState(service_path);
292  if (!network) {
293    InvokeErrorCallback(service_path, error_callback, kErrorNotFound);
294    return;
295  }
296  if (!network->IsConnectedState()) {
297    InvokeErrorCallback(service_path, error_callback, kErrorNotConnected);
298    return;
299  }
300  CallShillDisconnect(service_path, success_callback, error_callback);
301}
302
303bool NetworkConnectionHandler::HasConnectingNetwork(
304    const std::string& service_path) {
305  return pending_requests_.count(service_path) != 0;
306}
307
308bool NetworkConnectionHandler::HasPendingConnectRequest() {
309  return pending_requests_.size() > 0;
310}
311
312void NetworkConnectionHandler::NetworkListChanged() {
313  CheckAllPendingRequests();
314}
315
316void NetworkConnectionHandler::NetworkPropertiesUpdated(
317    const NetworkState* network) {
318  if (HasConnectingNetwork(network->path()))
319    CheckPendingRequest(network->path());
320}
321
322NetworkConnectionHandler::ConnectRequest*
323NetworkConnectionHandler::GetPendingRequest(const std::string& service_path) {
324  std::map<std::string, ConnectRequest>::iterator iter =
325      pending_requests_.find(service_path);
326  return iter != pending_requests_.end() ? &(iter->second) : NULL;
327}
328
329// ConnectToNetwork implementation
330
331void NetworkConnectionHandler::VerifyConfiguredAndConnect(
332    bool check_error_state,
333    const std::string& service_path,
334    const base::DictionaryValue& service_properties) {
335  NET_LOG_EVENT("VerifyConfiguredAndConnect", service_path);
336
337  // If 'passphrase_required' is still true, then the 'Passphrase' property
338  // has not been set to a minimum length value.
339  bool passphrase_required = false;
340  service_properties.GetBooleanWithoutPathExpansion(
341      shill::kPassphraseRequiredProperty, &passphrase_required);
342  if (passphrase_required) {
343    ErrorCallbackForPendingRequest(service_path, kErrorPassphraseRequired);
344    return;
345  }
346
347  std::string type, security;
348  service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
349  service_properties.GetStringWithoutPathExpansion(
350      shill::kSecurityProperty, &security);
351  bool connectable = false;
352  service_properties.GetBooleanWithoutPathExpansion(
353      shill::kConnectableProperty, &connectable);
354
355  // In case NetworkState was not available in ConnectToNetwork (e.g. it had
356  // been recently configured), we need to check Connectable again.
357  if (connectable && type != shill::kTypeVPN) {
358    // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
359    CallShillConnect(service_path);
360    return;
361  }
362
363  // Get VPN provider type and host (required for configuration) and ensure
364  // that required VPN non-cert properties are set.
365  const base::DictionaryValue* provider_properties = NULL;
366  std::string vpn_provider_type, vpn_provider_host;
367  if (type == shill::kTypeVPN) {
368    // VPN Provider values are read from the "Provider" dictionary, not the
369    // "Provider.Type", etc keys (which are used only to set the values).
370    if (service_properties.GetDictionaryWithoutPathExpansion(
371            shill::kProviderProperty, &provider_properties)) {
372      provider_properties->GetStringWithoutPathExpansion(
373          shill::kTypeProperty, &vpn_provider_type);
374      provider_properties->GetStringWithoutPathExpansion(
375          shill::kHostProperty, &vpn_provider_host);
376    }
377    if (vpn_provider_type.empty() || vpn_provider_host.empty()) {
378      ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
379      return;
380    }
381  }
382
383  client_cert::ConfigType client_cert_type = client_cert::CONFIG_TYPE_NONE;
384  if (type == shill::kTypeVPN) {
385    if (vpn_provider_type == shill::kProviderOpenVpn)
386      client_cert_type = client_cert::CONFIG_TYPE_OPENVPN;
387    else
388      client_cert_type = client_cert::CONFIG_TYPE_IPSEC;
389  } else if (type == shill::kTypeWifi && security == shill::kSecurity8021x) {
390    client_cert_type = client_cert::CONFIG_TYPE_EAP;
391  }
392
393  base::DictionaryValue config_properties;
394  if (client_cert_type != client_cert::CONFIG_TYPE_NONE) {
395    // If the client certificate must be configured, this will be set to a
396    // non-empty string.
397    std::string pkcs11_id;
398
399    // Check certificate properties in kUIDataProperty if configured.
400    // Note: Wifi/VPNConfigView set these properties explicitly, in which case
401    //   only the TPM must be configured.
402    scoped_ptr<NetworkUIData> ui_data =
403        shill_property_util::GetUIDataFromProperties(service_properties);
404    if (ui_data && ui_data->certificate_type() == CLIENT_CERT_TYPE_PATTERN) {
405      // User must be logged in to connect to a network requiring a certificate.
406      if (!logged_in_ || !cert_loader_) {
407        ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
408        return;
409      }
410
411      // If certificates have not been loaded yet, queue the connect request.
412      if (!certificates_loaded_) {
413        ConnectRequest* request = GetPendingRequest(service_path);
414        if (!request) {
415          NET_LOG_ERROR("No pending request to queue", service_path);
416          return;
417        }
418        NET_LOG_EVENT("Connect Request Queued", service_path);
419        queued_connect_.reset(new ConnectRequest(
420            service_path, request->profile_path,
421            request->success_callback, request->error_callback));
422        pending_requests_.erase(service_path);
423        return;
424      }
425
426      pkcs11_id = CertificateIsConfigured(ui_data.get());
427      // Ensure the certificate is available and configured.
428      if (!cert_loader_->IsHardwareBacked() || pkcs11_id.empty()) {
429        ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
430        return;
431      }
432    } else if (check_error_state &&
433               !client_cert::IsCertificateConfigured(client_cert_type,
434                                                     service_properties)) {
435      // Network may not be configured.
436      ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
437      return;
438    }
439
440    // The network may not be 'Connectable' because the TPM properties are not
441    // set up, so configure tpm slot/pin before connecting.
442    if (cert_loader_ && cert_loader_->IsHardwareBacked()) {
443      // Pass NULL if pkcs11_id is empty, so that it doesn't clear any
444      // previously configured client cert.
445      client_cert::SetShillProperties(
446          client_cert_type,
447          base::IntToString(cert_loader_->tpm_token_slot_id()),
448          cert_loader_->tpm_user_pin(),
449          pkcs11_id.empty() ? NULL : &pkcs11_id,
450          &config_properties);
451    }
452  }
453
454  if (type == shill::kTypeVPN) {
455    // VPN may require a username, and/or passphrase to be set. (Check after
456    // ensuring that any required certificates are configured).
457    DCHECK(provider_properties);
458    if (VPNRequiresCredentials(
459            service_path, vpn_provider_type, *provider_properties)) {
460      NET_LOG_USER("VPN Requires Credentials", service_path);
461      ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
462      return;
463    }
464  }
465
466  if (!config_properties.empty()) {
467    NET_LOG_EVENT("Configuring Network", service_path);
468    network_configuration_handler_->SetProperties(
469        service_path,
470        config_properties,
471        base::Bind(&NetworkConnectionHandler::CallShillConnect,
472                   AsWeakPtr(),
473                   service_path),
474        base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
475                   AsWeakPtr(),
476                   service_path));
477    return;
478  }
479
480  // Otherwise, we probably still need to configure the network since
481  // 'Connectable' is false. If |check_error_state| is true, signal an
482  // error, otherwise attempt to connect to possibly gain additional error
483  // state from Shill (or in case 'Connectable' is improperly unset).
484  if (check_error_state)
485    ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
486  else
487    CallShillConnect(service_path);
488}
489
490void NetworkConnectionHandler::CallShillConnect(
491    const std::string& service_path) {
492  NET_LOG_EVENT("Sending Connect Request to Shill", service_path);
493  DBusThreadManager::Get()->GetShillServiceClient()->Connect(
494      dbus::ObjectPath(service_path),
495      base::Bind(&NetworkConnectionHandler::HandleShillConnectSuccess,
496                 AsWeakPtr(), service_path),
497      base::Bind(&NetworkConnectionHandler::HandleShillConnectFailure,
498                 AsWeakPtr(), service_path));
499}
500
501void NetworkConnectionHandler::HandleConfigurationFailure(
502    const std::string& service_path,
503    const std::string& error_name,
504    scoped_ptr<base::DictionaryValue> error_data) {
505  ConnectRequest* request = GetPendingRequest(service_path);
506  if (!request) {
507    NET_LOG_ERROR("HandleConfigurationFailure called with no pending request.",
508                  service_path);
509    return;
510  }
511  network_handler::ErrorCallback error_callback = request->error_callback;
512  pending_requests_.erase(service_path);
513  if (!error_callback.is_null())
514    error_callback.Run(kErrorConfigureFailed, error_data.Pass());
515}
516
517void NetworkConnectionHandler::HandleShillConnectSuccess(
518    const std::string& service_path) {
519  ConnectRequest* request = GetPendingRequest(service_path);
520  if (!request) {
521    NET_LOG_ERROR("HandleShillConnectSuccess called with no pending request.",
522                  service_path);
523    return;
524  }
525  request->connect_state = ConnectRequest::CONNECT_STARTED;
526  NET_LOG_EVENT("Connect Request Acknowledged", service_path);
527  // Do not call success_callback here, wait for one of the following
528  // conditions:
529  // * State transitions to a non connecting state indicating succes or failure
530  // * Network is no longer in the visible list, indicating failure
531  CheckPendingRequest(service_path);
532}
533
534void NetworkConnectionHandler::HandleShillConnectFailure(
535    const std::string& service_path,
536    const std::string& dbus_error_name,
537    const std::string& dbus_error_message) {
538  ConnectRequest* request = GetPendingRequest(service_path);
539  if (!request) {
540    NET_LOG_ERROR("HandleShillConnectFailure called with no pending request.",
541                  service_path);
542    return;
543  }
544  network_handler::ErrorCallback error_callback = request->error_callback;
545  pending_requests_.erase(service_path);
546  network_handler::ShillErrorCallbackFunction(
547      shill::kErrorConnectFailed, service_path, error_callback,
548      dbus_error_name, dbus_error_message);
549}
550
551void NetworkConnectionHandler::CheckPendingRequest(
552    const std::string service_path) {
553  ConnectRequest* request = GetPendingRequest(service_path);
554  DCHECK(request);
555  if (request->connect_state == ConnectRequest::CONNECT_REQUESTED)
556    return;  // Request has not started, ignore update
557  const NetworkState* network =
558      network_state_handler_->GetNetworkState(service_path);
559  if (!network)
560    return;  // NetworkState may not be be updated yet.
561
562  if (network->IsConnectingState()) {
563    request->connect_state = ConnectRequest::CONNECT_CONNECTING;
564    return;
565  }
566  if (network->IsConnectedState()) {
567    NET_LOG_EVENT("Connect Request Succeeded", service_path);
568    if (!request->profile_path.empty()) {
569      // If a profile path was specified, set it on a successful connection.
570      network_configuration_handler_->SetNetworkProfile(
571          service_path, request->profile_path,
572          base::Bind(&base::DoNothing),
573          chromeos::network_handler::ErrorCallback());
574    }
575    if (!request->success_callback.is_null())
576      request->success_callback.Run();
577    pending_requests_.erase(service_path);
578    return;
579  }
580  if (network->connection_state() == shill::kStateIdle &&
581      request->connect_state != ConnectRequest::CONNECT_CONNECTING) {
582    // Connection hasn't started yet, keep waiting.
583    return;
584  }
585
586  // Network is neither connecting or connected; an error occurred.
587  std::string error_name;  // 'Canceled' or 'Failed'
588  // If network->error() is empty here, we will look it up later, but we
589  // need to preserve it in case Shill clears it before then. crbug.com/302020.
590  std::string shill_error = network->error();
591  if (network->connection_state() == shill::kStateIdle &&
592      pending_requests_.size() > 1) {
593    // Another connect request canceled this one.
594    error_name = kErrorConnectCanceled;
595  } else {
596    error_name = shill::kErrorConnectFailed;
597    if (network->connection_state() != shill::kStateFailure) {
598      NET_LOG_ERROR("Unexpected State: " + network->connection_state(),
599                    service_path);
600    }
601  }
602  std::string error_msg = error_name;
603  if (!shill_error.empty())
604    error_msg += ": " + shill_error;
605  NET_LOG_ERROR(error_msg, service_path);
606
607  network_handler::ErrorCallback error_callback = request->error_callback;
608  pending_requests_.erase(service_path);
609  if (error_callback.is_null())
610    return;
611  network_handler::RunErrorCallback(
612      error_callback, service_path, error_name, shill_error);
613}
614
615void NetworkConnectionHandler::CheckAllPendingRequests() {
616  for (std::map<std::string, ConnectRequest>::iterator iter =
617           pending_requests_.begin(); iter != pending_requests_.end(); ++iter) {
618    CheckPendingRequest(iter->first);
619  }
620}
621
622std::string NetworkConnectionHandler::CertificateIsConfigured(
623    NetworkUIData* ui_data) {
624  if (ui_data->certificate_pattern().Empty())
625    return std::string();
626  // Find the matching certificate.
627  scoped_refptr<net::X509Certificate> matching_cert =
628      client_cert::GetCertificateMatch(ui_data->certificate_pattern());
629  if (!matching_cert.get())
630    return std::string();
631  return CertLoader::GetPkcs11IdForCert(*matching_cert.get());
632}
633
634void NetworkConnectionHandler::ErrorCallbackForPendingRequest(
635    const std::string& service_path,
636    const std::string& error_name) {
637  ConnectRequest* request = GetPendingRequest(service_path);
638  if (!request) {
639    NET_LOG_ERROR("ErrorCallbackForPendingRequest with no pending request.",
640                  service_path);
641    return;
642  }
643  // Remove the entry before invoking the callback in case it triggers a retry.
644  network_handler::ErrorCallback error_callback = request->error_callback;
645  pending_requests_.erase(service_path);
646  InvokeErrorCallback(service_path, error_callback, error_name);
647}
648
649// Disconnect
650
651void NetworkConnectionHandler::CallShillDisconnect(
652    const std::string& service_path,
653    const base::Closure& success_callback,
654    const network_handler::ErrorCallback& error_callback) {
655  NET_LOG_USER("Disconnect Request", service_path);
656  DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
657      dbus::ObjectPath(service_path),
658      base::Bind(&NetworkConnectionHandler::HandleShillDisconnectSuccess,
659                 AsWeakPtr(), service_path, success_callback),
660      base::Bind(&network_handler::ShillErrorCallbackFunction,
661                 kErrorShillError, service_path, error_callback));
662}
663
664void NetworkConnectionHandler::HandleShillDisconnectSuccess(
665    const std::string& service_path,
666    const base::Closure& success_callback) {
667  NET_LOG_EVENT("Disconnect Request Sent", service_path);
668  if (!success_callback.is_null())
669    success_callback.Run();
670}
671
672}  // namespace chromeos
673