xref: /freebsd/libexec/tftpd/tftp-io.c (revision 0b3105a37d7adcadcb720112fed4dc4e8040be99)
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 static 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, "Artificial 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, "Artificial 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 
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 
100 static int
101 send_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  */
136 void
137 send_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 	strcpy(tp->th_msg, pe->e_msg);
160 	length = strlen(pe->e_msg);
161 	tp->th_msg[length] = '\0';
162 	length += 5;
163 
164 	if (debug&DEBUG_PACKETS)
165 		tftp_log(LOG_DEBUG, "Sending ERROR %d: %s", error, tp->th_msg);
166 
167 	if (sendto(peer, buf, length, 0,
168 		(struct sockaddr *)&peer_sock, peer_sock.ss_len) != length)
169 		tftp_log(LOG_ERR, "send_error: %s", strerror(errno));
170 }
171 
172 /*
173  * Send an WRQ packet (write request).
174  */
175 int
176 send_wrq(int peer, char *filename, char *mode)
177 {
178 	int n;
179 	struct tftphdr *tp;
180 	char *bp;
181 	char buf[MAXPKTSIZE];
182 	int size;
183 
184 	if (debug&DEBUG_PACKETS)
185 		tftp_log(LOG_DEBUG, "Sending WRQ: filename: '%s', mode '%s'",
186 			filename, mode
187 		);
188 
189 	DROPPACKETn("send_wrq", 1);
190 
191 	tp = (struct tftphdr *)buf;
192 	tp->th_opcode = htons((u_short)WRQ);
193 	size = 2;
194 
195 	bp = tp->th_stuff;
196 	strcpy(bp, filename);
197 	bp += strlen(filename);
198 	*bp = 0;
199 	bp++;
200 	size += strlen(filename) + 1;
201 
202 	strcpy(bp, mode);
203 	bp += strlen(mode);
204 	*bp = 0;
205 	bp++;
206 	size += strlen(mode) + 1;
207 
208 	if (options_rfc_enabled)
209 		size += make_options(peer, bp, sizeof(buf) - size);
210 
211 	n = sendto(peer, buf, size, 0,
212 	    (struct sockaddr *)&peer_sock, peer_sock.ss_len);
213 	if (n != size) {
214 		tftp_log(LOG_ERR, "send_wrq: %s", strerror(errno));
215 		return (1);
216 	}
217 	return (0);
218 }
219 
220 /*
221  * Send an RRQ packet (write request).
222  */
223 int
224 send_rrq(int peer, char *filename, char *mode)
225 {
226 	int n;
227 	struct tftphdr *tp;
228 	char *bp;
229 	char buf[MAXPKTSIZE];
230 	int size;
231 
232 	if (debug&DEBUG_PACKETS)
233 		tftp_log(LOG_DEBUG, "Sending RRQ: filename: '%s', mode '%s'",
234 			filename, mode
235 		);
236 
237 	DROPPACKETn("send_rrq", 1);
238 
239 	tp = (struct tftphdr *)buf;
240 	tp->th_opcode = htons((u_short)RRQ);
241 	size = 2;
242 
243 	bp = tp->th_stuff;
244 	strcpy(bp, filename);
245 	bp += strlen(filename);
246 	*bp = 0;
247 	bp++;
248 	size += strlen(filename) + 1;
249 
250 	strcpy(bp, mode);
251 	bp += strlen(mode);
252 	*bp = 0;
253 	bp++;
254 	size += strlen(mode) + 1;
255 
256 	if (options_rfc_enabled) {
257 		options[OPT_TSIZE].o_request = strdup("0");
258 		size += make_options(peer, bp, sizeof(buf) - size);
259 	}
260 
261 	n = sendto(peer, buf, size, 0,
262 	    (struct sockaddr *)&peer_sock, peer_sock.ss_len);
263 	if (n != size) {
264 		tftp_log(LOG_ERR, "send_rrq: %d %s", n, strerror(errno));
265 		return (1);
266 	}
267 	return (0);
268 }
269 
270 /*
271  * Send an OACK packet (option acknowledgement).
272  */
273 int
274 send_oack(int peer)
275 {
276 	struct tftphdr *tp;
277 	int size, i, n;
278 	char *bp;
279 	char buf[MAXPKTSIZE];
280 
281 	if (debug&DEBUG_PACKETS)
282 		tftp_log(LOG_DEBUG, "Sending OACK");
283 
284 	DROPPACKETn("send_oack", 0);
285 
286 	/*
287 	 * Send back an options acknowledgement (only the ones with
288 	 * a reply for)
289 	 */
290 	tp = (struct tftphdr *)buf;
291 	bp = buf + 2;
292 	size = sizeof(buf) - 2;
293 	tp->th_opcode = htons((u_short)OACK);
294 	for (i = 0; options[i].o_type != NULL; i++) {
295 		if (options[i].o_reply != NULL) {
296 			n = snprintf(bp, size, "%s%c%s", options[i].o_type,
297 				     0, options[i].o_reply);
298 			bp += n+1;
299 			size -= n+1;
300 			if (size < 0) {
301 				tftp_log(LOG_ERR, "oack: buffer overflow");
302 				exit(1);
303 			}
304 		}
305 	}
306 	size = bp - buf;
307 
308 	if (sendto(peer, buf, size, 0,
309 		(struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
310 		tftp_log(LOG_INFO, "send_oack: %s", strerror(errno));
311 		return (1);
312 	}
313 
314 	return (0);
315 }
316 
317 /*
318  * Send an ACK packet (acknowledgement).
319  */
320 int
321 send_ack(int fp, uint16_t block)
322 {
323 	struct tftphdr *tp;
324 	int size;
325 	char buf[MAXPKTSIZE];
326 
327 	if (debug&DEBUG_PACKETS)
328 		tftp_log(LOG_DEBUG, "Sending ACK for block %d", block);
329 
330 	DROPPACKETn("send_ack", 0);
331 
332 	tp = (struct tftphdr *)buf;
333 	size = sizeof(buf) - 2;
334 	tp->th_opcode = htons((u_short)ACK);
335 	tp->th_block = htons((u_short)block);
336 	size = 4;
337 
338 	if (sendto(fp, buf, size, 0,
339 	    (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
340 		tftp_log(LOG_INFO, "send_ack: %s", strerror(errno));
341 		return (1);
342 	}
343 
344 	return (0);
345 }
346 
347 /*
348  * Send a DATA packet
349  */
350 int
351 send_data(int peer, uint16_t block, char *data, int size)
352 {
353 	char buf[MAXPKTSIZE];
354 	struct tftphdr *pkt;
355 	int n;
356 
357 	if (debug&DEBUG_PACKETS)
358 		tftp_log(LOG_DEBUG, "Sending DATA packet %d of %d bytes",
359 			block, size);
360 
361 	DROPPACKETn("send_data", 0);
362 
363 	pkt = (struct tftphdr *)buf;
364 
365 	pkt->th_opcode = htons((u_short)DATA);
366 	pkt->th_block = htons((u_short)block);
367 	memcpy(pkt->th_data, data, size);
368 
369 	n = send_packet(peer, block, (char *)pkt, size + 4);
370 	return (n);
371 }
372 
373 
374 /*
375  * Receive a packet
376  */
377 static jmp_buf timeoutbuf;
378 
379 static void
380 timeout(int sig __unused)
381 {
382 
383 	/* tftp_log(LOG_DEBUG, "Timeout\n");	Inside a signal handler... */
384 	longjmp(timeoutbuf, 1);
385 }
386 
387 int
388 receive_packet(int peer, char *data, int size, struct sockaddr_storage *from,
389     int thistimeout)
390 {
391 	struct tftphdr *pkt;
392 	struct sockaddr_storage from_local;
393 	struct sockaddr_storage *pfrom;
394 	socklen_t fromlen;
395 	int n;
396 	static int waiting;
397 
398 	if (debug&DEBUG_PACKETS)
399 		tftp_log(LOG_DEBUG,
400 		    "Waiting %d seconds for packet", timeoutpacket);
401 
402 	pkt = (struct tftphdr *)data;
403 
404 	waiting = 0;
405 	signal(SIGALRM, timeout);
406 	setjmp(timeoutbuf);
407 	alarm(thistimeout);
408 
409 	if (waiting > 0) {
410 		alarm(0);
411 		return (RP_TIMEOUT);
412 	}
413 
414 	if (waiting > 0) {
415 		tftp_log(LOG_ERR, "receive_packet: timeout");
416 		alarm(0);
417 		return (RP_TIMEOUT);
418 	}
419 
420 	waiting++;
421 	pfrom = (from == NULL) ? &from_local : from;
422 	fromlen = sizeof(*pfrom);
423 	n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen);
424 
425 	alarm(0);
426 
427 	DROPPACKETn("receive_packet", RP_TIMEOUT);
428 
429 	if (n < 0) {
430 		tftp_log(LOG_ERR, "receive_packet: timeout");
431 		return (RP_TIMEOUT);
432 	}
433 
434 	alarm(0);
435 
436 	if (n < 0) {
437 		/* No idea what could have happened if it isn't a timeout */
438 		tftp_log(LOG_ERR, "receive_packet: %s", strerror(errno));
439 		return (RP_RECVFROM);
440 	}
441 	if (n < 4) {
442 		tftp_log(LOG_ERR,
443 		    "receive_packet: packet too small (%d bytes)", n);
444 		return (RP_TOOSMALL);
445 	}
446 
447 	pkt->th_opcode = ntohs((u_short)pkt->th_opcode);
448 	if (pkt->th_opcode == DATA ||
449 	    pkt->th_opcode == ACK)
450 		pkt->th_block = ntohs((u_short)pkt->th_block);
451 
452 	if (pkt->th_opcode == DATA && n > pktsize) {
453 		tftp_log(LOG_ERR, "receive_packet: packet too big");
454 		return (RP_TOOBIG);
455 	}
456 
457 	if (((struct sockaddr_in *)(pfrom))->sin_addr.s_addr !=
458 	    ((struct sockaddr_in *)(&peer_sock))->sin_addr.s_addr) {
459 		tftp_log(LOG_ERR,
460 			"receive_packet: received packet from wrong source");
461 		return (RP_WRONGSOURCE);
462 	}
463 
464 	if (pkt->th_opcode == ERROR) {
465 		tftp_log(pkt->th_code == EUNDEF ? LOG_DEBUG : LOG_ERR,
466 		    "Got ERROR packet: %s", pkt->th_msg);
467 		return (RP_ERROR);
468 	}
469 
470 	if (debug&DEBUG_PACKETS)
471 		tftp_log(LOG_DEBUG, "Received %d bytes in a %s packet",
472 			n, packettype(pkt->th_opcode));
473 
474 	return n - 4;
475 }
476