You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tftpd.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. /*
  2. * Copyright (c) 1983 Regents of the University of California.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms are permitted
  6. * provided that the above copyright notice and this paragraph are
  7. * duplicated in all such forms and that any documentation,
  8. * advertising materials, and other materials related to such
  9. * distribution and use acknowledge that the software was developed
  10. * by the University of California, Berkeley. The name of the
  11. * University may not be used to endorse or promote products derived
  12. * from this software without specific prior written permission.
  13. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14. * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15. * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16. */
  17. #ifndef lint
  18. char copyright[] =
  19. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  20. All rights reserved.\n";
  21. #endif /* not lint */
  22. #ifndef lint
  23. static char sccsid[] = "@(#)tftpd.c 5.8 (Berkeley) 6/18/88";
  24. #endif /* not lint */
  25. /*
  26. * Trivial file transfer protocol server.
  27. *
  28. * This version includes many modifications by Jim Guyton <guyton@rand-unix>
  29. *
  30. * Further modifications by Markus Gutschke <gutschk@math.uni-muenster.de>
  31. * - RFC1782 option parsing
  32. * - RFC1783 extended blocksize
  33. * - "-c" option for changing the root directory
  34. * - "-d" option for debugging output
  35. */
  36. #include <sys/types.h>
  37. #include <sys/socket.h>
  38. #include <sys/ioctl.h>
  39. #include <sys/wait.h>
  40. #include <sys/stat.h>
  41. #include <netinet/in.h>
  42. #include <arpa/tftp.h>
  43. #include <alloca.h>
  44. #include <string.h>
  45. #include <signal.h>
  46. #include <stdio.h>
  47. #include <errno.h>
  48. #include <ctype.h>
  49. #include <netdb.h>
  50. #include <setjmp.h>
  51. #include <syslog.h>
  52. #define TIMEOUT 5
  53. #ifndef OACK
  54. #define OACK 06
  55. #endif
  56. #ifndef EOPTNEG
  57. #define EOPTNEG 8
  58. #endif
  59. extern int errno;
  60. struct sockaddr_in sin = { AF_INET };
  61. int peer;
  62. int rexmtval = TIMEOUT;
  63. int maxtimeout = 5*TIMEOUT;
  64. #define PKTSIZE (1432+4) /* SEGSIZE+4 */
  65. int segsize = SEGSIZE;
  66. char buf[PKTSIZE];
  67. char ackbuf[PKTSIZE];
  68. struct sockaddr_in from;
  69. int fromlen;
  70. char *rootdir = NULL;
  71. int debug = 0;
  72. struct filters {
  73. struct filters *next;
  74. char *fname;
  75. } *filters = NULL;
  76. int isfilter = 0;
  77. main(argc, argv)
  78. char *argv[];
  79. {
  80. register struct tftphdr *tp;
  81. register int n;
  82. int on = 1;
  83. extern int optind;
  84. extern char *optarg;
  85. openlog(argv[0], LOG_PID, LOG_DAEMON);
  86. while ((n = getopt(argc, argv, "c:dr:")) >= 0) {
  87. switch (n) {
  88. case 'c':
  89. if (rootdir)
  90. goto usage;
  91. rootdir = optarg;
  92. break;
  93. case 'd':
  94. debug++;
  95. break;
  96. case 'r': {
  97. struct filters *fp = (void *)
  98. malloc(sizeof(struct filters) +
  99. strlen(optarg) + 1);
  100. fp->next = filters;
  101. fp->fname = (char *)(fp + 1);
  102. strcpy(fp->fname, optarg);
  103. filters = fp;
  104. break; }
  105. default:
  106. usage:
  107. syslog(LOG_ERR, "Usage: %s [-c chroot] "
  108. "[-r readfilter] [-d]\n",
  109. argv[0]);
  110. exit(1);
  111. }
  112. }
  113. if (argc-optind != 0)
  114. goto usage;
  115. ioctl(0, FIONBIO, &on);
  116. /* if (ioctl(0, FIONBIO, &on) < 0) {
  117. syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
  118. exit(1);
  119. }
  120. */
  121. fromlen = sizeof (from);
  122. n = recvfrom(0, buf, segsize+4, 0,
  123. (struct sockaddr *)&from, &fromlen);
  124. if (n < 0) {
  125. syslog(LOG_ERR, "recvfrom: %m\n");
  126. exit(1);
  127. }
  128. /*
  129. * Now that we have read the message out of the UDP
  130. * socket, we fork and exit. Thus, inetd will go back
  131. * to listening to the tftp port, and the next request
  132. * to come in will start up a new instance of tftpd.
  133. *
  134. * We do this so that inetd can run tftpd in "wait" mode.
  135. * The problem with tftpd running in "nowait" mode is that
  136. * inetd may get one or more successful "selects" on the
  137. * tftp port before we do our receive, so more than one
  138. * instance of tftpd may be started up. Worse, if tftpd
  139. * break before doing the above "recvfrom", inetd would
  140. * spawn endless instances, clogging the system.
  141. */
  142. {
  143. int pid;
  144. int i, j;
  145. for (i = 1; i < 20; i++) {
  146. pid = fork();
  147. if (pid < 0) {
  148. sleep(i);
  149. /*
  150. * flush out to most recently sent request.
  151. *
  152. * This may drop some request, but those
  153. * will be resent by the clients when
  154. * they timeout. The positive effect of
  155. * this flush is to (try to) prevent more
  156. * than one tftpd being started up to service
  157. * a single request from a single client.
  158. */
  159. j = sizeof from;
  160. i = recvfrom(0, buf, segsize+4, 0,
  161. (struct sockaddr *)&from, &j);
  162. if (i > 0) {
  163. n = i;
  164. fromlen = j;
  165. }
  166. } else {
  167. break;
  168. }
  169. }
  170. if (pid < 0) {
  171. syslog(LOG_ERR, "fork: %m\n");
  172. exit(1);
  173. } else if (pid != 0) {
  174. exit(0);
  175. }
  176. }
  177. from.sin_family = AF_INET;
  178. alarm(0);
  179. close(0);
  180. close(1);
  181. peer = socket(AF_INET, SOCK_DGRAM, 0);
  182. if (peer < 0) {
  183. syslog(LOG_ERR, "socket: %m\n");
  184. exit(1);
  185. }
  186. if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
  187. syslog(LOG_ERR, "bind: %m\n");
  188. exit(1);
  189. }
  190. if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
  191. syslog(LOG_ERR, "connect: %m\n");
  192. exit(1);
  193. }
  194. tp = (struct tftphdr *)buf;
  195. tp->th_opcode = ntohs(tp->th_opcode);
  196. if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
  197. tftp(tp, n);
  198. exit(1);
  199. }
  200. int validate_access();
  201. int sendfile(), recvfile();
  202. struct formats {
  203. char *f_mode;
  204. int (*f_validate)();
  205. int (*f_send)();
  206. int (*f_recv)();
  207. int f_convert;
  208. } formats[] = {
  209. { "netascii", validate_access, sendfile, recvfile, 1 },
  210. { "octet", validate_access, sendfile, recvfile, 0 },
  211. #ifdef notdef
  212. { "mail", validate_user, sendmail, recvmail, 1 },
  213. #endif
  214. { 0 }
  215. };
  216. int set_blksize();
  217. struct options {
  218. char *o_opt;
  219. int (*o_fnc)();
  220. } options[] = {
  221. { "blksize", set_blksize },
  222. { 0 }
  223. };
  224. /*
  225. * Set a non-standard block size (c.f. RFC1783)
  226. */
  227. set_blksize(val, ret)
  228. char *val;
  229. char **ret;
  230. {
  231. static char b_ret[5];
  232. int sz = atoi(val);
  233. if (sz < 8) {
  234. if (debug)
  235. syslog(LOG_ERR, "Requested packetsize %d < 8\n", sz);
  236. return(0);
  237. } else if (sz > PKTSIZE-4) {
  238. if (debug)
  239. syslog(LOG_INFO, "Requested packetsize %d > %d\n",
  240. sz, PKTSIZE-4);
  241. sz = PKTSIZE-4;
  242. } else if (debug)
  243. syslog(LOG_INFO, "Adjusted packetsize to %d octets\n", sz);
  244. segsize = sz;
  245. sprintf(*ret = b_ret, "%d", sz);
  246. return(1);
  247. }
  248. /*
  249. * Parse RFC1782 style options
  250. */
  251. do_opt(opt, val, ap)
  252. char *opt;
  253. char *val;
  254. char **ap;
  255. {
  256. struct options *po;
  257. char *ret;
  258. for (po = options; po->o_opt; po++)
  259. if (strcasecmp(po->o_opt, opt) == 0) {
  260. if (po->o_fnc(val, &ret)) {
  261. if (*ap + strlen(opt) + strlen(ret) + 2 >=
  262. ackbuf + sizeof(ackbuf)) {
  263. if (debug)
  264. syslog(LOG_ERR,
  265. "Ackbuf overflow\n");
  266. nak(ENOSPACE);
  267. exit(1);
  268. }
  269. *ap = strrchr(strcpy(strrchr(strcpy(*ap, opt),
  270. '\000')+1, val),
  271. '\000')+1;
  272. } else {
  273. nak(EOPTNEG);
  274. exit(1);
  275. }
  276. break;
  277. }
  278. if (debug && !po->o_opt)
  279. syslog(LOG_WARNING, "Unhandled option: %d = %d\n", opt, val);
  280. return;
  281. }
  282. /*
  283. * Handle initial connection protocol.
  284. */
  285. tftp(tp, size)
  286. struct tftphdr *tp;
  287. int size;
  288. {
  289. register char *cp;
  290. int argn = 0, ecode;
  291. register struct formats *pf;
  292. char *filename, *mode;
  293. char *val, *opt;
  294. char *ap = ackbuf+2;
  295. int isopts;
  296. ((struct tftphdr *)ackbuf)->th_opcode = ntohs(OACK);
  297. filename = cp = tp->th_stuff;
  298. again:
  299. while (cp < buf + size) {
  300. if (*cp == '\0')
  301. break;
  302. cp++;
  303. }
  304. if (*cp != '\0') {
  305. if (debug)
  306. syslog(LOG_WARNING, "Received illegal request\n");
  307. nak(EBADOP);
  308. exit(1);
  309. }
  310. if (!argn++) {
  311. mode = ++cp;
  312. goto again;
  313. } else {
  314. if (debug && argn == 3)
  315. syslog(LOG_INFO, "Found RFC1782 style options\n");
  316. *(argn & 1 ? &val : &opt) = ++cp;
  317. if (argn & 1)
  318. do_opt(opt, val, &ap);
  319. if (cp < buf + size && *cp != '\000')
  320. goto again;
  321. }
  322. for (cp = mode; *cp; cp++)
  323. if (isupper(*cp))
  324. *cp = tolower(*cp);
  325. for (pf = formats; pf->f_mode; pf++)
  326. if (strcmp(pf->f_mode, mode) == 0)
  327. break;
  328. if (pf->f_mode == 0) {
  329. if (debug)
  330. syslog(LOG_WARNING, "Unknown data format: %s\n", mode);
  331. nak(EBADOP);
  332. exit(1);
  333. }
  334. if (rootdir) {
  335. cp = alloca(strlen(rootdir) + strlen(filename) + 1);
  336. if (cp == NULL) {
  337. nak(100+ENOMEM);
  338. exit(1);
  339. }
  340. if (*filename != '/') {
  341. if (debug)
  342. syslog(LOG_ERR,
  343. "Filename has to be absolute: %s\n",
  344. filename);
  345. nak(EACCESS);
  346. exit(1);
  347. }
  348. filename = strcat(strcpy(cp, rootdir), filename);
  349. }
  350. ecode = (*pf->f_validate)(filename, tp->th_opcode);
  351. if (ecode) {
  352. nak(ecode, ERROR);
  353. exit(1);
  354. }
  355. isopts = ap != (ackbuf+2);
  356. (tp->th_opcode == WRQ ? *pf->f_recv : *pf->f_send)
  357. (pf, isopts ? ackbuf : NULL, isopts ? ap-ackbuf : 0);
  358. exit(0);
  359. }
  360. FILE *file;
  361. /*
  362. * Validate file access. Since we
  363. * have no uid or gid, for now require
  364. * file to exist and be publicly
  365. * readable/writable.
  366. * Note also, full path name must be
  367. * given as we have no login directory.
  368. */
  369. validate_access(filename, mode)
  370. char *filename;
  371. int mode;
  372. {
  373. struct stat stbuf;
  374. int fd;
  375. char *cp;
  376. isfilter = 0;
  377. if (mode == RRQ) {
  378. struct filters *fp = filters;
  379. for (; fp; fp = fp->next) {
  380. if (!strcmp(fp->fname,
  381. filename +
  382. (rootdir ? strlen(rootdir) : 0))) {
  383. if (debug)
  384. syslog(LOG_INFO, "Opening input "
  385. "filter: %s\n", filename);
  386. if ((file = popen(filename, "r")) == NULL) {
  387. syslog(LOG_ERR, "Failed to open input "
  388. "filter\n");
  389. return (EACCESS); }
  390. fd = fileno(file);
  391. isfilter = 1;
  392. return (0);
  393. }
  394. }
  395. }
  396. if (*filename != '/') {
  397. if (debug)
  398. syslog(LOG_ERR, "Filename has to be absolute: %s\n",
  399. filename);
  400. return (EACCESS);
  401. }
  402. for (cp = filename; *cp; cp++)
  403. if (*cp == '~' || *cp == '$' ||
  404. (*cp == '/' && cp[1] == '.' && cp[2] == '.')) {
  405. if (debug)
  406. syslog(LOG_ERR, "Illegal filename: %s\n",
  407. filename);
  408. return (EACCESS);
  409. }
  410. if (debug)
  411. syslog(LOG_INFO, "Validating \"%s\" for %sing\n",
  412. filename, mode == RRQ ? "read" : "writ");
  413. if (stat(filename, &stbuf) < 0)
  414. return (errno == ENOENT ? ENOTFOUND : EACCESS);
  415. if (mode == RRQ) {
  416. if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)
  417. return (EACCESS);
  418. } else {
  419. if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)
  420. return (EACCESS);
  421. }
  422. fd = open(filename, mode == RRQ ? 0 : 1);
  423. if (fd < 0)
  424. return (errno + 100);
  425. file = fdopen(fd, (mode == RRQ)? "r":"w");
  426. if (file == NULL) {
  427. return errno+100;
  428. }
  429. return (0);
  430. }
  431. int timeout;
  432. jmp_buf timeoutbuf;
  433. void timer(int sig)
  434. {
  435. timeout += rexmtval;
  436. if (timeout >= maxtimeout) {
  437. if (debug)
  438. syslog(LOG_WARNING, "Timeout!\n");
  439. exit(1);
  440. }
  441. longjmp(timeoutbuf, 1);
  442. }
  443. /*
  444. * Send the requested file.
  445. */
  446. sendfile(pf, oap, oacklen)
  447. struct formats *pf;
  448. struct tftphdr *oap;
  449. int oacklen;
  450. {
  451. struct tftphdr *dp, *r_init();
  452. register struct tftphdr *ap; /* ack packet */
  453. register int size, n;
  454. u_short block = 1;
  455. signal(SIGALRM, timer);
  456. ap = (struct tftphdr *)ackbuf;
  457. if (oap) {
  458. timeout = 0;
  459. (void) setjmp(timeoutbuf);
  460. oack:
  461. if (send(peer, oap, oacklen, 0) != oacklen) {
  462. syslog(LOG_ERR, "tftpd: write: %m\n");
  463. goto abort;
  464. }
  465. for ( ; ; ) {
  466. alarm(rexmtval);
  467. n = recv(peer, ackbuf, sizeof (ackbuf), 0);
  468. alarm(0);
  469. if (n < 0) {
  470. syslog(LOG_ERR, "tftpd: read: %m\n");
  471. goto abort;
  472. }
  473. ap->th_opcode = ntohs((u_short)ap->th_opcode);
  474. ap->th_block = ntohs(ap->th_block);
  475. if (ap->th_opcode == ERROR) {
  476. if (debug)
  477. syslog(LOG_ERR, "Client does not "
  478. "accept options\n");
  479. goto abort; }
  480. if (ap->th_opcode == ACK) {
  481. if (ap->th_block == 0) {
  482. if (debug)
  483. syslog(LOG_DEBUG,
  484. "RFC1782 option "
  485. "negotiation "
  486. "succeeded\n");
  487. break;
  488. }
  489. /* Re-synchronize with the other side */
  490. (void) synchnet(peer);
  491. goto oack;
  492. }
  493. }
  494. }
  495. dp = r_init();
  496. do {
  497. size = readit(file, &dp, pf->f_convert);
  498. if (size < 0) {
  499. nak(errno + 100);
  500. goto abort;
  501. }
  502. dp->th_opcode = htons((u_short)DATA);
  503. dp->th_block = htons(block);
  504. timeout = 0;
  505. (void) setjmp(timeoutbuf);
  506. send_data:
  507. if (send(peer, dp, size + 4, 0) != size + 4) {
  508. syslog(LOG_ERR, "tftpd: write: %m\n");
  509. goto abort;
  510. }
  511. read_ahead(file, pf->f_convert);
  512. for ( ; ; ) {
  513. alarm(rexmtval); /* read the ack */
  514. n = recv(peer, ackbuf, sizeof (ackbuf), 0);
  515. alarm(0);
  516. if (n < 0) {
  517. syslog(LOG_ERR, "tftpd: read: %m\n");
  518. goto abort;
  519. }
  520. ap->th_opcode = ntohs((u_short)ap->th_opcode);
  521. ap->th_block = ntohs(ap->th_block);
  522. if (ap->th_opcode == ERROR)
  523. goto abort;
  524. if (ap->th_opcode == ACK) {
  525. if (ap->th_block == block) {
  526. break;
  527. }
  528. /* Re-synchronize with the other side */
  529. (void) synchnet(peer);
  530. if (ap->th_block == (block -1)) {
  531. goto send_data;
  532. }
  533. }
  534. }
  535. block++;
  536. } while (size == segsize);
  537. abort:
  538. if (isfilter)
  539. pclose(file);
  540. else
  541. (void) fclose(file);
  542. isfilter = 0;
  543. }
  544. void justquit(int sig)
  545. {
  546. exit(0);
  547. }
  548. /*
  549. * Receive a file.
  550. */
  551. recvfile(pf, oap, oacklen)
  552. struct formats *pf;
  553. struct tftphdr *oap;
  554. int oacklen;
  555. {
  556. struct tftphdr *dp, *w_init();
  557. register struct tftphdr *ap; /* ack buffer */
  558. register int acksize, n, size;
  559. u_short block = 0;
  560. signal(SIGALRM, timer);
  561. dp = w_init();
  562. do {
  563. timeout = 0;
  564. if (!block++ && oap) {
  565. ap = (struct tftphdr *)oap;
  566. acksize = oacklen;
  567. } else {
  568. ap = (struct tftphdr *)ackbuf;
  569. ap->th_opcode = htons((u_short)ACK);
  570. ap->th_block = htons(block-1);
  571. acksize = 4;
  572. }
  573. (void) setjmp(timeoutbuf);
  574. send_ack:
  575. if (send(peer, (char *)ap, acksize, 0) != acksize) {
  576. syslog(LOG_ERR, "tftpd: write: %m\n");
  577. goto abort;
  578. }
  579. write_behind(file, pf->f_convert);
  580. for ( ; ; ) {
  581. alarm(rexmtval);
  582. n = recv(peer, dp, segsize+4, 0);
  583. alarm(0);
  584. if (n < 0) { /* really? */
  585. syslog(LOG_ERR, "tftpd: read: %m\n");
  586. goto abort;
  587. }
  588. dp->th_opcode = ntohs((u_short)dp->th_opcode);
  589. dp->th_block = ntohs(dp->th_block);
  590. if (dp->th_opcode == ERROR)
  591. goto abort;
  592. if (dp->th_opcode == DATA) {
  593. if (dp->th_block == block) {
  594. break; /* normal */
  595. }
  596. /* Re-synchronize with the other side */
  597. (void) synchnet(peer);
  598. if (dp->th_block == (block-1))
  599. goto send_ack; /* rexmit */
  600. }
  601. }
  602. /* size = write(file, dp->th_data, n - 4); */
  603. size = writeit(file, &dp, n - 4, pf->f_convert);
  604. if (size != (n-4)) { /* ahem */
  605. if (size < 0) nak(errno + 100);
  606. else nak(ENOSPACE);
  607. goto abort;
  608. }
  609. } while (size == segsize);
  610. write_behind(file, pf->f_convert);
  611. if (isfilter)
  612. pclose(file);
  613. else
  614. (void) fclose(file); /* close data file */
  615. isfilter = 0;
  616. ap = (struct tftphdr *)ackbuf;
  617. ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
  618. ap->th_block = htons(block);
  619. (void) send(peer, ackbuf, 4, 0);
  620. signal(SIGALRM, justquit); /* just quit on timeout */
  621. alarm(rexmtval);
  622. n = recv(peer, buf, segsize, 0); /* normally times out and quits */
  623. alarm(0);
  624. if (n >= 4 && /* if read some data */
  625. dp->th_opcode == DATA && /* and got a data block */
  626. block == dp->th_block) { /* then my last ack was lost */
  627. (void) send(peer, ackbuf, 4, 0); /* resend final ack */
  628. }
  629. abort:
  630. return;
  631. }
  632. struct errmsg {
  633. int e_code;
  634. const char *e_msg;
  635. } errmsgs[] = {
  636. { EUNDEF, "Undefined error code" },
  637. { ENOTFOUND, "File not found" },
  638. { EACCESS, "Access violation" },
  639. { ENOSPACE, "Disk full or allocation exceeded" },
  640. { EBADOP, "Illegal TFTP operation" },
  641. { EBADID, "Unknown transfer ID" },
  642. { EEXISTS, "File already exists" },
  643. { ENOUSER, "No such user" },
  644. { EOPTNEG, "Failure to negotiate RFC1782 options" },
  645. { -1, 0 }
  646. };
  647. /*
  648. * Send a nak packet (error message).
  649. * Error code passed in is one of the
  650. * standard TFTP codes, or a UNIX errno
  651. * offset by 100.
  652. */
  653. nak(error)
  654. int error;
  655. {
  656. register struct tftphdr *tp;
  657. int length;
  658. register struct errmsg *pe;
  659. /* extern char *sys_errlist[]; */
  660. tp = (struct tftphdr *)buf;
  661. tp->th_opcode = htons((u_short)ERROR);
  662. tp->th_code = htons((u_short)error);
  663. for (pe = errmsgs; pe->e_code >= 0; pe++)
  664. if (pe->e_code == error)
  665. break;
  666. if (pe->e_code < 0) {
  667. pe->e_msg = sys_errlist[error -100];
  668. tp->th_code = EUNDEF; /* set 'undef' errorcode */
  669. }
  670. strcpy(tp->th_msg, pe->e_msg);
  671. length = strlen(pe->e_msg);
  672. tp->th_msg[length] = '\0';
  673. length += 5;
  674. if (debug)
  675. syslog(LOG_ERR, "Negative acknowledge: %s\n", tp->th_msg);
  676. if (send(peer, buf, length, 0) != length)
  677. syslog(LOG_ERR, "nak: %m\n");
  678. }