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 #include "shill/vpn/vpn_driver.h"
     18 
     19 #include <string>
     20 #include <vector>
     21 
     22 #include <base/strings/string_util.h>
     23 #if defined(__ANDROID__)
     24 #include <dbus/service_constants.h>
     25 #else
     26 #include <chromeos/dbus/service_constants.h>
     27 #endif  // __ANDROID__
     28 
     29 #include "shill/connection.h"
     30 #include "shill/event_dispatcher.h"
     31 #include "shill/logging.h"
     32 #include "shill/manager.h"
     33 #include "shill/property_accessor.h"
     34 #include "shill/property_store.h"
     35 #include "shill/store_interface.h"
     36 
     37 using std::string;
     38 using std::vector;
     39 
     40 namespace shill {
     41 
     42 namespace Logging {
     43 static auto kModuleLogScope = ScopeLogger::kVPN;
     44 static string ObjectID(VPNDriver* v) { return "(vpn_driver)"; }
     45 }
     46 
     47 // static
     48 const int VPNDriver::kDefaultConnectTimeoutSeconds = 60;
     49 
     50 VPNDriver::VPNDriver(EventDispatcher* dispatcher,
     51                      Manager* manager,
     52                      const Property* properties,
     53                      size_t property_count)
     54     : weak_ptr_factory_(this),
     55       dispatcher_(dispatcher),
     56       manager_(manager),
     57       properties_(properties),
     58       property_count_(property_count),
     59       connect_timeout_seconds_(0) {}
     60 
     61 VPNDriver::~VPNDriver() {}
     62 
     63 bool VPNDriver::Load(StoreInterface* storage, const string& storage_id) {
     64   SLOG(this, 2) << __func__;
     65   for (size_t i = 0; i < property_count_; i++) {
     66     if ((properties_[i].flags & Property::kEphemeral)) {
     67       continue;
     68     }
     69     const string property = properties_[i].property;
     70     if (properties_[i].flags & Property::kArray) {
     71       CHECK(!(properties_[i].flags & Property::kCredential))
     72           << "Property cannot be both an array and a credential";
     73       vector<string> value;
     74       if (storage->GetStringList(storage_id, property, &value)) {
     75         args_.SetStrings(property, value);
     76       } else {
     77         args_.RemoveStrings(property);
     78       }
     79     } else {
     80       string value;
     81       bool loaded = (properties_[i].flags & Property::kCredential) ?
     82           storage->GetCryptedString(storage_id, property, &value) :
     83           storage->GetString(storage_id, property, &value);
     84       if (loaded) {
     85         args_.SetString(property, value);
     86       } else {
     87         args_.RemoveString(property);
     88       }
     89     }
     90   }
     91   return true;
     92 }
     93 
     94 bool VPNDriver::Save(StoreInterface* storage,
     95                      const string& storage_id,
     96                      bool save_credentials) {
     97   SLOG(this, 2) << __func__;
     98   for (size_t i = 0; i < property_count_; i++) {
     99     if ((properties_[i].flags & Property::kEphemeral)) {
    100       continue;
    101     }
    102     bool credential = (properties_[i].flags & Property::kCredential);
    103     const string property = properties_[i].property;
    104     if (properties_[i].flags & Property::kArray) {
    105       CHECK(!credential)
    106           << "Property cannot be both an array and a credential";
    107       if (!args_.ContainsStrings(property)) {
    108         storage->DeleteKey(storage_id, property);
    109         continue;
    110       }
    111       Strings value = args_.GetStrings(property);
    112       storage->SetStringList(storage_id, property, value);
    113     } else {
    114       if (!args_.ContainsString(property) ||
    115           (credential && !save_credentials)) {
    116         storage->DeleteKey(storage_id, property);
    117         continue;
    118       }
    119       string value = args_.GetString(property);
    120       if (credential) {
    121         storage->SetCryptedString(storage_id, property, value);
    122       } else {
    123         storage->SetString(storage_id, property, value);
    124       }
    125     }
    126   }
    127   return true;
    128 }
    129 
    130 void VPNDriver::UnloadCredentials() {
    131   SLOG(this, 2) << __func__;
    132   for (size_t i = 0; i < property_count_; i++) {
    133     if ((properties_[i].flags &
    134          (Property::kEphemeral | Property::kCredential))) {
    135       args_.RemoveString(properties_[i].property);
    136     }
    137   }
    138 }
    139 
    140 void VPNDriver::InitPropertyStore(PropertyStore* store) {
    141   SLOG(this, 2) << __func__;
    142   for (size_t i = 0; i < property_count_; i++) {
    143     if (properties_[i].flags & Property::kArray) {
    144       store->RegisterDerivedStrings(
    145           properties_[i].property,
    146           StringsAccessor(
    147               new CustomMappedAccessor<VPNDriver, Strings, size_t>(
    148                   this,
    149                   &VPNDriver::ClearMappedStringsProperty,
    150                   &VPNDriver::GetMappedStringsProperty,
    151                   &VPNDriver::SetMappedStringsProperty,
    152                   i)));
    153     } else {
    154       store->RegisterDerivedString(
    155           properties_[i].property,
    156           StringAccessor(
    157               new CustomMappedAccessor<VPNDriver, string, size_t>(
    158                   this,
    159                   &VPNDriver::ClearMappedStringProperty,
    160                   &VPNDriver::GetMappedStringProperty,
    161                   &VPNDriver::SetMappedStringProperty,
    162                   i)));
    163     }
    164   }
    165 
    166   store->RegisterDerivedKeyValueStore(
    167       kProviderProperty,
    168       KeyValueStoreAccessor(
    169           new CustomAccessor<VPNDriver, KeyValueStore>(
    170               this, &VPNDriver::GetProvider, nullptr)));
    171 }
    172 
    173 void VPNDriver::ClearMappedStringProperty(const size_t& index, Error* error) {
    174   CHECK(index < property_count_);
    175   if (args_.ContainsString(properties_[index].property)) {
    176     args_.RemoveString(properties_[index].property);
    177   } else {
    178     error->Populate(Error::kNotFound, "Property is not set");
    179   }
    180 }
    181 
    182 void VPNDriver::ClearMappedStringsProperty(const size_t& index, Error* error) {
    183   CHECK(index < property_count_);
    184   if (args_.ContainsStrings(properties_[index].property)) {
    185     args_.RemoveStrings(properties_[index].property);
    186   } else {
    187     error->Populate(Error::kNotFound, "Property is not set");
    188   }
    189 }
    190 
    191 string VPNDriver::GetMappedStringProperty(const size_t& index, Error* error) {
    192   // Provider properties are set via SetProperty calls to "Provider.XXX",
    193   // however, they are retrieved via a GetProperty call, which returns all
    194   // properties in a single "Provider" dict.  Therefore, none of the individual
    195   // properties in the kProperties are available for enumeration in
    196   // GetProperties.  Instead, they are retrieved via GetProvider below.
    197   error->Populate(Error::kInvalidArguments,
    198                   "Provider properties are not read back in this manner");
    199   return string();
    200 }
    201 
    202 Strings VPNDriver::GetMappedStringsProperty(const size_t& index, Error* error) {
    203   // Provider properties are set via SetProperty calls to "Provider.XXX",
    204   // however, they are retrieved via a GetProperty call, which returns all
    205   // properties in a single "Provider" dict.  Therefore, none of the individual
    206   // properties in the kProperties are available for enumeration in
    207   // GetProperties.  Instead, they are retrieved via GetProvider below.
    208   error->Populate(Error::kInvalidArguments,
    209                   "Provider properties are not read back in this manner");
    210   return Strings();
    211 }
    212 
    213 bool VPNDriver::SetMappedStringProperty(
    214     const size_t& index, const string& value, Error* error) {
    215   CHECK(index < property_count_);
    216   if (args_.ContainsString(properties_[index].property) &&
    217       args_.GetString(properties_[index].property) == value) {
    218     return false;
    219   }
    220   args_.SetString(properties_[index].property, value);
    221   return true;
    222 }
    223 
    224 bool VPNDriver::SetMappedStringsProperty(
    225     const size_t& index, const Strings& value, Error* error) {
    226   CHECK(index < property_count_);
    227   if (args_.ContainsStrings(properties_[index].property) &&
    228       args_.GetStrings(properties_[index].property) == value) {
    229     return false;
    230   }
    231   args_.SetStrings(properties_[index].property, value);
    232   return true;
    233 }
    234 
    235 KeyValueStore VPNDriver::GetProvider(Error* error) {
    236   SLOG(this, 2) << __func__;
    237   string provider_prefix = string(kProviderProperty) + ".";
    238   KeyValueStore provider_properties;
    239 
    240   for (size_t i = 0; i < property_count_; i++) {
    241     if ((properties_[i].flags & Property::kWriteOnly)) {
    242       continue;
    243     }
    244     string prop = properties_[i].property;
    245 
    246     // Chomp off leading "Provider." from properties that have this prefix.
    247     string chopped_prop;
    248     if (base::StartsWith(prop, provider_prefix,
    249                          base::CompareCase::INSENSITIVE_ASCII)) {
    250       chopped_prop = prop.substr(provider_prefix.length());
    251     } else {
    252       chopped_prop = prop;
    253     }
    254 
    255     if (properties_[i].flags & Property::kArray) {
    256       if (!args_.ContainsStrings(prop)) {
    257         continue;
    258       }
    259       Strings value = args_.GetStrings(prop);
    260       provider_properties.SetStrings(chopped_prop, value);
    261     } else {
    262       if (!args_.ContainsString(prop)) {
    263         continue;
    264       }
    265       string value = args_.GetString(prop);
    266       provider_properties.SetString(chopped_prop, value);
    267     }
    268   }
    269 
    270   return provider_properties;
    271 }
    272 
    273 void VPNDriver::StartConnectTimeout(int timeout_seconds) {
    274   if (IsConnectTimeoutStarted()) {
    275     return;
    276   }
    277   LOG(INFO) << "Schedule VPN connect timeout: "
    278             << timeout_seconds << " seconds.";
    279   connect_timeout_seconds_ = timeout_seconds;
    280   connect_timeout_callback_.Reset(
    281       Bind(&VPNDriver::OnConnectTimeout, weak_ptr_factory_.GetWeakPtr()));
    282   dispatcher_->PostDelayedTask(
    283       connect_timeout_callback_.callback(), timeout_seconds * 1000);
    284 }
    285 
    286 void VPNDriver::StopConnectTimeout() {
    287   SLOG(this, 2) << __func__;
    288   connect_timeout_callback_.Cancel();
    289   connect_timeout_seconds_ = 0;
    290 }
    291 
    292 bool VPNDriver::IsConnectTimeoutStarted() const {
    293   return !connect_timeout_callback_.IsCancelled();
    294 }
    295 
    296 void VPNDriver::OnConnectTimeout() {
    297   LOG(INFO) << "VPN connect timeout.";
    298   StopConnectTimeout();
    299 }
    300 
    301 string VPNDriver::GetHost() const {
    302   return args_.LookupString(kProviderHostProperty, "");
    303 }
    304 
    305 }  // namespace shill
    306