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)
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 ftruncate(fileno(sf),0);
139 fprintf(sf,"%d\n", (seq_nbr+1) & UCHAR_MAX);
141 fflush(sf); /* fflush because a process may read it between the do_unlock and fclose */
143 if (do_unlock(fileno(sf)) != 0)
144 error("rc_get_seqnbr: couldn't release lock on %s: %s", seqfile, strerror(errno));
148 return (unsigned char)seq_nbr;
154 * Purpose: Builds an authentication request for port id client_port
155 * with the value_pairs send and submits it to a server
157 * Returns: received value_pairs in received, messages from the server in msg
158 * and 0 on success, negative on failure as return value
162 int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received,
163 char *msg, REQUEST_INFO *info)
165 SERVER *authserver = rc_conf_srv("authserver");
170 return rc_auth_using_server(authserver, client_port, send, received,
175 * Function: rc_auth_using_server
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.
181 * Returns: received value_pairs in received, messages from the server in msg
182 * and 0 on success, negative on failure as return value
186 int rc_auth_using_server(SERVER *authserver,
189 VALUE_PAIR **received,
190 char *msg, REQUEST_INFO *info)
195 int timeout = rc_conf_int("radius_timeout");
196 int retries = rc_conf_int("radius_retries");
198 data.send_pairs = send;
199 data.receive_pairs = NULL;
202 * Fill in NAS-IP-Address or NAS-Identifier
205 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
212 if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
216 for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
219 if (data.receive_pairs != NULL) {
220 rc_avpair_free(data.receive_pairs);
221 data.receive_pairs = NULL;
223 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
224 authserver->port[i], timeout, retries);
226 result = rc_send_server (&data, msg, info);
229 *received = data.receive_pairs;
235 * Function: rc_auth_proxy
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.
242 * Returns: received value_pairs in received, messages from the server in msg
243 * and 0 on success, negative on failure as return value
247 int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
252 SERVER *authserver = rc_conf_srv("authserver");
253 int timeout = rc_conf_int("radius_timeout");
254 int retries = rc_conf_int("radius_retries");
256 data.send_pairs = send;
257 data.receive_pairs = NULL;
260 for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
263 if (data.receive_pairs != NULL) {
264 rc_avpair_free(data.receive_pairs);
265 data.receive_pairs = NULL;
267 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
268 authserver->port[i], timeout, retries);
270 result = rc_send_server (&data, msg, NULL);
273 *received = data.receive_pairs;
280 * Function: rc_acct_using_server
282 * Purpose: Builds an accounting request for port id client_port
283 * with the value_pairs send. You explicitly supply server list.
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.
289 int rc_acct_using_server(SERVER *acctserver,
296 struct timeval start_time, dtime;
299 int timeout = rc_conf_int("radius_timeout");
300 int retries = rc_conf_int("radius_retries");
302 data.send_pairs = send;
303 data.receive_pairs = NULL;
306 * Fill in NAS-IP-Address or NAS-Identifier
309 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
316 if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
320 * Fill in Acct-Delay-Time
324 if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime.tv_sec, 0, VENDOR_NONE)) == NULL)
327 get_time(&start_time);
329 for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
332 if (data.receive_pairs != NULL) {
333 rc_avpair_free(data.receive_pairs);
334 data.receive_pairs = NULL;
336 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
337 acctserver->port[i], timeout, retries);
340 dtime.tv_sec -= start_time.tv_sec;
341 rc_avpair_assign(adt_vp, &dtime.tv_sec, 0);
343 result = rc_send_server (&data, msg, NULL);
346 rc_avpair_free(data.receive_pairs);
354 * Purpose: Builds an accounting request for port id client_port
355 * with the value_pairs send
357 * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
358 * filled in by this function, the rest has to be supplied.
361 int rc_acct(UINT4 client_port, VALUE_PAIR *send)
363 SERVER *acctserver = rc_conf_srv("acctserver");
364 if (!acctserver) return (ERROR_RC);
366 return rc_acct_using_server(acctserver, client_port, send);
370 * Function: rc_acct_proxy
372 * Purpose: Builds an accounting request with the value_pairs send
376 int rc_acct_proxy(VALUE_PAIR *send)
382 SERVER *acctserver = rc_conf_srv("authserver");
383 int timeout = rc_conf_int("radius_timeout");
384 int retries = rc_conf_int("radius_retries");
386 data.send_pairs = send;
387 data.receive_pairs = NULL;
390 for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
393 if (data.receive_pairs != NULL) {
394 rc_avpair_free(data.receive_pairs);
395 data.receive_pairs = NULL;
397 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
398 acctserver->port[i], timeout, retries);
400 result = rc_send_server (&data, msg, NULL);
403 rc_avpair_free(data.receive_pairs);
411 * Purpose: ask the server hostname on the specified port for a
416 int rc_check(char *host, unsigned short port, char *msg)
421 int timeout = rc_conf_int("radius_timeout");
422 int retries = rc_conf_int("radius_retries");
424 data.send_pairs = data.receive_pairs = NULL;
427 * Fill in NAS-IP-Address or NAS-Identifier,
428 * although it isn't neccessary
431 if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
435 * Fill in Service-Type
438 service_type = PW_ADMINISTRATIVE;
439 rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE);
441 rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries);
442 result = rc_send_server (&data, msg, NULL);
444 rc_avpair_free(data.receive_pairs);