2 * $Id: buildreq.c,v 1.1 2004/11/14 07:26:26 paulus 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.
13 #include <radiusclient.h>
15 unsigned char rc_get_seqnbr(void);
18 * Function: rc_get_nas_id
20 * Purpose: fills in NAS-Identifier or NAS-IP-Address in request
24 int rc_get_nas_id(VALUE_PAIR **sendpairs)
29 nasid = rc_conf_str("nas_identifier");
32 * Fill in NAS-Identifier
34 if (rc_avpair_add(sendpairs, PW_NAS_IDENTIFIER, nasid, 0,
42 * Fill in NAS-IP-Address
44 if ((client_id = rc_own_ipaddress()) == 0)
47 if (rc_avpair_add(sendpairs, PW_NAS_IP_ADDRESS, &client_id,
48 0, VENDOR_NONE) == NULL)
56 * Function: rc_buildreq
58 * Purpose: builds a skeleton RADIUS request using information from the
63 void rc_buildreq(SEND_DATA *data, int code, char *server, unsigned short port,
64 int timeout, int retries)
66 data->server = server;
67 data->svc_port = port;
68 data->seq_nbr = rc_get_seqnbr();
69 data->timeout = timeout;
70 data->retries = retries;
75 * Function: rc_guess_seqnbr
77 * Purpose: return a random sequence number
81 static unsigned char rc_guess_seqnbr(void)
83 return (unsigned char)(magic() & UCHAR_MAX);
87 * Function: rc_get_seqnbr
89 * Purpose: generate a sequence number
93 unsigned char rc_get_seqnbr(void)
97 int seq_nbr, pos, ret;
98 char *seqfile = rc_conf_str("seqfile");
100 if ((sf = fopen(seqfile, "a+")) == NULL)
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();
107 while (do_lock_exclusive(fileno(sf))!= 0)
109 if (errno != EWOULDBLOCK) {
110 error("rc_get_seqnbr: flock failure: %s: %s", seqfile, strerror(errno));
112 return rc_guess_seqnbr();
122 error("rc_get_seqnbr: couldn't get lock after %d tries: %s", tries-1, seqfile);
124 return rc_guess_seqnbr();
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);
134 seq_nbr = rc_guess_seqnbr();
138 ret = ftruncate(fileno(sf),0);
140 error("rc_get_seqnbr: couldn't truncate sequence file, %m");
142 fprintf(sf,"%d\n", (seq_nbr+1) & UCHAR_MAX);
144 fflush(sf); /* fflush because a process may read it between the do_unlock and fclose */
146 if (do_unlock(fileno(sf)) != 0)
147 error("rc_get_seqnbr: couldn't release lock on %s: %s", seqfile, strerror(errno));
151 return (unsigned char)seq_nbr;
157 * Purpose: Builds an authentication request for port id client_port
158 * with the value_pairs send and submits it to a server
160 * Returns: received value_pairs in received, messages from the server in msg
161 * and 0 on success, negative on failure as return value
165 int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received,
166 char *msg, REQUEST_INFO *info)
168 SERVER *authserver = rc_conf_srv("authserver");
173 return rc_auth_using_server(authserver, client_port, send, received,
178 * Function: rc_auth_using_server
180 * Purpose: Builds an authentication request for port id client_port
181 * with the value_pairs send and submits it to a server. You
182 * explicitly supply a server list.
184 * Returns: received value_pairs in received, messages from the server in msg
185 * and 0 on success, negative on failure as return value
189 int rc_auth_using_server(SERVER *authserver,
192 VALUE_PAIR **received,
193 char *msg, REQUEST_INFO *info)
198 int timeout = rc_conf_int("radius_timeout");
199 int retries = rc_conf_int("radius_retries");
201 data.send_pairs = send;
202 data.receive_pairs = NULL;
205 * Fill in NAS-IP-Address or NAS-Identifier
208 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
215 if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
219 for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
222 if (data.receive_pairs != NULL) {
223 rc_avpair_free(data.receive_pairs);
224 data.receive_pairs = NULL;
226 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
227 authserver->port[i], timeout, retries);
229 result = rc_send_server (&data, msg, info);
232 *received = data.receive_pairs;
238 * Function: rc_auth_proxy
240 * Purpose: Builds an authentication request
241 * with the value_pairs send and submits it to a server.
242 * Works for a proxy; does not add IP address, and does
243 * does not rely on config file.
245 * Returns: received value_pairs in received, messages from the server in msg
246 * and 0 on success, negative on failure as return value
250 int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
255 SERVER *authserver = rc_conf_srv("authserver");
256 int timeout = rc_conf_int("radius_timeout");
257 int retries = rc_conf_int("radius_retries");
259 data.send_pairs = send;
260 data.receive_pairs = NULL;
263 for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
266 if (data.receive_pairs != NULL) {
267 rc_avpair_free(data.receive_pairs);
268 data.receive_pairs = NULL;
270 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
271 authserver->port[i], timeout, retries);
273 result = rc_send_server (&data, msg, NULL);
276 *received = data.receive_pairs;
283 * Function: rc_acct_using_server
285 * Purpose: Builds an accounting request for port id client_port
286 * with the value_pairs send. You explicitly supply server list.
288 * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
289 * filled in by this function, the rest has to be supplied.
292 int rc_acct_using_server(SERVER *acctserver,
299 struct timeval start_time, dtime;
302 int timeout = rc_conf_int("radius_timeout");
303 int retries = rc_conf_int("radius_retries");
305 data.send_pairs = send;
306 data.receive_pairs = NULL;
309 * Fill in NAS-IP-Address or NAS-Identifier
312 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
319 if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
323 * Fill in Acct-Delay-Time
327 if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime.tv_sec, 0, VENDOR_NONE)) == NULL)
330 get_time(&start_time);
332 for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
335 if (data.receive_pairs != NULL) {
336 rc_avpair_free(data.receive_pairs);
337 data.receive_pairs = NULL;
339 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
340 acctserver->port[i], timeout, retries);
343 dtime.tv_sec -= start_time.tv_sec;
344 rc_avpair_assign(adt_vp, &dtime.tv_sec, 0);
346 result = rc_send_server (&data, msg, NULL);
349 rc_avpair_free(data.receive_pairs);
357 * Purpose: Builds an accounting request for port id client_port
358 * with the value_pairs send
360 * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
361 * filled in by this function, the rest has to be supplied.
364 int rc_acct(UINT4 client_port, VALUE_PAIR *send)
366 SERVER *acctserver = rc_conf_srv("acctserver");
367 if (!acctserver) return (ERROR_RC);
369 return rc_acct_using_server(acctserver, client_port, send);
373 * Function: rc_acct_proxy
375 * Purpose: Builds an accounting request with the value_pairs send
379 int rc_acct_proxy(VALUE_PAIR *send)
385 SERVER *acctserver = rc_conf_srv("authserver");
386 int timeout = rc_conf_int("radius_timeout");
387 int retries = rc_conf_int("radius_retries");
389 data.send_pairs = send;
390 data.receive_pairs = NULL;
393 for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
396 if (data.receive_pairs != NULL) {
397 rc_avpair_free(data.receive_pairs);
398 data.receive_pairs = NULL;
400 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
401 acctserver->port[i], timeout, retries);
403 result = rc_send_server (&data, msg, NULL);
406 rc_avpair_free(data.receive_pairs);
414 * Purpose: ask the server hostname on the specified port for a
419 int rc_check(char *host, unsigned short port, char *msg)
424 int timeout = rc_conf_int("radius_timeout");
425 int retries = rc_conf_int("radius_retries");
427 data.send_pairs = data.receive_pairs = NULL;
430 * Fill in NAS-IP-Address or NAS-Identifier,
431 * although it isn't neccessary
434 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
438 * Fill in Service-Type
441 service_type = PW_ADMINISTRATIVE;
442 rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE);
444 rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries);
445 result = rc_send_server (&data, msg, NULL);
447 rc_avpair_free(data.receive_pairs);