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