1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include <bio.h> 6 #include <ctype.h> 7 #include <ndb.h> 8 #include <ip.h> 9 #include <lock.h> 10 11 enum 12 { 13 Nreply= 8, 14 Maxreply= 256, 15 Maxrequest= 4*NAMELEN, 16 Ncache= 8, 17 18 Qcs= 1, 19 }; 20 21 typedef struct Mfile Mfile; 22 typedef struct Mlist Mlist; 23 typedef struct Network Network; 24 25 int vers; /* incremented each clone/attach */ 26 27 struct Mfile 28 { 29 int busy; 30 31 char user[NAMELEN]; 32 Qid qid; 33 int fid; 34 35 int nreply; 36 char *reply[Nreply]; 37 int replylen[Nreply]; 38 }; 39 40 struct Mlist 41 { 42 Mlist *next; 43 Mfile mf; 44 }; 45 46 Fcall *rhp; 47 Fcall *thp; 48 Mlist *mlist; 49 int mfd[2]; 50 char user[NAMELEN]; 51 int debug; 52 jmp_buf masterjmp; /* return through here after a slave process has been created */ 53 int *isslave; /* *isslave non-zero means this is a slave process */ 54 char *dbfile; 55 56 void rsession(void); 57 void rflush(void); 58 void rattach(Mfile *); 59 void rclone(Mfile *); 60 char* rwalk(Mfile *); 61 void rclwalk(Mfile *); 62 void ropen(Mfile *); 63 void rcreate(Mfile *); 64 void rread(Mfile *); 65 void rwrite(Mfile *); 66 void rclunk(Mfile *); 67 void rremove(Mfile *); 68 void rstat(Mfile *); 69 void rauth(void); 70 void rwstat(Mfile *); 71 void sendmsg(char*); 72 void error(char*); 73 void mountinit(char*, ulong); 74 void io(void); 75 void netinit(void); 76 void netadd(char*); 77 int lookup(Mfile*, char*, char*, char*); 78 char *genquery(Mfile*, char*); 79 int mygetfields(char*, char**, int, char); 80 int needproto(Network*, Ndbtuple*); 81 Ndbtuple* lookval(Ndbtuple*, Ndbtuple*, char*, char*); 82 Ndbtuple* reorder(Ndbtuple*, Ndbtuple*); 83 84 extern void paralloc(void); 85 86 char *mname[]={ 87 [Tnop] "Tnop", 88 [Tsession] "Tsession", 89 [Tflush] "Tflush", 90 [Tattach] "Tattach", 91 [Tclone] "Tclone", 92 [Twalk] "Twalk", 93 [Topen] "Topen", 94 [Tcreate] "Tcreate", 95 [Tclunk] "Tclunk", 96 [Tread] "Tread", 97 [Twrite] "Twrite", 98 [Tremove] "Tremove", 99 [Tstat] "Tstat", 100 [Twstat] "Twstat", 101 0, 102 }; 103 104 Lock dblock; /* mutex on database operations */ 105 106 char *logfile = "cs"; 107 108 109 void 110 main(int argc, char *argv[]) 111 { 112 Fcall rhdr; 113 Fcall thdr; 114 char *service = "#s/cs"; 115 int justsetname; 116 117 justsetname = 0; 118 rhp = &rhdr; 119 thp = &thdr; 120 ARGBEGIN{ 121 case 'd': 122 debug = 1; 123 service = "#s/dcs"; 124 break; 125 case 'f': 126 dbfile = ARGF(); 127 break; 128 case 'n': 129 justsetname = 1; 130 break; 131 }ARGEND 132 USED(argc); 133 USED(argv); 134 135 if(justsetname){ 136 netinit(); 137 exits(0); 138 } 139 unmount(service, "/net"); 140 remove(service); 141 mountinit(service, MAFTER); 142 143 lockinit(); 144 fmtinstall('F', fcallconv); 145 netinit(); 146 147 io(); 148 exits(0); 149 } 150 151 void 152 mountinit(char *service, ulong flags) 153 { 154 int f; 155 int p[2]; 156 char buf[32]; 157 158 if(pipe(p) < 0) 159 error("pipe failed"); 160 switch(rfork(RFFDG|RFPROC|RFNAMEG)){ 161 case 0: 162 close(p[1]); 163 break; 164 case -1: 165 error("fork failed\n"); 166 default: 167 /* 168 * make a /srv/cs 169 */ 170 f = create(service, 1, 0666); 171 if(f < 0) 172 error(service); 173 snprint(buf, sizeof(buf), "%d", p[1]); 174 if(write(f, buf, strlen(buf)) != strlen(buf)) 175 error("write /srv/cs"); 176 close(f); 177 178 /* 179 * put ourselves into the file system 180 */ 181 close(p[0]); 182 if(mount(p[1], "/net", flags, "") < 0) 183 error("mount failed\n"); 184 _exits(0); 185 } 186 mfd[0] = mfd[1] = p[0]; 187 } 188 189 Mfile* 190 newfid(int fid) 191 { 192 Mlist *f, *ff; 193 Mfile *mf; 194 195 ff = 0; 196 for(f = mlist; f; f = f->next) 197 if(f->mf.busy && f->mf.fid == fid) 198 return &f->mf; 199 else if(!ff && !f->mf.busy) 200 ff = f; 201 if(ff == 0){ 202 ff = malloc(sizeof *f); 203 if(ff == 0){ 204 fprint(2, "cs: malloc(%d)\n", sizeof *ff); 205 error("malloc failure"); 206 } 207 ff->next = mlist; 208 mlist = ff; 209 } 210 mf = &ff->mf; 211 memset(mf, 0, sizeof *mf); 212 mf->fid = fid; 213 return mf; 214 } 215 216 void 217 io(void) 218 { 219 long n; 220 Mfile *mf; 221 int slaveflag; 222 char mdata[MAXFDATA + MAXMSG]; 223 224 /* 225 * if we ask dns to fulfill requests, 226 * a slave process is created to wait for replies. The 227 * master process returns immediately via a longjmp's 228 * through 'masterjmp'. 229 * 230 * *isslave is a pointer into the call stack to a variable 231 * that tells whether or not the current process is a slave. 232 */ 233 slaveflag = 0; /* init slave variable */ 234 isslave = &slaveflag; 235 setjmp(masterjmp); 236 237 for(;;){ 238 n = read9p(mfd[0], mdata, sizeof mdata); 239 if(n<=0) 240 error("mount read"); 241 if(convM2S(mdata, rhp, n) == 0){ 242 syslog(1, logfile, "format error %ux %ux %ux %ux %ux", mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]); 243 continue; 244 } 245 if(rhp->fid<0) 246 error("fid out of range"); 247 lock(&dblock); 248 mf = newfid(rhp->fid); 249 if(debug) 250 syslog(0, logfile, "%F", rhp); 251 252 253 switch(rhp->type){ 254 default: 255 syslog(1, logfile, "unknown request type %d", rhp->type); 256 break; 257 case Tsession: 258 rsession(); 259 break; 260 case Tnop: 261 rflush(); 262 break; 263 case Tflush: 264 rflush(); 265 break; 266 case Tattach: 267 rattach(mf); 268 break; 269 case Tclone: 270 rclone(mf); 271 break; 272 case Twalk: 273 rwalk(mf); 274 break; 275 case Tclwalk: 276 rclwalk(mf); 277 break; 278 case Topen: 279 ropen(mf); 280 break; 281 case Tcreate: 282 rcreate(mf); 283 break; 284 case Tread: 285 rread(mf); 286 break; 287 case Twrite: 288 rwrite(mf); 289 break; 290 case Tclunk: 291 rclunk(mf); 292 break; 293 case Tremove: 294 rremove(mf); 295 break; 296 case Tstat: 297 rstat(mf); 298 break; 299 case Twstat: 300 rwstat(mf); 301 break; 302 } 303 unlock(&dblock); 304 /* 305 * slave processes die after replying 306 */ 307 if(*isslave){ 308 if(debug) 309 syslog(0, logfile, "slave death %d", getpid()); 310 _exits(0); 311 } 312 } 313 } 314 315 void 316 rsession(void) 317 { 318 memset(thp->authid, 0, sizeof(thp->authid)); 319 memset(thp->authdom, 0, sizeof(thp->authdom)); 320 memset(thp->chal, 0, sizeof(thp->chal)); 321 sendmsg(0); 322 } 323 324 void 325 rflush(void) /* synchronous so easy */ 326 { 327 sendmsg(0); 328 } 329 330 void 331 rattach(Mfile *mf) 332 { 333 if(mf->busy == 0){ 334 mf->busy = 1; 335 strcpy(mf->user, rhp->uname); 336 } 337 mf->qid.vers = vers++; 338 mf->qid.path = CHDIR; 339 thp->qid = mf->qid; 340 sendmsg(0); 341 } 342 343 void 344 rclone(Mfile *mf) 345 { 346 Mfile *nmf; 347 char *err=0; 348 349 if(rhp->newfid<0){ 350 err = "clone nfid out of range"; 351 goto send; 352 } 353 nmf = newfid(rhp->newfid); 354 if(nmf->busy){ 355 err = "clone to used channel"; 356 goto send; 357 } 358 *nmf = *mf; 359 nmf->fid = rhp->newfid; 360 nmf->qid.vers = vers++; 361 send: 362 sendmsg(err); 363 } 364 365 void 366 rclwalk(Mfile *mf) 367 { 368 Mfile *nmf; 369 370 if(rhp->newfid<0){ 371 sendmsg("clone nfid out of range"); 372 return; 373 } 374 nmf = newfid(rhp->newfid); 375 if(nmf->busy){ 376 sendmsg("clone to used channel"); 377 return; 378 } 379 *nmf = *mf; 380 nmf->fid = rhp->newfid; 381 rhp->fid = rhp->newfid; 382 nmf->qid.vers = vers++; 383 if(rwalk(nmf)) 384 nmf->busy = 0; 385 } 386 387 char* 388 rwalk(Mfile *mf) 389 { 390 char *err; 391 char *name; 392 393 err = 0; 394 name = rhp->name; 395 if((mf->qid.path & CHDIR) == 0){ 396 err = "not a directory"; 397 goto send; 398 } 399 if(strcmp(name, ".") == 0){ 400 mf->qid.path = CHDIR; 401 goto send; 402 } 403 if(strcmp(name, "cs") == 0){ 404 mf->qid.path = Qcs; 405 goto send; 406 } 407 err = "nonexistent file"; 408 send: 409 thp->qid = mf->qid; 410 sendmsg(err); 411 return err; 412 } 413 414 void 415 ropen(Mfile *mf) 416 { 417 int mode; 418 char *err; 419 420 err = 0; 421 mode = rhp->mode; 422 if(mf->qid.path & CHDIR){ 423 if(mode) 424 err = "permission denied"; 425 } 426 send: 427 thp->qid = mf->qid; 428 sendmsg(err); 429 } 430 431 void 432 rcreate(Mfile *mf) 433 { 434 USED(mf); 435 sendmsg("creation permission denied"); 436 } 437 438 void 439 rread(Mfile *mf) 440 { 441 int i, n, cnt; 442 long off, toff, clock; 443 Dir dir; 444 char buf[MAXFDATA]; 445 char *err; 446 447 n = 0; 448 err = 0; 449 off = rhp->offset; 450 cnt = rhp->count; 451 if(mf->qid.path & CHDIR){ 452 if(off%DIRLEN || cnt%DIRLEN){ 453 err = "bad offset"; 454 goto send; 455 } 456 clock = time(0); 457 if(off == 0){ 458 memmove(dir.name, "cs", NAMELEN); 459 dir.qid.vers = vers; 460 dir.qid.path = Qcs; 461 dir.mode = 0666; 462 dir.length = 0; 463 dir.hlength = 0; 464 strcpy(dir.uid, mf->user); 465 strcpy(dir.gid, mf->user); 466 dir.atime = clock; /* wrong */ 467 dir.mtime = clock; /* wrong */ 468 convD2M(&dir, buf+n); 469 n += DIRLEN; 470 } 471 thp->data = buf; 472 } else { 473 toff = 0; 474 for(i = 0; mf->reply[i] && i < mf->nreply; i++){ 475 n = mf->replylen[i]; 476 if(off < toff + n) 477 break; 478 toff += n; 479 } 480 if(i >= mf->nreply){ 481 n = 0; 482 goto send; 483 } 484 thp->data = mf->reply[i] + (off - toff); 485 if(cnt > toff - off + n) 486 n = toff - off + n; 487 else 488 n = cnt; 489 } 490 send: 491 thp->count = n; 492 sendmsg(err); 493 } 494 495 void 496 rwrite(Mfile *mf) 497 { 498 int cnt, n; 499 char *err; 500 char *field[3]; 501 int rv; 502 503 err = 0; 504 cnt = rhp->count; 505 if(mf->qid.path & CHDIR){ 506 err = "can't write directory"; 507 goto send; 508 } 509 if(cnt >= Maxrequest){ 510 err = "request too long"; 511 goto send; 512 } 513 rhp->data[cnt] = 0; 514 515 /* 516 * toggle debugging 517 */ 518 if(strncmp(rhp->data, "debug", 5)==0){ 519 debug ^= 1; 520 syslog(1, logfile, "debug %d", debug); 521 goto send; 522 } 523 524 /* 525 * add networks to the default list 526 */ 527 if(strncmp(rhp->data, "add ", 4)==0){ 528 if(rhp->data[cnt-1] == '\n') 529 rhp->data[cnt-1] = 0; 530 netadd(rhp->data+4); 531 goto send; 532 } 533 534 /* 535 * look for a general query 536 */ 537 if(*rhp->data == '!'){ 538 err = genquery(mf, rhp->data+1); 539 goto send; 540 } 541 542 /* 543 * break up name 544 */ 545 if(debug) 546 syslog(0, logfile, "write %s", rhp->data); 547 548 n = mygetfields(rhp->data, field, 3, '!'); 549 rv = -1; 550 switch(n){ 551 case 1: 552 rv = lookup(mf, "net", field[0], 0); 553 break; 554 case 2: 555 rv = lookup(mf, field[0], field[1], 0); 556 break; 557 case 3: 558 rv = lookup(mf, field[0], field[1], field[2]); 559 break; 560 } 561 562 if(rv < 0) 563 err = "can't translate address"; 564 565 send: 566 thp->count = cnt; 567 sendmsg(err); 568 } 569 570 void 571 rclunk(Mfile *mf) 572 { 573 int i; 574 575 for(i = 0; i < mf->nreply; i++) 576 free(mf->reply[i]); 577 mf->busy = 0; 578 mf->fid = 0; 579 sendmsg(0); 580 } 581 582 void 583 rremove(Mfile *mf) 584 { 585 USED(mf); 586 sendmsg("remove permission denied"); 587 } 588 589 void 590 rstat(Mfile *mf) 591 { 592 Dir dir; 593 594 if(mf->qid.path & CHDIR){ 595 strcpy(dir.name, "."); 596 dir.mode = CHDIR|0555; 597 } else { 598 strcpy(dir.name, "cs"); 599 dir.mode = 0666; 600 } 601 dir.qid = mf->qid; 602 dir.length = 0; 603 dir.hlength = 0; 604 strcpy(dir.uid, mf->user); 605 strcpy(dir.gid, mf->user); 606 dir.atime = dir.mtime = time(0); 607 convD2M(&dir, (char*)thp->stat); 608 sendmsg(0); 609 } 610 611 void 612 rwstat(Mfile *mf) 613 { 614 USED(mf); 615 sendmsg("wstat permission denied"); 616 } 617 618 void 619 sendmsg(char *err) 620 { 621 int n; 622 char mdata[MAXFDATA + MAXMSG]; 623 624 if(err){ 625 thp->type = Rerror; 626 snprint(thp->ename, sizeof(thp->ename), "cs: %s", err); 627 }else{ 628 thp->type = rhp->type+1; 629 thp->fid = rhp->fid; 630 } 631 thp->tag = rhp->tag; 632 n = convS2M(thp, mdata); 633 if(n == 0){ 634 syslog(1, logfile, "sendmsg convS2M of %F returns 0", thp); 635 abort(); 636 } 637 if(write9p(mfd[1], mdata, n)!=n) 638 error("mount write"); 639 if(debug) 640 syslog(0, logfile, "%F %d", thp, n); 641 } 642 643 void 644 error(char *s) 645 { 646 syslog(1, "cs", "%s: %r", s); 647 _exits(0); 648 } 649 650 /* 651 * Network specific translators 652 */ 653 Ndbtuple* iplookup(Network*, char*, char*, int); 654 char* iptrans(Ndbtuple*, Network*, char*); 655 Ndbtuple* dklookup(Network*, char*, char*, int); 656 char* dktrans(Ndbtuple*, Network*, char*); 657 Ndbtuple* telcolookup(Network*, char*, char*, int); 658 char* telcotrans(Ndbtuple*, Network*, char*); 659 Ndbtuple* dnsiplookup(char*, Ndbs*, char*); 660 661 struct Network 662 { 663 char *net; 664 int nolookup; 665 Ndbtuple *(*lookup)(Network*, char*, char*, int); 666 char *(*trans)(Ndbtuple*, Network*, char*); 667 int needproto; 668 Network *next; 669 int def; 670 }; 671 672 Network network[] = { 673 { "il", 0, iplookup, iptrans, 1, }, 674 { "fil", 0, iplookup, iptrans, 1, }, 675 { "tcp", 0, iplookup, iptrans, 0, }, 676 { "udp", 0, iplookup, iptrans, 0, }, 677 { "dk", 1, dklookup, dktrans, 0, }, 678 { "telco", 0, telcolookup, telcotrans, 0, }, 679 { 0, 0, 0, 0, 0, }, 680 }; 681 682 char eaddr[Ndbvlen]; /* ascii ethernet address */ 683 char ipaddr[Ndbvlen]; /* ascii internet address */ 684 char dknet[Ndbvlen]; /* ascii datakit network name */ 685 uchar ipa[4]; /* binary internet address */ 686 char sysname[Ndbvlen]; 687 int isdk; 688 689 Network *netlist; /* networks ordered by preference */ 690 Network *last; 691 692 static Ndb *db; 693 694 695 /* 696 * get ip address and system name 697 */ 698 void 699 ipid(void) 700 { 701 uchar addr[6]; 702 Ndbtuple *t; 703 char *p, *attr; 704 Ndbs s; 705 int f; 706 static int isether; 707 708 /* grab ether addr from the device */ 709 if(isether == 0){ 710 if(myetheraddr(addr, "/net/ether") >= 0){ 711 snprint(eaddr, sizeof(eaddr), "%E", addr); 712 isether = 1; 713 } 714 } 715 716 /* grab ip addr from the device */ 717 if(*ipa == 0){ 718 if(myipaddr(ipa, "/net/tcp") >= 0){ 719 if(*ipa) 720 snprint(ipaddr, sizeof(ipaddr), "%I", ipa); 721 } 722 } 723 724 /* use ether addr plus db to get ipaddr */ 725 if(*ipa == 0 && isether){ 726 t = ndbgetval(db, &s, "ether", eaddr, "ip", ipaddr); 727 if(t){ 728 ndbfree(t); 729 parseip(ipa, ipaddr); 730 } 731 } 732 733 /* use environment, ether addr, or ipaddr to get system name */ 734 if(*sysname == 0){ 735 /* environment has priority */ 736 p = getenv("sysname"); 737 if(p ){ 738 attr = ipattr(p); 739 if(strcmp(attr, "ip") != 0) 740 strcpy(sysname, p); 741 } 742 743 /* next use ether and ip addresses to find system name */ 744 if(*sysname == 0){ 745 t = 0; 746 if(isether) 747 t = ndbgetval(db, &s, "ether", eaddr, "sys", sysname); 748 if(t == 0 && *ipa) 749 t = ndbgetval(db, &s, "ip", ipaddr, "sys", sysname); 750 if(t) 751 ndbfree(t); 752 } 753 754 /* set /dev/sysname if we now know it */ 755 if(*sysname){ 756 f = open("/dev/sysname", OWRITE); 757 if(f >= 0){ 758 write(f, sysname, strlen(sysname)); 759 close(f); 760 } 761 } 762 } 763 } 764 765 /* 766 * set the datakit network name from a datakit network address 767 */ 768 int 769 setdknet(char *x) 770 { 771 char *p; 772 773 strncpy(dknet, x, sizeof(dknet)-2); 774 p = strrchr(dknet, '/'); 775 if(p == 0 || p == strchr(dknet, '/')){ 776 *dknet = 0; 777 return 0; 778 } 779 *++p = '*'; 780 *(p+1) = 0; 781 return 1; 782 } 783 784 /* 785 * get datakit address 786 */ 787 void 788 dkid(void) 789 { 790 Ndbtuple *t; 791 Ndbs s; 792 char dkname[Ndbvlen]; 793 char raddr[Ndbvlen]; 794 int i, f, n; 795 static int isdknet; 796 797 /* try for a datakit network name in the database */ 798 if(isdknet == 0){ 799 /* use ether and ip addresses to find dk name */ 800 t = 0; 801 if(t == 0 && *ipa) 802 t = ndbgetval(db, &s, "ip", ipaddr, "dk", dkname); 803 if(t == 0 && *sysname) 804 t = ndbgetval(db, &s, "sys", sysname, "dk", dkname); 805 if(t){ 806 ndbfree(t); 807 isdknet = setdknet(dkname); 808 } 809 } 810 811 /* try for a datakit network name from a system we've connected to */ 812 if(isdknet == 0){ 813 for(i = 0; isdknet == 0 && i < 7; i++){ 814 snprint(raddr, sizeof(raddr), "/net/dk/%d/remote", i); 815 f = open(raddr, OREAD); 816 if(f < 0){ 817 isdknet = -1; 818 break; 819 } 820 n = read(f, raddr, sizeof(raddr)-1); 821 close(f); 822 if(n > 0){ 823 raddr[n] = 0; 824 isdknet = setdknet(raddr); 825 } 826 } 827 } 828 /* hack for gnots */ 829 if(isdknet <= 0) 830 isdknet = setdknet("nj/astro/Nfs"); 831 } 832 833 /* 834 * Set up a list of default networks by looking for 835 * /net/ * /clone. 836 */ 837 void 838 netinit(void) 839 { 840 char clone[256]; 841 Dir d; 842 Network *np; 843 844 /* add the mounted networks to the default list */ 845 for(np = network; np->net; np++){ 846 snprint(clone, sizeof(clone), "/net/%s/clone", np->net); 847 if(dirstat(clone, &d) < 0) 848 continue; 849 if(netlist) 850 last->next = np; 851 else 852 netlist = np; 853 last = np; 854 np->next = 0; 855 np->def = 1; 856 } 857 858 fmtinstall('E', eipconv); 859 fmtinstall('I', eipconv); 860 861 db = ndbopen(dbfile); 862 ipid(); 863 dkid(); 864 865 if(debug) 866 syslog(0, logfile, "sysname %s dknet %s eaddr %s ipaddr %s ipa %I\n", 867 sysname, dknet, eaddr, ipaddr, ipa); 868 } 869 870 /* 871 * add networks to the standard list 872 */ 873 void 874 netadd(char *p) 875 { 876 Network *np; 877 char *field[12]; 878 int i, n; 879 880 n = mygetfields(p, field, 12, ' '); 881 for(i = 0; i < n; i++){ 882 for(np = network; np->net; np++){ 883 if(strcmp(field[i], np->net) != 0) 884 continue; 885 if(np->def) 886 break; 887 if(netlist) 888 last->next = np; 889 else 890 netlist = np; 891 last = np; 892 np->next = 0; 893 np->def = 1; 894 } 895 } 896 } 897 898 /* 899 * make a tuple 900 */ 901 Ndbtuple* 902 mktuple(char *attr, char *val) 903 { 904 Ndbtuple *t; 905 906 t = malloc(sizeof(Ndbtuple)); 907 strcpy(t->attr, attr); 908 strncpy(t->val, val, sizeof(t->val)); 909 t->val[sizeof(t->val)-1] = 0; 910 t->line = t; 911 t->entry = 0; 912 return t; 913 } 914 915 /* 916 * lookup a request. the network "net" means we should pick the 917 * best network to get there. 918 */ 919 int 920 lookup(Mfile *mf, char *net, char *host, char *serv) 921 { 922 Network *np, *p; 923 char *cp; 924 Ndbtuple *nt, *t; 925 int i; 926 char reply[Maxreply]; 927 928 /* start transaction with a clean slate */ 929 for(i = 0; i < Nreply; i++){ 930 if(mf->reply[i]) 931 free(mf->reply[i]); 932 mf->reply[i] = 0; 933 mf->replylen[i] = 0; 934 } 935 mf->nreply = 0; 936 937 /* open up the standard db files */ 938 if(db == 0) 939 db = ndbopen(dbfile); 940 if(db == 0) 941 error("can't open network database\n"); 942 943 nt = 0; 944 if(strcmp(net, "net") == 0){ 945 /* 946 * go through set of default nets 947 */ 948 for(np = netlist; np; np = np->next){ 949 nt = (*np->lookup)(np, host, serv, 0); 950 if(nt){ 951 if(needproto(np, nt) == 0) 952 break; 953 ndbfree(nt); 954 nt = 0; 955 } 956 } 957 958 /* 959 * try first net that requires no table lookup 960 */ 961 if(nt == 0) 962 for(np = netlist; np; np = np->next){ 963 if(np->nolookup && *host != '$'){ 964 nt = (*np->lookup)(np, host, serv, 1); 965 if(nt) 966 break; 967 } 968 } 969 970 if(nt == 0) 971 return -1; 972 973 /* 974 * create replies 975 */ 976 for(p = np; p; p = p->next){ 977 for(t = nt; mf->nreply < Nreply && t; t = t->entry){ 978 if(needproto(p, nt) < 0) 979 continue; 980 cp = (*p->trans)(t, p, serv); 981 if(cp){ 982 mf->replylen[mf->nreply] = strlen(cp); 983 mf->reply[mf->nreply++] = cp; 984 } 985 } 986 } 987 for(p = netlist; mf->nreply < Nreply && p != np; p = p->next){ 988 for(t = nt; mf->nreply < Nreply && t; t = t->entry){ 989 if(needproto(p, nt) < 0) 990 continue; 991 cp = (*p->trans)(t, p, serv); 992 if(cp){ 993 mf->replylen[mf->nreply] = strlen(cp); 994 mf->reply[mf->nreply++] = cp; 995 } 996 } 997 } 998 ndbfree(nt); 999 return 0; 1000 } else { 1001 /* 1002 * look on a specific network 1003 */ 1004 for(p = network; p->net; p++){ 1005 if(strcmp(p->net, net) == 0){ 1006 nt = (*p->lookup)(p, host, serv, 1); 1007 if (nt == 0) 1008 return -1; 1009 1010 /* create replies */ 1011 for(t = nt; mf->nreply < Nreply && t; t = t->entry){ 1012 cp = (*p->trans)(t, p, serv); 1013 if(cp){ 1014 mf->replylen[mf->nreply] = strlen(cp); 1015 mf->reply[mf->nreply++] = cp; 1016 } 1017 } 1018 ndbfree(nt); 1019 return 0; 1020 } 1021 } 1022 } 1023 1024 /* 1025 * not a known network, don't translate host or service 1026 */ 1027 if(serv) 1028 snprint(reply, sizeof(reply), "/net/%s/clone %s!%s", 1029 net, host, serv); 1030 else 1031 snprint(reply, sizeof(reply), "/net/%s/clone %s", 1032 net, host); 1033 mf->reply[0] = strdup(reply); 1034 mf->replylen[0] = strlen(reply); 1035 mf->nreply = 1; 1036 return 0; 1037 } 1038 1039 /* 1040 * see if we can use this protocol 1041 */ 1042 int 1043 needproto(Network *np, Ndbtuple *t) 1044 { 1045 if(np->needproto == 0) 1046 return 0; 1047 for(; t; t = t->entry) 1048 if(strcmp(t->attr, "proto")==0 && strcmp(t->val, np->net)==0) 1049 return 0; 1050 return -1; 1051 } 1052 1053 /* 1054 * translate an ip service name into a port number. If it's a numeric port 1055 * number, look for restricted access. 1056 * 1057 * the service '*' needs no translation. 1058 */ 1059 char* 1060 ipserv(Network *np, char *name, char *buf) 1061 { 1062 char *p; 1063 int alpha = 0; 1064 int restr = 0; 1065 char port[Ndbvlen]; 1066 Ndbtuple *t, *nt; 1067 Ndbs s; 1068 1069 /* '*' means any service */ 1070 if(strcmp(name, "*")==0){ 1071 strcpy(buf, name); 1072 return buf; 1073 } 1074 1075 /* see if it's numeric or symbolic */ 1076 port[0] = 0; 1077 for(p = name; *p; p++){ 1078 if(isdigit(*p)) 1079 ; 1080 else if(isalpha(*p) || *p == '-' || *p == '$') 1081 alpha = 1; 1082 else 1083 return 0; 1084 } 1085 if(alpha){ 1086 t = ndbgetval(db, &s, np->net, name, "port", port); 1087 if(t == 0) 1088 return 0; 1089 } else { 1090 t = ndbgetval(db, &s, "port", name, "port", port); 1091 if(t == 0){ 1092 strncpy(port, name, sizeof(port)); 1093 port[sizeof(port)-1] = 0; 1094 } 1095 } 1096 1097 if(t){ 1098 for(nt = t; nt; nt = nt->entry) 1099 if(strcmp(nt->attr, "restricted") == 0) 1100 restr = 1; 1101 ndbfree(t); 1102 } 1103 sprint(buf, "%s%s", port, restr ? "!r" : ""); 1104 return buf; 1105 } 1106 1107 /* 1108 * look for the value associated with this attribute for our system. 1109 * the precedence is highest to lowest: 1110 * - an attr/value pair in this system's entry 1111 * - an attr/value pair in this system's subnet entry 1112 * - an attr/value pair in this system's net entry 1113 */ 1114 void 1115 ipattrlookup(char *attr, char *buf) 1116 { 1117 Ndbtuple *t, *st; 1118 Ndbs s, ss; 1119 char ip[Ndbvlen+1]; 1120 uchar net[4]; 1121 uchar mask[4]; 1122 1123 *buf = 0; 1124 1125 /* 1126 * look for an entry for this system 1127 */ 1128 ipid(); 1129 if(*ipa == 0) 1130 return; 1131 t = ndbsearch(db, &s, "ip", ipaddr); 1132 if(t){ 1133 /* 1134 * look for a closely bound attribute 1135 */ 1136 lookval(t, s.t, attr, buf); 1137 ndbfree(t); 1138 if(*buf) 1139 return; 1140 } 1141 1142 /* 1143 * Look up the client's network and find a subnet mask for it. 1144 * Fill in from the subnet (or net) entry anything we can't figure 1145 * out from the client record. 1146 */ 1147 maskip(ipa, classmask[CLASS(ipa)], net); 1148 snprint(ip, sizeof(ip), "%I", net); 1149 t = ndbsearch(db, &s, "ip", ip); 1150 if(t){ 1151 /* got a net, look for a subnet */ 1152 if(lookval(t, s.t, "ipmask", ip)){ 1153 parseip(mask, ip); 1154 maskip(ipa, mask, net); 1155 snprint(ip, sizeof(ip), "%I", net); 1156 st = ndbsearch(db, &ss, "ip", ip); 1157 if(st){ 1158 lookval(st, ss.t, attr, buf); 1159 ndbfree(st); 1160 } 1161 } 1162 1163 1164 /* fill in what the client and subnet entries didn't have */ 1165 if(*buf == 0) 1166 lookval(t, s.t, attr, buf); 1167 ndbfree(t); 1168 } 1169 } 1170 1171 /* 1172 * lookup (and translate) an ip destination 1173 */ 1174 Ndbtuple* 1175 iplookup(Network *np, char *host, char *serv, int nolookup) 1176 { 1177 char *attr; 1178 Ndbtuple *t; 1179 Ndbs s; 1180 char ts[Ndbvlen+1]; 1181 char th[Ndbvlen+1]; 1182 char dollar[Ndbvlen+1]; 1183 1184 USED(nolookup); 1185 1186 /* 1187 * start with the service since it's the most likely to fail 1188 * and costs the least 1189 */ 1190 if(serv==0 || ipserv(np, serv, ts) == 0) 1191 return 0; 1192 1193 /* for dial strings with no host */ 1194 if(strcmp(host, "*") == 0) 1195 return mktuple("ip", "*"); 1196 1197 /* 1198 * '$' means the rest of the name is an attribute that we 1199 * need to search for 1200 */ 1201 if(*host == '$'){ 1202 ipattrlookup(host+1, dollar); 1203 if(*dollar) 1204 host = dollar; 1205 } 1206 1207 /* 1208 * just accept addresses 1209 */ 1210 attr = ipattr(host); 1211 if(strcmp(attr, "ip") == 0) 1212 return mktuple("ip", host); 1213 1214 /* 1215 * give the domain name server the first opportunity to 1216 * resolve domain names. if that fails try the database. 1217 */ 1218 t = 0; 1219 if(strcmp(attr, "dom") == 0) 1220 t = dnsiplookup(host, &s, th); 1221 if(t == 0) 1222 t = ndbgetval(db, &s, attr, host, "ip", th); 1223 if(t == 0) 1224 return 0; 1225 1226 /* 1227 * reorder the tuple to have the matched line first and 1228 * save that in the request structure. 1229 */ 1230 return reorder(t, s.t); 1231 } 1232 1233 /* 1234 * translate an ip address 1235 */ 1236 char* 1237 iptrans(Ndbtuple *t, Network *np, char *serv) 1238 { 1239 char ts[Ndbvlen+1]; 1240 char reply[Maxreply]; 1241 1242 if(strcmp(t->attr, "ip") != 0) 1243 return 0; 1244 1245 if(serv == 0 || ipserv(np, serv, ts) == 0) 1246 return 0; 1247 1248 if(*t->val == '*') 1249 snprint(reply, sizeof(reply), "/net/%s/clone %s", 1250 np->net, ts); 1251 else 1252 snprint(reply, sizeof(reply), "/net/%s/clone %s!%s", 1253 np->net, t->val, ts); 1254 1255 return strdup(reply); 1256 } 1257 1258 /* 1259 * look for the value associated with this attribute for our system. 1260 * the precedence is highest to lowest: 1261 * - an attr/value pair in this system's entry 1262 * - an attr/value pair in this system's net entry 1263 */ 1264 void 1265 dkattrlookup(char *attr, char *buf) 1266 { 1267 Ndbtuple *t; 1268 Ndbs s; 1269 1270 *buf = 0; 1271 1272 dkid(); 1273 if(*dknet == 0) 1274 return; 1275 t = ndbsearch(db, &s, "dk", dknet); 1276 if(t){ 1277 lookval(t, s.t, attr, buf); 1278 ndbfree(t); 1279 } 1280 } 1281 1282 /* 1283 * lookup (and translate) a datakit destination 1284 */ 1285 Ndbtuple* 1286 dklookup(Network *np, char *host, char *serv, int nolookup) 1287 { 1288 char *p; 1289 int slash = 0; 1290 Ndbtuple *t, *nt; 1291 Ndbs s; 1292 char th[Ndbvlen+1]; 1293 char dollar[Ndbvlen+1]; 1294 char *attr; 1295 1296 USED(np); 1297 1298 /* 1299 * '$' means the rest of the name is an attribute that we 1300 * need to search for 1301 */ 1302 if(*host == '$'){ 1303 dkattrlookup(host+1, dollar); 1304 if(*dollar) 1305 host = dollar; 1306 } 1307 1308 for(p = host; *p; p++){ 1309 if(isalnum(*p) || *p == '-' || *p == '.') 1310 ; 1311 else if(*p == '/') 1312 slash = 1; 1313 else 1314 return 0; 1315 } 1316 1317 /* hack for announcements */ 1318 if(nolookup && serv == 0) 1319 return mktuple("dk", host); 1320 1321 /* let dk addresses be domain names */ 1322 attr = ipattr(host); 1323 1324 /* don't translate paths, just believe the user */ 1325 if(slash) 1326 return mktuple("dk", host); 1327 1328 t = ndbgetval(db, &s, attr, host, "dk", th); 1329 if(t == 0){ 1330 if(nolookup) 1331 return mktuple("dk", host); 1332 return 0; 1333 } 1334 1335 /* don't allow services in calls to consoles */ 1336 for(nt = t; nt; nt = nt->entry) 1337 if(strcmp("flavor", nt->attr)==0 1338 && strcmp("console", nt->val)==0 1339 && serv && *serv){ 1340 ndbfree(t); 1341 return 0; 1342 } 1343 1344 return reorder(t, s.t); 1345 } 1346 1347 /* 1348 * translate a datakit address 1349 */ 1350 char* 1351 dktrans(Ndbtuple *t, Network *np, char *serv) 1352 { 1353 char reply[Maxreply]; 1354 1355 if(strcmp(t->attr, "dk") != 0) 1356 return 0; 1357 1358 if(serv) 1359 snprint(reply, sizeof(reply), "/net/%s/clone %s!%s", np->net, 1360 t->val, serv); 1361 else 1362 snprint(reply, sizeof(reply), "/net/%s/clone %s", np->net, 1363 t->val); 1364 return strdup(reply); 1365 } 1366 1367 /* 1368 * lookup a telephone number 1369 */ 1370 Ndbtuple* 1371 telcolookup(Network *np, char *host, char *serv, int nolookup) 1372 { 1373 Ndbtuple *t; 1374 Ndbs s; 1375 char th[Ndbvlen+1]; 1376 1377 USED(np, nolookup, serv); 1378 1379 t = ndbgetval(db, &s, "sys", host, "telco", th); 1380 if(t == 0) 1381 return mktuple("telco", host); 1382 1383 return reorder(t, s.t); 1384 } 1385 1386 /* 1387 * translate a telephone address 1388 */ 1389 char* 1390 telcotrans(Ndbtuple *t, Network *np, char *serv) 1391 { 1392 char reply[Maxreply]; 1393 1394 if(strcmp(t->attr, "telco") != 0) 1395 return 0; 1396 1397 if(serv) 1398 snprint(reply, sizeof(reply), "/net/%s/clone %s!%s", np->net, 1399 t->val, serv); 1400 else 1401 snprint(reply, sizeof(reply), "/net/%s/clone %s", np->net, 1402 t->val); 1403 return strdup(reply); 1404 } 1405 int 1406 mygetfields(char *lp, char **fields, int n, char sep) 1407 { 1408 int i; 1409 char sep2=0; 1410 1411 if(sep == ' ') 1412 sep2 = '\t'; 1413 for(i=0; lp && *lp && i<n; i++){ 1414 if(*lp==sep || *lp==sep2) 1415 *lp++ = 0; 1416 if(*lp == 0) 1417 break; 1418 fields[i] = lp; 1419 while(*lp && *lp!=sep && *lp!=sep2) 1420 lp++; 1421 } 1422 return i; 1423 } 1424 1425 /* 1426 * Look for a pair with the given attribute. look first on the same line, 1427 * then in the whole entry. 1428 */ 1429 Ndbtuple* 1430 lookval(Ndbtuple *entry, Ndbtuple *line, char *attr, char *to) 1431 { 1432 Ndbtuple *nt; 1433 1434 /* first look on same line (closer binding) */ 1435 for(nt = line;;){ 1436 if(strcmp(attr, nt->attr) == 0){ 1437 strncpy(to, nt->val, Ndbvlen); 1438 return nt; 1439 } 1440 nt = nt->line; 1441 if(nt == line) 1442 break; 1443 } 1444 /* search whole tuple */ 1445 for(nt = entry; nt; nt = nt->entry) 1446 if(strcmp(attr, nt->attr) == 0){ 1447 strncpy(to, nt->val, Ndbvlen); 1448 return nt; 1449 } 1450 return 0; 1451 } 1452 1453 /* 1454 * reorder the tuple to put x's line first in the entry 1455 */ 1456 Ndbtuple* 1457 reorder(Ndbtuple *t, Ndbtuple *x) 1458 { 1459 Ndbtuple *nt; 1460 Ndbtuple *line; 1461 1462 /* find start of this entry's line */ 1463 for(line = x; line->entry == line->line; line = line->line) 1464 ; 1465 line = line->line; 1466 if(line == t) 1467 return t; /* already the first line */ 1468 1469 /* remove this line and everything after it from the entry */ 1470 for(nt = t; nt->entry != line; nt = nt->entry) 1471 ; 1472 nt->entry = 0; 1473 1474 /* make that the start of the entry */ 1475 for(nt = line; nt->entry; nt = nt->entry) 1476 ; 1477 nt->entry = t; 1478 return line; 1479 } 1480 1481 /* 1482 * create a slave process to handle a request to avoid one request blocking 1483 * another 1484 */ 1485 void 1486 slave(void) 1487 { 1488 if(*isslave) 1489 return; /* we're already a slave process */ 1490 1491 switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){ 1492 case -1: 1493 break; 1494 case 0: 1495 if(debug) 1496 syslog(0, logfile, "slave %d", getpid()); 1497 *isslave = 1; 1498 break; 1499 default: 1500 longjmp(masterjmp, 1); 1501 } 1502 } 1503 1504 int 1505 dnsmount(void) 1506 { 1507 int fd; 1508 1509 fd = open("#s/dns", ORDWR); 1510 if(fd < 0) 1511 return -1; 1512 if(mount(fd, "/net", MAFTER, "") < 0){ 1513 close(fd); 1514 return -1; 1515 } 1516 close(fd); 1517 return 0; 1518 } 1519 1520 /* 1521 * call the dns process and have it try to translate a name 1522 */ 1523 Ndbtuple* 1524 dnsiplookup(char *host, Ndbs *s, char *ht) 1525 { 1526 int fd, n; 1527 char buf[Ndbvlen + 4]; 1528 Ndbtuple *t, *nt, **le, **ll; 1529 char *fields[4]; 1530 1531 unlock(&dblock); 1532 1533 /* save the name before starting a slave */ 1534 snprint(buf, sizeof(buf), "%s ip", host); 1535 1536 slave(); 1537 1538 fd = open("/net/dns", ORDWR); 1539 if(fd < 0 && dnsmount() == 0) 1540 fd = open("/net/dns", ORDWR); 1541 if(fd < 0){ 1542 lock(&dblock); 1543 return 0; 1544 } 1545 1546 t = 0; 1547 ll = le = 0; 1548 if(write(fd, buf, strlen(buf)) >= 0){ 1549 seek(fd, 0, 0); 1550 ll = &t; 1551 le = &t; 1552 while((n = read(fd, buf, sizeof(buf)-1)) > 0){ 1553 buf[n] = 0; 1554 n = mygetfields(buf, fields, 4, ' '); 1555 if(n < 3) 1556 continue; 1557 nt = malloc(sizeof(Ndbtuple)); 1558 strcpy(nt->attr, "ip"); 1559 strncpy(nt->val, fields[2], Ndbvlen-1); 1560 *ll = nt; 1561 *le = nt; 1562 ll = &nt->line; 1563 le = &nt->entry; 1564 nt->line = t; 1565 } 1566 } 1567 if(t){ 1568 strcpy(ht, t->val); 1569 1570 /* add in domain name */ 1571 nt = malloc(sizeof(Ndbtuple)); 1572 strcpy(nt->attr, "dom"); 1573 strcpy(nt->val, host); 1574 *ll = nt; 1575 *le = nt; 1576 nt->line = t; 1577 } 1578 close(fd); 1579 s->t = t; 1580 lock(&dblock); 1581 return t; 1582 } 1583 1584 int 1585 qmatch(Ndbtuple *t, char **attr, char **val, int n) 1586 { 1587 int i, found; 1588 Ndbtuple *nt; 1589 1590 for(i = 1; i < n; i++){ 1591 found = 0; 1592 for(nt = t; nt; nt = nt->entry) 1593 if(strcmp(attr[i], nt->attr) == 0) 1594 if(strcmp(val[i], "*") == 0 1595 || strcmp(val[i], nt->val) == 0){ 1596 found = 1; 1597 break; 1598 } 1599 if(found == 0) 1600 break; 1601 } 1602 return i == n; 1603 } 1604 1605 void 1606 qreply(Mfile *mf, Ndbtuple *t) 1607 { 1608 int i; 1609 Ndbtuple *nt; 1610 char buf[512]; 1611 1612 buf[0] = 0; 1613 for(nt = t; mf->nreply < Nreply && nt; nt = nt->entry){ 1614 strcat(buf, nt->attr); 1615 strcat(buf, "="); 1616 strcat(buf, nt->val); 1617 i = strlen(buf); 1618 if(nt->line != nt->entry || sizeof(buf) - i < 2*Ndbvlen+2){ 1619 mf->replylen[mf->nreply] = strlen(buf); 1620 mf->reply[mf->nreply++] = strdup(buf); 1621 buf[0] = 0; 1622 } else 1623 strcat(buf, " "); 1624 } 1625 } 1626 1627 /* 1628 * generic query lookup. 1629 */ 1630 char* 1631 genquery(Mfile *mf, char *query) 1632 { 1633 int i, n; 1634 char *p; 1635 char *attr[32]; 1636 char *val[32]; 1637 char ip[Ndbvlen]; 1638 Ndbtuple *t; 1639 Ndbs s; 1640 1641 n = mygetfields(query, attr, 32, ' '); 1642 if(n == 0) 1643 return "bad query"; 1644 1645 /* parse pairs */ 1646 for(i = 0; i < n; i++){ 1647 p = strchr(attr[i], '='); 1648 if(p == 0) 1649 return "bad query"; 1650 *p++ = 0; 1651 val[i] = p; 1652 } 1653 1654 /* give dns a chance */ 1655 if((strcmp(attr[0], "dom") == 0 || strcmp(attr[0], "ip") == 0) && val[0]){ 1656 t = dnsiplookup(val[0], &s, ip); 1657 if(t){ 1658 if(qmatch(t, attr, val, n)){ 1659 qreply(mf, t); 1660 ndbfree(t); 1661 return 0; 1662 } 1663 ndbfree(t); 1664 } 1665 } 1666 1667 /* first pair is always the key. It can't be a '*' */ 1668 t = ndbsearch(db, &s, attr[0], val[0]); 1669 1670 /* search is the and of all the pairs */ 1671 while(t){ 1672 if(qmatch(t, attr, val, n)){ 1673 qreply(mf, t); 1674 ndbfree(t); 1675 return 0; 1676 } 1677 1678 ndbfree(t); 1679 t = ndbsnext(&s, attr[0], val[0]); 1680 } 1681 1682 return "no match"; 1683 } 1684