shithub: gefs

Download patch

ref: ffa663fec1eec67cf8f81fe2882e7393076ff235
parent: eed6e68174a13a4b7c0b39acdcfa911a302f96c2
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Jan 21 00:01:34 EST 2022

fs: add auth support

--- a/TODO
+++ b/TODO
@@ -1,8 +1,4 @@
-*** must have before usable for testing ***
-- auth against authservers
-- implement special file modes: ORCLOSE, OEXCL, etc
-
-*** must have before full release ***
+*** major issues, need to fix ***
 - live alloc log recompression
 - Reserve blocks for deletion
 - transient exec snapshots
@@ -11,7 +7,7 @@
 	- reduce io ops per update
 	- async page writeback: currently, every write to device is sync.
 
-*** nice to have, can get testing without ***
+*** nice to have, can go without ***
 - add missing management commands in console
 - performance optimization:
 	- bulk block frees
--- a/blk.c
+++ b/blk.c
@@ -135,7 +135,7 @@
 {
 	int n;
 
-	n = hint+ainc(&fs->roundrobin)/1024;
+	n = hint+ainc(&fs->roundrobin)/(64*1024);
 	return &fs->arenas[n%fs->narena];
 }
 
@@ -865,7 +865,7 @@
 	lock(&fs->activelk);
 	allquiesced = 1;
 	fs->active[tid]++;
-	for(i = 0; i < fs->nproc; i++){
+	for(i = 0; i < fs->nquiesce; i++){
 		/*
 		 * Odd parity on quiescence implies
 		 * that we're between the exit from
@@ -879,7 +879,7 @@
 			allquiesced = 0;
 	}
 	if(allquiesced)
-		for(i = 0; i < fs->nproc; i++)
+		for(i = 0; i < fs->nquiesce; i++)
 			fs->lastactive[i] = fs->active[i];
 	unlock(&fs->activelk);
 	if(!allquiesced)
--- a/dat.h
+++ b/dat.h
@@ -40,7 +40,6 @@
 	Nsec	= 1000*1000*1000,	/* nanoseconds to the second */
 	Maxname	= 256,			/* maximum size of a name element */
 	Maxent	= 9+Maxname+1,		/* maximum size of ent key, with terminator */
-	Maxproc	= 8,			/* maximum number of worker procs */
 
 	/*
 	 * Kpmax must be no more than 1/4 of pivspc, or
@@ -125,6 +124,11 @@
 #define Ebadu	"attach -- unknown user or failed authentication"
 #define Erdonly	"file system read only"
 #define Elocked	"open/create -- file is locked"
+#define Eauthp	"authread -- auth protocol not finished"
+#define Eauthd	"authread -- not enough data"
+#define Ephase	"auth phase error"
+#define Enone	"auth -- user 'none' requires no authentication"
+#define Enoauth	"auth -- authentication disabled"
 
 #define Ewstatb	"wstat -- unknown bits in qid.type/mode"
 #define Ewstatd	"wstat -- attempt to change directory"
@@ -407,11 +411,11 @@
 
 	Chan	*wrchan;
 	Chan	*rdchan;
-	int	nproc;
+	int	nquiesce;
 
 	Lock	activelk;
-	int	active[Maxproc];
-	int	lastactive[Maxproc];
+	int	active[32];
+	int	lastactive[32];
 	Lock	freelk;
 	Bfree	*freep;
 	Bfree	*freehd;
@@ -419,6 +423,7 @@
 	int	fd;
 	long	broken;
 	long	rdonly;
+	int	noauth;
 
 	/* root snapshot tree */
 	Tree	snap;
@@ -522,7 +527,6 @@
 	Mount	*next;
 	long	ref;
 	vlong	gen;
-	int	uid;
 	char	*name;
 	Tree	*root;
 };
@@ -537,7 +541,8 @@
 	 */
 	Mount	*mnt;
 	Scan	*scan;	/* in progres scan */
-	Dent	*dent;	/* (pqid, name) ref, modified on rename */
+	Dent	*dent;	/* (pqid, name) ref, modified on rename */	
+	void	*auth;
 
 	u32int	fid;
 	vlong	qpath;
@@ -546,6 +551,7 @@
 	int	mode;
 	int	iounit;
 
+	int	uid;
 	int	duid;
 	int	dgid;
 	int	dmode;
--- a/dump.c
+++ b/dump.c
@@ -20,6 +20,8 @@
 	 * ptr:  off[8] hash[8] -- a key for an Dir block.
 	 * dir:  fixed statbuf header, user ids
 	 */
+	if(k->nk == 0)
+		return fmtprint(fmt, "\"\"");
 	switch(k->k[0]){
 	case Kdat:	/* qid[8] off[8] => ptr[16]:	pointer to data page */
 		n = fmtprint(fmt, "dat qid:%llx off:%llx", GBIT64(k->k+1), GBIT64(k->k+9));
--- a/fs.c
+++ b/fs.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <auth.h>
 #include <fcall.h>
 #include <avl.h>
 #include <bio.h>
@@ -165,8 +166,10 @@
 
 	r->tag = m->tag;
 	dprint("→ %F\n", r);
-	if((n = convS2M(r, buf, sizeof(buf))) == 0)
+	if((n = convS2M(r, buf, sizeof(buf))) == 0){
+		fprint(2, "wut: %r\n");
 		abort();
+	}
 	w = write(m->fd, buf, n);
 	if(w != n)
 		fshangup(m->fd, Eio);
@@ -339,11 +342,10 @@
 	de->ref = 1;
 	de->qid = d->qid;
 	de->length = d->length;
-	de->k = de->buf;
-	de->nk = 9 + strlen(d->name) + 1;
 
 	if((e = packdkey(de->buf, sizeof(de->buf), pqid, d->name)) == nil)
 		return nil;
+	de->k = de->buf;
 	de->nk = e - de->buf;
 	de->next = fs->dtab[h];
 	fs->dtab[h] = de;
@@ -529,13 +531,83 @@
 	respond(m, &r);
 }
 
+void
+authfree(AuthRpc *auth)
+{
+	AuthRpc *rpc;
+
+	if(rpc = auth){
+		close(rpc->afd);
+		auth_freerpc(rpc);
+	}
+}
+
+AuthRpc*
+authnew(void)
+{
+	static char *keyspec = "proto=p9any role=server";
+	AuthRpc *rpc;
+	int fd;
+
+	if(access("/mnt/factotum", 0) < 0)
+		if((fd = open("/srv/factotum", ORDWR)) >= 0)
+			mount(fd, -1, "/mnt", MBEFORE, "");
+	if((fd = open("/mnt/factotum/rpc", ORDWR)) < 0)
+		return nil;
+	if((rpc = auth_allocrpc(fd)) == nil){
+		close(fd);
+		return nil;
+	}
+	if(auth_rpc(rpc, "start", keyspec, strlen(keyspec)) != ARok){
+		authfree(rpc);
+		return nil;
+	}
+	return rpc;
+}
+
 static void
-fsauth(Fmsg *m)
+fsauth(Fmsg *m, int iounit)
 {
+	Dent *de;
 	Fcall r;
+	Fid f;
 
-	r.type = Rerror;
-	r.ename = "unimplemented auth";
+	if(fs->noauth){
+		rerror(m, Eauth);
+		return;
+	}
+	if((de = mallocz(sizeof(Dent), 1)) == nil){
+		rerror(m, Enomem);
+		return;
+	}
+	memset(de, 0, sizeof(Dent));
+	de->ref = 1;
+	de->qid.type = QTAUTH;
+	de->qid.path = inc64(&fs->nextqid, 1);
+	de->qid.vers = 0;
+	de->length = 0;
+	de->k = nil;
+	de->nk = 0;
+
+	memset(&f, 0, sizeof(Fid));
+	f.fid = NOFID;
+	f.mnt = nil;
+	f.qpath = de->qid.path;
+	f.pqpath = de->qid.path;
+	f.mode = -1;
+	f.iounit = iounit;
+	f.dent = de;
+	f.uid = -1;
+	f.duid = -1;
+	f.dgid = -1;
+	f.dmode = 0600;
+	f.auth = authnew();
+	if(dupfid(m->afid, &f) == nil){
+		rerror(m, Enomem);
+		return;
+	}
+	r.type = Rauth;
+	r.aqid = de->qid;
 	respond(m, &r);
 }
 
@@ -575,14 +647,14 @@
 }
 
 static int
-fsaccess(Mount *mnt, int fmode, int fuid, int fgid, int m)
+fsaccess(Fid *f, int fmode, int fuid, int fgid, int m)
 {
 	/* uid none gets only other permissions */
-	if(mnt->uid != 0) {
-		if(mnt->uid == fuid)
+	if(f->uid != 0) {
+		if(f->uid == fuid)
 			if((m & (fmode>>6)) == m)
 				return 0;
-		if(ingroup(mnt->uid, fgid))
+		if(ingroup(f->uid, fgid))
 			if((m & (fmode>>3)) == m)
 				return 0;
 	}
@@ -589,7 +661,7 @@
 	if(m & fmode) {
 		if((fmode & DMDIR) && (m == DMEXEC))
 			return 0;
-		if(!ingroup(mnt->uid, 9999))
+		if(!ingroup(f->uid, 9999))
 			return 0;
 	}
 	return -1;
@@ -617,12 +689,11 @@
 		return;
 	}
 	rlock(&fs->userlk);
-	if((u = name2user("glenda")) == nil){
+	if((u = name2user(m->uname)) == nil){
 		rerror(m, Enouser);
 		runlock(&fs->userlk);
 		return;
 	}
-	mnt->uid = u->id;
 	runlock(&fs->userlk);
 
 	if((mnt->root = openlabel(m->aname)) == nil){
@@ -665,7 +736,8 @@
 	f.mode = -1;
 	f.iounit = iounit;
 	f.dent = de;
-	f.duid = mnt->uid;
+	f.uid = u->id;
+	f.duid = u->id;
 	f.dgid = d.gid;
 	f.dmode = d.mode;
 	if(dupfid(m->fid, &f) == nil){
@@ -859,7 +931,7 @@
 		rerror(m, Edir);
 		goto Out;
 	}
-	if(fsaccess(f->mnt, de->mode, de->uid, de->gid, DMWRITE) == -1){
+	if(fsaccess(f, de->mode, de->uid, de->gid, DMWRITE) == -1){
 		rerror(m, Eperm);
 		goto Out;
 	}
@@ -941,8 +1013,8 @@
 		sync = 0;
 	}
 	op |= Owmuid;
-	de->muid = f->mnt->uid;
-	PBIT32(p, f->mnt->uid);
+	de->muid = f->uid;
+	PBIT32(p, f->uid);
 	p += 4;
 
 	opbuf[0] = op;
@@ -1018,7 +1090,7 @@
 	}
 	de = f->dent;
 	rlock(de);
-	if(fsaccess(f->mnt, de->mode, de->uid, de->gid, DMWRITE) == -1){
+	if(fsaccess(f, de->mode, de->uid, de->gid, DMWRITE) == -1){
 		rerror(m, Eperm);
 		runlock(de);
 		return;
@@ -1042,9 +1114,9 @@
 	d.atime = nsec();
 	d.mtime = d.atime;
 	d.length = 0;
-	d.uid = f->mnt->uid;
+	d.uid = f->uid;
 	d.gid = f->dgid;
-	d.muid = f->mnt->uid;
+	d.muid = f->uid;
 
 	mb[nm].op = Oinsert;
 	if(dir2kv(f->qpath, &d, &mb[nm], buf, sizeof(buf)) == -1){
@@ -1162,7 +1234,7 @@
 		clunkfid(f);
 		return;
 	}
-	if(fsaccess(f->mnt, f->dmode, f->duid, f->dgid, OWRITE) == -1){
+	if(fsaccess(f, f->dmode, f->duid, f->dgid, OWRITE) == -1){
 		rerror(m, Eperm);
 		runlock(f->dent);
 		return;
@@ -1218,7 +1290,7 @@
 		putfid(f);
 		return;
 	}
-	if(fsaccess(f->mnt, d.mode, d.uid, d.gid, mbits) == -1){
+	if(fsaccess(f, d.mode, d.uid, d.gid, mbits) == -1){
 		rerror(m, Eperm);
 		putfid(f);
 		return;
@@ -1246,7 +1318,7 @@
 //	}
 	if(m->mode & OTRUNC){
 		wlock(f->dent);
-		f->dent->muid = f->mnt->uid;
+		f->dent->muid = f->uid;
 		f->dent->qid.vers++;
 		f->dent->length = 0;
 
@@ -1254,7 +1326,7 @@
 		p = buf;
 		p[0] = Owsize|Owmuid;	p += 1;
 		PBIT64(p, 0);		p += 8;
-		PBIT32(p, f->mnt->uid);	p += 4;
+		PBIT32(p, f->uid);	p += 4;
 		mb.k = f->dent->k;
 		mb.nk = f->dent->nk;
 		mb.v = buf;
@@ -1273,8 +1345,44 @@
 }
 
 static char*
-fsreaddir(Fmsg *m, Fid *f, Fcall *r)
+readauth(Fmsg *m, Fid *f, Fcall *r)
 {
+	AuthInfo *ai;
+	AuthRpc *rpc;
+	User *u;
+
+	if((rpc = f->auth) == nil)
+		return Etype;
+
+	switch(auth_rpc(rpc, "read", nil, 0)){
+	default:
+		return Eauthp;
+	case ARdone:
+		if((ai = auth_getinfo(rpc)) == nil)
+			goto Phase;
+		u = name2user(ai->cuid);
+		auth_freeAI(ai);
+		if(u == nil)
+			return Enouser;
+		f->uid = u->id;
+		return nil;
+	case ARok:
+		if(m->count < rpc->narg)
+			return Eauthd;
+		if((r->data = malloc(rpc->narg)) == nil)
+			return Emem;
+		memmove(r->data, rpc->arg, rpc->narg);
+		r->count = rpc->narg;
+		return nil;
+	case ARphase:
+	Phase:
+		return Ephase;
+	}
+}
+
+static char*
+readdir(Fmsg *m, Fid *f, Fcall *r)
+{
 	char pfx[Dpfxsz], *p, *e;
 	int n, ns, done;
 	Scan *s;
@@ -1331,7 +1439,7 @@
 }
 
 static char*
-fsreadfile(Fmsg *m, Fid *f, Fcall *r)
+readfile(Fmsg *m, Fid *f, Fcall *r)
 {
 	vlong n, c, o;
 	char *p;
@@ -1384,10 +1492,12 @@
 		putfid(f);
 		return;
 	}
-	if(f->dent->qid.type & QTDIR)
-		e = fsreaddir(m, f, &r);
+	if(f->dent->qid.type & QTAUTH)
+		e = readauth(m, f, &r);
+	else if(f->dent->qid.type & QTDIR)
+		e = readdir(m, f, &r);
 	else
-		e = fsreadfile(m, f, &r);
+		e = readfile(m, f, &r);
 	if(e != nil)
 		rerror(m, e);
 	else
@@ -1396,7 +1506,22 @@
 	putfid(f);
 }
 
+static char*
+writeauth(Fmsg *m, Fid *f, Fcall *r)
+{
+	AuthRpc *rpc;
 
+	if((rpc = f->auth) == nil)
+		return Etype;
+	if(auth_rpc(rpc, "write", m->data, m->count) != ARok)
+		return Ebotch;
+	r->type = Rwrite;
+	r->count = m->count;
+	return nil;
+
+}
+
+
 static void
 fswrite(Fmsg *m)
 {
@@ -1418,6 +1543,15 @@
 		putfid(f);
 		return;
 	}
+	if(f->dent->qid.type == QTAUTH){
+		e = writeauth(m, f, &r);
+		if(e != nil)
+			rerror(m, e);
+		else
+			respond(m, &r);
+		putfid(f);
+		return;
+	}		
 
 	wlock(f->dent);
 	p = m->data;
@@ -1457,7 +1591,7 @@
 		f->dent->length = m->offset+m->count;
 	}
 	sbuf[0] |= Owmuid;
-	PBIT32(p, f->mnt->uid);
+	PBIT32(p, f->uid);
 	p += 4;
 
 	kv[i].v = sbuf;
@@ -1506,7 +1640,7 @@
 		switch(m->type){
 		/* sync setup */
 		case Tversion:	fsversion(m, &msgmax);	break;
-		case Tauth:	fsauth(m);		break;
+		case Tauth:	fsauth(m, msgmax);	break;
 		case Tclunk:	fsclunk(m);		break;
 		case Tattach:	fsattach(m, msgmax);	break;
 
--- a/main.c
+++ b/main.c
@@ -11,6 +11,8 @@
 
 int	ream;
 int	debug;
+int	noauth;
+int	nproc;
 char	*srvname = "gefs";
 
 vlong
@@ -32,6 +34,7 @@
 	if((fs = mallocz(sizeof(Gefs), 1)) == nil)
 		sysfatal("malloc: %r");
 
+	fs->noauth = noauth;
 	fs->cmax = cachesz/Blksz;
 	if(fs->cmax >= (2ULL*GiB)/sizeof(Bucket))
 		sysfatal("cache too big");
@@ -44,7 +47,7 @@
 {
 	int pid;
 
-
+	assert(wid == -1 || wid < nelem(fs->active));
 	pid = rfork(RFPROC|RFMEM|RFNOWAIT);
 	if (pid < 0)
 		sysfatal("can't fork: %r");
@@ -83,8 +86,9 @@
 void
 main(int argc, char **argv)
 {
-	int srvfd, ctlfd;
+	int i, srvfd, ctlfd;
 	vlong cachesz;
+	char *s;
 
 	cachesz = 16*MiB;
 	ARGBEGIN{
@@ -100,6 +104,9 @@
 	case 's':
 		srvname = EARGF(usage());
 		break;
+	case 'A':
+		noauth = 1;
+		break;
 	default:
 		usage();
 		break;
@@ -125,6 +132,11 @@
 	fmtinstall('R', Rconv);
 	fmtinstall('F', fcallfmt);
 	fmtinstall('Q', Qconv);
+
+	if((s = getenv("NPROC")) != nil)
+		nproc = atoi(s);
+	if(nproc == 0)
+		nproc = 2;
 	if(ream){
 		reamfs(argv[0]);
 		exits(nil);
@@ -134,13 +146,13 @@
 		srvfd = postfd(srvname, "");
 		ctlfd = postfd(srvname, ".cmd");
 		loadfs(argv[0]);
-		launch(runcons, fs->nproc++, (void*)ctlfd, "ctl");
-		launch(runwrite, fs->nproc++, nil, "writeio");
-		launch(runread, fs->nproc++, nil, "readio");
-		launch(runtasks, fs->nproc++, nil, "tasks");
-//		launch(runfs, fs->nproc++, (void*)srvfd, "fs");
-		assert(fs->nproc < Maxproc);
-		runfs(fs->nproc++, (void*)srvfd);
+		launch(runtasks, -1, nil, "tasks");
+		launch(runcons, fs->nquiesce++, (void*)ctlfd, "ctl");
+		launch(runwrite, fs->nquiesce++, nil, "writeio");
+		for(i = 0; i < nproc; i++)
+			launch(runread, fs->nquiesce++, nil, "readio");
+		if(srvfd != -1)
+			launch(runfs, -1, (void*)srvfd, "srvio");
 		exits(nil);
 	}
 }
--- a/ream.c
+++ b/ream.c
@@ -167,7 +167,7 @@
 
 	asz = sz/fs->narena;
 	asz = asz - (asz % Blksz) - Blksz;
-	if(asz < 512*MiB)
+	if(asz < 128*MiB)
 		sysfatal("disk too small");
 	fs->arenasz = asz;
 	off = 0;