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