new auth
This commit is contained in:
parent
0f8ec41b0a
commit
6e527fbc4d
44 changed files with 9955 additions and 0 deletions
531
src/cmd/auth/factotum/fs.c
Normal file
531
src/cmd/auth/factotum/fs.c
Normal file
|
|
@ -0,0 +1,531 @@
|
|||
#include "std.h"
|
||||
#include "dat.h"
|
||||
|
||||
enum
|
||||
{
|
||||
Qroot,
|
||||
Qfactotum,
|
||||
Qrpc,
|
||||
Qkeylist,
|
||||
Qprotolist,
|
||||
Qconfirm,
|
||||
Qlog,
|
||||
Qctl,
|
||||
Qneedkey,
|
||||
Qconv,
|
||||
};
|
||||
|
||||
static int qtop;
|
||||
|
||||
Qid
|
||||
mkqid(int type, int path)
|
||||
{
|
||||
Qid q;
|
||||
|
||||
q.type = type;
|
||||
q.path = path;
|
||||
q.vers = 0;
|
||||
return q;
|
||||
}
|
||||
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
int qidpath;
|
||||
ulong perm;
|
||||
} dirtab[] = {
|
||||
/* positions of confirm and needkey known below */
|
||||
"confirm", Qconfirm, 0600|DMEXCL,
|
||||
"needkey", Qneedkey, 0600|DMEXCL,
|
||||
"ctl", Qctl, 0600,
|
||||
"rpc", Qrpc, 0666,
|
||||
"proto", Qprotolist, 0444,
|
||||
"log", Qlog, 0600|DMEXCL,
|
||||
"conv", Qconv, 0400,
|
||||
};
|
||||
|
||||
static void
|
||||
fillstat(Dir *dir, char *name, int type, int path, ulong perm)
|
||||
{
|
||||
dir->name = estrdup(name);
|
||||
dir->uid = estrdup(owner);
|
||||
dir->gid = estrdup(owner);
|
||||
dir->mode = perm;
|
||||
dir->length = 0;
|
||||
dir->qid = mkqid(type, path);
|
||||
dir->atime = time(0);
|
||||
dir->mtime = time(0);
|
||||
dir->muid = estrdup("");
|
||||
}
|
||||
|
||||
static int
|
||||
rootdirgen(int n, Dir *dir, void *v)
|
||||
{
|
||||
USED(v);
|
||||
|
||||
if(n > 0)
|
||||
return -1;
|
||||
|
||||
fillstat(dir, factname, QTDIR, Qfactotum, DMDIR|0555);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fsdirgen(int n, Dir *dir, void *v)
|
||||
{
|
||||
USED(v);
|
||||
|
||||
if(n >= nelem(dirtab))
|
||||
return -1;
|
||||
fillstat(dir, dirtab[n].name, 0, dirtab[n].qidpath, dirtab[n].perm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char*
|
||||
fswalk1(Fid *fid, char *name, Qid *qid)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch((int)fid->qid.path){
|
||||
default:
|
||||
return "fswalk1: cannot happen";
|
||||
case Qroot:
|
||||
if(strcmp(name, factname) == 0){
|
||||
*qid = mkqid(QTDIR, Qfactotum);
|
||||
fid->qid = *qid;
|
||||
return nil;
|
||||
}
|
||||
if(strcmp(name, "..") == 0){
|
||||
*qid = fid->qid;
|
||||
return nil;
|
||||
}
|
||||
return "not found";
|
||||
case Qfactotum:
|
||||
for(i=0; i<nelem(dirtab); i++)
|
||||
if(strcmp(name, dirtab[i].name) == 0){
|
||||
*qid = mkqid(0, dirtab[i].qidpath);
|
||||
fid->qid = *qid;
|
||||
return nil;
|
||||
}
|
||||
if(strcmp(name, "..") == 0){
|
||||
*qid = mkqid(QTDIR, qtop);
|
||||
fid->qid = *qid;
|
||||
return nil;
|
||||
}
|
||||
return "not found";
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fsstat(Req *r)
|
||||
{
|
||||
int i, path;
|
||||
|
||||
path = r->fid->qid.path;
|
||||
switch(path){
|
||||
case Qroot:
|
||||
fillstat(&r->d, "/", QTDIR, Qroot, 0555|DMDIR);
|
||||
break;
|
||||
case Qfactotum:
|
||||
fillstat(&r->d, "factotum", QTDIR, Qfactotum, 0555|DMDIR);
|
||||
break;
|
||||
default:
|
||||
for(i=0; i<nelem(dirtab); i++)
|
||||
if(dirtab[i].qidpath == path){
|
||||
fillstat(&r->d, dirtab[i].name, 0, dirtab[i].qidpath, dirtab[i].perm);
|
||||
goto Break2;
|
||||
}
|
||||
respond(r, "file not found");
|
||||
break;
|
||||
}
|
||||
Break2:
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
static int
|
||||
readlist(int off, int (*gen)(int, char*, uint), Req *r)
|
||||
{
|
||||
char *a, *ea;
|
||||
int n;
|
||||
|
||||
a = r->ofcall.data;
|
||||
ea = a+r->ifcall.count;
|
||||
for(;;){
|
||||
n = (*gen)(off, a, ea-a);
|
||||
if(n == 0){
|
||||
r->ofcall.count = a - (char*)r->ofcall.data;
|
||||
return off;
|
||||
}
|
||||
a += n;
|
||||
off++;
|
||||
}
|
||||
return -1; /* not reached */
|
||||
}
|
||||
|
||||
static int
|
||||
keylist(int i, char *a, uint nn)
|
||||
{
|
||||
int n;
|
||||
char buf[512];
|
||||
Key *k;
|
||||
|
||||
if(i >= ring.nkey)
|
||||
return 0;
|
||||
|
||||
k = ring.key[i];
|
||||
k->attr = sortattr(k->attr);
|
||||
n = snprint(buf, sizeof buf, "key %A %N\n", k->attr, k->privattr);
|
||||
if(n >= sizeof(buf)-5)
|
||||
strcpy(buf+sizeof(buf)-5, "...\n");
|
||||
n = strlen(buf);
|
||||
if(n > nn)
|
||||
return 0;
|
||||
memmove(a, buf, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
protolist(int i, char *a, uint n)
|
||||
{
|
||||
if(prototab[i] == nil)
|
||||
return 0;
|
||||
if(strlen(prototab[i]->name)+1 > n)
|
||||
return 0;
|
||||
n = strlen(prototab[i]->name)+1;
|
||||
memmove(a, prototab[i]->name, n-1);
|
||||
a[n-1] = '\n';
|
||||
return n;
|
||||
}
|
||||
|
||||
/* BUG this is O(n^2) to fill in the list */
|
||||
static int
|
||||
convlist(int i, char *a, uint nn)
|
||||
{
|
||||
Conv *c;
|
||||
char buf[512];
|
||||
int n;
|
||||
|
||||
for(c=conv; c && i-- > 0; c=c->next)
|
||||
;
|
||||
|
||||
if(c == nil)
|
||||
return 0;
|
||||
|
||||
if(c->state)
|
||||
n = snprint(buf, sizeof buf, "conv state=%q %A\n", c->state, c->attr);
|
||||
else
|
||||
n = snprint(buf, sizeof buf, "conv state=closed err=%q\n", c->err);
|
||||
|
||||
if(n >= sizeof(buf)-5)
|
||||
strcpy(buf+sizeof(buf)-5, "...\n");
|
||||
n = strlen(buf);
|
||||
if(n > nn)
|
||||
return 0;
|
||||
memmove(a, buf, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
fskickreply(Conv *c)
|
||||
{
|
||||
Req *r;
|
||||
|
||||
if(c->hangup){
|
||||
if(c->req){
|
||||
respond(c->req, "hangup");
|
||||
c->req = nil;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!c->req || !c->nreply)
|
||||
return;
|
||||
|
||||
r = c->req;
|
||||
r->ofcall.count = c->nreply;
|
||||
r->ofcall.data = c->reply;
|
||||
if(r->ofcall.count > r->ifcall.count)
|
||||
r->ofcall.count = r->ifcall.count;
|
||||
respond(r, nil);
|
||||
c->req = nil;
|
||||
c->nreply = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some of the file system work happens in the fs proc, but
|
||||
* fsopen, fsread, fswrite, fsdestroyfid, and fsflush happen in
|
||||
* the main proc so that they can access the various shared
|
||||
* data structures without worrying about locking.
|
||||
*/
|
||||
static int inuse[nelem(dirtab)];
|
||||
int *confirminuse = &inuse[0];
|
||||
int *needkeyinuse = &inuse[1];
|
||||
static void
|
||||
fsopen(Req *r)
|
||||
{
|
||||
int i, *inusep, perm;
|
||||
static int need[4] = { 4, 2, 6, 1 };
|
||||
Conv *c;
|
||||
|
||||
inusep = nil;
|
||||
perm = 5; /* directory */
|
||||
for(i=0; i<nelem(dirtab); i++)
|
||||
if(dirtab[i].qidpath == r->fid->qid.path){
|
||||
if(dirtab[i].perm & DMEXCL)
|
||||
inusep = &inuse[i];
|
||||
if(strcmp(r->fid->uid, owner) == 0)
|
||||
perm = dirtab[i].perm>>6;
|
||||
else
|
||||
perm = dirtab[i].perm;
|
||||
break;
|
||||
}
|
||||
|
||||
if((r->ifcall.mode&~(OMASK|OTRUNC))
|
||||
|| (need[r->ifcall.mode&3] & ~perm)){
|
||||
respond(r, "permission denied");
|
||||
return;
|
||||
}
|
||||
|
||||
if(inusep){
|
||||
if(*inusep){
|
||||
respond(r, "file in use");
|
||||
return;
|
||||
}
|
||||
*inusep = 1;
|
||||
}
|
||||
|
||||
if(r->fid->qid.path == Qrpc){
|
||||
if((c = convalloc(r->fid->uid)) == nil){
|
||||
char e[ERRMAX];
|
||||
|
||||
rerrstr(e, sizeof e);
|
||||
respond(r, e);
|
||||
return;
|
||||
}
|
||||
c->kickreply = fskickreply;
|
||||
r->fid->aux = c;
|
||||
}
|
||||
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
fsread(Req *r)
|
||||
{
|
||||
Conv *c;
|
||||
|
||||
switch((int)r->fid->qid.path){
|
||||
default:
|
||||
respond(r, "fsread: cannot happen");
|
||||
break;
|
||||
case Qroot:
|
||||
dirread9p(r, rootdirgen, nil);
|
||||
respond(r, nil);
|
||||
break;
|
||||
case Qfactotum:
|
||||
dirread9p(r, fsdirgen, nil);
|
||||
respond(r, nil);
|
||||
break;
|
||||
case Qrpc:
|
||||
c = r->fid->aux;
|
||||
if(c->rpc.op == RpcUnknown){
|
||||
respond(r, "no rpc pending");
|
||||
break;
|
||||
}
|
||||
if(c->req){
|
||||
respond(r, "read already pending");
|
||||
break;
|
||||
}
|
||||
c->req = r;
|
||||
if(c->nreply)
|
||||
(*c->kickreply)(c);
|
||||
else
|
||||
rpcexec(c);
|
||||
break;
|
||||
case Qconfirm:
|
||||
confirmread(r);
|
||||
break;
|
||||
case Qlog:
|
||||
logread(r);
|
||||
break;
|
||||
case Qctl:
|
||||
r->fid->aux = (void*)readlist((int)r->fid->aux, keylist, r);
|
||||
respond(r, nil);
|
||||
break;
|
||||
case Qneedkey:
|
||||
needkeyread(r);
|
||||
break;
|
||||
case Qprotolist:
|
||||
r->fid->aux = (void*)readlist((int)r->fid->aux, protolist, r);
|
||||
respond(r, nil);
|
||||
break;
|
||||
case Qconv:
|
||||
r->fid->aux = (void*)readlist((int)r->fid->aux, convlist, r);
|
||||
respond(r, nil);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fswrite(Req *r)
|
||||
{
|
||||
int ret;
|
||||
char err[ERRMAX], *s;
|
||||
int (*strfn)(char*);
|
||||
|
||||
switch((int)r->fid->qid.path){
|
||||
default:
|
||||
respond(r, "fswrite: cannot happen");
|
||||
break;
|
||||
case Qrpc:
|
||||
if(rpcwrite(r->fid->aux, r->ifcall.data, r->ifcall.count) < 0){
|
||||
rerrstr(err, sizeof err);
|
||||
respond(r, err);
|
||||
}else{
|
||||
r->ofcall.count = r->ifcall.count;
|
||||
respond(r, nil);
|
||||
}
|
||||
break;
|
||||
case Qneedkey:
|
||||
strfn = needkeywrite;
|
||||
goto string;
|
||||
case Qctl:
|
||||
strfn = ctlwrite;
|
||||
goto string;
|
||||
case Qconfirm:
|
||||
strfn = confirmwrite;
|
||||
string:
|
||||
s = emalloc(r->ifcall.count+1);
|
||||
memmove(s, r->ifcall.data, r->ifcall.count);
|
||||
s[r->ifcall.count] = '\0';
|
||||
ret = (*strfn)(s);
|
||||
free(s);
|
||||
if(ret < 0){
|
||||
rerrstr(err, sizeof err);
|
||||
respond(r, err);
|
||||
}else{
|
||||
r->ofcall.count = r->ifcall.count;
|
||||
respond(r, nil);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fsflush(Req *r)
|
||||
{
|
||||
confirmflush(r);
|
||||
logflush(r);
|
||||
}
|
||||
|
||||
static void
|
||||
fsdestroyfid(Fid *fid)
|
||||
{
|
||||
if(fid->qid.path == Qrpc && fid->aux){
|
||||
convhangup(fid->aux);
|
||||
convclose(fid->aux);
|
||||
}
|
||||
}
|
||||
|
||||
static Channel *creq;
|
||||
static Channel *cfid, *cfidr;
|
||||
|
||||
static void
|
||||
fsreqthread(void *v)
|
||||
{
|
||||
Req *r;
|
||||
|
||||
USED(v);
|
||||
|
||||
while((r = recvp(creq)) != nil){
|
||||
switch(r->ifcall.type){
|
||||
default:
|
||||
respond(r, "bug in fsreqthread");
|
||||
break;
|
||||
case Topen:
|
||||
fsopen(r);
|
||||
break;
|
||||
case Tread:
|
||||
fsread(r);
|
||||
break;
|
||||
case Twrite:
|
||||
fswrite(r);
|
||||
break;
|
||||
case Tflush:
|
||||
fsflush(r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fsclunkthread(void *v)
|
||||
{
|
||||
Fid *f;
|
||||
|
||||
USED(v);
|
||||
|
||||
while((f = recvp(cfid)) != nil){
|
||||
fsdestroyfid(f);
|
||||
sendp(cfidr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fsproc(void *v)
|
||||
{
|
||||
USED(v);
|
||||
|
||||
threadcreate(fsreqthread, nil, STACK);
|
||||
threadcreate(fsclunkthread, nil, STACK);
|
||||
threadexits(nil);
|
||||
}
|
||||
|
||||
static void
|
||||
fsattach(Req *r)
|
||||
{
|
||||
r->fid->qid = mkqid(QTDIR, qtop);
|
||||
r->ofcall.qid = r->fid->qid;
|
||||
respond(r, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
fssend(Req *r)
|
||||
{
|
||||
sendp(creq, r);
|
||||
}
|
||||
|
||||
static void
|
||||
fssendclunk(Fid *f)
|
||||
{
|
||||
sendp(cfid, f);
|
||||
recvp(cfidr);
|
||||
}
|
||||
|
||||
void
|
||||
fsstart(Srv *s)
|
||||
{
|
||||
USED(s);
|
||||
|
||||
if(extrafactotumdir)
|
||||
qtop = Qroot;
|
||||
else
|
||||
qtop = Qfactotum;
|
||||
creq = chancreate(sizeof(Req*), 0);
|
||||
cfid = chancreate(sizeof(Fid*), 0);
|
||||
cfidr = chancreate(sizeof(Fid*), 0);
|
||||
proccreate(fsproc, nil, STACK);
|
||||
}
|
||||
|
||||
Srv fs = {
|
||||
.attach= fsattach,
|
||||
.walk1= fswalk1,
|
||||
.open= fssend,
|
||||
.read= fssend,
|
||||
.write= fssend,
|
||||
.stat= fsstat,
|
||||
.flush= fssend,
|
||||
.destroyfid= fssendclunk,
|
||||
.start= fsstart,
|
||||
};
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue