tftpd.c 17 KB

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