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
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
56static 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
85const char *
86errtomsg(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
100static int
101send_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 */
136void
137send_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 */
175int
176send_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 */
223int
224send_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 */
273int
274send_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 */
320int
321send_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 */
350int
351send_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 */
377static jmp_buf timeoutbuf;
378
379static void
380timeout(int sig __unused)
381{
382
383	/* tftp_log(LOG_DEBUG, "Timeout\n");	Inside a signal handler... */
384	longjmp(timeoutbuf, 1);
385}
386
387int
388receive_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