shithub: riscv

Download patch

ref: 3ef51c16d4bb22371f198f5a336e14503a3ebafa
parent: e614cdf02fc49cc11a3adca160d9a8cfe9b8acf8
author: cinap_lenrek <[email protected]>
date: Sun Dec 3 00:10:04 EST 2017

auth/factotum: add role=login protocol variant to dp9ik/p9sk1

the role=login protocol is ment to replace proto=p9cr in
auth_userpasswd() from libauth to authenticate a user
given a username and a password. in contrast to p9cr, it
does not require an authentication server when user is the
hostowner and its key is present in factotum.

--- a/sys/src/cmd/auth/factotum/p9sk1.c
+++ b/sys/src/cmd/auth/factotum/p9sk1.c
@@ -19,6 +19,10 @@
  *	 write tickreq[tickreqlen]		(p9sk1 only)
  *	read ticket + authenticator
  *	write authenticator
+ *
+ * Login protocol:
+ *	write user
+ *	write password
  */
 
 #include "dat.h"
@@ -55,6 +59,10 @@
 	 SHaveTreq,	/* p9sk1 only */
 	SNeedTicket,
 	SHaveAuth,
+
+	/* login phases */
+	SNeedUser,
+	SNeedPass,
 	
 	Maxphase,
 };
@@ -74,9 +82,12 @@
 [SHaveTreq]		"SHaveTreq",
 [SNeedTicket]		"SNeedTicket",
 [SHaveAuth]		"SHaveAuth",
+
+[SNeedUser]		"SNeedUser",
+[SNeedPass]		"SNeedPass",
 };
 
-static int gettickets(State*, Ticketreq*, uchar*, char*, int);
+static int gettickets(State*, uchar*, char*, int);
 
 static int
 p9skinit(Proto *p, Fsstate *fss)
@@ -86,8 +97,12 @@
 	Key *k;
 	Keyinfo ki;
 	Attr *attr;
+	char *role;
 
-	if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
+	role = _strfindattr(fss->attr, "role");
+	if(role != nil && strcmp(role, "login") == 0)
+		iscli = 0;
+	else if((iscli = isclient(role)) < 0)
 		return failure(fss, nil);
 
 	s = emalloc(sizeof *s);
@@ -99,8 +114,13 @@
 		fss->phase = CHaveChal;
 		genrandom((uchar*)s->cchal, CHALLEN);
 	}else{
+		fss->phase = SNeedChal;
 		s->tr.type = AuthTreq;
 		attr = setattr(_copyattr(fss->attr), "proto=%q", p->name);
+		if(strcmp(role, "login") == 0){
+			attr = setattr(attr, "role=server");
+			fss->phase = SNeedUser;
+		}
 		mkkeyinfo(&ki, fss, attr);
 		ki.user = nil;
 		ret = findkey(&k, &ki, "user? dom?");
@@ -114,7 +134,6 @@
 		s->key = k;
 		memmove(&s->k, k->priv, sizeof(Authkey));
 		genrandom((uchar*)s->tr.chal, sizeof s->tr.chal);
-		fss->phase = SNeedChal;
 	}
 	s->tbuflen = 0;
 	s->secret = nil;
@@ -317,10 +336,11 @@
 			safecpy(s->tr.uid, s->tr.hostid, sizeof s->tr.uid);
 
 		/* get tickets from authserver or invent if we can */
+		memmove(&s->k, s->key->priv, sizeof(Authkey));
 		if(fss->phase == CNeedPAKreq)
-			ret = gettickets(s, &s->tr, (uchar*)a + m, tbuf, sizeof(tbuf));
+			ret = gettickets(s, (uchar*)a + m, tbuf, sizeof(tbuf));
 		else
-			ret = gettickets(s, &s->tr, nil, tbuf, sizeof(tbuf));
+			ret = gettickets(s, nil, tbuf, sizeof(tbuf));
 		if(ret <= 0){
 			_freeattr(attr);
 			return failure(fss, nil);
@@ -398,6 +418,73 @@
 			return failure(fss, Easproto);
 		memmove(s->rand+NONCELEN, auth.rand, NONCELEN);
 		return establish(fss);
+
+	case SNeedUser:
+		if(n >= sizeof(s->tr.hostid))
+			return failure(fss, "user id too long");
+		strncpy(s->tr.hostid, a, n);
+		s->tr.hostid[n] = 0;
+		strncpy(s->tr.uid, a, n);
+		s->tr.uid[n] = 0;
+		fss->phase = SNeedPass;
+		return RpcOk;
+
+	case SNeedPass:
+		{
+			Authkey ks;
+			uchar tk[NONCELEN];
+			char pass[PASSWDLEN];
+
+			if(n >= sizeof(pass))
+				return failure(fss, "password too long");
+
+			/* save server key */
+			memmove(&ks, &s->k, sizeof(ks));
+
+			/* derive client key */
+			strncpy(pass, a, n);
+			pass[n] = 0;
+			passtokey(&s->k, pass);
+			memset(pass, 0, sizeof(pass));
+
+			if(fss->proto == &dp9ik){
+				uchar ys[PAKYLEN];
+				PAKpriv ps;
+
+				authpak_hash(&s->k, s->tr.hostid);
+
+				authpak_new(&ps, &ks, ys, 1);
+				ret = gettickets(s, ys, tbuf, sizeof(tbuf));
+				if(ret > 0 && authpak_finish(&ps, &ks, s->y))
+					return failure(fss, Easproto);
+			} else {
+				ret = gettickets(s, nil, tbuf, sizeof(tbuf));
+			}
+			if(ret <= 0)
+				return failure(fss, nil);
+
+			/* verify client ticket */
+			m = convM2T(tbuf, ret, &s->t, &s->k);
+			if(m <= 0 || (fss->proto == &dp9ik && s->t.form == 0))
+				return failure(fss, Easproto);
+			if(s->t.num != AuthTc || tsmemcmp(s->t.chal, s->tr.chal, CHALLEN) != 0)
+				return failure(fss, Ebadkey);
+			memmove(tk, s->t.key, sizeof(tk));
+
+			/* restore sever key */
+			memmove(&s->k, &ks, sizeof(ks));
+
+			/* verify server ticket */
+			m = convM2T(tbuf+m, ret-m, &s->t, &s->k);
+			if(m <= 0 || (fss->proto == &dp9ik && s->t.form == 0))
+				return failure(fss, Easproto);
+			if(s->t.num != AuthTs || tsmemcmp(s->t.chal, s->tr.chal, CHALLEN) != 0
+			|| tsmemcmp(tk, s->t.key, sizeof(tk)) != 0)
+				return failure(fss, Ebadkey);
+
+		}
+		genrandom(s->rand, 2*NONCELEN);
+		return establish(fss);
 	}
 }
 
@@ -530,9 +617,10 @@
 }
 
 static int
-getastickets(State *s, Ticketreq *tr, uchar *y, char *tbuf, int tbuflen)
+getastickets(State *s, uchar *y, char *tbuf, int tbuflen)
 {
-	int asfd, rv;
+	Ticketreq *tr = &s->tr;
+ 	int asfd, rv;
 	char *dom;
 
 	if((dom = _strfindattr(s->key->attr, "dom")) == nil){
@@ -569,19 +657,18 @@
 }
 
 static int
-gettickets(State *s, Ticketreq *tr, uchar *y, char *tbuf, int tbuflen)
+gettickets(State *s, uchar *y, char *tbuf, int tbuflen)
 {
 	int ret;
 
-	if(tr->authdom[0] == 0
-	|| tr->authid[0] == 0
-	|| tr->hostid[0] == 0
-	|| tr->uid[0] == 0){
+	if(s->tr.authdom[0] == 0
+	|| s->tr.authid[0] == 0
+	|| s->tr.hostid[0] == 0
+	|| s->tr.uid[0] == 0){
 		werrstr("bad ticket request");
 		return -1;
 	}
-	memmove(&s->k, s->key->priv, sizeof(Authkey));
-	ret = getastickets(s, tr, y, tbuf, tbuflen);
+	ret = getastickets(s, y, tbuf, tbuflen);
 	if(ret > 0)
 		return ret;
 	return mkservertickets(s, y, tbuf, tbuflen);