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