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