]> git.ozlabs.org Git - ppp.git/blob - pppd/plugins/radius/radiusclient/lib/buildreq.c
rc_get_seqnbr(): Avoid "fscanf failure" errors if the sequence file was
[ppp.git] / pppd / plugins / radius / radiusclient / lib / buildreq.c
1 /*
2  * $Id: buildreq.c,v 1.5 2003/04/25 08:10:46 fcusack 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_get_nas_id
20  *
21  * Purpose: fills in NAS-Identifier or NAS-IP-Address in request
22  *
23  */
24
25 int 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
64 void 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
82 static 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
95 unsigned 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
164 int 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
188 int 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
249 int 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
291 int 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
362 int 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
377 int 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
417 int 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 }