]> git.ozlabs.org Git - ppp.git/blob - pppd/plugins/radius/buildreq.c
Makefile.am: Add explicit openssl directory to pppd include path
[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, ret;
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         ret = ftruncate(fileno(sf),0);
139         if (ret != 0) {
140                 error("rc_get_seqnbr: couldn't truncate sequence file, %m");
141         }
142         fprintf(sf,"%d\n", (seq_nbr+1) & UCHAR_MAX);
143
144         fflush(sf); /* fflush because a process may read it between the do_unlock and fclose */
145
146         if (do_unlock(fileno(sf)) != 0)
147                 error("rc_get_seqnbr: couldn't release lock on %s: %s", seqfile, strerror(errno));
148
149         fclose(sf);
150
151         return (unsigned char)seq_nbr;
152 }
153
154 /*
155  * Function: rc_auth
156  *
157  * Purpose: Builds an authentication request for port id client_port
158  *          with the value_pairs send and submits it to a server
159  *
160  * Returns: received value_pairs in received, messages from the server in msg
161  *          and 0 on success, negative on failure as return value
162  *
163  */
164
165 int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received,
166             char *msg, REQUEST_INFO *info)
167 {
168     SERVER *authserver = rc_conf_srv("authserver");
169
170     if (!authserver) {
171         return (ERROR_RC);
172     }
173     return rc_auth_using_server(authserver, client_port, send, received,
174                                 msg, info);
175 }
176
177 /*
178  * Function: rc_auth_using_server
179  *
180  * Purpose: Builds an authentication request for port id client_port
181  *          with the value_pairs send and submits it to a server.  You
182  *          explicitly supply a server list.
183  *
184  * Returns: received value_pairs in received, messages from the server in msg
185  *          and 0 on success, negative on failure as return value
186  *
187  */
188
189 int rc_auth_using_server(SERVER *authserver,
190                          UINT4 client_port,
191                          VALUE_PAIR *send,
192                          VALUE_PAIR **received,
193                          char *msg, REQUEST_INFO *info)
194 {
195         SEND_DATA       data;
196         int             result;
197         int             i;
198         int             timeout = rc_conf_int("radius_timeout");
199         int             retries = rc_conf_int("radius_retries");
200
201         data.send_pairs = send;
202         data.receive_pairs = NULL;
203
204         /*
205          * Fill in NAS-IP-Address or NAS-Identifier
206          */
207
208         if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
209             return (ERROR_RC);
210
211         /*
212          * Fill in NAS-Port
213          */
214
215         if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
216                 return (ERROR_RC);
217
218         result = ERROR_RC;
219         for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
220                 ; i++)
221         {
222                 if (data.receive_pairs != NULL) {
223                         rc_avpair_free(data.receive_pairs);
224                         data.receive_pairs = NULL;
225                 }
226                 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
227                             authserver->port[i], timeout, retries);
228
229                 result = rc_send_server (&data, msg, info);
230         }
231
232         *received = data.receive_pairs;
233
234         return result;
235 }
236
237 /*
238  * Function: rc_auth_proxy
239  *
240  * Purpose: Builds an authentication request
241  *          with the value_pairs send and submits it to a server.
242  *          Works for a proxy; does not add IP address, and does
243  *          does not rely on config file.
244  *
245  * Returns: received value_pairs in received, messages from the server in msg
246  *          and 0 on success, negative on failure as return value
247  *
248  */
249
250 int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
251 {
252         SEND_DATA       data;
253         int             result;
254         int             i;
255         SERVER          *authserver = rc_conf_srv("authserver");
256         int             timeout = rc_conf_int("radius_timeout");
257         int             retries = rc_conf_int("radius_retries");
258
259         data.send_pairs = send;
260         data.receive_pairs = NULL;
261
262         result = ERROR_RC;
263         for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
264                 ; i++)
265         {
266                 if (data.receive_pairs != NULL) {
267                         rc_avpair_free(data.receive_pairs);
268                         data.receive_pairs = NULL;
269                 }
270                 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
271                             authserver->port[i], timeout, retries);
272
273                 result = rc_send_server (&data, msg, NULL);
274         }
275
276         *received = data.receive_pairs;
277
278         return result;
279 }
280
281
282 /*
283  * Function: rc_acct_using_server
284  *
285  * Purpose: Builds an accounting request for port id client_port
286  *          with the value_pairs send.  You explicitly supply server list.
287  *
288  * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
289  *          filled in by this function, the rest has to be supplied.
290  */
291
292 int rc_acct_using_server(SERVER *acctserver,
293                          UINT4 client_port,
294                          VALUE_PAIR *send)
295 {
296         SEND_DATA       data;
297         VALUE_PAIR      *adt_vp;
298         int             result;
299         struct timeval  start_time, dtime;
300         char            msg[4096];
301         int             i;
302         int             timeout = rc_conf_int("radius_timeout");
303         int             retries = rc_conf_int("radius_retries");
304
305         data.send_pairs = send;
306         data.receive_pairs = NULL;
307
308         /*
309          * Fill in NAS-IP-Address or NAS-Identifier
310          */
311
312         if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
313             return (ERROR_RC);
314
315         /*
316          * Fill in NAS-Port
317          */
318
319         if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
320                 return (ERROR_RC);
321
322         /*
323          * Fill in Acct-Delay-Time
324          */
325
326         dtime.tv_sec = 0;
327         if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime.tv_sec, 0, VENDOR_NONE)) == NULL)
328                 return (ERROR_RC);
329
330         ppp_get_time(&start_time);
331         result = ERROR_RC;
332         for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
333                 ; i++)
334         {
335                 if (data.receive_pairs != NULL) {
336                         rc_avpair_free(data.receive_pairs);
337                         data.receive_pairs = NULL;
338                 }
339                 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
340                             acctserver->port[i], timeout, retries);
341
342                 ppp_get_time(&dtime);
343                 dtime.tv_sec -= start_time.tv_sec;
344                 rc_avpair_assign(adt_vp, &dtime.tv_sec, 0);
345
346                 result = rc_send_server (&data, msg, NULL);
347         }
348
349         rc_avpair_free(data.receive_pairs);
350
351         return result;
352 }
353
354 /*
355  * Function: rc_acct
356  *
357  * Purpose: Builds an accounting request for port id client_port
358  *          with the value_pairs send
359  *
360  * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
361  *          filled in by this function, the rest has to be supplied.
362  */
363
364 int rc_acct(UINT4 client_port, VALUE_PAIR *send)
365 {
366     SERVER *acctserver = rc_conf_srv("acctserver");
367     if (!acctserver) return (ERROR_RC);
368
369     return rc_acct_using_server(acctserver, client_port, send);
370 }
371
372 /*
373  * Function: rc_acct_proxy
374  *
375  * Purpose: Builds an accounting request with the value_pairs send
376  *
377  */
378
379 int rc_acct_proxy(VALUE_PAIR *send)
380 {
381         SEND_DATA       data;
382         int             result;
383         char            msg[4096];
384         int             i;
385         SERVER          *acctserver = rc_conf_srv("authserver");
386         int             timeout = rc_conf_int("radius_timeout");
387         int             retries = rc_conf_int("radius_retries");
388
389         data.send_pairs = send;
390         data.receive_pairs = NULL;
391
392         result = ERROR_RC;
393         for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
394                 ; i++)
395         {
396                 if (data.receive_pairs != NULL) {
397                         rc_avpair_free(data.receive_pairs);
398                         data.receive_pairs = NULL;
399                 }
400                 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
401                             acctserver->port[i], timeout, retries);
402
403                 result = rc_send_server (&data, msg, NULL);
404         }
405
406         rc_avpair_free(data.receive_pairs);
407
408         return result;
409 }
410
411 /*
412  * Function: rc_check
413  *
414  * Purpose: ask the server hostname on the specified port for a
415  *          status message
416  *
417  */
418
419 int rc_check(char *host, unsigned short port, char *msg)
420 {
421         SEND_DATA       data;
422         int             result;
423         UINT4           service_type;
424         int             timeout = rc_conf_int("radius_timeout");
425         int             retries = rc_conf_int("radius_retries");
426
427         data.send_pairs = data.receive_pairs = NULL;
428
429         /*
430          * Fill in NAS-IP-Address or NAS-Identifier,
431          * although it isn't neccessary
432          */
433
434         if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
435             return (ERROR_RC);
436
437         /*
438          * Fill in Service-Type
439          */
440
441         service_type = PW_ADMINISTRATIVE;
442         rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE);
443
444         rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries);
445         result = rc_send_server (&data, msg, NULL);
446
447         rc_avpair_free(data.receive_pairs);
448
449         return result;
450 }