Files
openairinterface5g/openair3/PMIPv6/freeradius-client-1.1.6/lib/buildreq.c
T
2013-06-25 09:05:02 +00:00

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;
}