Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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
  • Loading branch information
franku committed Oct 30, 2018
1 parent 25d6a98 commit 0bc514b
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 84 deletions.
12 changes: 5 additions & 7 deletions core/src/console/console.cc
Expand Up @@ -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 */

Expand Down
2 changes: 1 addition & 1 deletion core/src/console/console_conf.cc
Expand Up @@ -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),
Expand All @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion core/src/console/console_conf.h
Expand Up @@ -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() {}
};

Expand All @@ -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() {}
};

Expand Down
29 changes: 22 additions & 7 deletions core/src/dird/auth_pam.cc
Expand Up @@ -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;
}
};

Expand Down Expand Up @@ -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<PamData> pam_callback_data(new PamData(UA_sock, username_in));
std::unique_ptr<struct pam_conv> pam_conversation_container(new struct pam_conv);
Expand All @@ -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<const char*>(data);
authenticated_username = temp_str;
}
}

if (pam_end(pamh, err) != PAM_SUCCESS) {
Expand All @@ -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;
}
5 changes: 4 additions & 1 deletion core/src/dird/auth_pam.h
Expand Up @@ -25,6 +25,9 @@
#include <string>

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_ */
163 changes: 111 additions & 52 deletions core/src/dird/authenticate.cc
Expand Up @@ -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"
Expand All @@ -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;
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -193,9 +187,6 @@ bool AuthenticateWithFileDaemon(JobControlRecord *jcr)
return true;
}

/**
* Authenticate File daemon connection
*/
bool AuthenticateFileDaemon(BareosSocket *fd, char *client_name)
{
ClientResource *client;
Expand Down Expand Up @@ -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;
Expand All @@ -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 */
2 changes: 1 addition & 1 deletion core/src/dird/dird_conf.cc
Expand Up @@ -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),
Expand Down Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion core/src/dird/dird_conf.h
Expand Up @@ -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() {}
};
Expand Down Expand Up @@ -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 */
};

/**
Expand Down

0 comments on commit 0bc514b

Please sign in to comment.