Skip to content

Commit

Permalink
console/pam: console pam authentication using separate pam and passwo…
Browse files Browse the repository at this point in the history
…rd file

- added console commandline parameter -p <path-to-textfile>
- changed base class of BStringList from std::list to std::vector
  so the arguments can be accessed using direct access [] or .at() operators
- added additional error messages
- removed one message from bnet.cc; this would show the password in cleartext
  • Loading branch information
franku committed Nov 5, 2018
1 parent 2e01d86 commit caeb22d
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 62 deletions.
58 changes: 52 additions & 6 deletions core/src/console/console.cc
Expand Up @@ -37,7 +37,11 @@
#include "console/console_output.h"
#include "include/jcr.h"
#include "lib/bnet.h"
#include "lib/bstringlist.h"
#include "lib/qualified_resource_name_type_converter.h"
#include <stdio.h>
#include <fstream>
#include <string>

#define ConInit(x)
#define ConTerm()
Expand All @@ -58,6 +62,8 @@ static void TerminateConsole(int sig);
static int CheckResources();
int GetCmd(FILE *input, const char *prompt, BareosSocket *sock, int sec);
static int DoOutputcmd(FILE *input, BareosSocket *UA_sock);
static bool ExaminePamAuthentication(bool use_pam_credentials_file,
const std::string &pam_credentials_filename);

extern "C" void GotSigstop(int sig);
extern "C" void GotSigcontinue(int sig);
Expand Down Expand Up @@ -930,6 +936,8 @@ int main(int argc, char *argv[])
JobControlRecord jcr;
PoolMem history_file;
utime_t heart_beat;
std::string pam_credentials_filename;
bool use_pam_credentials_file = false;

errmsg_len = sizeof(errmsg);
setlocale(LC_ALL, "");
Expand All @@ -943,7 +951,7 @@ int main(int argc, char *argv[])
working_directory = "/tmp";
args = GetPoolMemory(PM_FNAME);

while ((ch = getopt(argc, argv, "D:lc:d:nstu:x:?")) != -1) {
while ((ch = getopt(argc, argv, "D:lc:d:np:stu:x:?")) != -1) {
switch (ch) {
case 'D': /* Director */
if (director) {
Expand Down Expand Up @@ -975,6 +983,21 @@ int main(int argc, char *argv[])
}
break;

case 'p':
pam_credentials_filename = optarg;
if (pam_credentials_filename.empty()) {
Emsg0(M_ERROR_TERM, 0, _("No filename given for -p.\n"));
usage();
} else {
if (FILE *f = fopen(pam_credentials_filename.c_str(), "r+")) {
use_pam_credentials_file = true;
fclose(f);
} else { /* file does not exist */
Emsg0(M_ERROR_TERM, 0, _("Could not open file for -p.\n"));
}
}
break;

case 's': /* turn off signals */
no_signals = true;
break;
Expand Down Expand Up @@ -1097,11 +1120,7 @@ int main(int argc, char *argv[])

if (response == kMessageIdPamRequired) {
#if defined(HAVE_PAM)
FormatAndSendResponseMessage(UA_sock, kMessageIdPamInteractive, "OK");
if (!ConsolePamAuthenticate(stdin, UA_sock)) {
TerminateConsole(0);
return 1;
}
ExaminePamAuthentication(use_pam_credentials_file, pam_credentials_filename);
#else
Dmsg0(100, "This Console program does not have the pam feature\n");
TerminateConsole(0);
Expand Down Expand Up @@ -1162,6 +1181,33 @@ int main(int argc, char *argv[])
return 0;
}

static bool ExaminePamAuthentication(bool use_pam_credentials_file, const std::string &pam_credentials_filename)
{
if (use_pam_credentials_file) {
std::fstream s(pam_credentials_filename, s.in);
if (!s.is_open()) {
Emsg0(M_ERROR_TERM, 0, _("Could not open PAM credentials file.\n"));
return false;
} else {
std::string user, pw;
s >> user >> pw;
if (user.empty() || pw.empty()) {
Emsg0(M_ERROR_TERM, 0, _("Could not read user or password.\n"));
}
BStringList args;
args << user << pw;
FormatAndSendResponseMessage(UA_sock, kMessageIdPamUserCredentials, args);
}
} else {
FormatAndSendResponseMessage(UA_sock, kMessageIdPamInteractive, "OK");
if (!ConsolePamAuthenticate(stdin, UA_sock)) {
TerminateConsole(0);
return false;
}
}
return true;
}

static void TerminateConsole(int sig)
{
static bool already_here = false;
Expand Down
8 changes: 4 additions & 4 deletions core/src/dird/auth_pam.cc
Expand Up @@ -153,13 +153,13 @@ static int PamLocalCallback(int num_msg, const struct pam_message **msgm,
}

bool PamAuthenticateUser(BareosSocket *UA_sock,
const std::string &username_in,
const std::string &password_in,
std::string& authenticated_username)
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, password_in));
std::unique_ptr<struct pam_conv> pam_conversation_container(new struct pam_conv);
struct pam_handle *pamh; /* pam session handle */
struct pam_handle *pamh = nullptr; /* pam session handle */

bool not_interactive = !username_in.empty() && !password_in.empty();
pam_conversation_container->conv = not_interactive ? PamLocalCallback : PamConversationCallback;
Expand Down
24 changes: 17 additions & 7 deletions core/src/dird/authenticate.cc
Expand Up @@ -41,6 +41,7 @@
#include "dird/dird_globals.h"
#include "lib/bnet.h"
#include "lib/qualified_resource_name_type_converter.h"
#include "lib/bstringlist.h"

namespace directordaemon {

Expand Down Expand Up @@ -315,22 +316,30 @@ static bool OptionalAuthenticatePamUser(std::string console_name, UaContext *ua,
/* no need to evaluate auth_success if no pam is required */
if (!cons->use_pam_authentication_) { return false; }

uint32_t response;
std::string message;
uint32_t response_id;
BStringList message_arguments;

if (!ReceiveAndEvaluateResponseMessage(ua->UA_sock, response, message)) {
Dmsg2(100, "Could not evaluate response: %d - %d", response, message.c_str());
if (!ReceiveAndEvaluateResponseMessage(ua->UA_sock, response_id, message_arguments)) {
Dmsg2(100, "Could not evaluate response_id: %d - %d", response_id,
message_arguments.JoinReadable().c_str());
auth_success = false;
return true;
}

std::string pam_username;
std::string pam_password;

if (response == kMessageIdPamUserCredentials) {
/* Ueb: receive username and password */
if (response_id == kMessageIdPamUserCredentials) {
Dmsg0(200, "Console chooses Pam direct credentials\n");
} else if (response == kMessageIdPamInteractive) {
if (message_arguments.size() < 3) {
Dmsg0(200, "Console sent wrong number of credentials\n");
auth_success = false;
return true;
} else {
pam_username = message_arguments.at(1);
pam_password = message_arguments.at(2);
}
} else if (response_id == kMessageIdPamInteractive) {
Dmsg0(200, "Console chooses Pam interactive\n");
}

Expand All @@ -342,6 +351,7 @@ static bool OptionalAuthenticatePamUser(std::string console_name, UaContext *ua,
ConsoleResource *user = (ConsoleResource *)my_config->GetResWithName(R_CONSOLE,
authenticated_username.c_str());
if (!user) {
Dmsg1(200, "No user config found for user %s\n", authenticated_username.c_str());
ua->cons = nullptr;
auth_success = false;
} else {
Expand Down
21 changes: 11 additions & 10 deletions core/src/lib/bnet.cc
Expand Up @@ -612,20 +612,22 @@ bool ReadoutCommandIdFromMessage(const BStringList& list_of_arguments, uint32_t
return true;
}

bool EvaluateResponseMessageId(const std::string &message, uint32_t &id_out, std::string &human_readable_message_out)
bool EvaluateResponseMessageId(const std::string &message, uint32_t &id_out, BStringList &args_out)
{
BStringList list_of_arguments(message, AsciiControlCharacters::RecordSeparator());
uint32_t id = kMessageIdUnknown;

bool ok = ReadoutCommandIdFromMessage(list_of_arguments, id);

id_out = id;
human_readable_message_out = list_of_arguments.Join(' ');
if (ok) {
id_out = id;
}
args_out = list_of_arguments;

return ok;
}

bool ReceiveAndEvaluateResponseMessage(BareosSocket *bsock, uint32_t &id_out, std::string &human_readable_message_out)
bool ReceiveAndEvaluateResponseMessage(BareosSocket *bsock, uint32_t &id_out, BStringList &args_out)
{
int ret = bsock->recv();
bsock->StopTimer();
Expand All @@ -635,21 +637,21 @@ bool ReceiveAndEvaluateResponseMessage(BareosSocket *bsock, uint32_t &id_out, st
return false;
}

Dmsg1(10, "<bsockd: %s", bsock->msg);

std::string message(bsock->msg);

if (message.empty()) {
Dmsg0(100, "Received message is empty\n");
return false;
}

return EvaluateResponseMessageId(message, id_out, human_readable_message_out);
return EvaluateResponseMessageId(message, id_out, args_out);
}

bool FormatAndSendResponseMessage(BareosSocket *bsock, uint32_t id, BStringList list_of_agruments)
bool FormatAndSendResponseMessage(BareosSocket *bsock, uint32_t id, const BStringList &list_of_agruments)
{
std::string m = list_of_agruments.Join(AsciiControlCharacters::RecordSeparator());
std::string m = std::to_string(id);
m += AsciiControlCharacters::RecordSeparator();
m += list_of_agruments.Join(AsciiControlCharacters::RecordSeparator());

if (bsock->send(m.c_str(), m.size()) <=0 ) {
Dmsg1(100, "Could not send response message: %d\n", m.c_str());
Expand All @@ -661,7 +663,6 @@ bool FormatAndSendResponseMessage(BareosSocket *bsock, uint32_t id, BStringList
bool FormatAndSendResponseMessage(BareosSocket *bsock, uint32_t id, const std::string &str)
{
BStringList message;
message << id;
message << str;
message << "\n";

Expand Down
6 changes: 3 additions & 3 deletions core/src/lib/bnet.h
Expand Up @@ -63,13 +63,13 @@ class BStringList;

#ifdef BAREOS_TEST_LIB
bool ReadoutCommandIdFromMessage(const BStringList &list_of_arguments, uint32_t &id_out);
bool EvaluateResponseMessageId(const std::string &message, uint32_t &id_out, std::string &human_readable_message_out);
bool EvaluateResponseMessageId(const std::string &message, uint32_t &id_out, BStringList &args_out);
#endif

bool ReceiveAndEvaluateResponseMessage(BareosSocket *bsock, uint32_t &id_out, std::string &human_readable_message_out);
bool ReceiveAndEvaluateResponseMessage(BareosSocket *bsock, uint32_t &id_out, BStringList &args_out);
bool FormatAndSendResponseMessage(BareosSocket *bsock, uint32_t id, const std::string &str);
bool FormatAndSendResponseMessage(BareosSocket *bsock,
uint32_t id,
BStringList list_of_agruments);
const BStringList &list_of_agruments);

#endif // BAREOS_LIB_BNET_H_
7 changes: 4 additions & 3 deletions core/src/lib/bsock.cc
Expand Up @@ -32,6 +32,7 @@
#include "lib/cram_md5.h"
#include "lib/tls.h"
#include "lib/util.h"
#include "lib/bstringlist.h"

static constexpr int debuglevel = 50;

Expand Down Expand Up @@ -349,10 +350,10 @@ bool BareosSocket::ConsoleAuthenticateWithDirector(JobControlRecord *jcr,
Dmsg1(6, ">dird: %s", dir->msg);

uint32_t message_id;
std::string received_message;
if (ReceiveAndEvaluateResponseMessage(dir, message_id, received_message)) {
BStringList args;
if (ReceiveAndEvaluateResponseMessage(dir, message_id, args)) {
response_id = message_id;
Bsnprintf(response, response_len, "%s\n", received_message.c_str());
Bsnprintf(response, response_len, "%s\n", args.JoinReadable().c_str());
return true;
}
Dmsg0(100, "Wrong Message Protocol ID\n");
Expand Down
19 changes: 12 additions & 7 deletions core/src/lib/bstringlist.cc
Expand Up @@ -25,10 +25,10 @@
#include <algorithm>
#include <iterator>

BStringList::BStringList() : std::list<std::string>() { return; }
BStringList::BStringList() : std::vector<std::string>() { return; }

BStringList::BStringList(const std::string &string_to_split, char separator)
: std::list<std::string>()
: std::vector<std::string>()
{
std::stringstream ss(string_to_split);
std::string token;
Expand All @@ -38,14 +38,14 @@ BStringList::BStringList(const std::string &string_to_split, char separator)
}

BStringList::BStringList(const BStringList &other)
: std::list<std::string>()
: std::vector<std::string>()
{
*this = other;
}

BStringList& BStringList::operator=(const BStringList &rhs)
{
std::list<std::string>::const_iterator it = rhs.cbegin();
std::vector<std::string>::const_iterator it = rhs.cbegin();
while (it != rhs.cend()) {
push_back(*it++);
}
Expand All @@ -64,7 +64,7 @@ BStringList& BStringList::operator << (const int &rhs)
return *this;
}

BStringList& BStringList::operator << (const std::list<std::string> &rhs)
BStringList& BStringList::operator << (const std::vector<std::string> &rhs)
{
Append(rhs);
return *this;
Expand All @@ -76,7 +76,7 @@ BStringList& BStringList::operator << (const char *rhs)
return *this;
}

void BStringList::Append(const std::list<std::string> &vec)
void BStringList::Append(const std::vector<std::string> &vec)
{
for (auto str : vec) {
push_back(str);
Expand All @@ -103,9 +103,14 @@ std::string BStringList::Join() const
return Join(nullptr);
}

std::string BStringList::JoinReadable() const
{
return Join(' ');
}

std::string BStringList::Join(const char *separator) const
{
std::list<std::string>::const_iterator it = cbegin();
std::vector<std::string>::const_iterator it = cbegin();
std::string output;

while (it != cend()) {
Expand Down
7 changes: 4 additions & 3 deletions core/src/lib/bstringlist.h
Expand Up @@ -24,7 +24,7 @@

#include "include/bareos.h"

class BStringList : public std::list<std::string>
class BStringList : public std::vector<std::string>
{
public:
BStringList();
Expand All @@ -34,10 +34,11 @@ class BStringList : public std::list<std::string>
BStringList &operator << (const std::string &rhs);
BStringList &operator << (const int &rhs);
BStringList &operator << (const char *rhs);
BStringList &operator << (const std::list<std::string> &vec);
BStringList &operator << (const std::vector<std::string> &vec);
std::string Join(char separator) const;
std::string JoinReadable() const;
std::string Join() const;
void Append(const std::list<std::string> &vec);
void Append(const std::vector<std::string> &vec);
void Append(char character);
void Append(const char *str);

Expand Down
7 changes: 4 additions & 3 deletions core/src/tests/bsock_test.cc
Expand Up @@ -38,6 +38,7 @@

#include "lib/tls_openssl.h"
#include "lib/bnet.h"
#include "lib/bstringlist.h"

#include "include/jcr.h"

Expand Down Expand Up @@ -446,12 +447,12 @@ TEST(BNet, FormatAndSendResponseMessage)
FormatAndSendResponseMessage(test_sockets->client.get(), kMessageIdOk, m);

uint32_t id = kMessageIdUnknown;
std::string m1;
bool ok = ReceiveAndEvaluateResponseMessage(test_sockets->server.get(), id, m1);
BStringList args;
bool ok = ReceiveAndEvaluateResponseMessage(test_sockets->server.get(), id, args);

EXPECT_TRUE(ok) << "ReceiveAndEvaluateResponseMessage errored.";
EXPECT_EQ(id, kMessageIdOk) << "Wrong MessageID received.";

std::string test("1000 Test123 \n");
EXPECT_STREQ(m1.c_str(), test.c_str());
EXPECT_STREQ(args.JoinReadable().c_str(), test.c_str());
}

0 comments on commit caeb22d

Please sign in to comment.