Added the select-group and auto-select-group config options.

These options allow to prompt the user for a group prior to login.
That in addition enhances the password file format and multiple groups
can be specified on a comma separated list, as:
user:group1,group2,group3:$5$encodedpassword
This commit is contained in:
Nikos Mavrogiannopoulos
2014-05-19 13:12:47 +02:00
committed by Nikos Mavrogiannopoulos
parent 6bc625df81
commit 4755ee48c5
14 changed files with 442 additions and 238 deletions

View File

@@ -271,6 +271,19 @@ route = 192.168.5.0/255.255.255.0
#default-user-config = /etc/ocserv/defaults/user.conf
#default-group-config = /etc/ocserv/defaults/group.conf
# Groups that a client is allowed to select from.
# A client may belong in multiple groups, and in certain use-cases
# it is needed to switch between them. For these cases the client can
# select prior to authentication. Add multiple entries for multiple groups.
#select-group = group1
#select-group = group2
#select-group = tost
# Instead of specifying manually all the allowed groups, you may instruct
# ocserv to scan all available groups and include the full list. That
# option is only functional on plain authentication.
#auto-select-group = true
# The system command to use to setup a route. %R will be replaced with the
# route/mask and %D with the (tun) device.
#

View File

@@ -1,2 +1,2 @@
test:tost:$5$i6SNmLDCgBNjyJ7q$SZ4bVJb7I/DLgXo3txHBVohRFBjOtdbxGQZp.DOnrA.
test:tost , group1 , group2:$5$i6SNmLDCgBNjyJ7q$SZ4bVJb7I/DLgXo3txHBVohRFBjOtdbxGQZp.DOnrA.
tost:*:$5$qc1CKWjcmlrFREe2$h9zQJcD3AeuQmwMncdIqqls47TDOUvu2r2nXQ7aDfcD

View File

@@ -264,17 +264,40 @@ struct pam_ctx_st * pctx = ctx;
/* Returns 0 if the user is successfully authenticated
*/
static int pam_auth_group(void* ctx, char *groupname, int groupname_size)
static int pam_auth_group(void* ctx, const char *suggested, char *groupname, int groupname_size)
{
struct passwd * pwd;
struct pam_ctx_st * pctx = ctx;
struct group *grp;
int ret;
groupname[0] = 0;
pwd = getpwnam(pctx->username);
if (pwd != NULL) {
struct group* grp = getgrgid(pwd->pw_gid);
if (grp != NULL)
snprintf(groupname, groupname_size, "%s", grp->gr_name);
if (suggested != NULL) {
gid_t groups[MAX_GROUPS];
int ngroups = sizeof(groups)/sizeof(groups[0]);
unsigned i;
ret = getgrouplist(pctx->username, pwd->pw_gid, groups, &ngroups);
if (ret <= 0) {
return 0;
}
for (i=0;i<ngroups;i++) {
grp = getgrgid(groups[i]);
if (grp != NULL && strcmp(suggested, grp->gr_name) == 0) {
snprintf(groupname, groupname_size, "%s", grp->gr_name);
return 0;
}
}
} else {
struct group* grp = getgrgid(pwd->pw_gid);
if (grp != NULL)
snprintf(groupname, groupname_size, "%s", grp->gr_name);
}
}
return 0;
@@ -322,7 +345,8 @@ const struct auth_mod_st pam_auth_funcs = {
.auth_msg = pam_auth_msg,
.auth_pass = pam_auth_pass,
.auth_group = pam_auth_group,
.auth_user = pam_auth_user
.auth_user = pam_auth_user,
.group_list = NULL
};
#endif

View File

@@ -24,7 +24,10 @@
#include <syslog.h>
#include <unistd.h>
#include <vpn.h>
#include <c-ctype.h>
#include "plain.h"
#include <ccan/htable/htable.h>
#include <ccan/hash/hash.h>
#define MAX_CPASS_SIZE 128
#define MAX_TRIES 3
@@ -35,17 +38,66 @@ const char* pass_msg_failed = "Login failed.\nPlease enter your password.";
struct plain_ctx_st {
char username[MAX_USERNAME_SIZE];
char cpass[MAX_CPASS_SIZE]; /* crypt() passwd */
char groupname[MAX_GROUPNAME_SIZE];
char *groupnames[MAX_GROUPS];
unsigned groupnames_size;
const char *passwd; /* password file */
const char *pass_msg;
unsigned retries;
};
/* Breaks a list of "xxx", "yyy", to a character array, of
* MAX_COMMA_SEP_ELEMENTS size; Note that the given string is modified.
*/
static void
break_group_list(void *pool, char *text,
char *broken_text[MAX_GROUPS], unsigned *elements)
{
char *p = talloc_strdup(pool, text);
char *p2;
unsigned len;
*elements = 0;
if (p == NULL)
return;
do {
broken_text[*elements] = p;
(*elements)++;
p = strchr(p, ',');
if (p) {
*p = 0;
len = p - broken_text[*elements-1];
/* remove any trailing space */
p2 = p-1;
while (c_isspace(*p2)) {
*p2 = 0;
p2--;
}
p++; /* move to next entry and skip white
* space.
*/
while (c_isspace(*p))
p++;
if (len == 1) {
/* skip the group */
(*elements)--;
}
}
}
while (p != NULL && *elements < MAX_GROUPS);
}
/* Returns 0 if the user is successfully authenticated, and sets the appropriate group name.
*/
static int read_auth_pass(struct plain_ctx_st *pctx)
{
unsigned groupname_size;
FILE *fp;
char line[512];
ssize_t ll;
@@ -81,12 +133,7 @@ static int read_auth_pass(struct plain_ctx_st *pctx)
if (p != NULL && strcmp(pctx->username, p) == 0) {
p = strtok_r(NULL, ":", &sp);
if (p != NULL) {
groupname_size = sizeof(pctx->groupname);
groupname_size =
snprintf(pctx->groupname, groupname_size,
"%s", p);
if (groupname_size == 1) /* values like '*' or 'x' indicate empty group */
pctx->groupname[0] = 0;
break_group_list(pctx, p, pctx->groupnames, &pctx->groupnames_size);
p = strtok_r(NULL, ":", &sp);
if (p != NULL) {
@@ -118,10 +165,7 @@ static int plain_auth_init(void **ctx, void *pool, const char *username, const c
return ERR_AUTH_FAIL;
snprintf(pctx->username, sizeof(pctx->username), "%s", username);
pctx->groupname[0] = 0;
pctx->cpass[0] = 0;
pctx->passwd = additional;
pctx->retries = 0;
pctx->pass_msg = pass_msg_first;
ret = read_auth_pass(pctx);
@@ -135,12 +179,25 @@ static int plain_auth_init(void **ctx, void *pool, const char *username, const c
return 0;
}
static int plain_auth_group(void *ctx, char *groupname, int groupname_size)
static int plain_auth_group(void *ctx, const char *suggested, char *groupname, int groupname_size)
{
struct plain_ctx_st *pctx = ctx;
unsigned i;
snprintf(groupname, groupname_size, "%s", pctx->groupname);
groupname[0] = 0;
if (suggested != NULL) {
for (i=0;i<pctx->groupnames_size;i++) {
if (strcmp(suggested, pctx->groupnames[i]) == 0) {
snprintf(groupname, groupname_size, "%s", pctx->groupnames[i]);
break;
}
}
}
if (pctx->groupnames_size > 0 && groupname[0] == 0) {
snprintf(groupname, groupname_size, "%s", pctx->groupnames[0]);
}
return 0;
}
@@ -185,6 +242,101 @@ static void plain_auth_deinit(void *ctx)
talloc_free(ctx);
}
static size_t rehash(const void *_e, void *unused)
{
const char *e = _e;
return hash_any(e, strlen(e), 0);
}
static bool str_cmp(const void* _c1, void* _c2)
{
const char *c1 = _c1, *c2 = c2;
if (strcmp(c1, c2) == 0)
return 1;
return 0;
}
static void plain_group_list(void *pool, void *additional, char ***groupname, unsigned *groupname_size)
{
FILE *fp;
char line[512];
ssize_t ll;
char *p, *sp;
unsigned i;
size_t hval;
struct htable_iter iter;
char *tgroup[MAX_GROUPS];
unsigned tgroup_size;
struct htable hash;
htable_init(&hash, rehash, NULL);
pool = talloc_init("plain");
fp = fopen(additional, "r");
if (fp == NULL) {
syslog(LOG_AUTH,
"error in plain authentication; cannot open: %s",
(char*)additional);
return;
}
line[sizeof(line)-1] = 0;
while ((p=fgets(line, sizeof(line)-1, fp)) != NULL) {
ll = strlen(p);
if (ll <= 4)
continue;
if (line[ll - 1] == '\n') {
ll--;
line[ll] = 0;
}
if (line[ll - 1] == '\r') {
ll--;
line[ll] = 0;
}
p = strtok_r(line, ":", &sp);
if (p != NULL) {
p = strtok_r(NULL, ":", &sp);
if (p != NULL) {
break_group_list(pool, p, tgroup, &tgroup_size);
for (i=0;i<tgroup_size;i++) {
hval = rehash(tgroup[i], NULL);
if (htable_get(&hash, hval, str_cmp, tgroup[i]) == NULL) {
if (strlen(tgroup[i]) > 1)
htable_add(&hash, hval, tgroup[i]);
}
}
}
}
}
*groupname_size = 0;
*groupname = talloc_size(pool, sizeof(char*)*MAX_GROUPS);
if (*groupname == NULL) {
goto exit;
}
p = htable_first(&hash, &iter);
while (p != NULL) {
(*groupname)[(*groupname_size)] = talloc_strdup(*groupname, p);
p = htable_next(&hash, &iter);
(*groupname_size)++;
}
/* always succeed */
exit:
htable_clear(&hash);
safe_memset(line, 0, sizeof(line));
fclose(fp);
return;
}
const struct auth_mod_st plain_auth_funcs = {
.type = AUTH_TYPE_PLAIN | AUTH_TYPE_USERNAME_PASS,
.auth_init = plain_auth_init,
@@ -192,5 +344,6 @@ const struct auth_mod_st plain_auth_funcs = {
.auth_msg = plain_auth_msg,
.auth_pass = plain_auth_pass,
.auth_user = plain_auth_user,
.auth_group = plain_auth_group
.auth_group = plain_auth_group,
.group_list = plain_group_list
};

View File

@@ -30,8 +30,11 @@
#include <limits.h>
#include <common.h>
#include <c-strcase.h>
#include <auth/pam.h>
#include <auth/plain.h>
#include <vpn.h>
#include <main.h>
#include <ctl.h>
#include <tlslib.h>
@@ -51,6 +54,7 @@ struct cfg_options {
static struct cfg_options available_options[] = {
{ .name = "auth", .type = OPTION_MULTI_LINE, .mandatory = 1 },
{ .name = "route", .type = OPTION_MULTI_LINE, .mandatory = 0 },
{ .name = "select-group", .type = OPTION_MULTI_LINE, .mandatory = 0 },
{ .name = "custom-header", .type = OPTION_MULTI_LINE, .mandatory = 0 },
{ .name = "split-dns", .type = OPTION_MULTI_LINE, .mandatory = 0 },
{ .name = "listen-host", .type = OPTION_STRING, .mandatory = 0 },
@@ -79,6 +83,7 @@ static struct cfg_options available_options[] = {
{ .name = "occtl-socket-file", .type = OPTION_STRING, .mandatory = 0 },
{ .name = "banner", .type = OPTION_STRING, .mandatory = 0 },
{ .name = "predictable-ips", .type = OPTION_BOOLEAN, .mandatory = 0 },
{ .name = "auto-select-group", .type = OPTION_BOOLEAN, .mandatory = 0 },
/* this is alias for cisco-client-compat */
{ .name = "always-require-cert", .type = OPTION_BOOLEAN, .mandatory = 0 },
{ .name = "cisco-client-compat", .type = OPTION_BOOLEAN, .mandatory = 0 },
@@ -257,7 +262,8 @@ const tOptionValue* val, *prev;
unsigned j, i, mand;
char** auth = NULL;
unsigned auth_size = 0;
unsigned prefix = 0;
unsigned prefix = 0, auto_select_group = 0;
const struct auth_mod_st *amod = NULL;
char *tmp;
unsigned force_cert_auth;
@@ -294,6 +300,7 @@ unsigned force_cert_auth;
}
#ifdef HAVE_PAM
config->auth_types |= AUTH_TYPE_PAM;
amod = &pam_auth_funcs;
#else
fprintf(stderr, "PAM support is disabled\n");
exit(1);
@@ -313,6 +320,7 @@ unsigned force_cert_auth;
exit(1);
}
*p = 0;
amod = &plain_auth_funcs;
config->auth_types |= AUTH_TYPE_PLAIN;
} else if (c_strcasecmp(auth[j], "certificate") == 0) {
config->auth_types |= AUTH_TYPE_CERTIFICATE;
@@ -492,6 +500,13 @@ unsigned force_cert_auth;
}
}
READ_TF("auto-select-group", auto_select_group, 0);
if (auto_select_group != 0 && amod != NULL && amod->group_list != NULL) {
amod->group_list(config, config->plain_passwd, &config->group_list, &config->group_list_size);
} else {
READ_MULTI_LINE("select-group", config->group_list, config->group_list_size);
}
READ_MULTI_LINE("dns", config->network.dns, config->network.dns_size);
if (config->network.dns_size == 0) {
/* try the aliases */
@@ -691,6 +706,9 @@ unsigned i;
for (i=0;i<config->split_dns_size;i++)
DEL(config->split_dns[i]);
DEL(config->split_dns);
for (i=0;i<config->group_list_size;i++)
DEL(config->group_list[i]);
DEL(config->group_list);
#ifdef HAVE_LIBTALLOC
/* our included talloc don't include that */
talloc_free_children(config);

View File

@@ -129,10 +129,11 @@ message sec_auth_init_msg
required bool user_present = 1;
required bool tls_auth_ok = 2 [default = false];
required string user_name = 3;
optional string cert_user_name = 4;
optional string cert_group_name = 5;
optional string hostname = 6;
required string ip = 7;
optional string group_name = 4; /* selected group name */
optional string cert_user_name = 5;
optional string cert_group_name = 6;
optional string hostname = 7;
required string ip = 8;
}
/* SEC_AUTH_CONT */

View File

@@ -754,7 +754,7 @@ unsigned total = 10;
if (reload_conf != 0) {
mslog(s, NULL, LOG_INFO, "reloading configuration");
reload_cfg_file(s->main_pool, &s->config);
reload_cfg_file(s->main_pool, s->config);
tls_reload_crl(s, s->creds);
reload_conf = 0;
}

View File

@@ -32,7 +32,7 @@
#include <common.h>
int cmd_parser (void *pool, int argc, char **argv, struct cfg_st** config);
void reload_cfg_file(void *pool, struct cfg_st** config);
void reload_cfg_file(void *pool, struct cfg_st* config);
void clear_cfg_file(struct cfg_st* config);
void write_pid_file(void);
void remove_pid_file(void);

View File

@@ -345,6 +345,18 @@ route = 192.168.1.0/255.255.255.0
route = 192.168.5.0/255.255.255.0
#route = fef4:db8:1000:1001::/64
# Groups that a client is allowed to select from.
# A client may belong in multiple groups, and in certain use-cases
# it is needed to switch between them. For these cases the client can
# select prior to authentication. Add multiple entries for multiple groups.
#select-group = group1
#select-group = group2
# Instead of specifying manually all the allowed groups, you may instruct
# ocserv to scan all available groups and include the full list. That
# option is only functional on plain authentication.
#auto-select-group = true
# Configuration files that will be applied per user connection or
# per group. Each file name on these directories must match the username
# or the groupname.

View File

@@ -353,7 +353,6 @@ int handle_sec_auth_init(sec_mod_st * sec, const SecAuthInitMsg * req)
snprintf(e->hostname, sizeof(e->hostname), "%s", req->hostname);
}
if (sec->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
/* req->username is non-null at this point */
ret =
@@ -364,7 +363,7 @@ int handle_sec_auth_init(sec_mod_st * sec, const SecAuthInitMsg * req)
}
ret =
module->auth_group(e->auth_ctx, e->groupname,
module->auth_group(e->auth_ctx, req->group_name, e->groupname,
sizeof(e->groupname));
if (ret != 0)
return -1;

View File

@@ -24,15 +24,17 @@
#include <main.h>
#define MAX_AUTH_REQS 8
#define MAX_GROUPS 32
struct auth_mod_st {
unsigned int type;
int (*auth_init)(void** ctx, void *pool, const char* username, const char* ip, void* additional);
int (*auth_msg)(void* ctx, char* msg, size_t msg_size);
int (*auth_pass)(void* ctx, const char* pass, unsigned pass_len);
int (*auth_group)(void* ctx, char *groupname, int groupname_size);
int (*auth_group)(void* ctx, const char *suggested, char *groupname, int groupname_size);
int (*auth_user)(void* ctx, char *groupname, int groupname_size);
void (*auth_deinit)(void* ctx);
void (*group_list)(void *pool, void *additional, char ***groupname, unsigned *groupname_size);
};
void main_auth_init(main_server_st *s);

View File

@@ -199,6 +199,9 @@ struct cfg_st {
char *ocsp_response; /* file with the OCSP response */
char *default_domain; /* domain to be advertised */
char **group_list; /* select_group */
unsigned int group_list_size;
char **custom_header;
unsigned custom_header_size;;

View File

@@ -54,22 +54,27 @@
#define SUCCESS_MSG_FOOT "</auth></config-auth>\n"
static const char login_msg_user[] =
static const char login_msg_user_start[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<config-auth client=\"vpn\" type=\"auth-request\">\n"
VERSION_MSG
"<auth id=\"main\">\n"
"<message>Please enter your username</message>\n"
"<form method=\"post\" action=\"/auth\">\n"
"<input type=\"text\" name=\"username\" label=\"Username:\" />\n"
"<input type=\"text\" name=\"username\" label=\"Username:\" />\n";
static const char login_msg_user_end[] =
"</form></auth>\n" "</config-auth>";
static const char login_msg_no_user[] =
static const char login_msg_no_user_start[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<config-auth client=\"vpn\" type=\"auth-request\">\n"
VERSION_MSG
"<auth id=\"main\">\n"
"<message>%s</message>\n"
"<message>";
static const char login_msg_no_user_end[] =
"</message>\n"
"<form method=\"post\" action=\"/auth\">\n"
"<input type=\"password\" name=\"password\" label=\"Password:\" />\n"
"</form></auth></config-auth>\n";
@@ -77,9 +82,12 @@ static const char login_msg_no_user[] =
int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg)
{
int ret;
char login_msg[MAX_MSG_SIZE + sizeof(login_msg_user)];
char context[BASE64_LENGTH(SID_SIZE) + 1];
unsigned int lsize;
char temp[128];
unsigned int i;
str_st str;
str_init(&str, ws);
tls_cork(ws->session);
ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver);
@@ -105,46 +113,111 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg)
}
ret = tls_puts(ws->session, "Content-Type: text/xml\r\n");
if (ret < 0)
return -1;
if (ret < 0) {
ret = -1;
goto cleanup;
}
if (ws->auth_state == S_AUTH_REQ) {
/* only ask password */
if (pmsg == NULL)
pmsg = "Please enter your password.";
lsize =
snprintf(login_msg, sizeof(login_msg), login_msg_no_user,
pmsg);
ret = str_append_str(&str, login_msg_no_user_start);
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = str_append_str(&str, pmsg);
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = str_append_str(&str, login_msg_no_user_end);
if (ret < 0) {
ret = -1;
goto cleanup;
}
} else {
/* ask for username only */
lsize =
snprintf(login_msg, sizeof(login_msg), "%s",
login_msg_user);
/* ask for username and group */
ret = str_append_str(&str, login_msg_user_start);
if (ret < 0) {
ret = -1;
goto cleanup;
}
/* send groups */
if (ws->groupname[0] == 0 && ws->config->group_list_size > 0) {
ret = str_append_str(&str, "<select name=\"group_list\" label=\"GROUP:\">\n");
if (ret < 0) {
ret = -1;
goto cleanup;
}
for (i=0;i<ws->config->group_list_size;i++) {
snprintf(temp, sizeof(temp), "<option>%s</option>\n", ws->config->group_list[i]);
ret = str_append_str(&str, temp);
if (ret < 0) {
ret = -1;
goto cleanup;
}
}
ret = str_append_str(&str, "</select>\n");
if (ret < 0) {
ret = -1;
goto cleanup;
}
}
ret = str_append_str(&str, login_msg_user_end);
if (ret < 0) {
ret = -1;
goto cleanup;
}
}
ret =
tls_printf(ws->session, "Content-Length: %u\r\n",
(unsigned int)lsize);
if (ret < 0)
return -1;
(unsigned int)str.length);
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n");
if (ret < 0)
return -1;
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = tls_puts(ws->session, "\r\n");
if (ret < 0)
return -1;
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = tls_send(ws->session, str.data, str.length);
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = tls_send(ws->session, login_msg, lsize);
if (ret < 0)
return -1;
ret = tls_uncork(ws->session);
if (ret < 0)
return -1;
if (ret < 0) {
ret = -1;
goto cleanup;
}
return 0;
ret = 0;
cleanup:
str_clear(&str);
return ret;
}
int get_auth_handler(worker_st * ws, unsigned http_ver)
@@ -670,151 +743,93 @@ int post_common_handler(worker_st * ws, unsigned http_ver)
* buffers.
*/
static
int read_user_pass(worker_st * ws, char *body, unsigned body_length,
char **username, char **password)
int parse_reply(worker_st * ws, char *body, unsigned body_length,
const char *field, unsigned field_size,
const char *xml_field, unsigned xml_field_size,
char **value)
{
char *p;
char temp1[64];
char temp2[64];
unsigned temp2_len, temp1_len;
unsigned len;
if (memmem(body, body_length, "<?xml", 5) != 0) {
if (username != NULL) {
/* body should contain <username>test</username><password>test</password> */
*username =
memmem(body, body_length, XMLUSER,
sizeof(XMLUSER) - 1);
if (*username == NULL) {
oclog(ws, LOG_DEBUG,
"cannot find username in client XML message");
return -1;
}
*username += sizeof(XMLUSER) - 1;
if (xml_field) {
field = xml_field;
field_size = xml_field_size;
}
if (password != NULL) {
*password =
memmem(body, body_length, XMLPASS,
sizeof(XMLPASS) - 1);
if (*password == NULL) {
oclog(ws, LOG_DEBUG,
"cannot find password in client XML message");
return -1;
}
*password += sizeof(XMLPASS) - 1;
temp1_len = snprintf(temp1, sizeof(temp1), "<%s>", field);
temp2_len = snprintf(temp2, sizeof(temp2), "</%s>", field);
/* body should contain <username>test</username><password>test</password> */
*value =
memmem(body, body_length, temp1, temp1_len);
if (*value == NULL) {
oclog(ws, LOG_DEBUG,
"cannot find '%s' in client XML message", field);
return -1;
}
*value += temp1_len;
/* modify body */
if (username != NULL) {
p = *username;
while (*p != 0) {
if (*p == '<'
&&
(strncmp
(p, XMLUSER_END,
sizeof(XMLUSER_END) - 1) == 0)) {
*p = 0;
break;
}
p++;
p = *value;
len = 0;
while (*p != 0) {
if (*p == '<'
&& (strncmp(p, temp2, temp2_len) == 0)) {
break;
}
*username =
unescape_html(ws, *username, strlen(*username),
NULL);
p++;
len++;
}
if (password != NULL) {
p = *password;
while (*p != 0) {
if (*p == '<'
&&
(strncmp
(p, XMLPASS_END,
sizeof(XMLPASS_END) - 1) == 0)) {
*p = 0;
break;
}
p++;
}
*password =
unescape_html(ws, *password, strlen(*password),
NULL);
}
} else { /* non-xml version */
temp1_len = snprintf(temp1, sizeof(temp1), "%s=", field);
/* body should be "username=test&password=test" */
if (username != NULL) {
*username =
memmem(body, body_length, "username=",
sizeof("username=") - 1);
if (*username == NULL) {
oclog(ws, LOG_DEBUG,
"cannot find username in client message");
return -1;
}
*username += sizeof("username=") - 1;
*value =
memmem(body, body_length, temp1, temp1_len);
if (*value == NULL) {
oclog(ws, LOG_DEBUG,
"cannot find '%s' in client message", field);
return -1;
}
if (password != NULL) {
*password =
memmem(body, body_length, "password=",
sizeof("password=") - 1);
if (*password == NULL) {
oclog(ws, LOG_DEBUG,
"cannot find password in client message");
return -1;
*value += temp1_len;
p = *value;
len = 0;
while (*p != 0) {
if (*p == '&') {
break;
}
*password += sizeof("password=") - 1;
}
/* modify body */
if (username != NULL) {
p = *username;
while (*p != 0) {
if (*p == '&') {
*p = 0;
break;
}
p++;
}
*username =
unescape_url(ws, *username, strlen(*username),
NULL);
}
if (password != NULL) {
p = *password;
while (*p != 0) {
if (*p == '&') {
*p = 0;
break;
}
p++;
}
*password =
unescape_url(ws, *password, strlen(*password),
NULL);
p++;
len++;
}
}
if (username != NULL && *username == NULL) {
oclog(ws, LOG_ERR,
"username requested but no username in client message");
if (len == 0) {
oclog(ws, LOG_DEBUG,
"cannot parse '%s' in client XML message", field);
return -1;
}
*value =
unescape_url(ws->req.body, *value, len, NULL);
if (password != NULL && *password == NULL) {
if (*value == NULL) {
oclog(ws, LOG_ERR,
"password requested but no password in client message");
"%s requested but no such field in client message", field);
return -1;
}
return 0;
}
#define USERNAME_FIELD "username"
#define PASSWORD_FIELD "password"
#define GROUPNAME_FIELD "group%5flist"
#define GROUPNAME_FIELD_XML "group-select"
int post_auth_handler(worker_st * ws, unsigned http_ver)
{
int ret, sd = -1;
@@ -822,6 +837,7 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
const char *reason = "Authentication failed";
char *username = NULL;
char *password = NULL;
char *groupname = NULL;
char tmp_user[MAX_USERNAME_SIZE];
char tmp_group[MAX_USERNAME_SIZE];
char ipbuf[128];
@@ -830,71 +846,31 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
oclog(ws, LOG_HTTP_DEBUG, "POST body: '%.*s'", (int)req->body_length,
req->body);
if (ws->sid_set && ws->auth_state == S_AUTH_INACTIVE)
ws->auth_state = S_AUTH_INIT;
if (ws->auth_state == S_AUTH_INACTIVE) {
SecAuthInitMsg ireq = SEC_AUTH_INIT_MSG__INIT;
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
ret =
read_user_pass(ws, req->body, req->body_length,
&username, NULL);
ret = parse_reply(ws, req->body, req->body_length,
GROUPNAME_FIELD, sizeof(GROUPNAME_FIELD)-1,
GROUPNAME_FIELD_XML, sizeof(GROUPNAME_FIELD_XML)-1,
&groupname);
if (ret < 0) {
/* No username, see if we are continuing a previous session */
if (ws->config->cisco_client_compat != 0 &&
gnutls_session_is_resumed(ws->session) !=
0) {
SecAuthContMsg rreq =
SEC_AUTH_CONT_MSG__INIT;
/* could it be a client reconnecting and sending
* his password? */
ret =
read_user_pass(ws, req->body,
req->body_length,
NULL, &password);
if (ret < 0) {
oclog(ws, LOG_INFO,
"failed reading password as well");
goto ask_auth;
}
rreq.tls_auth_ok = ws->cert_auth_ok;
rreq.password = password;
rreq.ip =
human_addr2((void *)&ws->remote_addr, ws->remote_addr_len,
ipbuf, sizeof(ipbuf), 0);
if (ws->sid_set != 0) {
rreq.sid.data = ws->sid;
rreq.sid.len = sizeof(ws->sid);
}
sd = connect_to_secmod(ws);
if (sd == -1) {
oclog(ws, LOG_ERR,
"failed connecting to sec mod");
goto auth_fail;
}
ret =
send_msg_to_secmod(ws, sd,
SM_CMD_AUTH_CONT,
&rreq,
(pack_size_func)
sec_auth_cont_msg__get_packed_size,
(pack_func)
sec_auth_cont_msg__pack);
talloc_free(username);
if (ret < 0) {
oclog(ws, LOG_ERR,
"failed sending auth reinit message to main");
goto auth_fail;
}
ws->auth_state = S_AUTH_INIT;
goto recv_reply;
}
oclog(ws, LOG_DEBUG, "failed reading groupname");
} else {
snprintf(ws->groupname, sizeof(ws->groupname), "%s",
groupname);
ireq.group_name = ws->groupname;
talloc_free(groupname);
}
ret = parse_reply(ws, req->body, req->body_length,
USERNAME_FIELD, sizeof(USERNAME_FIELD)-1,
NULL, 0,
&username);
if (ret < 0) {
oclog(ws, LOG_INFO, "failed reading username");
goto ask_auth;
}
@@ -952,9 +928,10 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
SecAuthContMsg areq = SEC_AUTH_CONT_MSG__INIT;
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
ret =
read_user_pass(ws, req->body, req->body_length,
NULL, &password);
ret = parse_reply(ws, req->body, req->body_length,
PASSWORD_FIELD, sizeof(PASSWORD_FIELD)-1,
NULL, 0,
&password);
if (ret < 0) {
oclog(ws, LOG_ERR, "failed reading password");
goto auth_fail;
@@ -996,7 +973,6 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
goto auth_fail;
}
recv_reply:
ret = recv_auth_reply(ws, sd, msg, sizeof(msg));
if (sd != -1)
close(sd);
@@ -1019,11 +995,13 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
return post_common_handler(ws, http_ver);
ask_auth:
if (sd != -1)
close(sd);
return get_auth_handler(ws, http_ver);
auth_fail:
if (sd != -1)
close(sd);
tls_printf(ws->session,

View File

@@ -197,6 +197,7 @@ typedef struct worker_st {
char username[MAX_USERNAME_SIZE];
char groupname[MAX_USERNAME_SIZE];
char hostname[MAX_HOSTNAME_SIZE];
uint8_t cookie[COOKIE_SIZE];
unsigned int cookie_set;