diff options
author | brian <brian@cvs.openbsd.org> | 1999-02-18 00:50:46 +0000 |
---|---|---|
committer | brian <brian@cvs.openbsd.org> | 1999-02-18 00:50:46 +0000 |
commit | 95150ba97bf728e00d3949838b3c906dc01757ce (patch) | |
tree | 769a28c2688fa48c319201929eb1f86c88417bc1 /usr.sbin | |
parent | db5ebd071b5420151b2644ac669687dc0f086d78 (diff) |
Fully support both NT and LANMan CHAP type 0x80 as both
authenticator and authenticatee.
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/ppp/ppp/auth.c | 9 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/auth.h | 4 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/chap.c | 187 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/chap.h | 7 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/chap_ms.c | 80 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/chap_ms.h | 5 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/command.c | 54 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/datalink.c | 19 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/lcp.c | 135 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/lcp.h | 11 | ||||
-rw-r--r-- | usr.sbin/ppp/ppp/ppp.8 | 53 |
11 files changed, 394 insertions, 170 deletions
diff --git a/usr.sbin/ppp/ppp/auth.c b/usr.sbin/ppp/ppp/auth.c index 170f41c46ac..0fef71fc145 100644 --- a/usr.sbin/ppp/ppp/auth.c +++ b/usr.sbin/ppp/ppp/auth.c @@ -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.5 1999/02/06 03:22:31 brian Exp $ + * $Id: auth.c,v 1.6 1999/02/18 00:50:44 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"; } diff --git a/usr.sbin/ppp/ppp/auth.h b/usr.sbin/ppp/ppp/auth.h index 16683709b9a..bc5f53aba6c 100644 --- a/usr.sbin/ppp/ppp/auth.h +++ b/usr.sbin/ppp/ppp/auth.h @@ -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.4 1999/02/06 03:22:31 brian Exp $ + * $Id: auth.h,v 1.5 1999/02/18 00:50:44 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 *); diff --git a/usr.sbin/ppp/ppp/chap.c b/usr.sbin/ppp/ppp/chap.c index 5036b53e9fc..4cf95b0ebde 100644 --- a/usr.sbin/ppp/ppp/chap.c +++ b/usr.sbin/ppp/ppp/chap.c @@ -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.5 1999/02/11 10:14:49 brian Exp $ + * $Id: chap.c,v 1.6 1999/02/18 00:50:44 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 (!lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) { + log_Printf(LogPHASE, "Auth failure: mschap not enabled\n"); + if (chap_HaveAnotherGo(chap)) + break; key = NULL; - else { - if (*myans != alen || memcmp(myans + 1, ans + 1, *myans)) + } 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); + } } } diff --git a/usr.sbin/ppp/ppp/chap.h b/usr.sbin/ppp/ppp/chap.h index b4fdaf4b624..fa697474509 100644 --- a/usr.sbin/ppp/ppp/chap.h +++ b/usr.sbin/ppp/ppp/chap.h @@ -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.3 1999/02/11 10:14:49 brian Exp $ + * $Id: chap.h,v 1.4 1999/02/18 00:50:45 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) \ diff --git a/usr.sbin/ppp/ppp/chap_ms.c b/usr.sbin/ppp/ppp/chap_ms.c index 3a220c95211..6a89f16338d 100644 --- a/usr.sbin/ppp/ppp/chap_ms.c +++ b/usr.sbin/ppp/ppp/chap_ms.c @@ -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.2 1999/02/06 03:22:33 brian Exp $ + * $Id: chap_ms.c,v 1.3 1999/02/18 00:50:45 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); } diff --git a/usr.sbin/ppp/ppp/chap_ms.h b/usr.sbin/ppp/ppp/chap_ms.h index e8a5eb20c84..c2647d35964 100644 --- a/usr.sbin/ppp/ppp/chap_ms.h +++ b/usr.sbin/ppp/ppp/chap_ms.h @@ -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 1999/02/06 03:22:33 brian Exp $ + * $Id: chap_ms.h,v 1.3 1999/02/18 00:50:45 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 *); diff --git a/usr.sbin/ppp/ppp/command.c b/usr.sbin/ppp/ppp/command.c index dbafd9717c8..e9487b5231a 100644 --- a/usr.sbin/ppp/ppp/command.c +++ b/usr.sbin/ppp/ppp/command.c @@ -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.9 1999/02/16 00:18:01 brian Exp $ + * $Id: command.c,v 1.10 1999/02/18 00:50:45 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/16 00:18:01 $"; +const char VersionDate[] = "$Date: 1999/02/18 00:50:45 $"; 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}, diff --git a/usr.sbin/ppp/ppp/datalink.c b/usr.sbin/ppp/ppp/datalink.c index 3564568253a..dd0ddee201b 100644 --- a/usr.sbin/ppp/ppp/datalink.c +++ b/usr.sbin/ppp/ppp/datalink.c @@ -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.12 1999/02/17 02:11:34 brian Exp $ + * $Id: datalink.c,v 1.13 1999/02/18 00:50:45 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); diff --git a/usr.sbin/ppp/ppp/lcp.c b/usr.sbin/ppp/ppp/lcp.c index 4071968e148..2209539aff9 100644 --- a/usr.sbin/ppp/ppp/lcp.c +++ b/usr.sbin/ppp/ppp/lcp.c @@ -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.6 1999/02/06 03:22:40 brian Exp $ + * $Id: lcp.c,v 1.7 1999/02/18 00:50:45 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 + 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 - log_Printf(LogWARN, "Chap 0x%02x not supported\n", - (unsigned)cp[4]); - } - if (IsAccepted(lcp->cfg.pap)) { + } 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; + 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; - else { - log_Printf(LogLCP, "Peer will only send CHAP (not enabled)\n"); + 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; diff --git a/usr.sbin/ppp/ppp/lcp.h b/usr.sbin/ppp/ppp/lcp.h index 7261bc094ea..9669293d2cc 100644 --- a/usr.sbin/ppp/ppp/lcp.h +++ b/usr.sbin/ppp/ppp/lcp.h @@ -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.2 1999/02/06 03:22:41 brian Exp $ + * $Id: lcp.h,v 1.3 1999/02/18 00:50:45 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; diff --git a/usr.sbin/ppp/ppp/ppp.8 b/usr.sbin/ppp/ppp/ppp.8 index c4d97b9f95f..3bcb91a872e 100644 --- a/usr.sbin/ppp/ppp/ppp.8 +++ b/usr.sbin/ppp/ppp/ppp.8 @@ -1,4 +1,4 @@ -.\" $Id: ppp.8,v 1.20 1999/02/16 00:18:03 brian Exp $ +.\" $Id: ppp.8,v 1.21 1999/02/18 00:50:45 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 |