Understand the following Microsoft Vendor Specific RADIUS attributes:
RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES RAD_MICROSOFT_MS_MPPE_RECV_KEY RAD_MICROSOFT_MS_MPPE_SEND_KEY These attributes may be supplied by a RADIUS server when MSCHAPv2 is used to authenticate. It *should* now be possible to build ppp with -DNODES and still support CHAP/MSCHAP/MSCHAPv2/MPPE via a RADIUS server, but the code isn't yet smart enough to do that (building with -DNODES just looses these facilities). Sponsored by: Monzoon
This commit is contained in:
parent
628e6cd45f
commit
8fb5ef5ae2
@ -369,7 +369,7 @@ CcpSendConfigReq(struct fsm *fp)
|
||||
(*o)->val.hdr.len = 2;
|
||||
(*o)->next = NULL;
|
||||
(*o)->algorithm = f;
|
||||
(*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg);
|
||||
(*algorithm[f]->o.OptInit)(fp->bundle, &(*o)->val, &ccp->cfg);
|
||||
}
|
||||
|
||||
if (cp + (*o)->val.hdr.len > buff + sizeof buff) {
|
||||
@ -517,7 +517,8 @@ CcpLayerUp(struct fsm *fp)
|
||||
|
||||
if (ccp->in.state == NULL && ccp->in.algorithm >= 0 &&
|
||||
ccp->in.algorithm < NALGORITHMS) {
|
||||
ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt);
|
||||
ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)
|
||||
(fp->bundle, &ccp->in.opt);
|
||||
if (ccp->in.state == NULL) {
|
||||
log_Printf(LogERROR, "%s: %s (in) initialisation failure\n",
|
||||
fp->link->name, protoname(ccp->his_proto));
|
||||
@ -534,7 +535,8 @@ CcpLayerUp(struct fsm *fp)
|
||||
|
||||
if (ccp->out.state == NULL && ccp->out.algorithm >= 0 &&
|
||||
ccp->out.algorithm < NALGORITHMS) {
|
||||
ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)(&(*o)->val);
|
||||
ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init)
|
||||
(fp->bundle, &(*o)->val);
|
||||
if (ccp->out.state == NULL) {
|
||||
log_Printf(LogERROR, "%s: %s (out) initialisation failure\n",
|
||||
fp->link->name, protoname(ccp->my_proto));
|
||||
@ -596,7 +598,7 @@ CcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
|
||||
(*algorithm[f]->Usable)(fp) &&
|
||||
ccp->in.algorithm == -1) {
|
||||
memcpy(&ccp->in.opt, opt, opt->hdr.len);
|
||||
switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) {
|
||||
switch ((*algorithm[f]->i.Set)(fp->bundle, &ccp->in.opt, &ccp->cfg)) {
|
||||
case MODE_REJ:
|
||||
fsm_rej(dec, &ccp->in.opt);
|
||||
break;
|
||||
@ -622,7 +624,8 @@ CcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
|
||||
" option\n", fp->link->name);
|
||||
else {
|
||||
memcpy(&o->val, opt, opt->hdr.len);
|
||||
if ((*algorithm[f]->o.Set)(&o->val, &ccp->cfg) == MODE_ACK)
|
||||
if ((*algorithm[f]->o.Set)(fp->bundle, &o->val, &ccp->cfg) ==
|
||||
MODE_ACK)
|
||||
ccp->my_proto = algorithm[f]->id;
|
||||
else {
|
||||
ccp->his_reject |= (1 << opt->hdr.id);
|
||||
|
@ -127,8 +127,8 @@ struct ccp_algorithm {
|
||||
int (*Usable)(struct fsm *); /* Ok to negotiate ? */
|
||||
int (*Required)(struct fsm *); /* Must negotiate ? */
|
||||
struct {
|
||||
int (*Set)(struct fsm_opt *, const struct ccp_config *);
|
||||
void *(*Init)(struct fsm_opt *);
|
||||
int (*Set)(struct bundle *, struct fsm_opt *, const struct ccp_config *);
|
||||
void *(*Init)(struct bundle *, struct fsm_opt *);
|
||||
void (*Term)(void *);
|
||||
void (*Reset)(void *);
|
||||
struct mbuf *(*Read)(void *, struct ccp *, u_short *, struct mbuf *);
|
||||
@ -136,9 +136,10 @@ struct ccp_algorithm {
|
||||
} i;
|
||||
struct {
|
||||
int MTUOverhead;
|
||||
void (*OptInit)(struct fsm_opt *, const struct ccp_config *);
|
||||
int (*Set)(struct fsm_opt *, const struct ccp_config *);
|
||||
void *(*Init)(struct fsm_opt *);
|
||||
void (*OptInit)(struct bundle *, struct fsm_opt *,
|
||||
const struct ccp_config *);
|
||||
int (*Set)(struct bundle *, struct fsm_opt *, const struct ccp_config *);
|
||||
void *(*Init)(struct bundle *, struct fsm_opt *);
|
||||
void (*Term)(void *);
|
||||
int (*Reset)(void *);
|
||||
struct mbuf *(*Write)(void *, struct ccp *, struct link *, int, u_short *,
|
||||
|
@ -440,7 +440,8 @@ DeflateDispOpts(struct fsm_opt *o)
|
||||
}
|
||||
|
||||
static void
|
||||
DeflateInitOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
DeflateInitOptsOutput(struct bundle *bundle, struct fsm_opt *o,
|
||||
const struct ccp_config *cfg)
|
||||
{
|
||||
o->hdr.len = 4;
|
||||
o->data[0] = ((cfg->deflate.out.winsize - 8) << 4) + 8;
|
||||
@ -448,7 +449,8 @@ DeflateInitOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
}
|
||||
|
||||
static int
|
||||
DeflateSetOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
DeflateSetOptsOutput(struct bundle *bundle, struct fsm_opt *o,
|
||||
const struct ccp_config *cfg)
|
||||
{
|
||||
if (o->hdr.len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0')
|
||||
return MODE_REJ;
|
||||
@ -462,7 +464,8 @@ DeflateSetOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
}
|
||||
|
||||
static int
|
||||
DeflateSetOptsInput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
DeflateSetOptsInput(struct bundle *bundle, struct fsm_opt *o,
|
||||
const struct ccp_config *cfg)
|
||||
{
|
||||
int want;
|
||||
|
||||
@ -483,7 +486,7 @@ DeflateSetOptsInput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
}
|
||||
|
||||
static void *
|
||||
DeflateInitInput(struct fsm_opt *o)
|
||||
DeflateInitInput(struct bundle *bundle, struct fsm_opt *o)
|
||||
{
|
||||
struct deflate_state *state;
|
||||
|
||||
@ -506,7 +509,7 @@ DeflateInitInput(struct fsm_opt *o)
|
||||
}
|
||||
|
||||
static void *
|
||||
DeflateInitOutput(struct fsm_opt *o)
|
||||
DeflateInitOutput(struct bundle *bundle, struct fsm_opt *o)
|
||||
{
|
||||
struct deflate_state *state;
|
||||
|
||||
|
@ -26,11 +26,13 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -54,6 +56,19 @@
|
||||
#include "proto.h"
|
||||
#include "mppe.h"
|
||||
#include "ua.h"
|
||||
#include "descriptor.h"
|
||||
#ifndef NORADIUS
|
||||
#include "radius.h"
|
||||
#endif
|
||||
#include "ncpaddr.h"
|
||||
#include "iplist.h"
|
||||
#include "slcompress.h"
|
||||
#include "ipcp.h"
|
||||
#include "ipv6cp.h"
|
||||
#include "filter.h"
|
||||
#include "mp.h"
|
||||
#include "ncp.h"
|
||||
#include "bundle.h"
|
||||
|
||||
/*
|
||||
* Documentation:
|
||||
@ -427,29 +442,50 @@ MPPEUsable(struct fsm *fp)
|
||||
static int
|
||||
MPPERequired(struct fsm *fp)
|
||||
{
|
||||
#ifndef NORADIUS
|
||||
/*
|
||||
* If the radius server gave us RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY,
|
||||
* use that instead of our configuration value.
|
||||
*/
|
||||
if (*fp->bundle->radius.cfg.file && fp->bundle->radius.mppe.policy)
|
||||
return fp->bundle->radius.mppe.policy == MPPE_POLICY_REQUIRED ? 1 : 0;
|
||||
#endif
|
||||
|
||||
return fp->link->ccp.cfg.mppe.required;
|
||||
}
|
||||
|
||||
static u_int32_t
|
||||
MPPE_ConfigVal(const struct ccp_config *cfg)
|
||||
MPPE_ConfigVal(struct bundle *bundle, const struct ccp_config *cfg)
|
||||
{
|
||||
u_int32_t val;
|
||||
|
||||
val = cfg->mppe.state == MPPE_STATELESS ? MPPE_OPT_STATELESS : 0;
|
||||
switch(cfg->mppe.keybits) {
|
||||
case 128:
|
||||
val |= MPPE_OPT_128BIT;
|
||||
break;
|
||||
case 56:
|
||||
val |= MPPE_OPT_56BIT;
|
||||
break;
|
||||
case 40:
|
||||
val |= MPPE_OPT_40BIT;
|
||||
break;
|
||||
case 0:
|
||||
val |= MPPE_OPT_128BIT | MPPE_OPT_56BIT | MPPE_OPT_40BIT;
|
||||
break;
|
||||
}
|
||||
#ifndef NORADIUS
|
||||
/*
|
||||
* If the radius server gave us RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES,
|
||||
* use that instead of our configuration value.
|
||||
*/
|
||||
if (*bundle->radius.cfg.file && bundle->radius.mppe.types) {
|
||||
if (bundle->radius.mppe.types & MPPE_TYPE_40BIT)
|
||||
val |= MPPE_OPT_40BIT;
|
||||
if (bundle->radius.mppe.types & MPPE_TYPE_128BIT)
|
||||
val |= MPPE_OPT_128BIT;
|
||||
} else
|
||||
#endif
|
||||
switch(cfg->mppe.keybits) {
|
||||
case 128:
|
||||
val |= MPPE_OPT_128BIT;
|
||||
break;
|
||||
case 56:
|
||||
val |= MPPE_OPT_56BIT;
|
||||
break;
|
||||
case 40:
|
||||
val |= MPPE_OPT_40BIT;
|
||||
break;
|
||||
case 0:
|
||||
val |= MPPE_OPT_128BIT | MPPE_OPT_56BIT | MPPE_OPT_40BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
@ -458,7 +494,8 @@ MPPE_ConfigVal(const struct ccp_config *cfg)
|
||||
* What options should we use for our first configure request
|
||||
*/
|
||||
static void
|
||||
MPPEInitOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
MPPEInitOptsOutput(struct bundle *bundle, struct fsm_opt *o,
|
||||
const struct ccp_config *cfg)
|
||||
{
|
||||
u_int32_t mval;
|
||||
|
||||
@ -471,7 +508,8 @@ MPPEInitOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
return;
|
||||
}
|
||||
|
||||
mval = MPPE_ConfigVal(cfg);
|
||||
|
||||
mval = MPPE_ConfigVal(bundle, cfg);
|
||||
ua_htonl(&mval, o->data);
|
||||
}
|
||||
|
||||
@ -479,7 +517,8 @@ MPPEInitOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
* Our CCP request was NAK'd with the given options
|
||||
*/
|
||||
static int
|
||||
MPPESetOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
MPPESetOptsOutput(struct bundle *bundle, struct fsm_opt *o,
|
||||
const struct ccp_config *cfg)
|
||||
{
|
||||
u_int32_t mval, peer;
|
||||
|
||||
@ -489,7 +528,7 @@ MPPESetOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
/* Treat their NAK as a REJ */
|
||||
return MODE_NAK;
|
||||
|
||||
mval = MPPE_ConfigVal(cfg);
|
||||
mval = MPPE_ConfigVal(bundle, cfg);
|
||||
|
||||
/*
|
||||
* If we haven't been configured with a specific number of keybits, allow
|
||||
@ -517,7 +556,8 @@ MPPESetOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
* The peer has requested the given options
|
||||
*/
|
||||
static int
|
||||
MPPESetOptsInput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
MPPESetOptsInput(struct bundle *bundle, struct fsm_opt *o,
|
||||
const struct ccp_config *cfg)
|
||||
{
|
||||
u_int32_t mval, peer;
|
||||
int res = MODE_ACK;
|
||||
@ -532,7 +572,7 @@ MPPESetOptsInput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
return MODE_ACK;
|
||||
}
|
||||
|
||||
mval = MPPE_ConfigVal(cfg);
|
||||
mval = MPPE_ConfigVal(bundle, cfg);
|
||||
|
||||
if (peer & ~MPPE_OPT_MASK)
|
||||
/* He's asking for bits we don't know about */
|
||||
@ -620,7 +660,7 @@ MPPE_InitState(struct fsm_opt *o)
|
||||
}
|
||||
|
||||
static void *
|
||||
MPPEInitInput(struct fsm_opt *o)
|
||||
MPPEInitInput(struct bundle *bundle, struct fsm_opt *o)
|
||||
{
|
||||
struct mppe_state *mip;
|
||||
|
||||
@ -636,8 +676,17 @@ MPPEInitInput(struct fsm_opt *o)
|
||||
|
||||
log_Printf(LogDEBUG, "MPPE: InitInput: %d-bits\n", mip->keybits);
|
||||
|
||||
GetAsymetricStartKey(MPPE_MasterKey, mip->mastkey, mip->keylen, 0,
|
||||
MPPE_IsServer);
|
||||
#ifndef NORADIUS
|
||||
if (*bundle->radius.cfg.file && bundle->radius.mppe.recvkey) {
|
||||
mip->keylen = bundle->radius.mppe.recvkeylen;
|
||||
if (mip->keylen > sizeof mip->mastkey)
|
||||
mip->keylen = sizeof mip->mastkey;
|
||||
memcpy(mip->mastkey, bundle->radius.mppe.recvkey, mip->keylen);
|
||||
} else
|
||||
#endif
|
||||
GetAsymetricStartKey(MPPE_MasterKey, mip->mastkey, mip->keylen, 0,
|
||||
MPPE_IsServer);
|
||||
|
||||
GetNewKeyFromSHA(mip->mastkey, mip->mastkey, mip->keylen, mip->sesskey);
|
||||
|
||||
MPPEReduceSessionKey(mip);
|
||||
@ -666,7 +715,7 @@ MPPEInitInput(struct fsm_opt *o)
|
||||
}
|
||||
|
||||
static void *
|
||||
MPPEInitOutput(struct fsm_opt *o)
|
||||
MPPEInitOutput(struct bundle *bundle, struct fsm_opt *o)
|
||||
{
|
||||
struct mppe_state *mop;
|
||||
|
||||
@ -682,8 +731,17 @@ MPPEInitOutput(struct fsm_opt *o)
|
||||
|
||||
log_Printf(LogDEBUG, "MPPE: InitOutput: %d-bits\n", mop->keybits);
|
||||
|
||||
GetAsymetricStartKey(MPPE_MasterKey, mop->mastkey, mop->keylen, 1,
|
||||
MPPE_IsServer);
|
||||
#ifndef NORADIUS
|
||||
if (*bundle->radius.cfg.file && bundle->radius.mppe.sendkey) {
|
||||
mop->keylen = bundle->radius.mppe.sendkeylen;
|
||||
if (mop->keylen > sizeof mop->mastkey)
|
||||
mop->keylen = sizeof mop->mastkey;
|
||||
memcpy(mop->mastkey, bundle->radius.mppe.sendkey, mop->keylen);
|
||||
} else
|
||||
#endif
|
||||
GetAsymetricStartKey(MPPE_MasterKey, mop->mastkey, mop->keylen, 1,
|
||||
MPPE_IsServer);
|
||||
|
||||
GetNewKeyFromSHA(mop->mastkey, mop->mastkey, mop->keylen, mop->sesskey);
|
||||
|
||||
MPPEReduceSessionKey(mop);
|
||||
|
@ -5081,7 +5081,8 @@ If any arguments are given,
|
||||
.Nm
|
||||
will
|
||||
.Em insist
|
||||
on using MPPE and will close the link if it's rejected by the peer.
|
||||
on using MPPE and will close the link if it's rejected by the peer (Note;
|
||||
this behaviour can be overridden by a configured RADIUS server).
|
||||
.Pp
|
||||
The first argument specifies the number of bits that
|
||||
.Nm
|
||||
@ -5243,7 +5244,7 @@ This command enables RADIUS support (if it's compiled in).
|
||||
.Ar config-file
|
||||
refers to the radius client configuration file as described in
|
||||
.Xr radius.conf 5 .
|
||||
If PAP or CHAP are
|
||||
If PAP, CHAP, MSCHAP or MSCHAPv2 are
|
||||
.Dq enable Ns No d ,
|
||||
.Nm
|
||||
behaves as a
|
||||
@ -5255,7 +5256,7 @@ authenticating from the
|
||||
.Pa ppp.secret
|
||||
file or from the passwd database.
|
||||
.Pp
|
||||
If neither PAP or CHAP are enabled,
|
||||
If none of PAP, CHAP, MSCHAP or MSCHAPv2 are enabled,
|
||||
.Dq set radius
|
||||
will do nothing.
|
||||
.Pp
|
||||
@ -5342,7 +5343,44 @@ If this
|
||||
.Dv RAD_VENDOR_MICROSOFT
|
||||
vendor specific attribute is supplied and if MS-CHAPv2 authentication is
|
||||
being used, it is passed back to the peer as the authentication SUCCESS text.
|
||||
.It RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY
|
||||
If this
|
||||
.Dv RAD_VENDOR_MICROSOFT
|
||||
vendor specific attribute is supplied and has a value of 2 (Required),
|
||||
.Nm
|
||||
will insist that MPPE encryption is used (even if no
|
||||
.Dq set mppe
|
||||
configuration command has been given with arguments).
|
||||
If it is supplied with a value of 1 (Allowed), encryption is made optional
|
||||
(despite any
|
||||
.Dq set mppe
|
||||
configuration commands with arguments).
|
||||
.It RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES
|
||||
If this
|
||||
.Dv RAD_VENDOR_MICROSOFT
|
||||
vendor specific attribute is supplied, bits 1 and 2 are examined.
|
||||
If either or both are set, 40 bit and/or 128 bit (respectively) encryption
|
||||
options are set, overriding any given first argument to the
|
||||
.Dq set mppe
|
||||
command.
|
||||
Note, it is not currently possible for the RADIUS server to specify 56 bit
|
||||
encryption.
|
||||
.It RAD_MICROSOFT_MS_MPPE_RECV_KEY
|
||||
If this
|
||||
.Dv RAD_VENDOR_MICROSOFT
|
||||
vendor specific attribute is supplied, it's value is used as the master
|
||||
key for decryption of incoming data. When clients are authenticated using
|
||||
MSCHAPv2, the RADIUS server MUST provide this attribute if inbound MPPE is
|
||||
to function.
|
||||
.It RAD_MICROSOFT_MS_MPPE_SEND_KEY
|
||||
If this
|
||||
.Dv RAD_VENDOR_MICROSOFT
|
||||
vendor specific attribute is supplied, it's value is used as the master
|
||||
key for encryption of outgoing data. When clients are authenticated using
|
||||
MSCHAPv2, the RADIUS server MUST provide this attribute if outbound MPPE is
|
||||
to function.
|
||||
.El
|
||||
.Pp
|
||||
Values received from the RADIUS server may be viewed using
|
||||
.Dq show bundle .
|
||||
.It set reconnect Ar timeout ntries
|
||||
|
@ -151,7 +151,7 @@ Pred1ResetOutput(void *v)
|
||||
}
|
||||
|
||||
static void *
|
||||
Pred1InitInput(struct fsm_opt *o)
|
||||
Pred1InitInput(struct bundle *bundle, struct fsm_opt *o)
|
||||
{
|
||||
struct pred1_state *state;
|
||||
state = (struct pred1_state *)malloc(sizeof(struct pred1_state));
|
||||
@ -161,7 +161,7 @@ Pred1InitInput(struct fsm_opt *o)
|
||||
}
|
||||
|
||||
static void *
|
||||
Pred1InitOutput(struct fsm_opt *o)
|
||||
Pred1InitOutput(struct bundle *bundle, struct fsm_opt *o)
|
||||
{
|
||||
struct pred1_state *state;
|
||||
state = (struct pred1_state *)malloc(sizeof(struct pred1_state));
|
||||
@ -300,13 +300,15 @@ Pred1DispOpts(struct fsm_opt *o)
|
||||
}
|
||||
|
||||
static void
|
||||
Pred1InitOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
Pred1InitOptsOutput(struct bundle *bundle, struct fsm_opt *o,
|
||||
const struct ccp_config *cfg)
|
||||
{
|
||||
o->hdr.len = 2;
|
||||
}
|
||||
|
||||
static int
|
||||
Pred1SetOpts(struct fsm_opt *o, const struct ccp_config *cfg)
|
||||
Pred1SetOpts(struct bundle *bundle, struct fsm_opt *o,
|
||||
const struct ccp_config *cfg)
|
||||
{
|
||||
if (o->hdr.len != 2) {
|
||||
o->hdr.len = 2;
|
||||
|
@ -28,6 +28,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in.h>
|
||||
@ -45,6 +46,9 @@
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef NODES
|
||||
#include <md5.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -104,6 +108,112 @@ struct mschap2_response {
|
||||
u_char reserved[8];
|
||||
u_char response[24];
|
||||
};
|
||||
|
||||
#define AUTH_LEN 16
|
||||
#define SALT_LEN 2
|
||||
#endif
|
||||
|
||||
static const char *
|
||||
radius_policyname(int policy)
|
||||
{
|
||||
switch(policy) {
|
||||
case MPPE_POLICY_ALLOWED:
|
||||
return "Allowed";
|
||||
case MPPE_POLICY_REQUIRED:
|
||||
return "Required";
|
||||
}
|
||||
return NumStr(policy, NULL, 0);
|
||||
}
|
||||
|
||||
static const char *
|
||||
radius_typesname(int types)
|
||||
{
|
||||
switch(types) {
|
||||
case MPPE_TYPE_40BIT:
|
||||
return "40 bit";
|
||||
case MPPE_TYPE_128BIT:
|
||||
return "128 bit";
|
||||
case MPPE_TYPE_40BIT|MPPE_TYPE_128BIT:
|
||||
return "40 or 128 bit";
|
||||
}
|
||||
return NumStr(types, NULL, 0);
|
||||
}
|
||||
|
||||
#ifndef NODES
|
||||
static void
|
||||
demangle(struct radius *r, const void *mangled, size_t mlen,
|
||||
char **buf, size_t *len)
|
||||
{
|
||||
char R[AUTH_LEN]; /* variable names as per rfc2548 */
|
||||
const char *S;
|
||||
u_char b[16];
|
||||
const u_char *A, *C;
|
||||
MD5_CTX Context;
|
||||
int Slen, i, Clen, Ppos;
|
||||
u_char *P;
|
||||
|
||||
if (mlen % 16 != SALT_LEN) {
|
||||
log_Printf(LogWARN, "Cannot interpret mangled data of length %ld\n",
|
||||
(u_long)mlen);
|
||||
*buf = NULL;
|
||||
*len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* We need the RADIUS Request-Authenticator */
|
||||
if (rad_request_authenticator(r->cx.rad, R, sizeof R) != AUTH_LEN) {
|
||||
log_Printf(LogWARN, "Cannot obtain the RADIUS request authenticator\n");
|
||||
*buf = NULL;
|
||||
*len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
A = (const u_char *)mangled; /* Salt comes first */
|
||||
C = (const u_char *)mangled + SALT_LEN; /* Then the ciphertext */
|
||||
Clen = mlen - SALT_LEN;
|
||||
S = rad_server_secret(r->cx.rad); /* We need the RADIUS secret */
|
||||
Slen = strlen(S);
|
||||
P = alloca(Clen); /* We derive our plaintext */
|
||||
|
||||
MD5Init(&Context);
|
||||
MD5Update(&Context, S, Slen);
|
||||
MD5Update(&Context, R, AUTH_LEN);
|
||||
MD5Update(&Context, A, SALT_LEN);
|
||||
MD5Final(b, &Context);
|
||||
Ppos = 0;
|
||||
|
||||
while (Clen) {
|
||||
Clen -= 16;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
P[Ppos++] = C[i] ^ b[i];
|
||||
|
||||
if (Clen) {
|
||||
MD5Init(&Context);
|
||||
MD5Update(&Context, S, Slen);
|
||||
MD5Update(&Context, C, 16);
|
||||
MD5Final(b, &Context);
|
||||
}
|
||||
|
||||
C += 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* The resulting plain text consists of a one-byte length, the text and
|
||||
* maybe some padding.
|
||||
*/
|
||||
*len = *P;
|
||||
if (*len > mlen - 1) {
|
||||
log_Printf(LogWARN, "Mangled data seems to be garbage\n");
|
||||
*buf = NULL;
|
||||
*len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
*buf = malloc(*len);
|
||||
memcpy(*buf, P + 1, *len);
|
||||
log_Printf(LogWARN, "demangled %d bytes\n", *len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -304,6 +414,7 @@ radius_Process(struct radius *r, int got)
|
||||
switch (vendor) {
|
||||
case RAD_VENDOR_MICROSOFT:
|
||||
switch (res) {
|
||||
#ifndef NODES
|
||||
case RAD_MICROSOFT_MS_CHAP_ERROR:
|
||||
free(r->errstr);
|
||||
if ((r->errstr = rad_cvt_string(data, len)) == NULL) {
|
||||
@ -328,6 +439,30 @@ radius_Process(struct radius *r, int got)
|
||||
log_Printf(LogPHASE, " MS-CHAP2-Success \"%s\"\n", r->msrepstr);
|
||||
break;
|
||||
|
||||
case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
|
||||
r->mppe.policy = rad_cvt_int(data);
|
||||
log_Printf(LogPHASE, " MS-MPPE-Encryption-Policy %s\n",
|
||||
radius_policyname(r->mppe.policy));
|
||||
break;
|
||||
|
||||
case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
|
||||
r->mppe.types = rad_cvt_int(data);
|
||||
log_Printf(LogPHASE, " MS-MPPE-Encryption-Types %s\n",
|
||||
radius_typesname(r->mppe.types));
|
||||
break;
|
||||
|
||||
case RAD_MICROSOFT_MS_MPPE_RECV_KEY:
|
||||
free(r->mppe.recvkey);
|
||||
demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen);
|
||||
log_Printf(LogPHASE, " MS-MPPE-Recv-Key ********\n");
|
||||
break;
|
||||
|
||||
case RAD_MICROSOFT_MS_MPPE_SEND_KEY:
|
||||
demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen);
|
||||
log_Printf(LogPHASE, " MS-MPPE-Send-Key ********\n");
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific "
|
||||
"RADIUS attribute %d\n", res);
|
||||
@ -464,6 +599,12 @@ radius_Init(struct radius *r)
|
||||
r->msrepstr = NULL;
|
||||
r->repstr = NULL;
|
||||
r->errstr = NULL;
|
||||
r->mppe.policy = 0;
|
||||
r->mppe.types = 0;
|
||||
r->mppe.recvkey = NULL;
|
||||
r->mppe.recvkeylen = 0;
|
||||
r->mppe.sendkey = NULL;
|
||||
r->mppe.sendkeylen = 0;
|
||||
*r->cfg.file = '\0';;
|
||||
log_Printf(LogDEBUG, "Radius: radius_Init\n");
|
||||
}
|
||||
@ -486,6 +627,12 @@ radius_Destroy(struct radius *r)
|
||||
r->repstr = NULL;
|
||||
free(r->errstr);
|
||||
r->errstr = NULL;
|
||||
free(r->mppe.recvkey);
|
||||
r->mppe.recvkey = NULL;
|
||||
r->mppe.recvkeylen = 0;
|
||||
free(r->mppe.sendkey);
|
||||
r->mppe.sendkey = NULL;
|
||||
r->mppe.sendkeylen = 0;
|
||||
if (r->cx.fd != -1) {
|
||||
r->cx.fd = -1;
|
||||
rad_close(r->cx.rad);
|
||||
@ -550,8 +697,8 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
#if 0
|
||||
struct hostent *hp;
|
||||
#endif
|
||||
struct in_addr hostaddr;
|
||||
#endif
|
||||
#ifndef NODES
|
||||
struct mschap_response msresp;
|
||||
struct mschap2_response msresp2;
|
||||
@ -723,8 +870,8 @@ radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
#if 0
|
||||
struct hostent *hp;
|
||||
#endif
|
||||
struct in_addr hostaddr;
|
||||
#endif
|
||||
|
||||
if (!*r->cfg.file)
|
||||
return;
|
||||
@ -736,7 +883,7 @@ radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
|
||||
*/
|
||||
return;
|
||||
|
||||
radius_Destroy(r);
|
||||
timer_Stop(&r->cx.timer);
|
||||
|
||||
if ((r->cx.rad = rad_acct_open()) == NULL) {
|
||||
log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
|
||||
@ -865,6 +1012,14 @@ radius_Show(struct radius *r, struct prompt *p)
|
||||
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, " MPPE Enc Policy: %s\n",
|
||||
radius_policyname(r->mppe.policy));
|
||||
prompt_Printf(p, " MPPE Enc Types: %s\n",
|
||||
radius_typesname(r->mppe.types));
|
||||
prompt_Printf(p, " MPPE Recv Key: %seceived\n",
|
||||
r->mppe.recvkey ? "R" : "Not r");
|
||||
prompt_Printf(p, " MPPE Send Key: %seceived\n",
|
||||
r->mppe.sendkey ? "R" : "Not r");
|
||||
prompt_Printf(p, " MS-CHAP2-Response: %s\n",
|
||||
r->msrepstr ? r->msrepstr : "");
|
||||
prompt_Printf(p, " Error Message: %s\n", r->errstr ? r->errstr : "");
|
||||
|
@ -26,6 +26,12 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#define MPPE_POLICY_ALLOWED 1
|
||||
#define MPPE_POLICY_REQUIRED 2
|
||||
|
||||
#define MPPE_TYPE_40BIT 2
|
||||
#define MPPE_TYPE_128BIT 4
|
||||
|
||||
struct radius {
|
||||
struct fdescriptor desc; /* We're a sort of (selectable) fdescriptor */
|
||||
struct {
|
||||
@ -45,6 +51,14 @@ struct radius {
|
||||
char *msrepstr; /* MS-CHAP2-Response */
|
||||
char *repstr; /* Reply-Message */
|
||||
char *errstr; /* Error-Message */
|
||||
struct {
|
||||
int policy; /* MPPE_POLICY_* */
|
||||
int types; /* MPPE_TYPE_*BIT bitmask */
|
||||
char *recvkey;
|
||||
size_t recvkeylen;
|
||||
char *sendkey;
|
||||
size_t sendkeylen;
|
||||
} mppe;
|
||||
struct {
|
||||
char file[PATH_MAX]; /* Radius config file */
|
||||
} cfg;
|
||||
|
Loading…
Reference in New Issue
Block a user