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 
15 unsigned 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 
rc_get_nas_id(VALUE_PAIR ** sendpairs)24 int 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 
rc_buildreq(SEND_DATA * data,int code,char * server,unsigned short port,int timeout,int retries)63 void 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 
rc_guess_seqnbr(void)81 static 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 
rc_get_seqnbr(void)93 unsigned 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 
rc_auth(UINT4 client_port,VALUE_PAIR * send,VALUE_PAIR ** received,char * msg,REQUEST_INFO * info)162 int 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 
rc_auth_using_server(SERVER * authserver,UINT4 client_port,VALUE_PAIR * send,VALUE_PAIR ** received,char * msg,REQUEST_INFO * info)186 int 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 
rc_auth_proxy(VALUE_PAIR * send,VALUE_PAIR ** received,char * msg)247 int 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 
rc_acct_using_server(SERVER * acctserver,UINT4 client_port,VALUE_PAIR * send)289 int 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 
rc_acct(UINT4 client_port,VALUE_PAIR * send)360 int 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 
rc_acct_proxy(VALUE_PAIR * send)375 int 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 
rc_check(char * host,unsigned short port,char * msg)415 int 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