CHAP support

This commit is contained in:
Brendan O'Dea 2005-01-07 07:18:33 +00:00
parent 04d0b477be
commit 5e68a154b6

225
l2tpns.c
View file

@ -1,10 +1,10 @@
// L2TP Network Server
// Adrian Kennard 2002
// Copyright (c) 2003, 2004 Optus Internet Engineering
// Copyright (c) 2003, 2004, 2005 Optus Internet Engineering
// Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
// vim: sw=8 ts=8
char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.74 2004-12-18 01:20:05 bodea Exp $";
char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.75 2005-01-07 07:18:33 bodea Exp $";
#include <arpa/inet.h>
#include <assert.h>
@ -62,6 +62,7 @@ int clifd = -1; // Socket listening for CLI connections.
int snoopfd = -1; // UDP file handle for sending out intercept data
int *radfds = NULL; // RADIUS requests file handles
int ifrfd = -1; // File descriptor for routing, etc
static int rand_fd = -1; // Random data source
time_t basetime = 0; // base clock
char hostname[1000] = ""; // us.
static uint32_t sessionid = 0; // session id for radius accounting
@ -94,6 +95,7 @@ config_descriptt config_values[] = {
CONFIG("debug", debug, INT),
CONFIG("log_file", log_filename, STRING),
CONFIG("pid_file", pid_file, STRING),
CONFIG("random_device", random_device, STRING),
CONFIG("l2tp_secret", l2tpsecret, STRING),
CONFIG("primary_dns", default_dns1, IPv4),
CONFIG("secondary_dns", default_dns2, IPv4),
@ -104,6 +106,7 @@ config_descriptt config_values[] = {
CONFIG("secondary_radius_port", radiusport[1], SHORT),
CONFIG("radius_accounting", radius_accounting, BOOL),
CONFIG("radius_secret", radiussecret, STRING),
CONFIG("radius_authtypes", radius_authtypes_s, STRING),
CONFIG("bind_address", bind_address, IPv4),
CONFIG("peer_address", peer_address, IPv4),
CONFIG("send_garp", send_garp, BOOL),
@ -203,7 +206,6 @@ clockt backoff(uint8_t try)
void _log(int level, sessionidt s, tunnelidt t, const char *format, ...)
{
static char message[65536] = {0};
static char message2[65536] = {0};
va_list ap;
#ifdef RINGBUFFER
@ -227,18 +229,13 @@ void _log(int level, sessionidt s, tunnelidt t, const char *format, ...)
if (config->debug < level) return;
va_start(ap, format);
vsnprintf(message, sizeof(message), format, ap);
if (log_stream)
{
vsnprintf(message2, 65535, format, ap);
snprintf(message, 65535, "%s %02d/%02d %s", time_now_string, t, s, message2);
fprintf(log_stream, "%s", message);
}
fprintf(log_stream, "%s %02d/%02d %s", time_now_string, t, s, message);
else if (syslog_log)
{
vsnprintf(message2, 65535, format, ap);
snprintf(message, 65535, "%02d/%02d %s", t, s, message2);
syslog(level + 2, message); // We don't need LOG_EMERG or LOG_ALERT
}
syslog(level + 2, "%02d/%02d %s", t, s, message); // We don't need LOG_EMERG or LOG_ALERT
va_end(ap);
}
@ -293,6 +290,72 @@ void _log_hex(int level, const char *title, const char *data, int maxsize)
}
}
// initialise the random generator
static void initrandom(char *source)
{
static char path[sizeof(config->random_device)] = "*undefined*";
// reinitialise only if we are forced to do so or if the config has changed
if (source && !strncmp(path, source, sizeof(path)))
return;
// close previous source, if any
if (rand_fd >= 0) close(rand_fd);
rand_fd = -1;
if (source)
{
// register changes
snprintf(path, sizeof(path), "%s", source);
if (*path == '/')
{
rand_fd = open(path, O_RDONLY|O_NONBLOCK);
if (rand_fd < 0)
LOG(0, 0, 0, "Error opening the random device %s: %s\n",
path, strerror(errno));
}
}
// no source: seed prng
{
unsigned seed = time_now ^ getpid();
LOG(4, 0, 0, "Seeding the pseudo random generator: %u\n", seed);
srand(seed);
}
}
// fill buffer with random data
void random_data(uint8_t *buf, int len)
{
int n = 0;
CSTAT(random_data);
if (rand_fd >= 0)
{
n = read(rand_fd, buf, len);
if (n >= len) return;
if (n < 0)
{
if (errno != EAGAIN)
{
LOG(0, 0, 0, "Error reading from random source: %s\n",
strerror(errno));
// fall back to rand()
initrandom(0);
}
n = 0;
}
}
// append missing data
while (n < len)
// not using the low order bits from the prng stream
buf[n++] = (rand() >> 4) & 0xff;
}
// Add a route
//
@ -476,7 +539,7 @@ static int lookup_ipmap(in_addr_t ip)
sessionidt sessionbyip(in_addr_t ip)
{
int s = lookup_ipmap(ip);
CSTAT(call_sessionbyip);
CSTAT(sessionbyip);
if (s > 0 && s < MAXSESSION && session[s].tunnel)
return (sessionidt) s;
@ -576,7 +639,7 @@ int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc)
sessionidt sessionbyuser(char *username)
{
int s;
CSTAT(call_sessionbyuser);
CSTAT(sessionbyuser);
for (s = 1; s < MAXSESSION ; ++s)
{
@ -640,7 +703,7 @@ void tunnelsend(uint8_t * buf, uint16_t l, tunnelidt t)
{
struct sockaddr_in addr;
CSTAT(call_tunnelsend);
CSTAT(tunnelsend);
if (!t)
{
@ -716,7 +779,7 @@ static void processipout(uint8_t * buf, int len)
uint8_t b[MAXETHER + 20];
CSTAT(call_processipout);
CSTAT(processipout);
if (len < MIN_IP_SIZE)
{
@ -1051,7 +1114,7 @@ void sessionshutdown(sessionidt s, char *reason)
int walled_garden = session[s].walled_garden;
CSTAT(call_sessionshutdown);
CSTAT(sessionshutdown);
if (!session[s].tunnel)
{
@ -1079,9 +1142,7 @@ void sessionshutdown(sessionidt s, char *reason)
}
else
{
int n;
for (n = 0; n < 15; n++)
radius[r].auth[n] = rand();
random_data(radius[r].auth, sizeof(radius[r].auth));
}
}
@ -1142,7 +1203,7 @@ void sendipcp(tunnelidt t, sessionidt s)
uint16_t r = session[s].radius;
uint8_t *q;
CSTAT(call_sendipcp);
CSTAT(sendipcp);
if (!r)
r = radiusnew(s);
@ -1181,7 +1242,7 @@ void sendipcp(tunnelidt t, sessionidt s)
static void sessionkill(sessionidt s, char *reason)
{
CSTAT(call_sessionkill);
CSTAT(sessionkill);
session[s].die = now();
sessionshutdown(s, reason); // close radius/routes, etc.
@ -1211,7 +1272,7 @@ static void tunnelkill(tunnelidt t, char *reason)
sessionidt s;
controlt *c;
CSTAT(call_tunnelkill);
CSTAT(tunnelkill);
tunnel[t].state = TUNNELDIE;
@ -1241,7 +1302,7 @@ static void tunnelshutdown(tunnelidt t, char *reason)
{
sessionidt s;
CSTAT(call_tunnelshutdown);
CSTAT(tunnelshutdown);
if (!tunnel[t].last || !tunnel[t].far || tunnel[t].state == TUNNELFREE)
{
@ -1276,7 +1337,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
uint8_t *p = buf + 2;
CSTAT(call_processudp);
CSTAT(processudp);
udp_rx += len;
udp_rx_pkt++;
@ -1523,12 +1584,12 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
b += 2;
n -= 6;
LOG(4, s, t, " AVP %d (%s) len %d\n", mtype, avpnames[mtype], n);
LOG(4, s, t, " AVP %d (%s) len %d\n", mtype, avp_name(mtype), n);
switch (mtype)
{
case 0: // message type
message = ntohs(*(uint16_t *) b);
LOG(4, s, t, " Message type = %d (%s)\n", *b, l2tp_message_types[message]);
LOG(4, s, t, " Message type = %d (%s)\n", *b, l2tp_message_type(message));
mandatorymessage = flags;
break;
case 1: // result code
@ -1537,23 +1598,18 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
const char* resdesc = "(unknown)";
if (message == 4)
{ /* StopCCN */
if (rescode <= MAX_STOPCCN_RESULT_CODE)
resdesc = stopccn_result_codes[rescode];
resdesc = stopccn_result_code(rescode);
}
else if (message == 14)
{ /* CDN */
if (rescode <= MAX_CDN_RESULT_CODE)
resdesc = cdn_result_codes[rescode];
resdesc = cdn_result_code(rescode);
}
LOG(4, s, t, " Result Code %d: %s\n", rescode, resdesc);
if (n >= 4)
{
uint16_t errcode = ntohs(*(uint16_t *)(b + 2));
const char* errdesc = "(unknown)";
if (errcode <= MAX_ERROR_CODE)
errdesc = error_codes[errcode];
LOG(4, s, t, " Error Code %d: %s\n", errcode, errdesc);
LOG(4, s, t, " Error Code %d: %s\n", errcode, error_code(errcode));
}
if (n > 4)
LOG(4, s, t, " Error String: %.*s\n", n-4, b+4);
@ -1681,9 +1737,9 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
}
case 29: // Proxy Authentication Type
{
uint16_t authtype = ntohs(*(uint16_t *)b);
LOG(4, s, t, " Proxy Auth Type %d (%s)\n", authtype, authtypes[authtype]);
requestchap = (authtype == 2);
uint16_t atype = ntohs(*(uint16_t *)b);
LOG(4, s, t, " Proxy Auth Type %d (%s)\n", atype, auth_type(atype));
requestchap = (atype == 2);
break;
}
case 30: // Proxy Authentication Name
@ -1827,12 +1883,9 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
LOG(3, s, t, "New session (%d/%d)\n", tunnel[t].far, session[s].far);
control16(c, 14, s, 1); // assigned session
controladd(c, t, s); // send the reply
{
// Generate a random challenge
int n;
for (n = 0; n < 15; n++)
radius[r].auth[n] = rand();
}
// Generate a random challenge
random_data(radius[r].auth, sizeof(radius[r].auth));
strncpy(radius[r].calling, calling, sizeof(radius[r].calling) - 1);
strncpy(session[s].called, called, sizeof(session[s].called) - 1);
strncpy(session[s].calling, calling, sizeof(session[s].calling) - 1);
@ -1982,7 +2035,7 @@ static void processtun(uint8_t * buf, int len)
STAT(tun_rx_packets);
INC_STAT(tun_rx_bytes, len);
CSTAT(call_processtun);
CSTAT(processtun);
eth_rx_pkt++;
eth_rx += len;
@ -2625,6 +2678,7 @@ static void initdata(int optdebug, char *optconfig)
config->debug = optdebug;
config->num_tbfs = MAXTBFS;
config->rl_rate = 28; // 28kbps
strcpy(config->random_device, RANDOMDEVICE);
if (!(tunnel = shared_malloc(sizeof(tunnelt) * MAXTUNNEL)))
{
@ -2655,12 +2709,12 @@ static void initdata(int optdebug, char *optconfig)
exit(1);
}
if (!(ip_filters = shared_malloc(sizeof(ip_filtert) * MAXFILTER)))
{
LOG(0, 0, 0, "Error doing malloc for ip_filters: %s\n", strerror(errno));
exit(1);
}
memset(ip_filters, 0, sizeof(ip_filtert) * MAXFILTER);
if (!(ip_filters = shared_malloc(sizeof(ip_filtert) * MAXFILTER)))
{
LOG(0, 0, 0, "Error doing malloc for ip_filters: %s\n", strerror(errno));
exit(1);
}
memset(ip_filters, 0, sizeof(ip_filtert) * MAXFILTER);
#ifdef RINGBUFFER
if (!(ringbuffer = shared_malloc(sizeof(struct Tringbuffer))))
@ -2730,7 +2784,7 @@ static int assign_ip_address(sessionidt s)
char reuse = 0;
CSTAT(call_assign_ip_address);
CSTAT(assign_ip_address);
for (i = 1; i < ip_pool_size; i++)
{
@ -2783,7 +2837,7 @@ static void free_ip_address(sessionidt s)
int i = session[s].ip_pool_index;
CSTAT(call_free_ip_address);
CSTAT(free_ip_address);
if (!session[s].ip)
return; // what the?
@ -3054,7 +3108,7 @@ static void dump_acct_info(int all)
FILE *f = NULL;
CSTAT(call_dump_acct_info);
CSTAT(dump_acct_info);
if (shut_acct_n)
{
@ -3128,7 +3182,7 @@ int main(int argc, char *argv[])
init_tbf(config->num_tbfs);
LOG(0, 0, 0, "L2TPNS version " VERSION "\n");
LOG(0, 0, 0, "Copyright (c) 2003, 2004 Optus Internet Engineering\n");
LOG(0, 0, 0, "Copyright (c) 2003, 2004, 2005 Optus Internet Engineering\n");
LOG(0, 0, 0, "Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced\n");
{
struct rlimit rlim;
@ -3533,6 +3587,7 @@ static int facility_value(char *name)
static void update_config()
{
int i;
char *p;
static int timeout = 0;
static int interval = 0;
@ -3544,6 +3599,7 @@ static void update_config()
fclose(log_stream);
log_stream = NULL;
}
if (*config->log_filename)
{
if (strstr(config->log_filename, "syslog:") == config->log_filename)
@ -3575,7 +3631,6 @@ static void update_config()
setbuf(log_stream, NULL);
}
// Update radius
config->numradiusservers = 0;
for (i = 0; i < MAXRADSERVER; i++)
@ -3600,6 +3655,59 @@ static void update_config()
config->num_radfds = 2 << RADIUS_SHIFT;
// parse radius_authtypes_s
config->radius_authtypes = config->radius_authprefer = 0;
p = config->radius_authtypes_s;
while (*p)
{
char *s = strpbrk(p, " \t,");
int type = 0;
if (s)
{
*s++ = 0;
while (*s == ' ' || *s == '\t')
s++;
if (!*s)
s = 0;
}
if (!strncasecmp("chap", p, strlen(p)))
type = AUTHCHAP;
else if (!strncasecmp("pap", p, strlen(p)))
type = AUTHPAP;
else
LOG(0, 0, 0, "Invalid RADIUS authentication type \"%s\"", p);
config->radius_authtypes |= type;
if (!config->radius_authprefer)
config->radius_authprefer = type;
}
if (!config->radius_authtypes)
{
LOG(0, 0, 0, "Defaulting to PAP authentication\n");
config->radius_authtypes = config->radius_authprefer = AUTHPAP;
}
// normalise radius_authtypes_s
if (config->radius_authprefer == AUTHPAP)
{
strcpy(config->radius_authtypes_s, "pap");
if (config->radius_authtypes & AUTHCHAP)
strcat(config->radius_authtypes_s, ", chap");
}
else
{
strcpy(config->radius_authtypes_s, "chap");
if (config->radius_authtypes & AUTHPAP)
strcat(config->radius_authtypes_s, ", pap");
}
// re-initialise the random number source
initrandom(config->random_device);
// Update plugins
for (i = 0; i < MAXPLUGINS; i++)
{
@ -3617,6 +3725,7 @@ static void update_config()
remove_plugin(config->old_plugins[i]);
}
}
memcpy(config->old_plugins, config->plugins, sizeof(config->plugins));
if (!config->cleanup_interval) config->cleanup_interval = 10;
if (!config->multi_read_count) config->multi_read_count = 10;
@ -3695,7 +3804,7 @@ int sessionsetup(tunnelidt t, sessionidt s)
sessionidt i;
int r;
CSTAT(call_sessionsetup);
CSTAT(sessionsetup);
LOG(3, s, t, "Doing session setup for session\n");