summaryrefslogtreecommitdiff
path: root/sys/src/cmd/cifs
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2013-12-11 05:48:48 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2013-12-11 05:48:48 +0100
commit3c8db40def613d036715a092eafb6ef7be22928a (patch)
tree12748968e37105c81252d23fc9a94dfde286d6e4 /sys/src/cmd/cifs
parent71dbddef166f855e28dfae1989ddbd663d38176a (diff)
factotum: add ntlmv2 (mschap2) client auth for cifs
Diffstat (limited to 'sys/src/cmd/cifs')
-rw-r--r--sys/src/cmd/cifs/auth.c243
1 files changed, 27 insertions, 216 deletions
diff --git a/sys/src/cmd/cifs/auth.c b/sys/src/cmd/cifs/auth.c
index 9dc9b4664..9887d3655 100644
--- a/sys/src/cmd/cifs/auth.c
+++ b/sys/src/cmd/cifs/auth.c
@@ -21,7 +21,6 @@ static enum {
MACkeylen = 40, /* MAC key len */
MAClen = 8, /* signature length */
MACoff = 14, /* sign. offset from start of SMB (not netbios) pkt */
- Bliplen = 8, /* size of LMv2 client nonce */
};
static void
@@ -67,18 +66,25 @@ auth_plain(char *windom, char *keyp, uchar *chal, int len)
}
static Auth *
-auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len)
+auth_proto(char *proto, char *windom, char *keyp, uchar *chal, int len)
{
- int err;
+ MSchapreply *mcr;
+ uchar resp[4096];
+ int nresp;
char user[64];
Auth *ap;
- MSchapreply mcr;
- err = auth_respond(chal, len, user, sizeof user, &mcr, sizeof mcr,
- auth_getkey, "windom=%s proto=mschap role=client service=cifs %s",
- windom, keyp);
- if(err == -1)
- sysfatal("cannot get key - %r");
+ mcr = (MSchapreply*)resp;
+ nresp = sizeof(resp);
+ if(strcmp(proto, "mschap") == 0)
+ nresp = sizeof(*mcr); /* backwards compatibility with old factotum */
+ nresp = auth_respond(chal, len, user, sizeof user, resp, nresp,
+ auth_getkey, "proto=%s role=client service=cifs windom=%s %s",
+ proto, windom, keyp);
+ if(nresp < 0)
+ sysfatal("cannot get response - %r");
+ if(nresp < sizeof(*mcr))
+ sysfatal("bad response size");
ap = emalloc9p(sizeof(Auth));
memset(ap, 0, sizeof(ap));
@@ -86,18 +92,24 @@ auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len)
ap->windom = estrdup9p(windom);
/* LM response */
- ap->len[0] = sizeof(mcr.LMresp);
+ ap->len[0] = sizeof(mcr->LMresp);
ap->resp[0] = emalloc9p(ap->len[0]);
- memcpy(ap->resp[0], mcr.LMresp, ap->len[0]);
+ memcpy(ap->resp[0], mcr->LMresp, ap->len[0]);
- /* NTLM response */
- ap->len[1] = sizeof(mcr.NTresp);
+ /* NT response */
+ ap->len[1] = nresp+sizeof(mcr->NTresp)-sizeof(*mcr);
ap->resp[1] = emalloc9p(ap->len[1]);
- memcpy(ap->resp[1], mcr.NTresp, ap->len[1]);
+ memcpy(ap->resp[1], mcr->NTresp, ap->len[1]);
return ap;
}
+static Auth *
+auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len)
+{
+ return auth_proto("mschap", windom, keyp, chal, len);
+}
+
/*
* NTLM response only, the LM response is a just
* copy of the NTLM one. we do this because the lm
@@ -119,211 +131,10 @@ auth_ntlm(char *windom, char *keyp, uchar *chal, int len)
return ap;
}
-/*
- * This is not really nescessary as all fields hmac_md5'ed
- * in the ntlmv2 protocol are less than 64 bytes long, however
- * I still do this for completeness
- */
-static DigestState *
-hmac_t64(uchar *data, ulong dlen, uchar *key, ulong klen, uchar *digest,
- DigestState *state)
-{
- if(klen > 64)
- klen = 64;
- return hmac_md5(data, dlen, key, klen, digest, state);
-}
-
-
-static int
-putname(uchar *buf, int len, char *name, int type)
-{
- int n;
- Rune r;
- char *d;
- uchar *p = buf;
-
- *p++ = type;
- *p++ = 0; /* 16bit: name type */
-
- n = utflen(name) * 2;
- *p++ = n;
- *p++ = n >> 8; /* 16bit: name length */
-
- d = name;
- while(*d != 0 && p-buf < len-8){
- d += chartorune(&r, d);
- r = toupperrune(r);
- *p++ = r;
- *p++ = r >> 8;
- } /* var: actual name */
-
- return p - buf;
-}
-
-static int
-ntv2_blob(uchar *blob, int len, char *windom)
-{
- uvlong t;
- uchar *p;
- enum { /* name types */
- Beof, /* end of name list */
- Bhost, /* Netbios host name */
- Bdomain, /* Windows Domain name (NT) */
- Bdnshost, /* DNS host name */
- Bdnsdomain, /* DNS domain name */
- };
-
- p = blob;
- *p++ = 1; /* 8bit: response type */
- *p++ = 1; /* 8bit: max response type understood by client */
-
- *p++ = 0; /* 16bit: reserved */
- *p++ = 0;
-
- *p++ = 0; /* 32bit: unknown */
- *p++ = 0;
- *p++ = 0;
- *p++ = 0;
-
- t = time(nil);
- t += 11644473600LL;
- t *= 10000000LL;
-
- *p++ = t; /* 64bit: time in NT format */
- *p++ = t >> 8;
- *p++ = t >> 16;
- *p++ = t >> 24;
- *p++ = t >> 32;
- *p++ = t >> 40;
- *p++ = t >> 48;
- *p++ = t >> 56;
-
- genrandom(p, 8);
- p += 8; /* 64bit: client nonce */
-
- *p++ = 0; /* 32bit: unknown data */
- *p++ = 0;
- *p++ = 0;
- *p++ = 0;
-
- len -= 4;
- p += putname(p, len - (p-blob), windom, Bdomain);
- p += putname(p, len - (p-blob), "", Beof);
-
- *p++ = 0; /* 32bit: unknown data */
- *p++ = 0;
- *p++ = 0;
- *p++ = 0;
-
- return p - blob;
-}
-
static Auth *
auth_ntlmv2(char *windom, char *keyp, uchar *chal, int len)
{
- int i, n;
- Rune r;
- char *p, *u;
- uchar v1hash[MD5dlen], blip[Bliplen], blob[1024], v2hash[MD5dlen];
- uchar c, lm_hmac[MD5dlen], nt_hmac[MD5dlen], nt_sesskey[MD5dlen],
- lm_sesskey[MD5dlen];
- DigestState *ds;
- UserPasswd *up;
- static Auth *ap;
-
- up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs-ntlmv2 %s",
- windom, keyp);
- if(!up)
- sysfatal("cannot get key - %r");
-
- ap = emalloc9p(sizeof(Auth));
- memset(ap, 0, sizeof(ap));
-
- /* Standard says unlimited length, experience says 128 max */
- if((n = strlen(up->passwd)) > 128)
- n = 128;
-
- ds = md4(nil, 0, nil, nil);
- for(i=0, p=up->passwd; i < n; i++) {
- p += chartorune(&r, p);
- c = r;
- md4(&c, 1, nil, ds);
- c = r >> 8;
- md4(&c, 1, nil, ds);
- }
- md4(nil, 0, v1hash, ds);
-
- /*
- * 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_t64(nil, 0, v1hash, MD5dlen, nil, nil);
- u = up->user;
- while(*u){
- u += chartorune(&r, u);
- r = toupperrune(r);
- c = r;
- hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
- c = r >> 8;
- hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
- }
- u = windom;
-
- while(*u){
- u += chartorune(&r, u);
- c = r;
- hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
- c = r >> 8;
- hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
- }
- hmac_t64(nil, 0, v1hash, MD5dlen, v2hash, ds);
- ap->user = estrdup9p(up->user);
- ap->windom = estrdup9p(windom);
-
- /* LM v2 */
-
- genrandom(blip, Bliplen);
- ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil);
- hmac_t64(blip, Bliplen, v2hash, MD5dlen, lm_hmac, ds);
- ap->len[0] = MD5dlen+Bliplen;
- ap->resp[0] = emalloc9p(ap->len[0]);
- memcpy(ap->resp[0], lm_hmac, MD5dlen);
- memcpy(ap->resp[0]+MD5dlen, blip, Bliplen);
-
- /* LM v2 session key */
- hmac_t64(lm_hmac, MD5dlen, v2hash, MD5dlen, lm_sesskey, nil);
-
- /* LM v2 MAC key */
- ap->mackey[0] = emalloc9p(MACkeylen);
- memcpy(ap->mackey[0], lm_sesskey, MD5dlen);
- memcpy(ap->mackey[0]+MD5dlen, ap->resp[0], MACkeylen-MD5dlen);
-
- /* NTLM v2 */
- n = ntv2_blob(blob, sizeof blob, windom);
- ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil);
- hmac_t64(blob, n, v2hash, MD5dlen, nt_hmac, ds);
- ap->len[1] = MD5dlen+n;
- ap->resp[1] = emalloc9p(ap->len[1]);
- memcpy(ap->resp[1], nt_hmac, MD5dlen);
- memcpy(ap->resp[1]+MD5dlen, blob, n);
-
- /*
- * v2hash definitely OK by
- * the time we get here.
- */
- /* NTLM v2 session key */
- hmac_t64(nt_hmac, MD5dlen, v2hash, MD5dlen, nt_sesskey, nil);
-
- /* NTLM v2 MAC key */
- ap->mackey[1] = emalloc9p(MACkeylen);
- memcpy(ap->mackey[1], nt_sesskey, MD5dlen);
- memcpy(ap->mackey[1]+MD5dlen, ap->resp[1], MACkeylen-MD5dlen);
- free(up);
-
- return ap;
+ return auth_proto("mschap2", windom, keyp, chal, len);
}
struct {