when multiple password prompts are sent, utilize a counter to differentiate them

This commit is contained in:
Nikos Mavrogiannopoulos
2015-05-19 13:10:26 +02:00
parent 2f266e5828
commit 9797ccee81
9 changed files with 170 additions and 47 deletions
+3 -5
View File
@@ -319,7 +319,7 @@ static int gssapi_auth_pass(void *ctx, const char *spnego, unsigned spnego_len)
}
}
static int gssapi_auth_msg(void *ctx, void *pool, char **msg, char **prompt)
static int gssapi_auth_msg(void *ctx, void *pool, passwd_msg_st *pst)
{
struct gssapi_ctx_st *pctx = ctx;
OM_uint32 min;
@@ -328,13 +328,11 @@ static int gssapi_auth_msg(void *ctx, void *pool, char **msg, char **prompt)
/* our msg is our SPNEGO reply */
if (pctx->msg.value != NULL) {
length = BASE64_LENGTH(pctx->msg.length)+1;
*msg = talloc_size(pool, length);
pst->msg_str = talloc_size(pool, length);
base64_encode((char *)pctx->msg.value, pctx->msg.length, *msg, length);
base64_encode((char *)pctx->msg.value, pctx->msg.length, pst->msg_str, length);
gss_release_buffer(&min, &pctx->msg);
pctx->msg.value = NULL;
} else {
*msg = NULL;
}
return 0;
}
+23 -17
View File
@@ -26,6 +26,7 @@
#include "pam.h"
#include "cfg.h"
#include <sec-mod-auth.h>
#include <ccan/hash/hash.h>
#ifdef HAVE_PAM
@@ -194,12 +195,12 @@ fail1:
return -1;
}
static int pam_auth_msg(void* ctx, void *pool, char** msg, char **prompt)
static int pam_auth_msg(void* ctx, void *pool, passwd_msg_st *pst)
{
struct pam_ctx_st * pctx = ctx;
size_t prompt_hash = 0;
if (pctx->state != PAM_S_INIT && pctx->state != PAM_S_WAIT_FOR_PASS) {
*msg = NULL;
return 0;
}
@@ -214,26 +215,31 @@ struct pam_ctx_st * pctx = ctx;
}
}
if (msg != NULL) {
if (pctx->msg.length == 0)
if (pctx->changing)
*msg = talloc_strdup(pool, "Please enter the new password.");
else
*msg = talloc_strdup(pool, "Please enter your password.");
else {
if (str_append_data(&pctx->msg, "\0", 1) < 0)
return -1;
*msg = talloc_strdup(pool, (char*)pctx->msg.data);
}
if (pctx->msg.length == 0) {
if (pctx->changing)
pst->msg_str = talloc_strdup(pool, "Please enter the new password.");
/* else use the default prompt */
} else {
if (str_append_data(&pctx->msg, "\0", 1) < 0)
return -1;
pst->msg_str = talloc_strdup(pool, (char*)pctx->msg.data);
}
if (prompt != NULL) {
if (pctx->prompt.length > 0)
*prompt = talloc_strdup(pool, (char*)pctx->prompt.data);
if (pctx->prompt.length > 0) {
pst->prompt_str = talloc_strdup(pool, (char*)pctx->prompt.data);
prompt_hash = hash_any(pctx->prompt.data, pctx->prompt.length, 0);
}
pst->counter = pctx->passwd_counter;
/* differentiate password prompts, if the hash of the prompt
* is different.
*/
if (pctx->prev_prompt_hash != prompt_hash)
pctx->passwd_counter++;
pctx->prev_prompt_hash = prompt_hash;
return 0;
}
+2
View File
@@ -45,6 +45,8 @@ struct pam_ctx_st {
unsigned sent_msg;
struct pam_response *replies; /* for safety */
unsigned state; /* PAM_S_ */
unsigned passwd_counter;
size_t prev_prompt_hash;
};
#endif
+4 -2
View File
@@ -268,11 +268,13 @@ static int plain_auth_pass(void *ctx, const char *pass, unsigned pass_len)
}
}
static int plain_auth_msg(void *ctx, void *pool, char **msg, char **prompt)
static int plain_auth_msg(void *ctx, void *pool, passwd_msg_st *pst)
{
struct plain_ctx_st *pctx = ctx;
*msg = talloc_strdup(pool, pctx->pass_msg);
pst->msg_str = talloc_strdup(pool, pctx->pass_msg);
pst->counter = 0; /* we support a single password */
/* use the default prompt */
return 0;
}
+1
View File
@@ -209,6 +209,7 @@ message sec_auth_reply_msg
optional bytes dtls_session_id = 5;
optional bytes sid = 6;
optional string prompt = 7; /* brief prompt */
optional uint32 passwd_counter = 8; /* if that's a password prompt indicates the number of password asked */
}
/* SEC_SIGN/DECRYPT */
+11 -1
View File
@@ -214,6 +214,10 @@ int send_sec_auth_reply_msg(int cfd, sec_mod_st * sec, client_entry_st * e)
msg.msg = e->msg_str;
msg.prompt = e->prompt_str;
msg.passwd_counter = e->passwd_counter;
if (e->passwd_counter > 0)
msg.has_passwd_counter = 1;
msg.reply = AUTH__REP__MSG;
msg.has_sid = 1;
@@ -301,14 +305,20 @@ static
int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int result)
{
int ret;
passwd_msg_st pst;
if ((result == ERR_AUTH_CONTINUE || result == 0) && e->module) {
ret = e->module->auth_msg(e->auth_ctx, e, &e->msg_str, &e->prompt_str);
memset(&pst, 0, sizeof(pst));
ret = e->module->auth_msg(e->auth_ctx, e, &pst);
if (ret < 0) {
e->status = PS_AUTH_FAILED;
seclog(sec, LOG_ERR, "error getting auth msg");
return ret;
}
e->msg_str = pst.msg_str;
e->prompt_str = pst.prompt_str;
e->passwd_counter = pst.counter;
}
if (result == ERR_AUTH_CONTINUE) {
+7 -1
View File
@@ -27,13 +27,19 @@
#define MAX_AUTH_REQS 8
#define MAX_GROUPS 32
typedef struct passwd_msg_st {
char *prompt_str;
char *msg_str;
unsigned counter;
} passwd_msg_st;
typedef struct auth_mod_st {
unsigned int type;
unsigned int allows_retries; /* whether the module allows retries of the same password */
void (*global_init)(void *pool, void* additional);
void (*global_deinit)(void);
int (*auth_init)(void** ctx, void *pool, const char* username, const char *remote_ip, const char *our_ip, unsigned id);
int (*auth_msg)(void* ctx, void *pool, char** msg, char **prompt);
int (*auth_msg)(void* ctx, void *pool, passwd_msg_st *);
int (*auth_pass)(void* ctx, const char* pass, unsigned pass_len);
int (*auth_group)(void* ctx, const char *suggested, char *groupname, int groupname_size);
int (*auth_user)(void* ctx, char *groupname, int groupname_size);
+1
View File
@@ -75,6 +75,7 @@ typedef struct client_entry_st {
char *msg_str;
char *prompt_str;
unsigned passwd_counter; /* if prompt_str is for a password this indicates the passwrd number (0,1,2) */
stats_st saved_stats; /* saved from previous cookie usage */
stats_st stats; /* current */
+118 -21
View File
@@ -76,6 +76,8 @@ static const char login_msg_user[] =
#define LOGIN_MSG_PASSWORD \
"<input type=\"password\" name=\"password\" label=\"%s\" />\n"
#define LOGIN_MSG_PASSWORD_CTR \
"<input type=\"password\" name=\"password%d\" label=\"%s\" />\n"
#define OCV3_LOGIN_MSG_START \
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
@@ -162,7 +164,7 @@ static int append_group_str(worker_st * ws, str_st *str, const char *group)
return 0;
}
int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg, const char *prompt)
int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg, const char *prompt, unsigned pcounter)
{
int ret;
char context[BASE64_LENGTH(SID_SIZE) + 1];
@@ -235,7 +237,10 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg, const
goto cleanup;
}
ret = str_append_printf(&str, LOGIN_MSG_PASSWORD, prompt);
if (pcounter > 0)
ret = str_append_printf(&str, LOGIN_MSG_PASSWORD_CTR, pcounter, prompt);
else
ret = str_append_printf(&str, LOGIN_MSG_PASSWORD, prompt);
if (ret < 0) {
ret = -1;
goto cleanup;
@@ -399,7 +404,7 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg, const
int get_auth_handler(worker_st * ws, unsigned http_ver)
{
return get_auth_handler2(ws, http_ver, NULL, NULL);
return get_auth_handler2(ws, http_ver, NULL, NULL, 0);
}
int get_cert_names(worker_st * ws, const gnutls_datum_t * raw)
@@ -728,7 +733,7 @@ int connect_to_secmod(worker_st * ws)
return sd;
}
static int recv_auth_reply(worker_st * ws, int sd, char **txt, char **prompt)
static int recv_auth_reply(worker_st * ws, int sd, char **txt, char **prompt, unsigned *pcounter)
{
int ret;
SecAuthReplyMsg *msg = NULL;
@@ -749,11 +754,6 @@ static int recv_auth_reply(worker_st * ws, int sd, char **txt, char **prompt)
switch (msg->reply) {
case AUTH__REP__MSG:
if (txt == NULL || msg->msg == NULL) {
oclog(ws, LOG_ERR, "received unexpected msg");
return ERR_AUTH_FAIL;
}
if (msg->prompt)
*prompt = talloc_strdup(ws, msg->prompt);
else
@@ -764,6 +764,11 @@ static int recv_auth_reply(worker_st * ws, int sd, char **txt, char **prompt)
else
*txt = NULL;
if (msg->has_passwd_counter)
*pcounter = msg->passwd_counter;
else
*pcounter = 0;
if (msg->has_sid && msg->sid.len == sizeof(ws->sid)) {
/* update our sid */
memcpy(ws->sid, msg->sid.data, sizeof(ws->sid));
@@ -1028,10 +1033,104 @@ int post_common_handler(worker_st * ws, unsigned http_ver, const char *imsg)
return 0;
}
#define XMLUSER "<username>"
#define XMLPASS "<password>"
#define XMLUSER_END "</username>"
#define XMLPASS_END "</password>"
/* Returns the contents of the provided fields in a newly allocated
* string, or a negative value on error.
*
* @body: is the string to search the xml field at, should be null-terminated.
* @xml_field: the XML field to check for (e.g., MYFIELD)
* @value: the value that was found
*/
static
int match_password_in_reply(worker_st * ws, char *body, unsigned body_length,
char **value)
{
char *p;
char temp1[64];
unsigned len, xml = 0;
if (body == NULL || body_length == 0)
return -1;
if (memmem(body, body_length, "<?xml", 5) != 0) {
xml = 1;
strlcpy(temp1, "<password", sizeof(temp1));
/* body should contain <field>test</field> */
*value =
strcasestr(body, temp1);
if (*value == NULL) {
oclog(ws, LOG_HTTP_DEBUG,
"cannot find password in client XML message");
return -1;
}
/* find terminator */
p = strchr(*value, '>');
if (p == NULL) {
oclog(ws, LOG_HTTP_DEBUG,
"unterminated password in client XML message");
return -1;
}
p++;
*value = p;
len = 0;
while (*p != 0) {
if (*p == '<'
&& (strncasecmp(p, "</password", sizeof("</password")-1) == 0)) {
break;
}
p++;
len++;
}
} else { /* non-xml version */
/* body should be "username=test&password=test" */
*value =
strcasestr(body, "password");
if (*value == NULL) {
oclog(ws, LOG_HTTP_DEBUG,
"cannot find password in client message");
return -1;
}
p = strchr(*value, '=');
if (p == NULL) {
oclog(ws, LOG_HTTP_DEBUG,
"unterminated password in client message");
return -1;
}
p++;
*value = p;
len = 0;
while (*p != 0) {
if (*p == '&') {
break;
}
p++;
len++;
}
}
if (len == 0) {
*value = talloc_strdup(ws->req.body, "");
if (*value != NULL)
return 0;
return -1;
}
if (xml)
*value = unescape_html(ws->req.body, *value, len, NULL);
else
*value = unescape_url(ws->req.body, *value, len, NULL);
if (*value == NULL) {
oclog(ws, LOG_ERR,
"password requested but no such field in client message");
return -1;
}
return 0;
}
/* Returns the contents of the provided fields in a newly allocated
* string, or a negative value on error.
@@ -1207,7 +1306,6 @@ static char *get_our_ip(int fd, char str[MAX_IP_STR])
}
#define USERNAME_FIELD "username"
#define PASSWORD_FIELD "password"
#define GROUPNAME_FIELD "group%5flist"
#define GROUPNAME_FIELD2 "group_list"
#define GROUPNAME_FIELD_XML "group-select"
@@ -1228,6 +1326,7 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
char our_ip_str[MAX_IP_STR];
char *msg = NULL, *prompt = NULL;
unsigned def_group = 0;
unsigned pcounter = 0;
if (req->body_length > 0) {
oclog(ws, LOG_HTTP_DEBUG, "POST body: '%.*s'", (int)req->body_length,
@@ -1312,7 +1411,7 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
if (def_group == 0 && ws->cert_groups_size > 0 && ws->groupname[0] == 0) {
oclog(ws, LOG_HTTP_DEBUG, "user has not selected a group");
return get_auth_handler2(ws, http_ver, "Please select your group", NULL);
return get_auth_handler2(ws, http_ver, "Please select your group", NULL, 0);
}
ireq.tls_auth_ok = ws->cert_auth_ok;
@@ -1361,10 +1460,8 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
}
if (areq.password == NULL && ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) {
ret = parse_reply(ws, req->body, req->body_length,
PASSWORD_FIELD, sizeof(PASSWORD_FIELD)-1,
NULL, 0,
&password);
ret = match_password_in_reply(ws, req->body, req->body_length,
&password);
if (ret < 0) {
reason = MSG_NO_PASSWORD_ERROR;
oclog(ws, LOG_ERR, "failed reading password");
@@ -1412,7 +1509,7 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
goto auth_fail;
}
ret = recv_auth_reply(ws, sd, &msg, &prompt);
ret = recv_auth_reply(ws, sd, &msg, &prompt, &pcounter);
if (sd != -1) {
close(sd);
sd = -1;
@@ -1426,7 +1523,7 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) {
ret = basic_auth_handler(ws, http_ver, msg);
} else {
ret = get_auth_handler2(ws, http_ver, msg, prompt);
ret = get_auth_handler2(ws, http_ver, msg, prompt, pcounter);
}
goto cleanup;
} else if (ret < 0) {