mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-10-12 01:26:48 +08:00
when multiple password prompts are sent, utilize a counter to differentiate them
This commit is contained in:
+3
-5
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user