blob: 4255f24250c63f2312cd921bca471c60f1e80923 [file] [log] [blame]
Darin Petkov1c115202012-03-22 15:35:47 +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/openvpn_management_server.h"
6
Darin Petkov46463022012-03-29 14:57:32 +02007#include <arpa/inet.h>
Darin Petkov78f63262012-03-26 01:30:24 +02008#include <netinet/in.h>
9
10#include <base/bind.h>
Ben Chana0ddf462014-02-06 11:32:42 -080011#include <base/strings/string_number_conversions.h>
12#include <base/strings/string_split.h>
13#include <base/strings/string_util.h>
14#include <base/strings/stringprintf.h>
Darin Petkov683942b2012-03-27 18:00:04 +020015#include <chromeos/dbus/service_constants.h>
Darin Petkov78f63262012-03-26 01:30:24 +020016
Darin Petkov3273da72013-02-13 11:50:25 +010017#include "shill/error.h"
Darin Petkov78f63262012-03-26 01:30:24 +020018#include "shill/event_dispatcher.h"
Darin Petkov683942b2012-03-27 18:00:04 +020019#include "shill/glib.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070020#include "shill/logging.h"
Darin Petkov271fe522012-03-27 13:47:29 +020021#include "shill/openvpn_driver.h"
Darin Petkov78f63262012-03-26 01:30:24 +020022#include "shill/sockets.h"
23
24using base::Bind;
Darin Petkov46463022012-03-29 14:57:32 +020025using base::IntToString;
Darin Petkov78f63262012-03-26 01:30:24 +020026using base::SplitString;
27using base::StringPrintf;
Darin Petkov3273da72013-02-13 11:50:25 +010028using base::Unretained;
Darin Petkov78f63262012-03-26 01:30:24 +020029using std::string;
30using std::vector;
Darin Petkov1c115202012-03-22 15:35:47 +010031
32namespace shill {
33
Darin Petkovaba89322013-03-11 14:48:22 +010034namespace {
35const char kPasswordTagAuth[] = "Auth";
36} // namespace
37
Darin Petkov1c049c72013-03-21 13:15:45 +010038const char OpenVPNManagementServer::kStateReconnecting[] = "RECONNECTING";
39const char OpenVPNManagementServer::kStateResolve[] = "RESOLVE";
40
Darin Petkov683942b2012-03-27 18:00:04 +020041OpenVPNManagementServer::OpenVPNManagementServer(OpenVPNDriver *driver,
42 GLib *glib)
Darin Petkov78f63262012-03-26 01:30:24 +020043 : driver_(driver),
Darin Petkov683942b2012-03-27 18:00:04 +020044 glib_(glib),
Darin Petkov78f63262012-03-26 01:30:24 +020045 sockets_(NULL),
46 socket_(-1),
47 dispatcher_(NULL),
Darin Petkova5e07ef2012-07-09 14:27:57 +020048 connected_socket_(-1),
49 hold_waiting_(false),
50 hold_release_(false) {}
Darin Petkov1c115202012-03-22 15:35:47 +010051
Darin Petkov78f63262012-03-26 01:30:24 +020052OpenVPNManagementServer::~OpenVPNManagementServer() {
Darin Petkov46463022012-03-29 14:57:32 +020053 OpenVPNManagementServer::Stop();
Darin Petkov78f63262012-03-26 01:30:24 +020054}
Darin Petkov1c115202012-03-22 15:35:47 +010055
Darin Petkov78f63262012-03-26 01:30:24 +020056bool OpenVPNManagementServer::Start(EventDispatcher *dispatcher,
Darin Petkov46463022012-03-29 14:57:32 +020057 Sockets *sockets,
Paul Stewart406c4732013-08-01 09:30:12 -070058 vector<vector<string>> *options) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070059 SLOG(VPN, 2) << __func__;
Darin Petkove08084d2012-06-11 13:19:35 +020060 if (IsStarted()) {
Darin Petkov78f63262012-03-26 01:30:24 +020061 return true;
62 }
63
Darin Petkov271fe522012-03-27 13:47:29 +020064 int socket = sockets->Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
Darin Petkov78f63262012-03-26 01:30:24 +020065 if (socket < 0) {
66 PLOG(ERROR) << "Unable to create management server socket.";
67 return false;
68 }
69
70 struct sockaddr_in addr;
71 socklen_t addrlen = sizeof(addr);
72 memset(&addr, 0, sizeof(addr));
73 addr.sin_family = AF_INET;
74 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
75 if (sockets->Bind(
76 socket, reinterpret_cast<struct sockaddr *>(&addr), addrlen) < 0 ||
77 sockets->Listen(socket, 1) < 0 ||
78 sockets->GetSockName(
79 socket, reinterpret_cast<struct sockaddr *>(&addr), &addrlen) < 0) {
80 PLOG(ERROR) << "Socket setup failed.";
81 sockets->Close(socket);
82 return false;
83 }
84
Ben Chanfad4a0b2012-04-18 15:49:59 -070085 SLOG(VPN, 2) << "Listening socket: " << socket;
Darin Petkov271fe522012-03-27 13:47:29 +020086 sockets_ = sockets;
Darin Petkov78f63262012-03-26 01:30:24 +020087 socket_ = socket;
88 ready_handler_.reset(
89 dispatcher->CreateReadyHandler(
Darin Petkov3273da72013-02-13 11:50:25 +010090 socket, IOHandler::kModeInput,
91 Bind(&OpenVPNManagementServer::OnReady, Unretained(this))));
Darin Petkov78f63262012-03-26 01:30:24 +020092 dispatcher_ = dispatcher;
Darin Petkov46463022012-03-29 14:57:32 +020093
94 // Append openvpn management API options.
Paul Stewartb26347a2013-08-02 12:12:09 -070095 driver_->AppendOption("management", inet_ntoa(addr.sin_addr),
Paul Stewart406c4732013-08-01 09:30:12 -070096 IntToString(ntohs(addr.sin_port)), options);
Paul Stewartb26347a2013-08-02 12:12:09 -070097 driver_->AppendOption("management-client", options);
98 driver_->AppendOption("management-hold", options);
Darin Petkova5e07ef2012-07-09 14:27:57 +020099 hold_release_ = false;
100 hold_waiting_ = false;
101
Paul Stewartb26347a2013-08-02 12:12:09 -0700102 driver_->AppendOption("management-query-passwords", options);
Ben Chan73728782013-09-20 13:40:54 -0700103 if (driver_->AppendValueOption(kOpenVPNStaticChallengeProperty,
Paul Stewartb26347a2013-08-02 12:12:09 -0700104 "static-challenge",
Darin Petkov46463022012-03-29 14:57:32 +0200105 options)) {
Paul Stewart406c4732013-08-01 09:30:12 -0700106 options->back().push_back("1"); // Force echo.
Darin Petkov46463022012-03-29 14:57:32 +0200107 }
Darin Petkov78f63262012-03-26 01:30:24 +0200108 return true;
109}
110
111void OpenVPNManagementServer::Stop() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700112 SLOG(VPN, 2) << __func__;
Darin Petkove08084d2012-06-11 13:19:35 +0200113 if (!IsStarted()) {
Darin Petkov78f63262012-03-26 01:30:24 +0200114 return;
115 }
Darin Petkov1c049c72013-03-21 13:15:45 +0100116 state_.clear();
Darin Petkov78f63262012-03-26 01:30:24 +0200117 input_handler_.reset();
118 if (connected_socket_ >= 0) {
119 sockets_->Close(connected_socket_);
120 connected_socket_ = -1;
121 }
122 dispatcher_ = NULL;
123 ready_handler_.reset();
124 if (socket_ >= 0) {
125 sockets_->Close(socket_);
126 socket_ = -1;
127 }
128 sockets_ = NULL;
129}
130
Darin Petkova5e07ef2012-07-09 14:27:57 +0200131void OpenVPNManagementServer::ReleaseHold() {
132 SLOG(VPN, 2) << __func__;
133 hold_release_ = true;
134 if (!hold_waiting_) {
135 return;
136 }
137 LOG(INFO) << "Releasing hold.";
138 hold_waiting_ = false;
139 SendHoldRelease();
140}
141
142void OpenVPNManagementServer::Hold() {
143 SLOG(VPN, 2) << __func__;
144 hold_release_ = false;
145}
146
Darin Petkova42afe32013-02-05 16:53:52 +0100147void OpenVPNManagementServer::Restart() {
148 LOG(INFO) << "Restart.";
149 SendSignal("SIGUSR1");
150}
151
Darin Petkov78f63262012-03-26 01:30:24 +0200152void OpenVPNManagementServer::OnReady(int fd) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700153 SLOG(VPN, 2) << __func__ << "(" << fd << ")";
Darin Petkov78f63262012-03-26 01:30:24 +0200154 connected_socket_ = sockets_->Accept(fd, NULL, NULL);
155 if (connected_socket_ < 0) {
156 PLOG(ERROR) << "Connected socket accept failed.";
157 return;
158 }
159 ready_handler_.reset();
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800160 input_handler_.reset(dispatcher_->CreateInputHandler(
Darin Petkov3273da72013-02-13 11:50:25 +0100161 connected_socket_,
162 Bind(&OpenVPNManagementServer::OnInput, Unretained(this)),
163 Bind(&OpenVPNManagementServer::OnInputError, Unretained(this))));
Darin Petkov78f63262012-03-26 01:30:24 +0200164 SendState("on");
165}
166
167void OpenVPNManagementServer::OnInput(InputData *data) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700168 SLOG(VPN, 2) << __func__ << "(" << data->len << ")";
Darin Petkov78f63262012-03-26 01:30:24 +0200169 vector<string> messages;
170 SplitString(
171 string(reinterpret_cast<char *>(data->buf), data->len), '\n', &messages);
172 for (vector<string>::const_iterator it = messages.begin();
Darin Petkove08084d2012-06-11 13:19:35 +0200173 it != messages.end() && IsStarted(); ++it) {
Darin Petkov78f63262012-03-26 01:30:24 +0200174 ProcessMessage(*it);
175 }
176}
177
Darin Petkov3273da72013-02-13 11:50:25 +0100178void OpenVPNManagementServer::OnInputError(const Error &error) {
179 LOG(ERROR) << error;
Darin Petkov1c049c72013-03-21 13:15:45 +0100180 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkov3273da72013-02-13 11:50:25 +0100181}
182
Darin Petkov78f63262012-03-26 01:30:24 +0200183void OpenVPNManagementServer::ProcessMessage(const string &message) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700184 SLOG(VPN, 2) << __func__ << "(" << message << ")";
Darin Petkov92e65612012-06-10 12:52:10 +0200185 if (message.empty()) {
186 return;
187 }
188 if (!ProcessInfoMessage(message) &&
189 !ProcessNeedPasswordMessage(message) &&
190 !ProcessFailedPasswordMessage(message) &&
Darin Petkov16e70322013-03-07 15:54:23 +0100191 !ProcessAuthTokenMessage(message) &&
Darin Petkova5e07ef2012-07-09 14:27:57 +0200192 !ProcessStateMessage(message) &&
Darin Petkova42afe32013-02-05 16:53:52 +0100193 !ProcessHoldMessage(message) &&
194 !ProcessSuccessMessage(message)) {
Darin Petkov16e70322013-03-07 15:54:23 +0100195 LOG(WARNING) << "Message ignored: " << message;
Darin Petkov92e65612012-06-10 12:52:10 +0200196 }
Darin Petkov271fe522012-03-27 13:47:29 +0200197}
198
199bool OpenVPNManagementServer::ProcessInfoMessage(const string &message) {
Darin Petkov92e65612012-06-10 12:52:10 +0200200 if (!StartsWithASCII(message, ">INFO:", true)) {
201 return false;
202 }
Darin Petkova42afe32013-02-05 16:53:52 +0100203 LOG(INFO) << message;
Darin Petkov92e65612012-06-10 12:52:10 +0200204 return true;
Darin Petkov271fe522012-03-27 13:47:29 +0200205}
206
207bool OpenVPNManagementServer::ProcessNeedPasswordMessage(
208 const string &message) {
209 if (!StartsWithASCII(message, ">PASSWORD:Need ", true)) {
210 return false;
Darin Petkov78f63262012-03-26 01:30:24 +0200211 }
Darin Petkov92e65612012-06-10 12:52:10 +0200212 LOG(INFO) << "Processing need-password message.";
Darin Petkovaba89322013-03-11 14:48:22 +0100213 string tag = ParsePasswordTag(message);
214 if (tag == kPasswordTagAuth) {
Darin Petkov683942b2012-03-27 18:00:04 +0200215 if (message.find("SC:") != string::npos) {
Darin Petkove0d5dd12012-04-04 16:10:48 +0200216 PerformStaticChallenge(tag);
Darin Petkov683942b2012-03-27 18:00:04 +0200217 } else {
Darin Petkovdaaa5532012-07-24 15:37:55 +0200218 PerformAuthentication(tag);
Darin Petkov683942b2012-03-27 18:00:04 +0200219 }
Darin Petkove0d5dd12012-04-04 16:10:48 +0200220 } else if (StartsWithASCII(tag, "User-Specific TPM Token", true)) {
221 SupplyTPMToken(tag);
Darin Petkov92e65612012-06-10 12:52:10 +0200222 } else {
223 NOTIMPLEMENTED() << ": Unsupported need-password message: " << message;
Darin Petkov1c049c72013-03-21 13:15:45 +0100224 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkov683942b2012-03-27 18:00:04 +0200225 }
Darin Petkov271fe522012-03-27 13:47:29 +0200226 return true;
227}
228
Darin Petkove0d5dd12012-04-04 16:10:48 +0200229// static
Darin Petkovaba89322013-03-11 14:48:22 +0100230string OpenVPNManagementServer::ParseSubstring(const string &message,
231 const string &start,
232 const string &end) {
233 SLOG(VPN, 2) << __func__ << "(" << message
234 << ", " << start << ", " << end << ")";
235 DCHECK(!start.empty() && !end.empty());
236 size_t start_pos = message.find(start);
237 if (start_pos == string::npos) {
Darin Petkove0d5dd12012-04-04 16:10:48 +0200238 return string();
239 }
Darin Petkovaba89322013-03-11 14:48:22 +0100240 size_t end_pos = message.find(end, start_pos + start.size());
241 if (end_pos == string::npos) {
Darin Petkove0d5dd12012-04-04 16:10:48 +0200242 return string();
243 }
Darin Petkovaba89322013-03-11 14:48:22 +0100244 return message.substr(start_pos + start.size(),
245 end_pos - start_pos - start.size());
246}
247
248// static
249string OpenVPNManagementServer::ParsePasswordTag(const string &message) {
250 return ParseSubstring(message, "'", "'");
251}
252
253// static
254string OpenVPNManagementServer::ParsePasswordFailedReason(
255 const string &message) {
256 return ParseSubstring(message, "['", "']");
Darin Petkove0d5dd12012-04-04 16:10:48 +0200257}
258
259void OpenVPNManagementServer::PerformStaticChallenge(const string &tag) {
Darin Petkov92e65612012-06-10 12:52:10 +0200260 LOG(INFO) << "Perform static challenge: " << tag;
Ben Chan73728782013-09-20 13:40:54 -0700261 string user = driver_->args()->LookupString(kOpenVPNUserProperty, "");
262 string password = driver_->args()->LookupString(kOpenVPNPasswordProperty, "");
263 string otp = driver_->args()->LookupString(kOpenVPNOTPProperty, "");
Paul Stewartb5768232014-02-27 07:21:34 -0800264 string token = driver_->args()->LookupString(kOpenVPNTokenProperty, "");
265 if (user.empty() || (token.empty() && (password.empty() || otp.empty()))) {
Darin Petkove08084d2012-06-11 13:19:35 +0200266 NOTIMPLEMENTED() << ": Missing credentials:"
267 << (user.empty() ? " no-user" : "")
Paul Stewartb5768232014-02-27 07:21:34 -0800268 << (token.empty() ? " no-token" : "")
Darin Petkove08084d2012-06-11 13:19:35 +0200269 << (password.empty() ? " no-password" : "")
270 << (otp.empty() ? " no-otp" : "");
Darin Petkov1c049c72013-03-21 13:15:45 +0100271 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkov683942b2012-03-27 18:00:04 +0200272 return;
273 }
Paul Stewartb5768232014-02-27 07:21:34 -0800274
275 string password_encoded;
276 if (!token.empty()) {
Paul Stewart5351cbd2014-03-12 09:07:44 -0700277 password_encoded = token;
Paul Stewartb5768232014-02-27 07:21:34 -0800278 // Don't reuse token.
279 driver_->args()->RemoveString(kOpenVPNTokenProperty);
280 } else {
281 string b64_password;
282 string b64_otp;
283 if (!glib_->B64Encode(password, &b64_password) ||
284 !glib_->B64Encode(otp, &b64_otp)) {
285 LOG(ERROR) << "Unable to base64-encode credentials.";
286 return;
287 }
288 password_encoded = StringPrintf("SCRV1:%s:%s",
289 b64_password.c_str(),
290 b64_otp.c_str());
291 // Don't reuse OTP.
292 driver_->args()->RemoveString(kOpenVPNOTPProperty);
Darin Petkov683942b2012-03-27 18:00:04 +0200293 }
Darin Petkove0d5dd12012-04-04 16:10:48 +0200294 SendUsername(tag, user);
Paul Stewartb5768232014-02-27 07:21:34 -0800295 SendPassword(tag, password_encoded);
Darin Petkov683942b2012-03-27 18:00:04 +0200296}
297
Darin Petkovdaaa5532012-07-24 15:37:55 +0200298void OpenVPNManagementServer::PerformAuthentication(const string &tag) {
299 LOG(INFO) << "Perform authentication: " << tag;
Ben Chan73728782013-09-20 13:40:54 -0700300 string user = driver_->args()->LookupString(kOpenVPNUserProperty, "");
301 string password = driver_->args()->LookupString(kOpenVPNPasswordProperty, "");
Darin Petkovdaaa5532012-07-24 15:37:55 +0200302 if (user.empty() || password.empty()) {
303 NOTIMPLEMENTED() << ": Missing credentials:"
304 << (user.empty() ? " no-user" : "")
305 << (password.empty() ? " no-password" : "");
Darin Petkov1c049c72013-03-21 13:15:45 +0100306 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkovdaaa5532012-07-24 15:37:55 +0200307 return;
308 }
309 SendUsername(tag, user);
310 SendPassword(tag, password);
311}
312
Darin Petkove0d5dd12012-04-04 16:10:48 +0200313void OpenVPNManagementServer::SupplyTPMToken(const string &tag) {
Darin Petkov92e65612012-06-10 12:52:10 +0200314 SLOG(VPN, 2) << __func__ << "(" << tag << ")";
Ben Chan73728782013-09-20 13:40:54 -0700315 string pin = driver_->args()->LookupString(kOpenVPNPinProperty, "");
Darin Petkove0d5dd12012-04-04 16:10:48 +0200316 if (pin.empty()) {
Darin Petkov0440b9b2012-04-17 16:11:56 +0200317 NOTIMPLEMENTED() << ": Missing PIN.";
Darin Petkov1c049c72013-03-21 13:15:45 +0100318 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkove0d5dd12012-04-04 16:10:48 +0200319 return;
320 }
321 SendPassword(tag, pin);
322}
323
Darin Petkov271fe522012-03-27 13:47:29 +0200324bool OpenVPNManagementServer::ProcessFailedPasswordMessage(
325 const string &message) {
326 if (!StartsWithASCII(message, ">PASSWORD:Verification Failed:", true)) {
327 return false;
Darin Petkov78f63262012-03-26 01:30:24 +0200328 }
Darin Petkovaba89322013-03-11 14:48:22 +0100329 LOG(INFO) << message;
330 string reason;
331 if (ParsePasswordTag(message) == kPasswordTagAuth) {
332 reason = ParsePasswordFailedReason(message);
333 }
Darin Petkov1c049c72013-03-21 13:15:45 +0100334 driver_->FailService(Service::kFailureConnect, reason);
Darin Petkov271fe522012-03-27 13:47:29 +0200335 return true;
336}
337
Darin Petkov16e70322013-03-07 15:54:23 +0100338bool OpenVPNManagementServer::ProcessAuthTokenMessage(const string &message) {
339 if (!StartsWithASCII(message, ">PASSWORD:Auth-Token:", true)) {
340 return false;
341 }
342 LOG(INFO) << "Auth-Token message ignored.";
343 return true;
344}
345
Darin Petkov271fe522012-03-27 13:47:29 +0200346// >STATE:* message support. State messages are of the form:
347// >STATE:<date>,<state>,<detail>,<local-ip>,<remote-ip>
348// where:
349// <date> is the current time (since epoch) in seconds
350// <state> is one of:
351// INITIAL, CONNECTING, WAIT, AUTH, GET_CONFIG, ASSIGN_IP, ADD_ROUTES,
352// CONNECTED, RECONNECTING, EXITING, RESOLVE, TCP_CONNECT
353// <detail> is a free-form string giving details about the state change
354// <local-ip> is a dotted-quad for the local IPv4 address (when available)
355// <remote-ip> is a dotted-quad for the remote IPv4 address (when available)
356bool OpenVPNManagementServer::ProcessStateMessage(const string &message) {
357 if (!StartsWithASCII(message, ">STATE:", true)) {
358 return false;
Darin Petkov78f63262012-03-26 01:30:24 +0200359 }
Darin Petkov271fe522012-03-27 13:47:29 +0200360 vector<string> details;
361 SplitString(message, ',', &details);
362 if (details.size() > 1) {
Darin Petkov1c049c72013-03-21 13:15:45 +0100363 state_ = details[1];
364 LOG(INFO) << "OpenVPN state: " << state_;
365 if (state_ == kStateReconnecting) {
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100366 OpenVPNDriver::ReconnectReason reason =
367 OpenVPNDriver::kReconnectReasonUnknown;
368 if (details.size() > 2 && details[2] == "tls-error") {
369 reason = OpenVPNDriver::kReconnectReasonTLSError;
370 }
371 driver_->OnReconnecting(reason);
Darin Petkov271fe522012-03-27 13:47:29 +0200372 }
Darin Petkov78f63262012-03-26 01:30:24 +0200373 }
Darin Petkov1c049c72013-03-21 13:15:45 +0100374
Darin Petkov271fe522012-03-27 13:47:29 +0200375 return true;
Darin Petkov78f63262012-03-26 01:30:24 +0200376}
377
Darin Petkova5e07ef2012-07-09 14:27:57 +0200378bool OpenVPNManagementServer::ProcessHoldMessage(const string &message) {
379 if (!StartsWithASCII(message, ">HOLD:Waiting for hold release", true)) {
380 return false;
381 }
Darin Petkova42afe32013-02-05 16:53:52 +0100382 LOG(INFO) << "Client waiting for hold release.";
Darin Petkova5e07ef2012-07-09 14:27:57 +0200383 hold_waiting_ = true;
384 if (hold_release_) {
385 ReleaseHold();
386 }
387 return true;
388}
389
Darin Petkova42afe32013-02-05 16:53:52 +0100390bool OpenVPNManagementServer::ProcessSuccessMessage(const string &message) {
391 if (!StartsWithASCII(message, "SUCCESS: ", true)) {
392 return false;
393 }
394 LOG(INFO) << message;
395 return true;
396}
397
Darin Petkovdaaa5532012-07-24 15:37:55 +0200398// static
399string OpenVPNManagementServer::EscapeToQuote(const string &str) {
400 string escaped;
401 for (string::const_iterator it = str.begin(); it != str.end(); ++it) {
402 if (*it == '\\' || *it == '"') {
403 escaped += '\\';
404 }
405 escaped += *it;
406 }
407 return escaped;
408}
409
Darin Petkov78f63262012-03-26 01:30:24 +0200410void OpenVPNManagementServer::Send(const string &data) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700411 SLOG(VPN, 2) << __func__;
Darin Petkov78f63262012-03-26 01:30:24 +0200412 ssize_t len = sockets_->Send(connected_socket_, data.data(), data.size(), 0);
413 PLOG_IF(ERROR, len < 0 || static_cast<size_t>(len) != data.size())
Darin Petkov683942b2012-03-27 18:00:04 +0200414 << "Send failed.";
Darin Petkov78f63262012-03-26 01:30:24 +0200415}
416
417void OpenVPNManagementServer::SendState(const string &state) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700418 SLOG(VPN, 2) << __func__ << "(" << state << ")";
Darin Petkov78f63262012-03-26 01:30:24 +0200419 Send(StringPrintf("state %s\n", state.c_str()));
Darin Petkov1c115202012-03-22 15:35:47 +0100420}
421
Darin Petkov683942b2012-03-27 18:00:04 +0200422void OpenVPNManagementServer::SendUsername(const string &tag,
423 const string &username) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700424 SLOG(VPN, 2) << __func__;
Darin Petkov683942b2012-03-27 18:00:04 +0200425 Send(StringPrintf("username \"%s\" %s\n", tag.c_str(), username.c_str()));
426}
427
428void OpenVPNManagementServer::SendPassword(const string &tag,
429 const string &password) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700430 SLOG(VPN, 2) << __func__;
Darin Petkovdaaa5532012-07-24 15:37:55 +0200431 Send(StringPrintf("password \"%s\" \"%s\"\n",
432 tag.c_str(),
433 EscapeToQuote(password).c_str()));
Darin Petkov683942b2012-03-27 18:00:04 +0200434}
435
Darin Petkova42afe32013-02-05 16:53:52 +0100436void OpenVPNManagementServer::SendSignal(const string &signal) {
437 SLOG(VPN, 2) << __func__ << "(" << signal << ")";
438 Send(StringPrintf("signal %s\n", signal.c_str()));
439}
440
Darin Petkova5e07ef2012-07-09 14:27:57 +0200441void OpenVPNManagementServer::SendHoldRelease() {
442 SLOG(VPN, 2) << __func__;
443 Send("hold release\n");
444}
445
Darin Petkov1c115202012-03-22 15:35:47 +0100446} // namespace shill