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