1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <sys/stat.h>
31
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <arpa/tftp.h>
35
36#include <assert.h>
37#include <errno.h>
38#include <poll.h>
39#include <stddef.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <syslog.h>
44#include <unistd.h>
45
46#include "tftp-file.h"
47#include "tftp-io.h"
48#include "tftp-utils.h"
49#include "tftp-options.h"
50
51struct sockaddr_storage peer_sock;
52struct sockaddr_storage me_sock;
53
54static int send_packet(int peer, uint16_t block, char *pkt, int size);
55
56static struct errmsg {
57	int	e_code;
58	const char	*e_msg;
59} errmsgs[] = {
60	{ EUNDEF,	"Undefined error code" },
61	{ ENOTFOUND,	"File not found" },
62	{ EACCESS,	"Access violation" },
63	{ ENOSPACE,	"Disk full or allocation exceeded" },
64	{ EBADOP,	"Illegal TFTP operation" },
65	{ EBADID,	"Unknown transfer ID" },
66	{ EEXISTS,	"File already exists" },
67	{ ENOUSER,	"No such user" },
68	{ EOPTNEG,	"Option negotiation" },
69	{ -1,		NULL }
70};
71
72#define DROPPACKET(s)							\
73	if (packetdroppercentage != 0 &&				\
74	    arc4random()%100 < packetdroppercentage) {			\
75		tftp_log(LOG_DEBUG, "Artificial packet drop in %s", s);	\
76		return;							\
77	}
78#define DROPPACKETn(s,n)						\
79	if (packetdroppercentage != 0 &&				\
80	    arc4random()%100 < packetdroppercentage) {			\
81		tftp_log(LOG_DEBUG, "Artificial packet drop in %s", s);	\
82		return (n);						\
83	}
84
85const char *
86errtomsg(int error)
87{
88	static char ebuf[40];
89	struct errmsg *pe;
90
91	if (error == 0)
92		return ("success");
93	for (pe = errmsgs; pe->e_code >= 0; pe++)
94		if (pe->e_code == error)
95			return (pe->e_msg);
96	snprintf(ebuf, sizeof(ebuf), "error %d", error);
97	return (ebuf);
98}
99
100static int
101send_packet(int peer, uint16_t block, char *pkt, int size)
102{
103	int i;
104	int t = 1;
105
106	for (i = 0; i < 12 ; i++) {
107		DROPPACKETn("send_packet", 0);
108
109		if (sendto(peer, pkt, size, 0, (struct sockaddr *)&peer_sock,
110		    peer_sock.ss_len) == size) {
111			if (i)
112				tftp_log(LOG_ERR,
113				    "%s block %d, attempt %d successful",
114		    		    packettype(ntohs(((struct tftphdr *)
115				    (pkt))->th_opcode)), block, i);
116			return (0);
117		}
118		tftp_log(LOG_ERR,
119		    "%s block %d, attempt %d failed (Error %d: %s)",
120		    packettype(ntohs(((struct tftphdr *)(pkt))->th_opcode)),
121		    block, i, errno, strerror(errno));
122		sleep(t);
123		if (t < 32)
124			t <<= 1;
125	}
126	tftp_log(LOG_ERR, "send_packet: %s", strerror(errno));
127	return (1);
128}
129
130/*
131 * Send an ERROR packet (error message).
132 * Error code passed in is one of the
133 * standard TFTP codes, or a UNIX errno
134 * offset by 100.
135 */
136void
137send_error(int peer, int error)
138{
139	struct tftphdr *tp;
140	int length;
141	struct errmsg *pe;
142	char buf[MAXPKTSIZE];
143
144	if (debug & DEBUG_PACKETS)
145		tftp_log(LOG_DEBUG, "Sending ERROR %d", error);
146
147	DROPPACKET("send_error");
148
149	tp = (struct tftphdr *)buf;
150	tp->th_opcode = htons((u_short)ERROR);
151	tp->th_code = htons((u_short)error);
152	for (pe = errmsgs; pe->e_code >= 0; pe++)
153		if (pe->e_code == error)
154			break;
155	if (pe->e_code < 0) {
156		pe->e_msg = strerror(error - 100);
157		tp->th_code = EUNDEF;   /* set 'undef' errorcode */
158	}
159	snprintf(tp->th_msg, MAXPKTSIZE - 4, "%s%n", pe->e_msg, &length);
160	length += 5; /* header and terminator */
161
162	if (debug & DEBUG_PACKETS)
163		tftp_log(LOG_DEBUG, "Sending ERROR %d: %s", error, tp->th_msg);
164
165	if (sendto(peer, buf, length, 0,
166		(struct sockaddr *)&peer_sock, peer_sock.ss_len) != length)
167		tftp_log(LOG_ERR, "send_error: %s", strerror(errno));
168}
169
170/*
171 * Send an WRQ packet (write request).
172 */
173int
174send_wrq(int peer, char *filename, char *mode)
175{
176	int n;
177	struct tftphdr *tp;
178	char *bp;
179	char buf[MAXPKTSIZE];
180	int size;
181
182	if (debug & DEBUG_PACKETS)
183		tftp_log(LOG_DEBUG, "Sending WRQ: filename: '%s', mode '%s'",
184			filename, mode
185		);
186
187	DROPPACKETn("send_wrq", 0);
188
189	tp = (struct tftphdr *)buf;
190	tp->th_opcode = htons((u_short)WRQ);
191	size = offsetof(struct tftphdr, th_stuff);
192
193	bp = tp->th_stuff;
194	strlcpy(bp, filename, sizeof(buf) - size);
195	bp += strlen(filename);
196	*bp = 0;
197	bp++;
198	size += strlen(filename) + 1;
199
200	strlcpy(bp, mode, sizeof(buf) - size);
201	bp += strlen(mode);
202	*bp = 0;
203	bp++;
204	size += strlen(mode) + 1;
205
206	if (options_rfc_enabled)
207		size += make_options(peer, bp, sizeof(buf) - size);
208
209	n = sendto(peer, buf, size, 0,
210	    (struct sockaddr *)&peer_sock, peer_sock.ss_len);
211	if (n != size) {
212		tftp_log(LOG_ERR, "send_wrq: %s", strerror(errno));
213		return (1);
214	}
215	return (0);
216}
217
218/*
219 * Send an RRQ packet (write request).
220 */
221int
222send_rrq(int peer, char *filename, char *mode)
223{
224	int n;
225	struct tftphdr *tp;
226	char *bp;
227	char buf[MAXPKTSIZE];
228	int size;
229
230	if (debug & DEBUG_PACKETS)
231		tftp_log(LOG_DEBUG, "Sending RRQ: filename: '%s', mode '%s'",
232			filename, mode
233		);
234
235	DROPPACKETn("send_rrq", 0);
236
237	tp = (struct tftphdr *)buf;
238	tp->th_opcode = htons((u_short)RRQ);
239	size = offsetof(struct tftphdr, th_stuff);
240
241	bp = tp->th_stuff;
242	strlcpy(bp, filename, sizeof(buf) - size);
243	bp += strlen(filename);
244	*bp = 0;
245	bp++;
246	size += strlen(filename) + 1;
247
248	strlcpy(bp, mode, sizeof(buf) - size);
249	bp += strlen(mode);
250	*bp = 0;
251	bp++;
252	size += strlen(mode) + 1;
253
254	if (options_rfc_enabled) {
255		options_set_request(OPT_TSIZE, "0");
256		size += make_options(peer, bp, sizeof(buf) - size);
257	}
258
259	n = sendto(peer, buf, size, 0,
260	    (struct sockaddr *)&peer_sock, peer_sock.ss_len);
261	if (n != size) {
262		tftp_log(LOG_ERR, "send_rrq: %d %s", n, strerror(errno));
263		return (1);
264	}
265	return (0);
266}
267
268/*
269 * Send an OACK packet (option acknowledgement).
270 */
271int
272send_oack(int peer)
273{
274	struct tftphdr *tp;
275	int size, i, n;
276	char *bp;
277	char buf[MAXPKTSIZE];
278
279	if (debug & DEBUG_PACKETS)
280		tftp_log(LOG_DEBUG, "Sending OACK");
281
282	DROPPACKETn("send_oack", 0);
283
284	/*
285	 * Send back an options acknowledgement (only the ones with
286	 * a reply for)
287	 */
288	tp = (struct tftphdr *)buf;
289	bp = buf + 2;
290	size = sizeof(buf) - 2;
291	tp->th_opcode = htons((u_short)OACK);
292	for (i = 0; options[i].o_type != NULL; i++) {
293		if (options[i].o_reply != NULL) {
294			n = snprintf(bp, size, "%s%c%s", options[i].o_type,
295				     0, options[i].o_reply);
296			bp += n+1;
297			size -= n+1;
298			if (size < 0) {
299				tftp_log(LOG_ERR, "oack: buffer overflow");
300				exit(1);
301			}
302		}
303	}
304	size = bp - buf;
305
306	if (sendto(peer, buf, size, 0,
307		(struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
308		tftp_log(LOG_INFO, "send_oack: %s", strerror(errno));
309		return (1);
310	}
311
312	return (0);
313}
314
315/*
316 * Send an ACK packet (acknowledgement).
317 */
318int
319send_ack(int fp, uint16_t block)
320{
321	struct tftphdr *tp;
322	int size;
323	char buf[MAXPKTSIZE];
324
325	if (debug & DEBUG_PACKETS)
326		tftp_log(LOG_DEBUG, "Sending ACK for block %d", block);
327
328	DROPPACKETn("send_ack", 0);
329
330	tp = (struct tftphdr *)buf;
331	tp->th_opcode = htons((u_short)ACK);
332	tp->th_block = htons((u_short)block);
333	size = 4;
334
335	if (sendto(fp, buf, size, 0,
336	    (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
337		tftp_log(LOG_INFO, "send_ack: %s", strerror(errno));
338		return (1);
339	}
340
341	return (0);
342}
343
344/*
345 * Send a DATA packet
346 */
347int
348send_data(int peer, uint16_t block, char *data, int size)
349{
350	char buf[MAXPKTSIZE];
351	struct tftphdr *pkt;
352	int n;
353
354	if (debug & DEBUG_PACKETS)
355		tftp_log(LOG_DEBUG, "Sending DATA packet %d of %d bytes",
356			block, size);
357
358	DROPPACKETn("send_data", 0);
359
360	pkt = (struct tftphdr *)buf;
361
362	pkt->th_opcode = htons((u_short)DATA);
363	pkt->th_block = htons((u_short)block);
364	memcpy(pkt->th_data, data, size);
365
366	n = send_packet(peer, block, (char *)pkt, size + 4);
367	return (n);
368}
369
370
371/*
372 * Receive a packet
373 *
374 * If timeout is negative, no error will be logged on timeout.
375 */
376int
377receive_packet(int peer, char *data, int size, struct sockaddr_storage *from,
378    int timeout)
379{
380	struct pollfd pfd;
381	struct tftphdr *pkt;
382	struct sockaddr_storage from_local;
383	struct sockaddr_storage *pfrom;
384	socklen_t fromlen;
385	int n;
386
387	if (debug & DEBUG_PACKETS)
388		tftp_log(LOG_DEBUG,
389		    "Waiting %d seconds for packet", timeoutpacket);
390
391	pkt = (struct tftphdr *)data;
392
393	pfd.fd = peer;
394	pfd.events = POLLIN;
395	if (poll(&pfd, 1, 1000 * (timeout < 0 ? -timeout : timeout)) < 1) {
396		if (timeout > 0)
397			tftp_log(LOG_ERR, "receive_packet: timeout");
398		return (RP_TIMEOUT);
399	}
400
401	pfrom = (from == NULL) ? &from_local : from;
402	fromlen = sizeof(*pfrom);
403	n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen);
404
405	DROPPACKETn("receive_packet", RP_TIMEOUT);
406
407	if (n < 0) {
408		/* No idea what could have happened if it isn't a timeout */
409		tftp_log(LOG_ERR, "receive_packet: %s", strerror(errno));
410		return (RP_RECVFROM);
411	}
412	if (n < 4) {
413		tftp_log(LOG_ERR,
414		    "receive_packet: packet too small (%d bytes)", n);
415		return (RP_TOOSMALL);
416	}
417
418	pkt->th_opcode = ntohs((u_short)pkt->th_opcode);
419	if (pkt->th_opcode == DATA ||
420	    pkt->th_opcode == ACK)
421		pkt->th_block = ntohs((u_short)pkt->th_block);
422
423	if (pkt->th_opcode == DATA && n > pktsize) {
424		tftp_log(LOG_ERR, "receive_packet: packet too big");
425		return (RP_TOOBIG);
426	}
427
428	if (((struct sockaddr_in *)(pfrom))->sin_addr.s_addr !=
429	    ((struct sockaddr_in *)(&peer_sock))->sin_addr.s_addr) {
430		tftp_log(LOG_ERR,
431			"receive_packet: received packet from wrong source");
432		return (RP_WRONGSOURCE);
433	}
434
435	if (pkt->th_opcode == ERROR) {
436		tftp_log(pkt->th_code == EUNDEF ? LOG_DEBUG : LOG_ERR,
437		    "Got ERROR packet: %s", pkt->th_msg);
438		return (RP_ERROR);
439	}
440
441	if (debug & DEBUG_PACKETS)
442		tftp_log(LOG_DEBUG, "Received %d bytes in a %s packet",
443			n, packettype(pkt->th_opcode));
444
445	return n - 4;
446}
447