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