tftp.c revision 339060
1/* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#if 0 31#ifndef lint 32static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; 33#endif /* not lint */ 34#endif 35 36#include <sys/cdefs.h> 37__FBSDID("$FreeBSD: stable/10/usr.bin/tftp/tftp.c 339060 2018-10-01 16:09:20Z asomers $"); 38 39/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 40 41/* 42 * TFTP User Program -- Protocol Machines 43 */ 44#include <sys/socket.h> 45#include <sys/stat.h> 46 47#include <netinet/in.h> 48 49#include <arpa/tftp.h> 50 51#include <assert.h> 52#include <err.h> 53#include <netdb.h> 54#include <stdio.h> 55#include <stdlib.h> 56#include <string.h> 57#include <syslog.h> 58 59#include "tftp.h" 60#include "tftp-file.h" 61#include "tftp-utils.h" 62#include "tftp-io.h" 63#include "tftp-transfer.h" 64#include "tftp-options.h" 65 66/* 67 * Send the requested file. 68 */ 69void 70xmitfile(int peer, char *port, int fd, char *name, char *mode) 71{ 72 struct tftphdr *rp; 73 int n, i; 74 uint16_t block; 75 struct sockaddr_storage serv; /* valid server port number */ 76 char recvbuffer[MAXPKTSIZE]; 77 struct tftp_stats tftp_stats; 78 79 stats_init(&tftp_stats); 80 81 memset(&serv, 0, sizeof(serv)); 82 rp = (struct tftphdr *)recvbuffer; 83 84 if (port == NULL) { 85 struct servent *se; 86 se = getservbyname("tftp", "udp"); 87 assert(se != NULL); 88 ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port; 89 } else 90 ((struct sockaddr_in *)&peer_sock)->sin_port = 91 htons(atoi(port)); 92 93 for (i = 0; i < 12; i++) { 94 struct sockaddr_storage from; 95 96 /* Tell the other side what we want to do */ 97 if (debug&DEBUG_SIMPLE) 98 printf("Sending %s\n", name); 99 100 n = send_wrq(peer, name, mode); 101 if (n > 0) { 102 printf("Cannot send WRQ packet\n"); 103 return; 104 } 105 106 /* 107 * The first packet we receive has the new destination port 108 * we have to send the next packets to. 109 */ 110 n = receive_packet(peer, recvbuffer, 111 MAXPKTSIZE, &from, timeoutpacket); 112 113 /* We got some data! */ 114 if (n >= 0) { 115 ((struct sockaddr_in *)&peer_sock)->sin_port = 116 ((struct sockaddr_in *)&from)->sin_port; 117 break; 118 } 119 120 /* This should be retried */ 121 if (n == RP_TIMEOUT) { 122 printf("Try %d, didn't receive answer from remote.\n", 123 i + 1); 124 continue; 125 } 126 127 /* Everything else is fatal */ 128 break; 129 } 130 if (i == 12) { 131 printf("Transfer timed out.\n"); 132 return; 133 } 134 if (rp->th_opcode == ERROR) { 135 printf("Got ERROR, aborted\n"); 136 return; 137 } 138 139 /* 140 * If the first packet is an OACK instead of an ACK packet, 141 * handle it different. 142 */ 143 if (rp->th_opcode == OACK) { 144 if (!options_rfc_enabled) { 145 printf("Got OACK while options are not enabled!\n"); 146 send_error(peer, EBADOP); 147 return; 148 } 149 150 parse_options(peer, rp->th_stuff, n + 2); 151 } 152 153 if (read_init(fd, NULL, mode) < 0) { 154 warn("read_init()"); 155 return; 156 } 157 158 block = 1; 159 tftp_send(peer, &block, &tftp_stats); 160 161 read_close(); 162 if (tftp_stats.amount > 0) 163 printstats("Sent", verbose, &tftp_stats); 164 165 txrx_error = 1; 166} 167 168/* 169 * Receive a file. 170 */ 171void 172recvfile(int peer, char *port, int fd, char *name, char *mode) 173{ 174 struct tftphdr *rp; 175 uint16_t block; 176 char recvbuffer[MAXPKTSIZE]; 177 int n, i; 178 struct tftp_stats tftp_stats; 179 180 stats_init(&tftp_stats); 181 182 rp = (struct tftphdr *)recvbuffer; 183 184 if (port == NULL) { 185 struct servent *se; 186 se = getservbyname("tftp", "udp"); 187 assert(se != NULL); 188 ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port; 189 } else 190 ((struct sockaddr_in *)&peer_sock)->sin_port = 191 htons(atoi(port)); 192 193 for (i = 0; i < 12; i++) { 194 struct sockaddr_storage from; 195 196 /* Tell the other side what we want to do */ 197 if (debug&DEBUG_SIMPLE) 198 printf("Requesting %s\n", name); 199 200 n = send_rrq(peer, name, mode); 201 if (n > 0) { 202 printf("Cannot send RRQ packet\n"); 203 return; 204 } 205 206 /* 207 * The first packet we receive has the new destination port 208 * we have to send the next packets to. 209 */ 210 n = receive_packet(peer, recvbuffer, 211 MAXPKTSIZE, &from, timeoutpacket); 212 213 /* We got something useful! */ 214 if (n >= 0) { 215 ((struct sockaddr_in *)&peer_sock)->sin_port = 216 ((struct sockaddr_in *)&from)->sin_port; 217 break; 218 } 219 220 /* We should retry if this happens */ 221 if (n == RP_TIMEOUT) { 222 printf("Try %d, didn't receive answer from remote.\n", 223 i + 1); 224 continue; 225 } 226 227 /* Otherwise it is a fatal error */ 228 break; 229 } 230 if (i == 12) { 231 printf("Transfer timed out.\n"); 232 return; 233 } 234 if (rp->th_opcode == ERROR) { 235 tftp_log(LOG_ERR, "Error code %d: %s", rp->th_code, rp->th_msg); 236 return; 237 } 238 239 if (write_init(fd, NULL, mode) < 0) { 240 warn("write_init"); 241 return; 242 } 243 244 /* 245 * If the first packet is an OACK packet instead of an DATA packet, 246 * handle it different. 247 */ 248 if (rp->th_opcode == OACK) { 249 if (!options_rfc_enabled) { 250 printf("Got OACK while options are not enabled!\n"); 251 send_error(peer, EBADOP); 252 return; 253 } 254 255 parse_options(peer, rp->th_stuff, n + 2); 256 257 n = send_ack(peer, 0); 258 if (n > 0) { 259 printf("Cannot send ACK on OACK.\n"); 260 return; 261 } 262 block = 0; 263 tftp_receive(peer, &block, &tftp_stats, NULL, 0); 264 } else { 265 block = 1; 266 tftp_receive(peer, &block, &tftp_stats, rp, n); 267 } 268 269 if (tftp_stats.amount > 0) 270 printstats("Received", verbose, &tftp_stats); 271 return; 272} 273