henesyinit from p9fd787fda5 years agoHistory
854 lines · 15.1 KB · C
RawDownload
/* * exportfs - Export a plan 9 name space across a network */#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <libsec.h>#define Extern#include "exportfs.h" #define QIDPATH	((1LL<<48)-1)vlong newqid = 0; enum {	Encnone,	Encssl,	Enctls,}; void (*fcalls[])(Fsrpc*) ={	[Tversion]	Xversion,	[Tauth]	Xauth,	[Tflush]	Xflush,	[Tattach]	Xattach,	[Twalk]		Xwalk,	[Topen]		slave,	[Tcreate]	Xcreate,	[Tclunk]	Xclunk,	[Tread]		slave,	[Twrite]	slave,	[Tremove]	Xremove,	[Tstat]		Xstat,	[Twstat]	Xwstat,}; /* accounting and debugging counters */int	filecnt;int	freecnt;int	qidcnt;int	qfreecnt;int	ncollision; int	netfd;int	srvfd = -1;int	nonone = 1;char	*filterp;char	*ealgs = "rc4_256 sha1";char *aanfilter = "/bin/aan";int encproto = Encnone;static void	mksecret(char *, uchar *);static int localread9pmsg(int, void *, uint, ulong *);static char *anstring  = "il!*!0";int	filter(int, char *); voidusage(void){	fprint(2, "usage: %s [-ads] [-f dbgfile] [-m msize] [-r root] [-S srvfile] [-e 'crypt hash'] [-A announce-string]\n", argv0);	fatal("usage");} voidmain(int argc, char **argv){	char buf[ERRMAX], ebuf[ERRMAX];	Fsrpc *r;	int n;	char *dbfile, *srv, *file;	AuthInfo *ai;	ulong initial; 	dbfile = "/tmp/exportdb";	srv = nil;	srvfd = -1; 	ai = nil;	ARGBEGIN{	case 'a':		/*		 * We use p9any so we don't have to visit this code again, with the		 * cost that this code is incompatible with the old world, which		 * requires p9sk2. (The two differ in who talks first, so compatibility		 * is awkward.)		 */		ai = auth_proxy(0, auth_getkey, "proto=p9any role=server");		if(ai == nil)			fatal("auth_proxy: %r");		if(nonone && strcmp(ai->cuid, "none") == 0)			fatal("exportfs by none disallowed");		if(auth_chuid(ai, nil) < 0)			fatal("auth_chuid: %r");		if(newns(ai->cuid, 0) < 0)			fatal("newns");		putenv("service", "exportfs");		break; 	case 'e':		ealgs = ARGF();		if(ealgs == nil)			usage();		if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)			ealgs = nil;		break; 	case 'S':		if(srvfd != -1)			usage();		file = EARGF(usage());		if((srvfd = open(file, ORDWR)) < 0)			sysfatal("open '%s': %r", file);		break; 	case 'd':		dbg++;		break; 	case 'f':		dbfile = EARGF(usage());		break; 	case 'F':		/* accepted but ignored, for backwards compatibility */		break; 	case 'm':		messagesize = strtoul(EARGF(usage()), nil, 0);		break; 	case 'r':		srv = EARGF(usage());		break; 	case 's':		srv = "/";		break; 	case 'A':		anstring = EARGF(usage());		break; 	default:		usage();	}ARGEND	USED(argc, argv); 	if(dbg) {		n = create(dbfile, OWRITE|OTRUNC, 0666);		dup(n, DFD);		close(n);	} 	if(srvfd >= 0 && srv){		fprint(2, "exportfs: -S cannot be used with -r or -s\n");		usage();	} 	DEBUG(DFD, "exportfs: started\n"); 	rfork(RFNOTEG); 	if(messagesize == 0){		messagesize = iounit(netfd);		if(messagesize == 0)			messagesize = 8192+IOHDRSZ;	} 	Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs);//	for(i=0; i<Nr_workbufs; i++)//		Workq[i].buf = emallocz(messagesize);	fhash = emallocz(sizeof(Fid*)*FHASHSIZE); 	fmtinstall('F', fcallfmt); 	/*	 * Get tree to serve from network connection,	 * check we can get there and ack the connection 	 */	if(srvfd != -1) {		/* do nothing */	}	else if(srv) {		chdir(srv);		DEBUG(DFD, "invoked as server for %s", srv);		strncpy(buf, srv, sizeof buf);	}	else {		buf[0] = 0;		n = read(0, buf, sizeof(buf)-1);		if(n < 0) {			errstr(buf, sizeof buf);			fprint(0, "read(0): %s", buf);			DEBUG(DFD, "read(0): %s", buf);			exits(buf);		}		buf[n] = 0;		if(chdir(buf) < 0) {			errstr(ebuf, sizeof ebuf);			fprint(0, "chdir(%d:\"%s\"): %s", n, buf, ebuf);			DEBUG(DFD, "chdir(%d:\"%s\"): %s", n, buf, ebuf);			exits(ebuf);		}	} 	DEBUG(DFD, "initing root\n");	initroot(); 	DEBUG(DFD, "exportfs: %s\n", buf); 	if(srv == nil && srvfd == -1 && write(0, "OK", 2) != 2)		fatal("open ack write"); 	if ((n = readn(netfd, &initial, sizeof(ulong))) < 0)		fatal("can't read initial string: %r\n");	assert(n == sizeof(ulong)); 	if (!strncmp((char *)&initial, "impo", sizeof(ulong))) {		char buf[128], *p, *args[3]; 		// New import.  Read import's parameters...		initial = 0; 		p = buf;		while (p - buf < sizeof buf) {			if ((n = read(netfd, p, 1)) < 0)				fatal("can't read impo arguments: %r\n"); 			if (n == 0)				fatal("connection closed while reading arguments\n"); 			if (*p == '\n') 				*p = '\0';			if (*p++ == '\0')				break;		}				if (tokenize(buf, args, nelem(args)) != 2)			fatal("impo arguments invalid: impo%s...\n", buf); 		if (!strcmp(args[0], "aan"))			filterp = aanfilter;		else if (strcmp(args[0], "nofilter"))			fatal("import filter argument unsupported: %s\n", args[0]); 		if (!strcmp(args[1], "ssl"))			encproto = Encssl;		else if (!strcmp(args[1], "tls"))			encproto = Enctls;		else if (strcmp(args[1], "clear"))			fatal("import encryption proto unsupported: %s\n", args[1]); 		if (encproto == Enctls)			sysfatal("%s: tls has not yet been implemented\n", argv[0]);	} 	if (encproto != Encnone && ealgs && ai) {		uchar key[16];		uchar digest[SHA1dlen];		char fromclientsecret[21];		char fromserversecret[21];		int i; 		memmove(key+4, ai->secret, ai->nsecret); 		/* exchange random numbers */		srand(truerand());		for(i = 0; i < 4; i++)			key[i+12] = rand(); 		if (initial) 			fatal("Protocol botch: old import\n");		if(readn(netfd, key, 4) != 4)			fatal("can't read key part; %r\n"); 		if(write(netfd, key+12, 4) != 4)			fatal("can't write key part; %r\n"); 		/* scramble into two secrets */		sha1(key, sizeof(key), digest, nil);		mksecret(fromclientsecret, digest);		mksecret(fromserversecret, digest+10); 		if (filterp)			netfd = filter(netfd, filterp); 		switch (encproto) {		case Encssl:			netfd = pushssl(netfd, ealgs, fromserversecret, 						fromclientsecret, nil);			break;		case Enctls:		default:			fatal("Unsupported encryption protocol\n");		} 		if(netfd < 0)			fatal("can't establish ssl connection: %r");	}	else if (filterp) {		if (initial) 			fatal("Protocol botch: don't know how to deal with this\n");		netfd = filter(netfd, filterp);	} 	/*	 * Start serving file requests from the network	 */	for(;;) {		r = getsbuf();		if(r == 0)			fatal("Out of service buffers");					n = localread9pmsg(netfd, r->buf, messagesize, &initial);		if(n <= 0)			fatal(nil); 		if(convM2S(r->buf, n, &r->work) == 0)			fatal("convM2S format error"); 		DEBUG(DFD, "%F\n", &r->work);		(fcalls[r->work.type])(r);	}} // WARNING: Replace this with the original version as soon as all // _old_ imports have been replaced with negotiating imports.  Also// cpu relies on this (which needs to be fixed!) -- pb.static intlocalread9pmsg(int fd, void *abuf, uint n, ulong *initial){	int m, len;	uchar *buf; 	buf = abuf; 	/* read count */	assert(BIT32SZ == sizeof(ulong));	if (*initial) {		memcpy(buf, initial, BIT32SZ);		*initial = 0;	}	else {		m = readn(fd, buf, BIT32SZ);		if(m != BIT32SZ){			if(m < 0)				return -1;			return 0;		}	} 	len = GBIT32(buf);	if(len <= BIT32SZ || len > n){		werrstr("bad length in 9P2000 message header");		return -1;	}	len -= BIT32SZ;	m = readn(fd, buf+BIT32SZ, len);	if(m < len)		return 0;	return BIT32SZ+m;}voidreply(Fcall *r, Fcall *t, char *err){	uchar *data;	int n; 	t->tag = r->tag;	t->fid = r->fid;	if(err) {		t->type = Rerror;		t->ename = err;	}	else 		t->type = r->type + 1; 	DEBUG(DFD, "\t%F\n", t); 	data = malloc(messagesize);	/* not mallocz; no need to clear */	if(data == nil)		fatal(Enomem);	n = convS2M(t, data, messagesize);	if(write(netfd, data, n)!=n){syslog(0, "exportfs", "short write: %r");		fatal("mount write");}	free(data);} Fid *getfid(int nr){	Fid *f; 	for(f = fidhash(nr); f; f = f->next)		if(f->nr == nr)			return f; 	return 0;} intfreefid(int nr){	Fid *f, **l;	char buf[128]; 	l = &fidhash(nr);	for(f = *l; f; f = f->next) {		if(f->nr == nr) {			if(f->mid) {				sprint(buf, "/mnt/exportfs/%d", f->mid);				unmount(0, buf);				psmap[f->mid] = 0;			}			if(f->f) {				freefile(f->f);				f->f = nil;			}			*l = f->next;			f->next = fidfree;			fidfree = f;			return 1;		}		l = &f->next;	} 	return 0;	} Fid *newfid(int nr){	Fid *new, **l;	int i; 	l = &fidhash(nr);	for(new = *l; new; new = new->next)		if(new->nr == nr)			return 0; 	if(fidfree == 0) {		fidfree = emallocz(sizeof(Fid) * Fidchunk); 		for(i = 0; i < Fidchunk-1; i++)			fidfree[i].next = &fidfree[i+1]; 		fidfree[Fidchunk-1].next = 0;	} 	new = fidfree;	fidfree = new->next; 	memset(new, 0, sizeof(Fid));	new->next = *l;	*l = new;	new->nr = nr;	new->fid = -1;	new->mid = 0; 	return new;	} Fsrpc *getsbuf(void){	static int ap;	int look, rounds;	Fsrpc *wb;	int small_instead_of_fast = 1; 	if(small_instead_of_fast)		ap = 0;	/* so we always start looking at the beginning and reuse buffers */ 	for(rounds = 0; rounds < 10; rounds++) {		for(look = 0; look < Nr_workbufs; look++) {			if(++ap == Nr_workbufs)				ap = 0;			if(Workq[ap].busy == 0)				break;		} 		if(look == Nr_workbufs){			sleep(10 * rounds);			continue;		} 		wb = &Workq[ap];		wb->pid = 0;		wb->canint = 0;		wb->flushtag = NOTAG;		wb->busy = 1;		if(wb->buf == nil)	/* allocate buffers dynamically to keep size down */			wb->buf = emallocz(messagesize);		return wb;	}	fatal("No more work buffers");	return nil;}

Lines 1–500 of 854.