tftpd.c revision 71926
1/*
2 * Copyright (c) 1983, 1993
3 *	The Regents of the University of California.  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
35static const char copyright[] =
36"@(#) Copyright (c) 1983, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)tftpd.c	8.1 (Berkeley) 6/4/93";
43#endif
44static const char rcsid[] =
45  "$FreeBSD: head/libexec/tftpd/tftpd.c 71926 2001-02-02 10:53:02Z asmodai $";
46#endif /* not lint */
47
48/*
49 * Trivial file transfer protocol server.
50 *
51 * This version includes many modifications by Jim Guyton
52 * <guyton@rand-unix>.
53 */
54
55#include <sys/param.h>
56#include <sys/ioctl.h>
57#include <sys/stat.h>
58#include <sys/socket.h>
59#include <sys/types.h>
60
61#include <netinet/in.h>
62#include <arpa/tftp.h>
63#include <arpa/inet.h>
64
65#include <ctype.h>
66#include <errno.h>
67#include <fcntl.h>
68#include <libutil.h>
69#include <netdb.h>
70#include <pwd.h>
71#include <setjmp.h>
72#include <signal.h>
73#include <stdio.h>
74#include <stdlib.h>
75#include <string.h>
76#include <syslog.h>
77#include <unistd.h>
78
79#include "tftpsubs.h"
80
81#define	TIMEOUT		5
82
83int	peer;
84int	rexmtval = TIMEOUT;
85int	maxtimeout = 5*TIMEOUT;
86
87#define	PKTSIZE	SEGSIZE+4
88char	buf[PKTSIZE];
89char	ackbuf[PKTSIZE];
90struct	sockaddr_in from;
91int	fromlen;
92
93void	tftp __P((struct tftphdr *, int));
94
95/*
96 * Null-terminated directory prefix list for absolute pathname requests and
97 * search list for relative pathname requests.
98 *
99 * MAXDIRS should be at least as large as the number of arguments that
100 * inetd allows (currently 20).
101 */
102#define MAXDIRS	20
103static struct dirlist {
104	char	*name;
105	int	len;
106} dirs[MAXDIRS+1];
107static int	suppress_naks;
108static int	logging;
109static int	ipchroot;
110
111static char *errtomsg __P((int));
112static void  nak __P((int));
113
114int
115main(argc, argv)
116	int argc;
117	char *argv[];
118{
119	register struct tftphdr *tp;
120	register int n;
121	int ch, on;
122	struct sockaddr_in sin;
123	char *chroot_dir = NULL;
124	struct passwd *nobody;
125	char *chuser = "nobody";
126
127	openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
128	while ((ch = getopt(argc, argv, "cClns:u:")) != -1) {
129		switch (ch) {
130		case 'c':
131			ipchroot = 1;
132			break;
133		case 'C':
134			ipchroot = 2;
135			break;
136		case 'l':
137			logging = 1;
138			break;
139		case 'n':
140			suppress_naks = 1;
141			break;
142		case 's':
143			chroot_dir = optarg;
144			break;
145		case 'u':
146			chuser = optarg;
147			break;
148		default:
149			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
150		}
151	}
152	if (optind < argc) {
153		struct dirlist *dirp;
154
155		/* Get list of directory prefixes. Skip relative pathnames. */
156		for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
157		     optind++) {
158			if (argv[optind][0] == '/') {
159				dirp->name = argv[optind];
160				dirp->len  = strlen(dirp->name);
161				dirp++;
162			}
163		}
164	}
165	else if (chroot_dir) {
166		dirs->name = "/";
167		dirs->len = 1;
168	}
169	if (ipchroot && chroot_dir == NULL) {
170		syslog(LOG_ERR, "-c requires -s");
171		exit(1);
172	}
173
174	on = 1;
175	if (ioctl(0, FIONBIO, &on) < 0) {
176		syslog(LOG_ERR, "ioctl(FIONBIO): %m");
177		exit(1);
178	}
179	fromlen = sizeof (from);
180	n = recvfrom(0, buf, sizeof (buf), 0,
181	    (struct sockaddr *)&from, &fromlen);
182	if (n < 0) {
183		syslog(LOG_ERR, "recvfrom: %m");
184		exit(1);
185	}
186	/*
187	 * Now that we have read the message out of the UDP
188	 * socket, we fork and exit.  Thus, inetd will go back
189	 * to listening to the tftp port, and the next request
190	 * to come in will start up a new instance of tftpd.
191	 *
192	 * We do this so that inetd can run tftpd in "wait" mode.
193	 * The problem with tftpd running in "nowait" mode is that
194	 * inetd may get one or more successful "selects" on the
195	 * tftp port before we do our receive, so more than one
196	 * instance of tftpd may be started up.  Worse, if tftpd
197	 * break before doing the above "recvfrom", inetd would
198	 * spawn endless instances, clogging the system.
199	 */
200	{
201		int pid;
202		int i, j;
203
204		for (i = 1; i < 20; i++) {
205		    pid = fork();
206		    if (pid < 0) {
207				sleep(i);
208				/*
209				 * flush out to most recently sent request.
210				 *
211				 * This may drop some request, but those
212				 * will be resent by the clients when
213				 * they timeout.  The positive effect of
214				 * this flush is to (try to) prevent more
215				 * than one tftpd being started up to service
216				 * a single request from a single client.
217				 */
218				j = sizeof from;
219				i = recvfrom(0, buf, sizeof (buf), 0,
220				    (struct sockaddr *)&from, &j);
221				if (i > 0) {
222					n = i;
223					fromlen = j;
224				}
225		    } else {
226				break;
227		    }
228		}
229		if (pid < 0) {
230			syslog(LOG_ERR, "fork: %m");
231			exit(1);
232		} else if (pid != 0) {
233			exit(0);
234		}
235	}
236
237	/*
238	 * Since we exit here, we should do that only after the above
239	 * recvfrom to keep inetd from constantly forking should there
240	 * be a problem.  See the above comment about system clogging.
241	 */
242	if (chroot_dir) {
243		if (ipchroot) {
244			char *tempchroot;
245			struct stat sb;
246			int statret;
247
248			tempchroot = inet_ntoa(from.sin_addr);
249			asprintf(&tempchroot, "%s/%s", chroot_dir, tempchroot);
250			statret = stat(tempchroot, &sb);
251			if ((sb.st_mode & S_IFDIR) &&
252			    (statret == 0 || (statret == -1 && ipchroot == 1)))
253				chroot_dir = tempchroot;
254		}
255		/* Must get this before chroot because /etc might go away */
256		if ((nobody = getpwnam(chuser)) == NULL) {
257			syslog(LOG_ERR, "%s: no such user", chuser);
258			exit(1);
259		}
260		if (chroot(chroot_dir)) {
261			syslog(LOG_ERR, "chroot: %s: %m", chroot_dir);
262			exit(1);
263		}
264		chdir( "/" );
265		setuid(nobody->pw_uid);
266	}
267
268	from.sin_family = AF_INET;
269	alarm(0);
270	close(0);
271	close(1);
272	peer = socket(AF_INET, SOCK_DGRAM, 0);
273	if (peer < 0) {
274		syslog(LOG_ERR, "socket: %m");
275		exit(1);
276	}
277	memset(&sin, 0, sizeof(sin));
278	sin.sin_family = AF_INET;
279	if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
280		syslog(LOG_ERR, "bind: %m");
281		exit(1);
282	}
283	if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
284		syslog(LOG_ERR, "connect: %m");
285		exit(1);
286	}
287	tp = (struct tftphdr *)buf;
288	tp->th_opcode = ntohs(tp->th_opcode);
289	if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
290		tftp(tp, n);
291	exit(1);
292}
293
294struct formats;
295int	validate_access __P((char **, int));
296void	xmitfile __P((struct formats *));
297void	recvfile __P((struct formats *));
298
299struct formats {
300	char	*f_mode;
301	int	(*f_validate) __P((char **, int));
302	void	(*f_send) __P((struct formats *));
303	void	(*f_recv) __P((struct formats *));
304	int	f_convert;
305} formats[] = {
306	{ "netascii",	validate_access,	xmitfile,	recvfile, 1 },
307	{ "octet",	validate_access,	xmitfile,	recvfile, 0 },
308#ifdef notdef
309	{ "mail",	validate_user,		sendmail,	recvmail, 1 },
310#endif
311	{ 0 }
312};
313
314/*
315 * Handle initial connection protocol.
316 */
317void
318tftp(tp, size)
319	struct tftphdr *tp;
320	int size;
321{
322	register char *cp;
323	int first = 1, ecode;
324	register struct formats *pf;
325	char *filename, *mode;
326
327	filename = cp = tp->th_stuff;
328again:
329	while (cp < buf + size) {
330		if (*cp == '\0')
331			break;
332		cp++;
333	}
334	if (*cp != '\0') {
335		nak(EBADOP);
336		exit(1);
337	}
338	if (first) {
339		mode = ++cp;
340		first = 0;
341		goto again;
342	}
343	for (cp = mode; *cp; cp++)
344		if (isupper(*cp))
345			*cp = tolower(*cp);
346	for (pf = formats; pf->f_mode; pf++)
347		if (strcmp(pf->f_mode, mode) == 0)
348			break;
349	if (pf->f_mode == 0) {
350		nak(EBADOP);
351		exit(1);
352	}
353	ecode = (*pf->f_validate)(&filename, tp->th_opcode);
354	if (logging) {
355		char host[MAXHOSTNAMELEN];
356
357		realhostname(host, sizeof(host) - 1, &from.sin_addr);
358		host[sizeof(host) - 1] = '\0';
359		syslog(LOG_INFO, "%s: %s request for %s: %s", host,
360			tp->th_opcode == WRQ ? "write" : "read",
361			filename, errtomsg(ecode));
362	}
363	if (ecode) {
364		/*
365		 * Avoid storms of naks to a RRQ broadcast for a relative
366		 * bootfile pathname from a diskless Sun.
367		 */
368		if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
369			exit(0);
370		nak(ecode);
371		exit(1);
372	}
373	if (tp->th_opcode == WRQ)
374		(*pf->f_recv)(pf);
375	else
376		(*pf->f_send)(pf);
377	exit(0);
378}
379
380
381FILE *file;
382
383/*
384 * Validate file access.  Since we
385 * have no uid or gid, for now require
386 * file to exist and be publicly
387 * readable/writable.
388 * If we were invoked with arguments
389 * from inetd then the file must also be
390 * in one of the given directory prefixes.
391 * Note also, full path name must be
392 * given as we have no login directory.
393 */
394int
395validate_access(filep, mode)
396	char **filep;
397	int mode;
398{
399	struct stat stbuf;
400	int	fd;
401	struct dirlist *dirp;
402	static char pathname[MAXPATHLEN];
403	char *filename = *filep;
404
405	/*
406	 * Prevent tricksters from getting around the directory restrictions
407	 */
408	if (strstr(filename, "/../"))
409		return (EACCESS);
410
411	if (*filename == '/') {
412		/*
413		 * Allow the request if it's in one of the approved locations.
414		 * Special case: check the null prefix ("/") by looking
415		 * for length = 1 and relying on the arg. processing that
416		 * it's a /.
417		 */
418		for (dirp = dirs; dirp->name != NULL; dirp++) {
419			if (dirp->len == 1 ||
420			    (!strncmp(filename, dirp->name, dirp->len) &&
421			     filename[dirp->len] == '/'))
422				    break;
423		}
424		/* If directory list is empty, allow access to any file */
425		if (dirp->name == NULL && dirp != dirs)
426			return (EACCESS);
427		if (stat(filename, &stbuf) < 0)
428			return (errno == ENOENT ? ENOTFOUND : EACCESS);
429		if ((stbuf.st_mode & S_IFMT) != S_IFREG)
430			return (ENOTFOUND);
431		if (mode == RRQ) {
432			if ((stbuf.st_mode & S_IROTH) == 0)
433				return (EACCESS);
434		} else {
435			if ((stbuf.st_mode & S_IWOTH) == 0)
436				return (EACCESS);
437		}
438	} else {
439		int err;
440
441		/*
442		 * Relative file name: search the approved locations for it.
443		 * Don't allow write requests that avoid directory
444		 * restrictions.
445		 */
446
447		if (!strncmp(filename, "../", 3))
448			return (EACCESS);
449
450		/*
451		 * If the file exists in one of the directories and isn't
452		 * readable, continue looking. However, change the error code
453		 * to give an indication that the file exists.
454		 */
455		err = ENOTFOUND;
456		for (dirp = dirs; dirp->name != NULL; dirp++) {
457			snprintf(pathname, sizeof(pathname), "%s/%s",
458				dirp->name, filename);
459			if (stat(pathname, &stbuf) == 0 &&
460			    (stbuf.st_mode & S_IFMT) == S_IFREG) {
461				if ((stbuf.st_mode & S_IROTH) != 0) {
462					break;
463				}
464				err = EACCESS;
465			}
466		}
467		if (dirp->name == NULL)
468			return (err);
469		*filep = filename = pathname;
470	}
471	fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY|O_TRUNC);
472	if (fd < 0)
473		return (errno + 100);
474	file = fdopen(fd, (mode == RRQ)? "r":"w");
475	if (file == NULL) {
476		return errno+100;
477	}
478	return (0);
479}
480
481int	timeout;
482jmp_buf	timeoutbuf;
483
484void
485timer()
486{
487
488	timeout += rexmtval;
489	if (timeout >= maxtimeout)
490		exit(1);
491	longjmp(timeoutbuf, 1);
492}
493
494/*
495 * Send the requested file.
496 */
497void
498xmitfile(pf)
499	struct formats *pf;
500{
501	struct tftphdr *dp, *r_init();
502	register struct tftphdr *ap;    /* ack packet */
503	register int size, n;
504	volatile unsigned short block;
505
506	signal(SIGALRM, timer);
507	dp = r_init();
508	ap = (struct tftphdr *)ackbuf;
509	block = 1;
510	do {
511		size = readit(file, &dp, pf->f_convert);
512		if (size < 0) {
513			nak(errno + 100);
514			goto abort;
515		}
516		dp->th_opcode = htons((u_short)DATA);
517		dp->th_block = htons((u_short)block);
518		timeout = 0;
519		(void)setjmp(timeoutbuf);
520
521send_data:
522		if (send(peer, dp, size + 4, 0) != size + 4) {
523			syslog(LOG_ERR, "write: %m");
524			goto abort;
525		}
526		read_ahead(file, pf->f_convert);
527		for ( ; ; ) {
528			alarm(rexmtval);        /* read the ack */
529			n = recv(peer, ackbuf, sizeof (ackbuf), 0);
530			alarm(0);
531			if (n < 0) {
532				syslog(LOG_ERR, "read: %m");
533				goto abort;
534			}
535			ap->th_opcode = ntohs((u_short)ap->th_opcode);
536			ap->th_block = ntohs((u_short)ap->th_block);
537
538			if (ap->th_opcode == ERROR)
539				goto abort;
540
541			if (ap->th_opcode == ACK) {
542				if (ap->th_block == block)
543					break;
544				/* Re-synchronize with the other side */
545				(void) synchnet(peer);
546				if (ap->th_block == (block -1))
547					goto send_data;
548			}
549
550		}
551		block++;
552	} while (size == SEGSIZE);
553abort:
554	(void) fclose(file);
555}
556
557void
558justquit()
559{
560	exit(0);
561}
562
563
564/*
565 * Receive a file.
566 */
567void
568recvfile(pf)
569	struct formats *pf;
570{
571	struct tftphdr *dp, *w_init();
572	register struct tftphdr *ap;    /* ack buffer */
573	register int n, size;
574	volatile unsigned short block;
575
576	signal(SIGALRM, timer);
577	dp = w_init();
578	ap = (struct tftphdr *)ackbuf;
579	block = 0;
580	do {
581		timeout = 0;
582		ap->th_opcode = htons((u_short)ACK);
583		ap->th_block = htons((u_short)block);
584		block++;
585		(void) setjmp(timeoutbuf);
586send_ack:
587		if (send(peer, ackbuf, 4, 0) != 4) {
588			syslog(LOG_ERR, "write: %m");
589			goto abort;
590		}
591		write_behind(file, pf->f_convert);
592		for ( ; ; ) {
593			alarm(rexmtval);
594			n = recv(peer, dp, PKTSIZE, 0);
595			alarm(0);
596			if (n < 0) {            /* really? */
597				syslog(LOG_ERR, "read: %m");
598				goto abort;
599			}
600			dp->th_opcode = ntohs((u_short)dp->th_opcode);
601			dp->th_block = ntohs((u_short)dp->th_block);
602			if (dp->th_opcode == ERROR)
603				goto abort;
604			if (dp->th_opcode == DATA) {
605				if (dp->th_block == block) {
606					break;   /* normal */
607				}
608				/* Re-synchronize with the other side */
609				(void) synchnet(peer);
610				if (dp->th_block == (block-1))
611					goto send_ack;          /* rexmit */
612			}
613		}
614		/*  size = write(file, dp->th_data, n - 4); */
615		size = writeit(file, &dp, n - 4, pf->f_convert);
616		if (size != (n-4)) {                    /* ahem */
617			if (size < 0) nak(errno + 100);
618			else nak(ENOSPACE);
619			goto abort;
620		}
621	} while (size == SEGSIZE);
622	write_behind(file, pf->f_convert);
623	(void) fclose(file);            /* close data file */
624
625	ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
626	ap->th_block = htons((u_short)(block));
627	(void) send(peer, ackbuf, 4, 0);
628
629	signal(SIGALRM, justquit);      /* just quit on timeout */
630	alarm(rexmtval);
631	n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
632	alarm(0);
633	if (n >= 4 &&                   /* if read some data */
634	    dp->th_opcode == DATA &&    /* and got a data block */
635	    block == dp->th_block) {	/* then my last ack was lost */
636		(void) send(peer, ackbuf, 4, 0);     /* resend final ack */
637	}
638abort:
639	return;
640}
641
642struct errmsg {
643	int	e_code;
644	char	*e_msg;
645} errmsgs[] = {
646	{ EUNDEF,	"Undefined error code" },
647	{ ENOTFOUND,	"File not found" },
648	{ EACCESS,	"Access violation" },
649	{ ENOSPACE,	"Disk full or allocation exceeded" },
650	{ EBADOP,	"Illegal TFTP operation" },
651	{ EBADID,	"Unknown transfer ID" },
652	{ EEXISTS,	"File already exists" },
653	{ ENOUSER,	"No such user" },
654	{ -1,		0 }
655};
656
657static char *
658errtomsg(error)
659	int error;
660{
661	static char buf[20];
662	register struct errmsg *pe;
663	if (error == 0)
664		return "success";
665	for (pe = errmsgs; pe->e_code >= 0; pe++)
666		if (pe->e_code == error)
667			return pe->e_msg;
668	snprintf(buf, sizeof(buf), "error %d", error);
669	return buf;
670}
671
672/*
673 * Send a nak packet (error message).
674 * Error code passed in is one of the
675 * standard TFTP codes, or a UNIX errno
676 * offset by 100.
677 */
678static void
679nak(error)
680	int error;
681{
682	register struct tftphdr *tp;
683	int length;
684	register struct errmsg *pe;
685
686	tp = (struct tftphdr *)buf;
687	tp->th_opcode = htons((u_short)ERROR);
688	tp->th_code = htons((u_short)error);
689	for (pe = errmsgs; pe->e_code >= 0; pe++)
690		if (pe->e_code == error)
691			break;
692	if (pe->e_code < 0) {
693		pe->e_msg = strerror(error - 100);
694		tp->th_code = EUNDEF;   /* set 'undef' errorcode */
695	}
696	strcpy(tp->th_msg, pe->e_msg);
697	length = strlen(pe->e_msg);
698	tp->th_msg[length] = '\0';
699	length += 5;
700	if (send(peer, buf, length, 0) != length)
701		syslog(LOG_ERR, "nak: %m");
702}
703