View | Details | Raw Unified | Return to bug 30710
Collapse All | Expand All

(-)libexec/tftpd/tftpd.c (-9 / +120 lines)
Lines 79-88 Link Here
79
#include "tftpsubs.h"
79
#include "tftpsubs.h"
80
80
81
#define	TIMEOUT		5
81
#define	TIMEOUT		5
82
#define	MAX_TIMEOUTS	5
82
83
83
int	peer;
84
int	peer;
84
int	rexmtval = TIMEOUT;
85
int	rexmtval = TIMEOUT;
85
int	maxtimeout = 5*TIMEOUT;
86
int	max_rexmtval = 2*TIMEOUT;
86
87
87
#define	PKTSIZE	SEGSIZE+4
88
#define	PKTSIZE	SEGSIZE+4
88
char	buf[PKTSIZE];
89
char	buf[PKTSIZE];
Lines 110-115 Link Here
110
111
111
static char *errtomsg __P((int));
112
static char *errtomsg __P((int));
112
static void  nak __P((int));
113
static void  nak __P((int));
114
static void  oack __P(());
113
115
114
int
116
int
115
main(argc, argv)
117
main(argc, argv)
Lines 311-316 Link Here
311
	{ 0 }
313
	{ 0 }
312
};
314
};
313
315
316
struct options {
317
	char	*o_type;
318
	char	*o_request;
319
	int	o_reply;	/* turn into union if need be */
320
} options[] = {
321
	{ "tsize" },		/* OPT_TSIZE */
322
	{ "timeout" },		/* OPT_TIMEOUT */
323
	{ NULL }
324
};
325
326
enum opt_enum {
327
	OPT_TSIZE = 0,
328
	OPT_TIMEOUT,
329
};
330
314
/*
331
/*
315
 * Handle initial connection protocol.
332
 * Handle initial connection protocol.
316
 */
333
 */
Lines 320-328 Link Here
320
	int size;
337
	int size;
321
{
338
{
322
	register char *cp;
339
	register char *cp;
323
	int first = 1, ecode;
340
	int i, first = 1, has_options = 0, ecode;
324
	register struct formats *pf;
341
	register struct formats *pf;
325
	char *filename, *mode;
342
	char *filename, *mode, *option, *ccp;
326
343
327
	filename = cp = tp->th_stuff;
344
	filename = cp = tp->th_stuff;
328
again:
345
again:
Lines 350-356 Link Here
350
		nak(EBADOP);
367
		nak(EBADOP);
351
		exit(1);
368
		exit(1);
352
	}
369
	}
370
	while (++cp < buf + size) {
371
		for (i = 2, ccp = cp; i > 0; ccp++) {
372
			if (ccp >= buf + size) {
373
				nak(EBADOP);
374
				exit(1);
375
			} else if (*ccp == '\0')
376
				i--;
377
		}
378
		for (option = cp; *cp; cp++)
379
			if (isupper(*cp))
380
				*cp = tolower(*cp);
381
		for (i = 0; options[i].o_type != NULL; i++)
382
			if (strcmp(option, options[i].o_type) == 0) {
383
				options[i].o_request = ++cp;
384
				has_options = 1;
385
			}
386
		cp = ccp-1;
387
	}
388
389
	if (options[OPT_TIMEOUT].o_request) {
390
		int to = atoi(options[OPT_TIMEOUT].o_request);
391
		if (to < 1 || to > 255) {
392
			nak(EBADOP);
393
			exit(1);
394
		}
395
		else if (to <= max_rexmtval)
396
			options[OPT_TIMEOUT].o_reply = rexmtval = to;
397
		else
398
			options[OPT_TIMEOUT].o_request = NULL;
399
	}
400
353
	ecode = (*pf->f_validate)(&filename, tp->th_opcode);
401
	ecode = (*pf->f_validate)(&filename, tp->th_opcode);
402
	if (has_options)
403
		oack();
354
	if (logging) {
404
	if (logging) {
355
		char host[MAXHOSTNAMELEN];
405
		char host[MAXHOSTNAMELEN];
356
406
Lines 468-473 Link Here
468
			return (err);
518
			return (err);
469
		*filep = filename = pathname;
519
		*filep = filename = pathname;
470
	}
520
	}
521
	if (options[OPT_TSIZE].o_request) {
522
		if (mode == RRQ) 
523
			options[OPT_TSIZE].o_reply = stbuf.st_size;
524
		else
525
			/* XXX Allows writes of all sizes. */
526
			options[OPT_TSIZE].o_reply =
527
				atoi(options[OPT_TSIZE].o_request);
528
	}
471
	fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY|O_TRUNC);
529
	fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY|O_TRUNC);
472
	if (fd < 0)
530
	if (fd < 0)
473
		return (errno + 100);
531
		return (errno + 100);
Lines 478-492 Link Here
478
	return (0);
536
	return (0);
479
}
537
}
480
538
481
int	timeout;
539
int	timeouts;
482
jmp_buf	timeoutbuf;
540
jmp_buf	timeoutbuf;
483
541
484
void
542
void
485
timer()
543
timer()
486
{
544
{
487
545
	if (++timeouts > MAX_TIMEOUTS)
488
	timeout += rexmtval;
489
	if (timeout >= maxtimeout)
490
		exit(1);
546
		exit(1);
491
	longjmp(timeoutbuf, 1);
547
	longjmp(timeoutbuf, 1);
492
}
548
}
Lines 515-521 Link Here
515
		}
571
		}
516
		dp->th_opcode = htons((u_short)DATA);
572
		dp->th_opcode = htons((u_short)DATA);
517
		dp->th_block = htons((u_short)block);
573
		dp->th_block = htons((u_short)block);
518
		timeout = 0;
574
		timeouts = 0;
519
		(void)setjmp(timeoutbuf);
575
		(void)setjmp(timeoutbuf);
520
576
521
send_data:
577
send_data:
Lines 578-584 Link Here
578
	ap = (struct tftphdr *)ackbuf;
634
	ap = (struct tftphdr *)ackbuf;
579
	block = 0;
635
	block = 0;
580
	do {
636
	do {
581
		timeout = 0;
637
		timeouts = 0;
582
		ap->th_opcode = htons((u_short)ACK);
638
		ap->th_opcode = htons((u_short)ACK);
583
		ap->th_block = htons((u_short)block);
639
		ap->th_block = htons((u_short)block);
584
		block++;
640
		block++;
Lines 651-656 Link Here
651
	{ EBADID,	"Unknown transfer ID" },
707
	{ EBADID,	"Unknown transfer ID" },
652
	{ EEXISTS,	"File already exists" },
708
	{ EEXISTS,	"File already exists" },
653
	{ ENOUSER,	"No such user" },
709
	{ ENOUSER,	"No such user" },
710
	{ EOPTNEG,	"Option negotiation" },
654
	{ -1,		0 }
711
	{ -1,		0 }
655
};
712
};
656
713
Lines 699-702 Link Here
699
	length += 5;
756
	length += 5;
700
	if (send(peer, buf, length, 0) != length)
757
	if (send(peer, buf, length, 0) != length)
701
		syslog(LOG_ERR, "nak: %m");
758
		syslog(LOG_ERR, "nak: %m");
759
}
760
761
/*
762
 * Send an oack packet (option acknowledgement).
763
 */
764
static void
765
oack()
766
{
767
	struct tftphdr *tp, *ap;
768
	int size, i, n;
769
	char *bp;
770
771
	tp = (struct tftphdr *)buf;
772
	bp = buf + 2;
773
	size = sizeof(buf) - 2;
774
	tp->th_opcode = htons((u_short)OACK);
775
	for (i = 0; options[i].o_type != NULL; i++) {
776
		if (options[i].o_request) {
777
			n = snprintf(bp, size, "%s%c%d", options[i].o_type,
778
				     0, options[i].o_reply);
779
			bp += n+1;
780
			size -= n+1;
781
			if (size < 0) {
782
				syslog(LOG_ERR, "oack: buffer overflow");
783
				exit(1);
784
			}
785
		}
786
	}
787
	size = bp - buf;
788
	ap = (struct tftphdr *)ackbuf;
789
	signal(SIGALRM, timer);
790
	timeouts = 0;
791
792
	(void)setjmp(timeoutbuf);
793
	if (send(peer, buf, size, 0) != size) {
794
		syslog(LOG_INFO, "oack: %m");
795
		exit(1);
796
	}
797
798
	for (;;) {
799
		alarm(rexmtval);
800
		n = recv(peer, ackbuf, sizeof (ackbuf), 0);
801
		alarm(0);
802
		if (n < 0) {
803
			syslog(LOG_ERR, "recv: %m");
804
			exit(1);
805
		}
806
		ap->th_opcode = ntohs((u_short)ap->th_opcode);
807
		ap->th_block = ntohs((u_short)ap->th_block);
808
		if (ap->th_opcode == ERROR)
809
			exit(1);
810
		if (ap->th_opcode == ACK && ap->th_block == 0)
811
			break;
812
	}
702
}
813
}
(-)include/arpa/tftp.h (+2 lines)
Lines 49-54 Link Here
49
#define	DATA	03			/* data packet */
49
#define	DATA	03			/* data packet */
50
#define	ACK	04			/* acknowledgement */
50
#define	ACK	04			/* acknowledgement */
51
#define	ERROR	05			/* error code */
51
#define	ERROR	05			/* error code */
52
#define	OACK	06			/* option acknowledgement */
52
53
53
struct	tftphdr {
54
struct	tftphdr {
54
	unsigned short	th_opcode;		/* packet type */
55
	unsigned short	th_opcode;		/* packet type */
Lines 76-80 Link Here
76
#define	EBADID		5		/* unknown transfer ID */
77
#define	EBADID		5		/* unknown transfer ID */
77
#define	EEXISTS		6		/* file already exists */
78
#define	EEXISTS		6		/* file already exists */
78
#define	ENOUSER		7		/* no such user */
79
#define	ENOUSER		7		/* no such user */
80
#define	EOPTNEG		8		/* option negotiation failed */
79
81
80
#endif /* !_TFTP_H_ */
82
#endif /* !_TFTP_H_ */

Return to bug 30710