OLD | NEW |
---|---|
(Empty) | |
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 "chromeos/dbus/dbus_thread_manager.h" | |
9 #include "chromeos/dbus/shill_manager_client.h" | |
10 #include "chromeos/dbus/shill_service_client.h" | |
11 #include "chromeos/network/cert_loader.h" | |
12 #include "chromeos/network/certificate_pattern_matcher.h" | |
13 #include "chromeos/network/network_configuration_handler.h" | |
14 #include "chromeos/network/network_event_log.h" | |
15 #include "chromeos/network/network_handler_callbacks.h" | |
16 #include "chromeos/network/network_state.h" | |
17 #include "chromeos/network/network_state_handler.h" | |
18 #include "chromeos/network/network_ui_data.h" | |
19 #include "dbus/object_path.h" | |
20 #include "net/cert/x509_certificate.h" | |
21 #include "third_party/cros_system_api/dbus/service_constants.h" | |
22 | |
23 namespace { | |
24 const char kLogModule[] = "NetworkConnectionHandler"; | |
25 } | |
26 | |
27 namespace chromeos { | |
28 | |
29 NetworkConnectionHandler* g_connection_handler_instance = NULL; | |
30 | |
31 const char NetworkConnectionHandler::kNetworkNotFound[] = "not-found"; | |
32 const char NetworkConnectionHandler::kConnected[] = "connected"; | |
33 const char NetworkConnectionHandler::kConnecting[] = "connecting"; | |
34 const char NetworkConnectionHandler::kNotConnected[] = "not-connected"; | |
35 const char NetworkConnectionHandler::kPassphraseRequired[] = | |
36 "passphrase-required"; | |
37 const char NetworkConnectionHandler::kActivationRequired[] = | |
38 "activation-required"; | |
39 const char NetworkConnectionHandler::kCertificateRequired[] = | |
40 "certificate-required"; | |
41 const char NetworkConnectionHandler::kConfigurationRequired[] = | |
42 "configuration-required"; | |
43 const char NetworkConnectionHandler::kShillError[] = "shill-error"; | |
44 | |
45 // static | |
46 void NetworkConnectionHandler::Initialize() { | |
47 CHECK(!g_connection_handler_instance); | |
48 g_connection_handler_instance = new NetworkConnectionHandler; | |
49 } | |
50 | |
51 // static | |
52 void NetworkConnectionHandler::Shutdown() { | |
53 CHECK(g_connection_handler_instance); | |
54 delete g_connection_handler_instance; | |
55 g_connection_handler_instance = NULL; | |
56 } | |
57 | |
58 // static | |
59 NetworkConnectionHandler* NetworkConnectionHandler::Get() { | |
60 CHECK(g_connection_handler_instance) | |
61 << "NetworkConnectionHandler::Get() called before Initialize()"; | |
62 return g_connection_handler_instance; | |
63 } | |
64 | |
65 NetworkConnectionHandler::NetworkConnectionHandler() { | |
66 } | |
67 | |
68 NetworkConnectionHandler::~NetworkConnectionHandler() { | |
69 } | |
70 | |
71 void NetworkConnectionHandler::ConnectToNetwork( | |
72 const std::string& service_path, | |
73 const base::Closure& success_callback, | |
74 const network_handler::ErrorCallback& error_callback) { | |
75 const NetworkState* network = | |
76 NetworkStateHandler::Get()->GetNetworkState(service_path); | |
77 if (!network) { | |
78 InvokeErrorCallback(service_path, error_callback, kNetworkNotFound); | |
79 return; | |
80 } | |
81 if (network->IsConnectedState()) { | |
82 InvokeErrorCallback(service_path, error_callback, kConnected); | |
83 return; | |
84 } | |
85 if (network->IsConnectingState() || | |
86 pending_requests_.find(service_path) != pending_requests_.end()) { | |
87 InvokeErrorCallback(service_path, error_callback, kConnecting); | |
88 return; | |
89 } | |
90 if (network->passphrase_required()) { | |
91 InvokeErrorCallback(service_path, error_callback, kPassphraseRequired); | |
92 return; | |
93 } | |
94 if (NetworkRequiresActivation(network)) { | |
95 InvokeErrorCallback(service_path, error_callback, kActivationRequired); | |
96 return; | |
97 } | |
98 | |
99 // All synchronous checks passed, add |service_path| to connecting list. | |
100 pending_requests_.insert(service_path); | |
101 | |
102 if (!network->connectable() && NetworkMayNeedCredentials(network)) { | |
103 // Request additional properties to check. | |
104 NetworkConfigurationHandler::Get()->GetProperties( | |
105 network->path(), | |
106 base::Bind(&NetworkConnectionHandler::GetPropertiesCallback, | |
107 AsWeakPtr(), success_callback, error_callback), | |
108 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure, | |
109 AsWeakPtr(), network->path(), error_callback)); | |
110 return; | |
111 } | |
112 // All checks passed, send connect request. | |
113 CallShillConnect(service_path, success_callback, error_callback); | |
114 } | |
115 | |
116 void NetworkConnectionHandler::DisconnectNetwork( | |
117 const std::string& service_path, | |
118 const base::Closure& success_callback, | |
119 const network_handler::ErrorCallback& error_callback) { | |
120 const NetworkState* network = | |
121 NetworkStateHandler::Get()->GetNetworkState(service_path); | |
122 if (!network) { | |
123 InvokeErrorCallback(service_path, error_callback, kNetworkNotFound); | |
124 return; | |
125 } | |
126 if (!network->IsConnectedState()) { | |
127 InvokeErrorCallback(service_path, error_callback, kNotConnected); | |
128 return; | |
129 } | |
130 CallShillDisconnect(service_path, success_callback, error_callback); | |
131 } | |
132 | |
133 void NetworkConnectionHandler::CallShillConnect( | |
134 const std::string& service_path, | |
135 const base::Closure& success_callback, | |
136 const network_handler::ErrorCallback& error_callback) { | |
137 // TODO(stevenjb): Remove SetConnectingNetwork and use this class to maintain | |
138 // the connecting network(s) once NetworkLibrary path is eliminated. | |
139 NetworkStateHandler::Get()->SetConnectingNetwork(service_path); | |
140 network_event_log::AddEntry(kLogModule, "Connect Request", service_path); | |
141 DBusThreadManager::Get()->GetShillServiceClient()->Connect( | |
142 dbus::ObjectPath(service_path), | |
143 base::Bind(&NetworkConnectionHandler::HandleShillSuccess, | |
144 AsWeakPtr(), service_path, success_callback), | |
145 base::Bind(&NetworkConnectionHandler::HandleShillFailure, | |
146 AsWeakPtr(), service_path, error_callback)); | |
147 } | |
148 | |
149 void NetworkConnectionHandler::CallShillDisconnect( | |
150 const std::string& service_path, | |
151 const base::Closure& success_callback, | |
152 const network_handler::ErrorCallback& error_callback) { | |
153 network_event_log::AddEntry(kLogModule, "Disconnect Request", service_path); | |
154 DBusThreadManager::Get()->GetShillServiceClient()->Disconnect( | |
155 dbus::ObjectPath(service_path), | |
156 base::Bind(&NetworkConnectionHandler::HandleShillSuccess, | |
157 AsWeakPtr(), service_path, success_callback), | |
158 base::Bind(&NetworkConnectionHandler::HandleShillFailure, | |
159 AsWeakPtr(), service_path, error_callback)); | |
160 } | |
161 | |
162 void NetworkConnectionHandler::InvokeErrorCallback( | |
pneubeck (no reviews)
2013/05/07 08:46:39
cc-local
stevenjb
2013/05/08 01:57:22
Done.
| |
163 const std::string& service_path, | |
164 const network_handler::ErrorCallback& error_callback, | |
165 const std::string& error_name) { | |
166 std::string error_message = "Connect Error: " + error_name; | |
pneubeck (no reviews)
2013/05/07 08:46:39
These error_messages are so useless. Not only here
stevenjb
2013/05/08 01:57:22
I'm not quite sure what your complaint is, I have
pneubeck (no reviews)
2013/05/08 08:07:46
In many places of chrome where we create (not forw
stevenjb
2013/05/08 18:48:00
I see. In this case, it is helpful to know that th
| |
167 network_handler::ShillErrorCallbackFunction( | |
168 kLogModule, service_path, error_callback, error_name, error_message); | |
169 } | |
170 | |
171 bool NetworkConnectionHandler::NetworkMayNeedCredentials( | |
pneubeck (no reviews)
2013/05/07 08:46:39
cc-local
stevenjb
2013/05/08 01:57:22
Done.
| |
172 const NetworkState* network) const { | |
pneubeck (no reviews)
2013/05/07 08:46:39
should be
const NetworkState&
stevenjb
2013/05/08 01:57:22
Even though cost& is generally preferred, const* i
| |
173 if (network->type() == flimflam::kTypeWifi && | |
174 (network->security() == flimflam::kSecurity8021x || | |
175 network->security() == flimflam::kSecurityWep /* For dynamic WEP*/)) | |
176 return true; | |
177 if (network->type() == flimflam::kTypeVPN) | |
178 return true; | |
179 return false; | |
180 } | |
181 | |
182 bool NetworkConnectionHandler::NetworkRequiresActivation( | |
pneubeck (no reviews)
2013/05/07 08:46:39
cc-local
stevenjb
2013/05/08 01:57:22
Done.
| |
183 const NetworkState* network) const { | |
pneubeck (no reviews)
2013/05/07 08:46:39
should be
const NetworkState&
stevenjb
2013/05/08 01:57:22
ditto.
| |
184 return (network->type() == flimflam::kTypeCellular && | |
185 (network->activation_state() != flimflam::kActivationStateActivated || | |
186 network->cellular_out_of_credits())); | |
187 } | |
188 | |
189 void NetworkConnectionHandler::GetPropertiesCallback( | |
pneubeck (no reviews)
2013/05/07 08:46:39
this should use ONC as the NetworkConfigurationHan
stevenjb
2013/05/08 01:57:22
I don't fully understand your comment.
I am fine
pneubeck (no reviews)
2013/05/08 08:07:46
NetworkConfigurationHandler::GetProperties returns
stevenjb
2013/05/08 18:48:00
I see. Somehow I didn't realize that. OK, I'll swi
pneubeck (no reviews)
2013/05/13 09:29:35
yes, fine with me.
| |
190 const base::Closure& success_callback, | |
191 const network_handler::ErrorCallback& error_callback, | |
192 const std::string& service_path, | |
193 const base::DictionaryValue& properties) { | |
194 const NetworkState* network = | |
195 NetworkStateHandler::Get()->GetNetworkState(service_path); | |
196 if (!network) { | |
197 InvokeErrorCallback(service_path, error_callback, kNetworkNotFound); | |
198 return; | |
199 } | |
200 | |
201 std::string provider_type; // For VPN | |
202 // Note: we use Value path expansion to extract Provider.Type. | |
203 properties.GetString(flimflam::kProviderTypeProperty, &provider_type); | |
204 | |
205 // VPN requires a host and username to be set. | |
206 if (network->type() == flimflam::kTypeVPN) { | |
207 std::string hostname; | |
208 properties.GetString(flimflam::kProviderHostProperty, &hostname); | |
pneubeck (no reviews)
2013/05/07 08:46:39
I'm strongly against adding general configuration
stevenjb
2013/05/08 01:57:22
I am duplicating the logic from NetworkLibrary. I
pneubeck (no reviews)
2013/05/13 09:29:35
then better add a comment that this code is prelim
| |
209 bool config_required; | |
210 if (provider_type == flimflam::kProviderOpenVpn) { | |
211 std::string username, client_cert_id; | |
212 properties.GetStringWithoutPathExpansion( | |
213 flimflam::kOpenVPNUserProperty, &username); | |
214 properties.GetStringWithoutPathExpansion( | |
215 flimflam::kOpenVPNClientCertIdProperty, &client_cert_id); | |
216 config_required = | |
217 hostname.empty() || username.empty() || client_cert_id.empty(); | |
218 } else { | |
219 bool passphrase_required = false; | |
220 std::string passphrase; | |
221 properties.GetBooleanWithoutPathExpansion( | |
222 flimflam::kL2tpIpsecPskRequiredProperty, &passphrase_required); | |
223 properties.GetStringWithoutPathExpansion( | |
224 flimflam::kL2tpIpsecPskProperty, &passphrase); | |
225 config_required = passphrase_required && passphrase.empty(); | |
226 } | |
227 if (config_required) { | |
228 InvokeErrorCallback(service_path, error_callback, kConfigurationRequired); | |
229 return; | |
230 } | |
231 } | |
232 | |
233 // Get certificate properties from kUIDataProperty. | |
234 scoped_ptr<NetworkUIData> ui_data = | |
235 NetworkUIData::CreateUIDataFromShill(properties); | |
pneubeck (no reviews)
2013/05/07 08:46:39
UIData is and should be read by the config handler
stevenjb
2013/05/08 01:57:22
Same comment as above - that sounds like a good fo
pneubeck (no reviews)
2013/05/13 09:29:35
then also add a comment here, please.
| |
236 if (!ui_data.get()) { | |
237 std::string error_message = "Error parsing UIData"; | |
238 HandleShillFailure( | |
239 service_path, error_callback, kConfigurationRequired, error_message); | |
pneubeck (no reviews)
2013/05/07 08:46:39
is that really "ConfigurationRequired"
stevenjb
2013/05/08 01:57:22
I screwed up this logic; what were intended to be
| |
240 return; | |
241 } | |
242 if (ui_data->certificate_type() != CLIENT_CERT_TYPE_PATTERN || | |
pneubeck (no reviews)
2013/05/07 08:46:39
Why is that an error? Certificate references shoul
| |
243 ui_data->certificate_pattern().Empty()) { | |
244 InvokeErrorCallback(service_path, error_callback, kConfigurationRequired); | |
245 return; | |
246 } | |
247 | |
248 // We skip certificate patterns for device policy ONC so that an unmanaged | |
249 // user can't get to the place where a cert is presented for them | |
250 // involuntarily. | |
251 if (ui_data->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY) { | |
252 InvokeErrorCallback(service_path, error_callback, kConfigurationRequired); | |
253 return; | |
254 } | |
255 | |
256 // Find the matching certificate. | |
257 scoped_refptr<net::X509Certificate> matching_cert = | |
pneubeck (no reviews)
2013/05/07 08:46:39
I don't like this code to be here: investigating c
stevenjb
2013/05/08 01:57:22
This also seems like something that can be improve
| |
258 certificate_pattern::GetCertificateMatch(ui_data->certificate_pattern()); | |
259 if (!matching_cert.get()) { | |
260 InvokeErrorCallback(service_path, error_callback, kCertificateRequired); | |
261 return; | |
262 } | |
263 | |
264 // Set the appropriate propeties, then call connect on success. | |
pneubeck (no reviews)
2013/05/07 08:46:39
nit: propeties -> properties
| |
265 std::string pkcs11_id = | |
266 CertLoader::Get()->GetPkcs11IdForCert(*matching_cert.get()); | |
267 base::DictionaryValue new_properties; | |
268 network->GetConfigProperties(&new_properties); | |
pneubeck (no reviews)
2013/05/07 08:46:39
why is this necessary?
| |
269 if (network->type() == flimflam::kTypeWifi) { | |
270 // shill requires both CertID and KeyID for TLS connections. | |
271 new_properties.SetStringWithoutPathExpansion( | |
272 flimflam::kEapCertIdProperty, pkcs11_id); | |
273 new_properties.SetStringWithoutPathExpansion( | |
274 flimflam::kEapKeyIdProperty, pkcs11_id); | |
275 if (network->security() == flimflam::kSecurity8021x) { | |
276 new_properties.SetStringWithoutPathExpansion( | |
277 flimflam::kEapPinProperty, CertLoader::Get()->tpm_user_pin()); | |
278 } | |
279 } else if (network->type() == flimflam::kTypeVPN) { | |
280 if (provider_type == flimflam::kProviderOpenVpn) { | |
281 new_properties.SetStringWithoutPathExpansion( | |
282 flimflam::kOpenVPNClientCertIdProperty, pkcs11_id); | |
283 new_properties.SetStringWithoutPathExpansion( | |
284 flimflam::kOpenVPNPinProperty, | |
285 CertLoader::Get()->tpm_user_pin()); | |
286 new_properties.SetStringWithoutPathExpansion( | |
287 flimflam::kOpenVPNClientCertSlotProperty, | |
288 CertLoader::Get()->tpm_token_slot()); | |
289 } else { | |
290 new_properties.SetStringWithoutPathExpansion( | |
291 flimflam::kL2tpIpsecClientCertIdProperty, pkcs11_id); | |
292 new_properties.SetStringWithoutPathExpansion( | |
293 flimflam::kL2tpIpsecPinProperty, | |
294 CertLoader::Get()->tpm_user_pin()); | |
295 new_properties.SetStringWithoutPathExpansion( | |
296 flimflam::kL2tpIpsecClientCertSlotProperty, | |
297 CertLoader::Get()->tpm_token_slot()); | |
298 } | |
299 } | |
300 NetworkConfigurationHandler::Get()->SetProperties( | |
pneubeck (no reviews)
2013/05/07 08:46:39
CertId, KeyId, Pin, ... are not configuration prop
stevenjb
2013/05/08 01:57:22
I removed the configuration from this flow, as I m
| |
301 network->path(), | |
302 new_properties, | |
303 base::Bind(&NetworkConnectionHandler::CallShillConnect, | |
304 AsWeakPtr(), network->path(), | |
305 success_callback, error_callback), | |
306 base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure, | |
307 AsWeakPtr(), network->path(), error_callback)); | |
308 } | |
309 | |
310 void NetworkConnectionHandler::HandleConfigurationFailure( | |
311 const std::string& service_path, | |
312 const network_handler::ErrorCallback& error_callback, | |
313 const std::string& error_name, | |
314 scoped_ptr<base::DictionaryValue> error_data) { | |
315 pending_requests_.erase(service_path); | |
316 if (!error_callback.is_null()) | |
317 error_callback.Run(error_name, error_data.Pass()); | |
318 } | |
319 | |
320 void NetworkConnectionHandler::HandleShillSuccess( | |
321 const std::string& service_path, | |
322 const base::Closure& success_callback) { | |
323 // TODO(stevenjb): Currently, this only indicates that the connect request | |
324 // succeeded. It might be preferable to wait for the actually connect | |
325 // attempt to succeed or fail here and only call |success_callback| at that | |
326 // point (or maybe call it twice, once indicating in-progress, then success | |
327 // or failure). | |
328 pending_requests_.erase(service_path); | |
329 network_event_log::AddEntry(kLogModule, "Connected", service_path); | |
330 success_callback.Run(); | |
331 } | |
332 | |
333 void NetworkConnectionHandler::HandleShillFailure( | |
334 const std::string& service_path, | |
335 const network_handler::ErrorCallback& error_callback, | |
336 const std::string& error_name, | |
337 const std::string& error_message) { | |
338 pending_requests_.erase(service_path); | |
339 std::string error = "Connect Failure: " + error_name + ": " + error_message; | |
340 network_handler::ShillErrorCallbackFunction( | |
341 kLogModule, service_path, error_callback, error_name, error_message); | |
342 } | |
343 | |
344 } // namespace chromeos | |
OLD | NEW |