summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorbrian <brian@cvs.openbsd.org>1999-02-18 00:50:46 +0000
committerbrian <brian@cvs.openbsd.org>1999-02-18 00:50:46 +0000
commit95150ba97bf728e00d3949838b3c906dc01757ce (patch)
tree769a28c2688fa48c319201929eb1f86c88417bc1 /usr.sbin
parentdb5ebd071b5420151b2644ac669687dc0f086d78 (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.c9
-rw-r--r--usr.sbin/ppp/ppp/auth.h4
-rw-r--r--usr.sbin/ppp/ppp/chap.c187
-rw-r--r--usr.sbin/ppp/ppp/chap.h7
-rw-r--r--usr.sbin/ppp/ppp/chap_ms.c80
-rw-r--r--usr.sbin/ppp/ppp/chap_ms.h5
-rw-r--r--usr.sbin/ppp/ppp/command.c54
-rw-r--r--usr.sbin/ppp/ppp/datalink.c19
-rw-r--r--usr.sbin/ppp/ppp/lcp.c135
-rw-r--r--usr.sbin/ppp/ppp/lcp.h11
-rw-r--r--usr.sbin/ppp/ppp/ppp.853
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