tftp.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /* vi: set sw=4 ts=4: */
  2. /* -------------------------------------------------------------------------
  3. * tftp.c
  4. *
  5. * A simple tftp client for busybox.
  6. * Tries to follow RFC1350.
  7. * Only "octet" mode supported.
  8. * Optional blocksize negotiation (RFC2347 + RFC2348)
  9. *
  10. * Copyright (C) 2001 Magnus Damm <damm@opensource.se>
  11. *
  12. * Parts of the code based on:
  13. *
  14. * atftp: Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca>
  15. * and Remi Lefebvre <remi@debian.org>
  16. *
  17. * utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de>
  18. *
  19. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  20. * ------------------------------------------------------------------------- */
  21. #include "busybox.h"
  22. #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
  23. #define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
  24. #define TFTP_TIMEOUT 5 /* seconds */
  25. #define TFTP_NUM_RETRIES 5 /* number of retries */
  26. /* opcodes we support */
  27. #define TFTP_RRQ 1
  28. #define TFTP_WRQ 2
  29. #define TFTP_DATA 3
  30. #define TFTP_ACK 4
  31. #define TFTP_ERROR 5
  32. #define TFTP_OACK 6
  33. static const char *const tftp_bb_error_msg[] = {
  34. "Undefined error",
  35. "File not found",
  36. "Access violation",
  37. "Disk full or allocation error",
  38. "Illegal TFTP operation",
  39. "Unknown transfer ID",
  40. "File already exists",
  41. "No such user"
  42. };
  43. #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
  44. #define USE_GETPUT(a)
  45. #define CMD_GET(cmd) 1
  46. #define CMD_PUT(cmd) 0
  47. #elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
  48. #define USE_GETPUT(a)
  49. #define CMD_GET(cmd) 0
  50. #define CMD_PUT(cmd) 1
  51. #else
  52. #define USE_GETPUT(a) a
  53. /* masks coming from getpot32 */
  54. #define CMD_GET(cmd) ((cmd) & 1)
  55. #define CMD_PUT(cmd) ((cmd) & 2)
  56. #endif
  57. /* NB: in the code below
  58. * CMD_GET(cmd) and CMD_GET(cmd) are mutually exclusive
  59. */
  60. #if ENABLE_FEATURE_TFTP_BLOCKSIZE
  61. static int tftp_blocksize_check(int blocksize, int bufsize)
  62. {
  63. /* Check if the blocksize is valid:
  64. * RFC2348 says between 8 and 65464,
  65. * but our implementation makes it impossible
  66. * to use blocksizes smaller than 22 octets.
  67. */
  68. if ((bufsize && (blocksize > bufsize))
  69. || (blocksize < 8) || (blocksize > 65564)
  70. ) {
  71. bb_error_msg("bad blocksize");
  72. return 0;
  73. }
  74. return blocksize;
  75. }
  76. static char *tftp_option_get(char *buf, int len, const char * const option)
  77. {
  78. int opt_val = 0;
  79. int opt_found = 0;
  80. int k;
  81. while (len > 0) {
  82. /* Make sure the options are terminated correctly */
  83. for (k = 0; k < len; k++) {
  84. if (buf[k] == '\0') {
  85. break;
  86. }
  87. }
  88. if (k >= len) {
  89. break;
  90. }
  91. if (opt_val == 0) {
  92. if (strcasecmp(buf, option) == 0) {
  93. opt_found = 1;
  94. }
  95. } else {
  96. if (opt_found) {
  97. return buf;
  98. }
  99. }
  100. k++;
  101. buf += k;
  102. len -= k;
  103. opt_val ^= 1;
  104. }
  105. return NULL;
  106. }
  107. #endif
  108. static int tftp(
  109. #if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
  110. const int cmd,
  111. #endif
  112. len_and_sockaddr *peer_lsa,
  113. const char *remotefile, const int localfd,
  114. unsigned port, int tftp_bufsize)
  115. {
  116. struct timeval tv;
  117. fd_set rfds;
  118. int socketfd;
  119. int len;
  120. int opcode = 0;
  121. int finished = 0;
  122. int timeout = TFTP_NUM_RETRIES;
  123. uint16_t block_nr = 1;
  124. uint16_t tmp;
  125. char *cp;
  126. USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;)
  127. unsigned org_port;
  128. len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len);
  129. /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
  130. * size varies meaning BUFFERS_GO_ON_STACK would fail */
  131. /* We must keep the transmit and receive buffers seperate */
  132. /* In case we rcv a garbage pkt and we need to rexmit the last pkt */
  133. char *xbuf = xmalloc(tftp_bufsize += 4);
  134. char *rbuf = xmalloc(tftp_bufsize);
  135. port = org_port = htons(port);
  136. socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0);
  137. /* build opcode */
  138. opcode = TFTP_WRQ;
  139. if (CMD_GET(cmd)) {
  140. opcode = TFTP_RRQ;
  141. }
  142. while (1) {
  143. cp = xbuf;
  144. /* first create the opcode part */
  145. /* (this 16bit store is aligned) */
  146. *((uint16_t*)cp) = htons(opcode);
  147. cp += 2;
  148. /* add filename and mode */
  149. if (CMD_GET(cmd) ? (opcode == TFTP_RRQ) : (opcode == TFTP_WRQ)) {
  150. int too_long = 0;
  151. /* see if the filename fits into xbuf
  152. * and fill in packet. */
  153. len = strlen(remotefile) + 1;
  154. if ((cp + len) >= &xbuf[tftp_bufsize - 1]) {
  155. too_long = 1;
  156. } else {
  157. safe_strncpy(cp, remotefile, len);
  158. cp += len;
  159. }
  160. if (too_long || (&xbuf[tftp_bufsize - 1] - cp) < sizeof("octet")) {
  161. bb_error_msg("remote filename too long");
  162. break;
  163. }
  164. /* add "mode" part of the package */
  165. memcpy(cp, "octet", sizeof("octet"));
  166. cp += sizeof("octet");
  167. #if ENABLE_FEATURE_TFTP_BLOCKSIZE
  168. len = tftp_bufsize - 4; /* data block size */
  169. if (len != TFTP_BLOCKSIZE_DEFAULT) {
  170. if ((&xbuf[tftp_bufsize - 1] - cp) < 15) {
  171. bb_error_msg("remote filename too long");
  172. break;
  173. }
  174. /* add "blksize" + number of blocks */
  175. memcpy(cp, "blksize", sizeof("blksize"));
  176. cp += sizeof("blksize");
  177. cp += snprintf(cp, 6, "%d", len) + 1;
  178. want_option_ack = 1;
  179. }
  180. #endif
  181. }
  182. /* add ack and data */
  183. if (CMD_GET(cmd) ? (opcode == TFTP_ACK) : (opcode == TFTP_DATA)) {
  184. /* TODO: unaligned access! */
  185. *((uint16_t*)cp) = htons(block_nr);
  186. cp += 2;
  187. block_nr++;
  188. if (CMD_PUT(cmd) && (opcode == TFTP_DATA)) {
  189. len = full_read(localfd, cp, tftp_bufsize - 4);
  190. if (len < 0) {
  191. bb_perror_msg(bb_msg_read_error);
  192. break;
  193. }
  194. if (len != (tftp_bufsize - 4)) {
  195. finished++;
  196. }
  197. cp += len;
  198. }
  199. }
  200. /* send packet */
  201. timeout = TFTP_NUM_RETRIES; /* re-initialize */
  202. do {
  203. len = cp - xbuf;
  204. #if ENABLE_DEBUG_TFTP
  205. fprintf(stderr, "sending %u bytes\n", len);
  206. for (cp = xbuf; cp < &xbuf[len]; cp++)
  207. fprintf(stderr, "%02x ", (unsigned char) *cp);
  208. fprintf(stderr, "\n");
  209. #endif
  210. if (sendto(socketfd, xbuf, len, 0,
  211. &peer_lsa->sa, peer_lsa->len) < 0) {
  212. bb_perror_msg("send");
  213. len = -1;
  214. break;
  215. }
  216. if (finished && (opcode == TFTP_ACK)) {
  217. break;
  218. }
  219. /* receive packet */
  220. recv_again:
  221. tv.tv_sec = TFTP_TIMEOUT;
  222. tv.tv_usec = 0;
  223. FD_ZERO(&rfds);
  224. FD_SET(socketfd, &rfds);
  225. switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
  226. unsigned from_port;
  227. case 1:
  228. from->len = peer_lsa->len;
  229. memset(&from->sa, 0, peer_lsa->len);
  230. len = recvfrom(socketfd, rbuf, tftp_bufsize, 0,
  231. &from->sa, &from->len);
  232. if (len < 0) {
  233. bb_perror_msg("recvfrom");
  234. break;
  235. }
  236. from_port = get_nport(from);
  237. if (port == org_port) {
  238. /* Our first query went to port 69
  239. * but reply will come from different one.
  240. * Remember and use this new port */
  241. port = from_port;
  242. set_nport(peer_lsa, from_port);
  243. }
  244. if (port != from_port)
  245. goto recv_again;
  246. timeout = 0;
  247. break;
  248. case 0:
  249. bb_error_msg("timeout");
  250. timeout--;
  251. if (timeout == 0) {
  252. len = -1;
  253. bb_error_msg("last timeout");
  254. }
  255. break;
  256. default:
  257. bb_perror_msg("select");
  258. len = -1;
  259. }
  260. } while (timeout && (len >= 0));
  261. if (finished || (len < 0)) {
  262. break;
  263. }
  264. /* process received packet */
  265. /* (both accesses seems to be aligned) */
  266. opcode = ntohs( ((uint16_t*)rbuf)[0] );
  267. tmp = ntohs( ((uint16_t*)rbuf)[1] );
  268. #if ENABLE_DEBUG_TFTP
  269. fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp);
  270. #endif
  271. if (opcode == TFTP_ERROR) {
  272. const char *msg = NULL;
  273. if (rbuf[4] != '\0') {
  274. msg = &rbuf[4];
  275. rbuf[tftp_bufsize - 1] = '\0';
  276. } else if (tmp < (sizeof(tftp_bb_error_msg)
  277. / sizeof(char *))) {
  278. msg = tftp_bb_error_msg[tmp];
  279. }
  280. if (msg) {
  281. bb_error_msg("server says: %s", msg);
  282. }
  283. break;
  284. }
  285. #if ENABLE_FEATURE_TFTP_BLOCKSIZE
  286. if (want_option_ack) {
  287. want_option_ack = 0;
  288. if (opcode == TFTP_OACK) {
  289. /* server seems to support options */
  290. char *res;
  291. res = tftp_option_get(&rbuf[2], len - 2, "blksize");
  292. if (res) {
  293. int blksize = xatoi_u(res);
  294. if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) {
  295. if (CMD_PUT(cmd)) {
  296. opcode = TFTP_DATA;
  297. } else {
  298. opcode = TFTP_ACK;
  299. }
  300. #if ENABLE_DEBUG_TFTP
  301. fprintf(stderr, "using blksize %u\n",
  302. blksize);
  303. #endif
  304. tftp_bufsize = blksize + 4;
  305. block_nr = 0;
  306. continue;
  307. }
  308. }
  309. /* FIXME:
  310. * we should send ERROR 8 */
  311. bb_error_msg("bad server option");
  312. break;
  313. }
  314. bb_error_msg("warning: blksize not supported by server"
  315. " - reverting to 512");
  316. tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
  317. }
  318. #endif
  319. if (CMD_GET(cmd) && (opcode == TFTP_DATA)) {
  320. if (tmp == block_nr) {
  321. len = full_write(localfd, &rbuf[4], len - 4);
  322. if (len < 0) {
  323. bb_perror_msg(bb_msg_write_error);
  324. break;
  325. }
  326. if (len != (tftp_bufsize - 4)) {
  327. finished++;
  328. }
  329. opcode = TFTP_ACK;
  330. continue;
  331. }
  332. /* in case the last ack disappeared into the ether */
  333. if (tmp == (block_nr - 1)) {
  334. --block_nr;
  335. opcode = TFTP_ACK;
  336. continue;
  337. // tmp==(block_nr-1) and (tmp+1)==block_nr is always same, I think. wtf?
  338. } else if (tmp + 1 == block_nr) {
  339. /* Server lost our TFTP_ACK. Resend it */
  340. block_nr = tmp;
  341. opcode = TFTP_ACK;
  342. continue;
  343. }
  344. }
  345. if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) {
  346. if (tmp == (uint16_t) (block_nr - 1)) {
  347. if (finished) {
  348. break;
  349. }
  350. opcode = TFTP_DATA;
  351. continue;
  352. }
  353. }
  354. }
  355. if (ENABLE_FEATURE_CLEAN_UP) {
  356. close(socketfd);
  357. free(xbuf);
  358. free(rbuf);
  359. }
  360. return finished ? EXIT_SUCCESS : EXIT_FAILURE;
  361. }
  362. int tftp_main(int argc, char **argv)
  363. {
  364. len_and_sockaddr *peer_lsa;
  365. const char *localfile = NULL;
  366. const char *remotefile = NULL;
  367. #if ENABLE_FEATURE_TFTP_BLOCKSIZE
  368. const char *sblocksize = NULL;
  369. #endif
  370. int port;
  371. USE_GETPUT(int cmd;)
  372. int fd = -1;
  373. int flags = 0;
  374. int result;
  375. int blocksize = TFTP_BLOCKSIZE_DEFAULT;
  376. /* -p or -g is mandatory, and they are mutually exclusive */
  377. opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:")
  378. USE_GETPUT("?g--p:p--g");
  379. USE_GETPUT(cmd =) getopt32(argc, argv,
  380. USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p")
  381. "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"),
  382. &localfile, &remotefile
  383. USE_FEATURE_TFTP_BLOCKSIZE(, &sblocksize));
  384. flags = O_RDONLY;
  385. if (CMD_GET(cmd))
  386. flags = O_WRONLY | O_CREAT | O_TRUNC;
  387. #if ENABLE_FEATURE_TFTP_BLOCKSIZE
  388. if (sblocksize) {
  389. blocksize = xatoi_u(sblocksize);
  390. if (!tftp_blocksize_check(blocksize, 0)) {
  391. return EXIT_FAILURE;
  392. }
  393. }
  394. #endif
  395. if (localfile == NULL)
  396. localfile = remotefile;
  397. if (remotefile == NULL)
  398. remotefile = localfile;
  399. if ((localfile == NULL && remotefile == NULL) || (argv[optind] == NULL))
  400. bb_show_usage();
  401. if (localfile == NULL || LONE_DASH(localfile)) {
  402. fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO;
  403. } else {
  404. fd = xopen3(localfile, flags, 0644);
  405. }
  406. port = bb_lookup_port(argv[optind + 1], "udp", 69);
  407. peer_lsa = host2sockaddr(argv[optind], port);
  408. #if ENABLE_DEBUG_TFTP
  409. fprintf(stderr, "using server \"%s\", "
  410. "remotefile \"%s\", localfile \"%s\".\n",
  411. xmalloc_sockaddr2dotted(&peer_lsa->sa, peer_lsa->len),
  412. remotefile, localfile);
  413. #endif
  414. result = tftp(
  415. #if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
  416. cmd,
  417. #endif
  418. peer_lsa, remotefile, fd, port, blocksize);
  419. if (fd > 1) {
  420. if (ENABLE_FEATURE_CLEAN_UP)
  421. close(fd);
  422. if (CMD_GET(cmd) && result != EXIT_SUCCESS)
  423. unlink(localfile);
  424. }
  425. return result;
  426. }
  427. #endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */