1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #if 0 33 #ifndef lint 34 static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; 35 #endif /* not lint */ 36 #endif 37 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD$"); 40 41 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 42 43 /* 44 * TFTP User Program -- Protocol Machines 45 */ 46 #include <sys/socket.h> 47 #include <sys/stat.h> 48 49 #include <netinet/in.h> 50 51 #include <arpa/tftp.h> 52 53 #include <err.h> 54 #include <netdb.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <syslog.h> 59 60 #include "tftp.h" 61 #include "tftp-file.h" 62 #include "tftp-utils.h" 63 #include "tftp-io.h" 64 #include "tftp-transfer.h" 65 #include "tftp-options.h" 66 67 /* 68 * Send the requested file. 69 */ 70 void 71 xmitfile(int peer, char *port, int fd, char *name, char *mode) 72 { 73 struct tftphdr *rp; 74 int n, i; 75 uint16_t block; 76 struct sockaddr_storage serv; /* valid server port number */ 77 char recvbuffer[MAXPKTSIZE]; 78 struct tftp_stats tftp_stats; 79 80 stats_init(&tftp_stats); 81 82 memset(&serv, 0, sizeof(serv)); 83 rp = (struct tftphdr *)recvbuffer; 84 85 if (port == NULL) { 86 struct servent *se; 87 se = getservbyname("tftp", "udp"); 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 */ 171 void 172 recvfile(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 ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port; 188 } else 189 ((struct sockaddr_in *)&peer_sock)->sin_port = 190 htons(atoi(port)); 191 192 for (i = 0; i < 12; i++) { 193 struct sockaddr_storage from; 194 195 /* Tell the other side what we want to do */ 196 if (debug&DEBUG_SIMPLE) 197 printf("Requesting %s\n", name); 198 199 n = send_rrq(peer, name, mode); 200 if (n > 0) { 201 printf("Cannot send RRQ packet\n"); 202 return; 203 } 204 205 /* 206 * The first packet we receive has the new destination port 207 * we have to send the next packets to. 208 */ 209 n = receive_packet(peer, recvbuffer, 210 MAXPKTSIZE, &from, timeoutpacket); 211 212 /* We got something useful! */ 213 if (n >= 0) { 214 ((struct sockaddr_in *)&peer_sock)->sin_port = 215 ((struct sockaddr_in *)&from)->sin_port; 216 break; 217 } 218 219 /* We should retry if this happens */ 220 if (n == RP_TIMEOUT) { 221 printf("Try %d, didn't receive answer from remote.\n", 222 i + 1); 223 continue; 224 } 225 226 /* Otherwise it is a fatal error */ 227 break; 228 } 229 if (i == 12) { 230 printf("Transfer timed out.\n"); 231 return; 232 } 233 if (rp->th_opcode == ERROR) { 234 tftp_log(LOG_ERR, "Error code %d: %s", rp->th_code, rp->th_msg); 235 return; 236 } 237 238 if (write_init(fd, NULL, mode) < 0) { 239 warn("write_init"); 240 return; 241 } 242 243 /* 244 * If the first packet is an OACK packet instead of an DATA packet, 245 * handle it different. 246 */ 247 if (rp->th_opcode == OACK) { 248 if (!options_rfc_enabled) { 249 printf("Got OACK while options are not enabled!\n"); 250 send_error(peer, EBADOP); 251 return; 252 } 253 254 parse_options(peer, rp->th_stuff, n + 2); 255 256 n = send_ack(peer, 0); 257 if (n > 0) { 258 printf("Cannot send ACK on OACK.\n"); 259 return; 260 } 261 block = 0; 262 tftp_receive(peer, &block, &tftp_stats, NULL, 0); 263 } else { 264 block = 1; 265 tftp_receive(peer, &block, &tftp_stats, rp, n); 266 } 267 268 write_close(); 269 if (tftp_stats.amount > 0) 270 printstats("Received", verbose, &tftp_stats); 271 return; 272 } 273