3 char const *cvs_id_radius
= "$Id: radius.c,v 1.19 2004-11-30 06:50:26 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
;
25 extern configt
*config
;
27 extern ip_filtert
*ip_filters
;
29 static const char *radius_state(int state
)
31 static char *tmp
= NULL
;
33 for (i
= 0; radius_states
[i
]; i
++)
34 if (i
== state
) return radius_states
[i
];
36 if (tmp
== NULL
) tmp
= (char *)calloc(64, 1);
37 sprintf(tmp
, "%d", state
);
41 // Set up socket for radius requests
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
++)
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
);
56 void radiusclear(u16 r
, sessionidt s
)
58 if (s
) session
[s
].radius
= 0;
59 memset(&radius
[r
], 0, sizeof(radius
[r
])); // radius[r].state = RADIUSNULL;
63 static u16
get_free_radius()
66 static u32 next_radius_id
= 0;
68 for (count
= MAXRADIUS
; count
> 0 ; --count
)
70 ++next_radius_id
; // Find the next ID to check.
71 if (next_radius_id
>= MAXRADIUS
)
74 if (radius
[next_radius_id
].state
== RADIUSNULL
)
76 return next_radius_id
;
80 LOG(0, 0, 0, "Can't find a free radius session! This is very bad!\n");
84 u16
radiusnew(sessionidt s
)
86 u16 r
= session
[s
].radius
;
91 LOG(3, s
, session
[s
].tunnel
, "Re-used radius %d\n", r
);
95 if (!(r
= get_free_radius()))
97 LOG(1, s
, session
[s
].tunnel
, "No free RADIUS sessions\n");
98 STAT(radius_overflow
);
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.
108 LOG(3, s
, session
[s
].tunnel
, "Allocated radius %d\n", r
);
112 // Send a RADIUS request
113 void radiussend(u16 r
, u8 state
)
115 struct sockaddr_in addr
;
116 u8 b
[4096]; // RADIUS packet
122 CSTAT(call_radiussend
);
124 s
= radius
[r
].session
;
125 if (!config
->numradiusservers
)
127 LOG(0, s
, session
[s
].tunnel
, "No RADIUS servers\n");
130 if (!*config
->radiussecret
)
132 LOG(0, s
, session
[s
].tunnel
, "No RADIUS secret\n");
136 if (state
!= RADIUSAUTH
&& !config
->radius_accounting
)
138 // Radius accounting is turned off
143 if (radius
[r
].state
!= state
)
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);
151 if (radius
[r
].try > config
->numradiusservers
* 2)
155 if (state
== RADIUSAUTH
)
156 sessionshutdown(s
, "RADIUS timeout");
159 LOG(1, s
, session
[s
].tunnel
, "RADIUS timeout, but in state %s so don't timeout session\n",
160 radius_states
[state
]);
163 STAT(radius_timeout
);
167 STAT(radius_retries
);
168 radius
[r
].state
= RADIUSWAIT
;
169 radius
[r
].retry
= 100;
173 // contruct RADIUS access request
177 b
[0] = 1; // access request
181 b
[0] = 4; // accounting request
184 LOG(0, 0, 0, "Unknown radius state %d\n", state
);
186 b
[1] = r
>> RADIUS_SHIFT
; // identifier
187 memcpy(b
+ 4, radius
[r
].auth
, 16);
192 p
[1] = strlen(session
[s
].user
) + 2;
193 strcpy(p
+ 2, session
[s
].user
);
196 if (state
== RADIUSAUTH
)
200 *p
= 3; // CHAP password
202 p
[2] = radius
[r
].id
; // ID
203 memcpy(p
+ 3, radius
[r
].pass
, 16); // response from CHAP request
205 *p
= 60; // CHAP Challenge
207 memcpy(p
+ 2, radius
[r
].auth
, 16);
212 strcpy(pass
, radius
[r
].pass
);
215 pass
[pl
++] = 0; // pad
224 MD5Update(&ctx
, config
->radiussecret
, strlen(config
->radiussecret
));
226 MD5Update(&ctx
, pass
+ p
- 16, 16);
228 MD5Update(&ctx
, radius
[r
].auth
, 16);
229 MD5Final(hash
, &ctx
);
232 pass
[p
] ^= hash
[p
& 15];
241 memcpy(p
+ 2, pass
, pl
);
245 else if (state
== RADIUSSTART
|| state
== RADIUSSTOP
)
247 *p
= 40; // accounting type
249 *(u32
*) (p
+ 2) = htonl((state
== RADIUSSTART
) ? 1 : 2);
253 *p
= 44; // session ID
255 sprintf(p
+ 2, "%08X%08X", session
[s
].id
, session
[s
].opened
);
257 if (state
== RADIUSSTOP
)
259 *p
= 42; // input octets
261 *(u32
*) (p
+ 2) = htonl(session
[s
].cin
);
263 *p
= 43; // output octets
265 *(u32
*) (p
+ 2) = htonl(session
[s
].cout
);
267 *p
= 46; // session time
269 *(u32
*) (p
+ 2) = htonl(time(NULL
) - session
[s
].opened
);
271 *p
= 47; // input packets
273 *(u32
*) (p
+ 2) = htonl(session
[s
].pin
);
275 *p
= 48; // output spackets
277 *(u32
*) (p
+ 2) = htonl(session
[s
].pout
);
284 *(u32
*) (p
+ 2) = htonl(time(NULL
) - session
[s
].opened
);
293 *(u32
*) (p
+ 2) = htonl(s
);
296 if (s
&& session
[s
].ip
)
298 *p
= 8; // Framed-IP-Address
300 *(u32
*) (p
+ 2) = htonl(session
[s
].ip
);
303 if (*session
[s
].called
)
306 p
[1] = strlen(session
[s
].called
) + 2;
307 strcpy(p
+ 2, session
[s
].called
);
310 if (*radius
[r
].calling
)
313 p
[1] = strlen(radius
[r
].calling
) + 2;
314 strcpy(p
+ 2, radius
[r
].calling
);
317 else if (*session
[s
].calling
)
320 p
[1] = strlen(session
[s
].calling
) + 2;
321 strcpy(p
+ 2, session
[s
].calling
);
327 *(u32
*)(p
+ 2) = config
->bind_address
;
331 *(u16
*) (b
+ 2) = htons(p
- b
);
332 if (state
!= RADIUSAUTH
)
334 // Build auth for accounting packet
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);
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
];
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);
359 LOG_HEX(5, "RADIUS Send", b
, (p
- b
));
360 sendto(radfds
[r
& RADIUS_MASK
], b
, p
- b
, 0, (void *) &addr
, sizeof(addr
));
363 // process RADIUS response
364 void processrad(u8
*buf
, int len
, char socket_index
)
374 int r_code
, r_id
; // Radius code.
376 r_code
= buf
[0]; // First byte in radius packet.
377 r_id
= buf
[1]; // radius reply indentifier.
380 CSTAT(call_processrad
);
382 LOG_HEX(5, "RADIUS Response", buf
, len
);
383 if (len
< 20 || len
< ntohs(*(u16
*) (buf
+ 2)))
385 LOG(1, 0, 0, "Duff RADIUS response length %d\n", len
);
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
)
395 LOG(1, s
, session
[s
].tunnel
, " Unexpected RADIUS response\n");
398 if (radius
[r
].state
!= RADIUSAUTH
&& radius
[r
].state
!= RADIUSSTART
&& radius
[r
].state
!= RADIUSSTOP
)
400 LOG(1, s
, session
[s
].tunnel
, " Unexpected RADIUS response\n");
403 t
= session
[s
].tunnel
;
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
);
411 if (memcmp(hash
, buf
+ 4, 16))
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.
416 if ((radius
[r
].state
== RADIUSAUTH
&& *buf
!= 2 && *buf
!= 3) ||
417 ((radius
[r
].state
== RADIUSSTART
|| radius
[r
].state
== RADIUSSTOP
) && *buf
!= 5))
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.
423 if (radius
[r
].state
== RADIUSAUTH
)
425 LOG(4, s
, session
[s
].tunnel
, " Original response is \"%s\"\n", (*buf
== 2) ? "accept" : "reject");
426 // process auth response
430 u8
*p
= makeppp(b
, sizeof(b
), 0, 0, t
, s
, PPPCHAP
);
431 if (!p
) return; // Abort!
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;
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
443 *(u16
*) (p
+ 2) = ntohs(4); // no message
444 tunnelsend(b
, (p
- b
) + 4, t
); // send it
449 u8
*p
= makeppp(b
, sizeof(b
), 0, 0, t
, s
, PPPPAP
);
450 if (!p
) return; // Abort!
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;
458 LOG(3, s
, session
[s
].tunnel
, " PAP User %s authentication %s.\n", session
[s
].user
,
459 (*buf
== 2) ? "allowed" : "denied");
463 *(u16
*) (p
+ 2) = ntohs(5);
464 p
[4] = 0; // no message
465 tunnelsend(b
, (p
- b
) + 5, t
); // send it
471 // Extract IP, routes, etc
474 for (; p
+ 2 <= e
&& p
[1] && p
+ p
[1] <= e
; p
+= p
[1])
479 if (p
[1] < 6) continue;
480 session
[s
].ip
= ntohl(*(u32
*) (p
+ 2));
481 session
[s
].ip_pool_index
= -1;
482 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains IP address %s\n",
483 fmtaddr(htonl(session
[s
].ip
), 0));
488 if (p
[1] < 6) continue;
489 session
[s
].dns1
= ntohl(*(u32
*) (p
+ 2));
490 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains primary DNS address %s\n",
491 fmtaddr(htonl(session
[s
].dns1
), 0));
496 if (p
[1] < 6) continue;
497 session
[s
].dns2
= ntohl(*(u32
*) (p
+ 2));
498 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains secondary DNS address %s\n",
499 fmtaddr(htonl(session
[s
].dns2
), 0));
504 ipt ip
= 0, mask
= 0;
509 while (n
< e
&& (isdigit(*n
) || *n
== '.'))
517 u
= u
* 10 + *n
- '0';
524 while (n
< e
&& isdigit(*n
))
525 bits
= bits
* 10 + *n
++ - '0';
526 mask
= (( -1) << (32 - bits
));
528 else if ((ip
>> 24) < 128)
530 else if ((ip
>> 24) < 192)
535 if (routes
== MAXROUTE
)
537 LOG(1, s
, session
[s
].tunnel
, " Too many routes\n");
541 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains route for %s/%s\n",
542 fmtaddr(htonl(ip
), 0), fmtaddr(htonl(mask
), 1));
544 session
[s
].route
[routes
].ip
= ip
;
545 session
[s
].route
[routes
].mask
= mask
;
552 char *filter
= p
+ 2;
558 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains Filter-Id \"%.*s\"\n", l
, filter
);
559 if ((suffix
= memchr(filter
, '.', l
)))
561 int b
= suffix
- filter
;
562 if (l
- b
== 3 && !memcmp("in", suffix
+1, 2))
563 f
= &session
[s
].filter_in
;
564 else if (l
- b
== 4 && !memcmp("out", suffix
+1, 3))
565 f
= &session
[s
].filter_out
;
572 LOG(3, s
, session
[s
].tunnel
, " Invalid filter\n");
576 for (*f
= 0, i
= 0; !*f
&& i
< MAXFILTER
; i
++)
577 if (strlen(ip_filters
[i
].name
) == l
&&
578 !strncmp(ip_filters
[i
].name
, filter
, l
))
582 ip_filters
[*f
- 1].used
++;
584 LOG(3, s
, session
[s
].tunnel
, " Unknown filter\n");
587 else if (*p
== 26 && p
[1] >= 7)
589 // Vendor-Specific Attribute
590 int vendor
= ntohl(*(int *)(p
+ 2));
591 char attrib
= *(p
+ 6);
592 char attrib_length
= *(p
+ 7) - 2;
593 char *avpair
, *value
, *key
, *newp
;
595 LOG(3, s
, session
[s
].tunnel
, " Radius reply contains Vendor-Specific. Vendor=%d Attrib=%d Length=%d\n", vendor
, attrib
, attrib_length
);
596 if (vendor
!= 9 || attrib
!= 1)
598 LOG(3, s
, session
[s
].tunnel
, " Unknown vendor-specific\n");
602 if (attrib_length
< 0) continue;
604 avpair
= key
= calloc(attrib_length
+ 1, 1);
605 memcpy(avpair
, p
+ 8, attrib_length
);
606 LOG(3, s
, session
[s
].tunnel
, " Cisco-Avpair value: %s\n", avpair
);
608 value
= strchr(key
, '=');
612 // Trim quotes off reply string
613 if (*value
== '\'' || *value
== '\"')
617 x
= value
+ strlen(value
) - 1;
618 if (*x
== '\'' || *x
== '\"')
623 newp
= strchr(value
, ',');
624 if (newp
) *newp
++ = 0;
626 struct param_radius_response p
= { &tunnel
[session
[s
].tunnel
], &session
[s
], key
, value
};
627 run_plugins(PLUGIN_RADIUS_RESPONSE
, &p
);
637 LOG(2, s
, session
[s
].tunnel
, " Authentication denied for %s\n", session
[s
].user
);
638 //FIXME: We should tear down the session here!
642 if (!session
[s
].dns1
&& config
->default_dns1
)
644 session
[s
].dns1
= htonl(config
->default_dns1
);
645 LOG(3, s
, t
, " Sending dns1 = %s\n", fmtaddr(config
->default_dns1
, 0));
647 if (!session
[s
].dns2
&& config
->default_dns2
)
649 session
[s
].dns2
= htonl(config
->default_dns2
);
650 LOG(3, s
, t
, " Sending dns2 = %s\n", fmtaddr(config
->default_dns2
, 0));
653 // Valid Session, set it up
654 session
[s
].unique_id
= 0;
659 // An ack for a stop or start record.
660 LOG(3, s
, t
, " RADIUS accounting ack recv in state %s\n", radius_states
[radius
[r
].state
]);
665 // finished with RADIUS
669 // Send a retry for RADIUS/CHAP message
670 void radiusretry(u16 r
)
672 sessionidt s
= radius
[r
].session
;
675 CSTAT(call_radiusretry
);
678 t
= session
[s
].tunnel
;
679 radius
[r
].retry
= backoff(radius
[r
].try + 1);
680 switch (radius
[r
].state
)
682 case RADIUSCHAP
: // sending CHAP down PPP
686 sendipcp(t
, s
); // send IPCP
688 case RADIUSAUTH
: // sending auth to RADIUS server
689 radiussend(r
, RADIUSAUTH
);
691 case RADIUSSTART
: // sending start accounting to RADIUS server
692 radiussend(r
, RADIUSSTART
);
694 case RADIUSSTOP
: // sending stop accounting to RADIUS server
695 radiussend(r
, RADIUSSTOP
);
698 case RADIUSNULL
: // Not in use
699 case RADIUSWAIT
: // waiting timeout before available, in case delayed reply from RADIUS server
700 // free up RADIUS task
702 LOG(3, s
, session
[s
].tunnel
, "Freeing up radius session %d\n", r
);