blob: 07e1246e6e5c3ebfaed4ca53508a8e5c78007b9d [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,
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, "");
Darin Petkov683942b2012-03-27 18:00:04 +0200264 if (user.empty() || password.empty() || otp.empty()) {
Darin Petkove08084d2012-06-11 13:19:35 +0200265 NOTIMPLEMENTED() << ": Missing credentials:"
266 << (user.empty() ? " no-user" : "")
267 << (password.empty() ? " no-password" : "")
268 << (otp.empty() ? " no-otp" : "");
Darin Petkov1c049c72013-03-21 13:15:45 +0100269 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkov683942b2012-03-27 18:00:04 +0200270 return;
271 }
Christopher Wiley0f3eab32013-03-21 11:55:41 -0700272 string b64_password;
273 string b64_otp;
274 if (!glib_->B64Encode(password, &b64_password) ||
275 !glib_->B64Encode(otp, &b64_otp)) {
Darin Petkov683942b2012-03-27 18:00:04 +0200276 LOG(ERROR) << "Unable to base64-encode credentials.";
277 return;
278 }
Darin Petkove0d5dd12012-04-04 16:10:48 +0200279 SendUsername(tag, user);
Christopher Wiley0f3eab32013-03-21 11:55:41 -0700280 SendPassword(tag, StringPrintf("SCRV1:%s:%s",
281 b64_password.c_str(),
282 b64_otp.c_str()));
Darin Petkov683942b2012-03-27 18:00:04 +0200283 // Don't reuse OTP.
Ben Chan73728782013-09-20 13:40:54 -0700284 driver_->args()->RemoveString(kOpenVPNOTPProperty);
Darin Petkov683942b2012-03-27 18:00:04 +0200285}
286
Darin Petkovdaaa5532012-07-24 15:37:55 +0200287void OpenVPNManagementServer::PerformAuthentication(const string &tag) {
288 LOG(INFO) << "Perform authentication: " << tag;
Ben Chan73728782013-09-20 13:40:54 -0700289 string user = driver_->args()->LookupString(kOpenVPNUserProperty, "");
290 string password = driver_->args()->LookupString(kOpenVPNPasswordProperty, "");
Darin Petkovdaaa5532012-07-24 15:37:55 +0200291 if (user.empty() || password.empty()) {
292 NOTIMPLEMENTED() << ": Missing credentials:"
293 << (user.empty() ? " no-user" : "")
294 << (password.empty() ? " no-password" : "");
Darin Petkov1c049c72013-03-21 13:15:45 +0100295 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkovdaaa5532012-07-24 15:37:55 +0200296 return;
297 }
298 SendUsername(tag, user);
299 SendPassword(tag, password);
300}
301
Darin Petkove0d5dd12012-04-04 16:10:48 +0200302void OpenVPNManagementServer::SupplyTPMToken(const string &tag) {
Darin Petkov92e65612012-06-10 12:52:10 +0200303 SLOG(VPN, 2) << __func__ << "(" << tag << ")";
Ben Chan73728782013-09-20 13:40:54 -0700304 string pin = driver_->args()->LookupString(kOpenVPNPinProperty, "");
Darin Petkove0d5dd12012-04-04 16:10:48 +0200305 if (pin.empty()) {
Darin Petkov0440b9b2012-04-17 16:11:56 +0200306 NOTIMPLEMENTED() << ": Missing PIN.";
Darin Petkov1c049c72013-03-21 13:15:45 +0100307 driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
Darin Petkove0d5dd12012-04-04 16:10:48 +0200308 return;
309 }
310 SendPassword(tag, pin);
311}
312
Darin Petkov271fe522012-03-27 13:47:29 +0200313bool OpenVPNManagementServer::ProcessFailedPasswordMessage(
314 const string &message) {
315 if (!StartsWithASCII(message, ">PASSWORD:Verification Failed:", true)) {
316 return false;
Darin Petkov78f63262012-03-26 01:30:24 +0200317 }
Darin Petkovaba89322013-03-11 14:48:22 +0100318 LOG(INFO) << message;
319 string reason;
320 if (ParsePasswordTag(message) == kPasswordTagAuth) {
321 reason = ParsePasswordFailedReason(message);
322 }
Darin Petkov1c049c72013-03-21 13:15:45 +0100323 driver_->FailService(Service::kFailureConnect, reason);
Darin Petkov271fe522012-03-27 13:47:29 +0200324 return true;
325}
326
Darin Petkov16e70322013-03-07 15:54:23 +0100327bool OpenVPNManagementServer::ProcessAuthTokenMessage(const string &message) {
328 if (!StartsWithASCII(message, ">PASSWORD:Auth-Token:", true)) {
329 return false;
330 }
331 LOG(INFO) << "Auth-Token message ignored.";
332 return true;
333}
334
Darin Petkov271fe522012-03-27 13:47:29 +0200335// >STATE:* message support. State messages are of the form:
336// >STATE:<date>,<state>,<detail>,<local-ip>,<remote-ip>
337// where:
338// <date> is the current time (since epoch) in seconds
339// <state> is one of:
340// INITIAL, CONNECTING, WAIT, AUTH, GET_CONFIG, ASSIGN_IP, ADD_ROUTES,
341// CONNECTED, RECONNECTING, EXITING, RESOLVE, TCP_CONNECT
342// <detail> is a free-form string giving details about the state change
343// <local-ip> is a dotted-quad for the local IPv4 address (when available)
344// <remote-ip> is a dotted-quad for the remote IPv4 address (when available)
345bool OpenVPNManagementServer::ProcessStateMessage(const string &message) {
346 if (!StartsWithASCII(message, ">STATE:", true)) {
347 return false;
Darin Petkov78f63262012-03-26 01:30:24 +0200348 }
Darin Petkov271fe522012-03-27 13:47:29 +0200349 vector<string> details;
350 SplitString(message, ',', &details);
351 if (details.size() > 1) {
Darin Petkov1c049c72013-03-21 13:15:45 +0100352 state_ = details[1];
353 LOG(INFO) << "OpenVPN state: " << state_;
354 if (state_ == kStateReconnecting) {
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100355 OpenVPNDriver::ReconnectReason reason =
356 OpenVPNDriver::kReconnectReasonUnknown;
357 if (details.size() > 2 && details[2] == "tls-error") {
358 reason = OpenVPNDriver::kReconnectReasonTLSError;
359 }
360 driver_->OnReconnecting(reason);
Darin Petkov271fe522012-03-27 13:47:29 +0200361 }
Darin Petkov78f63262012-03-26 01:30:24 +0200362 }
Darin Petkov1c049c72013-03-21 13:15:45 +0100363
Darin Petkov271fe522012-03-27 13:47:29 +0200364 return true;
Darin Petkov78f63262012-03-26 01:30:24 +0200365}
366
Darin Petkova5e07ef2012-07-09 14:27:57 +0200367bool OpenVPNManagementServer::ProcessHoldMessage(const string &message) {
368 if (!StartsWithASCII(message, ">HOLD:Waiting for hold release", true)) {
369 return false;
370 }
Darin Petkova42afe32013-02-05 16:53:52 +0100371 LOG(INFO) << "Client waiting for hold release.";
Darin Petkova5e07ef2012-07-09 14:27:57 +0200372 hold_waiting_ = true;
373 if (hold_release_) {
374 ReleaseHold();
375 }
376 return true;
377}
378
Darin Petkova42afe32013-02-05 16:53:52 +0100379bool OpenVPNManagementServer::ProcessSuccessMessage(const string &message) {
380 if (!StartsWithASCII(message, "SUCCESS: ", true)) {
381 return false;
382 }
383 LOG(INFO) << message;
384 return true;
385}
386
Darin Petkovdaaa5532012-07-24 15:37:55 +0200387// static
388string OpenVPNManagementServer::EscapeToQuote(const string &str) {
389 string escaped;
390 for (string::const_iterator it = str.begin(); it != str.end(); ++it) {
391 if (*it == '\\' || *it == '"') {
392 escaped += '\\';
393 }
394 escaped += *it;
395 }
396 return escaped;
397}
398
Darin Petkov78f63262012-03-26 01:30:24 +0200399void OpenVPNManagementServer::Send(const string &data) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700400 SLOG(VPN, 2) << __func__;
Darin Petkov78f63262012-03-26 01:30:24 +0200401 ssize_t len = sockets_->Send(connected_socket_, data.data(), data.size(), 0);
402 PLOG_IF(ERROR, len < 0 || static_cast<size_t>(len) != data.size())
Darin Petkov683942b2012-03-27 18:00:04 +0200403 << "Send failed.";
Darin Petkov78f63262012-03-26 01:30:24 +0200404}
405
406void OpenVPNManagementServer::SendState(const string &state) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700407 SLOG(VPN, 2) << __func__ << "(" << state << ")";
Darin Petkov78f63262012-03-26 01:30:24 +0200408 Send(StringPrintf("state %s\n", state.c_str()));
Darin Petkov1c115202012-03-22 15:35:47 +0100409}
410
Darin Petkov683942b2012-03-27 18:00:04 +0200411void OpenVPNManagementServer::SendUsername(const string &tag,
412 const string &username) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700413 SLOG(VPN, 2) << __func__;
Darin Petkov683942b2012-03-27 18:00:04 +0200414 Send(StringPrintf("username \"%s\" %s\n", tag.c_str(), username.c_str()));
415}
416
417void OpenVPNManagementServer::SendPassword(const string &tag,
418 const string &password) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700419 SLOG(VPN, 2) << __func__;
Darin Petkovdaaa5532012-07-24 15:37:55 +0200420 Send(StringPrintf("password \"%s\" \"%s\"\n",
421 tag.c_str(),
422 EscapeToQuote(password).c_str()));
Darin Petkov683942b2012-03-27 18:00:04 +0200423}
424
Darin Petkova42afe32013-02-05 16:53:52 +0100425void OpenVPNManagementServer::SendSignal(const string &signal) {
426 SLOG(VPN, 2) << __func__ << "(" << signal << ")";
427 Send(StringPrintf("signal %s\n", signal.c_str()));
428}
429
Darin Petkova5e07ef2012-07-09 14:27:57 +0200430void OpenVPNManagementServer::SendHoldRelease() {
431 SLOG(VPN, 2) << __func__;
432 Send("hold release\n");
433}
434
Darin Petkov1c115202012-03-22 15:35:47 +0100435} // namespace shill