Large patch from Frank Cusack <fcusack@fcusack.com> to add proper

support for MS-CHAP (client and server are now supported.)

Allow another plugin to select a different RADIUS server.

Modified radiusclient library to include two new APIs:
rc_acct_using_server and rc_auth_using_server in which caller specifies
which RADIUS servers to use, instead of using the default ones in the
config file.  The /etc/radiusclient/servers file must still contain
secrets for those servers.
This commit is contained in:
David F. Skoll 2002-03-01 14:39:19 +00:00
parent a6b70c095f
commit c062322f9e
14 changed files with 329 additions and 120 deletions

View File

@ -1,10 +1,11 @@
PPP Client Support for Microsoft's CHAP-80
==========================================
PPP Support for Microsoft's CHAP-80
===================================
Eric Rosenquist rosenqui@strataware.com
(updated by Paul Mackerras)
(updated by Al Longyear)
(updated by Farrell Woods)
(updated by Frank Cusack)
INTRODUCTION
@ -16,7 +17,7 @@ by a bogus client to gain access to the server just as easily as if
the password were stored in cleartext.) The details of the Microsoft
extensions can be found in the document:
<ftp://ftp.microsoft.com/developr/rfc/chapexts.txt>
<http://www.ietf.org/rfc/rfc2433.txt>
In short, MS-CHAP is identified as <auth chap 80> since the hex value
of 80 is used to designate Microsoft's scheme. Standard PPP CHAP uses
@ -35,12 +36,7 @@ MS-CHAP by NAKing it:
Windows NT Server systems are often configured to "Accept only
Microsoft Authentication" (this is intended to enhance security). Up
until now, that meant that you couldn't use this version of PPPD to
connect to such a system. I've managed to get a client-only
implementation of MS-CHAP working; it will authenticate itself to
another system using MS-CHAP, but if you're using PPPD as a dial-in
server, you won't be able to use MS-CHAP to authenticate the clients.
This would not be a lot of extra work given that the framework is in
place, but I didn't need it myself so I didn't implement it.
connect to such a system.
BUILDING THE PPPD
@ -275,10 +271,5 @@ to be used in chap-secrets in place of the password. The code to do this
could quite easily be lifted from chap_ms.c (you have to convert the
password to Unicode before hashing it). The chap_ms.c file would also have
to be changed to recognize a password hash (16 binary bytes == 32 ASCII hex
characters) and skip the hashing stage.
A server implementation would allow MS-CHAP to be used with Windows NT and
Windows 95 clients for enhanced security. Some new command-line options
would be required, as would code to generate the Challenge packet and
verify the response. Most of the helper functions are in place, so this
shouldn't be too hard for someone to add.
characters) and skip the hashing stage. This would have no real security
value as the hash is plaintext-equivalent.

View File

@ -32,7 +32,7 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#define RCSID "$Id: auth.c,v 1.73 2002/01/22 16:02:58 dfs Exp $"
#define RCSID "$Id: auth.c,v 1.74 2002/03/01 14:39:18 dfs Exp $"
#include <stdio.h>
#include <stddef.h>
@ -169,6 +169,11 @@ bool uselogin = 0; /* Use /etc/passwd for checking PAP */
bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */
bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */
bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */
#ifdef CHAPMS
bool refuse_mschap = 0; /* Don't wanna auth. ourselves with MS-CHAP */
#else
bool refuse_mschap = 1; /* Don't wanna auth. ourselves with MS-CHAP */
#endif
bool usehostname = 0; /* Use hostname for our_name */
bool auth_required = 0; /* Always require authentication from peer */
bool allow_any_ip = 0; /* Allow peer to use any IP address */
@ -218,30 +223,53 @@ option_t auth_options[] = {
{ "auth", o_bool, &auth_required,
"Require authentication from peer", OPT_PRIO | 1 },
{ "noauth", o_bool, &auth_required,
"Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV,
"Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV | OPT_A2COPY,
&allow_any_ip },
{ "require-pap", o_bool, &lcp_wantoptions[0].neg_upap,
"Require PAP authentication from peer",
OPT_PRIOSUB | 1, &auth_required },
OPT_PRIOSUB | OPT_A2COPY | 1, &auth_required },
{ "+pap", o_bool, &lcp_wantoptions[0].neg_upap,
"Require PAP authentication from peer",
OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required },
OPT_ALIAS | OPT_PRIOSUB | OPT_A2COPY | 1, &auth_required },
{ "require-chap", o_bool, &lcp_wantoptions[0].neg_chap,
"Require CHAP authentication from peer",
OPT_PRIOSUB | 1, &auth_required },
OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MD5,
&auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
{ "+chap", o_bool, &lcp_wantoptions[0].neg_chap,
"Require CHAP authentication from peer",
OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required },
OPT_ALIAS | OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MD5,
&auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
#ifdef CHAPMS
{ "require-mschap", o_bool, &lcp_wantoptions[0].neg_chap,
"Require MS-CHAP authentication from peer",
OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MICROSOFT,
&auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
{ "+mschap", o_bool, &lcp_wantoptions[0].neg_chap,
"Require MS-CHAP authentication from peer",
OPT_ALIAS | OPT_PRIOSUB | OPT_A2COPY | OPT_A3OR | MDTYPE_MICROSOFT,
&auth_required, 0, 0, NULL, 0, 0, &lcp_wantoptions[0].chap_mdtype },
#endif
{ "refuse-pap", o_bool, &refuse_pap,
"Don't agree to auth to peer with PAP", 1 },
{ "-pap", o_bool, &refuse_pap,
"Don't allow PAP authentication with peer", OPT_ALIAS | 1 },
{ "refuse-chap", o_bool, &refuse_chap,
"Don't agree to auth to peer with CHAP", 1 },
"Don't agree to auth to peer with CHAP", OPT_A2CLRB | MDTYPE_MD5,
&lcp_allowoptions[0].chap_mdtype },
{ "-chap", o_bool, &refuse_chap,
"Don't allow CHAP authentication with peer", OPT_ALIAS | 1 },
"Don't allow CHAP authentication with peer",
OPT_ALIAS | OPT_A2CLRB | MDTYPE_MD5,
&lcp_allowoptions[0].chap_mdtype },
#ifdef CHAPMS
{ "refuse-mschap", o_bool, &refuse_mschap,
"Don't agree to auth to peer with MS-CHAP", OPT_A2CLRB | MDTYPE_MICROSOFT,
&lcp_allowoptions[0].chap_mdtype },
{ "-mschap", o_bool, &refuse_mschap,
"Don't allow MS-CHAP authentication with peer",
OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT,
&lcp_allowoptions[0].chap_mdtype },
#endif
{ "name", o_string, our_name,
"Set local name for authentication",
@ -466,12 +494,12 @@ link_established(unit)
&& protp->lowerup != NULL)
(*protp->lowerup)(unit);
if (auth_required && !(go->neg_chap || go->neg_upap)) {
if (auth_required && !(go->neg_upap || go->neg_chap)) {
/*
* We wanted the peer to authenticate itself, and it refused:
* if we have some address(es) it can use without auth, fine,
* otherwise treat it as though it authenticated with PAP using
* a username * of "" and a password of "". If that's not OK,
* a username of "" and a password of "". If that's not OK,
* boot it out.
*/
if (noauth_addrs != NULL) {
@ -488,14 +516,14 @@ link_established(unit)
used_login = 0;
auth = 0;
if (go->neg_chap) {
ChapAuthPeer(unit, our_name, go->chap_mdtype);
ChapAuthPeer(unit, our_name, CHAP_DIGEST(go->chap_mdtype));
auth |= CHAP_PEER;
} else if (go->neg_upap) {
upap_authpeer(unit);
auth |= PAP_PEER;
}
if (ho->neg_chap) {
ChapAuthWithPeer(unit, user, ho->chap_mdtype);
ChapAuthWithPeer(unit, user, CHAP_DIGEST(ho->chap_mdtype));
auth |= CHAP_WITHPEER;
} else if (ho->neg_upap) {
if (passwd[0] == 0) {
@ -834,11 +862,11 @@ auth_check_options()
if (auth_required) {
allow_any_ip = 0;
if (!wo->neg_chap && !wo->neg_upap) {
wo->neg_chap = 1;
wo->neg_chap = 1; wo->chap_mdtype = MDTYPE_ALL;
wo->neg_upap = 1;
}
} else {
wo->neg_chap = 0;
wo->neg_chap = 0; wo->chap_mdtype = MDTYPE_NONE;
wo->neg_upap = 0;
}
@ -848,7 +876,7 @@ auth_check_options()
*/
lacks_ip = 0;
can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip));
if (!can_auth && wo->neg_chap) {
if (!can_auth && (wo->neg_chap)) {
can_auth = have_chap_secret((explicit_remote? remote_name: NULL),
our_name, 1, &lacks_ip);
}
@ -889,7 +917,7 @@ auth_reset(unit)
lcp_options *ao = &lcp_allowoptions[0];
ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL));
ao->neg_chap = !refuse_chap
ao->neg_chap = (!refuse_chap || !refuse_mschap)
&& (passwd[0] != 0
|| have_chap_secret(user, (explicit_remote? remote_name: NULL),
0, NULL));

View File

@ -1,5 +1,5 @@
/*
* chap.c - Challenge Handshake Authentication Protocol.
* chap_ms.c - Challenge Handshake Authentication Protocol.
*
* Copyright (c) 1993 The Australian National University.
* All rights reserved.
@ -33,7 +33,7 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#define RCSID "$Id: chap.c,v 1.26 2002/01/22 16:02:58 dfs Exp $"
#define RCSID "$Id: chap.c,v 1.27 2002/03/01 14:39:18 dfs Exp $"
/*
* TODO:
@ -579,20 +579,48 @@ ChapReceiveResponse(cstate, inp, id, len)
/* generate MD based on negotiated type */
switch (cstate->chal_type) {
case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
case CHAP_DIGEST_MD5:
if (remmd_len != MD5_SIGNATURE_SIZE)
break; /* it's not even the right length */
break; /* not even the right length */
MD5Init(&mdContext);
MD5Update(&mdContext, &cstate->chal_id, 1);
MD5Update(&mdContext, secret, secret_len);
MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
MD5Final(hash, &mdContext);
/* compare local and remote MDs and send the appropriate status */
/* compare MDs and send the appropriate status */
if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
code = CHAP_SUCCESS; /* they are the same! */
break;
#ifdef CHAPMS
case CHAP_MICROSOFT:
{
int response_offset, response_size;
if (remmd_len != MS_CHAP_RESPONSE_LEN)
break; /* not even the right length */
ChapMS(cstate, cstate->challenge, cstate->chal_len,
secret, secret_len);
/* Determine which part of response to verify against */
if ((u_char *) (remmd + offsetof(MS_ChapResponse, UseNT))) {
response_offset = offsetof(MS_ChapResponse, NTResp);
response_size = sizeof(((MS_ChapResponse *) remmd)->NTResp);
} else {
response_offset = offsetof(MS_ChapResponse, LANManResp);
response_size =
sizeof(((MS_ChapResponse *) remmd)->LANManResp);
}
/* compare MDs and send the appropriate status */
if (memcmp(cstate->response + response_offset,
remmd + response_offset, response_size) == 0)
code = CHAP_SUCCESS; /* they are the same! */
break;
}
#endif /* CHAPMS */
default:
CHAPDEBUG(("unknown digest type %d", cstate->chal_type));
}
@ -759,15 +787,33 @@ static void
ChapGenChallenge(cstate)
chap_state *cstate;
{
int chal_len;
int chal_len = 0; /* Avoid compiler warning */
u_char *ptr = cstate->challenge;
int i;
/* pick a random challenge length between MIN_CHALLENGE_LENGTH and
MAX_CHALLENGE_LENGTH */
chal_len = (unsigned) ((drand48() *
(MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
MIN_CHALLENGE_LENGTH);
switch (cstate->chal_type) {
case CHAP_DIGEST_MD5:
/*
* pick a random challenge length between MIN_CHALLENGE_LENGTH and
* MAX_CHALLENGE_LENGTH
*/
chal_len = (unsigned) ((drand48() *
(MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
MIN_CHALLENGE_LENGTH);
break;
#ifdef CHAPMS
case CHAP_MICROSOFT:
/* MS-CHAP is fixed to an 8 octet challenge. */
chal_len = 8;
break;
#endif
default:
fatal("ChapGenChallenge: Unsupported challenge type %d",
(int) cstate->chal_type);
break;
}
cstate->chal_len = chal_len;
cstate->chal_id = ++cstate->id;
cstate->chal_transmits = 0;

View File

@ -30,7 +30,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: chap.h,v 1.9 2002/01/22 16:02:58 dfs Exp $
* $Id: chap.h,v 1.10 2002/03/01 14:39:18 dfs Exp $
*/
#ifndef __CHAP_INCLUDE__
@ -45,7 +45,42 @@
#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */
#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */
#define CHAP_MICROSOFT 0x80 /* use Microsoft-compatible alg. */
#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */
/*
* Digest type and selection.
*/
/* bitmask of supported algorithms */
#define MDTYPE_MD5 0x1
#define MDTYPE_MICROSOFT 0x2
#ifdef CHAPMS
#define MDTYPE_ALL (MDTYPE_MD5 | MDTYPE_MICROSOFT)
#else
#define MDTYPE_ALL (MDTYPE_MD5)
#endif
#define MDTYPE_NONE 0
/* Return the digest alg. ID for the most preferred digest type. */
#define CHAP_DIGEST(mdtype) \
((mdtype) & MDTYPE_MD5)? CHAP_DIGEST_MD5: \
((mdtype) & MDTYPE_MICROSOFT)? CHAP_MICROSOFT: \
0
/* Return the bit flag (lsb set) for our most preferred digest type. */
#define CHAP_MDTYPE(mdtype) ((mdtype) ^ ((mdtype) - 1)) & (mdtype)
/* Return the bit flag for a given digest algorithm ID. */
#define CHAP_MDTYPE_D(digest) \
((digest) == CHAP_DIGEST_MD5)? MDTYPE_MD5: \
((digest) == CHAP_MICROSOFT)? MDTYPE_MICROSOFT: \
0
/* Can we do the requested digest? */
#define CHAP_CANDIGEST(mdtype, digest) \
((digest) == CHAP_DIGEST_MD5)? (mdtype) & MDTYPE_MD5: \
((digest) == CHAP_MICROSOFT)? (mdtype) & MDTYPE_MICROSOFT: \
0
#define CHAP_CHALLENGE 1
#define CHAP_RESPONSE 2

View File

@ -31,7 +31,7 @@
* You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
*/
#define RCSID "$Id: chap_ms.c,v 1.15 1999/08/13 06:46:12 paulus Exp $"
#define RCSID "$Id: chap_ms.c,v 1.16 2002/03/01 14:39:18 dfs Exp $"
#ifdef CHAPMS
@ -57,14 +57,6 @@
static const char rcsid[] = RCSID;
typedef struct {
u_char LANManResp[24];
u_char NTResp[24];
u_char UseNT; /* If 1, ignore the LANMan response field */
} MS_ChapResponse;
/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
in case this struct gets padded. */
static void ChallengeResponse __P((u_char *, u_char *, u_char *));
static void DesEncrypt __P((u_char *, u_char *, u_char *));

View File

@ -1,5 +1,5 @@
/*
* chap.h - Challenge Handshake Authentication Protocol definitions.
* chap_ms.h - Challenge Handshake Authentication Protocol definitions.
*
* Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
* http://www.strataware.com/
@ -19,13 +19,25 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: chap_ms.h,v 1.2 1997/11/27 06:08:10 paulus Exp $
* $Id: chap_ms.h,v 1.3 2002/03/01 14:39:18 dfs Exp $
*/
#ifndef __CHAPMS_INCLUDE__
#define MD4_SIGNATURE_SIZE 16 /* 16 bytes in a MD4 message digest */
#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */
#define MAX_NT_PASSWORD 256 /* Max (Unicode) chars in an NT pass */
#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */
/*
* Use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
* in case this struct gets padded.
*/
typedef struct {
u_char LANManResp[24];
u_char NTResp[24];
u_char UseNT; /* If 1, ignore the LANMan response field */
} MS_ChapResponse;
void ChapMS __P((chap_state *, char *, int, char *, int));

View File

@ -17,7 +17,7 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#define RCSID "$Id: lcp.c,v 1.57 2001/03/08 05:11:14 paulus Exp $"
#define RCSID "$Id: lcp.c,v 1.58 2002/03/01 14:39:18 dfs Exp $"
/*
* TODO:
@ -327,7 +327,6 @@ lcp_init(unit)
wo->neg_mru = 1;
wo->mru = DEFMRU;
wo->neg_asyncmap = 1;
wo->chap_mdtype = CHAP_DIGEST_MD5;
wo->neg_magicnumber = 1;
wo->neg_pcompression = 1;
wo->neg_accompression = 1;
@ -337,7 +336,7 @@ lcp_init(unit)
ao->mru = MAXMRU;
ao->neg_asyncmap = 1;
ao->neg_chap = 1;
ao->chap_mdtype = CHAP_DIGEST_MD5;
ao->chap_mdtype = MDTYPE_ALL;
ao->neg_upap = 1;
ao->neg_magicnumber = 1;
ao->neg_pcompression = 1;
@ -679,10 +678,10 @@ lcp_addci(f, ucp, lenp)
}
#define ADDCICHAP(opt, neg, val, digest) \
if (neg) { \
PUTCHAR(opt, ucp); \
PUTCHAR((opt), ucp); \
PUTCHAR(CILEN_CHAP, ucp); \
PUTSHORT(val, ucp); \
PUTCHAR(digest, ucp); \
PUTSHORT((val), ucp); \
PUTCHAR((digest), ucp); \
}
#define ADDCILONG(opt, neg, val) \
if (neg) { \
@ -716,7 +715,7 @@ lcp_addci(f, ucp, lenp)
ADDCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
go->asyncmap);
ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP,CHAP_DIGEST(go->chap_mdtype));
ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
@ -802,13 +801,13 @@ lcp_ackci(f, p, len)
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
if (cilen != CILEN_CHAP || \
citype != opt) \
citype != (opt)) \
goto bad; \
GETSHORT(cishort, p); \
if (cishort != val) \
if (cishort != (val)) \
goto bad; \
GETCHAR(cichar, p); \
if (cichar != digest) \
if (cichar != (digest)) \
goto bad; \
}
#define ACKCILONG(opt, neg, val) \
@ -863,7 +862,7 @@ lcp_ackci(f, p, len)
ACKCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
go->asyncmap);
ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP,CHAP_DIGEST(go->chap_mdtype));
ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
@ -1035,7 +1034,7 @@ lcp_nakci(f, p, len)
no.neg_chap = go->neg_chap;
no.neg_upap = go->neg_upap;
INCPTR(2, p);
GETSHORT(cishort, p);
GETSHORT(cishort, p);
if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
/*
* If we were asking for CHAP, they obviously don't want to do it.
@ -1050,18 +1049,25 @@ lcp_nakci(f, p, len)
GETCHAR(cichar, p);
if (go->neg_chap) {
/*
* We were asking for CHAP/MD5; they must want a different
* algorithm. If they can't do MD5, we can ask for M$-CHAP
* if we support it, otherwise we'll have to stop
* asking for CHAP.
* We were asking for our preferred algorithm, they must
* want something different.
*/
if (cichar != go->chap_mdtype) {
#ifdef CHAPMS
if (cichar == CHAP_MICROSOFT)
go->chap_mdtype = CHAP_MICROSOFT;
else
#endif /* CHAPMS */
try.neg_chap = 0;
if (cichar != CHAP_DIGEST(go->chap_mdtype)) {
if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) {
/* Use their suggestion if we support it ... */
go->chap_mdtype = CHAP_MDTYPE_D(cichar);
} else {
/* ... otherwise, try our next-preferred algorithm. */
go->chap_mdtype &= ~(CHAP_MDTYPE(go->chap_mdtype));
if (go->chap_mdtype == MDTYPE_NONE) /* out of algos */
try.neg_chap = 0;
}
} else {
/*
* Whoops, they Nak'd our algorithm of choice
* but then suggested it back to us.
*/
goto bad;
}
} else {
/*
@ -1304,7 +1310,7 @@ lcp_rejci(f, p, len)
GETSHORT(cishort, p); \
GETCHAR(cichar, p); \
/* Check rejected value. */ \
if (cishort != val || cichar != digest) \
if ((cishort != (val)) || (cichar != (digest))) \
goto bad; \
try.neg = 0; \
try.neg_upap = 0; \
@ -1370,7 +1376,7 @@ lcp_rejci(f, p, len)
REJCISHORT(CI_MRU, neg_mru, go->mru);
REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, CHAP_DIGEST(go->chap_mdtype));
if (!go->neg_chap) {
REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
}
@ -1527,7 +1533,7 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
* for UPAP, then we will reject the second request.
* Whether we end up doing CHAP or UPAP depends then on
* the ordering of the CIs in the peer's Configure-Request.
*/
*/
if (cishort == PPP_PAP) {
if (ho->neg_chap || /* we've already accepted CHAP */
@ -1541,9 +1547,7 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
PUTCHAR(CI_AUTHTYPE, nakp);
PUTCHAR(CILEN_CHAP, nakp);
PUTSHORT(PPP_CHAP, nakp);
PUTCHAR(ao->chap_mdtype, nakp);
/* XXX if we can do CHAP_MICROSOFT as well, we should
probably put in another option saying so */
PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakp);
break;
}
ho->neg_upap = 1;
@ -1563,20 +1567,20 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
PUTSHORT(PPP_PAP, nakp);
break;
}
GETCHAR(cichar, p); /* get digest type*/
if (cichar != CHAP_DIGEST_MD5
#ifdef CHAPMS
&& cichar != CHAP_MICROSOFT
#endif
) {
GETCHAR(cichar, p); /* get digest type */
if (!(CHAP_CANDIGEST(ao->chap_mdtype, cichar))) {
/*
* We can't/won't do the requested type,
* suggest something else.
*/
orc = CONFNAK;
PUTCHAR(CI_AUTHTYPE, nakp);
PUTCHAR(CILEN_CHAP, nakp);
PUTSHORT(PPP_CHAP, nakp);
PUTCHAR(ao->chap_mdtype, nakp);
PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakp);
break;
}
ho->chap_mdtype = cichar; /* save md type */
ho->chap_mdtype = CHAP_MDTYPE_D(cichar); /* save md type */
ho->neg_chap = 1;
break;
}
@ -1591,7 +1595,7 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
if (ao->neg_chap) {
PUTCHAR(CILEN_CHAP, nakp);
PUTSHORT(PPP_CHAP, nakp);
PUTCHAR(ao->chap_mdtype, nakp);
PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakp);
} else {
PUTCHAR(CILEN_SHORT, nakp);
PUTSHORT(PPP_PAP, nakp);

View File

@ -16,7 +16,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: lcp.h,v 1.16 2001/03/08 05:11:14 paulus Exp $
* $Id: lcp.h,v 1.17 2002/03/01 14:39:18 dfs Exp $
*/
/*
@ -64,7 +64,7 @@ typedef struct lcp_options {
bool neg_endpoint; /* negotiate endpoint discriminator */
int mru; /* Value of MRU */
int mrru; /* Value of MRRU, and multilink enable */
u_char chap_mdtype; /* which MD type (hashing algorithm) */
u_char chap_mdtype; /* which MD types (hashing algorithm) */
u_int32_t asyncmap; /* Value of async map */
u_int32_t magicnumber;
int numloops; /* Number of loops during magic number neg. */

View File

@ -17,7 +17,7 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#define RCSID "$Id: options.c,v 1.81 2002/01/11 18:11:51 etbe Exp $"
#define RCSID "$Id: options.c,v 1.82 2002/03/01 14:39:18 dfs Exp $"
#include <ctype.h>
#include <stdio.h>
@ -623,6 +623,12 @@ process_option(opt, cmd, argv)
*(bool *)(opt->addr) = v;
if (opt->addr2 && (opt->flags & OPT_A2COPY))
*(bool *)(opt->addr2) = v;
else if (opt->addr2 && (opt->flags & OPT_A2CLR))
*(bool *)(opt->addr2) = 0;
else if (opt->addr2 && (opt->flags & OPT_A2CLRB))
*(u_char *)(opt->addr2) &= ~v;
if (opt->addr3 && (opt->flags & OPT_A3OR))
*(u_char *)(opt->addr3) |= v;
break;
case o_int:

View File

@ -21,7 +21,7 @@
*
***********************************************************************/
static char const RCSID[] =
"$Id: radius.c,v 1.2 2002/02/08 17:28:31 dfs Exp $";
"$Id: radius.c,v 1.3 2002/03/01 14:39:18 dfs Exp $";
#include "pppd.h"
#include "chap.h"
@ -61,9 +61,6 @@ static int radius_init(char *msg);
static int get_client_port(char *ifname);
static int radius_allowed_address(u_int32_t addr);
void (*radius_attributes_hook)(VALUE_PAIR *) = NULL;
void (*radius_pre_auth_hook)(char const *user) = NULL;
#ifndef MAXSESSIONID
#define MAXSESSIONID 32
#endif
@ -80,8 +77,18 @@ struct radius_state {
char config_file[MAXPATHLEN];
char session_id[MAXSESSIONID + 1];
time_t start_time;
SERVER *authserver; /* Authentication server to use */
SERVER *acctserver; /* Accounting server to use */
};
void (*radius_attributes_hook)(VALUE_PAIR *) = NULL;
/* The pre_auth_hook MAY set authserver and acctserver if it wants.
In that case, they override the values in the radiusclient.conf file */
void (*radius_pre_auth_hook)(char const *user,
SERVER **authserver,
SERVER **acctserver) = NULL;
static struct radius_state rstate;
char pppd_version[] = VERSION;
@ -189,7 +196,9 @@ radius_pap_auth(char *user,
make_username_realm(user);
if (radius_pre_auth_hook) {
radius_pre_auth_hook(rstate.user);
radius_pre_auth_hook(rstate.user,
&rstate.authserver,
&rstate.acctserver);
}
send = NULL;
@ -212,7 +221,13 @@ radius_pap_auth(char *user,
VENDOR_NONE);
}
result = rc_auth(rstate.client_port, send, &received, radius_msg);
if (rstate.authserver) {
result = rc_auth_using_server(rstate.authserver,
rstate.client_port, send,
&received, radius_msg);
} else {
result = rc_auth(rstate.client_port, send, &received, radius_msg);
}
if (result == OK_RC) {
if (radius_setparams(received, radius_msg) < 0) {
@ -268,7 +283,9 @@ radius_chap_auth(char *user,
make_username_realm(user);
rstate.client_port = get_client_port (ifname);
if (radius_pre_auth_hook) {
radius_pre_auth_hook(rstate.user);
radius_pre_auth_hook(rstate.user,
&rstate.authserver,
&rstate.acctserver);
}
}
@ -298,7 +315,13 @@ radius_chap_auth(char *user,
* make authentication with RADIUS server
*/
result = rc_auth (rstate.client_port, send, &received, radius_msg);
if (rstate.authserver) {
result = rc_auth_using_server(rstate.authserver,
rstate.client_port, send,
&received, radius_msg);
} else {
result = rc_auth(rstate.client_port, send, &received, radius_msg);
}
if (result == OK_RC) {
if (!rstate.done_chap_once) {
@ -474,7 +497,12 @@ radius_acct_start(void)
av_type = htonl(hisaddr);
rc_avpair_add(&send, PW_FRAMED_IP_ADDRESS , &av_type , 0, VENDOR_NONE);
result = rc_acct(rstate.client_port, send);
if (rstate.acctserver) {
result = rc_acct_using_server(rstate.acctserver,
rstate.client_port, send);
} else {
result = rc_acct(rstate.client_port, send);
}
rc_avpair_free(send);
@ -561,7 +589,13 @@ radius_acct_stop(void)
av_type = htonl(hisaddr);
rc_avpair_add(&send, PW_FRAMED_IP_ADDRESS , &av_type , 0, VENDOR_NONE);
result = rc_acct(rstate.client_port, send);
if (rstate.acctserver) {
result = rc_acct_using_server(rstate.acctserver,
rstate.client_port, send);
} else {
result = rc_acct(rstate.client_port, send);
}
if (result != OK_RC) {
/* RADIUS server could be down so make this a warning */
syslog(LOG_WARNING,

View File

@ -1,5 +1,5 @@
/*
* $Id: radiusclient.h,v 1.2 2002/02/27 15:51:19 dfs Exp $
* $Id: radiusclient.h,v 1.3 2002/03/01 14:39:19 dfs Exp $
*
* Copyright (C) 1995,1996,1997,1998 Lars Fenneberg
*
@ -379,8 +379,10 @@ VALUE_PAIR *rc_avpair_readin __P((FILE *));
void rc_buildreq __P((SEND_DATA *, int, char *, unsigned short, int, int));
unsigned char rc_get_seqnbr __P((void));
int rc_auth __P((UINT4, VALUE_PAIR *, VALUE_PAIR **, char *));
int rc_auth_using_server __P((SERVER *, UINT4, VALUE_PAIR *, VALUE_PAIR **, char *));
int rc_auth_proxy __P((VALUE_PAIR *, VALUE_PAIR **, char *));
int rc_acct __P((UINT4, VALUE_PAIR *));
int rc_acct_using_server __P((SERVER *, UINT4, VALUE_PAIR *));
int rc_acct_proxy __P((VALUE_PAIR *));
int rc_check __P((char *, unsigned short, char *));

View File

@ -1,5 +1,5 @@
/*
* $Id: buildreq.c,v 1.1 2002/01/22 16:03:02 dfs Exp $
* $Id: buildreq.c,v 1.2 2002/03/01 14:39:19 dfs Exp $
*
* Copyright (C) 1995,1997 Lars Fenneberg
*
@ -121,12 +121,37 @@ unsigned char rc_get_seqnbr(void)
int rc_auth(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received,
char *msg)
{
SERVER *authserver = rc_conf_srv("authserver");
if (!authserver) {
return (ERROR_RC);
}
return rc_auth_using_server(authserver, client_port, send, received, msg);
}
/*
* Function: rc_auth_using_server
*
* Purpose: Builds an authentication request for port id client_port
* with the value_pairs send and submits it to a server. You
* explicitly supply a server list.
*
* Returns: received value_pairs in received, messages from the server in msg
* and 0 on success, negative on failure as return value
*
*/
int rc_auth_using_server(SERVER *authserver,
UINT4 client_port,
VALUE_PAIR *send,
VALUE_PAIR **received,
char *msg)
{
SEND_DATA data;
UINT4 client_id;
int result;
int i;
SERVER *authserver = rc_conf_srv("authserver");
int timeout = rc_conf_int("radius_timeout");
int retries = rc_conf_int("radius_retries");
@ -215,16 +240,18 @@ int rc_auth_proxy(VALUE_PAIR *send, VALUE_PAIR **received, char *msg)
/*
* Function: rc_acct
* Function: rc_acct_using_server
*
* Purpose: Builds an accounting request for port id client_port
* with the value_pairs send
* with the value_pairs send. You explicitly supply server list.
*
* Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled
* in by this function, the rest has to be supplied.
*/
int rc_acct(UINT4 client_port, VALUE_PAIR *send)
int rc_acct_using_server(SERVER *acctserver,
UINT4 client_port,
VALUE_PAIR *send)
{
SEND_DATA data;
VALUE_PAIR *adt_vp;
@ -233,7 +260,6 @@ int rc_acct(UINT4 client_port, VALUE_PAIR *send)
time_t start_time, dtime;
char msg[4096];
int i;
SERVER *acctserver = rc_conf_srv("acctserver");
int timeout = rc_conf_int("radius_timeout");
int retries = rc_conf_int("radius_retries");
@ -288,6 +314,24 @@ int rc_acct(UINT4 client_port, VALUE_PAIR *send)
return result;
}
/*
* Function: rc_acct
*
* Purpose: Builds an accounting request for port id client_port
* with the value_pairs send
*
* Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled
* in by this function, the rest has to be supplied.
*/
int rc_acct(UINT4 client_port, VALUE_PAIR *send)
{
SERVER *acctserver = rc_conf_srv("acctserver");
if (!acctserver) return (ERROR_RC);
return rc_acct_using_server(acctserver, client_port, send);
}
/*
* Function: rc_acct_proxy
*

View File

@ -1,5 +1,5 @@
.\" manual page [] for pppd 2.4
.\" $Id: pppd.8,v 1.59 2002/01/11 18:04:37 etbe Exp $
.\" $Id: pppd.8,v 1.60 2002/03/01 14:39:18 dfs Exp $
.\" SH section heading
.\" SS subsection heading
.\" LP paragraph
@ -853,6 +853,10 @@ to \fIname\fR.
With this option, pppd will not agree to authenticate itself to the
peer using CHAP.
.TP
.B refuse-mschap
With this option, pppd will not agree to authenticate itself to the
peer using MS-CHAP.
.TP
.B refuse-pap
With this option, pppd will not agree to authenticate itself to the
peer using PAP.
@ -861,6 +865,10 @@ peer using PAP.
Require the peer to authenticate itself using CHAP [Challenge
Handshake Authentication Protocol] authentication.
.TP
.B require-mschap
Require the peer to authenticate itself using MS-CHAP [Microsft Challenge
Handshake Authentication Protocol] authentication.
.TP
.B require-pap
Require the peer to authenticate itself using PAP [Password
Authentication Protocol] authentication.
@ -1012,7 +1020,7 @@ pppd will not agree to authenticate itself with a particular protocol
if it has no secrets which could be used to do so.
.LP
Pppd stores secrets for use in authentication in secrets
files (/etc/ppp/pap-secrets for PAP, /etc/ppp/chap-secrets for CHAP).
files (/etc/ppp/pap-secrets for PAP, /etc/ppp/chap-secrets for CHAP/MS-CHAP).
Both secrets files have the same format. The secrets files can
contain secrets for pppd to use in authenticating itself to other
systems, as well as secrets for pppd to use when authenticating other
@ -1500,7 +1508,7 @@ file should be owned by root and not readable or writable by any other
user. Pppd will log a warning if this is not the case.
.TP
.B /etc/ppp/chap-secrets
Names, secrets and IP addresses for CHAP authentication. As for
Names, secrets and IP addresses for CHAP/MS-CHAP authentication. As for
/etc/ppp/pap-secrets, this file should be owned by root and not
readable or writable by any other user. Pppd will log a warning if
this is not the case.

View File

@ -16,7 +16,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: pppd.h,v 1.65 2002/02/12 20:07:09 dfs Exp $
* $Id: pppd.h,v 1.66 2002/03/01 14:39:18 dfs Exp $
*/
/*
@ -86,6 +86,7 @@ typedef struct {
const char *source;
short int priority;
short int winner;
void *addr3;
} option_t;
/* Values for flags */
@ -102,6 +103,7 @@ typedef struct {
#define OPT_ZEROOK 0x10000 /* 0 value is OK even if not within limits */
#define OPT_HIDE 0x10000 /* for o_string, print value as ?????? */
#define OPT_A2LIST 0x10000 /* for o_special, keep list of values */
#define OPT_A2CLRB 0x10000 /* o_bool, clr val bits in *(u_char *)addr2 */
#define OPT_NOINCR 0x20000 /* value mustn't be increased */
#define OPT_ZEROINF 0x40000 /* with OPT_NOINCR, 0 == infinity */
#define OPT_PRIO 0x80000 /* process option priorities for this option */
@ -117,6 +119,7 @@ typedef struct {
#define OPT_A2PRINTER 0x10000000 /* *addr2 is a fn for printing option */
#define OPT_A2STRVAL 0x20000000 /* *addr2 points to current string value */
#define OPT_NOPRINT 0x40000000 /* don't print this option at all */
#define OPT_A3OR 0x80000000 /* addr3 -> third location to rcv | value */
#define OPT_VAL(x) ((x) & OPT_VALUE)
@ -808,4 +811,8 @@ extern void (*snoop_send_hook) __P((unsigned char *p, int len));
#define MAX(a, b) ((a) > (b)? (a): (b))
#endif
#ifndef offsetof
#define offsetof(type, member) ((size_t) &((type *)0)->member)
#endif
#endif /* __PPP_H__ */