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