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