Subversion Repositories planix.SVN

Rev

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