/*
* See ``COPYRIGHT.mpd''
*
* $Id: radius.c,v 1.83 2007/08/10 11:06:39 amotin Exp $
*
*/
#include "ppp.h"
#ifdef PHYSTYPE_PPPOE
#include "pppoe.h"
#endif
#ifdef PHYSTYPE_MODEM
#include "modem.h"
#endif
#ifdef PHYSTYPE_NG_SOCKET
#include "ng.h"
#endif
#include "util.h"
#include <sys/types.h>
#include <radlib.h>
#include <radlib_vs.h>
/* Global variables */
static int RadiusSetCommand(Context ctx, int ac, char *av[], void *arg);
static int RadiusAddServer(AuthData auth, short request_type);
static int RadiusOpen(AuthData auth, short request_type);
static int RadiusStart(AuthData auth, short request_type);
static int RadiusPutAuth(AuthData auth);
static int RadiusGetParams(AuthData auth, int eap_proxy);
static int RadiusSendRequest(AuthData auth);
/* Set menu options */
enum {
SET_SERVER,
SET_ME,
SET_MEV6,
SET_TIMEOUT,
SET_RETRIES,
SET_CONFIG,
SET_ENABLE,
SET_DISABLE,
};
/*
* GLOBAL VARIABLES
*/
const struct cmdtab RadiusSetCmds[] = {
{ "server <name> <secret> [auth port] [acct port]", "Set radius server parameters" ,
RadiusSetCommand, NULL, (void *) SET_SERVER },
{ "me <ip>", "Set NAS IP address" ,
RadiusSetCommand, NULL, (void *) SET_ME },
{ "v6me <ip>", "Set NAS IPv6 address" ,
RadiusSetCommand, NULL, (void *) SET_MEV6 },
{ "timeout <seconds>", "Set timeout in seconds",
RadiusSetCommand, NULL, (void *) SET_TIMEOUT },
{ "retries <# retries>", "set number of retries",
RadiusSetCommand, NULL, (void *) SET_RETRIES },
{ "config <path to radius.conf>", "set path to config file for libradius",
RadiusSetCommand, NULL, (void *) SET_CONFIG },
{ "enable [opt ...]", "Enable option",
RadiusSetCommand, NULL, (void *) SET_ENABLE },
{ "disable [opt ...]", "Disable option",
RadiusSetCommand, NULL, (void *) SET_DISABLE },
{ NULL },
};
/*
* INTERNAL VARIABLES
*/
static struct confinfo gConfList[] = {
{ 0, RADIUS_CONF_MESSAGE_AUTHENTIC, "message-authentic" },
{ 0, RADIUS_CONF_PEER_AS_CALLING, "peer-as-calling" },
{ 0, 0, NULL },
};
/*
* RadiusInit()
*/
void
RadiusInit(Link l)
{
RadConf const conf = &l->lcp.auth.conf.radius;
memset(conf, 0, sizeof(*conf));
Disable(&conf->options, RADIUS_CONF_MESSAGE_AUTHENTIC);
Enable(&conf->options, RADIUS_CONF_PEER_AS_CALLING);
conf->radius_retries = 3;
conf->radius_timeout = 5;
}
int
RadiusAuthenticate(AuthData auth)
{
Log(LG_RADIUS, ("[%s] RADIUS: %s for: %s",
auth->info.lnkname, __func__, auth->params.authname));
if ((RadiusStart(auth, RAD_ACCESS_REQUEST) == RAD_NACK) ||
(RadiusPutAuth(auth) == RAD_NACK) ||
(RadiusSendRequest(auth) == RAD_NACK)) {
return RAD_NACK;
}
return RAD_ACK;
}
/*
* RadiusEapProxy()
*
* paction handler for RADIUS EAP Proxy requests.
* Thread-Safety is needed here
* auth->status must be set to AUTH_STATUS_FAIL, if the
* request couldn't sent, because for EAP a successful
* RADIUS request is mandatory
*/
void
RadiusEapProxy(void *arg)
{
AuthData auth = (AuthData)arg;
int pos = 0, mlen = RAD_MAX_ATTR_LEN;
if (RadiusStart(auth, RAD_ACCESS_REQUEST) == RAD_NACK) {
auth->status = AUTH_STATUS_FAIL;
return;
}
if (rad_put_string(auth->radius.handle, RAD_USER_NAME, auth->params.authname) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS-EAP: %s: rad_put_string(RAD_USER_NAME) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
auth->status = AUTH_STATUS_FAIL;
return;
}
for (pos = 0; pos <= auth->params.eapmsg_len; pos += RAD_MAX_ATTR_LEN) {
char chunk[RAD_MAX_ATTR_LEN];
if (pos + RAD_MAX_ATTR_LEN > auth->params.eapmsg_len)
mlen = auth->params.eapmsg_len - pos;
memcpy(chunk, &auth->params.eapmsg[pos], mlen);
if (rad_put_attr(auth->radius.handle, RAD_EAP_MESSAGE, chunk, mlen) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS-EAP: %s: rad_put_attr(RAD_EAP_MESSAGE) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
auth->status = AUTH_STATUS_FAIL;
return;
}
#ifdef DEBUG
Log(LG_RADIUS, ("[%s] RADIUS-EAP: chunk:%d len:%d",
auth->info.lnkname, pos / RAD_MAX_ATTR_LEN, mlen));
#endif
}
if (RadiusSendRequest(auth) == RAD_NACK) {
auth->status = AUTH_STATUS_FAIL;
return;
}
return;
}
/*
* RadiusAccount()
*
* Do RADIUS accounting
* NOTE: thread-safety is needed here
*/
void
RadiusAccount(AuthData auth)
{
char *username;
int authentic;
Log(LG_RADIUS, ("[%s] RADIUS: %s for: %s (Type: %d)",
auth->info.lnkname, __func__, auth->params.authname, auth->acct_type));
if (auth->params.authentic == AUTH_CONF_RADIUS_AUTH) {
authentic = RAD_AUTH_RADIUS;
} else {
authentic = RAD_AUTH_LOCAL;
}
if (RadiusStart(auth, RAD_ACCOUNTING_REQUEST) == RAD_NACK)
return;
if (auth->acct_type == AUTH_ACCT_START) {
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_STATUS_TYPE): RAD_START",
auth->info.lnkname, __func__));
if (rad_put_int(auth->radius.handle, RAD_ACCT_STATUS_TYPE, RAD_START)) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(STATUS_TYPE): %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
}
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_addr(RAD_FRAMED_IP_ADDRESS): %s",
auth->info.lnkname, __func__, inet_ntoa(auth->info.peer_addr)));
if (rad_put_addr(auth->radius.handle, RAD_FRAMED_IP_ADDRESS, auth->info.peer_addr)) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_addr(RAD_FRAMED_IP_ADDRESS): %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
if (auth->params.netmask != 0) {
struct in_addr ip;
widthtoin_addr(auth->params.netmask, &ip);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_addr(RAD_FRAMED_IP_NETMASK): %s",
auth->info.lnkname, __func__, inet_ntoa(ip)));
if (rad_put_addr(auth->radius.handle, RAD_FRAMED_IP_NETMASK, ip)) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_addr(RAD_FRAMED_IP_NETMASK): %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
}
#if 0
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_addr(RAD_FRAMED_IP_NETMASK): %s",
auth->info.lnkname, __func__, inet_ntoa(ac->mask)));
if (rad_put_addr(auth->radius.handle, RAD_FRAMED_IP_NETMASK, ac->mask) != 0) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_addr(RAD_FRAMED_IP_NETMASK): %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
#endif
username = auth->params.authname;
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_string(RAD_USER_NAME): %s",
auth->info.lnkname, __func__, username));
if (rad_put_string(auth->radius.handle, RAD_USER_NAME, username) != 0) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(RAD_USER_NAME): %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_string(RAD_ACCT_SESSION_ID): %s",
auth->info.lnkname, __func__, auth->info.session_id));
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_string(RAD_ACCT_MULTI_SESSION_ID): %s",
auth->info.lnkname, __func__, auth->info.msession_id));
if (rad_put_string(auth->radius.handle, RAD_ACCT_SESSION_ID, auth->info.session_id) != 0 ||
rad_put_string(auth->radius.handle, RAD_ACCT_MULTI_SESSION_ID, auth->info.msession_id) != 0) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: put (SESSION_ID, MULTI_SESSION_ID): %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_LINK_COUNT): %d",
auth->info.lnkname, __func__, auth->info.n_links));
if (rad_put_int(auth->radius.handle, RAD_ACCT_LINK_COUNT, auth->info.n_links) != 0) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_LINK_COUNT) failed: %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_AUTHENTIC): %d",
auth->info.lnkname, __func__, authentic));
if (rad_put_int(auth->radius.handle, RAD_ACCT_AUTHENTIC, authentic) != 0) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_AUTHENTIC) failed: %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
if (auth->acct_type == AUTH_ACCT_STOP
|| auth->acct_type == AUTH_ACCT_UPDATE) {
if (auth->acct_type == AUTH_ACCT_STOP) {
int termCause = RAD_TERM_PORT_ERROR;
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_STATUS_TYPE): RAD_STOP",
auth->info.lnkname, __func__));
if (rad_put_int(auth->radius.handle, RAD_ACCT_STATUS_TYPE, RAD_STOP)) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_STATUS_TYPE): %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
if ((auth->info.downReason == NULL) || (!strcmp(auth->info.downReason, ""))) {
termCause = RAD_TERM_NAS_REQUEST;
} else if (!strncmp(auth->info.downReason, STR_MANUALLY, strlen(STR_MANUALLY))) {
termCause = RAD_TERM_ADMIN_RESET;
} else if (!strncmp(auth->info.downReason, STR_PEER_DISC, strlen(STR_PEER_DISC))) {
termCause = RAD_TERM_USER_REQUEST;
} else if (!strncmp(auth->info.downReason, STR_ADMIN_SHUTDOWN, strlen(STR_ADMIN_SHUTDOWN))) {
termCause = RAD_TERM_ADMIN_REBOOT;
} else if (!strncmp(auth->info.downReason, STR_FATAL_SHUTDOWN, strlen(STR_FATAL_SHUTDOWN))) {
termCause = RAD_TERM_NAS_REBOOT;
} else if (!strncmp(auth->info.downReason, STR_IDLE_TIMEOUT, strlen(STR_IDLE_TIMEOUT))) {
termCause = RAD_TERM_IDLE_TIMEOUT;
} else if (!strncmp(auth->info.downReason, STR_SESSION_TIMEOUT, strlen(STR_SESSION_TIMEOUT))) {
termCause = RAD_TERM_SESSION_TIMEOUT;
} else if (!strncmp(auth->info.downReason, STR_DROPPED, strlen(STR_DROPPED))) {
termCause = RAD_TERM_LOST_CARRIER;
} else if (!strncmp(auth->info.downReason, STR_ECHO_TIMEOUT, strlen(STR_ECHO_TIMEOUT))) {
termCause = RAD_TERM_LOST_SERVICE;
} else if (!strncmp(auth->info.downReason, STR_PROTO_ERR, strlen(STR_PROTO_ERR))) {
termCause = RAD_TERM_SERVICE_UNAVAILABLE;
} else if (!strncmp(auth->info.downReason, STR_LOGIN_FAIL, strlen(STR_LOGIN_FAIL))) {
termCause = RAD_TERM_USER_ERROR;
} else if (!strncmp(auth->info.downReason, STR_PORT_UNNEEDED, strlen(STR_PORT_UNNEEDED))) {
termCause = RAD_TERM_PORT_UNNEEDED;
};
Log(LG_RADIUS, ("[%s] RADIUS: Termination cause: %s, RADIUS: %d",
auth->info.lnkname, auth->info.downReason, termCause));
if (rad_put_int(auth->radius.handle, RAD_ACCT_TERMINATE_CAUSE, termCause) != 0) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_TERMINATE_CAUSE) failed: %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
} else {
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_STATUS_TYPE): RAD_UPDATE",
auth->info.lnkname, __func__));
if (rad_put_int(auth->radius.handle, RAD_ACCT_STATUS_TYPE, RAD_UPDATE)) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(STATUS_TYPE): %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
}
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_SESSION_TIME): %ld",
auth->info.lnkname, __func__, (long int)(time(NULL) - auth->info.last_open)));
if (rad_put_int(auth->radius.handle, RAD_ACCT_SESSION_TIME, time(NULL) - auth->info.last_open) != 0) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_SESSION_TIME) failed: %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return;
}
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_INPUT_OCTETS): %lu",
auth->info.lnkname, __func__, (long unsigned int)(auth->info.stats.recvOctets % MAX_U_INT32)));
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_INPUT_PACKETS): %lu",
auth->info.lnkname, __func__, (long unsigned int)(auth->info.stats.recvFrames)));
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_OUTPUT_OCTETS): %lu",
auth->info.lnkname, __func__, (long unsigned int)(auth->info.stats.xmitOctets % MAX_U_INT32)));
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_OUTPUT_PACKETS): %lu",
auth->info.lnkname, __func__, (long unsigned int)(auth->info.stats.xmitFrames)));
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_INPUT_GIGAWORDS): %lu",
auth->info.lnkname, __func__, (long unsigned int)(auth->info.stats.recvOctets / MAX_U_INT32)));
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_ACCT_OUTPUT_GIGAWORDS): %lu",
auth->info.lnkname, __func__, (long unsigned int)(auth->info.stats.xmitOctets / MAX_U_INT32)));
if (rad_put_int(auth->radius.handle, RAD_ACCT_INPUT_OCTETS, auth->info.stats.recvOctets % MAX_U_INT32) != 0 ||
rad_put_int(auth->radius.handle, RAD_ACCT_INPUT_PACKETS, auth->info.stats.recvFrames) != 0 ||
rad_put_int(auth->radius.handle, RAD_ACCT_OUTPUT_OCTETS, auth->info.stats.xmitOctets % MAX_U_INT32) != 0 ||
rad_put_int(auth->radius.handle, RAD_ACCT_OUTPUT_PACKETS, auth->info.stats.xmitFrames) != 0 ||
rad_put_int(auth->radius.handle, RAD_ACCT_INPUT_GIGAWORDS, auth->info.stats.recvOctets / MAX_U_INT32) != 0 ||
rad_put_int(auth->radius.handle, RAD_ACCT_OUTPUT_GIGAWORDS, auth->info.stats.xmitOctets / MAX_U_INT32) != 0) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: put stats: %s", auth->info.lnkname, __func__,
rad_strerror(auth->radius.handle)));
return;
}
}
Log(LG_RADIUS2, ("[%s] RADIUS: %s: Sending accounting data (Type: %d)",
auth->info.lnkname, __func__, auth->acct_type));
RadiusSendRequest(auth);
}
void
RadiusClose(AuthData auth)
{
if (auth->radius.handle != NULL)
rad_close(auth->radius.handle);
auth->radius.handle = NULL;
}
int
RadStat(Context ctx, int ac, char *av[], void *arg)
{
Auth const a = &ctx->lnk->lcp.auth;
RadConf const conf = &a->conf.radius;
int i;
char *buf;
RadServe_Conf server;
char buf1[64];
Printf("Configuration:\r\n");
Printf("\tTimeout : %d\r\n", conf->radius_timeout);
Printf("\tRetries : %d\r\n", conf->radius_retries);
Printf("\tConfig-file : %s\r\n", (conf->file ? conf->file : "none"));
Printf("\tMe (NAS-IP) : %s\r\n", inet_ntoa(conf->radius_me));
Printf("\tv6Me (NAS-IP): %s\r\n", u_addrtoa(&conf->radius_mev6, buf1, sizeof(buf1)));
if (conf->server != NULL) {
server = conf->server;
i = 1;
while (server) {
Printf("\t--------------- Radius Server %d ---------------\r\n", i);
Printf("\thostname : %s\r\n", server->hostname);
Printf("\tsecret : *********\r\n");
Printf("\tauth port : %d\r\n", server->auth_port);
Printf("\tacct port : %d\r\n", server->acct_port);
i++;
server = server->next;
}
}
Printf("RADIUS options\r\n");
OptStat(ctx, &conf->options, gConfList);
Printf("Data:\r\n");
Printf("\tAuthenticated : %s\r\n", a->params.authentic == AUTH_CONF_RADIUS_AUTH ?
"yes" : "no");
buf = Bin2Hex(a->params.state, a->params.state_len);
Printf("\tState : 0x%s\r\n", buf);
Freee(MB_UTIL, buf);
buf = Bin2Hex(a->params.class, a->params.class_len);
Printf("\tClass : 0x%s\r\n", buf);
Freee(MB_UTIL, buf);
return (0);
}
static int
RadiusAddServer(AuthData auth, short request_type)
{
int i;
RadConf const c = &auth->conf.radius;
RadServe_Conf s;
if (c->server == NULL)
return (RAD_ACK);
s = c->server;
i = 1;
while (s) {
Log(LG_RADIUS2, ("[%s] RADIUS: %s Adding %s", auth->info.lnkname, __func__, s->hostname));
if (request_type == RAD_ACCESS_REQUEST) {
if (rad_add_server (auth->radius.handle, s->hostname,
s->auth_port,
s->sharedsecret,
c->radius_timeout,
c->radius_retries) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s error: %s", auth->info.lnkname, __func__,
rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
} else {
if (rad_add_server (auth->radius.handle, s->hostname,
s->acct_port,
s->sharedsecret,
c->radius_timeout,
c->radius_retries) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s error: %s", auth->info.lnkname, __func__,
rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
}
s = s->next;
}
return (RAD_ACK);
}
/* Set menu options */
static int
RadiusSetCommand(Context ctx, int ac, char *av[], void *arg)
{
RadConf const conf = &ctx->lnk->lcp.auth.conf.radius;
RadServe_Conf server;
RadServe_Conf t_server;
int val, count;
struct u_addr t;
if (ac == 0)
return(-1);
switch ((intptr_t)arg) {
case SET_SERVER:
if (ac > 4 || ac < 2) {
return(-1);
}
count = 0;
for ( t_server = conf->server ; t_server ;
t_server = t_server->next) {
count++;
}
if (count > RADIUS_MAX_SERVERS) {
Log(LG_RADIUS, ("[%s] %s: cannot configure more than %d servers",
ctx->lnk->name, __func__, RADIUS_MAX_SERVERS));
return (-1);
}
server = Malloc(MB_RADIUS, sizeof(*server));
server->auth_port = 1812;
server->acct_port = 1813;
server->next = NULL;
if (strlen(av[0]) > 255) {
Log(LG_ERR, ("RADIUS: Hostname too long. > 255 char."));
return(-1);
}
if (strlen(av[1]) > 127) {
Log(LG_ERR, ("RADIUS: Shared Secret too long. > 127 char."));
return(-1);
}
if (ac > 2 && atoi(av[2]) < 65535 && atoi(av[2]) > 1) {
server->auth_port = atoi (av[2]);
} else if ( ac > 2 ) {
Log(LG_ERR, ("RADIUS: Auth Port number too high. > 65535"));
return(-1);
}
if (ac > 3 && atoi(av[3]) < 65535 && atoi(av[3]) > 1) {
server->acct_port = atoi (av[3]);
} else if ( ac > 3 ) {
Log(LG_ERR, ("RADIUS: Acct Port number too high > 65535"));
return(-1);
}
server->hostname = Malloc(MB_RADIUS, strlen(av[0]) + 1);
server->sharedsecret = Malloc(MB_RADIUS, strlen(av[1]) + 1);
sprintf(server->hostname, "%s" , av[0]);
sprintf(server->sharedsecret, "%s" , av[1]);
if (conf->server != NULL)
server->next = conf->server;
conf->server = server;
break;
case SET_ME:
if (ParseAddr(*av, &t, ALLOW_IPV4)) {
u_addrtoin_addr(&t,&conf->radius_me);
} else {
Log(LG_ERR, ("RADIUS: Bad NAS address '%s'.", *av));
}
break;
case SET_MEV6:
if (!ParseAddr(*av, &conf->radius_mev6, ALLOW_IPV6)) {
Log(LG_ERR, ("RADIUS: Bad NAS address '%s'.", *av));
}
break;
case SET_TIMEOUT:
val = atoi(*av);
if (val <= 0)
Log(LG_ERR, ("RADIUS: Timeout must be positive."));
else
conf->radius_timeout = val;
break;
case SET_RETRIES:
val = atoi(*av);
if (val <= 0)
Log(LG_ERR, ("RADIUS: Retries must be positive."));
else
conf->radius_retries = val;
break;
case SET_CONFIG:
if (strlen(av[0]) > PATH_MAX) {
Log(LG_ERR, ("RADIUS: Config file name too long."));
} else {
if (conf->file)
Freee(MB_RADIUS, conf->file);
conf->file = Malloc(MB_RADIUS, strlen(av[0])+1);
strcpy(conf->file, av[0]);
}
break;
case SET_ENABLE:
EnableCommand(ac, av, &conf->options, gConfList);
break;
case SET_DISABLE:
DisableCommand(ac, av, &conf->options, gConfList);
break;
default:
assert(0);
}
return 0;
}
static int
RadiusOpen(AuthData auth, short request_type)
{
RadConf const conf = &auth->conf.radius;
if (request_type == RAD_ACCESS_REQUEST) {
auth->radius.handle = rad_open();
if (auth->radius.handle == NULL) {
Log(LG_RADIUS, ("[%s] RADIUS: rad_open failed", auth->info.lnkname));
return (RAD_NACK);
}
/* RAD_ACCOUNTING_REQUEST */
} else {
auth->radius.handle = rad_acct_open();
if (auth->radius.handle == NULL) {
Log(LG_RADIUS, ("[%s] RADIUS: rad_acct_open failed", auth->info.lnkname));
return (RAD_NACK);
}
}
if (conf->file && strlen(conf->file)) {
Log(LG_RADIUS2, ("[%s] RADIUS: using %s", auth->info.lnkname, conf->file));
if (rad_config(auth->radius.handle, conf->file) != 0) {
Log(LG_RADIUS, ("[%s] RADIUS: rad_config: %s", auth->info.lnkname,
rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
}
if (RadiusAddServer(auth, request_type) == RAD_NACK)
return (RAD_NACK);
return RAD_ACK;
}
static int
RadiusStart(AuthData auth, short request_type)
{
RadConf const conf = &auth->conf.radius;
char host[MAXHOSTNAMELEN];
int porttype;
char buf[64];
char *tmpval;
if (RadiusOpen(auth, request_type) == RAD_NACK)
return RAD_NACK;
if (rad_create_request(auth->radius.handle, request_type) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: rad_create_request: %s",
auth->info.lnkname, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
if (gethostname(host, sizeof(host)) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: gethostname() failed",
auth->info.lnkname, __func__));
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_string(RAD_NAS_IDENTIFIER): %s",
auth->info.lnkname, __func__, host));
if (rad_put_string(auth->radius.handle, RAD_NAS_IDENTIFIER, host) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(RAD_NAS_IDENTIFIER) failed %s", auth->info.lnkname,
__func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
if (conf->radius_me.s_addr != 0) {
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_addr(RAD_NAS_IP_ADDRESS): %s",
auth->info.lnkname, __func__, inet_ntoa(conf->radius_me)));
if (rad_put_addr(auth->radius.handle, RAD_NAS_IP_ADDRESS, conf->radius_me) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_addr(RAD_NAS_IP_ADDRESS) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
}
if (!u_addrempty(&conf->radius_mev6)) {
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_addr(RAD_NAS_IPV6_ADDRESS): %s",
auth->info.lnkname, __func__, u_addrtoa(&conf->radius_mev6,buf,sizeof(buf))));
if (rad_put_attr(auth->radius.handle, RAD_NAS_IPV6_ADDRESS, &conf->radius_mev6.u.ip6, sizeof(conf->radius_mev6.u.ip6)) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_addr(RAD_NAS_IPV6_ADDRESS) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
}
#if (!defined(__FreeBSD__) || __FreeBSD_version >= 503100)
/* Insert the Message Authenticator RFC 3579
* If using EAP this is mandatory
*/
if ((Enabled(&conf->options, RADIUS_CONF_MESSAGE_AUTHENTIC)
|| auth->proto == PROTO_EAP)
&& request_type != RAD_ACCOUNTING_REQUEST) {
Log(LG_RADIUS2, ("[%s] RADIUS: Adding Message Authenticator", auth->info.lnkname));
if (rad_put_message_authentic(auth->radius.handle) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_message_authentic failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
}
#endif
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_NAS_PORT): %d",
auth->info.lnkname, __func__, auth->info.linkID));
if (rad_put_int(auth->radius.handle, RAD_NAS_PORT, auth->info.linkID) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_NAS_PORT) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
#ifdef PHYSTYPE_MODEM
if (auth->info.phys_type == &gModemPhysType) {
porttype = RAD_ASYNC;
} else
#endif
#ifdef PHYSTYPE_NG_SOCKET
if (auth->info.phys_type == &gNgPhysType) {
porttype = RAD_SYNC;
} else
#endif
#ifdef PHYSTYPE_PPPOE
if (auth->info.phys_type == &gPppoePhysType) {
porttype = RAD_ETHERNET;
} else
#endif
{
porttype = RAD_VIRTUAL;
};
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_NAS_PORT_TYPE): %d",
auth->info.lnkname, __func__, porttype));
if (rad_put_int(auth->radius.handle, RAD_NAS_PORT_TYPE, porttype) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_NAS_PORT_TYPE) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_SERVICE_TYPE): RAD_FRAMED",
auth->info.lnkname, __func__));
if (rad_put_int(auth->radius.handle, RAD_SERVICE_TYPE, RAD_FRAMED) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_SERVICE_TYPE) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_int(RAD_FRAMED_PROTOCOL): RAD_PPP",
auth->info.lnkname, __func__));
if (rad_put_int(auth->radius.handle, RAD_FRAMED_PROTOCOL, RAD_PPP) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_FRAMED_PROTOCOL) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
if (auth->params.state != NULL) {
tmpval = Bin2Hex(auth->params.state, auth->params.state_len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_attr(RAD_STATE): 0x%s", auth->info.lnkname, __func__, tmpval));
Freee(MB_UTIL, tmpval);
if (rad_put_attr(auth->radius.handle, RAD_STATE, auth->params.state, auth->params.state_len) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_attr(RAD_STATE) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
}
if (auth->params.class != NULL) {
tmpval = Bin2Hex(auth->params.class, auth->params.class_len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_attr(RAD_CLASS): 0x%s", auth->info.lnkname, __func__, tmpval));
Freee(MB_UTIL, tmpval);
if (rad_put_attr(auth->radius.handle, RAD_CLASS, auth->params.class, auth->params.class_len) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_attr(RAD_CLASS) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
}
/* For compatibility and for untrusted peers use peeraddr as calling */
if (Enabled(&conf->options, RADIUS_CONF_PEER_AS_CALLING)) {
if (strlen(auth->params.peeraddr)) {
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_string(RAD_CALLING_STATION_ID) %s",
auth->info.lnkname, __func__, auth->params.peeraddr));
if (rad_put_string(auth->radius.handle, RAD_CALLING_STATION_ID,
auth->params.peeraddr) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(RAD_CALLING_STATION_ID) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
}
} else {
if (strlen(auth->params.callingnum)) {
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_string(RAD_CALLING_STATION_ID) %s",
auth->info.lnkname, __func__, auth->params.callingnum));
if (rad_put_string(auth->radius.handle, RAD_CALLING_STATION_ID,
auth->params.callingnum) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(RAD_CALLING_STATION_ID) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
}
}
if (strlen(auth->params.callednum)) {
Log(LG_RADIUS2, ("[%s] RADIUS: %s: rad_put_string(RAD_CALLED_STATION_ID) %s",
auth->info.lnkname, __func__, auth->params.callednum));
if (rad_put_string(auth->radius.handle, RAD_CALLED_STATION_ID,
auth->params.callednum) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(RAD_CALLED_STATION_ID) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
}
return RAD_ACK;
}
static int
RadiusPutAuth(AuthData auth)
{
ChapParams const cp = &auth->params.chap;
PapParams const pp = &auth->params.pap;
struct rad_chapvalue rad_chapval;
struct rad_mschapvalue rad_mschapval;
struct rad_mschapv2value rad_mschapv2val;
struct mschapvalue *mschapval;
struct mschapv2value *mschapv2val;
if (rad_put_string(auth->radius.handle, RAD_USER_NAME, auth->params.authname) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(username) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
if (auth->proto == PROTO_CHAP || auth->proto == PROTO_EAP) {
switch (cp->recv_alg) {
case CHAP_ALG_MSOFT:
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv1) peer name: %s",
auth->info.lnkname, __func__, auth->params.authname));
if (cp->value_len != 49) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv1) unrecognised key length %d/%d",
auth->info.lnkname, __func__, cp->value_len, 49));
return (RAD_NACK);
}
if (rad_put_vendor_attr(auth->radius.handle, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP_CHALLENGE,
cp->chal_data, cp->chal_len) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP_CHALLENGE) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
mschapval = (struct mschapvalue *)cp->value;
rad_mschapval.ident = auth->id;
rad_mschapval.flags = 0x01;
memcpy(rad_mschapval.lm_response, mschapval->lmHash, 24);
memcpy(rad_mschapval.nt_response, mschapval->ntHash, 24);
if (rad_put_vendor_attr(auth->radius.handle, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP_RESPONSE,
&rad_mschapval, sizeof(rad_mschapval)) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP_RESPONSE) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
break;
case CHAP_ALG_MSOFTv2:
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv2) peer name: %s",
auth->info.lnkname, __func__, auth->params.authname));
if (rad_put_vendor_attr(auth->radius.handle, RAD_VENDOR_MICROSOFT,
RAD_MICROSOFT_MS_CHAP_CHALLENGE, cp->chal_data, cp->chal_len) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP_CHALLENGE) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
if (cp->value_len != sizeof(*mschapv2val)) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv2) unrecognised key length %d/%d", auth->info.lnkname,
__func__, cp->value_len, (int)sizeof(*mschapv2val)));
return (RAD_NACK);
}
mschapv2val = (struct mschapv2value *)cp->value;
rad_mschapv2val.ident = auth->id;
rad_mschapv2val.flags = mschapv2val->flags;
memcpy(rad_mschapv2val.response, mschapv2val->ntHash,
sizeof(rad_mschapv2val.response));
memset(rad_mschapv2val.reserved, '\0',
sizeof(rad_mschapv2val.reserved));
memcpy(rad_mschapv2val.pchallenge, mschapv2val->peerChal,
sizeof(rad_mschapv2val.pchallenge));
if (rad_put_vendor_attr(auth->radius.handle, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP2_RESPONSE,
&rad_mschapv2val, sizeof(rad_mschapv2val)) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP2_RESPONSE) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
break;
case CHAP_ALG_MD5:
/* RADIUS requires the CHAP Ident in the first byte of the CHAP-Password */
rad_chapval.ident = auth->id;
memcpy(rad_chapval.response, cp->value, cp->value_len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RADIUS_CHAP (MD5) peer name: %s",
auth->info.lnkname, __func__, auth->params.authname));
if (rad_put_attr(auth->radius.handle, RAD_CHAP_PASSWORD, &rad_chapval, cp->value_len + 1) == -1 ||
rad_put_attr(auth->radius.handle, RAD_CHAP_CHALLENGE, cp->chal_data, cp->chal_len) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(password) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
break;
default:
Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS unkown CHAP ALG %d",
auth->info.lnkname, __func__, cp->recv_alg));
return (RAD_NACK);
}
} else if (auth->proto == PROTO_PAP) {
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RADIUS_PAP peer name: %s",
auth->info.lnkname, __func__, auth->params.authname));
if (rad_put_string(auth->radius.handle, RAD_USER_PASSWORD, pp->peer_pass) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(password) failed %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return (RAD_NACK);
}
} else {
Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS unkown Proto %d",
auth->info.lnkname, __func__, auth->proto));
return (RAD_NACK);
}
return (RAD_ACK);
}
static int
RadiusSendRequest(AuthData auth)
{
struct timeval timelimit;
struct timeval tv;
int fd, n;
Log(LG_RADIUS2, ("[%s] RADIUS: %s: username: %s",
auth->info.lnkname, __func__, auth->params.authname));
n = rad_init_send_request(auth->radius.handle, &fd, &tv);
if (n != 0) {
Log(LG_RADIUS, ("[%s] RADIUS: rad_init_send_request failed: %d %s",
auth->info.lnkname, n, rad_strerror(auth->radius.handle)));
return RAD_NACK;
}
gettimeofday(&timelimit, NULL);
timeradd(&tv, &timelimit, &timelimit);
for ( ; ; ) {
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;
fds[0].revents = 0;
n = poll(fds,1,tv.tv_sec*1000+tv.tv_usec/1000);
if (n == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: poll failed %s", auth->info.lnkname,
strerror(errno)));
return RAD_NACK;
}
if ((fds[0].revents&POLLIN)!=POLLIN) {
/* Compute a new timeout */
gettimeofday(&tv, NULL);
timersub(&timelimit, &tv, &tv);
if (tv.tv_sec > 0 || (tv.tv_sec == 0 && tv.tv_usec > 0))
/* Continue the select */
continue;
}
Log(LG_RADIUS2, ("[%s] RADIUS: %s: username: %s trying",
auth->info.lnkname, __func__, auth->params.authname));
n = rad_continue_send_request(auth->radius.handle, n, &fd, &tv);
if (n != 0)
break;
gettimeofday(&timelimit, NULL);
timeradd(&tv, &timelimit, &timelimit);
}
switch (n) {
case RAD_ACCESS_ACCEPT:
Log(LG_RADIUS, ("[%s] RADIUS: rec'd RAD_ACCESS_ACCEPT for user %s",
auth->info.lnkname, auth->params.authname));
auth->status = AUTH_STATUS_SUCCESS;
auth->params.authentic = AUTH_CONF_RADIUS_AUTH;
break;
case RAD_ACCESS_CHALLENGE:
Log(LG_RADIUS, ("[%s] RADIUS: rec'd RAD_ACCESS_CHALLENGE for user %s",
auth->info.lnkname, auth->params.authname));
break;
case RAD_ACCESS_REJECT:
Log(LG_RADIUS, ("[%s] RADIUS: rec'd RAD_ACCESS_REJECT for user %s",
auth->info.lnkname, auth->params.authname));
auth->status = AUTH_STATUS_FAIL;
break;
case RAD_ACCOUNTING_RESPONSE:
Log(LG_RADIUS, ("[%s] RADIUS: rec'd RAD_ACCOUNTING_RESPONSE for user %s",
auth->info.lnkname, auth->params.authname));
break;
case -1:
Log(LG_RADIUS, ("[%s] RADIUS: rad_send_request failed: %s",
auth->info.lnkname, rad_strerror(auth->radius.handle)));
return(RAD_NACK);
default:
Log(LG_RADIUS, ("[%s] RADIUS: rad_send_request: unexpected return value: %d",
auth->info.lnkname, n));
return(RAD_NACK);
}
RadiusGetParams(auth, n == RAD_ACCESS_CHALLENGE);
return RAD_ACK;
}
static int
RadiusGetParams(AuthData auth, int eap_proxy)
{
ChapParams const cp = &auth->params.chap;
int res, i, j;
size_t len;
const void *data;
u_int32_t vendor;
char *route, *acl, *acl1, *acl2;
char *tmpval;
short got_mppe_keys = FALSE;
struct in_addr ip;
struct acl **acls, *acls1;
struct ifaceroute *r, *r1;
struct u_range range;
#if (!defined(__FreeBSD__) || __FreeBSD_version >= 503100)
u_char *tmpkey;
size_t tmpkey_len;
#endif
Freee(MB_AUTH, auth->params.eapmsg);
auth->params.eapmsg = NULL;
while ((res = rad_get_attr(auth->radius.handle, &data, &len)) > 0) {
switch (res) {
case RAD_STATE:
tmpval = Bin2Hex(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_STATE: 0x%s", auth->info.lnkname, __func__, tmpval));
Freee(MB_UTIL, tmpval);
auth->params.state_len = len;
if (auth->params.state != NULL)
Freee(MB_AUTH, auth->params.state);
auth->params.state = Malloc(MB_AUTH, len);
memcpy(auth->params.state, data, len);
continue;
case RAD_CLASS:
tmpval = Bin2Hex(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_CLASS: 0x%s", auth->info.lnkname, __func__, tmpval));
Freee(MB_UTIL, tmpval);
auth->params.class_len = len;
if (auth->params.class != NULL)
Freee(MB_AUTH, auth->params.class);
auth->params.class = Malloc(MB_AUTH, len);
memcpy(auth->params.class, data, len);
continue;
/* libradius already checks the message-authenticator, so simply ignore it */
case RAD_MESSAGE_AUTHENTIC:
Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MESSAGE_AUTHENTIC", auth->info.lnkname, __func__));
continue;
case RAD_EAP_MESSAGE:
if (auth->params.eapmsg != NULL) {
char *tbuf;
#ifdef DEBUG
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_EAP_MESSAGE (continued) Len:%d",
auth->info.lnkname, __func__, auth->params.eapmsg_len + len));
#endif
tbuf = Malloc(MB_AUTH, auth->params.eapmsg_len + len);
memcpy(tbuf, auth->params.eapmsg, auth->params.eapmsg_len);
memcpy(&tbuf[auth->params.eapmsg_len], data, len);
auth->params.eapmsg_len += len;
Freee(MB_AUTH, auth->params.eapmsg);
auth->params.eapmsg = tbuf;
} else {
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_EAP_MESSAGE", auth->info.lnkname, __func__));
auth->params.eapmsg = Malloc(MB_AUTH, len);
memcpy(auth->params.eapmsg, data, len);
auth->params.eapmsg_len = len;
}
continue;
}
if (!eap_proxy)
switch (res) {
case RAD_FRAMED_IP_ADDRESS:
ip = rad_cvt_addr(data);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_FRAMED_IP_ADDRESS: %s ",
auth->info.lnkname, __func__, inet_ntoa(ip)));
if (strcmp(inet_ntoa(ip), "255.255.255.255") == 0) {
/* the peer can choose an address */
Log(LG_RADIUS2, (" the peer can choose an address"));
ip.s_addr=0;
in_addrtou_range(&ip, 0, &auth->params.range);
auth->params.range_valid = 1;
} else if (strcmp(inet_ntoa(ip), "255.255.255.254") == 0) {
/* we should choose the ip */
Log(LG_RADIUS2, (" we should choose an address"));
auth->params.range_valid = 0;
} else {
/* or use IP from Radius-server */
in_addrtou_range(&ip, 32, &auth->params.range);
auth->params.range_valid = 1;
}
break;
case RAD_USER_NAME:
tmpval = rad_cvt_string(data, len);
/* copy it into the persistent data struct */
strcpy(auth->params.authname, tmpval);
free(tmpval);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_USER_NAME: %s ",
auth->info.lnkname, __func__, auth->params.authname));
break;
case RAD_FRAMED_IP_NETMASK:
ip = rad_cvt_addr(data);
auth->params.netmask = in_addrtowidth(&ip);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_FRAMED_IP_NETMASK: %s (/%d) ",
auth->info.lnkname, __func__, inet_ntoa(ip), auth->params.netmask));
break;
case RAD_FRAMED_ROUTE:
route = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_FRAMED_ROUTE: %s ",
auth->info.lnkname, __func__, route));
if (!ParseRange(route, &range, ALLOW_IPV4)) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_ROUTE: Bad route \"%s\"", auth->info.lnkname, __func__, route));
free(route);
break;
}
free(route);
r = Malloc(MB_AUTH, sizeof(struct ifaceroute));
r->dest = range;
r->ok = 0;
j = 0;
SLIST_FOREACH(r1, &auth->params.routes, next) {
if (!u_rangecompare(&r->dest, &r1->dest)) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: Duplicate route", auth->info.lnkname, __func__));
j = 1;
}
};
if (j == 0) {
SLIST_INSERT_HEAD(&auth->params.routes, r, next);
} else {
Freee(MB_AUTH, r);
}
break;
case RAD_FRAMED_IPV6_ROUTE:
route = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_FRAMED_IPV6_ROUTE: %s ",
auth->info.lnkname, __func__, route));
if (!ParseRange(route, &range, ALLOW_IPV6)) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_IPV6_ROUTE: Bad route \"%s\"", auth->info.lnkname, __func__, route));
free(route);
break;
}
free(route);
r = Malloc(MB_AUTH, sizeof(struct ifaceroute));
r->dest = range;
r->ok = 0;
j = 0;
SLIST_FOREACH(r1, &auth->params.routes, next) {
if (!u_rangecompare(&r->dest, &r1->dest)) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: Duplicate route", auth->info.lnkname, __func__));
j = 1;
}
};
if (j == 0) {
SLIST_INSERT_HEAD(&auth->params.routes, r, next);
} else {
Freee(MB_AUTH, r);
}
break;
case RAD_SESSION_TIMEOUT:
auth->params.session_timeout = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_SESSION_TIMEOUT: %u ",
auth->info.lnkname, __func__, auth->params.session_timeout));
break;
case RAD_IDLE_TIMEOUT:
auth->params.idle_timeout = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_IDLE_TIMEOUT: %u ",
auth->info.lnkname, __func__, auth->params.idle_timeout));
break;
case RAD_ACCT_INTERIM_INTERVAL:
auth->params.acct_update = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_ACCT_INTERIM_INTERVAL: %u ",
auth->info.lnkname, __func__, auth->params.acct_update));
break;
case RAD_FRAMED_MTU:
i = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_FRAMED_MTU: %u ",
auth->info.lnkname, __func__, i));
if (i < IFACE_MIN_MTU || i > IFACE_MAX_MTU) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_MTU: invalid MTU: %u ",
auth->info.lnkname, __func__, i));
auth->params.mtu = 0;
break;
}
auth->params.mtu = i;
break;
case RAD_FRAMED_COMPRESSION:
Log(LG_RADIUS2, ("[%s] RADIUS: %s: (RAD_FRAMED_COMPRESSION: %d)",
auth->info.lnkname, __func__, rad_cvt_int(data)));
break;
case RAD_FRAMED_PROTOCOL:
Log(LG_RADIUS2, ("[%s] RADIUS: %s: (RAD_FRAMED_PROTOCOL: %d)",
auth->info.lnkname, __func__, rad_cvt_int(data)));
break;
case RAD_FRAMED_ROUTING:
Log(LG_RADIUS2, ("[%s] RADIUS: %s: (RAD_FRAMED_ROUTING: %d)",
auth->info.lnkname, __func__, rad_cvt_int(data)));
break;
case RAD_FILTER_ID:
tmpval = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: (RAD_FILTER_ID: %s)",
auth->info.lnkname, __func__, tmpval));
free(tmpval);
break;
case RAD_SERVICE_TYPE:
Log(LG_RADIUS2, ("[%s] RADIUS: %s: (RAD_SERVICE_TYPE: %d)",
auth->info.lnkname, __func__, rad_cvt_int(data)));
break;
case RAD_REPLY_MESSAGE:
tmpval = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_REPLY_MESSAGE: %s ",
auth->info.lnkname, __func__, auth->reply_message));
auth->reply_message = Malloc(MB_AUTH, len + 1);
memcpy(auth->reply_message, tmpval, len + 1);
free(tmpval);
break;
case RAD_VENDOR_SPECIFIC:
if ((res = rad_get_vendor_attr(&vendor, &data, &len)) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_get_vendor_attr failed: %s ",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return RAD_NACK;
}
switch (vendor) {
case RAD_VENDOR_MICROSOFT:
switch (res) {
case RAD_MICROSOFT_MS_CHAP_ERROR:
if (auth->mschap_error != NULL) {
Freee(MB_AUTH, auth->mschap_error);
auth->mschap_error = NULL;
}
if (len == 0)
break;
/* there is a nullbyte on the first pos, don't know why */
if (((const char *)data)[0] == '\0') {
data = (const char *)data + 1;
len--;
}
tmpval = rad_cvt_string(data, len);
auth->mschap_error = Malloc(MB_AUTH, len + 1);
memcpy(auth->mschap_error, tmpval, len + 1);
free(tmpval);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: MS-CHAP-Error: %s",
auth->info.lnkname, __func__, auth->mschap_error));
break;
/* this was taken from userland ppp */
case RAD_MICROSOFT_MS_CHAP2_SUCCESS:
if (auth->mschapv2resp != NULL) {
Freee(MB_AUTH, auth->mschapv2resp);
auth->mschapv2resp = NULL;
}
if (len == 0)
break;
if (len < 3 || ((const char *)data)[1] != '=') {
/*
* Only point at the String field if we don't think the
* peer has misformatted the response.
*/
data = (const char *)data + 1;
len--;
} else {
Log(LG_RADIUS, ("[%s] RADIUS: %s: Warning: The MS-CHAP2-Success attribute is mis-formatted. Compensating",
auth->info.lnkname, __func__));
}
if ((tmpval = rad_cvt_string((const char *)data, len)) == NULL) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_cvt_string failed: %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return RAD_NACK;
}
auth->mschapv2resp = Malloc(MB_AUTH, len + 1);
memcpy(auth->mschapv2resp, tmpval, len + 1);
free(tmpval);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_CHAP2_SUCCESS: %s",
auth->info.lnkname, __func__, auth->mschapv2resp));
break;
case RAD_MICROSOFT_MS_CHAP_DOMAIN:
Freee(MB_AUTH, auth->params.msdomain);
tmpval = rad_cvt_string(data, len);
auth->params.msdomain = Malloc(MB_AUTH, len + 1);
memcpy(auth->params.msdomain, tmpval, len + 1);
free(tmpval);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_CHAP_DOMAIN: %s",
auth->info.lnkname, __func__, auth->params.msdomain));
break;
#if (!defined(__FreeBSD__) || __FreeBSD_version >= 503100)
/* MPPE Keys MS-CHAPv2 and EAP-TLS */
case RAD_MICROSOFT_MS_MPPE_RECV_KEY:
got_mppe_keys = TRUE;
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_RECV_KEY",
auth->info.lnkname, __func__));
tmpkey = rad_demangle_mppe_key(auth->radius.handle, data, len, &tmpkey_len);
if (!tmpkey) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_demangle_mppe_key failed: %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return RAD_NACK;
}
memcpy(auth->params.msoft.recv_key, tmpkey, MPPE_KEY_LEN);
free(tmpkey);
auth->params.msoft.has_keys = TRUE;
break;
case RAD_MICROSOFT_MS_MPPE_SEND_KEY:
got_mppe_keys = TRUE;
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_SEND_KEY",
auth->info.lnkname, __func__));
tmpkey = rad_demangle_mppe_key(auth->radius.handle, data, len, &tmpkey_len);
if (!tmpkey) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_demangle_mppe_key failed: %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return RAD_NACK;
}
memcpy(auth->params.msoft.xmit_key, tmpkey, MPPE_KEY_LEN);
free(tmpkey);
auth->params.msoft.has_keys = TRUE;
break;
/* MPPE Keys MS-CHAPv1 */
case RAD_MICROSOFT_MS_CHAP_MPPE_KEYS:
got_mppe_keys = TRUE;
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_CHAP_MPPE_KEYS",
auth->info.lnkname, __func__));
if (len != 32) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: Server returned garbage %d of expected %d Bytes",
auth->info.lnkname, __func__, (int)len, 32));
return RAD_NACK;
}
tmpkey = rad_demangle(auth->radius.handle, data, len);
if (tmpkey == NULL) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_demangle failed: %s",
auth->info.lnkname, __func__, rad_strerror(auth->radius.handle)));
return RAD_NACK;
}
memcpy(auth->params.msoft.lm_hash, tmpkey, sizeof(auth->params.msoft.lm_hash));
auth->params.msoft.has_lm_hash = TRUE;
memcpy(auth->params.msoft.nt_hash_hash, &tmpkey[8], sizeof(auth->params.msoft.nt_hash_hash));
free(tmpkey);
break;
#endif
case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
auth->params.msoft.policy = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: %d (%s)",
auth->info.lnkname, __func__, auth->params.msoft.policy, AuthMPPEPolicyname(auth->params.msoft.policy)));
break;
case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
{
char buf[64];
auth->params.msoft.types = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: %d (%s)",
auth->info.lnkname, __func__, auth->params.msoft.types,
AuthMPPETypesname(auth->params.msoft.types, buf, sizeof(buf))));
}
break;
default:
Log(LG_RADIUS2, ("[%s] RADIUS: %s: Dropping MICROSOFT vendor specific attribute: %d ",
auth->info.lnkname, __func__, res));
break;
}
break;
case RAD_VENDOR_MPD:
if (res == RAD_MPD_RULE) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MPD_RULE: %s",
auth->info.lnkname, __func__, acl));
acls = &(auth->params.acl_rule);
} else if (res == RAD_MPD_PIPE) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MPD_PIPE: %s",
auth->info.lnkname, __func__, acl));
acls = &(auth->params.acl_pipe);
} else if (res == RAD_MPD_QUEUE) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MPD_QUEUE: %s",
auth->info.lnkname, __func__, acl));
acls = &(auth->params.acl_queue);
} else if (res == RAD_MPD_TABLE) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MPD_TABLE: %s",
auth->info.lnkname, __func__, acl));
acls = &(auth->params.acl_table);
} else if (res == RAD_MPD_TABLE_STATIC) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MPD_TABLE_STATIC: %s",
auth->info.lnkname, __func__, acl));
acls = &(auth->params.acl_table);
} else if (res == RAD_MPD_FILTER) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MPD_FILTER: %s",
auth->info.lnkname, __func__, acl));
acl2 = strsep(&acl1, "#");
i = atol(acl2);
if (i <= 0 || i > ACL_FILTERS) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: wrong filter number: %i",
auth->info.lnkname, __func__, i));
free(acl);
break;
}
acls = &(auth->params.acl_filters[i - 1]);
} else if (res == RAD_MPD_LIMIT) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MPD_LIMIT: %s",
auth->info.lnkname, __func__, acl));
acl2 = strsep(&acl1, "#");
if (strcasecmp(acl2, "in") == 0) {
i = 0;
} else if (strcasecmp(acl2, "out") == 0) {
i = 1;
} else {
Log(LG_ERR, ("[%s] RADIUS: %s: wrong limit direction: '%s'",
auth->info.lnkname, __func__, acl2));
free(acl);
break;
}
acls = &(auth->params.acl_limits[i]);
} else if (res == RAD_MPD_DROP_USER) {
auth->drop_user = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: %s: RAD_MPD_DROP_USER: %d",
auth->info.lnkname, __func__, auth->drop_user));
break;
} else {
Log(LG_RADIUS2, ("[%s] RADIUS: %s: Dropping MPD vendor specific attribute: %d",
auth->info.lnkname, __func__, res));
break;
}
if (acl1 == NULL) {
Log(LG_ERR, ("[%s] RADIUS: %s: incorrect acl!",
auth->info.lnkname, __func__));
break;
}
acl2 = acl1;
acl1 = strsep(&acl2, "=");
i = atol(acl1);
if (i <= 0) {
Log(LG_ERR, ("[%s] RADIUS: %s: wrong acl number: %i",
auth->info.lnkname, __func__, i));
free(acl);
break;
}
if ((acl2 == NULL) && (acl2[0] == 0)) {
Log(LG_ERR, ("[%s] RADIUS: %s: wrong acl", auth->info.lnkname, __func__));
free(acl);
break;
}
acls1 = Malloc(MB_AUTH, sizeof(struct acl));
if (res != RAD_MPD_TABLE_STATIC) {
acls1->number = i;
acls1->real_number = 0;
} else {
acls1->number = 0;
acls1->real_number = i;
}
strncpy(acls1->rule, acl2, ACL_LEN);
while ((*acls != NULL) && ((*acls)->number < acls1->number))
acls = &((*acls)->next);
if (*acls == NULL) {
acls1->next = NULL;
} else if (((*acls)->number == acls1->number) &&
(res != RAD_MPD_TABLE) &&
(res != RAD_MPD_TABLE_STATIC)) {
Log(LG_ERR, ("[%s] RADIUS: %s: duplicate acl",
auth->info.lnkname, __func__));
free(acl);
break;
} else {
acls1->next = *acls;
}
*acls = acls1;
free(acl);
break;
default:
Log(LG_RADIUS2, ("[%s] RADIUS: %s: Dropping vendor %d attribute: %d ",
auth->info.lnkname, __func__, vendor, res));
break;
}
break;
default:
Log(LG_RADIUS2, ("[%s] RADIUS: %s: Dropping attribute: %d ",
auth->info.lnkname, __func__, res));
break;
}
}
/* sanity check, this happens when FreeRADIUS has no msoft-dictionary loaded */
if (auth->proto == PROTO_CHAP && cp->recv_alg == CHAP_ALG_MSOFTv2
&& auth->mschapv2resp == NULL && auth->mschap_error == NULL) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: PANIC no MS-CHAPv2 response received",
auth->info.lnkname, __func__));
return RAD_NACK;
}
/* MPPE allowed or required, but no MPPE keys returned */
/* print warning, because MPPE doesen't work */
if (!got_mppe_keys && auth->params.msoft.policy != MPPE_POLICY_NONE) {
Log(LG_RADIUS, ("[%s] RADIUS: %s: WARNING no MPPE-Keys received, MPPE will not work",
auth->info.lnkname, __func__));
}
/* If no MPPE-Infos are returned by the RADIUS server, then allow all */
/* MSoft IAS sends no Infos if all MPPE-Types are enabled and if encryption is optional */
if (auth->params.msoft.policy == MPPE_POLICY_NONE &&
auth->params.msoft.types == MPPE_TYPE_0BIT &&
got_mppe_keys) {
auth->params.msoft.policy = MPPE_POLICY_ALLOWED;
auth->params.msoft.types = MPPE_TYPE_40BIT | MPPE_TYPE_128BIT | MPPE_TYPE_56BIT;
Log(LG_RADIUS, ("[%s] RADIUS: %s: MPPE-Keys, but no MPPE-Infos received => allowing MPPE with all types",
auth->info.lnkname, __func__));
}
return RAD_ACK;
}
syntax highlighted by Code2HTML, v. 0.9.1