From 0bc514b792b4705ae5cc8399b987d0b2997e5c38 Mon Sep 17 00:00:00 2001 From: Frank Ueberschar Date: Sat, 13 Oct 2018 13:55:20 +0200 Subject: [PATCH] pam: refactored authentication and resource definitions - UsePamAuthentication only used in a named console for the director-connection - after successful authentication the username will be used for the according ACL --- core/src/console/console.cc | 12 +-- core/src/console/console_conf.cc | 2 +- core/src/console/console_conf.h | 2 +- core/src/dird/auth_pam.cc | 29 ++++-- core/src/dird/auth_pam.h | 5 +- core/src/dird/authenticate.cc | 163 +++++++++++++++++++++---------- core/src/dird/dird_conf.cc | 2 +- core/src/dird/dird_conf.h | 2 +- core/src/dird/ua_server.cc | 13 --- 9 files changed, 146 insertions(+), 84 deletions(-) diff --git a/core/src/console/console.cc b/core/src/console/console.cc index b8be08f367a..9354942a02a 100644 --- a/core/src/console/console.cc +++ b/core/src/console/console.cc @@ -1094,13 +1094,11 @@ int main(int argc, char *argv[]) ConsoleOutput(errmsg); #if defined(HAVE_PAM) - if (console_resource) { /* not for root console */ - if (director_resource && director_resource->UsePamAuthentication_) { - if (!ConsolePamAuthenticate(stdin, UA_sock)) { - TerminateConsole(0); - return 1; - } - } + if (console_resource && console_resource->use_pam_authentication_) { + if (!ConsolePamAuthenticate(stdin, UA_sock)) { + TerminateConsole(0); + return 1; + } } #endif /* HAVE_PAM */ diff --git a/core/src/console/console_conf.cc b/core/src/console/console_conf.cc index 98d66c7709a..98b4463c646 100644 --- a/core/src/console/console_conf.cc +++ b/core/src/console/console_conf.cc @@ -91,6 +91,7 @@ static ResourceItem cons_items[] = { { "Password", CFG_TYPE_MD5PASSWORD, ITEM(res_cons.password), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL }, { "Director", CFG_TYPE_STR, ITEM(res_cons.director), 0, 0, NULL, NULL, NULL }, { "HeartbeatInterval", CFG_TYPE_TIME, ITEM(res_cons.heartbeat_interval), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL }, + { "UsePamAuthentication", CFG_TYPE_BOOL, ITEM(res_cons.use_pam_authentication_), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL }, TLS_COMMON_CONFIG(res_dir), TLS_CERT_CONFIG(res_dir), TLS_PSK_CONFIG(res_dir), @@ -105,7 +106,6 @@ static ResourceItem dir_items[] = { { "Address", CFG_TYPE_STR, ITEM(res_dir.address), 0, 0, NULL, NULL, NULL }, { "Password", CFG_TYPE_MD5PASSWORD, ITEM(res_dir.password), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL }, { "HeartbeatInterval", CFG_TYPE_TIME, ITEM(res_dir.heartbeat_interval), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL }, - { "UsePamAuthentication", CFG_TYPE_BOOL, ITEM(res_dir.UsePamAuthentication_), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL }, TLS_COMMON_CONFIG(res_dir), TLS_CERT_CONFIG(res_dir), TLS_PSK_CONFIG(res_dir), diff --git a/core/src/console/console_conf.h b/core/src/console/console_conf.h index ed39c34daa9..95918b45f10 100644 --- a/core/src/console/console_conf.h +++ b/core/src/console/console_conf.h @@ -71,6 +71,7 @@ class ConsoleResource : public TlsResource { uint32_t history_length; /**< readline history length */ char *director; /**< bind to director */ utime_t heartbeat_interval; /**< Interval to send heartbeats to Dir */ + bool use_pam_authentication_; /**< Use this console as a PAM console */ ConsoleResource() : TlsResource() {} }; @@ -80,7 +81,6 @@ class DirectorResource : public TlsResource { uint32_t DIRport; /**< UA server port */ char *address; /**< UA server address */ utime_t heartbeat_interval; /**< Interval to send heartbeats to Dir */ - bool UsePamAuthentication_; /**< Use Pam authentication instead of password */ DirectorResource() : TlsResource() {} }; diff --git a/core/src/dird/auth_pam.cc b/core/src/dird/auth_pam.cc index ddf4fe98f0c..89701b35020 100644 --- a/core/src/dird/auth_pam.cc +++ b/core/src/dird/auth_pam.cc @@ -32,12 +32,10 @@ static const int debuglevel = 200; static const std::string service_name("bareos"); struct PamData { - std::string username_; BareosSocket *UA_sock_; PamData(BareosSocket *UA_sock, std::string username) { UA_sock_ = UA_sock; - username_ = username; } }; @@ -139,7 +137,10 @@ static int PamConversionCallback(int num_msg, const struct pam_message **msgm, return PAM_SUCCESS; } -bool PamAuthenticateUseragent(BareosSocket *UA_sock, const std::string &username_in) +bool PamAuthenticateUseragent(BareosSocket *UA_sock, + const std::string &username_in, + const std::string &password_in, + std::string& authenticated_username) { std::unique_ptr pam_callback_data(new PamData(UA_sock, username_in)); std::unique_ptr pam_conversation_container(new struct pam_conv); @@ -153,16 +154,31 @@ bool PamAuthenticateUseragent(BareosSocket *UA_sock, const std::string &username pam_conversation_container.get(), &pamh); if (err != PAM_SUCCESS) { Dmsg1(debuglevel, "PAM start failed: %s\n", pam_strerror(pamh, err)); + return false; } err = pam_set_item(pamh, PAM_RUSER, username); if (err != PAM_SUCCESS) { Dmsg1(debuglevel, "PAM set_item failed: %s\n", pam_strerror(pamh, err)); + return false; } err = pam_authenticate(pamh, 0); if (err != PAM_SUCCESS) { Dmsg1(debuglevel, "PAM authentication failed: %s\n", pam_strerror(pamh, err)); + return false; + } + + const void* data; + err = pam_get_item(pamh, PAM_USER, &data); + if (err != PAM_SUCCESS) { + Dmsg1(debuglevel, "PAM set_item failed: %s\n", pam_strerror(pamh, err)); + return false; + } else { + if (data) { + const char *temp_str = reinterpret_cast(data); + authenticated_username = temp_str; + } } if (pam_end(pamh, err) != PAM_SUCCESS) { @@ -171,10 +187,9 @@ bool PamAuthenticateUseragent(BareosSocket *UA_sock, const std::string &username } if (err == PAM_SUCCESS) { - if (!PamConvSendMessage(UA_sock, "", PAM_SUCCESS)) { - Dmsg1(debuglevel, "PAM end failed: %s\n", pam_strerror(pamh, err)); - return false; + if (PamConvSendMessage(UA_sock, "", PAM_SUCCESS)) { + return true; } } - return err == PAM_SUCCESS; + return false; } diff --git a/core/src/dird/auth_pam.h b/core/src/dird/auth_pam.h index f02607d38b0..ef13209a708 100644 --- a/core/src/dird/auth_pam.h +++ b/core/src/dird/auth_pam.h @@ -25,6 +25,9 @@ #include class BareosSocket; -bool PamAuthenticateUseragent(BareosSocket *UA_sock, const std::string &username); +bool PamAuthenticateUseragent(BareosSocket *UA_sock, + const std::string &username, + const std::string &passwd, + std::string& authenticated_username); #endif /* BAREOS_DIRD_AUTH_PAM_H_ */ diff --git a/core/src/dird/authenticate.cc b/core/src/dird/authenticate.cc index a9ada7e7df2..ae266c9b465 100644 --- a/core/src/dird/authenticate.cc +++ b/core/src/dird/authenticate.cc @@ -33,6 +33,9 @@ #include "include/bareos.h" #include "dird.h" #include "dird/authenticate.h" +#if defined(HAVE_PAM) +#include "dird/auth_pam.h" +#endif #include "dird/fd_cmds.h" #include "dird/client_connection_handshake_mode.h" #include "dird/dird_globals.h" @@ -55,14 +58,8 @@ static char OKhello[] = "3000 OK Hello\n"; static char FDOKhello[] = "2000 OK Hello\n"; static char FDOKnewHello[] = "2000 OK Hello %d\n"; -/* - * Sent to User Agent - */ static char Dir_sorry[] = "1999 You are not authorized.\n"; -/** - * Authenticate with a remote Storage daemon - */ bool AuthenticateWithStorageDaemon(BareosSocket* sd, JobControlRecord *jcr, StorageResource *store) { std::string qualified_resource_name; @@ -121,9 +118,6 @@ bool AuthenticateWithStorageDaemon(BareosSocket* sd, JobControlRecord *jcr, Stor return true; } -/** - * Authenticate with a remote File daemon - */ bool AuthenticateWithFileDaemon(JobControlRecord *jcr) { if (jcr->authenticated) { return true; } @@ -193,9 +187,6 @@ bool AuthenticateWithFileDaemon(JobControlRecord *jcr) return true; } -/** - * Authenticate File daemon connection - */ bool AuthenticateFileDaemon(BareosSocket *fd, char *client_name) { ClientResource *client; @@ -225,10 +216,7 @@ bool AuthenticateFileDaemon(BareosSocket *fd, char *client_name) return true; } -/** - * Count the number of established console connections. - */ -static inline bool count_console_connections() +static bool NumberOfConsoleConnectionsExceeded() { JobControlRecord *jcr; unsigned int cnt = 0; @@ -239,58 +227,129 @@ static inline bool count_console_connections() } endeach_jcr(jcr); - return (cnt >= me->MaxConsoleConnections) ? false : true; + return (cnt >= me->MaxConsoleConnections) ? true : false; } -/** - * Authenticate user agent. - */ -bool AuthenticateUserAgent(UaContext *uac) +static bool GetConsoleName(BareosSocket *ua_sock, std::string &name) { - char name[MAX_NAME_LENGTH]; - ConsoleResource *cons = NULL; - BareosSocket *ua = uac->UA_sock; - bool auth_success = false; + char buffer[MAX_NAME_LENGTH]; /* zero terminated C-string */ - if (sscanf(ua->msg, "Hello %127s calling\n", name) != 1) { - ua->msg[100] = 0; /* Terminate string */ - Emsg4(M_ERROR, 0, _("UA Hello from %s:%s:%d is invalid. Got: %s\n"), ua->who(), ua->host(), ua->port(), - ua->msg); + if (sscanf(ua_sock->msg, "Hello %127s calling\n", buffer) != 1) { + Emsg4(M_ERROR, 0, _("UA Hello from %s:%s:%d is invalid. Got: %s\n"), ua_sock->who(), ua_sock->host(), ua_sock->port(), + ua_sock->msg); return false; } - name[sizeof(name) - 1] = 0; /* Terminate name */ + UnbashSpaces(buffer); + name = buffer; + return true; +} - if (!count_console_connections()) { - ua->fsend("%s", _(Dir_sorry)); - Emsg0(M_ERROR, 0, - _("Number of console connections exhausted, please increase MaximumConsoleConnections\n")); - return false; +static void SendErrorMessage(std::string name_console, UaContext *ua) +{ + ua->UA_sock->fsend("%s", _(Dir_sorry)); + Emsg4(M_ERROR, 0, _("Unable to authenticate console \"%s\" at %s:%s:%d.\n"), name_console.c_str(), + ua->UA_sock->who(), ua->UA_sock->host(), ua->UA_sock->port()); + sleep(5); +} + +static void SendOkMessage(UaContext *ua) +{ + ua->UA_sock->fsend(_("1000 OK: %s Version: %s (%s)\n"), my_name, VERSION, BDATE); +} + +static bool TryAuthenticateRootConsole(std::string name_console, UaContext *ua, bool &auth_success) +{ + const std::string name_root_console { "*UserAgent*" }; + if (name_console == name_root_console) { + auth_success = ua->UA_sock->AuthenticateInboundConnection(NULL, "Console", name_root_console.c_str(), me->password, me); + return true; + } + return false; +} + +static bool TryAuthenticateNamedConsole(std::string name_console, UaContext *ua, bool &auth_success) +{ + ConsoleResource *cons; + cons = (ConsoleResource *)my_config->GetResWithName(R_CONSOLE, name_console.c_str()); + if (cons) { + if (!ua->UA_sock->AuthenticateInboundConnection(NULL, "Console", name_console.c_str(), cons->password, cons)) { + ua->cons = nullptr; + auth_success = false; + } else { + ua->cons = cons; + auth_success = true; + } + return true; } + return false; +} + +static bool TryAuthenticatePamConsole(std::string name_console, UaContext *ua, bool &auth_success) +{ + ConsoleResource *cons = (ConsoleResource *)my_config->GetResWithName(R_CONSOLE, name_console.c_str()); - if (bstrcmp(name, "*UserAgent*")) { /* default console */ - auth_success = ua->AuthenticateInboundConnection(NULL, "Console", "*UserAgent*", me->password, me); + if (!cons) { + auth_success = false; + return true; + } + + if (!cons->use_pam_authentication_) { return false; } + +#if defined(HAVE_PAM) + std::string authenticated_username; + if (!PamAuthenticateUseragent(ua->UA_sock, std::string(), std::string(), authenticated_username)) { + ua->cons = nullptr; + auth_success = false; } else { - UnbashSpaces(name); - cons = (ConsoleResource *)my_config->GetResWithName(R_CONSOLE, name); - if (cons) { - auth_success = ua->AuthenticateInboundConnection(NULL, "Console", name, cons->password, cons); + ConsoleResource *user = (ConsoleResource *)my_config->GetResWithName(R_CONSOLE, + authenticated_username.c_str()); + ua->cons = user; + auth_success = true; + } +#else + Emsg0(M_ERROR, 0, _("PAM is not available on this director\n")); + auth_success = false; +#endif /* HAVE_PAM */ - if (auth_success) { uac->cons = cons; /* save console resource pointer */ } - } + return true; +} + +bool AuthenticateUserAgent(UaContext *ua) +{ + std::string name_console; + if (!GetConsoleName(ua->UA_sock, name_console)) { + return false; } - /* - * Authorization Completed - */ - if (!auth_success) { - ua->fsend("%s", _(Dir_sorry)); - Emsg4(M_ERROR, 0, _("Unable to authenticate console \"%s\" at %s:%s:%d.\n"), name, ua->who(), ua->host(), - ua->port()); - sleep(5); + if (NumberOfConsoleConnectionsExceeded()) { + ua->UA_sock->fsend("%s", _(Dir_sorry)); + Emsg0(M_ERROR, 0, _("Number of console connections exceeded MaximumConsoleConnections\n")); return false; } - ua->fsend(_("1000 OK: %s Version: %s (%s)\n"), my_name, VERSION, BDATE); + bool auth_success = false; + + if (TryAuthenticateRootConsole(name_console, ua, auth_success)) { + if (!auth_success) { + SendErrorMessage(name_console, ua); + return false; + } else { + SendOkMessage(ua); + } + } else if (TryAuthenticateNamedConsole(name_console, ua, auth_success)) { + if (!auth_success) { + SendErrorMessage(name_console, ua); + return false; + } else { + SendOkMessage(ua); + } + if (TryAuthenticatePamConsole(name_console, ua, auth_success)) { + if (!auth_success) { + SendErrorMessage(name_console, ua); + return false; + } + } + } return true; } } /* namespace directordaemon */ diff --git a/core/src/dird/dird_conf.cc b/core/src/dird/dird_conf.cc index 5559c194a71..94e02d00499 100644 --- a/core/src/dird/dird_conf.cc +++ b/core/src/dird/dird_conf.cc @@ -156,7 +156,6 @@ static ResourceItem dir_items[] = { { "SecureEraseCommand", CFG_TYPE_STR, ITEM(res_dir.secure_erase_cmdline), 0, 0, NULL, "15.2.1-", "Specify command that will be called when bareos unlinks files." }, { "LogTimestampFormat", CFG_TYPE_STR, ITEM(res_dir.log_timestamp_format), 0, 0, NULL, "15.2.3-", NULL }, - { "UsePamAuthentication", CFG_TYPE_BOOL, ITEM(res_dir.UsePamAuthentication_), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL }, TLS_COMMON_CONFIG(res_dir), TLS_CERT_CONFIG(res_dir), TLS_PSK_CONFIG(res_dir), @@ -219,6 +218,7 @@ static ResourceItem con_items[] = { { "Profile", CFG_TYPE_ALIST_RES, ITEM(res_con.profiles), R_PROFILE, 0, NULL, "14.2.3-", "Profiles can be assigned to a Console. ACL are checked until either a deny ACL is found or an allow ACL. " "First the console ACL is checked then any profile the console is linked to." }, + { "UsePamAuthentication", CFG_TYPE_BOOL, ITEM(res_con.use_pam_authentication_), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL }, TLS_COMMON_CONFIG(res_con), TLS_CERT_CONFIG(res_con), TLS_PSK_CONFIG(res_con), diff --git a/core/src/dird/dird_conf.h b/core/src/dird/dird_conf.h index a4dca4ee9cc..8c4a45dc23e 100644 --- a/core/src/dird/dird_conf.h +++ b/core/src/dird/dird_conf.h @@ -143,7 +143,6 @@ class DirectorResource: public TlsResource { char *secure_erase_cmdline; /* Cmdline to execute to perform secure erase of file */ char *log_timestamp_format; /* Timestamp format to use in generic logging messages */ s_password keyencrkey; /* Key Encryption Key */ - bool UsePamAuthentication_; /* Optimize daemon for minimum memory size */ DirectorResource() : TlsResource() {} }; @@ -212,6 +211,7 @@ class ConsoleResource : public TlsResource { public: alist *ACL_lists[Num_ACL]; /**< Pointers to ACLs */ alist *profiles; /**< Pointers to profile resources */ + bool use_pam_authentication_; /**< PAM Console */ }; /** diff --git a/core/src/dird/ua_server.cc b/core/src/dird/ua_server.cc index 7665325df2b..fedcfcc2dbf 100644 --- a/core/src/dird/ua_server.cc +++ b/core/src/dird/ua_server.cc @@ -32,9 +32,6 @@ #include "dird.h" #include "dird/dird_globals.h" #include "dird/authenticate.h" -#if defined(HAVE_PAM) -#include "dird/auth_pam.h" -#endif #include "dird/job.h" #include "dird/ua_cmds.h" #include "dird/ua_db.h" @@ -89,16 +86,6 @@ void *HandleUserAgentClientRequest(BareosSocket *user_agent_socket) bool success = AuthenticateUserAgent(ua); -#if defined(HAVE_PAM) - if (success && me->UsePamAuthentication_) { - std::string username; - if (ua->cons) { - username = ua->cons->name(); - success = PamAuthenticateUseragent(ua->UA_sock, username); - } - } -#endif /* HAVE_PAM */ - if (!success) { ua->quit = true; }