2 // $Id: radius.c,v 1.4 2004-06-23 03:52:24 fred_nerk Exp $
7 #include <sys/socket.h>
11 #include <arpa/inet.h>
13 #include <netinet/in.h>
15 #include "constants.h"
20 extern radiust
*radius
;
21 extern sessiont
*session
;
22 extern tunnelt
*tunnel
;
24 extern struct configt
*config
;
27 const char *radius_state(int state
)
29 static char *tmp
= NULL
;
31 for (i
= 0; radius_states
[i
]; i
++)
32 if (i
== state
) return radius_states
[i
];
34 if (tmp
== NULL
) tmp
= (char *)calloc(64, 1);
35 sprintf(tmp
, "%d", state
);
39 // Set up socket for radius requests
43 log(3, 0, 0, 0, "Creating %d sockets for RADIUS queries\n", config
->num_radfds
);
44 radfds
= calloc(sizeof(int), config
->num_radfds
);
45 for (i
= 0; i
< config
->num_radfds
; i
++)
48 if (!radfds
[i
]) radfds
[i
] = socket(AF_INET
, SOCK_DGRAM
, UDP
);
49 flags
= fcntl(radfds
[i
], F_GETFL
, 0);
50 fcntl(radfds
[i
], F_SETFL
, flags
| O_NONBLOCK
);
54 void radiusclear(u16 r
, sessionidt s
)
56 if (s
) session
[s
].radius
= 0;
57 memset(&radius
[r
], 0, sizeof(radius
[r
])); // radius[r].state = RADIUSNULL;
60 int next_radius_id
= 1;
62 static u16
new_radius()
66 for (i
= next_radius_id
; ; i
= (i
+ 1) % MAXRADIUS
)
68 if (radius
[i
].state
== RADIUSNULL
)
70 next_radius_id
= (next_radius_id
+ 1) % MAXRADIUS
;
73 if (next_radius_id
== i
)
77 log(0, 0, 0, 0, "Can't find a free radius session! This is very bad!\n");
84 u16
radiusnew(sessionidt s
)
87 if (!(r
= new_radius()))
89 log(1, 0, s
, session
[s
].tunnel
, "No free RADIUS sessions\n");
90 STAT(radius_overflow
);
93 memset(&radius
[r
], 0, sizeof(radius
[r
]));
94 session
[s
].radius
= r
;
95 radius
[r
].session
= s
;
96 radius
[r
].state
= RADIUSWAIT
;
97 radius
[r
].retry
= config
->current_time
+ 1200; // Wait at least 120 seconds to re-claim this.
99 log(3,0,s
, session
[s
].tunnel
, "Allocated radius %d\n", r
);
103 // Send a RADIUS request
104 void radiussend(u16 r
, u8 state
)
106 struct sockaddr_in addr
;
107 u8 b
[4096]; // RADIUS packet
113 STAT(call_radiussend
);
115 s
= radius
[r
].session
;
116 if (!config
->numradiusservers
)
118 log(0, 0, s
, session
[s
].tunnel
, "No RADIUS servers\n");
121 if (!*config
->radiussecret
)
123 log(0, 0, s
, session
[s
].tunnel
, "No RADIUS secret\n");
127 if (state
!= RADIUSAUTH
&& !config
->radius_accounting
)
129 // Radius accounting is turned off
134 if (radius
[r
].state
!= state
)
136 radius
[r
].state
= state
;
137 radius
[r
].retry
= backoff(radius
[r
].try++);
138 log(4, 0, s
, session
[s
].tunnel
, "Send RADIUS id %d sock %d state %s try %d\n",
139 r
>> RADIUS_SHIFT
, r
& RADIUS_MASK
,
140 radius_state(radius
[r
].state
), radius
[r
].try);
141 if (radius
[r
].try > config
->numradiusservers
* 2)
145 if (state
== RADIUSAUTH
)
146 sessionshutdown(s
, "RADIUS timeout");
149 log(1, 0, s
, session
[s
].tunnel
, "RADIUS timeout, but in state %s so don't timeout session\n",
150 radius_states
[state
]);
153 STAT(radius_timeout
);
157 STAT(radius_retries
);
158 radius
[r
].state
= RADIUSWAIT
;
159 radius
[r
].retry
= 100;
163 // contruct RADIUS access request
167 b
[0] = 1; // access request
171 b
[0] = 4; // accounting request
174 log(0, 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
)
237 *p
= 40; // accounting type
239 *(u32
*) (p
+ 2) = htonl((state
== RADIUSSTART
) ? 1 : 2);
243 *p
= 44; // session ID
245 sprintf(p
+ 2, "%08X%08X", session
[s
].id
, session
[s
].opened
);
247 if (state
== RADIUSSTOP
)
249 *p
= 42; // input octets
251 *(u32
*) (p
+ 2) = htonl(session
[s
].cin
);
253 *p
= 43; // output octets
255 *(u32
*) (p
+ 2) = htonl(session
[s
].cout
);
257 *p
= 46; // session time
259 *(u32
*) (p
+ 2) = htonl(time(NULL
) - session
[s
].opened
);
261 *p
= 47; // input packets
263 *(u32
*) (p
+ 2) = htonl(session
[s
].pin
);
265 *p
= 48; // output spackets
267 *(u32
*) (p
+ 2) = htonl(session
[s
].pout
);
274 *(u32
*) (p
+ 2) = htonl(time(NULL
) - session
[s
].opened
);
283 *(u32
*) (p
+ 2) = htonl(s
);
286 if (s
&& session
[s
].ip
)
288 *p
= 8; // Framed-IP-Address
290 *(u32
*) (p
+ 2) = htonl(session
[s
].ip
);
293 if (*session
[s
].called
)
296 p
[1] = strlen(session
[s
].called
) + 2;
297 strcpy(p
+ 2, session
[s
].called
);
300 if (*radius
[r
].calling
)
303 p
[1] = strlen(radius
[r
].calling
) + 2;
304 strcpy(p
+ 2, radius
[r
].calling
);
307 else if (*session
[s
].calling
)
310 p
[1] = strlen(session
[s
].calling
) + 2;
311 strcpy(p
+ 2, session
[s
].calling
);
317 *(u32
*)(p
+ 2) = config
->bind_address
;
321 *(u16
*) (b
+ 2) = htons(p
- b
);
322 if (state
!= RADIUSAUTH
)
324 // Build auth for accounting packet
329 MD5Update(&ctx
, b
, 4);
330 MD5Update(&ctx
, z
, 16);
331 MD5Update(&ctx
, b
+ 20, (p
- b
) - 20);
332 MD5Update(&ctx
, config
->radiussecret
, strlen(config
->radiussecret
));
333 MD5Final(hash
, &ctx
);
334 memcpy(b
+ 4, hash
, 16);
335 memcpy(radius
[r
].auth
, hash
, 16);
337 memset(&addr
, 0, sizeof(addr
));
338 addr
.sin_family
= AF_INET
;
339 *(u32
*) & addr
.sin_addr
= config
->radiusserver
[(radius
[r
].try - 1) % config
->numradiusservers
];
340 addr
.sin_port
= htons((state
== RADIUSAUTH
) ? RADPORT
: RADAPORT
);
342 log_hex(5, "RADIUS Send", b
, (p
- b
));
343 sendto(radfds
[r
& RADIUS_MASK
], b
, p
- b
, 0, (void *) &addr
, sizeof(addr
));
346 // process RADIUS response
347 void processrad(u8
*buf
, int len
, char socket_index
)
357 int r_code
, r_id
; // Radius code.
359 r_code
= buf
[0]; // First byte in radius packet.
360 r_id
= buf
[1]; // radius reply indentifier.
363 STAT(call_processrad
);
365 log_hex(5, "RADIUS Response", buf
, len
);
366 if (len
< 20 || len
< ntohs(*(u16
*) (buf
+ 2)))
368 log(1, 0, 0, 0, "Duff RADIUS response length %d\n", len
);
371 len
= ntohs(*(u16
*) (buf
+ 2));
372 r
= socket_index
| (r_id
<< RADIUS_SHIFT
);
373 s
= radius
[r
].session
;
374 log(3, 0, s
, session
[s
].tunnel
, "Received %s, radius %d response for session %u (code %d, id %d)\n",
375 radius_states
[radius
[r
].state
], r
, s
, r_code
, r_id
);
376 if (!s
&& radius
[r
].state
!= RADIUSSTOP
)
378 log(1, 0, s
, session
[s
].tunnel
, " Unexpected RADIUS response\n");
381 if (radius
[r
].state
!= RADIUSAUTH
&& radius
[r
].state
!= RADIUSSTART
&& radius
[r
].state
!= RADIUSSTOP
)
383 log(1, 0, s
, session
[s
].tunnel
, " Unexpected RADIUS response\n");
386 t
= session
[s
].tunnel
;
388 MD5Update(&ctx
, buf
, 4);
389 MD5Update(&ctx
, radius
[r
].auth
, 16);
390 MD5Update(&ctx
, buf
+ 20, len
- 20);
391 MD5Update(&ctx
, config
->radiussecret
, strlen(config
->radiussecret
));
392 MD5Final(hash
, &ctx
);
394 if (memcmp(hash
, buf
+ 4, 16))
396 log(0, 0, s
, session
[s
].tunnel
, " Incorrect auth on RADIUS response!! (wrong secret in radius config?)\n");
397 // radius[r].state = RADIUSWAIT;
399 return; // Do nothing. On timeout, it will try the next radius server.
401 if ((radius
[r
].state
== RADIUSAUTH
&& *buf
!= 2 && *buf
!= 3) ||
402 ((radius
[r
].state
== RADIUSSTART
|| radius
[r
].state
== RADIUSSTOP
) && *buf
!= 5))
404 log(1, 0, s
, session
[s
].tunnel
, " Unexpected RADIUS response %d\n", *buf
);
406 return; // We got something we didn't expect. Let the timeouts take
407 // care off finishing the radius session if that's really correct.
408 // old code. I think incorrect. --mo
409 // radius[r].state = RADIUSWAIT;
410 // break; // Finish the radius sesssion.
412 if (radius
[r
].state
== RADIUSAUTH
)
414 log(4, 0, s
, session
[s
].tunnel
, " Original response is \"%s\"\n", (*buf
== 2) ? "accept" : "reject");
415 // process auth response
419 u8
*p
= makeppp(b
, sizeof(b
), 0, 0, t
, s
, PPPCHAP
);
424 struct param_post_auth packet
= { &tunnel
[t
], &session
[s
], session
[s
].user
, (*buf
== 2), PPPCHAP
};
425 run_plugins(PLUGIN_POST_AUTH
, &packet
);
426 *buf
= packet
.auth_allowed
? 2 : 3;
429 log(3, 0, s
, session
[s
].tunnel
, " CHAP User %s authentication %s.\n", session
[s
].user
,
430 (*buf
== 2) ? "allowed" : "denied");
431 *p
= (*buf
== 2) ? 3 : 4; // ack/nak
433 *(u16
*) (p
+ 2) = ntohs(4); // no message
434 tunnelsend(b
, (p
- b
) + 4, t
); // send it
439 u8
*p
= makeppp(b
, sizeof(b
), 0, 0, t
, s
, PPPPAP
);
444 struct param_post_auth packet
= { &tunnel
[t
], &session
[s
], session
[s
].user
, (*buf
== 2), PPPPAP
};
445 run_plugins(PLUGIN_POST_AUTH
, &packet
);
446 *buf
= packet
.auth_allowed
? 2 : 3;
449 log(3, 0, s
, session
[s
].tunnel
, " PAP User %s authentication %s.\n", session
[s
].user
,
450 (*buf
== 2) ? "allowed" : "denied");
454 *(u16
*) (p
+ 2) = ntohs(5);
455 p
[4] = 0; // no message
456 tunnelsend(b
, (p
- b
) + 5, t
); // send it
462 // Extract IP, routes, etc
465 for (p
= buf
+ 20; p
< e
&& p
[1]; p
+= p
[1])
469 // Statically assigned address
470 log(3, 0, s
, session
[s
].tunnel
, " Radius reply contains IP address %s\n", inet_toa(*(u32
*) (p
+ 2)));
471 session
[s
].ip
= ntohl(*(u32
*) (p
+ 2));
472 session
[s
].ip_pool_index
= -1;
477 log(3, 0, s
, session
[s
].tunnel
, " Radius reply contains primary DNS address %s\n", inet_toa(*(u32
*) (p
+ 2)));
478 session
[s
].dns1
= ntohl(*(u32
*) (p
+ 2));
483 log(3, 0, s
, session
[s
].tunnel
, " Radius reply contains secondary DNS address %s\n", inet_toa(*(u32
*) (p
+ 2)));
484 session
[s
].dns2
= ntohl(*(u32
*) (p
+ 2));
489 ipt ip
= 0, mask
= 0;
494 while (n
< e
&& (isdigit(*n
) || *n
== '.'))
502 u
= u
* 10 + *n
- '0';
509 while (n
< e
&& isdigit(*n
))
510 bits
= bits
* 10 + *n
++ - '0';
511 mask
= (( -1) << (32 - bits
));
513 else if ((ip
>> 24) < 128)
515 else if ((ip
>> 24) < 192)
519 if (routes
== MAXROUTE
)
521 log(1, 0, s
, session
[s
].tunnel
, " Too many routes\n");
526 ips
= strdup(inet_toa(htonl(ip
)));
527 masks
= strdup(inet_toa(htonl(mask
)));
528 log(3, 0, s
, session
[s
].tunnel
, " Radius reply contains route for %s/%s\n", ips
, masks
);
531 session
[s
].route
[routes
].ip
= ip
;
532 session
[s
].route
[routes
].mask
= mask
;
538 // Vendor-Specific Attribute
539 int vendor
= ntohl(*(int *)(p
+ 2));
540 char attrib
= *(p
+ 6);
541 char attrib_length
= *(p
+ 7) - 2;
542 log(3, 0, s
, session
[s
].tunnel
, " Radius reply contains Vendor-Specific. Vendor=%d Attrib=%d Length=%d\n", vendor
, attrib
, attrib_length
);
543 if (attrib_length
== 0) continue;
545 log(3, 0, s
, session
[s
].tunnel
, " Unknown vendor-specific\n");
548 char *avpair
, *value
, *key
, *newp
;
549 avpair
= key
= calloc(attrib_length
+ 1, 1);
550 memcpy(avpair
, p
+ 8, attrib_length
);
551 log(3, 0, s
, session
[s
].tunnel
, " Cisco-Avpair value: %s\n", avpair
);
553 value
= strchr(key
, '=');
557 // Trim quotes off reply string
558 if (*value
== '\'' || *value
== '\"')
562 x
= value
+ strlen(value
) - 1;
563 if (*x
== '\'' || *x
== '\"')
568 newp
= strchr(value
, ',');
569 if (newp
) *newp
++ = 0;
571 struct param_radius_response p
= { &tunnel
[session
[s
].tunnel
], &session
[s
], key
, value
};
572 run_plugins(PLUGIN_RADIUS_RESPONSE
, &p
);
583 log(2, 0, s
, session
[s
].tunnel
, " Authentication denied for %s\n", session
[s
].user
);
584 //FIXME: We should tear down the session here!
588 if (!session
[s
].dns1
&& config
->default_dns1
)
590 session
[s
].dns1
= htonl(config
->default_dns1
);
591 log(3, 0, s
, t
, " Sending dns1 = %s\n", inet_toa(config
->default_dns1
));
593 if (!session
[s
].dns2
&& config
->default_dns2
)
595 session
[s
].dns2
= htonl(config
->default_dns2
);
596 log(3, 0, s
, t
, " Sending dns2 = %s\n", inet_toa(config
->default_dns2
));
599 // Valid Session, set it up
605 // An ack for a stop or start record.
606 log(3, 0, s
, t
, " RADIUS accounting ack recv in state %s\n", radius_states
[radius
[r
].state
]);
611 // finished with RADIUS
615 // Send a retry for RADIUS/CHAP message
616 void radiusretry(u16 r
)
618 sessionidt s
= radius
[r
].session
;
621 STAT(call_radiusretry
);
624 t
= session
[s
].tunnel
;
625 radius
[r
].retry
= backoff(radius
[r
].try + 1);
626 switch (radius
[r
].state
)
628 case RADIUSCHAP
: // sending CHAP down PPP
632 sendipcp(t
, s
); // send IPCP
634 case RADIUSAUTH
: // sending auth to RADIUS server
635 radiussend(r
, RADIUSAUTH
);
637 case RADIUSSTART
: // sending start accounting to RADIUS server
638 radiussend(r
, RADIUSSTART
);
640 case RADIUSSTOP
: // sending stop accounting to RADIUS server
641 radiussend(r
, RADIUSSTOP
);
644 case RADIUSNULL
: // Not in use
645 case RADIUSWAIT
: // waiting timeout before available, in case delayed reply from RADIUS server
646 // free up RADIUS task
648 log(3, 0, s
, session
[s
].tunnel
, "Freeing up radius session %d\n", r
);
657 log(1, 0, 0, 0, "Cleaning radius session array\n");
659 for (i
= 1; i
< MAXRADIUS
; i
++)
661 if (radius
[i
].retry
== 0
662 || !session
[radius
[i
].session
].opened
663 || session
[radius
[i
].session
].die
664 || session
[radius
[i
].session
].tunnel
== 0)