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 
40 using base::Bind;
41 using base::IntToString;
42 using base::SplitString;
43 using base::StringPrintf;
44 using base::Unretained;
45 using std::string;
46 using std::vector;
47 
48 namespace shill {
49 
50 namespace Logging {
51 static auto kModuleLogScope = ScopeLogger::kVPN;
ObjectID(OpenVPNManagementServer * o)52 static string ObjectID(OpenVPNManagementServer* o) {
53   return o->GetServiceRpcIdentifier();
54 }
55 }
56 
57 namespace {
58 const char kPasswordTagAuth[] = "Auth";
59 }  // namespace
60 
61 const char OpenVPNManagementServer::kStateReconnecting[] = "RECONNECTING";
62 const char OpenVPNManagementServer::kStateResolve[] = "RESOLVE";
63 
OpenVPNManagementServer(OpenVPNDriver * driver)64 OpenVPNManagementServer::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 
~OpenVPNManagementServer()73 OpenVPNManagementServer::~OpenVPNManagementServer() {
74   OpenVPNManagementServer::Stop();
75 }
76 
Start(EventDispatcher * dispatcher,Sockets * sockets,vector<vector<string>> * options)77 bool 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 
Stop()132 void 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 
ReleaseHold()152 void 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 
Hold()163 void OpenVPNManagementServer::Hold() {
164   SLOG(this, 2) << __func__;
165   hold_release_ = false;
166 }
167 
Restart()168 void OpenVPNManagementServer::Restart() {
169   LOG(INFO) << "Restart.";
170   SendSignal("SIGUSR1");
171 }
172 
GetServiceRpcIdentifier()173 std::string OpenVPNManagementServer::GetServiceRpcIdentifier() {
174   return driver_->GetServiceRpcIdentifier();
175 }
176 
OnReady(int fd)177 void 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 
OnInput(InputData * data)192 void 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 
OnInputError(const std::string & error_msg)203 void OpenVPNManagementServer::OnInputError(const std::string& error_msg) {
204   LOG(ERROR) << error_msg;
205   driver_->FailService(Service::kFailureInternal, Service::kErrorDetailsNone);
206 }
207 
ProcessMessage(const string & message)208 void 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 
ProcessInfoMessage(const string & message)224 bool 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 
ProcessNeedPasswordMessage(const string & message)232 bool 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
ParseSubstring(const string & message,const string & start,const string & end)257 string 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
ParsePasswordTag(const string & message)276 string OpenVPNManagementServer::ParsePasswordTag(const string& message) {
277   return ParseSubstring(message, "'", "'");
278 }
279 
280 // static
ParsePasswordFailedReason(const string & message)281 string OpenVPNManagementServer::ParsePasswordFailedReason(
282     const string& message) {
283   return ParseSubstring(message, "['", "']");
284 }
285 
PerformStaticChallenge(const string & tag)286 void 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 
PerformAuthentication(const string & tag)320 void 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 
SupplyTPMToken(const string & tag)335 void 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 
ProcessFailedPasswordMessage(const string & message)346 bool 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 
ProcessAuthTokenMessage(const string & message)361 bool 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)
ProcessStateMessage(const string & message)380 bool 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 
ProcessHoldMessage(const string & message)402 bool 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 
ProcessSuccessMessage(const string & message)415 bool 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
EscapeToQuote(const string & str)424 string 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 
Send(const string & data)435 void 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 
SendState(const string & state)442 void OpenVPNManagementServer::SendState(const string& state) {
443   SLOG(this, 2) << __func__ << "(" << state << ")";
444   Send(StringPrintf("state %s\n", state.c_str()));
445 }
446 
SendUsername(const string & tag,const string & username)447 void 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 
SendPassword(const string & tag,const string & password)453 void 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 
SendSignal(const string & signal)461 void OpenVPNManagementServer::SendSignal(const string& signal) {
462   SLOG(this, 2) << __func__ << "(" << signal << ")";
463   Send(StringPrintf("signal %s\n", signal.c_str()));
464 }
465 
SendHoldRelease()466 void OpenVPNManagementServer::SendHoldRelease() {
467   SLOG(this, 2) << __func__;
468   Send("hold release\n");
469 }
470 
471 }  // namespace shill
472