xref: /openbsd-src/usr.bin/tftp/tftp.c (revision e5157e49389faebcb42b7237d55fbf096d9c2523)
1 /*	$OpenBSD: tftp.c,v 1.24 2014/10/21 06:15:16 dlg Exp $	*/
2 /*	$NetBSD: tftp.c,v 1.5 1995/04/29 05:55:25 cgd Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * TFTP User Program -- Protocol Machines
35  *
36  * This version includes many modifications by Jim Guyton <guyton@rand-unix>
37  */
38 
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/time.h>
42 #include <sys/stat.h>
43 
44 #include <netinet/in.h>
45 #include <arpa/tftp.h>
46 
47 #include <err.h>
48 #include <errno.h>
49 #include <poll.h>
50 #include <signal.h>
51 #include <stdio.h>
52 #include <stddef.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <netdb.h>
57 
58 #include "extern.h"
59 #include "tftpsubs.h"
60 
61 static int	cmpport(struct sockaddr *, struct sockaddr *);
62 static int	makerequest(int, const char *, struct tftphdr *, const char *);
63 static void	nak(int, struct sockaddr *);
64 static void 	tpacket(const char *, struct tftphdr *, int);
65 static void	startclock(void);
66 static void	stopclock(void);
67 static void	printstats(const char *, unsigned long);
68 static void	printtimeout(void);
69 static void	oack(struct tftphdr *, int, int);
70 static int	oack_set(const char *, const char *);
71 
72 extern struct sockaddr_storage	 peeraddr;	/* filled in by main */
73 extern int			 f;		/* the opened socket */
74 extern int			 trace;
75 extern int			 verbose;
76 extern int			 rexmtval;
77 extern int			 maxtimeout;
78 extern FILE			*file;
79 extern volatile sig_atomic_t	 intrflag;
80 extern char			*ackbuf;
81 extern int			 has_options;
82 extern int			 opt_tsize;
83 extern int			 opt_tout;
84 extern int			 opt_blksize;
85 
86 struct timeval	tstart;
87 struct timeval	tstop;
88 unsigned int	segment_size = SEGSIZE;
89 unsigned int	packet_size = SEGSIZE + 4;
90 
91 struct errmsg {
92 	int	 e_code;
93 	char	*e_msg;
94 } errmsgs[] = {
95 	{ EUNDEF,	"Undefined error code" },
96 	{ ENOTFOUND,	"File not found" },
97 	{ EACCESS,	"Access violation" },
98 	{ ENOSPACE,	"Disk full or allocation exceeded" },
99 	{ EBADOP,	"Illegal TFTP operation" },
100 	{ EBADID,	"Unknown transfer ID" },
101 	{ EEXISTS,	"File already exists" },
102 	{ ENOUSER,	"No such user" },
103 	{ EOPTNEG,	"Option negotiation failed" },
104 	{ -1,		NULL }
105 };
106 
107 struct options {
108 	const char      *o_type;
109 } options[] = {
110 	{ "tsize" },
111 	{ "timeout" },
112 	{ "blksize" },
113 	{ NULL }
114 };
115 
116 enum opt_enum {
117 	OPT_TSIZE = 0,
118 	OPT_TIMEOUT,
119 	OPT_BLKSIZE
120 };
121 
122 /*
123  * Send the requested file.
124  */
125 void
126 sendfile(int fd, char *name, char *mode)
127 {
128 	struct tftphdr		*dp, *ap; /* data and ack packets */
129 	struct sockaddr_storage	 from, peer;
130 	struct sockaddr_storage	 serv; /* valid server port number */
131 	struct pollfd		 pfd[1];
132 	unsigned long		 amount;
133 	socklen_t		 fromlen;
134 	int			 convert; /* true if converting crlf -> lf */
135 	int			 n, nfds, error, timeouts, size;
136 	uint16_t		 block = 0;
137 	int			 firsttrip = 1;
138 
139 	startclock();		/* start stat's clock */
140 	dp = r_init();		/* reset fillbuf/read-ahead code */
141 	ap = (struct tftphdr *)ackbuf;
142 	file = fdopen(fd, "r");
143 	convert = !strcmp(mode, "netascii");
144 	amount = 0;
145 	memcpy(&peer, &peeraddr, peeraddr.ss_len);
146 	memset(&serv, 0, sizeof(serv));
147 
148 	do {
149 		/* read data from file */
150 		if (firsttrip)
151 			size = makerequest(WRQ, name, dp, mode) - 4;
152 		else {
153 			size = readit(file, &dp, convert, segment_size);
154 			if (size < 0) {
155 				nak(errno + 100, (struct sockaddr *)&peer);
156 				break;
157 			}
158 			dp->th_opcode = htons((u_short)DATA);
159 			dp->th_block = htons(block);
160 		}
161 
162 		/* send data to server and wait for server ACK */
163 		for (timeouts = 0, error = 0; !intrflag;) {
164 			if (timeouts >= maxtimeout) {
165 				printtimeout();
166 				goto abort;
167 			}
168 
169 			if (!error) {
170 				if (trace)
171 					tpacket("sent", dp, size + 4);
172 				if (sendto(f, dp, size + 4, 0,
173 				    (struct sockaddr *)&peer,
174 				    peer.ss_len) != size + 4) {
175 					warn("sendto");
176 					goto abort;
177 				}
178 				if (!firsttrip)
179 					read_ahead(file, convert, segment_size);
180 			}
181 			error = 0;
182 
183 			pfd[0].fd = f;
184 			pfd[0].events = POLLIN;
185 			nfds = poll(pfd, 1, rexmtval * 1000);
186 			if (nfds == 0) {
187 				timeouts += rexmtval;
188 				continue;
189 			}
190 			if (nfds == -1) {
191 				error = 1;
192 				if (errno == EINTR)
193 					continue;
194 				warn("poll");
195 				goto abort;
196 			}
197 			fromlen = sizeof(from);
198 			n = recvfrom(f, ackbuf, packet_size, 0,
199 			    (struct sockaddr *)&from, &fromlen);
200 			if (n == 0) {
201 				warn("recvfrom");
202 				goto abort;
203 			}
204 			if (n == -1) {
205 				error = 1;
206 				if (errno == EINTR)
207 					continue;
208 				warn("recvfrom");
209 				goto abort;
210 			}
211 			if (!serv.ss_family)
212 				serv = from;
213 			else if (!cmpport((struct sockaddr *)&serv,
214 			    (struct sockaddr *)&from)) {
215 				warn("server port mismatch");
216 				goto abort;
217 			}
218 			peer = from;
219 			if (trace)
220 				tpacket("received", ap, n);
221 
222 			ap->th_opcode = ntohs(ap->th_opcode);
223 
224 			if (ap->th_opcode == OACK) {
225 				oack(ap, n, 0);
226 				break;
227 			}
228 
229 			ap->th_block = ntohs(ap->th_block);
230 
231 			if (ap->th_opcode == ERROR) {
232 				printf("Error code %d: %s\n",
233 				    ap->th_code, ap->th_msg);
234 				goto abort;
235 			}
236 			if (ap->th_opcode == ACK) {
237 				int j;
238 				if (ap->th_block == block)
239 					break;
240 				/* re-synchronize with other side */
241 				j = synchnet(f);
242 				if (j && trace)
243 					printf("discarded %d packets\n", j);
244 				if (ap->th_block == (block - 1))
245 					continue;
246 			}
247 			error = 1;	/* received packet does not match */
248 		}
249 
250 		if (firsttrip) {
251 			size = segment_size;
252 			firsttrip = 0;
253 		} else
254 			amount += size;
255 		block++;
256 	} while ((size == segment_size) && !intrflag);
257 
258 abort:
259 	fclose(file);
260 	stopclock();
261 	if (amount > 0) {
262 		if (intrflag)
263 			putchar('\n');
264 		printstats("Sent", amount);
265 	}
266 }
267 
268 /*
269  * Receive a file.
270  */
271 void
272 recvfile(int fd, char *name, char *mode)
273 {
274 	struct tftphdr		*dp, *ap; /* data and ack packets */
275 	struct sockaddr_storage	 from, peer;
276 	struct sockaddr_storage	 serv; /* valid server port number */
277 	struct pollfd		 pfd[1];
278 	unsigned long		 amount;
279 	socklen_t		 fromlen;
280 	int			 convert; /* true if converting crlf -> lf */
281 	int			 n, nfds, error, timeouts, size;
282 	int			 firsttrip;
283 	uint16_t		 block;
284 
285 	startclock();		/* start stat's clock */
286 	dp = w_init();		/* reset fillbuf/read-ahead code */
287 	ap = (struct tftphdr *)ackbuf;
288 	file = fdopen(fd, "w");
289 	convert = !strcmp(mode, "netascii");
290 	n = 0;
291 	block = 1;
292 	amount = 0;
293 	firsttrip = 1;
294 	memcpy(&peer, &peeraddr, peeraddr.ss_len);
295 	memset(&serv, 0, sizeof(serv));
296 
297 options:
298 	do {
299 		/* create new ACK packet */
300 		if (firsttrip) {
301 			size = makerequest(RRQ, name, ap, mode);
302 			firsttrip = 0;
303 		} else {
304 			ap->th_opcode = htons((u_short)ACK);
305 			ap->th_block = htons(block);
306 			size = 4;
307 			block++;
308 		}
309 
310 		/* send ACK to server and wait for server data */
311 		for (timeouts = 0, error = 0; !intrflag;) {
312 			if (timeouts >= maxtimeout) {
313 				printtimeout();
314 				goto abort;
315 			}
316 
317 			if (!error) {
318 				if (trace)
319 					tpacket("sent", ap, size);
320 				if (sendto(f, ackbuf, size, 0,
321 				    (struct sockaddr *)&peer,
322 				    peer.ss_len) != size) {
323 					warn("sendto");
324 					goto abort;
325 				}
326 				write_behind(file, convert);
327 			}
328 			error = 0;
329 
330 			pfd[0].fd = f;
331 			pfd[0].events = POLLIN;
332 			nfds = poll(pfd, 1, rexmtval * 1000);
333 			if (nfds == 0) {
334 				timeouts += rexmtval;
335 				continue;
336 			}
337 			if (nfds == -1) {
338 				error = 1;
339 				if (errno == EINTR)
340 					continue;
341 				warn("poll");
342 				goto abort;
343 			}
344 			fromlen = sizeof(from);
345 			n = recvfrom(f, dp, packet_size, 0,
346 			    (struct sockaddr *)&from, &fromlen);
347 			if (n == 0) {
348 				warn("recvfrom");
349 				goto abort;
350 			}
351 			if (n == -1) {
352 				error = 1;
353 				if (errno == EINTR)
354 					continue;
355 				warn("recvfrom");
356 				goto abort;
357 			}
358 			if (!serv.ss_family)
359 				serv = from;
360 			else if (!cmpport((struct sockaddr *)&serv,
361 			    (struct sockaddr *)&from)) {
362 				warn("server port mismatch");
363 				goto abort;
364 			}
365 			peer = from;
366 			if (trace)
367 				tpacket("received", dp, n);
368 
369 			dp->th_opcode = ntohs(dp->th_opcode);
370 
371 			if (dp->th_opcode == OACK) {
372 				oack(dp, n, 0);
373 				block = 0;
374 				goto options;
375 			}
376 
377 			dp->th_block = ntohs(dp->th_block);
378 
379 			if (dp->th_opcode == ERROR) {
380 				printf("Error code %d: %s\n",
381 				    dp->th_code, dp->th_msg);
382 				goto abort;
383 			}
384 			if (dp->th_opcode == DATA) {
385 				int j;
386 				if (dp->th_block == block)
387 					break;
388 				/* re-synchronize with other side */
389 				j = synchnet(f);
390 				if (j && trace)
391 					printf("discarded %d packets\n", j);
392 				if (dp->th_block == (block - 1))
393 					continue;
394 			}
395 			error = 1;	/* received packet does not match */
396 		}
397 
398 		/* write data to file */
399 		size = writeit(file, &dp, n - 4, convert);
400 		if (size < 0) {
401 			nak(errno + 100, (struct sockaddr *)&peer);
402 			break;
403 		}
404 		amount += size;
405 	} while (size == segment_size && !intrflag);
406 
407 abort:
408 	/* ok to ack, since user has seen err msg */
409 	ap->th_opcode = htons((u_short)ACK);
410 	ap->th_block = htons(block);
411 	(void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer,
412 	    peer.ss_len);
413 	write_behind(file, convert);	/* flush last buffer */
414 
415 	fclose(file);
416 	stopclock();
417 	if (amount > 0) {
418 		if (intrflag)
419 			putchar('\n');
420 		printstats("Received", amount);
421 	}
422 }
423 
424 static int
425 cmpport(struct sockaddr *sa, struct sockaddr *sb)
426 {
427 	char a[NI_MAXSERV], b[NI_MAXSERV];
428 	if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV))
429 		return (0);
430 	if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV))
431 		return (0);
432 	if (strcmp(a, b) != 0)
433 		return (0);
434 
435 	return (1);
436 }
437 
438 static int
439 makerequest(int request, const char *name, struct tftphdr *tp,
440     const char *mode)
441 {
442 	char		*cp;
443 	int		 len, pktlen;
444 	off_t		 fsize = 0;
445 	struct stat	 st;
446 
447 	tp->th_opcode = htons((u_short)request);
448 	cp = tp->th_stuff;
449 	pktlen = packet_size - offsetof(struct tftphdr, th_stuff);
450 	len = strlen(name) + 1;
451 	strlcpy(cp, name, pktlen);
452 	strlcpy(cp + len, mode, pktlen - len);
453 	len += strlen(mode) + 1;
454 
455 	if (opt_tsize) {
456 		if (request == WRQ) {
457 			stat(name, &st);
458 			fsize = st.st_size;
459 		}
460 		len += snprintf(cp + len, pktlen - len, "%s%c%lld%c",
461 		    options[OPT_TSIZE].o_type, 0, fsize, 0);
462 	}
463 	if (opt_tout)
464 		len += snprintf(cp + len, pktlen - len, "%s%c%d%c",
465 		    options[OPT_TIMEOUT].o_type, 0, rexmtval, 0);
466 	if (opt_blksize)
467 		len += snprintf(cp + len, pktlen - len, "%s%c%d%c",
468 		    options[OPT_BLKSIZE].o_type, 0, opt_blksize, 0);
469 
470 	return (cp + len - (char *)tp);
471 }
472 
473 /*
474  * Send a nak packet (error message).
475  * Error code passed in is one of the
476  * standard TFTP codes, or a UNIX errno
477  * offset by 100.
478  */
479 static void
480 nak(int error, struct sockaddr *peer)
481 {
482 	struct errmsg	*pe;
483 	struct tftphdr	*tp;
484 	int		 length;
485 
486 	tp = (struct tftphdr *)ackbuf;
487 	tp->th_opcode = htons((u_short)ERROR);
488 	tp->th_code = htons((u_short)error);
489 	for (pe = errmsgs; pe->e_code >= 0; pe++)
490 		if (pe->e_code == error)
491 			break;
492 	if (pe->e_code < 0) {
493 		pe->e_msg = strerror(error - 100);
494 		tp->th_code = EUNDEF;
495 	}
496 	length = strlcpy(tp->th_msg, pe->e_msg, packet_size) + 5;
497 	if (length > packet_size)
498 		length = packet_size;
499 	if (trace)
500 		tpacket("sent", tp, length);
501 	if (sendto(f, ackbuf, length, 0, peer,
502 	    peer->sa_len) != length)
503 		warn("nak");
504 }
505 
506 static void
507 tpacket(const char *s, struct tftphdr *tp, int n)
508 {
509 	char		*cp, *file;
510 	static char	*opcodes[] =
511 	    { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
512 
513 	u_short op = ntohs(tp->th_opcode);
514 
515 	if (op < RRQ || op > OACK)
516 		printf("%s opcode=%x ", s, op);
517 	else
518 		printf("%s %s ", s, opcodes[op]);
519 
520 	switch (op) {
521 	case RRQ:
522 	case WRQ:
523 		n -= 2;
524 		file = cp = tp->th_stuff;
525 		cp = strchr(cp, '\0');
526 		printf("<file=%s, mode=%s", file, cp + 1);
527 		if (has_options)
528 			oack(tp, n, 1);
529 		printf(">\n");
530 		break;
531 	case DATA:
532 		printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
533 		break;
534 	case ACK:
535 		printf("<block=%d>\n", ntohs(tp->th_block));
536 		break;
537 	case ERROR:
538 		printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
539 		break;
540 	case OACK:
541 		printf("<");
542 		oack(tp, n, 1);
543 		printf(">\n");
544 		break;
545 	}
546 }
547 
548 static void
549 startclock(void)
550 {
551 	(void)gettimeofday(&tstart, NULL);
552 }
553 
554 static void
555 stopclock(void)
556 {
557 	(void)gettimeofday(&tstop, NULL);
558 }
559 
560 static void
561 printstats(const char *direction, unsigned long amount)
562 {
563 	double	delta;
564 
565 	/* compute delta in 1/10's second units */
566 	delta = ((tstop.tv_sec * 10.) + (tstop.tv_usec / 100000)) -
567 	    ((tstart.tv_sec * 10.) + (tstart.tv_usec / 100000));
568 	delta = delta / 10.;	/* back to seconds */
569 	printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
570 	if (verbose)
571 		printf(" [%.0f bits/sec]", (amount * 8.) / delta);
572 	putchar('\n');
573 }
574 
575 static void
576 printtimeout(void)
577 {
578 	printf("Transfer timed out.\n");
579 }
580 
581 static void
582 oack(struct tftphdr *tp, int size, int trace)
583 {
584 	int	 i, len, off;
585 	char	*opt, *val;
586 
587 	u_short op = ntohs(tp->th_opcode);
588 
589 	opt = tp->th_u.tu_stuff;
590 	val = tp->th_u.tu_stuff;
591 
592 	if (op == RRQ || op == WRQ) {
593 		len = strlen(opt) + 1;
594 		opt = strchr(opt, '\0');
595 		opt++;
596 		len += strlen(opt) + 1;
597 		opt = strchr(opt, '\0');
598 		opt++;
599 		val = opt;
600 		off = len;
601 		if (trace)
602 			printf(", ");
603 	} else
604 		off = 2;
605 
606 	for (i = off, len = 0; i < size - 1; i++) {
607 		if (*val != '\0') {
608 			val++;
609 			continue;
610 		}
611 		/* got option and value */
612 		val++;
613 		if (trace)
614 			printf("%s=%s", opt, val);
615 		else
616 			if (oack_set(opt, val) == -1)
617 				break;
618 		len = strlen(val) + 1;
619 		val += len;
620 		opt = val;
621 		i += len;
622 		if (trace && i < size - 1)
623 			printf(", ");
624 	}
625 }
626 
627 int
628 oack_set(const char *option, const char *value)
629 {
630 	int		 i, n;
631 	const char	*errstr;
632 	struct sockaddr_storage peer;
633 	memcpy(&peer, &peeraddr, peeraddr.ss_len);
634 
635 	for (i = 0; options[i].o_type != NULL; i++) {
636 		if (!strcasecmp(options[i].o_type, option)) {
637 			if (i == OPT_TSIZE) {
638 				/* XXX verify OACK response */
639 			}
640 			if (i == OPT_TIMEOUT) {
641 				/* verify OACK response */
642 				n = strtonum(value, TIMEOUT_MIN, TIMEOUT_MAX,
643 				    &errstr);
644 				if (errstr || rexmtval != n ||
645 				    opt_tout == 0) {
646 					nak(EOPTNEG, (struct sockaddr *)&peer);
647 					intrflag = 1;
648 					return (-1);
649 				}
650 				/* OK */
651 			}
652 			if (i == OPT_BLKSIZE) {
653 				/* verify OACK response */
654 				n = strtonum(value, SEGSIZE_MIN, SEGSIZE_MAX,
655 				    &errstr);
656 				if (errstr || opt_blksize != n ||
657 				    opt_blksize == 0) {
658 					nak(EOPTNEG, (struct sockaddr *)&peer);
659 					intrflag = 1;
660 					return (-1);
661 				}
662 				/* OK, set option */
663 				segment_size = n;
664 				packet_size = segment_size + 4;
665 			}
666 		}
667 	}
668 
669 	return (1);
670 }
671