Home | History | Annotate | Download | only in radius
      1 /*
      2  * $Id: buildreq.c,v 1.1 2004/11/14 07:26:26 paulus Exp $
      3  *
      4  * Copyright (C) 1995,1997 Lars Fenneberg
      5  *
      6  * See the file COPYRIGHT for the respective terms and conditions.
      7  * If the file is missing contact me at lf (at) elemental.net
      8  * and I'll send you a copy.
      9  *
     10  */
     11 
     12 #include <includes.h>
     13 #include <radiusclient.h>
     14 
     15 unsigned char rc_get_seqnbr(void);
     16 
     17 /*
     18  * Function: rc_get_nas_id
     19  *
     20  * Purpose: fills in NAS-Identifier or NAS-IP-Address in request
     21  *
     22  */
     23 
     24 int rc_get_nas_id(VALUE_PAIR **sendpairs)
     25 {
     26 	UINT4		client_id;
     27 	char *nasid;
     28 
     29 	nasid = rc_conf_str("nas_identifier");
     30 	if (strlen(nasid)) {
     31 		/*
     32 		 * Fill in NAS-Identifier
     33 		 */
     34 		if (rc_avpair_add(sendpairs, PW_NAS_IDENTIFIER, nasid, 0,
     35 				  VENDOR_NONE) == NULL)
     36 			return (ERROR_RC);
     37 
     38 		return (OK_RC);
     39 
     40 	} else {
     41 		/*
     42 		 * Fill in NAS-IP-Address
     43 		 */
     44 		if ((client_id = rc_own_ipaddress()) == 0)
     45 			return (ERROR_RC);
     46 
     47 		if (rc_avpair_add(sendpairs, PW_NAS_IP_ADDRESS, &client_id,
     48 				  0, VENDOR_NONE) == NULL)
     49 			return (ERROR_RC);
     50 	}
     51 
     52 	return (OK_RC);
     53 }
     54 
     55 /*
     56  * Function: rc_buildreq
     57  *
     58  * Purpose: builds a skeleton RADIUS request using information from the
     59  *	    config file.
     60  *
     61  */
     62 
     63 void rc_buildreq(SEND_DATA *data, int code, char *server, unsigned short port,
     64 		 int timeout, int retries)
     65 {
     66 	data->server = server;
     67 	data->svc_port = port;
     68 	data->seq_nbr = rc_get_seqnbr();
     69 	data->timeout = timeout;
     70 	data->retries = retries;
     71 	data->code = code;
     72 }
     73 
     74 /*
     75  * Function: rc_guess_seqnbr
     76  *
     77  * Purpose: return a random sequence number
     78  *
     79  */
     80 
     81 static unsigned char rc_guess_seqnbr(void)
     82 {
     83 	return (unsigned char)(magic() & UCHAR_MAX);
     84 }
     85 
     86 /*
     87  * Function: rc_get_seqnbr
     88  *
     89  * Purpose: generate a sequence number
     90  *
     91  */
     92 
     93 unsigned char rc_get_seqnbr(void)
     94 {
     95 	FILE *sf;
     96 	int tries = 1;
     97 	int seq_nbr, pos;
     98 	char *seqfile = rc_conf_str("seqfile");
     99 
    100 	if ((sf = fopen(seqfile, "a+")) == NULL)
    101 	{
    102 		error("rc_get_seqnbr: couldn't open sequence file %s: %s", seqfile, strerror(errno));
    103 		/* well, so guess a sequence number */
    104 		return rc_guess_seqnbr();
    105 	}
    106 
    107 	while (do_lock_exclusive(fileno(sf))!= 0)
    108 	{
    109 		if (errno != EWOULDBLOCK) {
    110 			error("rc_get_seqnbr: flock failure: %s: %s", seqfile, strerror(errno));
    111 			fclose(sf);
    112 			return rc_guess_seqnbr();
    113 		}
    114 		tries++;
    115 		if (tries <= 10)
    116 			rc_mdelay(500);
    117 		else
    118 			break;
    119 	}
    120 
    121 	if (tries > 10) {
    122 		error("rc_get_seqnbr: couldn't get lock after %d tries: %s", tries-1, seqfile);
    123 		fclose(sf);
    124 		return rc_guess_seqnbr();
    125 	}
    126 
    127 	pos = ftell(sf);
    128 	rewind(sf);
    129 	if (fscanf(sf, "%d", &seq_nbr) != 1) {
    130 		if (pos != ftell(sf)) {
    131 			/* file was not empty */
    132 			error("rc_get_seqnbr: fscanf failure: %s", seqfile);
    133 		}
    134 		seq_nbr = rc_guess_seqnbr();
    135 	}
    136 
    137 	rewind(sf);
    138 	ftruncate(fileno(sf),0);
    139 	fprintf(sf,"%d\n", (seq_nbr+1) & UCHAR_MAX);
    140 
    141 	fflush(sf); /* fflush because a process may read it between the do_unlock and fclose */
    142 
    143 	if (do_unlock(fileno(sf)) != 0)
    144 		error("rc_get_seqnbr: couldn't release lock on %s: %s", seqfile, strerror(errno));
    145 
    146 	fclose(sf);
    147 
    148 	return (unsigned char)seq_nbr;
    149 }
    150 
    151 /*
    152  * Function: rc_auth
    153  *
    154  * Purpose: Builds an authentication request for port id client_port
    155  *	    with the value_pairs send and submits it to a server
    156  *
    157  * Returns: received value_pairs in received, messages from the server in msg
    158  *	    and 0 on success, negative on failure as return value
    159  *
    160  */
    161 
    162 int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received,
    163 	    char *msg, REQUEST_INFO *info)
    164 {
    165     SERVER *authserver = rc_conf_srv("authserver");
    166 
    167     if (!authserver) {
    168 	return (ERROR_RC);
    169     }
    170     return rc_auth_using_server(authserver, client_port, send, received,
    171 				msg, info);
    172 }
    173 
    174 /*
    175  * Function: rc_auth_using_server
    176  *
    177  * Purpose: Builds an authentication request for port id client_port
    178  *	    with the value_pairs send and submits it to a server.  You
    179  *          explicitly supply a server list.
    180  *
    181  * Returns: received value_pairs in received, messages from the server in msg
    182  *	    and 0 on success, negative on failure as return value
    183  *
    184  */
    185 
    186 int rc_auth_using_server(SERVER *authserver,
    187 			 UINT4 client_port,
    188 			 VALUE_PAIR *send,
    189 			 VALUE_PAIR **received,
    190 			 char *msg, REQUEST_INFO *info)
    191 {
    192 	SEND_DATA       data;
    193 	int		result;
    194 	int		i;
    195 	int		timeout = rc_conf_int("radius_timeout");
    196 	int		retries = rc_conf_int("radius_retries");
    197 
    198 	data.send_pairs = send;
    199 	data.receive_pairs = NULL;
    200 
    201 	/*
    202 	 * Fill in NAS-IP-Address or NAS-Identifier
    203 	 */
    204 
    205 	if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
    206 	    return (ERROR_RC);
    207 
    208 	/*
    209 	 * Fill in NAS-Port
    210 	 */
    211 
    212 	if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
    213 		return (ERROR_RC);
    214 
    215 	result = ERROR_RC;
    216 	for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
    217 		; i++)
    218 	{
    219 		if (data.receive_pairs != NULL) {
    220 			rc_avpair_free(data.receive_pairs);
    221 			data.receive_pairs = NULL;
    222 		}
    223 		rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
    224 			    authserver->port[i], timeout, retries);
    225 
    226 		result = rc_send_server (&data, msg, info);
    227 	}
    228 
    229 	*received = data.receive_pairs;
    230 
    231 	return result;
    232 }
    233 
    234 /*
    235  * Function: rc_auth_proxy
    236  *
    237  * Purpose: Builds an authentication request
    238  *	    with the value_pairs send and submits it to a server.
    239  *	    Works for a proxy; does not add IP address, and does
    240  *	    does not rely on config file.
    241  *
    242  * Returns: received value_pairs in received, messages from the server in msg
    243  *	    and 0 on success, negative on failure as return value
    244  *
    245  */
    246 
    247 int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
    248 {
    249 	SEND_DATA       data;
    250 	int		result;
    251 	int		i;
    252 	SERVER		*authserver = rc_conf_srv("authserver");
    253 	int		timeout = rc_conf_int("radius_timeout");
    254 	int		retries = rc_conf_int("radius_retries");
    255 
    256 	data.send_pairs = send;
    257 	data.receive_pairs = NULL;
    258 
    259 	result = ERROR_RC;
    260 	for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
    261 		; i++)
    262 	{
    263 		if (data.receive_pairs != NULL) {
    264 			rc_avpair_free(data.receive_pairs);
    265 			data.receive_pairs = NULL;
    266 		}
    267 		rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
    268 			    authserver->port[i], timeout, retries);
    269 
    270 		result = rc_send_server (&data, msg, NULL);
    271 	}
    272 
    273 	*received = data.receive_pairs;
    274 
    275 	return result;
    276 }
    277 
    278 
    279 /*
    280  * Function: rc_acct_using_server
    281  *
    282  * Purpose: Builds an accounting request for port id client_port
    283  *	    with the value_pairs send.  You explicitly supply server list.
    284  *
    285  * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
    286  *	    filled in by this function, the rest has to be supplied.
    287  */
    288 
    289 int rc_acct_using_server(SERVER *acctserver,
    290 			 UINT4 client_port,
    291 			 VALUE_PAIR *send)
    292 {
    293 	SEND_DATA       data;
    294 	VALUE_PAIR	*adt_vp;
    295 	int		result;
    296 	time_t		start_time, dtime;
    297 	char		msg[4096];
    298 	int		i;
    299 	int		timeout = rc_conf_int("radius_timeout");
    300 	int		retries = rc_conf_int("radius_retries");
    301 
    302 	data.send_pairs = send;
    303 	data.receive_pairs = NULL;
    304 
    305 	/*
    306 	 * Fill in NAS-IP-Address or NAS-Identifier
    307 	 */
    308 
    309 	if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
    310 	    return (ERROR_RC);
    311 
    312 	/*
    313 	 * Fill in NAS-Port
    314 	 */
    315 
    316 	if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
    317 		return (ERROR_RC);
    318 
    319 	/*
    320 	 * Fill in Acct-Delay-Time
    321 	 */
    322 
    323 	dtime = 0;
    324 	if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, VENDOR_NONE)) == NULL)
    325 		return (ERROR_RC);
    326 
    327 	start_time = time(NULL);
    328 	result = ERROR_RC;
    329 	for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
    330 		; i++)
    331 	{
    332 		if (data.receive_pairs != NULL) {
    333 			rc_avpair_free(data.receive_pairs);
    334 			data.receive_pairs = NULL;
    335 		}
    336 		rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
    337 			    acctserver->port[i], timeout, retries);
    338 
    339 		dtime = time(NULL) - start_time;
    340 		rc_avpair_assign(adt_vp, &dtime, 0);
    341 
    342 		result = rc_send_server (&data, msg, NULL);
    343 	}
    344 
    345 	rc_avpair_free(data.receive_pairs);
    346 
    347 	return result;
    348 }
    349 
    350 /*
    351  * Function: rc_acct
    352  *
    353  * Purpose: Builds an accounting request for port id client_port
    354  *	    with the value_pairs send
    355  *
    356  * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
    357  *	    filled in by this function, the rest has to be supplied.
    358  */
    359 
    360 int rc_acct(UINT4 client_port, VALUE_PAIR *send)
    361 {
    362     SERVER *acctserver = rc_conf_srv("acctserver");
    363     if (!acctserver) return (ERROR_RC);
    364 
    365     return rc_acct_using_server(acctserver, client_port, send);
    366 }
    367 
    368 /*
    369  * Function: rc_acct_proxy
    370  *
    371  * Purpose: Builds an accounting request with the value_pairs send
    372  *
    373  */
    374 
    375 int rc_acct_proxy(VALUE_PAIR *send)
    376 {
    377 	SEND_DATA       data;
    378 	int		result;
    379 	char		msg[4096];
    380 	int		i;
    381 	SERVER		*acctserver = rc_conf_srv("authserver");
    382 	int		timeout = rc_conf_int("radius_timeout");
    383 	int		retries = rc_conf_int("radius_retries");
    384 
    385 	data.send_pairs = send;
    386 	data.receive_pairs = NULL;
    387 
    388 	result = ERROR_RC;
    389 	for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
    390 		; i++)
    391 	{
    392 		if (data.receive_pairs != NULL) {
    393 			rc_avpair_free(data.receive_pairs);
    394 			data.receive_pairs = NULL;
    395 		}
    396 		rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
    397 			    acctserver->port[i], timeout, retries);
    398 
    399 		result = rc_send_server (&data, msg, NULL);
    400 	}
    401 
    402 	rc_avpair_free(data.receive_pairs);
    403 
    404 	return result;
    405 }
    406 
    407 /*
    408  * Function: rc_check
    409  *
    410  * Purpose: ask the server hostname on the specified port for a
    411  *	    status message
    412  *
    413  */
    414 
    415 int rc_check(char *host, unsigned short port, char *msg)
    416 {
    417 	SEND_DATA       data;
    418 	int		result;
    419 	UINT4		service_type;
    420 	int		timeout = rc_conf_int("radius_timeout");
    421 	int		retries = rc_conf_int("radius_retries");
    422 
    423 	data.send_pairs = data.receive_pairs = NULL;
    424 
    425 	/*
    426 	 * Fill in NAS-IP-Address or NAS-Identifier,
    427          * although it isn't neccessary
    428 	 */
    429 
    430 	if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
    431 	    return (ERROR_RC);
    432 
    433 	/*
    434 	 * Fill in Service-Type
    435 	 */
    436 
    437 	service_type = PW_ADMINISTRATIVE;
    438 	rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE);
    439 
    440 	rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries);
    441 	result = rc_send_server (&data, msg, NULL);
    442 
    443 	rc_avpair_free(data.receive_pairs);
    444 
    445 	return result;
    446 }
    447