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 if(n == 0) 1079 n = 1; 1080 p = malloc(n); 1081 if(p == 0) 1082 sysfatal("malloc(%ld) fails", (long)n); 1083 memset(p, 0, n); 1084 return p; 1085 } 1086 1087 void* 1088 erealloc(void *p, size_t n) 1089 { 1090 if(p == 0) 1091 p = malloc(n); 1092 else 1093 p = realloc(p, n); 1094 if(p == 0) 1095 sysfatal("realloc(..., %ld) fails", (long)n); 1096 return p; 1097 } 1098 1099 char* 1100 estrdup(char *p) 1101 { 1102 p = strdup(p); 1103 if(p == 0) 1104 sysfatal("strdup(%.20s) fails", p); 1105 return p; 1106 } 1107 1108 char* 1109 estrpath(char *p, char *q) 1110 { 1111 char *r, *s; 1112 1113 if(strcmp(q, "..") == 0){ 1114 r = estrdup(p); 1115 if((s = strrchr(r, '/')) && s > r) 1116 *s = '\0'; 1117 else if(s == r) 1118 s[1] = '\0'; 1119 return r; 1120 } 1121 1122 r = emalloc(strlen(p)+1+strlen(q)+1); 1123 strcpy(r, p); 1124 if(r[0]=='\0' || r[strlen(r)-1] != '/') 1125 strcat(r, "/"); 1126 strcat(r, q); 1127 return r; 1128 } 1129 1130 Fid *newfid(int, char**); 1131 Fid *oldfid(int, char**); 1132 int fidstat(Fid*, char**); 1133 void freefid(Fid*); 1134 1135 Fid *fidtab[1]; 1136 1137 Fid* 1138 lookupfid(int fid) 1139 { 1140 Fid *f; 1141 1142 for(f=fidtab[fid%nelem(fidtab)]; f; f=f->next) 1143 if(f->fid == fid) 1144 return f; 1145 return nil; 1146 } 1147 1148 Fid* 1149 newfid(int fid, char **ep) 1150 { 1151 Fid *f; 1152 1153 if(lookupfid(fid) != nil){ 1154 *ep = Efidactive; 1155 return nil; 1156 } 1157 1158 f = emalloc(sizeof(*f)); 1159 f->next = fidtab[fid%nelem(fidtab)]; 1160 if(f->next) 1161 f->next->prev = f; 1162 fidtab[fid%nelem(fidtab)] = f; 1163 f->fid = fid; 1164 f->fd = -1; 1165 f->omode = -1; 1166 return f; 1167 } 1168 1169 Fid* 1170 oldfid(int fid, char **ep) 1171 { 1172 Fid *f; 1173 1174 if((f = lookupfid(fid)) == nil){ 1175 *ep = Ebadfid; 1176 return nil; 1177 } 1178 1179 if(userchange(f->u, ep) < 0) 1180 return nil; 1181 1182 return f; 1183 } 1184 1185 void 1186 freefid(Fid *f) 1187 { 1188 if(f->prev) 1189 f->prev->next = f->next; 1190 else 1191 fidtab[f->fid%nelem(fidtab)] = f->next; 1192 if(f->next) 1193 f->next->prev = f->prev; 1194 if(f->dir) 1195 closedir(f->dir); 1196 if(f->fd) 1197 close(f->fd); 1198 free(f->path); 1199 free(f); 1200 } 1201 1202 int 1203 fidstat(Fid *fid, char **ep) 1204 { 1205 if(stat(fid->path, &fid->st) < 0){ 1206 fprint(2, "fidstat(%s) failed\n", fid->path); 1207 if(ep) 1208 *ep = strerror(errno); 1209 return -1; 1210 } 1211 if(S_ISDIR(fid->st.st_mode)) 1212 fid->st.st_size = 0; 1213 return 0; 1214 } 1215 1216 int 1217 userchange(User *u, char **ep) 1218 { 1219 if(defaultuser) 1220 return 0; 1221 1222 if(setreuid(0, 0) < 0){ 1223 fprint(2, "setreuid(0, 0) failed\n"); 1224 *ep = "cannot setuid back to root"; 1225 return -1; 1226 } 1227 1228 /* 1229 * Initgroups does not appear to be SUSV standard. 1230 * But it exists on SGI and on Linux, which makes me 1231 * think it's standard enough. We have to do something 1232 * like this, and the closest other function I can find is 1233 * setgroups (which initgroups eventually calls). 1234 * Setgroups is the same as far as standardization though, 1235 * so we're stuck using a non-SUSV call. Sigh. 1236 */ 1237 if(initgroups(u->name, u->defaultgid) < 0) 1238 fprint(2, "initgroups(%s) failed: %s\n", u->name, strerror(errno)); 1239 1240 if(setreuid(-1, u->id) < 0){ 1241 fprint(2, "setreuid(-1, %s) failed\n", u->name); 1242 *ep = strerror(errno); 1243 return -1; 1244 } 1245 1246 return 0; 1247 } 1248 1249 /* 1250 * We do our own checking here, then switch to root temporarily 1251 * to set our gid. In a perfect world, you'd be allowed to set your 1252 * egid to any of the supplemental groups of your euid, but this 1253 * is not the case on Linux 2.2.14 (and perhaps others). 1254 * 1255 * This is a race, of course, but it's a race against processes 1256 * that can edit the group lists. If you can do that, you can 1257 * change your own group without our help. 1258 */ 1259 int 1260 groupchange(User *u, User *g, char **ep) 1261 { 1262 if(!useringroup(u, g)){ 1263 if(chatty9p) 1264 fprint(2, "%s not in group %s\n", u->name, g->name); 1265 *ep = Enotingroup; 1266 return -1; 1267 } 1268 1269 setreuid(0,0); 1270 if(setregid(-1, g->id) < 0){ 1271 fprint(2, "setegid(%s/%d) failed in groupchange\n", g->name, g->id); 1272 *ep = strerror(errno); 1273 return -1; 1274 } 1275 if(userchange(u, ep) < 0) 1276 return -1; 1277 1278 return 0; 1279 } 1280 1281 1282 /* 1283 * An attempt to enforce permissions by looking at the 1284 * file system. Separation of checking permission and 1285 * actually performing the action is a terrible idea, of 1286 * course, so we use setreuid for most of the permission 1287 * enforcement. This is here only so we can give errors 1288 * on open(ORCLOSE) in some cases. 1289 */ 1290 int 1291 userperm(User *u, char *path, int type, int need) 1292 { 1293 char *p, *q; 1294 int i, have; 1295 struct stat st; 1296 User *g; 1297 1298 switch(type){ 1299 default: 1300 fprint(2, "bad type %d in userperm\n", type); 1301 return -1; 1302 case Tdot: 1303 if(stat(path, &st) < 0){ 1304 fprint(2, "userperm: stat(%s) failed\n", path); 1305 return -1; 1306 } 1307 break; 1308 case Tdotdot: 1309 p = estrdup(path); 1310 if((q = strrchr(p, '/'))==nil){ 1311 fprint(2, "userperm(%s, ..): bad path\n", p); 1312 free(p); 1313 return -1; 1314 } 1315 if(q > p) 1316 *q = '\0'; 1317 else 1318 *(q+1) = '\0'; 1319 if(stat(p, &st) < 0){ 1320 fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n", 1321 p, path); 1322 free(p); 1323 return -1; 1324 } 1325 free(p); 1326 break; 1327 } 1328 1329 if(u == none){ 1330 fprint(2, "userperm: none wants %d in 0%luo\n", need, st.st_mode); 1331 have = st.st_mode&7; 1332 if((have&need)==need) 1333 return 0; 1334 return -1; 1335 } 1336 have = st.st_mode&7; 1337 if((uid_t)u->id == st.st_uid) 1338 have |= (st.st_mode>>6)&7; 1339 if((have&need)==need) 1340 return 0; 1341 if(((have|((st.st_mode>>3)&7))&need) != need) /* group won't help */ 1342 return -1; 1343 g = gid2user(st.st_gid); 1344 for(i=0; i<g->nmem; i++){ 1345 if(strcmp(g->mem[i], u->name) == 0){ 1346 have |= (st.st_mode>>3)&7; 1347 break; 1348 } 1349 } 1350 if((have&need)==need) 1351 return 0; 1352 return -1; 1353 } 1354 1355 int 1356 userwalk(User *u, char **path, char *elem, Qid *qid, char **ep) 1357 { 1358 char *npath; 1359 struct stat st; 1360 1361 npath = estrpath(*path, elem); 1362 if(stat(npath, &st) < 0){ 1363 free(npath); 1364 *ep = strerror(errno); 1365 return -1; 1366 } 1367 *qid = stat2qid(&st); 1368 free(*path); 1369 *path = npath; 1370 return 0; 1371 } 1372 1373 int 1374 useropen(Fid *fid, int omode, char **ep) 1375 { 1376 int a, o; 1377 1378 /* 1379 * Check this anyway, to try to head off problems later. 1380 */ 1381 if((omode&ORCLOSE) && userperm(fid->u, fid->path, Tdotdot, W_OK) < 0){ 1382 *ep = Eperm; 1383 return -1; 1384 } 1385 1386 switch(omode&3){ 1387 default: 1388 *ep = "programmer error"; 1389 return -1; 1390 case OREAD: 1391 a = R_OK; 1392 o = O_RDONLY; 1393 break; 1394 case ORDWR: 1395 a = R_OK|W_OK; 1396 o = O_RDWR; 1397 break; 1398 case OWRITE: 1399 a = R_OK; 1400 o = O_WRONLY; 1401 break; 1402 case OEXEC: 1403 a = X_OK; 1404 o = O_RDONLY; 1405 break; 1406 } 1407 if(omode & OTRUNC){ 1408 a |= W_OK; 1409 o |= O_TRUNC; 1410 } 1411 1412 if(S_ISDIR(fid->st.st_mode)){ 1413 if(a != R_OK){ 1414 fprint(2, "attempt by %s to open dir %d\n", fid->u->name, omode); 1415 *ep = Eperm; 1416 return -1; 1417 } 1418 if((fid->dir = opendir(fid->path)) == nil){ 1419 *ep = strerror(errno); 1420 return -1; 1421 } 1422 }else{ 1423 if(access(fid->path, a) < 0){ 1424 *ep = strerror(errno); 1425 return -1; 1426 } 1427 if((fid->fd = open(fid->path, o)) < 0){ 1428 *ep = strerror(errno); 1429 return -1; 1430 } 1431 } 1432 fid->omode = omode; 1433 return 0; 1434 } 1435 1436 int 1437 usercreate(Fid *fid, char *elem, int omode, long perm, char **ep) 1438 { 1439 int o, m; 1440 char *opath, *npath; 1441 struct stat st, parent; 1442 1443 if(stat(fid->path, &parent) < 0){ 1444 *ep = strerror(errno); 1445 return -1; 1446 } 1447 1448 /* 1449 * Change group so that created file has expected group 1450 * by Plan 9 semantics. If that fails, might as well go 1451 * with the user's default group. 1452 */ 1453 if(groupchange(fid->u, gid2user(parent.st_gid), ep) < 0 1454 && groupchange(fid->u, gid2user(fid->u->defaultgid), ep) < 0) 1455 return -1; 1456 1457 m = (perm & DMDIR) ? 0777 : 0666; 1458 perm = perm & (~m | (fid->st.st_mode & m)); 1459 1460 npath = estrpath(fid->path, elem); 1461 if(perm & DMDIR){ 1462 if((omode&~ORCLOSE) != OREAD){ 1463 *ep = Eperm; 1464 free(npath); 1465 return -1; 1466 } 1467 if(stat(npath, &st) >= 0 || errno != ENOENT){ 1468 *ep = Eexist; 1469 free(npath); 1470 return -1; 1471 } 1472 /* race */ 1473 if(mkdir(npath, perm&0777) < 0){ 1474 *ep = strerror(errno); 1475 free(npath); 1476 return -1; 1477 } 1478 if((fid->dir = opendir(npath)) == nil){ 1479 *ep = strerror(errno); 1480 remove(npath); /* race */ 1481 free(npath); 1482 return -1; 1483 } 1484 }else{ 1485 o = O_CREAT|O_EXCL; 1486 switch(omode&3){ 1487 default: 1488 *ep = "programmer error"; 1489 return -1; 1490 case OREAD: 1491 case OEXEC: 1492 o |= O_RDONLY; 1493 break; 1494 case ORDWR: 1495 o |= O_RDWR; 1496 break; 1497 case OWRITE: 1498 o |= O_WRONLY; 1499 break; 1500 } 1501 if(omode & OTRUNC) 1502 o |= O_TRUNC; 1503 if((fid->fd = open(npath, o, perm&0777)) < 0){ 1504 if(chatty9p) 1505 fprint(2, "create(%s, 0x%x, 0%o) failed\n", npath, o, perm&0777); 1506 *ep = strerror(errno); 1507 free(npath); 1508 return -1; 1509 } 1510 } 1511 1512 opath = fid->path; 1513 fid->path = npath; 1514 if(fidstat(fid, ep) < 0){ 1515 fprint(2, "stat after create on %s failed\n", npath); 1516 remove(npath); /* race */ 1517 free(npath); 1518 fid->path = opath; 1519 if(fid->fd >= 0){ 1520 close(fid->fd); 1521 fid->fd = -1; 1522 }else{ 1523 closedir(fid->dir); 1524 fid->dir = nil; 1525 } 1526 return -1; 1527 } 1528 fid->omode = omode; 1529 free(opath); 1530 return 0; 1531 } 1532 1533 int 1534 userremove(Fid *fid, char **ep) 1535 { 1536 if(remove(fid->path) < 0){ 1537 *ep = strerror(errno); 1538 return -1; 1539 } 1540 return 0; 1541 } 1542 1543 void 1544 usage(void) 1545 { 1546 fprint(2, "usage: u9fs [-Dnz] [-a authmethod] [-m msize] [-u user] [root]\n"); 1547 exit(1); 1548 } 1549 1550 int 1551 main(int argc, char **argv) 1552 { 1553 char *authtype; 1554 int i; 1555 int fd; 1556 int logflag; 1557 1558 auth = authmethods[0]; 1559 logflag = O_WRONLY|O_APPEND|O_CREAT; 1560 ARGBEGIN{ 1561 case 'D': 1562 chatty9p = 1; 1563 break; 1564 case 'a': 1565 authtype = EARGF(usage()); 1566 auth = nil; 1567 for(i=0; i<nelem(authmethods); i++) 1568 if(strcmp(authmethods[i]->name, authtype)==0) 1569 auth = authmethods[i]; 1570 if(auth == nil) 1571 sysfatal("unknown auth type '%s'", authtype); 1572 break; 1573 case 'A': 1574 autharg = EARGF(usage()); 1575 break; 1576 case 'l': 1577 logfile = EARGF(usage()); 1578 break; 1579 case 'm': 1580 msize = strtol(EARGF(usage()), 0, 0); 1581 break; 1582 case 'n': 1583 network = 0; 1584 break; 1585 case 'u': 1586 defaultuser = EARGF(usage()); 1587 break; 1588 case 'z': 1589 logflag |= O_TRUNC; 1590 }ARGEND 1591 1592 if(argc > 1) 1593 usage(); 1594 1595 fd = open(logfile, logflag, 0666); 1596 if(fd < 0) 1597 sysfatal("cannot open log '%s'", logfile); 1598 1599 if(dup2(fd, 2) < 0) 1600 sysfatal("cannot dup fd onto stderr"); 1601 fprint(2, "u9fs\nkill %d\n", (int)getpid()); 1602 1603 fmtinstall('F', fcallconv); 1604 fmtinstall('D', dirconv); 1605 fmtinstall('M', dirmodeconv); 1606 1607 rxbuf = emalloc(msize); 1608 txbuf = emalloc(msize); 1609 databuf = emalloc(msize); 1610 1611 if(auth->init) 1612 auth->init(); 1613 1614 if(network) 1615 getremotehostname(remotehostname, sizeof remotehostname); 1616 1617 if(gethostname(hostname, sizeof hostname) < 0) 1618 strcpy(hostname, "gnot"); 1619 1620 umask(0); 1621 1622 if(argc == 1) 1623 if(chroot(argv[0]) < 0) 1624 sysfatal("chroot '%s' failed", argv[0]); 1625 1626 none = uname2user("none"); 1627 serve(0, 1); 1628 return 0; 1629 } 1630