Home | History | Annotate | Download | only in vpn
      1 //
      2 // Copyright (C) 2012 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 // The term "L2TP / IPSec" refers to a pair of layered protocols used
     18 // together to establish a tunneled VPN connection.  First, an "IPSec"
     19 // link is created, which secures a single IP traffic pair between the
     20 // client and server.  For this link to complete, one or two levels of
     21 // authentication are performed.  The first, inner mandatory authentication
     22 // ensures the two parties establishing the IPSec link are correct.  This
     23 // can use a certificate exchange or a less secure "shared group key"
     24 // (PSK) authentication.  An optional outer IPSec authentication can also be
     25 // performed, which is not fully supported by shill's implementation.
     26 // In order to support "tunnel groups" from some vendor VPNs shill supports
     27 // supplying the authentication realm portion during the outer authentication.
     28 // Notably, XAUTH and other forms of user authentication on this outer link
     29 // are not supported.
     30 //
     31 // When IPSec authentication completes, traffic is tunneled through a
     32 // layer 2 tunnel, called "L2TP".  Using the secured link, we tunnel a
     33 // PPP link, through which a second layer of authentication is performed,
     34 // using the provided "user" and "password" properties.
     35 
     36 #include "shill/vpn/l2tp_ipsec_driver.h"
     37 
     38 #include <base/bind.h>
     39 #include <base/files/file_util.h>
     40 #include <base/strings/string_util.h>
     41 #include <base/strings/stringprintf.h>
     42 #if defined(__ANDROID__)
     43 #include <dbus/service_constants.h>
     44 #else
     45 #include <chromeos/dbus/service_constants.h>
     46 #endif  // __ANDROID__
     47 #include <vpn-manager/service_error.h>
     48 
     49 #include "shill/certificate_file.h"
     50 #include "shill/device_info.h"
     51 #include "shill/error.h"
     52 #include "shill/external_task.h"
     53 #include "shill/ipconfig.h"
     54 #include "shill/logging.h"
     55 #include "shill/manager.h"
     56 #include "shill/ppp_daemon.h"
     57 #include "shill/ppp_device.h"
     58 #include "shill/ppp_device_factory.h"
     59 #include "shill/process_manager.h"
     60 #include "shill/vpn/vpn_service.h"
     61 
     62 using base::Bind;
     63 using base::Closure;
     64 using base::FilePath;
     65 using std::map;
     66 using std::string;
     67 using std::vector;
     68 
     69 namespace shill {
     70 
     71 namespace Logging {
     72 static auto kModuleLogScope = ScopeLogger::kVPN;
     73 static string ObjectID(L2TPIPSecDriver* l) {
     74   return l->GetServiceRpcIdentifier();
     75 }
     76 }
     77 
     78 namespace {
     79 const char kL2TPIPSecIPSecTimeoutProperty[] = "L2TPIPsec.IPsecTimeout";
     80 const char kL2TPIPSecLeftProtoPortProperty[] = "L2TPIPsec.LeftProtoPort";
     81 const char kL2TPIPSecLengthBitProperty[] = "L2TPIPsec.LengthBit";
     82 const char kL2TPIPSecPFSProperty[] = "L2TPIPsec.PFS";
     83 const char kL2TPIPSecRefusePapProperty[] = "L2TPIPsec.RefusePap";
     84 const char kL2TPIPSecRekeyProperty[] = "L2TPIPsec.Rekey";
     85 const char kL2TPIPSecRequireAuthProperty[] = "L2TPIPsec.RequireAuth";
     86 const char kL2TPIPSecRequireChapProperty[] = "L2TPIPsec.RequireChap";
     87 const char kL2TPIPSecRightProtoPortProperty[] = "L2TPIPsec.RightProtoPort";
     88 }  // namespace
     89 
     90 // static
     91 const char L2TPIPSecDriver::kL2TPIPSecVPNPath[] = "/usr/sbin/l2tpipsec_vpn";
     92 // static
     93 const VPNDriver::Property L2TPIPSecDriver::kProperties[] = {
     94   { kL2tpIpsecAuthenticationType, 0 },
     95   { kL2tpIpsecCaCertNssProperty, 0 },
     96   { kL2tpIpsecClientCertIdProperty, 0 },
     97   { kL2tpIpsecClientCertSlotProperty, 0 },
     98   { kL2tpIpsecIkeVersion, 0 },
     99   { kL2tpIpsecPasswordProperty, Property::kCredential | Property::kWriteOnly },
    100   { kL2tpIpsecPinProperty, Property::kCredential },
    101   { kL2tpIpsecPskProperty, Property::kCredential | Property::kWriteOnly },
    102   { kL2tpIpsecUserProperty, 0 },
    103   { kProviderHostProperty, 0 },
    104   { kProviderTypeProperty, 0 },
    105   { kL2tpIpsecCaCertPemProperty, Property::kArray },
    106   { kL2tpIpsecTunnelGroupProperty, 0 },
    107   { kL2TPIPSecIPSecTimeoutProperty, 0 },
    108   { kL2TPIPSecLeftProtoPortProperty, 0 },
    109   { kL2TPIPSecLengthBitProperty, 0 },
    110   { kL2TPIPSecPFSProperty, 0 },
    111   { kL2TPIPSecRefusePapProperty, 0 },
    112   { kL2TPIPSecRekeyProperty, 0 },
    113   { kL2TPIPSecRequireAuthProperty, 0 },
    114   { kL2TPIPSecRequireChapProperty, 0 },
    115   { kL2TPIPSecRightProtoPortProperty, 0 },
    116   { kL2tpIpsecXauthUserProperty, Property::kCredential | Property::kWriteOnly },
    117   { kL2tpIpsecXauthPasswordProperty,
    118     Property::kCredential | Property::kWriteOnly },
    119   { kL2tpIpsecLcpEchoDisabledProperty, 0 },
    120 };
    121 
    122 L2TPIPSecDriver::L2TPIPSecDriver(ControlInterface* control,
    123                                  EventDispatcher* dispatcher,
    124                                  Metrics* metrics,
    125                                  Manager* manager,
    126                                  DeviceInfo* device_info,
    127                                  ProcessManager* process_manager)
    128     : VPNDriver(dispatcher, manager, kProperties, arraysize(kProperties)),
    129       control_(control),
    130       metrics_(metrics),
    131       device_info_(device_info),
    132       process_manager_(process_manager),
    133       ppp_device_factory_(PPPDeviceFactory::GetInstance()),
    134       certificate_file_(new CertificateFile()),
    135       weak_ptr_factory_(this) {}
    136 
    137 L2TPIPSecDriver::~L2TPIPSecDriver() {
    138   IdleService();
    139 }
    140 
    141 std::string L2TPIPSecDriver::GetServiceRpcIdentifier() {
    142   if (service_ == nullptr)
    143     return "(l2tp_ipsec_driver)";
    144   return service_->GetRpcIdentifier();
    145 }
    146 
    147 bool L2TPIPSecDriver::ClaimInterface(const string& link_name,
    148                                      int interface_index) {
    149   // TODO(petkov): crbug.com/212446.
    150   NOTIMPLEMENTED();
    151   return false;
    152 }
    153 
    154 void L2TPIPSecDriver::Connect(const VPNServiceRefPtr& service, Error* error) {
    155   StartConnectTimeout(kDefaultConnectTimeoutSeconds);
    156   service_ = service;
    157   service_->SetState(Service::kStateConfiguring);
    158   if (!SpawnL2TPIPSecVPN(error)) {
    159     FailService(Service::kFailureInternal);
    160   }
    161 }
    162 
    163 void L2TPIPSecDriver::Disconnect() {
    164   SLOG(this, 2) << __func__;
    165   IdleService();
    166 }
    167 
    168 void L2TPIPSecDriver::OnConnectionDisconnected() {
    169   LOG(INFO) << "Underlying connection disconnected.";
    170   IdleService();
    171 }
    172 
    173 void L2TPIPSecDriver::OnConnectTimeout() {
    174   VPNDriver::OnConnectTimeout();
    175   FailService(Service::kFailureConnect);
    176 }
    177 
    178 string L2TPIPSecDriver::GetProviderType() const {
    179   return kProviderL2tpIpsec;
    180 }
    181 
    182 void L2TPIPSecDriver::IdleService() {
    183   Cleanup(Service::kStateIdle, Service::kFailureUnknown);
    184 }
    185 
    186 void L2TPIPSecDriver::FailService(Service::ConnectFailure failure) {
    187   Cleanup(Service::kStateFailure, failure);
    188 }
    189 
    190 void L2TPIPSecDriver::Cleanup(Service::ConnectState state,
    191                               Service::ConnectFailure failure) {
    192   SLOG(this, 2) << __func__ << "("
    193                 << Service::ConnectStateToString(state) << ", "
    194                 << Service::ConnectFailureToString(failure) << ")";
    195   StopConnectTimeout();
    196   DeleteTemporaryFiles();
    197   external_task_.reset();
    198   if (device_) {
    199     device_->DropConnection();
    200     device_->SetEnabled(false);
    201     device_ = nullptr;
    202   }
    203   if (service_) {
    204     if (state == Service::kStateFailure) {
    205       service_->SetFailure(failure);
    206     } else {
    207       service_->SetState(state);
    208     }
    209     service_ = nullptr;
    210   }
    211 }
    212 
    213 void L2TPIPSecDriver::DeleteTemporaryFile(base::FilePath* temporary_file) {
    214   if (!temporary_file->empty()) {
    215     base::DeleteFile(*temporary_file, false);
    216     temporary_file->clear();
    217   }
    218 }
    219 
    220 void L2TPIPSecDriver::DeleteTemporaryFiles() {
    221   DeleteTemporaryFile(&psk_file_);
    222   DeleteTemporaryFile(&xauth_credentials_file_);
    223 }
    224 
    225 bool L2TPIPSecDriver::SpawnL2TPIPSecVPN(Error* error) {
    226   SLOG(this, 2) << __func__;
    227   std::unique_ptr<ExternalTask> external_task_local(
    228       new ExternalTask(control_,
    229                        process_manager_,
    230                        weak_ptr_factory_.GetWeakPtr(),
    231                        Bind(&L2TPIPSecDriver::OnL2TPIPSecVPNDied,
    232                             weak_ptr_factory_.GetWeakPtr())));
    233 
    234   vector<string> options;
    235   map<string, string> environment;  // No env vars passed.
    236   if (!InitOptions(&options, error)) {
    237     return false;
    238   }
    239   LOG(INFO) << "L2TP/IPSec VPN process options: "
    240             << base::JoinString(options, " ");
    241 
    242   if (external_task_local->Start(
    243           FilePath(kL2TPIPSecVPNPath), options, environment, true, error)) {
    244     external_task_ = std::move(external_task_local);
    245     return true;
    246   }
    247   return false;
    248 }
    249 
    250 bool L2TPIPSecDriver::InitOptions(vector<string>* options, Error* error) {
    251   string vpnhost = args()->LookupString(kProviderHostProperty, "");
    252   if (vpnhost.empty()) {
    253     Error::PopulateAndLog(
    254         FROM_HERE, error, Error::kInvalidArguments, "VPN host not specified.");
    255     return false;
    256   }
    257 
    258   if (!InitPSKOptions(options, error)) {
    259     return false;
    260   }
    261 
    262   if (!InitXauthOptions(options, error)) {
    263     return false;
    264   }
    265 
    266   options->push_back(base::StringPrintf("--remote_host=%s", vpnhost.c_str()));
    267   options->push_back(base::StringPrintf("--pppd_plugin=%s",
    268                                         PPPDaemon::kShimPluginPath));
    269   // Disable pppd from configuring IP addresses, routes, DNS.
    270   options->push_back("--nosystemconfig");
    271 
    272   // Accept a PEM CA certificate.
    273   InitPEMOptions(options);
    274 
    275   AppendValueOption(kL2tpIpsecClientCertIdProperty,
    276                     "--client_cert_id", options);
    277   AppendValueOption(kL2tpIpsecClientCertSlotProperty,
    278                     "--client_cert_slot", options);
    279   AppendValueOption(kL2tpIpsecPinProperty, "--user_pin", options);
    280   AppendValueOption(kL2tpIpsecUserProperty, "--user", options);
    281   AppendValueOption(kL2TPIPSecIPSecTimeoutProperty, "--ipsec_timeout", options);
    282   AppendValueOption(kL2TPIPSecLeftProtoPortProperty,
    283                     "--leftprotoport", options);
    284   AppendFlag(kL2TPIPSecPFSProperty, "--pfs", "--nopfs", options);
    285   AppendFlag(kL2TPIPSecRekeyProperty, "--rekey", "--norekey", options);
    286   AppendValueOption(kL2TPIPSecRightProtoPortProperty,
    287                     "--rightprotoport", options);
    288   AppendFlag(kL2TPIPSecRequireChapProperty,
    289              "--require_chap", "--norequire_chap", options);
    290   AppendFlag(kL2TPIPSecRefusePapProperty,
    291              "--refuse_pap", "--norefuse_pap", options);
    292   AppendFlag(kL2TPIPSecRequireAuthProperty,
    293              "--require_authentication", "--norequire_authentication", options);
    294   AppendFlag(kL2TPIPSecLengthBitProperty,
    295              "--length_bit", "--nolength_bit", options);
    296   AppendFlag(kL2tpIpsecLcpEchoDisabledProperty,
    297              "--noppp_lcp_echo", "--ppp_lcp_echo", options);
    298   AppendValueOption(kL2tpIpsecTunnelGroupProperty, "--tunnel_group", options);
    299   if (SLOG_IS_ON(VPN, 0)) {
    300     options->push_back("--debug");
    301   }
    302   return true;
    303 }
    304 
    305 bool L2TPIPSecDriver::InitPSKOptions(vector<string>* options, Error* error) {
    306   string psk = args()->LookupString(kL2tpIpsecPskProperty, "");
    307   if (!psk.empty()) {
    308     if (!base::CreateTemporaryFileInDir(manager()->run_path(), &psk_file_) ||
    309         chmod(psk_file_.value().c_str(), S_IRUSR | S_IWUSR) ||
    310         base::WriteFile(psk_file_, psk.data(), psk.size()) !=
    311             static_cast<int>(psk.size())) {
    312       Error::PopulateAndLog(
    313           FROM_HERE, error, Error::kInternalError, "Unable to setup psk file.");
    314       return false;
    315     }
    316     options->push_back(base::StringPrintf("--psk_file=%s",
    317                                           psk_file_.value().c_str()));
    318   }
    319   return true;
    320 }
    321 
    322 bool L2TPIPSecDriver::InitPEMOptions(vector<string>* options) {
    323   vector<string> ca_certs;
    324   if (args()->ContainsStrings(kL2tpIpsecCaCertPemProperty)) {
    325     ca_certs = args()->GetStrings(kL2tpIpsecCaCertPemProperty);
    326   }
    327   if (ca_certs.empty()) {
    328     return false;
    329   }
    330   FilePath certfile = certificate_file_->CreatePEMFromStrings(ca_certs);
    331   if (certfile.empty()) {
    332     LOG(ERROR) << "Unable to extract certificates from PEM string.";
    333     return false;
    334   }
    335   options->push_back(base::StringPrintf("--server_ca_file=%s",
    336                                         certfile.value().c_str()));
    337   return true;
    338 }
    339 
    340 bool L2TPIPSecDriver::InitXauthOptions(vector<string>* options, Error* error) {
    341   string user = args()->LookupString(kL2tpIpsecXauthUserProperty, "");
    342   string password = args()->LookupString(kL2tpIpsecXauthPasswordProperty, "");
    343   if (user.empty() && password.empty()) {
    344     // Xauth credentials not configured.
    345     return true;
    346   }
    347   if (user.empty() || password.empty()) {
    348       Error::PopulateAndLog(
    349           FROM_HERE, error, Error::kInvalidArguments,
    350           "XAUTH credentials are partially configured.");
    351     return false;
    352   }
    353   string xauth_credentials = user + "\n" + password + "\n";
    354   if (!base::CreateTemporaryFileInDir(manager()->run_path(),
    355                                       &xauth_credentials_file_) ||
    356       chmod(xauth_credentials_file_.value().c_str(), S_IRUSR | S_IWUSR) ||
    357       base::WriteFile(xauth_credentials_file_, xauth_credentials.data(),
    358                       xauth_credentials.size()) !=
    359           static_cast<int>(xauth_credentials.size())) {
    360     Error::PopulateAndLog(
    361         FROM_HERE, error, Error::kInternalError,
    362         "Unable to setup XAUTH credentials file.");
    363     return false;
    364   }
    365   options->push_back(base::StringPrintf("--xauth_credentials_file=%s",
    366                          xauth_credentials_file_.value().c_str()));
    367   return true;
    368 }
    369 
    370 bool L2TPIPSecDriver::AppendValueOption(
    371     const string& property, const string& option, vector<string>* options) {
    372   string value = args()->LookupString(property, "");
    373   if (!value.empty()) {
    374     options->push_back(base::StringPrintf("%s=%s", option.c_str(),
    375                                           value.c_str()));
    376     return true;
    377   }
    378   return false;
    379 }
    380 
    381 bool L2TPIPSecDriver::AppendFlag(const string& property,
    382                                  const string& true_option,
    383                                  const string& false_option,
    384                                  vector<string>* options) {
    385   string value = args()->LookupString(property, "");
    386   if (!value.empty()) {
    387     options->push_back(value == "true" ? true_option : false_option);
    388     return true;
    389   }
    390   return false;
    391 }
    392 
    393 void L2TPIPSecDriver::OnL2TPIPSecVPNDied(pid_t /*pid*/, int status) {
    394   FailService(TranslateExitStatusToFailure(status));
    395   // TODO(petkov): Figure if we need to restart the connection.
    396 }
    397 
    398 // static
    399 Service::ConnectFailure L2TPIPSecDriver::TranslateExitStatusToFailure(
    400     int status) {
    401   if (!WIFEXITED(status)) {
    402     return Service::kFailureInternal;
    403   }
    404   switch (WEXITSTATUS(status)) {
    405     case vpn_manager::kServiceErrorResolveHostnameFailed:
    406       return Service::kFailureDNSLookup;
    407     case vpn_manager::kServiceErrorIpsecConnectionFailed:
    408     case vpn_manager::kServiceErrorL2tpConnectionFailed:
    409     case vpn_manager::kServiceErrorPppConnectionFailed:
    410       return Service::kFailureConnect;
    411     case vpn_manager::kServiceErrorIpsecPresharedKeyAuthenticationFailed:
    412       return Service::kFailureIPSecPSKAuth;
    413     case vpn_manager::kServiceErrorIpsecCertificateAuthenticationFailed:
    414       return Service::kFailureIPSecCertAuth;
    415     case vpn_manager::kServiceErrorPppAuthenticationFailed:
    416       return Service::kFailurePPPAuth;
    417     default:
    418       break;
    419   }
    420   return Service::kFailureUnknown;
    421 }
    422 
    423 void L2TPIPSecDriver::GetLogin(string* user, string* password) {
    424   LOG(INFO) << "Login requested.";
    425   string user_property =
    426       args()->LookupString(kL2tpIpsecUserProperty, "");
    427   if (user_property.empty()) {
    428     LOG(ERROR) << "User not set.";
    429     return;
    430   }
    431   string password_property =
    432       args()->LookupString(kL2tpIpsecPasswordProperty, "");
    433   if (password_property.empty()) {
    434     LOG(ERROR) << "Password not set.";
    435     return;
    436   }
    437   *user = user_property;
    438   *password = password_property;
    439 }
    440 
    441 void L2TPIPSecDriver::Notify(
    442     const string& reason, const map<string, string>& dict) {
    443   LOG(INFO) << "IP configuration received: " << reason;
    444 
    445   if (reason == kPPPReasonAuthenticating ||
    446       reason == kPPPReasonAuthenticated) {
    447     // These are uninteresting intermediate states that do not indicate failure.
    448     return;
    449   }
    450 
    451   if (reason != kPPPReasonConnect) {
    452     DCHECK_EQ(kPPPReasonDisconnect, reason);
    453     // DestroyLater, rather than while on stack.
    454     external_task_.release()->DestroyLater(dispatcher());
    455     FailService(Service::kFailureUnknown);
    456     return;
    457   }
    458 
    459   DeleteTemporaryFiles();
    460 
    461   string interface_name = PPPDevice::GetInterfaceName(dict);
    462   int interface_index = device_info_->GetIndex(interface_name);
    463   if (interface_index < 0) {
    464     // TODO(petkov): Consider handling the race when the RTNL notification about
    465     // the new PPP device has not been received yet. We can keep the IP
    466     // configuration and apply it when ClaimInterface is
    467     // invoked. crbug.com/212446.
    468     NOTIMPLEMENTED() << ": No device info for " << interface_name << ".";
    469     return;
    470   }
    471 
    472   // There is no IPv6 support for L2TP/IPsec VPN at this moment, so create a
    473   // blackhole route for IPv6 traffic after establishing a IPv4 VPN.
    474   // TODO(benchan): Generalize this when IPv6 support is added.
    475   bool blackhole_ipv6 = true;
    476 
    477   if (!device_) {
    478     device_ = ppp_device_factory_->CreatePPPDevice(
    479         control_, dispatcher(), metrics_, manager(), interface_name,
    480         interface_index);
    481   }
    482   device_->SetEnabled(true);
    483   device_->SelectService(service_);
    484 
    485   // Reduce MTU to the minimum viable for IPv6, since the IPSec layer consumes
    486   // some variable portion of the payload.  Although this system does not yet
    487   // support IPv6, it is a reasonable value to start with, since the minimum
    488   // IPv6 packet size will plausibly be a size any gateway would support, and
    489   // is also larger than the IPv4 minimum size.
    490   device_->UpdateIPConfigFromPPPWithMTU(
    491       dict, blackhole_ipv6, IPConfig::kMinIPv6MTU);
    492 
    493   ReportConnectionMetrics();
    494   StopConnectTimeout();
    495 }
    496 
    497 bool L2TPIPSecDriver::IsPskRequired() const {
    498   return
    499     const_args()->LookupString(kL2tpIpsecPskProperty, "").empty() &&
    500     const_args()->LookupString(kL2tpIpsecClientCertIdProperty, "").empty();
    501 }
    502 
    503 KeyValueStore L2TPIPSecDriver::GetProvider(Error* error) {
    504   SLOG(this, 2) << __func__;
    505   KeyValueStore props = VPNDriver::GetProvider(error);
    506   props.SetBool(kPassphraseRequiredProperty,
    507                 args()->LookupString(kL2tpIpsecPasswordProperty, "").empty());
    508   props.SetBool(kL2tpIpsecPskRequiredProperty, IsPskRequired());
    509   return props;
    510 }
    511 
    512 void L2TPIPSecDriver::ReportConnectionMetrics() {
    513   metrics_->SendEnumToUMA(
    514       Metrics::kMetricVpnDriver,
    515       Metrics::kVpnDriverL2tpIpsec,
    516       Metrics::kMetricVpnDriverMax);
    517 
    518   // We output an enum for each of the authentication types specified,
    519   // even if more than one is set at the same time.
    520   bool has_remote_authentication = false;
    521   if (args()->LookupString(kL2tpIpsecPskProperty, "") != "") {
    522     metrics_->SendEnumToUMA(
    523         Metrics::kMetricVpnRemoteAuthenticationType,
    524         Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecPsk,
    525         Metrics::kMetricVpnRemoteAuthenticationTypeMax);
    526     has_remote_authentication = true;
    527   }
    528   if (!has_remote_authentication) {
    529     metrics_->SendEnumToUMA(
    530         Metrics::kMetricVpnRemoteAuthenticationType,
    531         Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecDefault,
    532         Metrics::kMetricVpnRemoteAuthenticationTypeMax);
    533   }
    534 
    535   bool has_user_authentication = false;
    536   if (args()->LookupString(kL2tpIpsecClientCertIdProperty,
    537                            "") != "") {
    538     metrics_->SendEnumToUMA(
    539         Metrics::kMetricVpnUserAuthenticationType,
    540         Metrics::kVpnUserAuthenticationTypeL2tpIpsecCertificate,
    541         Metrics::kMetricVpnUserAuthenticationTypeMax);
    542     has_user_authentication = true;
    543   }
    544   if (args()->LookupString(kL2tpIpsecPasswordProperty, "") != "") {
    545     metrics_->SendEnumToUMA(
    546         Metrics::kMetricVpnUserAuthenticationType,
    547         Metrics::kVpnUserAuthenticationTypeL2tpIpsecUsernamePassword,
    548         Metrics::kMetricVpnUserAuthenticationTypeMax);
    549     has_user_authentication = true;
    550   }
    551   if (!has_user_authentication) {
    552     metrics_->SendEnumToUMA(
    553         Metrics::kMetricVpnUserAuthenticationType,
    554         Metrics::kVpnUserAuthenticationTypeL2tpIpsecNone,
    555         Metrics::kMetricVpnUserAuthenticationTypeMax);
    556   }
    557 }
    558 
    559 }  // namespace shill
    560