mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-04 12:52:15 +00:00
Add support for MS-CHAP authentication via a RADIUS server.
Add support for Reply-Message and MS-CHAP-Error. Sponsored by: Monzoon
This commit is contained in:
parent
066003a540
commit
ff8e577bc6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=96324
@ -52,8 +52,8 @@ struct authinfo {
|
||||
} cfg;
|
||||
};
|
||||
|
||||
#define auth_Failure(a) (*a->fn.failure)(a);
|
||||
#define auth_Success(a) (*a->fn.success)(a);
|
||||
#define auth_Failure(a) (*(a)->fn.failure)(a)
|
||||
#define auth_Success(a) (*(a)->fn.success)(a)
|
||||
|
||||
extern const char *Auth2Nam(u_short, u_char);
|
||||
extern void auth_Init(struct authinfo *, struct physical *,
|
||||
|
@ -544,13 +544,20 @@ chap_Challenge(struct authinfo *authp)
|
||||
static void
|
||||
chap_Success(struct authinfo *authp)
|
||||
{
|
||||
struct bundle *bundle = authp->physical->dl->bundle;
|
||||
const char *msg;
|
||||
|
||||
datalink_GotAuthname(authp->physical->dl, authp->in.name);
|
||||
#ifndef NODES
|
||||
if (authp->physical->link.lcp.want_authtype == 0x81) {
|
||||
msg = auth2chap(authp)->authresponse;
|
||||
MPPE_MasterKeyValid = 1; /* XXX Global ! */
|
||||
} else
|
||||
#endif
|
||||
#ifndef NORADIUS
|
||||
if (*bundle->radius.cfg.file && bundle->radius.repstr)
|
||||
msg = bundle->radius.repstr;
|
||||
else
|
||||
#endif
|
||||
msg = "Welcome!!";
|
||||
|
||||
@ -558,7 +565,7 @@ chap_Success(struct authinfo *authp)
|
||||
NULL);
|
||||
|
||||
authp->physical->link.lcp.auth_ineed = 0;
|
||||
if (Enabled(authp->physical->dl->bundle, OPT_UTMP))
|
||||
if (Enabled(bundle, OPT_UTMP))
|
||||
physical_Login(authp->physical, authp->in.name);
|
||||
|
||||
if (authp->physical->link.lcp.auth_iwait == 0)
|
||||
@ -573,13 +580,21 @@ static void
|
||||
chap_Failure(struct authinfo *authp)
|
||||
{
|
||||
#ifndef NODES
|
||||
char buf[1024];
|
||||
char buf[1024], *ptr;
|
||||
#endif
|
||||
const char *msg;
|
||||
|
||||
#ifndef NORADIUS
|
||||
struct bundle *bundle = authp->physical->link.lcp.fsm.bundle;
|
||||
if (*bundle->radius.cfg.file && bundle->radius.errstr)
|
||||
msg = bundle->radius.errstr;
|
||||
else
|
||||
#endif
|
||||
#ifndef NODES
|
||||
if (authp->physical->link.lcp.want_authtype == 0x81) {
|
||||
char *ptr;
|
||||
if (authp->physical->link.lcp.want_authtype == 0x80) {
|
||||
sprintf(buf, "E=691 R=1 M=Invalid!");
|
||||
msg = buf;
|
||||
} else if (authp->physical->link.lcp.want_authtype == 0x81) {
|
||||
int i;
|
||||
|
||||
ptr = buf;
|
||||
|
@ -143,10 +143,17 @@ SendPapCode(struct authinfo *authp, int code, const char *message)
|
||||
static void
|
||||
pap_Success(struct authinfo *authp)
|
||||
{
|
||||
struct bundle *bundle = authp->physical->dl->bundle;
|
||||
|
||||
datalink_GotAuthname(authp->physical->dl, authp->in.name);
|
||||
SendPapCode(authp, PAP_ACK, "Greetings!!");
|
||||
#ifndef NORADIUS
|
||||
if (*bundle->radius.cfg.file && bundle->radius.repstr)
|
||||
SendPapCode(authp, PAP_ACK, bundle->radius.repstr);
|
||||
else
|
||||
#endif
|
||||
SendPapCode(authp, PAP_ACK, "Greetings!!");
|
||||
authp->physical->link.lcp.auth_ineed = 0;
|
||||
if (Enabled(authp->physical->dl->bundle, OPT_UTMP))
|
||||
if (Enabled(bundle, OPT_UTMP))
|
||||
physical_Login(authp->physical, authp->in.name);
|
||||
|
||||
if (authp->physical->link.lcp.auth_iwait == 0)
|
||||
|
@ -5329,6 +5329,14 @@ keywords.
|
||||
.It RAD_SESSION_TIMEOUT
|
||||
If supplied, the client connection is closed after the given number of
|
||||
seconds.
|
||||
.It RAD_REPLY_MESSAGE
|
||||
If supplied, this message is passed back to the peer as the authentication
|
||||
SUCCESS text.
|
||||
.It RAD_MICROSOFT_MS_CHAP_ERROR
|
||||
If this
|
||||
.Dv RAD_VENDOR_MICROSOFT
|
||||
vendor specific attribute is supplied, it is passed back to the peer as the
|
||||
authentication FAILURE text.
|
||||
.El
|
||||
Values received from the RADIUS server may be viewed using
|
||||
.Dq show bundle .
|
||||
|
@ -38,8 +38,10 @@
|
||||
|
||||
#ifdef LOCALRAD
|
||||
#include "radlib.h"
|
||||
#include "radlib_vs.h"
|
||||
#else
|
||||
#include <radlib.h>
|
||||
#include <radlib_vs.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
@ -86,6 +88,16 @@
|
||||
#include "datalink.h"
|
||||
#include "ncp.h"
|
||||
#include "bundle.h"
|
||||
#include "proto.h"
|
||||
|
||||
#ifndef NODES
|
||||
struct mschap_request {
|
||||
u_char ident;
|
||||
u_char flags;
|
||||
u_char lm_response[24];
|
||||
u_char nt_response[24];
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* rad_continue_send_request() has given us `got' (non-zero). Deal with it.
|
||||
@ -95,13 +107,13 @@ radius_Process(struct radius *r, int got)
|
||||
{
|
||||
char *argv[MAXARGS], *nuke;
|
||||
struct bundle *bundle;
|
||||
int argc, addrs, width;
|
||||
int argc, addrs, res, width;
|
||||
size_t len;
|
||||
struct ncprange dest;
|
||||
struct ncpaddr gw;
|
||||
const void *data;
|
||||
const char *stype;
|
||||
u_int32_t ipaddr;
|
||||
u_int32_t ipaddr, vendor;
|
||||
struct in_addr ip;
|
||||
|
||||
r->cx.fd = -1; /* Stop select()ing */
|
||||
@ -118,10 +130,11 @@ radius_Process(struct radius *r, int got)
|
||||
|
||||
case RAD_ACCESS_REJECT:
|
||||
log_Printf(LogPHASE, "Radius(%s): REJECT received\n", stype);
|
||||
if (r->cx.auth)
|
||||
auth_Failure(r->cx.auth);
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
if (!r->cx.auth) {
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case RAD_ACCESS_CHALLENGE:
|
||||
/* we can't deal with this (for now) ! */
|
||||
@ -156,40 +169,41 @@ radius_Process(struct radius *r, int got)
|
||||
return;
|
||||
}
|
||||
|
||||
/* So we've been accepted ! Let's see what we've got in our reply :-I */
|
||||
/* Let's see what we've got in our reply */
|
||||
r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
|
||||
r->mtu = 0;
|
||||
r->vj = 0;
|
||||
while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
|
||||
switch (got) {
|
||||
while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
|
||||
switch (res) {
|
||||
case RAD_FRAMED_IP_ADDRESS:
|
||||
r->ip = rad_cvt_addr(data);
|
||||
log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip));
|
||||
log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip));
|
||||
break;
|
||||
|
||||
case RAD_FILTER_ID:
|
||||
free(r->filterid);
|
||||
if ((r->filterid = rad_cvt_string(data, len)) == NULL) {
|
||||
log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
|
||||
auth_Failure(r->cx.auth);
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
}
|
||||
log_Printf(LogPHASE, " Filter \"%s\"\n", r->filterid);
|
||||
log_Printf(LogPHASE, " Filter \"%s\"\n", r->filterid);
|
||||
break;
|
||||
|
||||
case RAD_SESSION_TIMEOUT:
|
||||
r->sessiontime = rad_cvt_int(data);
|
||||
log_Printf(LogPHASE, " Session-Timeout %lu\n", r->sessiontime);
|
||||
log_Printf(LogPHASE, " Session-Timeout %lu\n", r->sessiontime);
|
||||
break;
|
||||
|
||||
case RAD_FRAMED_IP_NETMASK:
|
||||
r->mask = rad_cvt_addr(data);
|
||||
log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask));
|
||||
log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask));
|
||||
break;
|
||||
|
||||
case RAD_FRAMED_MTU:
|
||||
r->mtu = rad_cvt_int(data);
|
||||
log_Printf(LogPHASE, " MTU %lu\n", r->mtu);
|
||||
log_Printf(LogPHASE, " MTU %lu\n", r->mtu);
|
||||
break;
|
||||
|
||||
case RAD_FRAMED_ROUTING:
|
||||
@ -201,7 +215,7 @@ radius_Process(struct radius *r, int got)
|
||||
|
||||
case RAD_FRAMED_COMPRESSION:
|
||||
r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
|
||||
log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis");
|
||||
log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis");
|
||||
break;
|
||||
|
||||
case RAD_FRAMED_ROUTE:
|
||||
@ -214,11 +228,12 @@ radius_Process(struct radius *r, int got)
|
||||
|
||||
if ((nuke = rad_cvt_string(data, len)) == NULL) {
|
||||
log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
|
||||
auth_Failure(r->cx.auth);
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
}
|
||||
|
||||
log_Printf(LogPHASE, " Route: %s\n", nuke);
|
||||
log_Printf(LogPHASE, " Route: %s\n", nuke);
|
||||
bundle = r->cx.auth->physical->dl->bundle;
|
||||
ip.s_addr = INADDR_ANY;
|
||||
ncprange_setip4host(&dest, ip);
|
||||
@ -258,19 +273,73 @@ radius_Process(struct radius *r, int got)
|
||||
}
|
||||
free(nuke);
|
||||
break;
|
||||
|
||||
case RAD_REPLY_MESSAGE:
|
||||
free(r->repstr);
|
||||
if ((r->repstr = rad_cvt_string(data, len)) == NULL) {
|
||||
log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
|
||||
auth_Failure(r->cx.auth);
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
}
|
||||
log_Printf(LogPHASE, " Reply-Message \"%s\"\n", r->repstr);
|
||||
break;
|
||||
|
||||
case RAD_VENDOR_SPECIFIC:
|
||||
if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) {
|
||||
log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n",
|
||||
rad_strerror(r->cx.rad));
|
||||
auth_Failure(r->cx.auth);
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (vendor) {
|
||||
case RAD_VENDOR_MICROSOFT:
|
||||
switch (res) {
|
||||
case RAD_MICROSOFT_MS_CHAP_ERROR:
|
||||
free(r->errstr);
|
||||
if ((r->errstr = rad_cvt_string(data, len)) == NULL) {
|
||||
log_Printf(LogERROR, "rad_cvt_string: %s\n",
|
||||
rad_strerror(r->cx.rad));
|
||||
auth_Failure(r->cx.auth);
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
}
|
||||
log_Printf(LogPHASE, " MS-CHAP-Error \"%s\"\n", r->errstr);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific "
|
||||
"RADIUS attribute %d\n", res);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n",
|
||||
(unsigned long)vendor, res);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (got == -1) {
|
||||
if (res == -1) {
|
||||
log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
|
||||
rad_strerror(r->cx.rad));
|
||||
auth_Failure(r->cx.auth);
|
||||
rad_close(r->cx.rad);
|
||||
} else {
|
||||
} else if (got == RAD_ACCESS_REJECT)
|
||||
auth_Failure(r->cx.auth);
|
||||
else {
|
||||
r->valid = 1;
|
||||
auth_Success(r->cx.auth);
|
||||
rad_close(r->cx.rad);
|
||||
}
|
||||
rad_close(r->cx.rad);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -358,15 +427,24 @@ radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
|
||||
void
|
||||
radius_Init(struct radius *r)
|
||||
{
|
||||
r->valid = 0;
|
||||
r->cx.fd = -1;
|
||||
*r->cfg.file = '\0';;
|
||||
r->desc.type = RADIUS_DESCRIPTOR;
|
||||
r->desc.UpdateSet = radius_UpdateSet;
|
||||
r->desc.IsSet = radius_IsSet;
|
||||
r->desc.Read = radius_Read;
|
||||
r->desc.Write = radius_Write;
|
||||
r->cx.fd = -1;
|
||||
r->cx.rad = NULL;
|
||||
memset(&r->cx.timer, '\0', sizeof r->cx.timer);
|
||||
r->cx.auth = NULL;
|
||||
r->valid = 0;
|
||||
r->vj = 0;
|
||||
r->ip.s_addr = INADDR_ANY;
|
||||
r->mask.s_addr = INADDR_NONE;
|
||||
r->routes = NULL;
|
||||
r->mtu = DEF_MTU;
|
||||
r->repstr = NULL;
|
||||
r->errstr = NULL;
|
||||
*r->cfg.file = '\0';;
|
||||
log_Printf(LogDEBUG, "Radius: radius_Init\n");
|
||||
}
|
||||
|
||||
@ -382,6 +460,10 @@ radius_Destroy(struct radius *r)
|
||||
route_DeleteAll(&r->routes);
|
||||
free(r->filterid);
|
||||
r->filterid = NULL;
|
||||
free(r->repstr);
|
||||
r->repstr = NULL;
|
||||
free(r->errstr);
|
||||
r->errstr = NULL;
|
||||
if (r->cx.fd != -1) {
|
||||
r->cx.fd = -1;
|
||||
rad_close(r->cx.rad);
|
||||
@ -401,6 +483,9 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
struct hostent *hp;
|
||||
struct in_addr hostaddr;
|
||||
#ifndef NODES
|
||||
struct mschap_request msreq;
|
||||
#endif
|
||||
|
||||
if (!*r->cfg.file)
|
||||
return;
|
||||
@ -439,20 +524,54 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
|
||||
return;
|
||||
}
|
||||
|
||||
if (challenge != NULL) {
|
||||
/* We're talking CHAP */
|
||||
if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 ||
|
||||
rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, challenge, clen) != 0) {
|
||||
log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
|
||||
switch (authp->physical->link.lcp.want_auth) {
|
||||
case PROTO_PAP:
|
||||
/* We're talking PAP */
|
||||
if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) {
|
||||
log_Printf(LogERROR, "PAP: rad_put_string: %s\n",
|
||||
rad_strerror(r->cx.rad));
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
}
|
||||
} else if (rad_put_attr(r->cx.rad, RAD_USER_PASSWORD, key, klen) != 0) {
|
||||
/* We're talking PAP */
|
||||
log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad));
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
break;
|
||||
|
||||
case PROTO_CHAP:
|
||||
switch (authp->physical->link.lcp.want_authtype) {
|
||||
case 0x5:
|
||||
if (rad_put_attr(r->cx.rad, RAD_CHAP_PASSWORD, key, klen) != 0 ||
|
||||
rad_put_attr(r->cx.rad, RAD_CHAP_CHALLENGE, challenge, clen) != 0) {
|
||||
log_Printf(LogERROR, "CHAP: rad_put_string: %s\n",
|
||||
rad_strerror(r->cx.rad));
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifndef NODES
|
||||
case 0x80:
|
||||
if (klen != 50) {
|
||||
log_Printf(LogERROR, "CHAP80: Unrecognised length %d\n", klen);
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
}
|
||||
rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
|
||||
RAD_MICROSOFT_MS_CHAP_CHALLENGE, challenge, clen);
|
||||
msreq.ident = *key;
|
||||
msreq.flags = 0x01;
|
||||
memcpy(msreq.lm_response, key + 1, 24);
|
||||
memcpy(msreq.nt_response, key + 25, 24);
|
||||
rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
|
||||
RAD_MICROSOFT_MS_CHAP_RESPONSE, &msreq, 50);
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
#endif
|
||||
default:
|
||||
log_Printf(LogERROR, "CHAP: Unrecognised type 0x%02x\n",
|
||||
authp->physical->link.lcp.want_authtype);
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (gethostname(hostname, sizeof hostname) != 0)
|
||||
@ -481,7 +600,7 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
|
||||
for (slot = 1; (ttyp = getttyent()); ++slot)
|
||||
if (!strcmp(ttyp->ty_name, authp->physical->name.base)) {
|
||||
if (rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) {
|
||||
log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
|
||||
log_Printf(LogERROR, "rad_put: rad_put_int: %s\n",
|
||||
rad_strerror(r->cx.rad));
|
||||
rad_close(r->cx.rad);
|
||||
endttyent();
|
||||
@ -490,6 +609,11 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
|
||||
break;
|
||||
}
|
||||
endttyent();
|
||||
} else if (rad_put_int(r->cx.rad, RAD_NAS_PORT, 0) != 0) {
|
||||
log_Printf(LogERROR, "rad_put: rad_put_int: %s\n",
|
||||
rad_strerror(r->cx.rad));
|
||||
rad_close(r->cx.rad);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -673,6 +797,8 @@ radius_Show(struct radius *r, struct prompt *p)
|
||||
prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask));
|
||||
prompt_Printf(p, " MTU: %lu\n", r->mtu);
|
||||
prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis");
|
||||
prompt_Printf(p, " Message: %s\n", r->repstr ? r->repstr : "");
|
||||
prompt_Printf(p, " Error Message: %s\n", r->errstr ? r->errstr : "");
|
||||
if (r->routes)
|
||||
route_ShowSticky(p, r->routes, " Routes", 16);
|
||||
} else
|
||||
|
@ -42,6 +42,8 @@ struct radius {
|
||||
unsigned long sessiontime; /* Session-Timeout */
|
||||
char *filterid; /* FRAMED Filter Id */
|
||||
struct sticky_route *routes; /* FRAMED Routes */
|
||||
char *repstr; /* Reply-Message */
|
||||
char *errstr; /* Error-Message */
|
||||
struct {
|
||||
char file[PATH_MAX]; /* Radius config file */
|
||||
} cfg;
|
||||
|
Loading…
Reference in New Issue
Block a user