305 lines
9.8 KiB
C++
305 lines
9.8 KiB
C++
//
|
|
// Copyright (C) 2012 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
#include "shill/vpn/vpn_driver.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <base/strings/string_util.h>
|
|
#if defined(__ANDROID__)
|
|
#include <dbus/service_constants.h>
|
|
#else
|
|
#include <chromeos/dbus/service_constants.h>
|
|
#endif // __ANDROID__
|
|
|
|
#include "shill/connection.h"
|
|
#include "shill/event_dispatcher.h"
|
|
#include "shill/logging.h"
|
|
#include "shill/manager.h"
|
|
#include "shill/property_accessor.h"
|
|
#include "shill/property_store.h"
|
|
#include "shill/store_interface.h"
|
|
|
|
using std::string;
|
|
using std::vector;
|
|
|
|
namespace shill {
|
|
|
|
namespace Logging {
|
|
static auto kModuleLogScope = ScopeLogger::kVPN;
|
|
static string ObjectID(VPNDriver* v) { return "(vpn_driver)"; }
|
|
}
|
|
|
|
// static
|
|
const int VPNDriver::kDefaultConnectTimeoutSeconds = 60;
|
|
|
|
VPNDriver::VPNDriver(EventDispatcher* dispatcher,
|
|
Manager* manager,
|
|
const Property* properties,
|
|
size_t property_count)
|
|
: weak_ptr_factory_(this),
|
|
dispatcher_(dispatcher),
|
|
manager_(manager),
|
|
properties_(properties),
|
|
property_count_(property_count),
|
|
connect_timeout_seconds_(0) {}
|
|
|
|
VPNDriver::~VPNDriver() {}
|
|
|
|
bool VPNDriver::Load(StoreInterface* storage, const string& storage_id) {
|
|
SLOG(this, 2) << __func__;
|
|
for (size_t i = 0; i < property_count_; i++) {
|
|
if ((properties_[i].flags & Property::kEphemeral)) {
|
|
continue;
|
|
}
|
|
const string property = properties_[i].property;
|
|
if (properties_[i].flags & Property::kArray) {
|
|
CHECK(!(properties_[i].flags & Property::kCredential))
|
|
<< "Property cannot be both an array and a credential";
|
|
vector<string> value;
|
|
if (storage->GetStringList(storage_id, property, &value)) {
|
|
args_.SetStrings(property, value);
|
|
} else {
|
|
args_.RemoveStrings(property);
|
|
}
|
|
} else {
|
|
string value;
|
|
bool loaded = (properties_[i].flags & Property::kCredential) ?
|
|
storage->GetCryptedString(storage_id, property, &value) :
|
|
storage->GetString(storage_id, property, &value);
|
|
if (loaded) {
|
|
args_.SetString(property, value);
|
|
} else {
|
|
args_.RemoveString(property);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool VPNDriver::Save(StoreInterface* storage,
|
|
const string& storage_id,
|
|
bool save_credentials) {
|
|
SLOG(this, 2) << __func__;
|
|
for (size_t i = 0; i < property_count_; i++) {
|
|
if ((properties_[i].flags & Property::kEphemeral)) {
|
|
continue;
|
|
}
|
|
bool credential = (properties_[i].flags & Property::kCredential);
|
|
const string property = properties_[i].property;
|
|
if (properties_[i].flags & Property::kArray) {
|
|
CHECK(!credential)
|
|
<< "Property cannot be both an array and a credential";
|
|
if (!args_.ContainsStrings(property)) {
|
|
storage->DeleteKey(storage_id, property);
|
|
continue;
|
|
}
|
|
Strings value = args_.GetStrings(property);
|
|
storage->SetStringList(storage_id, property, value);
|
|
} else {
|
|
if (!args_.ContainsString(property) ||
|
|
(credential && !save_credentials)) {
|
|
storage->DeleteKey(storage_id, property);
|
|
continue;
|
|
}
|
|
string value = args_.GetString(property);
|
|
if (credential) {
|
|
storage->SetCryptedString(storage_id, property, value);
|
|
} else {
|
|
storage->SetString(storage_id, property, value);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void VPNDriver::UnloadCredentials() {
|
|
SLOG(this, 2) << __func__;
|
|
for (size_t i = 0; i < property_count_; i++) {
|
|
if ((properties_[i].flags &
|
|
(Property::kEphemeral | Property::kCredential))) {
|
|
args_.RemoveString(properties_[i].property);
|
|
}
|
|
}
|
|
}
|
|
|
|
void VPNDriver::InitPropertyStore(PropertyStore* store) {
|
|
SLOG(this, 2) << __func__;
|
|
for (size_t i = 0; i < property_count_; i++) {
|
|
if (properties_[i].flags & Property::kArray) {
|
|
store->RegisterDerivedStrings(
|
|
properties_[i].property,
|
|
StringsAccessor(
|
|
new CustomMappedAccessor<VPNDriver, Strings, size_t>(
|
|
this,
|
|
&VPNDriver::ClearMappedStringsProperty,
|
|
&VPNDriver::GetMappedStringsProperty,
|
|
&VPNDriver::SetMappedStringsProperty,
|
|
i)));
|
|
} else {
|
|
store->RegisterDerivedString(
|
|
properties_[i].property,
|
|
StringAccessor(
|
|
new CustomMappedAccessor<VPNDriver, string, size_t>(
|
|
this,
|
|
&VPNDriver::ClearMappedStringProperty,
|
|
&VPNDriver::GetMappedStringProperty,
|
|
&VPNDriver::SetMappedStringProperty,
|
|
i)));
|
|
}
|
|
}
|
|
|
|
store->RegisterDerivedKeyValueStore(
|
|
kProviderProperty,
|
|
KeyValueStoreAccessor(
|
|
new CustomAccessor<VPNDriver, KeyValueStore>(
|
|
this, &VPNDriver::GetProvider, nullptr)));
|
|
}
|
|
|
|
void VPNDriver::ClearMappedStringProperty(const size_t& index, Error* error) {
|
|
CHECK(index < property_count_);
|
|
if (args_.ContainsString(properties_[index].property)) {
|
|
args_.RemoveString(properties_[index].property);
|
|
} else {
|
|
error->Populate(Error::kNotFound, "Property is not set");
|
|
}
|
|
}
|
|
|
|
void VPNDriver::ClearMappedStringsProperty(const size_t& index, Error* error) {
|
|
CHECK(index < property_count_);
|
|
if (args_.ContainsStrings(properties_[index].property)) {
|
|
args_.RemoveStrings(properties_[index].property);
|
|
} else {
|
|
error->Populate(Error::kNotFound, "Property is not set");
|
|
}
|
|
}
|
|
|
|
string VPNDriver::GetMappedStringProperty(const size_t& index, Error* error) {
|
|
// Provider properties are set via SetProperty calls to "Provider.XXX",
|
|
// however, they are retrieved via a GetProperty call, which returns all
|
|
// properties in a single "Provider" dict. Therefore, none of the individual
|
|
// properties in the kProperties are available for enumeration in
|
|
// GetProperties. Instead, they are retrieved via GetProvider below.
|
|
error->Populate(Error::kInvalidArguments,
|
|
"Provider properties are not read back in this manner");
|
|
return string();
|
|
}
|
|
|
|
Strings VPNDriver::GetMappedStringsProperty(const size_t& index, Error* error) {
|
|
// Provider properties are set via SetProperty calls to "Provider.XXX",
|
|
// however, they are retrieved via a GetProperty call, which returns all
|
|
// properties in a single "Provider" dict. Therefore, none of the individual
|
|
// properties in the kProperties are available for enumeration in
|
|
// GetProperties. Instead, they are retrieved via GetProvider below.
|
|
error->Populate(Error::kInvalidArguments,
|
|
"Provider properties are not read back in this manner");
|
|
return Strings();
|
|
}
|
|
|
|
bool VPNDriver::SetMappedStringProperty(
|
|
const size_t& index, const string& value, Error* error) {
|
|
CHECK(index < property_count_);
|
|
if (args_.ContainsString(properties_[index].property) &&
|
|
args_.GetString(properties_[index].property) == value) {
|
|
return false;
|
|
}
|
|
args_.SetString(properties_[index].property, value);
|
|
return true;
|
|
}
|
|
|
|
bool VPNDriver::SetMappedStringsProperty(
|
|
const size_t& index, const Strings& value, Error* error) {
|
|
CHECK(index < property_count_);
|
|
if (args_.ContainsStrings(properties_[index].property) &&
|
|
args_.GetStrings(properties_[index].property) == value) {
|
|
return false;
|
|
}
|
|
args_.SetStrings(properties_[index].property, value);
|
|
return true;
|
|
}
|
|
|
|
KeyValueStore VPNDriver::GetProvider(Error* error) {
|
|
SLOG(this, 2) << __func__;
|
|
string provider_prefix = string(kProviderProperty) + ".";
|
|
KeyValueStore provider_properties;
|
|
|
|
for (size_t i = 0; i < property_count_; i++) {
|
|
if ((properties_[i].flags & Property::kWriteOnly)) {
|
|
continue;
|
|
}
|
|
string prop = properties_[i].property;
|
|
|
|
// Chomp off leading "Provider." from properties that have this prefix.
|
|
string chopped_prop;
|
|
if (base::StartsWith(prop, provider_prefix,
|
|
base::CompareCase::INSENSITIVE_ASCII)) {
|
|
chopped_prop = prop.substr(provider_prefix.length());
|
|
} else {
|
|
chopped_prop = prop;
|
|
}
|
|
|
|
if (properties_[i].flags & Property::kArray) {
|
|
if (!args_.ContainsStrings(prop)) {
|
|
continue;
|
|
}
|
|
Strings value = args_.GetStrings(prop);
|
|
provider_properties.SetStrings(chopped_prop, value);
|
|
} else {
|
|
if (!args_.ContainsString(prop)) {
|
|
continue;
|
|
}
|
|
string value = args_.GetString(prop);
|
|
provider_properties.SetString(chopped_prop, value);
|
|
}
|
|
}
|
|
|
|
return provider_properties;
|
|
}
|
|
|
|
void VPNDriver::StartConnectTimeout(int timeout_seconds) {
|
|
if (IsConnectTimeoutStarted()) {
|
|
return;
|
|
}
|
|
LOG(INFO) << "Schedule VPN connect timeout: "
|
|
<< timeout_seconds << " seconds.";
|
|
connect_timeout_seconds_ = timeout_seconds;
|
|
connect_timeout_callback_.Reset(
|
|
Bind(&VPNDriver::OnConnectTimeout, weak_ptr_factory_.GetWeakPtr()));
|
|
dispatcher_->PostDelayedTask(
|
|
connect_timeout_callback_.callback(), timeout_seconds * 1000);
|
|
}
|
|
|
|
void VPNDriver::StopConnectTimeout() {
|
|
SLOG(this, 2) << __func__;
|
|
connect_timeout_callback_.Cancel();
|
|
connect_timeout_seconds_ = 0;
|
|
}
|
|
|
|
bool VPNDriver::IsConnectTimeoutStarted() const {
|
|
return !connect_timeout_callback_.IsCancelled();
|
|
}
|
|
|
|
void VPNDriver::OnConnectTimeout() {
|
|
LOG(INFO) << "VPN connect timeout.";
|
|
StopConnectTimeout();
|
|
}
|
|
|
|
string VPNDriver::GetHost() const {
|
|
return args_.LookupString(kProviderHostProperty, "");
|
|
}
|
|
|
|
} // namespace shill
|