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