Subversion Repositories planix.SVN

Rev

Rev 71 | Details | Compare with Previous | Last modification | View Log | RSS feed

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