Skip to content

Commit

Permalink
pam: pam interactive is working with the server handshake protokol
Browse files Browse the repository at this point in the history
- added some functions to convert messages into command strings and vice versa
- added tests for the convert functions
- traymon does not work yet
  • Loading branch information
franku committed Nov 5, 2018
1 parent 9793393 commit 8632eaa
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 110 deletions.
24 changes: 14 additions & 10 deletions core/src/console/console.cc
Expand Up @@ -858,7 +858,7 @@ static bool SelectDirector(const char *director, DirectorResource **ret_dir, Con
}

namespace console {
BareosSocket *ConnectToDirector(JobControlRecord &jcr, utime_t heart_beat, char *errmsg, int errmsg_len)
BareosSocket *ConnectToDirector(JobControlRecord &jcr, utime_t heart_beat, char *errmsg, int errmsg_len, uint32_t &response)
{
BareosSocketTCP *UA_sock = New(BareosSocketTCP);
if (!UA_sock->connect(NULL, 5, 15, heart_beat, "Director daemon", director_resource->address, NULL,
Expand Down Expand Up @@ -903,7 +903,8 @@ BareosSocket *ConnectToDirector(JobControlRecord &jcr, utime_t heart_beat, char
return nullptr;
}

if (!UA_sock->AuthenticateWithDirector(&jcr, name, *password, errmsg, errmsg_len, director_resource)) {
if (!UA_sock->ConsoleAuthenticateWithDirector(&jcr, name, *password, errmsg,
errmsg_len, director_resource, response)) {
ConsoleOutput(errmsg);
TerminateConsole(0);
return nullptr;
Expand Down Expand Up @@ -1086,24 +1087,27 @@ int main(int argc, char *argv[])
heart_beat = 0;
}

UA_sock = ConnectToDirector(jcr, heart_beat, errmsg, errmsg_len);
uint32_t response;
UA_sock = ConnectToDirector(jcr, heart_beat, errmsg, errmsg_len, response);
if (!UA_sock) { return 1; }

UA_sock->OutputCipherMessageString(ConsoleOutput);

ConsoleOutput(errmsg);

#if 0 // Ueb
if (response == kMessageIdPamRequired) {
#if defined(HAVE_PAM)
// UA_sock->fsend("@@username:bareos-pam");
// UA_sock->fsend("@@password:linuxlinux");
Bmicrosleep(1,0);
if (!ConsolePamAuthenticate(stdin, UA_sock)) {
FormatAndSendResponseMessage(UA_sock, kMessageIdPamInteractive, "OK");
if (!ConsolePamAuthenticate(stdin, UA_sock)) {
TerminateConsole(0);
return 1;
}
#else
Dmsg0(100, "This Console program does not have the pam feature\n");
TerminateConsole(0);
return 1;
}
#endif /* HAVE_PAM */
#endif
}

Dmsg0(40, "Opened connection with Director daemon\n");

Expand Down
84 changes: 34 additions & 50 deletions core/src/dird/authenticate.cc
Expand Up @@ -254,7 +254,14 @@ static void SendErrorMessage(std::string console_name, UaContext *ua)

static void SendOkMessage(UaContext *ua)
{
ua->UA_sock->fsend(_("1000 OK: %s Version: %s (%s)\n"), my_name, VERSION, BDATE);
char buffer[100];
::snprintf(buffer, 100, "OK: %s Version: %s (%s)", my_name, VERSION, BDATE);

if (ua->cons && ua->cons->use_pam_authentication_) {
FormatAndSendResponseMessage(ua->UA_sock, kMessageIdPamRequired, std::string(buffer));
} else {
FormatAndSendResponseMessage(ua->UA_sock, kMessageIdOk, std::string(buffer));
}
}

static bool OptionalAuthenticateRootConsole(std::string console_name, UaContext *ua, bool &auth_success)
Expand Down Expand Up @@ -284,49 +291,21 @@ static void AuthenticateNamedConsole(std::string console_name, UaContext *ua, bo
}
}

#if defined(HAVE_PAM)
static void LookupTokenFromSocketStream(BareosSocket *ua_sock, const std::string& token, std::string& output)
{
std::unique_ptr<char> buffer(new char[token.size()]);
memset(buffer.get(), 0, token.size());

int flags = ua_sock->SetNonblocking();

int tries = 3;
bool ready = false;

do {
Bmicrosleep(1,0);
int ret = ::recv(ua_sock->fd_, buffer.get(), token.size(), MSG_PEEK);
if (ret == (int)token.size()) {
if (ua_sock->recv() <= 0) { return; }
std::string temp(ua_sock->msg);
output = temp.substr(temp.find(':')+1);
ready = true;
}
} while (tries-- && !ready);

ua_sock->RestoreBlocking(flags);
}

static void LookupOptionalUsername(BareosSocket *ua_sock, std::string& pam_username)
{
const std::string token {"@@username:"};
LookupTokenFromSocketStream(ua_sock, token, pam_username);
}

static void LookupOptionalPassword(BareosSocket *ua_sock, std::string& pam_password)
{
const std::string token {"@@password:"};
LookupTokenFromSocketStream(ua_sock, token, pam_password);
}
#endif /* HAVE PAM */

static bool OptionalAuthenticatePamUser(std::string console_name, UaContext *ua, bool &auth_success)
{
ConsoleResource *cons = (ConsoleResource *)my_config->GetResWithName(R_CONSOLE, console_name.c_str());

#if defined(HAVE_PAM)
#if !defined(HAVE_PAM)
{
if (cons && cons->use_pam_authentication_) {
Emsg0(M_ERROR, 0, _("PAM is not available on this director\n"));
auth_success = false;
return true;
} else {
return false; /* auth_success can be ignored */
}
}
#else /* HAVE_PAM */
{
if (!cons) { /* if console resource cannot be obtained is treated as an error */
auth_success = false;
Expand All @@ -336,11 +315,24 @@ 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;

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

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

LookupOptionalUsername(ua->UA_sock, pam_username);
LookupOptionalPassword(ua->UA_sock, pam_password);
if (response == kMessageIdPamUserCredentials) {
/* Ueb: receive username and password */
Dmsg0(200, "Console chooses Pam direct credentials\n");
} else if (response == kMessageIdPamInteractive) {
Dmsg0(200, "Console chooses Pam interactive\n");
}

std::string authenticated_username;
if (!PamAuthenticateUser(ua->UA_sock, pam_username, pam_password, authenticated_username)) {
Expand All @@ -359,14 +351,6 @@ static bool OptionalAuthenticatePamUser(std::string console_name, UaContext *ua,
}
return true;
} /* HAVE PAM */
#else /* !HAVE_PAM */
if (cons && cons->use_pam_authentication_) {
Emsg0(M_ERROR, 0, _("PAM is not available on this director\n"));
auth_success = false;
return true;
} else {
return false; /* auth_success can be ignored */
}
#endif /* !HAVE_PAM */
}

Expand Down
6 changes: 3 additions & 3 deletions core/src/lib/ascii_control_characters.h
Expand Up @@ -24,9 +24,9 @@

class AsciiControlCharacters {
public:
static char UnitSeparator() { return unit_separator_; }
static char RecordSeparator() { return record_separator_; }
static char GroupSeparator() { return group_separator_; }
static char UnitSeparator() { return unit_separator_; } /* smallest data item separator */
static char RecordSeparator() { return record_separator_; } /* data record separator within a group */
static char GroupSeparator() { return group_separator_; } /* group separator to separate datasets */

private:
static constexpr char unit_separator_ = 0x1f;
Expand Down
84 changes: 64 additions & 20 deletions core/src/lib/bnet.cc
Expand Up @@ -37,6 +37,7 @@
#include "jcr.h"
#include "lib/bnet.h"
#include "lib/bsys.h"
#include "lib/ascii_control_characters.h"

#include <netdb.h>
#include "lib/tls.h"
Expand Down Expand Up @@ -590,50 +591,93 @@ const char *BnetSigToAscii(BareosSocket * bs)
}
}

bool ReadoutCommandIdFromString(const std::string &message, uint32_t &id_out)
bool ReadoutCommandIdFromMessage(const std::string &message, uint32_t &id_out)
{
const char delimiter = ' ';
size_t pos = message.find(delimiter);
if (pos == std::string::npos) {
const char delimiter = AsciiControlCharacters::RecordSeparator();

size_t delimiter_position = message.find(delimiter);
if (delimiter_position == std::string::npos) {
id_out = kMessageIdProtokollError;
return false;
}

uint32_t id;
size_t pos1;
size_t position_after_number;

try {
id = std::stoul(message, &pos1);
try { /* "1000 OK: <director name> ..." */
id = std::stoul(message, &position_after_number);
} catch (const std::exception &e) {
id_out = kMessageIdProtokollError;
return false;
}
if (pos == pos1) {
id_out = id;
return true;
} else {

if (position_after_number != delimiter_position) {
id_out = kMessageIdProtokollError;
return false;
} else {
id_out = id;
return true;
}
}

bool ReceiveAndEvaluateResponse(BareosSocket *bsock, uint32_t &id_out, std::string &message_out)
bool EvaluateResponseMessage(std::string &message, uint32_t &id_out, std::string &human_readable_message_out)
{
int recv_return_value = bsock->recv();
uint32_t id = kMessageIdUnknown;
bool ok = ReadoutCommandIdFromMessage(message, id);

id_out = id;
SwapSeparatorsInString(message);
human_readable_message_out = message;

return ok;

}

bool ReceiveAndEvaluateResponseMessage(BareosSocket *bsock, uint32_t &id_out, std::string &human_readable_message_out)
{
int ret = bsock->recv();
bsock->StopTimer();

if (recv_return_value <= 0) {
if (ret <= 0) {
Dmsg1(100, "Error while receiving response message: %s", bsock->msg);
return false;
}

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

const std::string message(bsock->msg);
uint32_t id;
bool ok = ReadoutCommandIdFromString(message, id);
std::string message(bsock->msg);

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

return ok;
return EvaluateResponseMessage(message, id_out, human_readable_message_out);
}

bool FormatAndSendResponseMessage(BareosSocket *bsock, uint32_t id, std::vector<std::string> optional_arguments)
{
std::string message;
message += std::to_string(id);

for (auto s : optional_arguments) {
message += AsciiControlCharacters::RecordSeparator();
message += s;
}

message += '\n';

const char *m = message.c_str();

if (bsock->send(m, message.size()) <=0 ) {
Dmsg1(100, "Could not send response message: %d\n", message.c_str());
return false;
}
return true;
}

bool FormatAndSendResponseMessage(BareosSocket *bsock, uint32_t id, const std::string &str)
{
std::vector<std::string> vec { str };
FormatAndSendResponseMessage(bsock, id, vec);
}
12 changes: 10 additions & 2 deletions core/src/lib/bnet.h
Expand Up @@ -59,7 +59,15 @@ enum : uint32_t {
kMessageIdPamUserCredentials = 4002
};

bool ReadoutCommandIdFromString(const std::string &message, uint32_t &id_out);
bool ReceiveAndEvaluateResponse(BareosSocket *bsock, uint32_t &id_out, std::string &message_out);
#ifdef BAREOS_TEST_LIB
bool ReadoutCommandIdFromMessage(const std::string &message, uint32_t &id_out);
bool EvaluateResponseMessage(std::string &message, uint32_t &id_out, std::string &human_readable_message_out);
#endif

bool ReceiveAndEvaluateResponseMessage(BareosSocket *bsock, uint32_t &id_out, std::string &human_readable_message_out);
bool FormatAndSendResponseMessage(BareosSocket *bsock, uint32_t id, const std::string &str);
bool FormatAndSendResponseMessage(BareosSocket *bsock,
uint32_t id,
std::vector<std::string> optional_arguments = std::vector<std::string>());

#endif // BAREOS_LIB_BNET_H_

0 comments on commit 8632eaa

Please sign in to comment.