Deleted Added
full compact
radius.c (43401) radius.c (43693)
1/*
2 * Copyright 1999 Internet Business Solutions Ltd., Switzerland
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 9 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
1/*
2 * Copyright 1999 Internet Business Solutions Ltd., Switzerland
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 9 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: radius.c,v 1.1 1999/01/28 01:56:34 brian Exp $
26 * $Id: radius.c,v 1.2 1999/01/29 22:46:31 brian Exp $
27 *
28 */
29
30#include <sys/param.h>
31#include <netinet/in_systm.h>
32#include <netinet/in.h>
33#include <netinet/ip.h>
34#include <arpa/inet.h>
35#include <sys/un.h>
36
37#include <errno.h>
38#include <radlib.h>
27 *
28 */
29
30#include <sys/param.h>
31#include <netinet/in_systm.h>
32#include <netinet/in.h>
33#include <netinet/ip.h>
34#include <arpa/inet.h>
35#include <sys/un.h>
36
37#include <errno.h>
38#include <radlib.h>
39#include <signal.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <sys/time.h>
43#include <termios.h>
44
45#include "defs.h"
46#include "log.h"
47#include "descriptor.h"
48#include "prompt.h"
49#include "timer.h"
50#include "fsm.h"
51#include "iplist.h"
52#include "slcompress.h"
53#include "throughput.h"
54#include "lqr.h"
55#include "hdlc.h"
56#include "mbuf.h"
57#include "ipcp.h"
58#include "route.h"
59#include "command.h"
60#include "filter.h"
43#include <termios.h>
44
45#include "defs.h"
46#include "log.h"
47#include "descriptor.h"
48#include "prompt.h"
49#include "timer.h"
50#include "fsm.h"
51#include "iplist.h"
52#include "slcompress.h"
53#include "throughput.h"
54#include "lqr.h"
55#include "hdlc.h"
56#include "mbuf.h"
57#include "ipcp.h"
58#include "route.h"
59#include "command.h"
60#include "filter.h"
61#include "server.h"
62#include "lcp.h"
63#include "ccp.h"
64#include "link.h"
65#include "mp.h"
66#include "radius.h"
61#include "lcp.h"
62#include "ccp.h"
63#include "link.h"
64#include "mp.h"
65#include "radius.h"
66#include "auth.h"
67#include "async.h"
68#include "physical.h"
69#include "chat.h"
70#include "cbcp.h"
71#include "chap.h"
72#include "datalink.h"
67#include "bundle.h"
68
73#include "bundle.h"
74
69void
70radius_Init(struct radius *r)
75/*
76 * rad_continue_send_request() has given us `got' (non-zero). Deal with it.
77 */
78static void
79radius_Process(struct radius *r, int got)
71{
80{
72 r->valid = 0;
73 *r->cfg.file = '\0';;
74}
75
76void
77radius_Destroy(struct radius *r)
78{
79 r->valid = 0;
80 route_DeleteAll(&r->routes);
81}
82
83int
84radius_Authenticate(struct radius *r, struct bundle *bundle, const char *name,
85 const char *key, const char *challenge)
86{
87 struct rad_handle *h;
88 sigset_t alrm, prevset;
89 const void *data;
90 int got, len, argc, addrs;
91 char *argv[MAXARGS], *nuke;
81 char *argv[MAXARGS], *nuke;
82 struct bundle *bundle;
83 int len, argc, addrs;
92 struct in_range dest;
93 struct in_addr gw;
84 struct in_range dest;
85 struct in_addr gw;
86 const void *data;
94
87
95 radius_Destroy(r);
88 r->cx.fd = -1; /* Stop select()ing */
96
89
97 if (!*r->cfg.file)
98 return 0;
99
100 if ((h = rad_open()) == NULL) {
101 log_Printf(LogERROR, "rad_open: %s\n", strerror(errno));
102 return 0;
103 }
104
105 if (rad_config(h, r->cfg.file) != 0) {
106 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(h));
107 rad_close(h);
108 return 0;
109 }
110
111 if (rad_create_request(h, RAD_ACCESS_REQUEST) != 0) {
112 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(h));
113 rad_close(h);
114 return 0;
115 }
116
117 if (rad_put_string(h, RAD_USER_NAME, name) != 0 ||
118 rad_put_int(h, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
119 rad_put_int(h, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
120 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(h));
121 rad_close(h);
122 return 0;
123 }
124
125 if (challenge != NULL) { /* CHAP */
126 if (rad_put_string(h, RAD_CHAP_PASSWORD, key) != 0 ||
127 rad_put_string(h, RAD_CHAP_CHALLENGE, challenge) != 0) {
128 log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", rad_strerror(h));
129 rad_close(h);
130 return 0;
131 }
132 } else if (rad_put_string(h, RAD_USER_PASSWORD, key) != 0) { /* PAP */
133 /* We're talking PAP */
134 log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(h));
135 rad_close(h);
136 return 0;
137 }
138
139 /*
140 * Having to do this is bad news. The right way is to grab the
141 * descriptor that rad_send_request() selects on and add it to
142 * our own selection list (making a full ``struct descriptor''),
143 * then to ``continue'' the call when the descriptor is ready.
144 * This requires altering libradius....
145 */
146 sigemptyset(&alrm);
147 sigaddset(&alrm, SIGALRM);
148 sigprocmask(SIG_BLOCK, &alrm, &prevset);
149 got = rad_send_request(h);
150 sigprocmask(SIG_SETMASK, &prevset, NULL);
151
152 switch (got) {
153 case RAD_ACCESS_ACCEPT:
90 switch (got) {
91 case RAD_ACCESS_ACCEPT:
92 log_Printf(LogPHASE, "Radius: ACCEPT received\n");
154 break;
155
93 break;
94
95 case RAD_ACCESS_REJECT:
96 log_Printf(LogPHASE, "Radius: REJECT received\n");
97 auth_Failure(r->cx.auth);
98 rad_close(r->cx.rad);
99 return;
100
156 case RAD_ACCESS_CHALLENGE:
157 /* we can't deal with this (for now) ! */
101 case RAD_ACCESS_CHALLENGE:
102 /* we can't deal with this (for now) ! */
158 log_Printf(LogPHASE, "Can't handle radius CHALLENGEs !\n");
159 rad_close(h);
160 return 0;
103 log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n");
104 auth_Failure(r->cx.auth);
105 rad_close(r->cx.rad);
106 return;
161
162 case -1:
107
108 case -1:
163 log_Printf(LogPHASE, "radius: %s\n", rad_strerror(h));
164 rad_close(h);
165 return 0;
109 log_Printf(LogPHASE, "radius: %s\n", rad_strerror(r->cx.rad));
110 auth_Failure(r->cx.auth);
111 rad_close(r->cx.rad);
112 return;
166
167 default:
168 log_Printf(LogERROR, "rad_send_request: Failed %d: %s\n",
113
114 default:
115 log_Printf(LogERROR, "rad_send_request: Failed %d: %s\n",
169 got, rad_strerror(h));
170 rad_close(h);
171 return 0;
172
173 case RAD_ACCESS_REJECT:
174 log_Printf(LogPHASE, "radius: Rejected !\n");
175 rad_close(h);
176 return 0;
116 got, rad_strerror(r->cx.rad));
117 auth_Failure(r->cx.auth);
118 rad_close(r->cx.rad);
119 return;
177 }
178
179 /* So we've been accepted ! Let's see what we've got in our reply :-I */
180 r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
181 r->mtu = 0;
182 r->vj = 0;
120 }
121
122 /* So we've been accepted ! Let's see what we've got in our reply :-I */
123 r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
124 r->mtu = 0;
125 r->vj = 0;
183 while ((got = rad_get_attr(h, &data, &len)) > 0) {
126 while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
184 switch (got) {
185 case RAD_FRAMED_IP_ADDRESS:
186 r->ip = rad_cvt_addr(data);
127 switch (got) {
128 case RAD_FRAMED_IP_ADDRESS:
129 r->ip = rad_cvt_addr(data);
187 log_Printf(LogDEBUG, "radius: Got IP %s\n", inet_ntoa(r->ip));
130 log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip));
188 break;
189
190 case RAD_FRAMED_IP_NETMASK:
191 r->mask = rad_cvt_addr(data);
131 break;
132
133 case RAD_FRAMED_IP_NETMASK:
134 r->mask = rad_cvt_addr(data);
192 log_Printf(LogDEBUG, "radius: Got MASK %s\n", inet_ntoa(r->mask));
135 log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask));
193 break;
194
195 case RAD_FRAMED_MTU:
196 r->mtu = rad_cvt_int(data);
136 break;
137
138 case RAD_FRAMED_MTU:
139 r->mtu = rad_cvt_int(data);
197 log_Printf(LogDEBUG, "radius: Got MTU %lu\n", r->mtu);
140 log_Printf(LogPHASE, " MTU %lu\n", r->mtu);
198 break;
199
200 case RAD_FRAMED_ROUTING:
201 /* Disabled for now - should we automatically set up some filters ? */
202 /* rad_cvt_int(data); */
203 /* bit 1 = Send routing packets */
204 /* bit 2 = Receive routing packets */
205 break;
206
207 case RAD_FRAMED_COMPRESSION:
208 r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
141 break;
142
143 case RAD_FRAMED_ROUTING:
144 /* Disabled for now - should we automatically set up some filters ? */
145 /* rad_cvt_int(data); */
146 /* bit 1 = Send routing packets */
147 /* bit 2 = Receive routing packets */
148 break;
149
150 case RAD_FRAMED_COMPRESSION:
151 r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
209 log_Printf(LogDEBUG, "radius: Got VJ %sabled\n", r->vj ? "en" : "dis");
152 log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis");
210 break;
211
212 case RAD_FRAMED_ROUTE:
213 /*
214 * We expect a string of the format ``dest[/bits] gw [metrics]''
215 * Any specified metrics are ignored. MYADDR and HISADDR are
216 * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
217 * as ``HISADDR''.
218 */
219
220 if ((nuke = rad_cvt_string(data, len)) == NULL) {
153 break;
154
155 case RAD_FRAMED_ROUTE:
156 /*
157 * We expect a string of the format ``dest[/bits] gw [metrics]''
158 * Any specified metrics are ignored. MYADDR and HISADDR are
159 * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
160 * as ``HISADDR''.
161 */
162
163 if ((nuke = rad_cvt_string(data, len)) == NULL) {
221 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(h));
222 rad_close(h);
223 return 0;
164 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
165 rad_close(r->cx.rad);
166 return;
224 }
225
167 }
168
169 log_Printf(LogPHASE, " Route: %s\n", nuke);
170 bundle = r->cx.auth->physical->dl->bundle;
226 dest.ipaddr.s_addr = dest.mask.s_addr = INADDR_ANY;
227 dest.width = 0;
228 argc = command_Interpret(nuke, strlen(nuke), argv);
229 if (argc < 2)
230 log_Printf(LogWARN, "radius: %s: Invalid route\n",
231 argc == 1 ? argv[0] : "\"\"");
232 else if ((strcasecmp(argv[0], "default") != 0 &&
233 !ParseAddr(&bundle->ncp.ipcp, argv[0], &dest.ipaddr,

--- 21 unchanged lines hidden (view full) ---

255 route_Add(&r->routes, addrs, dest.ipaddr, dest.mask, gw);
256 }
257 free(nuke);
258 break;
259 }
260 }
261
262 if (got == -1) {
171 dest.ipaddr.s_addr = dest.mask.s_addr = INADDR_ANY;
172 dest.width = 0;
173 argc = command_Interpret(nuke, strlen(nuke), argv);
174 if (argc < 2)
175 log_Printf(LogWARN, "radius: %s: Invalid route\n",
176 argc == 1 ? argv[0] : "\"\"");
177 else if ((strcasecmp(argv[0], "default") != 0 &&
178 !ParseAddr(&bundle->ncp.ipcp, argv[0], &dest.ipaddr,

--- 21 unchanged lines hidden (view full) ---

200 route_Add(&r->routes, addrs, dest.ipaddr, dest.mask, gw);
201 }
202 free(nuke);
203 break;
204 }
205 }
206
207 if (got == -1) {
263 log_Printf(LogERROR, "rad_get_attr: %s\n", rad_strerror(h));
264 rad_close(h);
265 return 0;
208 log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
209 rad_strerror(r->cx.rad));
210 auth_Failure(r->cx.auth);
211 rad_close(r->cx.rad);
212 } else {
213 r->valid = 1;
214 auth_Success(r->cx.auth);
215 rad_close(r->cx.rad);
266 }
216 }
217}
267
218
268 rad_close(h);
269 r->valid = 1;
270 log_Printf(LogPHASE, "radius: SUCCESS\n");
219/*
220 * We've either timed out or select()ed on the read descriptor
221 */
222static void
223radius_Continue(struct radius *r, int sel)
224{
225 struct timeval tv;
226 int got;
271
227
272 return 1;
228 timer_Stop(&r->cx.timer);
229 if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) {
230 log_Printf(LogPHASE, "Radius: Request re-sent\n");
231 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
232 timer_Start(&r->cx.timer);
233 return;
234 }
235
236 radius_Process(r, got);
273}
274
237}
238
239/*
240 * Time to call rad_continue_send_request() - timed out.
241 */
242static void
243radius_Timeout(void *v)
244{
245 radius_Continue((struct radius *)v, 0);
246}
247
248/*
249 * Time to call rad_continue_send_request() - something to read.
250 */
251static void
252radius_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
253{
254 radius_Continue(descriptor2radius(d), 1);
255}
256
257/*
258 * Behave as a struct descriptor (descriptor.h)
259 */
260static int
261radius_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
262{
263 struct radius *rad = descriptor2radius(d);
264
265 if (r && rad->cx.fd != -1) {
266 FD_SET(rad->cx.fd, r);
267 if (*n < rad->cx.fd + 1)
268 *n = rad->cx.fd + 1;
269 log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd);
270 return 1;
271 }
272
273 return 0;
274}
275
276/*
277 * Behave as a struct descriptor (descriptor.h)
278 */
279static int
280radius_IsSet(struct descriptor *d, const fd_set *fdset)
281{
282 struct radius *r = descriptor2radius(d);
283
284 return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset);
285}
286
287/*
288 * Behave as a struct descriptor (descriptor.h)
289 */
290static int
291radius_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
292{
293 /* We never want to write here ! */
294 log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n");
295 return 0;
296}
297
298/*
299 * Initialise ourselves
300 */
275void
301void
302radius_Init(struct radius *r)
303{
304 r->valid = 0;
305 r->cx.fd = -1;
306 *r->cfg.file = '\0';;
307 r->desc.type = RADIUS_DESCRIPTOR;
308 r->desc.UpdateSet = radius_UpdateSet;
309 r->desc.IsSet = radius_IsSet;
310 r->desc.Read = radius_Read;
311 r->desc.Write = radius_Write;
312 memset(&r->cx.timer, '\0', sizeof r->cx.timer);
313}
314
315/*
316 * Forget everything and go back to initialised state.
317 */
318void
319radius_Destroy(struct radius *r)
320{
321 r->valid = 0;
322 timer_Stop(&r->cx.timer);
323 route_DeleteAll(&r->routes);
324 if (r->cx.fd != -1) {
325 r->cx.fd = -1;
326 rad_close(r->cx.rad);
327 }
328}
329
330/*
331 * Start an authentication request to the RADIUS server.
332 */
333void
334radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
335 const char *key, const char *challenge)
336{
337 struct timeval tv;
338 int got;
339
340 if (!*r->cfg.file)
341 return;
342
343 if (r->cx.fd != -1)
344 /*
345 * We assume that our name/key/challenge is the same as last time,
346 * and just continue to wait for the RADIUS server(s).
347 */
348 return;
349
350 radius_Destroy(r);
351
352 if ((r->cx.rad = rad_open()) == NULL) {
353 log_Printf(LogERROR, "rad_open: %s\n", strerror(errno));
354 return;
355 }
356
357 if (rad_config(r->cx.rad, r->cfg.file) != 0) {
358 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
359 rad_close(r->cx.rad);
360 return;
361 }
362
363 if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) {
364 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
365 rad_close(r->cx.rad);
366 return;
367 }
368
369 if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 ||
370 rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
371 rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) {
372 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
373 rad_close(r->cx.rad);
374 return;
375 }
376
377 if (challenge != NULL) {
378 /* We're talking CHAP */
379 if (rad_put_string(r->cx.rad, RAD_CHAP_PASSWORD, key) != 0 ||
380 rad_put_string(r->cx.rad, RAD_CHAP_CHALLENGE, challenge) != 0) {
381 log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
382 rad_strerror(r->cx.rad));
383 rad_close(r->cx.rad);
384 return;
385 }
386 } else if (rad_put_string(r->cx.rad, RAD_USER_PASSWORD, key) != 0) {
387 /* We're talking PAP */
388 log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad));
389 rad_close(r->cx.rad);
390 return;
391 }
392
393 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
394 radius_Process(r, got);
395 else {
396 log_Printf(LogPHASE, "Radius: Request sent\n");
397 log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
398 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
399 r->cx.timer.func = radius_Timeout;
400 r->cx.timer.name = "radius";
401 r->cx.timer.arg = r;
402 r->cx.auth = authp;
403 timer_Start(&r->cx.timer);
404 }
405}
406
407/*
408 * How do things look at the moment ?
409 */
410void
276radius_Show(struct radius *r, struct prompt *p)
277{
278 prompt_Printf(p, " Radius config: %s", *r->cfg.file ? r->cfg.file : "none");
279 if (r->valid) {
280 prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip));
281 prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask));
282 prompt_Printf(p, " MTU: %lu\n", r->mtu);
283 prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis");
284 if (r->routes)
285 route_ShowSticky(p, r->routes, " Routes", 16);
286 } else
287 prompt_Printf(p, " (not authenticated)\n");
288}
411radius_Show(struct radius *r, struct prompt *p)
412{
413 prompt_Printf(p, " Radius config: %s", *r->cfg.file ? r->cfg.file : "none");
414 if (r->valid) {
415 prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip));
416 prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask));
417 prompt_Printf(p, " MTU: %lu\n", r->mtu);
418 prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis");
419 if (r->routes)
420 route_ShowSticky(p, r->routes, " Routes", 16);
421 } else
422 prompt_Printf(p, " (not authenticated)\n");
423}