summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/src/cmd/auth/authsrv.c174
-rw-r--r--sys/src/cmd/auth/factotum/chap.c59
-rw-r--r--sys/src/cmd/ip/cifsd/smb.c19
3 files changed, 199 insertions, 53 deletions
diff --git a/sys/src/cmd/auth/authsrv.c b/sys/src/cmd/auth/authsrv.c
index 491eec42c..e6d9749e6 100644
--- a/sys/src/cmd/auth/authsrv.c
+++ b/sys/src/cmd/auth/authsrv.c
@@ -34,6 +34,7 @@ void mkkey(char*);
void randombytes(uchar*, int);
void nthash(uchar hash[MShashlen], char *passwd);
void lmhash(uchar hash[MShashlen], char *passwd);
+void ntv2hash(uchar hash[MShashlen], char *passwd, char *user, char *dom);
void mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]);
void desencrypt(uchar data[8], uchar key[7]);
int tickauthreply(Ticketreq*, char*);
@@ -629,19 +630,59 @@ printresp(uchar resp[MSresplen])
syslog(0, AUTHLOG, "resp = %s", buf);
}
+enum {
+ MsvAvEOL = 0,
+ MsvAvNbComputerName,
+ MsvAvNbDomainName,
+ MsvAvDnsComputerName,
+ MsvAvDnsomainName,
+};
+
+char*
+getname(int id, uchar *ntblob, int ntbloblen, char *buf, int nbuf)
+{
+ int aid, alen, i;
+ uchar *p, *e;
+ char *d;
+ Rune r;
+
+ d = buf;
+ p = ntblob+8+8+8+4; /* AvPair offset */
+ e = ntblob+ntbloblen;
+ while(p+4 <= e){
+ aid = *p++;
+ aid |= *p++ << 8;
+ alen = *p++;
+ alen |= *p++ << 8;
+
+ if(p+alen > e)
+ break;
+ if(aid == id){
+ for(i=0; i+1 < alen && d-buf < nbuf-(UTFmax+1); i+=2){
+ r = p[i] | p[i+1]<<8;
+ d += runetochar(d, &r);
+ }
+ break;
+ }
+ p += alen;
+ }
+ *d = '\0';
+ return buf;
+}
+
+static uchar ntblobsig[] = {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
void
mschap(Ticketreq *tr)
{
-
char *secret, *hkey;
- char sbuf[SECRETLEN], hbuf[DESKEYLEN];
- uchar chal[CHALLEN];
+ char sbuf[SECRETLEN], hbuf[DESKEYLEN], windom[128];
+ uchar chal[CHALLEN], ntblob[1024];
uchar hash[MShashlen];
uchar hash2[MShashlen];
uchar resp[MSresplen];
OMSchapreply reply;
- int dupe, lmok, ntok;
+ int dupe, lmok, ntok, ntbloblen;
DigestState *s;
uchar digest[SHA1dlen];
@@ -657,6 +698,43 @@ mschap(Ticketreq *tr)
if(readn(0, &reply, sizeof(reply)) < 0)
exits(0);
+ /*
+ * CIFS/NTLMv2 uses variable length NT response.
+ */
+ ntbloblen = 0;
+ if(memcmp(reply.NTresp+16, ntblobsig, sizeof(ntblobsig)) == 0){
+ /* Version[1], HiVision[1], Z[6] */
+ ntbloblen += 1+1+6;
+ memmove(ntblob, reply.NTresp+16, ntbloblen);
+
+ /* Time[8], CC[8], Z[4] */
+ if(readn(0, ntblob+ntbloblen, 8+8+4) < 0)
+ exits(0);
+ ntbloblen += 8+8+4;
+
+ /* variable AvPairs */
+ for(;;){
+ int len, id;
+
+ if(ntbloblen > sizeof(ntblob)-4)
+ exits(0);
+ /* AvId[2], AvLen[2], Vairable[AvLen] */
+ if(readn(0, ntblob+ntbloblen, 4) < 0)
+ exits(0);
+ id = ntblob[ntbloblen+0] | ntblob[ntbloblen+1]<<8;
+ len = ntblob[ntbloblen+2] | ntblob[ntbloblen+3]<<8;
+ ntbloblen += 4;
+
+ if(ntbloblen+len > sizeof(ntblob))
+ exits(0);
+ if(readn(0, ntblob+ntbloblen, len) < 0)
+ exits(0);
+ ntbloblen += len;
+ if(id == MsvAvEOL)
+ break;
+ }
+ }
+
safecpy(tr->uid, reply.uid, sizeof(tr->uid));
/*
* lookup
@@ -670,13 +748,33 @@ mschap(Ticketreq *tr)
exits(0);
}
- lmhash(hash, secret);
- mschalresp(resp, hash, chal);
- lmok = memcmp(resp, reply.LMresp, MSresplen) == 0;
- nthash(hash, secret);
- mschalresp(resp, hash, chal);
- ntok = memcmp(resp, reply.NTresp, MSresplen) == 0;
- dupe = memcmp(reply.LMresp, reply.NTresp, MSresplen) == 0;
+ if(ntbloblen > 0){
+ getname(MsvAvNbDomainName, ntblob, ntbloblen, windom, sizeof(windom));
+ 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);
+ lmok = memcmp(resp, reply.LMresp, 16) == 0;
+
+ /*
+ * NtResponse = Cat(HMAC_MD5(NtHash, Cat(SC, NtBlob)), NtBlob)
+ */
+ s = hmac_md5(chal, 8, hash, MShashlen, nil, nil);
+ hmac_md5(ntblob, ntbloblen, hash, MShashlen, resp, s);
+ ntok = memcmp(resp, reply.NTresp, 16) == 0;
+ dupe = 0;
+ } else {
+ lmhash(hash, secret);
+ mschalresp(resp, hash, chal);
+ lmok = memcmp(resp, reply.LMresp, MSresplen) == 0;
+ nthash(hash, secret);
+ mschalresp(resp, hash, chal);
+ ntok = memcmp(resp, reply.NTresp, MSresplen) == 0;
+ dupe = memcmp(reply.LMresp, reply.NTresp, MSresplen) == 0;
+ }
/*
* It is valid to send the same response in both the LM and NTLM
@@ -707,8 +805,7 @@ mschap(Ticketreq *tr)
exits(0);
if(debug)
- replyerror("mschap-ok %s/%s(%s) %ux",
- tr->uid, tr->hostid, raddr);
+ replyerror("mschap-ok %s/%s(%s)", tr->uid, tr->hostid, raddr);
nthash(hash, secret);
md4(hash, 16, hash2, 0);
@@ -723,19 +820,52 @@ mschap(Ticketreq *tr)
void
nthash(uchar hash[MShashlen], char *passwd)
{
- uchar buf[512];
- int i;
+ DigestState *ds;
+ uchar b[2];
+ Rune r;
- for (i = 0; *passwd && i + 1 < sizeof(buf);) {
- Rune r;
+ ds = md4(nil, 0, nil, nil);
+ while(*passwd){
passwd += chartorune(&r, passwd);
- buf[i++] = r;
- buf[i++] = r >> 8;
+ b[0] = r & 0xff;
+ b[1] = r >> 8;
+ md4(b, 2, nil, ds);
}
+ md4(nil, 0, hash, ds);
+}
+
+void
+ntv2hash(uchar hash[MShashlen], char *passwd, char *user, char *dom)
+{
+ uchar v1hash[MShashlen];
+ DigestState *ds;
+ uchar b[2];
+ Rune r;
- memset(hash, 0, 16);
+ nthash(v1hash, passwd);
- md4(buf, i, hash, 0);
+ /*
+ * 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);
}
void
@@ -745,12 +875,12 @@ lmhash(uchar hash[MShashlen], char *passwd)
char *stdtext = "KGS!@#$%";
int i;
+ 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';
- memset(hash, 0, 16);
memcpy(hash, stdtext, 8);
memcpy(hash+8, stdtext, 8);
diff --git a/sys/src/cmd/auth/factotum/chap.c b/sys/src/cmd/auth/factotum/chap.c
index c92b99706..550f253cd 100644
--- a/sys/src/cmd/auth/factotum/chap.c
+++ b/sys/src/cmd/auth/factotum/chap.c
@@ -130,14 +130,14 @@ chapwrite(Fsstate *fss, void *va, uint n)
{
int ret, nreply;
char *a, *v;
- void *reply;
Key *k;
Keyinfo ki;
State *s;
- Chapreply cr;
- MSchapreply mcr;
- OChapreply ocr;
- OMSchapreply omcr;
+ Chapreply *cr;
+ MSchapreply *mcr;
+ OChapreply *ocr;
+ OMSchapreply *omcr;
+ uchar reply[4*1024];
s = fss->ps;
a = va;
@@ -150,17 +150,28 @@ chapwrite(Fsstate *fss, void *va, uint n)
if(ret != RpcOk)
return ret;
v = _strfindattr(k->privattr, "!password");
- if(v == nil)
+ if(v == nil){
+ closekey(k);
return failure(fss, "key has no password");
+ }
setattrs(fss->attr, k->attr);
switch(s->astype){
default:
- abort();
+ 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);
break;
case AuthChap:
+ if(n < ChapChallen+1){
+ closekey(k);
+ return failure(fss, "challenge too short");
+ }
dochap(v, *a, a+1, (uchar *)s->cr);
break;
}
@@ -181,26 +192,28 @@ chapwrite(Fsstate *fss, void *va, uint n)
default:
return failure(fss, "chap internal botch");
case AuthChap:
- if(n != sizeof(Chapreply))
+ if(n != sizeof(*cr))
return failure(fss, "did not get Chapreply");
- memmove(&cr, va, sizeof cr);
- ocr.id = cr.id;
- memmove(ocr.resp, cr.resp, sizeof ocr.resp);
- memset(omcr.uid, 0, sizeof(omcr.uid));
- strecpy(ocr.uid, ocr.uid+sizeof ocr.uid, s->user);
- reply = &ocr;
- nreply = sizeof ocr;
+ cr = (Chapreply*)va;
+ nreply = sizeof(*ocr);
+ memset(reply, 0, nreply);
+ ocr = (OChapreply*)reply;
+ strecpy(ocr->uid, ocr->uid+sizeof(ocr->uid), s->user);
+ ocr->id = cr->id;
+ memmove(ocr->resp, cr->resp, sizeof(ocr->resp));
break;
case AuthMSchap:
- if(n != sizeof(MSchapreply))
+ if(n < sizeof(*mcr))
return failure(fss, "did not get MSchapreply");
- memmove(&mcr, va, sizeof mcr);
- memmove(omcr.LMresp, mcr.LMresp, sizeof omcr.LMresp);
- memmove(omcr.NTresp, mcr.NTresp, sizeof omcr.NTresp);
- memset(omcr.uid, 0, sizeof(omcr.uid));
- strecpy(omcr.uid, omcr.uid+sizeof omcr.uid, s->user);
- reply = &omcr;
- nreply = sizeof omcr;
+ if(n > sizeof(reply)+sizeof(*mcr)-sizeof(*omcr))
+ return failure(fss, "MSchapreply too long");
+ mcr = (MSchapreply*)va;
+ nreply = n+sizeof(*omcr)-sizeof(*mcr);
+ memset(reply, 0, nreply);
+ omcr = (OMSchapreply*)reply;
+ strecpy(omcr->uid, omcr->uid+sizeof(omcr->uid), s->user);
+ memmove(omcr->LMresp, mcr->LMresp, sizeof(omcr->LMresp));
+ memmove(omcr->NTresp, mcr->NTresp, n+sizeof(mcr->NTresp)-sizeof(*mcr));
break;
}
if(doreply(s, reply, nreply) < 0)
diff --git a/sys/src/cmd/ip/cifsd/smb.c b/sys/src/cmd/ip/cifsd/smb.c
index 145266a42..9e6f9cf3c 100644
--- a/sys/src/cmd/ip/cifsd/smb.c
+++ b/sys/src/cmd/ip/cifsd/smb.c
@@ -99,22 +99,25 @@ smbsessionsetupandx(Req *r, uchar *h, uchar *p, uchar *e)
logit("ignoring bad session key");
while(!remoteuser){
if(needauth){
- MSchapreply mcr;
+ MSchapreply *mcr;
if(smbcs == nil || strlen(user) == 0)
break;
- memset(&mcr, 0, sizeof(mcr));
- if((lme - lm) == sizeof(mcr.LMresp))
- memmove(mcr.LMresp, lm, lme - lm);
- if((nte - nt) == sizeof(mcr.NTresp))
- memmove(mcr.NTresp, nt, nte - nt);
smbcs->user = user;
- smbcs->resp = &mcr;
- smbcs->nresp = sizeof(mcr);
+ 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;
+ 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)
logit("auth_response: %r");
auth_freechal(smbcs);
smbcs = nil;
+ free(mcr);
if(ai == nil)
break;
if(auth_chuid(ai, nil) < 0)