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 <assert.h> 54 #include <err.h> 55 #include <netdb.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <syslog.h> 60 61 #include "tftp.h" 62 #include "tftp-file.h" 63 #include "tftp-utils.h" 64 #include "tftp-io.h" 65 #include "tftp-transfer.h" 66 #include "tftp-options.h" 67 68 /* 69 * Send the requested file. 70 */ 71 int 72 xmitfile(int peer, char *port, int fd, char *name, char *mode) 73 { 74 struct tftphdr *rp; 75 int n, i, ret = 0; 76 uint16_t block; 77 struct sockaddr_storage serv; /* valid server port number */ 78 char recvbuffer[MAXPKTSIZE]; 79 struct tftp_stats tftp_stats; 80 81 stats_init(&tftp_stats); 82 83 memset(&serv, 0, sizeof(serv)); 84 rp = (struct tftphdr *)recvbuffer; 85 86 if (port == NULL) { 87 struct servent *se; 88 se = getservbyname("tftp", "udp"); 89 assert(se != NULL); 90 ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port; 91 } else 92 ((struct sockaddr_in *)&peer_sock)->sin_port = 93 htons(atoi(port)); 94 95 for (i = 0; i < 12; i++) { 96 struct sockaddr_storage from; 97 98 /* Tell the other side what we want to do */ 99 if (debug & DEBUG_SIMPLE) 100 printf("Sending %s\n", name); 101 102 n = send_wrq(peer, name, mode); 103 if (n > 0) { 104 printf("Cannot send WRQ packet\n"); 105 return -1; 106 } 107 108 /* 109 * The first packet we receive has the new destination port 110 * we have to send the next packets to. 111 */ 112 n = receive_packet(peer, recvbuffer, 113 MAXPKTSIZE, &from, timeoutpacket); 114 115 /* We got some data! */ 116 if (n >= 0) { 117 ((struct sockaddr_in *)&peer_sock)->sin_port = 118 ((struct sockaddr_in *)&from)->sin_port; 119 break; 120 } 121 122 /* This should be retried */ 123 if (n == RP_TIMEOUT) { 124 printf("Try %d, didn't receive answer from remote.\n", 125 i + 1); 126 continue; 127 } 128 129 /* Everything else is fatal */ 130 break; 131 } 132 if (i == 12) { 133 printf("Transfer timed out.\n"); 134 return -1; 135 } 136 if (rp->th_opcode == ERROR) { 137 printf("Got ERROR, aborted\n"); 138 return -1; 139 } 140 141 /* 142 * If the first packet is an OACK instead of an ACK packet, 143 * handle it different. 144 */ 145 if (rp->th_opcode == OACK) { 146 if (!options_rfc_enabled) { 147 printf("Got OACK while options are not enabled!\n"); 148 send_error(peer, EBADOP); 149 return -1; 150 } 151 152 parse_options(peer, rp->th_stuff, n + 2); 153 } 154 155 if (read_init(fd, NULL, mode) < 0) { 156 warn("read_init()"); 157 return -1; 158 } 159 160 block = 1; 161 if (tftp_send(peer, &block, &tftp_stats) != 0) 162 ret = -1; 163 164 read_close(); 165 if (tftp_stats.amount > 0) 166 printstats("Sent", verbose, &tftp_stats); 167 return ret; 168 } 169 170 /* 171 * Receive a file. 172 */ 173 int 174 recvfile(int peer, char *port, int fd, char *name, char *mode) 175 { 176 struct tftphdr *rp; 177 uint16_t block; 178 char recvbuffer[MAXPKTSIZE]; 179 int n, i, ret = 0; 180 struct tftp_stats tftp_stats; 181 182 stats_init(&tftp_stats); 183 184 rp = (struct tftphdr *)recvbuffer; 185 186 if (port == NULL) { 187 struct servent *se; 188 se = getservbyname("tftp", "udp"); 189 assert(se != NULL); 190 ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port; 191 } else 192 ((struct sockaddr_in *)&peer_sock)->sin_port = 193 htons(atoi(port)); 194 195 for (i = 0; i < 12; i++) { 196 struct sockaddr_storage from; 197 198 /* Tell the other side what we want to do */ 199 if (debug & DEBUG_SIMPLE) 200 printf("Requesting %s\n", name); 201 202 n = send_rrq(peer, name, mode); 203 if (n > 0) { 204 printf("Cannot send RRQ packet\n"); 205 return -1; 206 } 207 208 /* 209 * The first packet we receive has the new destination port 210 * we have to send the next packets to. 211 */ 212 n = receive_packet(peer, recvbuffer, 213 MAXPKTSIZE, &from, timeoutpacket); 214 215 /* We got something useful! */ 216 if (n >= 0) { 217 ((struct sockaddr_in *)&peer_sock)->sin_port = 218 ((struct sockaddr_in *)&from)->sin_port; 219 break; 220 } 221 222 /* We should retry if this happens */ 223 if (n == RP_TIMEOUT) { 224 printf("Try %d, didn't receive answer from remote.\n", 225 i + 1); 226 continue; 227 } 228 229 /* Otherwise it is a fatal error */ 230 break; 231 } 232 if (i == 12) { 233 printf("Transfer timed out.\n"); 234 return -1; 235 } 236 if (rp->th_opcode == ERROR) { 237 tftp_log(LOG_ERR, "Error code %d: %s", rp->th_code, rp->th_msg); 238 return -1; 239 } 240 241 if (write_init(fd, NULL, mode) < 0) { 242 warn("write_init"); 243 return -1; 244 } 245 246 /* 247 * If the first packet is an OACK packet instead of an DATA packet, 248 * handle it different. 249 */ 250 if (rp->th_opcode == OACK) { 251 if (!options_rfc_enabled) { 252 printf("Got OACK while options are not enabled!\n"); 253 send_error(peer, EBADOP); 254 return -1; 255 } 256 257 parse_options(peer, rp->th_stuff, n + 2); 258 259 n = send_ack(peer, 0); 260 if (n > 0) { 261 printf("Cannot send ACK on OACK.\n"); 262 return -1; 263 } 264 block = 0; 265 if (tftp_receive(peer, &block, &tftp_stats, NULL, 0) != 0) 266 ret = -1; 267 } else { 268 block = 1; 269 if (tftp_receive(peer, &block, &tftp_stats, rp, n) != 0) 270 ret = -1; 271 } 272 273 if (tftp_stats.amount > 0) 274 printstats("Received", verbose, &tftp_stats); 275 return ret; 276 } 277