1*bd1f8aebSAndroid Build Coastguard Worker /*
2*bd1f8aebSAndroid Build Coastguard Worker * Copyright (c) 1983 Regents of the University of California.
3*bd1f8aebSAndroid Build Coastguard Worker * All rights reserved.
4*bd1f8aebSAndroid Build Coastguard Worker *
5*bd1f8aebSAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*bd1f8aebSAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
7*bd1f8aebSAndroid Build Coastguard Worker * are met:
8*bd1f8aebSAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
9*bd1f8aebSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
10*bd1f8aebSAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
11*bd1f8aebSAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
12*bd1f8aebSAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
13*bd1f8aebSAndroid Build Coastguard Worker * 3. All advertising materials mentioning features or use of this software
14*bd1f8aebSAndroid Build Coastguard Worker * must display the following acknowledgement:
15*bd1f8aebSAndroid Build Coastguard Worker * This product includes software developed by the University of
16*bd1f8aebSAndroid Build Coastguard Worker * California, Berkeley and its contributors.
17*bd1f8aebSAndroid Build Coastguard Worker * 4. Neither the name of the University nor the names of its contributors
18*bd1f8aebSAndroid Build Coastguard Worker * may be used to endorse or promote products derived from this software
19*bd1f8aebSAndroid Build Coastguard Worker * without specific prior written permission.
20*bd1f8aebSAndroid Build Coastguard Worker *
21*bd1f8aebSAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22*bd1f8aebSAndroid Build Coastguard Worker * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*bd1f8aebSAndroid Build Coastguard Worker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*bd1f8aebSAndroid Build Coastguard Worker * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25*bd1f8aebSAndroid Build Coastguard Worker * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*bd1f8aebSAndroid Build Coastguard Worker * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27*bd1f8aebSAndroid Build Coastguard Worker * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*bd1f8aebSAndroid Build Coastguard Worker * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29*bd1f8aebSAndroid Build Coastguard Worker * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30*bd1f8aebSAndroid Build Coastguard Worker * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*bd1f8aebSAndroid Build Coastguard Worker * SUCH DAMAGE.
32*bd1f8aebSAndroid Build Coastguard Worker */
33*bd1f8aebSAndroid Build Coastguard Worker
34*bd1f8aebSAndroid Build Coastguard Worker #ifndef lint
35*bd1f8aebSAndroid Build Coastguard Worker char copyright[] =
36*bd1f8aebSAndroid Build Coastguard Worker "@(#) Copyright (c) 1983 Regents of the University of California.\n\
37*bd1f8aebSAndroid Build Coastguard Worker All rights reserved.\n";
38*bd1f8aebSAndroid Build Coastguard Worker #endif /* not lint */
39*bd1f8aebSAndroid Build Coastguard Worker
40*bd1f8aebSAndroid Build Coastguard Worker #ifndef lint
41*bd1f8aebSAndroid Build Coastguard Worker /*static char sccsid[] = "from: @(#)tftpd.c 5.13 (Berkeley) 2/26/91";*/
42*bd1f8aebSAndroid Build Coastguard Worker /*static char rcsid[] = "$Id: tftpd.c,v 1.3 1993/08/01 18:28:53 mycroft Exp $";*/
43*bd1f8aebSAndroid Build Coastguard Worker #endif /* not lint */
44*bd1f8aebSAndroid Build Coastguard Worker
45*bd1f8aebSAndroid Build Coastguard Worker /*
46*bd1f8aebSAndroid Build Coastguard Worker * Trivial file transfer protocol server.
47*bd1f8aebSAndroid Build Coastguard Worker *
48*bd1f8aebSAndroid Build Coastguard Worker * This version includes many modifications by Jim Guyton <guyton@rand-unix>
49*bd1f8aebSAndroid Build Coastguard Worker */
50*bd1f8aebSAndroid Build Coastguard Worker
51*bd1f8aebSAndroid Build Coastguard Worker #include <sys/types.h>
52*bd1f8aebSAndroid Build Coastguard Worker #include <sys/ioctl.h>
53*bd1f8aebSAndroid Build Coastguard Worker #include <sys/stat.h>
54*bd1f8aebSAndroid Build Coastguard Worker #include <unistd.h>
55*bd1f8aebSAndroid Build Coastguard Worker #include <signal.h>
56*bd1f8aebSAndroid Build Coastguard Worker #include <fcntl.h>
57*bd1f8aebSAndroid Build Coastguard Worker
58*bd1f8aebSAndroid Build Coastguard Worker #include <sys/socket.h>
59*bd1f8aebSAndroid Build Coastguard Worker #include <netinet/in.h>
60*bd1f8aebSAndroid Build Coastguard Worker #include <netdb.h>
61*bd1f8aebSAndroid Build Coastguard Worker
62*bd1f8aebSAndroid Build Coastguard Worker #include <setjmp.h>
63*bd1f8aebSAndroid Build Coastguard Worker #include <syslog.h>
64*bd1f8aebSAndroid Build Coastguard Worker #include <stdio.h>
65*bd1f8aebSAndroid Build Coastguard Worker #include <errno.h>
66*bd1f8aebSAndroid Build Coastguard Worker #include <ctype.h>
67*bd1f8aebSAndroid Build Coastguard Worker #include <string.h>
68*bd1f8aebSAndroid Build Coastguard Worker #include <stdlib.h>
69*bd1f8aebSAndroid Build Coastguard Worker
70*bd1f8aebSAndroid Build Coastguard Worker #include "tftp.h"
71*bd1f8aebSAndroid Build Coastguard Worker
72*bd1f8aebSAndroid Build Coastguard Worker #ifndef MSG_CONFIRM
73*bd1f8aebSAndroid Build Coastguard Worker #define MSG_CONFIRM 0
74*bd1f8aebSAndroid Build Coastguard Worker #warning Please, upgrade kernel, otherwise this tftpd has no advantages.
75*bd1f8aebSAndroid Build Coastguard Worker #endif
76*bd1f8aebSAndroid Build Coastguard Worker
77*bd1f8aebSAndroid Build Coastguard Worker #define TIMEOUT 5
78*bd1f8aebSAndroid Build Coastguard Worker
79*bd1f8aebSAndroid Build Coastguard Worker int peer;
80*bd1f8aebSAndroid Build Coastguard Worker int rexmtval = TIMEOUT;
81*bd1f8aebSAndroid Build Coastguard Worker int maxtimeout = 5*TIMEOUT;
82*bd1f8aebSAndroid Build Coastguard Worker
83*bd1f8aebSAndroid Build Coastguard Worker #define PKTSIZE SEGSIZE+4
84*bd1f8aebSAndroid Build Coastguard Worker char buf[PKTSIZE];
85*bd1f8aebSAndroid Build Coastguard Worker char ackbuf[PKTSIZE];
86*bd1f8aebSAndroid Build Coastguard Worker union {
87*bd1f8aebSAndroid Build Coastguard Worker struct sockaddr sa;
88*bd1f8aebSAndroid Build Coastguard Worker struct sockaddr_in sin;
89*bd1f8aebSAndroid Build Coastguard Worker struct sockaddr_in6 sin6;
90*bd1f8aebSAndroid Build Coastguard Worker } from;
91*bd1f8aebSAndroid Build Coastguard Worker socklen_t fromlen;
92*bd1f8aebSAndroid Build Coastguard Worker
93*bd1f8aebSAndroid Build Coastguard Worker #define MAXARG 1
94*bd1f8aebSAndroid Build Coastguard Worker char *dirs[MAXARG+1];
95*bd1f8aebSAndroid Build Coastguard Worker
96*bd1f8aebSAndroid Build Coastguard Worker void tftp(struct tftphdr *tp, int size) __attribute__((noreturn));
97*bd1f8aebSAndroid Build Coastguard Worker void nak(int error);
98*bd1f8aebSAndroid Build Coastguard Worker int validate_access(char *filename, int mode);
99*bd1f8aebSAndroid Build Coastguard Worker
100*bd1f8aebSAndroid Build Coastguard Worker struct formats;
101*bd1f8aebSAndroid Build Coastguard Worker
102*bd1f8aebSAndroid Build Coastguard Worker void sendfile(struct formats *pf);
103*bd1f8aebSAndroid Build Coastguard Worker void recvfile(struct formats *pf);
104*bd1f8aebSAndroid Build Coastguard Worker
105*bd1f8aebSAndroid Build Coastguard Worker
main(int ac,char ** av)106*bd1f8aebSAndroid Build Coastguard Worker int main(int ac, char **av)
107*bd1f8aebSAndroid Build Coastguard Worker {
108*bd1f8aebSAndroid Build Coastguard Worker register struct tftphdr *tp;
109*bd1f8aebSAndroid Build Coastguard Worker register int n = 0;
110*bd1f8aebSAndroid Build Coastguard Worker int on = 1;
111*bd1f8aebSAndroid Build Coastguard Worker
112*bd1f8aebSAndroid Build Coastguard Worker /* Sanity. If parent forgot to setuid() on us. */
113*bd1f8aebSAndroid Build Coastguard Worker if (geteuid() == 0) {
114*bd1f8aebSAndroid Build Coastguard Worker setgid(65534);
115*bd1f8aebSAndroid Build Coastguard Worker setuid(65534);
116*bd1f8aebSAndroid Build Coastguard Worker }
117*bd1f8aebSAndroid Build Coastguard Worker
118*bd1f8aebSAndroid Build Coastguard Worker ac--; av++;
119*bd1f8aebSAndroid Build Coastguard Worker while (ac-- > 0 && n < MAXARG)
120*bd1f8aebSAndroid Build Coastguard Worker dirs[n++] = *av++;
121*bd1f8aebSAndroid Build Coastguard Worker
122*bd1f8aebSAndroid Build Coastguard Worker openlog("tftpd", LOG_PID, LOG_DAEMON);
123*bd1f8aebSAndroid Build Coastguard Worker if (ioctl(0, FIONBIO, &on) < 0) {
124*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
125*bd1f8aebSAndroid Build Coastguard Worker exit(1);
126*bd1f8aebSAndroid Build Coastguard Worker }
127*bd1f8aebSAndroid Build Coastguard Worker fromlen = sizeof (from);
128*bd1f8aebSAndroid Build Coastguard Worker n = recvfrom(0, buf, sizeof (buf), 0,
129*bd1f8aebSAndroid Build Coastguard Worker (struct sockaddr *)&from, &fromlen);
130*bd1f8aebSAndroid Build Coastguard Worker if (n < 0) {
131*bd1f8aebSAndroid Build Coastguard Worker if (errno != EAGAIN)
132*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "recvfrom: %m\n");
133*bd1f8aebSAndroid Build Coastguard Worker exit(1);
134*bd1f8aebSAndroid Build Coastguard Worker }
135*bd1f8aebSAndroid Build Coastguard Worker /*
136*bd1f8aebSAndroid Build Coastguard Worker * Now that we have read the message out of the UDP
137*bd1f8aebSAndroid Build Coastguard Worker * socket, we fork and exit. Thus, inetd will go back
138*bd1f8aebSAndroid Build Coastguard Worker * to listening to the tftp port, and the next request
139*bd1f8aebSAndroid Build Coastguard Worker * to come in will start up a new instance of tftpd.
140*bd1f8aebSAndroid Build Coastguard Worker *
141*bd1f8aebSAndroid Build Coastguard Worker * We do this so that inetd can run tftpd in "wait" mode.
142*bd1f8aebSAndroid Build Coastguard Worker * The problem with tftpd running in "nowait" mode is that
143*bd1f8aebSAndroid Build Coastguard Worker * inetd may get one or more successful "selects" on the
144*bd1f8aebSAndroid Build Coastguard Worker * tftp port before we do our receive, so more than one
145*bd1f8aebSAndroid Build Coastguard Worker * instance of tftpd may be started up. Worse, if tftpd
146*bd1f8aebSAndroid Build Coastguard Worker * break before doing the above "recvfrom", inetd would
147*bd1f8aebSAndroid Build Coastguard Worker * spawn endless instances, clogging the system.
148*bd1f8aebSAndroid Build Coastguard Worker */
149*bd1f8aebSAndroid Build Coastguard Worker {
150*bd1f8aebSAndroid Build Coastguard Worker int pid;
151*bd1f8aebSAndroid Build Coastguard Worker int i;
152*bd1f8aebSAndroid Build Coastguard Worker socklen_t j;
153*bd1f8aebSAndroid Build Coastguard Worker
154*bd1f8aebSAndroid Build Coastguard Worker for (i = 1; i < 20; i++) {
155*bd1f8aebSAndroid Build Coastguard Worker pid = fork();
156*bd1f8aebSAndroid Build Coastguard Worker if (pid < 0) {
157*bd1f8aebSAndroid Build Coastguard Worker sleep(i);
158*bd1f8aebSAndroid Build Coastguard Worker /*
159*bd1f8aebSAndroid Build Coastguard Worker * flush out to most recently sent request.
160*bd1f8aebSAndroid Build Coastguard Worker *
161*bd1f8aebSAndroid Build Coastguard Worker * This may drop some request, but those
162*bd1f8aebSAndroid Build Coastguard Worker * will be resent by the clients when
163*bd1f8aebSAndroid Build Coastguard Worker * they timeout. The positive effect of
164*bd1f8aebSAndroid Build Coastguard Worker * this flush is to (try to) prevent more
165*bd1f8aebSAndroid Build Coastguard Worker * than one tftpd being started up to service
166*bd1f8aebSAndroid Build Coastguard Worker * a single request from a single client.
167*bd1f8aebSAndroid Build Coastguard Worker */
168*bd1f8aebSAndroid Build Coastguard Worker j = sizeof from;
169*bd1f8aebSAndroid Build Coastguard Worker i = recvfrom(0, buf, sizeof (buf), 0,
170*bd1f8aebSAndroid Build Coastguard Worker (struct sockaddr *)&from, &j);
171*bd1f8aebSAndroid Build Coastguard Worker if (i > 0) {
172*bd1f8aebSAndroid Build Coastguard Worker n = i;
173*bd1f8aebSAndroid Build Coastguard Worker fromlen = j;
174*bd1f8aebSAndroid Build Coastguard Worker }
175*bd1f8aebSAndroid Build Coastguard Worker } else {
176*bd1f8aebSAndroid Build Coastguard Worker break;
177*bd1f8aebSAndroid Build Coastguard Worker }
178*bd1f8aebSAndroid Build Coastguard Worker }
179*bd1f8aebSAndroid Build Coastguard Worker if (pid < 0) {
180*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "fork: %m\n");
181*bd1f8aebSAndroid Build Coastguard Worker exit(1);
182*bd1f8aebSAndroid Build Coastguard Worker } else if (pid != 0) {
183*bd1f8aebSAndroid Build Coastguard Worker exit(0);
184*bd1f8aebSAndroid Build Coastguard Worker }
185*bd1f8aebSAndroid Build Coastguard Worker }
186*bd1f8aebSAndroid Build Coastguard Worker alarm(0);
187*bd1f8aebSAndroid Build Coastguard Worker close(0);
188*bd1f8aebSAndroid Build Coastguard Worker close(1);
189*bd1f8aebSAndroid Build Coastguard Worker peer = socket(from.sa.sa_family, SOCK_DGRAM, 0);
190*bd1f8aebSAndroid Build Coastguard Worker if (peer < 0) {
191*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "socket: %m\n");
192*bd1f8aebSAndroid Build Coastguard Worker exit(1);
193*bd1f8aebSAndroid Build Coastguard Worker }
194*bd1f8aebSAndroid Build Coastguard Worker if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
195*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "connect: %m\n");
196*bd1f8aebSAndroid Build Coastguard Worker exit(1);
197*bd1f8aebSAndroid Build Coastguard Worker }
198*bd1f8aebSAndroid Build Coastguard Worker tp = (struct tftphdr *)buf;
199*bd1f8aebSAndroid Build Coastguard Worker tp->th_opcode = ntohs(tp->th_opcode);
200*bd1f8aebSAndroid Build Coastguard Worker if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
201*bd1f8aebSAndroid Build Coastguard Worker tftp(tp, n);
202*bd1f8aebSAndroid Build Coastguard Worker exit(1);
203*bd1f8aebSAndroid Build Coastguard Worker }
204*bd1f8aebSAndroid Build Coastguard Worker
205*bd1f8aebSAndroid Build Coastguard Worker struct formats {
206*bd1f8aebSAndroid Build Coastguard Worker char *f_mode;
207*bd1f8aebSAndroid Build Coastguard Worker int (*f_validate)(char *filename, int mode);
208*bd1f8aebSAndroid Build Coastguard Worker void (*f_send)(struct formats*);
209*bd1f8aebSAndroid Build Coastguard Worker void (*f_recv)(struct formats*);
210*bd1f8aebSAndroid Build Coastguard Worker int f_convert;
211*bd1f8aebSAndroid Build Coastguard Worker } formats[] = {
212*bd1f8aebSAndroid Build Coastguard Worker { "netascii", validate_access, sendfile, recvfile, 1 },
213*bd1f8aebSAndroid Build Coastguard Worker { "octet", validate_access, sendfile, recvfile, 0 },
214*bd1f8aebSAndroid Build Coastguard Worker #ifdef notdef
215*bd1f8aebSAndroid Build Coastguard Worker { "mail", validate_user, sendmail, recvmail, 1 },
216*bd1f8aebSAndroid Build Coastguard Worker #endif
217*bd1f8aebSAndroid Build Coastguard Worker { 0 }
218*bd1f8aebSAndroid Build Coastguard Worker };
219*bd1f8aebSAndroid Build Coastguard Worker
220*bd1f8aebSAndroid Build Coastguard Worker /*
221*bd1f8aebSAndroid Build Coastguard Worker * Handle initial connection protocol.
222*bd1f8aebSAndroid Build Coastguard Worker */
tftp(struct tftphdr * tp,int size)223*bd1f8aebSAndroid Build Coastguard Worker void tftp(struct tftphdr *tp, int size)
224*bd1f8aebSAndroid Build Coastguard Worker {
225*bd1f8aebSAndroid Build Coastguard Worker register char *cp;
226*bd1f8aebSAndroid Build Coastguard Worker int first = 1, ecode;
227*bd1f8aebSAndroid Build Coastguard Worker register struct formats *pf;
228*bd1f8aebSAndroid Build Coastguard Worker char *filename, *mode = NULL;
229*bd1f8aebSAndroid Build Coastguard Worker
230*bd1f8aebSAndroid Build Coastguard Worker filename = cp = tp->th_stuff;
231*bd1f8aebSAndroid Build Coastguard Worker again:
232*bd1f8aebSAndroid Build Coastguard Worker while (cp < buf + size) {
233*bd1f8aebSAndroid Build Coastguard Worker if (*cp == '\0')
234*bd1f8aebSAndroid Build Coastguard Worker break;
235*bd1f8aebSAndroid Build Coastguard Worker cp++;
236*bd1f8aebSAndroid Build Coastguard Worker }
237*bd1f8aebSAndroid Build Coastguard Worker if (*cp != '\0') {
238*bd1f8aebSAndroid Build Coastguard Worker nak(EBADOP);
239*bd1f8aebSAndroid Build Coastguard Worker exit(1);
240*bd1f8aebSAndroid Build Coastguard Worker }
241*bd1f8aebSAndroid Build Coastguard Worker if (first) {
242*bd1f8aebSAndroid Build Coastguard Worker mode = ++cp;
243*bd1f8aebSAndroid Build Coastguard Worker first = 0;
244*bd1f8aebSAndroid Build Coastguard Worker goto again;
245*bd1f8aebSAndroid Build Coastguard Worker }
246*bd1f8aebSAndroid Build Coastguard Worker for (cp = mode; *cp; cp++)
247*bd1f8aebSAndroid Build Coastguard Worker if (isupper(*cp))
248*bd1f8aebSAndroid Build Coastguard Worker *cp = tolower(*cp);
249*bd1f8aebSAndroid Build Coastguard Worker for (pf = formats; pf->f_mode; pf++)
250*bd1f8aebSAndroid Build Coastguard Worker if (strcmp(pf->f_mode, mode) == 0)
251*bd1f8aebSAndroid Build Coastguard Worker break;
252*bd1f8aebSAndroid Build Coastguard Worker if (pf->f_mode == 0) {
253*bd1f8aebSAndroid Build Coastguard Worker nak(EBADOP);
254*bd1f8aebSAndroid Build Coastguard Worker exit(1);
255*bd1f8aebSAndroid Build Coastguard Worker }
256*bd1f8aebSAndroid Build Coastguard Worker ecode = (*pf->f_validate)(filename, tp->th_opcode);
257*bd1f8aebSAndroid Build Coastguard Worker if (ecode) {
258*bd1f8aebSAndroid Build Coastguard Worker nak(ecode);
259*bd1f8aebSAndroid Build Coastguard Worker exit(1);
260*bd1f8aebSAndroid Build Coastguard Worker }
261*bd1f8aebSAndroid Build Coastguard Worker if (tp->th_opcode == WRQ)
262*bd1f8aebSAndroid Build Coastguard Worker (*pf->f_recv)(pf);
263*bd1f8aebSAndroid Build Coastguard Worker else
264*bd1f8aebSAndroid Build Coastguard Worker (*pf->f_send)(pf);
265*bd1f8aebSAndroid Build Coastguard Worker exit(0);
266*bd1f8aebSAndroid Build Coastguard Worker }
267*bd1f8aebSAndroid Build Coastguard Worker
268*bd1f8aebSAndroid Build Coastguard Worker
269*bd1f8aebSAndroid Build Coastguard Worker FILE *file;
270*bd1f8aebSAndroid Build Coastguard Worker
271*bd1f8aebSAndroid Build Coastguard Worker /*
272*bd1f8aebSAndroid Build Coastguard Worker * Validate file access. Since we
273*bd1f8aebSAndroid Build Coastguard Worker * have no uid or gid, for now require
274*bd1f8aebSAndroid Build Coastguard Worker * file to exist and be publicly
275*bd1f8aebSAndroid Build Coastguard Worker * readable/writable.
276*bd1f8aebSAndroid Build Coastguard Worker * If we were invoked with arguments
277*bd1f8aebSAndroid Build Coastguard Worker * from inetd then the file must also be
278*bd1f8aebSAndroid Build Coastguard Worker * in one of the given directory prefixes.
279*bd1f8aebSAndroid Build Coastguard Worker * Note also, full path name must be
280*bd1f8aebSAndroid Build Coastguard Worker * given as we have no login directory.
281*bd1f8aebSAndroid Build Coastguard Worker */
validate_access(char * filename,int mode)282*bd1f8aebSAndroid Build Coastguard Worker int validate_access(char *filename, int mode)
283*bd1f8aebSAndroid Build Coastguard Worker {
284*bd1f8aebSAndroid Build Coastguard Worker struct stat stbuf;
285*bd1f8aebSAndroid Build Coastguard Worker int fd;
286*bd1f8aebSAndroid Build Coastguard Worker char *cp;
287*bd1f8aebSAndroid Build Coastguard Worker char fnamebuf[1024+512];
288*bd1f8aebSAndroid Build Coastguard Worker
289*bd1f8aebSAndroid Build Coastguard Worker for (cp = filename; *cp; cp++) {
290*bd1f8aebSAndroid Build Coastguard Worker if(*cp == '.' && (cp == filename || strncmp(cp-1, "/../", 4) == 0)) {
291*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "bad path %s", filename);
292*bd1f8aebSAndroid Build Coastguard Worker return(EACCESS);
293*bd1f8aebSAndroid Build Coastguard Worker }
294*bd1f8aebSAndroid Build Coastguard Worker }
295*bd1f8aebSAndroid Build Coastguard Worker
296*bd1f8aebSAndroid Build Coastguard Worker if (*filename == '/')
297*bd1f8aebSAndroid Build Coastguard Worker filename++;
298*bd1f8aebSAndroid Build Coastguard Worker
299*bd1f8aebSAndroid Build Coastguard Worker if (!*dirs) {
300*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "no dirs");
301*bd1f8aebSAndroid Build Coastguard Worker return EACCESS;
302*bd1f8aebSAndroid Build Coastguard Worker }
303*bd1f8aebSAndroid Build Coastguard Worker snprintf(fnamebuf, sizeof(fnamebuf)-1, "%s/%s", *dirs, filename);
304*bd1f8aebSAndroid Build Coastguard Worker filename = fnamebuf;
305*bd1f8aebSAndroid Build Coastguard Worker
306*bd1f8aebSAndroid Build Coastguard Worker if (stat(filename, &stbuf) < 0) {
307*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "stat %s : %m", filename);
308*bd1f8aebSAndroid Build Coastguard Worker return (errno == ENOENT ? ENOTFOUND : EACCESS);
309*bd1f8aebSAndroid Build Coastguard Worker }
310*bd1f8aebSAndroid Build Coastguard Worker if (mode == RRQ) {
311*bd1f8aebSAndroid Build Coastguard Worker if ((stbuf.st_mode&(S_IREAD >> 6)) == 0) {
312*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "not readable %s", filename);
313*bd1f8aebSAndroid Build Coastguard Worker return (EACCESS);
314*bd1f8aebSAndroid Build Coastguard Worker }
315*bd1f8aebSAndroid Build Coastguard Worker } else {
316*bd1f8aebSAndroid Build Coastguard Worker if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0) {
317*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "not writable %s", filename);
318*bd1f8aebSAndroid Build Coastguard Worker return (EACCESS);
319*bd1f8aebSAndroid Build Coastguard Worker }
320*bd1f8aebSAndroid Build Coastguard Worker }
321*bd1f8aebSAndroid Build Coastguard Worker fd = open(filename, mode == RRQ ? 0 : 1);
322*bd1f8aebSAndroid Build Coastguard Worker if (fd < 0) {
323*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "cannot open %s: %m", filename);
324*bd1f8aebSAndroid Build Coastguard Worker return (errno + 100);
325*bd1f8aebSAndroid Build Coastguard Worker }
326*bd1f8aebSAndroid Build Coastguard Worker file = fdopen(fd, (mode == RRQ)? "r":"w");
327*bd1f8aebSAndroid Build Coastguard Worker if (file == NULL) {
328*bd1f8aebSAndroid Build Coastguard Worker return errno+100;
329*bd1f8aebSAndroid Build Coastguard Worker }
330*bd1f8aebSAndroid Build Coastguard Worker return (0);
331*bd1f8aebSAndroid Build Coastguard Worker }
332*bd1f8aebSAndroid Build Coastguard Worker
333*bd1f8aebSAndroid Build Coastguard Worker int confirmed;
334*bd1f8aebSAndroid Build Coastguard Worker int timeout;
335*bd1f8aebSAndroid Build Coastguard Worker jmp_buf timeoutbuf;
336*bd1f8aebSAndroid Build Coastguard Worker
timer(int signo)337*bd1f8aebSAndroid Build Coastguard Worker void timer(int signo)
338*bd1f8aebSAndroid Build Coastguard Worker {
339*bd1f8aebSAndroid Build Coastguard Worker confirmed = 0;
340*bd1f8aebSAndroid Build Coastguard Worker timeout += rexmtval;
341*bd1f8aebSAndroid Build Coastguard Worker if (timeout >= maxtimeout)
342*bd1f8aebSAndroid Build Coastguard Worker exit(1);
343*bd1f8aebSAndroid Build Coastguard Worker longjmp(timeoutbuf, 1);
344*bd1f8aebSAndroid Build Coastguard Worker }
345*bd1f8aebSAndroid Build Coastguard Worker
346*bd1f8aebSAndroid Build Coastguard Worker /*
347*bd1f8aebSAndroid Build Coastguard Worker * Send the requested file.
348*bd1f8aebSAndroid Build Coastguard Worker */
sendfile(struct formats * pf)349*bd1f8aebSAndroid Build Coastguard Worker void sendfile(struct formats *pf)
350*bd1f8aebSAndroid Build Coastguard Worker {
351*bd1f8aebSAndroid Build Coastguard Worker struct tftphdr *dp;
352*bd1f8aebSAndroid Build Coastguard Worker register struct tftphdr *ap; /* ack packet */
353*bd1f8aebSAndroid Build Coastguard Worker volatile int block = 1;
354*bd1f8aebSAndroid Build Coastguard Worker int size, n;
355*bd1f8aebSAndroid Build Coastguard Worker
356*bd1f8aebSAndroid Build Coastguard Worker confirmed = 0;
357*bd1f8aebSAndroid Build Coastguard Worker signal(SIGALRM, timer);
358*bd1f8aebSAndroid Build Coastguard Worker dp = r_init();
359*bd1f8aebSAndroid Build Coastguard Worker ap = (struct tftphdr *)ackbuf;
360*bd1f8aebSAndroid Build Coastguard Worker do {
361*bd1f8aebSAndroid Build Coastguard Worker size = readit(file, &dp, pf->f_convert);
362*bd1f8aebSAndroid Build Coastguard Worker if (size < 0) {
363*bd1f8aebSAndroid Build Coastguard Worker nak(errno + 100);
364*bd1f8aebSAndroid Build Coastguard Worker goto abort;
365*bd1f8aebSAndroid Build Coastguard Worker }
366*bd1f8aebSAndroid Build Coastguard Worker dp->th_opcode = htons((u_short)DATA);
367*bd1f8aebSAndroid Build Coastguard Worker dp->th_block = htons((u_short)block);
368*bd1f8aebSAndroid Build Coastguard Worker timeout = 0;
369*bd1f8aebSAndroid Build Coastguard Worker (void) setjmp(timeoutbuf);
370*bd1f8aebSAndroid Build Coastguard Worker
371*bd1f8aebSAndroid Build Coastguard Worker send_data:
372*bd1f8aebSAndroid Build Coastguard Worker if (send(peer, dp, size + 4, confirmed) != size + 4) {
373*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "tftpd: write: %m\n");
374*bd1f8aebSAndroid Build Coastguard Worker goto abort;
375*bd1f8aebSAndroid Build Coastguard Worker }
376*bd1f8aebSAndroid Build Coastguard Worker confirmed = 0;
377*bd1f8aebSAndroid Build Coastguard Worker read_ahead(file, pf->f_convert);
378*bd1f8aebSAndroid Build Coastguard Worker for ( ; ; ) {
379*bd1f8aebSAndroid Build Coastguard Worker alarm(rexmtval); /* read the ack */
380*bd1f8aebSAndroid Build Coastguard Worker n = recv(peer, ackbuf, sizeof (ackbuf), 0);
381*bd1f8aebSAndroid Build Coastguard Worker alarm(0);
382*bd1f8aebSAndroid Build Coastguard Worker if (n < 0) {
383*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "tftpd: read: %m\n");
384*bd1f8aebSAndroid Build Coastguard Worker goto abort;
385*bd1f8aebSAndroid Build Coastguard Worker }
386*bd1f8aebSAndroid Build Coastguard Worker ap->th_opcode = ntohs((u_short)ap->th_opcode);
387*bd1f8aebSAndroid Build Coastguard Worker ap->th_block = ntohs((u_short)ap->th_block);
388*bd1f8aebSAndroid Build Coastguard Worker
389*bd1f8aebSAndroid Build Coastguard Worker if (ap->th_opcode == ERROR)
390*bd1f8aebSAndroid Build Coastguard Worker goto abort;
391*bd1f8aebSAndroid Build Coastguard Worker
392*bd1f8aebSAndroid Build Coastguard Worker if (ap->th_opcode == ACK) {
393*bd1f8aebSAndroid Build Coastguard Worker if (ap->th_block == block) {
394*bd1f8aebSAndroid Build Coastguard Worker confirmed = MSG_CONFIRM;
395*bd1f8aebSAndroid Build Coastguard Worker break;
396*bd1f8aebSAndroid Build Coastguard Worker }
397*bd1f8aebSAndroid Build Coastguard Worker /* Re-synchronize with the other side */
398*bd1f8aebSAndroid Build Coastguard Worker synchnet(peer);
399*bd1f8aebSAndroid Build Coastguard Worker if (ap->th_block == (block -1)) {
400*bd1f8aebSAndroid Build Coastguard Worker goto send_data;
401*bd1f8aebSAndroid Build Coastguard Worker }
402*bd1f8aebSAndroid Build Coastguard Worker }
403*bd1f8aebSAndroid Build Coastguard Worker
404*bd1f8aebSAndroid Build Coastguard Worker }
405*bd1f8aebSAndroid Build Coastguard Worker block++;
406*bd1f8aebSAndroid Build Coastguard Worker } while (size == SEGSIZE);
407*bd1f8aebSAndroid Build Coastguard Worker abort:
408*bd1f8aebSAndroid Build Coastguard Worker (void) fclose(file);
409*bd1f8aebSAndroid Build Coastguard Worker }
410*bd1f8aebSAndroid Build Coastguard Worker
justquit(int signo)411*bd1f8aebSAndroid Build Coastguard Worker void justquit(int signo)
412*bd1f8aebSAndroid Build Coastguard Worker {
413*bd1f8aebSAndroid Build Coastguard Worker exit(0);
414*bd1f8aebSAndroid Build Coastguard Worker }
415*bd1f8aebSAndroid Build Coastguard Worker
416*bd1f8aebSAndroid Build Coastguard Worker
417*bd1f8aebSAndroid Build Coastguard Worker /*
418*bd1f8aebSAndroid Build Coastguard Worker * Receive a file.
419*bd1f8aebSAndroid Build Coastguard Worker */
recvfile(struct formats * pf)420*bd1f8aebSAndroid Build Coastguard Worker void recvfile(struct formats *pf)
421*bd1f8aebSAndroid Build Coastguard Worker {
422*bd1f8aebSAndroid Build Coastguard Worker struct tftphdr *dp;
423*bd1f8aebSAndroid Build Coastguard Worker register struct tftphdr *ap; /* ack buffer */
424*bd1f8aebSAndroid Build Coastguard Worker volatile int block = 0, n, size;
425*bd1f8aebSAndroid Build Coastguard Worker
426*bd1f8aebSAndroid Build Coastguard Worker confirmed = 0;
427*bd1f8aebSAndroid Build Coastguard Worker signal(SIGALRM, timer);
428*bd1f8aebSAndroid Build Coastguard Worker dp = w_init();
429*bd1f8aebSAndroid Build Coastguard Worker ap = (struct tftphdr *)ackbuf;
430*bd1f8aebSAndroid Build Coastguard Worker do {
431*bd1f8aebSAndroid Build Coastguard Worker timeout = 0;
432*bd1f8aebSAndroid Build Coastguard Worker ap->th_opcode = htons((u_short)ACK);
433*bd1f8aebSAndroid Build Coastguard Worker ap->th_block = htons((u_short)block);
434*bd1f8aebSAndroid Build Coastguard Worker block++;
435*bd1f8aebSAndroid Build Coastguard Worker (void) setjmp(timeoutbuf);
436*bd1f8aebSAndroid Build Coastguard Worker send_ack:
437*bd1f8aebSAndroid Build Coastguard Worker if (send(peer, ackbuf, 4, confirmed) != 4) {
438*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "tftpd: write: %m\n");
439*bd1f8aebSAndroid Build Coastguard Worker goto abort;
440*bd1f8aebSAndroid Build Coastguard Worker }
441*bd1f8aebSAndroid Build Coastguard Worker confirmed = 0;
442*bd1f8aebSAndroid Build Coastguard Worker write_behind(file, pf->f_convert);
443*bd1f8aebSAndroid Build Coastguard Worker for ( ; ; ) {
444*bd1f8aebSAndroid Build Coastguard Worker alarm(rexmtval);
445*bd1f8aebSAndroid Build Coastguard Worker n = recv(peer, dp, PKTSIZE, 0);
446*bd1f8aebSAndroid Build Coastguard Worker alarm(0);
447*bd1f8aebSAndroid Build Coastguard Worker if (n < 0) { /* really? */
448*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "tftpd: read: %m\n");
449*bd1f8aebSAndroid Build Coastguard Worker goto abort;
450*bd1f8aebSAndroid Build Coastguard Worker }
451*bd1f8aebSAndroid Build Coastguard Worker dp->th_opcode = ntohs((u_short)dp->th_opcode);
452*bd1f8aebSAndroid Build Coastguard Worker dp->th_block = ntohs((u_short)dp->th_block);
453*bd1f8aebSAndroid Build Coastguard Worker if (dp->th_opcode == ERROR)
454*bd1f8aebSAndroid Build Coastguard Worker goto abort;
455*bd1f8aebSAndroid Build Coastguard Worker if (dp->th_opcode == DATA) {
456*bd1f8aebSAndroid Build Coastguard Worker if (dp->th_block == block) {
457*bd1f8aebSAndroid Build Coastguard Worker confirmed = MSG_CONFIRM;
458*bd1f8aebSAndroid Build Coastguard Worker break; /* normal */
459*bd1f8aebSAndroid Build Coastguard Worker }
460*bd1f8aebSAndroid Build Coastguard Worker /* Re-synchronize with the other side */
461*bd1f8aebSAndroid Build Coastguard Worker (void) synchnet(peer);
462*bd1f8aebSAndroid Build Coastguard Worker if (dp->th_block == (block-1))
463*bd1f8aebSAndroid Build Coastguard Worker goto send_ack; /* rexmit */
464*bd1f8aebSAndroid Build Coastguard Worker }
465*bd1f8aebSAndroid Build Coastguard Worker }
466*bd1f8aebSAndroid Build Coastguard Worker /* size = write(file, dp->th_data, n - 4); */
467*bd1f8aebSAndroid Build Coastguard Worker size = writeit(file, &dp, n - 4, pf->f_convert);
468*bd1f8aebSAndroid Build Coastguard Worker if (size != (n-4)) { /* ahem */
469*bd1f8aebSAndroid Build Coastguard Worker if (size < 0) nak(errno + 100);
470*bd1f8aebSAndroid Build Coastguard Worker else nak(ENOSPACE);
471*bd1f8aebSAndroid Build Coastguard Worker goto abort;
472*bd1f8aebSAndroid Build Coastguard Worker }
473*bd1f8aebSAndroid Build Coastguard Worker } while (size == SEGSIZE);
474*bd1f8aebSAndroid Build Coastguard Worker write_behind(file, pf->f_convert);
475*bd1f8aebSAndroid Build Coastguard Worker (void) fclose(file); /* close data file */
476*bd1f8aebSAndroid Build Coastguard Worker
477*bd1f8aebSAndroid Build Coastguard Worker ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
478*bd1f8aebSAndroid Build Coastguard Worker ap->th_block = htons((u_short)(block));
479*bd1f8aebSAndroid Build Coastguard Worker (void) send(peer, ackbuf, 4, confirmed);
480*bd1f8aebSAndroid Build Coastguard Worker
481*bd1f8aebSAndroid Build Coastguard Worker signal(SIGALRM, justquit); /* just quit on timeout */
482*bd1f8aebSAndroid Build Coastguard Worker alarm(rexmtval);
483*bd1f8aebSAndroid Build Coastguard Worker n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
484*bd1f8aebSAndroid Build Coastguard Worker alarm(0);
485*bd1f8aebSAndroid Build Coastguard Worker if (n >= 4 && /* if read some data */
486*bd1f8aebSAndroid Build Coastguard Worker dp->th_opcode == DATA && /* and got a data block */
487*bd1f8aebSAndroid Build Coastguard Worker block == dp->th_block) { /* then my last ack was lost */
488*bd1f8aebSAndroid Build Coastguard Worker (void) send(peer, ackbuf, 4, 0); /* resend final ack */
489*bd1f8aebSAndroid Build Coastguard Worker }
490*bd1f8aebSAndroid Build Coastguard Worker abort:
491*bd1f8aebSAndroid Build Coastguard Worker return;
492*bd1f8aebSAndroid Build Coastguard Worker }
493*bd1f8aebSAndroid Build Coastguard Worker
494*bd1f8aebSAndroid Build Coastguard Worker struct errmsg {
495*bd1f8aebSAndroid Build Coastguard Worker int e_code;
496*bd1f8aebSAndroid Build Coastguard Worker char *e_msg;
497*bd1f8aebSAndroid Build Coastguard Worker } errmsgs[] = {
498*bd1f8aebSAndroid Build Coastguard Worker { EUNDEF, "Undefined error code" },
499*bd1f8aebSAndroid Build Coastguard Worker { ENOTFOUND, "File not found" },
500*bd1f8aebSAndroid Build Coastguard Worker { EACCESS, "Access violation" },
501*bd1f8aebSAndroid Build Coastguard Worker { ENOSPACE, "Disk full or allocation exceeded" },
502*bd1f8aebSAndroid Build Coastguard Worker { EBADOP, "Illegal TFTP operation" },
503*bd1f8aebSAndroid Build Coastguard Worker { EBADID, "Unknown transfer ID" },
504*bd1f8aebSAndroid Build Coastguard Worker { EEXISTS, "File already exists" },
505*bd1f8aebSAndroid Build Coastguard Worker { ENOUSER, "No such user" },
506*bd1f8aebSAndroid Build Coastguard Worker { -1, 0 }
507*bd1f8aebSAndroid Build Coastguard Worker };
508*bd1f8aebSAndroid Build Coastguard Worker
509*bd1f8aebSAndroid Build Coastguard Worker /*
510*bd1f8aebSAndroid Build Coastguard Worker * Send a nak packet (error message).
511*bd1f8aebSAndroid Build Coastguard Worker * Error code passed in is one of the
512*bd1f8aebSAndroid Build Coastguard Worker * standard TFTP codes, or a UNIX errno
513*bd1f8aebSAndroid Build Coastguard Worker * offset by 100.
514*bd1f8aebSAndroid Build Coastguard Worker */
nak(int error)515*bd1f8aebSAndroid Build Coastguard Worker void nak(int error)
516*bd1f8aebSAndroid Build Coastguard Worker {
517*bd1f8aebSAndroid Build Coastguard Worker register struct tftphdr *tp;
518*bd1f8aebSAndroid Build Coastguard Worker int length;
519*bd1f8aebSAndroid Build Coastguard Worker register struct errmsg *pe;
520*bd1f8aebSAndroid Build Coastguard Worker
521*bd1f8aebSAndroid Build Coastguard Worker tp = (struct tftphdr *)buf;
522*bd1f8aebSAndroid Build Coastguard Worker tp->th_opcode = htons((u_short)ERROR);
523*bd1f8aebSAndroid Build Coastguard Worker tp->th_code = htons((u_short)error);
524*bd1f8aebSAndroid Build Coastguard Worker for (pe = errmsgs; pe->e_code >= 0; pe++)
525*bd1f8aebSAndroid Build Coastguard Worker if (pe->e_code == error)
526*bd1f8aebSAndroid Build Coastguard Worker break;
527*bd1f8aebSAndroid Build Coastguard Worker if (pe->e_code < 0) {
528*bd1f8aebSAndroid Build Coastguard Worker pe->e_msg = strerror(error - 100);
529*bd1f8aebSAndroid Build Coastguard Worker tp->th_code = EUNDEF; /* set 'undef' errorcode */
530*bd1f8aebSAndroid Build Coastguard Worker }
531*bd1f8aebSAndroid Build Coastguard Worker strcpy(tp->th_msg, pe->e_msg);
532*bd1f8aebSAndroid Build Coastguard Worker length = strlen(pe->e_msg);
533*bd1f8aebSAndroid Build Coastguard Worker tp->th_msg[length] = '\0';
534*bd1f8aebSAndroid Build Coastguard Worker length += 5;
535*bd1f8aebSAndroid Build Coastguard Worker if (send(peer, buf, length, 0) != length)
536*bd1f8aebSAndroid Build Coastguard Worker syslog(LOG_ERR, "nak: %m\n");
537*bd1f8aebSAndroid Build Coastguard Worker }
538