blob: 959bc0e67c246e16809c6cc38602bac0b147d44a [file] [log] [blame]
Darin Petkov33af05c2012-02-28 10:10:30 +01001// 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_provider.h"
6
Paul Stewart65512e12012-03-26 18:01:08 -07007#include <algorithm>
8
Paul Stewart66815332012-04-09 18:09:36 -07009#include <base/string_util.h>
Darin Petkov33af05c2012-02-28 10:10:30 +010010#include <chromeos/dbus/service_constants.h>
11
12#include "shill/error.h"
Darin Petkov9d1bbe72012-04-25 10:58:59 +020013#include "shill/l2tp_ipsec_driver.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070014#include "shill/logging.h"
Paul Stewartca6abd42012-03-01 15:45:29 -080015#include "shill/manager.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010016#include "shill/openvpn_driver.h"
Paul Stewart66815332012-04-09 18:09:36 -070017#include "shill/profile.h"
18#include "shill/store_interface.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010019#include "shill/vpn_service.h"
20
Paul Stewart66815332012-04-09 18:09:36 -070021using std::set;
Darin Petkov33af05c2012-02-28 10:10:30 +010022using std::string;
Paul Stewartca6abd42012-03-01 15:45:29 -080023using std::vector;
Darin Petkov33af05c2012-02-28 10:10:30 +010024
25namespace shill {
26
27VPNProvider::VPNProvider(ControlInterface *control_interface,
28 EventDispatcher *dispatcher,
29 Metrics *metrics,
30 Manager *manager)
31 : control_interface_(control_interface),
32 dispatcher_(dispatcher),
33 metrics_(metrics),
34 manager_(manager) {}
35
36VPNProvider::~VPNProvider() {}
37
38void VPNProvider::Start() {}
39
40void VPNProvider::Stop() {}
41
Paul Stewartbc14fb72013-07-30 08:21:58 -070042// static
43bool VPNProvider::GetServiceParametersFromArgs(const KeyValueStore &args,
44 string *type_ptr,
45 string *name_ptr,
46 string *host_ptr,
47 Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070048 SLOG(VPN, 2) << __func__;
Darin Petkov7f060332012-03-14 11:46:47 +010049 string type = args.LookupString(flimflam::kProviderTypeProperty, "");
50 if (type.empty()) {
Darin Petkov33af05c2012-02-28 10:10:30 +010051 Error::PopulateAndLog(
52 error, Error::kNotSupported, "Missing VPN type property.");
Paul Stewartbc14fb72013-07-30 08:21:58 -070053 return false;
Darin Petkov33af05c2012-02-28 10:10:30 +010054 }
Paul Stewartca6abd42012-03-01 15:45:29 -080055
Darin Petkov9c6e9812013-03-26 13:49:07 +010056 string host = args.LookupString(flimflam::kProviderHostProperty, "");
57 if (host.empty()) {
58 Error::PopulateAndLog(
59 error, Error::kNotSupported, "Missing VPN host property.");
Paul Stewartbc14fb72013-07-30 08:21:58 -070060 return false;
61 }
62
63 *type_ptr = type,
64 *host_ptr = host,
65 *name_ptr = args.LookupString(flimflam::kNameProperty, "");
66
67 return true;
68}
69
70ServiceRefPtr VPNProvider::GetService(const KeyValueStore &args,
71 Error *error) {
72 SLOG(VPN, 2) << __func__;
73 string type;
74 string name;
75 string host;
76
77 if (!GetServiceParametersFromArgs(args, &type, &name, &host, error)) {
Darin Petkov9c6e9812013-03-26 13:49:07 +010078 return NULL;
79 }
80
Darin Petkov02867712012-03-12 14:25:05 +010081 string storage_id = VPNService::CreateStorageIdentifier(args, error);
82 if (storage_id.empty()) {
83 return NULL;
84 }
85
Darin Petkov9c6e9812013-03-26 13:49:07 +010086 // Find a service in the provider list which matches these parameters.
87 VPNServiceRefPtr service = FindService(type, name, host);
88 if (service == NULL) {
89 service = CreateService(type, name, storage_id, error);
90 }
Darin Petkov79d74c92012-03-07 17:20:32 +010091 return service;
Paul Stewartca6abd42012-03-01 15:45:29 -080092}
93
Paul Stewartbc14fb72013-07-30 08:21:58 -070094ServiceRefPtr VPNProvider::FindSimilarService(const KeyValueStore &args,
95 Error *error) const {
96 SLOG(VPN, 2) << __func__;
97 string type;
98 string name;
99 string host;
100
101 if (!GetServiceParametersFromArgs(args, &type, &name, &host, error)) {
102 return NULL;
103 }
104
105 // Find a service in the provider list which matches these parameters.
106 VPNServiceRefPtr service = FindService(type, name, host);
107 if (!service) {
108 error->Populate(Error::kNotFound, "Matching service was not found");
109 }
110
111 return service;
112}
113
Paul Stewartca6abd42012-03-01 15:45:29 -0800114bool VPNProvider::OnDeviceInfoAvailable(const string &link_name,
115 int interface_index) {
116 for (vector<VPNServiceRefPtr>::const_iterator it = services_.begin();
117 it != services_.end();
118 ++it) {
119 if ((*it)->driver()->ClaimInterface(link_name, interface_index)) {
120 return true;
121 }
122 }
123
124 return false;
Darin Petkov33af05c2012-02-28 10:10:30 +0100125}
126
Paul Stewart65512e12012-03-26 18:01:08 -0700127void VPNProvider::RemoveService(VPNServiceRefPtr service) {
128 vector<VPNServiceRefPtr>::iterator it;
129 it = std::find(services_.begin(), services_.end(), service);
130 if (it != services_.end()) {
131 services_.erase(it);
132 }
133}
134
Paul Stewart0e51ad92013-07-26 14:42:55 -0700135void VPNProvider::CreateServicesFromProfile(const ProfileRefPtr &profile) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700136 SLOG(VPN, 2) << __func__;
Paul Stewart66815332012-04-09 18:09:36 -0700137 const StoreInterface *storage = profile->GetConstStorage();
138 set<string> groups =
139 storage->GetGroupsWithKey(flimflam::kProviderTypeProperty);
140 for (set<string>::iterator it = groups.begin(); it != groups.end(); ++it) {
141 if (!StartsWithASCII(*it, "vpn_", false)) {
142 continue;
143 }
144
145 string type;
146 if (!storage->GetString(*it, flimflam::kProviderTypeProperty, &type)) {
147 LOG(ERROR) << "Group " << *it << " is missing the "
148 << flimflam::kProviderTypeProperty << " property.";
149 continue;
150 }
151
Paul Stewart451aa7f2012-04-11 19:07:58 -0700152 string name;
Darin Petkov4e02ba22013-04-02 13:44:08 +0200153 if (!storage->GetString(*it, flimflam::kNameProperty, &name)) {
Paul Stewart451aa7f2012-04-11 19:07:58 -0700154 LOG(ERROR) << "Group " << *it << " is missing the "
Darin Petkov4e02ba22013-04-02 13:44:08 +0200155 << flimflam::kNameProperty << " property.";
Paul Stewart451aa7f2012-04-11 19:07:58 -0700156 continue;
157 }
158
Darin Petkov9c6e9812013-03-26 13:49:07 +0100159 string host;
160 if (!storage->GetString(*it, flimflam::kProviderHostProperty, &host)) {
161 LOG(ERROR) << "Group " << *it << " is missing the "
162 << flimflam::kProviderHostProperty << " property.";
163 continue;
164 }
165
166 VPNServiceRefPtr service = FindService(type, name, host);
Paul Stewart66815332012-04-09 18:09:36 -0700167 if (service != NULL) {
168 // If the service already exists, it does not need to be configured,
169 // since PushProfile would have already called ConfigureService on it.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700170 SLOG(VPN, 2) << "Service already exists " << *it;
Paul Stewart66815332012-04-09 18:09:36 -0700171 continue;
172 }
173
Paul Stewart66815332012-04-09 18:09:36 -0700174 Error error;
Paul Stewart451aa7f2012-04-11 19:07:58 -0700175 service = CreateService(type, name, *it, &error);
Paul Stewart66815332012-04-09 18:09:36 -0700176
177 if (service == NULL) {
178 LOG(ERROR) << "Could not create service for " << *it;
179 continue;
180 }
181
182 if (!profile->ConfigureService(service)) {
183 LOG(ERROR) << "Could not configure service for " << *it;
184 continue;
185 }
186 }
187}
188
Paul Stewartbc14fb72013-07-30 08:21:58 -0700189VPNServiceRefPtr VPNProvider::CreateServiceInner(const string &type,
190 const string &name,
191 const string &storage_id,
192 Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700193 SLOG(VPN, 2) << __func__ << " type " << type << " name " << name
194 << " storage id " << storage_id;
Darin Petkovc3505a52013-03-18 15:13:29 +0100195#if defined(DISABLE_VPN)
196
197 Error::PopulateAndLog(error, Error::kNotSupported, "VPN is not supported.");
198 return NULL;
199
200#else
201
Paul Stewart66815332012-04-09 18:09:36 -0700202 scoped_ptr<VPNDriver> driver;
203 if (type == flimflam::kProviderOpenVpn) {
204 driver.reset(new OpenVPNDriver(
205 control_interface_, dispatcher_, metrics_, manager_,
Paul Stewart451aa7f2012-04-11 19:07:58 -0700206 manager_->device_info(), manager_->glib()));
Darin Petkov9d1bbe72012-04-25 10:58:59 +0200207 } else if (type == flimflam::kProviderL2tpIpsec) {
208 driver.reset(new L2TPIPSecDriver(
209 control_interface_, dispatcher_, metrics_, manager_,
210 manager_->device_info(), manager_->glib()));
Paul Stewart66815332012-04-09 18:09:36 -0700211 } else {
212 Error::PopulateAndLog(
213 error, Error::kNotSupported, "Unsupported VPN type: " + type);
214 return NULL;
215 }
216
217 VPNServiceRefPtr service = new VPNService(
218 control_interface_, dispatcher_, metrics_, manager_, driver.release());
219 service->set_storage_id(storage_id);
220 service->InitDriverPropertyStore();
Paul Stewart66815332012-04-09 18:09:36 -0700221 if (!name.empty()) {
222 service->set_friendly_name(name);
223 }
Paul Stewart66815332012-04-09 18:09:36 -0700224 return service;
Darin Petkovc3505a52013-03-18 15:13:29 +0100225
226#endif // DISABLE_VPN
Paul Stewart66815332012-04-09 18:09:36 -0700227}
228
Paul Stewartbc14fb72013-07-30 08:21:58 -0700229VPNServiceRefPtr VPNProvider::CreateService(const string &type,
230 const string &name,
231 const string &storage_id,
232 Error *error) {
233 VPNServiceRefPtr service = CreateServiceInner(type, name, storage_id, error);
234 if (service) {
235 services_.push_back(service);
236 manager_->RegisterService(service);
237 }
238
239 return service;
240}
241
Darin Petkov9c6e9812013-03-26 13:49:07 +0100242VPNServiceRefPtr VPNProvider::FindService(const string &type,
243 const string &name,
Paul Stewartbc14fb72013-07-30 08:21:58 -0700244 const string &host) const {
Paul Stewart66815332012-04-09 18:09:36 -0700245 for (vector<VPNServiceRefPtr>::const_iterator it = services_.begin();
246 it != services_.end();
247 ++it) {
248 if (type == (*it)->driver()->GetProviderType() &&
Darin Petkov9c6e9812013-03-26 13:49:07 +0100249 name == (*it)->friendly_name() &&
250 host == (*it)->driver()->GetHost()) {
Paul Stewart66815332012-04-09 18:09:36 -0700251 return *it;
252 }
253 }
Paul Stewart66815332012-04-09 18:09:36 -0700254 return NULL;
255}
256
Paul Stewartbc14fb72013-07-30 08:21:58 -0700257ServiceRefPtr VPNProvider::CreateTemporaryService(
258 const KeyValueStore &args, Error *error) {
259 string type;
260 string name;
261 string host;
262
263 if (!GetServiceParametersFromArgs(args, &type, &name, &host, error)) {
264 return NULL;
265 }
266
267 string storage_id = VPNService::CreateStorageIdentifier(args, error);
268 if (storage_id.empty()) {
269 return NULL;
270 }
271
272 return CreateServiceInner(type, name, storage_id, error);
273}
274
Darin Petkov4cbff5b2013-01-29 16:29:05 +0100275bool VPNProvider::HasActiveService() const {
276 for (vector<VPNServiceRefPtr>::const_iterator it = services_.begin();
277 it != services_.end(); ++it) {
278 if ((*it)->IsConnecting() || (*it)->IsConnected()) {
279 return true;
280 }
281 }
282 return false;
283}
284
Darin Petkov33af05c2012-02-28 10:10:30 +0100285} // namespace shill