new auth
This commit is contained in:
parent
0f8ec41b0a
commit
6e527fbc4d
44 changed files with 9955 additions and 0 deletions
315
src/cmd/auth/factotum/rpc.c
Normal file
315
src/cmd/auth/factotum/rpc.c
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
#include "std.h"
|
||||
#include "dat.h"
|
||||
|
||||
/*
|
||||
* Factotum RPC
|
||||
*
|
||||
* Must be paired write/read cycles on /mnt/factotum/rpc.
|
||||
* The format of a request is verb, single space, data.
|
||||
* Data format is verb-dependent; in particular, it can be binary.
|
||||
* The format of a response is the same. The write only sets up
|
||||
* the RPC. The read tries to execute it. If the /mnt/factotum/key
|
||||
* file is open, we ask for new keys using that instead of returning
|
||||
* an error in the RPC. This means the read blocks.
|
||||
* Textual arguments are parsed with tokenize, so rc-style quoting
|
||||
* rules apply.
|
||||
*
|
||||
* Only authentication protocol messages go here. Configuration
|
||||
* is still via ctl (below).
|
||||
*
|
||||
* Request RPCs are:
|
||||
* start attrs - initializes protocol for authentication, can fail.
|
||||
* returns "ok read" or "ok write" on success.
|
||||
* read - execute protocol read
|
||||
* write - execute protocol write
|
||||
* authinfo - if the protocol is finished, return the AI if any
|
||||
* attr - return protocol information
|
||||
* Return values are:
|
||||
* error message - an error happened.
|
||||
* ok [data] - success, possible data is request dependent.
|
||||
* needkey attrs - request aborted, get me this key and try again
|
||||
* badkey attrs - request aborted, this key might be bad
|
||||
* done [haveai] - authentication is done [haveai: you can get an ai with authinfo]
|
||||
*/
|
||||
|
||||
char *rpcname[] =
|
||||
{
|
||||
"unknown",
|
||||
"authinfo",
|
||||
"attr",
|
||||
"read",
|
||||
"start",
|
||||
"write",
|
||||
};
|
||||
|
||||
static int
|
||||
classify(char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=1; i<nelem(rpcname); i++)
|
||||
if(strcmp(s, rpcname[i]) == 0)
|
||||
return i;
|
||||
return RpcUnknown;
|
||||
}
|
||||
|
||||
int
|
||||
rpcwrite(Conv *c, void *data, int count)
|
||||
{
|
||||
int op;
|
||||
uchar *p;
|
||||
|
||||
if(count >= MaxRpc){
|
||||
werrstr("rpc too large");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* cancel any current rpc */
|
||||
c->rpc.op = RpcUnknown;
|
||||
c->nreply = 0;
|
||||
|
||||
/* parse new rpc */
|
||||
memmove(c->rpcbuf, data, count);
|
||||
c->rpcbuf[count] = 0;
|
||||
if(p = (uchar*)strchr((char*)c->rpcbuf, ' ')){
|
||||
*p++ = '\0';
|
||||
c->rpc.data = p;
|
||||
c->rpc.count = count - (p - (uchar*)c->rpcbuf);
|
||||
}else{
|
||||
c->rpc.data = "";
|
||||
c->rpc.count = 0;
|
||||
}
|
||||
op = classify(c->rpcbuf);
|
||||
if(op == RpcUnknown){
|
||||
werrstr("bad rpc verb: %s", c->rpcbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
c->rpc.op = op;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
convthread(void *v)
|
||||
{
|
||||
Conv *c;
|
||||
Attr *a;
|
||||
char *role, *proto;
|
||||
Proto *p;
|
||||
Role *r;
|
||||
|
||||
c = v;
|
||||
a = parseattr(c->rpc.data);
|
||||
if(a == nil){
|
||||
werrstr("empty attr");
|
||||
goto out;
|
||||
}
|
||||
c->attr = a;
|
||||
proto = strfindattr(a, "proto");
|
||||
role = strfindattr(a, "role");
|
||||
|
||||
if(proto == nil){
|
||||
werrstr("no proto in attrs");
|
||||
goto out;
|
||||
}
|
||||
if(role == nil){
|
||||
werrstr("no role in attrs");
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = protolookup(proto);
|
||||
if(p == nil){
|
||||
werrstr("unknown proto %s", proto);
|
||||
goto out;
|
||||
}
|
||||
|
||||
c->proto = p;
|
||||
for(r=p->roles; r->name; r++){
|
||||
if(strcmp(r->name, role) != 0)
|
||||
continue;
|
||||
rpcrespond(c, "ok");
|
||||
c->active = 1;
|
||||
if((*r->fn)(c) == 0){
|
||||
c->done = 1;
|
||||
werrstr("protocol finished");
|
||||
}else
|
||||
werrstr("%s %s %s: %r", p->name, r->name, c->state);
|
||||
goto out;
|
||||
}
|
||||
werrstr("unknown role");
|
||||
|
||||
out:
|
||||
c->active = 0;
|
||||
c->state = 0;
|
||||
rerrstr(c->err, sizeof c->err);
|
||||
rpcrespond(c, "error %r");
|
||||
convclose(c);
|
||||
}
|
||||
|
||||
static uchar* convAI2M(uchar *p, int n, char *cuid, char *suid, char *cap, char *hex);
|
||||
|
||||
void
|
||||
rpcexec(Conv *c)
|
||||
{
|
||||
uchar *p;
|
||||
|
||||
switch(c->rpc.op){
|
||||
case RpcRead:
|
||||
if(c->rpc.count > 0){
|
||||
rpcrespond(c, "error read takes no parameters");
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
if(!c->active){
|
||||
if(c->done)
|
||||
rpcrespond(c, "done");
|
||||
else
|
||||
rpcrespond(c, "error %s", c->err);
|
||||
break;
|
||||
}
|
||||
nbsendp(c->rpcwait, 0);
|
||||
break;
|
||||
case RpcUnknown:
|
||||
break;
|
||||
case RpcAuthinfo:
|
||||
/* deprecated */
|
||||
if(c->active)
|
||||
rpcrespond(c, "error conversation still active");
|
||||
else if(!c->done)
|
||||
rpcrespond(c, "error conversation not successful");
|
||||
else{
|
||||
/* make up an auth info using the attr */
|
||||
p = convAI2M((uchar*)c->reply+3, sizeof c->reply-3,
|
||||
strfindattr(c->attr, "cuid"),
|
||||
strfindattr(c->attr, "suid"),
|
||||
strfindattr(c->attr, "cap"),
|
||||
strfindattr(c->attr, "secret"));
|
||||
if(p == nil)
|
||||
rpcrespond(c, "error %r");
|
||||
else
|
||||
rpcrespondn(c, "ok", c->reply+3, p-(uchar*)(c->reply+3));
|
||||
}
|
||||
break;
|
||||
case RpcAttr:
|
||||
rpcrespond(c, "ok %A", c->attr);
|
||||
break;
|
||||
case RpcStart:
|
||||
convreset(c);
|
||||
c->ref++;
|
||||
threadcreate(convthread, c, STACK);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rpcrespond(Conv *c, char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
if(c->hangup)
|
||||
return;
|
||||
|
||||
if(fmt == nil)
|
||||
fmt = "";
|
||||
|
||||
va_start(arg, fmt);
|
||||
c->nreply = vsnprint(c->reply, sizeof c->reply, fmt, arg);
|
||||
va_end(arg);
|
||||
(*c->kickreply)(c);
|
||||
c->rpc.op = RpcUnknown;
|
||||
}
|
||||
|
||||
void
|
||||
rpcrespondn(Conv *c, char *verb, void *data, int count)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if(c->hangup)
|
||||
return;
|
||||
|
||||
if(strlen(verb)+1+count > sizeof c->reply){
|
||||
print("RPC response too large; caller %#lux", getcallerpc(&c));
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy(c->reply, verb);
|
||||
p = c->reply + strlen(c->reply);
|
||||
*p++ = ' ';
|
||||
memmove(p, data, count);
|
||||
c->nreply = count + (p - c->reply);
|
||||
(*c->kickreply)(c);
|
||||
c->rpc.op = RpcUnknown;
|
||||
}
|
||||
|
||||
/* deprecated */
|
||||
static uchar*
|
||||
pstring(uchar *p, uchar *e, char *s)
|
||||
{
|
||||
uint n;
|
||||
|
||||
if(p == nil)
|
||||
return nil;
|
||||
if(s == nil)
|
||||
s = "";
|
||||
n = strlen(s);
|
||||
if(p+n+BIT16SZ >= e)
|
||||
return nil;
|
||||
PBIT16(p, n);
|
||||
p += BIT16SZ;
|
||||
memmove(p, s, n);
|
||||
p += n;
|
||||
return p;
|
||||
}
|
||||
|
||||
static uchar*
|
||||
pcarray(uchar *p, uchar *e, uchar *s, uint n)
|
||||
{
|
||||
if(p == nil)
|
||||
return nil;
|
||||
if(s == nil){
|
||||
if(n > 0)
|
||||
sysfatal("pcarray");
|
||||
s = (uchar*)"";
|
||||
}
|
||||
if(p+n+BIT16SZ >= e)
|
||||
return nil;
|
||||
PBIT16(p, n);
|
||||
p += BIT16SZ;
|
||||
memmove(p, s, n);
|
||||
p += n;
|
||||
return p;
|
||||
}
|
||||
|
||||
static uchar*
|
||||
convAI2M(uchar *p, int n, char *cuid, char *suid, char *cap, char *hex)
|
||||
{
|
||||
uchar *e = p+n;
|
||||
uchar *secret;
|
||||
int nsecret;
|
||||
|
||||
if(cuid == nil)
|
||||
cuid = "";
|
||||
if(suid == nil)
|
||||
suid = "";
|
||||
if(cap == nil)
|
||||
cap = "";
|
||||
if(hex == nil)
|
||||
hex = "";
|
||||
nsecret = strlen(hex)/2;
|
||||
secret = emalloc(nsecret);
|
||||
if(hexparse(hex, secret, nsecret) < 0){
|
||||
werrstr("hexparse %s failed", hex); /* can't happen */
|
||||
free(secret);
|
||||
return nil;
|
||||
}
|
||||
p = pstring(p, e, cuid);
|
||||
p = pstring(p, e, suid);
|
||||
p = pstring(p, e, cap);
|
||||
p = pcarray(p, e, secret, nsecret);
|
||||
free(secret);
|
||||
if(p == nil)
|
||||
werrstr("authinfo too big");
|
||||
return p;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue