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