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