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