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