19531f299079699193ea4534144420462f980f4faAshwini Sharma/* tftpd.c - TFTP server. 29531f299079699193ea4534144420462f980f4faAshwini Sharma * 39531f299079699193ea4534144420462f980f4faAshwini Sharma * Copyright 2013 Ranjan Kumar <ranjankumar.bth@gmail.com> 49531f299079699193ea4534144420462f980f4faAshwini Sharma * Copyright 2013 Kyungwan Han <asura321@gmail.com> 59531f299079699193ea4534144420462f980f4faAshwini Sharma * 69531f299079699193ea4534144420462f980f4faAshwini Sharma * No Standard. 79531f299079699193ea4534144420462f980f4faAshwini Sharma 8c8018a263d5e67c57411477fbb1e532d7139a75eRob LandleyUSE_TFTPD(NEWTOY(tftpd, "rcu:l", TOYFLAG_BIN)) 99531f299079699193ea4534144420462f980f4faAshwini Sharma 109531f299079699193ea4534144420462f980f4faAshwini Sharmaconfig TFTPD 119531f299079699193ea4534144420462f980f4faAshwini Sharma bool "tftpd" 12f467297736e8edfa0fee9099243d167074595ab8Rob Landley default n 139531f299079699193ea4534144420462f980f4faAshwini Sharma help 149531f299079699193ea4534144420462f980f4faAshwini Sharma usage: tftpd [-cr] [-u USER] [DIR] 159531f299079699193ea4534144420462f980f4faAshwini Sharma 169531f299079699193ea4534144420462f980f4faAshwini Sharma Transfer file from/to tftp server. 179531f299079699193ea4534144420462f980f4faAshwini Sharma 18f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley -r read only 199531f299079699193ea4534144420462f980f4faAshwini Sharma -c Allow file creation via upload 20f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley -u run as USER 21c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley -l Log to syslog (inetd mode requires this) 229531f299079699193ea4534144420462f980f4faAshwini Sharma*/ 23afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley 249531f299079699193ea4534144420462f980f4faAshwini Sharma#define FOR_tftpd 259531f299079699193ea4534144420462f980f4faAshwini Sharma#include "toys.h" 269531f299079699193ea4534144420462f980f4faAshwini Sharma 279531f299079699193ea4534144420462f980f4faAshwini SharmaGLOBALS( 289531f299079699193ea4534144420462f980f4faAshwini Sharma char *user; 29afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley 309531f299079699193ea4534144420462f980f4faAshwini Sharma long sfd; 319531f299079699193ea4534144420462f980f4faAshwini Sharma struct passwd *pw; 329531f299079699193ea4534144420462f980f4faAshwini Sharma) 339531f299079699193ea4534144420462f980f4faAshwini Sharma 349531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_BLKSIZE 512 // as per RFC 1350. 359531f299079699193ea4534144420462f980f4faAshwini Sharma 369531f299079699193ea4534144420462f980f4faAshwini Sharma// opcodes 379531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_RRQ 1 // Read Request RFC 1350, RFC 2090 389531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_WRQ 2 // Write Request RFC 1350 399531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_DATA 3 // Data chunk RFC 1350 409531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_ACK 4 // Acknowledgement RFC 1350 419531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_ERR 5 // Error Message RFC 1350 429531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_OP_OACK 6 // Option acknowledgment RFC 2347 439531f299079699193ea4534144420462f980f4faAshwini Sharma 449531f299079699193ea4534144420462f980f4faAshwini Sharma// Error Codes: 459531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_NOSUCHFILE 1 // File not found 469531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_ACCESS 2 // Access violation 479531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_FULL 3 // Disk full or allocation exceeded 489531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_ILLEGALOP 4 // Illegal TFTP operation 499531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_UNKID 5 // Unknown transfer ID 509531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_EXISTS 6 // File already exists 519531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_UNKUSER 7 // No such user 529531f299079699193ea4534144420462f980f4faAshwini Sharma#define TFTPD_ER_NEGOTIATE 8 // Terminate transfer due to option negotiation 539531f299079699193ea4534144420462f980f4faAshwini Sharma 549531f299079699193ea4534144420462f980f4faAshwini Sharma/* TFTP Packet Formats 559531f299079699193ea4534144420462f980f4faAshwini Sharma * Type Op # Format without header 569531f299079699193ea4534144420462f980f4faAshwini Sharma * 2 bytes string 1 byte string 1 byte 579531f299079699193ea4534144420462f980f4faAshwini Sharma * ----------------------------------------------- 589531f299079699193ea4534144420462f980f4faAshwini Sharma * RRQ/ | 01/02 | Filename | 0 | Mode | 0 | 599531f299079699193ea4534144420462f980f4faAshwini Sharma * WRQ ----------------------------------------------- 609531f299079699193ea4534144420462f980f4faAshwini Sharma * 2 bytes 2 bytes n bytes 619531f299079699193ea4534144420462f980f4faAshwini Sharma * --------------------------------- 629531f299079699193ea4534144420462f980f4faAshwini Sharma * DATA | 03 | Block # | Data | 639531f299079699193ea4534144420462f980f4faAshwini Sharma * --------------------------------- 649531f299079699193ea4534144420462f980f4faAshwini Sharma * 2 bytes 2 bytes 659531f299079699193ea4534144420462f980f4faAshwini Sharma * ------------------- 669531f299079699193ea4534144420462f980f4faAshwini Sharma * ACK | 04 | Block # | 679531f299079699193ea4534144420462f980f4faAshwini Sharma * -------------------- 689531f299079699193ea4534144420462f980f4faAshwini Sharma * 2 bytes 2 bytes string 1 byte 699531f299079699193ea4534144420462f980f4faAshwini Sharma * ---------------------------------------- 709531f299079699193ea4534144420462f980f4faAshwini Sharma * ERROR | 05 | ErrorCode | ErrMsg | 0 | 719531f299079699193ea4534144420462f980f4faAshwini Sharma * ---------------------------------------- 729531f299079699193ea4534144420462f980f4faAshwini Sharma */ 739531f299079699193ea4534144420462f980f4faAshwini Sharma 74c8018a263d5e67c57411477fbb1e532d7139a75eRob Landleystatic char *g_errpkt = toybuf + TFTPD_BLKSIZE; 759531f299079699193ea4534144420462f980f4faAshwini Sharma 769531f299079699193ea4534144420462f980f4faAshwini Sharma// Create and send error packet. 779531f299079699193ea4534144420462f980f4faAshwini Sharmastatic void send_errpkt(struct sockaddr *dstaddr, 789531f299079699193ea4534144420462f980f4faAshwini Sharma socklen_t socklen, char *errmsg) 799531f299079699193ea4534144420462f980f4faAshwini Sharma{ 809531f299079699193ea4534144420462f980f4faAshwini Sharma error_msg(errmsg); 819531f299079699193ea4534144420462f980f4faAshwini Sharma g_errpkt[1] = TFTPD_OP_ERR; 829531f299079699193ea4534144420462f980f4faAshwini Sharma strcpy(g_errpkt + 4, errmsg); 839531f299079699193ea4534144420462f980f4faAshwini Sharma if (sendto(TT.sfd, g_errpkt, strlen(errmsg)+5, 0, dstaddr, socklen) < 0) 849531f299079699193ea4534144420462f980f4faAshwini Sharma perror_exit("sendto failed"); 859531f299079699193ea4534144420462f980f4faAshwini Sharma} 869531f299079699193ea4534144420462f980f4faAshwini Sharma 879531f299079699193ea4534144420462f980f4faAshwini Sharma// Used to send / receive packets. 889531f299079699193ea4534144420462f980f4faAshwini Sharmastatic void do_action(struct sockaddr *srcaddr, struct sockaddr *dstaddr, 899531f299079699193ea4534144420462f980f4faAshwini Sharma socklen_t socklen, char *file, int opcode, int tsize, int blksize) 909531f299079699193ea4534144420462f980f4faAshwini Sharma{ 919531f299079699193ea4534144420462f980f4faAshwini Sharma int fd, done = 0, retry_count = 12, timeout = 100, len; 929531f299079699193ea4534144420462f980f4faAshwini Sharma uint16_t blockno = 1, pktopcode, rblockno; 939531f299079699193ea4534144420462f980f4faAshwini Sharma char *ptr, *spkt, *rpkt; 949531f299079699193ea4534144420462f980f4faAshwini Sharma struct pollfd pollfds[1]; 959531f299079699193ea4534144420462f980f4faAshwini Sharma 969531f299079699193ea4534144420462f980f4faAshwini Sharma spkt = xzalloc(blksize + 4); 979531f299079699193ea4534144420462f980f4faAshwini Sharma rpkt = xzalloc(blksize + 4); 989531f299079699193ea4534144420462f980f4faAshwini Sharma ptr = spkt+2; //point after opcode. 999531f299079699193ea4534144420462f980f4faAshwini Sharma 1009531f299079699193ea4534144420462f980f4faAshwini Sharma pollfds[0].fd = TT.sfd; 1019531f299079699193ea4534144420462f980f4faAshwini Sharma // initialize groups, setgid and setuid 102afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley if (TT.pw) xsetuser(TT.pw); 1039531f299079699193ea4534144420462f980f4faAshwini Sharma 1049531f299079699193ea4534144420462f980f4faAshwini Sharma if (opcode == TFTPD_OP_RRQ) fd = open(file, O_RDONLY, 0666); 1059531f299079699193ea4534144420462f980f4faAshwini Sharma else fd = open(file, ((toys.optflags & FLAG_c) ? 1069531f299079699193ea4534144420462f980f4faAshwini Sharma (O_WRONLY|O_TRUNC|O_CREAT) : (O_WRONLY|O_TRUNC)) , 0666); 1079531f299079699193ea4534144420462f980f4faAshwini Sharma if (fd < 0) { 1089531f299079699193ea4534144420462f980f4faAshwini Sharma g_errpkt[3] = TFTPD_ER_NOSUCHFILE; 1099531f299079699193ea4534144420462f980f4faAshwini Sharma send_errpkt(dstaddr, socklen, "can't open file"); 1109531f299079699193ea4534144420462f980f4faAshwini Sharma goto CLEAN_APP; 1119531f299079699193ea4534144420462f980f4faAshwini Sharma } 1129531f299079699193ea4534144420462f980f4faAshwini Sharma // For download -> blockno will be 1. 1139531f299079699193ea4534144420462f980f4faAshwini Sharma // 1st ACK will be from dst,which will have blockno-=1 1149531f299079699193ea4534144420462f980f4faAshwini Sharma // Create and send ACK packet. 1159531f299079699193ea4534144420462f980f4faAshwini Sharma if (blksize != TFTPD_BLKSIZE || tsize) { 1169531f299079699193ea4534144420462f980f4faAshwini Sharma pktopcode = TFTPD_OP_OACK; 1179531f299079699193ea4534144420462f980f4faAshwini Sharma // add "blksize\000blksize_val\000" in send buffer. 1189531f299079699193ea4534144420462f980f4faAshwini Sharma if (blksize != TFTPD_BLKSIZE) { 1199531f299079699193ea4534144420462f980f4faAshwini Sharma strcpy(ptr, "blksize"); 1209531f299079699193ea4534144420462f980f4faAshwini Sharma ptr += strlen("blksize") + 1; 1219531f299079699193ea4534144420462f980f4faAshwini Sharma ptr += snprintf(ptr, 6, "%d", blksize) + 1; 1229531f299079699193ea4534144420462f980f4faAshwini Sharma } 1239531f299079699193ea4534144420462f980f4faAshwini Sharma if (tsize) {// add "tsize\000tsize_val\000" in send buffer. 1249531f299079699193ea4534144420462f980f4faAshwini Sharma struct stat sb; 1259531f299079699193ea4534144420462f980f4faAshwini Sharma 1269531f299079699193ea4534144420462f980f4faAshwini Sharma sb.st_size = 0; 1279531f299079699193ea4534144420462f980f4faAshwini Sharma fstat(fd, &sb); 1289531f299079699193ea4534144420462f980f4faAshwini Sharma strcpy(ptr, "tsize"); 1299531f299079699193ea4534144420462f980f4faAshwini Sharma ptr += strlen("tsize") + 1; 1309531f299079699193ea4534144420462f980f4faAshwini Sharma ptr += sprintf(ptr, "%lu", (unsigned long)sb.st_size)+1; 1319531f299079699193ea4534144420462f980f4faAshwini Sharma } 1329531f299079699193ea4534144420462f980f4faAshwini Sharma goto SEND_PKT; 1339531f299079699193ea4534144420462f980f4faAshwini Sharma } 1349531f299079699193ea4534144420462f980f4faAshwini Sharma // upload -> ACK 1st packet with filename, as it has blockno 0. 1359531f299079699193ea4534144420462f980f4faAshwini Sharma if (opcode == TFTPD_OP_WRQ) blockno = 0; 1369531f299079699193ea4534144420462f980f4faAshwini Sharma 1379531f299079699193ea4534144420462f980f4faAshwini Sharma // Prepare DATA and/or ACK pkt and send it. 1389531f299079699193ea4534144420462f980f4faAshwini Sharma for (;;) { 1399531f299079699193ea4534144420462f980f4faAshwini Sharma int poll_ret; 1409531f299079699193ea4534144420462f980f4faAshwini Sharma 1419531f299079699193ea4534144420462f980f4faAshwini Sharma retry_count = 12, timeout = 100, pktopcode = TFTPD_OP_ACK; 1429531f299079699193ea4534144420462f980f4faAshwini Sharma ptr = spkt+2; 1439531f299079699193ea4534144420462f980f4faAshwini Sharma *((uint16_t*)ptr) = htons(blockno); 1449531f299079699193ea4534144420462f980f4faAshwini Sharma blockno++; 1459531f299079699193ea4534144420462f980f4faAshwini Sharma ptr += 2; 1469531f299079699193ea4534144420462f980f4faAshwini Sharma if (opcode == TFTPD_OP_RRQ) { 1479531f299079699193ea4534144420462f980f4faAshwini Sharma pktopcode = TFTPD_OP_DATA; 1489531f299079699193ea4534144420462f980f4faAshwini Sharma len = readall(fd, ptr, blksize); 1499531f299079699193ea4534144420462f980f4faAshwini Sharma if (len < 0) { 1509531f299079699193ea4534144420462f980f4faAshwini Sharma send_errpkt(dstaddr, socklen, "read-error"); 1519531f299079699193ea4534144420462f980f4faAshwini Sharma break; 1529531f299079699193ea4534144420462f980f4faAshwini Sharma } 1539531f299079699193ea4534144420462f980f4faAshwini Sharma if (len != blksize) done = 1; //last pkt. 1549531f299079699193ea4534144420462f980f4faAshwini Sharma ptr += len; 1559531f299079699193ea4534144420462f980f4faAshwini Sharma } 1569531f299079699193ea4534144420462f980f4faAshwini SharmaSEND_PKT: 1579531f299079699193ea4534144420462f980f4faAshwini Sharma // 1st ACK will be from dst, which will have blockno-=1 1589531f299079699193ea4534144420462f980f4faAshwini Sharma *((uint16_t*)spkt) = htons(pktopcode); //append send pkt's opcode. 1599531f299079699193ea4534144420462f980f4faAshwini SharmaRETRY_SEND: 1609531f299079699193ea4534144420462f980f4faAshwini Sharma if (sendto(TT.sfd, spkt, (ptr - spkt), 0, dstaddr, socklen) <0) 1619531f299079699193ea4534144420462f980f4faAshwini Sharma perror_exit("sendto failed"); 1629531f299079699193ea4534144420462f980f4faAshwini Sharma // if "block size < 512", send ACK and exit. 1639531f299079699193ea4534144420462f980f4faAshwini Sharma if ((pktopcode == TFTPD_OP_ACK) && done) break; 1649531f299079699193ea4534144420462f980f4faAshwini Sharma 165afba5b8efdf1bac2c02ca787840a2be053c800f7Rob LandleyPOLL_INPUT: 1669531f299079699193ea4534144420462f980f4faAshwini Sharma pollfds[0].events = POLLIN; 1679531f299079699193ea4534144420462f980f4faAshwini Sharma pollfds[0].fd = TT.sfd; 1689531f299079699193ea4534144420462f980f4faAshwini Sharma poll_ret = poll(pollfds, 1, timeout); 169afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley if (poll_ret < 0 && (errno == EINTR || errno == ENOMEM)) goto POLL_INPUT; 1709531f299079699193ea4534144420462f980f4faAshwini Sharma if (!poll_ret) { 1719531f299079699193ea4534144420462f980f4faAshwini Sharma if (!--retry_count) { 1729531f299079699193ea4534144420462f980f4faAshwini Sharma error_msg("timeout"); 1739531f299079699193ea4534144420462f980f4faAshwini Sharma break; 1749531f299079699193ea4534144420462f980f4faAshwini Sharma } 1759531f299079699193ea4534144420462f980f4faAshwini Sharma timeout += 150; 1769531f299079699193ea4534144420462f980f4faAshwini Sharma goto RETRY_SEND; 1779531f299079699193ea4534144420462f980f4faAshwini Sharma } else if (poll_ret == 1) { 1789531f299079699193ea4534144420462f980f4faAshwini Sharma len = read(pollfds[0].fd, rpkt, blksize + 4); 1799531f299079699193ea4534144420462f980f4faAshwini Sharma if (len < 0) { 1809531f299079699193ea4534144420462f980f4faAshwini Sharma send_errpkt(dstaddr, socklen, "read-error"); 1819531f299079699193ea4534144420462f980f4faAshwini Sharma break; 1829531f299079699193ea4534144420462f980f4faAshwini Sharma } 183afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley if (len < 4) goto POLL_INPUT; 1849531f299079699193ea4534144420462f980f4faAshwini Sharma } else { 1859531f299079699193ea4534144420462f980f4faAshwini Sharma perror_msg("poll"); 1869531f299079699193ea4534144420462f980f4faAshwini Sharma break; 1879531f299079699193ea4534144420462f980f4faAshwini Sharma } 1889531f299079699193ea4534144420462f980f4faAshwini Sharma // Validate receive packet. 1899531f299079699193ea4534144420462f980f4faAshwini Sharma pktopcode = ntohs(((uint16_t*)rpkt)[0]); 1909531f299079699193ea4534144420462f980f4faAshwini Sharma rblockno = ntohs(((uint16_t*)rpkt)[1]); 1919531f299079699193ea4534144420462f980f4faAshwini Sharma if (pktopcode == TFTPD_OP_ERR) { 192c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley char *message = "DATA Check failure."; 193c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley char *arr[] = {"File not found", "Access violation", 194c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley "Disk full or allocation exceeded", "Illegal TFTP operation", 195c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley "Unknown transfer ID", "File already exists", 196c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley "No such user", "Terminate transfer due to option negotiation"}; 197c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley 198c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley if (rblockno && (rblockno < 9)) message = arr[rblockno - 1]; 199c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley error_msg(message); 2009531f299079699193ea4534144420462f980f4faAshwini Sharma break; // Break the for loop. 2019531f299079699193ea4534144420462f980f4faAshwini Sharma } 2029531f299079699193ea4534144420462f980f4faAshwini Sharma 2039531f299079699193ea4534144420462f980f4faAshwini Sharma // if download requested by client, 2049531f299079699193ea4534144420462f980f4faAshwini Sharma // server will send data pkt and will receive ACK pkt from client. 2059531f299079699193ea4534144420462f980f4faAshwini Sharma if ((opcode == TFTPD_OP_RRQ) && (pktopcode == TFTPD_OP_ACK)) { 2069531f299079699193ea4534144420462f980f4faAshwini Sharma if (rblockno == (uint16_t) (blockno - 1)) { 2079531f299079699193ea4534144420462f980f4faAshwini Sharma if (!done) continue; // Send next chunk of data. 2089531f299079699193ea4534144420462f980f4faAshwini Sharma break; 2099531f299079699193ea4534144420462f980f4faAshwini Sharma } 2109531f299079699193ea4534144420462f980f4faAshwini Sharma } 2119531f299079699193ea4534144420462f980f4faAshwini Sharma 2129531f299079699193ea4534144420462f980f4faAshwini Sharma // server will receive DATA pkt and write the data. 2139531f299079699193ea4534144420462f980f4faAshwini Sharma if ((opcode == TFTPD_OP_WRQ) && (pktopcode == TFTPD_OP_DATA)) { 2149531f299079699193ea4534144420462f980f4faAshwini Sharma if (rblockno == blockno) { 2159531f299079699193ea4534144420462f980f4faAshwini Sharma int nw = writeall(fd, &rpkt[4], len-4); 2169531f299079699193ea4534144420462f980f4faAshwini Sharma if (nw != len-4) { 2179531f299079699193ea4534144420462f980f4faAshwini Sharma g_errpkt[3] = TFTPD_ER_FULL; 2189531f299079699193ea4534144420462f980f4faAshwini Sharma send_errpkt(dstaddr, socklen, "write error"); 2199531f299079699193ea4534144420462f980f4faAshwini Sharma break; 2209531f299079699193ea4534144420462f980f4faAshwini Sharma } 2219531f299079699193ea4534144420462f980f4faAshwini Sharma 2229531f299079699193ea4534144420462f980f4faAshwini Sharma if (nw != blksize) done = 1; 2239531f299079699193ea4534144420462f980f4faAshwini Sharma } 2249531f299079699193ea4534144420462f980f4faAshwini Sharma continue; 2259531f299079699193ea4534144420462f980f4faAshwini Sharma } 226afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley goto POLL_INPUT; 2279531f299079699193ea4534144420462f980f4faAshwini Sharma } // end of loop 2289531f299079699193ea4534144420462f980f4faAshwini Sharma 2299531f299079699193ea4534144420462f980f4faAshwini SharmaCLEAN_APP: 2309531f299079699193ea4534144420462f980f4faAshwini Sharma if (CFG_TOYBOX_FREE) { 2319531f299079699193ea4534144420462f980f4faAshwini Sharma free(spkt); 2329531f299079699193ea4534144420462f980f4faAshwini Sharma free(rpkt); 2339531f299079699193ea4534144420462f980f4faAshwini Sharma close(fd); 2349531f299079699193ea4534144420462f980f4faAshwini Sharma } 2359531f299079699193ea4534144420462f980f4faAshwini Sharma} 2369531f299079699193ea4534144420462f980f4faAshwini Sharma 2379531f299079699193ea4534144420462f980f4faAshwini Sharmavoid tftpd_main(void) 2389531f299079699193ea4534144420462f980f4faAshwini Sharma{ 239f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley int fd = 0, recvmsg_len, rbuflen, opcode, blksize = TFTPD_BLKSIZE, tsize = 0, set =1; 2409531f299079699193ea4534144420462f980f4faAshwini Sharma struct sockaddr_storage srcaddr, dstaddr; 241c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley socklen_t socklen = sizeof(struct sockaddr_storage); 242c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley char *buf = toybuf; 2439531f299079699193ea4534144420462f980f4faAshwini Sharma 2449531f299079699193ea4534144420462f980f4faAshwini Sharma memset(&srcaddr, 0, sizeof(srcaddr)); 245afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley if (getsockname(0, (struct sockaddr *)&srcaddr, &socklen)) { 2469531f299079699193ea4534144420462f980f4faAshwini Sharma toys.exithelp = 1; 2479531f299079699193ea4534144420462f980f4faAshwini Sharma error_exit(NULL); 2489531f299079699193ea4534144420462f980f4faAshwini Sharma } 2499531f299079699193ea4534144420462f980f4faAshwini Sharma 2505ec4ab3113dcc813b6040d7ded38e297df99dc0eRob Landley if (TT.user) TT.pw = xgetpwnam(TT.user); 251afba5b8efdf1bac2c02ca787840a2be053c800f7Rob Landley if (*toys.optargs) xchroot(*toys.optargs); 2529531f299079699193ea4534144420462f980f4faAshwini Sharma 253f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley recvmsg_len = recvfrom(fd, toybuf, blksize, 0, (void *)&dstaddr, &socklen); 254c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley 255f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley TT.sfd = xsocket(dstaddr.ss_family, SOCK_DGRAM, 0); 256c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley if (setsockopt(TT.sfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&set, 257c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley sizeof(set)) < 0) perror_exit("setsockopt failed"); 258f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley if (bind(TT.sfd, (void *)&srcaddr, socklen)) perror_exit("bind"); 259f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley if (connect(TT.sfd, (void *)&dstaddr, socklen) < 0) 260c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley perror_exit("can't connect to remote host"); 2619531f299079699193ea4534144420462f980f4faAshwini Sharma // Error condition. 262f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley if (recvmsg_len<4 || recvmsg_len>TFTPD_BLKSIZE || toybuf[recvmsg_len-1]) { 2639531f299079699193ea4534144420462f980f4faAshwini Sharma send_errpkt((struct sockaddr*)&dstaddr, socklen, "packet format error"); 2649531f299079699193ea4534144420462f980f4faAshwini Sharma return; 2659531f299079699193ea4534144420462f980f4faAshwini Sharma } 2669531f299079699193ea4534144420462f980f4faAshwini Sharma 2679531f299079699193ea4534144420462f980f4faAshwini Sharma // request is either upload or Download. 268f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley opcode = buf[1]; 2699531f299079699193ea4534144420462f980f4faAshwini Sharma if (((opcode != TFTPD_OP_RRQ) && (opcode != TFTPD_OP_WRQ)) 2709531f299079699193ea4534144420462f980f4faAshwini Sharma || ((opcode == TFTPD_OP_WRQ) && (toys.optflags & FLAG_r))) { 2719531f299079699193ea4534144420462f980f4faAshwini Sharma send_errpkt((struct sockaddr*)&dstaddr, socklen, 272f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley (opcode == TFTPD_OP_WRQ) ? "write error" : "packet format error"); 2739531f299079699193ea4534144420462f980f4faAshwini Sharma return; 2749531f299079699193ea4534144420462f980f4faAshwini Sharma } 2759531f299079699193ea4534144420462f980f4faAshwini Sharma 2769531f299079699193ea4534144420462f980f4faAshwini Sharma buf += 2; 2779531f299079699193ea4534144420462f980f4faAshwini Sharma if (*buf == '.' || strstr(buf, "/.")) { 2789531f299079699193ea4534144420462f980f4faAshwini Sharma send_errpkt((struct sockaddr*)&dstaddr, socklen, "dot in filename"); 2799531f299079699193ea4534144420462f980f4faAshwini Sharma return; 2809531f299079699193ea4534144420462f980f4faAshwini Sharma } 2819531f299079699193ea4534144420462f980f4faAshwini Sharma 2829531f299079699193ea4534144420462f980f4faAshwini Sharma buf += strlen(buf) + 1; //1 '\0'. 2839531f299079699193ea4534144420462f980f4faAshwini Sharma // As per RFC 1350, mode is case in-sensitive. 284f383983d9868d2f3151b307c5f5bbc506e2f87d6Rob Landley if (buf >= toybuf+recvmsg_len || strcasecmp(buf, "octet")) { 2859531f299079699193ea4534144420462f980f4faAshwini Sharma send_errpkt((struct sockaddr*)&dstaddr, socklen, "packet format error"); 2869531f299079699193ea4534144420462f980f4faAshwini Sharma return; 2879531f299079699193ea4534144420462f980f4faAshwini Sharma } 2889531f299079699193ea4534144420462f980f4faAshwini Sharma 2899531f299079699193ea4534144420462f980f4faAshwini Sharma //RFC2348. e.g. of size type: "ttype1\0ttype1_val\0...ttypeN\0ttypeN_val\0" 2909531f299079699193ea4534144420462f980f4faAshwini Sharma buf += strlen(buf) + 1; 291c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley rbuflen = toybuf + recvmsg_len - buf; 2929531f299079699193ea4534144420462f980f4faAshwini Sharma if (rbuflen) { 2939531f299079699193ea4534144420462f980f4faAshwini Sharma int jump = 0, bflag = 0; 2949531f299079699193ea4534144420462f980f4faAshwini Sharma 2959531f299079699193ea4534144420462f980f4faAshwini Sharma for (; rbuflen; rbuflen -= jump, buf += jump) { 2969531f299079699193ea4534144420462f980f4faAshwini Sharma if (!bflag && !strcasecmp(buf, "blksize")) { //get blksize 2979531f299079699193ea4534144420462f980f4faAshwini Sharma errno = 0; 2989531f299079699193ea4534144420462f980f4faAshwini Sharma blksize = strtoul(buf, NULL, 10); 2999531f299079699193ea4534144420462f980f4faAshwini Sharma if (errno || blksize > 65564 || blksize < 8) blksize = TFTPD_BLKSIZE; 3009531f299079699193ea4534144420462f980f4faAshwini Sharma bflag ^= 1; 3019531f299079699193ea4534144420462f980f4faAshwini Sharma } else if (!tsize && !strcasecmp(buf, "tsize")) tsize ^= 1; 3029531f299079699193ea4534144420462f980f4faAshwini Sharma 3039531f299079699193ea4534144420462f980f4faAshwini Sharma jump += strlen(buf) + 1; 3049531f299079699193ea4534144420462f980f4faAshwini Sharma } 3059531f299079699193ea4534144420462f980f4faAshwini Sharma tsize &= (opcode == TFTPD_OP_RRQ); 3069531f299079699193ea4534144420462f980f4faAshwini Sharma } 3079531f299079699193ea4534144420462f980f4faAshwini Sharma 3089531f299079699193ea4534144420462f980f4faAshwini Sharma //do send / receive file. 3099531f299079699193ea4534144420462f980f4faAshwini Sharma do_action((struct sockaddr*)&srcaddr, (struct sockaddr*)&dstaddr, 310c8018a263d5e67c57411477fbb1e532d7139a75eRob Landley socklen, toybuf + 2, opcode, tsize, blksize); 3119531f299079699193ea4534144420462f980f4faAshwini Sharma if (CFG_TOYBOX_FREE) close(STDIN_FILENO); 3129531f299079699193ea4534144420462f980f4faAshwini Sharma} 313