Fully support both NT and LANMan CHAP type 0x80 as both

authenticator and authenticatee.
This commit is contained in:
Brian Somers 1999-02-18 00:52:15 +00:00
parent 75ffaf5939
commit 5e31549897
12 changed files with 444 additions and 173 deletions

View File

@ -17,7 +17,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: auth.c,v 1.37 1999/02/02 09:35:17 brian Exp $
* $Id: auth.c,v 1.38 1999/02/06 02:54:43 brian Exp $
*
* TODO:
* o Implement check against with registered IP addresses.
@ -66,13 +66,16 @@
#include "bundle.h"
const char *
Auth2Nam(u_short auth)
Auth2Nam(u_short auth, u_char type)
{
static char chap[10];
switch (auth) {
case PROTO_PAP:
return "PAP";
case PROTO_CHAP:
return "CHAP";
snprintf(chap, sizeof chap, "CHAP 0x%02x", type);
return chap;
case 0:
return "none";
}

View File

@ -15,7 +15,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: auth.h,v 1.14 1999/02/02 09:35:17 brian Exp $
* $Id: auth.h,v 1.15 1999/02/06 02:54:43 brian Exp $
*
* TODO:
*/
@ -47,7 +47,7 @@ struct authinfo {
#define auth_Failure(a) (*a->fn.failure)(a);
#define auth_Success(a) (*a->fn.success)(a);
extern const char *Auth2Nam(u_short);
extern const char *Auth2Nam(u_short, u_char);
extern void auth_Init(struct authinfo *, struct physical *,
auth_func, auth_func, auth_func);
extern void auth_StopTimer(struct authinfo *);

View File

@ -17,7 +17,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: chap.c,v 1.42 1999/02/07 13:56:29 brian Exp $
* $Id: chap.c,v 1.43 1999/02/11 10:14:07 brian Exp $
*
* TODO:
*/
@ -31,12 +31,12 @@
#include <fcntl.h>
#ifdef HAVE_DES
#include <md4.h>
#include <string.h>
#endif
#include <md5.h>
#include <paths.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
@ -105,7 +105,8 @@ ChapOutput(struct physical *physical, u_int code, u_int id,
}
static char *
chap_BuildAnswer(char *name, char *key, u_char id, char *challenge, int MSChap)
chap_BuildAnswer(char *name, char *key, u_char id, char *challenge,
u_char type, int lanman)
{
char *result, *digest;
size_t nlen, klen;
@ -114,7 +115,7 @@ chap_BuildAnswer(char *name, char *key, u_char id, char *challenge, int MSChap)
klen = strlen(key);
#ifdef HAVE_DES
if (MSChap) {
if (type == 0x80) {
char expkey[AUTHLEN << 2];
MD4_CTX MD4context;
int f;
@ -122,38 +123,42 @@ chap_BuildAnswer(char *name, char *key, u_char id, char *challenge, int MSChap)
if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL)
return result;
digest = result; /* this is the response */
*digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */
memset(digest, '\0', 24);
digest += 24;
digest = result; /* the response */
*digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */
memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen);
if (lanman) {
memset(digest + 24, '\0', 25);
mschap_LANMan(digest, challenge + 1, key); /* LANMan response */
} else {
memset(digest, '\0', 25);
digest += 24;
for (f = klen; f; f--) {
expkey[2*f-2] = key[f-1];
expkey[2*f-1] = 0;
for (f = 0; f < klen; f++) {
expkey[2*f] = key[f];
expkey[2*f+1] = '\0';
}
/*
* -----------
* expkey = | k\0e\0y\0 |
* -----------
*/
MD4Init(&MD4context);
MD4Update(&MD4context, expkey, klen << 1);
MD4Final(digest, &MD4context);
/*
* ---- -------- ---------------- ------- ------
* result = | 49 | LANMan | 16 byte digest | 9 * ? | name |
* ---- -------- ---------------- ------- ------
*/
mschap_NT(digest, challenge + 1);
}
/*
* -----------
* answer = | k\0e\0y\0 |
* -----------
*/
MD4Init(&MD4context);
MD4Update(&MD4context, expkey, klen << 1);
MD4Final(digest, &MD4context);
memcpy(digest + 25, name, nlen);
/*
* ``result'' is:
* ---- --------- -------------------- ------
* result = | 49 | 24 * \0 | digest (pad to 25) | name |
* ---- --------- -------------------- ------
*/
chap_MS(digest, challenge + 1, *challenge);
/*
* ---- --------- ---------------- --- ----------
* result = | 49 | 24 * \0 | 24 byte digest | 1 | authname |
* ---- --------- ---------------- --- ----------
* ---- -------- ------------- ----- ------
* | | struct MS_ChapResponse24 | |
* result = | 49 | LANMan | NT digest | 0/1 | name |
* ---- -------- ------------- ----- ------
* where only one of LANMan & NT digest are set.
*/
} else
#endif
@ -281,18 +286,20 @@ chap_Cleanup(struct chap *chap, int sig)
log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status));
}
*chap->challenge = 0;
chap->peertries = 0;
}
static void
chap_SendResponse(struct chap *chap, char *name, char *key)
chap_Respond(struct chap *chap, char *name, char *key, u_char type, int lm)
{
char *ans;
u_char *ans;
ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge, 0);
ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge, type, lm);
if (ans) {
ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id,
ans, *ans + 1 + strlen(name), name);
chap->NTRespSent = !lm;
free(ans);
} else
ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id,
@ -355,6 +362,11 @@ chap_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
chap_Cleanup(chap, SIGTERM);
}
} else {
int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 &&
((chap->NTRespSent &&
IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) ||
!IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt));
while (end >= name && strchr(" \t\r\n", *end))
*end-- = '\0';
end = key - 1;
@ -362,7 +374,8 @@ chap_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
*end-- = '\0';
key += strspn(key, " \t");
chap_SendResponse(chap, name, key);
chap_Respond(chap, name, key,
chap->auth.physical->link.lcp.his_authtype, lanman);
chap_Cleanup(chap, 0);
}
}
@ -398,7 +411,12 @@ chap_Challenge(struct authinfo *authp)
} else
#endif
{
*cp++ = random() % (CHAPCHALLENGELEN-16) + 16;
#ifdef HAVE_DES
if (authp->physical->link.lcp.want_authtype == 0x80)
*cp++ = 8; /* MS does 8 byte callenges :-/ */
else
#endif
*cp++ = random() % (CHAPCHALLENGELEN-16) + 16;
for (i = 0; i < *chap->challenge; i++)
*cp++ = random() & 0xff;
}
@ -432,6 +450,35 @@ chap_Failure(struct authinfo *authp)
datalink_AuthNotOk(authp->physical->dl);
}
static int
chap_Cmp(u_char type, int lm, char *myans, int mylen, char *hisans, int hislen)
{
if (mylen != hislen)
return 0;
else if (type == 0x80) {
int off = lm ? 0 : 24;
if (memcmp(myans + off, hisans + off, 24))
return 0;
} else if (memcmp(myans, hisans, mylen))
return 0;
return 1;
}
static int
chap_HaveAnotherGo(struct chap *chap)
{
if (++chap->peertries < 3) {
/* Give the peer another shot */
*chap->challenge = '\0';
chap_Challenge(&chap->auth);
return 1;
}
return 0;
}
void
chap_Init(struct chap *chap, struct physical *p)
{
@ -444,7 +491,8 @@ chap_Init(struct chap *chap, struct physical *p)
chap->child.fd = -1;
auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure);
*chap->challenge = 0;
chap->using_MSChap = 0;
chap->NTRespSent = 0;
chap->peertries = 0;
}
void
@ -457,8 +505,8 @@ void
chap_Input(struct physical *p, struct mbuf *bp)
{
struct chap *chap = &p->dl->chap;
char *name, *key, *ans, *myans;
int len, nlen;
char *name, *key, *ans;
int len, nlen, lanman;
u_char alen;
if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL)
@ -482,17 +530,22 @@ chap_Input(struct physical *p, struct mbuf *bp)
}
chap->auth.id = chap->auth.in.hdr.id; /* We respond with this id */
lanman = 0;
switch (chap->auth.in.hdr.code) {
case CHAP_CHALLENGE:
bp = mbuf_Read(bp, chap->challenge, 1);
len -= *chap->challenge + 1;
bp = mbuf_Read(bp, &alen, 1);
len -= alen + 1;
if (len < 0) {
log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
mbuf_Free(bp);
return;
}
bp = mbuf_Read(bp, chap->challenge + 1, *chap->challenge);
*chap->challenge = alen;
bp = mbuf_Read(bp, chap->challenge + 1, alen);
bp = auth_ReadName(&chap->auth, bp, len);
lanman = p->link.lcp.his_authtype == 0x80 &&
((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
!IsAccepted(p->link.lcp.cfg.chap80nt));
break;
case CHAP_RESPONSE:
@ -513,6 +566,7 @@ chap_Input(struct physical *p, struct mbuf *bp)
bp = mbuf_Read(bp, ans + 1, alen);
ans[alen+1] = '\0';
bp = auth_ReadName(&chap->auth, bp, len);
lanman = alen == 49 && ans[alen] == 0;
break;
case CHAP_SUCCESS:
@ -532,11 +586,16 @@ chap_Input(struct physical *p, struct mbuf *bp)
case CHAP_CHALLENGE:
case CHAP_RESPONSE:
if (*chap->auth.in.name)
log_Printf(LogPHASE, "Chap Input: %s (from %s)\n",
chapcodes[chap->auth.in.hdr.code], chap->auth.in.name);
log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
chapcodes[chap->auth.in.hdr.code], alen,
chap->auth.in.name,
lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
" - lanman" : "");
else
log_Printf(LogPHASE, "Chap Input: %s\n",
chapcodes[chap->auth.in.hdr.code]);
log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
chapcodes[chap->auth.in.hdr.code], alen,
lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
" - lanman" : "");
break;
case CHAP_SUCCESS:
@ -556,8 +615,9 @@ chap_Input(struct physical *p, struct mbuf *bp)
chap_StartChild(chap, p->dl->bundle->cfg.auth.key + 1,
p->dl->bundle->cfg.auth.name);
else
chap_SendResponse(chap, p->dl->bundle->cfg.auth.name,
p->dl->bundle->cfg.auth.key);
chap_Respond(chap, p->dl->bundle->cfg.auth.name,
p->dl->bundle->cfg.auth.key,
p->link.lcp.his_authtype, lanman);
break;
case CHAP_RESPONSE:
@ -573,14 +633,29 @@ chap_Input(struct physical *p, struct mbuf *bp)
{
key = auth_GetSecret(p->dl->bundle, name, nlen, p);
if (key) {
myans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge,
chap->using_MSChap);
if (myans == NULL)
char *myans;
if (lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
if (chap_HaveAnotherGo(chap))
break;
key = NULL;
else {
if (*myans != alen || memcmp(myans + 1, ans + 1, *myans))
} else if (!lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
if (chap_HaveAnotherGo(chap))
break;
key = NULL;
} else {
myans = chap_BuildAnswer(name, key, chap->auth.id,
chap->challenge,
p->link.lcp.want_authtype, lanman);
if (myans == NULL)
key = NULL;
free(myans);
else {
if (!chap_Cmp(p->link.lcp.want_authtype, lanman,
myans + 1, *myans, ans + 1, alen))
key = NULL;
free(myans);
}
}
}

View File

@ -15,7 +15,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: chap.h,v 1.11 1999/02/06 02:54:44 brian Exp $
* $Id: chap.h,v 1.12 1999/02/11 10:14:07 brian Exp $
*
* TODO:
*/
@ -39,8 +39,9 @@ struct chap {
} buf;
} child;
struct authinfo auth;
char challenge[CHAPCHALLENGELEN + AUTHLEN];
unsigned using_MSChap : 1; /* A combination of MD4 & DES */
u_char challenge[CHAPCHALLENGELEN + AUTHLEN];
unsigned NTRespSent : 1; /* Our last response */
int peertries;
};
#define descriptor2chap(d) \

View File

@ -1,5 +1,5 @@
/*
* chap_ms.c - Microsoft MS-CHAP compatible implementation.
* chap_ms.c - Microsoft MS-CHAP (NT only) compatible implementation.
*
* Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
* http://www.strataware.com/
@ -19,12 +19,13 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: chap_ms.c,v 1.5.4.3 1998/05/01 19:24:07 brian Exp $
* $Id: chap_ms.c,v 1.6 1998/05/21 21:44:30 brian Exp $
*
*/
#include <sys/types.h>
#include <ctype.h>
#include <des.h>
#include <string.h>
@ -38,33 +39,6 @@ struct MS_ChapResponse {
u_char UseNT; /* If 1, ignore the LANMan response field */
};
static void DesEncrypt(u_char *, u_char *, u_char *);
static void MakeKey(u_char *, u_char *);
static void /* IN 8 octets IN 16 octets OUT 24 octets */
ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response)
{
char ZPasswordHash[21];
memset(ZPasswordHash, '\0', sizeof ZPasswordHash);
memcpy(ZPasswordHash, pwHash, 16);
DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
}
static void /* IN 8 octets IN 7 octest OUT 8 octets */
DesEncrypt(u_char *clear, u_char *key, u_char *cipher)
{
des_cblock des_key;
des_key_schedule key_schedule;
MakeKey(key, des_key);
des_set_key(&des_key, key_schedule);
des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
}
static u_char Get7Bits(u_char *input, int startBit)
{
register unsigned int word;
@ -93,16 +67,58 @@ static void MakeKey(u_char *key, u_char *des_key)
des_set_odd_parity((des_cblock *)des_key);
}
static void /* IN 8 octets IN 7 octest OUT 8 octets */
DesEncrypt(u_char *clear, u_char *key, u_char *cipher)
{
des_cblock des_key;
des_key_schedule key_schedule;
MakeKey(key, des_key);
des_set_key(&des_key, key_schedule);
des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
}
static void /* IN 8 octets IN 16 octets OUT 24 octets */
ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response)
{
char ZPasswordHash[21];
memset(ZPasswordHash, '\0', sizeof ZPasswordHash);
memcpy(ZPasswordHash, pwHash, 16);
DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
}
/* passwordHash 16-bytes MD4 hashed password
challenge 8-bytes peer CHAP challenge
since passwordHash is in a 24-byte buffer, response is written in there */
void
chap_MS(char *passwordHash, char *challenge, int challenge_len)
mschap_NT(char *passwordHash, char *challenge)
{
u_char response[24];
ChallengeResponse(challenge, passwordHash, response);
memcpy(passwordHash, response, 24);
passwordHash += 24;
*passwordHash = 1;
passwordHash[24] = 1; /* NT-style response */
}
void
mschap_LANMan(char *digest, char *challenge, char *secret)
{
static u_char salt[] = "KGS!@#$%"; /* RASAPI32.dll */
char SECRET[14], *ptr, *end;
u_char hash[16];
end = SECRET + sizeof SECRET;
for (ptr = SECRET; *secret && ptr < end; ptr++, secret++)
*ptr = toupper(*secret);
if (ptr < end)
memset(ptr, '\0', end - ptr);
DesEncrypt(salt, SECRET, hash);
DesEncrypt(salt, SECRET + 7, hash + 8);
ChallengeResponse(challenge, hash, digest);
}

View File

@ -19,7 +19,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: chap_ms.h,v 1.2.4.1 1998/05/01 19:24:08 brian Exp $
* $Id: chap_ms.h,v 1.3 1998/05/21 21:44:32 brian Exp $
*/
/* Max # of (Unicode) chars in an NT password */
@ -28,4 +28,5 @@
/* Don't rely on sizeof(MS_ChapResponse) in case of struct padding */
#define MS_CHAP_RESPONSE_LEN 49
extern void chap_MS(char *, char *, int);
extern void mschap_NT(char *, char *);
extern void mschap_LANMan(char *, char *, char *);

View File

@ -17,7 +17,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: command.c,v 1.180 1999/02/11 10:14:07 brian Exp $
* $Id: command.c,v 1.181 1999/02/16 00:16:55 brian Exp $
*
*/
#include <sys/param.h>
@ -127,19 +127,21 @@
/* ``accept|deny|disable|enable'' values */
#define NEG_ACFCOMP 40
#define NEG_CHAP 41
#define NEG_DEFLATE 42
#define NEG_LQR 43
#define NEG_PAP 44
#define NEG_PPPDDEFLATE 45
#define NEG_PRED1 46
#define NEG_PROTOCOMP 47
#define NEG_SHORTSEQ 48
#define NEG_VJCOMP 49
#define NEG_DNS 50
#define NEG_CHAP05 41
#define NEG_CHAP80 42
#define NEG_CHAP80LM 43
#define NEG_DEFLATE 44
#define NEG_LQR 45
#define NEG_PAP 46
#define NEG_PPPDDEFLATE 47
#define NEG_PRED1 48
#define NEG_PROTOCOMP 49
#define NEG_SHORTSEQ 50
#define NEG_VJCOMP 51
#define NEG_DNS 52
const char Version[] = "2.11";
const char VersionDate[] = "$Date: 1999/02/11 10:14:07 $";
const char VersionDate[] = "$Date: 1999/02/16 00:16:55 $";
static int ShowCommand(struct cmdargs const *);
static int TerminalCommand(struct cmdargs const *);
@ -2170,10 +2172,20 @@ NegotiateSet(struct cmdargs const *arg)
cx->physical->link.lcp.cfg.acfcomp &= keep;
cx->physical->link.lcp.cfg.acfcomp |= add;
break;
case NEG_CHAP:
cx->physical->link.lcp.cfg.chap &= keep;
cx->physical->link.lcp.cfg.chap |= add;
case NEG_CHAP05:
cx->physical->link.lcp.cfg.chap05 &= keep;
cx->physical->link.lcp.cfg.chap05 |= add;
break;
#ifdef HAVE_DES
case NEG_CHAP80:
cx->physical->link.lcp.cfg.chap80nt &= keep;
cx->physical->link.lcp.cfg.chap80nt |= add;
break;
case NEG_CHAP80LM:
cx->physical->link.lcp.cfg.chap80lm &= keep;
cx->physical->link.lcp.cfg.chap80lm |= add;
break;
#endif
case NEG_DEFLATE:
l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
@ -2257,9 +2269,17 @@ static struct cmdtab const NegotiateCommands[] = {
{"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
"Address & Control field compression", "accept|deny|disable|enable",
(const void *)NEG_ACFCOMP},
{"chap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
{"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
"Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
(const void *)NEG_CHAP},
(const void *)NEG_CHAP05},
#ifdef HAVE_DES
{"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
"Microsoft (NT) CHAP", "accept|deny|disable|enable",
(const void *)NEG_CHAP80},
{"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
"Microsoft (NT) CHAP", "accept|deny|disable|enable",
(const void *)NEG_CHAP80LM},
#endif
{"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
"Deflate compression", "accept|deny|disable|enable",
(const void *)NEG_DEFLATE},

View File

@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: datalink.c,v 1.30 1999/02/11 10:14:08 brian Exp $
* $Id: datalink.c,v 1.31 1999/02/17 02:11:28 brian Exp $
*/
#include <sys/param.h>
@ -475,20 +475,21 @@ datalink_LayerUp(void *v, struct fsm *fp)
{
/* The given fsm is now up */
struct datalink *dl = (struct datalink *)v;
struct lcp *lcp = &dl->physical->link.lcp;
if (fp->proto == PROTO_LCP) {
datalink_GotAuthname(dl, "");
dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth;
dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth;
if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) {
lcp->auth_ineed = lcp->want_auth;
lcp->auth_iwait = lcp->his_auth;
if (lcp->his_auth || lcp->want_auth) {
if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH)
bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE);
log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name,
Auth2Nam(dl->physical->link.lcp.his_auth),
Auth2Nam(dl->physical->link.lcp.want_auth));
if (dl->physical->link.lcp.his_auth == PROTO_PAP)
Auth2Nam(lcp->his_auth, lcp->his_authtype),
Auth2Nam(lcp->want_auth, lcp->want_authtype));
if (lcp->his_auth == PROTO_PAP)
auth_StartReq(&dl->pap);
if (dl->physical->link.lcp.want_auth == PROTO_CHAP)
if (lcp->want_auth == PROTO_CHAP)
auth_StartReq(&dl->chap.auth);
} else
datalink_AuthOk(dl);
@ -955,8 +956,6 @@ datalink_Show(struct cmdargs const *arg)
prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name);
prompt_Printf(arg->prompt, " State: %s\n",
datalink_State(arg->cx));
prompt_Printf(arg->prompt, " CHAP Encryption: %s\n",
arg->cx->chap.using_MSChap ? "MSChap" : "MD5" );
prompt_Printf(arg->prompt, " Peer name: ");
if (*arg->cx->peer.authname)
prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname);

View File

@ -17,7 +17,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: lcp.c,v 1.66 1999/01/12 21:50:20 brian Exp $
* $Id: lcp.c,v 1.67 1999/01/28 01:56:32 brian Exp $
*
* TODO:
* o Limit data field length by MRU
@ -177,7 +177,13 @@ lcp_ReportStatus(struct cmdargs const *arg)
prompt_Printf(arg->prompt, " ACFCOMP = %s\n",
command_ShowNegval(lcp->cfg.acfcomp));
prompt_Printf(arg->prompt, " CHAP = %s\n",
command_ShowNegval(lcp->cfg.chap));
command_ShowNegval(lcp->cfg.chap05));
#ifdef HAVE_DES
prompt_Printf(arg->prompt, " MSCHAP = %s\n",
command_ShowNegval(lcp->cfg.chap80nt));
prompt_Printf(arg->prompt, " LANMan = %s\n",
command_ShowNegval(lcp->cfg.chap80lm));
#endif
prompt_Printf(arg->prompt, " LQR = %s\n",
command_ShowNegval(lcp->cfg.lqr));
prompt_Printf(arg->prompt, " PAP = %s\n",
@ -222,7 +228,11 @@ lcp_Init(struct lcp *lcp, struct bundle *bundle, struct link *l,
lcp->cfg.fsmretry = DEF_FSMRETRY;
lcp->cfg.acfcomp = NEG_ENABLED|NEG_ACCEPTED;
lcp->cfg.chap = NEG_ACCEPTED;
lcp->cfg.chap05 = NEG_ACCEPTED;
#ifdef HAVE_DES
lcp->cfg.chap80nt = NEG_ACCEPTED;
lcp->cfg.chap80lm = NEG_ACCEPTED;
#endif
lcp->cfg.lqr = NEG_ACCEPTED;
lcp->cfg.pap = NEG_ACCEPTED;
lcp->cfg.protocomp = NEG_ENABLED|NEG_ACCEPTED;
@ -244,6 +254,7 @@ lcp_Setup(struct lcp *lcp, int openmode)
lcp->his_lqrperiod = 0;
lcp->his_acfcomp = 0;
lcp->his_auth = 0;
lcp->his_authtype = 0;
lcp->his_callback.opmask = 0;
lcp->his_shortseq = 0;
@ -260,8 +271,24 @@ lcp_Setup(struct lcp *lcp, int openmode)
lcp->his_protocomp = 0;
lcp->want_protocomp = IsEnabled(lcp->cfg.protocomp) ? 1 : 0;
lcp->want_magic = GenerateMagic();
lcp->want_auth = IsEnabled(lcp->cfg.chap) ? PROTO_CHAP :
IsEnabled(lcp->cfg.pap) ? PROTO_PAP : 0;
if (IsEnabled(lcp->cfg.chap05)) {
lcp->want_auth = PROTO_CHAP;
lcp->want_authtype = 0x05;
#ifdef HAVE_DES
} else if (IsEnabled(lcp->cfg.chap80nt) ||
IsEnabled(lcp->cfg.chap80lm)) {
lcp->want_auth = PROTO_CHAP;
lcp->want_authtype = 0x80;
#endif
} else if (IsEnabled(lcp->cfg.pap)) {
lcp->want_auth = PROTO_PAP;
lcp->want_authtype = 0;
} else {
lcp->want_auth = 0;
lcp->want_authtype = 0;
}
if (p->type != PHYS_DIRECT)
memcpy(&lcp->want_callback, &p->dl->cfg.callback, sizeof(struct callback));
else
@ -273,6 +300,7 @@ lcp_Setup(struct lcp *lcp, int openmode)
lcp->his_protocomp = lcp->want_protocomp = 1;
lcp->want_magic = 0;
lcp->want_auth = 0;
lcp->want_authtype = 0;
lcp->want_callback.opmask = 0;
lcp->want_lqrperiod = 0;
}
@ -350,7 +378,7 @@ LcpSendConfigReq(struct fsm *fp)
case PROTO_CHAP:
proto = PROTO_CHAP;
ua_htons(&proto, o->data);
o->data[2] = 0x05;
o->data[2] = lcp->want_authtype;
INC_LCP_OPT(TY_AUTHPROTO, 5, o);
break;
}
@ -615,17 +643,8 @@ LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
case TY_AUTHPROTO:
ua_ntohs(cp + 2, &proto);
switch (proto) {
case PROTO_PAP:
log_Printf(LogLCP, "%s 0x%04x (PAP)\n", request, proto);
break;
case PROTO_CHAP:
log_Printf(LogLCP, "%s 0x%04x (CHAP 0x%02x)\n", request, proto, cp[4]);
break;
default:
log_Printf(LogLCP, "%s 0x%04x\n", request, proto);
break;
}
log_Printf(LogLCP, "%s 0x%04x (%s)\n", request, proto,
Auth2Nam(proto, length > 4 ? cp[4] : 0));
switch (mode_type) {
case MODE_REQ:
@ -637,46 +656,69 @@ LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
}
if (IsAccepted(lcp->cfg.pap)) {
lcp->his_auth = proto;
lcp->his_authtype = 0;
memcpy(dec->ackend, cp, length);
dec->ackend += length;
} else if (IsAccepted(lcp->cfg.chap)) {
} else if (IsAccepted(lcp->cfg.chap05)) {
*dec->nakend++ = *cp;
*dec->nakend++ = 5;
*dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
*dec->nakend++ = (unsigned char) PROTO_CHAP;
*dec->nakend++ = 0x05;
#ifdef HAVE_DES
} else if (IsAccepted(lcp->cfg.chap80nt) ||
IsAccepted(lcp->cfg.chap80lm)) {
*dec->nakend++ = *cp;
*dec->nakend++ = 5;
*dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
*dec->nakend++ = (unsigned char) PROTO_CHAP;
*dec->nakend++ = 0x80;
#endif
} else
goto reqreject;
break;
case PROTO_CHAP:
if (length < 5) {
if (length != 5) {
log_Printf(LogLCP, " Bad length!\n");
goto reqreject;
}
if ((cp[4] == 0x05 && IsAccepted(lcp->cfg.chap05))
#ifdef HAVE_DES
if (IsAccepted(lcp->cfg.chap) && (cp[4] == 0x05 || cp[4] == 0x80))
#else
if (IsAccepted(lcp->cfg.chap) && cp[4] == 0x05)
|| (cp[4] == 0x80 && (IsAccepted(lcp->cfg.chap80nt) ||
(IsAccepted(lcp->cfg.chap80lm))))
#endif
{
) {
lcp->his_auth = proto;
lcp->his_authtype = cp[4];
memcpy(dec->ackend, cp, length);
dec->ackend += length;
#ifdef HAVE_DES
link2physical(fp->link)->dl->chap.using_MSChap = cp[4] == 0x80;
#endif
} else {
if (IsAccepted(lcp->cfg.chap)) {
#ifndef HAVE_DES
if (cp[4] == 0x80)
log_Printf(LogWARN, "Chap 0x80 not available without DES\n");
else
if (cp[4] == 0x80)
log_Printf(LogWARN, "CHAP 0x80 not available without DES\n");
else
#endif
log_Printf(LogWARN, "Chap 0x%02x not supported\n",
(unsigned)cp[4]);
}
if (IsAccepted(lcp->cfg.pap)) {
if (cp[4] != 0x05)
log_Printf(LogWARN, "%s not supported\n",
Auth2Nam(PROTO_CHAP, cp[4]));
if (IsAccepted(lcp->cfg.chap05)) {
*dec->nakend++ = *cp;
*dec->nakend++ = 5;
*dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
*dec->nakend++ = (unsigned char) PROTO_CHAP;
*dec->nakend++ = 0x05;
#ifdef HAVE_DES
} else if (IsAccepted(lcp->cfg.chap80nt) ||
IsAccepted(lcp->cfg.chap80lm)) {
*dec->nakend++ = *cp;
*dec->nakend++ = 5;
*dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8);
*dec->nakend++ = (unsigned char) PROTO_CHAP;
*dec->nakend++ = 0x80;
#endif
} else if (IsAccepted(lcp->cfg.pap)) {
*dec->nakend++ = *cp;
*dec->nakend++ = 4;
*dec->nakend++ = (unsigned char) (PROTO_PAP >> 8);
@ -697,18 +739,33 @@ LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
case MODE_NAK:
switch (proto) {
case PROTO_PAP:
if (IsEnabled(lcp->cfg.pap))
if (IsEnabled(lcp->cfg.pap)) {
lcp->want_auth = PROTO_PAP;
else {
lcp->want_authtype = 0;
} else {
log_Printf(LogLCP, "Peer will only send PAP (not enabled)\n");
lcp->his_reject |= (1 << type);
}
break;
case PROTO_CHAP:
if (IsEnabled(lcp->cfg.chap))
if (cp[4] == 0x05 && IsEnabled(lcp->cfg.chap05)) {
lcp->want_auth = PROTO_CHAP;
else {
log_Printf(LogLCP, "Peer will only send CHAP (not enabled)\n");
lcp->want_authtype = 0x05;
#ifdef HAVE_DES
} else if (cp[4] == 0x80 && (IsEnabled(lcp->cfg.chap80nt) ||
IsEnabled(lcp->cfg.chap80lm))) {
lcp->want_auth = PROTO_CHAP;
lcp->want_authtype = 0x80;
#endif
} else {
#ifndef HAVE_DES
if (cp[4] == 0x80)
log_Printf(LogLCP, "Peer will only send MSCHAP (not available"
" without DES)\n");
else
#endif
log_Printf(LogLCP, "Peer will only send %s (not supported)\n",
Auth2Nam(PROTO_CHAP, cp[4]));
lcp->his_reject |= (1 << type);
}
break;

View File

@ -15,7 +15,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: lcp.h,v 1.18 1998/06/27 23:48:48 brian Exp $
* $Id: lcp.h,v 1.19 1998/08/07 18:42:49 brian Exp $
*
* TODO:
*/
@ -46,6 +46,7 @@ struct lcp {
u_int32_t his_magic; /* Peers magic number */
u_int32_t his_lqrperiod; /* Peers LQR frequency (100ths of seconds) */
u_short his_auth; /* Peer wants this type of authentication */
u_char his_authtype; /* Fifth octet of REQ/NAK/REJ */
struct callback his_callback; /* Peer wants callback ? */
unsigned his_shortseq : 1; /* Peer would like only 12bit seqs (MP) */
unsigned his_protocomp : 1; /* Does peer do Protocol field compression */
@ -57,6 +58,7 @@ struct lcp {
u_int32_t want_magic; /* Our magic number */
u_int32_t want_lqrperiod; /* Our LQR frequency (100ths of seconds) */
u_short want_auth; /* We want this type of authentication */
u_char want_authtype; /* Fifth octet of REQ/NAK/REJ */
struct callback want_callback;/* We want callback ? */
unsigned want_shortseq : 1; /* I'd like only 12bit seqs (MP) */
unsigned want_protocomp : 1; /* Do we do protocol field compression */
@ -78,7 +80,11 @@ struct lcp {
u_int fsmretry; /* FSM retry frequency */
unsigned acfcomp : 2; /* Address & Control Field Compression neg */
unsigned chap : 2; /* Challenge Handshake Authentication proto */
unsigned chap05 : 2; /* Challenge Handshake Authentication proto */
#ifdef HAVE_DES
unsigned chap80nt : 2; /* Microsoft (NT) CHAP */
unsigned chap80lm : 2; /* Microsoft (LANMan) CHAP */
#endif
unsigned lqr : 2; /* Link Quality Report */
unsigned pap : 2; /* Password Authentication protocol */
unsigned protocomp : 2; /* Protocol field compression */
@ -120,7 +126,6 @@ struct lcp_opt {
struct mbuf;
struct link;
struct physical;
struct bundle;
struct cmdargs;

View File

@ -1,4 +1,4 @@
.\" $Id: ppp.8,v 1.148 1999/02/14 12:16:41 brian Exp $
.\" $Id: ppp.8,v 1.149 1999/02/16 00:16:56 brian Exp $
.Dd 20 September 1995
.nr XX \w'\fC00'
.Os FreeBSD
@ -2111,7 +2111,7 @@ may be one of the following:
Default: Enabled and Accepted. ACFComp stands for Address and Control
Field Compression. Non LCP packets usually have very similar address
and control fields - making them easily compressible.
.It chap
.It chap[05]
Default: Disabled and Accepted. CHAP stands for Challenge Handshake
Authentication Protocol. Only one of CHAP and PAP (below) may be
negotiated. With CHAP, the authenticator sends a "challenge" message
@ -2210,6 +2210,18 @@ them. The answer is taken from
unless the
.Dq set dns
command is used as an override.
.It LANMan|chap80lm
Default: Disabled and Accepted. The use of this authentication protocol
is discouraged as it partially violates the authentication protocol by
implementing two different mechanisms (LANMan & NT) under the guise of
a single CHAP type (0x80).
.Dq LANMan
uses a simple DES encryption mechanism and is the least secure of the
CHAP alternatives (although is still more secure than PAP).
.Pp
Refer to the
.Dq MSChap
description below for more details.
.It lqr
Default: Disabled and Accepted. This option decides if Link Quality
Requests will be sent or accepted. LQR is a protocol that allows
@ -2238,6 +2250,39 @@ level, and any appropriate
.Dq reconnect
values are honoured as if the peer were responsible for dropping the
connection.
.It MSChap|chap80nt
Default: Disabled and Accepted. The use of this authentication protocol
is discouraged as it partially violates the authentication protocol by
implementing two different mechanisms (LANMan & NT) under the guise of
a single CHAP type (0x80). It is very similar to standard CHAP (type 0x05)
except that it issues challenges of a fixed 8 bytes in length and uses a
combination of MD4 and DES to encrypt the challenge rather than using the
standard MD5 mechanism. CHAP type 0x80 for LANMan is also supported - see
.Dq enable LANMan
for details.
.Pp
Because both
.Dq LANMan
and
.Dq NT
use CHAP type 0x80, when acting as authenticator with both
.Dq enable Ns No d ,
.Nm
will rechallenge the peer up to three times if it responds using the wrong
one of the two protocols. This gives the peer a chance to attempt using
both protocols.
.Pp
Conversely, when
.Nm
acts as the authenticatee with both protocols
.Dq accept Ns No ed ,
the protocols are used alternately in response to challenges.
.Pp
Note: If only LANMan is enabled,
.Xr pppd 8
(version 2.3.5) misbehaves when acting as authenticatee. It provides both
the NT and the LANMan answers, but also suggests that only the NT answer
should be used.
.It pap
Default: Disabled and Accepted. PAP stands for Password Authentication
Protocol. Only one of PAP and CHAP (above) may be negotiated. With
@ -2253,7 +2298,9 @@ and have an entry in
.Pa /etc/ppp/ppp.secret
for the peer (although see the
.Dq passwdauth
option below).
and
.Dq set radius
options below).
.Pp
When using PAP as the client, you need only specify
.Dq AuthName

View File

@ -1,4 +1,4 @@
.\" $Id: ppp.8,v 1.148 1999/02/14 12:16:41 brian Exp $
.\" $Id: ppp.8,v 1.149 1999/02/16 00:16:56 brian Exp $
.Dd 20 September 1995
.nr XX \w'\fC00'
.Os FreeBSD
@ -2111,7 +2111,7 @@ may be one of the following:
Default: Enabled and Accepted. ACFComp stands for Address and Control
Field Compression. Non LCP packets usually have very similar address
and control fields - making them easily compressible.
.It chap
.It chap[05]
Default: Disabled and Accepted. CHAP stands for Challenge Handshake
Authentication Protocol. Only one of CHAP and PAP (below) may be
negotiated. With CHAP, the authenticator sends a "challenge" message
@ -2210,6 +2210,18 @@ them. The answer is taken from
unless the
.Dq set dns
command is used as an override.
.It LANMan|chap80lm
Default: Disabled and Accepted. The use of this authentication protocol
is discouraged as it partially violates the authentication protocol by
implementing two different mechanisms (LANMan & NT) under the guise of
a single CHAP type (0x80).
.Dq LANMan
uses a simple DES encryption mechanism and is the least secure of the
CHAP alternatives (although is still more secure than PAP).
.Pp
Refer to the
.Dq MSChap
description below for more details.
.It lqr
Default: Disabled and Accepted. This option decides if Link Quality
Requests will be sent or accepted. LQR is a protocol that allows
@ -2238,6 +2250,39 @@ level, and any appropriate
.Dq reconnect
values are honoured as if the peer were responsible for dropping the
connection.
.It MSChap|chap80nt
Default: Disabled and Accepted. The use of this authentication protocol
is discouraged as it partially violates the authentication protocol by
implementing two different mechanisms (LANMan & NT) under the guise of
a single CHAP type (0x80). It is very similar to standard CHAP (type 0x05)
except that it issues challenges of a fixed 8 bytes in length and uses a
combination of MD4 and DES to encrypt the challenge rather than using the
standard MD5 mechanism. CHAP type 0x80 for LANMan is also supported - see
.Dq enable LANMan
for details.
.Pp
Because both
.Dq LANMan
and
.Dq NT
use CHAP type 0x80, when acting as authenticator with both
.Dq enable Ns No d ,
.Nm
will rechallenge the peer up to three times if it responds using the wrong
one of the two protocols. This gives the peer a chance to attempt using
both protocols.
.Pp
Conversely, when
.Nm
acts as the authenticatee with both protocols
.Dq accept Ns No ed ,
the protocols are used alternately in response to challenges.
.Pp
Note: If only LANMan is enabled,
.Xr pppd 8
(version 2.3.5) misbehaves when acting as authenticatee. It provides both
the NT and the LANMan answers, but also suggests that only the NT answer
should be used.
.It pap
Default: Disabled and Accepted. PAP stands for Password Authentication
Protocol. Only one of PAP and CHAP (above) may be negotiated. With
@ -2253,7 +2298,9 @@ and have an entry in
.Pa /etc/ppp/ppp.secret
for the peer (although see the
.Dq passwdauth
option below).
and
.Dq set radius
options below).
.Pp
When using PAP as the client, you need only specify
.Dq AuthName