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@elemental.net
8 * and I'll send you a copy.
9 *
10 */
11
12#include <includes.h>
13#include <radiusclient.h>
14
15unsigned 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
24int 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
63void 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
81static 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
93unsigned 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
162int 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
186int 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
247int 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
289int 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
360int 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
375int 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
415int 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