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_provider.h"
18
19#include <algorithm>
20#include <memory>
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/error.h"
30#include "shill/logging.h"
31#include "shill/manager.h"
32#include "shill/process_manager.h"
33#include "shill/profile.h"
34#include "shill/store_interface.h"
35#include "shill/vpn/l2tp_ipsec_driver.h"
36#include "shill/vpn/openvpn_driver.h"
37#include "shill/vpn/third_party_vpn_driver.h"
38#include "shill/vpn/vpn_service.h"
39
40using std::set;
41using std::string;
42using std::vector;
43
44namespace shill {
45
46namespace Logging {
47static auto kModuleLogScope = ScopeLogger::kVPN;
48static string ObjectID(const VPNProvider* v) { return "(vpn_provider)"; }
49}
50
51VPNProvider::VPNProvider(ControlInterface* control_interface,
52                         EventDispatcher* dispatcher,
53                         Metrics* metrics,
54                         Manager* manager)
55    : control_interface_(control_interface),
56      dispatcher_(dispatcher),
57      metrics_(metrics),
58      manager_(manager) {}
59
60VPNProvider::~VPNProvider() {}
61
62void VPNProvider::Start() {}
63
64void VPNProvider::Stop() {}
65
66// static
67bool VPNProvider::GetServiceParametersFromArgs(const KeyValueStore& args,
68                                               string* type_ptr,
69                                               string* name_ptr,
70                                               string* host_ptr,
71                                               Error* error) {
72  SLOG(nullptr, 2) << __func__;
73  string type = args.LookupString(kProviderTypeProperty, "");
74  if (type.empty()) {
75    Error::PopulateAndLog(
76        FROM_HERE, error, Error::kNotSupported, "Missing VPN type property.");
77    return false;
78  }
79
80  string host = args.LookupString(kProviderHostProperty, "");
81  if (host.empty()) {
82    Error::PopulateAndLog(
83        FROM_HERE, error, Error::kNotSupported, "Missing VPN host property.");
84    return false;
85  }
86
87  *type_ptr = type,
88  *host_ptr = host,
89  *name_ptr = args.LookupString(kNameProperty, "");
90
91  return true;
92}
93
94// static
95bool VPNProvider::GetServiceParametersFromStorage(const StoreInterface* storage,
96                                                  const string& entry_name,
97                                                  string* vpn_type_ptr,
98                                                  string* name_ptr,
99                                                  string* host_ptr,
100                                                  Error* error) {
101  string service_type;
102  if (!storage->GetString(entry_name, kTypeProperty, &service_type) ||
103      service_type != kTypeVPN) {
104    Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments,
105                          "Unspecified or invalid network type");
106    return false;
107  }
108  if (!storage->GetString(entry_name, kProviderTypeProperty, vpn_type_ptr) ||
109      vpn_type_ptr->empty()) {
110    Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments,
111                          "VPN type not specified");
112    return false;
113  }
114  if (!storage->GetString(entry_name, kNameProperty, name_ptr) ||
115      name_ptr->empty()) {
116    Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments,
117                          "Network name not specified");
118    return false;
119  }
120  if (!storage->GetString(entry_name, kProviderHostProperty, host_ptr) ||
121      host_ptr->empty()) {
122    Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments,
123                          "Host not specified");
124    return false;
125  }
126  return true;
127}
128
129ServiceRefPtr VPNProvider::GetService(const KeyValueStore& args,
130                                      Error* error) {
131  SLOG(this, 2) << __func__;
132  string type;
133  string name;
134  string host;
135
136  if (!GetServiceParametersFromArgs(args, &type, &name, &host, error)) {
137    return nullptr;
138  }
139
140  string storage_id = VPNService::CreateStorageIdentifier(args, error);
141  if (storage_id.empty()) {
142    return nullptr;
143  }
144
145  // Find a service in the provider list which matches these parameters.
146  VPNServiceRefPtr service = FindService(type, name, host);
147  if (service == nullptr) {
148    service = CreateService(type, name, storage_id, error);
149  }
150  return service;
151}
152
153ServiceRefPtr VPNProvider::FindSimilarService(const KeyValueStore& args,
154                                              Error* error) const {
155  SLOG(this, 2) << __func__;
156  string type;
157  string name;
158  string host;
159
160  if (!GetServiceParametersFromArgs(args, &type, &name, &host, error)) {
161    return nullptr;
162  }
163
164  // Find a service in the provider list which matches these parameters.
165  VPNServiceRefPtr service = FindService(type, name, host);
166  if (!service) {
167    error->Populate(Error::kNotFound, "Matching service was not found");
168  }
169
170  return service;
171}
172
173bool VPNProvider::OnDeviceInfoAvailable(const string& link_name,
174                                        int interface_index) {
175  for (const auto& service : services_) {
176    if (service->driver()->ClaimInterface(link_name, interface_index)) {
177      return true;
178    }
179  }
180
181  return false;
182}
183
184void VPNProvider::RemoveService(VPNServiceRefPtr service) {
185  const auto it = std::find(services_.begin(), services_.end(), service);
186  if (it != services_.end()) {
187    services_.erase(it);
188  }
189}
190
191void VPNProvider::CreateServicesFromProfile(const ProfileRefPtr& profile) {
192  SLOG(this, 2) << __func__;
193  const StoreInterface* storage = profile->GetConstStorage();
194  KeyValueStore args;
195  args.SetString(kTypeProperty, kTypeVPN);
196  for (const auto& group : storage->GetGroupsWithProperties(args)) {
197    string type;
198    string name;
199    string host;
200    if (!GetServiceParametersFromStorage(storage,
201                                         group,
202                                         &type,
203                                         &name,
204                                         &host,
205                                         nullptr)) {
206      continue;
207    }
208
209    VPNServiceRefPtr service = FindService(type, name, host);
210    if (service != nullptr) {
211      // If the service already exists, it does not need to be configured,
212      // since PushProfile would have already called ConfigureService on it.
213      SLOG(this, 2) << "Service already exists " << group;
214      continue;
215    }
216
217    Error error;
218    service = CreateService(type, name, group, &error);
219
220    if (service == nullptr) {
221      LOG(ERROR) << "Could not create service for " << group;
222      continue;
223    }
224
225    if (!profile->ConfigureService(service)) {
226      LOG(ERROR) << "Could not configure service for " << group;
227      continue;
228    }
229  }
230}
231
232VPNServiceRefPtr VPNProvider::CreateServiceInner(const string& type,
233                                                 const string& name,
234                                                 const string& storage_id,
235                                                 Error* error) {
236  SLOG(this, 2) << __func__ << " type " << type << " name " << name
237                << " storage id " << storage_id;
238#if defined(DISABLE_VPN)
239
240  Error::PopulateAndLog(
241      FROM_HERE, error, Error::kNotSupported, "VPN is not supported.");
242  return nullptr;
243
244#else
245
246  std::unique_ptr<VPNDriver> driver;
247  if (type == kProviderOpenVpn) {
248    driver.reset(new OpenVPNDriver(
249        control_interface_, dispatcher_, metrics_, manager_,
250        manager_->device_info(), ProcessManager::GetInstance()));
251  } else if (type == kProviderL2tpIpsec) {
252    driver.reset(new L2TPIPSecDriver(
253        control_interface_, dispatcher_, metrics_, manager_,
254        manager_->device_info(), ProcessManager::GetInstance()));
255  } else if (type == kProviderThirdPartyVpn) {
256    // For third party VPN host contains extension ID
257    driver.reset(new ThirdPartyVpnDriver(
258        control_interface_, dispatcher_, metrics_, manager_,
259        manager_->device_info()));
260  } else {
261    Error::PopulateAndLog(
262        FROM_HERE, error, Error::kNotSupported,
263        "Unsupported VPN type: " + type);
264    return nullptr;
265  }
266
267  VPNServiceRefPtr service = new VPNService(
268      control_interface_, dispatcher_, metrics_, manager_, driver.release());
269  service->set_storage_id(storage_id);
270  service->InitDriverPropertyStore();
271  if (!name.empty()) {
272    service->set_friendly_name(name);
273  }
274  return service;
275
276#endif  // DISABLE_VPN
277}
278
279VPNServiceRefPtr VPNProvider::CreateService(const string& type,
280                                            const string& name,
281                                            const string& storage_id,
282                                            Error* error) {
283  VPNServiceRefPtr service = CreateServiceInner(type, name, storage_id, error);
284  if (service) {
285    services_.push_back(service);
286    manager_->RegisterService(service);
287  }
288
289  return service;
290}
291
292VPNServiceRefPtr VPNProvider::FindService(const string& type,
293                                          const string& name,
294                                          const string& host) const {
295  for (const auto& service : services_) {
296    if (type == service->driver()->GetProviderType() &&
297        name == service->friendly_name() &&
298        host == service->driver()->GetHost()) {
299      return service;
300    }
301  }
302  return nullptr;
303}
304
305ServiceRefPtr VPNProvider::CreateTemporaryService(
306      const KeyValueStore& args, Error* error) {
307  string type;
308  string name;
309  string host;
310
311  if (!GetServiceParametersFromArgs(args, &type, &name, &host, error)) {
312    return nullptr;
313  }
314
315  string storage_id = VPNService::CreateStorageIdentifier(args, error);
316  if (storage_id.empty()) {
317    return nullptr;
318  }
319
320  return CreateServiceInner(type, name, storage_id, error);
321}
322
323ServiceRefPtr VPNProvider::CreateTemporaryServiceFromProfile(
324    const ProfileRefPtr& profile, const std::string& entry_name, Error* error) {
325  string type;
326  string name;
327  string host;
328  if (!GetServiceParametersFromStorage(profile->GetConstStorage(),
329                                       entry_name,
330                                       &type,
331                                       &name,
332                                       &host,
333                                       error)) {
334    return nullptr;
335  }
336
337  return CreateServiceInner(type, name, entry_name, error);
338}
339
340bool VPNProvider::HasActiveService() const {
341  for (const auto& service : services_) {
342    if (service->IsConnecting() || service->IsConnected()) {
343      return true;
344    }
345  }
346  return false;
347}
348
349void VPNProvider::DisconnectAll() {
350  for (const auto& service : services_) {
351    if (service->IsConnecting() || service->IsConnected()) {
352      service->Disconnect(nullptr, "user selected new config");
353    }
354  }
355}
356
357}  // namespace shill
358