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