3 char const *cvs_id_radius
= "$Id: radius.c,v 1.32 2005-06-02 11:32:32 bodea Exp $";
8 #include <sys/socket.h>
12 #include <arpa/inet.h>
14 #include <netinet/in.h>
16 #include "constants.h"
21 extern radiust
*radius
;
22 extern sessiont
*session
;
23 extern tunnelt
*tunnel
;
24 extern configt
*config
;
26 extern ip_filtert
*ip_filters
;
28 // Set up socket for radius requests
32 LOG(3, 0, 0, "Creating %d sockets for RADIUS queries\n", config
->num_radfds
);
33 radfds
= calloc(sizeof(int), config
->num_radfds
);
34 for (i
= 0; i
< config
->num_radfds
; i
++)
37 radfds
[i
] = socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
38 flags
= fcntl(radfds
[i
], F_GETFL
, 0);
39 fcntl(radfds
[i
], F_SETFL
, flags
| O_NONBLOCK
);
43 void radiusclear(uint16_t r
, sessionidt s
)
45 if (s
) sess_local
[s
].radius
= 0;
46 memset(&radius
[r
], 0, sizeof(radius
[r
])); // radius[r].state = RADIUSNULL;
49 static uint16_t get_free_radius()
52 static uint32_t next_radius_id
= 0;
54 for (count
= MAXRADIUS
; count
> 0 ; --count
)
56 ++next_radius_id
; // Find the next ID to check.
57 if (next_radius_id
>= MAXRADIUS
)
60 if (radius
[next_radius_id
].state
== RADIUSNULL
)
62 return next_radius_id
;
66 LOG(0, 0, 0, "Can't find a free radius session! This is very bad!\n");
70 uint16_t radiusnew(sessionidt s
)
72 uint16_t r
= sess_local
[s
].radius
;
77 LOG(3, s
, session
[s
].tunnel
, "Re-used radius %d\n", r
);
81 if (!(r
= get_free_radius()))
83 LOG(1, s
, session
[s
].tunnel
, "No free RADIUS sessions\n");
84 STAT(radius_overflow
);
88 memset(&radius
[r
], 0, sizeof(radius
[r
]));
89 sess_local
[s
].radius
= r
;
90 radius
[r
].session
= s
;
91 radius
[r
].state
= RADIUSWAIT
;
92 radius
[r
].retry
= TIME
+ 1200; // Wait at least 120 seconds to re-claim this.
94 random_data(radius
[r
].auth
, sizeof(radius
[r
].auth
));
96 LOG(3, s
, session
[s
].tunnel
, "Allocated radius %d\n", r
);
100 // Send a RADIUS request
101 void radiussend(uint16_t r
, uint8_t state
)
103 struct sockaddr_in addr
;
104 uint8_t b
[4096]; // RADIUS packet
112 s
= radius
[r
].session
;
113 if (!config
->numradiusservers
)
115 LOG(0, s
, session
[s
].tunnel
, "No RADIUS servers\n");
118 if (!*config
->radiussecret
)
120 LOG(0, s
, session
[s
].tunnel
, "No RADIUS secret\n");
124 if (state
!= RADIUSAUTH
&& !config
->radius_accounting
)
126 // Radius accounting is turned off
131 if (radius
[r
].state
!= state
)
134 radius
[r
].state
= state
;
135 radius
[r
].retry
= backoff(radius
[r
].try++) + 20; // 3s, 4s, 6s, 10s...
136 LOG(4, s
, session
[s
].tunnel
, "Send RADIUS id %d sock %d state %s try %d\n",
137 r
>> RADIUS_SHIFT
, r
& RADIUS_MASK
,
138 radius_state(radius
[r
].state
), radius
[r
].try);
140 if (radius
[r
].try > config
->numradiusservers
* 2)
144 if (state
== RADIUSAUTH
)
145 sessionshutdown(s
, "RADIUS timeout.", 3, 0);
148 LOG(1, s
, session
[s
].tunnel
, "RADIUS timeout, but in state %s so don't timeout session\n",
149 radius_state(state
));
152 STAT(radius_timeout
);
156 STAT(radius_retries
);
157 radius
[r
].state
= RADIUSWAIT
;
158 radius
[r
].retry
= 100;
162 // contruct RADIUS access request
166 b
[0] = AccessRequest
; // access request
171 b
[0] = AccountingRequest
; // accounting request
174 LOG(0, 0, 0, "Unknown radius state %d\n", state
);
176 b
[1] = r
>> RADIUS_SHIFT
; // identifier
177 memcpy(b
+ 4, radius
[r
].auth
, 16);
182 p
[1] = strlen(session
[s
].user
) + 2;
183 strcpy(p
+ 2, session
[s
].user
);
186 if (state
== RADIUSAUTH
)
190 *p
= 3; // CHAP password
192 p
[2] = radius
[r
].id
; // ID
193 memcpy(p
+ 3, radius
[r
].pass
, 16); // response from CHAP request
195 *p
= 60; // CHAP Challenge
197 memcpy(p
+ 2, radius
[r
].auth
, 16);
202 strcpy(pass
, radius
[r
].pass
);
205 pass
[pl
++] = 0; // pad
214 MD5Update(&ctx
, config
->radiussecret
, strlen(config
->radiussecret
));
216 MD5Update(&ctx
, pass
+ p
- 16, 16);
218 MD5Update(&ctx
, radius
[r
].auth
, 16);
219 MD5Final(hash
, &ctx
);
222 pass
[p
] ^= hash
[p
& 15];
231 memcpy(p
+ 2, pass
, pl
);
235 else if (state
== RADIUSSTART
|| state
== RADIUSSTOP
|| state
== RADIUSINTERIM
)
237 *p
= 40; // accounting type
239 *(uint32_t *) (p
+ 2) = htonl(state
- RADIUSSTART
+ 1); // start=1, stop=2, interim=3
243 *p
= 44; // session ID
245 sprintf(p
+ 2, "%08X%08X", session
[s
].unique_id
, session
[s
].opened
);
247 if (state
== RADIUSSTART
)
251 *(uint32_t *) (p
+ 2) = htonl(time(NULL
) - session
[s
].opened
);
253 sess_local
[s
].last_interim
= time_now
; // Setup "first" Interim
257 *p
= 42; // input octets
259 *(uint32_t *) (p
+ 2) = htonl(session
[s
].cin
);
262 *p
= 43; // output octets
264 *(uint32_t *) (p
+ 2) = htonl(session
[s
].cout
);
266 if (state
== RADIUSSTOP
)
268 *p
= 46; // session time
270 *(uint32_t *) (p
+ 2) = htonl(time(NULL
) - session
[s
].opened
);
274 *p
= 47; // input packets
276 *(uint32_t *) (p
+ 2) = htonl(session
[s
].pin
);
279 *p
= 48; // output packets
281 *(uint32_t *) (p
+ 2) = htonl(session
[s
].pout
);
284 *p
= 52; // input gigawords
286 *(uint32_t *) (p
+ 2) = htonl(session
[s
].cin_wrap
);
289 *p
= 53; // output gigawords
291 *(uint32_t *) (p
+ 2) = htonl(session
[s
].cout_wrap
);
295 if (session
[s
].snoop_ip
&& session
[s
].snoop_port
)
297 *p
= 26; // vendor-specific
298 *(uint32_t *) (p
+ 2) = htonl(9); // Cisco
299 p
[6] = 1; // Cisco-Avpair
300 p
[7] = 2 + sprintf(p
+ 8, "intercept=%s:%d",
301 fmtaddr(session
[s
].snoop_ip
, 0), session
[s
].snoop_port
);
312 *(uint32_t *) (p
+ 2) = htonl(s
);
315 if (s
&& session
[s
].ip
)
317 *p
= 8; // Framed-IP-Address
319 *(uint32_t *) (p
+ 2) = htonl(session
[s
].ip
);
322 if (*session
[s
].called
)
325 p
[1] = strlen(session
[s
].called
) + 2;
326 strcpy(p
+ 2, session
[s
].called
);
329 if (*radius
[r
].calling
)
332 p
[1] = strlen(radius
[r
].calling
) + 2;
333 strcpy(p
+ 2, radius
[r
].calling
);
336 else if (*session
[s
].calling
)
339 p
[1] = strlen(session
[s
].calling
) + 2;
340 strcpy(p
+ 2, session
[s
].calling
);
346 *(uint32_t *)(p
+ 2) = config
->bind_address
;
350 *(uint16_t *) (b
+ 2) = htons(p
- b
);
351 if (state
!= RADIUSAUTH
)
353 // Build auth for accounting packet
358 MD5Update(&ctx
, b
, 4);
359 MD5Update(&ctx
, z
, 16);
360 MD5Update(&ctx
, b
+ 20, (p
- b
) - 20);
361 MD5Update(&ctx
, config
->radiussecret
, strlen(config
->radiussecret
));
362 MD5Final(hash
, &ctx
);
363 memcpy(b
+ 4, hash
, 16);
364 memcpy(radius
[r
].auth
, hash
, 16);
366 memset(&addr
, 0, sizeof(addr
));
367 addr
.sin_family
= AF_INET
;
368 *(uint32_t *) & addr
.sin_addr
= config
->radiusserver
[(radius
[r
].try - 1) % config
->numradiusservers
];
371 uint16_t port
= config
->radiusport
[(radius
[r
].try - 1) % config
->numradiusservers
];
372 // assume RADIUS accounting port is the authentication port +1
373 addr
.sin_port
= htons((state
== RADIUSAUTH
) ? port
: port
+1);
376 LOG_HEX(5, "RADIUS Send", b
, (p
- b
));
377 sendto(radfds
[r
& RADIUS_MASK
], b
, p
- b
, 0, (void *) &addr
, sizeof(addr
));
380 // process RADIUS response
381 void processrad(uint8_t *buf
, int len
, char socket_index
)
383 uint8_t b
[MAXCONTROL
];
395 LOG_HEX(5, "RADIUS Response", buf
, len
);
396 if (len
< 20 || len
< ntohs(*(uint16_t *) (buf
+ 2)))
398 LOG(1, 0, 0, "Duff RADIUS response length %d\n", len
);
402 r_code
= buf
[0]; // response type
403 r_id
= buf
[1]; // radius reply indentifier.
405 len
= ntohs(*(uint16_t *) (buf
+ 2));
406 r
= socket_index
| (r_id
<< RADIUS_SHIFT
);
407 s
= radius
[r
].session
;
408 LOG(3, s
, session
[s
].tunnel
, "Received %s, radius %d response for session %u (%s, id %d)\n",
409 radius_state(radius
[r
].state
), r
, s
, radius_code(r_code
), r_id
);
411 if (!s
&& radius
[r
].state
!= RADIUSSTOP
)
413 LOG(1, s
, session
[s
].tunnel
, " Unexpected RADIUS response\n");
416 if (radius
[r
].state
!= RADIUSAUTH
&& radius
[r
].state
!= RADIUSSTART
417 && radius
[r
].state
!= RADIUSSTOP
&& radius
[r
].state
!= RADIUSINTERIM
)
419 LOG(1, s
, session
[s
].tunnel
, " Unexpected RADIUS response\n");
422 t
= session
[s
].tunnel
;
424 MD5Update(&ctx
, buf
, 4);
425 MD5Update(&ctx
, radius
[r
].auth
, 16);
426 MD5Update(&ctx
, buf
+ 20, len
- 20);
427 MD5Update(&ctx
, config
->radiussecret
, strlen(config
->radiussecret
));
428 MD5Final(hash
, &ctx
);
430 if (memcmp(hash
, buf
+ 4, 16))
432 LOG(0, s
, session
[s
].tunnel
, " Incorrect auth on RADIUS response!! (wrong secret in radius config?)\n");
433 return; // Do nothing. On timeout, it will try the next radius server.
436 if ((radius
[r
].state
== RADIUSAUTH
&& r_code
!= AccessAccept
&& r_code
!= AccessReject
) ||
437 ((radius
[r
].state
== RADIUSSTART
|| radius
[r
].state
== RADIUSSTOP
|| radius
[r
].state
== RADIUSINTERIM
) && r_code
!= AccountingResponse
))
439 LOG(1, s
, session
[s
].tunnel
, " Unexpected RADIUS response %s\n", radius_code(r_code
));
440 return; // We got something we didn't expect. Let the timeouts take
441 // care off finishing the radius session if that's really correct.
444 if (radius
[r
].state
== RADIUSAUTH
)
446 // run post-auth plugin
447 struct param_post_auth packet
= {
451 (r_code
== AccessAccept
),
452 radius
[r
].chap
? PPPCHAP
: PPPPAP
455 run_plugins(PLUGIN_POST_AUTH
, &packet
);
456 r_code
= packet
.auth_allowed
? AccessAccept
: AccessReject
;
458 // process auth response
462 uint8_t *p
= makeppp(b
, sizeof(b
), 0, 0, t
, s
, PPPCHAP
);
463 if (!p
) return; // Abort!
465 *p
= (r_code
== AccessAccept
) ? 3 : 4; // ack/nak
467 *(uint16_t *) (p
+ 2) = ntohs(4); // no message
468 tunnelsend(b
, (p
- b
) + 4, t
); // send it
470 LOG(3, s
, session
[s
].tunnel
, " CHAP User %s authentication %s.\n", session
[s
].user
,
471 (r_code
== AccessAccept
) ? "allowed" : "denied");
476 uint8_t *p
= makeppp(b
, sizeof(b
), 0, 0, t
, s
, PPPPAP
);
477 if (!p
) return; // Abort!
482 *(uint16_t *) (p
+ 2) = ntohs(5);
483 p
[4] = 0; // no message
484 tunnelsend(b
, (p
- b
) + 5, t
); // send it
486 LOG(3, s
, session
[s
].tunnel
, " PAP User %s authentication %s.\n", session
[s
].user
,
487 (r_code
== AccessAccept
) ? "allowed" : "denied");
490 if (r_code
== AccessAccept
)
493 // Extract IP, routes, etc
494 uint8_t *p
= buf
+ 20;
495 uint8_t *e
= buf
+ len
;
496 for (; p
+ 2 <= e
&& p
[1] && p
+ p
[1] <= e
; p
+= p
[1])
501 if (p
[1] < 6) continue;
502 session
[s
].ip
= ntohl(*(uint32_t *) (p
+ 2));
503 session
[s
].ip_pool_index
= -1;
504 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains IP address %s\n",
505 fmtaddr(htonl(session
[s
].ip
), 0));
507 if (session
[s
].ip
== 0xFFFFFFFE)
508 session
[s
].ip
= 0; // assign from pool
513 if (p
[1] < 6) continue;
514 session
[s
].dns1
= ntohl(*(uint32_t *) (p
+ 2));
515 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains primary DNS address %s\n",
516 fmtaddr(htonl(session
[s
].dns1
), 0));
521 if (p
[1] < 6) continue;
522 session
[s
].dns2
= ntohl(*(uint32_t *) (p
+ 2));
523 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains secondary DNS address %s\n",
524 fmtaddr(htonl(session
[s
].dns2
), 0));
529 in_addr_t ip
= 0, mask
= 0;
533 uint8_t *e
= p
+ p
[1];
534 while (n
< e
&& (isdigit(*n
) || *n
== '.'))
542 u
= u
* 10 + *n
- '0';
549 while (n
< e
&& isdigit(*n
))
550 bits
= bits
* 10 + *n
++ - '0';
551 mask
= (( -1) << (32 - bits
));
553 else if ((ip
>> 24) < 128)
555 else if ((ip
>> 24) < 192)
560 if (routes
== MAXROUTE
)
562 LOG(1, s
, session
[s
].tunnel
, " Too many routes\n");
566 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains route for %s/%s\n",
567 fmtaddr(htonl(ip
), 0), fmtaddr(htonl(mask
), 1));
569 session
[s
].route
[routes
].ip
= ip
;
570 session
[s
].route
[routes
].mask
= mask
;
577 char *filter
= p
+ 2;
583 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains Filter-Id \"%.*s\"\n", l
, filter
);
584 if ((suffix
= memchr(filter
, '.', l
)))
586 int b
= suffix
- filter
;
587 if (l
- b
== 3 && !memcmp("in", suffix
+1, 2))
588 f
= &session
[s
].filter_in
;
589 else if (l
- b
== 4 && !memcmp("out", suffix
+1, 3))
590 f
= &session
[s
].filter_out
;
597 LOG(3, s
, session
[s
].tunnel
, " Invalid filter\n");
601 for (*f
= 0, i
= 0; !*f
&& i
< MAXFILTER
; i
++)
602 if (strlen(ip_filters
[i
].name
) == l
&&
603 !strncmp(ip_filters
[i
].name
, filter
, l
))
607 ip_filters
[*f
- 1].used
++;
609 LOG(3, s
, session
[s
].tunnel
, " Unknown filter\n");
612 else if (*p
== 26 && p
[1] >= 7)
614 // Vendor-Specific Attribute
615 int vendor
= ntohl(*(int *)(p
+ 2));
616 char attrib
= *(p
+ 6);
617 int attrib_length
= *(p
+ 7) - 2;
618 char *avpair
, *value
, *key
, *newp
;
620 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains Vendor-Specific. Vendor=%d Attrib=%d Length=%d\n", vendor
, attrib
, attrib_length
);
621 if (vendor
!= 9 || attrib
!= 1)
623 LOG(3, s
, session
[s
].tunnel
, " Unknown vendor-specific\n");
627 if (attrib_length
< 0) continue;
629 avpair
= key
= calloc(attrib_length
+ 1, 1);
630 memcpy(avpair
, p
+ 8, attrib_length
);
631 LOG(3, s
, session
[s
].tunnel
, " Cisco-Avpair value: %s\n", avpair
);
633 value
= strchr(key
, '=');
637 // Trim quotes off reply string
638 if (*value
== '\'' || *value
== '\"')
642 x
= value
+ strlen(value
) - 1;
643 if (*x
== '\'' || *x
== '\"')
648 newp
= strchr(value
, ',');
649 if (newp
) *newp
++ = 0;
651 struct param_radius_response p
= { &tunnel
[session
[s
].tunnel
], &session
[s
], key
, value
};
652 run_plugins(PLUGIN_RADIUS_RESPONSE
, &p
);
664 uint8_t *e
= p
+ p
[1];
665 uint8_t *m
= strchr(n
, '/');
668 inet_pton(AF_INET6
, n
, &r6
);
671 while (m
< e
&& isdigit(*m
)) {
672 prefixlen
= prefixlen
* 10 + *m
++ - '0';
677 LOG(3, s
, session
[s
].tunnel
,
678 " Radius reply contains route for %s/%d\n",
680 session
[s
].ipv6route
= r6
;
681 session
[s
].ipv6prefixlen
= prefixlen
;
686 else if (r_code
== AccessReject
)
688 LOG(2, s
, session
[s
].tunnel
, " Authentication rejected for %s\n", session
[s
].user
);
689 sessionkill(s
, "Authentication rejected");
693 if (!session
[s
].dns1
&& config
->default_dns1
)
695 session
[s
].dns1
= htonl(config
->default_dns1
);
696 LOG(3, s
, t
, " Sending dns1 = %s\n", fmtaddr(config
->default_dns1
, 0));
698 if (!session
[s
].dns2
&& config
->default_dns2
)
700 session
[s
].dns2
= htonl(config
->default_dns2
);
701 LOG(3, s
, t
, " Sending dns2 = %s\n", fmtaddr(config
->default_dns2
, 0));
704 // Valid Session, set it up
705 session
[s
].unique_id
= 0;
710 // An ack for a stop or start record.
711 LOG(3, s
, t
, " RADIUS accounting ack recv in state %s\n", radius_state(radius
[r
].state
));
716 // finished with RADIUS
720 // Send a retry for RADIUS/CHAP message
721 void radiusretry(uint16_t r
)
723 sessionidt s
= radius
[r
].session
;
728 if (s
) t
= session
[s
].tunnel
;
730 switch (radius
[r
].state
)
732 case RADIUSCHAP
: // sending CHAP down PPP
736 sendipcp(t
, s
); // send IPCP
738 case RADIUSAUTH
: // sending auth to RADIUS server
739 radiussend(r
, RADIUSAUTH
);
741 case RADIUSSTART
: // sending start accounting to RADIUS server
742 radiussend(r
, RADIUSSTART
);
744 case RADIUSSTOP
: // sending stop accounting to RADIUS server
745 radiussend(r
, RADIUSSTOP
);
747 case RADIUSINTERIM
: // sending interim accounting to RADIUS server
748 radiussend(r
, RADIUSINTERIM
);
751 case RADIUSNULL
: // Not in use
752 case RADIUSWAIT
: // waiting timeout before available, in case delayed reply from RADIUS server
753 // free up RADIUS task
755 LOG(3, s
, session
[s
].tunnel
, "Freeing up radius session %d\n", r
);