blob: c170f21977a5735ab255bf00e4340e655bcb6b30 [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>
Darin Petkov46463022012-03-29 14:57:32 +020011#include <base/string_number_conversions.h>
Darin Petkov78f63262012-03-26 01:30:24 +020012#include <base/string_split.h>
13#include <base/string_util.h>
14#include <base/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,
58 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.
95 options->push_back("--management");
96 options->push_back(inet_ntoa(addr.sin_addr));
97 options->push_back(IntToString(ntohs(addr.sin_port)));
98 options->push_back("--management-client");
Darin Petkova5e07ef2012-07-09 14:27:57 +020099
100 options->push_back("--management-hold");
101 hold_release_ = false;
102 hold_waiting_ = false;
103
Darin Petkov46463022012-03-29 14:57:32 +0200104 options->push_back("--management-query-passwords");
Darin Petkov46463022012-03-29 14:57:32 +0200105 if (driver_->AppendValueOption(flimflam::kOpenVPNStaticChallengeProperty,
106 "--static-challenge",
107 options)) {
108 options->push_back("1"); // Force echo.
109 }
Darin Petkov78f63262012-03-26 01:30:24 +0200110 return true;
111}
112
113void OpenVPNManagementServer::Stop() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700114 SLOG(VPN, 2) << __func__;
Darin Petkove08084d2012-06-11 13:19:35 +0200115 if (!IsStarted()) {
Darin Petkov78f63262012-03-26 01:30:24 +0200116 return;
117 }
Darin Petkov1c049c72013-03-21 13:15:45 +0100118 state_.clear();
Darin Petkov78f63262012-03-26 01:30:24 +0200119 input_handler_.reset();
120 if (connected_socket_ >= 0) {
121 sockets_->Close(connected_socket_);
122 connected_socket_ = -1;
123 }
124 dispatcher_ = NULL;
125 ready_handler_.reset();
126 if (socket_ >= 0) {
127 sockets_->Close(socket_);
128 socket_ = -1;
129 }
130 sockets_ = NULL;
131}
132
Darin Petkova5e07ef2012-07-09 14:27:57 +0200133void OpenVPNManagementServer::ReleaseHold() {
134 SLOG(VPN, 2) << __func__;
135 hold_release_ = true;
136 if (!hold_waiting_) {
137 return;
138 }
139 LOG(INFO) << "Releasing hold.";
140 hold_waiting_ = false;
141 SendHoldRelease();
142}
143
144void OpenVPNManagementServer::Hold() {
145 SLOG(VPN, 2) << __func__;
146 hold_release_ = false;
147}
148
Darin Petkova42afe32013-02-05 16:53:52 +0100149void OpenVPNManagementServer::Restart() {
150 LOG(INFO) << "Restart.";
151 SendSignal("SIGUSR1");
152}
153
Darin Petkov78f63262012-03-26 01:30:24 +0200154void OpenVPNManagementServer::OnReady(int fd) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700155 SLOG(VPN, 2) << __func__ << "(" << fd << ")";
Darin Petkov78f63262012-03-26 01:30:24 +0200156 connected_socket_ = sockets_->Accept(fd, NULL, NULL);
157 if (connected_socket_ < 0) {
158 PLOG(ERROR) << "Connected socket accept failed.";
159 return;
160 }
161 ready_handler_.reset();
Paul Stewart5f06a0e2012-12-20 11:11:33 -0800162 input_handler_.reset(dispatcher_->CreateInputHandler(
Darin Petkov3273da72013-02-13 11:50:25 +0100163 connected_socket_,
164 Bind(&OpenVPNManagementServer::OnInput, Unretained(this)),
165 Bind(&OpenVPNManagementServer::OnInputError, Unretained(this))));
Darin Petkov78f63262012-03-26 01:30:24 +0200166 SendState("on");
167}
168
169void OpenVPNManagementServer::OnInput(InputData *data) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700170 SLOG(VPN, 2) << __func__ << "(" << data->len << ")";
Darin Petkov78f63262012-03-26 01:30:24 +0200171 vector<string> messages;
172 SplitString(
173 string(reinterpret_cast<char *>(data->buf), data->len), '\n', &messages);
174 for (vector<string>::const_iterator it = messages.begin();
Darin Petkove08084d2012-06-11 13:19:35 +0200175 it != messages.end() && IsStarted(); ++it) {
Darin Petkov78f63262012-03-26 01:30:24 +0200176 ProcessMessage(*it);
177 }
178}
179
Darin Petkov3273da72013-02-13 11:50:25 +0100180void OpenVPNManagementServer::OnInputError(const Error &error) {
181 LOG(ERROR) << error;
Darin Petkov1c049c72013-03-21 13:15:45 +0100182 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkov3273da72013-02-13 11:50:25 +0100183}
184
Darin Petkov78f63262012-03-26 01:30:24 +0200185void OpenVPNManagementServer::ProcessMessage(const string &message) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700186 SLOG(VPN, 2) << __func__ << "(" << message << ")";
Darin Petkov92e65612012-06-10 12:52:10 +0200187 if (message.empty()) {
188 return;
189 }
190 if (!ProcessInfoMessage(message) &&
191 !ProcessNeedPasswordMessage(message) &&
192 !ProcessFailedPasswordMessage(message) &&
Darin Petkov16e70322013-03-07 15:54:23 +0100193 !ProcessAuthTokenMessage(message) &&
Darin Petkova5e07ef2012-07-09 14:27:57 +0200194 !ProcessStateMessage(message) &&
Darin Petkova42afe32013-02-05 16:53:52 +0100195 !ProcessHoldMessage(message) &&
196 !ProcessSuccessMessage(message)) {
Darin Petkov16e70322013-03-07 15:54:23 +0100197 LOG(WARNING) << "Message ignored: " << message;
Darin Petkov92e65612012-06-10 12:52:10 +0200198 }
Darin Petkov271fe522012-03-27 13:47:29 +0200199}
200
201bool OpenVPNManagementServer::ProcessInfoMessage(const string &message) {
Darin Petkov92e65612012-06-10 12:52:10 +0200202 if (!StartsWithASCII(message, ">INFO:", true)) {
203 return false;
204 }
Darin Petkova42afe32013-02-05 16:53:52 +0100205 LOG(INFO) << message;
Darin Petkov92e65612012-06-10 12:52:10 +0200206 return true;
Darin Petkov271fe522012-03-27 13:47:29 +0200207}
208
209bool OpenVPNManagementServer::ProcessNeedPasswordMessage(
210 const string &message) {
211 if (!StartsWithASCII(message, ">PASSWORD:Need ", true)) {
212 return false;
Darin Petkov78f63262012-03-26 01:30:24 +0200213 }
Darin Petkov92e65612012-06-10 12:52:10 +0200214 LOG(INFO) << "Processing need-password message.";
Darin Petkovaba89322013-03-11 14:48:22 +0100215 string tag = ParsePasswordTag(message);
216 if (tag == kPasswordTagAuth) {
Darin Petkov683942b2012-03-27 18:00:04 +0200217 if (message.find("SC:") != string::npos) {
Darin Petkove0d5dd12012-04-04 16:10:48 +0200218 PerformStaticChallenge(tag);
Darin Petkov683942b2012-03-27 18:00:04 +0200219 } else {
Darin Petkovdaaa5532012-07-24 15:37:55 +0200220 PerformAuthentication(tag);
Darin Petkov683942b2012-03-27 18:00:04 +0200221 }
Darin Petkove0d5dd12012-04-04 16:10:48 +0200222 } else if (StartsWithASCII(tag, "User-Specific TPM Token", true)) {
223 SupplyTPMToken(tag);
Darin Petkov92e65612012-06-10 12:52:10 +0200224 } else {
225 NOTIMPLEMENTED() << ": Unsupported need-password message: " << message;
Darin Petkov1c049c72013-03-21 13:15:45 +0100226 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkov683942b2012-03-27 18:00:04 +0200227 }
Darin Petkov271fe522012-03-27 13:47:29 +0200228 return true;
229}
230
Darin Petkove0d5dd12012-04-04 16:10:48 +0200231// static
Darin Petkovaba89322013-03-11 14:48:22 +0100232string OpenVPNManagementServer::ParseSubstring(const string &message,
233 const string &start,
234 const string &end) {
235 SLOG(VPN, 2) << __func__ << "(" << message
236 << ", " << start << ", " << end << ")";
237 DCHECK(!start.empty() && !end.empty());
238 size_t start_pos = message.find(start);
239 if (start_pos == string::npos) {
Darin Petkove0d5dd12012-04-04 16:10:48 +0200240 return string();
241 }
Darin Petkovaba89322013-03-11 14:48:22 +0100242 size_t end_pos = message.find(end, start_pos + start.size());
243 if (end_pos == string::npos) {
Darin Petkove0d5dd12012-04-04 16:10:48 +0200244 return string();
245 }
Darin Petkovaba89322013-03-11 14:48:22 +0100246 return message.substr(start_pos + start.size(),
247 end_pos - start_pos - start.size());
248}
249
250// static
251string OpenVPNManagementServer::ParsePasswordTag(const string &message) {
252 return ParseSubstring(message, "'", "'");
253}
254
255// static
256string OpenVPNManagementServer::ParsePasswordFailedReason(
257 const string &message) {
258 return ParseSubstring(message, "['", "']");
Darin Petkove0d5dd12012-04-04 16:10:48 +0200259}
260
261void OpenVPNManagementServer::PerformStaticChallenge(const string &tag) {
Darin Petkov92e65612012-06-10 12:52:10 +0200262 LOG(INFO) << "Perform static challenge: " << tag;
Darin Petkov683942b2012-03-27 18:00:04 +0200263 string user =
264 driver_->args()->LookupString(flimflam::kOpenVPNUserProperty, "");
265 string password =
266 driver_->args()->LookupString(flimflam::kOpenVPNPasswordProperty, "");
267 string otp =
268 driver_->args()->LookupString(flimflam::kOpenVPNOTPProperty, "");
269 if (user.empty() || password.empty() || otp.empty()) {
Darin Petkove08084d2012-06-11 13:19:35 +0200270 NOTIMPLEMENTED() << ": Missing credentials:"
271 << (user.empty() ? " no-user" : "")
272 << (password.empty() ? " no-password" : "")
273 << (otp.empty() ? " no-otp" : "");
Darin Petkov1c049c72013-03-21 13:15:45 +0100274 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkov683942b2012-03-27 18:00:04 +0200275 return;
276 }
Christopher Wiley0f3eab32013-03-21 11:55:41 -0700277 string b64_password;
278 string b64_otp;
279 if (!glib_->B64Encode(password, &b64_password) ||
280 !glib_->B64Encode(otp, &b64_otp)) {
Darin Petkov683942b2012-03-27 18:00:04 +0200281 LOG(ERROR) << "Unable to base64-encode credentials.";
282 return;
283 }
Darin Petkove0d5dd12012-04-04 16:10:48 +0200284 SendUsername(tag, user);
Christopher Wiley0f3eab32013-03-21 11:55:41 -0700285 SendPassword(tag, StringPrintf("SCRV1:%s:%s",
286 b64_password.c_str(),
287 b64_otp.c_str()));
Darin Petkov683942b2012-03-27 18:00:04 +0200288 // Don't reuse OTP.
289 driver_->args()->RemoveString(flimflam::kOpenVPNOTPProperty);
290}
291
Darin Petkovdaaa5532012-07-24 15:37:55 +0200292void OpenVPNManagementServer::PerformAuthentication(const string &tag) {
293 LOG(INFO) << "Perform authentication: " << tag;
294 string user =
295 driver_->args()->LookupString(flimflam::kOpenVPNUserProperty, "");
296 string password =
297 driver_->args()->LookupString(flimflam::kOpenVPNPasswordProperty, "");
298 if (user.empty() || password.empty()) {
299 NOTIMPLEMENTED() << ": Missing credentials:"
300 << (user.empty() ? " no-user" : "")
301 << (password.empty() ? " no-password" : "");
Darin Petkov1c049c72013-03-21 13:15:45 +0100302 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkovdaaa5532012-07-24 15:37:55 +0200303 return;
304 }
305 SendUsername(tag, user);
306 SendPassword(tag, password);
307}
308
Darin Petkove0d5dd12012-04-04 16:10:48 +0200309void OpenVPNManagementServer::SupplyTPMToken(const string &tag) {
Darin Petkov92e65612012-06-10 12:52:10 +0200310 SLOG(VPN, 2) << __func__ << "(" << tag << ")";
Darin Petkove0d5dd12012-04-04 16:10:48 +0200311 string pin = driver_->args()->LookupString(flimflam::kOpenVPNPinProperty, "");
312 if (pin.empty()) {
Darin Petkov0440b9b2012-04-17 16:11:56 +0200313 NOTIMPLEMENTED() << ": Missing PIN.";
Darin Petkov1c049c72013-03-21 13:15:45 +0100314 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkove0d5dd12012-04-04 16:10:48 +0200315 return;
316 }
317 SendPassword(tag, pin);
318}
319
Darin Petkov271fe522012-03-27 13:47:29 +0200320bool OpenVPNManagementServer::ProcessFailedPasswordMessage(
321 const string &message) {
322 if (!StartsWithASCII(message, ">PASSWORD:Verification Failed:", true)) {
323 return false;
Darin Petkov78f63262012-03-26 01:30:24 +0200324 }
Darin Petkovaba89322013-03-11 14:48:22 +0100325 LOG(INFO) << message;
326 string reason;
327 if (ParsePasswordTag(message) == kPasswordTagAuth) {
328 reason = ParsePasswordFailedReason(message);
329 }
Darin Petkov1c049c72013-03-21 13:15:45 +0100330 driver_->FailService(Service::kFailureConnect, reason);
Darin Petkov271fe522012-03-27 13:47:29 +0200331 return true;
332}
333
Darin Petkov16e70322013-03-07 15:54:23 +0100334bool OpenVPNManagementServer::ProcessAuthTokenMessage(const string &message) {
335 if (!StartsWithASCII(message, ">PASSWORD:Auth-Token:", true)) {
336 return false;
337 }
338 LOG(INFO) << "Auth-Token message ignored.";
339 return true;
340}
341
Darin Petkov271fe522012-03-27 13:47:29 +0200342// >STATE:* message support. State messages are of the form:
343// >STATE:<date>,<state>,<detail>,<local-ip>,<remote-ip>
344// where:
345// <date> is the current time (since epoch) in seconds
346// <state> is one of:
347// INITIAL, CONNECTING, WAIT, AUTH, GET_CONFIG, ASSIGN_IP, ADD_ROUTES,
348// CONNECTED, RECONNECTING, EXITING, RESOLVE, TCP_CONNECT
349// <detail> is a free-form string giving details about the state change
350// <local-ip> is a dotted-quad for the local IPv4 address (when available)
351// <remote-ip> is a dotted-quad for the remote IPv4 address (when available)
352bool OpenVPNManagementServer::ProcessStateMessage(const string &message) {
353 if (!StartsWithASCII(message, ">STATE:", true)) {
354 return false;
Darin Petkov78f63262012-03-26 01:30:24 +0200355 }
Darin Petkov271fe522012-03-27 13:47:29 +0200356 vector<string> details;
357 SplitString(message, ',', &details);
358 if (details.size() > 1) {
Darin Petkov1c049c72013-03-21 13:15:45 +0100359 state_ = details[1];
360 LOG(INFO) << "OpenVPN state: " << state_;
361 if (state_ == kStateReconnecting) {
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100362 OpenVPNDriver::ReconnectReason reason =
363 OpenVPNDriver::kReconnectReasonUnknown;
364 if (details.size() > 2 && details[2] == "tls-error") {
365 reason = OpenVPNDriver::kReconnectReasonTLSError;
366 }
367 driver_->OnReconnecting(reason);
Darin Petkov271fe522012-03-27 13:47:29 +0200368 }
Darin Petkov78f63262012-03-26 01:30:24 +0200369 }
Darin Petkov1c049c72013-03-21 13:15:45 +0100370
Darin Petkov271fe522012-03-27 13:47:29 +0200371 return true;
Darin Petkov78f63262012-03-26 01:30:24 +0200372}
373
Darin Petkova5e07ef2012-07-09 14:27:57 +0200374bool OpenVPNManagementServer::ProcessHoldMessage(const string &message) {
375 if (!StartsWithASCII(message, ">HOLD:Waiting for hold release", true)) {
376 return false;
377 }
Darin Petkova42afe32013-02-05 16:53:52 +0100378 LOG(INFO) << "Client waiting for hold release.";
Darin Petkova5e07ef2012-07-09 14:27:57 +0200379 hold_waiting_ = true;
380 if (hold_release_) {
381 ReleaseHold();
382 }
383 return true;
384}
385
Darin Petkova42afe32013-02-05 16:53:52 +0100386bool OpenVPNManagementServer::ProcessSuccessMessage(const string &message) {
387 if (!StartsWithASCII(message, "SUCCESS: ", true)) {
388 return false;
389 }
390 LOG(INFO) << message;
391 return true;
392}
393
Darin Petkovdaaa5532012-07-24 15:37:55 +0200394// static
395string OpenVPNManagementServer::EscapeToQuote(const string &str) {
396 string escaped;
397 for (string::const_iterator it = str.begin(); it != str.end(); ++it) {
398 if (*it == '\\' || *it == '"') {
399 escaped += '\\';
400 }
401 escaped += *it;
402 }
403 return escaped;
404}
405
Darin Petkov78f63262012-03-26 01:30:24 +0200406void OpenVPNManagementServer::Send(const string &data) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700407 SLOG(VPN, 2) << __func__;
Darin Petkov78f63262012-03-26 01:30:24 +0200408 ssize_t len = sockets_->Send(connected_socket_, data.data(), data.size(), 0);
409 PLOG_IF(ERROR, len < 0 || static_cast<size_t>(len) != data.size())
Darin Petkov683942b2012-03-27 18:00:04 +0200410 << "Send failed.";
Darin Petkov78f63262012-03-26 01:30:24 +0200411}
412
413void OpenVPNManagementServer::SendState(const string &state) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700414 SLOG(VPN, 2) << __func__ << "(" << state << ")";
Darin Petkov78f63262012-03-26 01:30:24 +0200415 Send(StringPrintf("state %s\n", state.c_str()));
Darin Petkov1c115202012-03-22 15:35:47 +0100416}
417
Darin Petkov683942b2012-03-27 18:00:04 +0200418void OpenVPNManagementServer::SendUsername(const string &tag,
419 const string &username) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700420 SLOG(VPN, 2) << __func__;
Darin Petkov683942b2012-03-27 18:00:04 +0200421 Send(StringPrintf("username \"%s\" %s\n", tag.c_str(), username.c_str()));
422}
423
424void OpenVPNManagementServer::SendPassword(const string &tag,
425 const string &password) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700426 SLOG(VPN, 2) << __func__;
Darin Petkovdaaa5532012-07-24 15:37:55 +0200427 Send(StringPrintf("password \"%s\" \"%s\"\n",
428 tag.c_str(),
429 EscapeToQuote(password).c_str()));
Darin Petkov683942b2012-03-27 18:00:04 +0200430}
431
Darin Petkova42afe32013-02-05 16:53:52 +0100432void OpenVPNManagementServer::SendSignal(const string &signal) {
433 SLOG(VPN, 2) << __func__ << "(" << signal << ")";
434 Send(StringPrintf("signal %s\n", signal.c_str()));
435}
436
Darin Petkova5e07ef2012-07-09 14:27:57 +0200437void OpenVPNManagementServer::SendHoldRelease() {
438 SLOG(VPN, 2) << __func__;
439 Send("hold release\n");
440}
441
Darin Petkov1c115202012-03-22 15:35:47 +0100442} // namespace shill