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 "dns.h" 8 9 enum 10 { 11 Maxrequest= 4*NAMELEN, 12 Ncache= 8, 13 14 Qdns= 1, 15 }; 16 17 typedef struct Mfile Mfile; 18 typedef struct Network Network; 19 20 int vers; /* incremented each clone/attach */ 21 22 struct Mfile 23 { 24 int busy; 25 char user[NAMELEN]; 26 Qid qid; 27 int fid; 28 29 int tag; /* tag of current request */ 30 RR *rp; /* start of reply */ 31 int type; /* reply type */ 32 }; 33 34 Mfile *mfile; 35 int nmfile = 0; 36 int mfd[2]; 37 char user[NAMELEN]; 38 Fcall *rhp; 39 Fcall *thp; 40 int debug; 41 42 void rsession(void); 43 void rsimple(void); 44 void rflush(int tag); 45 void rattach(Mfile*); 46 void rclone(Mfile*); 47 char* rwalk(Mfile*); 48 void rclwalk(Mfile*); 49 void ropen(Mfile*); 50 void rcreate(Mfile*); 51 void rread(Mfile*); 52 void rwrite(Mfile*, Request*); 53 void rclunk(Mfile*); 54 void rremove(Mfile*); 55 void rstat(Mfile*); 56 void rauth(void); 57 void rwstat(Mfile*); 58 void sendmsg(char*); 59 void mountinit(char*); 60 void io(void); 61 int lookup(Mfile*, char*, char*, char*); 62 int fillreply(Mfile*, int); 63 int mygetfields(char*, char**, int, char); 64 65 char *mname[]={ 66 [Tnop] "Tnop", 67 [Tsession] "Tsession", 68 [Tflush] "Tflush", 69 [Tattach] "Tattach", 70 [Tclone] "Tclone", 71 [Twalk] "Twalk", 72 [Topen] "Topen", 73 [Tcreate] "Tcreate", 74 [Tclunk] "Tclunk", 75 [Tread] "Tread", 76 [Twrite] "Twrite", 77 [Tremove] "Tremove", 78 [Tstat] "Tstat", 79 [Twstat] "Twstat", 80 0, 81 }; 82 83 char *logfile = "dns"; 84 char *dbfile; 85 86 void 87 main(int argc, char *argv[]) 88 { 89 Fcall rhdr; 90 Fcall thdr; 91 int serve; 92 93 94 serve = 0; 95 rhp = &rhdr; 96 thp = &thdr; 97 ARGBEGIN{ 98 case 'd': 99 debug = 1; 100 break; 101 case 'f': 102 dbfile = ARGF(); 103 break; 104 case 's': 105 serve = 1; /* serve network */ 106 break; 107 }ARGEND 108 USED(argc); 109 USED(argv); 110 111 remove("#s/dns"); 112 unmount("/net/dns", "/net"); 113 mountinit("#s/dns"); 114 115 fmtinstall('F', fcallconv); 116 dninit(); 117 118 syslog(1, logfile, "started%s%s", serve?" serving":"", 119 debug?" debuging":""); 120 if(serve) 121 dnserver(); 122 io(); 123 exits(0); 124 } 125 126 void 127 mountinit(char *service) 128 { 129 int f; 130 int p[2]; 131 char buf[32]; 132 133 if(pipe(p) < 0) 134 fatal("pipe failed"); 135 switch(rfork(RFFDG|RFPROC|RFNAMEG)){ 136 case 0: 137 close(p[1]); 138 break; 139 case -1: 140 fatal("fork failed\n"); 141 default: 142 close(p[0]); 143 144 /* 145 * make a /srv/dns 146 */ 147 f = create(service, 1, 0666); 148 if(f < 0) 149 fatal(service); 150 snprint(buf, sizeof(buf), "%d", p[1]); 151 if(write(f, buf, strlen(buf)) != strlen(buf)) 152 fatal("write %s", service); 153 close(f); 154 155 /* 156 * put ourselves into the file system 157 */ 158 if(mount(p[1], "/net", MAFTER, "") < 0) 159 fatal("mount failed\n"); 160 _exits(0); 161 } 162 mfd[0] = mfd[1] = p[0]; 163 } 164 165 #define INC 4 166 Mfile* 167 newfid(int fid) 168 { 169 Mfile *mf; 170 Mfile *freemf; 171 int old; 172 Mfile *o; 173 174 freemf = 0; 175 for(mf = mfile; mf < &mfile[nmfile]; mf++){ 176 if(mf->fid==fid) 177 return mf; 178 if(mf->busy == 0) 179 freemf = mf; 180 } 181 if(freemf == 0){ 182 old = nmfile; 183 nmfile += INC; 184 o = mfile; 185 mfile = realloc(mfile, nmfile*sizeof(Mfile)); 186 if(mfile == 0){ 187 fprint(2, "dns: realloc(0x%lux, %d)\n", o, nmfile*sizeof(Mfile)); 188 fatal("realloc failure"); 189 } 190 mf = &mfile[old]; 191 memset(mf, 0, INC*sizeof(Mfile)); 192 } else 193 mf = freemf; 194 195 memset(mf, 0, sizeof mfile[0]); 196 mf->fid = fid; 197 return mf; 198 } 199 200 void 201 io(void) 202 { 203 long n; 204 Mfile *mf; 205 char mdata[MAXFDATA + MAXMSG]; 206 Request req; 207 208 /* 209 * a slave process is sometimes forked to wait for replies from other 210 * servers. The master process returns immediately via a longjmp 211 * through 'mret'. 212 */ 213 setjmp(req.mret); 214 req.isslave = 0; 215 loop: 216 n = read(mfd[0], mdata, sizeof mdata); 217 if(n<=0) 218 fatal("mount read"); 219 if(convM2S(mdata, rhp, n) == 0) 220 goto loop; 221 if(rhp->fid<0) 222 fatal("fid out of range"); 223 mf = newfid(rhp->fid); 224 if(debug) 225 syslog(0, logfile, "%F", rhp); 226 mf->tag = rhp->tag; 227 switch(rhp->type){ 228 default: 229 fatal("type"); 230 break; 231 case Tsession: 232 rsession(); 233 break; 234 case Tnop: 235 rsimple(); 236 break; 237 case Tflush: 238 rflush(rhp->tag); 239 break; 240 case Tattach: 241 rattach(mf); 242 break; 243 case Tclone: 244 rclone(mf); 245 break; 246 case Twalk: 247 rwalk(mf); 248 break; 249 case Tclwalk: 250 rclwalk(mf); 251 break; 252 case Topen: 253 ropen(mf); 254 break; 255 case Tcreate: 256 rcreate(mf); 257 break; 258 case Tread: 259 rread(mf); 260 break; 261 case Twrite: 262 rwrite(mf, &req); 263 break; 264 case Tclunk: 265 rclunk(mf); 266 break; 267 case Tremove: 268 rremove(mf); 269 break; 270 case Tstat: 271 rstat(mf); 272 break; 273 case Twstat: 274 rwstat(mf); 275 break; 276 } 277 /* 278 * slave processes die after replying 279 */ 280 if(req.isslave) 281 _exits(0); 282 goto loop; 283 } 284 285 void 286 rsession(void) 287 { 288 memset(thp->authid, 0, sizeof(thp->authid)); 289 memset(thp->authdom, 0, sizeof(thp->authdom)); 290 memset(thp->chal, 0, sizeof(thp->chal)); 291 sendmsg(0); 292 } 293 294 void 295 rsimple(void) 296 { 297 sendmsg(0); 298 } 299 300 void 301 rflush(int tag) 302 { 303 Mfile *mf; 304 305 for(mf = mfile; mf < &mfile[nmfile]; mf++){ 306 if(mf->busy == 0) 307 continue; 308 if(mf->tag == tag){ 309 mf->tag = -1; 310 break; 311 } 312 } 313 sendmsg(0); 314 } 315 316 void 317 rauth(void) 318 { 319 sendmsg("Authentication failed"); 320 } 321 322 void 323 rattach(Mfile *mf) 324 { 325 if(mf->busy == 0){ 326 mf->busy = 1; 327 strcpy(mf->user, rhp->uname); 328 } 329 mf->qid.vers = vers++; 330 mf->qid.path = CHDIR; 331 thp->qid = mf->qid; 332 sendmsg(0); 333 } 334 335 void 336 rclone(Mfile *mf) 337 { 338 Mfile *nmf; 339 char *err=0; 340 341 if(rhp->newfid<0){ 342 err = "clone nfid out of range"; 343 goto send; 344 } 345 nmf = newfid(rhp->newfid); 346 if(nmf->busy){ 347 err = "clone to used channel"; 348 goto send; 349 } 350 *nmf = *mf; 351 nmf->fid = rhp->newfid; 352 nmf->qid.vers = vers++; 353 send: 354 sendmsg(err); 355 } 356 357 void 358 rclwalk(Mfile *mf) 359 { 360 Mfile *nmf; 361 362 if(rhp->newfid<0){ 363 sendmsg("clone nfid out of range"); 364 return; 365 } 366 nmf = newfid(rhp->newfid); 367 if(nmf->busy){ 368 sendmsg("clone to used channel"); 369 return; 370 } 371 *nmf = *mf; 372 nmf->fid = rhp->newfid; 373 rhp->fid = rhp->newfid; 374 nmf->qid.vers = vers++; 375 if(rwalk(nmf)) 376 nmf->busy = 0; 377 } 378 379 char* 380 rwalk(Mfile *mf) 381 { 382 char *err; 383 char *name; 384 385 err = 0; 386 name = rhp->name; 387 if((mf->qid.path & CHDIR) == 0){ 388 err = "not a directory"; 389 goto send; 390 } 391 if(strcmp(name, ".") == 0){ 392 mf->qid.path = CHDIR; 393 goto send; 394 } 395 if(strcmp(name, "dns") == 0){ 396 mf->qid.path = Qdns; 397 goto send; 398 } 399 err = "nonexistent file"; 400 send: 401 thp->qid = mf->qid; 402 sendmsg(err); 403 return err; 404 } 405 406 void 407 ropen(Mfile *mf) 408 { 409 int mode; 410 char *err; 411 412 err = 0; 413 mode = rhp->mode; 414 if(mf->qid.path & CHDIR){ 415 if(mode) 416 err = "permission denied"; 417 } 418 send: 419 thp->qid = mf->qid; 420 sendmsg(err); 421 } 422 423 void 424 rcreate(Mfile *mf) 425 { 426 USED(mf); 427 sendmsg("creation permission denied"); 428 } 429 430 void 431 rread(Mfile *mf) 432 { 433 int n, cnt, len; 434 long toff, off, clock; 435 Dir dir; 436 char buf[MAXFDATA]; 437 char *err; 438 RR *rp; 439 440 n = 0; 441 err = 0; 442 off = rhp->offset; 443 cnt = rhp->count; 444 if(mf->qid.path & CHDIR){ 445 if(off%DIRLEN || cnt%DIRLEN){ 446 err = "bad offset"; 447 goto send; 448 } 449 clock = time(0); 450 if(off == 0){ 451 memmove(dir.name, "dns", NAMELEN); 452 dir.qid.vers = vers; 453 dir.qid.path = Qdns; 454 dir.mode = 0666; 455 dir.length = 0; 456 dir.hlength = 0; 457 strcpy(dir.uid, mf->user); 458 strcpy(dir.gid, mf->user); 459 dir.atime = clock; /* wrong */ 460 dir.mtime = clock; /* wrong */ 461 convD2M(&dir, buf+n); 462 n += DIRLEN; 463 } 464 thp->data = buf; 465 } else { 466 toff = 0; 467 n = 0; 468 thp->data = buf; 469 for(rp = mf->rp; rp && tsame(mf->type, rp->type); rp = rp->next){ 470 len = snprint(buf, sizeof(buf), "%R", rp); 471 if(toff + len > off){ 472 toff = off - toff; 473 if(cnt > len - toff) 474 cnt = len - toff; 475 thp->data = buf + toff; 476 n = cnt; 477 break; 478 } 479 toff += len; 480 } 481 } 482 send: 483 thp->count = n; 484 sendmsg(err); 485 } 486 487 void 488 rwrite(Mfile *mf, Request *req) 489 { 490 int cnt; 491 char *err; 492 char *atype; 493 494 err = 0; 495 cnt = rhp->count; 496 if(mf->qid.path & CHDIR){ 497 err = "can't write directory"; 498 goto send; 499 } 500 if(cnt >= Maxrequest){ 501 err = "request too long"; 502 goto send; 503 } 504 rhp->data[cnt] = 0; 505 506 /* 507 * toggle debugging 508 */ 509 if(strncmp(rhp->data, "debug", 5)==0){ 510 debug ^= 1; 511 goto send; 512 } else if(strncmp(rhp->data, "dump", 4)==0){ 513 dndump("/lib/ndb/dnsdump"); 514 goto send; 515 } 516 517 /* 518 * break up request (into a name and a type) 519 */ 520 atype = strchr(rhp->data, ' '); 521 if(atype == 0){ 522 err = "illegal request"; 523 goto send; 524 } else 525 *atype++ = 0; 526 527 mf->type = rrtype(atype); 528 if(mf->type < 0){ 529 err = "unknown type"; 530 goto send; 531 } 532 533 mf->rp = dnresolve(rhp->data, Cin, mf->type, req, 0); 534 if(mf->rp == 0){ 535 err = "not found"; 536 } 537 538 /* don't reply if the request was flushed */ 539 if(mf->tag < 0) 540 return; 541 542 send: 543 thp->count = cnt; 544 sendmsg(err); 545 } 546 547 void 548 rclunk(Mfile *mf) 549 { 550 if(mf->rp){ 551 /* free resource records from the database */ 552 if(mf->rp->db) 553 rrfreelist(mf->rp); 554 mf->rp = 0; 555 } 556 mf->busy = 0; 557 mf->fid = 0; 558 sendmsg(0); 559 } 560 561 void 562 rremove(Mfile *mf) 563 { 564 USED(mf); 565 sendmsg("remove permission denied"); 566 } 567 568 void 569 rstat(Mfile *mf) 570 { 571 Dir dir; 572 573 if(mf->qid.path & CHDIR){ 574 strcpy(dir.name, "."); 575 dir.mode = CHDIR|0555; 576 } else { 577 strcpy(dir.name, "dns"); 578 dir.mode = 0666; 579 } 580 dir.qid = mf->qid; 581 dir.length = 0; 582 dir.hlength = 0; 583 strcpy(dir.uid, mf->user); 584 strcpy(dir.gid, mf->user); 585 dir.atime = dir.mtime = time(0); 586 convD2M(&dir, (char*)thp->stat); 587 sendmsg(0); 588 } 589 590 void 591 rwstat(Mfile *mf) 592 { 593 USED(mf); 594 sendmsg("wstat permission denied"); 595 } 596 597 void 598 sendmsg(char *err) 599 { 600 int n; 601 char mdata[MAXFDATA + MAXMSG]; 602 603 if(err){ 604 thp->type = Rerror; 605 snprint(thp->ename, sizeof(thp->ename), "dns: %s", err); 606 }else{ 607 thp->type = rhp->type+1; 608 thp->fid = rhp->fid; 609 } 610 thp->tag = rhp->tag; 611 if(debug) 612 syslog(0, logfile, "%F", thp); 613 n = convS2M(thp, mdata); 614 if(write(mfd[1], mdata, n)!=n) 615 fatal("mount write"); 616 } 617 618 int 619 mygetfields(char *lp, char **fields, int n, char sep) 620 { 621 int i; 622 char sep2=0; 623 624 if(sep == ' ') 625 sep2 = '\t'; 626 for(i=0; lp && *lp && i<n; i++){ 627 if(*lp==sep || *lp==sep2) 628 *lp++=0; 629 if(*lp == 0) 630 break; 631 fields[i]=lp; 632 while(*lp && *lp!=sep && *lp!=sep2) 633 lp++; 634 } 635 return i; 636 } 637 638 void 639 warning(char *fmt, ...) 640 { 641 int n; 642 char dnserr[128]; 643 644 n = doprint(dnserr, dnserr+sizeof(dnserr), fmt, &fmt+1) - dnserr; 645 dnserr[n] = 0; 646 syslog(1, "dns", dnserr); 647 } 648 649 void 650 fatal(char *fmt, ...) 651 { 652 int n; 653 char dnserr[128]; 654 655 n = doprint(dnserr, dnserr+sizeof(dnserr), fmt, &fmt+1) - dnserr; 656 dnserr[n] = 0; 657 syslog(1, "dns", dnserr); 658 abort(); 659 } 660 661 /* 662 * create a slave process to handle a request to avoid one request blocking 663 * another 664 */ 665 void 666 slave(Request *req) 667 { 668 if(req->isslave) 669 return; /* we're already a slave process */ 670 671 switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){ 672 case -1: 673 break; 674 case 0: 675 req->isslave = 1; 676 break; 677 default: 678 longjmp(req->mret, 1); 679 } 680 } 681