sec-mod: perform group checks at auth completion stage

This allows to retrieve allowed groups from radius response.
This commit is contained in:
Nikos Mavrogiannopoulos
2016-03-29 20:51:51 +02:00
committed by Nikos Mavrogiannopoulos
parent b5cabb9589
commit e798493d08
3 changed files with 110 additions and 71 deletions

View File

@@ -36,6 +36,7 @@
#include <tlslib.h>
#include <script-list.h>
#include <ip-lease.h>
#include <minmax.h>
#include "str.h"
#include <vpn.h>
@@ -189,53 +190,47 @@ int send_sec_auth_reply_msg(int cfd, sec_mod_st * sec, client_entry_st * e)
return ret;
}
static int check_user_group_status(sec_mod_st * sec, client_entry_st * e,
int tls_auth_ok, const char *cert_user,
char **cert_groups,
unsigned cert_groups_size)
static int check_cert_user_group_status(sec_mod_st * sec, client_entry_st * e)
{
unsigned found, i;
if (e->auth_type & AUTH_TYPE_CERTIFICATE) {
if (tls_auth_ok == 0) {
if (e->tls_auth_ok == 0) {
seclog(sec, LOG_INFO, "user %s "SESSION_STR" presented no certificate; rejecting",
e->acct_info.username, e->acct_info.psid);
return -1;
}
e->tls_auth_ok = tls_auth_ok;
if (tls_auth_ok != 0) {
if (e->acct_info.username[0] == 0 && sec->config->cert_user_oid != NULL) {
if (cert_user == NULL) {
seclog(sec, LOG_INFO, "no username in the certificate; rejecting");
return -1;
}
if (e->acct_info.username[0] == 0 && sec->config->cert_user_oid != NULL) {
if (e->cert_user_name[0] == 0) {
seclog(sec, LOG_INFO, "no username in the certificate; rejecting");
return -1;
}
strlcpy(e->acct_info.username, cert_user, sizeof(e->acct_info.username));
if (cert_groups_size > 0 && sec->config->cert_group_oid != NULL && e->acct_info.groupname[0] == 0)
strlcpy(e->acct_info.groupname, cert_groups[0], sizeof(e->acct_info.groupname));
} else {
if (sec->config->cert_user_oid != NULL && cert_user && strcmp(e->acct_info.username, cert_user) != 0) {
strlcpy(e->acct_info.username, e->cert_user_name, sizeof(e->acct_info.username));
if (e->cert_group_names_size > 0 && sec->config->cert_group_oid != NULL && e->acct_info.groupname[0] == 0)
strlcpy(e->acct_info.groupname, e->cert_group_names[0], sizeof(e->acct_info.groupname));
} else {
if (sec->config->cert_user_oid != NULL && e->cert_user_name[0] && strcmp(e->acct_info.username, e->cert_user_name) != 0) {
seclog(sec, LOG_INFO,
"user '%s' "SESSION_STR" presented a certificate which is for user '%s'; rejecting",
e->acct_info.username, e->acct_info.psid, e->cert_user_name);
return -1;
}
if (sec->config->cert_group_oid != NULL) {
found = 0;
for (i=0;i<e->cert_group_names_size;i++) {
if (strcmp(e->acct_info.groupname, e->cert_group_names[i]) == 0) {
found++;
break;
}
}
if (found == 0) {
seclog(sec, LOG_INFO,
"user '%s' "SESSION_STR" presented a certificate which is for user '%s'; rejecting",
e->acct_info.username, e->acct_info.psid, cert_user);
return -1;
}
if (sec->config->cert_group_oid != NULL) {
found = 0;
for (i=0;i<cert_groups_size;i++) {
if (strcmp(e->acct_info.groupname, cert_groups[i]) == 0) {
found++;
break;
}
}
if (found == 0) {
seclog(sec, LOG_INFO,
"user '%s' "SESSION_STR" presented a certificate from group '%s' but he isn't a member of it; rejecting",
e->acct_info.username, e->acct_info.psid, e->acct_info.groupname);
return -1;
}
"user '%s' "SESSION_STR" presented a certificate from group '%s' but he isn't a member of it; rejecting",
e->acct_info.username, e->acct_info.psid, e->acct_info.groupname);
return -1;
}
}
}
@@ -244,6 +239,55 @@ static int check_user_group_status(sec_mod_st * sec, client_entry_st * e,
return 0;
}
static
int check_group(sec_mod_st * sec, client_entry_st * e)
{
int ret;
const char *req_group = NULL;
if (e->req_group_name[0] != 0)
req_group = e->req_group_name;
if (e->module && e->module->auth_group) {
ret =
e->module->auth_group(e->auth_ctx, req_group, e->acct_info.groupname,
sizeof(e->acct_info.groupname));
if (ret != 0) {
return -1;
}
e->acct_info.groupname[sizeof(e->acct_info.groupname) - 1] = 0;
}
/* set group name using the certificate info */
if (e->auth_type & AUTH_TYPE_CERTIFICATE) {
if (e->acct_info.groupname[0] == 0 && req_group != NULL && sec->config->cert_group_oid != NULL) {
unsigned i, found = 0;
for (i=0;i<e->cert_group_names_size;i++) {
if (strcmp(req_group, e->cert_group_names[i]) == 0) {
strlcpy(e->acct_info.groupname, e->cert_group_names[i], sizeof(e->acct_info.groupname));
found = 1;
break;
}
}
if (found == 0) {
seclog(sec, LOG_AUTH, "user '%s' requested group '%s' but is not included on his certificate groups",
e->acct_info.username, req_group);
return -1;
}
}
}
ret =
check_cert_user_group_status(sec, e);
if (ret < 0) {
return -1;
}
return 0;
}
/* Performs the required steps based on the result from the
* authentication function (e.g. handle_auth_init).
*
@@ -282,6 +326,13 @@ int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int resu
}
return 0; /* wait for another command */
} else if (result == 0 && e->status != PS_AUTH_FAILED) {
ret = check_group(sec, e);
if (ret < 0) {
e->status = PS_AUTH_FAILED;
seclog(sec, LOG_ERR, "could not accept group.");
return ret;
}
/* we check status for PS_AUTH_FAILED, because status may
* change async if we receive a message from main that the
* user is banned */
@@ -681,6 +732,7 @@ int handle_sec_auth_init(int cfd, sec_mod_st *sec, const SecAuthInitMsg *req, pi
{
int ret = -1;
client_entry_st *e;
unsigned i;
unsigned need_continue = 0;
e = new_client_entry(sec, req->ip, pid);
@@ -711,17 +763,10 @@ int handle_sec_auth_init(int cfd, sec_mod_st *sec, const SecAuthInitMsg *req, pi
} else if (ret < 0) {
goto cleanup;
}
ret =
e->module->auth_group(e->auth_ctx, req->group_name, e->acct_info.groupname,
sizeof(e->acct_info.groupname));
if (ret != 0) {
ret = -1;
goto cleanup;
}
e->acct_info.groupname[sizeof(e->acct_info.groupname) - 1] = 0;
}
e->tls_auth_ok = req->tls_auth_ok;
if (req->user_agent != NULL)
strlcpy(e->acct_info.user_agent, req->user_agent, sizeof(e->acct_info.user_agent));
@@ -733,33 +778,21 @@ int handle_sec_auth_init(int cfd, sec_mod_st *sec, const SecAuthInitMsg *req, pi
strlcpy(e->acct_info.our_ip, req->our_ip, sizeof(e->acct_info.our_ip));
}
if (e->auth_type & AUTH_TYPE_CERTIFICATE) {
if (e->acct_info.groupname[0] == 0 && req->group_name != NULL && sec->config->cert_group_oid != NULL) {
unsigned i, found = 0;
for (i=0;i<req->n_cert_group_names;i++) {
if (strcmp(req->group_name, req->cert_group_names[i]) == 0) {
strlcpy(e->acct_info.groupname, req->cert_group_names[i], sizeof(e->acct_info.groupname));
found = 1;
break;
}
}
if (found == 0) {
seclog(sec, LOG_AUTH, "user '%s' requested group '%s' but is not included on his certificate groups",
req->user_name, req->group_name);
ret = -1;
goto cleanup;
}
}
if (req->group_name != NULL) {
strlcpy(e->req_group_name, req->group_name, sizeof(e->req_group_name));
}
ret =
check_user_group_status(sec, e, req->tls_auth_ok,
req->cert_user_name, req->cert_group_names,
req->n_cert_group_names);
if (ret < 0) {
goto cleanup;
if (req->cert_user_name != NULL) {
strlcpy(e->cert_user_name, req->cert_user_name, sizeof(e->cert_user_name));
}
e->cert_group_names_size = MIN(MAX_GROUPS,req->n_cert_group_names);
for (i=0;i<e->cert_group_names_size;i++) {
e->cert_group_names[i] = talloc_strdup(e, req->cert_group_names[i]);
if (e->cert_group_names[i] == NULL) {
e->cert_group_names_size = 0;
break;
}
}
e->status = PS_AUTH_INIT;

View File

@@ -25,7 +25,6 @@
#include <sec-mod.h>
#define MAX_AUTH_REQS 8
#define MAX_GROUPS 32
typedef struct passwd_msg_st {
char *msg_str;

View File

@@ -27,6 +27,7 @@
#include <tlslib.h>
#define SESSION_STR "(session: %.6s)"
#define MAX_GROUPS 32
typedef struct sec_mod_st {
struct cfg_st *config;
@@ -103,6 +104,12 @@ typedef struct client_entry_st {
struct common_acct_info_st acct_info;
/* saved during authentication; used after successful auth */
char req_group_name[MAX_GROUPNAME_SIZE]; /* the requested by the user group */
char *cert_group_names[MAX_GROUPS];
unsigned cert_group_names_size;
char cert_user_name[MAX_USERNAME_SIZE];
/* the module this entry is using */
const struct auth_mod_st *module;
} client_entry_st;