diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-05-19 16:40:01 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-05-19 16:40:01 +0200 |
commit | 58aba2a67fa6b8a7a4527f3545be3551e37b7cc0 (patch) | |
tree | e93329d0388cc390f9ce2b1df23a614c7d6aa84a | |
parent | a59aa24a94f84afd0fe52c28896d24de4becef54 (diff) | |
download | plan9front-58aba2a67fa6b8a7a4527f3545be3551e37b7cc0.tar.xz |
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.
-rw-r--r-- | sys/src/cmd/auth/authsrv.c | 136 | ||||
-rw-r--r-- | sys/src/cmd/auth/factotum/chap.c | 5 | ||||
-rw-r--r-- | sys/src/cmd/ip/cifsd/smb.c | 20 |
3 files changed, 88 insertions, 73 deletions
diff --git a/sys/src/cmd/auth/authsrv.c b/sys/src/cmd/auth/authsrv.c index 5e9a7a02e..b9e8abc7a 100644 --- a/sys/src/cmd/auth/authsrv.c +++ b/sys/src/cmd/auth/authsrv.c @@ -422,57 +422,53 @@ apop(Ticketreq *tr, int type) 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]); - - /* - * 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; - } + /* + * 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); - /* - * 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; + /* + * 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]); + + /* + * 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 @@ chap(Ticketreq *tr) uchar digest[MD5dlen]; char chal[CHALLEN]; OChapreply reply; + int tries; /* * Create a challenge and send it. @@ -590,6 +587,11 @@ chap(Ticketreq *tr) 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 @@ chap(Ticketreq *tr) 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 @@ chap(Ticketreq *tr) 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 @@ mschap(Ticketreq *tr, int nchal) 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 @@ mschap(Ticketreq *tr, int nchal) if(write(1, chal, nchal) != nchal) exits(0); + tries = 5; +Retry: + if(--tries < 0) + exits(0); + /* * get chap reply */ @@ -758,39 +765,43 @@ mschap(Ticketreq *tr, int nchal) 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); /* * 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 */ } 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 @@ mschap(Ticketreq *tr, int nchal) 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 @@ mschap(Ticketreq *tr, int nchal) 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); diff --git a/sys/src/cmd/auth/factotum/chap.c b/sys/src/cmd/auth/factotum/chap.c index 03e1d3047..56ad476c3 100644 --- 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 @@ chapwrite(Fsstate *fss, void *va, uint n) 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; diff --git a/sys/src/cmd/ip/cifsd/smb.c b/sys/src/cmd/ip/cifsd/smb.c index 47e065c32..3dbf57b53 100644 --- a/sys/src/cmd/ip/cifsd/smb.c +++ b/sys/src/cmd/ip/cifsd/smb.c @@ -44,7 +44,7 @@ err: 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 @@ smbsessionsetupandx(Req *r, uchar *h, uchar *p, uchar *e) 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"); |