blob: 9a29babc9cd51030cb45589fe6b52b748fb15cd3 [file] [log] [blame]
Darin Petkov7476a262012-04-12 16:30:46 +02001// Copyright (c) 2012 The Chromium OS 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
Paul Stewart5bbf93b2013-03-21 12:06:08 -07005// The term "L2TP / IPSec" refers to a pair of layered protocols used
6// together to establish a tunneled VPN connection. First, an "IPSec"
7// link is created, which secures a single IP traffic pair between the
8// client and server. For this link to complete, one or two levels of
9// authentication are performed. The first, inner mandatory authentication
10// ensures the two parties establishing the IPSec link are correct. This
11// can use a certificate exchange or a less secure "shared group key"
12// (PSK) authentication. An optional outer IPSec authentication can also be
13// performed, which is not fully supported by shill's implementation.
14// In order to support "tunnel groups" from some vendor VPNs shill supports
15// supplying the authentication realm portion during the outer authentication.
16// Notably, XAUTH and other forms of user authentication on this outer link
17// are not supported.
18//
19// When IPSec authentication completes, traffic is tunneled through a
20// layer 2 tunnel, called "L2TP". Using the secured link, we tunnel a
21// PPP link, through which a second layer of authentication is performed,
22// using the provided "user" and "password" properties.
23
Darin Petkov7476a262012-04-12 16:30:46 +020024#include "shill/l2tp_ipsec_driver.h"
25
Darin Petkov69990222012-11-14 09:25:25 +010026#include <base/bind.h>
Darin Petkovf7ef50a2012-04-16 20:54:31 +020027#include <base/file_util.h>
Ben Chana0ddf462014-02-06 11:32:42 -080028#include <base/strings/string_util.h>
Darin Petkov7476a262012-04-12 16:30:46 +020029#include <chromeos/dbus/service_constants.h>
Liam McLoughlinef342b42013-09-13 21:05:36 +010030#include <vpn-manager/service_error.h>
Darin Petkov7476a262012-04-12 16:30:46 +020031
Paul Stewart5baebb72013-03-14 11:43:29 -070032#include "shill/certificate_file.h"
Darin Petkovf8046b82012-04-24 16:29:23 +020033#include "shill/device_info.h"
Darin Petkovf7ef50a2012-04-16 20:54:31 +020034#include "shill/error.h"
mukesh agrawalae30e9e2013-05-28 14:09:16 -070035#include "shill/external_task.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070036#include "shill/logging.h"
Darin Petkovf7ef50a2012-04-16 20:54:31 +020037#include "shill/manager.h"
mukesh agrawal9da07772013-05-15 14:15:17 -070038#include "shill/ppp_device.h"
mukesh agrawal2e382632013-08-01 13:41:15 -070039#include "shill/ppp_device_factory.h"
Darin Petkov209e6292012-04-20 11:33:32 +020040#include "shill/vpn_service.h"
Darin Petkovf7ef50a2012-04-16 20:54:31 +020041
Darin Petkov69990222012-11-14 09:25:25 +010042using base::Bind;
Darin Petkov5a850472012-06-06 15:44:24 +020043using base::Closure;
Albert Chaulk0e1cdea2013-02-27 15:32:55 -080044using base::FilePath;
Darin Petkov209e6292012-04-20 11:33:32 +020045using std::map;
Darin Petkov7476a262012-04-12 16:30:46 +020046using std::string;
Darin Petkovf7ef50a2012-04-16 20:54:31 +020047using std::vector;
Darin Petkov7476a262012-04-12 16:30:46 +020048
49namespace shill {
50
Darin Petkovf7ef50a2012-04-16 20:54:31 +020051namespace {
52const char kL2TPIPSecIPSecTimeoutProperty[] = "L2TPIPsec.IPsecTimeout";
53const char kL2TPIPSecLeftProtoPortProperty[] = "L2TPIPsec.LeftProtoPort";
54const char kL2TPIPSecLengthBitProperty[] = "L2TPIPsec.LengthBit";
55const char kL2TPIPSecPFSProperty[] = "L2TPIPsec.PFS";
56const char kL2TPIPSecRefusePapProperty[] = "L2TPIPsec.RefusePap";
57const char kL2TPIPSecRekeyProperty[] = "L2TPIPsec.Rekey";
58const char kL2TPIPSecRequireAuthProperty[] = "L2TPIPsec.RequireAuth";
59const char kL2TPIPSecRequireChapProperty[] = "L2TPIPsec.RequireChap";
60const char kL2TPIPSecRightProtoPortProperty[] = "L2TPIPsec.RightProtoPort";
61} // namespace
62
63// static
Darin Petkov209e6292012-04-20 11:33:32 +020064const char L2TPIPSecDriver::kL2TPIPSecVPNPath[] = "/usr/sbin/l2tpipsec_vpn";
Darin Petkovd4325392012-04-23 15:48:22 +020065// static
66const VPNDriver::Property L2TPIPSecDriver::kProperties[] = {
Ben Chan73728782013-09-20 13:40:54 -070067 { kL2tpIpsecAuthenticationType, 0 },
68 { kL2tpIpsecCaCertNssProperty, 0 },
69 { kL2tpIpsecClientCertIdProperty, 0 },
70 { kL2tpIpsecClientCertSlotProperty, 0 },
71 { kL2tpIpsecIkeVersion, 0 },
72 { kL2tpIpsecPasswordProperty, Property::kCredential | Property::kWriteOnly },
73 { kL2tpIpsecPinProperty, Property::kCredential },
Paul Stewarta7109d32014-04-14 12:24:42 -070074 { kL2tpIpsecPskProperty, Property::kCredential | Property::kWriteOnly },
Ben Chan73728782013-09-20 13:40:54 -070075 { kL2tpIpsecUserProperty, 0 },
76 { kProviderHostProperty, 0 },
77 { kProviderTypeProperty, 0 },
Paul Stewarteb713e82013-06-28 14:51:54 -070078 { kL2tpIpsecCaCertPemProperty, Property::kArray },
Paul Stewart5bbf93b2013-03-21 12:06:08 -070079 { kL2tpIpsecTunnelGroupProperty, 0 },
Darin Petkovd4325392012-04-23 15:48:22 +020080 { kL2TPIPSecIPSecTimeoutProperty, 0 },
81 { kL2TPIPSecLeftProtoPortProperty, 0 },
82 { kL2TPIPSecLengthBitProperty, 0 },
83 { kL2TPIPSecPFSProperty, 0 },
84 { kL2TPIPSecRefusePapProperty, 0 },
85 { kL2TPIPSecRekeyProperty, 0 },
86 { kL2TPIPSecRequireAuthProperty, 0 },
87 { kL2TPIPSecRequireChapProperty, 0 },
88 { kL2TPIPSecRightProtoPortProperty, 0 },
Paul Stewarta7109d32014-04-14 12:24:42 -070089 { kL2tpIpsecXauthUserProperty, Property::kCredential | Property::kWriteOnly },
90 { kL2tpIpsecXauthPasswordProperty,
91 Property::kCredential | Property::kWriteOnly },
Darin Petkovd4325392012-04-23 15:48:22 +020092};
Darin Petkovf7ef50a2012-04-16 20:54:31 +020093
Darin Petkov209e6292012-04-20 11:33:32 +020094L2TPIPSecDriver::L2TPIPSecDriver(ControlInterface *control,
Darin Petkovf8046b82012-04-24 16:29:23 +020095 EventDispatcher *dispatcher,
96 Metrics *metrics,
Darin Petkov209e6292012-04-20 11:33:32 +020097 Manager *manager,
Darin Petkovf8046b82012-04-24 16:29:23 +020098 DeviceInfo *device_info,
Darin Petkov209e6292012-04-20 11:33:32 +020099 GLib *glib)
Darin Petkov602303f2012-06-06 12:15:59 +0200100 : VPNDriver(dispatcher, manager, kProperties, arraysize(kProperties)),
Darin Petkovb451d6e2012-04-23 11:56:41 +0200101 control_(control),
Darin Petkovf8046b82012-04-24 16:29:23 +0200102 metrics_(metrics),
103 device_info_(device_info),
Darin Petkov209e6292012-04-20 11:33:32 +0200104 glib_(glib),
mukesh agrawal2e382632013-08-01 13:41:15 -0700105 ppp_device_factory_(PPPDeviceFactory::GetInstance()),
Paul Stewarteb713e82013-06-28 14:51:54 -0700106 certificate_file_(new CertificateFile()),
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700107 weak_ptr_factory_(this) {}
Darin Petkov7476a262012-04-12 16:30:46 +0200108
Darin Petkov209e6292012-04-20 11:33:32 +0200109L2TPIPSecDriver::~L2TPIPSecDriver() {
Darin Petkov85d53172013-03-13 16:43:28 +0100110 IdleService();
Darin Petkov209e6292012-04-20 11:33:32 +0200111}
Darin Petkov7476a262012-04-12 16:30:46 +0200112
113bool L2TPIPSecDriver::ClaimInterface(const string &link_name,
114 int interface_index) {
Paul Stewartee6b3d72013-07-12 16:07:51 -0700115 // TODO(petkov): crbug.com/212446.
Darin Petkov7476a262012-04-12 16:30:46 +0200116 NOTIMPLEMENTED();
117 return false;
118}
119
120void L2TPIPSecDriver::Connect(const VPNServiceRefPtr &service, Error *error) {
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100121 StartConnectTimeout(kDefaultConnectTimeoutSeconds);
Darin Petkov209e6292012-04-20 11:33:32 +0200122 service_ = service;
123 service_->SetState(Service::kStateConfiguring);
Darin Petkov209e6292012-04-20 11:33:32 +0200124 if (!SpawnL2TPIPSecVPN(error)) {
Darin Petkov1c049c72013-03-21 13:15:45 +0100125 FailService(Service::kFailureInternal);
Darin Petkov209e6292012-04-20 11:33:32 +0200126 }
Darin Petkov7476a262012-04-12 16:30:46 +0200127}
128
129void L2TPIPSecDriver::Disconnect() {
Darin Petkova0e645e2012-04-25 11:38:59 +0200130 SLOG(VPN, 2) << __func__;
Darin Petkov85d53172013-03-13 16:43:28 +0100131 IdleService();
Darin Petkov7476a262012-04-12 16:30:46 +0200132}
133
Darin Petkov5eb05422012-05-11 15:45:25 +0200134void L2TPIPSecDriver::OnConnectionDisconnected() {
Darin Petkova42afe32013-02-05 16:53:52 +0100135 LOG(INFO) << "Underlying connection disconnected.";
Darin Petkov85d53172013-03-13 16:43:28 +0100136 IdleService();
Darin Petkova42afe32013-02-05 16:53:52 +0100137}
138
139void L2TPIPSecDriver::OnConnectTimeout() {
140 VPNDriver::OnConnectTimeout();
Darin Petkov85d53172013-03-13 16:43:28 +0100141 FailService(Service::kFailureConnect);
Darin Petkov5eb05422012-05-11 15:45:25 +0200142}
143
Darin Petkov7476a262012-04-12 16:30:46 +0200144string L2TPIPSecDriver::GetProviderType() const {
Ben Chan73728782013-09-20 13:40:54 -0700145 return kProviderL2tpIpsec;
Darin Petkov7476a262012-04-12 16:30:46 +0200146}
147
Darin Petkov85d53172013-03-13 16:43:28 +0100148void L2TPIPSecDriver::IdleService() {
149 Cleanup(Service::kStateIdle, Service::kFailureUnknown);
150}
151
152void L2TPIPSecDriver::FailService(Service::ConnectFailure failure) {
153 Cleanup(Service::kStateFailure, failure);
154}
155
156void L2TPIPSecDriver::Cleanup(Service::ConnectState state,
157 Service::ConnectFailure failure) {
158 SLOG(VPN, 2) << __func__ << "("
159 << Service::ConnectStateToString(state) << ", "
160 << Service::ConnectFailureToString(failure) << ")";
Darin Petkov602303f2012-06-06 12:15:59 +0200161 StopConnectTimeout();
Paul Stewart3f713262013-12-24 20:12:53 -0800162 DeleteTemporaryFiles();
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700163 external_task_.reset();
Darin Petkovf8046b82012-04-24 16:29:23 +0200164 if (device_) {
mukesh agrawal9da07772013-05-15 14:15:17 -0700165 device_->DropConnection();
Darin Petkovf8046b82012-04-24 16:29:23 +0200166 device_->SetEnabled(false);
167 device_ = NULL;
168 }
Darin Petkov209e6292012-04-20 11:33:32 +0200169 if (service_) {
Darin Petkov85d53172013-03-13 16:43:28 +0100170 if (state == Service::kStateFailure) {
171 service_->SetFailure(failure);
172 } else {
173 service_->SetState(state);
174 }
Darin Petkov209e6292012-04-20 11:33:32 +0200175 service_ = NULL;
176 }
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200177}
178
Paul Stewart3f713262013-12-24 20:12:53 -0800179void L2TPIPSecDriver::DeleteTemporaryFile(base::FilePath *temporary_file) {
180 if (!temporary_file->empty()) {
Ben Chana0ddf462014-02-06 11:32:42 -0800181 base::DeleteFile(*temporary_file, false);
Paul Stewart3f713262013-12-24 20:12:53 -0800182 temporary_file->clear();
Darin Petkov0e9735d2012-04-24 12:33:45 +0200183 }
184}
185
Paul Stewart3f713262013-12-24 20:12:53 -0800186void L2TPIPSecDriver::DeleteTemporaryFiles() {
187 DeleteTemporaryFile(&psk_file_);
188 DeleteTemporaryFile(&xauth_credentials_file_);
189}
190
Darin Petkov209e6292012-04-20 11:33:32 +0200191bool L2TPIPSecDriver::SpawnL2TPIPSecVPN(Error *error) {
192 SLOG(VPN, 2) << __func__;
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700193 scoped_ptr<ExternalTask> external_task_local(
194 new ExternalTask(control_, glib_,
195 weak_ptr_factory_.GetWeakPtr(),
196 Bind(&L2TPIPSecDriver::OnL2TPIPSecVPNDied,
197 weak_ptr_factory_.GetWeakPtr())));
Darin Petkov209e6292012-04-20 11:33:32 +0200198
199 vector<string> options;
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700200 map<string, string> environment; // No env vars passed.
Darin Petkov209e6292012-04-20 11:33:32 +0200201 if (!InitOptions(&options, error)) {
202 return false;
203 }
Darin Petkov85d53172013-03-13 16:43:28 +0100204 LOG(INFO) << "L2TP/IPSec VPN process options: " << JoinString(options, ' ');
Darin Petkov209e6292012-04-20 11:33:32 +0200205
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700206 if (external_task_local->Start(
mukesh agrawalc4f9aa02013-08-15 19:23:13 -0700207 FilePath(kL2TPIPSecVPNPath), options, environment, true, error)) {
mukesh agrawal9da07772013-05-15 14:15:17 -0700208 external_task_ = external_task_local.Pass();
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700209 return true;
Darin Petkov209e6292012-04-20 11:33:32 +0200210 }
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700211 return false;
Darin Petkov209e6292012-04-20 11:33:32 +0200212}
213
214bool L2TPIPSecDriver::InitOptions(vector<string> *options, Error *error) {
Ben Chan73728782013-09-20 13:40:54 -0700215 string vpnhost = args()->LookupString(kProviderHostProperty, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200216 if (vpnhost.empty()) {
217 Error::PopulateAndLog(
218 error, Error::kInvalidArguments, "VPN host not specified.");
Darin Petkov209e6292012-04-20 11:33:32 +0200219 return false;
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200220 }
221
222 if (!InitPSKOptions(options, error)) {
Darin Petkov209e6292012-04-20 11:33:32 +0200223 return false;
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200224 }
225
Paul Stewart3f713262013-12-24 20:12:53 -0800226 if (!InitXauthOptions(options, error)) {
227 return false;
228 }
229
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200230 options->push_back("--remote_host");
231 options->push_back(vpnhost);
232 options->push_back("--pppd_plugin");
mukesh agrawal9da07772013-05-15 14:15:17 -0700233 options->push_back(PPPDevice::kPluginPath);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200234 // Disable pppd from configuring IP addresses, routes, DNS.
235 options->push_back("--nosystemconfig");
236
Paul Stewartc350e682014-06-19 15:44:30 -0700237 // Accept a PEM CA certificate.
238 InitPEMOptions(options);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200239
Ben Chan73728782013-09-20 13:40:54 -0700240 AppendValueOption(kL2tpIpsecClientCertIdProperty,
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200241 "--client_cert_id", options);
Ben Chan73728782013-09-20 13:40:54 -0700242 AppendValueOption(kL2tpIpsecClientCertSlotProperty,
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200243 "--client_cert_slot", options);
Ben Chan73728782013-09-20 13:40:54 -0700244 AppendValueOption(kL2tpIpsecPinProperty, "--user_pin", options);
245 AppendValueOption(kL2tpIpsecUserProperty, "--user", options);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200246 AppendValueOption(kL2TPIPSecIPSecTimeoutProperty, "--ipsec_timeout", options);
247 AppendValueOption(kL2TPIPSecLeftProtoPortProperty,
248 "--leftprotoport", options);
249 AppendFlag(kL2TPIPSecPFSProperty, "--pfs", "--nopfs", options);
250 AppendFlag(kL2TPIPSecRekeyProperty, "--rekey", "--norekey", options);
251 AppendValueOption(kL2TPIPSecRightProtoPortProperty,
252 "--rightprotoport", options);
253 AppendFlag(kL2TPIPSecRequireChapProperty,
254 "--require_chap", "--norequire_chap", options);
255 AppendFlag(kL2TPIPSecRefusePapProperty,
256 "--refuse_pap", "--norefuse_pap", options);
257 AppendFlag(kL2TPIPSecRequireAuthProperty,
258 "--require_authentication", "--norequire_authentication", options);
259 AppendFlag(kL2TPIPSecLengthBitProperty,
260 "--length_bit", "--nolength_bit", options);
Paul Stewart5bbf93b2013-03-21 12:06:08 -0700261 AppendValueOption(kL2tpIpsecTunnelGroupProperty, "--tunnel_group", options);
Darin Petkov209e6292012-04-20 11:33:32 +0200262 if (SLOG_IS_ON(VPN, 0)) {
263 options->push_back("--debug");
264 }
265 return true;
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200266}
267
268bool L2TPIPSecDriver::InitPSKOptions(vector<string> *options, Error *error) {
Ben Chan73728782013-09-20 13:40:54 -0700269 string psk = args()->LookupString(kL2tpIpsecPskProperty, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200270 if (!psk.empty()) {
Ben Chana0ddf462014-02-06 11:32:42 -0800271 if (!base::CreateTemporaryFileInDir(manager()->run_path(), &psk_file_) ||
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200272 chmod(psk_file_.value().c_str(), S_IRUSR | S_IWUSR) ||
Ben Chan6fbf64f2014-05-21 18:07:01 -0700273 base::WriteFile(psk_file_, psk.data(), psk.size()) !=
Ben Chana0ddf462014-02-06 11:32:42 -0800274 static_cast<int>(psk.size())) {
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200275 Error::PopulateAndLog(
276 error, Error::kInternalError, "Unable to setup psk file.");
277 return false;
278 }
279 options->push_back("--psk_file");
280 options->push_back(psk_file_.value());
281 }
282 return true;
283}
284
Paul Stewart5baebb72013-03-14 11:43:29 -0700285bool L2TPIPSecDriver::InitPEMOptions(vector<string> *options) {
Paul Stewarteb713e82013-06-28 14:51:54 -0700286 vector<string> ca_certs;
287 if (args()->ContainsStrings(kL2tpIpsecCaCertPemProperty)) {
288 ca_certs = args()->GetStrings(kL2tpIpsecCaCertPemProperty);
289 }
290 if (ca_certs.empty()) {
Paul Stewart5baebb72013-03-14 11:43:29 -0700291 return false;
292 }
Paul Stewarteb713e82013-06-28 14:51:54 -0700293 FilePath certfile = certificate_file_->CreatePEMFromStrings(ca_certs);
Paul Stewart5baebb72013-03-14 11:43:29 -0700294 if (certfile.empty()) {
Paul Stewarteb713e82013-06-28 14:51:54 -0700295 LOG(ERROR) << "Unable to extract certificates from PEM string.";
Paul Stewart5baebb72013-03-14 11:43:29 -0700296 return false;
297 }
298 options->push_back("--server_ca_file");
299 options->push_back(certfile.value());
300 return true;
301}
302
Paul Stewart3f713262013-12-24 20:12:53 -0800303bool L2TPIPSecDriver::InitXauthOptions(vector<string> *options, Error *error) {
304 string user = args()->LookupString(kL2tpIpsecXauthUserProperty, "");
305 string password = args()->LookupString(kL2tpIpsecXauthPasswordProperty, "");
306 if (user.empty() && password.empty()) {
307 // Xauth credentials not configured.
308 return true;
309 }
310 if (user.empty() || password.empty()) {
311 Error::PopulateAndLog(
312 error, Error::kInvalidArguments,
313 "XAUTH credentials are partially configured.");
314 return false;
315 }
316 string xauth_credentials = user + "\n" + password + "\n";
Ben Chana0ddf462014-02-06 11:32:42 -0800317 if (!base::CreateTemporaryFileInDir(manager()->run_path(),
318 &xauth_credentials_file_) ||
Paul Stewart3f713262013-12-24 20:12:53 -0800319 chmod(xauth_credentials_file_.value().c_str(), S_IRUSR | S_IWUSR) ||
Ben Chan6fbf64f2014-05-21 18:07:01 -0700320 base::WriteFile(xauth_credentials_file_, xauth_credentials.data(),
321 xauth_credentials.size()) !=
Paul Stewart3f713262013-12-24 20:12:53 -0800322 static_cast<int>(xauth_credentials.size())) {
323 Error::PopulateAndLog(
324 error, Error::kInternalError,
325 "Unable to setup XAUTH credentials file.");
326 return false;
327 }
328 options->push_back("--xauth_credentials_file");
329 options->push_back(xauth_credentials_file_.value());
330 return true;
331}
332
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200333bool L2TPIPSecDriver::AppendValueOption(
334 const string &property, const string &option, vector<string> *options) {
Darin Petkov01c66042012-04-26 11:10:45 +0200335 string value = args()->LookupString(property, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200336 if (!value.empty()) {
337 options->push_back(option);
338 options->push_back(value);
339 return true;
340 }
341 return false;
342}
343
344bool L2TPIPSecDriver::AppendFlag(const string &property,
345 const string &true_option,
346 const string &false_option,
347 vector<string> *options) {
Darin Petkov01c66042012-04-26 11:10:45 +0200348 string value = args()->LookupString(property, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200349 if (!value.empty()) {
350 options->push_back(value == "true" ? true_option : false_option);
351 return true;
352 }
353 return false;
354}
355
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700356void L2TPIPSecDriver::OnL2TPIPSecVPNDied(pid_t /*pid*/, int status) {
357 FailService(TranslateExitStatusToFailure(status));
Darin Petkov209e6292012-04-20 11:33:32 +0200358 // TODO(petkov): Figure if we need to restart the connection.
359}
360
Darin Petkov85d53172013-03-13 16:43:28 +0100361// static
362Service::ConnectFailure L2TPIPSecDriver::TranslateExitStatusToFailure(
363 int status) {
364 if (!WIFEXITED(status)) {
Darin Petkov1c049c72013-03-21 13:15:45 +0100365 return Service::kFailureInternal;
Darin Petkov85d53172013-03-13 16:43:28 +0100366 }
367 switch (WEXITSTATUS(status)) {
368 case vpn_manager::kServiceErrorResolveHostnameFailed:
369 return Service::kFailureDNSLookup;
370 case vpn_manager::kServiceErrorIpsecConnectionFailed:
371 case vpn_manager::kServiceErrorL2tpConnectionFailed:
372 case vpn_manager::kServiceErrorPppConnectionFailed:
373 return Service::kFailureConnect;
374 case vpn_manager::kServiceErrorIpsecPresharedKeyAuthenticationFailed:
375 return Service::kFailureIPSecPSKAuth;
376 case vpn_manager::kServiceErrorIpsecCertificateAuthenticationFailed:
377 return Service::kFailureIPSecCertAuth;
378 case vpn_manager::kServiceErrorPppAuthenticationFailed:
379 return Service::kFailurePPPAuth;
380 default:
381 break;
382 }
383 return Service::kFailureUnknown;
384}
385
Darin Petkov209e6292012-04-20 11:33:32 +0200386void L2TPIPSecDriver::GetLogin(string *user, string *password) {
Darin Petkov602303f2012-06-06 12:15:59 +0200387 LOG(INFO) << "Login requested.";
Darin Petkov209e6292012-04-20 11:33:32 +0200388 string user_property =
Ben Chan73728782013-09-20 13:40:54 -0700389 args()->LookupString(kL2tpIpsecUserProperty, "");
Darin Petkov209e6292012-04-20 11:33:32 +0200390 if (user_property.empty()) {
391 LOG(ERROR) << "User not set.";
392 return;
393 }
394 string password_property =
Ben Chan73728782013-09-20 13:40:54 -0700395 args()->LookupString(kL2tpIpsecPasswordProperty, "");
Darin Petkov209e6292012-04-20 11:33:32 +0200396 if (password_property.empty()) {
397 LOG(ERROR) << "Password not set.";
398 return;
399 }
400 *user = user_property;
401 *password = password_property;
402}
403
404void L2TPIPSecDriver::Notify(
405 const string &reason, const map<string, string> &dict) {
Darin Petkov602303f2012-06-06 12:15:59 +0200406 LOG(INFO) << "IP configuration received: " << reason;
Darin Petkov0e9735d2012-04-24 12:33:45 +0200407
Paul Stewart16de98c2013-08-12 15:21:06 -0700408 if (reason == kPPPReasonAuthenticating ||
409 reason == kPPPReasonAuthenticated) {
410 // These are uninteresting intermediate states that do not indicate failure.
411 return;
412 }
413
mukesh agrawal9da07772013-05-15 14:15:17 -0700414 if (reason != kPPPReasonConnect) {
415 DCHECK_EQ(kPPPReasonDisconnect, reason);
416 // DestroyLater, rather than while on stack.
417 external_task_.release()->DestroyLater(dispatcher());
Darin Petkov85d53172013-03-13 16:43:28 +0100418 FailService(Service::kFailureUnknown);
Darin Petkov0e9735d2012-04-24 12:33:45 +0200419 return;
420 }
421
Paul Stewart3f713262013-12-24 20:12:53 -0800422 DeleteTemporaryFiles();
Darin Petkovf8046b82012-04-24 16:29:23 +0200423
mukesh agrawal9da07772013-05-15 14:15:17 -0700424 string interface_name = PPPDevice::GetInterfaceName(dict);
Darin Petkovf8046b82012-04-24 16:29:23 +0200425 int interface_index = device_info_->GetIndex(interface_name);
426 if (interface_index < 0) {
427 // TODO(petkov): Consider handling the race when the RTNL notification about
428 // the new PPP device has not been received yet. We can keep the IP
Darin Petkovf8f970a2012-09-03 11:32:55 +0200429 // configuration and apply it when ClaimInterface is
Paul Stewartee6b3d72013-07-12 16:07:51 -0700430 // invoked. crbug.com/212446.
Darin Petkovf8046b82012-04-24 16:29:23 +0200431 NOTIMPLEMENTED() << ": No device info for " << interface_name << ".";
432 return;
433 }
434
mukesh agrawal9da07772013-05-15 14:15:17 -0700435 // There is no IPv6 support for L2TP/IPsec VPN at this moment, so create a
436 // blackhole route for IPv6 traffic after establishing a IPv4 VPN.
437 // TODO(benchan): Generalize this when IPv6 support is added.
438 bool blackhole_ipv6 = true;
439
Darin Petkovf8046b82012-04-24 16:29:23 +0200440 if (!device_) {
mukesh agrawal2e382632013-08-01 13:41:15 -0700441 device_ = ppp_device_factory_->CreatePPPDevice(
442 control_, dispatcher(), metrics_, manager(), interface_name,
443 interface_index);
Darin Petkovf8046b82012-04-24 16:29:23 +0200444 }
445 device_->SetEnabled(true);
446 device_->SelectService(service_);
mukesh agrawal9da07772013-05-15 14:15:17 -0700447 device_->UpdateIPConfigFromPPP(dict, blackhole_ipv6);
Paul Stewart91a43cb2013-03-02 21:34:15 -0800448 ReportConnectionMetrics();
Darin Petkov602303f2012-06-06 12:15:59 +0200449 StopConnectTimeout();
Darin Petkov209e6292012-04-20 11:33:32 +0200450}
451
Paul Stewartba8f1412013-09-30 17:52:03 -0700452bool L2TPIPSecDriver::IsPskRequired() const {
453 return
454 const_args()->LookupString(kL2tpIpsecPskProperty, "").empty() &&
455 const_args()->LookupString(kL2tpIpsecClientCertIdProperty, "").empty();
456}
457
Darin Petkovb536a742012-04-26 11:31:28 +0200458KeyValueStore L2TPIPSecDriver::GetProvider(Error *error) {
459 SLOG(VPN, 2) << __func__;
460 KeyValueStore props = VPNDriver::GetProvider(error);
Ben Chan73728782013-09-20 13:40:54 -0700461 props.SetBool(kPassphraseRequiredProperty,
462 args()->LookupString(kL2tpIpsecPasswordProperty, "").empty());
Paul Stewartba8f1412013-09-30 17:52:03 -0700463 props.SetBool(kL2tpIpsecPskRequiredProperty, IsPskRequired());
Darin Petkovb536a742012-04-26 11:31:28 +0200464 return props;
465}
466
Paul Stewart91a43cb2013-03-02 21:34:15 -0800467void L2TPIPSecDriver::ReportConnectionMetrics() {
468 metrics_->SendEnumToUMA(
469 Metrics::kMetricVpnDriver,
470 Metrics::kVpnDriverL2tpIpsec,
471 Metrics::kMetricVpnDriverMax);
472
473 // We output an enum for each of the authentication types specified,
474 // even if more than one is set at the same time.
475 bool has_remote_authentication = false;
Ben Chan73728782013-09-20 13:40:54 -0700476 if (args()->LookupString(kL2tpIpsecPskProperty, "") != "") {
Paul Stewart91a43cb2013-03-02 21:34:15 -0800477 metrics_->SendEnumToUMA(
478 Metrics::kMetricVpnRemoteAuthenticationType,
479 Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecPsk,
480 Metrics::kMetricVpnRemoteAuthenticationTypeMax);
481 has_remote_authentication = true;
482 }
483 if (!has_remote_authentication) {
484 metrics_->SendEnumToUMA(
485 Metrics::kMetricVpnRemoteAuthenticationType,
486 Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecDefault,
487 Metrics::kMetricVpnRemoteAuthenticationTypeMax);
488 }
489
490 bool has_user_authentication = false;
Ben Chan73728782013-09-20 13:40:54 -0700491 if (args()->LookupString(kL2tpIpsecClientCertIdProperty,
Paul Stewarte8e71da2013-03-20 08:48:33 -0700492 "") != "") {
Paul Stewart91a43cb2013-03-02 21:34:15 -0800493 metrics_->SendEnumToUMA(
494 Metrics::kMetricVpnUserAuthenticationType,
495 Metrics::kVpnUserAuthenticationTypeL2tpIpsecCertificate,
496 Metrics::kMetricVpnUserAuthenticationTypeMax);
497 has_user_authentication = true;
498 }
Ben Chan73728782013-09-20 13:40:54 -0700499 if (args()->LookupString(kL2tpIpsecPasswordProperty, "") != "") {
Paul Stewart91a43cb2013-03-02 21:34:15 -0800500 metrics_->SendEnumToUMA(
501 Metrics::kMetricVpnUserAuthenticationType,
502 Metrics::kVpnUserAuthenticationTypeL2tpIpsecUsernamePassword,
503 Metrics::kMetricVpnUserAuthenticationTypeMax);
504 has_user_authentication = true;
505 }
506 if (!has_user_authentication) {
507 metrics_->SendEnumToUMA(
508 Metrics::kMetricVpnUserAuthenticationType,
509 Metrics::kVpnUserAuthenticationTypeL2tpIpsecNone,
510 Metrics::kMetricVpnUserAuthenticationTypeMax);
511 }
512}
513
Darin Petkov7476a262012-04-12 16:30:46 +0200514} // namespace shill