1 /* 2 * tftpd - tftp service, see /lib/rfc/rfc783 (now rfc1350 + 234[789]) 3 */ 4 #include <u.h> 5 #include <libc.h> 6 #include <auth.h> 7 #include <bio.h> 8 #include <ip.h> 9 #include <ndb.h> 10 11 enum 12 { 13 Maxpath= 128, 14 Maxerr= 256, 15 16 Debug= 0, 17 18 Opsize= sizeof(short), 19 Blksize= sizeof(short), 20 Hdrsize= Opsize + Blksize, 21 22 Ackerr= -1, 23 Ackok= 0, 24 Ackrexmit= 1, 25 26 /* op codes */ 27 Tftp_READ = 1, 28 Tftp_WRITE = 2, 29 Tftp_DATA = 3, 30 Tftp_ACK = 4, 31 Tftp_ERROR = 5, 32 Tftp_OACK = 6, /* option acknowledge */ 33 34 Errnotdef = 0, /* see textual error instead */ 35 Errnotfound = 1, 36 Errnoaccess = 2, 37 Errdiskfull = 3, 38 Errbadop = 4, 39 Errbadtid = 5, 40 Errexists = 6, 41 Errnouser = 7, 42 Errbadopt = 8, /* really bad option value */ 43 44 Defsegsize = 512, 45 Maxsegsize = 65464, /* from rfc2348 */ 46 47 /* 48 * bandt (viaduct) tunnels use smaller mtu than ether's 49 * (1400 bytes for tcp mss of 1300 bytes). 50 */ 51 Bandtmtu = 1400, 52 /* 53 * maximum size of block's data content, excludes hdrs, 54 * notably IP/UDP and TFTP, using worst-case (IPv6) sizes. 55 */ 56 Bandtblksz = Bandtmtu - 40 - 8, 57 }; 58 59 typedef struct Opt Opt; 60 struct Opt { 61 char *name; 62 int *valp; /* set to client's value if within bounds */ 63 int min; 64 int max; 65 }; 66 67 int dbg; 68 int restricted; 69 int pid; 70 71 /* options */ 72 int blksize = Defsegsize; /* excluding 4-byte header */ 73 int timeout = 5; /* seconds */ 74 int tsize; 75 static Opt option[] = { 76 "timeout", &timeout, 1, 255, 77 /* see "hack" below */ 78 "blksize", &blksize, 8, Maxsegsize, 79 "tsize", &tsize, 0, ~0UL >> 1, 80 }; 81 82 void sendfile(int, char*, char*, int); 83 void recvfile(int, char*, char*); 84 void nak(int, int, char*); 85 void ack(int, ushort); 86 void clrcon(void); 87 void setuser(void); 88 char* sunkernel(char*); 89 void remoteaddr(char*, char*, int); 90 void doserve(int); 91 92 char bigbuf[32768]; 93 char raddr[64]; 94 95 char *dir = "/lib/tftpd"; 96 char *dirsl; 97 int dirsllen; 98 char flog[] = "ipboot"; 99 char net[Maxpath]; 100 101 static char *opnames[] = { 102 [Tftp_READ] "read", 103 [Tftp_WRITE] "write", 104 [Tftp_DATA] "data", 105 [Tftp_ACK] "ack", 106 [Tftp_ERROR] "error", 107 [Tftp_OACK] "oack", 108 }; 109 110 void 111 usage(void) 112 { 113 fprint(2, "usage: %s [-dr] [-h homedir] [-s svc] [-x netmtpt]\n", 114 argv0); 115 exits("usage"); 116 } 117 118 void 119 main(int argc, char **argv) 120 { 121 char buf[64]; 122 char adir[64], ldir[64]; 123 int cfd, lcfd, dfd; 124 char *svc = "69"; 125 126 setnetmtpt(net, sizeof net, nil); 127 ARGBEGIN{ 128 case 'd': 129 dbg++; 130 break; 131 case 'h': 132 dir = EARGF(usage()); 133 break; 134 case 'r': 135 restricted = 1; 136 break; 137 case 's': 138 svc = EARGF(usage()); 139 break; 140 case 'x': 141 setnetmtpt(net, sizeof net, EARGF(usage())); 142 break; 143 default: 144 usage(); 145 }ARGEND 146 147 snprint(buf, sizeof buf, "%s/", dir); 148 dirsl = strdup(buf); 149 dirsllen = strlen(dirsl); 150 151 fmtinstall('E', eipfmt); 152 fmtinstall('I', eipfmt); 153 154 /* 155 * setuser calls newns, and typical /lib/namespace files contain 156 * "cd /usr/$user", so call setuser before chdir. 157 */ 158 setuser(); 159 if(chdir(dir) < 0) 160 sysfatal("can't get to directory %s: %r", dir); 161 162 if(!dbg) 163 switch(rfork(RFNOTEG|RFPROC|RFFDG)) { 164 case -1: 165 sysfatal("fork: %r"); 166 case 0: 167 break; 168 default: 169 exits(0); 170 } 171 172 snprint(buf, sizeof buf, "%s/udp!*!%s", net, svc); 173 cfd = announce(buf, adir); 174 if (cfd < 0) 175 sysfatal("announcing on %s: %r", buf); 176 syslog(dbg, flog, "tftpd started on %s dir %s", buf, adir); 177 // setuser(); 178 for(;;) { 179 lcfd = listen(adir, ldir); 180 if(lcfd < 0) 181 sysfatal("listening on %s: %r", adir); 182 183 switch(fork()) { 184 case -1: 185 sysfatal("fork: %r"); 186 case 0: 187 dfd = accept(lcfd, ldir); 188 if(dfd < 0) 189 exits(0); 190 remoteaddr(ldir, raddr, sizeof(raddr)); 191 pid = getpid(); 192 syslog(0, flog, "tftp %d connection from %s dir %s", 193 pid, raddr, ldir); 194 doserve(dfd); 195 exits("done"); 196 break; 197 default: 198 close(lcfd); 199 continue; 200 } 201 } 202 } 203 204 static Opt * 205 handleopt(int fd, char *name, char *val) 206 { 207 int n; 208 Opt *op; 209 210 for (op = option; op < option + nelem(option); op++) 211 if(cistrcmp(name, op->name) == 0) { 212 n = strtol(val, nil, 10); 213 if (n < op->min || n > op->max) { 214 nak(fd, Errbadopt, "option value out of range"); 215 syslog(dbg, flog, "tftp bad option value from " 216 "client: %s %s", name, val); 217 sysfatal("bad option value from client: %s %s", 218 name, val); 219 } 220 *op->valp = n; 221 syslog(dbg, flog, "tftpd %d setting %s to %d", 222 pid, name, n); 223 return op; 224 } 225 return nil; 226 } 227 228 static vlong 229 filesize(char *file) 230 { 231 vlong size; 232 Dir *dp; 233 234 dp = dirstat(file); 235 if (dp == nil) 236 return 0; 237 size = dp->length; 238 free(dp); 239 return size; 240 } 241 242 static int 243 options(int fd, char *buf, char *file, ushort oper, char *p, int dlen) 244 { 245 int nmlen, vallen, nopts; 246 vlong size; 247 char *val, *bp; 248 Opt *op; 249 250 buf[0] = 0; 251 buf[1] = Tftp_OACK; 252 bp = buf + Opsize; 253 nopts = 0; 254 while (dlen > 0 && *p != '\0') { 255 nmlen = strlen(p) + 1; /* include NUL */ 256 if (nmlen > dlen) 257 break; 258 dlen -= nmlen; 259 val = p + nmlen; 260 if (dlen <= 0 || *val == '\0') 261 break; 262 263 vallen = strlen(val) + 1; 264 if (vallen > dlen) 265 break; 266 dlen -= vallen; 267 268 nopts++; 269 op = handleopt(fd, p, val); 270 if (op) { 271 /* append OACK response to buf */ 272 sprint(bp, "%s", p); 273 bp += nmlen; 274 if (oper == Tftp_READ && cistrcmp(p, "tsize") == 0) { 275 size = filesize(file); 276 sprint(bp, "%lld", size); 277 syslog(dbg, flog, "tftpd %d %s tsize is %,lld", 278 pid, file, size); 279 } 280 /* 281 * hack: bandt (viaducts) uses smaller mtu than ether's 282 * (1400 bytes for tcp mss of 1300 bytes), 283 * so offer at most bandt's mtu minus headers, 284 * to avoid failure of pxe booting via viaduct. 285 */ 286 else if (oper == Tftp_READ && 287 cistrcmp(p, "blksize") == 0 && 288 blksize > Bandtblksz) { 289 blksize = Bandtblksz; 290 sprint(bp, "%d", blksize); 291 syslog(dbg, flog, 292 "tftpd %d overriding blksize to %d", 293 pid, blksize); 294 } else 295 strcpy(bp, val); /* use requested value */ 296 bp += strlen(bp) + 1; 297 } 298 p = val + vallen; 299 } 300 if (nopts == 0) 301 return 0; /* no options actually seen */ 302 *bp++ = '\0'; 303 *bp++ = '\0'; /* overkill */ 304 *bp++ = '\0'; 305 if (write(fd, buf, bp - buf) < bp - buf) { 306 syslog(dbg, flog, "tftpd network write error on oack to %s: %r", 307 raddr); 308 sysfatal("tftpd: network write error: %r"); 309 } 310 if(Debug) 311 syslog(dbg, flog, "tftpd oack: options to %s", raddr); 312 return nopts; 313 } 314 315 /* this doesn't stop the cavium from barging ahead */ 316 //static void 317 //sendnoopts(int fd, char *name) 318 //{ 319 // char buf[64]; 320 // 321 // memset(buf, 0, sizeof buf); 322 // buf[0] = 0; 323 // buf[1] = Tftp_OACK; 324 // 325 // if(write(fd, buf, sizeof buf) < sizeof buf) { 326 // syslog(dbg, flog, "tftpd network write error on %s oack to %s: %r", 327 // name, raddr); 328 // sysfatal("tftpd: network write error: %r"); 329 // } 330 // if(Debug) 331 // syslog(dbg, flog, "tftpd oack: no options to %s", raddr); 332 //} 333 334 static void 335 optlog(char *bytes, char *p, int dlen) 336 { 337 char *bp; 338 339 bp = bytes; 340 sprint(bp, "tftpd %d option bytes: ", dlen); 341 bp += strlen(bp); 342 for (; dlen > 0; dlen--, p++) 343 *bp++ = *p? *p: ' '; 344 *bp = '\0'; 345 syslog(dbg, flog, "%s", bytes); 346 } 347 348 void 349 doserve(int fd) 350 { 351 int dlen, opts; 352 char *mode, *p, *file; 353 short op; 354 355 dlen = read(fd, bigbuf, sizeof(bigbuf)-1); 356 if(dlen < 0) 357 sysfatal("listen read: %r"); 358 359 bigbuf[dlen] = '\0'; 360 op = (bigbuf[0]<<8) | bigbuf[1]; 361 dlen -= Opsize; 362 mode = file = bigbuf + Opsize; 363 while(*mode != '\0' && dlen--) 364 mode++; 365 mode++; 366 p = mode; 367 while(*p && dlen--) 368 p++; 369 if(dlen == 0) { 370 nak(fd, 0, "bad tftpmode"); 371 close(fd); 372 syslog(dbg, flog, "tftpd %d bad mode %s for file %s from %s", 373 pid, mode, file, raddr); 374 return; 375 } 376 377 if(op != Tftp_READ && op != Tftp_WRITE) { 378 nak(fd, Errbadop, "Illegal TFTP operation"); 379 close(fd); 380 syslog(dbg, flog, "tftpd %d bad request %d %s", pid, op, raddr); 381 return; 382 } 383 384 if(restricted){ 385 if(file[0] == '#' || strncmp(file, "../", 3) == 0 || 386 strstr(file, "/../") != nil || 387 (file[0] == '/' && strncmp(file, dirsl, dirsllen) != 0)){ 388 nak(fd, Errnoaccess, "Permission denied"); 389 close(fd); 390 syslog(dbg, flog, "tftpd %d bad request %d from %s file %s", 391 pid, op, raddr, file); 392 return; 393 } 394 } 395 396 /* 397 * options are supposed to be negotiated, but the cavium board's 398 * u-boot really wants us to use a block size of 1432 bytes and won't 399 * take `no' for an answer. 400 */ 401 p++; /* skip NUL after mode */ 402 dlen--; 403 opts = 0; 404 if(dlen > 0) { /* might have options */ 405 char bytes[32*1024]; 406 407 if(Debug) 408 optlog(bytes, p, dlen); 409 opts = options(fd, bytes, file, op, p, dlen); 410 } 411 if(op == Tftp_READ) 412 sendfile(fd, file, mode, opts); 413 else 414 recvfile(fd, file, mode); 415 } 416 417 void 418 catcher(void *junk, char *msg) 419 { 420 USED(junk); 421 422 if(strncmp(msg, "exit", 4) == 0) 423 noted(NDFLT); 424 noted(NCONT); 425 } 426 427 static int 428 awaitack(int fd, int block) 429 { 430 int ackblock, al, rxl; 431 ushort op; 432 uchar ack[1024]; 433 434 for(rxl = 0; rxl < 10; rxl++) { 435 memset(ack, 0, Hdrsize); 436 alarm(1000); 437 al = read(fd, ack, sizeof(ack)); 438 alarm(0); 439 if(al < 0) { 440 if (Debug) 441 syslog(dbg, flog, "tftpd %d timed out " 442 "waiting for ack from %s", pid, raddr); 443 return Ackrexmit; 444 } 445 op = ack[0]<<8|ack[1]; 446 if(op == Tftp_ERROR) { 447 if (Debug) 448 syslog(dbg, flog, "tftpd %d got error " 449 "waiting for ack from %s", pid, raddr); 450 return Ackerr; 451 } else if(op != Tftp_ACK) { 452 syslog(dbg, flog, "tftpd %d rcvd %s op from %s", pid, 453 (op < nelem(opnames)? opnames[op]: "gok"), 454 raddr); 455 return Ackerr; 456 } 457 ackblock = ack[2]<<8|ack[3]; 458 if (Debug) 459 syslog(dbg, flog, "tftpd %d read ack of %d bytes " 460 "for block %d", pid, al, ackblock); 461 if(ackblock == block) 462 return Ackok; /* for block just sent */ 463 else if(ackblock == block + 1) /* intel pxe eof bug */ 464 return Ackok; 465 else if(ackblock == 0xffff) 466 return Ackrexmit; 467 else 468 /* ack is for some other block; ignore it, try again */ 469 syslog(dbg, flog, "tftpd %d expected ack for block %d, " 470 "got %d", pid, block, ackblock); 471 } 472 return Ackrexmit; 473 } 474 475 void 476 sendfile(int fd, char *name, char *mode, int opts) 477 { 478 int file, block, ret, rexmit, n, txtry; 479 uchar buf[Maxsegsize+Hdrsize]; 480 char errbuf[Maxerr]; 481 482 syslog(dbg, flog, "tftpd %d send file '%s' %s to %s", 483 pid, name, mode, raddr); 484 name = sunkernel(name); 485 if(name == 0){ 486 nak(fd, 0, "not in our database"); 487 return; 488 } 489 490 notify(catcher); 491 492 file = open(name, OREAD); 493 if(file < 0) { 494 errstr(errbuf, sizeof errbuf); 495 nak(fd, 0, errbuf); 496 return; 497 } 498 block = 0; 499 rexmit = Ackok; 500 n = 0; 501 /* 502 * if we sent an oack previously, wait for the client's ack or error. 503 * if we get no ack for our oack, it could be that we returned 504 * a tsize that the client can't handle, or it could be intel 505 * pxe just read-with-tsize to get size, couldn't be bothered to 506 * ack our oack and has just gone ahead and issued another read. 507 */ 508 if(opts && awaitack(fd, 0) != Ackok) 509 goto error; 510 511 for(txtry = 0; txtry < timeout;) { 512 if(rexmit == Ackok) { 513 block++; 514 buf[0] = 0; 515 buf[1] = Tftp_DATA; 516 buf[2] = block>>8; 517 buf[3] = block; 518 n = read(file, buf+Hdrsize, blksize); 519 if(n < 0) { 520 errstr(errbuf, sizeof errbuf); 521 nak(fd, 0, errbuf); 522 return; 523 } 524 txtry = 0; 525 } 526 else { 527 syslog(dbg, flog, "tftpd %d rexmit %d %s:%d to %s", 528 pid, Hdrsize+n, name, block, raddr); 529 txtry++; 530 } 531 532 ret = write(fd, buf, Hdrsize+n); 533 if(ret < Hdrsize+n) { 534 syslog(dbg, flog, 535 "tftpd network write error on %s to %s: %r", 536 name, raddr); 537 sysfatal("tftpd: network write error: %r"); 538 } 539 if (Debug) 540 syslog(dbg, flog, "tftpd %d sent block %d", pid, block); 541 542 rexmit = awaitack(fd, block); 543 if (rexmit == Ackerr) 544 break; 545 if(ret != blksize+Hdrsize && rexmit == Ackok) 546 break; 547 } 548 error: 549 close(fd); 550 close(file); 551 } 552 553 void 554 recvfile(int fd, char *name, char *mode) 555 { 556 ushort op, block, inblock; 557 uchar buf[Maxsegsize+8]; 558 char errbuf[Maxerr]; 559 int n, ret, file; 560 561 syslog(dbg, flog, "receive file '%s' %s from %s", name, mode, raddr); 562 563 file = create(name, OWRITE, 0666); 564 if(file < 0) { 565 errstr(errbuf, sizeof errbuf); 566 nak(fd, 0, errbuf); 567 syslog(dbg, flog, "can't create %s: %r", name); 568 return; 569 } 570 571 block = 0; 572 ack(fd, block); 573 block++; 574 575 for (;;) { 576 alarm(15000); 577 n = read(fd, buf, blksize+8); 578 alarm(0); 579 if(n < 0) { 580 syslog(dbg, flog, "tftpd: network error reading %s: %r", 581 name); 582 goto error; 583 } 584 if(n <= Hdrsize) { 585 syslog(dbg, flog, 586 "tftpd: short read from network, reading %s", 587 name); 588 goto error; 589 } 590 op = buf[0]<<8|buf[1]; 591 if(op == Tftp_ERROR) { 592 syslog(dbg, flog, "tftpd: tftp error reading %s", name); 593 goto error; 594 } 595 596 n -= Hdrsize; 597 inblock = buf[2]<<8|buf[3]; 598 if(op == Tftp_DATA) { 599 if(inblock == block) { 600 ret = write(file, buf+Hdrsize, n); 601 if(ret != n) { 602 errstr(errbuf, sizeof errbuf); 603 nak(fd, 0, errbuf); 604 syslog(dbg, flog, 605 "tftpd: error writing %s: %s", 606 name, errbuf); 607 goto error; 608 } 609 ack(fd, block); 610 block++; 611 } else 612 ack(fd, 0xffff); /* tell him to resend */ 613 } 614 } 615 error: 616 close(file); 617 } 618 619 void 620 ack(int fd, ushort block) 621 { 622 uchar ack[4]; 623 int n; 624 625 ack[0] = 0; 626 ack[1] = Tftp_ACK; 627 ack[2] = block>>8; 628 ack[3] = block; 629 630 n = write(fd, ack, 4); 631 if(n < 4) 632 sysfatal("network write: %r"); 633 } 634 635 void 636 nak(int fd, int code, char *msg) 637 { 638 char buf[128]; 639 int n; 640 641 buf[0] = 0; 642 buf[1] = Tftp_ERROR; 643 buf[2] = 0; 644 buf[3] = code; 645 strcpy(buf+4, msg); 646 n = strlen(msg) + 4 + 1; 647 if(write(fd, buf, n) < n) 648 sysfatal("write nak: %r"); 649 } 650 651 void 652 setuser(void) 653 { 654 int fd; 655 656 fd = open("#c/user", OWRITE); 657 if(fd < 0 || write(fd, "none", strlen("none")) < 0) 658 sysfatal("can't become none: %r"); 659 close(fd); 660 if(newns("none", nil) < 0) 661 sysfatal("can't build namespace: %r"); 662 } 663 664 char* 665 lookup(char *sattr, char *sval, char *tattr, char *tval, int len) 666 { 667 static Ndb *db; 668 char *attrs[1]; 669 Ndbtuple *t; 670 671 if(db == nil) 672 db = ndbopen(0); 673 if(db == nil) 674 return nil; 675 676 if(sattr == nil) 677 sattr = ipattr(sval); 678 679 attrs[0] = tattr; 680 t = ndbipinfo(db, sattr, sval, attrs, 1); 681 if(t == nil) 682 return nil; 683 strncpy(tval, t->val, len); 684 tval[len-1] = 0; 685 ndbfree(t); 686 return tval; 687 } 688 689 /* 690 * for sun kernel boots, replace the requested file name with 691 * a one from our database. If the database doesn't specify a file, 692 * don't answer. 693 */ 694 char* 695 sunkernel(char *name) 696 { 697 ulong addr; 698 uchar v4[IPv4addrlen]; 699 uchar v6[IPaddrlen]; 700 char buf[256]; 701 char ipbuf[128]; 702 char *suffix; 703 704 addr = strtoul(name, &suffix, 16); 705 if(suffix-name != 8 || (strcmp(suffix, "") != 0 && strcmp(suffix, ".SUN") != 0)) 706 return name; 707 708 v4[0] = addr>>24; 709 v4[1] = addr>>16; 710 v4[2] = addr>>8; 711 v4[3] = addr; 712 v4tov6(v6, v4); 713 sprint(ipbuf, "%I", v6); 714 return lookup("ip", ipbuf, "bootf", buf, sizeof buf); 715 } 716 717 void 718 remoteaddr(char *dir, char *raddr, int len) 719 { 720 char buf[64]; 721 int fd, n; 722 723 snprint(buf, sizeof(buf), "%s/remote", dir); 724 fd = open(buf, OREAD); 725 if(fd < 0){ 726 snprint(raddr, sizeof(raddr), "unknown"); 727 return; 728 } 729 n = read(fd, raddr, len-1); 730 close(fd); 731 if(n <= 0){ 732 snprint(raddr, sizeof(raddr), "unknown"); 733 return; 734 } 735 if(n > 0) 736 n--; 737 raddr[n] = 0; 738 } 739