radius: send user agent information as Connect-Info on accounting start

Relates #26
This commit is contained in:
Nikos Mavrogiannopoulos
2016-01-18 11:55:13 +01:00
parent 271ce75574
commit 40185fe0c2
5 changed files with 71 additions and 61 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Red Hat, Inc.
* Copyright (C) 2014-2016 Red Hat, Inc.
*
* This file is part of ocserv.
*
@@ -241,6 +241,13 @@ VALUE_PAIR *send = NULL, *recvd = NULL;
goto cleanup;
}
if (ai->user_agent[0] != 0) {
if (rc_avpair_add(rh, &send, PW_CONNECT_INFO, ai->user_agent, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
}
append_acct_standard(rh, ai, &send);
ret = rc_aaa(rh, ai->id, send, &recvd, NULL, 1, PW_ACCOUNTING_REQUEST);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2013, 2014 Nikos Mavrogiannopoulos
* Copyright (C) 2014 Red Hat
* Copyright (C) 2013-2016 Nikos Mavrogiannopoulos
* Copyright (C) 2014-2016 Red Hat
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -114,15 +114,15 @@ static int generate_cookie(sec_mod_st * sec, client_entry_st * entry)
int ret;
Cookie msg = COOKIE__INIT;
msg.username = entry->auth_info.username;
msg.groupname = entry->auth_info.groupname;
msg.username = entry->acct_info.username;
msg.groupname = entry->acct_info.groupname;
msg.hostname = entry->hostname;
msg.ip = entry->auth_info.remote_ip;
msg.ip = entry->acct_info.remote_ip;
msg.tls_auth_ok = entry->tls_auth_ok;
/* Fixme: possibly we should allow for completely random seeds */
if (sec->config->predictable_ips != 0) {
msg.ipv4_seed = hash_any(entry->auth_info.username, strlen(entry->auth_info.username), 0);
msg.ipv4_seed = hash_any(entry->acct_info.username, strlen(entry->acct_info.username), 0);
} else {
ret = gnutls_rnd(GNUTLS_RND_NONCE, &msg.ipv4_seed, sizeof(msg.ipv4_seed));
if (ret < 0)
@@ -164,7 +164,7 @@ int send_sec_auth_reply(int cfd, sec_mod_st * sec, client_entry_st * entry, AUTH
msg.cookie.data = entry->cookie;
msg.cookie.len = entry->cookie_size;
msg.user_name = entry->auth_info.username;
msg.user_name = entry->acct_info.username;
if (entry->msg_str != NULL) {
msg.msg = entry->msg_str;
@@ -245,33 +245,33 @@ static int check_user_group_status(sec_mod_st * sec, client_entry_st * e,
if (e->auth_type & AUTH_TYPE_CERTIFICATE) {
if (tls_auth_ok == 0) {
seclog(sec, LOG_INFO, "user %s "SESSION_STR" presented no certificate; rejecting",
e->auth_info.username, e->auth_info.psid);
e->acct_info.username, e->acct_info.psid);
return -1;
}
e->tls_auth_ok = tls_auth_ok;
if (tls_auth_ok != 0) {
if (e->auth_info.username[0] == 0 && sec->config->cert_user_oid != NULL) {
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;
}
strlcpy(e->auth_info.username, cert_user, sizeof(e->auth_info.username));
if (cert_groups_size > 0 && sec->config->cert_group_oid != NULL && e->auth_info.groupname[0] == 0)
strlcpy(e->auth_info.groupname, cert_groups[0], sizeof(e->auth_info.groupname));
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->auth_info.username, cert_user) != 0) {
if (sec->config->cert_user_oid != NULL && cert_user && strcmp(e->acct_info.username, cert_user) != 0) {
seclog(sec, LOG_INFO,
"user '%s' "SESSION_STR" presented a certificate which is for user '%s'; rejecting",
e->auth_info.username, e->auth_info.psid, cert_user);
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->auth_info.groupname, cert_groups[i]) == 0) {
if (strcmp(e->acct_info.groupname, cert_groups[i]) == 0) {
found++;
break;
}
@@ -279,7 +279,7 @@ static int check_user_group_status(sec_mod_st * sec, client_entry_st * e,
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->auth_info.username, e->auth_info.psid, e->auth_info.groupname);
e->acct_info.username, e->acct_info.psid, e->acct_info.groupname);
return -1;
}
}
@@ -317,7 +317,7 @@ int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int resu
if (result == ERR_AUTH_CONTINUE) {
/* if the module allows multiple retries for the password */
if (e->status != PS_AUTH_INIT && e->module && e->module->allows_retries) {
sec_mod_add_score_to_ip(sec, e, e->auth_info.remote_ip, sec->config->ban_points_wrong_password);
sec_mod_add_score_to_ip(sec, e, e->acct_info.remote_ip, sec->config->ban_points_wrong_password);
}
ret = send_sec_auth_reply_msg(cfd, sec, e);
@@ -334,8 +334,8 @@ int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int resu
e->status = PS_AUTH_COMPLETED;
if (e->module) {
e->module->auth_user(e->auth_ctx, e->auth_info.username,
sizeof(e->auth_info.username));
e->module->auth_user(e->auth_ctx, e->acct_info.username,
sizeof(e->acct_info.username));
}
ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__OK);
@@ -349,7 +349,7 @@ int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int resu
} else {
e->status = PS_AUTH_FAILED;
sec_mod_add_score_to_ip(sec, e, e->auth_info.remote_ip, sec->config->ban_points_wrong_password);
sec_mod_add_score_to_ip(sec, e, e->acct_info.remote_ip, sec->config->ban_points_wrong_password);
ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__FAILED);
if (ret < 0) {
@@ -427,33 +427,33 @@ int handle_sec_auth_session_open(sec_mod_st *sec, int fd, const SecAuthSessionMs
}
if (e->status != PS_AUTH_COMPLETED) {
seclog(sec, LOG_ERR, "session open received in unauthenticated client %s "SESSION_STR"!", e->auth_info.username, e->auth_info.psid);
seclog(sec, LOG_ERR, "session open received in unauthenticated client %s "SESSION_STR"!", e->acct_info.username, e->acct_info.psid);
return send_failed_session_open_reply(sec, fd);
}
if (e->time != -1 && time(0) > e->time + sec->config->cookie_timeout) {
seclog(sec, LOG_ERR, "session expired; denied session for user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
seclog(sec, LOG_ERR, "session expired; denied session for user '%s' "SESSION_STR, e->acct_info.username, e->acct_info.psid);
e->status = PS_AUTH_FAILED;
return send_failed_session_open_reply(sec, fd);
}
if (req->has_cookie == 0 || (req->cookie.len != e->cookie_size) ||
memcmp(req->cookie.data, e->cookie, e->cookie_size) != 0) {
seclog(sec, LOG_ERR, "cookie error; denied session for user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
seclog(sec, LOG_ERR, "cookie error; denied session for user '%s' "SESSION_STR, e->acct_info.username, e->acct_info.psid);
e->status = PS_AUTH_FAILED;
return send_failed_session_open_reply(sec, fd);
}
if (req->ipv4)
strlcpy(e->auth_info.ipv4, req->ipv4, sizeof(e->auth_info.ipv4));
strlcpy(e->acct_info.ipv4, req->ipv4, sizeof(e->acct_info.ipv4));
if (req->ipv6)
strlcpy(e->auth_info.ipv6, req->ipv6, sizeof(e->auth_info.ipv6));
strlcpy(e->acct_info.ipv6, req->ipv6, sizeof(e->acct_info.ipv6));
if (sec->perm_config->acct.amod != NULL && sec->perm_config->acct.amod->open_session != NULL && e->session_is_open == 0) {
ret = sec->perm_config->acct.amod->open_session(e->auth_type, &e->auth_info, req->sid.data, req->sid.len);
ret = sec->perm_config->acct.amod->open_session(e->auth_type, &e->acct_info, req->sid.data, req->sid.len);
if (ret < 0) {
e->status = PS_AUTH_FAILED;
seclog(sec, LOG_INFO, "denied session for user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
seclog(sec, LOG_INFO, "denied session for user '%s' "SESSION_STR, e->acct_info.username, e->acct_info.psid);
return send_failed_session_open_reply(sec, fd);
} else {
e->session_is_open = 1;
@@ -470,7 +470,7 @@ int handle_sec_auth_session_open(sec_mod_st *sec, int fd, const SecAuthSessionMs
if (sec->config_module && sec->config_module->get_sup_config) {
ret = sec->config_module->get_sup_config(sec->config, e, &rep, lpool);
if (ret < 0) {
seclog(sec, LOG_ERR, "error reading additional configuration for '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
seclog(sec, LOG_ERR, "error reading additional configuration for '%s' "SESSION_STR, e->acct_info.username, e->acct_info.psid);
talloc_free(lpool);
return send_failed_session_open_reply(sec, fd);
}
@@ -485,7 +485,7 @@ int handle_sec_auth_session_open(sec_mod_st *sec, int fd, const SecAuthSessionMs
}
talloc_free(lpool);
seclog(sec, LOG_INFO, "initiating session for user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
seclog(sec, LOG_INFO, "initiating session for user '%s' "SESSION_STR, e->acct_info.username, e->acct_info.psid);
e->time = -1;
e->in_use++;
@@ -516,7 +516,7 @@ int handle_sec_auth_session_close(sec_mod_st *sec, int fd, const SecAuthSessionM
}
if (e->status < PS_AUTH_COMPLETED) {
seclog(sec, LOG_DEBUG, "session close received in unauthenticated client %s "SESSION_STR"!", e->auth_info.username, e->auth_info.psid);
seclog(sec, LOG_DEBUG, "session close received in unauthenticated client %s "SESSION_STR"!", e->acct_info.username, e->acct_info.psid);
return send_msg(e, fd, SM_CMD_AUTH_CLI_STATS, &rep,
(pack_size_func) cli_stats_msg__get_packed_size,
(pack_func) cli_stats_msg__pack);
@@ -612,7 +612,7 @@ int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req)
}
if (e->status != PS_AUTH_COMPLETED) {
seclog(sec, LOG_ERR, "session stats received in unauthenticated client %s "SESSION_STR"!", e->auth_info.username, e->auth_info.psid);
seclog(sec, LOG_ERR, "session stats received in unauthenticated client %s "SESSION_STR"!", e->acct_info.username, e->acct_info.psid);
return -1;
}
@@ -633,13 +633,13 @@ int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req)
stats_add_to(&totals, &e->stats, &e->saved_stats);
if (req->remote_ip)
strlcpy(e->auth_info.remote_ip, req->remote_ip, sizeof(e->auth_info.remote_ip));
strlcpy(e->acct_info.remote_ip, req->remote_ip, sizeof(e->acct_info.remote_ip));
if (req->ipv4)
strlcpy(e->auth_info.ipv4, req->ipv4, sizeof(e->auth_info.ipv4));
strlcpy(e->acct_info.ipv4, req->ipv4, sizeof(e->acct_info.ipv4));
if (req->ipv6)
strlcpy(e->auth_info.ipv6, req->ipv6, sizeof(e->auth_info.ipv6));
strlcpy(e->acct_info.ipv6, req->ipv6, sizeof(e->acct_info.ipv6));
sec->perm_config->acct.amod->session_stats(e->auth_type, &e->auth_info, &totals);
sec->perm_config->acct.amod->session_stats(e->auth_type, &e->acct_info, &totals);
return 0;
}
@@ -663,16 +663,16 @@ int handle_sec_auth_cont(int cfd, sec_mod_st * sec, const SecAuthContMsg * req)
if (e->status != PS_AUTH_INIT && e->status != PS_AUTH_CONT) {
seclog(sec, LOG_ERR, "auth cont received for %s "SESSION_STR" but we are on state %u!",
e->auth_info.username, e->auth_info.psid, e->status);
e->acct_info.username, e->acct_info.psid, e->status);
ret = -1;
goto cleanup;
}
seclog(sec, LOG_DEBUG, "auth cont for user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
seclog(sec, LOG_DEBUG, "auth cont for user '%s' "SESSION_STR, e->acct_info.username, e->acct_info.psid);
if (req->password == NULL) {
seclog(sec, LOG_ERR, "no password given in auth cont for user '%s' "SESSION_STR,
e->auth_info.username, e->auth_info.psid);
e->acct_info.username, e->acct_info.psid);
ret = -1;
goto cleanup;
}
@@ -692,7 +692,7 @@ int handle_sec_auth_cont(int cfd, sec_mod_st * sec, const SecAuthContMsg * req)
if (ret != ERR_AUTH_CONTINUE) {
seclog(sec, LOG_DEBUG,
"error in password given in auth cont for user '%s' "SESSION_STR,
e->auth_info.username, e->auth_info.psid);
e->acct_info.username, e->acct_info.psid);
}
goto cleanup;
}
@@ -716,7 +716,7 @@ int set_module(sec_mod_st * sec, client_entry_st *e, unsigned auth_type)
e->module = sec->perm_config->auth[i].amod;
e->auth_type = sec->perm_config->auth[i].type;
seclog(sec, LOG_INFO, "using '%s' authentication to authenticate user "SESSION_STR, sec->perm_config->auth[i].name, e->auth_info.psid);
seclog(sec, LOG_INFO, "using '%s' authentication to authenticate user "SESSION_STR, sec->perm_config->auth[i].name, e->acct_info.psid);
return 0;
}
}
@@ -764,31 +764,33 @@ int handle_sec_auth_init(int cfd, sec_mod_st *sec, const SecAuthInitMsg *req, pi
}
ret =
e->module->auth_group(e->auth_ctx, req->group_name, e->auth_info.groupname,
sizeof(e->auth_info.groupname));
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->auth_info.groupname[sizeof(e->auth_info.groupname) - 1] = 0;
e->acct_info.groupname[sizeof(e->acct_info.groupname) - 1] = 0;
}
if (req->user_agent != NULL)
strlcpy(e->acct_info.user_agent, req->user_agent, sizeof(e->acct_info.user_agent));
if (req->user_name != NULL) {
strlcpy(e->auth_info.username, req->user_name, sizeof(e->auth_info.username));
strlcpy(e->acct_info.username, req->user_name, sizeof(e->acct_info.username));
}
if (req->our_ip != NULL) {
strlcpy(e->auth_info.our_ip, req->our_ip, sizeof(e->auth_info.our_ip));
strlcpy(e->acct_info.our_ip, req->our_ip, sizeof(e->acct_info.our_ip));
}
if (e->auth_type & AUTH_TYPE_CERTIFICATE) {
if (e->auth_info.groupname[0] == 0 && req->group_name != NULL && sec->config->cert_group_oid != NULL) {
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->auth_info.groupname, req->cert_group_names[i], sizeof(e->auth_info.groupname));
strlcpy(e->acct_info.groupname, req->cert_group_names[i], sizeof(e->acct_info.groupname));
found = 1;
break;
}
@@ -814,7 +816,7 @@ int handle_sec_auth_init(int cfd, sec_mod_st *sec, const SecAuthInitMsg *req, pi
e->status = PS_AUTH_INIT;
seclog(sec, LOG_DEBUG, "auth init %sfor user '%s' "SESSION_STR" of group: '%s' from '%s'",
req->tls_auth_ok?"(with cert) ":"",
e->auth_info.username, e->auth_info.psid, e->auth_info.groupname, req->ip);
e->acct_info.username, e->acct_info.psid, e->acct_info.groupname, req->ip);
if (need_continue != 0) {
ret = ERR_AUTH_CONTINUE;
@@ -828,9 +830,9 @@ int handle_sec_auth_init(int cfd, sec_mod_st *sec, const SecAuthInitMsg *req, pi
void sec_auth_user_deinit(sec_mod_st *sec, client_entry_st *e)
{
seclog(sec, LOG_DEBUG, "permamently closing session of user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
seclog(sec, LOG_DEBUG, "permamently closing session of user '%s' "SESSION_STR, e->acct_info.username, e->acct_info.psid);
if (sec->perm_config->acct.amod != NULL && sec->perm_config->acct.amod->close_session != NULL && e->session_is_open != 0) {
sec->perm_config->acct.amod->close_session(e->auth_type, &e->auth_info, &e->saved_stats, e->discon_reason);
sec->perm_config->acct.amod->close_session(e->auth_type, &e->acct_info, &e->saved_stats, e->discon_reason);
}
if (e->auth_ctx != NULL) {

View File

@@ -96,8 +96,8 @@ client_entry_st *new_client_entry(sec_mod_st *sec, const char *ip, unsigned pid)
return NULL;
}
strlcpy(e->auth_info.remote_ip, ip, sizeof(e->auth_info.remote_ip));
e->auth_info.id = pid;
strlcpy(e->acct_info.remote_ip, ip, sizeof(e->acct_info.remote_ip));
e->acct_info.id = pid;
do {
ret = gnutls_rnd(GNUTLS_RND_RANDOM, e->sid, sizeof(e->sid));
@@ -116,7 +116,7 @@ client_entry_st *new_client_entry(sec_mod_st *sec, const char *ip, unsigned pid)
goto fail;
}
oc_base64_encode((char *)e->sid, SID_SIZE, (char *)e->auth_info.psid, sizeof(e->auth_info.psid));
oc_base64_encode((char *)e->sid, SID_SIZE, (char *)e->acct_info.psid, sizeof(e->acct_info.psid));
e->time = time(0);
if (htable_add(db, rehash(e, NULL), e) == 0) {
@@ -196,11 +196,11 @@ void expire_client_entry(sec_mod_st *sec, client_entry_st * e)
if (sec->config->persistent_cookies == 0 && (e->discon_reason == REASON_USER_DISCONNECT
|| e->discon_reason == REASON_SERVER_DISCONNECT || e->discon_reason == REASON_SESSION_TIMEOUT)) {
seclog(sec, LOG_INFO, "invalidating session of user '%s' "SESSION_STR,
e->auth_info.username, e->auth_info.psid);
e->acct_info.username, e->acct_info.psid);
/* immediately disconnect the user */
del_client_entry(sec, e);
} else {
seclog(sec, LOG_INFO, "temporarily closing session for %s "SESSION_STR, e->auth_info.username, e->auth_info.psid);
seclog(sec, LOG_INFO, "temporarily closing session for %s "SESSION_STR, e->acct_info.username, e->acct_info.psid);
}
}
}

View File

@@ -65,6 +65,7 @@ typedef struct common_acct_info_st {
char groupname[MAX_GROUPNAME_SIZE]; /* the owner's group */
char psid[BASE64_ENCODE_RAW_LENGTH(SID_SIZE) + 1]; /* printable */
char remote_ip[MAX_IP_STR];
char user_agent[MAX_AGENT_NAME];
char our_ip[MAX_IP_STR];
char ipv4[MAX_IP_STR];
char ipv6[MAX_IP_STR];
@@ -105,7 +106,7 @@ typedef struct client_entry_st {
unsigned auth_type;
unsigned discon_reason; /* reason for disconnection */
struct common_acct_info_st auth_info;
struct common_acct_info_st acct_info;
/* the module this entry is using */
const struct auth_mod_st *module;

View File

@@ -325,9 +325,9 @@ static int get_sup_config(struct cfg_st *cfg, client_entry_st *entry,
char file[_POSIX_PATH_MAX];
int ret;
if (cfg->per_group_dir != NULL && entry->auth_info.groupname[0] != 0) {
if (cfg->per_group_dir != NULL && entry->acct_info.groupname[0] != 0) {
snprintf(file, sizeof(file), "%s/%s", cfg->per_group_dir,
entry->auth_info.groupname);
entry->acct_info.groupname);
ret = read_sup_config_file(cfg, msg, pool, file, cfg->default_group_conf, "group");
if (ret < 0)
@@ -336,7 +336,7 @@ static int get_sup_config(struct cfg_st *cfg, client_entry_st *entry,
if (cfg->per_user_dir != NULL) {
snprintf(file, sizeof(file), "%s/%s", cfg->per_user_dir,
entry->auth_info.username);
entry->acct_info.username);
ret = read_sup_config_file(cfg, msg, pool, file, cfg->default_user_conf, "user");
if (ret < 0)
return ret;