tftp.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. /* ------------------------------------------------------------------------- */
  2. /* tftp.c */
  3. /* */
  4. /* A simple tftp client for busybox. */
  5. /* Tries to follow RFC1350. */
  6. /* Only "octet" mode supported. */
  7. /* Optional blocksize negotiation (RFC2347 + RFC2348) */
  8. /* */
  9. /* Copyright (C) 2001 Magnus Damm <damm@opensource.se> */
  10. /* */
  11. /* Parts of the code based on: */
  12. /* */
  13. /* atftp: Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca> */
  14. /* and Remi Lefebvre <remi@debian.org> */
  15. /* */
  16. /* utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de> */
  17. /* */
  18. /* This program is free software; you can redistribute it and/or modify */
  19. /* it under the terms of the GNU General Public License as published by */
  20. /* the Free Software Foundation; either version 2 of the License, or */
  21. /* (at your option) any later version. */
  22. /* */
  23. /* This program is distributed in the hope that it will be useful, */
  24. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  25. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
  26. /* General Public License for more details. */
  27. /* */
  28. /* You should have received a copy of the GNU General Public License */
  29. /* along with this program; if not, write to the Free Software */
  30. /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
  31. /* */
  32. /* ------------------------------------------------------------------------- */
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <sys/types.h>
  37. #include <sys/socket.h>
  38. #include <sys/time.h>
  39. #include <sys/stat.h>
  40. #include <netdb.h>
  41. #include <netinet/in.h>
  42. #include <arpa/inet.h>
  43. #include <unistd.h>
  44. #include <fcntl.h>
  45. #include "busybox.h"
  46. //#define CONFIG_FEATURE_TFTP_DEBUG
  47. #define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
  48. #define TFTP_TIMEOUT 5 /* seconds */
  49. /* opcodes we support */
  50. #define TFTP_RRQ 1
  51. #define TFTP_WRQ 2
  52. #define TFTP_DATA 3
  53. #define TFTP_ACK 4
  54. #define TFTP_ERROR 5
  55. #define TFTP_OACK 6
  56. static const char *tftp_bb_error_msg[] = {
  57. "Undefined error",
  58. "File not found",
  59. "Access violation",
  60. "Disk full or allocation error",
  61. "Illegal TFTP operation",
  62. "Unknown transfer ID",
  63. "File already exists",
  64. "No such user"
  65. };
  66. static const int tftp_cmd_get = 1;
  67. static const int tftp_cmd_put = 2;
  68. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  69. static int tftp_blocksize_check(int blocksize, int bufsize)
  70. {
  71. /* Check if the blocksize is valid:
  72. * RFC2348 says between 8 and 65464,
  73. * but our implementation makes it impossible
  74. * to use blocksizes smaller than 22 octets.
  75. */
  76. if ((bufsize && (blocksize > bufsize)) ||
  77. (blocksize < 8) || (blocksize > 65464)) {
  78. bb_error_msg("bad blocksize");
  79. return 0;
  80. }
  81. return blocksize;
  82. }
  83. static char *tftp_option_get(char *buf, int len, char *option)
  84. {
  85. int opt_val = 0;
  86. int opt_found = 0;
  87. int k;
  88. while (len > 0) {
  89. /* Make sure the options are terminated correctly */
  90. for (k = 0; k < len; k++) {
  91. if (buf[k] == '\0') {
  92. break;
  93. }
  94. }
  95. if (k >= len) {
  96. break;
  97. }
  98. if (opt_val == 0) {
  99. if (strcasecmp(buf, option) == 0) {
  100. opt_found = 1;
  101. }
  102. }
  103. else {
  104. if (opt_found) {
  105. return buf;
  106. }
  107. }
  108. k++;
  109. buf += k;
  110. len -= k;
  111. opt_val ^= 1;
  112. }
  113. return NULL;
  114. }
  115. #endif
  116. static inline int tftp(const int cmd, const struct hostent *host,
  117. const char *remotefile, int localfd, const unsigned short port, int tftp_bufsize)
  118. {
  119. const int cmd_get = cmd & tftp_cmd_get;
  120. const int cmd_put = cmd & tftp_cmd_put;
  121. const int bb_tftp_num_retries = 5;
  122. struct sockaddr_in sa;
  123. struct sockaddr_in from;
  124. struct timeval tv;
  125. socklen_t fromlen;
  126. fd_set rfds;
  127. char *cp;
  128. unsigned short tmp;
  129. int socketfd;
  130. int len;
  131. int opcode = 0;
  132. int finished = 0;
  133. int timeout = bb_tftp_num_retries;
  134. unsigned short block_nr = 1;
  135. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  136. int want_option_ack = 0;
  137. #endif
  138. /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
  139. * size varies meaning BUFFERS_GO_ON_STACK would fail */
  140. char *buf=xmalloc(tftp_bufsize + 4);
  141. tftp_bufsize += 4;
  142. if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
  143. bb_perror_msg("socket");
  144. return EXIT_FAILURE;
  145. }
  146. len = sizeof(sa);
  147. memset(&sa, 0, len);
  148. bind(socketfd, (struct sockaddr *)&sa, len);
  149. sa.sin_family = host->h_addrtype;
  150. sa.sin_port = port;
  151. memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
  152. sizeof(sa.sin_addr));
  153. /* build opcode */
  154. if (cmd_get) {
  155. opcode = TFTP_RRQ;
  156. }
  157. if (cmd_put) {
  158. opcode = TFTP_WRQ;
  159. }
  160. while (1) {
  161. cp = buf;
  162. /* first create the opcode part */
  163. *((unsigned short *) cp) = htons(opcode);
  164. cp += 2;
  165. /* add filename and mode */
  166. if ((cmd_get && (opcode == TFTP_RRQ)) ||
  167. (cmd_put && (opcode == TFTP_WRQ))) {
  168. int too_long = 0;
  169. /* see if the filename fits into buf */
  170. /* and fill in packet */
  171. len = strlen(remotefile) + 1;
  172. if ((cp + len) >= &buf[tftp_bufsize - 1]) {
  173. too_long = 1;
  174. }
  175. else {
  176. safe_strncpy(cp, remotefile, len);
  177. cp += len;
  178. }
  179. if (too_long || ((&buf[tftp_bufsize - 1] - cp) < 6)) {
  180. bb_error_msg("too long remote-filename");
  181. break;
  182. }
  183. /* add "mode" part of the package */
  184. memcpy(cp, "octet", 6);
  185. cp += 6;
  186. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  187. len = tftp_bufsize - 4; /* data block size */
  188. if (len != TFTP_BLOCKSIZE_DEFAULT) {
  189. if ((&buf[tftp_bufsize - 1] - cp) < 15) {
  190. bb_error_msg("too long remote-filename");
  191. break;
  192. }
  193. /* add "blksize" + number of blocks */
  194. memcpy(cp, "blksize", 8);
  195. cp += 8;
  196. cp += snprintf(cp, 6, "%d", len) + 1;
  197. want_option_ack = 1;
  198. }
  199. #endif
  200. }
  201. /* add ack and data */
  202. if ((cmd_get && (opcode == TFTP_ACK)) ||
  203. (cmd_put && (opcode == TFTP_DATA))) {
  204. *((unsigned short *) cp) = htons(block_nr);
  205. cp += 2;
  206. block_nr++;
  207. if (cmd_put && (opcode == TFTP_DATA)) {
  208. len = bb_full_read(localfd, cp, tftp_bufsize - 4);
  209. if (len < 0) {
  210. bb_perror_msg("read");
  211. break;
  212. }
  213. if (len != (tftp_bufsize - 4)) {
  214. finished++;
  215. }
  216. cp += len;
  217. }
  218. }
  219. /* send packet */
  220. timeout = bb_tftp_num_retries; /* re-initialize */
  221. do {
  222. len = cp - buf;
  223. #ifdef CONFIG_FEATURE_TFTP_DEBUG
  224. fprintf(stderr, "sending %u bytes\n", len);
  225. for (cp = buf; cp < &buf[len]; cp++)
  226. fprintf(stderr, "%02x ", (unsigned char)*cp);
  227. fprintf(stderr, "\n");
  228. #endif
  229. if (sendto(socketfd, buf, len, 0,
  230. (struct sockaddr *) &sa, sizeof(sa)) < 0) {
  231. bb_perror_msg("send");
  232. len = -1;
  233. break;
  234. }
  235. if (finished && (opcode == TFTP_ACK)) {
  236. break;
  237. }
  238. /* receive packet */
  239. memset(&from, 0, sizeof(from));
  240. fromlen = sizeof(from);
  241. tv.tv_sec = TFTP_TIMEOUT;
  242. tv.tv_usec = 0;
  243. FD_ZERO(&rfds);
  244. FD_SET(socketfd, &rfds);
  245. switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
  246. case 1:
  247. len = recvfrom(socketfd, buf, tftp_bufsize, 0,
  248. (struct sockaddr *) &from, &fromlen);
  249. if (len < 0) {
  250. bb_perror_msg("recvfrom");
  251. break;
  252. }
  253. timeout = 0;
  254. if (sa.sin_port == port) {
  255. sa.sin_port = from.sin_port;
  256. }
  257. if (sa.sin_port == from.sin_port) {
  258. break;
  259. }
  260. /* fall-through for bad packets! */
  261. /* discard the packet - treat as timeout */
  262. timeout = bb_tftp_num_retries;
  263. case 0:
  264. bb_error_msg("timeout");
  265. timeout--;
  266. if (timeout == 0) {
  267. len = -1;
  268. bb_error_msg("last timeout");
  269. }
  270. break;
  271. default:
  272. bb_perror_msg("select");
  273. len = -1;
  274. }
  275. } while (timeout && (len >= 0));
  276. if ((finished) || (len < 0)) {
  277. break;
  278. }
  279. /* process received packet */
  280. opcode = ntohs(*((unsigned short *) buf));
  281. tmp = ntohs(*((unsigned short *) &buf[2]));
  282. #ifdef CONFIG_FEATURE_TFTP_DEBUG
  283. fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp);
  284. #endif
  285. if (opcode == TFTP_ERROR) {
  286. char *msg = NULL;
  287. if (buf[4] != '\0') {
  288. msg = &buf[4];
  289. buf[tftp_bufsize - 1] = '\0';
  290. } else if (tmp < (sizeof(tftp_bb_error_msg)
  291. / sizeof(char *))) {
  292. msg = (char *) tftp_bb_error_msg[tmp];
  293. }
  294. if (msg) {
  295. bb_error_msg("server says: %s", msg);
  296. }
  297. break;
  298. }
  299. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  300. if (want_option_ack) {
  301. want_option_ack = 0;
  302. if (opcode == TFTP_OACK) {
  303. /* server seems to support options */
  304. char *res;
  305. res = tftp_option_get(&buf[2], len-2,
  306. "blksize");
  307. if (res) {
  308. int blksize = atoi(res);
  309. if (tftp_blocksize_check(blksize,
  310. tftp_bufsize - 4)) {
  311. if (cmd_put) {
  312. opcode = TFTP_DATA;
  313. }
  314. else {
  315. opcode = TFTP_ACK;
  316. }
  317. #ifdef CONFIG_FEATURE_TFTP_DEBUG
  318. fprintf(stderr, "using blksize %u\n", blksize);
  319. #endif
  320. tftp_bufsize = blksize + 4;
  321. block_nr = 0;
  322. continue;
  323. }
  324. }
  325. /* FIXME:
  326. * we should send ERROR 8 */
  327. bb_error_msg("bad server option");
  328. break;
  329. }
  330. bb_error_msg("warning: blksize not supported by server"
  331. " - reverting to 512");
  332. tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
  333. }
  334. #endif
  335. if (cmd_get && (opcode == TFTP_DATA)) {
  336. if (tmp == block_nr) {
  337. len = bb_full_write(localfd, &buf[4], len - 4);
  338. if (len < 0) {
  339. bb_perror_msg("write");
  340. break;
  341. }
  342. if (len != (tftp_bufsize - 4)) {
  343. finished++;
  344. }
  345. opcode = TFTP_ACK;
  346. continue;
  347. }
  348. /* in case the last ack disappeared into the ether */
  349. if ( tmp == (block_nr - 1) ) {
  350. --block_nr;
  351. opcode = TFTP_ACK;
  352. continue;
  353. }
  354. }
  355. if (cmd_put && (opcode == TFTP_ACK)) {
  356. if (tmp == (unsigned short)(block_nr - 1)) {
  357. if (finished) {
  358. break;
  359. }
  360. opcode = TFTP_DATA;
  361. continue;
  362. }
  363. }
  364. }
  365. #ifdef CONFIG_FEATURE_CLEAN_UP
  366. close(socketfd);
  367. free(buf);
  368. #endif
  369. return finished ? EXIT_SUCCESS : EXIT_FAILURE;
  370. }
  371. int tftp_main(int argc, char **argv)
  372. {
  373. struct hostent *host = NULL;
  374. const char *localfile = NULL;
  375. const char *remotefile = NULL;
  376. int port;
  377. int cmd = 0;
  378. int fd = -1;
  379. int flags = 0;
  380. int opt;
  381. int result;
  382. int blocksize = TFTP_BLOCKSIZE_DEFAULT;
  383. /* figure out what to pass to getopt */
  384. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  385. #define BS "b:"
  386. #else
  387. #define BS
  388. #endif
  389. #ifdef CONFIG_FEATURE_TFTP_GET
  390. #define GET "g"
  391. #else
  392. #define GET
  393. #endif
  394. #ifdef CONFIG_FEATURE_TFTP_PUT
  395. #define PUT "p"
  396. #else
  397. #define PUT
  398. #endif
  399. while ((opt = getopt(argc, argv, BS GET PUT "l:r:")) != -1) {
  400. switch (opt) {
  401. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  402. case 'b':
  403. blocksize = atoi(optarg);
  404. if (!tftp_blocksize_check(blocksize, 0)) {
  405. return EXIT_FAILURE;
  406. }
  407. break;
  408. #endif
  409. #ifdef CONFIG_FEATURE_TFTP_GET
  410. case 'g':
  411. cmd = tftp_cmd_get;
  412. flags = O_WRONLY | O_CREAT | O_TRUNC;
  413. break;
  414. #endif
  415. #ifdef CONFIG_FEATURE_TFTP_PUT
  416. case 'p':
  417. cmd = tftp_cmd_put;
  418. flags = O_RDONLY;
  419. break;
  420. #endif
  421. case 'l':
  422. localfile = optarg;
  423. break;
  424. case 'r':
  425. remotefile = optarg;
  426. break;
  427. }
  428. }
  429. if ((cmd == 0) || (optind == argc)) {
  430. bb_show_usage();
  431. }
  432. if(localfile && strcmp(localfile, "-") == 0) {
  433. fd = fileno((cmd==tftp_cmd_get)? stdout : stdin);
  434. }
  435. if(localfile == NULL)
  436. localfile = remotefile;
  437. if(remotefile == NULL)
  438. remotefile = localfile;
  439. if (fd==-1) {
  440. fd = open(localfile, flags, 0644);
  441. }
  442. if (fd < 0) {
  443. bb_perror_msg_and_die("local file");
  444. }
  445. host = xgethostbyname(argv[optind]);
  446. port = bb_lookup_port(argv[optind + 1], "udp", 69);
  447. #ifdef CONFIG_FEATURE_TFTP_DEBUG
  448. fprintf(stderr, "using server \"%s\", remotefile \"%s\", "
  449. "localfile \"%s\".\n",
  450. inet_ntoa(*((struct in_addr *) host->h_addr)),
  451. remotefile, localfile);
  452. #endif
  453. result = tftp(cmd, host, remotefile, fd, port, blocksize);
  454. #ifdef CONFIG_FEATURE_CLEAN_UP
  455. if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) {
  456. close(fd);
  457. }
  458. #endif
  459. return(result);
  460. }