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