1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2001-2008 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2019 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    Affero General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 */
23 
24 #include "include/bareos.h"
25 #include "dird/authenticate_console.h"
26 #include "dird/dird.h"
27 #if defined(HAVE_PAM)
28 #include "dird/auth_pam.h"
29 #endif
30 #include "dird/dird_globals.h"
31 #include "lib/bnet.h"
32 #include "lib/bsock.h"
33 #include "lib/qualified_resource_name_type_converter.h"
34 #include "lib/bstringlist.h"
35 #include "lib/jcr.h"
36 #include "lib/parse_conf.h"
37 #include "lib/util.h"
38 #include "include/version_numbers.h"
39 
40 namespace directordaemon {
41 
42 enum class OptionResult
43 {
44   Completed,
45   Skipped
46 };
47 
48 class ConsoleAuthenticator {
49  public:
50   ConsoleAuthenticator(UaContext* ua, const std::string& console_name);
51   virtual ~ConsoleAuthenticator() = default;
52 
53   ConsoleAuthenticator(const ConsoleAuthenticator& other) = delete;
54   virtual OptionResult AuthenticateDefaultConsole() = 0;
55   virtual void AuthenticateNamedConsole() = 0;
56   virtual OptionResult AuthenticatePamUser() = 0;
SendInfoMessage()57   virtual bool SendInfoMessage() { return false; }
58 
59   bool auth_success_;
60   std::string console_name_;
61 
62  protected:
63   OptionResult DoDefaultAuthentication();
64   void DoNamedAuthentication();
65 
66   UaContext* ua_;
67   ConsoleResource* optional_console_resource_;
68 };
69 
ConsoleAuthenticator(UaContext * ua,const std::string & console_name)70 ConsoleAuthenticator::ConsoleAuthenticator(UaContext* ua,
71                                            const std::string& console_name)
72     : auth_success_(false), console_name_(console_name), ua_(ua)
73 {
74   optional_console_resource_ = (ConsoleResource*)my_config->GetResWithName(
75       R_CONSOLE, console_name_.c_str());
76 }
77 
DoDefaultAuthentication()78 OptionResult ConsoleAuthenticator::DoDefaultAuthentication()
79 {
80   const std::string default_console_name{"*UserAgent*"};
81 
82   if (console_name_ != default_console_name) { return OptionResult::Skipped; }
83 
84   auth_success_ = ua_->UA_sock->AuthenticateInboundConnection(
85       NULL, my_config, default_console_name.c_str(), me->password_, me);
86   ua_->user_acl = nullptr;
87   return OptionResult::Completed;
88 }
89 
DoNamedAuthentication()90 void ConsoleAuthenticator::DoNamedAuthentication()
91 {
92   if (!optional_console_resource_) {
93     Dmsg1(200, "Could not find resource for console %s\n",
94           console_name_.c_str());
95     auth_success_ = false;
96     return;
97   }
98 
99   auth_success_ = ua_->UA_sock->AuthenticateInboundConnection(
100       NULL, my_config, console_name_.c_str(),
101       optional_console_resource_->password_, optional_console_resource_);
102   if (auth_success_) {
103     ua_->user_acl = &optional_console_resource_->user_acl;
104   } else {
105     ua_->user_acl = nullptr;
106     Dmsg1(200, "Could not authenticate console %s\n", console_name_.c_str());
107   }
108 }
109 
110 class ConsoleAuthenticatorBefore_18_2 : public ConsoleAuthenticator {
111  public:
ConsoleAuthenticatorBefore_18_2(UaContext * ua,const std::string & console_name)112   ConsoleAuthenticatorBefore_18_2(UaContext* ua,
113                                   const std::string& console_name)
114       : ConsoleAuthenticator(ua, console_name)
115   {
116   }
117   OptionResult AuthenticateDefaultConsole() override;
118   void AuthenticateNamedConsole() override;
119   OptionResult AuthenticatePamUser() override;
120 
121  private:
SendOkMessageWithSpaceSeparators()122   bool SendOkMessageWithSpaceSeparators()
123   {
124     if (ua_) {
125       std::string cipher;
126       ua_->UA_sock->GetCipherMessageString(cipher);
127       if (ua_->UA_sock) {
128         return ua_->UA_sock->fsend(_("1000 OK: %s Version: %s (%s) "
129                                      "-- %s\n"),
130                                    my_name, kBareosVersionStrings.Full,
131                                    kBareosVersionStrings.Date, cipher.c_str());
132       }
133     }
134     return false;
135   }
136 
SendNotAuthorizedMessageWithSpaceSeparators()137   bool SendNotAuthorizedMessageWithSpaceSeparators()
138   {
139     if (ua_ && ua_->UA_sock) {
140       return ua_->UA_sock->fsend("%s", "1999 You are not authorized.\n");
141     }
142     return false;
143   }
144 };
145 
AuthenticateDefaultConsole()146 OptionResult ConsoleAuthenticatorBefore_18_2::AuthenticateDefaultConsole()
147 {
148   if (DoDefaultAuthentication() == OptionResult::Skipped) {
149     return OptionResult::Skipped;
150   }
151 
152   if (auth_success_) {
153     auth_success_ = SendOkMessageWithSpaceSeparators();
154   } else {
155     SendNotAuthorizedMessageWithSpaceSeparators();
156   }
157   if (!auth_success_) {
158     Dmsg1(200, "Could not authenticate outdated console %s\n",
159           console_name_.c_str());
160   }
161   return OptionResult::Completed;
162 }
163 
AuthenticateNamedConsole()164 void ConsoleAuthenticatorBefore_18_2::AuthenticateNamedConsole()
165 {
166   DoNamedAuthentication();
167 
168   if (auth_success_) {
169     auth_success_ = SendOkMessageWithSpaceSeparators();
170   } else {
171     SendNotAuthorizedMessageWithSpaceSeparators();
172   }
173 }
174 
AuthenticatePamUser()175 OptionResult ConsoleAuthenticatorBefore_18_2::AuthenticatePamUser()
176 {
177   if (!optional_console_resource_) { return OptionResult::Skipped; }
178   if (optional_console_resource_->use_pam_authentication_) {
179     Dmsg1(200, "PAM authentication using outdated Bareos console denied: %s\n",
180           console_name_.c_str());
181     auth_success_ =
182         false; /* console before 18_2 cannot do pam authentication */
183     return OptionResult::Completed;
184   }
185   return OptionResult::Skipped;
186 }
187 
188 class ConsoleAuthenticatorFrom_18_2 : public ConsoleAuthenticator {
189  public:
ConsoleAuthenticatorFrom_18_2(UaContext * ua,const std::string & console_name)190   ConsoleAuthenticatorFrom_18_2(UaContext* ua, const std::string& console_name)
191       : ConsoleAuthenticator(ua, console_name)
192   {
193   }
194   OptionResult AuthenticateDefaultConsole() override;
195   void AuthenticateNamedConsole() override;
196   OptionResult AuthenticatePamUser() override;
197   bool SendInfoMessage() override;
198 
199  private:
200   bool SendResponseMessage(uint32_t response_id, bool send_version_info);
201 };
202 
SendResponseMessage(uint32_t response_id,bool send_version_info)203 bool ConsoleAuthenticatorFrom_18_2::SendResponseMessage(uint32_t response_id,
204                                                         bool send_version_info)
205 {
206   std::string message;
207   if (send_version_info) {
208     char version_info[128];
209     ::snprintf(version_info, 100, "OK: %s Version: %s (%s)", my_name,
210                kBareosVersionStrings.Full, kBareosVersionStrings.Date);
211     message = version_info;
212   }
213   return ua_->UA_sock->FormatAndSendResponseMessage(response_id, message);
214 }
215 
SendInfoMessage()216 bool ConsoleAuthenticatorFrom_18_2::SendInfoMessage()
217 {
218   std::string message;
219   message += kBareosVersionStrings.BinaryInfo;
220   message += " binary\n";
221   message += kBareosVersionStrings.ServicesMessage;
222   message += "\n";
223   message += "You are ";
224   if (ua_->user_acl) {
225     message += "logged in as: ";
226     message += ua_->user_acl->corresponding_resource->resource_name_;
227   } else {
228     message += "connected using the default console";
229   }
230   auth_success_ = ua_->UA_sock->FormatAndSendResponseMessage(
231       kMessageIdInfoMessage, message);
232   return true;
233 }
234 
AuthenticateDefaultConsole()235 OptionResult ConsoleAuthenticatorFrom_18_2::AuthenticateDefaultConsole()
236 {
237   if (DoDefaultAuthentication() == OptionResult::Skipped) {
238     return OptionResult::Skipped;
239   }
240 
241   if (auth_success_) {
242     if (!SendResponseMessage(kMessageIdOk, true)) { auth_success_ = false; }
243   }
244 
245   if (!auth_success_) {
246     Dmsg1(200, "Could not authenticate console %s\n", console_name_.c_str());
247   }
248   return OptionResult::Completed;
249 }
250 
AuthenticateNamedConsole()251 void ConsoleAuthenticatorFrom_18_2::AuthenticateNamedConsole()
252 {
253   DoNamedAuthentication();
254 
255   if (!auth_success_) { return; }
256 
257   uint32_t response_id = kMessageIdOk;
258   bool send_version = true;
259 
260   if (optional_console_resource_ &&
261       optional_console_resource_->use_pam_authentication_) {
262     response_id = kMessageIdPamRequired;
263     send_version = false;
264   }
265 
266   if (!SendResponseMessage(response_id, send_version)) {
267     Dmsg1(200, "Send of response message failed %s\n", console_name_.c_str());
268     auth_success_ = false;
269   }
270 }
271 
AuthenticatePamUser()272 OptionResult ConsoleAuthenticatorFrom_18_2::AuthenticatePamUser()
273 {
274 #if !defined(HAVE_PAM)
275   {
276     if (optional_console_resource_ &&
277         optional_console_resource_->use_pam_authentication_) {
278       Emsg0(M_ERROR, 0, _("PAM is not available on this director\n"));
279       auth_success_ = false;
280       return OptionResult::Completed;
281     } else {
282       return OptionResult::Skipped;
283     }
284   }
285 #else  /* HAVE_PAM */
286   {
287     if (!optional_console_resource_) {
288       auth_success_ = false;
289       return OptionResult::Completed;
290     }
291 
292     if (!optional_console_resource_->use_pam_authentication_) {
293       return OptionResult::Skipped;
294     }
295 
296     uint32_t response_id;
297     BStringList message_arguments;
298 
299     if (!ua_->UA_sock->ReceiveAndEvaluateResponseMessage(response_id,
300                                                          message_arguments)) {
301       Dmsg2(100, "Could not evaluate response_id: %d - %d", response_id,
302             message_arguments.JoinReadable().c_str());
303       auth_success_ = false;
304       return OptionResult::Completed;
305     }
306 
307     std::string pam_username;
308     std::string pam_password;
309 
310     if (response_id == kMessageIdPamUserCredentials) {
311       Dmsg0(200, "Console chooses PAM direct credentials\n");
312       if (message_arguments.size() < 3) {
313         Dmsg0(200, "Console sent wrong number of credentials\n");
314         auth_success_ = false;
315         return OptionResult::Completed;
316       } else {
317         pam_username = message_arguments.at(1);
318         pam_password = message_arguments.at(2);
319       }
320     } else if (response_id == kMessageIdPamInteractive) {
321       Dmsg0(200, "Console chooses PAM interactive\n");
322     }
323 
324     Dmsg1(200, "Try to authenticate user using PAM:%s\n", pam_username.c_str());
325 
326     std::string authenticated_username;
327     if (!PamAuthenticateUser(ua_->UA_sock, pam_username, pam_password,
328                              authenticated_username)) {
329       ua_->user_acl = nullptr;
330       auth_success_ = false;
331     } else {
332       UserResource* user = (UserResource*)my_config->GetResWithName(
333           R_USER, authenticated_username.c_str());
334       if (!user) {
335         Dmsg1(200, "No user config found for user %s\n",
336               authenticated_username.c_str());
337         ua_->user_acl = nullptr;
338         auth_success_ = false;
339       } else {
340         ua_->user_acl = &user->user_acl;
341         auth_success_ = true;
342       }
343     }
344     if (auth_success_) {
345       if (!SendResponseMessage(kMessageIdOk, true)) { auth_success_ = false; }
346     }
347     return OptionResult::Completed;
348   } /* HAVE PAM */
349 #endif /* !HAVE_PAM */
350 }
351 
LogErrorMessage(std::string console_name,UaContext * ua)352 static void LogErrorMessage(std::string console_name, UaContext* ua)
353 {
354   Emsg4(M_ERROR, 0, _("Unable to authenticate console \"%s\" at %s:%s:%d.\n"),
355         console_name.c_str(), ua->UA_sock->who(), ua->UA_sock->host(),
356         ua->UA_sock->port());
357 }
358 
NumberOfConsoleConnectionsExceeded()359 static bool NumberOfConsoleConnectionsExceeded()
360 {
361   JobControlRecord* jcr;
362   unsigned int cnt = 0;
363 
364   foreach_jcr (jcr) {
365     if (jcr->is_JobType(JT_CONSOLE)) { cnt++; }
366   }
367   endeach_jcr(jcr);
368 
369   return (cnt >= me->MaxConsoleConnections) ? true : false;
370 }
371 
GetConsoleNameAndVersion(BareosSocket * ua_sock,std::string & name_out,BareosVersionNumber & version_out)372 static bool GetConsoleNameAndVersion(BareosSocket* ua_sock,
373                                      std::string& name_out,
374                                      BareosVersionNumber& version_out)
375 {
376   std::string name;
377   std::string r_code_str_unused;
378   BareosVersionNumber version = BareosVersionNumber::kUndefined;
379 
380   if (GetNameAndResourceTypeAndVersionFromHello(ua_sock->msg, name,
381                                                 r_code_str_unused, version)) {
382     name_out = name;
383     version_out = version;
384     return true;
385   } else {
386     Emsg4(M_ERROR, 0, _("UA Hello from %s:%s:%d is invalid. Got: %s\n"),
387           ua_sock->who(), ua_sock->host(), ua_sock->port(), ua_sock->msg);
388     return false;
389   }
390 }
391 
CreateConsoleAuthenticator(UaContext * ua)392 static ConsoleAuthenticator* CreateConsoleAuthenticator(UaContext* ua)
393 {
394   std::string console_name;
395   BareosVersionNumber version = BareosVersionNumber::kUndefined;
396   if (!GetConsoleNameAndVersion(ua->UA_sock, console_name, version)) {
397     return nullptr;
398   }
399 
400   ua->UA_sock->connected_daemon_version_ =
401       version; /* this is redundant if using cleartext handshake */
402 
403   if (version < BareosVersionNumber::kRelease_18_2) {
404     return new ConsoleAuthenticatorBefore_18_2(ua, console_name);
405   } else /* == kRelease_18_2 */ {
406     return new ConsoleAuthenticatorFrom_18_2(ua, console_name);
407   }
408 }
409 
AuthenticateConsole(UaContext * ua)410 bool AuthenticateConsole(UaContext* ua)
411 {
412   if (NumberOfConsoleConnectionsExceeded()) {
413     Emsg0(M_ERROR, 0,
414           _("Number of console connections exceeded "
415             "MaximumConsoleConnections\n"));
416     return false;
417   }
418 
419   std::unique_ptr<ConsoleAuthenticator> console_authenticator(
420       CreateConsoleAuthenticator(ua));
421   if (!console_authenticator) { return false; }
422 
423   if (console_authenticator->AuthenticateDefaultConsole() ==
424       OptionResult::Completed) {
425     if (!console_authenticator->auth_success_) {
426       LogErrorMessage(console_authenticator->console_name_, ua);
427       return false;
428     }
429   } else {
430     console_authenticator->AuthenticateNamedConsole();
431     if (!console_authenticator->auth_success_) {
432       LogErrorMessage(console_authenticator->console_name_, ua);
433       return false;
434     }
435     if (console_authenticator->AuthenticatePamUser() ==
436         OptionResult::Completed) {
437       if (!console_authenticator->auth_success_) {
438         LogErrorMessage(console_authenticator->console_name_, ua);
439         return false;
440       }
441     }
442   }
443   if (console_authenticator->SendInfoMessage()) {
444     if (!console_authenticator->auth_success_) { return false; }
445   }
446   return true;
447 }
448 } /* namespace directordaemon */
449