xref: /netbsd-src/libexec/tftpd/tftpd.c (revision d20841bb642898112fe68f0ad3f7b26dddf56f07)
1 /*	$NetBSD: tftpd.c,v 1.27 2004/01/06 14:30:10 briggs Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
35 	The Regents of the University of California.  All rights reserved.\n");
36 #if 0
37 static char sccsid[] = "@(#)tftpd.c	8.1 (Berkeley) 6/4/93";
38 #else
39 __RCSID("$NetBSD: tftpd.c,v 1.27 2004/01/06 14:30:10 briggs Exp $");
40 #endif
41 #endif /* not lint */
42 
43 /*
44  * Trivial file transfer protocol server.
45  *
46  * This version includes many modifications by Jim Guyton
47  * <guyton@rand-unix>.
48  */
49 
50 #include <sys/param.h>
51 #include <sys/ioctl.h>
52 #include <sys/stat.h>
53 #include <sys/socket.h>
54 
55 #include <netinet/in.h>
56 #include <arpa/tftp.h>
57 #include <arpa/inet.h>
58 
59 #include <ctype.h>
60 #include <errno.h>
61 #include <fcntl.h>
62 #include <grp.h>
63 #include <netdb.h>
64 #include <pwd.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 
73 #include "tftpsubs.h"
74 
75 #define	DEFAULTUSER	"nobody"
76 
77 #define	TIMEOUT		5
78 
79 int	peer;
80 int	rexmtval = TIMEOUT;
81 int	maxtimeout = 5*TIMEOUT;
82 
83 char	buf[MAXPKTSIZE];
84 char	ackbuf[PKTSIZE];
85 char	oackbuf[PKTSIZE];
86 struct	sockaddr_storage from;
87 int	fromlen;
88 int	debug;
89 
90 int	tftp_opt_tsize = 0;
91 int	tftp_blksize = SEGSIZE;
92 int	tftp_tsize = 0;
93 
94 /*
95  * Null-terminated directory prefix list for absolute pathname requests and
96  * search list for relative pathname requests.
97  *
98  * MAXDIRS should be at least as large as the number of arguments that
99  * inetd allows (currently 20).
100  */
101 #define MAXDIRS	20
102 static struct dirlist {
103 	char	*name;
104 	int	len;
105 } dirs[MAXDIRS+1];
106 static int	suppress_naks;
107 static int	logging;
108 static int	secure;
109 static char	*securedir;
110 
111 struct formats;
112 
113 static const char *errtomsg(int);
114 static void	 nak(int);
115 static void	 tftp(struct tftphdr *, int);
116 static void	 usage(void);
117 static char	*verifyhost(struct sockaddr *);
118 void	justquit(int);
119 int	main(int, char **);
120 void	recvfile(struct formats *, int, int);
121 void	sendfile(struct formats *, int, int);
122 void	timer(int);
123 static const char *opcode(int);
124 int	validate_access(char **, int);
125 
126 struct formats {
127 	const char	*f_mode;
128 	int		(*f_validate)(char **, int);
129 	void		(*f_send)(struct formats *, int, int);
130 	void		(*f_recv)(struct formats *, int, int);
131 	int		f_convert;
132 } formats[] = {
133 	{ "netascii",	validate_access,	sendfile,	recvfile, 1 },
134 	{ "octet",	validate_access,	sendfile,	recvfile, 0 },
135 	{ 0 }
136 };
137 
138 static void
139 usage(void)
140 {
141 
142 	syslog(LOG_ERR,
143     "Usage: %s [-dln] [-u user] [-g group] [-s directory] [directory ...]",
144 		    getprogname());
145 	exit(1);
146 }
147 
148 int
149 main(int argc, char *argv[])
150 {
151 	struct sockaddr_storage me;
152 	struct passwd	*pwent;
153 	struct group	*grent;
154 	struct tftphdr	*tp;
155 	char		*tgtuser, *tgtgroup, *ep;
156 	int	n, ch, on, fd;
157 	int	len, soopt;
158 	uid_t	curuid, tgtuid;
159 	gid_t	curgid, tgtgid;
160 	long	nid;
161 
162 	n = 0;
163 	fd = 0;
164 	openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
165 	tgtuser = DEFAULTUSER;
166 	tgtgroup = NULL;
167 	curuid = getuid();
168 	curgid = getgid();
169 
170 	while ((ch = getopt(argc, argv, "dg:lns:u:")) != -1)
171 		switch (ch) {
172 		case 'd':
173 			debug++;
174 			break;
175 
176 		case 'g':
177 			tgtgroup = optarg;
178 			break;
179 
180 		case 'l':
181 			logging = 1;
182 			break;
183 
184 		case 'n':
185 			suppress_naks = 1;
186 			break;
187 
188 		case 's':
189 			secure = 1;
190 			securedir = optarg;
191 			break;
192 
193 		case 'u':
194 			tgtuser = optarg;
195 			break;
196 
197 		default:
198 			usage();
199 			break;
200 		}
201 
202 	if (optind < argc) {
203 		struct dirlist *dirp;
204 
205 		/* Get list of directory prefixes. Skip relative pathnames. */
206 		for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
207 		     optind++) {
208 			if (argv[optind][0] == '/') {
209 				dirp->name = argv[optind];
210 				dirp->len  = strlen(dirp->name);
211 				dirp++;
212 			}
213 		}
214 	}
215 
216 	if (*tgtuser == '\0' || (tgtgroup != NULL && *tgtgroup == '\0'))
217 		usage();
218 
219 	nid = (strtol(tgtuser, &ep, 10));
220 	if (*ep == '\0') {
221 		if (nid > UID_MAX) {
222 			syslog(LOG_ERR, "uid %ld is too large", nid);
223 			exit(1);
224 		}
225 		pwent = getpwuid((uid_t)nid);
226 	} else
227 		pwent = getpwnam(tgtuser);
228 	if (pwent == NULL) {
229 		syslog(LOG_ERR, "unknown user `%s'", tgtuser);
230 		exit(1);
231 	}
232 	tgtuid = pwent->pw_uid;
233 	tgtgid = pwent->pw_gid;
234 
235 	if (tgtgroup != NULL) {
236 		nid = (strtol(tgtgroup, &ep, 10));
237 		if (*ep == '\0') {
238 			if (nid > GID_MAX) {
239 				syslog(LOG_ERR, "gid %ld is too large", nid);
240 				exit(1);
241 			}
242 			grent = getgrgid((gid_t)nid);
243 		} else
244 			grent = getgrnam(tgtgroup);
245 		if (grent != NULL)
246 			tgtgid = grent->gr_gid;
247 		else {
248 			syslog(LOG_ERR, "unknown group `%s'", tgtgroup);
249 			exit(1);
250 		}
251 	}
252 
253 	if (secure) {
254 		if (chdir(securedir) < 0) {
255 			syslog(LOG_ERR, "chdir %s: %m", securedir);
256 			exit(1);
257 		}
258 		if (chroot(".")) {
259 			syslog(LOG_ERR, "chroot: %m");
260 			exit(1);
261 		}
262 	}
263 
264 	if (logging)
265 		syslog(LOG_DEBUG, "running as user `%s' (%d), group `%s' (%d)",
266 		    tgtuser, tgtuid, tgtgroup ? tgtgroup : "(unspecified)",
267 		    tgtgid);
268 	if (curgid != tgtgid) {
269 		if (setgid(tgtgid)) {
270 			syslog(LOG_ERR, "setgid to %d: %m", (int)tgtgid);
271 			exit(1);
272 		}
273 		if (setgroups(0, NULL)) {
274 			syslog(LOG_ERR, "setgroups: %m");
275 			exit(1);
276 		}
277 	}
278 
279 	if (curuid != tgtuid) {
280 		if (setuid(tgtuid)) {
281 			syslog(LOG_ERR, "setuid to %d: %m", (int)tgtuid);
282 			exit(1);
283 		}
284 	}
285 
286 	on = 1;
287 	if (ioctl(fd, FIONBIO, &on) < 0) {
288 		syslog(LOG_ERR, "ioctl(FIONBIO): %m");
289 		exit(1);
290 	}
291 	fromlen = sizeof (from);
292 	n = recvfrom(fd, buf, sizeof (buf), 0,
293 	    (struct sockaddr *)&from, &fromlen);
294 	if (n < 0) {
295 		syslog(LOG_ERR, "recvfrom: %m");
296 		exit(1);
297 	}
298 	/*
299 	 * Now that we have read the message out of the UDP
300 	 * socket, we fork and exit.  Thus, inetd will go back
301 	 * to listening to the tftp port, and the next request
302 	 * to come in will start up a new instance of tftpd.
303 	 *
304 	 * We do this so that inetd can run tftpd in "wait" mode.
305 	 * The problem with tftpd running in "nowait" mode is that
306 	 * inetd may get one or more successful "selects" on the
307 	 * tftp port before we do our receive, so more than one
308 	 * instance of tftpd may be started up.  Worse, if tftpd
309 	 * break before doing the above "recvfrom", inetd would
310 	 * spawn endless instances, clogging the system.
311 	 */
312 	{
313 		int pid;
314 		int i, j;
315 
316 		for (i = 1; i < 20; i++) {
317 		    pid = fork();
318 		    if (pid < 0) {
319 				sleep(i);
320 				/*
321 				 * flush out to most recently sent request.
322 				 *
323 				 * This may drop some request, but those
324 				 * will be resent by the clients when
325 				 * they timeout.  The positive effect of
326 				 * this flush is to (try to) prevent more
327 				 * than one tftpd being started up to service
328 				 * a single request from a single client.
329 				 */
330 				j = sizeof from;
331 				i = recvfrom(fd, buf, sizeof (buf), 0,
332 				    (struct sockaddr *)&from, &j);
333 				if (i > 0) {
334 					n = i;
335 					fromlen = j;
336 				}
337 		    } else {
338 				break;
339 		    }
340 		}
341 		if (pid < 0) {
342 			syslog(LOG_ERR, "fork: %m");
343 			exit(1);
344 		} else if (pid != 0) {
345 			exit(0);
346 		}
347 	}
348 
349 	/*
350 	 * remember what address this was sent to, so we can respond on the
351 	 * same interface
352 	 */
353 	len = sizeof(me);
354 	if (getsockname(fd, (struct sockaddr *)&me, &len) == 0) {
355 		switch (me.ss_family) {
356 		case AF_INET:
357 			((struct sockaddr_in *)&me)->sin_port = 0;
358 			break;
359 		case AF_INET6:
360 			((struct sockaddr_in6 *)&me)->sin6_port = 0;
361 			break;
362 		default:
363 			/* unsupported */
364 			break;
365 		}
366 	} else {
367 		memset(&me, 0, sizeof(me));
368 		me.ss_family = from.ss_family;
369 		me.ss_len = from.ss_len;
370 	}
371 
372 	alarm(0);
373 	close(fd);
374 	close(1);
375 	peer = socket(from.ss_family, SOCK_DGRAM, 0);
376 	if (peer < 0) {
377 		syslog(LOG_ERR, "socket: %m");
378 		exit(1);
379 	}
380 	if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
381 		syslog(LOG_ERR, "bind: %m");
382 		exit(1);
383 	}
384 	if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
385 		syslog(LOG_ERR, "connect: %m");
386 		exit(1);
387 	}
388 	soopt = 65536;	/* larger than we'll ever need */
389 	if (setsockopt(peer, SOL_SOCKET, SO_SNDBUF, (void *) &soopt, sizeof(soopt)) < 0) {
390 		syslog(LOG_ERR, "set SNDBUF: %m");
391 		exit(1);
392 	}
393 	if (setsockopt(peer, SOL_SOCKET, SO_RCVBUF, (void *) &soopt, sizeof(soopt)) < 0) {
394 		syslog(LOG_ERR, "set RCVBUF: %m");
395 		exit(1);
396 	}
397 
398 	tp = (struct tftphdr *)buf;
399 	tp->th_opcode = ntohs(tp->th_opcode);
400 	if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
401 		tftp(tp, n);
402 	exit(1);
403 }
404 
405 static int
406 blk_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
407 	    int *ackl, int *ec)
408 {
409 	unsigned long bsize;
410 	char *endp;
411 	int l;
412 
413 	/*
414 	 * On these failures, we could just ignore the blocksize option.
415 	 * Perhaps that should be a command-line option.
416 	 */
417 	errno = 0;
418 	bsize = strtoul(val, &endp, 10);
419 	if ((bsize == ULONG_MAX && errno == ERANGE) || *endp) {
420 		syslog(LOG_NOTICE, "%s: %s request for %s: "
421 			"illegal value %s for blksize option",
422 			verifyhost((struct sockaddr *)&from),
423 			tp->th_opcode == WRQ ? "write" : "read",
424 			tp->th_stuff, val);
425 		return 0;
426 	}
427 	if (bsize < 8 || bsize > 65464) {
428 		syslog(LOG_NOTICE, "%s: %s request for %s: "
429 			"out of range value %s for blksize option",
430 			verifyhost((struct sockaddr *)&from),
431 			tp->th_opcode == WRQ ? "write" : "read",
432 			tp->th_stuff, val);
433 		return 0;
434 	}
435 
436 	tftp_blksize = bsize;
437 	strcpy(ack + *ackl, "blksize");
438 	*ackl += 8;
439 	l = sprintf(ack + *ackl, "%lu", bsize);
440 	*ackl += l + 1;
441 
442 	return 0;
443 }
444 
445 static int
446 timeout_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
447 		int *ackl, int *ec)
448 {
449 	unsigned long tout;
450 	char *endp;
451 	int l;
452 
453 	errno = 0;
454 	tout = strtoul(val, &endp, 10);
455 	if ((tout == ULONG_MAX && errno == ERANGE) || *endp) {
456 		syslog(LOG_NOTICE, "%s: %s request for %s: "
457 			"illegal value %s for timeout option",
458 			verifyhost((struct sockaddr *)&from),
459 			tp->th_opcode == WRQ ? "write" : "read",
460 			tp->th_stuff, val);
461 		return 0;
462 	}
463 	if (tout < 1 || tout > 255) {
464 		syslog(LOG_NOTICE, "%s: %s request for %s: "
465 			"out of range value %s for timeout option",
466 			verifyhost((struct sockaddr *)&from),
467 			tp->th_opcode == WRQ ? "write" : "read",
468 			tp->th_stuff, val);
469 		return 0;
470 	}
471 
472 	rexmtval = tout;
473 	strcpy(ack + *ackl, "timeout");
474 	*ackl += 8;
475 	l = sprintf(ack + *ackl, "%lu", tout);
476 	*ackl += l + 1;
477 
478 	/*
479 	 * Arbitrarily pick a maximum timeout on a request to 3
480 	 * retransmissions if the interval timeout is more than
481 	 * one minute.  Longest possible timeout is therefore
482 	 * 3 * 255 - 1, or 764 seconds.
483 	 */
484 	if (rexmtval > 60) {
485 		maxtimeout = rexmtval * 3;
486 	} else {
487 		maxtimeout = rexmtval * 5;
488 	}
489 
490 	return 0;
491 }
492 
493 static int
494 tsize_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
495 	      int *ackl, int *ec)
496 {
497 	unsigned long fsize;
498 	char *endp;
499 
500 	/*
501 	 * Maximum file even with extended tftp is 65535 blocks of
502 	 * length 65464, or 4290183240 octets (4784056 less than 2^32).
503 	 * unsigned long is at least 32 bits on all NetBSD archs.
504 	 */
505 
506 	errno = 0;
507 	fsize = strtoul(val, &endp, 10);
508 	if ((fsize == ULONG_MAX && errno == ERANGE) || *endp) {
509 		syslog(LOG_NOTICE, "%s: %s request for %s: "
510 			"illegal value %s for tsize option",
511 			verifyhost((struct sockaddr *)&from),
512 			tp->th_opcode == WRQ ? "write" : "read",
513 			tp->th_stuff, val);
514 		return 0;
515 	}
516 	if (fsize > (unsigned long) 65535 * 65464) {
517 		syslog(LOG_NOTICE, "%s: %s request for %s: "
518 			"out of range value %s for tsize option",
519 			verifyhost((struct sockaddr *)&from),
520 			tp->th_opcode == WRQ ? "write" : "read",
521 			tp->th_stuff, val);
522 		return 0;
523 	}
524 
525 	tftp_opt_tsize = 1;
526 	tftp_tsize = fsize;
527 	/*
528 	 * We will report this later -- either replying with the fsize (WRQ)
529 	 * or replying with the actual filesize (RRQ).
530 	 */
531 
532 	return 0;
533 }
534 
535 struct tftp_options {
536 	char *o_name;
537 	int (*o_handler)(struct tftphdr *, char *, char *, char *,
538 			 int *, int *);
539 } options[] = {
540 	{ "blksize", blk_handler },
541 	{ "timeout", timeout_handler },
542 	{ "tsize", tsize_handler },
543 	{ NULL, NULL }
544 };
545 
546 /*
547  * Get options for an extended tftp session.  Stuff the ones we
548  * recognize in oackbuf.
549  */
550 static int
551 get_options(struct tftphdr *tp, char *cp, int size, char *ackb,
552     int *alen, int *err)
553 {
554 	struct tftp_options *op;
555 	char *option, *value, *endp;
556 	int r, rv=0, ec=0;
557 
558 	endp = cp + size;
559 	while (cp < endp) {
560 		option = cp;
561 		while (*cp && cp < endp) {
562 			*cp = tolower(*cp);
563 			cp++;
564 		}
565 		if (*cp) {
566 			/* if we have garbage at the end, just ignore it */
567 			break;
568 		}
569 		cp++;	/* skip over NUL */
570 		value = cp;
571 		while (*cp && cp < endp) {
572 			cp++;
573 		}
574 		if (*cp) {
575 			/* if we have garbage at the end, just ignore it */
576 			break;
577 		}
578 		cp++;
579 		for (op = options; op->o_name; op++) {
580 			if (strcmp(op->o_name, option) == 0)
581 				break;
582 		}
583 		if (op->o_name) {
584 			r = op->o_handler(tp, option, value, ackb, alen, &ec);
585 			if (r < 0) {
586 				rv = -1;
587 				break;
588 			}
589 			rv++;
590 		} /* else ignore unknown options */
591 	}
592 
593 	if (rv < 0)
594 		*err = ec;
595 
596 	return rv;
597 }
598 
599 /*
600  * Handle initial connection protocol.
601  */
602 static void
603 tftp(struct tftphdr *tp, int size)
604 {
605 	struct formats *pf;
606 	char	*cp;
607 	char	*filename, *mode;
608 	int	 first, ecode, alen, etftp=0, r;
609 
610 	first = 1;
611 	mode = NULL;
612 
613 	filename = cp = tp->th_stuff;
614 again:
615 	while (cp < buf + size) {
616 		if (*cp == '\0')
617 			break;
618 		cp++;
619 	}
620 	if (*cp != '\0') {
621 		nak(EBADOP);
622 		exit(1);
623 	}
624 	if (first) {
625 		mode = ++cp;
626 		first = 0;
627 		goto again;
628 	}
629 	for (cp = mode; *cp; cp++)
630 		if (isupper(*cp))
631 			*cp = tolower(*cp);
632 	for (pf = formats; pf->f_mode; pf++)
633 		if (strcmp(pf->f_mode, mode) == 0)
634 			break;
635 	if (pf->f_mode == 0) {
636 		nak(EBADOP);
637 		exit(1);
638 	}
639 	/*
640 	 * cp currently points to the NUL byte following the mode.
641 	 *
642 	 * If we have some valid options, then let's assume that we're
643 	 * now dealing with an extended tftp session.  Note that if we
644 	 * don't get any options, then we *must* assume that we do not
645 	 * have an extended tftp session.  If we get options, we fill
646 	 * in the ack buf to acknowledge them.  If we skip that, then
647 	 * the client *must* assume that we are not using an extended
648 	 * session.
649 	 */
650 	size -= (++cp - (char *) tp);
651 	if (size > 0 && *cp) {
652 		alen = 2; /* Skip over opcode */
653 		r = get_options(tp, cp, size, oackbuf, &alen, &ecode);
654 		if (r > 0) {
655 			etftp = 1;
656 		} else if (r < 0) {
657 			nak(ecode);
658 			exit(1);
659 		}
660 	}
661 	ecode = (*pf->f_validate)(&filename, tp->th_opcode);
662 	if (logging) {
663 		syslog(LOG_INFO, "%s: %s request for %s: %s",
664 			verifyhost((struct sockaddr *)&from),
665 			tp->th_opcode == WRQ ? "write" : "read",
666 			filename, errtomsg(ecode));
667 	}
668 	if (ecode) {
669 		/*
670 		 * Avoid storms of naks to a RRQ broadcast for a relative
671 		 * bootfile pathname from a diskless Sun.
672 		 */
673 		if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
674 			exit(0);
675 		nak(ecode);
676 		exit(1);
677 	}
678 
679 	if (etftp) {
680 		struct tftphdr *oack_h;
681 
682 		if (tftp_opt_tsize) {
683 			int l;
684 
685 			strcpy(oackbuf + alen, "tsize");
686 			alen += 6;
687 			l = sprintf(oackbuf + alen, "%u", tftp_tsize);
688 			alen += l + 1;
689 		}
690 		oack_h = (struct tftphdr *) oackbuf;
691 		oack_h->th_opcode = htons(OACK);
692 	}
693 
694 	if (tp->th_opcode == WRQ)
695 		(*pf->f_recv)(pf, etftp, alen);
696 	else
697 		(*pf->f_send)(pf, etftp, alen);
698 	exit(0);
699 }
700 
701 
702 FILE *file;
703 
704 /*
705  * Validate file access.  Since we
706  * have no uid or gid, for now require
707  * file to exist and be publicly
708  * readable/writable.
709  * If we were invoked with arguments
710  * from inetd then the file must also be
711  * in one of the given directory prefixes.
712  */
713 int
714 validate_access(char **filep, int mode)
715 {
716 	struct stat	 stbuf;
717 	struct dirlist	*dirp;
718 	static char	 pathname[MAXPATHLEN];
719 	char		*filename;
720 	int		 fd;
721 
722 	filename = *filep;
723 
724 	/*
725 	 * Prevent tricksters from getting around the directory restrictions
726 	 */
727 	if (strstr(filename, "/../"))
728 		return (EACCESS);
729 
730 	if (*filename == '/') {
731 		/*
732 		 * Allow the request if it's in one of the approved locations.
733 		 * Special case: check the null prefix ("/") by looking
734 		 * for length = 1 and relying on the arg. processing that
735 		 * it's a /.
736 		 */
737 		for (dirp = dirs; dirp->name != NULL; dirp++) {
738 			if (dirp->len == 1 ||
739 			    (!strncmp(filename, dirp->name, dirp->len) &&
740 			     filename[dirp->len] == '/'))
741 				    break;
742 		}
743 		/* If directory list is empty, allow access to any file */
744 		if (dirp->name == NULL && dirp != dirs)
745 			return (EACCESS);
746 		if (stat(filename, &stbuf) < 0)
747 			return (errno == ENOENT ? ENOTFOUND : EACCESS);
748 		if (!S_ISREG(stbuf.st_mode))
749 			return (ENOTFOUND);
750 		if (mode == RRQ) {
751 			if ((stbuf.st_mode & S_IROTH) == 0)
752 				return (EACCESS);
753 		} else {
754 			if ((stbuf.st_mode & S_IWOTH) == 0)
755 				return (EACCESS);
756 		}
757 	} else {
758 		/*
759 		 * Relative file name: search the approved locations for it.
760 		 */
761 
762 		if (!strncmp(filename, "../", 3))
763 			return (EACCESS);
764 
765 		/*
766 		 * Find the first file that exists in any of the directories,
767 		 * check access on it.
768 		 */
769 		if (dirs[0].name != NULL) {
770 			for (dirp = dirs; dirp->name != NULL; dirp++) {
771 				snprintf(pathname, sizeof pathname, "%s/%s",
772 				    dirp->name, filename);
773 				if (stat(pathname, &stbuf) == 0 &&
774 				    (stbuf.st_mode & S_IFMT) == S_IFREG) {
775 					break;
776 				}
777 			}
778 			if (dirp->name == NULL)
779 				return (ENOTFOUND);
780 			if (mode == RRQ && !(stbuf.st_mode & S_IROTH))
781 				return (EACCESS);
782 			if (mode == WRQ && !(stbuf.st_mode & S_IWOTH))
783 				return (EACCESS);
784 			*filep = filename = pathname;
785 		} else {
786 			/*
787 			 * If there's no directory list, take our cue from the
788 			 * absolute file request check above (*filename == '/'),
789 			 * and allow access to anything.
790 			 */
791 			if (stat(filename, &stbuf) < 0)
792 				return (errno == ENOENT ? ENOTFOUND : EACCESS);
793 			if (!S_ISREG(stbuf.st_mode))
794 				return (ENOTFOUND);
795 			if (mode == RRQ) {
796 				if ((stbuf.st_mode & S_IROTH) == 0)
797 					return (EACCESS);
798 			} else {
799 				if ((stbuf.st_mode & S_IWOTH) == 0)
800 					return (EACCESS);
801 			}
802 			*filep = filename;
803 		}
804 	}
805 
806 	if (tftp_opt_tsize && mode == RRQ)
807 		tftp_tsize = (unsigned long) stbuf.st_size;
808 
809 	fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY | O_TRUNC);
810 	if (fd < 0)
811 		return (errno + 100);
812 	file = fdopen(fd, (mode == RRQ)? "r":"w");
813 	if (file == NULL) {
814 		close(fd);
815 		return (errno + 100);
816 	}
817 	return (0);
818 }
819 
820 int	timeout;
821 jmp_buf	timeoutbuf;
822 
823 void
824 timer(int dummy)
825 {
826 
827 	timeout += rexmtval;
828 	if (timeout >= maxtimeout)
829 		exit(1);
830 	longjmp(timeoutbuf, 1);
831 }
832 
833 static const char *
834 opcode(int code)
835 {
836 	static char buf[64];
837 
838 	switch (code) {
839 	case RRQ:
840 		return "RRQ";
841 	case WRQ:
842 		return "WRQ";
843 	case DATA:
844 		return "DATA";
845 	case ACK:
846 		return "ACK";
847 	case ERROR:
848 		return "ERROR";
849 	case OACK:
850 		return "OACK";
851 	default:
852 		(void)snprintf(buf, sizeof(buf), "*code %d*", code);
853 		return buf;
854 	}
855 }
856 
857 /*
858  * Send the requested file.
859  */
860 void
861 sendfile(struct formats *pf, int etftp, int acklength)
862 {
863 	volatile unsigned int block;
864 	struct tftphdr	*dp;
865 	struct tftphdr	*ap;    /* ack packet */
866 	int		 size, n;
867 
868 	signal(SIGALRM, timer);
869 	ap = (struct tftphdr *)ackbuf;
870 	if (etftp) {
871 		dp = (struct tftphdr *)oackbuf;
872 		size = acklength - 4;
873 		block = 0;
874 	} else {
875 		dp = r_init();
876 		size = 0;
877 		block = 1;
878 	}
879 
880 	do {
881 		if (block > 0) {
882 			size = readit(file, &dp, tftp_blksize, pf->f_convert);
883 			if (size < 0) {
884 				nak(errno + 100);
885 				goto abort;
886 			}
887 			dp->th_opcode = htons((u_short)DATA);
888 			dp->th_block = htons((u_short)block);
889 		}
890 		timeout = 0;
891 		(void)setjmp(timeoutbuf);
892 
893 send_data:
894 		if (!etftp && debug)
895 			syslog(LOG_DEBUG, "Send DATA %u", block);
896 		if ((n = send(peer, dp, size + 4, 0)) != size + 4) {
897 			syslog(LOG_ERR, "tftpd: write: %m");
898 			goto abort;
899 		}
900 		if (block)
901 			read_ahead(file, tftp_blksize, pf->f_convert);
902 		for ( ; ; ) {
903 			alarm(rexmtval);        /* read the ack */
904 			n = recv(peer, ackbuf, tftp_blksize, 0);
905 			alarm(0);
906 			if (n < 0) {
907 				syslog(LOG_ERR, "tftpd: read: %m");
908 				goto abort;
909 			}
910 			ap->th_opcode = ntohs((u_short)ap->th_opcode);
911 			ap->th_block = ntohs((u_short)ap->th_block);
912 			switch (ap->th_opcode) {
913 			case ERROR:
914 				goto abort;
915 
916 			case ACK:
917 				if (ap->th_block == 0) {
918 					etftp = 0;
919 					acklength = 0;
920 					dp = r_init();
921 					goto done;
922 				}
923 				if (ap->th_block == block)
924 					goto done;
925 				if (debug)
926 					syslog(LOG_DEBUG, "Resync ACK %u != %u",
927 					    (unsigned int)ap->th_block, block);
928 				/* Re-synchronize with the other side */
929 				(void) synchnet(peer, tftp_blksize);
930 				if (ap->th_block == (block -1))
931 					goto send_data;
932 			default:
933 				syslog(LOG_INFO, "Received %s in sendfile\n",
934 				    opcode(dp->th_opcode));
935 			}
936 
937 		}
938 done:
939 		if (debug)
940 			syslog(LOG_DEBUG, "Received ACK for block %u", block);
941 		block++;
942 	} while (size == tftp_blksize || block == 1);
943 abort:
944 	(void) fclose(file);
945 }
946 
947 void
948 justquit(int dummy)
949 {
950 
951 	exit(0);
952 }
953 
954 /*
955  * Receive a file.
956  */
957 void
958 recvfile(struct formats *pf, int etftp, int acklength)
959 {
960 	volatile unsigned int block;
961 	struct tftphdr	*dp;
962 	struct tftphdr	*ap;    /* ack buffer */
963 	int		 n, size;
964 
965 	signal(SIGALRM, timer);
966 	dp = w_init();
967 	ap = (struct tftphdr *)oackbuf;
968 	block = 0;
969 	do {
970 		timeout = 0;
971 		if (etftp == 0) {
972 			ap = (struct tftphdr *)ackbuf;
973 			ap->th_opcode = htons((u_short)ACK);
974 			ap->th_block = htons((u_short)block);
975 			acklength = 4;
976 		}
977 		if (debug)
978 			syslog(LOG_DEBUG, "Sending ACK for block %u\n", block);
979 		block++;
980 		(void) setjmp(timeoutbuf);
981 send_ack:
982 		if (send(peer, ap, acklength, 0) != acklength) {
983 			syslog(LOG_ERR, "tftpd: write: %m");
984 			goto abort;
985 		}
986 		write_behind(file, pf->f_convert);
987 		for ( ; ; ) {
988 			alarm(rexmtval);
989 			n = recv(peer, dp, tftp_blksize + 4, 0);
990 			alarm(0);
991 			if (n < 0) {            /* really? */
992 				syslog(LOG_ERR, "tftpd: read: %m");
993 				goto abort;
994 			}
995 			etftp = 0;
996 			dp->th_opcode = ntohs((u_short)dp->th_opcode);
997 			dp->th_block = ntohs((u_short)dp->th_block);
998 			if (debug)
999 				syslog(LOG_DEBUG, "Received %s for block %u",
1000 				    opcode(dp->th_opcode),
1001 				    (unsigned int)dp->th_block);
1002 
1003 			switch (dp->th_opcode) {
1004 			case ERROR:
1005 				goto abort;
1006 			case DATA:
1007 				if (dp->th_block == block)
1008 					goto done;   /* normal */
1009 				if (debug)
1010 					syslog(LOG_DEBUG, "Resync %u != %u",
1011 					    (unsigned int)dp->th_block, block);
1012 				/* Re-synchronize with the other side */
1013 				(void) synchnet(peer, tftp_blksize);
1014 				if (dp->th_block == (block-1))
1015 					goto send_ack;          /* rexmit */
1016 				break;
1017 			default:
1018 				syslog(LOG_INFO, "Received %s in recvfile\n",
1019 				    opcode(dp->th_opcode));
1020 				break;
1021 			}
1022 		}
1023 done:
1024 		if (debug)
1025 			syslog(LOG_DEBUG, "Got block %u", block);
1026 		/*  size = write(file, dp->th_data, n - 4); */
1027 		size = writeit(file, &dp, n - 4, pf->f_convert);
1028 		if (size != (n-4)) {                    /* ahem */
1029 			if (size < 0) nak(errno + 100);
1030 			else nak(ENOSPACE);
1031 			goto abort;
1032 		}
1033 	} while (size == tftp_blksize);
1034 	write_behind(file, pf->f_convert);
1035 	(void) fclose(file);            /* close data file */
1036 
1037 	ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
1038 	ap->th_block = htons((u_short)(block));
1039 	if (debug)
1040 		syslog(LOG_DEBUG, "Send final ACK %u", block);
1041 	(void) send(peer, ackbuf, 4, 0);
1042 
1043 	signal(SIGALRM, justquit);      /* just quit on timeout */
1044 	alarm(rexmtval);
1045 	n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
1046 	alarm(0);
1047 	if (n >= 4 &&                   /* if read some data */
1048 	    dp->th_opcode == DATA &&    /* and got a data block */
1049 	    block == dp->th_block) {	/* then my last ack was lost */
1050 		(void) send(peer, ackbuf, 4, 0);     /* resend final ack */
1051 	}
1052 abort:
1053 	return;
1054 }
1055 
1056 const struct errmsg {
1057 	int		 e_code;
1058 	const char	*e_msg;
1059 } errmsgs[] = {
1060 	{ EUNDEF,	"Undefined error code" },
1061 	{ ENOTFOUND,	"File not found" },
1062 	{ EACCESS,	"Access violation" },
1063 	{ ENOSPACE,	"Disk full or allocation exceeded" },
1064 	{ EBADOP,	"Illegal TFTP operation" },
1065 	{ EBADID,	"Unknown transfer ID" },
1066 	{ EEXISTS,	"File already exists" },
1067 	{ ENOUSER,	"No such user" },
1068 	{ EOPTNEG,	"Option negotiation failed" },
1069 	{ -1,		0 }
1070 };
1071 
1072 static const char *
1073 errtomsg(int error)
1074 {
1075 	static char ebuf[20];
1076 	const struct errmsg *pe;
1077 
1078 	if (error == 0)
1079 		return ("success");
1080 	for (pe = errmsgs; pe->e_code >= 0; pe++)
1081 		if (pe->e_code == error)
1082 			return (pe->e_msg);
1083 	snprintf(ebuf, sizeof(ebuf), "error %d", error);
1084 	return (ebuf);
1085 }
1086 
1087 /*
1088  * Send a nak packet (error message).
1089  * Error code passed in is one of the
1090  * standard TFTP codes, or a UNIX errno
1091  * offset by 100.
1092  */
1093 static void
1094 nak(int error)
1095 {
1096 	const struct errmsg *pe;
1097 	struct tftphdr *tp;
1098 	int	length;
1099 	size_t	msglen;
1100 
1101 	tp = (struct tftphdr *)buf;
1102 	tp->th_opcode = htons((u_short)ERROR);
1103 	msglen = sizeof(buf) - (&tp->th_msg[0] - buf);
1104 	for (pe = errmsgs; pe->e_code >= 0; pe++)
1105 		if (pe->e_code == error)
1106 			break;
1107 	if (pe->e_code < 0) {
1108 		tp->th_code = EUNDEF;   /* set 'undef' errorcode */
1109 		strlcpy(tp->th_msg, strerror(error - 100), msglen);
1110 	} else {
1111 		tp->th_code = htons((u_short)error);
1112 		strlcpy(tp->th_msg, pe->e_msg, msglen);
1113 	}
1114 	if (debug)
1115 		syslog(LOG_DEBUG, "Send NACK %s", tp->th_msg);
1116 	length = strlen(tp->th_msg);
1117 	msglen = &tp->th_msg[length + 1] - buf;
1118 	if (send(peer, buf, msglen, 0) != msglen)
1119 		syslog(LOG_ERR, "nak: %m");
1120 }
1121 
1122 static char *
1123 verifyhost(struct sockaddr *fromp)
1124 {
1125 	static char hbuf[MAXHOSTNAMELEN];
1126 
1127 	if (getnameinfo(fromp, fromp->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0))
1128 		strlcpy(hbuf, "?", sizeof(hbuf));
1129 	return (hbuf);
1130 }
1131