tftpd.c revision 173852
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 173852 2007-11-23 00:05:29Z edwin $";
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#include <sys/time.h>
61
62#include <netinet/in.h>
63#include <arpa/tftp.h>
64#include <arpa/inet.h>
65
66#include <ctype.h>
67#include <errno.h>
68#include <fcntl.h>
69#include <libutil.h>
70#include <netdb.h>
71#include <pwd.h>
72#include <setjmp.h>
73#include <signal.h>
74#include <stdio.h>
75#include <stdlib.h>
76#include <string.h>
77#include <syslog.h>
78#include <unistd.h>
79
80#include "tftpsubs.h"
81
82#define	TIMEOUT		5
83#define	MAX_TIMEOUTS	5
84
85int	peer;
86int	rexmtval = TIMEOUT;
87int	max_rexmtval = 2*TIMEOUT;
88
89#define	PKTSIZE	SEGSIZE+4
90char	buf[PKTSIZE];
91char	ackbuf[PKTSIZE];
92struct	sockaddr_storage from;
93
94void	tftp(struct tftphdr *, int);
95static void unmappedaddr(struct sockaddr_in6 *);
96
97/*
98 * Null-terminated directory prefix list for absolute pathname requests and
99 * search list for relative pathname requests.
100 *
101 * MAXDIRS should be at least as large as the number of arguments that
102 * inetd allows (currently 20).
103 */
104#define MAXDIRS	20
105static struct dirlist {
106	const char	*name;
107	int	len;
108} dirs[MAXDIRS+1];
109static int	suppress_naks;
110static int	logging;
111static int	ipchroot;
112static int	create_new = 0;
113static char	*newfile_format = "%Y%m%d";
114static int	increase_name = 0;
115static mode_t	mask = S_IWGRP|S_IWOTH;
116
117static const char *errtomsg(int);
118static void  nak(int);
119static void  oack(void);
120
121static void  timer(int);
122static void  justquit(int);
123
124int
125main(int argc, char *argv[])
126{
127	struct tftphdr *tp;
128	socklen_t fromlen, len;
129	int n;
130	int ch, on;
131	struct sockaddr_storage me;
132	char *chroot_dir = NULL;
133	struct passwd *nobody;
134	const char *chuser = "nobody";
135
136	tzset();			/* syslog in localtime */
137
138	openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
139	while ((ch = getopt(argc, argv, "cCF:lns:u:U:wW")) != -1) {
140		switch (ch) {
141		case 'c':
142			ipchroot = 1;
143			break;
144		case 'C':
145			ipchroot = 2;
146			break;
147		case 'F':
148			newfile_format = optarg;
149			break;
150		case 'l':
151			logging = 1;
152			break;
153		case 'n':
154			suppress_naks = 1;
155			break;
156		case 's':
157			chroot_dir = optarg;
158			break;
159		case 'u':
160			chuser = optarg;
161			break;
162		case 'U':
163			mask = strtol(optarg, NULL, 0);
164			break;
165		case 'w':
166			create_new = 1;
167			break;
168		case 'W':
169			create_new = 1;
170			increase_name = 1;
171			break;
172		default:
173			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
174		}
175	}
176	if (optind < argc) {
177		struct dirlist *dirp;
178
179		/* Get list of directory prefixes. Skip relative pathnames. */
180		for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
181		     optind++) {
182			if (argv[optind][0] == '/') {
183				dirp->name = argv[optind];
184				dirp->len  = strlen(dirp->name);
185				dirp++;
186			}
187		}
188	}
189	else if (chroot_dir) {
190		dirs->name = "/";
191		dirs->len = 1;
192	}
193	if (ipchroot > 0 && chroot_dir == NULL) {
194		syslog(LOG_ERR, "-c requires -s");
195		exit(1);
196	}
197
198	umask(mask);
199
200	on = 1;
201	if (ioctl(0, FIONBIO, &on) < 0) {
202		syslog(LOG_ERR, "ioctl(FIONBIO): %m");
203		exit(1);
204	}
205	fromlen = sizeof (from);
206	n = recvfrom(0, buf, sizeof (buf), 0,
207	    (struct sockaddr *)&from, &fromlen);
208	if (n < 0) {
209		syslog(LOG_ERR, "recvfrom: %m");
210		exit(1);
211	}
212	/*
213	 * Now that we have read the message out of the UDP
214	 * socket, we fork and exit.  Thus, inetd will go back
215	 * to listening to the tftp port, and the next request
216	 * to come in will start up a new instance of tftpd.
217	 *
218	 * We do this so that inetd can run tftpd in "wait" mode.
219	 * The problem with tftpd running in "nowait" mode is that
220	 * inetd may get one or more successful "selects" on the
221	 * tftp port before we do our receive, so more than one
222	 * instance of tftpd may be started up.  Worse, if tftpd
223	 * break before doing the above "recvfrom", inetd would
224	 * spawn endless instances, clogging the system.
225	 */
226	{
227		int i, pid;
228
229		for (i = 1; i < 20; i++) {
230		    pid = fork();
231		    if (pid < 0) {
232				sleep(i);
233				/*
234				 * flush out to most recently sent request.
235				 *
236				 * This may drop some request, but those
237				 * will be resent by the clients when
238				 * they timeout.  The positive effect of
239				 * this flush is to (try to) prevent more
240				 * than one tftpd being started up to service
241				 * a single request from a single client.
242				 */
243				fromlen = sizeof from;
244				i = recvfrom(0, buf, sizeof (buf), 0,
245				    (struct sockaddr *)&from, &fromlen);
246				if (i > 0) {
247					n = i;
248				}
249		    } else {
250				break;
251		    }
252		}
253		if (pid < 0) {
254			syslog(LOG_ERR, "fork: %m");
255			exit(1);
256		} else if (pid != 0) {
257			exit(0);
258		}
259	}
260
261	/*
262	 * Since we exit here, we should do that only after the above
263	 * recvfrom to keep inetd from constantly forking should there
264	 * be a problem.  See the above comment about system clogging.
265	 */
266	if (chroot_dir) {
267		if (ipchroot > 0) {
268			char *tempchroot;
269			struct stat sb;
270			int statret;
271			struct sockaddr_storage ss;
272			char hbuf[NI_MAXHOST];
273
274			memcpy(&ss, &from, from.ss_len);
275			unmappedaddr((struct sockaddr_in6 *)&ss);
276			getnameinfo((struct sockaddr *)&ss, ss.ss_len,
277				    hbuf, sizeof(hbuf), NULL, 0,
278				    NI_NUMERICHOST);
279			asprintf(&tempchroot, "%s/%s", chroot_dir, hbuf);
280			if (ipchroot == 2)
281				statret = stat(tempchroot, &sb);
282			if (ipchroot == 1 ||
283			    (statret == 0 && (sb.st_mode & S_IFDIR)))
284				chroot_dir = tempchroot;
285		}
286		/* Must get this before chroot because /etc might go away */
287		if ((nobody = getpwnam(chuser)) == NULL) {
288			syslog(LOG_ERR, "%s: no such user", chuser);
289			exit(1);
290		}
291		if (chroot(chroot_dir)) {
292			syslog(LOG_ERR, "chroot: %s: %m", chroot_dir);
293			exit(1);
294		}
295		chdir("/");
296		setgroups(1, &nobody->pw_gid);
297		setuid(nobody->pw_uid);
298	}
299
300	len = sizeof(me);
301	if (getsockname(0, (struct sockaddr *)&me, &len) == 0) {
302		switch (me.ss_family) {
303		case AF_INET:
304			((struct sockaddr_in *)&me)->sin_port = 0;
305			break;
306		case AF_INET6:
307			((struct sockaddr_in6 *)&me)->sin6_port = 0;
308			break;
309		default:
310			/* unsupported */
311			break;
312		}
313	} else {
314		memset(&me, 0, sizeof(me));
315		me.ss_family = from.ss_family;
316		me.ss_len = from.ss_len;
317	}
318	alarm(0);
319	close(0);
320	close(1);
321	peer = socket(from.ss_family, SOCK_DGRAM, 0);
322	if (peer < 0) {
323		syslog(LOG_ERR, "socket: %m");
324		exit(1);
325	}
326	if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
327		syslog(LOG_ERR, "bind: %m");
328		exit(1);
329	}
330	if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
331		syslog(LOG_ERR, "connect: %m");
332		exit(1);
333	}
334	tp = (struct tftphdr *)buf;
335	tp->th_opcode = ntohs(tp->th_opcode);
336	if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
337		tftp(tp, n);
338	exit(1);
339}
340
341static void
342reduce_path(char *fn)
343{
344	char *slash, *ptr;
345
346	/* Reduce all "/+./" to "/" (just in case we've got "/./../" later */
347	while ((slash = strstr(fn, "/./")) != NULL) {
348		for (ptr = slash; ptr > fn && ptr[-1] == '/'; ptr--)
349			;
350		slash += 2;
351		while (*slash)
352			*++ptr = *++slash;
353	}
354
355	/* Now reduce all "/something/+../" to "/" */
356	while ((slash = strstr(fn, "/../")) != NULL) {
357		if (slash == fn)
358			break;
359		for (ptr = slash; ptr > fn && ptr[-1] == '/'; ptr--)
360			;
361		for (ptr--; ptr >= fn; ptr--)
362			if (*ptr == '/')
363				break;
364		if (ptr < fn)
365			break;
366		slash += 3;
367		while (*slash)
368			*++ptr = *++slash;
369	}
370}
371
372struct formats;
373int	validate_access(char **, int);
374void	xmitfile(struct formats *);
375void	recvfile(struct formats *);
376
377struct formats {
378	const char	*f_mode;
379	int	(*f_validate)(char **, int);
380	void	(*f_send)(struct formats *);
381	void	(*f_recv)(struct formats *);
382	int	f_convert;
383} formats[] = {
384	{ "netascii",	validate_access,	xmitfile,	recvfile, 1 },
385	{ "octet",	validate_access,	xmitfile,	recvfile, 0 },
386#ifdef notdef
387	{ "mail",	validate_user,		sendmail,	recvmail, 1 },
388#endif
389	{ 0,		NULL,			NULL,		NULL,	  0 }
390};
391
392struct options {
393	const char	*o_type;
394	char	*o_request;
395	int	o_reply;	/* turn into union if need be */
396} options[] = {
397	{ "tsize",	NULL, 0 },		/* OPT_TSIZE */
398	{ "timeout",	NULL, 0 },		/* OPT_TIMEOUT */
399	{ NULL,		NULL, 0 }
400};
401
402enum opt_enum {
403	OPT_TSIZE = 0,
404	OPT_TIMEOUT,
405};
406
407/*
408 * Handle initial connection protocol.
409 */
410void
411tftp(struct tftphdr *tp, int size)
412{
413	char *cp;
414	int i, first = 1, has_options = 0, ecode;
415	struct formats *pf;
416	char *filename, *mode, *option, *ccp;
417	char fnbuf[PATH_MAX];
418
419	cp = tp->th_stuff;
420again:
421	while (cp < buf + size) {
422		if (*cp == '\0')
423			break;
424		cp++;
425	}
426	if (*cp != '\0') {
427		nak(EBADOP);
428		exit(1);
429	}
430	i = cp - tp->th_stuff;
431	if (i >= sizeof(fnbuf)) {
432		nak(EBADOP);
433		exit(1);
434	}
435	memcpy(fnbuf, tp->th_stuff, i);
436	fnbuf[i] = '\0';
437	reduce_path(fnbuf);
438	filename = fnbuf;
439	if (first) {
440		mode = ++cp;
441		first = 0;
442		goto again;
443	}
444	for (cp = mode; *cp; cp++)
445		if (isupper(*cp))
446			*cp = tolower(*cp);
447	for (pf = formats; pf->f_mode; pf++)
448		if (strcmp(pf->f_mode, mode) == 0)
449			break;
450	if (pf->f_mode == 0) {
451		nak(EBADOP);
452		exit(1);
453	}
454	while (++cp < buf + size) {
455		for (i = 2, ccp = cp; i > 0; ccp++) {
456			if (ccp >= buf + size) {
457				/*
458				 * Don't reject the request, just stop trying
459				 * to parse the option and get on with it.
460				 * Some Apple Open Firmware versions have
461				 * trailing garbage on the end of otherwise
462				 * valid requests.
463				 */
464				goto option_fail;
465			} else if (*ccp == '\0')
466				i--;
467		}
468		for (option = cp; *cp; cp++)
469			if (isupper(*cp))
470				*cp = tolower(*cp);
471		for (i = 0; options[i].o_type != NULL; i++)
472			if (strcmp(option, options[i].o_type) == 0) {
473				options[i].o_request = ++cp;
474				has_options = 1;
475			}
476		cp = ccp-1;
477	}
478
479option_fail:
480	if (options[OPT_TIMEOUT].o_request) {
481		int to = atoi(options[OPT_TIMEOUT].o_request);
482		if (to < 1 || to > 255) {
483			nak(EBADOP);
484			exit(1);
485		}
486		else if (to <= max_rexmtval)
487			options[OPT_TIMEOUT].o_reply = rexmtval = to;
488		else
489			options[OPT_TIMEOUT].o_request = NULL;
490	}
491
492	ecode = (*pf->f_validate)(&filename, tp->th_opcode);
493	if (has_options && ecode == 0)
494		oack();
495	if (logging) {
496		char hbuf[NI_MAXHOST];
497
498		getnameinfo((struct sockaddr *)&from, from.ss_len,
499			    hbuf, sizeof(hbuf), NULL, 0, 0);
500		syslog(LOG_INFO, "%s: %s request for %s: %s", hbuf,
501			tp->th_opcode == WRQ ? "write" : "read",
502			filename, errtomsg(ecode));
503	}
504	if (ecode) {
505		/*
506		 * Avoid storms of naks to a RRQ broadcast for a relative
507		 * bootfile pathname from a diskless Sun.
508		 */
509		if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
510			exit(0);
511		nak(ecode);
512		exit(1);
513	}
514	if (tp->th_opcode == WRQ)
515		(*pf->f_recv)(pf);
516	else
517		(*pf->f_send)(pf);
518	exit(0);
519}
520
521
522FILE *file;
523
524/*
525 * Find the next value for YYYYMMDD.nn when the file to be written should
526 * be unique. Due to the limitations of nn, we will fail if nn reaches 100.
527 * Besides, that is four updates per hour on a file, which is kind of
528 * execessive anyway.
529 */
530static int
531find_next_name(char *filename, int *fd)
532{
533	int i;
534	time_t tval;
535	size_t len;
536	struct tm lt;
537	char yyyymmdd[MAXPATHLEN];
538	char newname[MAXPATHLEN];
539	struct stat sb;
540	int ret;
541
542	/* Create the YYYYMMDD part of the filename */
543	time(&tval);
544	lt = *localtime(&tval);
545	len = strftime(yyyymmdd, sizeof(yyyymmdd), newfile_format, &lt);
546	if (len == 0) {
547		syslog(LOG_WARNING,
548			"Filename suffix too long (%d characters maximum)",
549			MAXPATHLEN);
550		return (EACCESS);
551	}
552
553	/* Make sure the new filename is not too long */
554	if (strlen(filename) > MAXPATHLEN - len - 5) {
555		syslog(LOG_WARNING,
556			"Filename too long (%d characters, %d maximum)",
557			strlen(filename), MAXPATHLEN - len - 5);
558		return (EACCESS);
559	}
560
561	/* Find the first file which doesn't exist */
562	for (i = 0; i < 100; i++) {
563		sprintf(newname, "%s.%s.%02d", filename, yyyymmdd, i);
564		*fd = open(newname,
565		    O_WRONLY | O_CREAT | O_EXCL,
566		    S_IRUSR | S_IWUSR | S_IRGRP |
567		    S_IWGRP | S_IROTH | S_IWOTH);
568		if (*fd > 0)
569			return 0;
570	}
571
572	return (EEXIST);
573}
574
575/*
576 * Validate file access.  Since we
577 * have no uid or gid, for now require
578 * file to exist and be publicly
579 * readable/writable.
580 * If we were invoked with arguments
581 * from inetd then the file must also be
582 * in one of the given directory prefixes.
583 * Note also, full path name must be
584 * given as we have no login directory.
585 */
586int
587validate_access(char **filep, int mode)
588{
589	struct stat stbuf;
590	int	fd;
591	int	error;
592	struct dirlist *dirp;
593	static char pathname[MAXPATHLEN];
594	char *filename = *filep;
595
596	/*
597	 * Prevent tricksters from getting around the directory restrictions
598	 */
599	if (strstr(filename, "/../"))
600		return (EACCESS);
601
602	if (*filename == '/') {
603		/*
604		 * Allow the request if it's in one of the approved locations.
605		 * Special case: check the null prefix ("/") by looking
606		 * for length = 1 and relying on the arg. processing that
607		 * it's a /.
608		 */
609		for (dirp = dirs; dirp->name != NULL; dirp++) {
610			if (dirp->len == 1 ||
611			    (!strncmp(filename, dirp->name, dirp->len) &&
612			     filename[dirp->len] == '/'))
613				    break;
614		}
615		/* If directory list is empty, allow access to any file */
616		if (dirp->name == NULL && dirp != dirs)
617			return (EACCESS);
618		if (stat(filename, &stbuf) < 0)
619			return (errno == ENOENT ? ENOTFOUND : EACCESS);
620		if ((stbuf.st_mode & S_IFMT) != S_IFREG)
621			return (ENOTFOUND);
622		if (mode == RRQ) {
623			if ((stbuf.st_mode & S_IROTH) == 0)
624				return (EACCESS);
625		} else {
626			if ((stbuf.st_mode & S_IWOTH) == 0)
627				return (EACCESS);
628		}
629	} else {
630		int err;
631
632		/*
633		 * Relative file name: search the approved locations for it.
634		 * Don't allow write requests that avoid directory
635		 * restrictions.
636		 */
637
638		if (!strncmp(filename, "../", 3))
639			return (EACCESS);
640
641		/*
642		 * If the file exists in one of the directories and isn't
643		 * readable, continue looking. However, change the error code
644		 * to give an indication that the file exists.
645		 */
646		err = ENOTFOUND;
647		for (dirp = dirs; dirp->name != NULL; dirp++) {
648			snprintf(pathname, sizeof(pathname), "%s/%s",
649				dirp->name, filename);
650			if (stat(pathname, &stbuf) == 0 &&
651			    (stbuf.st_mode & S_IFMT) == S_IFREG) {
652				if ((stbuf.st_mode & S_IROTH) != 0) {
653					break;
654				}
655				err = EACCESS;
656			}
657		}
658		if (dirp->name != NULL)
659			*filep = filename = pathname;
660		else if (mode == RRQ)
661			return (err);
662	}
663	if (options[OPT_TSIZE].o_request) {
664		if (mode == RRQ)
665			options[OPT_TSIZE].o_reply = stbuf.st_size;
666		else
667			/* XXX Allows writes of all sizes. */
668			options[OPT_TSIZE].o_reply =
669				atoi(options[OPT_TSIZE].o_request);
670	}
671	if (mode == RRQ)
672		fd = open(filename, O_RDONLY);
673	else {
674		if (create_new) {
675			if (increase_name) {
676				error = find_next_name(filename, &fd);
677				if (error > 0)
678					return (error + 100);
679			} else
680				fd = open(filename,
681				    O_WRONLY | O_TRUNC | O_CREAT,
682				    S_IRUSR | S_IWUSR | S_IRGRP |
683				    S_IWGRP | S_IROTH | S_IWOTH );
684		} else
685			fd = open(filename, O_WRONLY | O_TRUNC);
686	}
687	if (fd < 0)
688		return (errno + 100);
689	file = fdopen(fd, (mode == RRQ)? "r":"w");
690	if (file == NULL) {
691		close(fd);
692		return (errno + 100);
693	}
694	return (0);
695}
696
697int	timeouts;
698jmp_buf	timeoutbuf;
699
700void
701timer(int sig __unused)
702{
703	if (++timeouts > MAX_TIMEOUTS)
704		exit(1);
705	longjmp(timeoutbuf, 1);
706}
707
708/*
709 * Send the requested file.
710 */
711void
712xmitfile(struct formats *pf)
713{
714	struct tftphdr *dp;
715	struct tftphdr *ap;    /* ack packet */
716	int size, n;
717	volatile unsigned short block;
718
719	signal(SIGALRM, timer);
720	dp = r_init();
721	ap = (struct tftphdr *)ackbuf;
722	block = 1;
723	do {
724		size = readit(file, &dp, pf->f_convert);
725		if (size < 0) {
726			nak(errno + 100);
727			goto abort;
728		}
729		dp->th_opcode = htons((u_short)DATA);
730		dp->th_block = htons((u_short)block);
731		timeouts = 0;
732		(void)setjmp(timeoutbuf);
733
734send_data:
735		{
736			int i, t = 1;
737			for (i = 0; ; i++){
738				if (send(peer, dp, size + 4, 0) != size + 4) {
739					sleep(t);
740					t = (t < 32) ? t<< 1 : t;
741					if (i >= 12) {
742						syslog(LOG_ERR, "write: %m");
743						goto abort;
744					}
745				}
746				break;
747			}
748		}
749		read_ahead(file, pf->f_convert);
750		for ( ; ; ) {
751			alarm(rexmtval);        /* read the ack */
752			n = recv(peer, ackbuf, sizeof (ackbuf), 0);
753			alarm(0);
754			if (n < 0) {
755				syslog(LOG_ERR, "read: %m");
756				goto abort;
757			}
758			ap->th_opcode = ntohs((u_short)ap->th_opcode);
759			ap->th_block = ntohs((u_short)ap->th_block);
760
761			if (ap->th_opcode == ERROR)
762				goto abort;
763
764			if (ap->th_opcode == ACK) {
765				if (ap->th_block == block)
766					break;
767				/* Re-synchronize with the other side */
768				(void) synchnet(peer);
769				if (ap->th_block == (block -1))
770					goto send_data;
771			}
772
773		}
774		block++;
775	} while (size == SEGSIZE);
776abort:
777	(void) fclose(file);
778}
779
780void
781justquit(int sig __unused)
782{
783	exit(0);
784}
785
786
787/*
788 * Receive a file.
789 */
790void
791recvfile(struct formats *pf)
792{
793	struct tftphdr *dp;
794	struct tftphdr *ap;    /* ack buffer */
795	int n, size;
796	volatile unsigned short block;
797
798	signal(SIGALRM, timer);
799	dp = w_init();
800	ap = (struct tftphdr *)ackbuf;
801	block = 0;
802	do {
803		timeouts = 0;
804		ap->th_opcode = htons((u_short)ACK);
805		ap->th_block = htons((u_short)block);
806		block++;
807		(void) setjmp(timeoutbuf);
808send_ack:
809		if (send(peer, ackbuf, 4, 0) != 4) {
810			syslog(LOG_ERR, "write: %m");
811			goto abort;
812		}
813		write_behind(file, pf->f_convert);
814		for ( ; ; ) {
815			alarm(rexmtval);
816			n = recv(peer, dp, PKTSIZE, 0);
817			alarm(0);
818			if (n < 0) {            /* really? */
819				syslog(LOG_ERR, "read: %m");
820				goto abort;
821			}
822			dp->th_opcode = ntohs((u_short)dp->th_opcode);
823			dp->th_block = ntohs((u_short)dp->th_block);
824			if (dp->th_opcode == ERROR)
825				goto abort;
826			if (dp->th_opcode == DATA) {
827				if (dp->th_block == block) {
828					break;   /* normal */
829				}
830				/* Re-synchronize with the other side */
831				(void) synchnet(peer);
832				if (dp->th_block == (block-1))
833					goto send_ack;          /* rexmit */
834			}
835		}
836		/*  size = write(file, dp->th_data, n - 4); */
837		size = writeit(file, &dp, n - 4, pf->f_convert);
838		if (size != (n-4)) {                    /* ahem */
839			if (size < 0) nak(errno + 100);
840			else nak(ENOSPACE);
841			goto abort;
842		}
843	} while (size == SEGSIZE);
844	write_behind(file, pf->f_convert);
845	(void) fclose(file);            /* close data file */
846
847	ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
848	ap->th_block = htons((u_short)(block));
849	(void) send(peer, ackbuf, 4, 0);
850
851	signal(SIGALRM, justquit);      /* just quit on timeout */
852	alarm(rexmtval);
853	n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
854	alarm(0);
855	if (n >= 4 &&                   /* if read some data */
856	    dp->th_opcode == DATA &&    /* and got a data block */
857	    block == dp->th_block) {	/* then my last ack was lost */
858		(void) send(peer, ackbuf, 4, 0);     /* resend final ack */
859	}
860abort:
861	return;
862}
863
864struct errmsg {
865	int	e_code;
866	const char	*e_msg;
867} errmsgs[] = {
868	{ EUNDEF,	"Undefined error code" },
869	{ ENOTFOUND,	"File not found" },
870	{ EACCESS,	"Access violation" },
871	{ ENOSPACE,	"Disk full or allocation exceeded" },
872	{ EBADOP,	"Illegal TFTP operation" },
873	{ EBADID,	"Unknown transfer ID" },
874	{ EEXISTS,	"File already exists" },
875	{ ENOUSER,	"No such user" },
876	{ EOPTNEG,	"Option negotiation" },
877	{ -1,		0 }
878};
879
880static const char *
881errtomsg(int error)
882{
883	static char ebuf[20];
884	struct errmsg *pe;
885	if (error == 0)
886		return "success";
887	for (pe = errmsgs; pe->e_code >= 0; pe++)
888		if (pe->e_code == error)
889			return pe->e_msg;
890	snprintf(ebuf, sizeof(buf), "error %d", error);
891	return ebuf;
892}
893
894/*
895 * Send a nak packet (error message).
896 * Error code passed in is one of the
897 * standard TFTP codes, or a UNIX errno
898 * offset by 100.
899 */
900static void
901nak(int error)
902{
903	struct tftphdr *tp;
904	int length;
905	struct errmsg *pe;
906
907	tp = (struct tftphdr *)buf;
908	tp->th_opcode = htons((u_short)ERROR);
909	tp->th_code = htons((u_short)error);
910	for (pe = errmsgs; pe->e_code >= 0; pe++)
911		if (pe->e_code == error)
912			break;
913	if (pe->e_code < 0) {
914		pe->e_msg = strerror(error - 100);
915		tp->th_code = EUNDEF;   /* set 'undef' errorcode */
916	}
917	strcpy(tp->th_msg, pe->e_msg);
918	length = strlen(pe->e_msg);
919	tp->th_msg[length] = '\0';
920	length += 5;
921	if (send(peer, buf, length, 0) != length)
922		syslog(LOG_ERR, "nak: %m");
923}
924
925/* translate IPv4 mapped IPv6 address to IPv4 address */
926static void
927unmappedaddr(struct sockaddr_in6 *sin6)
928{
929	struct sockaddr_in *sin4;
930	u_int32_t addr;
931	int port;
932
933	if (sin6->sin6_family != AF_INET6 ||
934	    !IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
935		return;
936	sin4 = (struct sockaddr_in *)sin6;
937	addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
938	port = sin6->sin6_port;
939	memset(sin4, 0, sizeof(struct sockaddr_in));
940	sin4->sin_addr.s_addr = addr;
941	sin4->sin_port = port;
942	sin4->sin_family = AF_INET;
943	sin4->sin_len = sizeof(struct sockaddr_in);
944}
945
946/*
947 * Send an oack packet (option acknowledgement).
948 */
949static void
950oack(void)
951{
952	struct tftphdr *tp, *ap;
953	int size, i, n;
954	char *bp;
955
956	tp = (struct tftphdr *)buf;
957	bp = buf + 2;
958	size = sizeof(buf) - 2;
959	tp->th_opcode = htons((u_short)OACK);
960	for (i = 0; options[i].o_type != NULL; i++) {
961		if (options[i].o_request) {
962			n = snprintf(bp, size, "%s%c%d", options[i].o_type,
963				     0, options[i].o_reply);
964			bp += n+1;
965			size -= n+1;
966			if (size < 0) {
967				syslog(LOG_ERR, "oack: buffer overflow");
968				exit(1);
969			}
970		}
971	}
972	size = bp - buf;
973	ap = (struct tftphdr *)ackbuf;
974	signal(SIGALRM, timer);
975	timeouts = 0;
976
977	(void)setjmp(timeoutbuf);
978	if (send(peer, buf, size, 0) != size) {
979		syslog(LOG_INFO, "oack: %m");
980		exit(1);
981	}
982
983	for (;;) {
984		alarm(rexmtval);
985		n = recv(peer, ackbuf, sizeof (ackbuf), 0);
986		alarm(0);
987		if (n < 0) {
988			syslog(LOG_ERR, "recv: %m");
989			exit(1);
990		}
991		ap->th_opcode = ntohs((u_short)ap->th_opcode);
992		ap->th_block = ntohs((u_short)ap->th_block);
993		if (ap->th_opcode == ERROR)
994			exit(1);
995		if (ap->th_opcode == ACK && ap->th_block == 0)
996			break;
997	}
998}
999