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