xref: /plan9/sys/src/cmd/unix/u9fs/u9fs.c (revision ad6ca847b1a6a504acb0003cd6c5c6d92687369b)
1 /* already in plan9.h #include <sys/types.h> *//* for struct passwd, struct group, struct stat ... */
2 /* plan9.h is first to get the large file support definitions as early as possible */
3 #include <plan9.h>
4 #include <sys/stat.h>	/* for stat, umask */
5 #include <stdlib.h>	/* for malloc */
6 #include <string.h>	/* for strcpy, memmove */
7 #include <pwd.h>	/* for getpwnam, getpwuid */
8 #include <grp.h>	/* for getgrnam, getgrgid */
9 #include <unistd.h>	/* for gethostname, pread, pwrite, read, write */
10 #include <utime.h>	/* for utime */
11 #include <dirent.h>	/* for readdir */
12 #include <errno.h>	/* for errno */
13 #include <stdio.h>	/* for remove [sic] */
14 #include <fcntl.h>	/* for O_RDONLY, etc. */
15 
16 #include <sys/socket.h>	/* various networking crud */
17 #include <netinet/in.h>
18 #include <netdb.h>
19 
20 #include <fcall.h>
21 #include <oldfcall.h>
22 #include <u9fs.h>
23 
24 /* #ifndef because can be given in makefile */
25 #ifndef DEFAULTLOG
26 #define DEFAULTLOG "/tmp/u9fs.log"
27 #endif
28 
29 char *logfile = DEFAULTLOG;
30 
31 #define S_ISSPECIAL(m) (S_ISCHR(m) || S_ISBLK(m) || S_ISFIFO(m))
32 
33 enum {
34 	Tdot = 1,
35 	Tdotdot
36 };
37 
38 enum {
39 	P9P1,
40 	P9P2000
41 };
42 
43 typedef struct User User;
44 struct User {
45 	int id;
46 	gid_t defaultgid;
47 	char *name;
48 	char **mem;	/* group members */
49 	int nmem;
50 	User *next;
51 };
52 
53 struct Fid {
54 	int fid;
55 	char *path;
56 	struct stat st;
57 	User *u;
58 	int omode;
59 	DIR *dir;
60 	int diroffset;
61 	int fd;
62 	struct dirent *dirent;
63 	int direof;
64 	Fid *next;
65 	Fid *prev;
66 	int auth;
67 	void *authmagic;
68 };
69 
70 void*	emalloc(size_t);
71 void*	erealloc(void*, size_t);
72 char*	estrdup(char*);
73 char*	estrpath(char*, char*, int);
74 void	sysfatal(char*, ...);
75 int	okuser(char*);
76 
77 void	rversion(Fcall*, Fcall*);
78 void	rauth(Fcall*, Fcall*);
79 void	rattach(Fcall*, Fcall*);
80 void	rflush(Fcall*, Fcall*);
81 void	rclone(Fcall*, Fcall*);
82 void	rwalk(Fcall*, Fcall*);
83 void	ropen(Fcall*, Fcall*);
84 void	rcreate(Fcall*, Fcall*);
85 void	rread(Fcall*, Fcall*);
86 void	rwrite(Fcall*, Fcall*);
87 void	rclunk(Fcall*, Fcall*);
88 void	rstat(Fcall*, Fcall*);
89 void	rwstat(Fcall*, Fcall*);
90 void	rclwalk(Fcall*, Fcall*);
91 void	rremove(Fcall*, Fcall*);
92 
93 User*	uname2user(char*);
94 User*	gname2user(char*);
95 User*	uid2user(int);
96 User*	gid2user(int);
97 
98 Fid*	newfid(int, char**);
99 Fid*	oldfidex(int, int, char**);
100 Fid*	oldfid(int, char**);
101 int	fidstat(Fid*, char**);
102 void	freefid(Fid*);
103 
104 int	userchange(User*, char**);
105 int	userwalk(User*, char**, char*, Qid*, char**);
106 int	useropen(Fid*, int, char**);
107 int	usercreate(Fid*, char*, int, long, char**);
108 int	userremove(Fid*, char**);
109 int	userperm(User*, char*, int, int);
110 int	useringroup(User*, User*);
111 
112 Qid	stat2qid(struct stat*);
113 
114 void	getfcallold(int, Fcall*, int);
115 void	putfcallold(int, Fcall*);
116 
117 char	Eauth[] =	"authentication failed";
118 char	Ebadfid[] =	"fid unknown or out of range";
119 char	Ebadoffset[] =	"bad offset in directory read";
120 char	Ebadusefid[] =	"bad use of fid";
121 char	Edirchange[] =	"wstat can't convert between files and directories";
122 char	Eexist[] =	"file or directory already exists";
123 char	Efidactive[] =	"fid already in use";
124 char	Enotdir[] =	"not a directory";
125 char	Enotingroup[] =	"not a member of proposed group";
126 char	Enotowner[] = 	"only owner can change group in wstat";
127 char	Eperm[] =	"permission denied";
128 char	Especial0[] =	"already attached without access to special files";
129 char	Especial1[] =	"already attached with access to special files";
130 char	Especial[] =	"no access to special file";
131 char	Etoolarge[] =	"i/o count too large";
132 char	Eunknowngroup[] = "unknown group";
133 char	Eunknownuser[] = "unknown user";
134 char	Ewstatbuffer[] = "bogus wstat buffer";
135 
136 ulong	msize = IOHDRSZ+8192;
137 uchar*	rxbuf;
138 uchar*	txbuf;
139 void*	databuf;
140 int	connected;
141 int	devallowed;
142 char*	autharg;
143 char*	defaultuser;
144 char	hostname[256];
145 char	remotehostname[256];
146 int	chatty9p = 0;
147 int	network = 1;
148 int	old9p = -1;
149 int	authed;
150 User*	none;
151 
152 Auth *authmethods[] = {	/* first is default */
153 	&authrhosts,
154 	&authp9any,
155 	&authnone,
156 };
157 
158 Auth *auth;
159 
160 /*
161  * frogs: characters not valid in plan9
162  * filenames, keep this list in sync with
163  * /sys/src/9/port/chan.c:1656
164  */
165 char isfrog[256]={
166 	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1,
167 	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1,
168 	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1,
169 	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1,
170 	['/']	1,
171 	[0x7f]	1,
172 };
173 
174 void
getfcallnew(int fd,Fcall * fc,int have)175 getfcallnew(int fd, Fcall *fc, int have)
176 {
177 	int len;
178 
179 	if(have > BIT32SZ)
180 		sysfatal("cannot happen");
181 
182 	if(have < BIT32SZ && readn(fd, rxbuf+have, BIT32SZ-have) != BIT32SZ-have)
183 		sysfatal("couldn't read message");
184 
185 	len = GBIT32(rxbuf);
186 	if(len <= BIT32SZ)
187 		sysfatal("bogus message");
188 
189 	len -= BIT32SZ;
190 	if(readn(fd, rxbuf+BIT32SZ, len) != len)
191 		sysfatal("short message");
192 
193 	if(convM2S(rxbuf, len+BIT32SZ, fc) != len+BIT32SZ)
194 		sysfatal("badly sized message type %d", rxbuf[0]);
195 }
196 
197 void
getfcallold(int fd,Fcall * fc,int have)198 getfcallold(int fd, Fcall *fc, int have)
199 {
200 	int len, n;
201 
202 	if(have > 3)
203 		sysfatal("cannot happen");
204 
205 	if(have < 3 && readn(fd, rxbuf, 3-have) != 3-have)
206 		sysfatal("couldn't read message");
207 
208 	len = oldhdrsize(rxbuf[0]);
209 	if(len < 3)
210 		sysfatal("bad message %d", rxbuf[0]);
211 	if(len > 3 && readn(fd, rxbuf+3, len-3) != len-3)
212 		sysfatal("couldn't read message");
213 
214 	n = iosize(rxbuf);
215 	if(readn(fd, rxbuf+len, n) != n)
216 		sysfatal("couldn't read message");
217 	len += n;
218 
219 	if(convM2Sold(rxbuf, len, fc) != len)
220 		sysfatal("badly sized message type %d", rxbuf[0]);
221 }
222 
223 void
putfcallnew(int wfd,Fcall * tx)224 putfcallnew(int wfd, Fcall *tx)
225 {
226 	uint n;
227 
228 	if((n = convS2M(tx, txbuf, msize)) == 0)
229 		sysfatal("couldn't format message type %d", tx->type);
230 	if(write(wfd, txbuf, n) != n)
231 		sysfatal("couldn't send message");
232 }
233 
234 void
putfcallold(int wfd,Fcall * tx)235 putfcallold(int wfd, Fcall *tx)
236 {
237 	uint n;
238 
239 	if((n = convS2Mold(tx, txbuf, msize)) == 0)
240 		sysfatal("couldn't format message type %d", tx->type);
241 	if(write(wfd, txbuf, n) != n)
242 		sysfatal("couldn't send message");
243 }
244 
245 void
getfcall(int fd,Fcall * fc)246 getfcall(int fd, Fcall *fc)
247 {
248 	if(old9p == 1){
249 		getfcallold(fd, fc, 0);
250 		return;
251 	}
252 	if(old9p == 0){
253 		getfcallnew(fd, fc, 0);
254 		return;
255 	}
256 
257 	/* auto-detect */
258 	if(readn(fd, rxbuf, 3) != 3)
259 		sysfatal("couldn't read message");
260 
261 	/* is it an old (9P1) message? */
262 	if(50 <= rxbuf[0] && rxbuf[0] <= 87 && (rxbuf[0]&1)==0 && GBIT16(rxbuf+1) == 0xFFFF){
263 		old9p = 1;
264 		getfcallold(fd, fc, 3);
265 		return;
266 	}
267 
268 	getfcallnew(fd, fc, 3);
269 	old9p = 0;
270 }
271 
272 void
seterror(Fcall * f,char * error)273 seterror(Fcall *f, char *error)
274 {
275 	f->type = Rerror;
276 	f->ename = error ? error : "programmer error";
277 }
278 
279 int
isowner(User * u,Fid * f)280 isowner(User *u, Fid *f)
281 {
282 	return u->id == f->st.st_uid;
283 }
284 
285 
286 
287 void
serve(int rfd,int wfd)288 serve(int rfd, int wfd)
289 {
290 	Fcall rx, tx;
291 
292 	for(;;){
293 		getfcall(rfd, &rx);
294 
295 		if(chatty9p)
296 			fprint(2, "<- %F\n", &rx);
297 
298 		memset(&tx, 0, sizeof tx);
299 		tx.type = rx.type+1;
300 		tx.tag = rx.tag;
301 		switch(rx.type){
302 		case Tflush:
303 			break;
304 		case Tversion:
305 			rversion(&rx, &tx);
306 			break;
307 		case Tauth:
308 			rauth(&rx, &tx);
309 			break;
310 		case Tattach:
311 			rattach(&rx, &tx);
312 			break;
313 		case Twalk:
314 			rwalk(&rx, &tx);
315 			break;
316 		case Tstat:
317 			tx.stat = databuf;
318 			rstat(&rx, &tx);
319 			break;
320 		case Twstat:
321 			rwstat(&rx, &tx);
322 			break;
323 		case Topen:
324 			ropen(&rx, &tx);
325 			break;
326 		case Tcreate:
327 			rcreate(&rx, &tx);
328 			break;
329 		case Tread:
330 			tx.data = databuf;
331 			rread(&rx, &tx);
332 			break;
333 		case Twrite:
334 			rwrite(&rx, &tx);
335 			break;
336 		case Tclunk:
337 			rclunk(&rx, &tx);
338 			break;
339 		case Tremove:
340 			rremove(&rx, &tx);
341 			break;
342 		default:
343 			fprint(2, "unknown message %F\n", &rx);
344 			seterror(&tx, "bad message");
345 			break;
346 		}
347 
348 		if(chatty9p)
349 			fprint(2, "-> %F\n", &tx);
350 
351 		(old9p ? putfcallold : putfcallnew)(wfd, &tx);
352 	}
353 }
354 
355 void
rversion(Fcall * rx,Fcall * tx)356 rversion(Fcall *rx, Fcall *tx)
357 {
358 	if(msize > rx->msize)
359 		msize = rx->msize;
360 	tx->msize = msize;
361 	if(strncmp(rx->version, "9P", 2) != 0)
362 		tx->version = "unknown";
363 	else
364 		tx->version = "9P2000";
365 }
366 
367 void
rauth(Fcall * rx,Fcall * tx)368 rauth(Fcall *rx, Fcall *tx)
369 {
370 	char *e;
371 
372 	if((e = auth->auth(rx, tx)) != nil)
373 		seterror(tx, e);
374 }
375 
376 void
rattach(Fcall * rx,Fcall * tx)377 rattach(Fcall *rx, Fcall *tx)
378 {
379 	char *e;
380 	Fid *fid;
381 	User *u;
382 
383 	if(rx->aname == nil)
384 		rx->aname = "";
385 
386 	if(strcmp(rx->aname, "device") == 0){
387 		if(connected && !devallowed){
388 			seterror(tx, Especial0);
389 			return;
390 		}
391 		devallowed = 1;
392 	}else{
393 		if(connected && devallowed){
394 			seterror(tx, Especial1);
395 			return;
396 		}
397 	}
398 
399 	if(strcmp(rx->uname, "none") == 0){
400 		if(authed == 0){
401 			seterror(tx, Eauth);
402 			return;
403 		}
404 		if (none != nil)
405 			rx->uname = none->name;
406 	} else {
407 		if((e = auth->attach(rx, tx)) != nil){
408 			seterror(tx, e);
409 			return;
410 		}
411 		authed++;
412 	}
413 
414 	if((fid = newfid(rx->fid, &e)) == nil){
415 		seterror(tx, e);
416 		return;
417 	}
418 	fid->path = estrdup("/");
419 	if(fidstat(fid, &e) < 0){
420 		seterror(tx, e);
421 		freefid(fid);
422 		return;
423 	}
424 
425 	if(defaultuser)
426 		rx->uname = defaultuser;
427 
428 	if((u = uname2user(rx->uname)) == nil
429 	|| (!defaultuser && u->id == 0)){
430 		/* we don't know anyone named root... */
431 		seterror(tx, Eunknownuser);
432 		freefid(fid);
433 		return;
434 	}
435 
436 	fid->u = u;
437 	tx->qid = stat2qid(&fid->st);
438 	return;
439 }
440 
441 void
rwalk(Fcall * rx,Fcall * tx)442 rwalk(Fcall *rx, Fcall *tx)
443 {
444 	int i;
445 	char *path, *e;
446 	Fid *fid, *nfid;
447 
448 	e = nil;
449 	if((fid = oldfid(rx->fid, &e)) == nil){
450 		seterror(tx, e);
451 		return;
452 	}
453 
454 	if(fid->omode != -1){
455 		seterror(tx, Ebadusefid);
456 		return;
457 	}
458 
459 	if(fidstat(fid, &e) < 0){
460 		seterror(tx, e);
461 		return;
462 	}
463 
464 	if(!S_ISDIR(fid->st.st_mode) && rx->nwname){
465 		seterror(tx, Enotdir);
466 		return;
467 	}
468 
469 	nfid = nil;
470 	if(rx->newfid != rx->fid && (nfid = newfid(rx->newfid, &e)) == nil){
471 		seterror(tx, e);
472 		return;
473 	}
474 
475 	path = estrdup(fid->path);
476 	e = nil;
477 	for(i=0; i<rx->nwname; i++)
478 		if(userwalk(fid->u, &path, rx->wname[i], &tx->wqid[i], &e) < 0)
479 			break;
480 
481 	if(i == rx->nwname){		/* successful clone or walk */
482 		tx->nwqid = i;
483 		if(nfid){
484 			nfid->path = path;
485 			nfid->u = fid->u;
486 		}else{
487 			free(fid->path);
488 			fid->path = path;
489 		}
490 	}else{
491 		if(i > 0)		/* partial walk? */
492 			tx->nwqid = i;
493 		else
494 			seterror(tx, e);
495 
496 		if(nfid)		/* clone implicit new fid */
497 			freefid(nfid);
498 		free(path);
499 	}
500 	return;
501 }
502 
503 void
ropen(Fcall * rx,Fcall * tx)504 ropen(Fcall *rx, Fcall *tx)
505 {
506 	char *e;
507 	Fid *fid;
508 
509 	if((fid = oldfid(rx->fid, &e)) == nil){
510 		seterror(tx, e);
511 		return;
512 	}
513 
514 	if(fid->omode != -1){
515 		seterror(tx, Ebadusefid);
516 		return;
517 	}
518 
519 	if(fidstat(fid, &e) < 0){
520 		seterror(tx, e);
521 		return;
522 	}
523 
524 	if(!devallowed && S_ISSPECIAL(fid->st.st_mode)){
525 		seterror(tx, Especial);
526 		return;
527 	}
528 
529 	if(useropen(fid, rx->mode, &e) < 0){
530 		seterror(tx, e);
531 		return;
532 	}
533 
534 	tx->iounit = 0;
535 	tx->qid = stat2qid(&fid->st);
536 }
537 
538 void
rcreate(Fcall * rx,Fcall * tx)539 rcreate(Fcall *rx, Fcall *tx)
540 {
541 	char *e;
542 	Fid *fid;
543 
544 	if((fid = oldfid(rx->fid, &e)) == nil){
545 		seterror(tx, e);
546 		return;
547 	}
548 
549 	if(fid->omode != -1){
550 		seterror(tx, Ebadusefid);
551 		return;
552 	}
553 
554 	if(fidstat(fid, &e) < 0){
555 		seterror(tx, e);
556 		return;
557 	}
558 
559 	if(!S_ISDIR(fid->st.st_mode)){
560 		seterror(tx, Enotdir);
561 		return;
562 	}
563 
564 	if(usercreate(fid, rx->name, rx->mode, rx->perm, &e) < 0){
565 		seterror(tx, e);
566 		return;
567 	}
568 
569 	if(fidstat(fid, &e) < 0){
570 		seterror(tx, e);
571 		return;
572 	}
573 
574 	tx->iounit = 0;
575 	tx->qid = stat2qid(&fid->st);
576 }
577 
578 uchar
modebyte(struct stat * st)579 modebyte(struct stat *st)
580 {
581 	uchar b;
582 
583 	b = 0;
584 
585 	if(S_ISDIR(st->st_mode))
586 		b |= QTDIR;
587 
588 	/* no way to test append-only */
589 	/* no real way to test exclusive use, but mark devices as such */
590 	if(S_ISSPECIAL(st->st_mode))
591 		b |= QTEXCL;
592 
593 	return b;
594 }
595 
596 ulong
plan9mode(struct stat * st)597 plan9mode(struct stat *st)
598 {
599 	return ((ulong)modebyte(st)<<24) | (st->st_mode & 0777);
600 }
601 
602 /*
603  * this is for chmod, so don't worry about S_IFDIR
604  */
605 mode_t
unixmode(Dir * d)606 unixmode(Dir *d)
607 {
608 	return (mode_t)(d->mode&0777);
609 }
610 
611 Qid
stat2qid(struct stat * st)612 stat2qid(struct stat *st)
613 {
614 	uchar *p, *ep, *q;
615 	Qid qid;
616 
617 	/*
618 	 * For now, ignore the device number.
619 	 */
620 	qid.path = 0;
621 	p = (uchar*)&qid.path;
622 	ep = p+sizeof(qid.path);
623 	q = p+sizeof(ino_t);
624 	if(q > ep){
625 		fprint(2, "warning: inode number too big\n");
626 		q = ep;
627 	}
628 	memmove(p, &st->st_ino, q-p);
629 	q = q+sizeof(dev_t);
630 	if(q > ep){
631 /*
632  *		fprint(2, "warning: inode number + device number too big %d+%d\n",
633  *			sizeof(ino_t), sizeof(dev_t));
634  */
635 		q = ep - sizeof(dev_t);
636 		if(q < p)
637 			fprint(2, "warning: device number too big by itself\n");
638 		else
639 			*(dev_t*)q ^= st->st_dev;
640 	}
641 
642 	qid.vers = st->st_mtime ^ (st->st_size << 8);
643 	qid.type = modebyte(st);
644 	return qid;
645 }
646 
647 char *
enfrog(char * src)648 enfrog(char *src)
649 {
650 	char *d, *dst;
651 	uchar *s;
652 
653 	d = dst = emalloc(strlen(src)*3 + 1);
654 	for (s = (uchar *)src; *s; s++)
655 		if(isfrog[*s] || *s == '\\')
656 			d += sprintf(d, "\\%02x", *s);
657 		else
658 			*d++ = *s;
659 	*d = 0;
660 	return dst;
661 }
662 
663 char *
defrog(char * s)664 defrog(char *s)
665 {
666 	char *d, *dst, buf[3];
667 
668 	d = dst = emalloc(strlen(s) + 1);
669 	for(; *s; s++)
670 		if(*s == '\\' && strlen(s) >= 3){
671 			buf[0] = *++s;			/* skip \ */
672 			buf[1] = *++s;
673 			buf[2] = 0;
674 			*d++ = strtoul(buf, NULL, 16);
675 		} else
676 			*d++ = *s;
677 	*d = 0;
678 	return dst;
679 }
680 
681 void
stat2dir(char * path,struct stat * st,Dir * d)682 stat2dir(char *path, struct stat *st, Dir *d)
683 {
684 	User *u;
685 	char *q, *p, *npath;
686 
687 	memset(d, 0, sizeof(*d));
688 	d->qid = stat2qid(st);
689 	d->mode = plan9mode(st);
690 	d->atime = st->st_atime;
691 	d->mtime = st->st_mtime;
692 	d->length = st->st_size;
693 
694 	d->uid = (u = uid2user(st->st_uid)) ? u->name : "???";
695 	d->gid = (u = gid2user(st->st_gid)) ? u->name : "???";
696 	d->muid = "";
697 
698 	if((q = strrchr(path, '/')) != nil)
699 		d->name = enfrog(q+1);
700 	else
701 		d->name = enfrog(path);
702 }
703 
704 void
rread(Fcall * rx,Fcall * tx)705 rread(Fcall *rx, Fcall *tx)
706 {
707 	char *e, *path;
708 	uchar *p, *ep;
709 	int n;
710 	Fid *fid;
711 	Dir d;
712 	struct stat st;
713 
714 	if(rx->count > msize-IOHDRSZ){
715 		seterror(tx, Etoolarge);
716 		return;
717 	}
718 
719 	if((fid = oldfidex(rx->fid, -1, &e)) == nil){
720 		seterror(tx, e);
721 		return;
722 	}
723 
724 	if (fid->auth) {
725 		char *e;
726 		e = auth->read(rx, tx);
727 		if (e)
728 			seterror(tx, e);
729 		return;
730 	}
731 
732 	if(fid->omode == -1 || (fid->omode&3) == OWRITE){
733 		seterror(tx, Ebadusefid);
734 		return;
735 	}
736 
737 	if(fid->dir){
738 		if(rx->offset != fid->diroffset){
739 			if(rx->offset != 0){
740 				seterror(tx, Ebadoffset);
741 				return;
742 			}
743 			rewinddir(fid->dir);
744 			fid->diroffset = 0;
745 			fid->direof = 0;
746 		}
747 		if(fid->direof){
748 			tx->count = 0;
749 			return;
750 		}
751 
752 		p = (uchar*)tx->data;
753 		ep = (uchar*)tx->data+rx->count;
754 		for(;;){
755 			if(p+BIT16SZ >= ep)
756 				break;
757 			if(fid->dirent == nil)	/* one entry cache for when convD2M fails */
758 				if((fid->dirent = readdir(fid->dir)) == nil){
759 					fid->direof = 1;
760 					break;
761 				}
762 			if(strcmp(fid->dirent->d_name, ".") == 0
763 			|| strcmp(fid->dirent->d_name, "..") == 0){
764 				fid->dirent = nil;
765 				continue;
766 			}
767 			path = estrpath(fid->path, fid->dirent->d_name, 0);
768 			memset(&st, 0, sizeof st);
769 			if(stat(path, &st) < 0){
770 				fprint(2, "dirread: stat(%s) failed: %s\n", path, strerror(errno));
771 				fid->dirent = nil;
772 				free(path);
773 				continue;
774 			}
775 			free(path);
776 			stat2dir(fid->dirent->d_name, &st, &d);
777 			if((n=(old9p ? convD2Mold : convD2M)(&d, p, ep-p)) <= BIT16SZ)
778 				break;
779 			p += n;
780 			fid->dirent = nil;
781 		}
782 		tx->count = p - (uchar*)tx->data;
783 		fid->diroffset += tx->count;
784 	}else{
785 		if((n = pread(fid->fd, tx->data, rx->count, rx->offset)) < 0){
786 			seterror(tx, strerror(errno));
787 			return;
788 		}
789 		tx->count = n;
790 	}
791 }
792 
793 void
rwrite(Fcall * rx,Fcall * tx)794 rwrite(Fcall *rx, Fcall *tx)
795 {
796 	char *e;
797 	Fid *fid;
798 	int n;
799 
800 	if(rx->count > msize-IOHDRSZ){
801 		seterror(tx, Etoolarge);
802 		return;
803 	}
804 
805 	if((fid = oldfidex(rx->fid, -1, &e)) == nil){
806 		seterror(tx, e);
807 		return;
808 	}
809 
810 	if (fid->auth) {
811 		char *e;
812 		e = auth->write(rx, tx);
813 		if (e)
814 			seterror(tx, e);
815 		return;
816 	}
817 
818 	if(fid->omode == -1 || (fid->omode&3) == OREAD || (fid->omode&3) == OEXEC){
819 		seterror(tx, Ebadusefid);
820 		return;
821 	}
822 
823 	if((n = pwrite(fid->fd, rx->data, rx->count, rx->offset)) < 0){
824 		seterror(tx, strerror(errno));
825 		return;
826 	}
827 	tx->count = n;
828 }
829 
830 void
rclunk(Fcall * rx,Fcall * tx)831 rclunk(Fcall *rx, Fcall *tx)
832 {
833 	char *e;
834 	Fid *fid;
835 
836 	if((fid = oldfidex(rx->fid, -1, &e)) == nil){
837 		seterror(tx, e);
838 		return;
839 	}
840 	if (fid->auth) {
841 		if (auth->clunk) {
842 			e = (*auth->clunk)(rx, tx);
843 			if (e) {
844 				seterror(tx, e);
845 				return;
846 			}
847 		}
848 	}
849 	else if(fid->omode != -1 && fid->omode&ORCLOSE)
850 		remove(fid->path);
851 	freefid(fid);
852 }
853 
854 void
rremove(Fcall * rx,Fcall * tx)855 rremove(Fcall *rx, Fcall *tx)
856 {
857 	char *e;
858 	Fid *fid;
859 
860 	if((fid = oldfid(rx->fid, &e)) == nil){
861 		seterror(tx, e);
862 		return;
863 	}
864 	if(userremove(fid, &e) < 0)
865 		seterror(tx, e);
866 	freefid(fid);
867 }
868 
869 void
rstat(Fcall * rx,Fcall * tx)870 rstat(Fcall *rx, Fcall *tx)
871 {
872 	char *e;
873 	Fid *fid;
874 	Dir d;
875 
876 	if((fid = oldfid(rx->fid, &e)) == nil){
877 		seterror(tx, e);
878 		return;
879 	}
880 
881 	if(fidstat(fid, &e) < 0){
882 		seterror(tx, e);
883 		return;
884 	}
885 
886 	stat2dir(fid->path, &fid->st, &d);
887 	if((tx->nstat=(old9p ? convD2Mold : convD2M)(&d, tx->stat, msize)) <= BIT16SZ)
888 		seterror(tx, "convD2M fails");
889 }
890 
891 void
rwstat(Fcall * rx,Fcall * tx)892 rwstat(Fcall *rx, Fcall *tx)
893 {
894 	char *e;
895 	char *p, *old, *new, *dir;
896 	gid_t gid;
897 	Dir d;
898 	Fid *fid;
899 
900 	if((fid = oldfid(rx->fid, &e)) == nil){
901 		seterror(tx, e);
902 		return;
903 	}
904 
905 	/*
906 	 * wstat is supposed to be atomic.
907 	 * we check all the things we can before trying anything.
908 	 * still, if we are told to truncate a file and rename it and only
909 	 * one works, we're screwed.  in such cases we leave things
910 	 * half broken and return an error.  it's hardly perfect.
911 	 */
912 	if((old9p ? convM2Dold : convM2D)(rx->stat, rx->nstat, &d, (char*)rx->stat) <= BIT16SZ){
913 		seterror(tx, Ewstatbuffer);
914 		return;
915 	}
916 
917 	if(fidstat(fid, &e) < 0){
918 		seterror(tx, e);
919 		return;
920 	}
921 
922 	/*
923 	 * The casting is necessary because d.mode is ulong and might,
924 	 * on some systems, be 64 bits.  We only want to compare the
925 	 * bottom 32 bits, since that's all that gets sent in the protocol.
926 	 *
927 	 * Same situation for d.mtime and d.length (although that last check
928 	 * is admittedly superfluous, given the current lack of 128-bit machines).
929 	 */
930 	gid = (gid_t)-1;
931 	if(d.gid[0] != '\0'){
932 		User *g;
933 
934 		g = gname2user(d.gid);
935 		if(g == nil){
936 			seterror(tx, Eunknowngroup);
937 			return;
938 		}
939 		gid = (gid_t)g->id;
940 
941 		if(groupchange(fid->u, gid2user(gid), &e) < 0){
942 			seterror(tx, e);
943 			return;
944 		}
945 	}
946 
947 	if((u32int)d.mode != (u32int)~0 && (((d.mode&DMDIR)!=0) ^ (S_ISDIR(fid->st.st_mode)!=0))){
948 		seterror(tx, Edirchange);
949 		return;
950 	}
951 
952 	if(strcmp(fid->path, "/") == 0){
953 		seterror(tx, "no wstat of root");
954 		return;
955 	}
956 
957 	/*
958 	 * try things in increasing order of harm to the file.
959 	 * mtime should come after truncate so that if you
960 	 * do both the mtime actually takes effect, but i'd rather
961 	 * leave truncate until last.
962 	 * (see above comment about atomicity).
963 	 */
964 	if((u32int)d.mode != (u32int)~0 && chmod(fid->path, unixmode(&d)) < 0){
965 		if(chatty9p)
966 			fprint(2, "chmod(%s, 0%luo) failed\n", fid->path, unixmode(&d));
967 		seterror(tx, strerror(errno));
968 		return;
969 	}
970 
971 	if((u32int)d.mtime != (u32int)~0){
972 		struct utimbuf t;
973 
974 		t.actime = 0;
975 		t.modtime = d.mtime;
976 		if(utime(fid->path, &t) < 0){
977 			if(chatty9p)
978 				fprint(2, "utime(%s) failed\n", fid->path);
979 			seterror(tx, strerror(errno));
980 			return;
981 		}
982 	}
983 
984 	if(gid != (gid_t)-1 && gid != fid->st.st_gid){
985 		if(chown(fid->path, (uid_t)-1, gid) < 0){
986 			if(chatty9p)
987 				fprint(2, "chgrp(%s, %d) failed\n", fid->path, gid);
988 			seterror(tx, strerror(errno));
989 			return;
990 		}
991 	}
992 
993 	if(d.name[0]){
994 		old = fid->path;
995 		dir = estrdup(fid->path);
996 		if((p = strrchr(dir, '/')) > dir)
997 			*p = '\0';
998 		else{
999 			seterror(tx, "whoops: can't happen in u9fs");
1000 			return;
1001 		}
1002 		new = estrpath(dir, d.name, 1);
1003 		if(strcmp(old, new) != 0 && rename(old, new) < 0){
1004 			if(chatty9p)
1005 				fprint(2, "rename(%s, %s) failed\n", old, new);
1006 			seterror(tx, strerror(errno));
1007 			free(new);
1008 			free(dir);
1009 			return;
1010 		}
1011 		fid->path = new;
1012 		free(old);
1013 		free(dir);
1014 	}
1015 
1016 	if((u64int)d.length != (u64int)~0 && truncate(fid->path, d.length) < 0){
1017 		fprint(2, "truncate(%s, %lld) failed\n", fid->path, d.length);
1018 		seterror(tx, strerror(errno));
1019 		return;
1020 	}
1021 }
1022 
1023 /*
1024  * we keep a table by numeric id.  by name lookups happen infrequently
1025  * while by-number lookups happen once for every directory entry read
1026  * and every stat request.
1027  */
1028 User *utab[64];
1029 User *gtab[64];
1030 
1031 User*
adduser(struct passwd * p)1032 adduser(struct passwd *p)
1033 {
1034 	User *u;
1035 
1036 	u = emalloc(sizeof(*u));
1037 	u->id = p->pw_uid;
1038 	u->name = estrdup(p->pw_name);
1039 	u->next = utab[p->pw_uid%nelem(utab)];
1040 	u->defaultgid = p->pw_gid;
1041 	utab[p->pw_uid%nelem(utab)] = u;
1042 	return u;
1043 }
1044 
1045 int
useringroup(User * u,User * g)1046 useringroup(User *u, User *g)
1047 {
1048 	int i;
1049 
1050 	for(i=0; i<g->nmem; i++)
1051 		if(strcmp(g->mem[i], u->name) == 0)
1052 			return 1;
1053 
1054 	/*
1055 	 * Hack around common Unix problem that everyone has
1056 	 * default group "user" but /etc/group lists no members.
1057 	 */
1058 	if(u->defaultgid == g->id)
1059 		return 1;
1060 	return 0;
1061 }
1062 
1063 User*
addgroup(struct group * g)1064 addgroup(struct group *g)
1065 {
1066 	User *u;
1067 	char **p;
1068 	int n;
1069 
1070 	u = emalloc(sizeof(*u));
1071 	n = 0;
1072 	for(p=g->gr_mem; *p; p++)
1073 		n++;
1074 	u->mem = emalloc(sizeof(u->mem[0])*n);
1075 	n = 0;
1076 	for(p=g->gr_mem; *p; p++)
1077 		u->mem[n++] = estrdup(*p);
1078 	u->nmem = n;
1079 	u->id = g->gr_gid;
1080 	u->name = estrdup(g->gr_name);
1081 	u->next = gtab[g->gr_gid%nelem(gtab)];
1082 	gtab[g->gr_gid%nelem(gtab)] = u;
1083 	return u;
1084 }
1085 
1086 User*
uname2user(char * name)1087 uname2user(char *name)
1088 {
1089 	int i;
1090 	User *u;
1091 	struct passwd *p;
1092 
1093 	for(i=0; i<nelem(utab); i++)
1094 		for(u=utab[i]; u; u=u->next)
1095 			if(strcmp(u->name, name) == 0)
1096 				return u;
1097 
1098 	if((p = getpwnam(name)) == nil)
1099 		return nil;
1100 	return adduser(p);
1101 }
1102 
1103 User*
uid2user(int id)1104 uid2user(int id)
1105 {
1106 	User *u;
1107 	struct passwd *p;
1108 
1109 	for(u=utab[id%nelem(utab)]; u; u=u->next)
1110 		if(u->id == id)
1111 			return u;
1112 
1113 	if((p = getpwuid(id)) == nil)
1114 		return nil;
1115 	return adduser(p);
1116 }
1117 
1118 User*
gname2user(char * name)1119 gname2user(char *name)
1120 {
1121 	int i;
1122 	User *u;
1123 	struct group *g;
1124 
1125 	for(i=0; i<nelem(gtab); i++)
1126 		for(u=gtab[i]; u; u=u->next)
1127 			if(strcmp(u->name, name) == 0)
1128 				return u;
1129 
1130 	if((g = getgrnam(name)) == nil)
1131 		return nil;
1132 	return addgroup(g);
1133 }
1134 
1135 User*
gid2user(int id)1136 gid2user(int id)
1137 {
1138 	User *u;
1139 	struct group *g;
1140 
1141 	for(u=gtab[id%nelem(gtab)]; u; u=u->next)
1142 		if(u->id == id)
1143 			return u;
1144 
1145 	if((g = getgrgid(id)) == nil)
1146 		return nil;
1147 	return addgroup(g);
1148 }
1149 
1150 void
sysfatal(char * fmt,...)1151 sysfatal(char *fmt, ...)
1152 {
1153 	char buf[1024];
1154 	va_list va, temp;
1155 
1156 	va_start(va, fmt);
1157 	va_copy(temp, va);
1158 	doprint(buf, buf+sizeof buf, fmt, &temp);
1159 	va_end(temp);
1160 	va_end(va);
1161 	fprint(2, "u9fs: %s\n", buf);
1162 	fprint(2, "last unix error: %s\n", strerror(errno));
1163 	exit(1);
1164 }
1165 
1166 void*
emalloc(size_t n)1167 emalloc(size_t n)
1168 {
1169 	void *p;
1170 
1171 	if(n == 0)
1172 		n = 1;
1173 	p = malloc(n);
1174 	if(p == 0)
1175 		sysfatal("malloc(%ld) fails", (long)n);
1176 	memset(p, 0, n);
1177 	return p;
1178 }
1179 
1180 void*
erealloc(void * p,size_t n)1181 erealloc(void *p, size_t n)
1182 {
1183 	if(p == 0)
1184 		p = malloc(n);
1185 	else
1186 		p = realloc(p, n);
1187 	if(p == 0)
1188 		sysfatal("realloc(..., %ld) fails", (long)n);
1189 	return p;
1190 }
1191 
1192 char*
estrdup(char * p)1193 estrdup(char *p)
1194 {
1195 	p = strdup(p);
1196 	if(p == 0)
1197 		sysfatal("strdup(%.20s) fails", p);
1198 	return p;
1199 }
1200 
1201 char*
estrpath(char * p,char * q,int frog)1202 estrpath(char *p, char *q, int frog)
1203 {
1204 	char *r, *s;
1205 
1206 	if(strcmp(q, "..") == 0){
1207 		r = estrdup(p);
1208 		if((s = strrchr(r, '/')) && s > r)
1209 			*s = '\0';
1210 		else if(s == r)
1211 			s[1] = '\0';
1212 		return r;
1213 	}
1214 
1215 	if(frog)
1216 		q = defrog(q);
1217 	else
1218 		q = strdup(q);
1219 	r = emalloc(strlen(p)+1+strlen(q)+1);
1220 	strcpy(r, p);
1221 	if(r[0]=='\0' || r[strlen(r)-1] != '/')
1222 		strcat(r, "/");
1223 	strcat(r, q);
1224 	free(q);
1225 	return r;
1226 }
1227 
1228 Fid *fidtab[1];
1229 
1230 Fid*
lookupfid(int fid)1231 lookupfid(int fid)
1232 {
1233 	Fid *f;
1234 
1235 	for(f=fidtab[fid%nelem(fidtab)]; f; f=f->next)
1236 		if(f->fid == fid)
1237 			return f;
1238 	return nil;
1239 }
1240 
1241 Fid*
newfid(int fid,char ** ep)1242 newfid(int fid, char **ep)
1243 {
1244 	Fid *f;
1245 
1246 	if(lookupfid(fid) != nil){
1247 		*ep = Efidactive;
1248 		return nil;
1249 	}
1250 
1251 	f = emalloc(sizeof(*f));
1252 	f->next = fidtab[fid%nelem(fidtab)];
1253 	if(f->next)
1254 		f->next->prev = f;
1255 	fidtab[fid%nelem(fidtab)] = f;
1256 	f->fid = fid;
1257 	f->fd = -1;
1258 	f->omode = -1;
1259 	return f;
1260 }
1261 
1262 Fid*
newauthfid(int fid,void * magic,char ** ep)1263 newauthfid(int fid, void *magic, char **ep)
1264 {
1265 	Fid *af;
1266 	af = newfid(fid, ep);
1267 	if (af == nil)
1268 		return nil;
1269 	af->auth = 1;
1270 	af->authmagic = magic;
1271 	return af;
1272 }
1273 
1274 Fid*
oldfidex(int fid,int auth,char ** ep)1275 oldfidex(int fid, int auth, char **ep)
1276 {
1277 	Fid *f;
1278 
1279 	if((f = lookupfid(fid)) == nil){
1280 		*ep = Ebadfid;
1281 		return nil;
1282 	}
1283 
1284 	if (auth != -1 && f->auth != auth) {
1285 		*ep = Ebadfid;
1286 		return nil;
1287 	}
1288 
1289 	if (!f->auth) {
1290 		if(userchange(f->u, ep) < 0)
1291 			return nil;
1292 	}
1293 
1294 	return f;
1295 }
1296 
1297 Fid*
oldfid(int fid,char ** ep)1298 oldfid(int fid, char **ep)
1299 {
1300 	return oldfidex(fid, 0, ep);
1301 }
1302 
1303 Fid*
oldauthfid(int fid,void ** magic,char ** ep)1304 oldauthfid(int fid, void **magic, char **ep)
1305 {
1306 	Fid *af;
1307 	af = oldfidex(fid, 1, ep);
1308 	if (af == nil)
1309 		return nil;
1310 	*magic = af->authmagic;
1311 	return af;
1312 }
1313 
1314 void
freefid(Fid * f)1315 freefid(Fid *f)
1316 {
1317 	if(f->prev)
1318 		f->prev->next = f->next;
1319 	else
1320 		fidtab[f->fid%nelem(fidtab)] = f->next;
1321 	if(f->next)
1322 		f->next->prev = f->prev;
1323 	if(f->dir)
1324 		closedir(f->dir);
1325 	if(f->fd)
1326 		close(f->fd);
1327 	free(f->path);
1328 	free(f);
1329 }
1330 
1331 int
fidstat(Fid * fid,char ** ep)1332 fidstat(Fid *fid, char **ep)
1333 {
1334 	if(stat(fid->path, &fid->st) < 0){
1335 		fprint(2, "fidstat(%s) failed\n", fid->path);
1336 		if(ep)
1337 			*ep = strerror(errno);
1338 		return -1;
1339 	}
1340 	if(S_ISDIR(fid->st.st_mode))
1341 		fid->st.st_size = 0;
1342 	return 0;
1343 }
1344 
1345 int
userchange(User * u,char ** ep)1346 userchange(User *u, char **ep)
1347 {
1348 	if(defaultuser)
1349 		return 0;
1350 
1351 	if(setreuid(0, 0) < 0){
1352 		fprint(2, "setreuid(0, 0) failed\n");
1353 		*ep = "cannot setuid back to root";
1354 		return -1;
1355 	}
1356 
1357 	/*
1358 	 * Initgroups does not appear to be SUSV standard.
1359 	 * But it exists on SGI and on Linux, which makes me
1360 	 * think it's standard enough.  We have to do something
1361 	 * like this, and the closest other function I can find is
1362 	 * setgroups (which initgroups eventually calls).
1363 	 * Setgroups is the same as far as standardization though,
1364 	 * so we're stuck using a non-SUSV call.  Sigh.
1365 	 */
1366 	if(initgroups(u->name, u->defaultgid) < 0)
1367 		fprint(2, "initgroups(%s) failed: %s\n", u->name, strerror(errno));
1368 
1369 	if(setreuid(-1, u->id) < 0){
1370 		fprint(2, "setreuid(-1, %s) failed\n", u->name);
1371 		*ep = strerror(errno);
1372 		return -1;
1373 	}
1374 
1375 	return 0;
1376 }
1377 
1378 /*
1379  * We do our own checking here, then switch to root temporarily
1380  * to set our gid.  In a perfect world, you'd be allowed to set your
1381  * egid to any of the supplemental groups of your euid, but this
1382  * is not the case on Linux 2.2.14 (and perhaps others).
1383  *
1384  * This is a race, of course, but it's a race against processes
1385  * that can edit the group lists.  If you can do that, you can
1386  * change your own group without our help.
1387  */
1388 int
groupchange(User * u,User * g,char ** ep)1389 groupchange(User *u, User *g, char **ep)
1390 {
1391 	if(g == nil)
1392 		return -1;
1393 	if(!useringroup(u, g)){
1394 		if(chatty9p)
1395 			fprint(2, "%s not in group %s\n", u->name, g->name);
1396 		*ep = Enotingroup;
1397 		return -1;
1398 	}
1399 
1400 	setreuid(0,0);
1401 	if(setregid(-1, g->id) < 0){
1402 		fprint(2, "setegid(%s/%d) failed in groupchange\n", g->name, g->id);
1403 		*ep = strerror(errno);
1404 		return -1;
1405 	}
1406 	if(userchange(u, ep) < 0)
1407 		return -1;
1408 
1409 	return 0;
1410 }
1411 
1412 
1413 /*
1414  * An attempt to enforce permissions by looking at the
1415  * file system.  Separation of checking permission and
1416  * actually performing the action is a terrible idea, of
1417  * course, so we use setreuid for most of the permission
1418  * enforcement.  This is here only so we can give errors
1419  * on open(ORCLOSE) in some cases.
1420  */
1421 int
userperm(User * u,char * path,int type,int need)1422 userperm(User *u, char *path, int type, int need)
1423 {
1424 	char *p, *q;
1425 	int i, have;
1426 	struct stat st;
1427 	User *g;
1428 
1429 	switch(type){
1430 	default:
1431 		fprint(2, "bad type %d in userperm\n", type);
1432 		return -1;
1433 	case Tdot:
1434 		if(stat(path, &st) < 0){
1435 			fprint(2, "userperm: stat(%s) failed\n", path);
1436 			return -1;
1437 		}
1438 		break;
1439 	case Tdotdot:
1440 		p = estrdup(path);
1441 		if((q = strrchr(p, '/'))==nil){
1442 			fprint(2, "userperm(%s, ..): bad path\n", p);
1443 			free(p);
1444 			return -1;
1445 		}
1446 		if(q > p)
1447 			*q = '\0';
1448 		else
1449 			*(q+1) = '\0';
1450 		if(stat(p, &st) < 0){
1451 			fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n",
1452 				p, path);
1453 			free(p);
1454 			return -1;
1455 		}
1456 		free(p);
1457 		break;
1458 	}
1459 
1460 	if(u == none){
1461 		fprint(2, "userperm: none wants %d in 0%luo\n", need, st.st_mode);
1462 		have = st.st_mode&7;
1463 		if((have&need)==need)
1464 			return 0;
1465 		return -1;
1466 	}
1467 	have = st.st_mode&7;
1468 	if((uid_t)u->id == st.st_uid)
1469 		have |= (st.st_mode>>6)&7;
1470 	if((have&need)==need)
1471 		return 0;
1472 	if(((have|((st.st_mode>>3)&7))&need) != need)	/* group won't help */
1473 		return -1;
1474 	g = gid2user(st.st_gid);
1475 	for(i=0; i<g->nmem; i++){
1476 		if(strcmp(g->mem[i], u->name) == 0){
1477 			have |= (st.st_mode>>3)&7;
1478 			break;
1479 		}
1480 	}
1481 	if((have&need)==need)
1482 		return 0;
1483 	return -1;
1484 }
1485 
1486 int
userwalk(User * u,char ** path,char * elem,Qid * qid,char ** ep)1487 userwalk(User *u, char **path, char *elem, Qid *qid, char **ep)
1488 {
1489 	char *npath;
1490 	struct stat st;
1491 
1492 	npath = estrpath(*path, elem, 1);
1493 	if(stat(npath, &st) < 0){
1494 		free(npath);
1495 		*ep = strerror(errno);
1496 		return -1;
1497 	}
1498 	*qid = stat2qid(&st);
1499 	free(*path);
1500 	*path = npath;
1501 	return 0;
1502 }
1503 
1504 int
useropen(Fid * fid,int omode,char ** ep)1505 useropen(Fid *fid, int omode, char **ep)
1506 {
1507 	int a, o;
1508 
1509 	/*
1510 	 * Check this anyway, to try to head off problems later.
1511 	 */
1512 	if((omode&ORCLOSE) && userperm(fid->u, fid->path, Tdotdot, W_OK) < 0){
1513 		*ep = Eperm;
1514 		return -1;
1515 	}
1516 
1517 	switch(omode&3){
1518 	default:
1519 		*ep = "programmer error";
1520 		return -1;
1521 	case OREAD:
1522 		a = R_OK;
1523 		o = O_RDONLY;
1524 		break;
1525 	case ORDWR:
1526 		a = R_OK|W_OK;
1527 		o = O_RDWR;
1528 		break;
1529 	case OWRITE:
1530 		a = W_OK;
1531 		o = O_WRONLY;
1532 		break;
1533 	case OEXEC:
1534 		a = X_OK;
1535 		o = O_RDONLY;
1536 		break;
1537 	}
1538 	if(omode & OTRUNC){
1539 		a |= W_OK;
1540 		o |= O_TRUNC;
1541 	}
1542 
1543 	if(S_ISDIR(fid->st.st_mode)){
1544 		if(a != R_OK){
1545 			fprint(2, "attempt by %s to open dir %d\n", fid->u->name, omode);
1546 			*ep = Eperm;
1547 			return -1;
1548 		}
1549 		if((fid->dir = opendir(fid->path)) == nil){
1550 			*ep = strerror(errno);
1551 			return -1;
1552 		}
1553 	}else{
1554 		/*
1555 		 * This is wrong because access used the real uid
1556 		 * and not the effective uid.  Let the open sort it out.
1557 		 *
1558 		if(access(fid->path, a) < 0){
1559 			*ep = strerror(errno);
1560 			return -1;
1561 		}
1562 		 *
1563 		 */
1564 		if((fid->fd = open(fid->path, o)) < 0){
1565 			*ep = strerror(errno);
1566 			return -1;
1567 		}
1568 	}
1569 	fid->omode = omode;
1570 	return 0;
1571 }
1572 
1573 int
usercreate(Fid * fid,char * elem,int omode,long perm,char ** ep)1574 usercreate(Fid *fid, char *elem, int omode, long perm, char **ep)
1575 {
1576 	int o, m;
1577 	char *opath, *npath;
1578 	struct stat st, parent;
1579 
1580 	if(stat(fid->path, &parent) < 0){
1581 		*ep = strerror(errno);
1582 		return -1;
1583 	}
1584 
1585 	/*
1586 	 * Change group so that created file has expected group
1587 	 * by Plan 9 semantics.  If that fails, might as well go
1588 	 * with the user's default group.
1589 	 */
1590 	if(groupchange(fid->u, gid2user(parent.st_gid), ep) < 0
1591 	&& groupchange(fid->u, gid2user(fid->u->defaultgid), ep) < 0)
1592 		return -1;
1593 
1594 	m = (perm & DMDIR) ? 0777 : 0666;
1595 	perm = perm & (~m | (fid->st.st_mode & m));
1596 
1597 	npath = estrpath(fid->path, elem, 1);
1598 	if(perm & DMDIR){
1599 		if((omode&~ORCLOSE) != OREAD){
1600 			*ep = Eperm;
1601 			free(npath);
1602 			return -1;
1603 		}
1604 		if(stat(npath, &st) >= 0 || errno != ENOENT){
1605 			*ep = Eexist;
1606 			free(npath);
1607 			return -1;
1608 		}
1609 		/* race */
1610 		if(mkdir(npath, (perm|0400)&0777) < 0){
1611 			*ep = strerror(errno);
1612 			free(npath);
1613 			return -1;
1614 		}
1615 		if((fid->dir = opendir(npath)) == nil){
1616 			*ep = strerror(errno);
1617 			remove(npath);		/* race */
1618 			free(npath);
1619 			return -1;
1620 		}
1621 	}else{
1622 		o = O_CREAT|O_EXCL;
1623 		switch(omode&3){
1624 		default:
1625 			*ep = "programmer error";
1626 			return -1;
1627 		case OREAD:
1628 		case OEXEC:
1629 			o |= O_RDONLY;
1630 			break;
1631 		case ORDWR:
1632 			o |= O_RDWR;
1633 			break;
1634 		case OWRITE:
1635 			o |= O_WRONLY;
1636 			break;
1637 		}
1638 		if(omode & OTRUNC)
1639 			o |= O_TRUNC;
1640 		if((fid->fd = open(npath, o, perm&0777)) < 0){
1641 			if(chatty9p)
1642 				fprint(2, "create(%s, 0x%x, 0%o) failed\n", npath, o, perm&0777);
1643 			*ep = strerror(errno);
1644 			free(npath);
1645 			return -1;
1646 		}
1647 	}
1648 
1649 	opath = fid->path;
1650 	fid->path = npath;
1651 	if(fidstat(fid, ep) < 0){
1652 		fprint(2, "stat after create on %s failed\n", npath);
1653 		remove(npath);	/* race */
1654 		free(npath);
1655 		fid->path = opath;
1656 		if(fid->fd >= 0){
1657 			close(fid->fd);
1658 			fid->fd = -1;
1659 		}else{
1660 			closedir(fid->dir);
1661 			fid->dir = nil;
1662 		}
1663 		return -1;
1664 	}
1665 	fid->omode = omode;
1666 	free(opath);
1667 	return 0;
1668 }
1669 
1670 int
userremove(Fid * fid,char ** ep)1671 userremove(Fid *fid, char **ep)
1672 {
1673 	if(remove(fid->path) < 0){
1674 		*ep = strerror(errno);
1675 		return -1;
1676 	}
1677 	return 0;
1678 }
1679 
1680 void
usage(void)1681 usage(void)
1682 {
1683 	fprint(2, "usage: u9fs [-Dnz] [-a authmethod] [-m msize] [-u user] [root]\n");
1684 	exit(1);
1685 }
1686 
1687 int
main(int argc,char ** argv)1688 main(int argc, char **argv)
1689 {
1690 	char *authtype;
1691 	int i;
1692 	int fd;
1693 	int logflag;
1694 
1695 	auth = authmethods[0];
1696 	logflag = O_WRONLY|O_APPEND|O_CREAT;
1697 	ARGBEGIN{
1698 	case 'D':
1699 		chatty9p = 1;
1700 		break;
1701 	case 'a':
1702 		authtype = EARGF(usage());
1703 		auth = nil;
1704 		for(i=0; i<nelem(authmethods); i++)
1705 			if(strcmp(authmethods[i]->name, authtype)==0)
1706 				auth = authmethods[i];
1707 		if(auth == nil)
1708 			sysfatal("unknown auth type '%s'", authtype);
1709 		break;
1710 	case 'A':
1711 		autharg = EARGF(usage());
1712 		break;
1713 	case 'l':
1714 		logfile = EARGF(usage());
1715 		break;
1716 	case 'm':
1717 		msize = strtol(EARGF(usage()), 0, 0);
1718 		break;
1719 	case 'n':
1720 		network = 0;
1721 		break;
1722 	case 'u':
1723 		defaultuser = EARGF(usage());
1724 		break;
1725 	case 'z':
1726 		logflag |= O_TRUNC;
1727 	}ARGEND
1728 
1729 	if(argc > 1)
1730 		usage();
1731 
1732 	fd = open(logfile, logflag, 0666);
1733 	if(fd < 0)
1734 		sysfatal("cannot open log '%s'", logfile);
1735 
1736 	if(dup2(fd, 2) < 0)
1737 		sysfatal("cannot dup fd onto stderr");
1738 	fprint(2, "u9fs\nkill %d\n", (int)getpid());
1739 
1740 	fmtinstall('F', fcallconv);
1741 	fmtinstall('D', dirconv);
1742 	fmtinstall('M', dirmodeconv);
1743 
1744 	rxbuf = emalloc(msize);
1745 	txbuf = emalloc(msize);
1746 	databuf = emalloc(msize);
1747 
1748 	if(auth->init)
1749 		auth->init();
1750 
1751 	if(network)
1752 		getremotehostname(remotehostname, sizeof remotehostname);
1753 
1754 	if(gethostname(hostname, sizeof hostname) < 0)
1755 		strcpy(hostname, "gnot");
1756 
1757 	umask(0);
1758 
1759 	if(argc == 1)
1760 		if(chroot(argv[0]) < 0)
1761 			sysfatal("chroot '%s' failed", argv[0]);
1762 
1763 	none = uname2user("none");
1764 	if(none == nil)
1765 		none = uname2user("nobody");
1766 
1767 	serve(0, 1);
1768 	return 0;
1769 }
1770