shithub: riscv

Download patch

ref: 6e19d19285dddcd3c8f2a6b031fc0f0324b3e48b
parent: 40f6e00b9c4b0f5bdca1cc7caf27af23a6b10786
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun May 20 18:49:24 EDT 2018

separate MSCHAP(v2) and NTLM(v2) authentication

due to linux omiting the final Z(4) in the NTLMv2 reply, and
the need for the windom for LMv2 authentication, here is a new
AuthNTLM ticket request now with length and dom fields.

--- a/sys/include/auth.h
+++ b/sys/include/auth.h
@@ -53,6 +53,7 @@
 struct Chalstate
 {
 	char	*user;
+	char	*dom;
 	char	chal[MAXCHLEN];
 	int	nchal;
 	void	*resp;
@@ -71,7 +72,7 @@
 	char	resp[MD5LEN];
 };
 
-struct	MSchapreply	/* for protocol "mschap" */
+struct	MSchapreply		/* for protocol "mschap" and "ntlm" */
 {
 	char	LMresp[24];		/* Lan Manager response */
 	char	NTresp[24];		/* NT response */
--- a/sys/include/authsrv.h
+++ b/sys/include/authsrv.h
@@ -11,6 +11,7 @@
 typedef struct	Passwordreq	Passwordreq;
 typedef struct	OChapreply	OChapreply;
 typedef struct	OMSchapreply	OMSchapreply;
+typedef struct	NTLMreply	NTLMreply;
 
 typedef struct	Authkey		Authkey;
 
@@ -62,6 +63,7 @@
 	AuthVNC=14,	/* VNC server login (deprecated) */
 	AuthPAK=19,	/* authenticated diffie hellman key agreement */
 	AuthMSchapv2=21,/* MS chap v2 authentication for ppp */
+	AuthNTLM=22,	/* NTLM authentication for cifs */
 	AuthTs=64,	/* ticket encrypted with server's key */
 	AuthTc,		/* ticket encrypted with client's key */
 	AuthAs,		/* server generated authenticator */
@@ -126,6 +128,16 @@
 	char	NTresp[24];		/* NT response */
 };
 #define OMSCHAPREPLYLEN	(ANAMELEN+24+24)
+
+struct	NTLMreply
+{
+	uchar	len[2];			/* size of structure (lsb first) */
+	char	uid[ANAMELEN];
+	char	dom[DOMLEN];
+	char	LMresp[24];		/* Lan Manager response */
+	char	NTresp[24];		/* NT response (variable length) */
+};
+#define NTLMREPLYLEN	(2+ANAMELEN+DOMLEN+24+24)
 
 struct	Authkey
 {
--- a/sys/src/cmd/auth/factotum/chap.c
+++ b/sys/src/cmd/auth/factotum/chap.c
@@ -10,6 +10,7 @@
  * Server protocol:
  *	read challenge: 8 bytes binary (or 16 bytes for mschapv2)
  *	write user: utf8
+ *	write dom: utf8 (ntlm)
  *	write response: Chapreply or MSchapreply structure
  *	... retry another user
  */
@@ -36,7 +37,7 @@
 static int doreply(State *s, uchar *reply, int nreply);
 static int dochap(char *passwd, int id, char chal[ChapChallen], uchar *resp, int resplen);
 static int domschap(char *passwd, uchar chal[MSchallen], uchar *resp, int resplen);
-static int domschap2(char *passwd, char *user, char *dom, uchar chal[MSchallen], uchar *resp, int resplen);
+static int dontlmv2(char *passwd, char *user, char *dom, uchar chal[MSchallen], uchar *resp, int resplen);
 static void nthash(uchar hash[MShashlen], char *passwd);
 
 struct State
@@ -53,6 +54,7 @@
 	uchar resp[4096];
 	char err[ERRMAX];
 	char user[64];
+	char dom[DOMLEN];
 	uchar secret[16+20];	/* for mschap: MPPE Master secret + authenticator (v2) */
 	int nsecret;
 };
@@ -64,6 +66,7 @@
 
 	SHaveChal,
 	SNeedUser,
+	SNeedDom,
 	SNeedResp,
 
 	Maxphase
@@ -76,6 +79,7 @@
 
 [SHaveChal]	"SHaveChal",
 [SNeedUser]	"SNeedUser",
+[SNeedDom]	"SNeedDom",
 [SNeedResp]	"SNeedResp",
 };
 
@@ -98,14 +102,15 @@
 	if(p == &mschapv2) {
 		s->nchal = MSchallenv2;
 		s->astype = AuthMSchapv2;
+	} else if(p == &mschap){
+		s->nchal = MSchallen;
+		s->astype = AuthMSchap;
+	} else if(p == &ntlm || p == &ntlmv2){
+		s->nchal = MSchallen;
+		s->astype = AuthNTLM;
 	} else {
-		if(p == &mschap || p == &mschap2){
-			s->nchal = MSchallen;
-			s->astype = AuthMSchap;
-		}else {
-			s->nchal = ChapChallen;
-			s->astype = AuthChap;
-		}
+		s->nchal = ChapChallen;
+		s->astype = AuthChap;
 	}
 	if(iscli)
 		fss->phase = CNeedChal;
@@ -150,6 +155,7 @@
 	MSchapreply *mcr;
 	OChapreply *ocr;
 	OMSchapreply *omcr;
+	NTLMreply *ntcr;
 	uchar pchal[MSchallenv2];
 	uchar digest[SHA1dlen];
 	uchar reply[4096];
@@ -177,10 +183,10 @@
 		memset(s->resp, 0, sizeof(s->resp));
 		setattrs(fss->attr, k->attr);
 		switch(s->astype){
-		case AuthMSchap:
+		case AuthNTLM:
 			if(n < MSchallen)
 				break;
-			if(fss->proto == &mschap2){
+			if(fss->proto == &ntlmv2){
 				user = _strfindattr(fss->attr, "user");
 				if(user == nil)
 					break;
@@ -187,10 +193,15 @@
 				dom = _strfindattr(fss->attr, "windom");
 				if(dom == nil)
 					dom = "";
-				s->nresp = domschap2(pass, user, dom, (uchar*)a, s->resp, sizeof(s->resp));
+				s->nresp = dontlmv2(pass, user, dom, (uchar*)a, s->resp, sizeof(s->resp));
 			} else {
 				s->nresp = domschap(pass, (uchar*)a, s->resp, sizeof(s->resp));
 			}
+			break;
+		case AuthMSchap:
+			if(n < MSchallen)
+				break;
+			s->nresp = domschap(pass, (uchar*)a, s->resp, sizeof(s->resp));
 			nthash(digest, pass);
 			md4(digest, 16, digest, nil);
 			ds = sha1(digest, 16, nil, nil);
@@ -253,6 +264,14 @@
 			return failure(fss, "user name too long");
 		memmove(s->user, va, n);
 		s->user[n] = '\0';
+		fss->phase = (s->astype == AuthNTLM)? SNeedDom: SNeedResp;
+		return RpcOk;
+
+	case SNeedDom:
+		if(n >= sizeof s->dom)
+			return failure(fss, "domain name too long");
+		memmove(s->dom, va, n);
+		s->dom[n] = '\0';
 		fss->phase = SNeedResp;
 		return RpcOk;
 
@@ -275,16 +294,30 @@
 		case AuthMSchapv2:
 			if(n < MSchapreplylen)
 				return failure(fss, "did not get MSchapreply");
-			if(n > sizeof(reply)+MSchapreplylen-OMSCHAPREPLYLEN)
-				return failure(fss, "MSchapreply too long");
 			mcr = (MSchapreply*)va;
-			nreply = n+OMSCHAPREPLYLEN-MSchapreplylen;
+			nreply = OMSCHAPREPLYLEN;
 			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)-MSchapreplylen);
+			memmove(omcr->NTresp, mcr->NTresp, sizeof(mcr->NTresp));
 			break;
+		case AuthNTLM:
+			if(n < MSchapreplylen)
+				return failure(fss, "did not get MSchapreply");
+			if(n > sizeof(reply)+MSchapreplylen-NTLMREPLYLEN)
+				return failure(fss, "MSchapreply too long");
+			mcr = (MSchapreply*)va;
+			nreply = n+NTLMREPLYLEN-MSchapreplylen;
+			memset(reply, 0, nreply);
+			ntcr = (NTLMreply*)reply;
+			ntcr->len[0] = nreply;
+			ntcr->len[1] = nreply>>8;
+			strecpy(ntcr->uid, ntcr->uid+sizeof(ntcr->uid), s->user);
+			strecpy(ntcr->dom, ntcr->dom+sizeof(ntcr->dom), s->dom);
+			memmove(ntcr->LMresp, mcr->LMresp, sizeof(ntcr->LMresp));
+			memmove(ntcr->NTresp, mcr->NTresp, n+sizeof(mcr->NTresp)-MSchapreplylen);
+			break;
 		}
 		if(doreply(s, reply, nreply) < 0){
 			fss->phase = SNeedUser;
@@ -402,12 +435,12 @@
 		werrstr(Easproto);
 		return -1;
 	}
-	s->key->successes++;
 	if(a.num != AuthAc
 	|| tsmemcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0){
 		werrstr(Easproto);
 		return -1;
 	}
+	s->key->successes++;
 	s->nsecret = 0;
 	if(s->t.form != 0){
 		if(s->astype == AuthMSchap || s->astype == AuthMSchapv2){
@@ -457,13 +490,23 @@
 .keyprompt= "user? !password?"
 };
 
-Proto mschap2 = {
-.name=	"mschap2",	/* really NTLMv2 */
+Proto ntlm = {
+.name=	"ntlm",
 .init=	chapinit,
 .write=	chapwrite,
 .read=	chapread,
 .close=	chapclose,
 .addkey= replacekey,
+.keyprompt= "user? !password?"
+};
+
+Proto ntlmv2 = {
+.name=	"ntlmv2",
+.init=	chapinit,
+.write=	chapwrite,
+.read=	chapread,
+.close=	chapclose,
+.addkey= replacekey,
 .keyprompt= "user? windom? !password?"
 };
 
@@ -582,7 +625,7 @@
 }
 
 static int
-domschap2(char *passwd, char *user, char *dom, uchar chal[MSchallen], uchar *resp, int resplen)
+dontlmv2(char *passwd, char *user, char *dom, uchar chal[MSchallen], uchar *resp, int resplen)
 {
 	uchar hash[MShashlen], *p, *e;
 	MSchapreply *r;
--- a/sys/src/cmd/auth/factotum/dat.h
+++ b/sys/src/cmd/auth/factotum/dat.h
@@ -221,7 +221,7 @@
 /* protocols */
 extern Proto apop, cram;		/* apop.c */
 extern Proto p9any, p9sk1, dp9ik;	/* p9sk.c */
-extern Proto chap, mschap, mschapv2, mschap2;	/* chap.c */
+extern Proto chap, mschap, mschapv2, ntlm, ntlmv2;	/* chap.c */
 extern Proto p9cr, vnc;			/* p9cr.c */
 extern Proto pass;			/* pass.c */
 extern Proto rsa;			/* rsa.c */
--- a/sys/src/cmd/auth/factotum/fs.c
+++ b/sys/src/cmd/auth/factotum/fs.c
@@ -32,7 +32,8 @@
 	&httpdigest,
 	&mschap,
 	&mschapv2,
-	&mschap2,
+	&ntlm,
+	&ntlmv2,
 	&p9any,
 	&p9cr,
 	&p9sk1,
--- a/sys/src/cmd/cifs/auth.c
+++ b/sys/src/cmd/cifs/auth.c
@@ -78,8 +78,6 @@
 
 	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);
@@ -109,7 +107,7 @@
 static Auth *
 auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len)
 {
-	return auth_proto("mschap", windom, keyp, chal, len);
+	return auth_proto("ntlm", windom, keyp, chal, len);
 }
 
 /*
@@ -136,7 +134,7 @@
 static Auth *
 auth_ntlmv2(char *windom, char *keyp, uchar *chal, int len)
 {
-	return auth_proto("mschap2", windom, keyp, chal, len);
+	return auth_proto("ntlmv2", windom, keyp, chal, len);
 }
 
 struct {
--- a/sys/src/cmd/ip/cifsd/smb.c
+++ b/sys/src/cmd/ip/cifsd/smb.c
@@ -46,7 +46,7 @@
 	if(needauth){
 		if(smbcs != nil)
 			auth_freechal(smbcs);
-		if(smbcs = auth_challenge("proto=mschap role=server")){
+		if(smbcs = auth_challenge("proto=ntlm role=server")){
 			c = (uchar*)smbcs->chal;
 			ce = c + smbcs->nchal;
 			mode = NEGOTIATE_USER_SECURITY | NEGOTIATE_ENCRYPT_PASSWORDS;
@@ -104,6 +104,7 @@
 			if(smbcs == nil || strlen(user) == 0)
 				break;
 			smbcs->user = user;
+			smbcs->dom = dom;
 			smbcs->nresp = (nte - nt)+sizeof(*mcr)-sizeof(mcr->NTresp);
 			if(smbcs->nresp < sizeof(*mcr))
 				smbcs->nresp = sizeof(*mcr);
--- a/sys/src/libauth/auth_challenge.c
+++ b/sys/src/libauth/auth_challenge.c
@@ -74,6 +74,15 @@
 			goto Out;
 		}
 	}
+	if(c->dom){
+		if(auth_rpc(c->rpc, "write", c->dom, strlen(c->dom)) != ARok){
+			/*
+			 * if this fails we're out of phase with factotum.
+			 * give up.
+			 */
+			goto Out;
+		}
+	}
 
 	if(auth_rpc(c->rpc, "write", c->resp, c->nresp) != ARok){
 		/*