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 /* 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 */ 69 int 70 xmitfile(int peer, char *port, int fd, char *name, char *mode) 71 { 72 struct tftphdr *rp; 73 int n, i, ret = 0; 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 -1; 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 -1; 133 } 134 if (rp->th_opcode == ERROR) { 135 printf("Got ERROR, aborted\n"); 136 return -1; 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 -1; 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 -1; 156 } 157 158 block = 1; 159 if (tftp_send(peer, &block, &tftp_stats) != 0) 160 ret = -1; 161 162 read_close(); 163 if (tftp_stats.amount > 0) 164 printstats("Sent", verbose, &tftp_stats); 165 return ret; 166 } 167 168 /* 169 * Receive a file. 170 */ 171 int 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, ret = 0; 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 -1; 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 -1; 233 } 234 if (rp->th_opcode == ERROR) { 235 tftp_log(LOG_ERR, "Error code %d: %s", rp->th_code, rp->th_msg); 236 return -1; 237 } 238 239 if (write_init(fd, NULL, mode) < 0) { 240 warn("write_init"); 241 return -1; 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 -1; 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 -1; 261 } 262 block = 0; 263 if (tftp_receive(peer, &block, &tftp_stats, NULL, 0) != 0) 264 ret = -1; 265 } else { 266 block = 1; 267 if (tftp_receive(peer, &block, &tftp_stats, rp, n) != 0) 268 ret = -1; 269 } 270 271 if (tftp_stats.amount > 0) 272 printstats("Received", verbose, &tftp_stats); 273 return ret; 274 } 275