• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
InvokeErrorCallback(const std::string & service_path,const network_handler::ErrorCallback & error_callback,const std::string & error_name)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 
IsAuthenticationError(const std::string & error)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 
VPNRequiresCredentials(const std::string & service_path,const std::string & provider_type,const base::DictionaryValue & provider_properties)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 
GetDefaultUserProfilePath(const NetworkState * network)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 {
ConnectRequestchromeos::NetworkConnectionHandler::ConnectRequest128   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 
NetworkConnectionHandler()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 
~NetworkConnectionHandler()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 
Init(NetworkStateHandler * network_state_handler,NetworkConfigurationHandler * network_configuration_handler,ManagedNetworkConfigurationHandler * managed_network_configuration_handler)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 
LoggedInStateChanged()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 
OnCertificatesLoaded(const net::CertificateList & cert_list,bool initial_load)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 
PolicyChanged(const std::string & userhash)233 void NetworkConnectionHandler::PolicyChanged(const std::string& userhash) {
234   // Ignore user policies.
235   if (!userhash.empty())
236     return;
237   DisconnectIfPolicyRequires();
238 }
239 
ConnectToNetwork(const std::string & service_path,const base::Closure & success_callback,const network_handler::ErrorCallback & error_callback,bool check_error_state)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 
DisconnectNetwork(const std::string & service_path,const base::Closure & success_callback,const network_handler::ErrorCallback & error_callback)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 
HasConnectingNetwork(const std::string & service_path)340 bool NetworkConnectionHandler::HasConnectingNetwork(
341     const std::string& service_path) {
342   return pending_requests_.count(service_path) != 0;
343 }
344 
HasPendingConnectRequest()345 bool NetworkConnectionHandler::HasPendingConnectRequest() {
346   return pending_requests_.size() > 0;
347 }
348 
NetworkListChanged()349 void NetworkConnectionHandler::NetworkListChanged() {
350   CheckAllPendingRequests();
351 }
352 
NetworkPropertiesUpdated(const NetworkState * network)353 void NetworkConnectionHandler::NetworkPropertiesUpdated(
354     const NetworkState* network) {
355   if (HasConnectingNetwork(network->path()))
356     CheckPendingRequest(network->path());
357 }
358 
359 NetworkConnectionHandler::ConnectRequest*
GetPendingRequest(const std::string & service_path)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 
VerifyConfiguredAndConnect(bool check_error_state,const std::string & service_path,const base::DictionaryValue & service_properties)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 
QueueConnectRequest(const std::string & service_path)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 
CheckCertificatesLoaded()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 
ConnectToQueuedNetwork()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 
CallShillConnect(const std::string & service_path)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 
HandleConfigurationFailure(const std::string & service_path,const std::string & error_name,scoped_ptr<base::DictionaryValue> error_data)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 
HandleShillConnectSuccess(const std::string & service_path)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 
HandleShillConnectFailure(const std::string & service_path,const std::string & dbus_error_name,const std::string & dbus_error_message)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 
CheckPendingRequest(const std::string service_path)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 
CheckAllPendingRequests()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 
CertificateIsConfigured(NetworkUIData * ui_data)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 
ErrorCallbackForPendingRequest(const std::string & service_path,const std::string & error_name)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 
CallShillDisconnect(const std::string & service_path,const base::Closure & success_callback,const network_handler::ErrorCallback & error_callback)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 
HandleShillDisconnectSuccess(const std::string & service_path,const base::Closure & success_callback)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 
ConnectToBestNetworkAfterLogin()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 
DisconnectIfPolicyRequires()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