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
34static 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 */
71void
72xmitfile(int peer, char *port, int fd, char *name, char *mode)
73{
74	struct tftphdr *rp;
75	int n, i;
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;
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		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;
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	/*
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;
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;
263		}
264		block = 0;
265		tftp_receive(peer, &block, &tftp_stats, NULL, 0);
266	} else {
267		block = 1;
268		tftp_receive(peer, &block, &tftp_stats, rp, n);
269	}
270
271	if (tftp_stats.amount > 0)
272		printstats("Received", verbose, &tftp_stats);
273	return;
274}
275