2 * $Id: buildreq.c,v 1.4 2002/10/01 09:51:01 fcusack Exp $
4 * Copyright (C) 1995,1997 Lars Fenneberg
6 * See the file COPYRIGHT for the respective terms and conditions.
7 * If the file is missing contact me at lf@elemental.net
8 * and I'll send you a copy.
14 #include <radiusclient.h>
16 unsigned char rc_get_seqnbr(void);
19 * Function: rc_get_nas_id
21 * Purpose: fills in NAS-Identifier or NAS-IP-Address in request
25 int rc_get_nas_id(VALUE_PAIR **sendpairs)
30 nasid = rc_conf_str("nas_identifier");
33 * Fill in NAS-Identifier
35 if (rc_avpair_add(sendpairs, PW_NAS_IDENTIFIER, nasid, 0,
43 * Fill in NAS-IP-Address
45 if ((client_id = rc_own_ipaddress()) == 0)
48 if (rc_avpair_add(sendpairs, PW_NAS_IP_ADDRESS, &client_id,
49 0, VENDOR_NONE) == NULL)
57 * Function: rc_buildreq
59 * Purpose: builds a skeleton RADIUS request using information from the
64 void rc_buildreq(SEND_DATA *data, int code, char *server, unsigned short port,
65 int timeout, int retries)
67 data->server = server;
68 data->svc_port = port;
69 data->seq_nbr = rc_get_seqnbr();
70 data->timeout = timeout;
71 data->retries = retries;
76 * Function: rc_guess_seqnbr
78 * Purpose: return a random sequence number
82 static unsigned char rc_guess_seqnbr(void)
84 srandom((unsigned int)(time(NULL)+getpid()));
85 return (unsigned char)(random() & UCHAR_MAX);
89 * Function: rc_get_seqnbr
91 * Purpose: generate a sequence number
95 unsigned char rc_get_seqnbr(void)
100 char *seqfile = rc_conf_str("seqfile");
102 if ((sf = fopen(seqfile, "a+")) == NULL)
104 rc_log(LOG_ERR,"rc_get_seqnbr: couldn't open sequence file %s: %s", seqfile, strerror(errno));
105 /* well, so guess a sequence number */
106 return rc_guess_seqnbr();
109 while (do_lock_exclusive(fileno(sf))!= 0)
111 if (errno != EWOULDBLOCK) {
112 rc_log(LOG_ERR, "rc_get_seqnbr: flock failure: %s: %s", seqfile, strerror(errno));
114 return rc_guess_seqnbr();
124 rc_log(LOG_ERR,"rc_get_seqnbr: couldn't get lock after %d tries: %s", tries-1, seqfile);
126 return rc_guess_seqnbr();
130 if (fscanf(sf, "%d", &seq_nbr) != 1) {
131 rc_log(LOG_ERR,"rc_get_seqnbr: fscanf failure: %s", seqfile);
132 seq_nbr = rc_guess_seqnbr();
136 ftruncate(fileno(sf),0);
137 fprintf(sf,"%d\n", (seq_nbr+1) & UCHAR_MAX);
139 fflush(sf); /* fflush because a process may read it between the do_unlock and fclose */
141 if (do_unlock(fileno(sf)) != 0)
142 rc_log(LOG_ERR, "rc_get_seqnbr: couldn't release lock on %s: %s", seqfile, strerror(errno));
146 return (unsigned char)seq_nbr;
152 * Purpose: Builds an authentication request for port id client_port
153 * with the value_pairs send and submits it to a server
155 * Returns: received value_pairs in received, messages from the server in msg
156 * and 0 on success, negative on failure as return value
160 int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received,
161 char *msg, REQUEST_INFO *info)
163 SERVER *authserver = rc_conf_srv("authserver");
168 return rc_auth_using_server(authserver, client_port, send, received,
173 * Function: rc_auth_using_server
175 * Purpose: Builds an authentication request for port id client_port
176 * with the value_pairs send and submits it to a server. You
177 * explicitly supply a server list.
179 * Returns: received value_pairs in received, messages from the server in msg
180 * and 0 on success, negative on failure as return value
184 int rc_auth_using_server(SERVER *authserver,
187 VALUE_PAIR **received,
188 char *msg, REQUEST_INFO *info)
193 int timeout = rc_conf_int("radius_timeout");
194 int retries = rc_conf_int("radius_retries");
196 data.send_pairs = send;
197 data.receive_pairs = NULL;
200 * Fill in NAS-IP-Address or NAS-Identifier
203 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
210 if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
214 for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
217 if (data.receive_pairs != NULL) {
218 rc_avpair_free(data.receive_pairs);
219 data.receive_pairs = NULL;
221 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
222 authserver->port[i], timeout, retries);
224 result = rc_send_server (&data, msg, info);
227 *received = data.receive_pairs;
233 * Function: rc_auth_proxy
235 * Purpose: Builds an authentication request
236 * with the value_pairs send and submits it to a server.
237 * Works for a proxy; does not add IP address, and does
238 * does not rely on config file.
240 * Returns: received value_pairs in received, messages from the server in msg
241 * and 0 on success, negative on failure as return value
245 int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
250 SERVER *authserver = rc_conf_srv("authserver");
251 int timeout = rc_conf_int("radius_timeout");
252 int retries = rc_conf_int("radius_retries");
254 data.send_pairs = send;
255 data.receive_pairs = NULL;
258 for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
261 if (data.receive_pairs != NULL) {
262 rc_avpair_free(data.receive_pairs);
263 data.receive_pairs = NULL;
265 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
266 authserver->port[i], timeout, retries);
268 result = rc_send_server (&data, msg, NULL);
271 *received = data.receive_pairs;
278 * Function: rc_acct_using_server
280 * Purpose: Builds an accounting request for port id client_port
281 * with the value_pairs send. You explicitly supply server list.
283 * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
284 * filled in by this function, the rest has to be supplied.
287 int rc_acct_using_server(SERVER *acctserver,
294 time_t start_time, dtime;
297 int timeout = rc_conf_int("radius_timeout");
298 int retries = rc_conf_int("radius_retries");
300 data.send_pairs = send;
301 data.receive_pairs = NULL;
304 * Fill in NAS-IP-Address or NAS-Identifier
307 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
314 if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
318 * Fill in Acct-Delay-Time
322 if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, VENDOR_NONE)) == NULL)
325 start_time = time(NULL);
327 for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
330 if (data.receive_pairs != NULL) {
331 rc_avpair_free(data.receive_pairs);
332 data.receive_pairs = NULL;
334 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
335 acctserver->port[i], timeout, retries);
337 dtime = time(NULL) - start_time;
338 rc_avpair_assign(adt_vp, &dtime, 0);
340 result = rc_send_server (&data, msg, NULL);
343 rc_avpair_free(data.receive_pairs);
351 * Purpose: Builds an accounting request for port id client_port
352 * with the value_pairs send
354 * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
355 * filled in by this function, the rest has to be supplied.
358 int rc_acct(UINT4 client_port, VALUE_PAIR *send)
360 SERVER *acctserver = rc_conf_srv("acctserver");
361 if (!acctserver) return (ERROR_RC);
363 return rc_acct_using_server(acctserver, client_port, send);
367 * Function: rc_acct_proxy
369 * Purpose: Builds an accounting request with the value_pairs send
373 int rc_acct_proxy(VALUE_PAIR *send)
379 SERVER *acctserver = rc_conf_srv("authserver");
380 int timeout = rc_conf_int("radius_timeout");
381 int retries = rc_conf_int("radius_retries");
383 data.send_pairs = send;
384 data.receive_pairs = NULL;
387 for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
390 if (data.receive_pairs != NULL) {
391 rc_avpair_free(data.receive_pairs);
392 data.receive_pairs = NULL;
394 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
395 acctserver->port[i], timeout, retries);
397 result = rc_send_server (&data, msg, NULL);
400 rc_avpair_free(data.receive_pairs);
408 * Purpose: ask the server hostname on the specified port for a
413 int rc_check(char *host, unsigned short port, char *msg)
418 int timeout = rc_conf_int("radius_timeout");
419 int retries = rc_conf_int("radius_retries");
421 data.send_pairs = data.receive_pairs = NULL;
424 * Fill in NAS-IP-Address or NAS-Identifier,
425 * although it isn't neccessary
428 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
432 * Fill in Service-Type
435 service_type = PW_ADMINISTRATIVE;
436 rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE);
438 rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries);
439 result = rc_send_server (&data, msg, NULL);
441 rc_avpair_free(data.receive_pairs);