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