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/openvpn_management_server.h"
18
19#include <arpa/inet.h>
20#include <netinet/in.h>
21
22#include <base/bind.h>
23#include <base/strings/string_number_conversions.h>
24#include <base/strings/string_split.h>
25#include <base/strings/string_util.h>
26#include <base/strings/stringprintf.h>
27#include <brillo/data_encoding.h>
28#if defined(__ANDROID__)
29#include <dbus/service_constants.h>
30#else
31#include <chromeos/dbus/service_constants.h>
32#endif  // __ANDROID__
33
34#include "shill/error.h"
35#include "shill/event_dispatcher.h"
36#include "shill/logging.h"
37#include "shill/net/sockets.h"
38#include "shill/vpn/openvpn_driver.h"
39
40using base::Bind;
41using base::IntToString;
42using base::SplitString;
43using base::StringPrintf;
44using base::Unretained;
45using std::string;
46using std::vector;
47
48namespace shill {
49
50namespace Logging {
51static auto kModuleLogScope = ScopeLogger::kVPN;
52static string ObjectID(OpenVPNManagementServer* o) {
53  return o->GetServiceRpcIdentifier();
54}
55}
56
57namespace {
58const char kPasswordTagAuth[] = "Auth";
59}  // namespace
60
61const char OpenVPNManagementServer::kStateReconnecting[] = "RECONNECTING";
62const char OpenVPNManagementServer::kStateResolve[] = "RESOLVE";
63
64OpenVPNManagementServer::OpenVPNManagementServer(OpenVPNDriver* driver)
65    : driver_(driver),
66      sockets_(nullptr),
67      socket_(-1),
68      dispatcher_(nullptr),
69      connected_socket_(-1),
70      hold_waiting_(false),
71      hold_release_(false) {}
72
73OpenVPNManagementServer::~OpenVPNManagementServer() {
74  OpenVPNManagementServer::Stop();
75}
76
77bool OpenVPNManagementServer::Start(EventDispatcher* dispatcher,
78                                    Sockets* sockets,
79                                    vector<vector<string>>* options) {
80  SLOG(this, 2) << __func__;
81  if (IsStarted()) {
82    return true;
83  }
84
85  int socket = sockets->Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
86  if (socket < 0) {
87    PLOG(ERROR) << "Unable to create management server socket.";
88    return false;
89  }
90
91  struct sockaddr_in addr;
92  socklen_t addrlen = sizeof(addr);
93  memset(&addr, 0, sizeof(addr));
94  addr.sin_family = AF_INET;
95  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
96  if (sockets->Bind(
97          socket, reinterpret_cast<struct sockaddr*>(&addr), addrlen) < 0 ||
98      sockets->Listen(socket, 1) < 0 ||
99      sockets->GetSockName(
100          socket, reinterpret_cast<struct sockaddr*>(&addr), &addrlen) < 0) {
101    PLOG(ERROR) << "Socket setup failed.";
102    sockets->Close(socket);
103    return false;
104  }
105
106  SLOG(this, 2) << "Listening socket: " << socket;
107  sockets_ = sockets;
108  socket_ = socket;
109  ready_handler_.reset(
110      dispatcher->CreateReadyHandler(
111          socket, IOHandler::kModeInput,
112          Bind(&OpenVPNManagementServer::OnReady, Unretained(this))));
113  dispatcher_ = dispatcher;
114
115  // Append openvpn management API options.
116  driver_->AppendOption("management", inet_ntoa(addr.sin_addr),
117                        IntToString(ntohs(addr.sin_port)), options);
118  driver_->AppendOption("management-client", options);
119  driver_->AppendOption("management-hold", options);
120  hold_release_ = false;
121  hold_waiting_ = false;
122
123  driver_->AppendOption("management-query-passwords", options);
124  if (driver_->AppendValueOption(kOpenVPNStaticChallengeProperty,
125                                 "static-challenge",
126                                 options)) {
127    options->back().push_back("1");  // Force echo.
128  }
129  return true;
130}
131
132void OpenVPNManagementServer::Stop() {
133  SLOG(this, 2) << __func__;
134  if (!IsStarted()) {
135    return;
136  }
137  state_.clear();
138  input_handler_.reset();
139  if (connected_socket_ >= 0) {
140    sockets_->Close(connected_socket_);
141    connected_socket_ = -1;
142  }
143  dispatcher_ = nullptr;
144  ready_handler_.reset();
145  if (socket_ >= 0) {
146    sockets_->Close(socket_);
147    socket_ = -1;
148  }
149  sockets_ = nullptr;
150}
151
152void OpenVPNManagementServer::ReleaseHold() {
153  SLOG(this, 2) << __func__;
154  hold_release_ = true;
155  if (!hold_waiting_) {
156    return;
157  }
158  LOG(INFO) << "Releasing hold.";
159  hold_waiting_ = false;
160  SendHoldRelease();
161}
162
163void OpenVPNManagementServer::Hold() {
164  SLOG(this, 2) << __func__;
165  hold_release_ = false;
166}
167
168void OpenVPNManagementServer::Restart() {
169  LOG(INFO) << "Restart.";
170  SendSignal("SIGUSR1");
171}
172
173std::string OpenVPNManagementServer::GetServiceRpcIdentifier() {
174  return driver_->GetServiceRpcIdentifier();
175}
176
177void OpenVPNManagementServer::OnReady(int fd) {
178  SLOG(this, 2) << __func__ << "(" << fd << ")";
179  connected_socket_ = sockets_->Accept(fd, nullptr, nullptr);
180  if (connected_socket_ < 0) {
181    PLOG(ERROR) << "Connected socket accept failed.";
182    return;
183  }
184  ready_handler_.reset();
185  input_handler_.reset(dispatcher_->CreateInputHandler(
186      connected_socket_,
187      Bind(&OpenVPNManagementServer::OnInput, Unretained(this)),
188      Bind(&OpenVPNManagementServer::OnInputError, Unretained(this))));
189  SendState("on");
190}
191
192void OpenVPNManagementServer::OnInput(InputData* data) {
193  SLOG(this, 2) << __func__ << "(" << data->len << ")";
194  vector<string> messages = SplitString(
195      string(reinterpret_cast<char*>(data->buf), data->len), "\n",
196      base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
197  for (vector<string>::const_iterator it = messages.begin();
198       it != messages.end() && IsStarted(); ++it) {
199    ProcessMessage(*it);
200  }
201}
202
203void OpenVPNManagementServer::OnInputError(const std::string& error_msg) {
204  LOG(ERROR) << error_msg;
205  driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
206}
207
208void OpenVPNManagementServer::ProcessMessage(const string& message) {
209  SLOG(this, 2) << __func__ << "(" << message << ")";
210  if (message.empty()) {
211    return;
212  }
213  if (!ProcessInfoMessage(message) &&
214      !ProcessNeedPasswordMessage(message) &&
215      !ProcessFailedPasswordMessage(message) &&
216      !ProcessAuthTokenMessage(message) &&
217      !ProcessStateMessage(message) &&
218      !ProcessHoldMessage(message) &&
219      !ProcessSuccessMessage(message)) {
220    LOG(WARNING) << "Message ignored: " << message;
221  }
222}
223
224bool OpenVPNManagementServer::ProcessInfoMessage(const string& message) {
225  if (!base::StartsWith(message, ">INFO:", base::CompareCase::SENSITIVE)) {
226    return false;
227  }
228  LOG(INFO) << message;
229  return true;
230}
231
232bool OpenVPNManagementServer::ProcessNeedPasswordMessage(
233    const string& message) {
234  if (!base::StartsWith(message, ">PASSWORD:Need ",
235                        base::CompareCase::SENSITIVE)) {
236    return false;
237  }
238  LOG(INFO) << "Processing need-password message.";
239  string tag = ParsePasswordTag(message);
240  if (tag == kPasswordTagAuth) {
241    if (message.find("SC:") != string::npos) {
242      PerformStaticChallenge(tag);
243    } else {
244      PerformAuthentication(tag);
245    }
246  } else if (base::StartsWith(tag, "User-Specific TPM Token",
247                              base::CompareCase::SENSITIVE)) {
248    SupplyTPMToken(tag);
249  } else {
250    NOTIMPLEMENTED() << ": Unsupported need-password message: " << message;
251    driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
252  }
253  return true;
254}
255
256// static
257string OpenVPNManagementServer::ParseSubstring(const string& message,
258                                               const string& start,
259                                               const string& end) {
260  SLOG(VPN, nullptr, 2) << __func__ << "(" << message
261                        << ", " << start << ", " << end << ")";
262  DCHECK(!start.empty() && !end.empty());
263  size_t start_pos = message.find(start);
264  if (start_pos == string::npos) {
265    return string();
266  }
267  size_t end_pos = message.find(end, start_pos + start.size());
268  if (end_pos == string::npos) {
269    return string();
270  }
271  return message.substr(start_pos + start.size(),
272                        end_pos - start_pos - start.size());
273}
274
275// static
276string OpenVPNManagementServer::ParsePasswordTag(const string& message) {
277  return ParseSubstring(message, "'", "'");
278}
279
280// static
281string OpenVPNManagementServer::ParsePasswordFailedReason(
282    const string& message) {
283  return ParseSubstring(message, "['", "']");
284}
285
286void OpenVPNManagementServer::PerformStaticChallenge(const string& tag) {
287  LOG(INFO) << "Perform static challenge: " << tag;
288  string user = driver_->args()->LookupString(kOpenVPNUserProperty, "");
289  string password = driver_->args()->LookupString(kOpenVPNPasswordProperty, "");
290  string otp = driver_->args()->LookupString(kOpenVPNOTPProperty, "");
291  string token = driver_->args()->LookupString(kOpenVPNTokenProperty, "");
292  if (user.empty() || (token.empty() && (password.empty() || otp.empty()))) {
293    NOTIMPLEMENTED() << ": Missing credentials:"
294                     << (user.empty() ? " no-user" : "")
295                     << (token.empty() ? " no-token" : "")
296                     << (password.empty() ? " no-password" : "")
297                     << (otp.empty() ? " no-otp" : "");
298    driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
299    return;
300  }
301
302  string password_encoded;
303  if (!token.empty()) {
304    password_encoded = token;
305    // Don't reuse token.
306    driver_->args()->RemoveString(kOpenVPNTokenProperty);
307  } else {
308    string b64_password(brillo::data_encoding::Base64Encode(password));
309    string b64_otp(brillo::data_encoding::Base64Encode(otp));
310    password_encoded = StringPrintf("SCRV1:%s:%s",
311                                    b64_password.c_str(),
312                                    b64_otp.c_str());
313    // Don't reuse OTP.
314    driver_->args()->RemoveString(kOpenVPNOTPProperty);
315  }
316  SendUsername(tag, user);
317  SendPassword(tag, password_encoded);
318}
319
320void OpenVPNManagementServer::PerformAuthentication(const string& tag) {
321  LOG(INFO) << "Perform authentication: " << tag;
322  string user = driver_->args()->LookupString(kOpenVPNUserProperty, "");
323  string password = driver_->args()->LookupString(kOpenVPNPasswordProperty, "");
324  if (user.empty() || password.empty()) {
325    NOTIMPLEMENTED() << ": Missing credentials:"
326                     << (user.empty() ? " no-user" : "")
327                     << (password.empty() ? " no-password" : "");
328    driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
329    return;
330  }
331  SendUsername(tag, user);
332  SendPassword(tag, password);
333}
334
335void OpenVPNManagementServer::SupplyTPMToken(const string& tag) {
336  SLOG(this, 2) << __func__ << "(" << tag << ")";
337  string pin = driver_->args()->LookupString(kOpenVPNPinProperty, "");
338  if (pin.empty()) {
339    NOTIMPLEMENTED() << ": Missing PIN.";
340    driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
341    return;
342  }
343  SendPassword(tag, pin);
344}
345
346bool OpenVPNManagementServer::ProcessFailedPasswordMessage(
347    const string& message) {
348  if (!base::StartsWith(message, ">PASSWORD:Verification Failed:",
349                        base::CompareCase::SENSITIVE)) {
350    return false;
351  }
352  LOG(INFO) << message;
353  string reason;
354  if (ParsePasswordTag(message) == kPasswordTagAuth) {
355    reason = ParsePasswordFailedReason(message);
356  }
357  driver_->FailService(Service::kFailureConnect, reason);
358  return true;
359}
360
361bool OpenVPNManagementServer::ProcessAuthTokenMessage(const string& message) {
362  if (!base::StartsWith(message, ">PASSWORD:Auth-Token:",
363                        base::CompareCase::SENSITIVE)) {
364    return false;
365  }
366  LOG(INFO) << "Auth-Token message ignored.";
367  return true;
368}
369
370// >STATE:* message support. State messages are of the form:
371//    >STATE:<date>,<state>,<detail>,<local-ip>,<remote-ip>
372// where:
373// <date> is the current time (since epoch) in seconds
374// <state> is one of:
375//    INITIAL, CONNECTING, WAIT, AUTH, GET_CONFIG, ASSIGN_IP, ADD_ROUTES,
376//    CONNECTED, RECONNECTING, EXITING, RESOLVE, TCP_CONNECT
377// <detail> is a free-form string giving details about the state change
378// <local-ip> is a dotted-quad for the local IPv4 address (when available)
379// <remote-ip> is a dotted-quad for the remote IPv4 address (when available)
380bool OpenVPNManagementServer::ProcessStateMessage(const string& message) {
381  if (!base::StartsWith(message, ">STATE:", base::CompareCase::SENSITIVE)) {
382    return false;
383  }
384  vector<string> details = SplitString(message, ",", base::TRIM_WHITESPACE,
385                                       base::SPLIT_WANT_ALL);
386  if (details.size() > 1) {
387    state_ = details[1];
388    LOG(INFO) << "OpenVPN state: " << state_;
389    if (state_ == kStateReconnecting) {
390      OpenVPNDriver::ReconnectReason reason =
391          OpenVPNDriver::kReconnectReasonUnknown;
392      if (details.size() > 2 && details[2] == "tls-error") {
393        reason = OpenVPNDriver::kReconnectReasonTLSError;
394      }
395      driver_->OnReconnecting(reason);
396    }
397  }
398
399  return true;
400}
401
402bool OpenVPNManagementServer::ProcessHoldMessage(const string& message) {
403  if (!base::StartsWith(message, ">HOLD:Waiting for hold release",
404                        base::CompareCase::SENSITIVE)) {
405    return false;
406  }
407  LOG(INFO) << "Client waiting for hold release.";
408  hold_waiting_ = true;
409  if (hold_release_) {
410    ReleaseHold();
411  }
412  return true;
413}
414
415bool OpenVPNManagementServer::ProcessSuccessMessage(const string& message) {
416  if (!base::StartsWith(message, "SUCCESS: ", base::CompareCase::SENSITIVE)) {
417    return false;
418  }
419  LOG(INFO) << message;
420  return true;
421}
422
423// static
424string OpenVPNManagementServer::EscapeToQuote(const string& str) {
425  string escaped;
426  for (string::const_iterator it = str.begin(); it != str.end(); ++it) {
427    if (*it == '\\' || *it == '"') {
428      escaped += '\\';
429    }
430    escaped += *it;
431  }
432  return escaped;
433}
434
435void OpenVPNManagementServer::Send(const string& data) {
436  SLOG(this, 2) << __func__;
437  ssize_t len = sockets_->Send(connected_socket_, data.data(), data.size(), 0);
438  PLOG_IF(ERROR, len < 0 || static_cast<size_t>(len) != data.size())
439      << "Send failed.";
440}
441
442void OpenVPNManagementServer::SendState(const string& state) {
443  SLOG(this, 2) << __func__ << "(" << state << ")";
444  Send(StringPrintf("state %s\n", state.c_str()));
445}
446
447void OpenVPNManagementServer::SendUsername(const string& tag,
448                                           const string& username) {
449  SLOG(this, 2) << __func__;
450  Send(StringPrintf("username \"%s\" %s\n", tag.c_str(), username.c_str()));
451}
452
453void OpenVPNManagementServer::SendPassword(const string& tag,
454                                           const string& password) {
455  SLOG(this, 2) << __func__;
456  Send(StringPrintf("password \"%s\" \"%s\"\n",
457                    tag.c_str(),
458                    EscapeToQuote(password).c_str()));
459}
460
461void OpenVPNManagementServer::SendSignal(const string& signal) {
462  SLOG(this, 2) << __func__ << "(" << signal << ")";
463  Send(StringPrintf("signal %s\n", signal.c_str()));
464}
465
466void OpenVPNManagementServer::SendHoldRelease() {
467  SLOG(this, 2) << __func__;
468  Send("hold release\n");
469}
470
471}  // namespace shill
472