tftp-io.c revision 229780
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: head/libexec/tftpd/tftp-io.c 229780 2012-01-07 16:09:54Z uqs $");
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
51struct sockaddr_storage peer_sock;
52struct sockaddr_storage me_sock;
53
54static int send_packet(int peer, uint16_t block, char *pkt, int size);
55
56struct 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
85const char *
86errtomsg(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
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,
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 */
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: %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 */
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 *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 */
353int
354send_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 */
380jmp_buf	timeoutbuf;
381
382static void
383timeout(int sig __unused)
384{
385
386	/* tftp_log(LOG_DEBUG, "Timeout\n");	Inside a signal handler... */
387	longjmp(timeoutbuf, 1);
388}
389
390int
391receive_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	if (debug&DEBUG_PACKETS)
402		tftp_log(LOG_DEBUG,
403		    "Waiting %d seconds for packet", timeoutpacket);
404
405	pkt = (struct tftphdr *)data;
406
407	waiting = 0;
408	signal(SIGALRM, timeout);
409	setjmp(timeoutbuf);
410	alarm(thistimeout);
411
412	if (waiting > 0) {
413		alarm(0);
414		return (RP_TIMEOUT);
415	}
416
417	if (waiting > 0) {
418		tftp_log(LOG_ERR, "receive_packet: timeout");
419		alarm(0);
420		return (RP_TIMEOUT);
421	}
422
423	waiting++;
424	pfrom = (from == NULL) ? &from_local : from;
425	fromlen = sizeof(*pfrom);
426	n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen);
427
428	alarm(0);
429
430	DROPPACKETn("receive_packet", RP_TIMEOUT);
431
432	if (n < 0) {
433		tftp_log(LOG_ERR, "receive_packet: timeout");
434		return (RP_TIMEOUT);
435	}
436
437	alarm(0);
438
439	if (n < 0) {
440		/* No idea what could have happened if it isn't a timeout */
441		tftp_log(LOG_ERR, "receive_packet: %s", strerror(errno));
442		return (RP_RECVFROM);
443	}
444	if (n < 4) {
445		tftp_log(LOG_ERR,
446		    "receive_packet: packet too small (%d bytes)", n);
447		return (RP_TOOSMALL);
448	}
449
450	pkt->th_opcode = ntohs((u_short)pkt->th_opcode);
451	if (pkt->th_opcode == DATA ||
452	    pkt->th_opcode == ACK)
453		pkt->th_block = ntohs((u_short)pkt->th_block);
454
455	if (pkt->th_opcode == DATA && n > pktsize) {
456		tftp_log(LOG_ERR, "receive_packet: packet too big");
457		return (RP_TOOBIG);
458	}
459
460	if (((struct sockaddr_in *)(pfrom))->sin_addr.s_addr !=
461	    ((struct sockaddr_in *)(&peer_sock))->sin_addr.s_addr) {
462		tftp_log(LOG_ERR,
463			"receive_packet: received packet from wrong source");
464		return (RP_WRONGSOURCE);
465	}
466
467	if (pkt->th_opcode == ERROR) {
468		tftp_log(LOG_ERR, "Got ERROR packet: %s", pkt->th_msg);
469		return (RP_ERROR);
470	}
471
472	if (debug&DEBUG_PACKETS)
473		tftp_log(LOG_DEBUG, "Received %d bytes in a %s packet",
474			n, packettype(pkt->th_opcode));
475
476	return n - 4;
477}
478