plugins/radius: Handle bindaddr keyword in radiusclient.conf
[ppp.git] / pppd / plugins / radius / buildreq.c
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
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
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
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
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
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
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
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
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
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
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
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 }