Pre-ci test passed git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4000 818b1a75-f10b-46b9-bf7c-635c3b92a50f
337 lines
8.0 KiB
C
337 lines
8.0 KiB
C
/*
|
|
* $Id: buildreq.c,v 1.15 2008/03/05 16:35:20 cparker Exp $
|
|
*
|
|
* Copyright (C) 1995,1997 Lars Fenneberg
|
|
*
|
|
* See the file COPYRIGHT for the respective terms and conditions.
|
|
* If the file is missing contact me at lf@elemental.net
|
|
* and I'll send you a copy.
|
|
*
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <includes.h>
|
|
#include <freeradius-client.h>
|
|
|
|
unsigned char rc_get_seqnbr(rc_handle *);
|
|
|
|
/*
|
|
* Function: rc_buildreq
|
|
*
|
|
* Purpose: builds a skeleton RADIUS request using information from the
|
|
* config file.
|
|
*
|
|
*/
|
|
|
|
void rc_buildreq(rc_handle *rh, SEND_DATA *data, int code, char *server, unsigned short port,
|
|
char *secret, int timeout, int retries)
|
|
{
|
|
data->server = server;
|
|
data->secret = secret;
|
|
data->svc_port = port;
|
|
data->seq_nbr = rc_get_seqnbr(rh);
|
|
data->timeout = timeout;
|
|
data->retries = retries;
|
|
data->code = code;
|
|
}
|
|
|
|
/*
|
|
* Function: rc_guess_seqnbr
|
|
*
|
|
* Purpose: return a random sequence number
|
|
*
|
|
*/
|
|
|
|
static unsigned char rc_guess_seqnbr(void)
|
|
{
|
|
srandom((unsigned int)(time(NULL)+getpid()));
|
|
return (unsigned char)(random() & UCHAR_MAX);
|
|
}
|
|
|
|
/*
|
|
* Function: rc_get_seqnbr
|
|
*
|
|
* Purpose: generate a sequence number
|
|
*
|
|
*/
|
|
|
|
unsigned char rc_get_seqnbr(rc_handle *rh)
|
|
{
|
|
FILE *sf;
|
|
int tries = 1;
|
|
int seq_nbr;
|
|
char *seqfile = rc_conf_str(rh, "seqfile");
|
|
|
|
if ((sf = fopen(seqfile, "a+")) == NULL)
|
|
{
|
|
rc_log(LOG_ERR,"rc_get_seqnbr: couldn't open sequence file %s: %s", seqfile, strerror(errno));
|
|
/* well, so guess a sequence number */
|
|
return rc_guess_seqnbr();
|
|
}
|
|
|
|
while (do_lock_exclusive(sf)!= 0)
|
|
{
|
|
if (errno != EWOULDBLOCK) {
|
|
rc_log(LOG_ERR, "rc_get_seqnbr: flock failure: %s: %s", seqfile, strerror(errno));
|
|
fclose(sf);
|
|
return rc_guess_seqnbr();
|
|
}
|
|
tries++;
|
|
if (tries <= 10)
|
|
rc_mdelay(500);
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tries > 10) {
|
|
rc_log(LOG_ERR,"rc_get_seqnbr: couldn't get lock after %d tries: %s", tries-1, seqfile);
|
|
fclose(sf);
|
|
return rc_guess_seqnbr();
|
|
}
|
|
|
|
rewind(sf);
|
|
if (fscanf(sf, "%d", &seq_nbr) != 1) {
|
|
rc_log(LOG_ERR,"rc_get_seqnbr: fscanf failure: %s", seqfile);
|
|
seq_nbr = rc_guess_seqnbr();
|
|
}
|
|
|
|
rewind(sf);
|
|
ftruncate(fileno(sf),0);
|
|
fprintf(sf,"%d\n", (seq_nbr+1) & UCHAR_MAX);
|
|
|
|
fflush(sf); /* fflush because a process may read it between the do_unlock and fclose */
|
|
|
|
if (do_unlock(sf) != 0)
|
|
rc_log(LOG_ERR, "rc_get_seqnbr: couldn't release lock on %s: %s", seqfile, strerror(errno));
|
|
|
|
fclose(sf);
|
|
|
|
return (unsigned char)seq_nbr;
|
|
}
|
|
|
|
/*
|
|
* Function: rc_aaa
|
|
*
|
|
* Purpose: Builds an authentication/accounting request for port id client_port
|
|
* with the value_pairs send and submits it to a server
|
|
*
|
|
* Returns: received value_pairs in received, messages from the server in msg
|
|
* and 0 on success, negative on failure as return value
|
|
*
|
|
*/
|
|
|
|
int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received,
|
|
char *msg, int add_nas_port, int request_type)
|
|
{
|
|
SEND_DATA data;
|
|
VALUE_PAIR *adt_vp;
|
|
int result;
|
|
int i, skip_count;
|
|
SERVER *aaaserver;
|
|
int timeout = rc_conf_int(rh, "radius_timeout");
|
|
int retries = rc_conf_int(rh, "radius_retries");
|
|
int radius_deadtime = rc_conf_int(rh, "radius_deadtime");
|
|
double start_time;
|
|
time_t dtime;
|
|
|
|
if (request_type != PW_ACCOUNTING_REQUEST) {
|
|
aaaserver = rc_conf_srv(rh, "authserver");
|
|
} else {
|
|
aaaserver = rc_conf_srv(rh, "acctserver");
|
|
}
|
|
if (aaaserver == NULL)
|
|
return ERROR_RC;
|
|
|
|
data.send_pairs = send;
|
|
data.receive_pairs = NULL;
|
|
|
|
if (add_nas_port != 0) {
|
|
/*
|
|
* Fill in NAS-Port
|
|
*/
|
|
if (rc_avpair_add(rh, &(data.send_pairs), PW_NAS_PORT,
|
|
&client_port, 0, 0) == NULL) {
|
|
rc_log(LOG_ERR,"rc_aaa: PW_NAS_PORT ");
|
|
return ERROR_RC;
|
|
}
|
|
}
|
|
|
|
if (request_type == PW_ACCOUNTING_REQUEST) {
|
|
/*
|
|
* Fill in Acct-Delay-Time
|
|
*/
|
|
dtime = 0;
|
|
if ((adt_vp = rc_avpair_add(rh, &(data.send_pairs),
|
|
PW_ACCT_DELAY_TIME, &dtime, 0, 0)) == NULL) {
|
|
rc_log(LOG_ERR,"rc_aaa: PW_ACCOUNTING_REQUEST");
|
|
return ERROR_RC;
|
|
}
|
|
}
|
|
|
|
start_time = rc_getctime();
|
|
skip_count = 0;
|
|
result = ERROR_RC;
|
|
for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != BADRESP_RC)
|
|
; i++)
|
|
{
|
|
if (aaaserver->deadtime_ends[i] != -1 &&
|
|
aaaserver->deadtime_ends[i] > start_time) {
|
|
skip_count++;
|
|
continue;
|
|
}
|
|
if (data.receive_pairs != NULL) {
|
|
rc_avpair_free(data.receive_pairs);
|
|
data.receive_pairs = NULL;
|
|
}
|
|
rc_buildreq(rh, &data, request_type, aaaserver->name[i],
|
|
aaaserver->port[i], aaaserver->secret[i], timeout, retries);
|
|
|
|
if (request_type == PW_ACCOUNTING_REQUEST) {
|
|
dtime = rc_getctime() - start_time;
|
|
rc_avpair_assign(adt_vp, &dtime, 0);
|
|
}
|
|
|
|
result = rc_send_server (rh, &data, msg);
|
|
if (result == TIMEOUT_RC && radius_deadtime > 0)
|
|
aaaserver->deadtime_ends[i] = start_time + (double)radius_deadtime;
|
|
}
|
|
if (result == OK_RC || result == BADRESP_RC || skip_count == 0)
|
|
goto exit;
|
|
|
|
result = ERROR_RC;
|
|
for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != BADRESP_RC)
|
|
; i++)
|
|
{
|
|
if (aaaserver->deadtime_ends[i] == -1 ||
|
|
aaaserver->deadtime_ends[i] <= start_time) {
|
|
continue;
|
|
}
|
|
if (data.receive_pairs != NULL) {
|
|
rc_avpair_free(data.receive_pairs);
|
|
data.receive_pairs = NULL;
|
|
}
|
|
rc_buildreq(rh, &data, request_type, aaaserver->name[i],
|
|
aaaserver->port[i], aaaserver->secret[i], timeout, retries);
|
|
|
|
if (request_type == PW_ACCOUNTING_REQUEST) {
|
|
dtime = rc_getctime() - start_time;
|
|
rc_avpair_assign(adt_vp, &dtime, 0);
|
|
}
|
|
|
|
result = rc_send_server (rh, &data, msg);
|
|
if (result != TIMEOUT_RC)
|
|
aaaserver->deadtime_ends[i] = -1;
|
|
}
|
|
|
|
exit:
|
|
if (request_type != PW_ACCOUNTING_REQUEST) {
|
|
*received = data.receive_pairs;
|
|
} else {
|
|
rc_avpair_free(data.receive_pairs);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Function: rc_auth
|
|
*
|
|
* Purpose: Builds an authentication request for port id client_port
|
|
* with the value_pairs send and submits it to a server
|
|
*
|
|
* Returns: received value_pairs in received, messages from the server in msg
|
|
* and 0 on success, negative on failure as return value
|
|
*
|
|
*/
|
|
|
|
int rc_auth(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received,
|
|
char *msg)
|
|
{
|
|
|
|
return rc_aaa(rh, client_port, send, received, msg, 1, PW_ACCESS_REQUEST);
|
|
}
|
|
|
|
/*
|
|
* Function: rc_auth_proxy
|
|
*
|
|
* Purpose: Builds an authentication request
|
|
* with the value_pairs send and submits it to a server.
|
|
* Works for a proxy; does not add IP address, and does
|
|
* does not rely on config file.
|
|
*
|
|
* Returns: received value_pairs in received, messages from the server in msg
|
|
* and 0 on success, negative on failure as return value
|
|
*
|
|
*/
|
|
|
|
int rc_auth_proxy(rc_handle *rh, VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
|
|
{
|
|
|
|
return rc_aaa(rh, 0, send, received, msg, 0, PW_ACCESS_REQUEST);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: rc_acct
|
|
*
|
|
* Purpose: Builds an accounting request for port id client_port
|
|
* with the value_pairs send
|
|
*
|
|
* Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled
|
|
* in by this function, the rest has to be supplied.
|
|
*/
|
|
|
|
int rc_acct(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send)
|
|
{
|
|
char msg[4096];
|
|
|
|
return rc_aaa(rh, client_port, send, NULL, msg, 1, PW_ACCOUNTING_REQUEST);
|
|
}
|
|
|
|
/*
|
|
* Function: rc_acct_proxy
|
|
*
|
|
* Purpose: Builds an accounting request with the value_pairs send
|
|
*
|
|
*/
|
|
|
|
int rc_acct_proxy(rc_handle *rh, VALUE_PAIR *send)
|
|
{
|
|
char msg[4096];
|
|
|
|
return rc_aaa(rh, 0, send, NULL, msg, 0, PW_ACCOUNTING_REQUEST);
|
|
}
|
|
|
|
/*
|
|
* Function: rc_check
|
|
*
|
|
* Purpose: ask the server hostname on the specified port for a
|
|
* status message
|
|
*
|
|
*/
|
|
|
|
int rc_check(rc_handle *rh, char *host, char *secret, unsigned short port, char *msg)
|
|
{
|
|
SEND_DATA data;
|
|
int result;
|
|
uint32_t service_type;
|
|
int timeout = rc_conf_int(rh, "radius_timeout");
|
|
int retries = rc_conf_int(rh, "radius_retries");
|
|
|
|
data.send_pairs = data.receive_pairs = NULL;
|
|
|
|
/*
|
|
* Fill in Service-Type
|
|
*/
|
|
|
|
service_type = PW_ADMINISTRATIVE;
|
|
rc_avpair_add(rh, &(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, 0);
|
|
|
|
rc_buildreq(rh, &data, PW_STATUS_SERVER, host, port, secret, timeout, retries);
|
|
result = rc_send_server (rh, &data, msg);
|
|
|
|
rc_avpair_free(data.receive_pairs);
|
|
|
|
return result;
|
|
}
|