xref: /openbsd-src/usr.bin/tftp/tftp.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: tftp.c,v 1.23 2012/05/01 04:23:21 gsoares 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, block, size;
136 
137 	startclock();		/* start stat's clock */
138 	dp = r_init();		/* reset fillbuf/read-ahead code */
139 	ap = (struct tftphdr *)ackbuf;
140 	file = fdopen(fd, "r");
141 	convert = !strcmp(mode, "netascii");
142 	block = 0;
143 	amount = 0;
144 	memcpy(&peer, &peeraddr, peeraddr.ss_len);
145 	memset(&serv, 0, sizeof(serv));
146 
147 	do {
148 		/* read data from file */
149 		if (!block)
150 			size = makerequest(WRQ, name, dp, mode) - 4;
151 		else {
152 			size = readit(file, &dp, convert, segment_size);
153 			if (size < 0) {
154 				nak(errno + 100, (struct sockaddr *)&peer);
155 				break;
156 			}
157 			dp->th_opcode = htons((u_short)DATA);
158 			dp->th_block = htons((u_short)block);
159 		}
160 
161 		/* send data to server and wait for server ACK */
162 		for (timeouts = 0, error = 0; !intrflag;) {
163 			if (timeouts >= maxtimeout) {
164 				printtimeout();
165 				goto abort;
166 			}
167 
168 			if (!error) {
169 				if (trace)
170 					tpacket("sent", dp, size + 4);
171 				if (sendto(f, dp, size + 4, 0,
172 				    (struct sockaddr *)&peer,
173 				    peer.ss_len) != size + 4) {
174 					warn("sendto");
175 					goto abort;
176 				}
177 				if (block > 0)
178 					read_ahead(file, convert, segment_size);
179 			}
180 			error = 0;
181 
182 			pfd[0].fd = f;
183 			pfd[0].events = POLLIN;
184 			nfds = poll(pfd, 1, rexmtval * 1000);
185 			if (nfds == 0) {
186 				timeouts += rexmtval;
187 				continue;
188 			}
189 			if (nfds == -1) {
190 				error = 1;
191 				if (errno == EINTR)
192 					continue;
193 				warn("poll");
194 				goto abort;
195 			}
196 			fromlen = sizeof(from);
197 			n = recvfrom(f, ackbuf, packet_size, 0,
198 			    (struct sockaddr *)&from, &fromlen);
199 			if (n == 0) {
200 				warn("recvfrom");
201 				goto abort;
202 			}
203 			if (n == -1) {
204 				error = 1;
205 				if (errno == EINTR)
206 					continue;
207 				warn("recvfrom");
208 				goto abort;
209 			}
210 			if (!serv.ss_family)
211 				serv = from;
212 			else if (!cmpport((struct sockaddr *)&serv,
213 			    (struct sockaddr *)&from)) {
214 				warn("server port mismatch");
215 				goto abort;
216 			}
217 			peer = from;
218 			if (trace)
219 				tpacket("received", ap, n);
220 
221 			ap->th_opcode = ntohs(ap->th_opcode);
222 
223 			if (ap->th_opcode == OACK) {
224 				oack(ap, n, 0);
225 				break;
226 			}
227 
228 			ap->th_block = ntohs(ap->th_block);
229 
230 			if (ap->th_opcode == ERROR) {
231 				printf("Error code %d: %s\n",
232 				    ap->th_code, ap->th_msg);
233 				goto abort;
234 			}
235 			if (ap->th_opcode == ACK) {
236 				int j;
237 				if (ap->th_block == block)
238 					break;
239 				/* re-synchronize with other side */
240 				j = synchnet(f);
241 				if (j && trace)
242 					printf("discarded %d packets\n", j);
243 				if (ap->th_block == (block - 1))
244 					continue;
245 			}
246 			error = 1;	/* received packet does not match */
247 		}
248 
249 		if (block > 0)
250 			amount += size;
251 		block++;
252 	} while ((size == segment_size || block == 1) && !intrflag);
253 
254 abort:
255 	fclose(file);
256 	stopclock();
257 	if (amount > 0) {
258 		if (intrflag)
259 			putchar('\n');
260 		printstats("Sent", amount);
261 	}
262 }
263 
264 /*
265  * Receive a file.
266  */
267 void
268 recvfile(int fd, char *name, char *mode)
269 {
270 	struct tftphdr		*dp, *ap; /* data and ack packets */
271 	struct sockaddr_storage	 from, peer;
272 	struct sockaddr_storage	 serv; /* valid server port number */
273 	struct pollfd		 pfd[1];
274 	unsigned long		 amount;
275 	socklen_t		 fromlen;
276 	int			 convert; /* true if converting crlf -> lf */
277 	int			 n, nfds, error, timeouts, block, size;
278 	int			 firsttrip;
279 
280 	startclock();		/* start stat's clock */
281 	dp = w_init();		/* reset fillbuf/read-ahead code */
282 	ap = (struct tftphdr *)ackbuf;
283 	file = fdopen(fd, "w");
284 	convert = !strcmp(mode, "netascii");
285 	n = 0;
286 	block = 1;
287 	amount = 0;
288 	firsttrip = 1;
289 	memcpy(&peer, &peeraddr, peeraddr.ss_len);
290 	memset(&serv, 0, sizeof(serv));
291 
292 options:
293 	do {
294 		/* create new ACK packet */
295 		if (firsttrip) {
296 			size = makerequest(RRQ, name, ap, mode);
297 			firsttrip = 0;
298 		} else {
299 			ap->th_opcode = htons((u_short)ACK);
300 			ap->th_block = htons((u_short)(block));
301 			size = 4;
302 			block++;
303 		}
304 
305 		/* send ACK to server and wait for server data */
306 		for (timeouts = 0, error = 0; !intrflag;) {
307 			if (timeouts >= maxtimeout) {
308 				printtimeout();
309 				goto abort;
310 			}
311 
312 			if (!error) {
313 				if (trace)
314 					tpacket("sent", ap, size);
315 				if (sendto(f, ackbuf, size, 0,
316 				    (struct sockaddr *)&peer,
317 				    peer.ss_len) != size) {
318 					warn("sendto");
319 					goto abort;
320 				}
321 				write_behind(file, convert);
322 			}
323 			error = 0;
324 
325 			pfd[0].fd = f;
326 			pfd[0].events = POLLIN;
327 			nfds = poll(pfd, 1, rexmtval * 1000);
328 			if (nfds == 0) {
329 				timeouts += rexmtval;
330 				continue;
331 			}
332 			if (nfds == -1) {
333 				error = 1;
334 				if (errno == EINTR)
335 					continue;
336 				warn("poll");
337 				goto abort;
338 			}
339 			fromlen = sizeof(from);
340 			n = recvfrom(f, dp, packet_size, 0,
341 			    (struct sockaddr *)&from, &fromlen);
342 			if (n == 0) {
343 				warn("recvfrom");
344 				goto abort;
345 			}
346 			if (n == -1) {
347 				error = 1;
348 				if (errno == EINTR)
349 					continue;
350 				warn("recvfrom");
351 				goto abort;
352 			}
353 			if (!serv.ss_family)
354 				serv = from;
355 			else if (!cmpport((struct sockaddr *)&serv,
356 			    (struct sockaddr *)&from)) {
357 				warn("server port mismatch");
358 				goto abort;
359 			}
360 			peer = from;
361 			if (trace)
362 				tpacket("received", dp, n);
363 
364 			dp->th_opcode = ntohs(dp->th_opcode);
365 
366 			if (dp->th_opcode == OACK) {
367 				oack(dp, n, 0);
368 				block = 0;
369 				goto options;
370 			}
371 
372 			dp->th_block = ntohs(dp->th_block);
373 
374 			if (dp->th_opcode == ERROR) {
375 				printf("Error code %d: %s\n",
376 				    dp->th_code, dp->th_msg);
377 				goto abort;
378 			}
379 			if (dp->th_opcode == DATA) {
380 				int j;
381 				if (dp->th_block == block)
382 					break;
383 				/* re-synchronize with other side */
384 				j = synchnet(f);
385 				if (j && trace)
386 					printf("discarded %d packets\n", j);
387 				if (dp->th_block == (block - 1))
388 					continue;
389 			}
390 			error = 1;	/* received packet does not match */
391 		}
392 
393 		/* write data to file */
394 		size = writeit(file, &dp, n - 4, convert);
395 		if (size < 0) {
396 			nak(errno + 100, (struct sockaddr *)&peer);
397 			break;
398 		}
399 		amount += size;
400 	} while (size == segment_size && !intrflag);
401 
402 abort:
403 	/* ok to ack, since user has seen err msg */
404 	ap->th_opcode = htons((u_short)ACK);
405 	ap->th_block = htons((u_short)block);
406 	(void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer,
407 	    peer.ss_len);
408 	write_behind(file, convert);	/* flush last buffer */
409 
410 	fclose(file);
411 	stopclock();
412 	if (amount > 0) {
413 		if (intrflag)
414 			putchar('\n');
415 		printstats("Received", amount);
416 	}
417 }
418 
419 static int
420 cmpport(struct sockaddr *sa, struct sockaddr *sb)
421 {
422 	char a[NI_MAXSERV], b[NI_MAXSERV];
423 	if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV))
424 		return (0);
425 	if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV))
426 		return (0);
427 	if (strcmp(a, b) != 0)
428 		return (0);
429 
430 	return (1);
431 }
432 
433 static int
434 makerequest(int request, const char *name, struct tftphdr *tp,
435     const char *mode)
436 {
437 	char		*cp;
438 	int		 len, pktlen;
439 	off_t		 fsize = 0;
440 	struct stat	 st;
441 
442 	tp->th_opcode = htons((u_short)request);
443 	cp = tp->th_stuff;
444 	pktlen = packet_size - offsetof(struct tftphdr, th_stuff);
445 	len = strlen(name) + 1;
446 	strlcpy(cp, name, pktlen);
447 	strlcpy(cp + len, mode, pktlen - len);
448 	len += strlen(mode) + 1;
449 
450 	if (opt_tsize) {
451 		if (request == WRQ) {
452 			stat(name, &st);
453 			fsize = st.st_size;
454 		}
455 		len += snprintf(cp + len, pktlen - len, "%s%c%lld%c",
456 		    options[OPT_TSIZE].o_type, 0, fsize, 0);
457 	}
458 	if (opt_tout)
459 		len += snprintf(cp + len, pktlen - len, "%s%c%d%c",
460 		    options[OPT_TIMEOUT].o_type, 0, rexmtval, 0);
461 	if (opt_blksize)
462 		len += snprintf(cp + len, pktlen - len, "%s%c%d%c",
463 		    options[OPT_BLKSIZE].o_type, 0, opt_blksize, 0);
464 
465 	return (cp + len - (char *)tp);
466 }
467 
468 /*
469  * Send a nak packet (error message).
470  * Error code passed in is one of the
471  * standard TFTP codes, or a UNIX errno
472  * offset by 100.
473  */
474 static void
475 nak(int error, struct sockaddr *peer)
476 {
477 	struct errmsg	*pe;
478 	struct tftphdr	*tp;
479 	int		 length;
480 
481 	tp = (struct tftphdr *)ackbuf;
482 	tp->th_opcode = htons((u_short)ERROR);
483 	tp->th_code = htons((u_short)error);
484 	for (pe = errmsgs; pe->e_code >= 0; pe++)
485 		if (pe->e_code == error)
486 			break;
487 	if (pe->e_code < 0) {
488 		pe->e_msg = strerror(error - 100);
489 		tp->th_code = EUNDEF;
490 	}
491 	length = strlcpy(tp->th_msg, pe->e_msg, packet_size) + 5;
492 	if (length > packet_size)
493 		length = packet_size;
494 	if (trace)
495 		tpacket("sent", tp, length);
496 	if (sendto(f, ackbuf, length, 0, peer,
497 	    peer->sa_len) != length)
498 		warn("nak");
499 }
500 
501 static void
502 tpacket(const char *s, struct tftphdr *tp, int n)
503 {
504 	char		*cp, *file;
505 	static char	*opcodes[] =
506 	    { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
507 
508 	u_short op = ntohs(tp->th_opcode);
509 
510 	if (op < RRQ || op > OACK)
511 		printf("%s opcode=%x ", s, op);
512 	else
513 		printf("%s %s ", s, opcodes[op]);
514 
515 	switch (op) {
516 	case RRQ:
517 	case WRQ:
518 		n -= 2;
519 		file = cp = tp->th_stuff;
520 		cp = strchr(cp, '\0');
521 		printf("<file=%s, mode=%s", file, cp + 1);
522 		if (has_options)
523 			oack(tp, n, 1);
524 		printf(">\n");
525 		break;
526 	case DATA:
527 		printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
528 		break;
529 	case ACK:
530 		printf("<block=%d>\n", ntohs(tp->th_block));
531 		break;
532 	case ERROR:
533 		printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
534 		break;
535 	case OACK:
536 		printf("<");
537 		oack(tp, n, 1);
538 		printf(">\n");
539 		break;
540 	}
541 }
542 
543 static void
544 startclock(void)
545 {
546 	(void)gettimeofday(&tstart, NULL);
547 }
548 
549 static void
550 stopclock(void)
551 {
552 	(void)gettimeofday(&tstop, NULL);
553 }
554 
555 static void
556 printstats(const char *direction, unsigned long amount)
557 {
558 	double	delta;
559 
560 	/* compute delta in 1/10's second units */
561 	delta = ((tstop.tv_sec * 10.) + (tstop.tv_usec / 100000)) -
562 	    ((tstart.tv_sec * 10.) + (tstart.tv_usec / 100000));
563 	delta = delta / 10.;	/* back to seconds */
564 	printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
565 	if (verbose)
566 		printf(" [%.0f bits/sec]", (amount * 8.) / delta);
567 	putchar('\n');
568 }
569 
570 static void
571 printtimeout(void)
572 {
573 	printf("Transfer timed out.\n");
574 }
575 
576 static void
577 oack(struct tftphdr *tp, int size, int trace)
578 {
579 	int	 i, len, off;
580 	char	*opt, *val;
581 
582 	u_short op = ntohs(tp->th_opcode);
583 
584 	opt = tp->th_u.tu_stuff;
585 	val = tp->th_u.tu_stuff;
586 
587 	if (op == RRQ || op == WRQ) {
588 		len = strlen(opt) + 1;
589 		opt = strchr(opt, '\0');
590 		opt++;
591 		len += strlen(opt) + 1;
592 		opt = strchr(opt, '\0');
593 		opt++;
594 		val = opt;
595 		off = len;
596 		if (trace)
597 			printf(", ");
598 	} else
599 		off = 2;
600 
601 	for (i = off, len = 0; i < size - 1; i++) {
602 		if (*val != '\0') {
603 			val++;
604 			continue;
605 		}
606 		/* got option and value */
607 		val++;
608 		if (trace)
609 			printf("%s=%s", opt, val);
610 		else
611 			if (oack_set(opt, val) == -1)
612 				break;
613 		len = strlen(val) + 1;
614 		val += len;
615 		opt = val;
616 		i += len;
617 		if (trace && i < size - 1)
618 			printf(", ");
619 	}
620 }
621 
622 int
623 oack_set(const char *option, const char *value)
624 {
625 	int		 i, n;
626 	const char	*errstr;
627 	struct sockaddr_storage peer;
628 	memcpy(&peer, &peeraddr, peeraddr.ss_len);
629 
630 	for (i = 0; options[i].o_type != NULL; i++) {
631 		if (!strcasecmp(options[i].o_type, option)) {
632 			if (i == OPT_TSIZE) {
633 				/* XXX verify OACK response */
634 			}
635 			if (i == OPT_TIMEOUT) {
636 				/* verify OACK response */
637 				n = strtonum(value, TIMEOUT_MIN, TIMEOUT_MAX,
638 				    &errstr);
639 				if (errstr || rexmtval != n ||
640 				    opt_tout == 0) {
641 					nak(EOPTNEG, (struct sockaddr *)&peer);
642 					intrflag = 1;
643 					return (-1);
644 				}
645 				/* OK */
646 			}
647 			if (i == OPT_BLKSIZE) {
648 				/* verify OACK response */
649 				n = strtonum(value, SEGSIZE_MIN, SEGSIZE_MAX,
650 				    &errstr);
651 				if (errstr || opt_blksize != n ||
652 				    opt_blksize == 0) {
653 					nak(EOPTNEG, (struct sockaddr *)&peer);
654 					intrflag = 1;
655 					return (-1);
656 				}
657 				/* OK, set option */
658 				segment_size = n;
659 				packet_size = segment_size + 4;
660 			}
661 		}
662 	}
663 
664 	return (1);
665 }
666