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);