tftp.c revision 209551
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 209551 2010-06-27 14:21:08Z 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	struct sockaddr_storage serv;	/* valid server port number */
79	char recvbuffer[MAXPKTSIZE];
80	struct tftp_stats tftp_stats;
81
82	stats_init(&tftp_stats);
83
84	memset(&serv, 0, sizeof(serv));
85	rp = (struct tftphdr *)recvbuffer;
86
87	if (port == NULL) {
88		struct servent *se;
89		se = getservbyname("tftp", "udp");
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;
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;
135	}
136	if (rp->th_opcode == ERROR) {
137		printf("Got ERROR, aborted\n");
138		return;
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;
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;
158	}
159
160	block = 1;
161	tftp_send(peer, &block, &tftp_stats);
162
163	read_close();
164	if (tftp_stats.amount > 0)
165		printstats("Sent", verbose, &tftp_stats);
166
167	txrx_error = 1;
168}
169
170/*
171 * Receive a file.
172 */
173void
174recvfile(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;
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		((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port;
190	} else
191		((struct sockaddr_in *)&peer_sock)->sin_port =
192		    htons(atoi(port));
193
194	for (i = 0; i < 12; i++) {
195		struct sockaddr_storage from;
196
197		/* Tell the other side what we want to do */
198		if (debug&DEBUG_SIMPLE)
199			printf("Requesting %s\n", name);
200
201		n = send_rrq(peer, name, mode);
202		if (n > 0) {
203			printf("Cannot send RRQ packet\n");
204			return;
205		}
206
207		/*
208		 * The first packet we receive has the new destination port
209		 * we have to send the next packets to.
210		 */
211		n = receive_packet(peer, recvbuffer,
212		    MAXPKTSIZE, &from, timeoutpacket);
213
214		/* We got something useful! */
215		if (n >= 0) {
216			((struct sockaddr_in *)&peer_sock)->sin_port =
217			    ((struct sockaddr_in *)&from)->sin_port;
218			break;
219		}
220
221		/* We should retry if this happens */
222		if (n == RP_TIMEOUT) {
223			printf("Try %d, didn't receive answer from remote.\n",
224			    i + 1);
225			continue;
226		}
227
228		/* Otherwise it is a fatal error */
229		break;
230	}
231	if (i == 12) {
232		printf("Transfer timed out.\n");
233		return;
234	}
235	if (rp->th_opcode == ERROR) {
236		tftp_log(LOG_ERR, "Error code %d: %s", rp->th_code, rp->th_msg);
237		return;
238	}
239
240	if (write_init(fd, NULL, mode) < 0) {
241		warn("write_init");
242		return;
243	}
244
245	/*
246	 * If the first packet is an OACK packet instead of an DATA packet,
247	 * handle it different.
248	 */
249	if (rp->th_opcode == OACK) {
250		if (!options_rfc_enabled) {
251			printf("Got OACK while options are not enabled!\n");
252			send_error(peer, EBADOP);
253			return;
254		}
255
256		parse_options(peer, rp->th_stuff, n + 2);
257
258		n = send_ack(peer, 0);
259		if (n > 0) {
260			printf("Cannot send ACK on OACK.\n");
261			return;
262		}
263		block = 0;
264		tftp_receive(peer, &block, &tftp_stats, NULL, 0);
265	} else {
266		block = 1;
267		tftp_receive(peer, &block, &tftp_stats, rp, n);
268	}
269
270	write_close();
271	if (tftp_stats.amount > 0)
272		printstats("Received", verbose, &tftp_stats);
273	return;
274}
275