1 #include "u.h" 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include "libc.h" 5 #include "9p.h" 6 #include "stdio.h" 7 #include "setjmp.h" 8 #include "pwd.h" 9 #include "grp.h" 10 11 #define DBG(f) 12 13 struct group *getgrent(void); 14 struct passwd *getpwent(void); 15 16 #ifdef SYSV 17 # include <dirent.h> 18 # define DTYPE struct dirent 19 # define SOCKETS 20 #endif 21 #ifdef V10 22 # include <ndir.h> 23 # define DTYPE struct direct 24 #endif 25 #ifdef BSD 26 # include <sys/dir.h> 27 # define DTYPE struct direct 28 # define SOCKETS 29 #endif 30 #ifdef SOCKETS 31 # define sendmsg __sendmsg 32 # include <sys/socket.h> 33 # include <netinet/in.h> 34 # include <netdb.h> 35 # include <arpa/inet.h> 36 # undef sendmsg 37 char bsdhost[256]; 38 void remotehostname(void); 39 char ipaddr[20]; 40 #endif 41 42 typedef struct File File; 43 typedef struct Rfile Rfile; 44 typedef struct Fd Fd; 45 typedef struct Pass Pass; 46 47 struct Fd{ 48 int ref; 49 Ulong offset; 50 int fd; 51 DIR *dir; 52 }; 53 54 struct Rfile{ 55 int busy; 56 int uid; 57 int rclose; 58 File *file; 59 Fd *fd; 60 }; 61 62 struct File{ 63 int ref; 64 char *path; 65 char *name; 66 Qid qid; 67 struct stat stbuf; 68 }; 69 70 struct Pass{ 71 int id; 72 int gid; 73 char *name; 74 Pass *next; 75 Pass *nnext; 76 int nmem; 77 gid_t *mem; 78 }; 79 80 char data[2][MAXMSG+MAXFDATA]; 81 char tdata[MAXMSG+MAXFDATA]; 82 char rdata[MAXFDATA]; 83 Fcall rhdr; 84 Fcall thdr; 85 Rfile *rfile; 86 File *file0; 87 int nrfilealloc; 88 jmp_buf loopjmp; 89 Pass* uid[256]; 90 Pass* gid[256]; 91 Pass* uidname[256]; 92 Pass* gidname[256]; 93 int curuid; 94 int devallowed; 95 int connected; 96 int readonly; 97 int myuid; 98 char *onlyuser; 99 100 void io(void); 101 void error(char*); 102 char *mfmt(Fcall*); 103 void sendmsg(const char*); 104 int okfid(int); 105 Rfile* rfilefid(void); 106 File* newfile(void); 107 void* erealloc(void*, unsigned); 108 char* estrdup(char*); 109 const char* dostat(File*, char*); 110 char* bldpath(char*, char*, char*); 111 Ulong qid(struct stat*); 112 Ulong vers(struct stat*); 113 void errjmp(const char*); 114 int omode(int); 115 char* id2name(Pass**, int); 116 Pass* id2pass(Pass**, int); 117 Pass* name2pass(Pass**, char*); 118 void getpwdf(void); 119 void getgrpf(void); 120 int hash(char*); 121 void setupuser(int); 122 123 void rsession(void); 124 void rattach(void); 125 void rflush(void); 126 void rclone(void); 127 void rwalk(void); 128 void ropen(void); 129 void rcreate(void); 130 void rread(void); 131 void rwrite(void); 132 void rclunk(int); 133 void rstat(void); 134 void rwstat(void); 135 void rclwalk(void); 136 137 char Eauth[] = "authentication failed"; 138 char Eperm[] = "permission denied"; 139 char Ebadfid[] = "fid unknown or out of range"; 140 char Efidactive[] = "fid already in use"; 141 char Eopen[] = "file is open"; 142 char Emode[] = "invalid open mode"; 143 char Especial[] = "no access to special file"; 144 char Especial0[] = "already attached without access to special files"; 145 char Especial1[] = "already attached with access to special files"; 146 char Enotopen[] = "file is not open"; 147 char Etoolarge[] = "i/o count too large"; 148 char Ebaddir[] = "i/o error on directory"; 149 char Eunknown[] = "unknown user or group"; 150 char Euid[] = "can't set uid"; 151 char Egid[] = "can't set gid"; 152 char Eowner[] = "not owner"; 153 154 void 155 usage(void) 156 { 157 fprintf(stderr, "u9fs [-r] [-u user uid]\n"); 158 exit(1); 159 } 160 161 int 162 main(int argc, char *argv[]) 163 { 164 char *s; 165 int onlyuid; 166 167 # ifdef LOG 168 freopen(LOG, "a", stderr); 169 # endif 170 171 setbuf(stderr, (void*)0); 172 DBG(fprintf(stderr, "u9fs\nkill %d\n", getpid())); 173 174 onlyuid = -1; 175 ARGBEGIN{ 176 case 'r': 177 readonly++; 178 break; 179 case 'u': 180 onlyuser = ARGF(); 181 if(onlyuser == 0) 182 usage(); 183 s = ARGF(); 184 if(s == 0) 185 usage(); 186 onlyuid = atoi(s); 187 break; 188 default: 189 usage(); 190 break; 191 }ARGEND 192 193 if(argc) 194 usage(); 195 196 # ifdef SOCKETS 197 if(!onlyuser) 198 remotehostname(); 199 # endif 200 201 setreuid(0, 0); 202 myuid = geteuid(); 203 if(onlyuser && myuid != onlyuid) 204 error("invalid uid"); 205 206 io(); 207 return 0; 208 } 209 210 void 211 io(void) 212 { 213 int m; 214 static int toggle, ndata; 215 char *datap; 216 217 /* 218 * TCP does not preserve record boundaries; this dance works around 219 * the problem. 220 */ 221 setjmp(loopjmp); 222 223 /* 224 * Invariant: data[toggle] has ndata bytes already 225 */ 226 loop: 227 datap = data[toggle]; 228 toggle ^= 1; 229 for(;;){ 230 if(ndata){ 231 m = convM2S(datap, &rhdr, ndata); 232 /* m is number of bytes more than a full message */ 233 if(m >= 0){ 234 memmove(data[toggle], datap+(ndata-m), m); 235 ndata = m; 236 break; 237 } 238 } 239 m = read(0, datap+ndata, (MAXMSG+MAXFDATA)-ndata); 240 if(m == 0){ 241 fprintf(stderr, "u9fs: eof\n"); 242 exit(1); 243 } 244 if(m < 0) 245 error("read"); 246 ndata += m; 247 } 248 249 thdr.type = rhdr.type+1; 250 thdr.tag = rhdr.tag; 251 thdr.fid = rhdr.fid; 252 DBG(fprintf(stderr, ">> %s\n", mfmt(&rhdr))); 253 switch(rhdr.type){ 254 case Tnop: 255 case Tflush: /* this is a synchronous fs; easy */ 256 break; 257 case Tsession: 258 rsession(); 259 break; 260 case Tattach: 261 rattach(); 262 break; 263 case Tclone: 264 rclone(); 265 break; 266 case Twalk: 267 rwalk(); 268 break; 269 case Tstat: 270 rstat(); 271 break; 272 case Twstat: 273 rwstat(); 274 break; 275 case Topen: 276 ropen(); 277 break; 278 case Tcreate: 279 rcreate(); 280 break; 281 case Tread: 282 rread(); 283 break; 284 case Twrite: 285 rwrite(); 286 break; 287 case Tclunk: 288 rclunk(0); 289 break; 290 case Tremove: 291 rclunk(1); 292 break; 293 default: 294 fprintf(stderr, "unknown message %s\n", mfmt(&rhdr)); 295 error("bad message"); 296 } 297 sendmsg(0); 298 goto loop; 299 } 300 301 void 302 rsession(void) 303 { 304 memset(thdr.authid, 0, sizeof(thdr.authid)); 305 memset(thdr.authdom, 0, sizeof(thdr.authdom)); 306 memset(thdr.chal, 0, sizeof(thdr.chal)); 307 } 308 309 void 310 rattach(void) 311 { 312 Rfile *rf; 313 Pass *p; 314 315 if(file0 == 0){ 316 file0 = newfile(); 317 file0->ref++; /* one extra to hold it up */ 318 file0->path = estrdup("/"); 319 file0->name = estrdup("/"); 320 errjmp(dostat(file0, 0)); 321 } 322 if(!okfid(rhdr.fid)) 323 errjmp(Ebadfid); 324 if(strncmp(rhdr.aname, "device", 6) == 0){ 325 if(connected && !devallowed) 326 errjmp(Especial0); 327 devallowed = 1; 328 }else{ 329 if(connected && devallowed) 330 errjmp(Especial1); 331 } 332 getpwdf(); 333 getgrpf(); 334 rf = &rfile[rhdr.fid]; 335 if(rf->busy) 336 errjmp(Efidactive); 337 p = name2pass(uidname, rhdr.uname); 338 if(p == 0) 339 errjmp(Eunknown); 340 if(p->id == 0 || (uid_t)p->id == (uid_t)-1 341 || myuid && p->id != myuid) 342 errjmp(Eperm); 343 # ifdef SOCKETS 344 if(!myuid && ruserok(bsdhost, 0, rhdr.uname, rhdr.uname) < 0) 345 errjmp(Eperm); 346 # endif 347 /* mark busy & inc ref cnt only after committed to succeed */ 348 rf->busy = 1; 349 rf->file = file0; 350 file0->ref++; 351 rf->rclose = 0; 352 rf->uid = p->id; 353 thdr.qid = file0->qid; 354 connected = 1; 355 } 356 357 void 358 rclone(void) 359 { 360 Rfile *rf, *nrf; 361 File *f; 362 363 rfilefid(); 364 if(!okfid(rhdr.newfid)) 365 errjmp(Ebadfid); 366 rf = &rfile[rhdr.fid]; 367 nrf = &rfile[rhdr.newfid]; 368 f = rf->file; 369 if(nrf->busy) 370 errjmp(Efidactive); 371 nrf->busy = 1; 372 nrf->file = f; 373 f->ref++; 374 nrf->fd = rf->fd; 375 nrf->uid = rf->uid; 376 nrf->rclose = rf->rclose; 377 if(nrf->fd){ 378 if(nrf->fd->ref == 0) 379 error("clone fd count"); 380 nrf->fd->ref++; 381 } 382 } 383 384 void 385 rwalk(void) 386 { 387 const char *err; 388 Rfile *rf; 389 File *of, *f; 390 391 rf = rfilefid(); 392 if(rf->fd) 393 errjmp(Eopen); 394 of = rf->file; 395 f = newfile(); 396 f->path = estrdup(of->path); 397 err = dostat(f, rhdr.name); 398 if(err){ 399 free(f->path); 400 free(f->name); 401 free(f); 402 errjmp(err); 403 } 404 if(of->ref <= 0) 405 error("walk ref count"); 406 if(--of->ref == 0){ 407 free(of->path); 408 free(of->name); 409 free(of); 410 } 411 rf->file = f; 412 thdr.qid = f->qid; 413 } 414 415 void 416 ropen(void) 417 { 418 Rfile *rf; 419 File *f; 420 int fd; 421 DIR *dir; 422 int m, trunc; 423 424 rf = rfilefid(); 425 f = rf->file; 426 if(rf->fd) 427 error("open already open"); 428 if(!devallowed && (f->stbuf.st_mode & S_IFCHR)) 429 errjmp(Especial); 430 m = rhdr.mode & (16|3); 431 trunc = m & 16; /* OTRUNC */ 432 switch(m){ 433 case 0: 434 case 1: 435 case 1|16: 436 case 2: 437 case 0|16: 438 case 2|16: 439 case 3: 440 break; 441 default: 442 errjmp(Emode); 443 } 444 445 m = omode(m & 3); 446 errno = 0; 447 if(f->qid.path & CHDIR){ 448 if(rhdr.mode != 0) /* OREAD */ 449 errjmp(Eperm); 450 dir = opendir(f->path); 451 if(dir == 0) 452 errjmp(sys_errlist[errno]); 453 fd = 0; 454 }else{ 455 if(trunc){ 456 if(readonly) errjmp("trunc disallowed"); 457 fd = creat(f->path, 0666); 458 if(fd >= 0) 459 if(m != 1){ 460 close(fd); 461 fd = open(f->path, m); 462 } 463 }else 464 fd = open(f->path, m); 465 if(fd < 0) 466 errjmp(sys_errlist[errno]); 467 dir = 0; 468 } 469 rf->rclose = rhdr.mode & 64; /* ORCLOSE */ 470 rf->fd = erealloc(0, sizeof(Fd)); 471 rf->fd->ref = 1; 472 rf->fd->fd = fd; 473 rf->fd->dir = dir; 474 rf->fd->offset = 0; 475 thdr.qid = f->qid; 476 } 477 478 void 479 rcreate(void) 480 { 481 Rfile *rf; 482 File *f, *of; 483 char *path; 484 const char *err; 485 int fd, m; 486 char name[NAMELEN]; 487 488 if(readonly) errjmp("write disallowed"); 489 rf = rfilefid(); 490 if(rf->fd) 491 errjmp(Eopen); 492 path = bldpath(rf->file->path, rhdr.name, name); 493 m = omode(rhdr.mode&3); 494 errno = 0; 495 /* plan 9 group sematics: always inherit from directory */ 496 if(rhdr.perm & CHDIR){ 497 if(m){ 498 free(path); 499 errjmp(Eperm); 500 } 501 fd = mkdir(path, 0777); 502 if(fd < 0){ 503 free(path); 504 errjmp(sys_errlist[errno]); 505 } 506 fd = open(path, 0); 507 free(path); 508 if(fd >= 0) 509 fchmod(fd, S_ISGID|(rhdr.perm&rf->file->stbuf.st_mode&0777)); 510 }else{ 511 fd = creat(path, 0666); 512 if(fd >= 0){ 513 if(m != 1){ 514 close(fd); 515 fd = open(path, m); 516 } 517 fchmod(fd, rhdr.perm&rf->file->stbuf.st_mode&0777); 518 } 519 free(path); 520 if(fd < 0) 521 errjmp(sys_errlist[errno]); 522 } 523 f = newfile(); 524 of = rf->file; 525 f->path = estrdup(of->path); 526 err = dostat(f, rhdr.name); 527 if(err){ 528 free(f->path); 529 free(f->name); 530 free(f); 531 errjmp(err); 532 } 533 if(!devallowed && (f->stbuf.st_mode & S_IFCHR)){ 534 free(f->path); 535 free(f->name); 536 free(f); 537 errjmp(Especial); 538 } 539 if(--of->ref == 0){ 540 free(of->path); 541 free(of->name); 542 free(of); 543 } 544 rf->file = f; 545 rf->rclose = rhdr.mode & 64; /* ORCLOSE */ 546 rf->fd = erealloc(0, sizeof(Fd)); 547 rf->fd->ref = 1; 548 rf->fd->fd = fd; 549 rf->fd->dir = 0; 550 rf->fd->offset = 0; 551 thdr.qid = f->qid; 552 } 553 554 void 555 rread(void) 556 { 557 Rfile *rf; 558 File *f; 559 long n; 560 DTYPE *de; 561 Dir d; 562 struct stat stbuf; 563 char *path; 564 565 rf = rfilefid(); 566 if(rf->fd == 0) 567 errjmp(Enotopen); 568 if(rhdr.count > sizeof rdata) 569 errjmp(Etoolarge); 570 f = rf->file; 571 if(rf->fd->dir){ 572 errno = 0; 573 rhdr.count = (rhdr.count/DIRLEN)*DIRLEN; 574 if(rf->fd->offset != rhdr.offset){ 575 rf->fd->offset = rhdr.offset; /* sync offset */ 576 seekdir(rf->fd->dir, 0); 577 for(n=0; n<rhdr.offset; ){ 578 de = readdir(rf->fd->dir); 579 if(de == 0) 580 break; 581 if(de->d_ino==0 || de->d_name[0]==0) 582 continue; 583 if(strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0) 584 continue; 585 n += DIRLEN; 586 } 587 } 588 for(n=0; n<rhdr.count; ){ 589 de = readdir(rf->fd->dir); 590 if(de == 0) 591 break; 592 if(de->d_ino==0 || de->d_name[0]==0) 593 continue; 594 if(strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0) 595 continue; 596 strncpy(d.name, de->d_name, NAMELEN-1); 597 d.name[NAMELEN-1] = 0; 598 path = erealloc(0, strlen(f->path)+1+strlen(de->d_name)+1); 599 sprintf(path, "%s/%s", f->path, de->d_name); 600 memset(&stbuf, 0, sizeof stbuf); 601 if(stat(path, &stbuf) < 0){ 602 fprintf(stderr, "dir: bad path %s\n", path); 603 /* but continue... probably a bad symlink */ 604 } 605 free(path); 606 strncpy(d.uid, id2name(uid, stbuf.st_uid), NAMELEN); 607 strncpy(d.gid, id2name(gid, stbuf.st_gid), NAMELEN); 608 d.qid.path = qid(&stbuf); 609 d.qid.vers = vers(&stbuf); 610 d.mode = (d.qid.path&CHDIR)|(stbuf.st_mode&0777); 611 d.atime = stbuf.st_atime; 612 d.mtime = stbuf.st_mtime; 613 d.len.hlength = 0; 614 d.len.length = stbuf.st_size; 615 convD2M(&d, rdata+n); 616 n += DIRLEN; 617 } 618 }else{ 619 errno = 0; 620 if(rf->fd->offset != rhdr.offset){ 621 rf->fd->offset = rhdr.offset; 622 if(lseek(rf->fd->fd, rhdr.offset, 0) < 0) 623 errjmp(sys_errlist[errno]); 624 } 625 n = read(rf->fd->fd, rdata, rhdr.count); 626 if(n < 0) 627 errjmp(sys_errlist[errno]); 628 } 629 rf->fd->offset += n; 630 thdr.count = n; 631 thdr.data = rdata; 632 } 633 634 void 635 rwrite(void) 636 { 637 Rfile *rf; 638 int n; 639 640 if(readonly) errjmp("write disallowed"); 641 rf = rfilefid(); 642 if(rf->fd == 0) 643 errjmp(Enotopen); 644 if(rhdr.count > sizeof rdata) 645 errjmp(Etoolarge); 646 errno = 0; 647 if(rf->fd->offset != rhdr.offset){ 648 rf->fd->offset = rhdr.offset; 649 if(lseek(rf->fd->fd, rhdr.offset, 0) < 0) 650 errjmp(sys_errlist[errno]); 651 } 652 n = write(rf->fd->fd, rhdr.data, rhdr.count); 653 if(n < 0) 654 errjmp(sys_errlist[errno]); 655 rf->fd->offset += n; 656 thdr.count = n; 657 } 658 659 void 660 rstat(void) 661 { 662 Rfile *rf; 663 File *f; 664 Dir d; 665 666 rf = rfilefid(); 667 f = rf->file; 668 errjmp(dostat(f, 0)); 669 strncpy(d.name, f->name, NAMELEN); 670 strncpy(d.uid, id2name(uid, f->stbuf.st_uid), NAMELEN); 671 strncpy(d.gid, id2name(gid, f->stbuf.st_gid), NAMELEN); 672 d.qid = f->qid; 673 d.mode = (f->qid.path&CHDIR)|(f->stbuf.st_mode&0777); 674 d.atime = f->stbuf.st_atime; 675 d.mtime = f->stbuf.st_mtime; 676 d.len.hlength = 0; 677 d.len.length = f->stbuf.st_size; 678 convD2M(&d, thdr.stat); 679 } 680 681 void 682 rwstat(void) 683 { 684 Rfile *rf; 685 File *f; 686 Dir d; 687 Pass *p; 688 char *path, *dir, name[NAMELEN], *e; 689 690 if(readonly) errjmp("write disallowed"); 691 rf = rfilefid(); 692 f = rf->file; 693 errjmp(dostat(f, 0)); 694 convM2D(rhdr.stat, &d); 695 errno = 0; 696 if(strcmp(d.name, f->name) != 0){ 697 dir = bldpath(f->path, "..", name); 698 path = erealloc(0, strlen(dir)+1+strlen(d.name)+1); 699 sprintf(path, "%s/%s", dir, d.name); 700 if(rename(f->path, path) < 0){ 701 free(path); 702 errjmp(sys_errlist[errno]); 703 } 704 free(f->path); 705 free(f->name); 706 f->path = path; 707 f->name = estrdup(d.name); 708 } 709 if((d.mode&0777) != (f->stbuf.st_mode&0777)){ 710 f->stbuf.st_mode = (f->stbuf.st_mode&~0777) | (d.mode&0777); 711 if(chmod(f->path, f->stbuf.st_mode) < 0) 712 errjmp(sys_errlist[errno]); 713 } 714 p = name2pass(gidname, d.gid); 715 if(p == 0){ 716 if(strtol(d.gid, &e, 10) == f->stbuf.st_gid && *e == 0) 717 return; 718 errjmp(Eunknown); 719 } 720 if(p->id != f->stbuf.st_gid){ 721 if(chown(f->path, f->stbuf.st_uid, p->id) < 0) 722 errjmp(sys_errlist[errno]); 723 f->stbuf.st_gid = p->id; 724 } 725 } 726 727 void 728 rclunk(int rm) 729 { 730 int ret; 731 const char *err; 732 Rfile *rf; 733 File *f; 734 Fd *fd; 735 736 err = 0; 737 rf = rfilefid(); 738 f = rf->file; 739 if(rm){ 740 if(f->qid.path & CHDIR) 741 ret = rmdir(f->path); 742 else 743 ret = unlink(f->path); 744 if(ret) 745 err = sys_errlist[errno]; 746 }else if(rf->rclose){ /* ignore errors */ 747 if(f->qid.path & CHDIR) 748 rmdir(f->path); 749 else 750 unlink(f->path); 751 } 752 753 rf->busy = 0; 754 if(--f->ref == 0){ 755 free(f->path); 756 free(f->name); 757 free(f); 758 } 759 fd = rf->fd; 760 if(fd){ 761 if(fd->ref <= 0) 762 error("clunk fd count"); 763 if(--fd->ref == 0){ 764 if(fd->fd) 765 close(fd->fd); 766 if(fd->dir) 767 closedir(fd->dir); 768 free(fd); 769 } 770 rf->fd = 0; 771 } 772 if(err) 773 errjmp(err); 774 } 775 776 char* 777 bldpath(char *a, char *elem, char *name) 778 { 779 char *path, *p; 780 781 if(strcmp(elem, "..") == 0){ 782 if(strcmp(a, "/") == 0){ 783 path = estrdup(a); 784 strcpy(name, a); 785 }else{ 786 p = strrchr(a, '/'); 787 if(p == 0){ 788 fprintf(stderr, "path: '%s'\n", path); 789 error("malformed path 1"); 790 } 791 if(p == a) /* reduced to "/" */ 792 p++; 793 path = erealloc(0, (p-a)+1); 794 memmove(path, a, (p-a)); 795 path[(p-a)] = 0; 796 if(strcmp(path, "/") == 0) 797 p = path; 798 else{ 799 p = strrchr(path, '/'); 800 if(p == 0){ 801 fprintf(stderr, "path: '%s'\n", path); 802 error("malformed path 2"); 803 } 804 p++; 805 } 806 if(strlen(p) >= NAMELEN) 807 error("bldpath: name too long"); 808 strcpy(name, p); 809 } 810 }else{ 811 if(strcmp(a, "/") == 0) 812 a = ""; 813 path = erealloc(0, strlen(a)+1+strlen(elem)+1); 814 sprintf(path, "%s/%s", a, elem); 815 if(strlen(elem) >= NAMELEN) 816 error("bldpath: name too long"); 817 strcpy(name, elem); 818 } 819 return path; 820 } 821 822 const char* 823 dostat(File *f, char *elem) 824 { 825 char *path; 826 struct stat stbuf; 827 char name[NAMELEN]; 828 829 if(elem) 830 path = bldpath(f->path, elem, name); 831 else 832 path = f->path; 833 errno = 0; 834 if(stat(path, &stbuf) < 0) 835 return sys_errlist[errno]; 836 if(elem){ 837 free(f->path); 838 f->path = path; 839 f->name = estrdup(name); 840 } 841 f->qid.path = qid(&stbuf); 842 f->qid.vers = vers(&stbuf); 843 f->stbuf = stbuf; 844 return 0; 845 } 846 847 int 848 omode(int m) 849 { 850 switch(m){ 851 case 0: /* OREAD */ 852 case 3: /* OEXEC */ 853 return 0; 854 case 1: /* OWRITE */ 855 return 1; 856 case 2: /* ORDWR */ 857 return 2; 858 } 859 errjmp(Emode); 860 return 0; 861 } 862 863 void 864 sendmsg(const char *err) 865 { 866 int n; 867 868 if(err){ 869 thdr.type = Rerror; 870 strncpy(thdr.ename, err, ERRLEN); 871 } 872 DBG(fprintf(stderr, "<< %s\n", mfmt(&thdr))); 873 n = convS2M(&thdr, tdata); 874 if(n == 0) 875 error("bad sendmsg format"); 876 if(write(1, tdata, n) != n) 877 error("write error"); 878 } 879 880 int 881 okfid(int fid) 882 { 883 enum{ Delta=10 }; 884 885 if(fid < 0){ 886 fprintf(stderr, "u9fs: negative fid %d\n", fid); 887 return 0; 888 } 889 if(fid >= nrfilealloc){ 890 fid += Delta; 891 rfile = erealloc(rfile, fid*sizeof(Rfile)); 892 memset(rfile+nrfilealloc, 0, (fid-nrfilealloc)*sizeof(Rfile)); 893 nrfilealloc = fid; 894 } 895 return 1; 896 } 897 898 Rfile* 899 rfilefid(void) 900 { 901 Rfile *rf; 902 903 if(!okfid(rhdr.fid)) 904 errjmp(Ebadfid); 905 rf = &rfile[rhdr.fid]; 906 if(rf->busy == 0) 907 errjmp(Ebadfid); 908 if(rf->file->ref <= 0) 909 error("ref count"); 910 setupuser(rf->uid); 911 return rf; 912 } 913 914 File* 915 newfile(void) 916 { 917 File *f; 918 919 f = erealloc(0, sizeof(File)); 920 memset(f, 0, sizeof(File)); 921 f->ref = 1; 922 return f; 923 } 924 925 /* 926 * qids: directory bit, seven bits of device, 24 bits of inode 927 */ 928 Ulong 929 vers(struct stat *st) 930 { 931 return st->st_mtime ^ (st->st_size<<8); 932 } 933 934 Ulong 935 qid(struct stat *st) 936 { 937 static int nqdev; 938 static Uchar *qdev; 939 Ulong q; 940 int dev; 941 942 if(qdev == 0){ 943 qdev = erealloc(0, 65536U); 944 memset(qdev, 0, 65536U); 945 } 946 q = 0; 947 if((st->st_mode&S_IFMT) == S_IFDIR) 948 q = CHDIR; 949 dev = st->st_dev & 0xFFFFUL; 950 if(qdev[dev] == 0){ 951 if(++nqdev >= 128) 952 error("too many devices"); 953 qdev[dev] = nqdev; 954 } 955 q |= qdev[dev]<<24; 956 q |= st->st_ino & 0x00FFFFFFUL; 957 return q; 958 } 959 960 Pass* 961 name2pass(Pass **pw, char *name) 962 { 963 Pass *p; 964 965 for(p = pw[hash(name)]; p; p = p->nnext) 966 if(strcmp(name, p->name) == 0) 967 return p; 968 return 0; 969 } 970 971 Pass* 972 id2pass(Pass **pw, int id) 973 { 974 int i; 975 Pass *p, *pp; 976 977 pp = 0; 978 /* use last on list == first in file */ 979 i = (id&0xFF) ^ ((id>>8)&0xFF); 980 for(p = pw[i]; p; p = p->next) 981 if(p->id == id) 982 pp = p; 983 return pp; 984 } 985 986 char* 987 id2name(Pass **pw, int id) 988 { 989 int i; 990 Pass *p; 991 char *s; 992 static char buf[40]; 993 994 s = 0; 995 /* use last on list == first in file */ 996 i = (id&0xFF) ^ ((id>>8)&0xFF); 997 for(p = pw[i]; p; p = p->next) 998 if(p->id == id) 999 s = p->name; 1000 if(s) 1001 return s; 1002 sprintf(buf, "%d", id); 1003 return buf; 1004 } 1005 1006 void 1007 freepass(Pass **pass) 1008 { 1009 int i; 1010 Pass *p, *np; 1011 1012 for(i=0; i<256; i++){ 1013 for(p = pass[i]; p; p = np){ 1014 np = p->next; 1015 free(p->mem); 1016 free(p); 1017 } 1018 pass[i] = 0; 1019 } 1020 } 1021 1022 void 1023 setupuser(int u) 1024 { 1025 Pass *p; 1026 1027 if(curuid == u || myuid != 0) 1028 return; 1029 1030 p = id2pass(uid, u); 1031 if(p == 0 || p->id == 0 || (uid_t)p->id == (uid_t)-1) 1032 errjmp(Eunknown); 1033 1034 if(setreuid(0, 0) < 0) 1035 error("can't revert to root"); 1036 1037 /* 1038 * this error message is just a likely guess 1039 */ 1040 if(setgroups(p->nmem, p->mem) < 0) 1041 errjmp("member of too many groups"); 1042 1043 if(setgid(p->gid) < 0 1044 || setreuid(0, p->id) < 0) 1045 errjmp(Eunknown); 1046 } 1047 1048 void 1049 getpwdf(void) 1050 { 1051 static int mtime; 1052 struct stat stbuf; 1053 struct passwd *pw; 1054 int i; 1055 Pass *p; 1056 1057 if(onlyuser){ 1058 i = (myuid&0xFF) ^ ((myuid>>8)&0xFF); 1059 if(uid[i]) 1060 return; 1061 p = erealloc(0, sizeof(Pass)); 1062 uid[i] = p; 1063 p->name = strdup(onlyuser); 1064 uidname[hash(p->name)] = p; 1065 p->id = myuid; 1066 p->gid = 60001; 1067 p->next = 0; 1068 p->nnext = 0; 1069 p->nmem = 0; 1070 p->mem = 0; 1071 curuid = p->id; 1072 return; 1073 } 1074 1075 curuid = -1; 1076 if(myuid == 0 && setreuid(0, 0) < 0) 1077 error("can't revert to root"); 1078 1079 if(stat("/etc/passwd", &stbuf) < 0) 1080 error("can't read /etc/passwd"); 1081 if(stbuf.st_mtime <= mtime) 1082 return; 1083 freepass(uid); 1084 for(i=0; i<256; i++) 1085 uidname[i] = 0; 1086 for(;;) { 1087 pw = getpwent(); 1088 if(!pw) 1089 break; 1090 i = pw->pw_uid; 1091 i = (i&0xFF) ^ ((i>>8)&0xFF); 1092 p = erealloc(0, sizeof(Pass)); 1093 p->next = uid[i]; 1094 uid[i] = p; 1095 p->id = pw->pw_uid; 1096 p->gid = pw->pw_gid; 1097 p->name = estrdup(pw->pw_name); 1098 p->nmem = 1; 1099 p->mem = erealloc(0, sizeof(p->mem[0])); 1100 p->mem[0] = p->gid; 1101 i = hash(p->name); 1102 p->nnext = uidname[i]; 1103 uidname[i] = p; 1104 } 1105 setpwent(); 1106 endpwent(); 1107 } 1108 1109 int 1110 ismem(Pass *u, int gid) 1111 { 1112 int i; 1113 1114 if(u->gid == gid) 1115 return 1; 1116 for(i = 0; i < u->nmem; i++) 1117 if(u->mem[i] == gid) 1118 return 1; 1119 return 0; 1120 } 1121 1122 void 1123 getgrpf(void) 1124 { 1125 static int mtime; 1126 struct stat stbuf; 1127 struct group *pw; 1128 int i, m; 1129 Pass *p, *u; 1130 1131 if(onlyuser) 1132 return; 1133 1134 if(stat("/etc/group", &stbuf) < 0 1135 || stbuf.st_mtime <= mtime) 1136 return; 1137 freepass(gid); 1138 for(i=0; i<256; i++) 1139 gidname[i] = 0; 1140 for(;;) { 1141 pw = getgrent(); 1142 if(!pw) 1143 break; 1144 i = pw->gr_gid; 1145 i = (i&0xFF) ^ ((i>>8)&0xFF); 1146 p = erealloc(0, sizeof(Pass)); 1147 p->next = gid[i]; 1148 gid[i] = p; 1149 p->id = pw->gr_gid; 1150 p->gid = 0; 1151 p->name = estrdup(pw->gr_name); 1152 i = hash(p->name); 1153 p->nnext = gidname[i]; 1154 gidname[i] = p; 1155 1156 for(m=0; pw->gr_mem[m]; m++) 1157 ; 1158 p->nmem = m; 1159 p->mem = 0; 1160 if(m != 0) 1161 p->mem = erealloc(0, m*sizeof(p->mem[0])); 1162 for(m = 0; m<p->nmem; m++){ 1163 u = name2pass(uidname, pw->gr_mem[m]); 1164 p->mem[m] = -1; 1165 if(u){ 1166 p->mem[m] = u->id; 1167 if(!ismem(u, p->id)){ 1168 u->mem = erealloc(u->mem, (u->nmem+1)*sizeof(u->mem[0])); 1169 u->mem[u->nmem++] = p->id; 1170 } 1171 } 1172 } 1173 } 1174 setgrent(); 1175 endgrent(); 1176 } 1177 1178 int 1179 hash(char *s) 1180 { 1181 int h; 1182 1183 h = 0; 1184 for(; *s; s++) 1185 h = (h << 1) ^ *s; 1186 return h & 255; 1187 } 1188 1189 void 1190 error(char *s) 1191 { 1192 fprintf(stderr, "u9fs: %s\n", s); 1193 perror("unix error"); 1194 exit(1); 1195 } 1196 1197 void 1198 errjmp(const char *s) 1199 { 1200 if(s == 0) 1201 return; 1202 sendmsg(s); 1203 longjmp(loopjmp, 1); 1204 } 1205 1206 void* 1207 erealloc(void *p, unsigned n) 1208 { 1209 if(p == 0) 1210 p = malloc(n); 1211 else 1212 p = realloc(p, n); 1213 if(p == 0) 1214 error("realloc fail"); 1215 return p; 1216 } 1217 1218 char* 1219 estrdup(char *p) 1220 { 1221 p = strdup(p); 1222 if(p == 0) 1223 error("strdup fail"); 1224 return p; 1225 } 1226 1227 #ifdef SOCKETS 1228 void 1229 remotehostname(void) 1230 { 1231 struct sockaddr_in sock; 1232 struct hostent *hp; 1233 int len; 1234 int on = 1; 1235 1236 len = sizeof sock; 1237 if(getpeername(0, (struct sockaddr*)&sock, &len) < 0) 1238 error("getpeername"); 1239 hp = gethostbyaddr((char *)&sock.sin_addr, sizeof (struct in_addr), 1240 sock.sin_family); 1241 if(hp == 0) 1242 error("gethostbyaddr"); 1243 strncpy(bsdhost, hp->h_name, sizeof(bsdhost)-1); 1244 bsdhost[sizeof(bsdhost)-1] = '\0'; 1245 fprintf(stderr, "bsdhost %s on %d\n", bsdhost, getpid()); 1246 strcpy(ipaddr, inet_ntoa(sock.sin_addr)); 1247 1248 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char*)&on, sizeof(on)); 1249 } 1250 #endif 1251