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