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");