]> git.ozlabs.org Git - ppp.git/blob - pppd/plugins/radius/radiusclient/lib/buildreq.c
Send NAS-Identifier attribute instead of NAS-IP-Address, if configured.
[ppp.git] / pppd / plugins / radius / radiusclient / lib / buildreq.c
1 /*
2  * $Id: buildreq.c,v 1.4 2002/10/01 09:51:01 fcusack 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_get_nas_id
20  *
21  * Purpose: fills in NAS-Identifier or NAS-IP-Address in request
22  *
23  */
24
25 int rc_get_nas_id(VALUE_PAIR **sendpairs)
26 {
27         UINT4           client_id;
28         char *nasid;
29
30         nasid = rc_conf_str("nas_identifier");
31         if (strlen(nasid)) {
32                 /*
33                  * Fill in NAS-Identifier
34                  */
35                 if (rc_avpair_add(sendpairs, PW_NAS_IDENTIFIER, nasid, 0,
36                                   VENDOR_NONE) == NULL)
37                         return (ERROR_RC);
38
39                 return (OK_RC);
40           
41         } else {
42                 /*
43                  * Fill in NAS-IP-Address
44                  */
45                 if ((client_id = rc_own_ipaddress()) == 0)
46                         return (ERROR_RC);
47
48                 if (rc_avpair_add(sendpairs, PW_NAS_IP_ADDRESS, &client_id,
49                                   0, VENDOR_NONE) == NULL)
50                         return (ERROR_RC);
51         }
52
53         return (OK_RC);
54 }
55
56 /*
57  * Function: rc_buildreq
58  *
59  * Purpose: builds a skeleton RADIUS request using information from the
60  *          config file.
61  *
62  */
63
64 void rc_buildreq(SEND_DATA *data, int code, char *server, unsigned short port,
65                  int timeout, int retries)
66 {
67         data->server = server;
68         data->svc_port = port;
69         data->seq_nbr = rc_get_seqnbr();
70         data->timeout = timeout;
71         data->retries = retries;
72         data->code = code;
73 }
74
75 /*
76  * Function: rc_guess_seqnbr
77  *
78  * Purpose: return a random sequence number
79  *
80  */
81
82 static unsigned char rc_guess_seqnbr(void)
83 {
84         srandom((unsigned int)(time(NULL)+getpid()));
85         return (unsigned char)(random() & UCHAR_MAX);
86 }
87
88 /*
89  * Function: rc_get_seqnbr
90  *
91  * Purpose: generate a sequence number
92  *
93  */
94
95 unsigned char rc_get_seqnbr(void)
96 {
97         FILE *sf;
98         int tries = 1;
99         int seq_nbr;
100         char *seqfile = rc_conf_str("seqfile");
101
102         if ((sf = fopen(seqfile, "a+")) == NULL)
103         {
104                 rc_log(LOG_ERR,"rc_get_seqnbr: couldn't open sequence file %s: %s", seqfile, strerror(errno));
105                 /* well, so guess a sequence number */
106                 return rc_guess_seqnbr();
107         }
108
109         while (do_lock_exclusive(fileno(sf))!= 0)
110         {
111                 if (errno != EWOULDBLOCK) {
112                         rc_log(LOG_ERR, "rc_get_seqnbr: flock failure: %s: %s", seqfile, strerror(errno));
113                         fclose(sf);
114                         return rc_guess_seqnbr();
115                 }
116                 tries++;
117                 if (tries <= 10)
118                         rc_mdelay(500);
119                 else
120                         break;
121         }
122
123         if (tries > 10) {
124                 rc_log(LOG_ERR,"rc_get_seqnbr: couldn't get lock after %d tries: %s", tries-1, seqfile);
125                 fclose(sf);
126                 return rc_guess_seqnbr();
127         }
128
129         rewind(sf);
130         if (fscanf(sf, "%d", &seq_nbr) != 1) {
131                 rc_log(LOG_ERR,"rc_get_seqnbr: fscanf failure: %s", seqfile);
132                 seq_nbr = rc_guess_seqnbr();
133         }
134
135         rewind(sf);
136         ftruncate(fileno(sf),0);
137         fprintf(sf,"%d\n", (seq_nbr+1) & UCHAR_MAX);
138
139         fflush(sf); /* fflush because a process may read it between the do_unlock and fclose */
140
141         if (do_unlock(fileno(sf)) != 0)
142                 rc_log(LOG_ERR, "rc_get_seqnbr: couldn't release lock on %s: %s", seqfile, strerror(errno));
143
144         fclose(sf);
145
146         return (unsigned char)seq_nbr;
147 }
148
149 /*
150  * Function: rc_auth
151  *
152  * Purpose: Builds an authentication request for port id client_port
153  *          with the value_pairs send and submits it to a server
154  *
155  * Returns: received value_pairs in received, messages from the server in msg
156  *          and 0 on success, negative on failure as return value
157  *
158  */
159
160 int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received,
161             char *msg, REQUEST_INFO *info)
162 {
163     SERVER *authserver = rc_conf_srv("authserver");
164
165     if (!authserver) {
166         return (ERROR_RC);
167     }
168     return rc_auth_using_server(authserver, client_port, send, received,
169                                 msg, info);
170 }
171
172 /*
173  * Function: rc_auth_using_server
174  *
175  * Purpose: Builds an authentication request for port id client_port
176  *          with the value_pairs send and submits it to a server.  You
177  *          explicitly supply a server list.
178  *
179  * Returns: received value_pairs in received, messages from the server in msg
180  *          and 0 on success, negative on failure as return value
181  *
182  */
183
184 int rc_auth_using_server(SERVER *authserver,
185                          UINT4 client_port,
186                          VALUE_PAIR *send,
187                          VALUE_PAIR **received,
188                          char *msg, REQUEST_INFO *info)
189 {
190         SEND_DATA       data;
191         int             result;
192         int             i;
193         int             timeout = rc_conf_int("radius_timeout");
194         int             retries = rc_conf_int("radius_retries");
195
196         data.send_pairs = send;
197         data.receive_pairs = NULL;
198
199         /*
200          * Fill in NAS-IP-Address or NAS-Identifier
201          */
202
203         if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
204             return (ERROR_RC);
205
206         /*
207          * Fill in NAS-Port
208          */
209
210         if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
211                 return (ERROR_RC);
212
213         result = ERROR_RC;
214         for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
215                 ; i++)
216         {
217                 if (data.receive_pairs != NULL) {
218                         rc_avpair_free(data.receive_pairs);
219                         data.receive_pairs = NULL;
220                 }
221                 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
222                             authserver->port[i], timeout, retries);
223
224                 result = rc_send_server (&data, msg, info);
225         }
226
227         *received = data.receive_pairs;
228
229         return result;
230 }
231
232 /*
233  * Function: rc_auth_proxy
234  *
235  * Purpose: Builds an authentication request
236  *          with the value_pairs send and submits it to a server.
237  *          Works for a proxy; does not add IP address, and does
238  *          does not rely on config file.
239  *
240  * Returns: received value_pairs in received, messages from the server in msg
241  *          and 0 on success, negative on failure as return value
242  *
243  */
244
245 int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
246 {
247         SEND_DATA       data;
248         int             result;
249         int             i;
250         SERVER          *authserver = rc_conf_srv("authserver");
251         int             timeout = rc_conf_int("radius_timeout");
252         int             retries = rc_conf_int("radius_retries");
253
254         data.send_pairs = send;
255         data.receive_pairs = NULL;
256
257         result = ERROR_RC;
258         for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC)
259                 ; i++)
260         {
261                 if (data.receive_pairs != NULL) {
262                         rc_avpair_free(data.receive_pairs);
263                         data.receive_pairs = NULL;
264                 }
265                 rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i],
266                             authserver->port[i], timeout, retries);
267
268                 result = rc_send_server (&data, msg, NULL);
269         }
270
271         *received = data.receive_pairs;
272
273         return result;
274 }
275
276
277 /*
278  * Function: rc_acct_using_server
279  *
280  * Purpose: Builds an accounting request for port id client_port
281  *          with the value_pairs send.  You explicitly supply server list.
282  *
283  * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
284  *          filled in by this function, the rest has to be supplied.
285  */
286
287 int rc_acct_using_server(SERVER *acctserver,
288                          UINT4 client_port,
289                          VALUE_PAIR *send)
290 {
291         SEND_DATA       data;
292         VALUE_PAIR      *adt_vp;
293         int             result;
294         time_t          start_time, dtime;
295         char            msg[4096];
296         int             i;
297         int             timeout = rc_conf_int("radius_timeout");
298         int             retries = rc_conf_int("radius_retries");
299
300         data.send_pairs = send;
301         data.receive_pairs = NULL;
302
303         /*
304          * Fill in NAS-IP-Address or NAS-Identifier
305          */
306
307         if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
308             return (ERROR_RC);
309
310         /*
311          * Fill in NAS-Port
312          */
313
314         if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL)
315                 return (ERROR_RC);
316
317         /*
318          * Fill in Acct-Delay-Time
319          */
320
321         dtime = 0;
322         if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, VENDOR_NONE)) == NULL)
323                 return (ERROR_RC);
324
325         start_time = time(NULL);
326         result = ERROR_RC;
327         for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
328                 ; i++)
329         {
330                 if (data.receive_pairs != NULL) {
331                         rc_avpair_free(data.receive_pairs);
332                         data.receive_pairs = NULL;
333                 }
334                 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
335                             acctserver->port[i], timeout, retries);
336
337                 dtime = time(NULL) - start_time;
338                 rc_avpair_assign(adt_vp, &dtime, 0);
339
340                 result = rc_send_server (&data, msg, NULL);
341         }
342
343         rc_avpair_free(data.receive_pairs);
344
345         return result;
346 }
347
348 /*
349  * Function: rc_acct
350  *
351  * Purpose: Builds an accounting request for port id client_port
352  *          with the value_pairs send
353  *
354  * Remarks: NAS-Identifier/NAS-IP-Address, NAS-Port and Acct-Delay-Time get
355  *          filled in by this function, the rest has to be supplied.
356  */
357
358 int rc_acct(UINT4 client_port, VALUE_PAIR *send)
359 {
360     SERVER *acctserver = rc_conf_srv("acctserver");
361     if (!acctserver) return (ERROR_RC);
362
363     return rc_acct_using_server(acctserver, client_port, send);
364 }
365
366 /*
367  * Function: rc_acct_proxy
368  *
369  * Purpose: Builds an accounting request with the value_pairs send
370  *
371  */
372
373 int rc_acct_proxy(VALUE_PAIR *send)
374 {
375         SEND_DATA       data;
376         int             result;
377         char            msg[4096];
378         int             i;
379         SERVER          *acctserver = rc_conf_srv("authserver");
380         int             timeout = rc_conf_int("radius_timeout");
381         int             retries = rc_conf_int("radius_retries");
382
383         data.send_pairs = send;
384         data.receive_pairs = NULL;
385
386         result = ERROR_RC;
387         for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC)
388                 ; i++)
389         {
390                 if (data.receive_pairs != NULL) {
391                         rc_avpair_free(data.receive_pairs);
392                         data.receive_pairs = NULL;
393                 }
394                 rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i],
395                             acctserver->port[i], timeout, retries);
396
397                 result = rc_send_server (&data, msg, NULL);
398         }
399
400         rc_avpair_free(data.receive_pairs);
401
402         return result;
403 }
404
405 /*
406  * Function: rc_check
407  *
408  * Purpose: ask the server hostname on the specified port for a
409  *          status message
410  *
411  */
412
413 int rc_check(char *host, unsigned short port, char *msg)
414 {
415         SEND_DATA       data;
416         int             result;
417         UINT4           service_type;
418         int             timeout = rc_conf_int("radius_timeout");
419         int             retries = rc_conf_int("radius_retries");
420
421         data.send_pairs = data.receive_pairs = NULL;
422
423         /*
424          * Fill in NAS-IP-Address or NAS-Identifier,
425          * although it isn't neccessary
426          */
427
428         if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC)
429             return (ERROR_RC);
430
431         /*
432          * Fill in Service-Type
433          */
434
435         service_type = PW_ADMINISTRATIVE;
436         rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE);
437
438         rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries);
439         result = rc_send_server (&data, msg, NULL);
440
441         rc_avpair_free(data.receive_pairs);
442
443         return result;
444 }