]> git.ozlabs.org Git - ppp.git/blob - pppd/plugins/radius/radiusclient/lib/buildreq.c
Added RADIUS support for MPPE (patch from Frank Cusack)
[ppp.git] / pppd / plugins / radius / radiusclient / lib / buildreq.c
1 /*
2  * $Id: buildreq.c,v 1.3 2002/04/02 14:09:35 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, REQUEST_INFO *info)
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,
131                                 msg, info);
132 }
133
134 /*
135  * Function: rc_auth_using_server
136  *
137  * Purpose: Builds an authentication request for port id client_port
138  *          with the value_pairs send and submits it to a server.  You
139  *          explicitly supply a server list.
140  *
141  * Returns: received value_pairs in received, messages from the server in msg
142  *          and 0 on success, negative on failure as return value
143  *
144  */
145
146 int rc_auth_using_server(SERVER *authserver,
147                          UINT4 client_port,
148                          VALUE_PAIR *send,
149                          VALUE_PAIR **received,
150                          char *msg, REQUEST_INFO *info)
151 {
152         SEND_DATA       data;
153         UINT4           client_id;
154         int             result;
155         int             i;
156         int             timeout = rc_conf_int("radius_timeout");
157         int             retries = rc_conf_int("radius_retries");
158
159         data.send_pairs = send;
160         data.receive_pairs = NULL;
161
162         /*
163          * Fill in NAS-IP-Address
164          */
165
166         if ((client_id = rc_own_ipaddress()) == 0)
167                 return (ERROR_RC);
168
169         if (rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0, VENDOR_NONE) == NULL)
170                 return (ERROR_RC);
171
172         /*
173          * Fill in NAS-Port
174          */
175
176         if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
177                 return (ERROR_RC);
178
179         result = ERROR_RC;
180         for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
181                 ; i++)
182         {
183                 if (data.receive_pairs != NULL) {
184                         rc_avpair_free(data.receive_pairs);
185                         data.receive_pairs = NULL;
186                 }
187                 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
188                             authserver->port[i], timeout, retries);
189
190                 result = rc_send_server (&data, msg, info);
191         }
192
193         *received = data.receive_pairs;
194
195         return result;
196 }
197
198 /*
199  * Function: rc_auth_proxy
200  *
201  * Purpose: Builds an authentication request
202  *          with the value_pairs send and submits it to a server.
203  *          Works for a proxy; does not add IP address, and does
204  *          does not rely on config file.
205  *
206  * Returns: received value_pairs in received, messages from the server in msg
207  *          and 0 on success, negative on failure as return value
208  *
209  */
210
211 int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
212 {
213         SEND_DATA       data;
214         int             result;
215         int             i;
216         SERVER          *authserver = rc_conf_srv("authserver");
217         int             timeout = rc_conf_int("radius_timeout");
218         int             retries = rc_conf_int("radius_retries");
219
220         data.send_pairs = send;
221         data.receive_pairs = NULL;
222
223         result = ERROR_RC;
224         for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
225                 ; i++)
226         {
227                 if (data.receive_pairs != NULL) {
228                         rc_avpair_free(data.receive_pairs);
229                         data.receive_pairs = NULL;
230                 }
231                 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
232                             authserver->port[i], timeout, retries);
233
234                 result = rc_send_server (&data, msg, NULL);
235         }
236
237         *received = data.receive_pairs;
238
239         return result;
240 }
241
242
243 /*
244  * Function: rc_acct_using_server
245  *
246  * Purpose: Builds an accounting request for port id client_port
247  *          with the value_pairs send.  You explicitly supply server list.
248  *
249  * Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled
250  *          in by this function, the rest has to be supplied.
251  */
252
253 int rc_acct_using_server(SERVER *acctserver,
254                          UINT4 client_port,
255                          VALUE_PAIR *send)
256 {
257         SEND_DATA       data;
258         VALUE_PAIR      *adt_vp;
259         UINT4           client_id;
260         int             result;
261         time_t          start_time, dtime;
262         char            msg[4096];
263         int             i;
264         int             timeout = rc_conf_int("radius_timeout");
265         int             retries = rc_conf_int("radius_retries");
266
267         data.send_pairs = send;
268         data.receive_pairs = NULL;
269
270         /*
271          * Fill in NAS-IP-Address
272          */
273
274         if ((client_id = rc_own_ipaddress()) == 0)
275                 return (ERROR_RC);
276
277         if (rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0, VENDOR_NONE) == NULL)
278                 return (ERROR_RC);
279
280         /*
281          * Fill in NAS-Port
282          */
283
284         if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
285                 return (ERROR_RC);
286
287         /*
288          * Fill in Acct-Delay-Time
289          */
290
291         dtime = 0;
292         if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, VENDOR_NONE)) == NULL)
293                 return (ERROR_RC);
294
295         start_time = time(NULL);
296         result = ERROR_RC;
297         for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
298                 ; i++)
299         {
300                 if (data.receive_pairs != NULL) {
301                         rc_avpair_free(data.receive_pairs);
302                         data.receive_pairs = NULL;
303                 }
304                 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
305                             acctserver->port[i], timeout, retries);
306
307                 dtime = time(NULL) - start_time;
308                 rc_avpair_assign(adt_vp, &dtime, 0);
309
310                 result = rc_send_server (&data, msg, NULL);
311         }
312
313         rc_avpair_free(data.receive_pairs);
314
315         return result;
316 }
317
318 /*
319  * Function: rc_acct
320  *
321  * Purpose: Builds an accounting request for port id client_port
322  *          with the value_pairs send
323  *
324  * Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled
325  *          in by this function, the rest has to be supplied.
326  */
327
328 int rc_acct(UINT4 client_port, VALUE_PAIR *send)
329 {
330     SERVER *acctserver = rc_conf_srv("acctserver");
331     if (!acctserver) return (ERROR_RC);
332
333     return rc_acct_using_server(acctserver, client_port, send);
334 }
335
336 /*
337  * Function: rc_acct_proxy
338  *
339  * Purpose: Builds an accounting request with the value_pairs send
340  *
341  */
342
343 int rc_acct_proxy(VALUE_PAIR *send)
344 {
345         SEND_DATA       data;
346         int             result;
347         char            msg[4096];
348         int             i;
349         SERVER          *acctserver = rc_conf_srv("authserver");
350         int             timeout = rc_conf_int("radius_timeout");
351         int             retries = rc_conf_int("radius_retries");
352
353         data.send_pairs = send;
354         data.receive_pairs = NULL;
355
356         result = ERROR_RC;
357         for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
358                 ; i++)
359         {
360                 if (data.receive_pairs != NULL) {
361                         rc_avpair_free(data.receive_pairs);
362                         data.receive_pairs = NULL;
363                 }
364                 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
365                             acctserver->port[i], timeout, retries);
366
367                 result = rc_send_server (&data, msg, NULL);
368         }
369
370         rc_avpair_free(data.receive_pairs);
371
372         return result;
373 }
374
375 /*
376  * Function: rc_check
377  *
378  * Purpose: ask the server hostname on the specified port for a
379  *          status message
380  *
381  */
382
383 int rc_check(char *host, unsigned short port, char *msg)
384 {
385         SEND_DATA       data;
386         int             result;
387         UINT4           client_id, service_type;
388         int             timeout = rc_conf_int("radius_timeout");
389         int             retries = rc_conf_int("radius_retries");
390
391         data.send_pairs = data.receive_pairs = NULL;
392
393         /*
394          * Fill in NAS-IP-Address, although it isn't neccessary
395          */
396
397         if ((client_id = rc_own_ipaddress()) == 0)
398                 return (ERROR_RC);
399
400         rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0, VENDOR_NONE);
401
402         /*
403          * Fill in Service-Type
404          */
405
406         service_type = PW_ADMINISTRATIVE;
407         rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE);
408
409         rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries);
410         result = rc_send_server (&data, msg, NULL);
411
412         rc_avpair_free(data.receive_pairs);
413
414         return result;
415 }