shithub: riscv

Download patch

ref: 58aba2a67fa6b8a7a4527f3545be3551e37b7cc0
parent: a59aa24a94f84afd0fe52c28896d24de4becef54
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat May 19 12:40:01 EDT 2018

cifsd: fix ntlmv2 authentication

in ntlmv2, the client will retry the challenge response trying a bunch
of different domain names assuming the same server challenge. so we have
to make retries work with factotum and the auth server.

also, windows 7 with compatlevel=4 sends all zeros LM response.

--- a/sys/src/cmd/auth/authsrv.c
+++ b/sys/src/cmd/auth/authsrv.c
@@ -422,59 +422,55 @@
 	challen = p - chal;
 	print("%c%-5d%s", AuthOKvar, challen, chal);
 
-	/* give user a few attempts */
-	for(tries = 0; ; tries++) {
-		/*
-		 *  get ticket request
-		 */
-		n = readn(0, trbuf, sizeof(trbuf));
-		if(n <= 0 || convM2TR(trbuf, n, &treq) <= 0)
-			exits(0);
-		tr = &treq;
-		if(tr->type != type || tr->uid[0] == 0)
-			exits(0);
+	tries = 5;
+Retry:
+	if(--tries < 0)
+		exits(0);
 
-		/*
-		 * read response
-		 */
-		if(readn(0, buf, MD5dlen*2) != MD5dlen*2)
-			exits(0);
-		for(i = 0; i < MD5dlen; i++)
-			resp[i] = (h2b(buf[2*i])<<4)|h2b(buf[2*i+1]);
+	/*
+	 *  get ticket request
+	 */
+	n = readn(0, trbuf, sizeof(trbuf));
+	if(n <= 0 || convM2TR(trbuf, n, &treq) <= 0)
+		exits(0);
+	tr = &treq;
+	if(tr->type != type || tr->uid[0] == 0)
+		exits(0);
 
-		/*
-		 * lookup
-		 */
-		secret = findsecret(KEYDB, tr->uid, sbuf);
-		if(!getkey(tr->hostid, &hkey) || secret == nil){
-			replyerror("apop-fail bad response %s", raddr);
-			logfail(tr->uid);
-			if(tries > 5)
-				exits(0);
-			continue;
-		}
+	/*
+	 * read response
+	 */
+	if(readn(0, buf, MD5dlen*2) != MD5dlen*2)
+		exits(0);
+	for(i = 0; i < MD5dlen; i++)
+		resp[i] = (h2b(buf[2*i])<<4)|h2b(buf[2*i+1]);
 
-		/*
-		 *  check for match
-		 */
-		if(type == AuthCram){
-			hmac_md5((uchar*)chal, challen,
-				(uchar*)secret, strlen(secret),
-				digest, nil);
-		} else {
-			s = md5((uchar*)chal, challen, 0, 0);
-			md5((uchar*)secret, strlen(secret), digest, s);
-		}
-		if(tsmemcmp(digest, resp, MD5dlen) != 0){
-			replyerror("apop-fail bad response %s", raddr);
-			logfail(tr->uid);
-			if(tries > 5)
-				exits(0);
-			continue;
-		}
-		break;
+	/*
+	 * lookup
+	 */
+	secret = findsecret(KEYDB, tr->uid, sbuf);
+	if(!getkey(tr->hostid, &hkey) || secret == nil){
+		replyerror("apop-fail bad response %s", raddr);
+		goto Retry;
 	}
 
+	/*
+	 *  check for match
+	 */
+	if(type == AuthCram){
+		hmac_md5((uchar*)chal, challen,
+			(uchar*)secret, strlen(secret),
+			digest, nil);
+	} else {
+		s = md5((uchar*)chal, challen, 0, 0);
+		md5((uchar*)secret, strlen(secret), digest, s);
+	}
+	if(tsmemcmp(digest, resp, MD5dlen) != 0){
+		replyerror("apop-fail bad response %s", raddr);
+		logfail(tr->uid);
+		goto Retry;
+	}
+
 	succeed(tr->uid);
 
 	/*
@@ -582,6 +578,7 @@
 	uchar digest[MD5dlen];
 	char chal[CHALLEN];
 	OChapreply reply;
+	int tries;
 
 	/*
 	 *  Create a challenge and send it.
@@ -590,6 +587,11 @@
 	if(write(1, chal, sizeof(chal)) != sizeof(chal))
 		exits(0);
 
+	tries = 5;
+Retry:
+	if(--tries < 0)
+		exits(0);	
+
 	/*
 	 *  get chap reply
 	 */
@@ -606,8 +608,7 @@
 	secret = findsecret(KEYDB, tr->uid, sbuf);
 	if(!getkey(tr->hostid, &hkey) || secret == nil){
 		replyerror("chap-fail bad response %s", raddr);
-		logfail(tr->uid);
-		return;
+		goto Retry;
 	}
 
 	/*
@@ -620,7 +621,7 @@
 	if(tsmemcmp(digest, reply.resp, MD5dlen) != 0){
 		replyerror("chap-fail bad response %s", raddr);
 		logfail(tr->uid);
-		return;
+		goto Retry;
 	}
 
 	succeed(tr->uid);
@@ -690,6 +691,7 @@
 	int dupe, lmok, ntok, ntbloblen;
 	uchar phash[SHA1dlen], chash[SHA1dlen], ahash[SHA1dlen];
 	DigestState *s;
+	int tries;
 
 	/*
 	 *  Create a challenge and send it.
@@ -698,6 +700,11 @@
 	if(write(1, chal, nchal) != nchal)
 		exits(0);
 
+	tries = 5;
+Retry:
+	if(--tries < 0)
+		exits(0);
+
 	/*
 	 *  get chap reply
 	 */
@@ -758,13 +765,11 @@
 	secret = findsecret(KEYDB, tr->uid, sbuf);
 	if(!getkey(tr->hostid, &hkey) || secret == nil){
 		replyerror("mschap-fail bad response %s/%s(%s)", tr->uid, tr->hostid, raddr);
-		logfail(tr->uid);
-		return;
+		goto Retry;
 	}
 
 	if(ntbloblen > 0){
 		getname(MsvAvNbDomainName, ntblob, ntbloblen, windom, sizeof(windom));
-
 		for(;;){
 			ntv2hash(hash, secret, tr->uid, windom);
 
@@ -771,18 +776,24 @@
 			/*
 			 * LmResponse = Cat(HMAC_MD5(LmHash, Cat(SC, CC)), CC)
 			 */
-			s = hmac_md5(chal, 8, hash, MShashlen, nil, nil);
-			hmac_md5((uchar*)reply.LMresp+16, 8, hash, MShashlen, resp, s);
+			s = hmac_md5(chal, nchal, hash, MShashlen, nil, nil);
+			hmac_md5((uchar*)reply.LMresp+16, nchal, hash, MShashlen, resp, s);
 			lmok = tsmemcmp(resp, reply.LMresp, 16) == 0;
 
 			/*
 			 * NtResponse = Cat(HMAC_MD5(NtHash, Cat(SC, NtBlob)), NtBlob)
 			 */
-			s = hmac_md5(chal, 8, hash, MShashlen, nil, nil);
+			s = hmac_md5(chal, nchal, hash, MShashlen, nil, nil);
 			hmac_md5(ntblob, ntbloblen, hash, MShashlen, resp, s);
 			ntok = tsmemcmp(resp, reply.NTresp, 16) == 0;
 
-			if(lmok || ntok || windom[0] == '\0')
+			/*
+			 * LM response can be all zeros or signature key,
+			 * so make it valid when the NT respone matches.
+			 */
+			lmok |= ntok;
+
+			if(lmok || windom[0] == '\0')
 				break;
 
 			windom[0] = '\0';	/* try NIL domain */
@@ -789,8 +800,8 @@
 		}
 		dupe = 0;
 	} else if(nchal == MSchallenv2){
-		s = sha1((uchar*)reply.LMresp, MSchallenv2, nil, nil);
-		s = sha1(chal, MSchallenv2, nil, s);
+		s = sha1((uchar*)reply.LMresp, nchal, nil, nil);
+		s = sha1(chal, nchal, nil, s);
 		sha1((uchar*)tr->uid, strlen(tr->uid), chash, s);
 
 		nthash(hash, secret);
@@ -805,7 +816,6 @@
 		nthash(hash, secret);
 		mschalresp(resp, hash, chal);
 		ntok = tsmemcmp(resp, reply.NTresp, MSresplen) == 0;
-
 		dupe = tsmemcmp(reply.LMresp, reply.NTresp, MSresplen) == 0;
 	}
 
@@ -825,7 +835,7 @@
 	if((!ntok && !lmok) || ((!ntok || !lmok) && !dupe)){
 		replyerror("mschap-fail bad response %s/%s(%s)", tr->uid, tr->hostid, raddr);
 		logfail(tr->uid);
-		return;
+		goto Retry;
 	}
 
 	succeed(tr->uid);
--- a/sys/src/cmd/auth/factotum/chap.c
+++ b/sys/src/cmd/auth/factotum/chap.c
@@ -11,6 +11,7 @@
  *	read challenge: 8 bytes binary (or 16 bytes for mschapv2)
  *	write user: utf8
  *	write response: Chapreply or MSchapreply structure
+ *	... retry another user
  */
 
 #include <ctype.h>
@@ -285,8 +286,10 @@
 			memmove(omcr->NTresp, mcr->NTresp, n+sizeof(mcr->NTresp)-MSchapreplylen);
 			break;
 		}
-		if(doreply(s, reply, nreply) < 0)
+		if(doreply(s, reply, nreply) < 0){
+			fss->phase = SNeedUser;
 			return failure(fss, nil);
+		}
 		fss->phase = Established;
 		fss->ai.cuid = s->t.cuid;
 		fss->ai.suid = s->t.suid;
--- a/sys/src/cmd/ip/cifsd/smb.c
+++ b/sys/src/cmd/ip/cifsd/smb.c
@@ -44,7 +44,7 @@
 	c = ce = nil;
 	mode = 0;
 	if(needauth){
-		if(smbcs)
+		if(smbcs != nil)
 			auth_freechal(smbcs);
 		if(smbcs = auth_challenge("proto=mschap role=server")){
 			c = (uchar*)smbcs->chal;
@@ -107,22 +107,24 @@
 			smbcs->nresp = (nte - nt)+sizeof(*mcr)-sizeof(mcr->NTresp);
 			if(smbcs->nresp < sizeof(*mcr))
 				smbcs->nresp = sizeof(*mcr);
-			smbcs->resp = mallocz(smbcs->nresp, 1);
-			mcr = (MSchapreply*)smbcs->resp;
+			mcr = mallocz(smbcs->nresp, 1);
 			if((lme - lm) <= sizeof(mcr->LMresp))
 				memmove(mcr->LMresp, lm, lme - lm);
 			if((nte - nt) > 0)
 				memmove(mcr->NTresp, nt, nte - nt);
-			if((ai = auth_response(smbcs)) == nil)
+			smbcs->resp = mcr;
+			ai = auth_response(smbcs);
+			if(ai == nil){
 				logit("auth_response: %r");
-			auth_freechal(smbcs);
-			smbcs = nil;
-			free(mcr);
-			if(ai == nil)
-				break;
+				free(mcr);
+				break;	/* allow retry with the same challenge */
+			}
 			if(auth_chuid(ai, nil) < 0)
 				logit("auth_chuid: %r");
 			auth_freeAI(ai);
+			auth_freechal(smbcs);
+			smbcs = nil;
+			free(mcr);
 		}
 		remoteuser = getuser();
 		logit("auth successfull");