19b50d902SRodney W. Grimes /* 29b50d902SRodney W. Grimes * Copyright (c) 1983, 1993 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 69b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 79b50d902SRodney W. Grimes * are met: 89b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 99b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 109b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 129b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 139b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 149b50d902SRodney W. Grimes * must display the following acknowledgement: 159b50d902SRodney W. Grimes * This product includes software developed by the University of 169b50d902SRodney W. Grimes * California, Berkeley and its contributors. 179b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 189b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 199b50d902SRodney W. Grimes * without specific prior written permission. 209b50d902SRodney W. Grimes * 219b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 229b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 239b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 249b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 259b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 269b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 279b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 289b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 299b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 309b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 319b50d902SRodney W. Grimes * SUCH DAMAGE. 329b50d902SRodney W. Grimes */ 339b50d902SRodney W. Grimes 346dfc2060SDavid Malone #if 0 359b50d902SRodney W. Grimes #ifndef lint 366dfc2060SDavid Malone static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; 376dfc2060SDavid Malone #endif /* not lint */ 38fd129a02SPhilippe Charnier #endif 399b50d902SRodney W. Grimes 406dfc2060SDavid Malone #include <sys/cdefs.h> 416dfc2060SDavid Malone __FBSDID("$FreeBSD$"); 426dfc2060SDavid Malone 439b50d902SRodney W. Grimes /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 449b50d902SRodney W. Grimes 459b50d902SRodney W. Grimes /* 469b50d902SRodney W. Grimes * TFTP User Program -- Protocol Machines 479b50d902SRodney W. Grimes */ 489b50d902SRodney W. Grimes #include <sys/socket.h> 49*752fa694SWarner Losh #include <sys/stat.h> 509b50d902SRodney W. Grimes 519b50d902SRodney W. Grimes #include <netinet/in.h> 529b50d902SRodney W. Grimes 539b50d902SRodney W. Grimes #include <arpa/tftp.h> 549b50d902SRodney W. Grimes 55fd129a02SPhilippe Charnier #include <err.h> 564dac6235SHajimu UMEMOTO #include <netdb.h> 57*752fa694SWarner Losh #include <stdio.h> 58*752fa694SWarner Losh #include <stdlib.h> 59*752fa694SWarner Losh #include <string.h> 60*752fa694SWarner Losh #include <syslog.h> 619b50d902SRodney W. Grimes 62*752fa694SWarner Losh #include "tftp.h" 63*752fa694SWarner Losh #include "tftp-file.h" 64*752fa694SWarner Losh #include "tftp-utils.h" 65*752fa694SWarner Losh #include "tftp-io.h" 66*752fa694SWarner Losh #include "tftp-transfer.h" 67*752fa694SWarner Losh #include "tftp-options.h" 689b50d902SRodney W. Grimes 699b50d902SRodney W. Grimes /* 709b50d902SRodney W. Grimes * Send the requested file. 719b50d902SRodney W. Grimes */ 729b50d902SRodney W. Grimes void 73*752fa694SWarner Losh xmitfile(int peer, char *port, int fd, char *name, char *mode) 749b50d902SRodney W. Grimes { 75*752fa694SWarner Losh struct tftphdr *rp; 76*752fa694SWarner Losh int n, i; 77*752fa694SWarner Losh uint16_t block; 78*752fa694SWarner Losh uint32_t amount; 794dac6235SHajimu UMEMOTO struct sockaddr_storage serv; /* valid server port number */ 80*752fa694SWarner Losh char recvbuffer[MAXPKTSIZE]; 81*752fa694SWarner Losh struct tftp_stats tftp_stats; 829b50d902SRodney W. Grimes 83*752fa694SWarner Losh stats_init(&tftp_stats); 84*752fa694SWarner Losh 854dac6235SHajimu UMEMOTO memset(&serv, 0, sizeof(serv)); 86*752fa694SWarner Losh rp = (struct tftphdr *)recvbuffer; 879b50d902SRodney W. Grimes 88*752fa694SWarner Losh if (port == NULL) { 89*752fa694SWarner Losh struct servent *se; 90*752fa694SWarner Losh se = getservbyname("tftp", "udp"); 91*752fa694SWarner Losh ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port; 92*752fa694SWarner Losh } else 93*752fa694SWarner Losh ((struct sockaddr_in *)&peer_sock)->sin_port = 94*752fa694SWarner Losh htons(atoi(port)); 959b50d902SRodney W. Grimes 96*752fa694SWarner Losh for (i = 0; i < 12; i++) { 97*752fa694SWarner Losh struct sockaddr_storage from; 98*752fa694SWarner Losh 99*752fa694SWarner Losh /* Tell the other side what we want to do */ 100*752fa694SWarner Losh if (debug&DEBUG_SIMPLE) 101*752fa694SWarner Losh printf("Sending %s\n", name); 102*752fa694SWarner Losh 103*752fa694SWarner Losh n = send_wrq(peer, name, mode); 104*752fa694SWarner Losh if (n > 0) { 105*752fa694SWarner Losh printf("Cannot send WRQ packet\n"); 106*752fa694SWarner Losh return; 1079b50d902SRodney W. Grimes } 108*752fa694SWarner Losh 109*752fa694SWarner Losh /* 110*752fa694SWarner Losh * The first packet we receive has the new destination port 111*752fa694SWarner Losh * we have to send the next packets to. 1129b50d902SRodney W. Grimes */ 113*752fa694SWarner Losh n = receive_packet(peer, recvbuffer, 114*752fa694SWarner Losh MAXPKTSIZE, &from, timeoutpacket); 115*752fa694SWarner Losh 116*752fa694SWarner Losh /* We got some data! */ 117*752fa694SWarner Losh if (n >= 0) { 118*752fa694SWarner Losh ((struct sockaddr_in *)&peer_sock)->sin_port = 119*752fa694SWarner Losh ((struct sockaddr_in *)&from)->sin_port; 120*752fa694SWarner Losh break; 1219b50d902SRodney W. Grimes } 122*752fa694SWarner Losh 123*752fa694SWarner Losh /* This should be retried */ 124*752fa694SWarner Losh if (n == RP_TIMEOUT) { 125*752fa694SWarner Losh printf("Try %d, didn't receive answer from remote.\n", 126*752fa694SWarner Losh i + 1); 127*752fa694SWarner Losh continue; 1289b50d902SRodney W. Grimes } 129*752fa694SWarner Losh 130*752fa694SWarner Losh /* Everything else is fatal */ 131*752fa694SWarner Losh break; 1329b50d902SRodney W. Grimes } 133*752fa694SWarner Losh if (i == 12) { 134*752fa694SWarner Losh printf("Transfer timed out.\n"); 135*752fa694SWarner Losh return; 1369b50d902SRodney W. Grimes } 137*752fa694SWarner Losh if (rp->th_opcode == ERROR) { 138*752fa694SWarner Losh printf("Got ERROR, aborted\n"); 139*752fa694SWarner Losh return; 140*752fa694SWarner Losh } 141*752fa694SWarner Losh 142*752fa694SWarner Losh /* 143*752fa694SWarner Losh * If the first packet is an OACK instead of an ACK packet, 144*752fa694SWarner Losh * handle it different. 145*752fa694SWarner Losh */ 146*752fa694SWarner Losh if (rp->th_opcode == OACK) { 147*752fa694SWarner Losh if (!options_rfc_enabled) { 148*752fa694SWarner Losh printf("Got OACK while options are not enabled!\n"); 149*752fa694SWarner Losh send_error(peer, EBADOP); 150*752fa694SWarner Losh return; 151*752fa694SWarner Losh } 152*752fa694SWarner Losh 153*752fa694SWarner Losh parse_options(peer, rp->th_stuff, n + 2); 154*752fa694SWarner Losh } 155*752fa694SWarner Losh 156*752fa694SWarner Losh if (read_init(fd, NULL, mode) < 0) { 157*752fa694SWarner Losh warn("read_init()"); 158*752fa694SWarner Losh return; 159*752fa694SWarner Losh } 160*752fa694SWarner Losh 161*752fa694SWarner Losh block = 1; 162*752fa694SWarner Losh tftp_send(peer, &block, &tftp_stats); 163*752fa694SWarner Losh 164*752fa694SWarner Losh read_close(); 1659b50d902SRodney W. Grimes if (amount > 0) 166*752fa694SWarner Losh printstats("Sent", verbose, &tftp_stats); 167*752fa694SWarner Losh 168*752fa694SWarner Losh txrx_error = 1; 1699b50d902SRodney W. Grimes } 1709b50d902SRodney W. Grimes 1719b50d902SRodney W. Grimes /* 1729b50d902SRodney W. Grimes * Receive a file. 1739b50d902SRodney W. Grimes */ 1749b50d902SRodney W. Grimes void 175*752fa694SWarner Losh recvfile(int peer, char *port, int fd, char *name, char *mode) 1769b50d902SRodney W. Grimes { 177*752fa694SWarner Losh struct tftphdr *rp; 178*752fa694SWarner Losh uint16_t block; 179*752fa694SWarner Losh char recvbuffer[MAXPKTSIZE]; 180*752fa694SWarner Losh int n, i; 181*752fa694SWarner Losh struct tftp_stats tftp_stats; 182*752fa694SWarner Losh 183*752fa694SWarner Losh stats_init(&tftp_stats); 184*752fa694SWarner Losh 185*752fa694SWarner Losh rp = (struct tftphdr *)recvbuffer; 186*752fa694SWarner Losh 187*752fa694SWarner Losh if (port == NULL) { 188*752fa694SWarner Losh struct servent *se; 189*752fa694SWarner Losh se = getservbyname("tftp", "udp"); 190*752fa694SWarner Losh ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port; 191*752fa694SWarner Losh } else 192*752fa694SWarner Losh ((struct sockaddr_in *)&peer_sock)->sin_port = 193*752fa694SWarner Losh htons(atoi(port)); 194*752fa694SWarner Losh 195*752fa694SWarner Losh for (i = 0; i < 12; i++) { 1964dac6235SHajimu UMEMOTO struct sockaddr_storage from; 1979b50d902SRodney W. Grimes 198*752fa694SWarner Losh /* Tell the other side what we want to do */ 199*752fa694SWarner Losh if (debug&DEBUG_SIMPLE) 200*752fa694SWarner Losh printf("Requesting %s\n", name); 2019b50d902SRodney W. Grimes 202*752fa694SWarner Losh n = send_rrq(peer, name, mode); 203*752fa694SWarner Losh if (n > 0) { 204*752fa694SWarner Losh printf("Cannot send RRQ packet\n"); 205*752fa694SWarner Losh return; 2069b50d902SRodney W. Grimes } 2079b50d902SRodney W. Grimes 2089b50d902SRodney W. Grimes /* 209*752fa694SWarner Losh * The first packet we receive has the new destination port 210*752fa694SWarner Losh * we have to send the next packets to. 2119b50d902SRodney W. Grimes */ 212*752fa694SWarner Losh n = receive_packet(peer, recvbuffer, 213*752fa694SWarner Losh MAXPKTSIZE, &from, timeoutpacket); 2149b50d902SRodney W. Grimes 215*752fa694SWarner Losh /* We got something useful! */ 216*752fa694SWarner Losh if (n >= 0) { 217*752fa694SWarner Losh ((struct sockaddr_in *)&peer_sock)->sin_port = 218*752fa694SWarner Losh ((struct sockaddr_in *)&from)->sin_port; 2199b50d902SRodney W. Grimes break; 2209b50d902SRodney W. Grimes } 221*752fa694SWarner Losh 222*752fa694SWarner Losh /* We should retry if this happens */ 223*752fa694SWarner Losh if (n == RP_TIMEOUT) { 224*752fa694SWarner Losh printf("Try %d, didn't receive answer from remote.\n", 225*752fa694SWarner Losh i + 1); 226*752fa694SWarner Losh continue; 2279b50d902SRodney W. Grimes } 2289b50d902SRodney W. Grimes 229*752fa694SWarner Losh /* Otherwise it is a fatal error */ 230*752fa694SWarner Losh break; 2319b50d902SRodney W. Grimes } 2329b50d902SRodney W. Grimes 233*752fa694SWarner Losh if (rp->th_opcode == ERROR) { 234*752fa694SWarner Losh tftp_log(LOG_ERR, "Error code %d: %s", rp->th_code, rp->th_msg); 235*752fa694SWarner Losh return; 2369b50d902SRodney W. Grimes } 2379b50d902SRodney W. Grimes 238*752fa694SWarner Losh if (write_init(fd, NULL, mode) < 0) { 239*752fa694SWarner Losh warn("write_init"); 240*752fa694SWarner Losh return; 2419b50d902SRodney W. Grimes } 2429b50d902SRodney W. Grimes 243*752fa694SWarner Losh stats_init(&tftp_stats); 2449b50d902SRodney W. Grimes 245*752fa694SWarner Losh /* 246*752fa694SWarner Losh * If the first packet is an OACK packet instead of an DATA packet, 247*752fa694SWarner Losh * handle it different. 248*752fa694SWarner Losh */ 249*752fa694SWarner Losh if (rp->th_opcode == OACK) { 250*752fa694SWarner Losh if (!options_rfc_enabled) { 251*752fa694SWarner Losh printf("Got OACK while options are not enabled!\n"); 252*752fa694SWarner Losh send_error(peer, EBADOP); 253*752fa694SWarner Losh return; 2549b50d902SRodney W. Grimes } 2554dac6235SHajimu UMEMOTO 256*752fa694SWarner Losh parse_options(peer, rp->th_stuff, n + 2); 2574dac6235SHajimu UMEMOTO 258*752fa694SWarner Losh n = send_ack(peer, 0); 259*752fa694SWarner Losh if (n > 0) { 260*752fa694SWarner Losh printf("Cannot send ACK on OACK.\n"); 261*752fa694SWarner Losh return; 262*752fa694SWarner Losh } 263*752fa694SWarner Losh block = 0; 264*752fa694SWarner Losh tftp_receive(peer, &block, &tftp_stats, NULL, 0); 265*752fa694SWarner Losh } else { 266*752fa694SWarner Losh block = 1; 267*752fa694SWarner Losh tftp_receive(peer, &block, &tftp_stats, rp, n); 268*752fa694SWarner Losh } 2694dac6235SHajimu UMEMOTO 270*752fa694SWarner Losh write_close(); 271*752fa694SWarner Losh if (tftp_stats.amount > 0) 272*752fa694SWarner Losh printstats("Received", verbose, &tftp_stats); 273*752fa694SWarner Losh return; 2744dac6235SHajimu UMEMOTO } 275