1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2012 The Android Open Source Project
3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Licensed under the Apache License, Version 2.0 (the "License");
5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// you may not use this file except in compliance with the License.
6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// You may obtain a copy of the License at
7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//      http://www.apache.org/licenses/LICENSE-2.0
9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Unless required by applicable law or agreed to in writing, software
11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// distributed under the License is distributed on an "AS IS" BASIS,
12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// See the License for the specific language governing permissions and
14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// limitations under the License.
15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
167476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov
175bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// The term "L2TP / IPSec" refers to a pair of layered protocols used
185bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// together to establish a tunneled VPN connection.  First, an "IPSec"
195bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// link is created, which secures a single IP traffic pair between the
205bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// client and server.  For this link to complete, one or two levels of
215bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// authentication are performed.  The first, inner mandatory authentication
225bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// ensures the two parties establishing the IPSec link are correct.  This
235bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// can use a certificate exchange or a less secure "shared group key"
245bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// (PSK) authentication.  An optional outer IPSec authentication can also be
255bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// performed, which is not fully supported by shill's implementation.
265bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// In order to support "tunnel groups" from some vendor VPNs shill supports
275bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// supplying the authentication realm portion during the outer authentication.
285bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// Notably, XAUTH and other forms of user authentication on this outer link
295bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// are not supported.
305bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart//
315bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// When IPSec authentication completes, traffic is tunneled through a
325bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// layer 2 tunnel, called "L2TP".  Using the secured link, we tunnel a
335bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// PPP link, through which a second layer of authentication is performed,
345bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart// using the provided "user" and "password" properties.
355bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart
362240e8c03451c6b6f21eb8944d8a1c0747ac10b3Ben Chan#include "shill/vpn/l2tp_ipsec_driver.h"
377476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov
386999022029507e90bc8a032b85e87ef83d2c4d1dDarin Petkov#include <base/bind.h>
3911c213f3cf64f27a0e42ee6da95e98bd1d4b3202Ben Chan#include <base/files/file_util.h>
40a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/string_util.h>
41fca1a04aac5f5817e9e681567716826821c9790dSteve Fung#include <base/strings/stringprintf.h>
42289a5a5e18bb1a676b3dfce111af4c2c00c7776eSamuel Tan#if defined(__ANDROID__)
43289a5a5e18bb1a676b3dfce111af4c2c00c7776eSamuel Tan#include <dbus/service_constants.h>
44289a5a5e18bb1a676b3dfce111af4c2c00c7776eSamuel Tan#else
457476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov#include <chromeos/dbus/service_constants.h>
46289a5a5e18bb1a676b3dfce111af4c2c00c7776eSamuel Tan#endif  // __ANDROID__
47ef342b4400ad2338d3caf8f30ae06ba9f9fa4d77Liam McLoughlin#include <vpn-manager/service_error.h>
487476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov
495baebb73bd597f5896b43d38e8ed3447680f47f4Paul Stewart#include "shill/certificate_file.h"
50f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov#include "shill/device_info.h"
51f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov#include "shill/error.h"
52ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawal#include "shill/external_task.h"
5334628593c4c51e8f1d393d6a03e3ebf06e4d9979Paul Stewart#include "shill/ipconfig.h"
54b691efd71561246065eae3cdd73a96ca1b8a528dChristopher Wiley#include "shill/logging.h"
55f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov#include "shill/manager.h"
56cb832e8df5f61b223de86a9d4204c86f1e7d9c36Garret Kelly#include "shill/ppp_daemon.h"
579da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal#include "shill/ppp_device.h"
582e38263961190298d7198058ed91649dee106257mukesh agrawal#include "shill/ppp_device_factory.h"
59a24480aaca4d392d6d08cebdc508ee49615839d3Peter Qiu#include "shill/process_manager.h"
602240e8c03451c6b6f21eb8944d8a1c0747ac10b3Ben Chan#include "shill/vpn/vpn_service.h"
61f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
626999022029507e90bc8a032b85e87ef83d2c4d1dDarin Petkovusing base::Bind;
635a850476dd0d049fa07e54015430c4d19d3d6ae8Darin Petkovusing base::Closure;
640e1cdeae24dd678a5fe27c840802582c0ca45ec0Albert Chaulkusing base::FilePath;
65209e629754acc6807fd5deff888bf4521867f68dDarin Petkovusing std::map;
667476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkovusing std::string;
67f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovusing std::vector;
687476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov
697476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkovnamespace shill {
707476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov
71c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinnamespace Logging {
72c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinstatic auto kModuleLogScope = ScopeLogger::kVPN;
73e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewartstatic string ObjectID(L2TPIPSecDriver* l) {
74c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  return l->GetServiceRpcIdentifier();
75c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein}
76c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein}
77c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein
78f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovnamespace {
79f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovconst char kL2TPIPSecIPSecTimeoutProperty[] = "L2TPIPsec.IPsecTimeout";
80f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovconst char kL2TPIPSecLeftProtoPortProperty[] = "L2TPIPsec.LeftProtoPort";
81f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovconst char kL2TPIPSecLengthBitProperty[] = "L2TPIPsec.LengthBit";
82f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovconst char kL2TPIPSecPFSProperty[] = "L2TPIPsec.PFS";
83f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovconst char kL2TPIPSecRefusePapProperty[] = "L2TPIPsec.RefusePap";
84f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovconst char kL2TPIPSecRekeyProperty[] = "L2TPIPsec.Rekey";
85f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovconst char kL2TPIPSecRequireAuthProperty[] = "L2TPIPsec.RequireAuth";
86f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovconst char kL2TPIPSecRequireChapProperty[] = "L2TPIPsec.RequireChap";
87f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovconst char kL2TPIPSecRightProtoPortProperty[] = "L2TPIPsec.RightProtoPort";
88f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov}  // namespace
89f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
90f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov// static
91209e629754acc6807fd5deff888bf4521867f68dDarin Petkovconst char L2TPIPSecDriver::kL2TPIPSecVPNPath[] = "/usr/sbin/l2tpipsec_vpn";
92d432539fc85363734b2c60290822054087b6c82bDarin Petkov// static
93d432539fc85363734b2c60290822054087b6c82bDarin Petkovconst VPNDriver::Property L2TPIPSecDriver::kProperties[] = {
947372878af066cc079ad88a7b004ca3f769952de2Ben Chan  { kL2tpIpsecAuthenticationType, 0 },
957372878af066cc079ad88a7b004ca3f769952de2Ben Chan  { kL2tpIpsecCaCertNssProperty, 0 },
967372878af066cc079ad88a7b004ca3f769952de2Ben Chan  { kL2tpIpsecClientCertIdProperty, 0 },
977372878af066cc079ad88a7b004ca3f769952de2Ben Chan  { kL2tpIpsecClientCertSlotProperty, 0 },
987372878af066cc079ad88a7b004ca3f769952de2Ben Chan  { kL2tpIpsecIkeVersion, 0 },
997372878af066cc079ad88a7b004ca3f769952de2Ben Chan  { kL2tpIpsecPasswordProperty, Property::kCredential | Property::kWriteOnly },
1007372878af066cc079ad88a7b004ca3f769952de2Ben Chan  { kL2tpIpsecPinProperty, Property::kCredential },
101a7109d354b49f747a81bd9c87aa199336b7081d5Paul Stewart  { kL2tpIpsecPskProperty, Property::kCredential | Property::kWriteOnly },
1027372878af066cc079ad88a7b004ca3f769952de2Ben Chan  { kL2tpIpsecUserProperty, 0 },
1037372878af066cc079ad88a7b004ca3f769952de2Ben Chan  { kProviderHostProperty, 0 },
1047372878af066cc079ad88a7b004ca3f769952de2Ben Chan  { kProviderTypeProperty, 0 },
105eb713e8da9f6c97f3ac2218edef8d190ca4f99b0Paul Stewart  { kL2tpIpsecCaCertPemProperty, Property::kArray },
1065bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart  { kL2tpIpsecTunnelGroupProperty, 0 },
107d432539fc85363734b2c60290822054087b6c82bDarin Petkov  { kL2TPIPSecIPSecTimeoutProperty, 0 },
108d432539fc85363734b2c60290822054087b6c82bDarin Petkov  { kL2TPIPSecLeftProtoPortProperty, 0 },
109d432539fc85363734b2c60290822054087b6c82bDarin Petkov  { kL2TPIPSecLengthBitProperty, 0 },
110d432539fc85363734b2c60290822054087b6c82bDarin Petkov  { kL2TPIPSecPFSProperty, 0 },
111d432539fc85363734b2c60290822054087b6c82bDarin Petkov  { kL2TPIPSecRefusePapProperty, 0 },
112d432539fc85363734b2c60290822054087b6c82bDarin Petkov  { kL2TPIPSecRekeyProperty, 0 },
113d432539fc85363734b2c60290822054087b6c82bDarin Petkov  { kL2TPIPSecRequireAuthProperty, 0 },
114d432539fc85363734b2c60290822054087b6c82bDarin Petkov  { kL2TPIPSecRequireChapProperty, 0 },
115d432539fc85363734b2c60290822054087b6c82bDarin Petkov  { kL2TPIPSecRightProtoPortProperty, 0 },
116a7109d354b49f747a81bd9c87aa199336b7081d5Paul Stewart  { kL2tpIpsecXauthUserProperty, Property::kCredential | Property::kWriteOnly },
117a7109d354b49f747a81bd9c87aa199336b7081d5Paul Stewart  { kL2tpIpsecXauthPasswordProperty,
118a7109d354b49f747a81bd9c87aa199336b7081d5Paul Stewart    Property::kCredential | Property::kWriteOnly },
119c062538b3440f566120e302aac70e527e1cf5b07Paul Stewart  { kL2tpIpsecLcpEchoDisabledProperty, 0 },
120d432539fc85363734b2c60290822054087b6c82bDarin Petkov};
121f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
122e42d186ab3383b4a6bb267f490770af5932588b8Paul StewartL2TPIPSecDriver::L2TPIPSecDriver(ControlInterface* control,
123e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewart                                 EventDispatcher* dispatcher,
124e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewart                                 Metrics* metrics,
125e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewart                                 Manager* manager,
126e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewart                                 DeviceInfo* device_info,
127a24480aaca4d392d6d08cebdc508ee49615839d3Peter Qiu                                 ProcessManager* process_manager)
128602303fdc8e4a50c8f89bc7e1048a4b5438555bfDarin Petkov    : VPNDriver(dispatcher, manager, kProperties, arraysize(kProperties)),
129b451d6e5b5deb3a42ac09c3db349f325e4c8004eDarin Petkov      control_(control),
130f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov      metrics_(metrics),
131f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov      device_info_(device_info),
132a24480aaca4d392d6d08cebdc508ee49615839d3Peter Qiu      process_manager_(process_manager),
1332e38263961190298d7198058ed91649dee106257mukesh agrawal      ppp_device_factory_(PPPDeviceFactory::GetInstance()),
134eb713e8da9f6c97f3ac2218edef8d190ca4f99b0Paul Stewart      certificate_file_(new CertificateFile()),
135ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawal      weak_ptr_factory_(this) {}
1367476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov
137209e629754acc6807fd5deff888bf4521867f68dDarin PetkovL2TPIPSecDriver::~L2TPIPSecDriver() {
13885d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov  IdleService();
139209e629754acc6807fd5deff888bf4521867f68dDarin Petkov}
1407476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov
141c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinstd::string L2TPIPSecDriver::GetServiceRpcIdentifier() {
142c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  if (service_ == nullptr)
143c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    return "(l2tp_ipsec_driver)";
144c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  return service_->GetRpcIdentifier();
145c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein}
146c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein
147e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewartbool L2TPIPSecDriver::ClaimInterface(const string& link_name,
1487476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov                                     int interface_index) {
149ee6b3d7f9d49fa52072a352fbb59f06127b1ba4cPaul Stewart  // TODO(petkov): crbug.com/212446.
1507476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov  NOTIMPLEMENTED();
1517476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov  return false;
1527476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov}
1537476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov
154e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewartvoid L2TPIPSecDriver::Connect(const VPNServiceRefPtr& service, Error* error) {
1550cd0d1e07270b05016b29cd7c9d6f4c5440fb078Darin Petkov  StartConnectTimeout(kDefaultConnectTimeoutSeconds);
156209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  service_ = service;
157209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  service_->SetState(Service::kStateConfiguring);
158209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  if (!SpawnL2TPIPSecVPN(error)) {
1591c049c794175356e5b6c2b6bbb5ef4a12fbfe9a3Darin Petkov    FailService(Service::kFailureInternal);
160209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  }
1617476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov}
1627476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov
1637476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkovvoid L2TPIPSecDriver::Disconnect() {
164c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
16585d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov  IdleService();
1667476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov}
1677476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov
1685eb0542cb67358d9030367498a4ad741fc42af4fDarin Petkovvoid L2TPIPSecDriver::OnConnectionDisconnected() {
169a42afe3a1621b8262d5404ecfaf200d3d76bd454Darin Petkov  LOG(INFO) << "Underlying connection disconnected.";
17085d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov  IdleService();
171a42afe3a1621b8262d5404ecfaf200d3d76bd454Darin Petkov}
172a42afe3a1621b8262d5404ecfaf200d3d76bd454Darin Petkov
173a42afe3a1621b8262d5404ecfaf200d3d76bd454Darin Petkovvoid L2TPIPSecDriver::OnConnectTimeout() {
174a42afe3a1621b8262d5404ecfaf200d3d76bd454Darin Petkov  VPNDriver::OnConnectTimeout();
17585d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov  FailService(Service::kFailureConnect);
1765eb0542cb67358d9030367498a4ad741fc42af4fDarin Petkov}
1775eb0542cb67358d9030367498a4ad741fc42af4fDarin Petkov
1787476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkovstring L2TPIPSecDriver::GetProviderType() const {
1797372878af066cc079ad88a7b004ca3f769952de2Ben Chan  return kProviderL2tpIpsec;
1807476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov}
1817476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov
18285d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkovvoid L2TPIPSecDriver::IdleService() {
18385d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov  Cleanup(Service::kStateIdle, Service::kFailureUnknown);
18485d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov}
18585d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov
18685d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkovvoid L2TPIPSecDriver::FailService(Service::ConnectFailure failure) {
18785d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov  Cleanup(Service::kStateFailure, failure);
18885d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov}
18985d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov
19085d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkovvoid L2TPIPSecDriver::Cleanup(Service::ConnectState state,
19185d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov                              Service::ConnectFailure failure) {
192c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__ << "("
193c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << Service::ConnectStateToString(state) << ", "
194c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein                << Service::ConnectFailureToString(failure) << ")";
195602303fdc8e4a50c8f89bc7e1048a4b5438555bfDarin Petkov  StopConnectTimeout();
1963f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  DeleteTemporaryFiles();
197ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawal  external_task_.reset();
198f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  if (device_) {
1999da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal    device_->DropConnection();
200f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    device_->SetEnabled(false);
2014168b2c8d57755ea6b16763745379e0529541a3fBen Chan    device_ = nullptr;
202f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  }
203209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  if (service_) {
20485d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    if (state == Service::kStateFailure) {
20585d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov      service_->SetFailure(failure);
20685d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    } else {
20785d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov      service_->SetState(state);
20885d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    }
2094168b2c8d57755ea6b16763745379e0529541a3fBen Chan    service_ = nullptr;
210209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  }
211209e629754acc6807fd5deff888bf4521867f68dDarin Petkov}
212209e629754acc6807fd5deff888bf4521867f68dDarin Petkov
213e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewartvoid L2TPIPSecDriver::DeleteTemporaryFile(base::FilePath* temporary_file) {
2143f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  if (!temporary_file->empty()) {
215a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan    base::DeleteFile(*temporary_file, false);
2163f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart    temporary_file->clear();
2170e9735db6db73a48c4b0cc3151a5272e3a8b9d2fDarin Petkov  }
2180e9735db6db73a48c4b0cc3151a5272e3a8b9d2fDarin Petkov}
2190e9735db6db73a48c4b0cc3151a5272e3a8b9d2fDarin Petkov
2203f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewartvoid L2TPIPSecDriver::DeleteTemporaryFiles() {
2213f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  DeleteTemporaryFile(&psk_file_);
2223f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  DeleteTemporaryFile(&xauth_credentials_file_);
2233f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart}
2243f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart
225e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewartbool L2TPIPSecDriver::SpawnL2TPIPSecVPN(Error* error) {
226c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
227d5dce94ec196e160c0d4bfeeb5ab8d4eb021ef15Ben Chan  std::unique_ptr<ExternalTask> external_task_local(
228a24480aaca4d392d6d08cebdc508ee49615839d3Peter Qiu      new ExternalTask(control_,
229a24480aaca4d392d6d08cebdc508ee49615839d3Peter Qiu                       process_manager_,
230ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawal                       weak_ptr_factory_.GetWeakPtr(),
231ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawal                       Bind(&L2TPIPSecDriver::OnL2TPIPSecVPNDied,
232ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawal                            weak_ptr_factory_.GetWeakPtr())));
233209e629754acc6807fd5deff888bf4521867f68dDarin Petkov
234209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  vector<string> options;
235ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawal  map<string, string> environment;  // No env vars passed.
236209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  if (!InitOptions(&options, error)) {
237209e629754acc6807fd5deff888bf4521867f68dDarin Petkov    return false;
238209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  }
2393a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko  LOG(INFO) << "L2TP/IPSec VPN process options: "
2403a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko            << base::JoinString(options, " ");
241209e629754acc6807fd5deff888bf4521867f68dDarin Petkov
242ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawal  if (external_task_local->Start(
243c4f9aa0e795b6f79c628a763831d4dc6c01fb72bmukesh agrawal          FilePath(kL2TPIPSecVPNPath), options, environment, true, error)) {
244d5dce94ec196e160c0d4bfeeb5ab8d4eb021ef15Ben Chan    external_task_ = std::move(external_task_local);
245ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawal    return true;
246209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  }
247ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawal  return false;
248f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov}
249f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
250e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewartbool L2TPIPSecDriver::InitOptions(vector<string>* options, Error* error) {
2517372878af066cc079ad88a7b004ca3f769952de2Ben Chan  string vpnhost = args()->LookupString(kProviderHostProperty, "");
252f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  if (vpnhost.empty()) {
253f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov    Error::PopulateAndLog(
25434f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart        FROM_HERE, error, Error::kInvalidArguments, "VPN host not specified.");
255209e629754acc6807fd5deff888bf4521867f68dDarin Petkov    return false;
256f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  }
257f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
258f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  if (!InitPSKOptions(options, error)) {
259209e629754acc6807fd5deff888bf4521867f68dDarin Petkov    return false;
260f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  }
261f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
2623f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  if (!InitXauthOptions(options, error)) {
2633f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart    return false;
2643f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  }
2653f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart
266fca1a04aac5f5817e9e681567716826821c9790dSteve Fung  options->push_back(base::StringPrintf("--remote_host=%s", vpnhost.c_str()));
267fca1a04aac5f5817e9e681567716826821c9790dSteve Fung  options->push_back(base::StringPrintf("--pppd_plugin=%s",
2681e8414cbca190baa946388ede87a0b417c1f3d95Garret Kelly                                        PPPDaemon::kShimPluginPath));
269f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  // Disable pppd from configuring IP addresses, routes, DNS.
270f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  options->push_back("--nosystemconfig");
271f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
272c350e68360d08626cff8c4020c743b61d7da5a2bPaul Stewart  // Accept a PEM CA certificate.
273c350e68360d08626cff8c4020c743b61d7da5a2bPaul Stewart  InitPEMOptions(options);
274f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
2757372878af066cc079ad88a7b004ca3f769952de2Ben Chan  AppendValueOption(kL2tpIpsecClientCertIdProperty,
276f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov                    "--client_cert_id", options);
2777372878af066cc079ad88a7b004ca3f769952de2Ben Chan  AppendValueOption(kL2tpIpsecClientCertSlotProperty,
278f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov                    "--client_cert_slot", options);
2797372878af066cc079ad88a7b004ca3f769952de2Ben Chan  AppendValueOption(kL2tpIpsecPinProperty, "--user_pin", options);
2807372878af066cc079ad88a7b004ca3f769952de2Ben Chan  AppendValueOption(kL2tpIpsecUserProperty, "--user", options);
281f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  AppendValueOption(kL2TPIPSecIPSecTimeoutProperty, "--ipsec_timeout", options);
282f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  AppendValueOption(kL2TPIPSecLeftProtoPortProperty,
283f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov                    "--leftprotoport", options);
284f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  AppendFlag(kL2TPIPSecPFSProperty, "--pfs", "--nopfs", options);
285f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  AppendFlag(kL2TPIPSecRekeyProperty, "--rekey", "--norekey", options);
286f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  AppendValueOption(kL2TPIPSecRightProtoPortProperty,
287f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov                    "--rightprotoport", options);
288f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  AppendFlag(kL2TPIPSecRequireChapProperty,
289f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov             "--require_chap", "--norequire_chap", options);
290f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  AppendFlag(kL2TPIPSecRefusePapProperty,
291f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov             "--refuse_pap", "--norefuse_pap", options);
292f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  AppendFlag(kL2TPIPSecRequireAuthProperty,
293f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov             "--require_authentication", "--norequire_authentication", options);
294f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  AppendFlag(kL2TPIPSecLengthBitProperty,
295f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov             "--length_bit", "--nolength_bit", options);
296c062538b3440f566120e302aac70e527e1cf5b07Paul Stewart  AppendFlag(kL2tpIpsecLcpEchoDisabledProperty,
297c062538b3440f566120e302aac70e527e1cf5b07Paul Stewart             "--noppp_lcp_echo", "--ppp_lcp_echo", options);
2985bbf93bb7049fa216983763cae3b51e552edd36dPaul Stewart  AppendValueOption(kL2tpIpsecTunnelGroupProperty, "--tunnel_group", options);
299209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  if (SLOG_IS_ON(VPN, 0)) {
300209e629754acc6807fd5deff888bf4521867f68dDarin Petkov    options->push_back("--debug");
301209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  }
302209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  return true;
303f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov}
304f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
305e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewartbool L2TPIPSecDriver::InitPSKOptions(vector<string>* options, Error* error) {
3067372878af066cc079ad88a7b004ca3f769952de2Ben Chan  string psk = args()->LookupString(kL2tpIpsecPskProperty, "");
307f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  if (!psk.empty()) {
308a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan    if (!base::CreateTemporaryFileInDir(manager()->run_path(), &psk_file_) ||
309f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov        chmod(psk_file_.value().c_str(), S_IRUSR | S_IWUSR) ||
3106fbf64f493a9aae7d743888039c61a57386203dbBen Chan        base::WriteFile(psk_file_, psk.data(), psk.size()) !=
311a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan            static_cast<int>(psk.size())) {
312f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov      Error::PopulateAndLog(
31334f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart          FROM_HERE, error, Error::kInternalError, "Unable to setup psk file.");
314f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov      return false;
315f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov    }
316fca1a04aac5f5817e9e681567716826821c9790dSteve Fung    options->push_back(base::StringPrintf("--psk_file=%s",
317fca1a04aac5f5817e9e681567716826821c9790dSteve Fung                                          psk_file_.value().c_str()));
318f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  }
319f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  return true;
320f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov}
321f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
322e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewartbool L2TPIPSecDriver::InitPEMOptions(vector<string>* options) {
323eb713e8da9f6c97f3ac2218edef8d190ca4f99b0Paul Stewart  vector<string> ca_certs;
324eb713e8da9f6c97f3ac2218edef8d190ca4f99b0Paul Stewart  if (args()->ContainsStrings(kL2tpIpsecCaCertPemProperty)) {
325eb713e8da9f6c97f3ac2218edef8d190ca4f99b0Paul Stewart    ca_certs = args()->GetStrings(kL2tpIpsecCaCertPemProperty);
326eb713e8da9f6c97f3ac2218edef8d190ca4f99b0Paul Stewart  }
327eb713e8da9f6c97f3ac2218edef8d190ca4f99b0Paul Stewart  if (ca_certs.empty()) {
3285baebb73bd597f5896b43d38e8ed3447680f47f4Paul Stewart    return false;
3295baebb73bd597f5896b43d38e8ed3447680f47f4Paul Stewart  }
330eb713e8da9f6c97f3ac2218edef8d190ca4f99b0Paul Stewart  FilePath certfile = certificate_file_->CreatePEMFromStrings(ca_certs);
3315baebb73bd597f5896b43d38e8ed3447680f47f4Paul Stewart  if (certfile.empty()) {
332eb713e8da9f6c97f3ac2218edef8d190ca4f99b0Paul Stewart    LOG(ERROR) << "Unable to extract certificates from PEM string.";
3335baebb73bd597f5896b43d38e8ed3447680f47f4Paul Stewart    return false;
3345baebb73bd597f5896b43d38e8ed3447680f47f4Paul Stewart  }
335fca1a04aac5f5817e9e681567716826821c9790dSteve Fung  options->push_back(base::StringPrintf("--server_ca_file=%s",
336fca1a04aac5f5817e9e681567716826821c9790dSteve Fung                                        certfile.value().c_str()));
3375baebb73bd597f5896b43d38e8ed3447680f47f4Paul Stewart  return true;
3385baebb73bd597f5896b43d38e8ed3447680f47f4Paul Stewart}
3395baebb73bd597f5896b43d38e8ed3447680f47f4Paul Stewart
340e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewartbool L2TPIPSecDriver::InitXauthOptions(vector<string>* options, Error* error) {
3413f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  string user = args()->LookupString(kL2tpIpsecXauthUserProperty, "");
3423f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  string password = args()->LookupString(kL2tpIpsecXauthPasswordProperty, "");
3433f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  if (user.empty() && password.empty()) {
3443f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart    // Xauth credentials not configured.
3453f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart    return true;
3463f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  }
3473f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  if (user.empty() || password.empty()) {
3483f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart      Error::PopulateAndLog(
34934f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart          FROM_HERE, error, Error::kInvalidArguments,
3503f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart          "XAUTH credentials are partially configured.");
3513f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart    return false;
3523f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  }
3533f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  string xauth_credentials = user + "\n" + password + "\n";
354a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan  if (!base::CreateTemporaryFileInDir(manager()->run_path(),
355a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan                                      &xauth_credentials_file_) ||
3563f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart      chmod(xauth_credentials_file_.value().c_str(), S_IRUSR | S_IWUSR) ||
3576fbf64f493a9aae7d743888039c61a57386203dbBen Chan      base::WriteFile(xauth_credentials_file_, xauth_credentials.data(),
3586fbf64f493a9aae7d743888039c61a57386203dbBen Chan                      xauth_credentials.size()) !=
3593f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart          static_cast<int>(xauth_credentials.size())) {
3603f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart    Error::PopulateAndLog(
36134f424e672439bdf237a755f85245ebd7b66e8e2Paul Stewart        FROM_HERE, error, Error::kInternalError,
3623f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart        "Unable to setup XAUTH credentials file.");
3633f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart    return false;
3643f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  }
365fca1a04aac5f5817e9e681567716826821c9790dSteve Fung  options->push_back(base::StringPrintf("--xauth_credentials_file=%s",
366fca1a04aac5f5817e9e681567716826821c9790dSteve Fung                         xauth_credentials_file_.value().c_str()));
3673f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  return true;
3683f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart}
3693f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart
370f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkovbool L2TPIPSecDriver::AppendValueOption(
371e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewart    const string& property, const string& option, vector<string>* options) {
37201c6604021f3a47813c3dc98d3a5c3d1d45b5bccDarin Petkov  string value = args()->LookupString(property, "");
373f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  if (!value.empty()) {
374fca1a04aac5f5817e9e681567716826821c9790dSteve Fung    options->push_back(base::StringPrintf("%s=%s", option.c_str(),
375fca1a04aac5f5817e9e681567716826821c9790dSteve Fung                                          value.c_str()));
376f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov    return true;
377f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  }
378f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  return false;
379f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov}
380f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
381e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewartbool L2TPIPSecDriver::AppendFlag(const string& property,
382e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewart                                 const string& true_option,
383e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewart                                 const string& false_option,
384e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewart                                 vector<string>* options) {
38501c6604021f3a47813c3dc98d3a5c3d1d45b5bccDarin Petkov  string value = args()->LookupString(property, "");
386f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  if (!value.empty()) {
387f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov    options->push_back(value == "true" ? true_option : false_option);
388f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov    return true;
389f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  }
390f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov  return false;
391f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov}
392f7ef50a6054414c446f891fa87401e6f0a00097fDarin Petkov
393ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawalvoid L2TPIPSecDriver::OnL2TPIPSecVPNDied(pid_t /*pid*/, int status) {
394ae30e9e4f9050a5a2c3b18d20f8bd23f20aa8f38mukesh agrawal  FailService(TranslateExitStatusToFailure(status));
395209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  // TODO(petkov): Figure if we need to restart the connection.
396209e629754acc6807fd5deff888bf4521867f68dDarin Petkov}
397209e629754acc6807fd5deff888bf4521867f68dDarin Petkov
39885d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov// static
39985d5317bed668c1fb0e4225de614c7b386e3de25Darin PetkovService::ConnectFailure L2TPIPSecDriver::TranslateExitStatusToFailure(
40085d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    int status) {
40185d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov  if (!WIFEXITED(status)) {
4021c049c794175356e5b6c2b6bbb5ef4a12fbfe9a3Darin Petkov    return Service::kFailureInternal;
40385d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov  }
40485d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov  switch (WEXITSTATUS(status)) {
40585d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    case vpn_manager::kServiceErrorResolveHostnameFailed:
40685d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov      return Service::kFailureDNSLookup;
40785d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    case vpn_manager::kServiceErrorIpsecConnectionFailed:
40885d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    case vpn_manager::kServiceErrorL2tpConnectionFailed:
40985d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    case vpn_manager::kServiceErrorPppConnectionFailed:
41085d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov      return Service::kFailureConnect;
41185d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    case vpn_manager::kServiceErrorIpsecPresharedKeyAuthenticationFailed:
41285d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov      return Service::kFailureIPSecPSKAuth;
41385d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    case vpn_manager::kServiceErrorIpsecCertificateAuthenticationFailed:
41485d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov      return Service::kFailureIPSecCertAuth;
41585d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    case vpn_manager::kServiceErrorPppAuthenticationFailed:
41685d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov      return Service::kFailurePPPAuth;
41785d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    default:
41885d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov      break;
41985d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov  }
42085d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov  return Service::kFailureUnknown;
42185d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov}
42285d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov
423e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewartvoid L2TPIPSecDriver::GetLogin(string* user, string* password) {
424602303fdc8e4a50c8f89bc7e1048a4b5438555bfDarin Petkov  LOG(INFO) << "Login requested.";
425209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  string user_property =
4267372878af066cc079ad88a7b004ca3f769952de2Ben Chan      args()->LookupString(kL2tpIpsecUserProperty, "");
427209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  if (user_property.empty()) {
428209e629754acc6807fd5deff888bf4521867f68dDarin Petkov    LOG(ERROR) << "User not set.";
429209e629754acc6807fd5deff888bf4521867f68dDarin Petkov    return;
430209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  }
431209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  string password_property =
4327372878af066cc079ad88a7b004ca3f769952de2Ben Chan      args()->LookupString(kL2tpIpsecPasswordProperty, "");
433209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  if (password_property.empty()) {
434209e629754acc6807fd5deff888bf4521867f68dDarin Petkov    LOG(ERROR) << "Password not set.";
435209e629754acc6807fd5deff888bf4521867f68dDarin Petkov    return;
436209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  }
437209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  *user = user_property;
438209e629754acc6807fd5deff888bf4521867f68dDarin Petkov  *password = password_property;
439209e629754acc6807fd5deff888bf4521867f68dDarin Petkov}
440209e629754acc6807fd5deff888bf4521867f68dDarin Petkov
441209e629754acc6807fd5deff888bf4521867f68dDarin Petkovvoid L2TPIPSecDriver::Notify(
442e42d186ab3383b4a6bb267f490770af5932588b8Paul Stewart    const string& reason, const map<string, string>& dict) {
443602303fdc8e4a50c8f89bc7e1048a4b5438555bfDarin Petkov  LOG(INFO) << "IP configuration received: " << reason;
4440e9735db6db73a48c4b0cc3151a5272e3a8b9d2fDarin Petkov
44516de98cbcfdf89e9ee6c9fe29a0f46341ecfb9a4Paul Stewart  if (reason == kPPPReasonAuthenticating ||
44616de98cbcfdf89e9ee6c9fe29a0f46341ecfb9a4Paul Stewart      reason == kPPPReasonAuthenticated) {
44716de98cbcfdf89e9ee6c9fe29a0f46341ecfb9a4Paul Stewart    // These are uninteresting intermediate states that do not indicate failure.
44816de98cbcfdf89e9ee6c9fe29a0f46341ecfb9a4Paul Stewart    return;
44916de98cbcfdf89e9ee6c9fe29a0f46341ecfb9a4Paul Stewart  }
45016de98cbcfdf89e9ee6c9fe29a0f46341ecfb9a4Paul Stewart
4519da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal  if (reason != kPPPReasonConnect) {
4529da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal    DCHECK_EQ(kPPPReasonDisconnect, reason);
4539da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal    // DestroyLater, rather than while on stack.
4549da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal    external_task_.release()->DestroyLater(dispatcher());
45585d5317bed668c1fb0e4225de614c7b386e3de25Darin Petkov    FailService(Service::kFailureUnknown);
4560e9735db6db73a48c4b0cc3151a5272e3a8b9d2fDarin Petkov    return;
4570e9735db6db73a48c4b0cc3151a5272e3a8b9d2fDarin Petkov  }
4580e9735db6db73a48c4b0cc3151a5272e3a8b9d2fDarin Petkov
4593f71326c17aa63e13343d06cbdc8ee0a2cbac3d7Paul Stewart  DeleteTemporaryFiles();
460f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov
4619da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal  string interface_name = PPPDevice::GetInterfaceName(dict);
462f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  int interface_index = device_info_->GetIndex(interface_name);
463f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  if (interface_index < 0) {
464f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    // TODO(petkov): Consider handling the race when the RTNL notification about
465f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    // the new PPP device has not been received yet. We can keep the IP
466f8f970a33a751ccdbe6d058879aade2b0a9ad2cdDarin Petkov    // configuration and apply it when ClaimInterface is
467ee6b3d7f9d49fa52072a352fbb59f06127b1ba4cPaul Stewart    // invoked. crbug.com/212446.
468f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    NOTIMPLEMENTED() << ": No device info for " << interface_name << ".";
469f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov    return;
470f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  }
471f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov
4729da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal  // There is no IPv6 support for L2TP/IPsec VPN at this moment, so create a
4739da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal  // blackhole route for IPv6 traffic after establishing a IPv4 VPN.
4749da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal  // TODO(benchan): Generalize this when IPv6 support is added.
4759da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal  bool blackhole_ipv6 = true;
4769da07771df3dbbc99ff99114c26317d01f29f7fcmukesh agrawal
477f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  if (!device_) {
4782e38263961190298d7198058ed91649dee106257mukesh agrawal    device_ = ppp_device_factory_->CreatePPPDevice(
4792e38263961190298d7198058ed91649dee106257mukesh agrawal        control_, dispatcher(), metrics_, manager(), interface_name,
4802e38263961190298d7198058ed91649dee106257mukesh agrawal        interface_index);
481f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  }
482f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  device_->SetEnabled(true);
483f8046b8f975417255baf5cc7cdd025c63aa2f918Darin Petkov  device_->SelectService(service_);
48434628593c4c51e8f1d393d6a03e3ebf06e4d9979Paul Stewart
48534628593c4c51e8f1d393d6a03e3ebf06e4d9979Paul Stewart  // Reduce MTU to the minimum viable for IPv6, since the IPSec layer consumes
48634628593c4c51e8f1d393d6a03e3ebf06e4d9979Paul Stewart  // some variable portion of the payload.  Although this system does not yet
48734628593c4c51e8f1d393d6a03e3ebf06e4d9979Paul Stewart  // support IPv6, it is a reasonable value to start with, since the minimum
48834628593c4c51e8f1d393d6a03e3ebf06e4d9979Paul Stewart  // IPv6 packet size will plausibly be a size any gateway would support, and
48934628593c4c51e8f1d393d6a03e3ebf06e4d9979Paul Stewart  // is also larger than the IPv4 minimum size.
49034628593c4c51e8f1d393d6a03e3ebf06e4d9979Paul Stewart  device_->UpdateIPConfigFromPPPWithMTU(
49134628593c4c51e8f1d393d6a03e3ebf06e4d9979Paul Stewart      dict, blackhole_ipv6, IPConfig::kMinIPv6MTU);
49234628593c4c51e8f1d393d6a03e3ebf06e4d9979Paul Stewart
49391a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  ReportConnectionMetrics();
494602303fdc8e4a50c8f89bc7e1048a4b5438555bfDarin Petkov  StopConnectTimeout();
495209e629754acc6807fd5deff888bf4521867f68dDarin Petkov}
496209e629754acc6807fd5deff888bf4521867f68dDarin Petkov
497ba8f141693168a9613b1f86de0d6bf6ae4057e9cPaul Stewartbool L2TPIPSecDriver::IsPskRequired() const {
498ba8f141693168a9613b1f86de0d6bf6ae4057e9cPaul Stewart  return
499ba8f141693168a9613b1f86de0d6bf6ae4057e9cPaul Stewart    const_args()->LookupString(kL2tpIpsecPskProperty, "").empty() &&
500ba8f141693168a9613b1f86de0d6bf6ae4057e9cPaul Stewart    const_args()->LookupString(kL2tpIpsecClientCertIdProperty, "").empty();
501ba8f141693168a9613b1f86de0d6bf6ae4057e9cPaul Stewart}
502ba8f141693168a9613b1f86de0d6bf6ae4057e9cPaul Stewart
503e42d186ab3383b4a6bb267f490770af5932588b8Paul StewartKeyValueStore L2TPIPSecDriver::GetProvider(Error* error) {
504c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein  SLOG(this, 2) << __func__;
505b536a74030880f4a4df0ad3d6c1380b0602446c6Darin Petkov  KeyValueStore props = VPNDriver::GetProvider(error);
5067372878af066cc079ad88a7b004ca3f769952de2Ben Chan  props.SetBool(kPassphraseRequiredProperty,
5077372878af066cc079ad88a7b004ca3f769952de2Ben Chan                args()->LookupString(kL2tpIpsecPasswordProperty, "").empty());
508ba8f141693168a9613b1f86de0d6bf6ae4057e9cPaul Stewart  props.SetBool(kL2tpIpsecPskRequiredProperty, IsPskRequired());
509b536a74030880f4a4df0ad3d6c1380b0602446c6Darin Petkov  return props;
510b536a74030880f4a4df0ad3d6c1380b0602446c6Darin Petkov}
511b536a74030880f4a4df0ad3d6c1380b0602446c6Darin Petkov
51291a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewartvoid L2TPIPSecDriver::ReportConnectionMetrics() {
51391a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  metrics_->SendEnumToUMA(
51491a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart      Metrics::kMetricVpnDriver,
51591a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart      Metrics::kVpnDriverL2tpIpsec,
51691a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart      Metrics::kMetricVpnDriverMax);
51791a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart
51891a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  // We output an enum for each of the authentication types specified,
51991a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  // even if more than one is set at the same time.
52091a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  bool has_remote_authentication = false;
5217372878af066cc079ad88a7b004ca3f769952de2Ben Chan  if (args()->LookupString(kL2tpIpsecPskProperty, "") != "") {
52291a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart    metrics_->SendEnumToUMA(
52391a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kMetricVpnRemoteAuthenticationType,
52491a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecPsk,
52591a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kMetricVpnRemoteAuthenticationTypeMax);
52691a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart    has_remote_authentication = true;
52791a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  }
52891a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  if (!has_remote_authentication) {
52991a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart    metrics_->SendEnumToUMA(
53091a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kMetricVpnRemoteAuthenticationType,
53191a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecDefault,
53291a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kMetricVpnRemoteAuthenticationTypeMax);
53391a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  }
53491a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart
53591a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  bool has_user_authentication = false;
5367372878af066cc079ad88a7b004ca3f769952de2Ben Chan  if (args()->LookupString(kL2tpIpsecClientCertIdProperty,
537e8e71da2bb8487f2ae78fbe38dc6e01cdc5ad1c9Paul Stewart                           "") != "") {
53891a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart    metrics_->SendEnumToUMA(
53991a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kMetricVpnUserAuthenticationType,
54091a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kVpnUserAuthenticationTypeL2tpIpsecCertificate,
54191a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kMetricVpnUserAuthenticationTypeMax);
54291a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart    has_user_authentication = true;
54391a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  }
5447372878af066cc079ad88a7b004ca3f769952de2Ben Chan  if (args()->LookupString(kL2tpIpsecPasswordProperty, "") != "") {
54591a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart    metrics_->SendEnumToUMA(
54691a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kMetricVpnUserAuthenticationType,
54791a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kVpnUserAuthenticationTypeL2tpIpsecUsernamePassword,
54891a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kMetricVpnUserAuthenticationTypeMax);
54991a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart    has_user_authentication = true;
55091a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  }
55191a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  if (!has_user_authentication) {
55291a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart    metrics_->SendEnumToUMA(
55391a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kMetricVpnUserAuthenticationType,
55491a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kVpnUserAuthenticationTypeL2tpIpsecNone,
55591a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart        Metrics::kMetricVpnUserAuthenticationTypeMax);
55691a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart  }
55791a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart}
55891a43cb5ddb565ed9e4abcaee2d5f9373250012aPaul Stewart
5597476a26345c7b36be98c1e14b5d54d00d823ce07Darin Petkov}  // namespace shill
560