tftpd.c revision 113714
1207753Smm/*
2207753Smm * Copyright (c) 1983, 1993
3207753Smm *	The Regents of the University of California.  All rights reserved.
4207753Smm *
5207753Smm * Redistribution and use in source and binary forms, with or without
6207753Smm * modification, are permitted provided that the following conditions
7207753Smm * are met:
8207753Smm * 1. Redistributions of source code must retain the above copyright
9207753Smm *    notice, this list of conditions and the following disclaimer.
10207753Smm * 2. Redistributions in binary form must reproduce the above copyright
11207753Smm *    notice, this list of conditions and the following disclaimer in the
12207753Smm *    documentation and/or other materials provided with the distribution.
13207753Smm * 3. All advertising materials mentioning features or use of this software
14207753Smm *    must display the following acknowledgement:
15207753Smm *	This product includes software developed by the University of
16207753Smm *	California, Berkeley and its contributors.
17207753Smm * 4. Neither the name of the University nor the names of its contributors
18207753Smm *    may be used to endorse or promote products derived from this software
19207753Smm *    without specific prior written permission.
20207753Smm *
21207753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22207753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23207753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24207753Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25207753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26207753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27207753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28207753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29207753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30207753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31207753Smm * SUCH DAMAGE.
32207753Smm */
33207753Smm
34207753Smm#ifndef lint
35207753Smmstatic const char copyright[] =
36207753Smm"@(#) Copyright (c) 1983, 1993\n\
37207753Smm	The Regents of the University of California.  All rights reserved.\n";
38207753Smm#endif /* not lint */
39207753Smm
40207753Smm#ifndef lint
41207753Smm#if 0
42207753Smmstatic char sccsid[] = "@(#)tftpd.c	8.1 (Berkeley) 6/4/93";
43207753Smm#endif
44207753Smmstatic const char rcsid[] =
45207753Smm  "$FreeBSD: head/libexec/tftpd/tftpd.c 113714 2003-04-19 10:14:43Z billf $";
46207753Smm#endif /* not lint */
47207753Smm
48207753Smm/*
49207753Smm * Trivial file transfer protocol server.
50207753Smm *
51207753Smm * This version includes many modifications by Jim Guyton
52207753Smm * <guyton@rand-unix>.
53207753Smm */
54207753Smm
55207753Smm#include <sys/param.h>
56207753Smm#include <sys/ioctl.h>
57207753Smm#include <sys/stat.h>
58207753Smm#include <sys/socket.h>
59207753Smm#include <sys/types.h>
60207753Smm
61207753Smm#include <netinet/in.h>
62207753Smm#include <arpa/tftp.h>
63207753Smm#include <arpa/inet.h>
64207753Smm
65207753Smm#include <ctype.h>
66207753Smm#include <errno.h>
67207753Smm#include <fcntl.h>
68207753Smm#include <libutil.h>
69207753Smm#include <netdb.h>
70207753Smm#include <pwd.h>
71207753Smm#include <setjmp.h>
72207753Smm#include <signal.h>
73207753Smm#include <stdio.h>
74207753Smm#include <stdlib.h>
75207753Smm#include <string.h>
76207753Smm#include <syslog.h>
77207753Smm#include <unistd.h>
78207753Smm
79207753Smm#include "tftpsubs.h"
80207753Smm
81207753Smm#define	TIMEOUT		5
82207753Smm#define	MAX_TIMEOUTS	5
83
84int	peer;
85int	rexmtval = TIMEOUT;
86int	max_rexmtval = 2*TIMEOUT;
87
88#define	PKTSIZE	SEGSIZE+4
89char	buf[PKTSIZE];
90char	ackbuf[PKTSIZE];
91struct	sockaddr_storage from;
92int	fromlen;
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;
112
113static const char *errtomsg(int);
114static void  nak(int);
115static void  oack(void);
116
117static void  timer(int);
118static void  justquit(int);
119
120int
121main(int argc, char *argv[])
122{
123	struct tftphdr *tp;
124	int n;
125	int ch, on;
126	struct sockaddr_storage me;
127	int len;
128	char *chroot_dir = NULL;
129	struct passwd *nobody;
130	const char *chuser = "nobody";
131
132	openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
133	while ((ch = getopt(argc, argv, "cClns:u:")) != -1) {
134		switch (ch) {
135		case 'c':
136			ipchroot = 1;
137			break;
138		case 'C':
139			ipchroot = 2;
140			break;
141		case 'l':
142			logging = 1;
143			break;
144		case 'n':
145			suppress_naks = 1;
146			break;
147		case 's':
148			chroot_dir = optarg;
149			break;
150		case 'u':
151			chuser = optarg;
152			break;
153		default:
154			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
155		}
156	}
157	if (optind < argc) {
158		struct dirlist *dirp;
159
160		/* Get list of directory prefixes. Skip relative pathnames. */
161		for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
162		     optind++) {
163			if (argv[optind][0] == '/') {
164				dirp->name = argv[optind];
165				dirp->len  = strlen(dirp->name);
166				dirp++;
167			}
168		}
169	}
170	else if (chroot_dir) {
171		dirs->name = "/";
172		dirs->len = 1;
173	}
174	if (ipchroot > 0 && chroot_dir == NULL) {
175		syslog(LOG_ERR, "-c requires -s");
176		exit(1);
177	}
178
179	on = 1;
180	if (ioctl(0, FIONBIO, &on) < 0) {
181		syslog(LOG_ERR, "ioctl(FIONBIO): %m");
182		exit(1);
183	}
184	fromlen = sizeof (from);
185	n = recvfrom(0, buf, sizeof (buf), 0,
186	    (struct sockaddr *)&from, &fromlen);
187	if (n < 0) {
188		syslog(LOG_ERR, "recvfrom: %m");
189		exit(1);
190	}
191	/*
192	 * Now that we have read the message out of the UDP
193	 * socket, we fork and exit.  Thus, inetd will go back
194	 * to listening to the tftp port, and the next request
195	 * to come in will start up a new instance of tftpd.
196	 *
197	 * We do this so that inetd can run tftpd in "wait" mode.
198	 * The problem with tftpd running in "nowait" mode is that
199	 * inetd may get one or more successful "selects" on the
200	 * tftp port before we do our receive, so more than one
201	 * instance of tftpd may be started up.  Worse, if tftpd
202	 * break before doing the above "recvfrom", inetd would
203	 * spawn endless instances, clogging the system.
204	 */
205	{
206		int pid;
207		int i, j;
208
209		for (i = 1; i < 20; i++) {
210		    pid = fork();
211		    if (pid < 0) {
212				sleep(i);
213				/*
214				 * flush out to most recently sent request.
215				 *
216				 * This may drop some request, but those
217				 * will be resent by the clients when
218				 * they timeout.  The positive effect of
219				 * this flush is to (try to) prevent more
220				 * than one tftpd being started up to service
221				 * a single request from a single client.
222				 */
223				j = sizeof from;
224				i = recvfrom(0, buf, sizeof (buf), 0,
225				    (struct sockaddr *)&from, &j);
226				if (i > 0) {
227					n = i;
228					fromlen = j;
229				}
230		    } else {
231				break;
232		    }
233		}
234		if (pid < 0) {
235			syslog(LOG_ERR, "fork: %m");
236			exit(1);
237		} else if (pid != 0) {
238			exit(0);
239		}
240	}
241
242	/*
243	 * Since we exit here, we should do that only after the above
244	 * recvfrom to keep inetd from constantly forking should there
245	 * be a problem.  See the above comment about system clogging.
246	 */
247	if (chroot_dir) {
248		if (ipchroot > 0) {
249			char *tempchroot;
250			struct stat sb;
251			int statret;
252			struct sockaddr_storage ss;
253			char hbuf[NI_MAXHOST];
254
255			memcpy(&ss, &from, from.ss_len);
256			unmappedaddr((struct sockaddr_in6 *)&ss);
257			getnameinfo((struct sockaddr *)&ss, ss.ss_len,
258				    hbuf, sizeof(hbuf), NULL, 0,
259				    NI_NUMERICHOST | NI_WITHSCOPEID);
260			asprintf(&tempchroot, "%s/%s", chroot_dir, hbuf);
261			if (ipchroot == 2)
262				statret = stat(tempchroot, &sb);
263			if (ipchroot == 1 ||
264			    (statret == 0 && (sb.st_mode & S_IFDIR)))
265				chroot_dir = tempchroot;
266		}
267		/* Must get this before chroot because /etc might go away */
268		if ((nobody = getpwnam(chuser)) == NULL) {
269			syslog(LOG_ERR, "%s: no such user", chuser);
270			exit(1);
271		}
272		if (chroot(chroot_dir)) {
273			syslog(LOG_ERR, "chroot: %s: %m", chroot_dir);
274			exit(1);
275		}
276		chdir( "/" );
277		setuid(nobody->pw_uid);
278		setgroups(1, &nobody->pw_gid);
279	}
280
281	len = sizeof(me);
282	if (getsockname(0, (struct sockaddr *)&me, &len) == 0) {
283		switch (me.ss_family) {
284		case AF_INET:
285			((struct sockaddr_in *)&me)->sin_port = 0;
286			break;
287		case AF_INET6:
288			((struct sockaddr_in6 *)&me)->sin6_port = 0;
289			break;
290		default:
291			/* unsupported */
292			break;
293		}
294	} else {
295		memset(&me, 0, sizeof(me));
296		me.ss_family = from.ss_family;
297		me.ss_len = from.ss_len;
298	}
299	alarm(0);
300	close(0);
301	close(1);
302	peer = socket(from.ss_family, SOCK_DGRAM, 0);
303	if (peer < 0) {
304		syslog(LOG_ERR, "socket: %m");
305		exit(1);
306	}
307	if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
308		syslog(LOG_ERR, "bind: %m");
309		exit(1);
310	}
311	if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
312		syslog(LOG_ERR, "connect: %m");
313		exit(1);
314	}
315	tp = (struct tftphdr *)buf;
316	tp->th_opcode = ntohs(tp->th_opcode);
317	if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
318		tftp(tp, n);
319	exit(1);
320}
321
322struct formats;
323int	validate_access(char **, int);
324void	xmitfile(struct formats *);
325void	recvfile(struct formats *);
326
327struct formats {
328	const char	*f_mode;
329	int	(*f_validate)(char **, int);
330	void	(*f_send)(struct formats *);
331	void	(*f_recv)(struct formats *);
332	int	f_convert;
333} formats[] = {
334	{ "netascii",	validate_access,	xmitfile,	recvfile, 1 },
335	{ "octet",	validate_access,	xmitfile,	recvfile, 0 },
336#ifdef notdef
337	{ "mail",	validate_user,		sendmail,	recvmail, 1 },
338#endif
339	{ 0,		NULL,			NULL,		NULL,	  0 }
340};
341
342struct options {
343	const char	*o_type;
344	char	*o_request;
345	int	o_reply;	/* turn into union if need be */
346} options[] = {
347	{ "tsize",	NULL, 0 },		/* OPT_TSIZE */
348	{ "timeout",	NULL, 0 },		/* OPT_TIMEOUT */
349	{ NULL,		NULL, 0 }
350};
351
352enum opt_enum {
353	OPT_TSIZE = 0,
354	OPT_TIMEOUT,
355};
356
357/*
358 * Handle initial connection protocol.
359 */
360void
361tftp(struct tftphdr *tp, int size)
362{
363	char *cp;
364	int i, first = 1, has_options = 0, ecode;
365	struct formats *pf;
366	char *filename, *mode, *option, *ccp;
367
368	filename = cp = tp->th_stuff;
369again:
370	while (cp < buf + size) {
371		if (*cp == '\0')
372			break;
373		cp++;
374	}
375	if (*cp != '\0') {
376		nak(EBADOP);
377		exit(1);
378	}
379	if (first) {
380		mode = ++cp;
381		first = 0;
382		goto again;
383	}
384	for (cp = mode; *cp; cp++)
385		if (isupper(*cp))
386			*cp = tolower(*cp);
387	for (pf = formats; pf->f_mode; pf++)
388		if (strcmp(pf->f_mode, mode) == 0)
389			break;
390	if (pf->f_mode == 0) {
391		nak(EBADOP);
392		exit(1);
393	}
394	while (++cp < buf + size) {
395		for (i = 2, ccp = cp; i > 0; ccp++) {
396			if (ccp >= buf + size) {
397				/*
398				 * Don't reject the request, just stop trying
399				 * to parse the option and get on with it.
400				 * Some Apple OpenFirmware versions have
401				 * trailing garbage on the end of otherwise
402				 * valid requests.
403				 */
404				goto option_fail;
405			} else if (*ccp == '\0')
406				i--;
407		}
408		for (option = cp; *cp; cp++)
409			if (isupper(*cp))
410				*cp = tolower(*cp);
411		for (i = 0; options[i].o_type != NULL; i++)
412			if (strcmp(option, options[i].o_type) == 0) {
413				options[i].o_request = ++cp;
414				has_options = 1;
415			}
416		cp = ccp-1;
417	}
418
419option_fail:
420	if (options[OPT_TIMEOUT].o_request) {
421		int to = atoi(options[OPT_TIMEOUT].o_request);
422		if (to < 1 || to > 255) {
423			nak(EBADOP);
424			exit(1);
425		}
426		else if (to <= max_rexmtval)
427			options[OPT_TIMEOUT].o_reply = rexmtval = to;
428		else
429			options[OPT_TIMEOUT].o_request = NULL;
430	}
431
432	ecode = (*pf->f_validate)(&filename, tp->th_opcode);
433	if (has_options)
434		oack();
435	if (logging) {
436		char hbuf[NI_MAXHOST];
437
438		getnameinfo((struct sockaddr *)&from, from.ss_len,
439			    hbuf, sizeof(hbuf), NULL, 0,
440			    NI_WITHSCOPEID);
441		syslog(LOG_INFO, "%s: %s request for %s: %s", hbuf,
442			tp->th_opcode == WRQ ? "write" : "read",
443			filename, errtomsg(ecode));
444	}
445	if (ecode) {
446		/*
447		 * Avoid storms of naks to a RRQ broadcast for a relative
448		 * bootfile pathname from a diskless Sun.
449		 */
450		if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
451			exit(0);
452		nak(ecode);
453		exit(1);
454	}
455	if (tp->th_opcode == WRQ)
456		(*pf->f_recv)(pf);
457	else
458		(*pf->f_send)(pf);
459	exit(0);
460}
461
462
463FILE *file;
464
465/*
466 * Validate file access.  Since we
467 * have no uid or gid, for now require
468 * file to exist and be publicly
469 * readable/writable.
470 * If we were invoked with arguments
471 * from inetd then the file must also be
472 * in one of the given directory prefixes.
473 * Note also, full path name must be
474 * given as we have no login directory.
475 */
476int
477validate_access(char **filep, int mode)
478{
479	struct stat stbuf;
480	int	fd;
481	struct dirlist *dirp;
482	static char pathname[MAXPATHLEN];
483	char *filename = *filep;
484
485	/*
486	 * Prevent tricksters from getting around the directory restrictions
487	 */
488	if (strstr(filename, "/../"))
489		return (EACCESS);
490
491	if (*filename == '/') {
492		/*
493		 * Allow the request if it's in one of the approved locations.
494		 * Special case: check the null prefix ("/") by looking
495		 * for length = 1 and relying on the arg. processing that
496		 * it's a /.
497		 */
498		for (dirp = dirs; dirp->name != NULL; dirp++) {
499			if (dirp->len == 1 ||
500			    (!strncmp(filename, dirp->name, dirp->len) &&
501			     filename[dirp->len] == '/'))
502				    break;
503		}
504		/* If directory list is empty, allow access to any file */
505		if (dirp->name == NULL && dirp != dirs)
506			return (EACCESS);
507		if (stat(filename, &stbuf) < 0)
508			return (errno == ENOENT ? ENOTFOUND : EACCESS);
509		if ((stbuf.st_mode & S_IFMT) != S_IFREG)
510			return (ENOTFOUND);
511		if (mode == RRQ) {
512			if ((stbuf.st_mode & S_IROTH) == 0)
513				return (EACCESS);
514		} else {
515			if ((stbuf.st_mode & S_IWOTH) == 0)
516				return (EACCESS);
517		}
518	} else {
519		int err;
520
521		/*
522		 * Relative file name: search the approved locations for it.
523		 * Don't allow write requests that avoid directory
524		 * restrictions.
525		 */
526
527		if (!strncmp(filename, "../", 3))
528			return (EACCESS);
529
530		/*
531		 * If the file exists in one of the directories and isn't
532		 * readable, continue looking. However, change the error code
533		 * to give an indication that the file exists.
534		 */
535		err = ENOTFOUND;
536		for (dirp = dirs; dirp->name != NULL; dirp++) {
537			snprintf(pathname, sizeof(pathname), "%s/%s",
538				dirp->name, filename);
539			if (stat(pathname, &stbuf) == 0 &&
540			    (stbuf.st_mode & S_IFMT) == S_IFREG) {
541				if ((stbuf.st_mode & S_IROTH) != 0) {
542					break;
543				}
544				err = EACCESS;
545			}
546		}
547		if (dirp->name == NULL)
548			return (err);
549		*filep = filename = pathname;
550	}
551	if (options[OPT_TSIZE].o_request) {
552		if (mode == RRQ)
553			options[OPT_TSIZE].o_reply = stbuf.st_size;
554		else
555			/* XXX Allows writes of all sizes. */
556			options[OPT_TSIZE].o_reply =
557				atoi(options[OPT_TSIZE].o_request);
558	}
559	fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY|O_TRUNC);
560	if (fd < 0)
561		return (errno + 100);
562	file = fdopen(fd, (mode == RRQ)? "r":"w");
563	if (file == NULL) {
564		return errno+100;
565	}
566	return (0);
567}
568
569int	timeouts;
570jmp_buf	timeoutbuf;
571
572void
573timer(int sig __unused)
574{
575	if (++timeouts > MAX_TIMEOUTS)
576		exit(1);
577	longjmp(timeoutbuf, 1);
578}
579
580/*
581 * Send the requested file.
582 */
583void
584xmitfile(struct formats *pf)
585{
586	struct tftphdr *dp;
587	struct tftphdr *ap;    /* ack packet */
588	int size, n;
589	volatile unsigned short block;
590
591	signal(SIGALRM, timer);
592	dp = r_init();
593	ap = (struct tftphdr *)ackbuf;
594	block = 1;
595	do {
596		size = readit(file, &dp, pf->f_convert);
597		if (size < 0) {
598			nak(errno + 100);
599			goto abort;
600		}
601		dp->th_opcode = htons((u_short)DATA);
602		dp->th_block = htons((u_short)block);
603		timeouts = 0;
604		(void)setjmp(timeoutbuf);
605
606send_data:
607		{
608			int i, t = 1;
609			for (i = 0; ; i++){
610				if (send(peer, dp, size + 4, 0) != size + 4) {
611					sleep(t);
612					t = (t < 32) ? t<< 1 : t;
613					if (i >= 12) {
614						syslog(LOG_ERR, "write: %m");
615						goto abort;
616					}
617				}
618				break;
619			}
620		}
621		read_ahead(file, pf->f_convert);
622		for ( ; ; ) {
623			alarm(rexmtval);        /* read the ack */
624			n = recv(peer, ackbuf, sizeof (ackbuf), 0);
625			alarm(0);
626			if (n < 0) {
627				syslog(LOG_ERR, "read: %m");
628				goto abort;
629			}
630			ap->th_opcode = ntohs((u_short)ap->th_opcode);
631			ap->th_block = ntohs((u_short)ap->th_block);
632
633			if (ap->th_opcode == ERROR)
634				goto abort;
635
636			if (ap->th_opcode == ACK) {
637				if (ap->th_block == block)
638					break;
639				/* Re-synchronize with the other side */
640				(void) synchnet(peer);
641				if (ap->th_block == (block -1))
642					goto send_data;
643			}
644
645		}
646		block++;
647	} while (size == SEGSIZE);
648abort:
649	(void) fclose(file);
650}
651
652void
653justquit(int sig __unused)
654{
655	exit(0);
656}
657
658
659/*
660 * Receive a file.
661 */
662void
663recvfile(struct formats *pf)
664{
665	struct tftphdr *dp;
666	struct tftphdr *ap;    /* ack buffer */
667	int n, size;
668	volatile unsigned short block;
669
670	signal(SIGALRM, timer);
671	dp = w_init();
672	ap = (struct tftphdr *)ackbuf;
673	block = 0;
674	do {
675		timeouts = 0;
676		ap->th_opcode = htons((u_short)ACK);
677		ap->th_block = htons((u_short)block);
678		block++;
679		(void) setjmp(timeoutbuf);
680send_ack:
681		if (send(peer, ackbuf, 4, 0) != 4) {
682			syslog(LOG_ERR, "write: %m");
683			goto abort;
684		}
685		write_behind(file, pf->f_convert);
686		for ( ; ; ) {
687			alarm(rexmtval);
688			n = recv(peer, dp, PKTSIZE, 0);
689			alarm(0);
690			if (n < 0) {            /* really? */
691				syslog(LOG_ERR, "read: %m");
692				goto abort;
693			}
694			dp->th_opcode = ntohs((u_short)dp->th_opcode);
695			dp->th_block = ntohs((u_short)dp->th_block);
696			if (dp->th_opcode == ERROR)
697				goto abort;
698			if (dp->th_opcode == DATA) {
699				if (dp->th_block == block) {
700					break;   /* normal */
701				}
702				/* Re-synchronize with the other side */
703				(void) synchnet(peer);
704				if (dp->th_block == (block-1))
705					goto send_ack;          /* rexmit */
706			}
707		}
708		/*  size = write(file, dp->th_data, n - 4); */
709		size = writeit(file, &dp, n - 4, pf->f_convert);
710		if (size != (n-4)) {                    /* ahem */
711			if (size < 0) nak(errno + 100);
712			else nak(ENOSPACE);
713			goto abort;
714		}
715	} while (size == SEGSIZE);
716	write_behind(file, pf->f_convert);
717	(void) fclose(file);            /* close data file */
718
719	ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
720	ap->th_block = htons((u_short)(block));
721	(void) send(peer, ackbuf, 4, 0);
722
723	signal(SIGALRM, justquit);      /* just quit on timeout */
724	alarm(rexmtval);
725	n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
726	alarm(0);
727	if (n >= 4 &&                   /* if read some data */
728	    dp->th_opcode == DATA &&    /* and got a data block */
729	    block == dp->th_block) {	/* then my last ack was lost */
730		(void) send(peer, ackbuf, 4, 0);     /* resend final ack */
731	}
732abort:
733	return;
734}
735
736struct errmsg {
737	int	e_code;
738	const char	*e_msg;
739} errmsgs[] = {
740	{ EUNDEF,	"Undefined error code" },
741	{ ENOTFOUND,	"File not found" },
742	{ EACCESS,	"Access violation" },
743	{ ENOSPACE,	"Disk full or allocation exceeded" },
744	{ EBADOP,	"Illegal TFTP operation" },
745	{ EBADID,	"Unknown transfer ID" },
746	{ EEXISTS,	"File already exists" },
747	{ ENOUSER,	"No such user" },
748	{ EOPTNEG,	"Option negotiation" },
749	{ -1,		0 }
750};
751
752static const char *
753errtomsg(int error)
754{
755	static char ebuf[20];
756	struct errmsg *pe;
757	if (error == 0)
758		return "success";
759	for (pe = errmsgs; pe->e_code >= 0; pe++)
760		if (pe->e_code == error)
761			return pe->e_msg;
762	snprintf(ebuf, sizeof(buf), "error %d", error);
763	return ebuf;
764}
765
766/*
767 * Send a nak packet (error message).
768 * Error code passed in is one of the
769 * standard TFTP codes, or a UNIX errno
770 * offset by 100.
771 */
772static void
773nak(int error)
774{
775	struct tftphdr *tp;
776	int length;
777	struct errmsg *pe;
778
779	tp = (struct tftphdr *)buf;
780	tp->th_opcode = htons((u_short)ERROR);
781	tp->th_code = htons((u_short)error);
782	for (pe = errmsgs; pe->e_code >= 0; pe++)
783		if (pe->e_code == error)
784			break;
785	if (pe->e_code < 0) {
786		pe->e_msg = strerror(error - 100);
787		tp->th_code = EUNDEF;   /* set 'undef' errorcode */
788	}
789	strcpy(tp->th_msg, pe->e_msg);
790	length = strlen(pe->e_msg);
791	tp->th_msg[length] = '\0';
792	length += 5;
793	if (send(peer, buf, length, 0) != length)
794		syslog(LOG_ERR, "nak: %m");
795}
796
797/* translate IPv4 mapped IPv6 address to IPv4 address */
798static void
799unmappedaddr(struct sockaddr_in6 *sin6)
800{
801	struct sockaddr_in *sin4;
802	u_int32_t addr;
803	int port;
804
805	if (sin6->sin6_family != AF_INET6 ||
806	    !IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
807		return;
808	sin4 = (struct sockaddr_in *)sin6;
809	addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
810	port = sin6->sin6_port;
811	memset(sin4, 0, sizeof(struct sockaddr_in));
812	sin4->sin_addr.s_addr = addr;
813	sin4->sin_port = port;
814	sin4->sin_family = AF_INET;
815	sin4->sin_len = sizeof(struct sockaddr_in);
816}
817
818/*
819 * Send an oack packet (option acknowledgement).
820 */
821static void
822oack(void)
823{
824	struct tftphdr *tp, *ap;
825	int size, i, n;
826	char *bp;
827
828	tp = (struct tftphdr *)buf;
829	bp = buf + 2;
830	size = sizeof(buf) - 2;
831	tp->th_opcode = htons((u_short)OACK);
832	for (i = 0; options[i].o_type != NULL; i++) {
833		if (options[i].o_request) {
834			n = snprintf(bp, size, "%s%c%d", options[i].o_type,
835				     0, options[i].o_reply);
836			bp += n+1;
837			size -= n+1;
838			if (size < 0) {
839				syslog(LOG_ERR, "oack: buffer overflow");
840				exit(1);
841			}
842		}
843	}
844	size = bp - buf;
845	ap = (struct tftphdr *)ackbuf;
846	signal(SIGALRM, timer);
847	timeouts = 0;
848
849	(void)setjmp(timeoutbuf);
850	if (send(peer, buf, size, 0) != size) {
851		syslog(LOG_INFO, "oack: %m");
852		exit(1);
853	}
854
855	for (;;) {
856		alarm(rexmtval);
857		n = recv(peer, ackbuf, sizeof (ackbuf), 0);
858		alarm(0);
859		if (n < 0) {
860			syslog(LOG_ERR, "recv: %m");
861			exit(1);
862		}
863		ap->th_opcode = ntohs((u_short)ap->th_opcode);
864		ap->th_block = ntohs((u_short)ap->th_block);
865		if (ap->th_opcode == ERROR)
866			exit(1);
867		if (ap->th_opcode == ACK && ap->th_block == 0)
868			break;
869	}
870}
871