1123 lines · 19.1 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * keyfs */#include <u.h>#include <libc.h>#include <ctype.h>#include <authsrv.h>#include <fcall.h>#include <bio.h>#include <mp.h>#include <libsec.h>#include "authcmdlib.h" #pragma	varargck	type	"W"	char* char authkey[8]; typedef struct Fid	Fid;typedef struct User	User; enum {	Qroot,	Quser,	Qkey,	Qsecret,	Qlog,	Qstatus,	Qexpire,	Qwarnings,	Qmax, 	Nuser	= 512,	MAXBAD	= 10,	/* max # of bad attempts before disabling the account */	/* file must be randomly addressible, so names have fixed length */	Namelen	= ANAMELEN,}; enum {	Sok,	Sdisabled,	Smax,}; struct Fid {	int	fid;	ulong	qtype;	User	*user;	int	busy;	Fid	*next;}; struct User {	char	*name;	char	key[DESKEYLEN];	char	secret[SECRETLEN];	ulong	expire;			/* 0 == never */	uchar	status;	ulong	bad;		/* # of consecutive bad authentication attempts */	int	ref;	char	removed;	uchar	warnings;	long	purgatory;		/* time purgatory ends */	ulong	uniq;	User	*link;}; char	*qinfo[Qmax] = {	[Qroot]		"keys",	[Quser]		".",	[Qkey]		"key",	[Qsecret]	"secret",	[Qlog]		"log",	[Qexpire]	"expire",	[Qstatus]	"status",	[Qwarnings]	"warnings",}; char	*status[Smax] = {	[Sok]		"ok",	[Sdisabled]	"disabled",}; Fid	*fids;User	*users[Nuser];char	*userkeys;int	nuser;ulong	uniq = 1;Fcall	rhdr,	thdr;int	usepass;char	*warnarg;uchar	mdata[8192 + IOHDRSZ];int	messagesize = sizeof mdata; int	readusers(void);ulong	hash(char*);Fid	*findfid(int);User	*finduser(char*);User	*installuser(char*);int	removeuser(User*);void	insertuser(User*);void	writeusers(void);void	io(int, int);void	*emalloc(ulong);Qid	mkqid(User*, ulong);int	dostat(User*, ulong, void*, int);int	newkeys(void);void	warning(void);int	weirdfmt(Fmt *f); char	*Auth(Fid*), *Attach(Fid*), *Version(Fid*),	*Flush(Fid*), *Walk(Fid*),	*Open(Fid*), *Create(Fid*),	*Read(Fid *), *Write(Fid*), *Clunk(Fid*),	*Remove(Fid *), *Stat(Fid*), *Wstat(Fid*);char 	*(*fcalls[])(Fid*) = {	[Tattach]	Attach,	[Tauth]	Auth,	[Tclunk]	Clunk,	[Tcreate]	Create,	[Tflush]	Flush,	[Topen]		Open,	[Tread]		Read,	[Tremove]	Remove,	[Tstat]		Stat,	[Tversion]	Version,	[Twalk]		Walk,	[Twrite]	Write,	[Twstat]	Wstat,}; static voidusage(void){	fprint(2, "usage: %s [-p] [-m mtpt] [-w warn] [keyfile]\n", argv0);	exits("usage");} voidmain(int argc, char *argv[]){	char *mntpt;	int p[2]; 	fmtinstall('W', weirdfmt);	mntpt = "/mnt/keys";	ARGBEGIN{	case 'm':		mntpt = EARGF(usage());		break;	case 'p':		usepass = 1;		break;	case 'w':		warnarg = EARGF(usage());		break;	default:		usage();		break;	}ARGEND	argv0 = "keyfs"; 	userkeys = "/adm/keys";	if(argc > 1)		usage();	if(argc == 1)		userkeys = argv[0]; 	if(pipe(p) < 0)		error("can't make pipe: %r"); 	if(usepass) {		getpass(authkey, nil, 0, 0);	} else {		if(!getauthkey(authkey))			print("keyfs: warning: can't read NVRAM\n");	} 	switch(rfork(RFPROC|RFNAMEG|RFNOTEG|RFNOWAIT|RFENVG|RFFDG)){	case 0:		close(p[0]);		io(p[1], p[1]);		exits(0);	case -1:		error("fork");	default:		close(p[1]);		if(mount(p[0], -1, mntpt, MREPL|MCREATE, "") < 0)			error("can't mount: %r");		exits(0);	}} char *Flush(Fid *f){	USED(f);	return 0;} char *Auth(Fid *){	return "keyfs: authentication not required";} char *Attach(Fid *f){	if(f->busy)		Clunk(f);	f->user = 0;	f->qtype = Qroot;	f->busy = 1;	thdr.qid = mkqid(f->user, f->qtype);	return 0;} char*Version(Fid*){	Fid *f; 	for(f = fids; f; f = f->next)		if(f->busy)			Clunk(f);	if(rhdr.msize > sizeof mdata)		thdr.msize = sizeof mdata;	else		thdr.msize = rhdr.msize;	messagesize = thdr.msize;	if(strncmp(rhdr.version, "9P2000", 6) != 0)		return "bad 9P version";	thdr.version = "9P2000";	return 0;} char *Walk(Fid *f){	char *name, *err;	int i, j, max;	Fid *nf;	ulong qtype;	User *user; 	if(!f->busy)		return "walk of unused fid";	nf = nil;	qtype = f->qtype;	user = f->user;	if(rhdr.fid != rhdr.newfid){		nf = findfid(rhdr.newfid);		if(nf->busy)			return "fid in use";		f = nf;	/* walk f */	} 	err = nil;	i = 0;	if(rhdr.nwname > 0){		for(; i<rhdr.nwname; i++){			if(i >= MAXWELEM){				err = "too many path name elements";				break;			}			name = rhdr.wname[i];			switch(qtype){			case Qroot:				if(strcmp(name, "..") == 0)					goto Accept;				user = finduser(name);				if(!user)					goto Out;				qtype = Quser; 			Accept:				thdr.wqid[i] = mkqid(user, qtype);				break; 			case Quser:				if(strcmp(name, "..") == 0) {					qtype = Qroot;					user = 0;					goto Accept;				}				max = Qmax;				for(j = Quser + 1; j < Qmax; j++)					if(strcmp(name, qinfo[j]) == 0){						qtype = j;						break;					}				if(j < max)					goto Accept;				goto Out; 			default:				err = "file is not a directory";				goto Out;			}		}	    Out:		if(i < rhdr.nwname && err == nil)			err = "file not found";	} 	if(err != nil){		return err;	} 	/* if we cloned and then completed the walk, update new fid */	if(rhdr.fid != rhdr.newfid && i == rhdr.nwname){		nf->busy = 1;		nf->qtype = qtype;		if(nf->user = user)			nf->user->ref++;	}else if(nf == nil && rhdr.nwname > 0){	/* walk without clone (rare) */		Clunk(f);		f->busy = 1;		f->qtype = qtype;		if(f->user = user)			f->user->ref++;	} 	thdr.nwqid = i;	return 0;} char *Clunk(Fid *f){	f->busy = 0;	if(f->user && --f->user->ref == 0 && f->user->removed) {		free(f->user->name);		free(f->user);	}	f->user = 0;	return 0;} char *Open(Fid *f){	int mode; 	if(!f->busy)		return "open of unused fid";	mode = rhdr.mode;	if(f->qtype == Quser && (mode & (OWRITE|OTRUNC)))		return "user already exists";	thdr.qid = mkqid(f->user, f->qtype);	thdr.iounit = messagesize - IOHDRSZ;	return 0;} char *Create(Fid *f){	char *name;	long perm; 	if(!f->busy)		return "create of unused fid";	name = rhdr.name;	if(f->user){		return "permission denied";	}else{		perm = rhdr.perm;		if(!(perm & DMDIR))			return "permission denied";		if(strcmp(name, "") == 0)			return "empty file name";		if(strlen(name) >= Namelen)			return "file name too long";		if(finduser(name))			return "user already exists";		f->user = installuser(name);		f->user->ref++;		f->qtype = Quser;	}	thdr.qid = mkqid(f->user, f->qtype);	thdr.iounit = messagesize - IOHDRSZ;	writeusers();	return 0;} char *Read(Fid *f){	User *u;	char *data;	ulong off, n, m;	int i, j, max; 	if(!f->busy)		return "read of unused fid";	n = rhdr.count;	off = rhdr.offset;	thdr.count = 0;	data = thdr.data;	switch(f->qtype){	case Qroot:		j = 0;		for(i = 0; i < Nuser; i++)			for(u = users[i]; u; j += m, u = u->link){				m = dostat(u, Quser, data, n);				if(m <= BIT16SZ)					break;				if(j < off)					continue;				data += m;				n -= m;			}		thdr.count = data - thdr.data;		return 0;	case Quser:		max = Qmax;		max -= Quser + 1;		j = 0;		for(i = 0; i < max; j += m, i++){			m = dostat(f->user, i + Quser + 1, data, n);			if(m <= BIT16SZ)				break;			if(j < off)				continue;			data += m;			n -= m;		}		thdr.count = data - thdr.data;		return 0;	case Qkey:		if(f->user->status != Sok)			return "user disabled";		if(f->user->purgatory > time(0))			return "user in purgatory";		if(f->user->expire != 0 && f->user->expire < time(0))			return "user expired";		if(off != 0)			return 0;		if(n > DESKEYLEN)			n = DESKEYLEN;		memmove(thdr.data, f->user->key, n);		thdr.count = n;		return 0;	case Qsecret:		if(f->user->status != Sok)			return "user disabled";		if(f->user->purgatory > time(0))			return "user in purgatory";		if(f->user->expire != 0 && f->user->expire < time(0))			return "user expired";		if(off != 0)			return 0;		if(n > strlen(f->user->secret))			n = strlen(f->user->secret);		memmove(thdr.data, f->user->secret, n);		thdr.count = n;		return 0;	case Qstatus:		if(off != 0){			thdr.count = 0;			return 0;		}		if(f->user->status == Sok && f->user->expire && f->user->expire < time(0))			sprint(thdr.data, "expired\n");		else			sprint(thdr.data, "%s\n", status[f->user->status]);		thdr.count = strlen(thdr.data);		return 0;	case Qexpire:		if(off != 0){			thdr.count = 0;			return 0;		}		if(!f->user->expire)			strcpy(data, "never\n");		else			sprint(data, "%lud\n", f->user->expire);		if(n > strlen(data))			n = strlen(data);		thdr.count = n;		return 0;	case Qlog:		if(off != 0){			thdr.count = 0;			return 0;		}		sprint(data, "%lud\n", f->user->bad);		if(n > strlen(data))			n = strlen(data);		thdr.count = n;

Lines 1–500 of 1123.