Deleted Added
sdiff udiff text old ( 71926 ) new ( 84047 )
full compact
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 28 unchanged lines hidden (view full) ---

37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
43#endif
44static const char rcsid[] =
45 "$FreeBSD: head/libexec/tftpd/tftpd.c 84047 2001-09-27 20:50:14Z obrien $";
46#endif /* not lint */
47
48/*
49 * Trivial file transfer protocol server.
50 *
51 * This version includes many modifications by Jim Guyton
52 * <guyton@rand-unix>.
53 */

--- 20 unchanged lines hidden (view full) ---

74#include <stdlib.h>
75#include <string.h>
76#include <syslog.h>
77#include <unistd.h>
78
79#include "tftpsubs.h"
80
81#define TIMEOUT 5
82#define MAX_TIMEOUTS 5
83
84int peer;
85int rexmtval = TIMEOUT;
86int max_rexmtval = 2*TIMEOUT;
87
88#define PKTSIZE SEGSIZE+4
89char buf[PKTSIZE];
90char ackbuf[PKTSIZE];
91struct sockaddr_in from;
92int fromlen;
93
94void tftp __P((struct tftphdr *, int));

--- 11 unchanged lines hidden (view full) ---

106 int len;
107} dirs[MAXDIRS+1];
108static int suppress_naks;
109static int logging;
110static int ipchroot;
111
112static char *errtomsg __P((int));
113static void nak __P((int));
114static void oack __P(());
115
116int
117main(argc, argv)
118 int argc;
119 char *argv[];
120{
121 register struct tftphdr *tp;
122 register int n;

--- 185 unchanged lines hidden (view full) ---

308 { "netascii", validate_access, xmitfile, recvfile, 1 },
309 { "octet", validate_access, xmitfile, recvfile, 0 },
310#ifdef notdef
311 { "mail", validate_user, sendmail, recvmail, 1 },
312#endif
313 { 0 }
314};
315
316struct 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
326enum opt_enum {
327 OPT_TSIZE = 0,
328 OPT_TIMEOUT,
329};
330
331/*
332 * Handle initial connection protocol.
333 */
334void
335tftp(tp, size)
336 struct tftphdr *tp;
337 int size;
338{
339 register char *cp;
340 int i, first = 1, has_options = 0, ecode;
341 register struct formats *pf;
342 char *filename, *mode, *option, *ccp;
343
344 filename = cp = tp->th_stuff;
345again:
346 while (cp < buf + size) {
347 if (*cp == '\0')
348 break;
349 cp++;
350 }

--- 11 unchanged lines hidden (view full) ---

362 *cp = tolower(*cp);
363 for (pf = formats; pf->f_mode; pf++)
364 if (strcmp(pf->f_mode, mode) == 0)
365 break;
366 if (pf->f_mode == 0) {
367 nak(EBADOP);
368 exit(1);
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
401 ecode = (*pf->f_validate)(&filename, tp->th_opcode);
402 if (has_options)
403 oack();
404 if (logging) {
405 char host[MAXHOSTNAMELEN];
406
407 realhostname(host, sizeof(host) - 1, &from.sin_addr);
408 host[sizeof(host) - 1] = '\0';
409 syslog(LOG_INFO, "%s: %s request for %s: %s", host,
410 tp->th_opcode == WRQ ? "write" : "read",
411 filename, errtomsg(ecode));

--- 101 unchanged lines hidden (view full) ---

513 }
514 err = EACCESS;
515 }
516 }
517 if (dirp->name == NULL)
518 return (err);
519 *filep = filename = pathname;
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 }
529 fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY|O_TRUNC);
530 if (fd < 0)
531 return (errno + 100);
532 file = fdopen(fd, (mode == RRQ)? "r":"w");
533 if (file == NULL) {
534 return errno+100;
535 }
536 return (0);
537}
538
539int timeouts;
540jmp_buf timeoutbuf;
541
542void
543timer()
544{
545 if (++timeouts > MAX_TIMEOUTS)
546 exit(1);
547 longjmp(timeoutbuf, 1);
548}
549
550/*
551 * Send the requested file.
552 */
553void

--- 12 unchanged lines hidden (view full) ---

566 do {
567 size = readit(file, &dp, pf->f_convert);
568 if (size < 0) {
569 nak(errno + 100);
570 goto abort;
571 }
572 dp->th_opcode = htons((u_short)DATA);
573 dp->th_block = htons((u_short)block);
574 timeouts = 0;
575 (void)setjmp(timeoutbuf);
576
577send_data:
578 if (send(peer, dp, size + 4, 0) != size + 4) {
579 syslog(LOG_ERR, "write: %m");
580 goto abort;
581 }
582 read_ahead(file, pf->f_convert);

--- 46 unchanged lines hidden (view full) ---

629 register int n, size;
630 volatile unsigned short block;
631
632 signal(SIGALRM, timer);
633 dp = w_init();
634 ap = (struct tftphdr *)ackbuf;
635 block = 0;
636 do {
637 timeouts = 0;
638 ap->th_opcode = htons((u_short)ACK);
639 ap->th_block = htons((u_short)block);
640 block++;
641 (void) setjmp(timeoutbuf);
642send_ack:
643 if (send(peer, ackbuf, 4, 0) != 4) {
644 syslog(LOG_ERR, "write: %m");
645 goto abort;

--- 56 unchanged lines hidden (view full) ---

702 { EUNDEF, "Undefined error code" },
703 { ENOTFOUND, "File not found" },
704 { EACCESS, "Access violation" },
705 { ENOSPACE, "Disk full or allocation exceeded" },
706 { EBADOP, "Illegal TFTP operation" },
707 { EBADID, "Unknown transfer ID" },
708 { EEXISTS, "File already exists" },
709 { ENOUSER, "No such user" },
710 { EOPTNEG, "Option negotiation" },
711 { -1, 0 }
712};
713
714static char *
715errtomsg(error)
716 int error;
717{
718 static char buf[20];

--- 33 unchanged lines hidden (view full) ---

752 }
753 strcpy(tp->th_msg, pe->e_msg);
754 length = strlen(pe->e_msg);
755 tp->th_msg[length] = '\0';
756 length += 5;
757 if (send(peer, buf, length, 0) != length)
758 syslog(LOG_ERR, "nak: %m");
759}
760
761/*
762 * Send an oack packet (option acknowledgement).
763 */
764static void
765oack()
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 }
813}