tftpd.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /* tftpd.c - TFTP server.
  2. *
  3. * Copyright 2013 Ranjan Kumar <ranjankumar.bth@gmail.com>
  4. * Copyright 2013 Kyungwan Han <asura321@gmail.com>
  5. *
  6. * No Standard.
  7. USE_TFTPD(NEWTOY(tftpd, "rcu:l", TOYFLAG_BIN))
  8. config TFTPD
  9. bool "tftpd"
  10. default n
  11. help
  12. usage: tftpd [-cr] [-u USER] [DIR]
  13. Transfer file from/to tftp server.
  14. -r read only
  15. -c Allow file creation via upload
  16. -u run as USER
  17. -l Log to syslog (inetd mode requires this)
  18. */
  19. #define FOR_tftpd
  20. #include "toys.h"
  21. GLOBALS(
  22. char *user;
  23. long sfd;
  24. struct passwd *pw;
  25. )
  26. #define TFTPD_BLKSIZE 512 // as per RFC 1350.
  27. // opcodes
  28. #define TFTPD_OP_RRQ 1 // Read Request RFC 1350, RFC 2090
  29. #define TFTPD_OP_WRQ 2 // Write Request RFC 1350
  30. #define TFTPD_OP_DATA 3 // Data chunk RFC 1350
  31. #define TFTPD_OP_ACK 4 // Acknowledgement RFC 1350
  32. #define TFTPD_OP_ERR 5 // Error Message RFC 1350
  33. #define TFTPD_OP_OACK 6 // Option acknowledgment RFC 2347
  34. // Error Codes:
  35. #define TFTPD_ER_NOSUCHFILE 1 // File not found
  36. #define TFTPD_ER_ACCESS 2 // Access violation
  37. #define TFTPD_ER_FULL 3 // Disk full or allocation exceeded
  38. #define TFTPD_ER_ILLEGALOP 4 // Illegal TFTP operation
  39. #define TFTPD_ER_UNKID 5 // Unknown transfer ID
  40. #define TFTPD_ER_EXISTS 6 // File already exists
  41. #define TFTPD_ER_UNKUSER 7 // No such user
  42. #define TFTPD_ER_NEGOTIATE 8 // Terminate transfer due to option negotiation
  43. /* TFTP Packet Formats
  44. * Type Op # Format without header
  45. * 2 bytes string 1 byte string 1 byte
  46. * -----------------------------------------------
  47. * RRQ/ | 01/02 | Filename | 0 | Mode | 0 |
  48. * WRQ -----------------------------------------------
  49. * 2 bytes 2 bytes n bytes
  50. * ---------------------------------
  51. * DATA | 03 | Block # | Data |
  52. * ---------------------------------
  53. * 2 bytes 2 bytes
  54. * -------------------
  55. * ACK | 04 | Block # |
  56. * --------------------
  57. * 2 bytes 2 bytes string 1 byte
  58. * ----------------------------------------
  59. * ERROR | 05 | ErrorCode | ErrMsg | 0 |
  60. * ----------------------------------------
  61. */
  62. static char *g_errpkt = toybuf + TFTPD_BLKSIZE;
  63. // Create and send error packet.
  64. static void send_errpkt(struct sockaddr *dstaddr,
  65. socklen_t socklen, char *errmsg)
  66. {
  67. error_msg_raw(errmsg);
  68. g_errpkt[1] = TFTPD_OP_ERR;
  69. strcpy(g_errpkt + 4, errmsg);
  70. if (sendto(TT.sfd, g_errpkt, strlen(errmsg)+5, 0, dstaddr, socklen) < 0)
  71. perror_exit("sendto failed");
  72. }
  73. // Advance to the next option or value. Returns NULL if there are no
  74. // more options.
  75. static char *next_token(char *at, char *end)
  76. {
  77. if (at == NULL) return NULL;
  78. for (; at < end; at++) {
  79. if (*at == '\0') {
  80. at++;
  81. break;
  82. }
  83. }
  84. return (at < end) ? at : NULL;
  85. }
  86. // Used to send / receive packets.
  87. static void do_action(struct sockaddr *srcaddr, struct sockaddr *dstaddr,
  88. socklen_t socklen, char *file, int opcode, int tsize, int blksize)
  89. {
  90. int fd, done = 0, retry_count = 12, timeout = 100, len;
  91. uint16_t blockno = 1, pktopcode, rblockno;
  92. char *ptr, *spkt, *rpkt;
  93. struct pollfd pollfds[1];
  94. spkt = xzalloc(blksize + 4);
  95. rpkt = xzalloc(blksize + 4);
  96. ptr = spkt+2; //point after opcode.
  97. pollfds[0].fd = TT.sfd;
  98. // initialize groups, setgid and setuid
  99. if (TT.pw) xsetuser(TT.pw);
  100. if (opcode == TFTPD_OP_RRQ) fd = open(file, O_RDONLY, 0666);
  101. else fd = open(file,
  102. FLAG(c) ? (O_WRONLY|O_TRUNC|O_CREAT) : (O_WRONLY|O_TRUNC), 0666);
  103. if (fd < 0) {
  104. g_errpkt[3] = TFTPD_ER_NOSUCHFILE;
  105. send_errpkt(dstaddr, socklen, "can't open file");
  106. goto CLEAN_APP;
  107. }
  108. // For download -> blockno will be 1.
  109. // 1st ACK will be from dst,which will have blockno-=1
  110. // Create and send ACK packet.
  111. if (blksize != TFTPD_BLKSIZE || tsize) {
  112. pktopcode = TFTPD_OP_OACK;
  113. // add "blksize\000blksize_val\000" in send buffer.
  114. if (blksize != TFTPD_BLKSIZE) {
  115. strcpy(ptr, "blksize");
  116. ptr += strlen("blksize") + 1;
  117. ptr += snprintf(ptr, 6, "%d", blksize) + 1;
  118. }
  119. if (tsize) {// add "tsize\000tsize_val\000" in send buffer.
  120. struct stat sb;
  121. sb.st_size = 0;
  122. fstat(fd, &sb);
  123. strcpy(ptr, "tsize");
  124. ptr += strlen("tsize") + 1;
  125. ptr += sprintf(ptr, "%lu", (unsigned long)sb.st_size)+1;
  126. }
  127. goto SEND_PKT;
  128. }
  129. // upload -> ACK 1st packet with filename, as it has blockno 0.
  130. if (opcode == TFTPD_OP_WRQ) blockno = 0;
  131. // Prepare DATA and/or ACK pkt and send it.
  132. for (;;) {
  133. int poll_ret;
  134. retry_count = 12, timeout = 100, pktopcode = TFTPD_OP_ACK;
  135. ptr = spkt+2;
  136. *((uint16_t*)ptr) = htons(blockno);
  137. blockno++;
  138. ptr += 2;
  139. if (opcode == TFTPD_OP_RRQ) {
  140. pktopcode = TFTPD_OP_DATA;
  141. len = readall(fd, ptr, blksize);
  142. if (len < 0) {
  143. send_errpkt(dstaddr, socklen, "read-error");
  144. break;
  145. }
  146. if (len != blksize) done = 1; //last pkt.
  147. ptr += len;
  148. }
  149. SEND_PKT:
  150. // 1st ACK will be from dst, which will have blockno-=1
  151. *((uint16_t*)spkt) = htons(pktopcode); //append send pkt's opcode.
  152. RETRY_SEND:
  153. if (sendto(TT.sfd, spkt, (ptr - spkt), 0, dstaddr, socklen) <0)
  154. perror_exit("sendto failed");
  155. // if "block size < 512", send ACK and exit.
  156. if ((pktopcode == TFTPD_OP_ACK) && done) break;
  157. POLL_INPUT:
  158. pollfds[0].events = POLLIN;
  159. pollfds[0].fd = TT.sfd;
  160. poll_ret = poll(pollfds, 1, timeout);
  161. if (poll_ret < 0 && (errno == EINTR || errno == ENOMEM)) goto POLL_INPUT;
  162. if (!poll_ret) {
  163. if (!--retry_count) {
  164. error_msg("timeout");
  165. break;
  166. }
  167. timeout += 150;
  168. goto RETRY_SEND;
  169. } else if (poll_ret == 1) {
  170. len = read(pollfds[0].fd, rpkt, blksize + 4);
  171. if (len < 0) {
  172. send_errpkt(dstaddr, socklen, "read-error");
  173. break;
  174. }
  175. if (len < 4) goto POLL_INPUT;
  176. } else {
  177. perror_msg("poll");
  178. break;
  179. }
  180. // Validate receive packet.
  181. pktopcode = ntohs(((uint16_t*)rpkt)[0]);
  182. rblockno = ntohs(((uint16_t*)rpkt)[1]);
  183. if (pktopcode == TFTPD_OP_ERR) {
  184. char *message = "DATA Check failure.";
  185. char *arr[] = {"File not found", "Access violation",
  186. "Disk full or allocation exceeded", "Illegal TFTP operation",
  187. "Unknown transfer ID", "File already exists",
  188. "No such user", "Terminate transfer due to option negotiation"};
  189. if (rblockno && (rblockno < 9)) message = arr[rblockno - 1];
  190. error_msg_raw(message);
  191. break; // Break the for loop.
  192. }
  193. // if download requested by client,
  194. // server will send data pkt and will receive ACK pkt from client.
  195. if ((opcode == TFTPD_OP_RRQ) && (pktopcode == TFTPD_OP_ACK)) {
  196. if (rblockno == (uint16_t) (blockno - 1)) {
  197. if (!done) continue; // Send next chunk of data.
  198. break;
  199. }
  200. }
  201. // server will receive DATA pkt and write the data.
  202. if ((opcode == TFTPD_OP_WRQ) && (pktopcode == TFTPD_OP_DATA)) {
  203. if (rblockno == blockno) {
  204. int nw = writeall(fd, &rpkt[4], len-4);
  205. if (nw != len-4) {
  206. g_errpkt[3] = TFTPD_ER_FULL;
  207. send_errpkt(dstaddr, socklen, "write error");
  208. break;
  209. }
  210. if (nw != blksize) done = 1;
  211. }
  212. continue;
  213. }
  214. goto POLL_INPUT;
  215. } // end of loop
  216. CLEAN_APP:
  217. if (CFG_TOYBOX_FREE) {
  218. free(spkt);
  219. free(rpkt);
  220. close(fd);
  221. }
  222. }
  223. void tftpd_main(void)
  224. {
  225. int fd = 0, recvmsg_len, opcode, blksize = TFTPD_BLKSIZE, tsize = 0, set =1, bflag = 0;
  226. struct sockaddr_storage srcaddr, dstaddr;
  227. socklen_t socklen = sizeof(struct sockaddr_storage);
  228. char *buf = toybuf;
  229. char *end;
  230. memset(&srcaddr, 0, sizeof(srcaddr));
  231. if (getsockname(0, (struct sockaddr *)&srcaddr, &socklen)) help_exit(0);
  232. if (TT.user) TT.pw = xgetpwnam(TT.user);
  233. if (*toys.optargs) xchroot(*toys.optargs);
  234. recvmsg_len = recvfrom(fd, toybuf, blksize, 0, (void *)&dstaddr, &socklen);
  235. end = toybuf + recvmsg_len;
  236. TT.sfd = xsocket(dstaddr.ss_family, SOCK_DGRAM, 0);
  237. if (setsockopt(TT.sfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&set,
  238. sizeof(set)) < 0) perror_exit("setsockopt failed");
  239. xbind(TT.sfd, (void *)&srcaddr, socklen);
  240. xconnect(TT.sfd, (void *)&dstaddr, socklen);
  241. // Error condition.
  242. if (recvmsg_len<4 || recvmsg_len>TFTPD_BLKSIZE || toybuf[recvmsg_len-1]) {
  243. send_errpkt((struct sockaddr*)&dstaddr, socklen, "packet format error");
  244. return;
  245. }
  246. // request is either upload or Download.
  247. opcode = buf[1];
  248. if (((opcode != TFTPD_OP_RRQ) && (opcode != TFTPD_OP_WRQ))
  249. || ((opcode == TFTPD_OP_WRQ) && FLAG(r))) {
  250. send_errpkt((struct sockaddr*)&dstaddr, socklen,
  251. (opcode == TFTPD_OP_WRQ) ? "write error" : "packet format error");
  252. return;
  253. }
  254. buf += 2;
  255. if (*buf == '.' || strstr(buf, "/.")) {
  256. send_errpkt((struct sockaddr*)&dstaddr, socklen, "dot in filename");
  257. return;
  258. }
  259. buf = next_token(buf, end);
  260. // As per RFC 1350, mode is case in-sensitive.
  261. if (buf == NULL || strcasecmp(buf, "octet")) {
  262. send_errpkt((struct sockaddr*)&dstaddr, socklen, "packet format error");
  263. return;
  264. }
  265. //RFC2348. e.g. of size type: "ttype1\0ttype1_val\0...ttypeN\0ttypeN_val\0"
  266. for (buf = next_token(buf, end); buf != NULL; buf = next_token(buf, end)) {
  267. char *opt = buf;
  268. buf = next_token(buf, end);
  269. if (buf == NULL) break; // Missing value.
  270. if (!bflag && !strcasecmp(opt, "blksize")) {
  271. errno = 0;
  272. blksize = strtoul(buf, NULL, 10);
  273. if (errno || blksize > 65564 || blksize < 8) blksize = TFTPD_BLKSIZE;
  274. bflag ^= 1;
  275. } else if (!tsize && !strcasecmp(opt, "tsize")) tsize ^= 1;
  276. }
  277. tsize &= (opcode == TFTPD_OP_RRQ);
  278. //do send / receive file.
  279. do_action((struct sockaddr*)&srcaddr, (struct sockaddr*)&dstaddr,
  280. socklen, toybuf + 2, opcode, tsize, blksize);
  281. if (CFG_TOYBOX_FREE) close(0);
  282. }