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