xref: /freebsd/libexec/tftpd/tftp-io.c (revision 8fc257994d0ce2396196d7a06d50d20c8015f4b7)
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$");
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 <errno.h>
38 #include <setjmp.h>
39 #include <signal.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 
51 struct sockaddr_storage peer_sock;
52 struct sockaddr_storage me_sock;
53 
54 static int send_packet(int peer, uint16_t block, char *pkt, int size);
55 
56 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 	    random()%100 < packetdroppercentage) {			\
75 		tftp_log(LOG_DEBUG, "Artifical packet drop in %s", s);	\
76 		return;							\
77 	}
78 #define DROPPACKETn(s,n)						\
79 	if (packetdroppercentage != 0 &&				\
80 	    random()%100 < packetdroppercentage) {			\
81 		tftp_log(LOG_DEBUG, "Artifical packet drop in %s", s);	\
82 		return (n);						\
83 	}
84 
85 const char *
86 errtomsg(int error)
87 {
88 	static char ebuf[40];
89 	struct errmsg *pe;
90 	char buf[MAXPKTSIZE];
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(buf), "error %d", error);
98 	return (ebuf);
99 }
100 
101 static int
102 send_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,
111 			(struct sockaddr *)&peer_sock, peer_sock.ss_len)
112 			== size) {
113 			if (i)
114 				tftp_log(LOG_ERR,
115 				    "%s block %d, attempt %d successful",
116 				    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  */
137 void
138 send_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: %s", 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  */
176 int
177 send_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  */
224 int
225 send_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: %s", n, strerror(errno));
266 		return (1);
267 	}
268 	return (0);
269 }
270 
271 /*
272  * Send an OACK packet (option acknowledgement).
273  */
274 int
275 send_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  */
321 int
322 send_ack(int fp, uint16_t block)
323 {
324 	struct tftphdr *tp;
325 	int size;
326 	char *bp;
327 	char buf[MAXPKTSIZE];
328 
329 	if (debug&DEBUG_PACKETS)
330 		tftp_log(LOG_DEBUG, "Sending ACK for block %d", block);
331 
332 	DROPPACKETn("send_ack", 0);
333 
334 	tp = (struct tftphdr *)buf;
335 	bp = buf + 2;
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 jmp_buf	timeoutbuf;
381 
382 static void
383 timeout(int sig __unused)
384 {
385 
386 	/* tftp_log(LOG_DEBUG, "Timeout\n");	Inside a signal handler... */
387 	longjmp(timeoutbuf, 1);
388 }
389 
390 int
391 receive_packet(int peer, char *data, int size, struct sockaddr_storage *from,
392     int thistimeout)
393 {
394 	struct tftphdr *pkt;
395 	struct sockaddr_storage from_local;
396 	struct sockaddr_storage *pfrom;
397 	socklen_t fromlen;
398 	int n;
399 	static int waiting;
400 
401 	pfrom = (from == NULL) ? &from_local : from;
402 
403 	if (debug&DEBUG_PACKETS)
404 		tftp_log(LOG_DEBUG,
405 		    "Waiting %d seconds for packet", timeoutpacket);
406 
407 	pkt = (struct tftphdr *)data;
408 
409 	waiting = 0;
410 	signal(SIGALRM, timeout);
411 	setjmp(timeoutbuf);
412 	alarm(thistimeout);
413 
414 	if (waiting > 0) {
415 		alarm(0);
416 		return (RP_TIMEOUT);
417 	}
418 
419 	if (waiting > 0) {
420 		tftp_log(LOG_ERR, "receive_packet: timeout");
421 		alarm(0);
422 		return (RP_TIMEOUT);
423 	}
424 
425 	waiting++;
426 	fromlen = sizeof(*pfrom);
427 	n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen);
428 
429 	alarm(0);
430 
431 	DROPPACKETn("receive_packet", RP_TIMEOUT);
432 
433 	if (n < 0) {
434 		tftp_log(LOG_ERR, "receive_packet: timeout");
435 		return (RP_TIMEOUT);
436 	}
437 
438 	alarm(0);
439 
440 	if (n < 0) {
441 		/* No idea what could have happened if it isn't a timeout */
442 		tftp_log(LOG_ERR, "receive_packet: %s", strerror(errno));
443 		return (RP_RECVFROM);
444 	}
445 	if (n < 4) {
446 		tftp_log(LOG_ERR,
447 		    "receive_packet: packet too small (%d bytes)", n);
448 		return (RP_TOOSMALL);
449 	}
450 
451 	pkt->th_opcode = ntohs((u_short)pkt->th_opcode);
452 	if (pkt->th_opcode == DATA ||
453 	    pkt->th_opcode == ACK)
454 		pkt->th_block = ntohs((u_short)pkt->th_block);
455 
456 	if (pkt->th_opcode == DATA && n > pktsize) {
457 		tftp_log(LOG_ERR, "receive_packet: packet too big");
458 		return (RP_TOOBIG);
459 	}
460 
461 	if (((struct sockaddr_in *)(pfrom))->sin_addr.s_addr !=
462 	    ((struct sockaddr_in *)(&peer_sock))->sin_addr.s_addr) {
463 		tftp_log(LOG_ERR,
464 			"receive_packet: received packet from wrong source");
465 		return (RP_WRONGSOURCE);
466 	}
467 
468 	if (pkt->th_opcode == ERROR) {
469 		tftp_log(LOG_ERR, "Got ERROR packet: %s", pkt->th_msg);
470 		return (RP_ERROR);
471 	}
472 
473 	if (debug&DEBUG_PACKETS)
474 		tftp_log(LOG_DEBUG, "Received %d bytes in a %s packet",
475 			n, packettype(pkt->th_opcode));
476 
477 	return n - 4;
478 }
479