new auth
This commit is contained in:
parent
0f8ec41b0a
commit
6e527fbc4d
44 changed files with 9955 additions and 0 deletions
353
src/cmd/auth/factotum/p9sk1.c
Normal file
353
src/cmd/auth/factotum/p9sk1.c
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
* p9sk1, p9sk2 - Plan 9 secret (private) key authentication.
|
||||
* p9sk2 is an incomplete flawed variant of p9sk1.
|
||||
*
|
||||
* Client protocol:
|
||||
* write challenge[challen] (p9sk1 only)
|
||||
* read tickreq[tickreqlen]
|
||||
* write ticket[ticketlen]
|
||||
* read authenticator[authentlen]
|
||||
*
|
||||
* Server protocol:
|
||||
* read challenge[challen] (p9sk1 only)
|
||||
* write tickreq[tickreqlen]
|
||||
* read ticket[ticketlen]
|
||||
* write authenticator[authentlen]
|
||||
*/
|
||||
|
||||
#include "std.h"
|
||||
#include "dat.h"
|
||||
|
||||
extern Proto p9sk1, p9sk2;
|
||||
static int gettickets(Ticketreq*, char*, Key*);
|
||||
|
||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||
enum
|
||||
{
|
||||
MAXAUTH = max(TICKREQLEN, TICKETLEN+max(TICKETLEN, AUTHENTLEN))
|
||||
};
|
||||
|
||||
static int
|
||||
p9skclient(Conv *c)
|
||||
{
|
||||
char *user;
|
||||
char cchal[CHALLEN];
|
||||
uchar secret[8];
|
||||
char buf[MAXAUTH];
|
||||
int speakfor, ret;
|
||||
Attr *a;
|
||||
Authenticator au;
|
||||
Key *k;
|
||||
Ticket t;
|
||||
Ticketreq tr;
|
||||
|
||||
ret = -1;
|
||||
a = nil;
|
||||
k = nil;
|
||||
|
||||
/* p9sk1: send client challenge */
|
||||
if(c->proto == &p9sk1){
|
||||
c->state = "write challenge";
|
||||
memrandom(cchal, CHALLEN);
|
||||
if(convwrite(c, cchal, CHALLEN) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* read ticket request */
|
||||
c->state = "read tickreq";
|
||||
if(convread(c, buf, TICKREQLEN) < 0)
|
||||
goto out;
|
||||
convM2TR(buf, &tr);
|
||||
|
||||
/* p9sk2: use server challenge as client challenge */
|
||||
if(c->proto == &p9sk2)
|
||||
memmove(cchal, tr.chal, CHALLEN);
|
||||
|
||||
/*
|
||||
* find a key.
|
||||
*
|
||||
* if the user is the factotum owner, any key will do.
|
||||
* if not, then if we have a speakfor key,
|
||||
* we will only vouch for the user's local identity.
|
||||
*
|
||||
* this logic is duplicated in p9any.c
|
||||
*/
|
||||
user = strfindattr(c->attr, "user");
|
||||
a = delattr(copyattr(c->attr), "role");
|
||||
a = addattr(a, "proto=p9sk1");
|
||||
|
||||
if(strcmp(c->sysuser, owner) == 0){
|
||||
speakfor = 0;
|
||||
a = addattr(a, "proto=p9sk1 user? dom=%q", tr.authdom);
|
||||
}else if(user==nil || strcmp(c->sysuser, user)==0){
|
||||
speakfor = 1;
|
||||
a = delattr(a, "user");
|
||||
a = addattr(a, "proto=p9sk1 user? dom=%q role=speakfor", tr.authdom);
|
||||
}else{
|
||||
werrstr("will not authenticate for %q as %q", c->sysuser, user);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for(;;){
|
||||
c->state = "find key";
|
||||
k = keyfetch(c, "%A", a);
|
||||
if(k == nil)
|
||||
goto out;
|
||||
|
||||
/* relay ticket request to auth server, get tickets */
|
||||
strcpy(tr.hostid, strfindattr(k->attr, "user"));
|
||||
if(speakfor)
|
||||
strcpy(tr.uid, c->sysuser);
|
||||
else
|
||||
strcpy(tr.uid, tr.hostid);
|
||||
|
||||
c->state = "get tickets";
|
||||
if(gettickets(&tr, buf, k) < 0)
|
||||
goto out;
|
||||
|
||||
convM2T(buf, &t, k->priv);
|
||||
if(t.num == AuthTc)
|
||||
break;
|
||||
|
||||
/* we don't agree with the auth server about the key; try again */
|
||||
c->state = "replace key";
|
||||
if((k = keyreplace(c, k, "key mismatch with auth server")) == nil){
|
||||
werrstr("key mismatch with auth server");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* send second ticket and authenticator to server */
|
||||
c->state = "write ticket+auth";
|
||||
memmove(buf, buf+TICKETLEN, TICKETLEN);
|
||||
au.num = AuthAc;
|
||||
memmove(au.chal, tr.chal, CHALLEN);
|
||||
au.id = 0;
|
||||
convA2M(&au, buf+TICKETLEN, t.key);
|
||||
if(convwrite(c, buf, TICKETLEN+AUTHENTLEN) < 0)
|
||||
goto out;
|
||||
|
||||
/* read authenticator from server */
|
||||
c->state = "read auth";
|
||||
if(convread(c, buf, AUTHENTLEN) < 0)
|
||||
goto out;
|
||||
convM2A(buf, &au, t.key);
|
||||
if(au.num != AuthAs || memcmp(au.chal, cchal, CHALLEN) != 0 || au.id != 0){
|
||||
werrstr("server lies through his teeth");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* success */
|
||||
c->attr = addcap(c->attr, c->sysuser, &t);
|
||||
des56to64((uchar*)t.key, secret);
|
||||
c->attr = addattr(c->attr, "secret=%.8H", secret);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
freeattr(a);
|
||||
keyclose(k);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
p9skserver(Conv *c)
|
||||
{
|
||||
char cchal[CHALLEN], buf[MAXAUTH];
|
||||
uchar secret[8];
|
||||
int ret;
|
||||
Attr *a;
|
||||
Authenticator au;
|
||||
Key *k;
|
||||
Ticketreq tr;
|
||||
Ticket t;
|
||||
|
||||
ret = -1;
|
||||
|
||||
a = addattr(copyattr(c->attr), "user? dom?");
|
||||
a = addattr(a, "user? dom? proto=p9sk1");
|
||||
if((k = keyfetch(c, "%A", a)) == nil)
|
||||
goto out;
|
||||
|
||||
/* p9sk1: read client challenge */
|
||||
if(c->proto == &p9sk1){
|
||||
if(convread(c, cchal, CHALLEN) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* send ticket request */
|
||||
memset(&tr, 0, sizeof tr);
|
||||
tr.type = AuthTreq;
|
||||
strcpy(tr.authid, strfindattr(k->attr, "user"));
|
||||
strcpy(tr.authdom, strfindattr(k->attr, "dom"));
|
||||
memrandom(tr.chal, sizeof tr.chal);
|
||||
convTR2M(&tr, buf);
|
||||
if(convwrite(c, buf, TICKREQLEN) < 0)
|
||||
goto out;
|
||||
|
||||
/* p9sk2: use server challenge as client challenge */
|
||||
if(c->proto == &p9sk2)
|
||||
memmove(cchal, tr.chal, sizeof tr.chal);
|
||||
|
||||
/* read ticket+authenticator */
|
||||
if(convread(c, buf, TICKETLEN+AUTHENTLEN) < 0)
|
||||
goto out;
|
||||
|
||||
convM2T(buf, &t, k->priv);
|
||||
if(t.num != AuthTs || memcmp(t.chal, tr.chal, CHALLEN) != 0){
|
||||
/* BUG badkey */
|
||||
werrstr("key mismatch with auth server");
|
||||
goto out;
|
||||
}
|
||||
|
||||
convM2A(buf+TICKETLEN, &au, t.key);
|
||||
if(au.num != AuthAc || memcmp(au.chal, tr.chal, CHALLEN) != 0 || au.id != 0){
|
||||
werrstr("client lies through his teeth");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* send authenticator */
|
||||
au.num = AuthAs;
|
||||
memmove(au.chal, cchal, CHALLEN);
|
||||
convA2M(&au, buf, t.key);
|
||||
if(convwrite(c, buf, AUTHENTLEN) < 0)
|
||||
goto out;
|
||||
|
||||
/* success */
|
||||
c->attr = addcap(c->attr, c->sysuser, &t);
|
||||
des56to64((uchar*)t.key, secret);
|
||||
c->attr = addattr(c->attr, "secret=%.8H", secret);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
freeattr(a);
|
||||
keyclose(k);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
_asgetticket(int fd, char *trbuf, char *tbuf)
|
||||
{
|
||||
if(write(fd, trbuf, TICKREQLEN) < 0){
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return _asrdresp(fd, tbuf, 2*TICKETLEN);
|
||||
}
|
||||
static int
|
||||
getastickets(Ticketreq *tr, char *buf)
|
||||
{
|
||||
int asfd;
|
||||
int ret;
|
||||
|
||||
if((asfd = xioauthdial(nil, tr->authdom)) < 0)
|
||||
return -1;
|
||||
convTR2M(tr, buf);
|
||||
ret = xioasgetticket(asfd, buf, buf);
|
||||
xioclose(asfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mktickets(Ticketreq *tr, char *buf, Key *k)
|
||||
{
|
||||
Ticket t;
|
||||
|
||||
if(strcmp(tr->authid, tr->hostid) != 0)
|
||||
return -1;
|
||||
|
||||
memset(&t, 0, sizeof t);
|
||||
memmove(t.chal, tr->chal, CHALLEN);
|
||||
strcpy(t.cuid, tr->uid);
|
||||
strcpy(t.suid, tr->uid);
|
||||
memrandom(t.key, DESKEYLEN);
|
||||
t.num = AuthTc;
|
||||
convT2M(&t, buf, k->priv);
|
||||
t.num = AuthTs;
|
||||
convT2M(&t, buf+TICKETLEN, k->priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gettickets(Ticketreq *tr, char *buf, Key *k)
|
||||
{
|
||||
if(getastickets(tr, buf) == 0)
|
||||
return 0;
|
||||
if(mktickets(tr, buf, k) == 0)
|
||||
return 0;
|
||||
werrstr("gettickets: %r");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
p9sk1check(Key *k)
|
||||
{
|
||||
char *user, *dom, *pass;
|
||||
Ticketreq tr;
|
||||
|
||||
user = strfindattr(k->attr, "user");
|
||||
dom = strfindattr(k->attr, "dom");
|
||||
if(user==nil || dom==nil){
|
||||
werrstr("need user and dom attributes");
|
||||
return -1;
|
||||
}
|
||||
if(strlen(user) >= sizeof tr.authid){
|
||||
werrstr("user name too long");
|
||||
return -1;
|
||||
}
|
||||
if(strlen(dom) >= sizeof tr.authdom){
|
||||
werrstr("auth dom name too long");
|
||||
return -1;
|
||||
}
|
||||
|
||||
k->priv = emalloc(DESKEYLEN);
|
||||
if(pass = strfindattr(k->privattr, "!password"))
|
||||
passtokey(k->priv, pass);
|
||||
else if(pass = strfindattr(k->privattr, "!hex")){
|
||||
if(hexparse(pass, k->priv, 7) < 0){
|
||||
werrstr("malformed !hex key data");
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
werrstr("need !password or !hex attribute");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
p9sk1close(Key *k)
|
||||
{
|
||||
free(k->priv);
|
||||
k->priv = nil;
|
||||
}
|
||||
|
||||
static Role
|
||||
p9sk1roles[] =
|
||||
{
|
||||
"client", p9skclient,
|
||||
"server", p9skserver,
|
||||
0
|
||||
};
|
||||
|
||||
static Role
|
||||
p9sk2roles[] =
|
||||
{
|
||||
"client", p9skclient,
|
||||
"server", p9skserver,
|
||||
0
|
||||
};
|
||||
|
||||
Proto p9sk1 = {
|
||||
.name= "p9sk1",
|
||||
.roles= p9sk1roles,
|
||||
.checkkey= p9sk1check,
|
||||
.closekey= p9sk1close,
|
||||
.keyprompt= "user? dom? !password?",
|
||||
};
|
||||
|
||||
Proto p9sk2 = {
|
||||
.name= "p9sk2",
|
||||
.roles= p9sk2roles,
|
||||
};
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue