GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tftp/tftp.c Lines: 0 309 0.0 %
Date: 2016-12-06 Branches: 0 220 0.0 %

Line Branch Exec Source
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
}