shithub: riscv

Download patch

ref: 3c8db40def613d036715a092eafb6ef7be22928a
parent: 71dbddef166f855e28dfae1989ddbd663d38176a
author: cinap_lenrek <[email protected]>
date: Wed Dec 11 00:48:48 EST 2013

factotum: add ntlmv2 (mschap2) client auth for cifs

--- a/sys/src/cmd/auth/factotum/chap.c
+++ b/sys/src/cmd/auth/factotum/chap.c
@@ -19,27 +19,29 @@
 enum {
 	ChapChallen = 8,
 	ChapResplen = 16,
-	MSchapResplen = 24,
+
+	/* Microsoft auth constants */
+	MShashlen = 16,
+	MSchallen = 8,
+	MSresplen = 24,
 };
 
-static int dochal(State*);
-static int doreply(State*, void*, int);
-static void doLMchap(char *, uchar [ChapChallen], uchar [MSchapResplen]);
-static void doNTchap(char *, uchar [ChapChallen], uchar [MSchapResplen]);
-static void dochap(char *, int, char [ChapChallen], uchar [ChapResplen]);
+static int dochal(State *s);
+static int doreply(State *s, uchar *reply, int nreply);
+static int dochap(char *passwd, int id, char chal[ChapChallen], uchar *resp, int resplen);
+static int domschap(char *passwd, uchar chal[MSchallen], uchar *resp, int resplen);
+static int domschap2(char *passwd, char *user, char *dom, uchar chal[MSchallen], uchar *resp, int resplen);
 
-
 struct State
 {
-	char *protoname;
 	int astype;
 	int asfd;
 	Key *key;
-	Ticket	t;
-	Ticketreq	tr;
+	Ticket t;
+	Ticketreq tr;
 	char chal[ChapChallen];
-	MSchapreply mcr;
-	char cr[ChapResplen];
+	int nresp;
+	uchar resp[4096];
 	char err[ERRMAX];
 	char user[64];
 	uchar secret[16];	/* for mschap */
@@ -82,17 +84,16 @@
 		return failure(fss, nil);
 
 	s = emalloc(sizeof *s);
+	s->nresp = 0;
+	s->nsecret = 0;
 	fss->phasename = phasenames;
 	fss->maxphase = Maxphase;
 	s->asfd = -1;
-	if(p == &chap){
-		s->astype = AuthChap;
-		s->protoname = "chap";
-	}else{
+	if(p == &mschap || p == &mschap2){
 		s->astype = AuthMSchap;
-		s->protoname = "mschap";
+	}else {
+		s->astype = AuthChap;
 	}
-
 	if(iscli)
 		fss->phase = CNeedChal;
 	else{
@@ -124,7 +125,6 @@
 	free(s);
 }
 
-
 static int
 chapwrite(Fsstate *fss, void *va, uint n)
 {
@@ -137,7 +137,8 @@
 	MSchapreply *mcr;
 	OChapreply *ocr;
 	OMSchapreply *omcr;
-	uchar reply[4*1024];
+	uchar reply[4096];
+	char *user, *dom;
 
 	s = fss->ps;
 	a = va;
@@ -154,28 +155,33 @@
 			closekey(k);
 			return failure(fss, "key has no password");
 		}
+		s->nresp = 0;
+		memset(s->resp, 0, sizeof(s->resp));
 		setattrs(fss->attr, k->attr);
 		switch(s->astype){
-		default:
-			closekey(k);
-			return failure(fss, "chap internal botch");
 		case AuthMSchap:
-			if(n < ChapChallen){
-				closekey(k);
-				return failure(fss, "challenge too short");
-			}
-			doLMchap(v, (uchar *)a, (uchar *)s->mcr.LMresp);
-			doNTchap(v, (uchar *)a, (uchar *)s->mcr.NTresp);
+			if(n < MSchallen)
+				break;
+			if(fss->proto == &mschap2){
+				user = _strfindattr(fss->attr, "user");
+				if(user == nil)
+					break;
+				dom = _strfindattr(fss->attr, "windom");
+				if(dom == nil)
+					dom = "";
+				s->nresp = domschap2(v, user, dom, (uchar*)a, s->resp, sizeof(s->resp));
+			} else
+				s->nresp = domschap(v, (uchar*)a, s->resp, sizeof(s->resp));
 			break;
 		case AuthChap:
-			if(n < ChapChallen+1){
-				closekey(k);
-				return failure(fss, "challenge too short");
-			}
-			dochap(v, *a, a+1, (uchar *)s->cr);
+			if(n < ChapChallen+1)
+				break;
+			s->nresp = dochap(v, *a, a+1, s->resp, sizeof(s->resp));
 			break;
 		}
 		closekey(k);
+		if(s->nresp <= 0)
+			return failure(fss, "chap botch");
 		fss->phase = CHaveResp;
 		return RpcOk;
 
@@ -239,21 +245,9 @@
 		return phaseerror(fss, "read");
 
 	case CHaveResp:
-		switch(s->astype){
-		default:
-			phaseerror(fss, "write");
-			break;
-		case AuthMSchap:
-			if(*n > sizeof(MSchapreply))
-				*n = sizeof(MSchapreply);
-			memmove(va, &s->mcr, *n);
-			break;
-		case AuthChap:
-			if(*n > ChapResplen)
-				*n = ChapResplen;
-			memmove(va, s->cr, ChapResplen);
-			break;
-		}
+		if(*n > s->nresp)
+			*n = s->nresp;
+		memmove(va, s->resp, *n);
 		fss->phase = Established;
 		fss->haveai = 0;
 		return RpcOk;
@@ -313,7 +307,7 @@
 }
 
 static int
-doreply(State *s, void *reply, int nreply)
+doreply(State *s, uchar *reply, int nreply)
 {
 	char ticket[TICKETLEN+AUTHENTLEN];
 	int n;
@@ -382,90 +376,240 @@
 .keyprompt= "!password?"
 };
 
+Proto mschap2 = {
+.name=	"mschap2",
+.init=	chapinit,
+.write=	chapwrite,
+.read=	chapread,
+.close=	chapclose,
+.addkey= replacekey,
+.keyprompt= "user? windom? !password?"
+};
+
 static void
-hash(uchar pass[16], uchar c8[ChapChallen], uchar p24[MSchapResplen])
+nthash(uchar hash[MShashlen], char *passwd)
 {
-	int i;
-	uchar p21[21];
-	ulong schedule[32];
+	DigestState *ds;
+	uchar b[2];
+	Rune r;
 
-	memset(p21, 0, sizeof p21 );
-	memmove(p21, pass, 16);
-
-	for(i=0; i<3; i++) {
-		key_setup(p21+i*7, schedule);
-		memmove(p24+i*8, c8, 8);
-		block_cipher(schedule, p24+i*8, 0);
+	ds = md4(nil, 0, nil, nil);
+	while(*passwd){
+		passwd += chartorune(&r, passwd);
+		b[0] = r & 0xff;
+		b[1] = r >> 8;
+		md4(b, 2, nil, ds);
 	}
+	md4(nil, 0, hash, ds);
 }
 
 static void
-doNTchap(char *pass, uchar chal[ChapChallen], uchar reply[MSchapResplen])
+ntv2hash(uchar hash[MShashlen], char *passwd, char *user, char *dom)
 {
+	uchar v1hash[MShashlen];
+	DigestState *ds;
+	uchar b[2];
 	Rune r;
-	uchar digest[MD4dlen];
-	uchar *w, unipass[128*2];	// Standard says unlimited length, experience says 128 max
 
-	w=unipass;
-	while(*pass != '\0' && w < &unipass[nelem(unipass)]){
-		pass += chartorune(&r, pass);
-		/* BUG: UTF-16 surrogates */
-		*w++ = r & 0xff;
-		*w++ = r >> 8;
+	nthash(v1hash, passwd);
+
+	/*
+	 * Some documentation insists that the username must be forced to
+	 * uppercase, but the domain name should not be. Other shows both
+	 * being forced to uppercase. I am pretty sure this is irrevevant as the
+	 * domain name passed from the remote server always seems to be in
+	 * uppercase already.
+	 */
+        ds = hmac_md5(nil, 0, v1hash, sizeof(v1hash), nil, nil);
+	while(*user){
+		user += chartorune(&r, user);
+		r = toupperrune(r);
+		b[0] = r & 0xff;
+		b[1] = r >> 8;
+        	hmac_md5(b, 2, v1hash, sizeof(v1hash), nil, ds);
 	}
+	while(*dom){
+		dom += chartorune(&r, dom);
+		b[0] = r & 0xff;
+		b[1] = r >> 8;
+        	hmac_md5(b, 2, v1hash, sizeof(v1hash), nil, ds);
+	}
+        hmac_md5(nil, 0, v1hash, sizeof(v1hash), hash, ds);
+}
 
-	memset(digest, 0, sizeof digest);
-	md4(unipass, w-unipass, digest, nil);
-	memset(unipass, 0, sizeof unipass);
-	hash(digest, chal, reply);
+static void
+desencrypt(uchar data[8], uchar key[7])
+{
+	ulong ekey[32];
+
+	key_setup(key, ekey);
+	block_cipher(ekey, data, 0);
 }
 
 static void
-doLMchap(char *pass, uchar chal[ChapChallen], uchar reply[MSchapResplen])
+lmhash(uchar hash[MShashlen], char *passwd)
 {
+	uchar buf[14];
+	char *stdtext = "KGS!@#$%";
 	int i;
-	ulong schedule[32];
-	uchar p14[15], p16[16];
-	uchar s8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
-	int n = strlen(pass);
 
-	if(n > 14){
-		// let prudent people avoid the LM vulnerability
-		//   and protect the loop below from buffer overflow
-		memset(reply, 0, MSchapResplen);
-		return;
+	memset(buf, 0, sizeof(buf));
+	strncpy((char*)buf, passwd, sizeof(buf));
+	for(i=0; i<sizeof(buf); i++)
+		if(buf[i] >= 'a' && buf[i] <= 'z')
+			buf[i] += 'A' - 'a';
+
+	memcpy(hash, stdtext, 8);
+	memcpy(hash+8, stdtext, 8);
+
+	desencrypt(hash, buf);
+	desencrypt(hash+8, buf+7);
+}
+
+static void
+mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen])
+{
+	int i;
+	uchar buf[21];
+
+	memset(buf, 0, sizeof(buf));
+	memcpy(buf, hash, MShashlen);
+
+	for(i=0; i<3; i++) {
+		memmove(resp+i*MSchallen, chal, MSchallen);
+		desencrypt(resp+i*MSchallen, buf+i*7);
 	}
+}
 
-	// Spec says space padded, experience says otherwise
-	memset(p14, 0, sizeof p14 -1);
-	p14[sizeof p14 - 1] = '\0';
+static int
+domschap(char *passwd, uchar chal[MSchallen], uchar *resp, int resplen)
+{
+	uchar hash[MShashlen];
+	MSchapreply *r;
 
-	// NT4 requires uppercase, Win XP doesn't care
-	for (i = 0; pass[i]; i++)
-		p14[i] = islower(pass[i])? toupper(pass[i]): pass[i];
+	r = (MSchapreply*)resp;
+	if(resplen < sizeof(*r))
+		return 0;
 
-	for(i=0; i<2; i++) {
-		key_setup(p14+i*7, schedule);
-		memmove(p16+i*8, s8, 8);
-		block_cipher(schedule, p16+i*8, 0);
+	lmhash(hash, passwd);
+	mschalresp((uchar*)r->LMresp, hash, chal);
+
+	nthash(hash, passwd);
+	mschalresp((uchar*)r->NTresp, hash, chal);
+
+	return sizeof(*r);
+}
+
+static int
+domschap2(char *passwd, char *user, char *dom, uchar chal[MSchallen], uchar *resp, int resplen)
+{
+	uchar hash[MShashlen], *p, *e;
+	MSchapreply *r;
+	DigestState *s;
+	uvlong t;
+	Rune rr;
+	int nb;
+
+	ntv2hash(hash, passwd, user, dom);
+
+	r = (MSchapreply*)resp;
+	p = (uchar*)r->NTresp+16;
+	e = resp + resplen;
+
+	if(p+2+2+4+8+8+4+4+4+4 > e)
+		return 0;	
+
+	*p++ = 1;		/* 8bit: response type */
+	*p++ = 1;		/* 8bit: max response type understood by client */
+
+	*p++ = 0;		/* 16bit: reserved */
+	*p++ = 0;
+
+	*p++ = 0;		/* 32bit: unknown */
+	*p++ = 0;
+	*p++ = 0;
+	*p++ = 0;
+
+	t = time(nil);
+	t += 11644473600LL;
+	t *= 10000000LL;
+
+	*p++ = t;		/* 64bit: time in NT format */
+	*p++ = t >> 8;
+	*p++ = t >> 16;
+	*p++ = t >> 24;
+	*p++ = t >> 32;
+	*p++ = t >> 40;
+	*p++ = t >> 48;
+	*p++ = t >> 56;
+
+	memrandom(p, 8);
+	p += 8;			/* 64bit: client nonce */
+
+	*p++ = 0;		/* 32bit: unknown data */
+	*p++ = 0;
+	*p++ = 0;
+	*p++ = 0;
+
+	*p++ = 2;		/* AvPair Domain */
+	*p++ = 0;
+	*p++ = 0;		/* length */
+	*p++ = 0;
+	nb = 0;
+	while(*dom){
+		dom += chartorune(&rr, dom);
+		if(p+2+4+4 > e)
+			return 0;
+		*p++ = rr & 0xFF;
+		*p++ = rr >> 8;
+		nb += 2;
 	}
+	p[-nb - 2] = nb & 0xFF;
+	p[-nb - 1] = nb >> 8;
 
-	memset(p14, 0, sizeof p14);
-	hash(p16, chal, reply);
+	*p++ = 0;		/* AvPair EOF */
+	*p++ = 0;
+	*p++ = 0;
+	*p++ = 0;
+	
+	*p++ = 0;		/* 32bit: unknown data */
+	*p++ = 0;
+	*p++ = 0;
+	*p++ = 0;
+
+	/*
+	 * LmResponse = Cat(HMAC_MD5(LmHash, Cat(SC, CC)), CC)
+	 */
+	s = hmac_md5(chal, 8, hash, MShashlen, nil, nil);
+	memrandom((uchar*)r->LMresp+16, 8);
+	hmac_md5((uchar*)r->LMresp+16, 8, hash, MShashlen, (uchar*)r->LMresp, s);
+
+	/*
+	 * NtResponse = Cat(HMAC_MD5(NtHash, Cat(SC, NtBlob)), NtBlob)
+	 */
+	s = hmac_md5(chal, 8, hash, MShashlen, nil, nil);
+	hmac_md5((uchar*)r->NTresp+16, p - ((uchar*)r->NTresp+16), hash, MShashlen, (uchar*)r->NTresp, s);
+
+	return p - resp;
 }
 
-static void
-dochap(char *pass, int id, char chal[ChapChallen], uchar resp[ChapResplen])
+static int
+dochap(char *passwd, int id, char chal[ChapChallen], uchar *resp, int resplen)
 {
 	char buf[1+ChapChallen+MAXNAMELEN+1];
-	int n = strlen(pass);
+	int n;
 
+	if(resplen < ChapResplen)
+		return 0;
+
+	memset(buf, 0, sizeof buf);
 	*buf = id;
-	if (n > MAXNAMELEN)
+	n = strlen(passwd);
+	if(n > MAXNAMELEN)
 		n = MAXNAMELEN-1;
-	memset(buf, 0, sizeof buf);
-	strncpy(buf+1, pass, n);
+	strncpy(buf+1, passwd, n);
 	memmove(buf+1+n, chal, ChapChallen);
 	md5((uchar*)buf, 1+n+ChapChallen, resp, nil);
-}
 
+	return ChapResplen;
+}
--- a/sys/src/cmd/auth/factotum/dat.h
+++ b/sys/src/cmd/auth/factotum/dat.h
@@ -230,7 +230,7 @@
 /* protocols */
 extern Proto apop, cram;		/* apop.c */
 extern Proto p9any, p9sk1, p9sk2;	/* p9sk.c */
-extern Proto chap, mschap;		/* chap.c */
+extern Proto chap, mschap, mschap2;	/* chap.c */
 extern Proto p9cr, vnc;			/* p9cr.c */
 extern Proto pass;			/* pass.c */
 extern Proto rsa;			/* rsa.c */
--- a/sys/src/cmd/auth/factotum/fs.c
+++ b/sys/src/cmd/auth/factotum/fs.c
@@ -31,6 +31,7 @@
 	&cram,
 	&httpdigest,
 	&mschap,
+	&mschap2,
 	&p9any,
 	&p9cr,
 	&p9sk1,
--- a/sys/src/cmd/cifs/auth.c
+++ b/sys/src/cmd/cifs/auth.c
@@ -21,7 +21,6 @@
 	MACkeylen	= 40,	/* MAC key len */
 	MAClen		= 8,	/* signature length */
 	MACoff		= 14,	/* sign. offset from start of SMB (not netbios) pkt */
-	Bliplen		= 8,	/* size of LMv2 client nonce */
 };
 
 static void
@@ -67,18 +66,25 @@
 }
 
 static Auth *
-auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len)
+auth_proto(char *proto, char *windom, char *keyp, uchar *chal, int len)
 {
-	int err;
+	MSchapreply *mcr;
+	uchar resp[4096];
+	int nresp;
 	char user[64];
 	Auth *ap;
-	MSchapreply mcr;
 
-	err = auth_respond(chal, len, user, sizeof user, &mcr, sizeof mcr,
-		auth_getkey, "windom=%s proto=mschap role=client service=cifs %s",
-		windom, keyp);
-	if(err == -1)
-		sysfatal("cannot get key - %r");
+	mcr = (MSchapreply*)resp;
+	nresp = sizeof(resp);
+	if(strcmp(proto, "mschap") == 0)
+		nresp = sizeof(*mcr);	/* backwards compatibility with old factotum */
+	nresp = auth_respond(chal, len, user, sizeof user, resp, nresp,
+		auth_getkey, "proto=%s role=client service=cifs windom=%s %s",
+		proto, windom, keyp);
+	if(nresp < 0)
+		sysfatal("cannot get response - %r");
+	if(nresp < sizeof(*mcr))
+		sysfatal("bad response size");
 
 	ap = emalloc9p(sizeof(Auth));
 	memset(ap, 0, sizeof(ap));
@@ -86,18 +92,24 @@
 	ap->windom = estrdup9p(windom);
 
 	/* LM response */
-	ap->len[0] = sizeof(mcr.LMresp);
+	ap->len[0] = sizeof(mcr->LMresp);
 	ap->resp[0] = emalloc9p(ap->len[0]);
-	memcpy(ap->resp[0], mcr.LMresp, ap->len[0]);
+	memcpy(ap->resp[0], mcr->LMresp, ap->len[0]);
 
-	/* NTLM response */
-	ap->len[1] = sizeof(mcr.NTresp);
+	/* NT response */
+	ap->len[1] = nresp+sizeof(mcr->NTresp)-sizeof(*mcr);
 	ap->resp[1] = emalloc9p(ap->len[1]);
-	memcpy(ap->resp[1], mcr.NTresp, ap->len[1]);
+	memcpy(ap->resp[1], mcr->NTresp, ap->len[1]);
 
 	return ap;
 }
 
+static Auth *
+auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len)
+{
+	return auth_proto("mschap", windom, keyp, chal, len);
+}
+
 /*
  * NTLM response only, the LM response is a just
  * copy of the NTLM one. we do this because the lm
@@ -119,211 +131,10 @@
 	return ap;
 }
 
-/*
- * This is not really nescessary as all fields hmac_md5'ed
- * in the ntlmv2 protocol are less than 64 bytes long, however
- * I still do this for completeness
- */
-static DigestState *
-hmac_t64(uchar *data, ulong dlen, uchar *key, ulong klen, uchar *digest,
-	DigestState *state)
-{
-	if(klen > 64)
-		klen = 64;
-	return hmac_md5(data, dlen, key, klen, digest, state);
-}
-
-
-static int
-putname(uchar *buf, int len, char *name, int type)
-{
-	int n;
-	Rune r;
-	char *d;
-	uchar *p = buf;
-
-	*p++ = type;
-	*p++ = 0;		/* 16bit: name type */
-
-	n = utflen(name) * 2;
-	*p++ = n;
-	*p++ = n >> 8;		/* 16bit: name length */
-
-	d = name;
-	while(*d != 0 && p-buf < len-8){
-		d += chartorune(&r, d);
-		r = toupperrune(r);
-		*p++ = r;
-			*p++ = r >> 8;
-	}			/* var: actual name */
-
-	return p - buf;
-}
-
-static int
-ntv2_blob(uchar *blob, int len, char *windom)
-{
-	uvlong t;
-	uchar *p;
-	enum {			/* name types */
-		Beof,		/* end of name list */
-		Bhost,		/* Netbios host name */
-		Bdomain,	/* Windows Domain name (NT) */
-		Bdnshost,	/* DNS host name */
-		Bdnsdomain,	/* DNS domain name */
-	};
-
-	p = blob;
-	*p++ = 1;		/* 8bit: response type */
-	*p++ = 1;		/* 8bit: max response type understood by client */
-
-	*p++ = 0;		/* 16bit: reserved */
-	*p++ = 0;
-
-	*p++ = 0;		/* 32bit: unknown */
-	*p++ = 0;
-	*p++ = 0;
-	*p++ = 0;
-
-	t = time(nil);
-	t += 11644473600LL;
-	t *= 10000000LL;
-
-	*p++ = t;		/* 64bit: time in NT format */
-	*p++ = t >> 8;
-	*p++ = t >> 16;
-	*p++ = t >> 24;
-	*p++ = t >> 32;
-	*p++ = t >> 40;
-	*p++ = t >> 48;
-	*p++ = t >> 56;
-
-	genrandom(p, 8);
-	p += 8;			/* 64bit: client nonce */
-
-	*p++ = 0;		/* 32bit: unknown data */
-	*p++ = 0;
-	*p++ = 0;
-	*p++ = 0;
-
-	len -= 4;
-	p += putname(p, len - (p-blob), windom, Bdomain);
-	p += putname(p, len - (p-blob), "", Beof);
-
-	*p++ = 0;		/* 32bit: unknown data */
-	*p++ = 0;
-	*p++ = 0;
-	*p++ = 0;
-
-	return p - blob;
-}
-
 static Auth *
 auth_ntlmv2(char *windom, char *keyp, uchar *chal, int len)
 {
-	int i, n;
-	Rune r;
-	char *p, *u;
-	uchar v1hash[MD5dlen], blip[Bliplen], blob[1024], v2hash[MD5dlen];
-	uchar c, lm_hmac[MD5dlen], nt_hmac[MD5dlen], nt_sesskey[MD5dlen],
-		lm_sesskey[MD5dlen];
-	DigestState *ds;
-	UserPasswd *up;
-	static Auth *ap;
-
-	up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass  service=cifs-ntlmv2 %s",
-		windom, keyp);
-	if(!up)
-		sysfatal("cannot get key - %r");
-
-	ap = emalloc9p(sizeof(Auth));
-	memset(ap, 0, sizeof(ap));
-
-	/* Standard says unlimited length, experience says 128 max */
-	if((n = strlen(up->passwd)) > 128)
-		n = 128;
-
-	ds = md4(nil, 0, nil, nil);
-	for(i=0, p=up->passwd; i < n; i++) {
-		p += chartorune(&r, p);
-		c = r;
-		md4(&c, 1, nil, ds);
-		c = r >> 8;
-		md4(&c, 1, nil, ds);
-	}
-	md4(nil, 0, v1hash, ds);
-
-	/*
-	 * Some documentation insists that the username must be forced to
-	 * uppercase, but the domain name should not be. Other shows both
-	 * being forced to uppercase. I am pretty sure this is irrevevant as the
-	 * domain name passed from the remote server always seems to be in
-	 * uppercase already.
-	 */
-        ds = hmac_t64(nil, 0, v1hash, MD5dlen, nil, nil);
-	u = up->user;
-	while(*u){
-		u += chartorune(&r, u);
-		r = toupperrune(r);
-		c = r;
-        	hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
-		c = r >> 8;
-        	hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
-	}
-	u = windom;
-
-	while(*u){
-		u += chartorune(&r, u);
-		c = r;
-        	hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
-		c = r >> 8;
-        	hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
-	}
-        hmac_t64(nil, 0, v1hash, MD5dlen, v2hash, ds);
-	ap->user = estrdup9p(up->user);
-	ap->windom = estrdup9p(windom);
-
-	/* LM v2 */
-
-	genrandom(blip, Bliplen);
-        ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil);
-	hmac_t64(blip, Bliplen, v2hash, MD5dlen, lm_hmac, ds);
-	ap->len[0] = MD5dlen+Bliplen;
-	ap->resp[0] = emalloc9p(ap->len[0]);
-	memcpy(ap->resp[0], lm_hmac, MD5dlen);
-	memcpy(ap->resp[0]+MD5dlen, blip, Bliplen);
-
-	/* LM v2 session key */
-	hmac_t64(lm_hmac, MD5dlen, v2hash, MD5dlen, lm_sesskey, nil);
-
-	/* LM v2 MAC key */
-	ap->mackey[0] = emalloc9p(MACkeylen);
-	memcpy(ap->mackey[0], lm_sesskey, MD5dlen);
-	memcpy(ap->mackey[0]+MD5dlen, ap->resp[0], MACkeylen-MD5dlen);
-
-	/* NTLM v2 */
-	n = ntv2_blob(blob, sizeof blob, windom);
-        ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil);
-	hmac_t64(blob, n, v2hash, MD5dlen, nt_hmac, ds);
-	ap->len[1] = MD5dlen+n;
-	ap->resp[1] = emalloc9p(ap->len[1]);
-	memcpy(ap->resp[1], nt_hmac, MD5dlen);
-	memcpy(ap->resp[1]+MD5dlen, blob, n);
-
-	/*
-	 * v2hash definitely OK by
-	 * the time we get here.
-	 */
-	/* NTLM v2 session key */
-	hmac_t64(nt_hmac, MD5dlen, v2hash, MD5dlen, nt_sesskey, nil);
-
-	/* NTLM v2 MAC key */
-	ap->mackey[1] = emalloc9p(MACkeylen);
-	memcpy(ap->mackey[1], nt_sesskey, MD5dlen);
-	memcpy(ap->mackey[1]+MD5dlen, ap->resp[1], MACkeylen-MD5dlen);
-	free(up);
-
-	return ap;
+	return auth_proto("mschap2", windom, keyp, chal, len);
 }
 
 struct {