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.
This commit is contained in:
parent
a59aa24a94
commit
58aba2a67f
3 changed files with 87 additions and 72 deletions
|
@ -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]);
|
||||
/*
|
||||
* 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 @@ 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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in a new issue