diff --git a/core/src/console/console.cc b/core/src/console/console.cc index 7e9f7078ae2..5f96afbe999 100644 --- a/core/src/console/console.cc +++ b/core/src/console/console.cc @@ -28,6 +28,8 @@ * Bareos Console interface to the Director */ +#include + #include "include/bareos.h" #include "console_conf.h" #include "jcr.h" @@ -1134,45 +1136,101 @@ static bool SetEcho(FILE *stdin, bool on) return true; } +enum class PamAuthState { + INIT, + RECEIVE_MSG_TYPE, + RECEIVE_MSG, + READ_INPUT, + SEND_INPUT, + AUTH_OK +}; + +static PamAuthState state = PamAuthState::INIT; + static bool ConsolePamAuthenticate(FILE *stdin, BareosSocket *UA_sock) { bool quit = false; - bool failed = false; + bool error = false; + + int type; btimer_t *tid = nullptr; - static bool pw = false; - do { - if(tid) { - StopBsockTimer(tid); - } - tid = StartBsockTimer(UA_sock, 10); - if (!tid) { - failed = true; - continue; - } - if (UA_sock->recv() >= 0) { - sendit(UA_sock->msg); - } else { - failed = true; - continue; - } - if (!pw) { - pw = true; - } else { - SetEcho (stdin, false); - quit = true; + char *userinput = nullptr; + + while (!error && !quit) { + switch(state) { + case PamAuthState::INIT: + if(tid) { + StopBsockTimer(tid); + } + tid = StartBsockTimer(UA_sock, 10); + if (!tid) { + error = true; + } + state = PamAuthState::RECEIVE_MSG_TYPE; + break; + case PamAuthState::RECEIVE_MSG_TYPE: + if (UA_sock->recv() == 1) { + type = UA_sock->msg[0]; + switch (type) { + case PAM_PROMPT_ECHO_OFF: + case PAM_PROMPT_ECHO_ON: + SetEcho (stdin, type == PAM_PROMPT_ECHO_ON); + state = PamAuthState::RECEIVE_MSG; + break; + case PAM_SUCCESS: + state = PamAuthState::AUTH_OK; + quit = true; + break; + default: + Dmsg1(100, "Error, unknown pam type %d\n", type); + error = true; + break; + } /* switch (type) */ + } else { + error = true; + } + break; + case PamAuthState::RECEIVE_MSG: + if (UA_sock->recv() > 0) { + sendit(UA_sock->msg); + state = PamAuthState::READ_INPUT; + } else { + error = true; + } + break; + case PamAuthState::READ_INPUT: { + userinput = readline(""); + if (userinput) { + state = PamAuthState::SEND_INPUT; + } else { + error = true; + } + } + break; + case PamAuthState::SEND_INPUT: + UA_sock->fsend(userinput); + Actuallyfree(userinput); + state = PamAuthState::INIT; + break; + default: + break; } - char *line = readline(""); - if (line) { - UA_sock->fsend(line); - Actuallyfree(line); - } else { - failed = true; - continue; + if (UA_sock->IsStop() || UA_sock->IsError()) { + if(userinput) { + Actuallyfree(userinput); + } + if(tid) { + StopBsockTimer(tid); + } + error = true; + break; } - } while (!quit && !failed); + }; /* while (!quit) */ SetEcho (stdin, true); - return failed ? false : true; + sendit("\n"); + + return !error; } /* diff --git a/core/src/dird/auth_pam.cc b/core/src/dird/auth_pam.cc index 6c7cdd6d51d..4369fccccb9 100644 --- a/core/src/dird/auth_pam.cc +++ b/core/src/dird/auth_pam.cc @@ -39,69 +39,112 @@ struct PamData { } }; -/// PAM-Callback calls Bareos PAM-Handler -static int conv(int num_msg, const struct pam_message **msgm, - struct pam_response **response, void *appdata_ptr) { - if (!num_msg || !*msgm || !response) { +/* + * PAM-Callback called by Bareos PAM-Handler + * + */ +static bool pam_conv_callback_send_message(BareosSocket *bs, const char *msg, int msg_style) +{ + char buf = msg_style; + if (!bs->send((const char*)&buf, 1)) { + Dmsg0(debuglevel, "pam_conv_callback_send_message error\n"); + return false; + } + if (!bs->send(msg, strlen(msg) +1)) { + Dmsg0(debuglevel, "pam_conv_callback_send_message error\n"); + return false; + } + return true; +} + +static int pam_conv_callback(int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr) +{ + if (!appdata_ptr) { + Dmsg0(debuglevel, "pam_conv_callback pointer error\n"); return PAM_BUF_ERR; } if ((num_msg <= 0) || (num_msg > PAM_MAX_NUM_MSG)) { + Dmsg0(debuglevel, "pam_conv_callback wrong number of messages\n"); return (PAM_CONV_ERR); } - struct pam_response *resp; - resp = static_cast(actuallycalloc(num_msg, sizeof(struct pam_response))); - if (resp == nullptr) { + struct pam_response *resp = + reinterpret_cast (actuallycalloc( + num_msg, sizeof(struct pam_response))); + + if (!resp) { + Dmsg0(debuglevel, "pam_conv_callback memory error\n"); return PAM_BUF_ERR; } - auto pam_data = reinterpret_cast(appdata_ptr); - ASSERT(pam_data); - - switch ((*msgm)->msg_style) { - case PAM_PROMPT_ECHO_OFF: - case PAM_PROMPT_ECHO_ON: { - BareosSocket *bs = pam_data->bs_; - bs->fsend((*msgm)->msg); - if (bs->recv()) { - resp->resp = actuallystrdup(bs->msg); + PamData *pam_data = reinterpret_cast(appdata_ptr); + + bool error = false; + int i = 0; + for ( ; i < num_msg && !error; i++) { + switch (msgm[i]->msg_style) { + case PAM_PROMPT_ECHO_OFF: + case PAM_PROMPT_ECHO_ON: { + BareosSocket *bs = pam_data->bs_; + if (!pam_conv_callback_send_message(bs, + msgm[i]->msg, msgm[i]->msg_style)) { + error = true; + break; + } + if (bs->IsStop() || bs->IsError()) { + error = true; + break; + } + if (bs->recv()) { + resp[i].resp = actuallystrdup(bs->msg); + } + if (bs->IsStop() || bs->IsError()) { + error = true; + break; + } + break; + } + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: { + BareosSocket *bs = pam_data->bs_; + if (!pam_conv_callback_send_message(bs, + msgm[i]->msg, PAM_PROMPT_ECHO_ON)) { + error = true; + break; + } + } + default: + Dmsg3(debuglevel, "message[%d]: pam error type: %d error: \"%s\"\n", + 1, msgm[i]->msg_style, msgm[i]->msg); + error = true; + break; + } /* switch (msgm[i]->msg_style) { */ + } /* for( ; i < num_msg ..) */ + + + if (error) { + for (int i = 0; i < num_msg; ++i) { + if (resp[i].resp) { + memset(resp[i].resp, 0, strlen(resp[i].resp)); + Actuallyfree(resp[i].resp); } - break; - } - case PAM_ERROR_MSG: - case PAM_TEXT_INFO: { - BareosSocket *bs = pam_data->bs_; - bs->fsend((*msgm)->msg); - break; - } - default: { - const pam_message *m = *msgm; - Dmsg3(debuglevel, "message[%d]: pam error type: %d error: \"%s\"\n", - 1, m->msg_style, m->msg); - goto err; } + memset(resp, 0, num_msg * sizeof *resp); + Actuallyfree(resp); + *response = nullptr; + return PAM_CONV_ERR; } *response = resp; return PAM_SUCCESS; - - err: - for (int i = 0; i < num_msg; ++i) { - if (resp[i].resp) { - memset(resp[i].resp, 0, strlen(resp[i].resp)); - free(resp[i].resp); - } - } - memset(resp, 0, num_msg * sizeof *resp); - free(resp); - *response = nullptr; - return PAM_CONV_ERR; } -bool pam_authenticate_useragent(BareosSocket *bs, std::string username) { +bool pam_authenticate_useragent(BareosSocket *bs, std::string username) +{ PamData pam_data(bs, username); - const struct pam_conv pam_conversation = {conv, (void *) &pam_data}; + const struct pam_conv pam_conversation = {pam_conv_callback, (void *) &pam_data}; pam_handle_t *pamh = nullptr; int err = pam_start(service_name.c_str(), nullptr, &pam_conversation, &pamh); @@ -124,5 +167,12 @@ bool pam_authenticate_useragent(BareosSocket *bs, std::string username) { return false; } - return err == 0; + if (err == PAM_SUCCESS) { + if (!pam_conv_callback_send_message(bs, + "", PAM_SUCCESS)) { + Dmsg1(debuglevel, "PAM end failed: %s\n", pam_strerror(pamh, err)); + return false; + } + } + return err == PAM_SUCCESS; } diff --git a/core/src/dird/ua.h b/core/src/dird/ua.h index 31486bcfe75..e690cd08e6e 100644 --- a/core/src/dird/ua.h +++ b/core/src/dird/ua.h @@ -51,10 +51,10 @@ class UaContext { BareosSocket *sd; JobControlRecord *jcr; BareosDb *db; - BareosDb *shared_db; /**< Shared database connection used by multiple ua's */ - BareosDb *private_db; /**< Private database connection only used by this ua */ + BareosDb *shared_db; /**< Shared database connection used by multiple ua's */ + BareosDb *private_db; /**< Private database connection only used by this ua */ CatalogResource *catalog; - ConsoleResource *cons; /**< Console resource */ + ConsoleResource *cons; /**< Console resource */ POOLMEM *cmd; /**< Return command/name buffer */ POOLMEM *args; /**< Command line arguments */ POOLMEM *errmsg; /**< Store error message */ @@ -77,7 +77,7 @@ class UaContext { uint32_t pint32_val; /**< Positive integer */ int32_t int32_val; /**< Positive/negative */ int64_t int64_val; /**< Big int */ - OutputFormatter *send; /**< object instance to handle output */ + OutputFormatter *send; /**< object instance to handle output */ private: /* diff --git a/core/src/lib/bsock.cc b/core/src/lib/bsock.cc index cd855b6b183..8ff84b18873 100644 --- a/core/src/lib/bsock.cc +++ b/core/src/lib/bsock.cc @@ -268,6 +268,25 @@ bool BareosSocket::fsend(const char *fmt, ...) return send(); } +/** + * Send a message buffer + * Returns: false on error + * true on success + */ +bool BareosSocket::send(const char *msg_in, uint32_t nbytes) +{ + if (errors || IsTerminated()) { + return false; + } + + msg = CheckPoolMemorySize(msg, nbytes); + memcpy(msg, msg_in, nbytes); + + message_length = nbytes; + + return send(); +} + void BareosSocket::SetKillable(bool killable) { if (jcr_) { diff --git a/core/src/lib/bsock.h b/core/src/lib/bsock.h index a5e882e3ffa..734ef2ad527 100644 --- a/core/src/lib/bsock.h +++ b/core/src/lib/bsock.h @@ -149,6 +149,7 @@ class DLL_IMP_EXP BareosSocket : public SmartAlloc { virtual int WaitData(int sec, int usec = 0) = 0; virtual int WaitDataIntr(int sec, int usec = 0) = 0; bool fsend(const char*, ...); + bool send(const char *msg, uint32_t nbytes); void SetKillable(bool killable); bool signal(int signal); const char *bstrerror(); /* last error on socket */ diff --git a/core/src/lib/bsock_tcp.h b/core/src/lib/bsock_tcp.h index ba5383dc6a4..d7c15eff36b 100644 --- a/core/src/lib/bsock_tcp.h +++ b/core/src/lib/bsock_tcp.h @@ -60,6 +60,7 @@ class DLL_IMP_EXP BareosSocketTCP : public BareosSocket { int32_t recv(); bool send(); bool fsend(const char*, ...); + bool send(const char*, int32_t nbytes); int32_t read_nbytes(char *ptr, int32_t nbytes); int32_t write_nbytes(char *ptr, int32_t nbytes); bool signal(int signal);