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
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.
send_errpkt(struct sockaddr * dstaddr,socklen_t socklen,char * errmsg)77 static void send_errpkt(struct sockaddr *dstaddr,
78 socklen_t socklen, char *errmsg)
79 {
80 error_msg_raw(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 // Advance to the next option or value. Returns NULL if there are no
88 // more options.
next_token(char * at,char * end)89 static char *next_token(char *at, char *end)
90 {
91 if (at == NULL) return NULL;
92
93 for (; at < end; at++) {
94 if (*at == '\0') {
95 at++;
96 break;
97 }
98 }
99 return (at < end) ? at : NULL;
100 }
101
102 // Used to send / receive packets.
do_action(struct sockaddr * srcaddr,struct sockaddr * dstaddr,socklen_t socklen,char * file,int opcode,int tsize,int blksize)103 static void do_action(struct sockaddr *srcaddr, struct sockaddr *dstaddr,
104 socklen_t socklen, char *file, int opcode, int tsize, int blksize)
105 {
106 int fd, done = 0, retry_count = 12, timeout = 100, len;
107 uint16_t blockno = 1, pktopcode, rblockno;
108 char *ptr, *spkt, *rpkt;
109 struct pollfd pollfds[1];
110
111 spkt = xzalloc(blksize + 4);
112 rpkt = xzalloc(blksize + 4);
113 ptr = spkt+2; //point after opcode.
114
115 pollfds[0].fd = TT.sfd;
116 // initialize groups, setgid and setuid
117 if (TT.pw) xsetuser(TT.pw);
118
119 if (opcode == TFTPD_OP_RRQ) fd = open(file, O_RDONLY, 0666);
120 else fd = open(file,
121 FLAG(c) ? (O_WRONLY|O_TRUNC|O_CREAT) : (O_WRONLY|O_TRUNC), 0666);
122 if (fd < 0) {
123 g_errpkt[3] = TFTPD_ER_NOSUCHFILE;
124 send_errpkt(dstaddr, socklen, "can't open file");
125 goto CLEAN_APP;
126 }
127 // For download -> blockno will be 1.
128 // 1st ACK will be from dst,which will have blockno-=1
129 // Create and send ACK packet.
130 if (blksize != TFTPD_BLKSIZE || tsize) {
131 pktopcode = TFTPD_OP_OACK;
132 // add "blksize\000blksize_val\000" in send buffer.
133 if (blksize != TFTPD_BLKSIZE) {
134 strcpy(ptr, "blksize");
135 ptr += strlen("blksize") + 1;
136 ptr += snprintf(ptr, 6, "%d", blksize) + 1;
137 }
138 if (tsize) {// add "tsize\000tsize_val\000" in send buffer.
139 struct stat sb;
140
141 sb.st_size = 0;
142 fstat(fd, &sb);
143 strcpy(ptr, "tsize");
144 ptr += strlen("tsize") + 1;
145 ptr += sprintf(ptr, "%lu", (unsigned long)sb.st_size)+1;
146 }
147 goto SEND_PKT;
148 }
149 // upload -> ACK 1st packet with filename, as it has blockno 0.
150 if (opcode == TFTPD_OP_WRQ) blockno = 0;
151
152 // Prepare DATA and/or ACK pkt and send it.
153 for (;;) {
154 int poll_ret;
155
156 retry_count = 12, timeout = 100, pktopcode = TFTPD_OP_ACK;
157 ptr = spkt+2;
158 *((uint16_t*)ptr) = htons(blockno);
159 blockno++;
160 ptr += 2;
161 if (opcode == TFTPD_OP_RRQ) {
162 pktopcode = TFTPD_OP_DATA;
163 len = readall(fd, ptr, blksize);
164 if (len < 0) {
165 send_errpkt(dstaddr, socklen, "read-error");
166 break;
167 }
168 if (len != blksize) done = 1; //last pkt.
169 ptr += len;
170 }
171 SEND_PKT:
172 // 1st ACK will be from dst, which will have blockno-=1
173 *((uint16_t*)spkt) = htons(pktopcode); //append send pkt's opcode.
174 RETRY_SEND:
175 if (sendto(TT.sfd, spkt, (ptr - spkt), 0, dstaddr, socklen) <0)
176 perror_exit("sendto failed");
177 // if "block size < 512", send ACK and exit.
178 if ((pktopcode == TFTPD_OP_ACK) && done) break;
179
180 POLL_INPUT:
181 pollfds[0].events = POLLIN;
182 pollfds[0].fd = TT.sfd;
183 poll_ret = poll(pollfds, 1, timeout);
184 if (poll_ret < 0 && (errno == EINTR || errno == ENOMEM)) goto POLL_INPUT;
185 if (!poll_ret) {
186 if (!--retry_count) {
187 error_msg("timeout");
188 break;
189 }
190 timeout += 150;
191 goto RETRY_SEND;
192 } else if (poll_ret == 1) {
193 len = read(pollfds[0].fd, rpkt, blksize + 4);
194 if (len < 0) {
195 send_errpkt(dstaddr, socklen, "read-error");
196 break;
197 }
198 if (len < 4) goto POLL_INPUT;
199 } else {
200 perror_msg("poll");
201 break;
202 }
203 // Validate receive packet.
204 pktopcode = ntohs(((uint16_t*)rpkt)[0]);
205 rblockno = ntohs(((uint16_t*)rpkt)[1]);
206 if (pktopcode == TFTPD_OP_ERR) {
207 char *message = "DATA Check failure.";
208 char *arr[] = {"File not found", "Access violation",
209 "Disk full or allocation exceeded", "Illegal TFTP operation",
210 "Unknown transfer ID", "File already exists",
211 "No such user", "Terminate transfer due to option negotiation"};
212
213 if (rblockno && (rblockno < 9)) message = arr[rblockno - 1];
214 error_msg_raw(message);
215 break; // Break the for loop.
216 }
217
218 // if download requested by client,
219 // server will send data pkt and will receive ACK pkt from client.
220 if ((opcode == TFTPD_OP_RRQ) && (pktopcode == TFTPD_OP_ACK)) {
221 if (rblockno == (uint16_t) (blockno - 1)) {
222 if (!done) continue; // Send next chunk of data.
223 break;
224 }
225 }
226
227 // server will receive DATA pkt and write the data.
228 if ((opcode == TFTPD_OP_WRQ) && (pktopcode == TFTPD_OP_DATA)) {
229 if (rblockno == blockno) {
230 int nw = writeall(fd, &rpkt[4], len-4);
231 if (nw != len-4) {
232 g_errpkt[3] = TFTPD_ER_FULL;
233 send_errpkt(dstaddr, socklen, "write error");
234 break;
235 }
236
237 if (nw != blksize) done = 1;
238 }
239 continue;
240 }
241 goto POLL_INPUT;
242 } // end of loop
243
244 CLEAN_APP:
245 if (CFG_TOYBOX_FREE) {
246 free(spkt);
247 free(rpkt);
248 close(fd);
249 }
250 }
251
tftpd_main(void)252 void tftpd_main(void)
253 {
254 int fd = 0, recvmsg_len, opcode, blksize = TFTPD_BLKSIZE, tsize = 0, set =1, bflag = 0;
255 struct sockaddr_storage srcaddr, dstaddr;
256 socklen_t socklen = sizeof(struct sockaddr_storage);
257 char *buf = toybuf;
258 char *end;
259
260 memset(&srcaddr, 0, sizeof(srcaddr));
261 if (getsockname(0, (struct sockaddr *)&srcaddr, &socklen)) help_exit(0);
262
263 if (TT.user) TT.pw = xgetpwnam(TT.user);
264 if (*toys.optargs) xchroot(*toys.optargs);
265
266 recvmsg_len = recvfrom(fd, toybuf, blksize, 0, (void *)&dstaddr, &socklen);
267 end = toybuf + recvmsg_len;
268
269 TT.sfd = xsocket(dstaddr.ss_family, SOCK_DGRAM, 0);
270 if (setsockopt(TT.sfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&set,
271 sizeof(set)) < 0) perror_exit("setsockopt failed");
272 xbind(TT.sfd, (void *)&srcaddr, socklen);
273 xconnect(TT.sfd, (void *)&dstaddr, socklen);
274 // Error condition.
275 if (recvmsg_len<4 || recvmsg_len>TFTPD_BLKSIZE || toybuf[recvmsg_len-1]) {
276 send_errpkt((struct sockaddr*)&dstaddr, socklen, "packet format error");
277 return;
278 }
279
280 // request is either upload or Download.
281 opcode = buf[1];
282 if (((opcode != TFTPD_OP_RRQ) && (opcode != TFTPD_OP_WRQ))
283 || ((opcode == TFTPD_OP_WRQ) && FLAG(r))) {
284 send_errpkt((struct sockaddr*)&dstaddr, socklen,
285 (opcode == TFTPD_OP_WRQ) ? "write error" : "packet format error");
286 return;
287 }
288
289 buf += 2;
290 if (*buf == '.' || strstr(buf, "/.")) {
291 send_errpkt((struct sockaddr*)&dstaddr, socklen, "dot in filename");
292 return;
293 }
294
295 buf = next_token(buf, end);
296 // As per RFC 1350, mode is case in-sensitive.
297 if (buf == NULL || strcasecmp(buf, "octet")) {
298 send_errpkt((struct sockaddr*)&dstaddr, socklen, "packet format error");
299 return;
300 }
301
302 //RFC2348. e.g. of size type: "ttype1\0ttype1_val\0...ttypeN\0ttypeN_val\0"
303 for (buf = next_token(buf, end); buf != NULL; buf = next_token(buf, end)) {
304 char *opt = buf;
305 buf = next_token(buf, end);
306 if (buf == NULL) break; // Missing value.
307
308 if (!bflag && !strcasecmp(opt, "blksize")) {
309 errno = 0;
310 blksize = strtoul(buf, NULL, 10);
311 if (errno || blksize > 65564 || blksize < 8) blksize = TFTPD_BLKSIZE;
312 bflag ^= 1;
313 } else if (!tsize && !strcasecmp(opt, "tsize")) tsize ^= 1;
314 }
315
316 tsize &= (opcode == TFTPD_OP_RRQ);
317
318 //do send / receive file.
319 do_action((struct sockaddr*)&srcaddr, (struct sockaddr*)&dstaddr,
320 socklen, toybuf + 2, opcode, tsize, blksize);
321 if (CFG_TOYBOX_FREE) close(0);
322 }
323