xref: /plan9-contrib/sys/src/cmd/auth/factotum/fs.c (revision 13e26254f5367fe814be8d0c2fe81053db37f162)
19a747e4fSDavid du Colombier #include "dat.h"
29a747e4fSDavid du Colombier 
39a747e4fSDavid du Colombier int		askforkeys = 1;
49a747e4fSDavid du Colombier char		*authaddr;
59a747e4fSDavid du Colombier int		debug;
64de34a7eSDavid du Colombier int		doprivate = 1;
79a747e4fSDavid du Colombier int		gflag;
89a747e4fSDavid du Colombier char		*owner;
99a747e4fSDavid du Colombier int		kflag;
109a747e4fSDavid du Colombier char		*mtpt = "/mnt";
119a747e4fSDavid du Colombier Keyring	*ring;
129a747e4fSDavid du Colombier char		*service;
139a747e4fSDavid du Colombier int		sflag;
149a747e4fSDavid du Colombier int		uflag;
159a747e4fSDavid du Colombier 
169a747e4fSDavid du Colombier extern Srv		fs;
179a747e4fSDavid du Colombier static void		notifyf(void*, char*);
189a747e4fSDavid du Colombier static void		private(void);
199a747e4fSDavid du Colombier 
209a747e4fSDavid du Colombier char	Easproto[]		= "auth server protocol botch";
219a747e4fSDavid du Colombier char Ebadarg[]		= "invalid argument";
229a747e4fSDavid du Colombier char Ebadkey[]		= "bad key";
239a747e4fSDavid du Colombier char Enegotiation[]	= "negotiation failed, no common protocols or keys";
249a747e4fSDavid du Colombier char Etoolarge[]	= "rpc too large";
259a747e4fSDavid du Colombier 
269a747e4fSDavid du Colombier Proto*
279a747e4fSDavid du Colombier prototab[] =
289a747e4fSDavid du Colombier {
299a747e4fSDavid du Colombier 	&apop,
309a747e4fSDavid du Colombier 	&chap,
319a747e4fSDavid du Colombier 	&cram,
325ab4dd4cSDavid du Colombier 	&httpdigest,
339a747e4fSDavid du Colombier 	&mschap,
349a747e4fSDavid du Colombier 	&p9any,
359a747e4fSDavid du Colombier 	&p9cr,
369a747e4fSDavid du Colombier 	&p9sk1,
379a747e4fSDavid du Colombier 	&p9sk2,
389a747e4fSDavid du Colombier 	&pass,
3949eeb88aSDavid du Colombier /*	&srs, */
402ebbfa15SDavid du Colombier 	&rsa,
419a747e4fSDavid du Colombier 	&vnc,
42fb7f0c93SDavid du Colombier 	&wep,
43*13e26254SDavid du Colombier 	&wpapsk,
449a747e4fSDavid du Colombier 	nil,
459a747e4fSDavid du Colombier };
469a747e4fSDavid du Colombier 
479a747e4fSDavid du Colombier void
usage(void)489a747e4fSDavid du Colombier usage(void)
499a747e4fSDavid du Colombier {
5014cc0f53SDavid du Colombier 	fprint(2, "usage: %s [-DSdknpu] [-a authaddr] [-m mtpt] [-s service]\n",
5114cc0f53SDavid du Colombier 		argv0);
529a747e4fSDavid du Colombier 	fprint(2, "or    %s -g 'params'\n", argv0);
539a747e4fSDavid du Colombier 	exits("usage");
549a747e4fSDavid du Colombier }
559a747e4fSDavid du Colombier 
569a747e4fSDavid du Colombier void
main(int argc,char ** argv)579a747e4fSDavid du Colombier main(int argc, char **argv)
589a747e4fSDavid du Colombier {
599a747e4fSDavid du Colombier 	int i, trysecstore;
609a747e4fSDavid du Colombier 	char err[ERRMAX], *s;
619a747e4fSDavid du Colombier 	Dir d;
629a747e4fSDavid du Colombier 	Proto *p;
639a747e4fSDavid du Colombier 	char *secstorepw;
649a747e4fSDavid du Colombier 
659a747e4fSDavid du Colombier 	trysecstore = 1;
669a747e4fSDavid du Colombier 	secstorepw = nil;
679a747e4fSDavid du Colombier 
689a747e4fSDavid du Colombier 	ARGBEGIN{
699a747e4fSDavid du Colombier 	case 'D':
709a747e4fSDavid du Colombier 		chatty9p++;
719a747e4fSDavid du Colombier 		break;
729a747e4fSDavid du Colombier 	case 'S':		/* server: read nvram, no prompting for keys */
739a747e4fSDavid du Colombier 		askforkeys = 0;
749a747e4fSDavid du Colombier 		trysecstore = 0;
759a747e4fSDavid du Colombier 		sflag = 1;
769a747e4fSDavid du Colombier 		break;
779a747e4fSDavid du Colombier 	case 'a':
789a747e4fSDavid du Colombier 		authaddr = EARGF(usage());
799a747e4fSDavid du Colombier 		break;
809a747e4fSDavid du Colombier 	case 'd':
819a747e4fSDavid du Colombier 		debug = 1;
824de34a7eSDavid du Colombier 		doprivate = 0;
839a747e4fSDavid du Colombier 		break;
849a747e4fSDavid du Colombier 	case 'g':		/* get: prompt for key for name and domain */
859a747e4fSDavid du Colombier 		gflag = 1;
869a747e4fSDavid du Colombier 		break;
879a747e4fSDavid du Colombier 	case 'k':		/* reinitialize nvram */
889a747e4fSDavid du Colombier 		kflag = 1;
899a747e4fSDavid du Colombier 		break;
909a747e4fSDavid du Colombier 	case 'm':		/* set default mount point */
919a747e4fSDavid du Colombier 		mtpt = EARGF(usage());
929a747e4fSDavid du Colombier 		break;
939a747e4fSDavid du Colombier 	case 'n':
949a747e4fSDavid du Colombier 		trysecstore = 0;
959a747e4fSDavid du Colombier 		break;
964de34a7eSDavid du Colombier 	case 'p':
974de34a7eSDavid du Colombier 		doprivate = 0;
984de34a7eSDavid du Colombier 		break;
999a747e4fSDavid du Colombier 	case 's':		/* set service name */
1009a747e4fSDavid du Colombier 		service = EARGF(usage());
1019a747e4fSDavid du Colombier 		break;
1029a747e4fSDavid du Colombier 	case 'u':		/* user: set hostowner */
1039a747e4fSDavid du Colombier 		uflag = 1;
1049a747e4fSDavid du Colombier 		break;
105d9306527SDavid du Colombier 	default:
106d9306527SDavid du Colombier 		usage();
1079a747e4fSDavid du Colombier 	}ARGEND
1089a747e4fSDavid du Colombier 
109d9306527SDavid du Colombier 	if(argc != 0 && !gflag)
110d9306527SDavid du Colombier 		usage();
1114de34a7eSDavid du Colombier 	if(doprivate)
1129a747e4fSDavid du Colombier 		private();
1139a747e4fSDavid du Colombier 
1143ff48bf5SDavid du Colombier 	initcap();
1153ff48bf5SDavid du Colombier 
1169a747e4fSDavid du Colombier 	quotefmtinstall();
1179a747e4fSDavid du Colombier 	fmtinstall('A', _attrfmt);
1185d459b5aSDavid du Colombier 	fmtinstall('N', attrnamefmt);
1199a747e4fSDavid du Colombier 	fmtinstall('H', encodefmt);
1209a747e4fSDavid du Colombier 
1219a747e4fSDavid du Colombier 	ring = emalloc(sizeof(*ring));
122260f7b65SDavid du Colombier 	notify(notifyf);
1239a747e4fSDavid du Colombier 
1249a747e4fSDavid du Colombier 	if(gflag){
1259a747e4fSDavid du Colombier 		if(argc != 1)
1269a747e4fSDavid du Colombier 			usage();
1279a747e4fSDavid du Colombier 		askuser(argv[0]);
1289a747e4fSDavid du Colombier 		exits(nil);
1299a747e4fSDavid du Colombier 	}
1309a747e4fSDavid du Colombier 
1319a747e4fSDavid du Colombier 	for(i=0; prototab[i]; i++){
1329a747e4fSDavid du Colombier 		p = prototab[i];
1339a747e4fSDavid du Colombier 		if(p->name == nil)
1349a747e4fSDavid du Colombier 			sysfatal("protocol %d has no name", i);
1359a747e4fSDavid du Colombier 		if(p->init == nil)
1369a747e4fSDavid du Colombier 			sysfatal("protocol %s has no init", p->name);
1379a747e4fSDavid du Colombier 		if(p->write == nil)
1389a747e4fSDavid du Colombier 			sysfatal("protocol %s has no write", p->name);
1399a747e4fSDavid du Colombier 		if(p->read == nil)
1409a747e4fSDavid du Colombier 			sysfatal("protocol %s has no read", p->name);
1419a747e4fSDavid du Colombier 		if(p->close == nil)
1429a747e4fSDavid du Colombier 			sysfatal("protocol %s has no close", p->name);
1439a747e4fSDavid du Colombier 		if(p->keyprompt == nil)
1449a747e4fSDavid du Colombier 			p->keyprompt = "";
1459a747e4fSDavid du Colombier 	}
1469a747e4fSDavid du Colombier 
1479a747e4fSDavid du Colombier 	if(sflag){
1489a747e4fSDavid du Colombier 		s = getnvramkey(kflag ? NVwrite : NVwriteonerr, &secstorepw);
1499a747e4fSDavid du Colombier 		if(s == nil)
1509a747e4fSDavid du Colombier 			fprint(2, "factotum warning: cannot read nvram: %r\n");
15170b8e010SDavid du Colombier 		else if(ctlwrite(s, 0) < 0)
1529a747e4fSDavid du Colombier 			fprint(2, "factotum warning: cannot add nvram key: %r\n");
1539a747e4fSDavid du Colombier 		if(secstorepw != nil)
1549a747e4fSDavid du Colombier 			trysecstore = 1;
1556822557bSDavid du Colombier 		if (s != nil) {
156d9306527SDavid du Colombier 			memset(s, 0, strlen(s));
157d9306527SDavid du Colombier 			free(s);
1586822557bSDavid du Colombier 		}
1599a747e4fSDavid du Colombier 	} else if(uflag)
1609a747e4fSDavid du Colombier 		promptforhostowner();
161fb7f0c93SDavid du Colombier 	owner = getuser();
1629a747e4fSDavid du Colombier 
1639a747e4fSDavid du Colombier 	if(trysecstore){
1649a747e4fSDavid du Colombier 		if(havesecstore() == 1){
1659a747e4fSDavid du Colombier 			while(secstorefetch(secstorepw) < 0){
1669a747e4fSDavid du Colombier 				rerrstr(err, sizeof err);
1679a747e4fSDavid du Colombier 				if(strcmp(err, "cancel") == 0)
1689a747e4fSDavid du Colombier 					break;
169d854de59SDavid du Colombier 				fprint(2, "factotum: secstorefetch: %r\n");
1705d459b5aSDavid du Colombier 				fprint(2, "Enter an empty password to quit.\n");
171d9306527SDavid du Colombier 				free(secstorepw);
1729a747e4fSDavid du Colombier 				secstorepw = nil; /* just try nvram pw once */
1739a747e4fSDavid du Colombier 			}
1749a747e4fSDavid du Colombier 		}else{
1759a747e4fSDavid du Colombier /*
1769a747e4fSDavid du Colombier 			rerrstr(err, sizeof err);
1779a747e4fSDavid du Colombier 			if(*err)
178d854de59SDavid du Colombier 				fprint(2, "factotum: havesecstore: %r\n");
1799a747e4fSDavid du Colombier */
1809a747e4fSDavid du Colombier 		}
1819a747e4fSDavid du Colombier 	}
1829a747e4fSDavid du Colombier 
1839a747e4fSDavid du Colombier 	postmountsrv(&fs, service, mtpt, MBEFORE);
1849a747e4fSDavid du Colombier 	if(service){
1859a747e4fSDavid du Colombier 		nulldir(&d);
1869a747e4fSDavid du Colombier 		d.mode = 0666;
1879a747e4fSDavid du Colombier 		s = emalloc(10+strlen(service));
1889a747e4fSDavid du Colombier 		strcpy(s, "/srv/");
1899a747e4fSDavid du Colombier 		strcat(s, service);
1909a747e4fSDavid du Colombier 		if(dirwstat(s, &d) < 0)
1919a747e4fSDavid du Colombier 			fprint(2, "factotum warning: cannot chmod 666 %s: %r\n", s);
1929a747e4fSDavid du Colombier 		free(s);
1939a747e4fSDavid du Colombier 	}
1949a747e4fSDavid du Colombier 	exits(nil);
1959a747e4fSDavid du Colombier }
1969a747e4fSDavid du Colombier 
1979a747e4fSDavid du Colombier char *pmsg = "Warning! %s can't protect itself from debugging: %r\n";
198b7b24591SDavid du Colombier char *smsg = "Warning! %s can't turn off swapping: %r\n";
1999a747e4fSDavid du Colombier 
2009a747e4fSDavid du Colombier /* don't allow other processes to debug us and steal keys */
2019a747e4fSDavid du Colombier static void
private(void)2029a747e4fSDavid du Colombier private(void)
2039a747e4fSDavid du Colombier {
2049a747e4fSDavid du Colombier 	int fd;
2059a747e4fSDavid du Colombier 	char buf[64];
2069a747e4fSDavid du Colombier 
2079a747e4fSDavid du Colombier 	snprint(buf, sizeof(buf), "#p/%d/ctl", getpid());
2089a747e4fSDavid du Colombier 	fd = open(buf, OWRITE);
2099a747e4fSDavid du Colombier 	if(fd < 0){
2109a747e4fSDavid du Colombier 		fprint(2, pmsg, argv0);
2119a747e4fSDavid du Colombier 		return;
2129a747e4fSDavid du Colombier 	}
2139a747e4fSDavid du Colombier 	if(fprint(fd, "private") < 0)
2149a747e4fSDavid du Colombier 		fprint(2, pmsg, argv0);
215b7b24591SDavid du Colombier 	if(fprint(fd, "noswap") < 0)
216b7b24591SDavid du Colombier 		fprint(2, smsg, argv0);
2179a747e4fSDavid du Colombier 	close(fd);
2189a747e4fSDavid du Colombier }
2199a747e4fSDavid du Colombier 
2209a747e4fSDavid du Colombier static void
notifyf(void *,char * s)2219a747e4fSDavid du Colombier notifyf(void*, char *s)
2229a747e4fSDavid du Colombier {
2239a747e4fSDavid du Colombier 	if(strncmp(s, "interrupt", 9) == 0)
2249a747e4fSDavid du Colombier 		noted(NCONT);
2259a747e4fSDavid du Colombier 	noted(NDFLT);
2269a747e4fSDavid du Colombier }
2279a747e4fSDavid du Colombier 
2289a747e4fSDavid du Colombier enum
2299a747e4fSDavid du Colombier {
2309a747e4fSDavid du Colombier 	Qroot,
2319a747e4fSDavid du Colombier 	Qfactotum,
2329a747e4fSDavid du Colombier 	Qrpc,
2339a747e4fSDavid du Colombier 	Qkeylist,
2349a747e4fSDavid du Colombier 	Qprotolist,
2359a747e4fSDavid du Colombier 	Qconfirm,
2369a747e4fSDavid du Colombier 	Qlog,
2379a747e4fSDavid du Colombier 	Qctl,
2389a747e4fSDavid du Colombier 	Qneedkey,
2399a747e4fSDavid du Colombier };
2409a747e4fSDavid du Colombier 
2419a747e4fSDavid du Colombier Qid
mkqid(int type,int path)2429a747e4fSDavid du Colombier mkqid(int type, int path)
2439a747e4fSDavid du Colombier {
2449a747e4fSDavid du Colombier 	Qid q;
2459a747e4fSDavid du Colombier 
2469a747e4fSDavid du Colombier 	q.type = type;
2479a747e4fSDavid du Colombier 	q.path = path;
2489a747e4fSDavid du Colombier 	q.vers = 0;
2499a747e4fSDavid du Colombier 	return q;
2509a747e4fSDavid du Colombier }
2519a747e4fSDavid du Colombier 
2529a747e4fSDavid du Colombier static void
fsattach(Req * r)2539a747e4fSDavid du Colombier fsattach(Req *r)
2549a747e4fSDavid du Colombier {
2559a747e4fSDavid du Colombier 	r->fid->qid = mkqid(QTDIR, Qroot);
2569a747e4fSDavid du Colombier 	r->ofcall.qid = r->fid->qid;
2579a747e4fSDavid du Colombier 	respond(r, nil);
2589a747e4fSDavid du Colombier }
2599a747e4fSDavid du Colombier 
2609a747e4fSDavid du Colombier static struct {
2619a747e4fSDavid du Colombier 	char *name;
2629a747e4fSDavid du Colombier 	int qidpath;
2639a747e4fSDavid du Colombier 	ulong perm;
2649a747e4fSDavid du Colombier } dirtab[] = {
2659a747e4fSDavid du Colombier 	"confirm",	Qconfirm,	0600|DMEXCL,		/* we know this is slot #0 below */
2669a747e4fSDavid du Colombier 	"needkey", Qneedkey,	0600|DMEXCL,		/* we know this is slot #1 below */
267fb7f0c93SDavid du Colombier 	"ctl",		Qctl,			0644,
2689a747e4fSDavid du Colombier 	"rpc",	Qrpc,		0666,
2699a747e4fSDavid du Colombier 	"proto",	Qprotolist,	0444,
2709a747e4fSDavid du Colombier 	"log",	Qlog,		0400|DMEXCL,
2719a747e4fSDavid du Colombier };
2729a747e4fSDavid du Colombier static int inuse[nelem(dirtab)];
2739a747e4fSDavid du Colombier int *confirminuse = &inuse[0];
2749a747e4fSDavid du Colombier int *needkeyinuse = &inuse[1];
2759a747e4fSDavid du Colombier 
2769a747e4fSDavid du Colombier static void
fillstat(Dir * dir,char * name,int type,int path,ulong perm)2779a747e4fSDavid du Colombier fillstat(Dir *dir, char *name, int type, int path, ulong perm)
2789a747e4fSDavid du Colombier {
2799a747e4fSDavid du Colombier 	dir->name = estrdup(name);
280fb7f0c93SDavid du Colombier 	dir->uid = estrdup(owner);
281fb7f0c93SDavid du Colombier 	dir->gid = estrdup(owner);
2829a747e4fSDavid du Colombier 	dir->mode = perm;
2839a747e4fSDavid du Colombier 	dir->length = 0;
2849a747e4fSDavid du Colombier 	dir->qid = mkqid(type, path);
2859a747e4fSDavid du Colombier 	dir->atime = time(0);
2869a747e4fSDavid du Colombier 	dir->mtime = time(0);
2879a747e4fSDavid du Colombier 	dir->muid = estrdup("");
2889a747e4fSDavid du Colombier }
2899a747e4fSDavid du Colombier 
2909a747e4fSDavid du Colombier static int
rootdirgen(int n,Dir * dir,void *)2919a747e4fSDavid du Colombier rootdirgen(int n, Dir *dir, void*)
2929a747e4fSDavid du Colombier {
2939a747e4fSDavid du Colombier 	if(n > 0)
2949a747e4fSDavid du Colombier 		return -1;
2959a747e4fSDavid du Colombier 	fillstat(dir, "factotum", QTDIR, Qfactotum, DMDIR|0555);
2969a747e4fSDavid du Colombier 	return 0;
2979a747e4fSDavid du Colombier }
2989a747e4fSDavid du Colombier 
2999a747e4fSDavid du Colombier static int
fsdirgen(int n,Dir * dir,void *)3009a747e4fSDavid du Colombier fsdirgen(int n, Dir *dir, void*)
3019a747e4fSDavid du Colombier {
3029a747e4fSDavid du Colombier 	if(n >= nelem(dirtab))
3039a747e4fSDavid du Colombier 		return -1;
3049a747e4fSDavid du Colombier 	fillstat(dir, dirtab[n].name, 0, dirtab[n].qidpath, dirtab[n].perm);
3059a747e4fSDavid du Colombier 	return 0;
3069a747e4fSDavid du Colombier }
3079a747e4fSDavid du Colombier 
3089a747e4fSDavid du Colombier static char*
fswalk1(Fid * fid,char * name,Qid * qid)3099a747e4fSDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
3109a747e4fSDavid du Colombier {
3119a747e4fSDavid du Colombier 	int i;
3129a747e4fSDavid du Colombier 
3139a747e4fSDavid du Colombier 	switch((ulong)fid->qid.path){
3149a747e4fSDavid du Colombier 	default:
3159a747e4fSDavid du Colombier 		return "cannot happen";
3169a747e4fSDavid du Colombier 	case Qroot:
3179a747e4fSDavid du Colombier 		if(strcmp(name, "factotum") == 0){
3189a747e4fSDavid du Colombier 			*qid = mkqid(QTDIR, Qfactotum);
3199a747e4fSDavid du Colombier 			fid->qid = *qid;
3209a747e4fSDavid du Colombier 			return nil;
3219a747e4fSDavid du Colombier 		}
3229a747e4fSDavid du Colombier 		if(strcmp(name, "..") == 0){
3239a747e4fSDavid du Colombier 			*qid = fid->qid;
3249a747e4fSDavid du Colombier 			return nil;
3259a747e4fSDavid du Colombier 		}
3269a747e4fSDavid du Colombier 		return "not found";
3279a747e4fSDavid du Colombier 	case Qfactotum:
3289a747e4fSDavid du Colombier 		for(i=0; i<nelem(dirtab); i++)
3299a747e4fSDavid du Colombier 			if(strcmp(name, dirtab[i].name) == 0){
3309a747e4fSDavid du Colombier 				*qid = mkqid(0, dirtab[i].qidpath);
3319a747e4fSDavid du Colombier 				fid->qid = *qid;
3329a747e4fSDavid du Colombier 				return nil;
3339a747e4fSDavid du Colombier 			}
3349a747e4fSDavid du Colombier 		if(strcmp(name, "..") == 0){
3359a747e4fSDavid du Colombier 			*qid = mkqid(QTDIR, Qroot);
3369a747e4fSDavid du Colombier 			fid->qid = *qid;
3379a747e4fSDavid du Colombier 			return nil;
3389a747e4fSDavid du Colombier 		}
3399a747e4fSDavid du Colombier 		return "not found";
3409a747e4fSDavid du Colombier 	}
3419a747e4fSDavid du Colombier }
3429a747e4fSDavid du Colombier 
3439a747e4fSDavid du Colombier static void
fsstat(Req * r)3449a747e4fSDavid du Colombier fsstat(Req *r)
3459a747e4fSDavid du Colombier {
3469a747e4fSDavid du Colombier 	int i;
3479a747e4fSDavid du Colombier 	ulong path;
3489a747e4fSDavid du Colombier 
3499a747e4fSDavid du Colombier 	path = r->fid->qid.path;
3509a747e4fSDavid du Colombier 	if(path == Qroot){
3519a747e4fSDavid du Colombier 		fillstat(&r->d, "/", QTDIR, Qroot, 0555|DMDIR);
3529a747e4fSDavid du Colombier 		respond(r, nil);
3539a747e4fSDavid du Colombier 		return;
3549a747e4fSDavid du Colombier 	}
3559a747e4fSDavid du Colombier 	if(path == Qfactotum){
3569a747e4fSDavid du Colombier 		fillstat(&r->d, "factotum", QTDIR, Qfactotum, 0555|DMDIR);
3579a747e4fSDavid du Colombier 		respond(r, nil);
3589a747e4fSDavid du Colombier 		return;
3599a747e4fSDavid du Colombier 	}
3609a747e4fSDavid du Colombier 	for(i=0; i<nelem(dirtab); i++)
3619a747e4fSDavid du Colombier 		if(dirtab[i].qidpath == path){
3629a747e4fSDavid du Colombier 			fillstat(&r->d, dirtab[i].name, 0, dirtab[i].qidpath, dirtab[i].perm);
3639a747e4fSDavid du Colombier 			respond(r, nil);
3649a747e4fSDavid du Colombier 			return;
3659a747e4fSDavid du Colombier 		}
3669a747e4fSDavid du Colombier 	respond(r, "file not found");
3679a747e4fSDavid du Colombier }
3689a747e4fSDavid du Colombier 
3699a747e4fSDavid du Colombier static void
fsopen(Req * r)3709a747e4fSDavid du Colombier fsopen(Req *r)
3719a747e4fSDavid du Colombier {
3729a747e4fSDavid du Colombier 	int i, *p, perm;
3739a747e4fSDavid du Colombier 	static int need[4] = {4, 2, 6, 1};
374d35914a8SDavid du Colombier 	int n;
3759a747e4fSDavid du Colombier 	Fsstate *fss;
3769a747e4fSDavid du Colombier 
3779a747e4fSDavid du Colombier 	p = nil;
3789a747e4fSDavid du Colombier 	for(i=0; i<nelem(dirtab); i++)
3799a747e4fSDavid du Colombier 		if(dirtab[i].qidpath == r->fid->qid.path)
3809a747e4fSDavid du Colombier 			break;
3819a747e4fSDavid du Colombier 	if(i < nelem(dirtab)){
3829a747e4fSDavid du Colombier 		if(dirtab[i].perm & DMEXCL)
3839a747e4fSDavid du Colombier 			p = &inuse[i];
384fb7f0c93SDavid du Colombier 		if(strcmp(r->fid->uid, owner) == 0)
3859a747e4fSDavid du Colombier 			perm = dirtab[i].perm>>6;
3869a747e4fSDavid du Colombier 		else
3879a747e4fSDavid du Colombier 			perm = dirtab[i].perm;
3889a747e4fSDavid du Colombier 	}else
3899a747e4fSDavid du Colombier 		perm = 5;
3909a747e4fSDavid du Colombier 
391d35914a8SDavid du Colombier 	n = need[r->ifcall.mode&3];
392d35914a8SDavid du Colombier 	if((r->ifcall.mode&~(3|OTRUNC)) || ((perm&n) != n)){
3939a747e4fSDavid du Colombier 		respond(r, "permission denied");
3949a747e4fSDavid du Colombier 		return;
3959a747e4fSDavid du Colombier 	}
3969a747e4fSDavid du Colombier 	if(p){
3979a747e4fSDavid du Colombier 		if(*p){
3989a747e4fSDavid du Colombier 			respond(r, "file in use");
3999a747e4fSDavid du Colombier 			return;
4009a747e4fSDavid du Colombier 		}
4019a747e4fSDavid du Colombier 		(*p)++;
4029a747e4fSDavid du Colombier 	}
4039a747e4fSDavid du Colombier 
4049a747e4fSDavid du Colombier 	r->fid->aux = fss = emalloc(sizeof(Fsstate));
405d9306527SDavid du Colombier 	fss->phase = Notstarted;
4069a747e4fSDavid du Colombier 	fss->sysuser = r->fid->uid;
4079a747e4fSDavid du Colombier 	fss->attr = nil;
4089a747e4fSDavid du Colombier 	strcpy(fss->err, "factotum/fs.c no error");
4099a747e4fSDavid du Colombier 	respond(r, nil);
4109a747e4fSDavid du Colombier }
4119a747e4fSDavid du Colombier 
4129a747e4fSDavid du Colombier static void
fsdestroyfid(Fid * fid)4139a747e4fSDavid du Colombier fsdestroyfid(Fid *fid)
4149a747e4fSDavid du Colombier {
4159a747e4fSDavid du Colombier 	int i;
4169a747e4fSDavid du Colombier 	Fsstate *fss;
4179a747e4fSDavid du Colombier 
4189a747e4fSDavid du Colombier 	if(fid->omode != -1){
4199a747e4fSDavid du Colombier 		for(i=0; i<nelem(dirtab); i++)
4209a747e4fSDavid du Colombier 			if(dirtab[i].qidpath == fid->qid.path)
4219a747e4fSDavid du Colombier 				if(dirtab[i].perm&DMEXCL)
4229a747e4fSDavid du Colombier 					inuse[i] = 0;
4239a747e4fSDavid du Colombier 	}
4249a747e4fSDavid du Colombier 
4259a747e4fSDavid du Colombier 	fss = fid->aux;
4269a747e4fSDavid du Colombier 	if(fss == nil)
4279a747e4fSDavid du Colombier 		return;
4289a747e4fSDavid du Colombier 	if(fss->ps)
4299a747e4fSDavid du Colombier 		(*fss->proto->close)(fss);
4309a747e4fSDavid du Colombier 	_freeattr(fss->attr);
4319a747e4fSDavid du Colombier 	free(fss);
4329a747e4fSDavid du Colombier }
4339a747e4fSDavid du Colombier 
4349a747e4fSDavid du Colombier static int
readlist(int off,int (* gen)(int,char *,uint,Fsstate *),Req * r,Fsstate * fss)435fb7f0c93SDavid du Colombier readlist(int off, int (*gen)(int, char*, uint, Fsstate*), Req *r, Fsstate *fss)
4369a747e4fSDavid du Colombier {
4379a747e4fSDavid du Colombier 	char *a, *ea;
4389a747e4fSDavid du Colombier 	int n;
4399a747e4fSDavid du Colombier 
4409a747e4fSDavid du Colombier 	a = r->ofcall.data;
4419a747e4fSDavid du Colombier 	ea = a+r->ifcall.count;
4429a747e4fSDavid du Colombier 	for(;;){
443fb7f0c93SDavid du Colombier 		n = (*gen)(off, a, ea-a, fss);
4449a747e4fSDavid du Colombier 		if(n == 0){
4459a747e4fSDavid du Colombier 			r->ofcall.count = a - (char*)r->ofcall.data;
4469a747e4fSDavid du Colombier 			return off;
4479a747e4fSDavid du Colombier 		}
4489a747e4fSDavid du Colombier 		a += n;
4499a747e4fSDavid du Colombier 		off++;
4509a747e4fSDavid du Colombier 	}
4519a747e4fSDavid du Colombier }
4529a747e4fSDavid du Colombier 
4533b86f2f8SDavid du Colombier enum { Nearend = 2, };			/* at least room for \n and NUL */
4543b86f2f8SDavid du Colombier 
4553b86f2f8SDavid du Colombier /* result in `a', of `n' bytes maximum */
4569a747e4fSDavid du Colombier static int
keylist(int i,char * a,uint n,Fsstate * fss)457fb7f0c93SDavid du Colombier keylist(int i, char *a, uint n, Fsstate *fss)
4589a747e4fSDavid du Colombier {
4593b86f2f8SDavid du Colombier 	int wb;
460260f7b65SDavid du Colombier 	Keyinfo ki;
4619a747e4fSDavid du Colombier 	Key *k;
4623b86f2f8SDavid du Colombier 	static char zero[Nearend];
4639a747e4fSDavid du Colombier 
464fb7f0c93SDavid du Colombier 	k = nil;
465260f7b65SDavid du Colombier 	mkkeyinfo(&ki, fss, nil);
466260f7b65SDavid du Colombier 	ki.attr = nil;
467260f7b65SDavid du Colombier 	ki.skip = i;
468260f7b65SDavid du Colombier 	ki.usedisabled = 1;
469260f7b65SDavid du Colombier 	if(findkey(&k, &ki, "") != RpcOk)
4709a747e4fSDavid du Colombier 		return 0;
4713b86f2f8SDavid du Colombier 
4723b86f2f8SDavid du Colombier 	memset(a + n - Nearend, 0, Nearend);
4733b86f2f8SDavid du Colombier 	wb = snprint(a, n, "key %A %N\n", k->attr, k->privattr);
474fb7f0c93SDavid du Colombier 	closekey(k);
4753b86f2f8SDavid du Colombier 	if (wb >= n - 1 && a[n - 2] != '\n' && a[n - 2] != '\0') {
4763b86f2f8SDavid du Colombier 		/* line won't fit in `a', so just truncate */
4773b86f2f8SDavid du Colombier 		strcpy(a + n - 2, "\n");
4789a747e4fSDavid du Colombier 		return 0;
4793b86f2f8SDavid du Colombier 	}
4803b86f2f8SDavid du Colombier 	return wb;
4819a747e4fSDavid du Colombier }
4829a747e4fSDavid du Colombier 
4839a747e4fSDavid du Colombier static int
protolist(int i,char * a,uint n,Fsstate * fss)484fb7f0c93SDavid du Colombier protolist(int i, char *a, uint n, Fsstate *fss)
4859a747e4fSDavid du Colombier {
486fb7f0c93SDavid du Colombier 	USED(fss);
487fb7f0c93SDavid du Colombier 
4889a747e4fSDavid du Colombier 	if(i >= nelem(prototab)-1)
4899a747e4fSDavid du Colombier 		return 0;
4909a747e4fSDavid du Colombier 	if(strlen(prototab[i]->name)+1 > n)
4919a747e4fSDavid du Colombier 		return 0;
4929a747e4fSDavid du Colombier 	n = strlen(prototab[i]->name)+1;
4939a747e4fSDavid du Colombier 	memmove(a, prototab[i]->name, n-1);
4949a747e4fSDavid du Colombier 	a[n-1] = '\n';
4959a747e4fSDavid du Colombier 	return n;
4969a747e4fSDavid du Colombier }
4979a747e4fSDavid du Colombier 
4989a747e4fSDavid du Colombier static void
fsread(Req * r)4999a747e4fSDavid du Colombier fsread(Req *r)
5009a747e4fSDavid du Colombier {
5019a747e4fSDavid du Colombier 	Fsstate *s;
5029a747e4fSDavid du Colombier 
5039a747e4fSDavid du Colombier 	s = r->fid->aux;
5049a747e4fSDavid du Colombier 	switch((ulong)r->fid->qid.path){
5059a747e4fSDavid du Colombier 	default:
5069a747e4fSDavid du Colombier 		respond(r, "bug in fsread");
5079a747e4fSDavid du Colombier 		break;
5089a747e4fSDavid du Colombier 	case Qroot:
5099a747e4fSDavid du Colombier 		dirread9p(r, rootdirgen, nil);
5109a747e4fSDavid du Colombier 		respond(r, nil);
5119a747e4fSDavid du Colombier 		break;
5129a747e4fSDavid du Colombier 	case Qfactotum:
5139a747e4fSDavid du Colombier 		dirread9p(r, fsdirgen, nil);
5149a747e4fSDavid du Colombier 		respond(r, nil);
5159a747e4fSDavid du Colombier 		break;
5169a747e4fSDavid du Colombier 	case Qrpc:
5179a747e4fSDavid du Colombier 		rpcread(r);
5189a747e4fSDavid du Colombier 		break;
5199a747e4fSDavid du Colombier 	case Qneedkey:
5209a747e4fSDavid du Colombier 		needkeyread(r);
5219a747e4fSDavid du Colombier 		break;
5229a747e4fSDavid du Colombier 	case Qconfirm:
5239a747e4fSDavid du Colombier 		confirmread(r);
5249a747e4fSDavid du Colombier 		break;
5259a747e4fSDavid du Colombier 	case Qlog:
5269a747e4fSDavid du Colombier 		logread(r);
5279a747e4fSDavid du Colombier 		break;
5289a747e4fSDavid du Colombier 	case Qctl:
529fb7f0c93SDavid du Colombier 		s->listoff = readlist(s->listoff, keylist, r, s);
5309a747e4fSDavid du Colombier 		respond(r, nil);
5319a747e4fSDavid du Colombier 		break;
5329a747e4fSDavid du Colombier 	case Qprotolist:
533fb7f0c93SDavid du Colombier 		s->listoff = readlist(s->listoff, protolist, r, s);
5349a747e4fSDavid du Colombier 		respond(r, nil);
5359a747e4fSDavid du Colombier 		break;
5369a747e4fSDavid du Colombier 	}
5379a747e4fSDavid du Colombier }
5389a747e4fSDavid du Colombier 
5399a747e4fSDavid du Colombier static void
fswrite(Req * r)5409a747e4fSDavid du Colombier fswrite(Req *r)
5419a747e4fSDavid du Colombier {
5429a747e4fSDavid du Colombier 	int ret;
5439a747e4fSDavid du Colombier 	char err[ERRMAX], *s;
5449a747e4fSDavid du Colombier 
5459a747e4fSDavid du Colombier 	switch((ulong)r->fid->qid.path){
5469a747e4fSDavid du Colombier 	default:
5479a747e4fSDavid du Colombier 		respond(r, "bug in fswrite");
5489a747e4fSDavid du Colombier 		break;
5499a747e4fSDavid du Colombier 	case Qrpc:
5509a747e4fSDavid du Colombier 		rpcwrite(r);
5519a747e4fSDavid du Colombier 		break;
5529a747e4fSDavid du Colombier 	case Qneedkey:
5539a747e4fSDavid du Colombier 	case Qconfirm:
5549a747e4fSDavid du Colombier 	case Qctl:
5559a747e4fSDavid du Colombier 		s = emalloc(r->ifcall.count+1);
5569a747e4fSDavid du Colombier 		memmove(s, r->ifcall.data, r->ifcall.count);
5579a747e4fSDavid du Colombier 		s[r->ifcall.count] = '\0';
5589a747e4fSDavid du Colombier 		switch((ulong)r->fid->qid.path){
5599a747e4fSDavid du Colombier 		default:
5609a747e4fSDavid du Colombier 			abort();
5619a747e4fSDavid du Colombier 		case Qneedkey:
5629a747e4fSDavid du Colombier 			ret = needkeywrite(s);
5639a747e4fSDavid du Colombier 			break;
5649a747e4fSDavid du Colombier 		case Qconfirm:
5659a747e4fSDavid du Colombier 			ret = confirmwrite(s);
5669a747e4fSDavid du Colombier 			break;
5679a747e4fSDavid du Colombier 		case Qctl:
568260f7b65SDavid du Colombier 			ret = ctlwrite(s, 0);
5699a747e4fSDavid du Colombier 			break;
5709a747e4fSDavid du Colombier 		}
5719a747e4fSDavid du Colombier 		free(s);
5729a747e4fSDavid du Colombier 		if(ret < 0){
5739a747e4fSDavid du Colombier 			rerrstr(err, sizeof err);
5749a747e4fSDavid du Colombier 			respond(r, err);
5759a747e4fSDavid du Colombier 		}else{
5769a747e4fSDavid du Colombier 			r->ofcall.count = r->ifcall.count;
5779a747e4fSDavid du Colombier 			respond(r, nil);
5789a747e4fSDavid du Colombier 		}
5799a747e4fSDavid du Colombier 		break;
5809a747e4fSDavid du Colombier 	}
5819a747e4fSDavid du Colombier }
5829a747e4fSDavid du Colombier 
5839a747e4fSDavid du Colombier static void
fsflush(Req * r)5849a747e4fSDavid du Colombier fsflush(Req *r)
5859a747e4fSDavid du Colombier {
5869a747e4fSDavid du Colombier 	confirmflush(r->oldreq);
5879a747e4fSDavid du Colombier 	needkeyflush(r->oldreq);
5889a747e4fSDavid du Colombier 	logflush(r->oldreq);
5899a747e4fSDavid du Colombier 	respond(r, nil);
5909a747e4fSDavid du Colombier }
5919a747e4fSDavid du Colombier 
5929a747e4fSDavid du Colombier Srv fs = {
5939a747e4fSDavid du Colombier .attach=	fsattach,
5949a747e4fSDavid du Colombier .walk1=	fswalk1,
5959a747e4fSDavid du Colombier .open=	fsopen,
5969a747e4fSDavid du Colombier .read=	fsread,
5979a747e4fSDavid du Colombier .write=	fswrite,
5989a747e4fSDavid du Colombier .stat=	fsstat,
5999a747e4fSDavid du Colombier .flush=	fsflush,
6009a747e4fSDavid du Colombier .destroyfid=	fsdestroyfid,
6019a747e4fSDavid du Colombier };
6029a747e4fSDavid du Colombier 
603