3
0

tftp.c 13 KB

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