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