]> git.ozlabs.org Git - ppp.git/blob - pppd/plugins/radius/buildreq.c
CI: Updated the 'checkout' actions that were using Node.js 16 to Node.js 20. (#489)
[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         struct timeval  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.tv_sec = 0;
324         if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime.tv_sec, 0, VENDOR_NONE)) == NULL)
325                 return (ERROR_RC);
326
327         get_time(&start_time);
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                 get_time(&dtime);
340                 dtime.tv_sec -= start_time.tv_sec;
341                 rc_avpair_assign(adt_vp, &dtime.tv_sec, 0);
342
343                 result = rc_send_server (&data, msg, NULL);
344         }
345
346         rc_avpair_free(data.receive_pairs);
347
348         return result;
349 }
350
351 /*
352  * Function: rc_acct
353  *
354  * Purpose: Builds an accounting request for port id client_port
355  *          with the value_pairs send
356  *
357  * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
358  *          filled in by this function, the rest has to be supplied.
359  */
360
361 int rc_acct(UINT4 client_port, VALUE_PAIR *send)
362 {
363     SERVER *acctserver = rc_conf_srv("acctserver");
364     if (!acctserver) return (ERROR_RC);
365
366     return rc_acct_using_server(acctserver, client_port, send);
367 }
368
369 /*
370  * Function: rc_acct_proxy
371  *
372  * Purpose: Builds an accounting request with the value_pairs send
373  *
374  */
375
376 int rc_acct_proxy(VALUE_PAIR *send)
377 {
378         SEND_DATA       data;
379         int             result;
380         char            msg[4096];
381         int             i;
382         SERVER          *acctserver = rc_conf_srv("authserver");
383         int             timeout = rc_conf_int("radius_timeout");
384         int             retries = rc_conf_int("radius_retries");
385
386         data.send_pairs = send;
387         data.receive_pairs = NULL;
388
389         result = ERROR_RC;
390         for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
391                 ; i++)
392         {
393                 if (data.receive_pairs != NULL) {
394                         rc_avpair_free(data.receive_pairs);
395                         data.receive_pairs = NULL;
396                 }
397                 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
398                             acctserver->port[i], timeout, retries);
399
400                 result = rc_send_server (&data, msg, NULL);
401         }
402
403         rc_avpair_free(data.receive_pairs);
404
405         return result;
406 }
407
408 /*
409  * Function: rc_check
410  *
411  * Purpose: ask the server hostname on the specified port for a
412  *          status message
413  *
414  */
415
416 int rc_check(char *host, unsigned short port, char *msg)
417 {
418         SEND_DATA       data;
419         int             result;
420         UINT4           service_type;
421         int             timeout = rc_conf_int("radius_timeout");
422         int             retries = rc_conf_int("radius_retries");
423
424         data.send_pairs = data.receive_pairs = NULL;
425
426         /*
427          * Fill in NAS-IP-Address or NAS-Identifier,
428          * although it isn't neccessary
429          */
430
431         if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
432             return (ERROR_RC);
433
434         /*
435          * Fill in Service-Type
436          */
437
438         service_type = PW_ADMINISTRATIVE;
439         rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE);
440
441         rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries);
442         result = rc_send_server (&data, msg, NULL);
443
444         rc_avpair_free(data.receive_pairs);
445
446         return result;
447 }