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