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