tftp.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  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 * const 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. #ifdef CONFIG_FEATURE_TFTP_GET
  67. # define tftp_cmd_get 1
  68. #else
  69. # define tftp_cmd_get 0
  70. #endif
  71. #ifdef CONFIG_FEATURE_TFTP_PUT
  72. # define tftp_cmd_put (tftp_cmd_get+1)
  73. #else
  74. # define tftp_cmd_put 0
  75. #endif
  76. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  77. static int tftp_blocksize_check(int blocksize, int bufsize)
  78. {
  79. /* Check if the blocksize is valid:
  80. * RFC2348 says between 8 and 65464,
  81. * but our implementation makes it impossible
  82. * to use blocksizes smaller than 22 octets.
  83. */
  84. if ((bufsize && (blocksize > bufsize)) ||
  85. (blocksize < 8) || (blocksize > 65464)) {
  86. bb_error_msg("bad blocksize");
  87. return 0;
  88. }
  89. return blocksize;
  90. }
  91. static char *tftp_option_get(char *buf, int len, char *option)
  92. {
  93. int opt_val = 0;
  94. int opt_found = 0;
  95. int k;
  96. while (len > 0) {
  97. /* Make sure the options are terminated correctly */
  98. for (k = 0; k < len; k++) {
  99. if (buf[k] == '\0') {
  100. break;
  101. }
  102. }
  103. if (k >= len) {
  104. break;
  105. }
  106. if (opt_val == 0) {
  107. if (strcasecmp(buf, option) == 0) {
  108. opt_found = 1;
  109. }
  110. }
  111. else {
  112. if (opt_found) {
  113. return buf;
  114. }
  115. }
  116. k++;
  117. buf += k;
  118. len -= k;
  119. opt_val ^= 1;
  120. }
  121. return NULL;
  122. }
  123. #endif
  124. static inline int tftp(const int cmd, const struct hostent *host,
  125. const char *remotefile, int localfd, const unsigned short port, int tftp_bufsize)
  126. {
  127. const int cmd_get = cmd & tftp_cmd_get;
  128. const int cmd_put = cmd & tftp_cmd_put;
  129. const int bb_tftp_num_retries = 5;
  130. struct sockaddr_in sa;
  131. struct sockaddr_in from;
  132. struct timeval tv;
  133. socklen_t fromlen;
  134. fd_set rfds;
  135. char *cp;
  136. unsigned short tmp;
  137. int socketfd;
  138. int len;
  139. int opcode = 0;
  140. int finished = 0;
  141. int timeout = bb_tftp_num_retries;
  142. unsigned short block_nr = 1;
  143. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  144. int want_option_ack = 0;
  145. #endif
  146. /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
  147. * size varies meaning BUFFERS_GO_ON_STACK would fail */
  148. char *buf=xmalloc(tftp_bufsize + 4);
  149. tftp_bufsize += 4;
  150. if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
  151. bb_perror_msg("socket");
  152. return EXIT_FAILURE;
  153. }
  154. len = sizeof(sa);
  155. memset(&sa, 0, len);
  156. bind(socketfd, (struct sockaddr *)&sa, len);
  157. sa.sin_family = host->h_addrtype;
  158. sa.sin_port = port;
  159. memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
  160. sizeof(sa.sin_addr));
  161. /* build opcode */
  162. if (cmd_get) {
  163. opcode = TFTP_RRQ;
  164. }
  165. if (cmd_put) {
  166. opcode = TFTP_WRQ;
  167. }
  168. while (1) {
  169. cp = buf;
  170. /* first create the opcode part */
  171. *((unsigned short *) cp) = htons(opcode);
  172. cp += 2;
  173. /* add filename and mode */
  174. if ((cmd_get && (opcode == TFTP_RRQ)) ||
  175. (cmd_put && (opcode == TFTP_WRQ))) {
  176. int too_long = 0;
  177. /* see if the filename fits into buf */
  178. /* and fill in packet */
  179. len = strlen(remotefile) + 1;
  180. if ((cp + len) >= &buf[tftp_bufsize - 1]) {
  181. too_long = 1;
  182. }
  183. else {
  184. safe_strncpy(cp, remotefile, len);
  185. cp += len;
  186. }
  187. if (too_long || ((&buf[tftp_bufsize - 1] - cp) < 6)) {
  188. bb_error_msg("too long remote-filename");
  189. break;
  190. }
  191. /* add "mode" part of the package */
  192. memcpy(cp, "octet", 6);
  193. cp += 6;
  194. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  195. len = tftp_bufsize - 4; /* data block size */
  196. if (len != TFTP_BLOCKSIZE_DEFAULT) {
  197. if ((&buf[tftp_bufsize - 1] - cp) < 15) {
  198. bb_error_msg("too long remote-filename");
  199. break;
  200. }
  201. /* add "blksize" + number of blocks */
  202. memcpy(cp, "blksize", 8);
  203. cp += 8;
  204. cp += snprintf(cp, 6, "%d", len) + 1;
  205. want_option_ack = 1;
  206. }
  207. #endif
  208. }
  209. /* add ack and data */
  210. if ((cmd_get && (opcode == TFTP_ACK)) ||
  211. (cmd_put && (opcode == TFTP_DATA))) {
  212. *((unsigned short *) cp) = htons(block_nr);
  213. cp += 2;
  214. block_nr++;
  215. if (cmd_put && (opcode == TFTP_DATA)) {
  216. len = bb_full_read(localfd, cp, tftp_bufsize - 4);
  217. if (len < 0) {
  218. bb_perror_msg("read");
  219. break;
  220. }
  221. if (len != (tftp_bufsize - 4)) {
  222. finished++;
  223. }
  224. cp += len;
  225. }
  226. }
  227. /* send packet */
  228. timeout = bb_tftp_num_retries; /* re-initialize */
  229. do {
  230. len = cp - buf;
  231. #ifdef CONFIG_FEATURE_TFTP_DEBUG
  232. fprintf(stderr, "sending %u bytes\n", len);
  233. for (cp = buf; cp < &buf[len]; cp++)
  234. fprintf(stderr, "%02x ", (unsigned char)*cp);
  235. fprintf(stderr, "\n");
  236. #endif
  237. if (sendto(socketfd, buf, len, 0,
  238. (struct sockaddr *) &sa, sizeof(sa)) < 0) {
  239. bb_perror_msg("send");
  240. len = -1;
  241. break;
  242. }
  243. if (finished && (opcode == TFTP_ACK)) {
  244. break;
  245. }
  246. /* receive packet */
  247. memset(&from, 0, sizeof(from));
  248. fromlen = sizeof(from);
  249. tv.tv_sec = TFTP_TIMEOUT;
  250. tv.tv_usec = 0;
  251. FD_ZERO(&rfds);
  252. FD_SET(socketfd, &rfds);
  253. switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
  254. case 1:
  255. len = recvfrom(socketfd, buf, tftp_bufsize, 0,
  256. (struct sockaddr *) &from, &fromlen);
  257. if (len < 0) {
  258. bb_perror_msg("recvfrom");
  259. break;
  260. }
  261. timeout = 0;
  262. if (sa.sin_port == port) {
  263. sa.sin_port = from.sin_port;
  264. }
  265. if (sa.sin_port == from.sin_port) {
  266. break;
  267. }
  268. /* fall-through for bad packets! */
  269. /* discard the packet - treat as timeout */
  270. timeout = bb_tftp_num_retries;
  271. case 0:
  272. bb_error_msg("timeout");
  273. timeout--;
  274. if (timeout == 0) {
  275. len = -1;
  276. bb_error_msg("last timeout");
  277. }
  278. break;
  279. default:
  280. bb_perror_msg("select");
  281. len = -1;
  282. }
  283. } while (timeout && (len >= 0));
  284. if ((finished) || (len < 0)) {
  285. break;
  286. }
  287. /* process received packet */
  288. opcode = ntohs(*((unsigned short *) buf));
  289. tmp = ntohs(*((unsigned short *) &buf[2]));
  290. #ifdef CONFIG_FEATURE_TFTP_DEBUG
  291. fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp);
  292. #endif
  293. if (opcode == TFTP_ERROR) {
  294. const char *msg = NULL;
  295. if (buf[4] != '\0') {
  296. msg = &buf[4];
  297. buf[tftp_bufsize - 1] = '\0';
  298. } else if (tmp < (sizeof(tftp_bb_error_msg)
  299. / sizeof(char *))) {
  300. msg = tftp_bb_error_msg[tmp];
  301. }
  302. if (msg) {
  303. bb_error_msg("server says: %s", msg);
  304. }
  305. break;
  306. }
  307. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  308. if (want_option_ack) {
  309. want_option_ack = 0;
  310. if (opcode == TFTP_OACK) {
  311. /* server seems to support options */
  312. char *res;
  313. res = tftp_option_get(&buf[2], len-2,
  314. "blksize");
  315. if (res) {
  316. int blksize = atoi(res);
  317. if (tftp_blocksize_check(blksize,
  318. tftp_bufsize - 4)) {
  319. if (cmd_put) {
  320. opcode = TFTP_DATA;
  321. }
  322. else {
  323. opcode = TFTP_ACK;
  324. }
  325. #ifdef CONFIG_FEATURE_TFTP_DEBUG
  326. fprintf(stderr, "using blksize %u\n", blksize);
  327. #endif
  328. tftp_bufsize = blksize + 4;
  329. block_nr = 0;
  330. continue;
  331. }
  332. }
  333. /* FIXME:
  334. * we should send ERROR 8 */
  335. bb_error_msg("bad server option");
  336. break;
  337. }
  338. bb_error_msg("warning: blksize not supported by server"
  339. " - reverting to 512");
  340. tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
  341. }
  342. #endif
  343. if (cmd_get && (opcode == TFTP_DATA)) {
  344. if (tmp == block_nr) {
  345. len = bb_full_write(localfd, &buf[4], len - 4);
  346. if (len < 0) {
  347. bb_perror_msg("write");
  348. break;
  349. }
  350. if (len != (tftp_bufsize - 4)) {
  351. finished++;
  352. }
  353. opcode = TFTP_ACK;
  354. continue;
  355. }
  356. /* in case the last ack disappeared into the ether */
  357. if ( tmp == (block_nr - 1) ) {
  358. --block_nr;
  359. opcode = TFTP_ACK;
  360. continue;
  361. } else if (tmp + 1 == block_nr) {
  362. /* Server lost our TFTP_ACK. Resend it */
  363. block_nr = tmp;
  364. opcode = TFTP_ACK;
  365. continue;
  366. }
  367. }
  368. if (cmd_put && (opcode == TFTP_ACK)) {
  369. if (tmp == (unsigned short)(block_nr - 1)) {
  370. if (finished) {
  371. break;
  372. }
  373. opcode = TFTP_DATA;
  374. continue;
  375. }
  376. }
  377. }
  378. #ifdef CONFIG_FEATURE_CLEAN_UP
  379. close(socketfd);
  380. free(buf);
  381. #endif
  382. return finished ? EXIT_SUCCESS : EXIT_FAILURE;
  383. }
  384. int tftp_main(int argc, char **argv)
  385. {
  386. struct hostent *host = NULL;
  387. const char *localfile = NULL;
  388. const char *remotefile = NULL;
  389. int port;
  390. int cmd = 0;
  391. int fd = -1;
  392. int flags = 0;
  393. int result;
  394. int blocksize = TFTP_BLOCKSIZE_DEFAULT;
  395. /* figure out what to pass to getopt */
  396. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  397. char *sblocksize = NULL;
  398. #define BS "b:"
  399. #define BS_ARG , &sblocksize
  400. #else
  401. #define BS
  402. #define BS_ARG
  403. #endif
  404. #ifdef CONFIG_FEATURE_TFTP_GET
  405. #define GET "g"
  406. #define GET_COMPL ":g"
  407. #else
  408. #define GET
  409. #define GET_COMP
  410. #endif
  411. #ifdef CONFIG_FEATURE_TFTP_PUT
  412. #define PUT "p"
  413. #define PUT_COMPL ":p"
  414. #else
  415. #define PUT
  416. #define PUT_COMPL
  417. #endif
  418. #if defined(CONFIG_FEATURE_TFTP_GET) && defined(CONFIG_FEATURE_TFTP_PUT)
  419. bb_opt_complementally = GET_COMPL PUT_COMPL ":?g--p:p--g";
  420. #elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT)
  421. bb_opt_complementally = GET_COMPL PUT_COMPL;
  422. #else
  423. /* XXX: may be should #error ? */
  424. #endif
  425. cmd = bb_getopt_ulflags(argc, argv, GET PUT "l:r:" BS,
  426. &localfile, &remotefile BS_ARG);
  427. #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
  428. if(sblocksize) {
  429. blocksize = atoi(sblocksize);
  430. if (!tftp_blocksize_check(blocksize, 0)) {
  431. return EXIT_FAILURE;
  432. }
  433. }
  434. #endif
  435. cmd &= (tftp_cmd_get | tftp_cmd_put);
  436. #ifdef CONFIG_FEATURE_TFTP_GET
  437. if(cmd == tftp_cmd_get)
  438. flags = O_WRONLY | O_CREAT | O_TRUNC;
  439. #endif
  440. #ifdef CONFIG_FEATURE_TFTP_PUT
  441. if(cmd == tftp_cmd_put)
  442. flags = O_RDONLY;
  443. #endif
  444. if(localfile == NULL)
  445. localfile = remotefile;
  446. if(remotefile == NULL)
  447. remotefile = localfile;
  448. /* XXX: I corrected this, but may be wrong too. vodz */
  449. if(localfile==NULL || strcmp(localfile, "-") == 0) {
  450. fd = fileno((cmd==tftp_cmd_get)? stdout : stdin);
  451. } else if (fd==-1) {
  452. fd = open(localfile, flags, 0644);
  453. }
  454. if (fd < 0) {
  455. bb_perror_msg_and_die("local file");
  456. }
  457. /* XXX: argv[optind] and/or argv[optind + 1] may be NULL! */
  458. host = xgethostbyname(argv[optind]);
  459. port = bb_lookup_port(argv[optind + 1], "udp", 69);
  460. #ifdef CONFIG_FEATURE_TFTP_DEBUG
  461. fprintf(stderr, "using server \"%s\", remotefile \"%s\", "
  462. "localfile \"%s\".\n",
  463. inet_ntoa(*((struct in_addr *) host->h_addr)),
  464. remotefile, localfile);
  465. #endif
  466. result = tftp(cmd, host, remotefile, fd, port, blocksize);
  467. #ifdef CONFIG_FEATURE_CLEAN_UP
  468. if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) {
  469. close(fd);
  470. }
  471. #endif
  472. return(result);
  473. }