mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 00:37:00 +08:00
Added support for radius interim updates
This commit is contained in:
@@ -59,6 +59,12 @@ max-same-clients = 2
|
||||
# reconnects.
|
||||
#listen-host-is-dyndns = true
|
||||
|
||||
# Stats report time. The number of seconds after which each
|
||||
# worker process will report its usage statistics (number of
|
||||
# bytes transferred etc). This is useful when accounting like
|
||||
# radius is in use.
|
||||
#stats-report-time = 360
|
||||
|
||||
# TCP and UDP port number
|
||||
tcp-port = 443
|
||||
udp-port = 443
|
||||
|
||||
@@ -348,7 +348,7 @@ struct pam_ctx_st * pctx = ctx;
|
||||
talloc_free(pctx);
|
||||
}
|
||||
|
||||
static int pam_auth_open_session(void* ctx)
|
||||
static int pam_auth_open_session(void* ctx, const void *sid, unsigned sid_size)
|
||||
{
|
||||
struct pam_ctx_st * pctx = ctx;
|
||||
int pret;
|
||||
|
||||
@@ -149,7 +149,8 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
|
||||
syslog(LOG_ERR,
|
||||
"%s:%u: user '%s' auth error", __func__, __LINE__,
|
||||
pctx->username);
|
||||
return ERR_AUTH_FAIL;
|
||||
ret = ERR_AUTH_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
service = PW_AUTHENTICATE_ONLY;
|
||||
@@ -157,7 +158,8 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
|
||||
syslog(LOG_ERR,
|
||||
"%s:%u: user '%s' auth error", __func__, __LINE__,
|
||||
pctx->username);
|
||||
return ERR_AUTH_FAIL;
|
||||
ret = ERR_AUTH_FAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCESS_REQUEST);
|
||||
@@ -207,18 +209,24 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
|
||||
vp = vp->next;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
rc_avpair_free(send);
|
||||
if (recvd != NULL)
|
||||
rc_avpair_free(recvd);
|
||||
return 0;
|
||||
return ret;
|
||||
} else {
|
||||
fail:
|
||||
if (send != NULL)
|
||||
rc_avpair_free(send);
|
||||
|
||||
if (recvd != NULL)
|
||||
rc_avpair_free(recvd);
|
||||
|
||||
if (ret == PW_ACCESS_CHALLENGE) {
|
||||
pctx->pass_msg = pass_msg_second;
|
||||
return ERR_AUTH_CONTINUE;
|
||||
} else if ( pctx->retries++ < MAX_TRIES) {
|
||||
} else if (pctx->retries++ < MAX_TRIES) {
|
||||
pctx->pass_msg = pass_msg_failed;
|
||||
return ERR_AUTH_CONTINUE;
|
||||
} else {
|
||||
@@ -245,7 +253,74 @@ static void radius_auth_deinit(void *ctx)
|
||||
}
|
||||
|
||||
|
||||
static int radius_auth_open_session(void* ctx)
|
||||
static void radius_auth_session_stats(void* ctx, uint64_t bytes_in, uint64_t bytes_out)
|
||||
{
|
||||
struct radius_ctx_st * pctx = ctx;
|
||||
int ret;
|
||||
uint32_t status_type;
|
||||
VALUE_PAIR *send = NULL, *recvd = NULL;
|
||||
uint32_t uin, uout;
|
||||
|
||||
status_type = PW_STATUS_ALIVE;
|
||||
|
||||
syslog(LOG_DEBUG, "sending radius session interim update");
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
uin = bytes_in;
|
||||
uout = bytes_out;
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_OCTETS, &uin, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_OCTETS, &uout, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
uin = bytes_in / 4294967296;
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_GIGAWORDS, &uin, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
uout = bytes_in / 4294967296;
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_GIGAWORDS, &uout, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCOUNTING_REQUEST);
|
||||
|
||||
if (recvd != NULL)
|
||||
rc_avpair_free(recvd);
|
||||
|
||||
if (ret != OK_RC) {
|
||||
syslog(LOG_AUTH, "radius-auth: radius_open_session: %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
rc_avpair_free(send);
|
||||
return;
|
||||
}
|
||||
|
||||
static int radius_auth_open_session(void* ctx, const void *sid, unsigned sid_size)
|
||||
{
|
||||
struct radius_ctx_st * pctx = ctx;
|
||||
int ret;
|
||||
@@ -254,20 +329,45 @@ VALUE_PAIR *send = NULL, *recvd = NULL;
|
||||
|
||||
status_type = PW_STATUS_START;
|
||||
|
||||
syslog(LOG_DEBUG, "opening session with radius");
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL)
|
||||
if (sid_size != SID_SIZE) {
|
||||
syslog(LOG_DEBUG, "incorrect sid size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
base64_encode((char *)sid, sid_size, (char *)pctx->sid, sizeof(pctx->sid));
|
||||
|
||||
syslog(LOG_DEBUG, "opening session %s with radius", pctx->sid);
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCOUNTING_REQUEST);
|
||||
|
||||
if (recvd != NULL)
|
||||
rc_avpair_free(recvd);
|
||||
|
||||
if (ret != OK_RC) {
|
||||
syslog(LOG_AUTH, "radius-auth: radius_open_session: %d", ret);
|
||||
return -1;
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = 0;
|
||||
cleanup:
|
||||
rc_avpair_free(send);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void radius_auth_close_session(void* ctx)
|
||||
@@ -283,15 +383,26 @@ VALUE_PAIR *send = NULL, *recvd = NULL;
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL)
|
||||
return;
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCOUNTING_REQUEST);
|
||||
if (recvd != NULL)
|
||||
rc_avpair_free(recvd);
|
||||
|
||||
if (ret != OK_RC) {
|
||||
syslog(LOG_INFO, "radius-auth: radius_close_session: %d", ret);
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
rc_avpair_free(send);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -307,6 +418,7 @@ const struct auth_mod_st radius_auth_funcs = {
|
||||
.auth_group = radius_auth_group,
|
||||
.open_session = radius_auth_open_session,
|
||||
.close_session = radius_auth_close_session,
|
||||
.session_stats = radius_auth_session_stats,
|
||||
.group_list = NULL
|
||||
};
|
||||
|
||||
|
||||
@@ -22,10 +22,13 @@
|
||||
#define RADIUS_H
|
||||
|
||||
#include <sec-mod-auth.h>
|
||||
#include <base64.h>
|
||||
|
||||
struct radius_ctx_st {
|
||||
char username[MAX_USERNAME_SIZE*2];
|
||||
char groupname[MAX_GROUPNAME_SIZE];
|
||||
char sid[BASE64_LENGTH(SID_SIZE) + 1];
|
||||
|
||||
char msg[4096];
|
||||
|
||||
/* variables for configuration */
|
||||
|
||||
@@ -56,6 +56,8 @@ static char tmp[32];
|
||||
case CMD_CLI_STATS:
|
||||
return "cli stats";
|
||||
|
||||
case SM_CMD_CLI_STATS:
|
||||
return "sm: cli stats";
|
||||
case SM_CMD_AUTH_INIT:
|
||||
return "sm: auth init";
|
||||
case SM_CMD_AUTH_CONT:
|
||||
|
||||
@@ -327,7 +327,7 @@ int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req,
|
||||
if (module == NULL || module->open_session == NULL)
|
||||
return 0;
|
||||
|
||||
ret = module->open_session(e->auth_ctx);
|
||||
ret = module->open_session(e->auth_ctx, req->sid.data, req->sid.len);
|
||||
if (ret < 0) {
|
||||
e->status = PS_AUTH_FAILED;
|
||||
seclog(sec, LOG_ERR, "could not open session.");
|
||||
@@ -342,6 +342,37 @@ int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req)
|
||||
{
|
||||
client_entry_st *e;
|
||||
|
||||
if (req->sid.len != SID_SIZE) {
|
||||
seclog(sec, LOG_ERR, "auth session open/close but with illegal sid size (%d)!",
|
||||
(int)req->sid.len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
e = find_client_entry(sec, req->sid.data);
|
||||
if (e == NULL) {
|
||||
seclog(sec, LOG_INFO, "session open/close but with non-existing sid!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (e->status != PS_AUTH_COMPLETED) {
|
||||
seclog(sec, LOG_ERR, "session stats received in unauthenticated client!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
e->bytes_in = req->bytes_in;
|
||||
e->bytes_out = req->bytes_out;
|
||||
|
||||
if (module == NULL || module->session_stats == NULL)
|
||||
return 0;
|
||||
|
||||
module->session_stats(e->auth_ctx, e->bytes_in, e->bytes_out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_sec_auth_cont(sec_mod_st * sec, const SecAuthContMsg * req)
|
||||
{
|
||||
client_entry_st *e;
|
||||
|
||||
@@ -36,7 +36,8 @@ struct auth_mod_st {
|
||||
int (*auth_group)(void* ctx, const char *suggested, char *groupname, int groupname_size);
|
||||
int (*auth_user)(void* ctx, char *groupname, int groupname_size);
|
||||
|
||||
int (*open_session)(void *ctx); /* optional, may be null */
|
||||
int (*open_session)(void *ctx, const void *sid, unsigned sid_size); /* optional, may be null */
|
||||
void (*session_stats)(void *ctx, uint64_t bytes_in, uint64_t bytes_out); /* optional, may be null */
|
||||
void (*close_session)(void *ctx); /* optional */
|
||||
|
||||
void (*auth_deinit)(void* ctx);
|
||||
|
||||
@@ -251,7 +251,6 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd,
|
||||
|
||||
case SM_CMD_CLI_STATS:{
|
||||
CliStatsMsg *tmsg;
|
||||
client_entry_st *e;
|
||||
|
||||
tmsg = cli_stats_msg__unpack(&pa, data.size, data.data);
|
||||
if (tmsg == NULL) {
|
||||
@@ -260,28 +259,9 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tmsg->has_sid == 0 || tmsg->sid.len != SID_SIZE) {
|
||||
cli_stats_msg__free_unpacked(tmsg, &pa);
|
||||
seclog(sec, LOG_INFO, "error in SID received by client (size: %d)",
|
||||
(int)tmsg->sid.len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
e = find_client_entry(sec, tmsg->sid.data);
|
||||
if (e == NULL) {
|
||||
cli_stats_msg__free_unpacked(tmsg, &pa);
|
||||
seclog(sec, LOG_INFO, "session stats received with non-existing sid!");
|
||||
return -1;
|
||||
}
|
||||
ret = handle_sec_auth_stats_cmd(sec, tmsg);
|
||||
cli_stats_msg__free_unpacked(tmsg, &pa);
|
||||
|
||||
if (e->status != PS_AUTH_COMPLETED) {
|
||||
seclog(sec, LOG_ERR, "session stats received in unauthenticated client!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
e->bytes_in = tmsg->bytes_in;
|
||||
e->bytes_out = tmsg->bytes_out;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ void sec_auth_init(void *pool, struct cfg_st *config);
|
||||
int handle_sec_auth_init(sec_mod_st *sec, const SecAuthInitMsg * req);
|
||||
int handle_sec_auth_cont(sec_mod_st *sec, const SecAuthContMsg * req);
|
||||
int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, unsigned cmd, client_entry_st **_e);
|
||||
int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req);
|
||||
void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e);
|
||||
|
||||
void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_file,
|
||||
|
||||
Reference in New Issue
Block a user