1313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/* 2313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Copyright (c) 1983 Regents of the University of California. 3313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * All rights reserved. 4313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 5313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Redistribution and use in source and binary forms, with or without 6313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * modification, are permitted provided that the following conditions 7313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * are met: 8313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 1. Redistributions of source code must retain the above copyright 9313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * notice, this list of conditions and the following disclaimer. 10313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 2. Redistributions in binary form must reproduce the above copyright 11313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * notice, this list of conditions and the following disclaimer in the 12313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * documentation and/or other materials provided with the distribution. 13313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 3. All advertising materials mentioning features or use of this software 14313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * must display the following acknowledgement: 15313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * This product includes software developed by the University of 16313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * California, Berkeley and its contributors. 17313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 4. Neither the name of the University nor the names of its contributors 18313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * may be used to endorse or promote products derived from this software 19313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * without specific prior written permission. 20313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 21313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * SUCH DAMAGE. 32313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */ 33313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 34313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifndef lint 35313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittichar copyright[] = 36313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti"@(#) Copyright (c) 1983 Regents of the University of California.\n\ 37313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti All rights reserved.\n"; 38313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif /* not lint */ 39313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 40313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifndef lint 41313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/*static char sccsid[] = "from: @(#)tftpd.c 5.13 (Berkeley) 2/26/91";*/ 42313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/*static char rcsid[] = "$Id: tftpd.c,v 1.3 1993/08/01 18:28:53 mycroft Exp $";*/ 43313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif /* not lint */ 44313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 45313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/* 46313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Trivial file transfer protocol server. 47313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 48313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * This version includes many modifications by Jim Guyton <guyton@rand-unix> 49313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */ 50313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 51313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <sys/types.h> 52313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <sys/ioctl.h> 53313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <sys/stat.h> 54313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <unistd.h> 55313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <signal.h> 56313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <fcntl.h> 57313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 58313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <sys/socket.h> 59313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <netinet/in.h> 60313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <netdb.h> 61313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 62313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <setjmp.h> 63313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <syslog.h> 64313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <stdio.h> 65313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <errno.h> 66313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <ctype.h> 67313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <string.h> 68313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include <stdlib.h> 69313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 70313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#include "tftp.h" 71313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 72313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifndef MSG_CONFIRM 73313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define MSG_CONFIRM 0 74313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#warning Please, upgrade kernel, otherwise this tftpd has no advantages. 75313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif 76313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 77313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define TIMEOUT 5 78313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 79313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint peer; 80313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint rexmtval = TIMEOUT; 81313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint maxtimeout = 5*TIMEOUT; 82313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 83313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define PKTSIZE SEGSIZE+4 84313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittichar buf[PKTSIZE]; 85313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittichar ackbuf[PKTSIZE]; 86313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiunion { 87313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti struct sockaddr sa; 88313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti struct sockaddr_in sin; 89313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti struct sockaddr_in6 sin6; 90313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} from; 91313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittisocklen_t fromlen; 92313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 93313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#define MAXARG 1 94313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittichar *dirs[MAXARG+1]; 95313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 96313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid tftp(struct tftphdr *tp, int size) __attribute__((noreturn)); 97313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid nak(int error); 98313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint validate_access(char *filename, int mode); 99313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 100313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistruct formats; 101313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 102313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid sendfile(struct formats *pf); 103313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid recvfile(struct formats *pf); 104313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 105313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 106313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint main(int ac, char **av) 107313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{ 108313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti register struct tftphdr *tp; 109313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti register int n = 0; 110313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti int on = 1; 111313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 112313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti /* Sanity. If parent forgot to setuid() on us. */ 113313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (geteuid() == 0) { 114313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti setgid(65534); 115313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti setuid(65534); 116313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 117313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 118313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti ac--; av++; 119313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti while (ac-- > 0 && n < MAXARG) 120313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti dirs[n++] = *av++; 121313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 122313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti openlog("tftpd", LOG_PID, LOG_DAEMON); 123313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (ioctl(0, FIONBIO, &on) < 0) { 124313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "ioctl(FIONBIO): %m\n"); 125313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(1); 126313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 127313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti fromlen = sizeof (from); 128313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti n = recvfrom(0, buf, sizeof (buf), 0, 129313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti (struct sockaddr *)&from, &fromlen); 130313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (n < 0) { 131313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (errno != EAGAIN) 132313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "recvfrom: %m\n"); 133313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(1); 134313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 135313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti /* 136313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Now that we have read the message out of the UDP 137313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * socket, we fork and exit. Thus, inetd will go back 138313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * to listening to the tftp port, and the next request 139313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * to come in will start up a new instance of tftpd. 140313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 141313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * We do this so that inetd can run tftpd in "wait" mode. 142313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * The problem with tftpd running in "nowait" mode is that 143313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * inetd may get one or more successful "selects" on the 144313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * tftp port before we do our receive, so more than one 145313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * instance of tftpd may be started up. Worse, if tftpd 146313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * break before doing the above "recvfrom", inetd would 147313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * spawn endless instances, clogging the system. 148313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */ 149313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { 150313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti int pid; 151313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti int i; 152313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti socklen_t j; 153313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 154313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti for (i = 1; i < 20; i++) { 155313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti pid = fork(); 156313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (pid < 0) { 157313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti sleep(i); 158313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti /* 159313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * flush out to most recently sent request. 160313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * 161313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * This may drop some request, but those 162313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * will be resent by the clients when 163313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * they timeout. The positive effect of 164313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * this flush is to (try to) prevent more 165313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * than one tftpd being started up to service 166313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * a single request from a single client. 167313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */ 168313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti j = sizeof from; 169313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti i = recvfrom(0, buf, sizeof (buf), 0, 170313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti (struct sockaddr *)&from, &j); 171313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (i > 0) { 172313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti n = i; 173313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti fromlen = j; 174313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 175313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } else { 176313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti break; 177313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 178313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 179313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (pid < 0) { 180313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "fork: %m\n"); 181313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(1); 182313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } else if (pid != 0) { 183313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(0); 184313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 185313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 186313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti alarm(0); 187313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti close(0); 188313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti close(1); 189313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti peer = socket(from.sa.sa_family, SOCK_DGRAM, 0); 190313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (peer < 0) { 191313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "socket: %m\n"); 192313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(1); 193313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 194313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) { 195313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "connect: %m\n"); 196313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(1); 197313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 198313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti tp = (struct tftphdr *)buf; 199313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti tp->th_opcode = ntohs(tp->th_opcode); 200313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) 201313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti tftp(tp, n); 202313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(1); 203313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} 204313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 205313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistruct formats { 206313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti char *f_mode; 207313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti int (*f_validate)(char *filename, int mode); 208313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti void (*f_send)(struct formats*); 209313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti void (*f_recv)(struct formats*); 210313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti int f_convert; 211313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} formats[] = { 212313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { "netascii", validate_access, sendfile, recvfile, 1 }, 213313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { "octet", validate_access, sendfile, recvfile, 0 }, 214313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#ifdef notdef 215313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { "mail", validate_user, sendmail, recvmail, 1 }, 216313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti#endif 217313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { 0 } 218313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}; 219313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 220313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/* 221313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Handle initial connection protocol. 222313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */ 223313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid tftp(struct tftphdr *tp, int size) 224313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{ 225313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti register char *cp; 226313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti int first = 1, ecode; 227313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti register struct formats *pf; 228313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti char *filename, *mode = NULL; 229313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 230313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti filename = cp = tp->th_stuff; 231313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiagain: 232313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti while (cp < buf + size) { 233313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (*cp == '\0') 234313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti break; 235313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti cp++; 236313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 237313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (*cp != '\0') { 238313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti nak(EBADOP); 239313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(1); 240313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 241313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (first) { 242313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti mode = ++cp; 243313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti first = 0; 244313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti goto again; 245313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 246313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti for (cp = mode; *cp; cp++) 247313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (isupper(*cp)) 248313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti *cp = tolower(*cp); 249313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti for (pf = formats; pf->f_mode; pf++) 250313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (strcmp(pf->f_mode, mode) == 0) 251313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti break; 252313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (pf->f_mode == 0) { 253313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti nak(EBADOP); 254313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(1); 255313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 256313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti ecode = (*pf->f_validate)(filename, tp->th_opcode); 257313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (ecode) { 258313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti nak(ecode); 259313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(1); 260313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 261313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (tp->th_opcode == WRQ) 262313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti (*pf->f_recv)(pf); 263313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti else 264313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti (*pf->f_send)(pf); 265313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(0); 266313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} 267313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 268313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 269313379eb6b9da55f7371adef39a92153a0707d4aLorenzo ColittiFILE *file; 270313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 271313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/* 272313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Validate file access. Since we 273313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * have no uid or gid, for now require 274313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * file to exist and be publicly 275313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * readable/writable. 276313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * If we were invoked with arguments 277313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * from inetd then the file must also be 278313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * in one of the given directory prefixes. 279313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Note also, full path name must be 280313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * given as we have no login directory. 281313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */ 282313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint validate_access(char *filename, int mode) 283313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{ 284313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti struct stat stbuf; 285313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti int fd; 286313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti char *cp; 287313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti char fnamebuf[1024+512]; 288313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 289313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti for (cp = filename; *cp; cp++) { 290313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if(*cp == '.' && (cp == filename || strncmp(cp-1, "/../", 4) == 0)) { 291313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "bad path %s", filename); 292313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti return(EACCESS); 293313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 294313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 295313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 296313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (*filename == '/') 297313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti filename++; 298313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 299313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (!*dirs) { 300313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "no dirs"); 301313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti return EACCESS; 302313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 303313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti snprintf(fnamebuf, sizeof(fnamebuf)-1, "%s/%s", *dirs, filename); 304313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti filename = fnamebuf; 305313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 306313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (stat(filename, &stbuf) < 0) { 307313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "stat %s : %m", filename); 308313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti return (errno == ENOENT ? ENOTFOUND : EACCESS); 309313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 310313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (mode == RRQ) { 311313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if ((stbuf.st_mode&(S_IREAD >> 6)) == 0) { 312313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "not readable %s", filename); 313313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti return (EACCESS); 314313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 315313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } else { 316313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0) { 317313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "not writable %s", filename); 318313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti return (EACCESS); 319313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 320313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 321313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti fd = open(filename, mode == RRQ ? 0 : 1); 322313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (fd < 0) { 323313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "cannot open %s: %m", filename); 324313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti return (errno + 100); 325313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 326313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti file = fdopen(fd, (mode == RRQ)? "r":"w"); 327313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (file == NULL) { 328313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti return errno+100; 329313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 330313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti return (0); 331313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} 332313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 333313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint confirmed; 334313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiint timeout; 335313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittijmp_buf timeoutbuf; 336313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 337313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid timer(int signo) 338313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{ 339313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti confirmed = 0; 340313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti timeout += rexmtval; 341313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (timeout >= maxtimeout) 342313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(1); 343313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti longjmp(timeoutbuf, 1); 344313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} 345313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 346313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/* 347313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Send the requested file. 348313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */ 349313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid sendfile(struct formats *pf) 350313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{ 351313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti struct tftphdr *dp; 352313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti register struct tftphdr *ap; /* ack packet */ 353313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti volatile int block = 1; 354313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti int size, n; 355313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 356313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti confirmed = 0; 357313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti signal(SIGALRM, timer); 358313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti dp = r_init(); 359313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti ap = (struct tftphdr *)ackbuf; 360313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti do { 361313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti size = readit(file, &dp, pf->f_convert); 362313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (size < 0) { 363313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti nak(errno + 100); 364313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti goto abort; 365313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 366313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti dp->th_opcode = htons((u_short)DATA); 367313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti dp->th_block = htons((u_short)block); 368313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti timeout = 0; 369313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti (void) setjmp(timeoutbuf); 370313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 371313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittisend_data: 372313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (send(peer, dp, size + 4, confirmed) != size + 4) { 373313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "tftpd: write: %m\n"); 374313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti goto abort; 375313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 376313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti confirmed = 0; 377313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti read_ahead(file, pf->f_convert); 378313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti for ( ; ; ) { 379313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti alarm(rexmtval); /* read the ack */ 380313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti n = recv(peer, ackbuf, sizeof (ackbuf), 0); 381313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti alarm(0); 382313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (n < 0) { 383313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "tftpd: read: %m\n"); 384313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti goto abort; 385313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 386313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti ap->th_opcode = ntohs((u_short)ap->th_opcode); 387313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti ap->th_block = ntohs((u_short)ap->th_block); 388313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 389313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (ap->th_opcode == ERROR) 390313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti goto abort; 391313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 392313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (ap->th_opcode == ACK) { 393313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (ap->th_block == block) { 394313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti confirmed = MSG_CONFIRM; 395313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti break; 396313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 397313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti /* Re-synchronize with the other side */ 398313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti synchnet(peer); 399313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (ap->th_block == (block -1)) { 400313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti goto send_data; 401313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 402313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 403313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 404313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 405313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti block++; 406313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } while (size == SEGSIZE); 407313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiabort: 408313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti (void) fclose(file); 409313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} 410313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 411313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid justquit(int signo) 412313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{ 413313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti exit(0); 414313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} 415313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 416313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 417313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/* 418313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Receive a file. 419313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */ 420313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid recvfile(struct formats *pf) 421313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{ 422313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti struct tftphdr *dp; 423313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti register struct tftphdr *ap; /* ack buffer */ 424313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti volatile int block = 0, n, size; 425313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 426313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti confirmed = 0; 427313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti signal(SIGALRM, timer); 428313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti dp = w_init(); 429313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti ap = (struct tftphdr *)ackbuf; 430313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti do { 431313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti timeout = 0; 432313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti ap->th_opcode = htons((u_short)ACK); 433313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti ap->th_block = htons((u_short)block); 434313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti block++; 435313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti (void) setjmp(timeoutbuf); 436313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittisend_ack: 437313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (send(peer, ackbuf, 4, confirmed) != 4) { 438313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "tftpd: write: %m\n"); 439313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti goto abort; 440313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 441313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti confirmed = 0; 442313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti write_behind(file, pf->f_convert); 443313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti for ( ; ; ) { 444313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti alarm(rexmtval); 445313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti n = recv(peer, dp, PKTSIZE, 0); 446313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti alarm(0); 447313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (n < 0) { /* really? */ 448313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "tftpd: read: %m\n"); 449313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti goto abort; 450313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 451313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti dp->th_opcode = ntohs((u_short)dp->th_opcode); 452313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti dp->th_block = ntohs((u_short)dp->th_block); 453313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (dp->th_opcode == ERROR) 454313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti goto abort; 455313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (dp->th_opcode == DATA) { 456313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (dp->th_block == block) { 457313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti confirmed = MSG_CONFIRM; 458313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti break; /* normal */ 459313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 460313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti /* Re-synchronize with the other side */ 461313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti (void) synchnet(peer); 462313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (dp->th_block == (block-1)) 463313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti goto send_ack; /* rexmit */ 464313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 465313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 466313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti /* size = write(file, dp->th_data, n - 4); */ 467313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti size = writeit(file, &dp, n - 4, pf->f_convert); 468313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (size != (n-4)) { /* ahem */ 469313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (size < 0) nak(errno + 100); 470313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti else nak(ENOSPACE); 471313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti goto abort; 472313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 473313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } while (size == SEGSIZE); 474313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti write_behind(file, pf->f_convert); 475313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti (void) fclose(file); /* close data file */ 476313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 477313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ 478313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti ap->th_block = htons((u_short)(block)); 479313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti (void) send(peer, ackbuf, 4, confirmed); 480313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 481313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti signal(SIGALRM, justquit); /* just quit on timeout */ 482313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti alarm(rexmtval); 483313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */ 484313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti alarm(0); 485313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (n >= 4 && /* if read some data */ 486313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti dp->th_opcode == DATA && /* and got a data block */ 487313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti block == dp->th_block) { /* then my last ack was lost */ 488313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti (void) send(peer, ackbuf, 4, 0); /* resend final ack */ 489313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 490313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittiabort: 491313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti return; 492313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} 493313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 494313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittistruct errmsg { 495313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti int e_code; 496313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti char *e_msg; 497313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} errmsgs[] = { 498313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { EUNDEF, "Undefined error code" }, 499313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { ENOTFOUND, "File not found" }, 500313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { EACCESS, "Access violation" }, 501313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { ENOSPACE, "Disk full or allocation exceeded" }, 502313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { EBADOP, "Illegal TFTP operation" }, 503313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { EBADID, "Unknown transfer ID" }, 504313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { EEXISTS, "File already exists" }, 505313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { ENOUSER, "No such user" }, 506313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti { -1, 0 } 507313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti}; 508313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 509313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti/* 510313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Send a nak packet (error message). 511313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * Error code passed in is one of the 512313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * standard TFTP codes, or a UNIX errno 513313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti * offset by 100. 514313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti */ 515313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colittivoid nak(int error) 516313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti{ 517313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti register struct tftphdr *tp; 518313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti int length; 519313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti register struct errmsg *pe; 520313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti 521313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti tp = (struct tftphdr *)buf; 522313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti tp->th_opcode = htons((u_short)ERROR); 523313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti tp->th_code = htons((u_short)error); 524313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti for (pe = errmsgs; pe->e_code >= 0; pe++) 525313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (pe->e_code == error) 526313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti break; 527313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (pe->e_code < 0) { 528313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti pe->e_msg = strerror(error - 100); 529313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti tp->th_code = EUNDEF; /* set 'undef' errorcode */ 530313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti } 531313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti strcpy(tp->th_msg, pe->e_msg); 532313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti length = strlen(pe->e_msg); 533313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti tp->th_msg[length] = '\0'; 534313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti length += 5; 535313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti if (send(peer, buf, length, 0) != length) 536313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti syslog(LOG_ERR, "nak: %m\n"); 537313379eb6b9da55f7371adef39a92153a0707d4aLorenzo Colitti} 538