* Update cli callbacks to work with libcli 1.6.
[l2tpns.git] / radius.c
1 // L2TPNS Radius Stuff
2
3 char const *cvs_id_radius = "$Id: radius.c,v 1.5 2004/06/28 02:43:13 fred_nerk Exp $";
4
5 #include <time.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <malloc.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <arpa/inet.h>
13 #include <ctype.h>
14 #include <netinet/in.h>
15 #include "md5.h"
16 #include "constants.h"
17 #include "l2tpns.h"
18 #include "plugin.h"
19 #include "util.h"
20
21 extern radiust *radius;
22 extern sessiont *session;
23 extern tunnelt *tunnel;
24 extern u32 sessionid;
25 extern struct configt *config;
26 extern int *radfds;
27
28 const char *radius_state(int state)
29 {
30 static char *tmp = NULL;
31 int i;
32 for (i = 0; radius_states[i]; i++)
33 if (i == state) return radius_states[i];
34
35 if (tmp == NULL) tmp = (char *)calloc(64, 1);
36 sprintf(tmp, "%d", state);
37 return tmp;
38 }
39
40 // Set up socket for radius requests
41 void initrad(void)
42 {
43 int i;
44 log(3, 0, 0, 0, "Creating %d sockets for RADIUS queries\n", config->num_radfds);
45 radfds = calloc(sizeof(int), config->num_radfds);
46 for (i = 0; i < config->num_radfds; i++)
47 {
48 int flags;
49 if (!radfds[i]) radfds[i] = socket(AF_INET, SOCK_DGRAM, UDP);
50 flags = fcntl(radfds[i], F_GETFL, 0);
51 fcntl(radfds[i], F_SETFL, flags | O_NONBLOCK);
52 }
53 }
54
55 void radiusclear(u16 r, sessionidt s)
56 {
57 if (s) session[s].radius = 0;
58 memset(&radius[r], 0, sizeof(radius[r])); // radius[r].state = RADIUSNULL;
59 }
60
61
62 static u16 new_radius()
63 {
64 int count;
65 static u32 next_radius_id = 0;
66
67 for (count = MAXRADIUS; count > 0 ; --count)
68 {
69 ++next_radius_id; // Find the next ID to check.
70 if (next_radius_id >= MAXRADIUS)
71 next_radius_id = 1;
72
73 if (radius[next_radius_id].state == RADIUSNULL)
74 {
75 return next_radius_id;
76 }
77
78 }
79 log(0, 0, 0, 0, "Can't find a free radius session! This is very bad!\n");
80 return 0;
81 }
82
83 u16 radiusnew(sessionidt s)
84 {
85 u16 r;
86 if (!(r = new_radius()))
87 {
88 log(1, 0, s, session[s].tunnel, "No free RADIUS sessions\n");
89 STAT(radius_overflow);
90 return 0;
91 };
92 memset(&radius[r], 0, sizeof(radius[r]));
93 session[s].radius = r;
94 radius[r].session = s;
95 radius[r].state = RADIUSWAIT;
96 radius[r].retry = TIME + 1200; // Wait at least 120 seconds to re-claim this.
97
98 log(3,0,s, session[s].tunnel, "Allocated radius %d\n", r);
99 return r;
100 }
101
102 // Send a RADIUS request
103 void radiussend(u16 r, u8 state)
104 {
105 struct sockaddr_in addr;
106 u8 b[4096]; // RADIUS packet
107 char pass[129];
108 int pl;
109 u8 *p;
110 sessionidt s;
111
112 CSTAT(call_radiussend);
113
114 s = radius[r].session;
115 if (!config->numradiusservers)
116 {
117 log(0, 0, s, session[s].tunnel, "No RADIUS servers\n");
118 return;
119 }
120 if (!*config->radiussecret)
121 {
122 log(0, 0, s, session[s].tunnel, "No RADIUS secret\n");
123 return;
124 }
125
126 if (state != RADIUSAUTH && !config->radius_accounting)
127 {
128 // Radius accounting is turned off
129 radiusclear(r, s);
130 return;
131 }
132
133 if (radius[r].state != state)
134 radius[r].try = 0;
135 radius[r].state = state;
136 radius[r].retry = backoff(radius[r].try++);
137 log(4, 0, s, session[s].tunnel, "Send RADIUS id %d sock %d state %s try %d\n",
138 r >> RADIUS_SHIFT, r & RADIUS_MASK,
139 radius_state(radius[r].state), radius[r].try);
140 if (radius[r].try > config->numradiusservers * 2)
141 {
142 if (s)
143 {
144 if (state == RADIUSAUTH)
145 sessionshutdown(s, "RADIUS timeout");
146 else
147 {
148 log(1, 0, s, session[s].tunnel, "RADIUS timeout, but in state %s so don't timeout session\n",
149 radius_states[state]);
150 radiusclear(r, s);
151 }
152 STAT(radius_timeout);
153 }
154 else
155 {
156 STAT(radius_retries);
157 radius[r].state = RADIUSWAIT;
158 radius[r].retry = 100;
159 }
160 return ;
161 }
162 // contruct RADIUS access request
163 switch (state)
164 {
165 case RADIUSAUTH:
166 b[0] = 1; // access request
167 break;
168 case RADIUSSTART:
169 case RADIUSSTOP:
170 b[0] = 4; // accounting request
171 break;
172 default:
173 log(0, 0, 0, 0, "Unknown radius state %d\n", state);
174 }
175 b[1] = r >> RADIUS_SHIFT; // identifier
176 memcpy(b + 4, radius[r].auth, 16);
177 p = b + 20;
178 if (s)
179 {
180 *p = 1; // user name
181 p[1] = strlen(session[s].user) + 2;
182 strcpy(p + 2, session[s].user);
183 p += p[1];
184 }
185 if (state == RADIUSAUTH)
186 {
187 if (radius[r].chap)
188 {
189 *p = 3; // CHAP password
190 p[1] = 19; // length
191 p[2] = radius[r].id; // ID
192 memcpy(p + 3, radius[r].pass, 16); // response from CHAP request
193 p += p[1];
194 *p = 60; // CHAP Challenge
195 p[1] = 18; // length
196 memcpy(p + 2, radius[r].auth, 16);
197 p += p[1];
198 }
199 else
200 {
201 strcpy(pass, radius[r].pass);
202 pl = strlen(pass);
203 while (pl & 15)
204 pass[pl++] = 0; // pad
205 if (pl)
206 { // encrypt
207 hasht hash;
208 int p = 0;
209 while (p < pl)
210 {
211 MD5_CTX ctx;
212 MD5Init(&ctx);
213 MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
214 if (p)
215 MD5Update(&ctx, pass + p - 16, 16);
216 else
217 MD5Update(&ctx, radius[r].auth, 16);
218 MD5Final(hash, &ctx);
219 do
220 {
221 pass[p] ^= hash[p & 15];
222 p++;
223 }
224 while (p & 15);
225 }
226 }
227 *p = 2; // password
228 p[1] = pl + 2;
229 if (pl)
230 memcpy(p + 2, pass, pl);
231 p += p[1];
232 }
233 }
234 else if (state == RADIUSSTART || state == RADIUSSTOP)
235 { // accounting
236 *p = 40; // accounting type
237 p[1] = 6;
238 *(u32 *) (p + 2) = htonl((state == RADIUSSTART) ? 1 : 2);
239 p += p[1];
240 if (s)
241 {
242 *p = 44; // session ID
243 p[1] = 18;
244 sprintf(p + 2, "%08X%08X", session[s].id, session[s].opened);
245 p += p[1];
246 if (state == RADIUSSTOP)
247 { // stop
248 *p = 42; // input octets
249 p[1] = 6;
250 *(u32 *) (p + 2) = htonl(session[s].cin);
251 p += p[1];
252 *p = 43; // output octets
253 p[1] = 6;
254 *(u32 *) (p + 2) = htonl(session[s].cout);
255 p += p[1];
256 *p = 46; // session time
257 p[1] = 6;
258 *(u32 *) (p + 2) = htonl(time(NULL) - session[s].opened);
259 p += p[1];
260 *p = 47; // input packets
261 p[1] = 6;
262 *(u32 *) (p + 2) = htonl(session[s].pin);
263 p += p[1];
264 *p = 48; // output spackets
265 p[1] = 6;
266 *(u32 *) (p + 2) = htonl(session[s].pout);
267 p += p[1];
268 }
269 else
270 { // start
271 *p = 41; // delay
272 p[1] = 6;
273 *(u32 *) (p + 2) = htonl(time(NULL) - session[s].opened);
274 p += p[1];
275 }
276 }
277 }
278 if (s)
279 {
280 *p = 5; // NAS-Port
281 p[1] = 6;
282 *(u32 *) (p + 2) = htonl(s);
283 p += p[1];
284 }
285 if (s && session[s].ip)
286 {
287 *p = 8; // Framed-IP-Address
288 p[1] = 6;
289 *(u32 *) (p + 2) = htonl(session[s].ip);
290 p += p[1];
291 }
292 if (*session[s].called)
293 {
294 *p = 30; // called
295 p[1] = strlen(session[s].called) + 2;
296 strcpy(p + 2, session[s].called);
297 p += p[1];
298 }
299 if (*radius[r].calling)
300 {
301 *p = 31; // calling
302 p[1] = strlen(radius[r].calling) + 2;
303 strcpy(p + 2, radius[r].calling);
304 p += p[1];
305 }
306 else if (*session[s].calling)
307 {
308 *p = 31; // calling
309 p[1] = strlen(session[s].calling) + 2;
310 strcpy(p + 2, session[s].calling);
311 p += p[1];
312 }
313 // NAS-IP-Address
314 *p = 4;
315 p[1] = 6;
316 *(u32 *)(p + 2) = config->bind_address;
317 p += p[1];
318
319 // All AVpairs added
320 *(u16 *) (b + 2) = htons(p - b);
321 if (state != RADIUSAUTH)
322 {
323 // Build auth for accounting packet
324 char z[16] = {0};
325 char hash[16] = {0};
326 MD5_CTX ctx;
327 MD5Init(&ctx);
328 MD5Update(&ctx, b, 4);
329 MD5Update(&ctx, z, 16);
330 MD5Update(&ctx, b + 20, (p - b) - 20);
331 MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
332 MD5Final(hash, &ctx);
333 memcpy(b + 4, hash, 16);
334 memcpy(radius[r].auth, hash, 16);
335 }
336 memset(&addr, 0, sizeof(addr));
337 addr.sin_family = AF_INET;
338 *(u32 *) & addr.sin_addr = config->radiusserver[(radius[r].try - 1) % config->numradiusservers];
339 addr.sin_port = htons((state == RADIUSAUTH) ? RADPORT : RADAPORT);
340
341 log_hex(5, "RADIUS Send", b, (p - b));
342 sendto(radfds[r & RADIUS_MASK], b, p - b, 0, (void *) &addr, sizeof(addr));
343 }
344
345 // process RADIUS response
346 void processrad(u8 *buf, int len, char socket_index)
347 {
348 u8 b[MAXCONTROL];
349 MD5_CTX ctx;
350 u16 r;
351 sessionidt s;
352 tunnelidt t = 0;
353 hasht hash;
354 u8 routes = 0;
355
356 int r_code, r_id ; // Radius code.
357
358 r_code = buf[0]; // First byte in radius packet.
359 r_id = buf[1]; // radius reply indentifier.
360
361
362 CSTAT(call_processrad);
363
364 log_hex(5, "RADIUS Response", buf, len);
365 if (len < 20 || len < ntohs(*(u16 *) (buf + 2)))
366 {
367 log(1, 0, 0, 0, "Duff RADIUS response length %d\n", len);
368 return ;
369 }
370 len = ntohs(*(u16 *) (buf + 2));
371 r = socket_index | (r_id << RADIUS_SHIFT);
372 s = radius[r].session;
373 log(3, 0, s, session[s].tunnel, "Received %s, radius %d response for session %u (code %d, id %d)\n",
374 radius_states[radius[r].state], r, s, r_code, r_id);
375 if (!s && radius[r].state != RADIUSSTOP)
376 {
377 log(1, 0, s, session[s].tunnel, " Unexpected RADIUS response\n");
378 return;
379 }
380 if (radius[r].state != RADIUSAUTH && radius[r].state != RADIUSSTART && radius[r].state != RADIUSSTOP)
381 {
382 log(1, 0, s, session[s].tunnel, " Unexpected RADIUS response\n");
383 return;
384 }
385 t = session[s].tunnel;
386 MD5Init(&ctx);
387 MD5Update(&ctx, buf, 4);
388 MD5Update(&ctx, radius[r].auth, 16);
389 MD5Update(&ctx, buf + 20, len - 20);
390 MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
391 MD5Final(hash, &ctx);
392 do {
393 if (memcmp(hash, buf + 4, 16))
394 {
395 log(0, 0, s, session[s].tunnel, " Incorrect auth on RADIUS response!! (wrong secret in radius config?)\n");
396 // radius[r].state = RADIUSWAIT;
397
398 return; // Do nothing. On timeout, it will try the next radius server.
399 }
400 if ((radius[r].state == RADIUSAUTH && *buf != 2 && *buf != 3) ||
401 ((radius[r].state == RADIUSSTART || radius[r].state == RADIUSSTOP) && *buf != 5))
402 {
403 log(1, 0, s, session[s].tunnel, " Unexpected RADIUS response %d\n", *buf);
404
405 return; // We got something we didn't expect. Let the timeouts take
406 // care off finishing the radius session if that's really correct.
407 // old code. I think incorrect. --mo
408 // radius[r].state = RADIUSWAIT;
409 // break; // Finish the radius sesssion.
410 }
411 if (radius[r].state == RADIUSAUTH)
412 {
413 log(4, 0, s, session[s].tunnel, " Original response is \"%s\"\n", (*buf == 2) ? "accept" : "reject");
414 // process auth response
415 if (radius[r].chap)
416 {
417 // CHAP
418 u8 *p = makeppp(b, sizeof(b), 0, 0, t, s, PPPCHAP);
419 if (!p) {
420 return; // Abort!
421 }
422 {
423 struct param_post_auth packet = { &tunnel[t], &session[s], session[s].user, (*buf == 2), PPPCHAP };
424 run_plugins(PLUGIN_POST_AUTH, &packet);
425 *buf = packet.auth_allowed ? 2 : 3;
426 }
427
428 log(3, 0, s, session[s].tunnel, " CHAP User %s authentication %s.\n", session[s].user,
429 (*buf == 2) ? "allowed" : "denied");
430 *p = (*buf == 2) ? 3 : 4; // ack/nak
431 p[1] = radius[r].id;
432 *(u16 *) (p + 2) = ntohs(4); // no message
433 tunnelsend(b, (p - b) + 4, t); // send it
434 }
435 else
436 {
437 // PAP
438 u8 *p = makeppp(b, sizeof(b), 0, 0, t, s, PPPPAP);
439 if (!p)
440 return; // Abort!
441
442 {
443 struct param_post_auth packet = { &tunnel[t], &session[s], session[s].user, (*buf == 2), PPPPAP };
444 run_plugins(PLUGIN_POST_AUTH, &packet);
445 *buf = packet.auth_allowed ? 2 : 3;
446 }
447
448 log(3, 0, s, session[s].tunnel, " PAP User %s authentication %s.\n", session[s].user,
449 (*buf == 2) ? "allowed" : "denied");
450 // ack/nak
451 *p = *buf;
452 p[1] = radius[r].id;
453 *(u16 *) (p + 2) = ntohs(5);
454 p[4] = 0; // no message
455 tunnelsend(b, (p - b) + 5, t); // send it
456 }
457
458 if (*buf == 2)
459 {
460 // Login successful
461 // Extract IP, routes, etc
462 u8 *p = buf + 20;
463 u8 *e = buf + len;
464 for (p = buf + 20; p < e && p[1]; p += p[1])
465 {
466 if (*p == 8)
467 {
468 // Statically assigned address
469 log(3, 0, s, session[s].tunnel, " Radius reply contains IP address %s\n", inet_toa(*(u32 *) (p + 2)));
470 session[s].ip = ntohl(*(u32 *) (p + 2));
471 session[s].ip_pool_index = -1;
472 }
473 else if (*p == 135)
474 {
475 // DNS address
476 log(3, 0, s, session[s].tunnel, " Radius reply contains primary DNS address %s\n", inet_toa(*(u32 *) (p + 2)));
477 session[s].dns1 = ntohl(*(u32 *) (p + 2));
478 }
479 else if (*p == 136)
480 {
481 // DNS address
482 log(3, 0, s, session[s].tunnel, " Radius reply contains secondary DNS address %s\n", inet_toa(*(u32 *) (p + 2)));
483 session[s].dns2 = ntohl(*(u32 *) (p + 2));
484 }
485 else if (*p == 22)
486 {
487 // framed-route
488 ipt ip = 0, mask = 0;
489 u8 u = 0;
490 u8 bits = 0;
491 u8 *n = p + 2;
492 u8 *e = p + p[1];
493 while (n < e && (isdigit(*n) || *n == '.'))
494 {
495 if (*n == '.')
496 {
497 ip = (ip << 8) + u;
498 u = 0;
499 }
500 else
501 u = u * 10 + *n - '0';
502 n++;
503 }
504 ip = (ip << 8) + u;
505 if (*n == '/')
506 {
507 n++;
508 while (n < e && isdigit(*n))
509 bits = bits * 10 + *n++ - '0';
510 mask = (( -1) << (32 - bits));
511 }
512 else if ((ip >> 24) < 128)
513 mask = 0xFF0000;
514 else if ((ip >> 24) < 192)
515 mask = 0xFFFF0000;
516 else
517 mask = 0xFFFFFF00;
518 if (routes == MAXROUTE)
519 {
520 log(1, 0, s, session[s].tunnel, " Too many routes\n");
521 }
522 else if (ip)
523 {
524 char *ips, *masks;
525 ips = strdup(inet_toa(htonl(ip)));
526 masks = strdup(inet_toa(htonl(mask)));
527 log(3, 0, s, session[s].tunnel, " Radius reply contains route for %s/%s\n", ips, masks);
528 free(ips);
529 free(masks);
530 session[s].route[routes].ip = ip;
531 session[s].route[routes].mask = mask;
532 routes++;
533 }
534 }
535 else if (*p == 26)
536 {
537 // Vendor-Specific Attribute
538 int vendor = ntohl(*(int *)(p + 2));
539 char attrib = *(p + 6);
540 char attrib_length = *(p + 7) - 2;
541 log(3, 0, s, session[s].tunnel, " Radius reply contains Vendor-Specific. Vendor=%d Attrib=%d Length=%d\n", vendor, attrib, attrib_length);
542 if (attrib_length == 0) continue;
543 if (attrib != 1)
544 log(3, 0, s, session[s].tunnel, " Unknown vendor-specific\n");
545 else
546 {
547 char *avpair, *value, *key, *newp;
548 avpair = key = calloc(attrib_length + 1, 1);
549 memcpy(avpair, p + 8, attrib_length);
550 log(3, 0, s, session[s].tunnel, " Cisco-Avpair value: %s\n", avpair);
551 do {
552 value = strchr(key, '=');
553 if (!value) break;
554 *value++ = 0;
555
556 // Trim quotes off reply string
557 if (*value == '\'' || *value == '\"')
558 {
559 char *x;
560 value++;
561 x = value + strlen(value) - 1;
562 if (*x == '\'' || *x == '\"')
563 *x = 0;
564 }
565
566 // Run hooks
567 newp = strchr(value, ',');
568 if (newp) *newp++ = 0;
569 {
570 struct param_radius_response p = { &tunnel[session[s].tunnel], &session[s], key, value };
571 run_plugins(PLUGIN_RADIUS_RESPONSE, &p);
572 }
573 key = newp;
574 } while (newp);
575 free(avpair);
576 }
577 }
578 }
579 }
580 else if (*buf == 3)
581 {
582 log(2, 0, s, session[s].tunnel, " Authentication denied for %s\n", session[s].user);
583 //FIXME: We should tear down the session here!
584 break;
585 }
586
587 if (!session[s].dns1 && config->default_dns1)
588 {
589 session[s].dns1 = htonl(config->default_dns1);
590 log(3, 0, s, t, " Sending dns1 = %s\n", inet_toa(config->default_dns1));
591 }
592 if (!session[s].dns2 && config->default_dns2)
593 {
594 session[s].dns2 = htonl(config->default_dns2);
595 log(3, 0, s, t, " Sending dns2 = %s\n", inet_toa(config->default_dns2));
596 }
597
598 // Valid Session, set it up
599 session[s].sid = 0;
600 sessionsetup(t, s);
601 }
602 else
603 {
604 // An ack for a stop or start record.
605 log(3, 0, s, t, " RADIUS accounting ack recv in state %s\n", radius_states[radius[r].state]);
606 break;
607 }
608 } while (0);
609
610 // finished with RADIUS
611 radiusclear(r, s);
612 }
613
614 // Send a retry for RADIUS/CHAP message
615 void radiusretry(u16 r)
616 {
617 sessionidt s = radius[r].session;
618 tunnelidt t = 0;
619
620 CSTAT(call_radiusretry);
621
622 if (s)
623 t = session[s].tunnel;
624 radius[r].retry = backoff(radius[r].try + 1);
625 switch (radius[r].state)
626 {
627 case RADIUSCHAP: // sending CHAP down PPP
628 sendchap(t, s);
629 break;
630 case RADIUSIPCP:
631 sendipcp(t, s); // send IPCP
632 break;
633 case RADIUSAUTH: // sending auth to RADIUS server
634 radiussend(r, RADIUSAUTH);
635 break;
636 case RADIUSSTART: // sending start accounting to RADIUS server
637 radiussend(r, RADIUSSTART);
638 break;
639 case RADIUSSTOP: // sending stop accounting to RADIUS server
640 radiussend(r, RADIUSSTOP);
641 break;
642 default:
643 case RADIUSNULL: // Not in use
644 case RADIUSWAIT: // waiting timeout before available, in case delayed reply from RADIUS server
645 // free up RADIUS task
646 radiusclear(r, s);
647 log(3, 0, s, session[s].tunnel, "Freeing up radius session %d\n", r);
648 break;
649 }
650 }
651
652 void radius_clean()
653 {
654 int i;
655
656 log(1, 0, 0, 0, "Cleaning radius session array\n");
657
658 for (i = 1; i < MAXRADIUS; i++)
659 {
660 if (radius[i].retry == 0
661 || !session[radius[i].session].opened
662 || session[radius[i].session].die
663 || session[radius[i].session].tunnel == 0)
664 radiusclear(i, 0);
665 }
666 }