/*
* See ``COPYRIGHT.mpd''
*
* $Id: radius.c,v 1.1.1.4 2016/11/02 09:50:34 misho Exp $
*
*/
#include "ppp.h"
#ifdef PHYSTYPE_PPPOE
#include "pppoe.h"
#endif
#ifdef PHYSTYPE_PPTP
#include "pptp.h"
#endif
#ifdef PHYSTYPE_L2TP
#include "l2tp.h"
#endif
#ifdef PHYSTYPE_TCP
#include "tcp.h"
#endif
#ifdef PHYSTYPE_UDP
#include "udp.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 RadiusPutAcct(AuthData auth);
static int RadiusGetParams(AuthData auth, int eap_proxy);
static int RadiusSendRequest(AuthData auth);
static void RadiusLogError(AuthData auth, const char *errmsg);
/* Set menu options */
enum {
UNSET_SERVER,
SET_SERVER,
#ifdef HAVE_RAD_BIND
SET_SRC_ADDR,
#endif
SET_ME,
SET_MEV6,
SET_IDENTIFIER,
SET_TIMEOUT,
SET_RETRIES,
SET_CONFIG,
SET_ENABLE,
SET_DISABLE
};
/*
* GLOBAL VARIABLES
*/
const struct cmdtab RadiusUnSetCmds[] = {
{ "server {name} [{auth port}] [{acct port}]", "Unset (remove) radius server" ,
RadiusSetCommand, NULL, 2, (void *) UNSET_SERVER },
{ NULL },
};
const struct cmdtab RadiusSetCmds[] = {
{ "server {name} {secret} [{auth port}] [{acct port}]", "Set radius server parameters" ,
RadiusSetCommand, NULL, 2, (void *) SET_SERVER },
#ifdef HAVE_RAD_BIND
{ "src-addr {ip}", "Set source address for request" ,
RadiusSetCommand, NULL, 2, (void *) SET_SRC_ADDR },
#endif
{ "me {ip}", "Set NAS IP address" ,
RadiusSetCommand, NULL, 2, (void *) SET_ME },
{ "v6me {ip}", "Set NAS IPv6 address" ,
RadiusSetCommand, NULL, 2, (void *) SET_MEV6 },
{ "identifier {name}", "Set NAS identifier string" ,
RadiusSetCommand, NULL, 2, (void *) SET_IDENTIFIER },
{ "timeout {seconds}", "Set timeout in seconds",
RadiusSetCommand, NULL, 2, (void *) SET_TIMEOUT },
{ "retries {# retries}", "set number of retries",
RadiusSetCommand, NULL, 2, (void *) SET_RETRIES },
{ "config {path to radius.conf}", "set path to config file for libradius",
RadiusSetCommand, NULL, 2, (void *) SET_CONFIG },
{ "enable [opt ...]", "Enable option",
RadiusSetCommand, NULL, 2, (void *) SET_ENABLE },
{ "disable [opt ...]", "Disable option",
RadiusSetCommand, NULL, 2, (void *) SET_DISABLE },
{ NULL },
};
/*
* INTERNAL VARIABLES
*/
static struct confinfo gConfList[] = {
{ 0, RADIUS_CONF_MESSAGE_AUTHENTIC, "message-authentic" },
{ 0, 0, NULL },
};
#define RAD_NACK 0
#define RAD_ACK 1
static int
rad_put_string_tag(struct rad_handle *h, int type, u_char tag, const char *str);
static int
rad_put_string_tag(struct rad_handle *h, int type, u_char tag, const char *str)
{
char *tmp;
int res;
int len = strlen(str);
if (tag == 0) {
res = rad_put_attr(h, type, str, len);
} else if (tag <= 0x1F) {
tmp = Malloc(MB_RADIUS, len + 1);
tmp[0] = tag;
memcpy(tmp + 1, str, len);
res = rad_put_attr(h, type, tmp, len + 1);
Freee(tmp);
} else {
res = -1;
}
return (res);
}
/*
* RadiusInit()
*/
void
RadiusInit(Link l)
{
RadConf const conf = &l->lcp.auth.conf.radius;
memset(conf, 0, sizeof(*conf));
conf->radius_retries = 3;
conf->radius_timeout = 5;
}
int
RadiusAuthenticate(AuthData auth)
{
Log(LG_RADIUS, ("[%s] RADIUS: Authenticating user '%s'",
auth->info.lnkname, auth->params.authname));
if ((RadiusStart(auth, RAD_ACCESS_REQUEST) == RAD_NACK) ||
(RadiusPutAuth(auth) == RAD_NACK) ||
(RadiusSendRequest(auth) == RAD_NACK)) {
return (-1);
}
return (0);
}
/*
* RadiusAccount()
*
* Do RADIUS accounting
* NOTE: thread-safety is needed here
*/
int
RadiusAccount(AuthData auth)
{
Log(auth->acct_type != AUTH_ACCT_UPDATE ? LG_RADIUS : LG_RADIUS2,
("[%s] RADIUS: Accounting user '%s' (Type: %d)",
auth->info.lnkname, auth->params.authname, auth->acct_type));
if ((RadiusStart(auth, RAD_ACCOUNTING_REQUEST) == RAD_NACK) ||
(RadiusPutAcct(auth) == RAD_NACK) ||
(RadiusSendRequest(auth) == RAD_NACK)) {
return (-1);
}
return (0);
}
/*
* 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;
Log(LG_RADIUS, ("[%s] RADIUS: EAP proxying user '%s'",
auth->info.lnkname, auth->params.authname));
if (RadiusStart(auth, RAD_ACCESS_REQUEST) == RAD_NACK) {
auth->status = AUTH_STATUS_FAIL;
return;
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_USER_NAME: %s",
auth->info.lnkname, auth->params.authname));
if (rad_put_string(auth->radius.handle, RAD_USER_NAME, auth->params.authname) == -1) {
RadiusLogError(auth, "Put RAD_USER_NAME failed");
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;
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_EAP_MESSAGE: len %d of %d",
auth->info.lnkname, mlen, auth->params.eapmsg_len));
memcpy(chunk, &auth->params.eapmsg[pos], mlen);
if (rad_put_attr(auth->radius.handle, RAD_EAP_MESSAGE, chunk, mlen) == -1) {
RadiusLogError(auth, "Put RAD_EAP_MESSAGE failed");
auth->status = AUTH_STATUS_FAIL;
return;
}
}
if (RadiusSendRequest(auth) == RAD_NACK) {
auth->status = AUTH_STATUS_FAIL;
return;
}
return;
}
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"));
#ifdef HAVE_RAD_BIND
Printf("\tSrc address : %s\r\n", inet_ntoa(conf->src_addr));
#endif
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)));
Printf("\tIdentifier : %s\r\n", (conf->identifier ? conf->identifier : ""));
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(buf);
buf = Bin2Hex(a->params.class, a->params.class_len);
Printf("\tClass : 0x%s\r\n", buf);
Freee(buf);
Printf("\tFilter Id : %s\r\n", (a->params.filter_id ? a->params.filter_id : ""));
return (0);
}
static int
RadiusAddServer(AuthData auth, short request_type)
{
RadConf const c = &auth->conf.radius;
RadServe_Conf s;
if (c->server == NULL)
return (RAD_ACK);
s = c->server;
while (s) {
if (request_type == RAD_ACCESS_REQUEST) {
if (s->auth_port != 0) {
Log(LG_RADIUS2, ("[%s] RADIUS: Adding server %s %d", auth->info.lnkname, s->hostname, s->auth_port));
if (rad_add_server (auth->radius.handle, s->hostname,
s->auth_port,
s->sharedsecret,
c->radius_timeout,
c->radius_retries) == -1) {
RadiusLogError(auth, "Adding server error");
return (RAD_NACK);
}
}
} else if (s->acct_port != 0) {
Log(LG_RADIUS2, ("[%s] RADIUS: Adding server %s %d", auth->info.lnkname, s->hostname, s->acct_port));
if (rad_add_server (auth->radius.handle, s->hostname,
s->acct_port,
s->sharedsecret,
c->radius_timeout,
c->radius_retries) == -1) {
RadiusLogError(auth, "Adding server error");
return (RAD_NACK);
}
}
s = s->next;
}
#ifdef HAVE_RAD_BIND
if (c->src_addr.s_addr != INADDR_ANY)
rad_bind_to(auth->radius.handle, c->src_addr.s_addr);
#endif
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;
RadServe_Conf next, prev;
int val, count;
struct u_addr t;
int auth_port = 1812;
int acct_port = 1813;
if (ac == 0)
return(-1);
switch ((intptr_t)arg) {
case UNSET_SERVER:
if (ac > 3 || ac < 1) {
return(-1);
}
for ( prev = NULL, t_server = conf->server ;
t_server != NULL && (next = t_server->next, 1) ;
prev = t_server, t_server = next) {
if (strcmp(t_server->hostname, av[0]) != 0)
continue;
if (ac > 1 && t_server->auth_port != atoi(av[1]))
continue;
if (ac > 2 && t_server->acct_port != atoi(av[2]))
continue;
if (t_server == conf->server) {
conf->server = t_server->next;
} else {
prev->next = t_server->next;
t_server->next = NULL;
}
Freee(t_server->hostname);
Freee(t_server->sharedsecret);
Freee(t_server);
t_server = prev;
}
break;
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) {
Error("cannot configure more than %d servers",
RADIUS_MAX_SERVERS);
}
if (strlen(av[0]) > MAXHOSTNAMELEN)
Error("Hostname too long. > %d char.", MAXHOSTNAMELEN);
if (strlen(av[1]) > 127)
Error("Shared Secret too long. > 127 char.");
if (ac > 2) {
auth_port = atoi(av[2]);
if (auth_port < 0 || auth_port >= 65535)
Error("Auth Port number too high. > 65535");
}
if (ac > 3) {
acct_port = atoi(av[3]);
if (acct_port < 0 || acct_port >= 65535)
Error("Acct Port number too high > 65535");
}
if (auth_port == 0 && acct_port == 0)
Error("At least one port must be specified.");
server = Malloc(MB_RADIUS, sizeof(*server));
server->auth_port = auth_port;
server->acct_port = acct_port;
server->next = NULL;
server->hostname = Mstrdup(MB_RADIUS, av[0]);
server->sharedsecret = Mstrdup(MB_RADIUS, av[1]);
if (conf->server != NULL)
server->next = conf->server;
conf->server = server;
break;
#ifdef HAVE_RAD_BIND
case SET_SRC_ADDR:
if (ParseAddr(*av, &t, ALLOW_IPV4)) {
u_addrtoin_addr(&t, &conf->src_addr);
} else
Error("Bad Src address '%s'.", *av);
break;
#endif
case SET_ME:
if (ParseAddr(*av, &t, ALLOW_IPV4)) {
u_addrtoin_addr(&t, &conf->radius_me);
} else
Error("Bad NAS address '%s'.", *av);
break;
case SET_MEV6:
if (!ParseAddr(*av, &conf->radius_mev6, ALLOW_IPV6))
Error("Bad NAS address '%s'.", *av);
break;
case SET_TIMEOUT:
val = atoi(*av);
if (val <= 0)
Error("Timeout must be positive.");
else
conf->radius_timeout = val;
break;
case SET_RETRIES:
val = atoi(*av);
if (val <= 0)
Error("Retries must be positive.");
else
conf->radius_retries = val;
break;
case SET_CONFIG:
if (strlen(av[0]) > PATH_MAX) {
Error("RADIUS: Config file name too long.");
} else {
Freee(conf->file);
conf->file = Mstrdup(MB_RADIUS, av[0]);
}
break;
case SET_IDENTIFIER:
if (strlen(av[0]) > RAD_MAX_ATTR_LEN) {
Error("RADIUS: Identifier too long.");
} else {
Freee(conf->identifier);
if (av[0][0] == 0)
conf->identifier = NULL;
else
conf->identifier = Mstrdup(MB_RADIUS, 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) {
if ((auth->radius.handle = rad_open()) == NULL) {
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: rad_open failed",
auth->info.lnkname));
return (RAD_NACK);
}
} else { /* RAD_ACCOUNTING_REQUEST */
if ((auth->radius.handle = rad_acct_open()) == NULL) {
Log(LG_ERR|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) {
RadiusLogError(auth, "rad_config");
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[48];
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 (conf->identifier) {
tmpval = conf->identifier;
} else {
if (gethostname(host, sizeof(host)) == -1) {
Log(LG_ERR|LG_RADIUS,
("[%s] RADIUS: gethostname() for RAD_NAS_IDENTIFIER failed",
auth->info.lnkname));
return (RAD_NACK);
}
tmpval = host;
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_NAS_IDENTIFIER: %s",
auth->info.lnkname, tmpval));
if (rad_put_string(auth->radius.handle, RAD_NAS_IDENTIFIER, tmpval) == -1) {
RadiusLogError(auth, "Put RAD_NAS_IDENTIFIER failed");
return (RAD_NACK);
}
if (conf->radius_me.s_addr != 0) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_NAS_IP_ADDRESS: %s",
auth->info.lnkname, inet_ntoa(conf->radius_me)));
if (rad_put_addr(auth->radius.handle, RAD_NAS_IP_ADDRESS, conf->radius_me) == -1) {
RadiusLogError(auth, "Put RAD_NAS_IP_ADDRESS failed");
return (RAD_NACK);
}
}
if (!u_addrempty(&conf->radius_mev6)) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_NAS_IPV6_ADDRESS: %s",
auth->info.lnkname, u_addrtoa(&conf->radius_mev6,buf,sizeof(buf))));
#ifdef HAVE_RAD_ADDR6
if (rad_put_addr6(auth->radius.handle, RAD_NAS_IPV6_ADDRESS, conf->radius_mev6.u.ip6) == -1) {
#else
if (rad_put_attr(auth->radius.handle, RAD_NAS_IPV6_ADDRESS, &conf->radius_mev6.u.ip6, sizeof(conf->radius_mev6.u.ip6)) == -1) {
#endif
RadiusLogError(auth, "Put RAD_NAS_IPV6_ADDRESS failed");
return (RAD_NACK);
}
}
/* 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: Put Message Authenticator", auth->info.lnkname));
if (rad_put_message_authentic(auth->radius.handle) == -1) {
RadiusLogError(auth, "Put message_authentic failed");
return (RAD_NACK);
}
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_SESSION_ID: %s",
auth->info.lnkname, auth->info.session_id));
if (rad_put_string(auth->radius.handle, RAD_ACCT_SESSION_ID, auth->info.session_id) != 0) {
RadiusLogError(auth, "Put RAD_ACCT_SESSION_ID failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_NAS_PORT: %d",
auth->info.lnkname, auth->info.linkID));
if (rad_put_int(auth->radius.handle, RAD_NAS_PORT, auth->info.linkID) == -1) {
RadiusLogError(auth, "Put RAD_NAS_PORT failed");
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: Put RAD_NAS_PORT_TYPE: %d",
auth->info.lnkname, porttype));
if (rad_put_int(auth->radius.handle, RAD_NAS_PORT_TYPE, porttype) == -1) {
RadiusLogError(auth, "Put RAD_NAS_PORT_TYPE failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_SERVICE_TYPE: RAD_FRAMED",
auth->info.lnkname));
if (rad_put_int(auth->radius.handle, RAD_SERVICE_TYPE, RAD_FRAMED) == -1) {
RadiusLogError(auth, "Put RAD_SERVICE_TYPE failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_FRAMED_PROTOCOL: RAD_PPP",
auth->info.lnkname));
if (rad_put_int(auth->radius.handle, RAD_FRAMED_PROTOCOL, RAD_PPP) == -1) {
RadiusLogError(auth, "Put RAD_FRAMED_PROTOCOL failed");
return (RAD_NACK);
}
if (auth->params.state != NULL) {
tmpval = Bin2Hex(auth->params.state, auth->params.state_len);
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_STATE: 0x%s", auth->info.lnkname, tmpval));
Freee(tmpval);
if (rad_put_attr(auth->radius.handle, RAD_STATE, auth->params.state, auth->params.state_len) == -1) {
RadiusLogError(auth, "Put RAD_STATE failed");
return (RAD_NACK);
}
}
if (auth->params.class != NULL) {
tmpval = Bin2Hex(auth->params.class, auth->params.class_len);
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_CLASS: 0x%s", auth->info.lnkname, tmpval));
Freee(tmpval);
if (rad_put_attr(auth->radius.handle, RAD_CLASS, auth->params.class, auth->params.class_len) == -1) {
RadiusLogError(auth, "Put RAD_CLASS failed");
return (RAD_NACK);
}
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_CALLING_STATION_ID: %s",
auth->info.lnkname, auth->params.callingnum));
if (rad_put_string(auth->radius.handle, RAD_CALLING_STATION_ID,
auth->params.callingnum) == -1) {
RadiusLogError(auth, "Put RAD_CALLING_STATION_ID failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_CALLED_STATION_ID: %s",
auth->info.lnkname, auth->params.callednum));
if (rad_put_string(auth->radius.handle, RAD_CALLED_STATION_ID,
auth->params.callednum) == -1) {
RadiusLogError(auth, "Put RAD_CALLED_STATION_ID failed");
return (RAD_NACK);
}
if (auth->params.peeriface[0]) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_NAS_PORT_ID: %s",
auth->info.lnkname, auth->params.peeriface));
if (rad_put_string(auth->radius.handle, RAD_NAS_PORT_ID,
auth->params.peeriface) == -1) {
RadiusLogError(auth, "Put RAD_NAS_PORT_ID failed");
return (RAD_NACK);
}
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MPD_LINK: %s",
auth->info.lnkname, auth->info.lnkname));
if (rad_put_vendor_string(auth->radius.handle, RAD_VENDOR_MPD, RAD_MPD_LINK, auth->info.lnkname) != 0) {
RadiusLogError(auth, "Put RAD_MPD_LINK failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MPD_PEER_IDENT: %s",
auth->info.lnkname, auth->info.peer_ident));
if (rad_put_vendor_string(auth->radius.handle, RAD_VENDOR_MPD,
RAD_MPD_PEER_IDENT, auth->info.peer_ident) != 0) {
RadiusLogError(auth, "Put RAD_MPD_PEER_IDENT failed");
return (RAD_NACK);
}
#ifdef PHYSTYPE_PPTP
if (auth->info.phys_type == &gPptpPhysType) {
porttype = 1;
} else
#endif
#ifdef PHYSTYPE_L2TP
if (auth->info.phys_type == &gL2tpPhysType) {
porttype = 3;
} else
#endif
#ifdef PHYSTYPE_TCP
if (auth->info.phys_type == &gTcpPhysType) {
porttype = -1;
} else
#endif
#ifdef PHYSTYPE_UDP
if (auth->info.phys_type == &gUdpPhysType) {
porttype = -2;
} else
#endif
#ifdef PHYSTYPE_PPPOE
if (auth->info.phys_type == &gPppoePhysType) {
porttype = -3;
} else
#endif
{
porttype = 0;
};
if (porttype > 0) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_TUNNEL_TYPE: %d",
auth->info.lnkname, porttype));
if (rad_put_int(auth->radius.handle, RAD_TUNNEL_TYPE, porttype) == -1) {
RadiusLogError(auth, "Put RAD_TUNNEL_TYPE failed");
return (RAD_NACK);
}
}
if (porttype != 0) {
if (porttype == -3) {
porttype = 6;
} else {
struct in6_addr ip6;
if (inet_pton(AF_INET6, auth->params.peeraddr, &ip6) == 1) {
porttype = 2;
} else {
porttype = 1;
}
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_TUNNEL_MEDIUM_TYPE: %d",
auth->info.lnkname, porttype));
if (rad_put_int(auth->radius.handle, RAD_TUNNEL_MEDIUM_TYPE, porttype) == -1) {
RadiusLogError(auth, "Put RAD_TUNNEL_MEDIUM_TYPE failed");
return (RAD_NACK);
}
if (auth->info.originate == LINK_ORIGINATE_LOCAL) {
tmpval = auth->params.peeraddr;
} else {
tmpval = auth->params.selfaddr;
}
if (tmpval[0]) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_TUNNEL_SERVER_ENDPOINT: %s",
auth->info.lnkname, tmpval));
if (rad_put_string_tag(auth->radius.handle, RAD_TUNNEL_SERVER_ENDPOINT,
0, tmpval) == -1) {
RadiusLogError(auth, "Put RAD_TUNNEL_SERVER_ENDPOINT failed");
return (RAD_NACK);
}
}
if (auth->info.originate == LINK_ORIGINATE_LOCAL) {
tmpval = auth->params.selfaddr;
} else {
tmpval = auth->params.peeraddr;
}
if (tmpval[0]) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_TUNNEL_CLIENT_ENDPOINT: %s",
auth->info.lnkname, tmpval));
if (rad_put_string_tag(auth->radius.handle, RAD_TUNNEL_CLIENT_ENDPOINT,
0, tmpval) == -1) {
RadiusLogError(auth, "Put RAD_TUNNEL_CLIENT_ENDPOINT failed");
return (RAD_NACK);
}
}
if (auth->info.originate == LINK_ORIGINATE_LOCAL) {
tmpval = auth->params.peername;
} else {
tmpval = auth->params.selfname;
}
if (tmpval[0]) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_TUNNEL_SERVER_AUTH_ID: %s",
auth->info.lnkname, tmpval));
if (rad_put_string_tag(auth->radius.handle, RAD_TUNNEL_SERVER_AUTH_ID,
0, tmpval) == -1) {
RadiusLogError(auth, "Put RAD_TUNNEL_SERVER_AUTH_ID failed");
return (RAD_NACK);
}
}
if (auth->info.originate == LINK_ORIGINATE_LOCAL) {
tmpval = auth->params.selfname;
} else {
tmpval = auth->params.peername;
}
if (tmpval[0]) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_TUNNEL_CLIENT_AUTH_ID: %s",
auth->info.lnkname, tmpval));
if (rad_put_string_tag(auth->radius.handle, RAD_TUNNEL_CLIENT_AUTH_ID,
0, tmpval) == -1) {
RadiusLogError(auth, "Put RAD_TUNNEL_CLIENT_AUTH_ID failed");
return (RAD_NACK);
}
}
}
#ifdef PHYSTYPE_PPPOE
if (auth->info.phys_type == &gPppoePhysType) {
if (auth->params.selfname[0]) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put ADSL-Agent-Circuit-Id: %s",
auth->info.lnkname, auth->params.selfname));
if (rad_put_vendor_string(auth->radius.handle, 3561, 1,
auth->params.selfname) == -1) {
RadiusLogError(auth, "Put ADSL-Agent-Circuit-Id failed");
return (RAD_NACK);
}
}
if (auth->params.peername[0]) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put ADSL-Agent-Remote-Id: %s",
auth->info.lnkname, auth->params.peername));
if (rad_put_vendor_string(auth->radius.handle, 3561, 2,
auth->params.peername) == -1) {
RadiusLogError(auth, "Put ADSL-Agent-Remote-Id failed");
return (RAD_NACK);
}
}
}
#endif
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;
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_USER_NAME: %s",
auth->info.lnkname, auth->params.authname));
if (rad_put_string(auth->radius.handle, RAD_USER_NAME, auth->params.authname) == -1) {
RadiusLogError(auth, "Put RAD_USER_NAME failed");
return (RAD_NACK);
}
if (auth->proto == PROTO_CHAP || auth->proto == PROTO_EAP) {
switch (auth->alg) {
case CHAP_ALG_MSOFT:
if (cp->value_len != 49) {
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: RADIUS_CHAP (MSOFTv1) unrecognised key length %d/%d",
auth->info.lnkname, cp->value_len, 49));
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MICROSOFT_MS_CHAP_CHALLENGE",
auth->info.lnkname));
if (rad_put_vendor_attr(auth->radius.handle, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP_CHALLENGE,
cp->chal_data, cp->chal_len) == -1) {
RadiusLogError(auth, "Put RAD_MICROSOFT_MS_CHAP_CHALLENGE failed");
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);
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MICROSOFT_MS_CHAP_RESPONSE",
auth->info.lnkname));
if (rad_put_vendor_attr(auth->radius.handle, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP_RESPONSE,
&rad_mschapval, sizeof(rad_mschapval)) == -1) {
RadiusLogError(auth, "Put RAD_MICROSOFT_MS_CHAP_RESPONSE failed");
return (RAD_NACK);
}
break;
case CHAP_ALG_MSOFTv2:
if (cp->value_len != sizeof(*mschapv2val)) {
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: RADIUS_CHAP (MSOFTv2) unrecognised key length %d/%d",
auth->info.lnkname, cp->value_len, (int)sizeof(*mschapv2val)));
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MICROSOFT_MS_CHAP_CHALLENGE",
auth->info.lnkname));
if (rad_put_vendor_attr(auth->radius.handle, RAD_VENDOR_MICROSOFT,
RAD_MICROSOFT_MS_CHAP_CHALLENGE, cp->chal_data, cp->chal_len) == -1) {
RadiusLogError(auth, "Put RAD_MICROSOFT_MS_CHAP_CHALLENGE failed");
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));
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MICROSOFT_MS_CHAP2_RESPONSE",
auth->info.lnkname));
if (rad_put_vendor_attr(auth->radius.handle, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP2_RESPONSE,
&rad_mschapv2val, sizeof(rad_mschapv2val)) == -1) {
RadiusLogError(auth, "Put vendor_attr(RAD_MICROSOFT_MS_CHAP2_RESPONSE failed");
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: Put RAD_CHAP_CHALLENGE",
auth->info.lnkname));
if (rad_put_attr(auth->radius.handle, RAD_CHAP_CHALLENGE, cp->chal_data, cp->chal_len) == -1) {
RadiusLogError(auth, "Put RAD_CHAP_CHALLENGE failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_CHAP_PASSWORD",
auth->info.lnkname));
if (rad_put_attr(auth->radius.handle, RAD_CHAP_PASSWORD, &rad_chapval, cp->value_len + 1) == -1) {
RadiusLogError(auth, "Put RAD_CHAP_PASSWORD failed");
return (RAD_NACK);
}
break;
default:
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: RADIUS unkown CHAP ALG: %d",
auth->info.lnkname, auth->alg));
return (RAD_NACK);
}
} else if (auth->proto == PROTO_PAP) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_USER_PASSWORD", auth->info.lnkname));
if (rad_put_string(auth->radius.handle, RAD_USER_PASSWORD, pp->peer_pass) == -1) {
RadiusLogError(auth, "Put RAD_USER_PASSWORD failed");
return (RAD_NACK);
}
} else {
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: RADIUS unkown Proto: %d",
auth->info.lnkname, auth->proto));
return (RAD_NACK);
}
return (RAD_ACK);
}
static int
RadiusPutAcct(AuthData auth)
{
char *username;
int authentic;
char buf[64];
if (auth->acct_type == AUTH_ACCT_START) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_STATUS_TYPE: RAD_START",
auth->info.lnkname));
if (rad_put_int(auth->radius.handle, RAD_ACCT_STATUS_TYPE, RAD_START)) {
RadiusLogError(auth, "Put STATUS_TYPE failed");
return (RAD_NACK);
}
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_FRAMED_IP_ADDRESS: %s",
auth->info.lnkname, inet_ntoa(auth->info.peer_addr)));
if (rad_put_addr(auth->radius.handle, RAD_FRAMED_IP_ADDRESS, auth->info.peer_addr)) {
RadiusLogError(auth, "Put RAD_FRAMED_IP_ADDRESS failed");
return (RAD_NACK);
}
if (auth->params.netmask != 0) {
struct in_addr ip;
widthtoin_addr(auth->params.netmask, &ip);
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_FRAMED_IP_NETMASK: %s",
auth->info.lnkname, inet_ntoa(ip)));
if (rad_put_addr(auth->radius.handle, RAD_FRAMED_IP_NETMASK, ip)) {
RadiusLogError(auth, "Put RAD_FRAMED_IP_NETMASK failed");
return (RAD_NACK);
}
}
#ifdef HAVE_RAD_ADDR6
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_FRAMED_IPV6_ADDRESS: %s",
auth->info.lnkname, inet_ntop(AF_INET6, &auth->info.peer_addr6, buf,
sizeof(buf))));
if (rad_put_addr6(auth->radius.handle, RAD_FRAMED_IPV6_ADDRESS, auth->info.peer_addr6)) {
RadiusLogError(auth, "Put RAD_FRAMED_IPV6_ADDRESS failed");
return (RAD_NACK);
}
#endif
username = auth->params.authname;
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_USER_NAME: %s",
auth->info.lnkname, username));
if (rad_put_string(auth->radius.handle, RAD_USER_NAME, username) != 0) {
RadiusLogError(auth, "Put RAD_USER_NAME failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_MULTI_SESSION_ID: %s",
auth->info.lnkname, auth->info.msession_id));
if (rad_put_string(auth->radius.handle, RAD_ACCT_MULTI_SESSION_ID, auth->info.msession_id) != 0) {
RadiusLogError(auth, "Put RAD_ACCT_MULTI_SESSION_ID failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MPD_BUNDLE: %s",
auth->info.lnkname, auth->info.bundname));
if (rad_put_vendor_string(auth->radius.handle, RAD_VENDOR_MPD, RAD_MPD_BUNDLE, auth->info.bundname) != 0) {
RadiusLogError(auth, "Put RAD_MPD_BUNDLE failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MPD_IFACE: %s",
auth->info.lnkname, auth->info.ifname));
if (rad_put_vendor_string(auth->radius.handle, RAD_VENDOR_MPD, RAD_MPD_IFACE, auth->info.ifname) != 0) {
RadiusLogError(auth, "Put RAD_MPD_IFACE failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MPD_IFACE_INDEX: %u",
auth->info.lnkname, auth->info.ifindex));
if (rad_put_vendor_int(auth->radius.handle, RAD_VENDOR_MPD, RAD_MPD_IFACE_INDEX, auth->info.ifindex) != 0) {
RadiusLogError(auth, "Put RAD_MPD_IFACE_INDEX failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MPD_PEER_IDENT: %s",
auth->info.lnkname, auth->info.peer_ident));
if (rad_put_vendor_string(auth->radius.handle, RAD_VENDOR_MPD, RAD_MPD_PEER_IDENT, auth->info.peer_ident) != 0) {
RadiusLogError(auth, "Put RAD_MPD_PEER_IDENT failed");
return (RAD_NACK);
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_LINK_COUNT: %d",
auth->info.lnkname, auth->info.n_links));
if (rad_put_int(auth->radius.handle, RAD_ACCT_LINK_COUNT, auth->info.n_links) != 0) {
RadiusLogError(auth, "Put RAD_ACCT_LINK_COUNT failed");
return (RAD_NACK);
}
if (auth->params.authentic == AUTH_CONF_RADIUS_AUTH) {
authentic = RAD_AUTH_RADIUS;
} else {
authentic = RAD_AUTH_LOCAL;
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_AUTHENTIC: %d",
auth->info.lnkname, authentic));
if (rad_put_int(auth->radius.handle, RAD_ACCT_AUTHENTIC, authentic) != 0) {
RadiusLogError(auth, "Put RAD_ACCT_AUTHENTIC failed");
return (RAD_NACK);
}
if (auth->acct_type == AUTH_ACCT_STOP
|| auth->acct_type == AUTH_ACCT_UPDATE) {
#ifdef USE_NG_BPF
struct svcstatrec *ssr;
#endif
if (auth->acct_type == AUTH_ACCT_STOP) {
int termCause = RAD_TERM_PORT_ERROR;
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_STATUS_TYPE: RAD_STOP",
auth->info.lnkname));
if (rad_put_int(auth->radius.handle, RAD_ACCT_STATUS_TYPE, RAD_STOP)) {
RadiusLogError(auth, "Put RAD_ACCT_STATUS_TYPE failed");
return (RAD_NACK);
}
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_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_TERMINATE_CAUSE: %s, RADIUS: %d",
auth->info.lnkname, auth->info.downReason, termCause));
if (rad_put_int(auth->radius.handle, RAD_ACCT_TERMINATE_CAUSE, termCause) != 0) {
RadiusLogError(auth, "Put RAD_ACCT_TERMINATE_CAUSE failed");
return (RAD_NACK);
}
} else {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_STATUS_TYPE: RAD_UPDATE",
auth->info.lnkname));
if (rad_put_int(auth->radius.handle, RAD_ACCT_STATUS_TYPE, RAD_UPDATE)) {
RadiusLogError(auth, "Put RAD_ACCT_STATUS_TYPE failed");
return (RAD_NACK);
}
}
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_SESSION_TIME: %ld",
auth->info.lnkname, (long int)(time(NULL) - auth->info.last_up)));
if (rad_put_int(auth->radius.handle, RAD_ACCT_SESSION_TIME, time(NULL) - auth->info.last_up) != 0) {
RadiusLogError(auth, "Put RAD_ACCT_SESSION_TIME failed");
return (RAD_NACK);
}
#ifdef USE_NG_BPF
if (auth->params.std_acct[0][0] == 0) {
#endif
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_INPUT_OCTETS: %lu",
auth->info.lnkname, (long unsigned int)(auth->info.stats.recvOctets % MAX_U_INT32)));
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_INPUT_GIGAWORDS: %lu",
auth->info.lnkname, (long unsigned int)(auth->info.stats.recvOctets / MAX_U_INT32)));
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_INPUT_PACKETS: %lu",
auth->info.lnkname, (long unsigned int)(auth->info.stats.recvFrames)));
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_INPUT_GIGAWORDS, auth->info.stats.recvOctets / MAX_U_INT32) != 0) {
RadiusLogError(auth, "Put input stats failed");
return (RAD_NACK);
}
#ifdef USE_NG_BPF
}
if (auth->params.std_acct[1][0] == 0) {
#endif
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_OUTPUT_OCTETS: %lu",
auth->info.lnkname, (long unsigned int)(auth->info.stats.xmitOctets % MAX_U_INT32)));
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_OUTPUT_GIGAWORDS: %lu",
auth->info.lnkname, (long unsigned int)(auth->info.stats.xmitOctets / MAX_U_INT32)));
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_OUTPUT_PACKETS: %lu",
auth->info.lnkname, (long unsigned int)(auth->info.stats.xmitFrames)));
if (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_OUTPUT_GIGAWORDS, auth->info.stats.xmitOctets / MAX_U_INT32) != 0) {
RadiusLogError(auth, "Put output stats failed");
return (RAD_NACK);
}
#ifdef USE_NG_BPF
}
SLIST_FOREACH(ssr, &auth->info.ss.stat[0], next) {
char str[64];
snprintf(str, sizeof(str), "%s:%llu",
ssr->name, (long long unsigned)ssr->Octets);
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MPD_INPUT_OCTETS: %s",
auth->info.lnkname, str));
if (rad_put_vendor_string(auth->radius.handle, RAD_VENDOR_MPD, RAD_MPD_INPUT_OCTETS, str) != 0) {
RadiusLogError(auth, "Put RAD_MPD_INPUT_OCTETS failed");
return (RAD_NACK);
}
snprintf(str, sizeof(str), "%s:%llu",
ssr->name, (long long unsigned)ssr->Packets);
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MPD_INPUT_PACKETS: %s",
auth->info.lnkname, str));
if (rad_put_vendor_string(auth->radius.handle, RAD_VENDOR_MPD, RAD_MPD_INPUT_PACKETS, str) != 0) {
RadiusLogError(auth, "Put RAD_MPD_INPUT_PACKETS failed");
return (RAD_NACK);
}
if (strcmp(ssr->name,auth->params.std_acct[0]) == 0) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_INPUT_OCTETS: %lu",
auth->info.lnkname, (long unsigned int)(ssr->Octets % MAX_U_INT32)));
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_INPUT_GIGAWORDS: %lu",
auth->info.lnkname, (long unsigned int)(ssr->Octets / MAX_U_INT32)));
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_INPUT_PACKETS: %lu",
auth->info.lnkname, (long unsigned int)(ssr->Packets)));
if (rad_put_int(auth->radius.handle, RAD_ACCT_INPUT_OCTETS, ssr->Octets % MAX_U_INT32) != 0 ||
rad_put_int(auth->radius.handle, RAD_ACCT_INPUT_PACKETS, ssr->Packets) != 0 ||
rad_put_int(auth->radius.handle, RAD_ACCT_INPUT_GIGAWORDS, ssr->Octets / MAX_U_INT32) != 0) {
RadiusLogError(auth, "Put input stats failed");
return (RAD_NACK);
}
}
}
SLIST_FOREACH(ssr, &auth->info.ss.stat[1], next) {
char str[64];
snprintf(str, sizeof(str), "%s:%llu",
ssr->name, (long long unsigned)ssr->Octets);
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MPD_OUTPUT_OCTETS: %s",
auth->info.lnkname, str));
if (rad_put_vendor_string(auth->radius.handle, RAD_VENDOR_MPD, RAD_MPD_OUTPUT_OCTETS, str) != 0) {
RadiusLogError(auth, "Put RAD_MPD_OUTPUT_OCTETS failed");
return (RAD_NACK);
}
snprintf(str, sizeof(str), "%s:%llu",
ssr->name, (long long unsigned)ssr->Packets);
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_MPD_OUTPUT_PACKETS: %s",
auth->info.lnkname, str));
if (rad_put_vendor_string(auth->radius.handle, RAD_VENDOR_MPD, RAD_MPD_OUTPUT_PACKETS, str) != 0) {
RadiusLogError(auth, "Put RAD_MPD_OUTPUT_PACKETS failed");
return (RAD_NACK);
}
if (strcmp(ssr->name,auth->params.std_acct[1]) == 0) {
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_OUTPUT_OCTETS: %lu",
auth->info.lnkname, (long unsigned int)(ssr->Octets % MAX_U_INT32)));
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_OUTPUT_GIGAWORDS: %lu",
auth->info.lnkname, (long unsigned int)(ssr->Octets / MAX_U_INT32)));
Log(LG_RADIUS2, ("[%s] RADIUS: Put RAD_ACCT_OUTPUT_PACKETS: %lu",
auth->info.lnkname, (long unsigned int)(ssr->Packets)));
if (rad_put_int(auth->radius.handle, RAD_ACCT_OUTPUT_OCTETS, ssr->Octets % MAX_U_INT32) != 0 ||
rad_put_int(auth->radius.handle, RAD_ACCT_OUTPUT_PACKETS, ssr->Packets) != 0 ||
rad_put_int(auth->radius.handle, RAD_ACCT_OUTPUT_GIGAWORDS, ssr->Octets / MAX_U_INT32) != 0) {
RadiusLogError(auth, "Put output stats failed");
return (RAD_NACK);
}
}
}
#endif /* USE_NG_BPF */
}
return (RAD_ACK);
}
static int
RadiusSendRequest(AuthData auth)
{
struct timeval timelimit;
struct timeval tv;
int fd, n;
Log(LG_RADIUS2, ("[%s] RADIUS: Send request for user '%s'",
auth->info.lnkname, auth->params.authname));
n = rad_init_send_request(auth->radius.handle, &fd, &tv);
if (n != 0) {
Log(LG_ERR|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_ERR|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; /* Continue the select */
}
Log(LG_RADIUS2, ("[%s] RADIUS: Sending request for user '%s'",
auth->info.lnkname, 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;
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(auth->acct_type != AUTH_ACCT_UPDATE ? LG_RADIUS : LG_RADIUS2,
("[%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 for user '%s' failed: %s",
auth->info.lnkname, auth->params.authname,
rad_strerror(auth->radius.handle)));
return (RAD_NACK);
default:
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: rad_send_request: unexpected return value: %d",
auth->info.lnkname, n));
return (RAD_NACK);
}
return (RadiusGetParams(auth, n == RAD_ACCESS_CHALLENGE));
}
static int
RadiusGetParams(AuthData auth, int eap_proxy)
{
int res, i, j;
size_t len;
const void *data;
u_int32_t vendor;
char *route;
char *tmpval;
struct in_addr ip;
struct in6_addr ipv6;
char buf[64];
#if defined(USE_NG_BPF) || defined(USE_IPFW)
struct acl **acls, *acls1;
char *acl, *acl1, *acl2, *acl3;
#endif
struct ifaceroute *r, *r1;
struct u_range range;
#ifdef CCP_MPPC
u_char *tmpkey;
size_t tmpkey_len;
#endif
Freee(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: Get RAD_STATE: 0x%s", auth->info.lnkname, tmpval));
Freee(tmpval);
auth->params.state_len = len;
Freee(auth->params.state);
auth->params.state = Mdup(MB_AUTH, data, len);
continue;
case RAD_CLASS:
tmpval = Bin2Hex(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_CLASS: 0x%s", auth->info.lnkname, tmpval));
Freee(tmpval);
auth->params.class_len = len;
Freee(auth->params.class);
auth->params.class = Mdup(MB_AUTH, data, len);
continue;
/* libradius already checks the message-authenticator, so simply ignore it */
case RAD_MESSAGE_AUTHENTIC:
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MESSAGE_AUTHENTIC", auth->info.lnkname));
continue;
case RAD_EAP_MESSAGE:
if (auth->params.eapmsg != NULL) {
char *tbuf;
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_EAP_MESSAGE: len %d of %d",
auth->info.lnkname, (int)len, (int)(auth->params.eapmsg_len + len)));
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(auth->params.eapmsg);
auth->params.eapmsg = tbuf;
} else {
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_EAP_MESSAGE: len %d",
auth->info.lnkname, (int)len));
auth->params.eapmsg = Mdup(MB_AUTH, 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: Get RAD_FRAMED_IP_ADDRESS: %s",
auth->info.lnkname, inet_ntoa(ip)));
if (ip.s_addr == INADDR_BROADCAST) {
/* the peer can choose an address */
Log(LG_RADIUS2, ("[%s] the peer can choose an address", auth->info.lnkname));
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, ("[%s] we should choose an address", auth->info.lnkname));
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;
#ifdef HAVE_RAD_ADDR6
case RAD_FRAMED_IPV6_ADDRESS:
ipv6 = rad_cvt_addr6(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_FRAMED_IPV6_ADDRESS: %s",
auth->info.lnkname, inet_ntop(AF_INET6, &ipv6, buf, sizeof(buf))));
in6_addrtou_range(&ipv6, 64, &auth->params.range);
auth->params.range_valid = 1;
break;
#endif
case RAD_USER_NAME:
tmpval = rad_cvt_string(data, len);
/* copy it into the persistent data struct */
strlcpy(auth->params.authname, tmpval, sizeof(auth->params.authname));
free(tmpval);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_USER_NAME: %s",
auth->info.lnkname, 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: Get RAD_FRAMED_IP_NETMASK: %s (/%d)",
auth->info.lnkname, inet_ntoa(ip), auth->params.netmask));
break;
case RAD_FRAMED_ROUTE:
route = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_FRAMED_ROUTE: %s",
auth->info.lnkname, route));
if (!ParseRange(route, &range, ALLOW_IPV4)) {
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: Get RAD_FRAMED_ROUTE: Bad route \"%s\"",
auth->info.lnkname, route));
free(route);
break;
}
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_ERR|LG_RADIUS, ("[%s] RADIUS: Duplicate route %s",
auth->info.lnkname, route));
j = 1;
}
};
free(route);
if (j == 0) {
SLIST_INSERT_HEAD(&auth->params.routes, r, next);
} else {
Freee(r);
}
break;
case RAD_FRAMED_IPV6_ROUTE:
route = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_FRAMED_IPV6_ROUTE: %s",
auth->info.lnkname, route));
if (!ParseRange(route, &range, ALLOW_IPV6)) {
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: Get RAD_FRAMED_IPV6_ROUTE: Bad route \"%s\"", auth->info.lnkname, route));
free(route);
break;
}
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_ERR|LG_RADIUS, ("[%s] RADIUS: Duplicate route %s",
auth->info.lnkname, route));
j = 1;
}
};
free(route);
if (j == 0) {
SLIST_INSERT_HEAD(&auth->params.routes, r, next);
} else {
Freee(r);
}
break;
case RAD_SESSION_TIMEOUT:
auth->params.session_timeout = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_SESSION_TIMEOUT: %u",
auth->info.lnkname, auth->params.session_timeout));
break;
case RAD_IDLE_TIMEOUT:
auth->params.idle_timeout = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_IDLE_TIMEOUT: %u",
auth->info.lnkname, auth->params.idle_timeout));
break;
case RAD_ACCT_INTERIM_INTERVAL:
auth->params.acct_update = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_ACCT_INTERIM_INTERVAL: %u",
auth->info.lnkname, auth->params.acct_update));
break;
case RAD_FRAMED_MTU:
i = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_FRAMED_MTU: %u",
auth->info.lnkname, i));
if (i < IFACE_MIN_MTU || i > IFACE_MAX_MTU) {
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: Get RAD_FRAMED_MTU: invalid MTU: %u",
auth->info.lnkname, i));
auth->params.mtu = 0;
break;
}
auth->params.mtu = i;
break;
case RAD_FRAMED_COMPRESSION:
i = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_FRAMED_COMPRESSION: %d",
auth->info.lnkname, i));
if (i == RAD_COMP_VJ)
auth->params.vjc_enable = 1;
break;
case RAD_FRAMED_PROTOCOL:
Log(LG_RADIUS2, ("[%s] RADIUS: Get (RAD_FRAMED_PROTOCOL: %d)",
auth->info.lnkname, rad_cvt_int(data)));
break;
case RAD_FRAMED_ROUTING:
Log(LG_RADIUS2, ("[%s] RADIUS: Get (RAD_FRAMED_ROUTING: %d)",
auth->info.lnkname, rad_cvt_int(data)));
break;
case RAD_FILTER_ID:
Freee(auth->params.filter_id);
auth->params.filter_id = NULL;
if (len == 0)
break;
tmpval = rad_cvt_string(data, len);
auth->params.filter_id = Mdup(MB_AUTH, tmpval, len + 1);
free(tmpval);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_FILTER_ID: %s",
auth->info.lnkname, auth->params.filter_id));
break;
case RAD_SERVICE_TYPE:
Log(LG_RADIUS2, ("[%s] RADIUS: Get (RAD_SERVICE_TYPE: %d)",
auth->info.lnkname, rad_cvt_int(data)));
break;
case RAD_REPLY_MESSAGE:
Freee(auth->reply_message);
auth->reply_message = NULL;
if (len == 0)
break;
tmpval = rad_cvt_string(data, len);
auth->reply_message = Mdup(MB_AUTH, tmpval, len + 1);
free(tmpval);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_REPLY_MESSAGE: %s",
auth->info.lnkname, auth->reply_message));
break;
case RAD_FRAMED_POOL:
tmpval = rad_cvt_string(data, len);
/* copy it into the persistent data struct */
strlcpy(auth->params.ippool, tmpval, sizeof(auth->params.ippool));
free(tmpval);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_FRAMED_POOL: %s",
auth->info.lnkname, auth->params.ippool));
break;
case RAD_VENDOR_SPECIFIC:
if ((res = rad_get_vendor_attr(&vendor, &data, &len)) == -1) {
Log(LG_RADIUS, ("[%s] RADIUS: Get vendor attr failed: %s",
auth->info.lnkname, rad_strerror(auth->radius.handle)));
return RAD_NACK;
}
switch (vendor) {
case RAD_VENDOR_MICROSOFT:
switch (res) {
case RAD_MICROSOFT_MS_CHAP_ERROR:
Freee(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 = Mdup(MB_AUTH, tmpval, len + 1);
free(tmpval);
Log(LG_RADIUS2, ("[%s] RADIUS: Get MS-CHAP-Error: %s",
auth->info.lnkname, auth->mschap_error));
break;
/* this was taken from userland ppp */
case RAD_MICROSOFT_MS_CHAP2_SUCCESS:
Freee(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: Warning: The MS-CHAP2-Success attribute is mis-formatted. Compensating",
auth->info.lnkname));
}
if ((tmpval = rad_cvt_string((const char *)data, len)) == NULL) {
Log(LG_RADIUS, ("[%s] RADIUS: rad_cvt_string failed: %s",
auth->info.lnkname, rad_strerror(auth->radius.handle)));
return RAD_NACK;
}
auth->mschapv2resp = Mdup(MB_AUTH, tmpval, len + 1);
free(tmpval);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MICROSOFT_MS_CHAP2_SUCCESS: %s",
auth->info.lnkname, auth->mschapv2resp));
break;
case RAD_MICROSOFT_MS_CHAP_DOMAIN:
Freee(auth->params.msdomain);
auth->params.msdomain = NULL;
if (len == 0)
break;
tmpval = rad_cvt_string(data, len);
auth->params.msdomain = Mdup(MB_AUTH, tmpval, len + 1);
free(tmpval);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MICROSOFT_MS_CHAP_DOMAIN: %s",
auth->info.lnkname, auth->params.msdomain));
break;
#ifdef CCP_MPPC
/* MPPE Keys MS-CHAPv2 and EAP-TLS */
case RAD_MICROSOFT_MS_MPPE_RECV_KEY:
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MICROSOFT_MS_MPPE_RECV_KEY",
auth->info.lnkname));
tmpkey = rad_demangle_mppe_key(auth->radius.handle, data, len, &tmpkey_len);
if (!tmpkey) {
RadiusLogError(auth, "rad_demangle_mppe_key failed");
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:
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MICROSOFT_MS_MPPE_SEND_KEY",
auth->info.lnkname));
tmpkey = rad_demangle_mppe_key(auth->radius.handle, data, len, &tmpkey_len);
if (!tmpkey) {
RadiusLogError(auth, "rad_demangle_mppe_key failed");
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:
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MICROSOFT_MS_CHAP_MPPE_KEYS",
auth->info.lnkname));
if (len != 32) {
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: Server returned garbage %d of expected %d Bytes",
auth->info.lnkname, (int)len, 32));
return RAD_NACK;
}
tmpkey = rad_demangle(auth->radius.handle, data, len);
if (tmpkey == NULL) {
RadiusLogError(auth, "rad_demangle failed");
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));
auth->params.msoft.has_nt_hash = TRUE;
free(tmpkey);
break;
#endif
case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
auth->params.msoft.policy = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: %d (%s)",
auth->info.lnkname, auth->params.msoft.policy, AuthMPPEPolicyname(auth->params.msoft.policy)));
break;
case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
{
char buf[48];
auth->params.msoft.types = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: %d (%s)",
auth->info.lnkname, auth->params.msoft.types,
AuthMPPETypesname(auth->params.msoft.types, buf, sizeof(buf))));
}
break;
case RAD_MICROSOFT_MS_PRIMARY_DNS_SERVER:
auth->params.peer_dns[0] = rad_cvt_addr(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MICROSOFT_MS_PRIMARY_DNS_SERVER: %s",
auth->info.lnkname, inet_ntoa(auth->params.peer_dns[0])));
break;
case RAD_MICROSOFT_MS_SECONDARY_DNS_SERVER:
auth->params.peer_dns[1] = rad_cvt_addr(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MICROSOFT_MS_SECONDARY_DNS_SERVER: %s",
auth->info.lnkname, inet_ntoa(auth->params.peer_dns[1])));
break;
case RAD_MICROSOFT_MS_PRIMARY_NBNS_SERVER:
auth->params.peer_nbns[0] = rad_cvt_addr(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MICROSOFT_MS_PRIMARY_NBNS_SERVER: %s",
auth->info.lnkname, inet_ntoa(auth->params.peer_nbns[0])));
break;
case RAD_MICROSOFT_MS_SECONDARY_NBNS_SERVER:
auth->params.peer_nbns[1] = rad_cvt_addr(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MICROSOFT_MS_SECONDARY_NBNS_SERVER: %s",
auth->info.lnkname, inet_ntoa(auth->params.peer_nbns[1])));
break;
default:
Log(LG_RADIUS2, ("[%s] RADIUS: Dropping MICROSOFT vendor specific attribute: %d",
auth->info.lnkname, res));
break;
}
break;
case RAD_VENDOR_MPD:
if (res == RAD_MPD_DROP_USER) {
auth->drop_user = rad_cvt_int(data);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_DROP_USER: %d",
auth->info.lnkname, auth->drop_user));
break;
} else if (res == RAD_MPD_ACTION) {
tmpval = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_ACTION: %s",
auth->info.lnkname, tmpval));
strlcpy(auth->params.action, tmpval,
sizeof(auth->params.action));
free(tmpval);
break;
} else if (res == RAD_MPD_IFACE_NAME) {
tmpval = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_IFACE_NAME: %s",
auth->info.lnkname, tmpval));
strlcpy(auth->params.ifname, tmpval,
sizeof(auth->params.ifname));
free(tmpval);
break;
} else
#ifdef SIOCSIFDESCR
if (res == RAD_MPD_IFACE_DESCR) {
tmpval = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_IFACE_DESCR: %s",
auth->info.lnkname, tmpval));
Freee(auth->params.ifdescr);
auth->params.ifdescr = Mdup(MB_AUTH, tmpval, len + 1);
free(tmpval);
break;
} else
#endif /* SIOCSIFDESCR */
#ifdef SIOCAIFGROUP
if (res == RAD_MPD_IFACE_GROUP) {
tmpval = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_IFACE_GROUP: %s",
auth->info.lnkname, tmpval));
strlcpy(auth->params.ifgroup, tmpval,
sizeof(auth->params.ifgroup));
free(tmpval);
break;
} else
#endif /* SIOCAIFGROUP */
#ifdef USE_IPFW
if (res == RAD_MPD_RULE) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_RULE: %s",
auth->info.lnkname, acl));
acls = &(auth->params.acl_rule);
} else if (res == RAD_MPD_PIPE) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_PIPE: %s",
auth->info.lnkname, acl));
acls = &(auth->params.acl_pipe);
} else if (res == RAD_MPD_QUEUE) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_QUEUE: %s",
auth->info.lnkname, acl));
acls = &(auth->params.acl_queue);
} else if (res == RAD_MPD_TABLE) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_TABLE: %s",
auth->info.lnkname, 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: Get RAD_MPD_TABLE_STATIC: %s",
auth->info.lnkname, acl));
acls = &(auth->params.acl_table);
} else
#endif /* USE_IPFW */
#ifdef USE_NG_BPF
if (res == RAD_MPD_FILTER) {
acl1 = acl = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_FILTER: %s",
auth->info.lnkname, acl));
acl2 = strsep(&acl1, "#");
i = atoi(acl2);
if (i <= 0 || i > ACL_FILTERS) {
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: Wrong filter number: %i",
auth->info.lnkname, 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: Get RAD_MPD_LIMIT: %s",
auth->info.lnkname, acl));
acl2 = strsep(&acl1, "#");
if (strcasecmp(acl2, "in") == 0) {
i = 0;
} else if (strcasecmp(acl2, "out") == 0) {
i = 1;
} else {
Log(LG_ERR|LG_ERR, ("[%s] RADIUS: Wrong limit direction: '%s'",
auth->info.lnkname, acl2));
free(acl);
break;
}
acls = &(auth->params.acl_limits[i]);
} else if (res == RAD_MPD_INPUT_ACCT) {
tmpval = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_INPUT_ACCT: %s",
auth->info.lnkname, tmpval));
strlcpy(auth->params.std_acct[0], tmpval,
sizeof(auth->params.std_acct[0]));
free(tmpval);
break;
} else if (res == RAD_MPD_OUTPUT_ACCT) {
tmpval = rad_cvt_string(data, len);
Log(LG_RADIUS2, ("[%s] RADIUS: Get RAD_MPD_OUTPUT_ACCT: %s",
auth->info.lnkname, tmpval));
strlcpy(auth->params.std_acct[1], tmpval,
sizeof(auth->params.std_acct[1]));
free(tmpval);
break;
} else
#endif /* USE_NG_BPF */
{
Log(LG_RADIUS2, ("[%s] RADIUS: Dropping MPD vendor specific attribute: %d",
auth->info.lnkname, res));
break;
}
#if defined(USE_NG_BPF) || defined(USE_IPFW)
if (acl1 == NULL) {
Log(LG_ERR, ("[%s] RADIUS: Incorrect acl!", auth->info.lnkname));
free(acl);
break;
}
acl3 = acl1;
strsep(&acl3, "=");
acl2 = acl1;
strsep(&acl2, "#");
i = atoi(acl1);
if (i <= 0) {
Log(LG_ERR, ("[%s] RADIUS: Wrong acl number: %i",
auth->info.lnkname, i));
free(acl);
break;
}
if ((acl3 == NULL) || (acl3[0] == 0)) {
Log(LG_ERR, ("[%s] RADIUS: Wrong acl", auth->info.lnkname));
free(acl);
break;
}
acls1 = Malloc(MB_AUTH, sizeof(struct acl) + strlen(acl3));
if (res != RAD_MPD_TABLE_STATIC) {
acls1->number = i;
acls1->real_number = 0;
} else {
acls1->number = 0;
acls1->real_number = i;
}
if (acl2)
strlcpy(acls1->name, acl2, sizeof(acls1->name));
strcpy(acls1->rule, acl3);
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: Duplicate acl", auth->info.lnkname));
Freee(acls1);
free(acl);
break;
} else {
acls1->next = *acls;
}
*acls = acls1;
free(acl);
break;
#endif /* USE_NG_BPF or USE_IPFW */
default:
Log(LG_RADIUS2, ("[%s] RADIUS: Dropping vendor %d attribute: %d",
auth->info.lnkname, vendor, res));
break;
}
break;
default:
Log(LG_RADIUS2, ("[%s] RADIUS: Dropping attribute: %d",
auth->info.lnkname, res));
break;
}
}
if (auth->acct_type == 0) {
/* sanity check, this happens when FreeRADIUS has no msoft-dictionary loaded */
if (auth->proto == PROTO_CHAP && auth->alg == CHAP_ALG_MSOFTv2
&& auth->mschapv2resp == NULL && auth->status == AUTH_STATUS_SUCCESS) {
Log(LG_ERR|LG_RADIUS,
("[%s] RADIUS: PANIC no MS-CHAP2-Success received from server!",
auth->info.lnkname));
return RAD_NACK;
}
/* MPPE allowed or required, but no MPPE keys returned */
/* print warning, because MPPE doesen't work */
if (!(auth->params.msoft.has_keys || auth->params.msoft.has_nt_hash || auth->params.msoft.has_lm_hash) &&
auth->params.msoft.policy != MPPE_POLICY_NONE) {
Log(LG_ERR|LG_RADIUS,
("[%s] RADIUS: WARNING no MPPE-Keys received, MPPE will not work",
auth->info.lnkname));
}
/* 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 &&
(auth->params.msoft.has_keys || auth->params.msoft.has_nt_hash || auth->params.msoft.has_lm_hash)) {
auth->params.msoft.policy = MPPE_POLICY_ALLOWED;
auth->params.msoft.types = MPPE_TYPE_40BIT | MPPE_TYPE_128BIT | MPPE_TYPE_56BIT;
Log(LG_ERR|LG_RADIUS,
("[%s] RADIUS: MPPE-Keys present, but no MPPE-Infos received => allowing MPPE with all types",
auth->info.lnkname));
}
/* If Framed-IP-Address is present and Framed-Netmask != 32 add route */
if (auth->params.range_valid && auth->params.range.width == 32 &&
auth->params.netmask != 0 && auth->params.netmask != 32) {
struct in_addr tmpmask;
widthtoin_addr(auth->params.netmask, &tmpmask);
r = Malloc(MB_AUTH, sizeof(struct ifaceroute));
r->dest.addr = auth->params.range.addr;
r->dest.addr.u.ip4.s_addr &= tmpmask.s_addr;
r->dest.width = auth->params.netmask;
r->ok = 0;
j = 0;
SLIST_FOREACH(r1, &auth->params.routes, next) {
if (!u_rangecompare(&r->dest, &r1->dest)) {
Log(LG_ERR|LG_RADIUS,
("[%s] RADIUS: Duplicate route", auth->info.lnkname));
j = 1;
}
};
if (j == 0) {
SLIST_INSERT_HEAD(&auth->params.routes, r, next);
} else {
Freee(r);
}
}
}
return (RAD_ACK);
}
static void
RadiusLogError(AuthData auth, const char *errmsg)
{
Log(LG_ERR|LG_RADIUS, ("[%s] RADIUS: %s: %s",
auth->info.lnkname, errmsg, rad_strerror(auth->radius.handle)));
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>