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