From 22accddda0b5a47cb2f6ace54a359e102c31ec02 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 8 Jul 2008 17:14:44 -0400 Subject: [PATCH] Reformat the source code The source code was a mix of different styles; normalize on NASM style; basically K&R style with 4 space indentation. --- common/tftpsubs.c | 356 ++++---- common/tftpsubs.h | 13 +- config.h | 8 +- lib/bsdsignal.c | 27 +- lib/daemon.c | 43 +- lib/dup2.c | 18 +- lib/xmalloc.c | 12 +- lib/xstrdup.c | 12 +- tftp/extern.h | 4 +- tftp/main.c | 1356 ++++++++++++++-------------- tftp/tftp.c | 629 +++++++------ tftpd/misc.c | 51 +- tftpd/recvfrom.c | 222 ++--- tftpd/recvfrom.h | 6 +- tftpd/remap.c | 655 +++++++------- tftpd/remap.h | 11 +- tftpd/tftpd.c | 2189 ++++++++++++++++++++++----------------------- tftpd/tftpd.h | 2 +- 18 files changed, 2794 insertions(+), 2820 deletions(-) diff --git a/common/tftpsubs.c b/common/tftpsubs.c index b2eae71..b266efe 100644 --- a/common/tftpsubs.c +++ b/common/tftpsubs.c @@ -41,9 +41,8 @@ #ifndef lint /* static char sccsid[] = "@(#)tftpsubs.c 8.1 (Berkeley) 6/6/93"; */ /* static char rcsid[] = "$OpenBSD: tftpsubs.c,v 1.2 1996/06/26 05:40:36 deraadt Exp $"; */ -static const char *rcsid UNUSED = -"tftp-hpa: $Id$"; -#endif /* not lint */ +static const char *rcsid UNUSED = "tftp-hpa: $Id$"; +#endif /* not lint */ /* Simple minded read-ahead/write-behind subroutines for tftp user and server. Written originally with multiple buffers in mind, but current @@ -58,127 +57,130 @@ static const char *rcsid UNUSED = #include -#define PKTSIZE MAX_SEGSIZE+4 /* should be moved to tftp.h */ +#define PKTSIZE MAX_SEGSIZE+4 /* should be moved to tftp.h */ -int segsize = SEGSIZE; /* Default segsize */ +int segsize = SEGSIZE; /* Default segsize */ struct bf { - int counter; /* size of data in buffer, or flag */ - char buf[PKTSIZE]; /* room for data packet */ + int counter; /* size of data in buffer, or flag */ + char buf[PKTSIZE]; /* room for data packet */ } bfs[2]; - /* Values for bf.counter */ + /* Values for bf.counter */ #define BF_ALLOC -3 /* alloc'd but not yet filled */ #define BF_FREE -2 /* free */ /* [-1 .. segsize] = size of data in the data buffer */ -static int nextone; /* index of next buffer to use */ -static int current; /* index of buffer in use */ +static int nextone; /* index of next buffer to use */ +static int current; /* index of buffer in use */ - /* control flags for crlf conversions */ -int newline = 0; /* fillbuf: in middle of newline expansion */ -int prevchar = -1; /* putbuf: previous char (cr check) */ + /* control flags for crlf conversions */ +int newline = 0; /* fillbuf: in middle of newline expansion */ +int prevchar = -1; /* putbuf: previous char (cr check) */ static struct tftphdr *rw_init(int); -struct tftphdr *w_init() { return rw_init(0); } /* write-behind */ -struct tftphdr *r_init() { return rw_init(1); } /* read-ahead */ +struct tftphdr *w_init() +{ + return rw_init(0); +} /* write-behind */ + +struct tftphdr *r_init() +{ + return rw_init(1); +} /* read-ahead */ /* init for either read-ahead or write-behind */ /* x == zero for write-behind, one for read-head */ -static struct tftphdr * -rw_init(int x) +static struct tftphdr *rw_init(int x) { - newline = 0; /* init crlf flag */ - prevchar = -1; - bfs[0].counter = BF_ALLOC; /* pass out the first buffer */ - current = 0; - bfs[1].counter = BF_FREE; - nextone = x; /* ahead or behind? */ - return (struct tftphdr *)bfs[0].buf; + newline = 0; /* init crlf flag */ + prevchar = -1; + bfs[0].counter = BF_ALLOC; /* pass out the first buffer */ + current = 0; + bfs[1].counter = BF_FREE; + nextone = x; /* ahead or behind? */ + return (struct tftphdr *)bfs[0].buf; } - /* Have emptied current buffer by sending to net and getting ack. Free it and return next buffer filled with data. */ -int -readit(FILE *file, struct tftphdr **dpp, int convert) +int readit(FILE * file, struct tftphdr **dpp, int convert) { - struct bf *b; + struct bf *b; - bfs[current].counter = BF_FREE; /* free old one */ - current = !current; /* "incr" current */ + bfs[current].counter = BF_FREE; /* free old one */ + current = !current; /* "incr" current */ - b = &bfs[current]; /* look at new buffer */ - if (b->counter == BF_FREE) /* if it's empty */ - read_ahead(file, convert); /* fill it */ -/* assert(b->counter != BF_FREE);*//* check */ - *dpp = (struct tftphdr *)b->buf; /* set caller's ptr */ - return b->counter; + b = &bfs[current]; /* look at new buffer */ + if (b->counter == BF_FREE) /* if it's empty */ + read_ahead(file, convert); /* fill it */ + /* assert(b->counter != BF_FREE);*//* check */ + *dpp = (struct tftphdr *)b->buf; /* set caller's ptr */ + return b->counter; } /* * fill the input buffer, doing ascii conversions if requested * conversions are lf -> cr,lf and cr -> cr, nul */ -void -read_ahead(FILE *file, int convert) +void read_ahead(FILE * file, int convert) { - int i; - char *p; - int c; - struct bf *b; - struct tftphdr *dp; + int i; + char *p; + int c; + struct bf *b; + struct tftphdr *dp; - b = &bfs[nextone]; /* look at "next" buffer */ - if (b->counter != BF_FREE) /* nop if not free */ - return; - nextone = !nextone; /* "incr" next buffer ptr */ + b = &bfs[nextone]; /* look at "next" buffer */ + if (b->counter != BF_FREE) /* nop if not free */ + return; + nextone = !nextone; /* "incr" next buffer ptr */ - dp = (struct tftphdr *)b->buf; + dp = (struct tftphdr *)b->buf; - if (convert == 0) { - b->counter = read(fileno(file), dp->th_data, segsize); - return; - } + if (convert == 0) { + b->counter = read(fileno(file), dp->th_data, segsize); + return; + } - p = dp->th_data; - for (i = 0 ; i < segsize; i++) { - if (newline) { - if (prevchar == '\n') - c = '\n'; /* lf to cr,lf */ - else c = '\0'; /* cr to cr,nul */ - newline = 0; - } - else { - c = getc(file); - if (c == EOF) break; - if (c == '\n' || c == '\r') { - prevchar = c; - c = '\r'; - newline = 1; - } - } - *p++ = c; - } - b->counter = (int)(p - dp->th_data); + p = dp->th_data; + for (i = 0; i < segsize; i++) { + if (newline) { + if (prevchar == '\n') + c = '\n'; /* lf to cr,lf */ + else + c = '\0'; /* cr to cr,nul */ + newline = 0; + } else { + c = getc(file); + if (c == EOF) + break; + if (c == '\n' || c == '\r') { + prevchar = c; + c = '\r'; + newline = 1; + } + } + *p++ = c; + } + b->counter = (int)(p - dp->th_data); } /* Update count associated with the buffer, get new buffer from the queue. Calls write_behind only if next buffer not available. */ -int -writeit(FILE *file, struct tftphdr **dpp, int ct, int convert) +int writeit(FILE * file, struct tftphdr **dpp, int ct, int convert) { - bfs[current].counter = ct; /* set size of data to write */ - current = !current; /* switch to other buffer */ - if (bfs[current].counter != BF_FREE) /* if not free */ - (void)write_behind(file, convert); /* flush it */ - bfs[current].counter = BF_ALLOC; /* mark as alloc'd */ - *dpp = (struct tftphdr *)bfs[current].buf; - return ct; /* this is a lie of course */ + bfs[current].counter = ct; /* set size of data to write */ + current = !current; /* switch to other buffer */ + if (bfs[current].counter != BF_FREE) /* if not free */ + (void)write_behind(file, convert); /* flush it */ + bfs[current].counter = BF_ALLOC; /* mark as alloc'd */ + *dpp = (struct tftphdr *)bfs[current].buf; + return ct; /* this is a lie of course */ } /* @@ -187,52 +189,50 @@ writeit(FILE *file, struct tftphdr **dpp, int ct, int convert) * Note spec is undefined if we get CR as last byte of file or a * CR followed by anything else. In this case we leave it alone. */ -int -write_behind(FILE *file, int convert) +int write_behind(FILE * file, int convert) { - char *buf; - int count; - int ct; - char *p; - int c; /* current character */ - struct bf *b; - struct tftphdr *dp; + char *buf; + int count; + int ct; + char *p; + int c; /* current character */ + struct bf *b; + struct tftphdr *dp; - b = &bfs[nextone]; - if (b->counter < -1) /* anything to flush? */ - return 0; /* just nop if nothing to do */ + b = &bfs[nextone]; + if (b->counter < -1) /* anything to flush? */ + return 0; /* just nop if nothing to do */ - count = b->counter; /* remember byte count */ - b->counter = BF_FREE; /* reset flag */ - dp = (struct tftphdr *)b->buf; - nextone = !nextone; /* incr for next time */ - buf = dp->th_data; + count = b->counter; /* remember byte count */ + b->counter = BF_FREE; /* reset flag */ + dp = (struct tftphdr *)b->buf; + nextone = !nextone; /* incr for next time */ + buf = dp->th_data; - if (count <= 0) return -1; /* nak logic? */ + if (count <= 0) + return -1; /* nak logic? */ - if (convert == 0) - return write(fileno(file), buf, count); + if (convert == 0) + return write(fileno(file), buf, count); - p = buf; - ct = count; - while (ct--) { /* loop over the buffer */ - c = *p++; /* pick up a character */ - if (prevchar == '\r') { /* if prev char was cr */ - if (c == '\n') /* if have cr,lf then just */ - fseek(file, -1, 1); /* smash lf on top of the cr */ - else - if (c == '\0') /* if have cr,nul then */ - goto skipit; /* just skip over the putc */ - /* else just fall through and allow it */ - } - putc(c, file); -skipit: - prevchar = c; - } - return count; + p = buf; + ct = count; + while (ct--) { /* loop over the buffer */ + c = *p++; /* pick up a character */ + if (prevchar == '\r') { /* if prev char was cr */ + if (c == '\n') /* if have cr,lf then just */ + fseek(file, -1, 1); /* smash lf on top of the cr */ + else if (c == '\0') /* if have cr,nul then */ + goto skipit; /* just skip over the putc */ + /* else just fall through and allow it */ + } + putc(c, file); + skipit: + prevchar = c; + } + return count; } - /* When an error has occurred, it is possible that the two sides * are out of synch. Ie: that what I think is the other side's * response to packet N is really their response to packet N-1. @@ -244,69 +244,69 @@ skipit: * when trace is active). */ -int -synchnet(int f) /* socket to flush */ -{ - int pktcount = 0; - char rbuf[PKTSIZE]; - struct sockaddr_in from; - socklen_t fromlen; - fd_set socketset; - struct timeval notime; - - while ( 1 ) { - notime.tv_sec = notime.tv_usec = 0; - - FD_ZERO(&socketset); - FD_SET(f, &socketset); - - if ( select(f, &socketset, NULL, NULL, ¬ime) <= 0 ) - break; /* Nothing to read */ - - /* Otherwise drain the packet */ - pktcount++; - fromlen = sizeof from; - (void) recvfrom(f, rbuf, sizeof (rbuf), 0, - (struct sockaddr *)&from, &fromlen); - } +int synchnet(int f) +{ /* socket to flush */ + int pktcount = 0; + char rbuf[PKTSIZE]; + struct sockaddr_in from; + socklen_t fromlen; + fd_set socketset; + struct timeval notime; - return pktcount; /* Return packets drained */ -} + while (1) { + notime.tv_sec = notime.tv_usec = 0; + FD_ZERO(&socketset); + FD_SET(f, &socketset); -int pick_port_bind(int sockfd, struct sockaddr_in *myaddr, unsigned int port_range_from, unsigned int port_range_to) -{ - unsigned int port, firstport; - int port_range = 0; + if (select(f, &socketset, NULL, NULL, ¬ime) <= 0) + break; /* Nothing to read */ - if (port_range_from != 0 && port_range_to != 0) { - port_range = 1; - } - - firstport = port_range - ? port_range_from + rand() % (port_range_to-port_range_from+1) - : 0; - - port = firstport; - - do { - myaddr->sin_port = htons(port); - - if (bind(sockfd, (struct sockaddr *)myaddr, sizeof *myaddr) < 0) { - /* Some versions of Linux return EINVAL instead of EADDRINUSE */ - if ( !(port_range && (errno == EINVAL || errno == EADDRINUSE)) ) - return -1; - - /* Normally, we shouldn't have to loop, but some situations involving - aborted transfers make it possible. */ - } else { - return 0; + /* Otherwise drain the packet */ + pktcount++; + fromlen = sizeof from; + (void)recvfrom(f, rbuf, sizeof(rbuf), 0, + (struct sockaddr *)&from, &fromlen); } - port++; - if ( port > port_range_to ) - port = port_range_from; - } while ( port != firstport ); - - return -1; + return pktcount; /* Return packets drained */ +} + +int pick_port_bind(int sockfd, struct sockaddr_in *myaddr, + unsigned int port_range_from, + unsigned int port_range_to) +{ + unsigned int port, firstport; + int port_range = 0; + + if (port_range_from != 0 && port_range_to != 0) { + port_range = 1; + } + + firstport = port_range + ? port_range_from + rand() % (port_range_to - port_range_from + 1) + : 0; + + port = firstport; + + do { + myaddr->sin_port = htons(port); + + if (bind(sockfd, (struct sockaddr *)myaddr, sizeof *myaddr) < 0) { + /* Some versions of Linux return EINVAL instead of EADDRINUSE */ + if (!(port_range && (errno == EINVAL || errno == EADDRINUSE))) + return -1; + + /* Normally, we shouldn't have to loop, but some situations involving + aborted transfers make it possible. */ + } else { + return 0; + } + + port++; + if (port > port_range_to) + port = port_range_from; + } while (port != firstport); + + return -1; } diff --git a/common/tftpsubs.h b/common/tftpsubs.h index f986afc..f1269fd 100644 --- a/common/tftpsubs.h +++ b/common/tftpsubs.h @@ -50,18 +50,19 @@ struct tftphdr; struct tftphdr *r_init(void); -void read_ahead(FILE *, int); -int readit(FILE *, struct tftphdr **, int); +void read_ahead(FILE *, int); +int readit(FILE *, struct tftphdr **, int); -int synchnet(int); +int synchnet(int); struct tftphdr *w_init(void); -int write_behind(FILE *, int); -int writeit(FILE *, struct tftphdr **, int, int); +int write_behind(FILE *, int); +int writeit(FILE *, struct tftphdr **, int, int); extern int segsize; #define MAX_SEGSIZE 65464 -int pick_port_bind(int sockfd, struct sockaddr_in *myaddr, unsigned int from, unsigned int to); +int pick_port_bind(int sockfd, struct sockaddr_in *myaddr, + unsigned int from, unsigned int to); #endif diff --git a/config.h b/config.h index e4c5cc2..9c973b7 100644 --- a/config.h +++ b/config.h @@ -1,5 +1,5 @@ /* -*- c -*- ------------------------------------------------------------- * - * + * * Copyright 2001-2006 H. Peter Anvin - All Rights Reserved * * This program is free software available under the same license @@ -19,7 +19,7 @@ #define CONFIG_H 1 /* Must be included before we include any system headers! */ -#include "aconfig.h" /* autogenerated configuration header */ +#include "aconfig.h" /* autogenerated configuration header */ /* Standard includes */ @@ -54,7 +54,7 @@ #ifdef HAVE_STRINGS_H #include -#endif +#endif #ifdef HAVE_INTTYPES_H #ifdef INTTYPES_H_IS_SANE @@ -293,7 +293,7 @@ void *xmalloc(size_t); char *xstrdup(const char *); #ifndef HAVE_BSD_SIGNAL -void (*bsd_signal(int, void (*)(int)))(int); +void (*bsd_signal(int, void (*)(int))) (int); #endif #ifndef HAVE_DUP2 int dup2(int, int); diff --git a/lib/bsdsignal.c b/lib/bsdsignal.c index 92de999..0aae136 100644 --- a/lib/bsdsignal.c +++ b/lib/bsdsignal.c @@ -6,23 +6,22 @@ #include "config.h" -void (*bsd_signal(int signum, void (*handler)(int)))(int) -{ - struct sigaction action, oldaction; +void (*bsd_signal(int signum, void (*handler) (int))) (int) { + struct sigaction action, oldaction; - memset(&action, 0, sizeof action); - action.sa_handler = handler; - sigemptyset(&action.sa_mask); - sigaddset(&action.sa_mask, signum); - action.sa_flags = SA_RESTART; - - if (sigaction(signum, &action, &oldaction) == -1) { + memset(&action, 0, sizeof action); + action.sa_handler = handler; + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, signum); + action.sa_flags = SA_RESTART; + + if (sigaction(signum, &action, &oldaction) == -1) { #ifdef SIG_ERR - return SIG_ERR; + return SIG_ERR; #else - return NULL; + return NULL; #endif - } + } - return oldaction.sa_handler; + return oldaction.sa_handler; } diff --git a/lib/daemon.c b/lib/daemon.c index c3106b5..0eb39c9 100644 --- a/lib/daemon.c +++ b/lib/daemon.c @@ -6,32 +6,31 @@ int daemon(int nochdir, int noclose) { - int nullfd; - pid_t f; - - if (!nochdir) { - if (chdir("/")) - return -1; - } + int nullfd; + pid_t f; - if (!noclose) { - if ((nullfd = open("/dev/null", O_RDWR)) < 0 || - dup2(nullfd, 0) < 0 || - dup2(nullfd, 1) < 0 || - dup2(nullfd, 2) < 0) - return -1; - close(nullfd); - } + if (!nochdir) { + if (chdir("/")) + return -1; + } - f = fork(); - if (f < 0) - return -1; - else if (f > 0) - _exit(0); + if (!noclose) { + if ((nullfd = open("/dev/null", O_RDWR)) < 0 || + dup2(nullfd, 0) < 0 || + dup2(nullfd, 1) < 0 || dup2(nullfd, 2) < 0) + return -1; + close(nullfd); + } + + f = fork(); + if (f < 0) + return -1; + else if (f > 0) + _exit(0); #ifdef HAVE_SETSID - return setsid(); + return setsid(); #else - return 0; + return 0; #endif } diff --git a/lib/dup2.c b/lib/dup2.c index bdf3325..bba45c4 100644 --- a/lib/dup2.c +++ b/lib/dup2.c @@ -8,18 +8,16 @@ int dup2(int oldfd, int newfd) { - int rv, nfd; + int rv, nfd; - close(newfd); + close(newfd); - nfd = rv = dup(oldfd); + nfd = rv = dup(oldfd); - if (rv >= 0 && rv != newfd) { - rv = dup2(oldfd, newfd); - close(nfd); - } + if (rv >= 0 && rv != newfd) { + rv = dup2(oldfd, newfd); + close(nfd); + } - return rv; + return rv; } - - diff --git a/lib/xmalloc.c b/lib/xmalloc.c index f234a46..30704f3 100644 --- a/lib/xmalloc.c +++ b/lib/xmalloc.c @@ -9,12 +9,12 @@ void *xmalloc(size_t size) { - void *p = malloc(size); + void *p = malloc(size); - if ( !p ) { - fprintf(stderr, "Out of memory!\n"); - exit(128); - } + if (!p) { + fprintf(stderr, "Out of memory!\n"); + exit(128); + } - return p; + return p; } diff --git a/lib/xstrdup.c b/lib/xstrdup.c index 036b3b2..05e3054 100644 --- a/lib/xstrdup.c +++ b/lib/xstrdup.c @@ -9,12 +9,12 @@ char *xstrdup(const char *s) { - char *p = strdup(s); + char *p = strdup(s); - if ( !p ) { - fprintf(stderr, "Out of memory!\n"); - exit(128); - } + if (!p) { + fprintf(stderr, "Out of memory!\n"); + exit(128); + } - return p; + return p; } diff --git a/tftp/extern.h b/tftp/extern.h index 401608e..bfe9a97 100644 --- a/tftp/extern.h +++ b/tftp/extern.h @@ -41,7 +41,7 @@ #ifndef RECVFILE_H #define RECVFILE_H -void tftp_recvfile (int, const char *, const char *); -void tftp_sendfile (int, const char *, const char *); +void tftp_recvfile(int, const char *, const char *); +void tftp_sendfile(int, const char *, const char *); #endif diff --git a/tftp/main.c b/tftp/main.c index 6bc7c44..bd041a8 100644 --- a/tftp/main.c +++ b/tftp/main.c @@ -37,14 +37,12 @@ #include "common/tftpsubs.h" #ifndef lint -static const char *copyright UNUSED = -"@(#) Copyright (c) 1983, 1993\n\ +static const char *copyright UNUSED = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; /* static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; */ /* static char rcsid[] = "$OpenBSD: main.c,v 1.4 1997/01/17 07:13:30 millert Exp $"; */ -static const char *rcsid UNUSED = - "tftp-hpa $Id$"; -#endif /* not lint */ +static const char *rcsid UNUSED = "tftp-hpa $Id$"; +#endif /* not lint */ /* Many bug fixes are from Jim Guyton */ @@ -63,131 +61,132 @@ static const char *rcsid UNUSED = #include "extern.h" -#define TIMEOUT 5 /* secs between rexmt's */ -#define LBUFLEN 200 /* size of input buffer */ +#define TIMEOUT 5 /* secs between rexmt's */ +#define LBUFLEN 200 /* size of input buffer */ struct modes { - const char *m_name; - const char *m_mode; - int m_openflags; + const char *m_name; + const char *m_mode; + int m_openflags; }; static const struct modes modes[] = { - { "netascii", "netascii", O_TEXT }, - { "ascii", "netascii", O_TEXT }, - { "octet", "octet", O_BINARY }, - { "binary", "octet", O_BINARY }, - { "image", "octet", O_BINARY }, - { 0, 0, 0 } + {"netascii", "netascii", O_TEXT}, + {"ascii", "netascii", O_TEXT}, + {"octet", "octet", O_BINARY}, + {"binary", "octet", O_BINARY}, + {"image", "octet", O_BINARY}, + {0, 0, 0} }; + #define MODE_OCTET (&modes[2]) #define MODE_NETASCII (&modes[0]) #define MODE_DEFAULT MODE_NETASCII -struct sockaddr_in peeraddr; -int f; +struct sockaddr_in peeraddr; +int f; u_short port; -int trace; -int verbose; -int literal; -int connected; +int trace; +int verbose; +int literal; +int connected; const struct modes *mode; #ifdef WITH_READLINE -char *line = NULL; +char *line = NULL; #else -char line[LBUFLEN]; +char line[LBUFLEN]; #endif -int margc; -char *margv[20]; +int margc; +char *margv[20]; const char *prompt = "tftp> "; -sigjmp_buf toplevel; -void intr(int); -struct servent *sp; +sigjmp_buf toplevel; +void intr(int); +struct servent *sp; int portrange = 0; unsigned int portrange_from = 0; -unsigned int portrange_to = 0; +unsigned int portrange_to = 0; -void get (int, char **); -void help (int, char **); -void modecmd (int, char **); -void put (int, char **); -void quit (int, char **); -void setascii (int, char **); -void setbinary (int, char **); -void setpeer (int, char **); -void setrexmt (int, char **); -void settimeout (int, char **); -void settrace (int, char **); -void setverbose (int, char **); -void status (int, char **); -void setliteral (int, char **); +void get(int, char **); +void help(int, char **); +void modecmd(int, char **); +void put(int, char **); +void quit(int, char **); +void setascii(int, char **); +void setbinary(int, char **); +void setpeer(int, char **); +void setrexmt(int, char **); +void settimeout(int, char **); +void settrace(int, char **); +void setverbose(int, char **); +void status(int, char **); +void setliteral(int, char **); -static void command (void); +static void command(void); -static void getusage (char *); -static void makeargv (void); -static void putusage (char *); -static void settftpmode (const struct modes *); +static void getusage(char *); +static void makeargv(void); +static void putusage(char *); +static void settftpmode(const struct modes *); #define HELPINDENT (sizeof("connect")) struct cmd { - const char *name; - const char *help; - void (*handler) (int, char **); + const char *name; + const char *help; + void (*handler) (int, char **); }; struct cmd cmdtab[] = { - { "connect", - "connect to remote tftp", - setpeer }, - { "mode", - "set file transfer mode", - modecmd }, - { "put", - "send file", - put }, - { "get", - "receive file", - get }, - { "quit", - "exit tftp", - quit }, - { "verbose", - "toggle verbose mode", - setverbose }, - { "trace", - "toggle packet tracing", - settrace }, - { "literal", - "toggle literal mode, ignore ':' in file name", - setliteral }, - { "status", - "show current status", - status }, - { "binary", - "set mode to octet", - setbinary }, - { "ascii", - "set mode to netascii", - setascii }, - { "rexmt", - "set per-packet transmission timeout", - setrexmt }, - { "timeout", - "set total retransmission timeout", - settimeout }, - { "?", - "print help information", - help }, - { "help", - "print help information", - help }, - { 0, 0, 0 } + {"connect", + "connect to remote tftp", + setpeer}, + {"mode", + "set file transfer mode", + modecmd}, + {"put", + "send file", + put}, + {"get", + "receive file", + get}, + {"quit", + "exit tftp", + quit}, + {"verbose", + "toggle verbose mode", + setverbose}, + {"trace", + "toggle packet tracing", + settrace}, + {"literal", + "toggle literal mode, ignore ':' in file name", + setliteral}, + {"status", + "show current status", + status}, + {"binary", + "set mode to octet", + setbinary}, + {"ascii", + "set mode to netascii", + setascii}, + {"rexmt", + "set per-packet transmission timeout", + setrexmt}, + {"timeout", + "set total retransmission timeout", + settimeout}, + {"?", + "print help information", + help}, + {"help", + "print help information", + help}, + {0, 0, 0} }; -struct cmd *getcmd(char *); -char *tail(char *); +struct cmd *getcmd(char *); +char *tail(char *); char *xstrdup(const char *); @@ -195,722 +194,717 @@ const char *program; static inline void usage(int errcode) { - fprintf(stderr, "Usage: %s [-v][-l][-m mode] [host [port]] [-c command]\n", program); - exit(errcode); + fprintf(stderr, + "Usage: %s [-v][-l][-m mode] [host [port]] [-c command]\n", + program); + exit(errcode); } -int -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { - struct sockaddr_in s_in; - int arg; - static int pargc, peerargc; - static int iscmd = 0; - char **pargv; - const char *optx; - char *peerargv[3]; + struct sockaddr_in s_in; + int arg; + static int pargc, peerargc; + static int iscmd = 0; + char **pargv; + const char *optx; + char *peerargv[3]; - program = argv[0]; + program = argv[0]; - mode = MODE_DEFAULT; + mode = MODE_DEFAULT; - peerargv[0] = argv[0]; - peerargc = 1; + peerargv[0] = argv[0]; + peerargc = 1; - for ( arg = 1 ; !iscmd && arg < argc ; arg++ ) { - if ( argv[arg][0] == '-' ) { - for ( optx = &argv[arg][1] ; *optx ; optx++ ) { - switch ( *optx ) { - case 'v': - verbose = 1; - break; - case 'V': - /* Print version and configuration to stdout and exit */ - printf("%s\n", TFTP_CONFIG_STR); - exit(0); - case 'l': - literal = 1; - break; - case 'm': - if ( ++arg >= argc ) - usage(EX_USAGE); - { - const struct modes *p; - - for ( p = modes ; p->m_name ; p++ ) { - if (!strcmp(argv[arg], p->m_name)) - break; - } - if (p->m_name) { - settftpmode(p); - } else { - fprintf(stderr, "%s: invalid mode: %s\n", argv[0], argv[arg]); - exit(EX_USAGE); - } - } - break; - case 'c': - iscmd = 1; - break; - case 'R': - if ( ++arg >= argc ) - usage(EX_USAGE); - if ( sscanf(argv[arg], "%u:%u", &portrange_from, &portrange_to) != 2 || - portrange_from > portrange_to || portrange_to > 65535 ) { - fprintf(stderr, "Bad port range: %s\n", argv[arg]); - exit(EX_USAGE); - } - portrange = 1; - break; - case 'h': - default: - usage(*optx == 'h' ? 0 : EX_USAGE); - } - } - } else { - if ( peerargc >= 3 ) - usage(EX_USAGE); + for (arg = 1; !iscmd && arg < argc; arg++) { + if (argv[arg][0] == '-') { + for (optx = &argv[arg][1]; *optx; optx++) { + switch (*optx) { + case 'v': + verbose = 1; + break; + case 'V': + /* Print version and configuration to stdout and exit */ + printf("%s\n", TFTP_CONFIG_STR); + exit(0); + case 'l': + literal = 1; + break; + case 'm': + if (++arg >= argc) + usage(EX_USAGE); + { + const struct modes *p; - peerargv[peerargc++] = argv[arg]; + for (p = modes; p->m_name; p++) { + if (!strcmp(argv[arg], p->m_name)) + break; + } + if (p->m_name) { + settftpmode(p); + } else { + fprintf(stderr, "%s: invalid mode: %s\n", + argv[0], argv[arg]); + exit(EX_USAGE); + } + } + break; + case 'c': + iscmd = 1; + break; + case 'R': + if (++arg >= argc) + usage(EX_USAGE); + if (sscanf + (argv[arg], "%u:%u", &portrange_from, + &portrange_to) != 2 + || portrange_from > portrange_to + || portrange_to > 65535) { + fprintf(stderr, "Bad port range: %s\n", argv[arg]); + exit(EX_USAGE); + } + portrange = 1; + break; + case 'h': + default: + usage(*optx == 'h' ? 0 : EX_USAGE); + } + } + } else { + if (peerargc >= 3) + usage(EX_USAGE); + + peerargv[peerargc++] = argv[arg]; + } } - } - - pargv = argv + arg; - pargc = argc - arg; - - sp = getservbyname("tftp", "udp"); - if (sp == 0) { - /* Use canned values */ - if (verbose) - fprintf(stderr, "tftp: tftp/udp: unknown service, faking it...\n"); - sp = xmalloc(sizeof(struct servent)); - sp->s_name = (char *)"tftp"; - sp->s_aliases = NULL; - sp->s_port = htons(IPPORT_TFTP); - sp->s_proto = (char *)"udp"; - } - port = sp->s_port; /* Default port */ - f = socket(AF_INET, SOCK_DGRAM, 0); - if (f < 0) { - perror("tftp: socket"); - exit(EX_OSERR); - } - bzero((char *)&s_in, sizeof (s_in)); - s_in.sin_family = AF_INET; - if (pick_port_bind(f, &s_in, portrange_from, portrange_to)) { - perror("tftp: bind"); - exit(EX_OSERR); - } - bsd_signal(SIGINT, intr); - if ( peerargc ) { - /* Set peer */ - if (sigsetjmp(toplevel,1) != 0) - exit(EX_NOHOST); - setpeer(peerargc, peerargv); - } + pargv = argv + arg; + pargc = argc - arg; - if ( iscmd && pargc ) { - /* -c specified; execute command and exit */ - struct cmd *c; - - if (sigsetjmp(toplevel,1) != 0) - exit(EX_UNAVAILABLE); - - c = getcmd(pargv[0]); - if ( c == (struct cmd *)-1 || c == (struct cmd *)0 ) { - fprintf(stderr, "%s: invalid command: %s\n", argv[0], pargv[1]); - exit(EX_USAGE); - } - (*c->handler)(pargc, pargv); - exit(0); - } - + sp = getservbyname("tftp", "udp"); + if (sp == 0) { + /* Use canned values */ + if (verbose) + fprintf(stderr, + "tftp: tftp/udp: unknown service, faking it...\n"); + sp = xmalloc(sizeof(struct servent)); + sp->s_name = (char *)"tftp"; + sp->s_aliases = NULL; + sp->s_port = htons(IPPORT_TFTP); + sp->s_proto = (char *)"udp"; + } + port = sp->s_port; /* Default port */ + f = socket(AF_INET, SOCK_DGRAM, 0); + if (f < 0) { + perror("tftp: socket"); + exit(EX_OSERR); + } + bzero((char *)&s_in, sizeof(s_in)); + s_in.sin_family = AF_INET; + if (pick_port_bind(f, &s_in, portrange_from, portrange_to)) { + perror("tftp: bind"); + exit(EX_OSERR); + } + bsd_signal(SIGINT, intr); + + if (peerargc) { + /* Set peer */ + if (sigsetjmp(toplevel, 1) != 0) + exit(EX_NOHOST); + setpeer(peerargc, peerargv); + } + + if (iscmd && pargc) { + /* -c specified; execute command and exit */ + struct cmd *c; + + if (sigsetjmp(toplevel, 1) != 0) + exit(EX_UNAVAILABLE); + + c = getcmd(pargv[0]); + if (c == (struct cmd *)-1 || c == (struct cmd *)0) { + fprintf(stderr, "%s: invalid command: %s\n", argv[0], + pargv[1]); + exit(EX_USAGE); + } + (*c->handler) (pargc, pargv); + exit(0); + } #ifdef WITH_READLINE #ifdef HAVE_READLINE_HISTORY_H - using_history(); + using_history(); #endif #endif - - if (sigsetjmp(toplevel,1) != 0) - (void)putchar('\n'); - command(); - - return 0; /* Never reached */ + + if (sigsetjmp(toplevel, 1) != 0) + (void)putchar('\n'); + command(); + + return 0; /* Never reached */ } -char *hostname; +char *hostname; /* Called when a command is incomplete; modifies the global variable "line" */ -static void -getmoreargs(const char *partial, const char *mprompt) +static void getmoreargs(const char *partial, const char *mprompt) { #ifdef WITH_READLINE - char *eline; - int len, elen; - - len = strlen(partial); - eline = readline(mprompt); - if (!eline) - exit(0); /* EOF */ - - elen = strlen(eline); + char *eline; + int len, elen; - if (line) { - free(line); - line = NULL; - } - line = xmalloc(len+elen+1); - strcpy(line, partial); - strcpy(line+len, eline); - free(eline); + len = strlen(partial); + eline = readline(mprompt); + if (!eline) + exit(0); /* EOF */ + + elen = strlen(eline); + + if (line) { + free(line); + line = NULL; + } + line = xmalloc(len + elen + 1); + strcpy(line, partial); + strcpy(line + len, eline); + free(eline); #ifdef HAVE_READLINE_HISTORY_H - add_history(line); + add_history(line); #endif #else - int len = strlen(partial); - - strcpy(line, partial); - fputs(mprompt, stdout); - if ( fgets(line+len, LBUFLEN-len, stdin) == 0 ) - if ( feof(stdin) ) - exit(0); /* EOF */ + int len = strlen(partial); + + strcpy(line, partial); + fputs(mprompt, stdout); + if (fgets(line + len, LBUFLEN - len, stdin) == 0) + if (feof(stdin)) + exit(0); /* EOF */ #endif } -void -setpeer(int argc, char *argv[]) +void setpeer(int argc, char *argv[]) { - struct hostent *host; + struct hostent *host; - if (argc < 2) { - getmoreargs("connect ", "(to) "); - makeargv(); - argc = margc; - argv = margv; - } - if ((argc < 2) || (argc > 3)) { - printf("usage: %s host-name [port]\n", argv[0]); - return; - } + if (argc < 2) { + getmoreargs("connect ", "(to) "); + makeargv(); + argc = margc; + argv = margv; + } + if ((argc < 2) || (argc > 3)) { + printf("usage: %s host-name [port]\n", argv[0]); + return; + } - host = gethostbyname(argv[1]); - if (host == 0) { - connected = 0; - printf("%s: unknown host\n", argv[1]); - return; - } - peeraddr.sin_family = host->h_addrtype; - bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length); - hostname = xstrdup(host->h_name); + host = gethostbyname(argv[1]); + if (host == 0) { + connected = 0; + printf("%s: unknown host\n", argv[1]); + return; + } + peeraddr.sin_family = host->h_addrtype; + bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length); + hostname = xstrdup(host->h_name); - port = sp->s_port; - if (argc == 3) { - struct servent *usp; - usp = getservbyname(argv[2], "udp"); - if ( usp ) { - port = usp->s_port; - } else { - unsigned long myport; - char *ep; - myport = strtoul(argv[2], &ep, 10); - if (*ep || myport > 65535UL) { - printf("%s: bad port number\n", argv[2]); - connected = 0; - return; - } - port = htons((u_short)myport); - } - } + port = sp->s_port; + if (argc == 3) { + struct servent *usp; + usp = getservbyname(argv[2], "udp"); + if (usp) { + port = usp->s_port; + } else { + unsigned long myport; + char *ep; + myport = strtoul(argv[2], &ep, 10); + if (*ep || myport > 65535UL) { + printf("%s: bad port number\n", argv[2]); + connected = 0; + return; + } + port = htons((u_short) myport); + } + } - if (verbose) { - printf("Connected to %s (%s), port %u\n", - hostname, inet_ntoa(peeraddr.sin_addr), - (unsigned int)ntohs(port)); - } - connected = 1; + if (verbose) { + printf("Connected to %s (%s), port %u\n", + hostname, inet_ntoa(peeraddr.sin_addr), + (unsigned int)ntohs(port)); + } + connected = 1; } -void -modecmd(int argc, char *argv[]) +void modecmd(int argc, char *argv[]) { - const struct modes *p; - const char *sep; + const struct modes *p; + const char *sep; - if (argc < 2) { - printf("Using %s mode to transfer files.\n", mode->m_mode); - return; - } - if (argc == 2) { - for (p = modes; p->m_name; p++) - if (strcmp(argv[1], p->m_name) == 0) - break; - if (p->m_name) { - settftpmode(p); - return; - } - printf("%s: unknown mode\n", argv[1]); - /* drop through and print usage message */ - } + if (argc < 2) { + printf("Using %s mode to transfer files.\n", mode->m_mode); + return; + } + if (argc == 2) { + for (p = modes; p->m_name; p++) + if (strcmp(argv[1], p->m_name) == 0) + break; + if (p->m_name) { + settftpmode(p); + return; + } + printf("%s: unknown mode\n", argv[1]); + /* drop through and print usage message */ + } - printf("usage: %s [", argv[0]); - sep = " "; - for (p = modes; p->m_name; p++) { - printf("%s%s", sep, p->m_name); - if (*sep == ' ') - sep = " | "; - } - printf(" ]\n"); - return; + printf("usage: %s [", argv[0]); + sep = " "; + for (p = modes; p->m_name; p++) { + printf("%s%s", sep, p->m_name); + if (*sep == ' ') + sep = " | "; + } + printf(" ]\n"); + return; } -void -setbinary(int argc, char *argv[]) -{ - (void)argc; (void)argv; /* Quiet unused warning */ - settftpmode(MODE_OCTET); -} - -void -setascii(int argc, char *argv[]) +void setbinary(int argc, char *argv[]) { - (void)argc; (void)argv; /* Quiet unused warning */ - settftpmode(MODE_NETASCII); + (void)argc; + (void)argv; /* Quiet unused warning */ + settftpmode(MODE_OCTET); } -static void -settftpmode(const struct modes *newmode) +void setascii(int argc, char *argv[]) { - mode = newmode; - if (verbose) - printf("mode set to %s\n", mode->m_mode); + (void)argc; + (void)argv; /* Quiet unused warning */ + settftpmode(MODE_NETASCII); } +static void settftpmode(const struct modes *newmode) +{ + mode = newmode; + if (verbose) + printf("mode set to %s\n", mode->m_mode); +} /* * Send file(s). */ -void -put(int argc, char *argv[]) +void put(int argc, char *argv[]) { - int fd; - int n; - char *cp, *targ; + int fd; + int n; + char *cp, *targ; - if (argc < 2) { - getmoreargs("send ", "(file) "); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { - putusage(argv[0]); - return; - } - targ = argv[argc - 1]; - if (!literal && strchr(argv[argc - 1], ':')) { - struct hostent *hp; + if (argc < 2) { + getmoreargs("send ", "(file) "); + makeargv(); + argc = margc; + argv = margv; + } + if (argc < 2) { + putusage(argv[0]); + return; + } + targ = argv[argc - 1]; + if (!literal && strchr(argv[argc - 1], ':')) { + struct hostent *hp; - for (n = 1; n < argc - 1; n++) - if (strchr(argv[n], ':')) { - putusage(argv[0]); - return; - } - cp = argv[argc - 1]; - targ = strchr(cp, ':'); - *targ++ = 0; - hp = gethostbyname(cp); - if (hp == NULL) { - fprintf(stderr, "tftp: %s: ", cp); - herror((char *)NULL); - return; - } - bcopy(hp->h_addr, &peeraddr.sin_addr, hp->h_length); - peeraddr.sin_family = hp->h_addrtype; - connected = 1; - hostname = xstrdup(hp->h_name); - } - if (!connected) { - printf("No target machine specified.\n"); - return; - } - if (argc < 4) { - cp = argc == 2 ? tail(targ) : argv[1]; - fd = open(cp, O_RDONLY|mode->m_openflags); - if (fd < 0) { - fprintf(stderr, "tftp: "); perror(cp); - return; - } - if (verbose) - printf("putting %s to %s:%s [%s]\n", - cp, hostname, targ, mode->m_mode); - peeraddr.sin_port = port; - tftp_sendfile(fd, targ, mode->m_mode); - return; - } - /* this assumes the target is a directory */ - /* on a remote unix system. hmmmm. */ - cp = strchr(targ, '\0'); - *cp++ = '/'; - for (n = 1; n < argc - 1; n++) { - strcpy(cp, tail(argv[n])); - fd = open(argv[n], O_RDONLY|mode->m_openflags); - if (fd < 0) { - fprintf(stderr, "tftp: "); perror(argv[n]); - continue; - } - if (verbose) - printf("putting %s to %s:%s [%s]\n", - argv[n], hostname, targ, mode->m_mode); - peeraddr.sin_port = port; - tftp_sendfile(fd, targ, mode->m_mode); - } + for (n = 1; n < argc - 1; n++) + if (strchr(argv[n], ':')) { + putusage(argv[0]); + return; + } + cp = argv[argc - 1]; + targ = strchr(cp, ':'); + *targ++ = 0; + hp = gethostbyname(cp); + if (hp == NULL) { + fprintf(stderr, "tftp: %s: ", cp); + herror((char *)NULL); + return; + } + bcopy(hp->h_addr, &peeraddr.sin_addr, hp->h_length); + peeraddr.sin_family = hp->h_addrtype; + connected = 1; + hostname = xstrdup(hp->h_name); + } + if (!connected) { + printf("No target machine specified.\n"); + return; + } + if (argc < 4) { + cp = argc == 2 ? tail(targ) : argv[1]; + fd = open(cp, O_RDONLY | mode->m_openflags); + if (fd < 0) { + fprintf(stderr, "tftp: "); + perror(cp); + return; + } + if (verbose) + printf("putting %s to %s:%s [%s]\n", + cp, hostname, targ, mode->m_mode); + peeraddr.sin_port = port; + tftp_sendfile(fd, targ, mode->m_mode); + return; + } + /* this assumes the target is a directory */ + /* on a remote unix system. hmmmm. */ + cp = strchr(targ, '\0'); + *cp++ = '/'; + for (n = 1; n < argc - 1; n++) { + strcpy(cp, tail(argv[n])); + fd = open(argv[n], O_RDONLY | mode->m_openflags); + if (fd < 0) { + fprintf(stderr, "tftp: "); + perror(argv[n]); + continue; + } + if (verbose) + printf("putting %s to %s:%s [%s]\n", + argv[n], hostname, targ, mode->m_mode); + peeraddr.sin_port = port; + tftp_sendfile(fd, targ, mode->m_mode); + } } -static void -putusage(char *s) +static void putusage(char *s) { - printf("usage: %s file ... host:target, or\n", s); - printf(" %s file ... target (when already connected)\n", s); + printf("usage: %s file ... host:target, or\n", s); + printf(" %s file ... target (when already connected)\n", s); } /* * Receive file(s). */ -void -get(int argc, char *argv[]) +void get(int argc, char *argv[]) { - int fd; - int n; - char *cp; - char *src; + int fd; + int n; + char *cp; + char *src; - if (argc < 2) { - getmoreargs("get ", "(files) "); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { - getusage(argv[0]); - return; - } - if (!connected) { - for (n = 1; n < argc ; n++) - if (literal || strchr(argv[n], ':') == 0) { - getusage(argv[0]); - return; - } - } - for (n = 1; n < argc ; n++) { - src = strchr(argv[n], ':'); - if (literal || src == NULL) - src = argv[n]; - else { - struct hostent *hp; + if (argc < 2) { + getmoreargs("get ", "(files) "); + makeargv(); + argc = margc; + argv = margv; + } + if (argc < 2) { + getusage(argv[0]); + return; + } + if (!connected) { + for (n = 1; n < argc; n++) + if (literal || strchr(argv[n], ':') == 0) { + getusage(argv[0]); + return; + } + } + for (n = 1; n < argc; n++) { + src = strchr(argv[n], ':'); + if (literal || src == NULL) + src = argv[n]; + else { + struct hostent *hp; - *src++ = 0; - hp = gethostbyname(argv[n]); - if (hp == NULL) { - fprintf(stderr, "tftp: %s: ", argv[n]); - herror((char *)NULL); - continue; - } - bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, - hp->h_length); - peeraddr.sin_family = hp->h_addrtype; - connected = 1; - hostname = xstrdup(hp->h_name); - } - if (argc < 4) { - cp = argc == 3 ? argv[2] : tail(src); - fd = open(cp, O_WRONLY|O_CREAT|O_TRUNC|mode->m_openflags, 0666); - if (fd < 0) { - fprintf(stderr, "tftp: "); perror(cp); - return; - } - if (verbose) - printf("getting from %s:%s to %s [%s]\n", - hostname, src, cp, mode->m_mode); - peeraddr.sin_port = port; - tftp_recvfile(fd, src, mode->m_mode); - break; - } - cp = tail(src); /* new .. jdg */ - fd = open(cp, O_WRONLY|O_CREAT|O_TRUNC|mode->m_openflags, 0666); - if (fd < 0) { - fprintf(stderr, "tftp: "); perror(cp); - continue; - } - if (verbose) - printf("getting from %s:%s to %s [%s]\n", - hostname, src, cp, mode->m_mode); - peeraddr.sin_port = port; - tftp_recvfile(fd, src, mode->m_mode); - } + *src++ = 0; + hp = gethostbyname(argv[n]); + if (hp == NULL) { + fprintf(stderr, "tftp: %s: ", argv[n]); + herror((char *)NULL); + continue; + } + bcopy(hp->h_addr, (caddr_t) & peeraddr.sin_addr, hp->h_length); + peeraddr.sin_family = hp->h_addrtype; + connected = 1; + hostname = xstrdup(hp->h_name); + } + if (argc < 4) { + cp = argc == 3 ? argv[2] : tail(src); + fd = open(cp, O_WRONLY | O_CREAT | O_TRUNC | mode->m_openflags, + 0666); + if (fd < 0) { + fprintf(stderr, "tftp: "); + perror(cp); + return; + } + if (verbose) + printf("getting from %s:%s to %s [%s]\n", + hostname, src, cp, mode->m_mode); + peeraddr.sin_port = port; + tftp_recvfile(fd, src, mode->m_mode); + break; + } + cp = tail(src); /* new .. jdg */ + fd = open(cp, O_WRONLY | O_CREAT | O_TRUNC | mode->m_openflags, + 0666); + if (fd < 0) { + fprintf(stderr, "tftp: "); + perror(cp); + continue; + } + if (verbose) + printf("getting from %s:%s to %s [%s]\n", + hostname, src, cp, mode->m_mode); + peeraddr.sin_port = port; + tftp_recvfile(fd, src, mode->m_mode); + } } -static void -getusage(char *s) +static void getusage(char *s) { - printf("usage: %s host:file host:file ... file, or\n", s); - printf(" %s file file ... file if connected\n", s); + printf("usage: %s host:file host:file ... file, or\n", s); + printf(" %s file file ... file if connected\n", s); } -int rexmtval = TIMEOUT; +int rexmtval = TIMEOUT; -void -setrexmt(int argc, char *argv[]) +void setrexmt(int argc, char *argv[]) { - int t; + int t; - if (argc < 2) { - getmoreargs("rexmt-timeout ", "(value) "); - makeargv(); - argc = margc; - argv = margv; - } - if (argc != 2) { - printf("usage: %s value\n", argv[0]); - return; - } - t = atoi(argv[1]); - if (t < 0) - printf("%s: bad value\n", argv[1]); - else - rexmtval = t; + if (argc < 2) { + getmoreargs("rexmt-timeout ", "(value) "); + makeargv(); + argc = margc; + argv = margv; + } + if (argc != 2) { + printf("usage: %s value\n", argv[0]); + return; + } + t = atoi(argv[1]); + if (t < 0) + printf("%s: bad value\n", argv[1]); + else + rexmtval = t; } -int maxtimeout = 5 * TIMEOUT; +int maxtimeout = 5 * TIMEOUT; -void -settimeout(int argc, char *argv[]) +void settimeout(int argc, char *argv[]) { - int t; + int t; - if (argc < 2) { - getmoreargs("maximum-timeout ", "(value) "); - makeargv(); - argc = margc; - argv = margv; - } - if (argc != 2) { - printf("usage: %s value\n", argv[0]); - return; - } - t = atoi(argv[1]); - if (t < 0) - printf("%s: bad value\n", argv[1]); - else - maxtimeout = t; + if (argc < 2) { + getmoreargs("maximum-timeout ", "(value) "); + makeargv(); + argc = margc; + argv = margv; + } + if (argc != 2) { + printf("usage: %s value\n", argv[0]); + return; + } + t = atoi(argv[1]); + if (t < 0) + printf("%s: bad value\n", argv[1]); + else + maxtimeout = t; } -void -setliteral(int argc, char *argv[]) +void setliteral(int argc, char *argv[]) { - (void)argc; (void)argv; /* Quiet unused warning */ - literal = !literal; - printf("Literal mode %s.\n", literal ? "on" : "off"); + (void)argc; + (void)argv; /* Quiet unused warning */ + literal = !literal; + printf("Literal mode %s.\n", literal ? "on" : "off"); } -void -status(int argc, char *argv[]) +void status(int argc, char *argv[]) { - (void)argc; (void)argv; /* Quiet unused warning */ - if (connected) - printf("Connected to %s.\n", hostname); - else - printf("Not connected.\n"); - printf("Mode: %s Verbose: %s Tracing: %s Literal: %s\n", mode->m_mode, - verbose ? "on" : "off", trace ? "on" : "off", literal ? "on" : "off"); - printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", - rexmtval, maxtimeout); + (void)argc; + (void)argv; /* Quiet unused warning */ + if (connected) + printf("Connected to %s.\n", hostname); + else + printf("Not connected.\n"); + printf("Mode: %s Verbose: %s Tracing: %s Literal: %s\n", mode->m_mode, + verbose ? "on" : "off", trace ? "on" : "off", + literal ? "on" : "off"); + printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", + rexmtval, maxtimeout); } -void -intr(int sig) +void intr(int sig) { - (void)sig; /* Quiet unused warning */ + (void)sig; /* Quiet unused warning */ - bsd_signal(SIGALRM, SIG_IGN); - alarm(0); - siglongjmp(toplevel, -1); + bsd_signal(SIGALRM, SIG_IGN); + alarm(0); + siglongjmp(toplevel, -1); } -char * -tail(char *filename) +char *tail(char *filename) { - char *s; - - while (*filename) { - s = strrchr(filename, '/'); - if (s == NULL) - break; - if (s[1]) - return (s + 1); - *s = '\0'; - } - return (filename); + char *s; + + while (*filename) { + s = strrchr(filename, '/'); + if (s == NULL) + break; + if (s[1]) + return (s + 1); + *s = '\0'; + } + return (filename); } /* * Command parser. */ -static void -command(void) +static void command(void) { - struct cmd *c; + struct cmd *c; - for (;;) { + for (;;) { #ifdef WITH_READLINE - if ( line ) { - free(line); - line = NULL; - } - line = readline(prompt); - if ( !line ) - exit(0); /* EOF */ + if (line) { + free(line); + line = NULL; + } + line = readline(prompt); + if (!line) + exit(0); /* EOF */ #else - fputs(prompt, stdout); - if (fgets(line, LBUFLEN, stdin) == 0) { - if (feof(stdin)) { - exit(0); - } else { - continue; - } - } + fputs(prompt, stdout); + if (fgets(line, LBUFLEN, stdin) == 0) { + if (feof(stdin)) { + exit(0); + } else { + continue; + } + } #endif - if ((line[0] == 0) || (line[0] == '\n')) - continue; + if ((line[0] == 0) || (line[0] == '\n')) + continue; #ifdef WITH_READLINE #ifdef HAVE_READLINE_HISTORY_H - add_history(line); + add_history(line); #endif #endif - makeargv(); - if (margc == 0) - continue; + makeargv(); + if (margc == 0) + continue; - c = getcmd(margv[0]); - if (c == (struct cmd *)-1) { - printf("?Ambiguous command\n"); - continue; - } - if (c == 0) { - printf("?Invalid command\n"); - continue; - } - (*c->handler)(margc, margv); - } + c = getcmd(margv[0]); + if (c == (struct cmd *)-1) { + printf("?Ambiguous command\n"); + continue; + } + if (c == 0) { + printf("?Invalid command\n"); + continue; + } + (*c->handler) (margc, margv); + } } -struct cmd * -getcmd(char *name) +struct cmd *getcmd(char *name) { - const char *p; - char *q; - struct cmd *c, *found; - int nmatches, longest; + const char *p; + char *q; + struct cmd *c, *found; + int nmatches, longest; - longest = 0; - nmatches = 0; - found = 0; - for (c = cmdtab; (p = c->name) != NULL; c++) { - for (q = name; *q == *p++; q++) - if (*q == 0) /* exact match? */ - return (c); - if (!*q) { /* the name was a prefix */ - if (q - name > longest) { - longest = q - name; - nmatches = 1; - found = c; - } else if (q - name == longest) - nmatches++; - } - } - if (nmatches > 1) - return ((struct cmd *)-1); - return (found); + longest = 0; + nmatches = 0; + found = 0; + for (c = cmdtab; (p = c->name) != NULL; c++) { + for (q = name; *q == *p++; q++) + if (*q == 0) /* exact match? */ + return (c); + if (!*q) { /* the name was a prefix */ + if (q - name > longest) { + longest = q - name; + nmatches = 1; + found = c; + } else if (q - name == longest) + nmatches++; + } + } + if (nmatches > 1) + return ((struct cmd *)-1); + return (found); } /* * Slice a string up into argc/argv. */ -static void -makeargv(void) +static void makeargv(void) { - char *cp; - char **argp = margv; + char *cp; + char **argp = margv; - margc = 0; - for (cp = line; *cp;) { - while (isspace(*cp)) - cp++; - if (*cp == '\0') - break; - *argp++ = cp; - margc += 1; - while (*cp != '\0' && !isspace(*cp)) - cp++; - if (*cp == '\0') - break; - *cp++ = '\0'; - } - *argp++ = 0; + margc = 0; + for (cp = line; *cp;) { + while (isspace(*cp)) + cp++; + if (*cp == '\0') + break; + *argp++ = cp; + margc += 1; + while (*cp != '\0' && !isspace(*cp)) + cp++; + if (*cp == '\0') + break; + *cp++ = '\0'; + } + *argp++ = 0; } -void -quit(int argc, char *argv[]) +void quit(int argc, char *argv[]) { - (void)argc; (void)argv; /* Quiet unused warning */ - exit(0); + (void)argc; + (void)argv; /* Quiet unused warning */ + exit(0); } /* * Help command. */ -void -help(int argc, char *argv[]) +void help(int argc, char *argv[]) { - struct cmd *c; + struct cmd *c; - printf("%s\n", VERSION); + printf("%s\n", VERSION); - if (argc == 1) { - printf("Commands may be abbreviated. Commands are:\n\n"); - for (c = cmdtab; c->name; c++) - printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); - return; - } - while (--argc > 0) { - char *arg; - arg = *++argv; - c = getcmd(arg); - if (c == (struct cmd *)-1) - printf("?Ambiguous help command %s\n", arg); - else if (c == (struct cmd *)0) - printf("?Invalid help command %s\n", arg); - else - printf("%s\n", c->help); - } + if (argc == 1) { + printf("Commands may be abbreviated. Commands are:\n\n"); + for (c = cmdtab; c->name; c++) + printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); + return; + } + while (--argc > 0) { + char *arg; + arg = *++argv; + c = getcmd(arg); + if (c == (struct cmd *)-1) + printf("?Ambiguous help command %s\n", arg); + else if (c == (struct cmd *)0) + printf("?Invalid help command %s\n", arg); + else + printf("%s\n", c->help); + } } -void -settrace(int argc, char *argv[]) +void settrace(int argc, char *argv[]) { - (void)argc; (void)argv; /* Quiet unused warning */ + (void)argc; + (void)argv; /* Quiet unused warning */ - trace = !trace; - printf("Packet tracing %s.\n", trace ? "on" : "off"); + trace = !trace; + printf("Packet tracing %s.\n", trace ? "on" : "off"); } -void -setverbose(int argc, char *argv[]) +void setverbose(int argc, char *argv[]) { - (void)argc; (void)argv; /* Quiet unused warning */ + (void)argc; + (void)argv; /* Quiet unused warning */ - verbose = !verbose; - printf("Verbose mode %s.\n", verbose ? "on" : "off"); + verbose = !verbose; + printf("Verbose mode %s.\n", verbose ? "on" : "off"); } diff --git a/tftp/tftp.c b/tftp/tftp.c index 8dfec29..41c6fbd 100644 --- a/tftp/tftp.c +++ b/tftp/tftp.c @@ -39,9 +39,8 @@ #ifndef lint /* static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; */ /* static char rcsid[] = "$OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt Exp $"; */ -static const char *rcsid UNUSED = -"tftp-hpa $Id$"; -#endif /* not lint */ +static const char *rcsid UNUSED = "tftp-hpa $Id$"; +#endif /* not lint */ /* Many bug fixes are from Jim Guyton */ @@ -50,18 +49,18 @@ static const char *rcsid UNUSED = */ #include "extern.h" -extern struct sockaddr_in peeraddr; /* filled in by main */ -extern int f; /* the opened socket */ -extern int trace; -extern int verbose; -extern int rexmtval; -extern int maxtimeout; +extern struct sockaddr_in peeraddr; /* filled in by main */ +extern int f; /* the opened socket */ +extern int trace; +extern int verbose; +extern int rexmtval; +extern int maxtimeout; #define PKTSIZE SEGSIZE+4 -char ackbuf[PKTSIZE]; -int timeout; -sigjmp_buf toplevel; -sigjmp_buf timeoutbuf; +char ackbuf[PKTSIZE]; +int timeout; +sigjmp_buf toplevel; +sigjmp_buf timeoutbuf; static void nak(int, const char *); static int makerequest(int, const char *, struct tftphdr *, const char *); @@ -74,251 +73,247 @@ static void tpacket(const char *, struct tftphdr *, int); /* * Send the requested file. */ -void -tftp_sendfile(int fd, const char *name, const char *mode) +void tftp_sendfile(int fd, const char *name, const char *mode) { - struct tftphdr *ap; /* data and ack packets */ - struct tftphdr *dp; - int n; - volatile int is_request; - volatile u_short block; - volatile int size, convert; - volatile off_t amount; - struct sockaddr_in from; - socklen_t fromlen; - FILE *file; - u_short ap_opcode, ap_block; + struct tftphdr *ap; /* data and ack packets */ + struct tftphdr *dp; + int n; + volatile int is_request; + volatile u_short block; + volatile int size, convert; + volatile off_t amount; + struct sockaddr_in from; + socklen_t fromlen; + FILE *file; + u_short ap_opcode, ap_block; - startclock(); /* start stat's clock */ - dp = r_init(); /* reset fillbuf/read-ahead code */ - ap = (struct tftphdr *)ackbuf; - convert = !strcmp(mode, "netascii"); - file = fdopen(fd, convert ? "rt" : "rb"); - block = 0; - is_request = 1; /* First packet is the actual WRQ */ - amount = 0; + startclock(); /* start stat's clock */ + dp = r_init(); /* reset fillbuf/read-ahead code */ + ap = (struct tftphdr *)ackbuf; + convert = !strcmp(mode, "netascii"); + file = fdopen(fd, convert ? "rt" : "rb"); + block = 0; + is_request = 1; /* First packet is the actual WRQ */ + amount = 0; - bsd_signal(SIGALRM, timer); - do { - if (is_request) { - size = makerequest(WRQ, name, dp, mode) - 4; - } else { - /* size = read(fd, dp->th_data, SEGSIZE); */ - size = readit(file, &dp, convert); - if (size < 0) { - nak(errno + 100, NULL); - break; - } - dp->th_opcode = htons((u_short)DATA); - dp->th_block = htons((u_short)block); - } - timeout = 0; - (void) sigsetjmp(timeoutbuf,1); + bsd_signal(SIGALRM, timer); + do { + if (is_request) { + size = makerequest(WRQ, name, dp, mode) - 4; + } else { + /* size = read(fd, dp->th_data, SEGSIZE); */ + size = readit(file, &dp, convert); + if (size < 0) { + nak(errno + 100, NULL); + break; + } + dp->th_opcode = htons((u_short) DATA); + dp->th_block = htons((u_short) block); + } + timeout = 0; + (void)sigsetjmp(timeoutbuf, 1); - if (trace) - tpacket("sent", dp, size + 4); - n = sendto(f, dp, size + 4, 0, - (struct sockaddr *)&peeraddr, sizeof(peeraddr)); - if (n != size + 4) { - perror("tftp: sendto"); - goto abort; - } - read_ahead(file, convert); - for ( ; ; ) { - alarm(rexmtval); - do { - fromlen = sizeof(from); - n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, - (struct sockaddr *)&from, &fromlen); - } while (n <= 0); - alarm(0); - if (n < 0) { - perror("tftp: recvfrom"); - goto abort; - } - peeraddr.sin_port = from.sin_port; /* added */ - if (trace) - tpacket("received", ap, n); - /* should verify packet came from server */ - ap_opcode = ntohs((u_short)ap->th_opcode); - ap_block = ntohs((u_short)ap->th_block); - if (ap_opcode == ERROR) { - printf("Error code %d: %s\n", ap_block, - ap->th_msg); - goto abort; - } - if (ap_opcode == ACK) { - int j; + if (trace) + tpacket("sent", dp, size + 4); + n = sendto(f, dp, size + 4, 0, + (struct sockaddr *)&peeraddr, sizeof(peeraddr)); + if (n != size + 4) { + perror("tftp: sendto"); + goto abort; + } + read_ahead(file, convert); + for (;;) { + alarm(rexmtval); + do { + fromlen = sizeof(from); + n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, + (struct sockaddr *)&from, &fromlen); + } while (n <= 0); + alarm(0); + if (n < 0) { + perror("tftp: recvfrom"); + goto abort; + } + peeraddr.sin_port = from.sin_port; /* added */ + if (trace) + tpacket("received", ap, n); + /* should verify packet came from server */ + ap_opcode = ntohs((u_short) ap->th_opcode); + ap_block = ntohs((u_short) ap->th_block); + if (ap_opcode == ERROR) { + printf("Error code %d: %s\n", ap_block, ap->th_msg); + goto abort; + } + if (ap_opcode == ACK) { + int j; - if (ap_block == block) { - break; - } - /* On an error, try to synchronize - * both sides. - */ - j = synchnet(f); - if (j && trace) { - printf("discarded %d packets\n", - j); - } - /* - * RFC1129/RFC1350: We MUST NOT re-send the DATA - * packet in response to an invalid ACK. Doing so - * would cause the Sorcerer's Apprentice bug. - */ - } - } - if ( !is_request ) - amount += size; - is_request = 0; - block++; - } while (size == SEGSIZE || block == 1); -abort: - fclose(file); - stopclock(); - if (amount > 0) - printstats("Sent", amount); + if (ap_block == block) { + break; + } + /* On an error, try to synchronize + * both sides. + */ + j = synchnet(f); + if (j && trace) { + printf("discarded %d packets\n", j); + } + /* + * RFC1129/RFC1350: We MUST NOT re-send the DATA + * packet in response to an invalid ACK. Doing so + * would cause the Sorcerer's Apprentice bug. + */ + } + } + if (!is_request) + amount += size; + is_request = 0; + block++; + } while (size == SEGSIZE || block == 1); + abort: + fclose(file); + stopclock(); + if (amount > 0) + printstats("Sent", amount); } /* * Receive a file. */ -void -tftp_recvfile(int fd, const char *name, const char *mode) +void tftp_recvfile(int fd, const char *name, const char *mode) { - struct tftphdr *ap; - struct tftphdr *dp; - int n; - volatile u_short block; - volatile int size, firsttrip; - volatile unsigned long amount; - struct sockaddr_in from; - socklen_t fromlen; - FILE *file; - volatile int convert; /* true if converting crlf -> lf */ - u_short dp_opcode, dp_block; + struct tftphdr *ap; + struct tftphdr *dp; + int n; + volatile u_short block; + volatile int size, firsttrip; + volatile unsigned long amount; + struct sockaddr_in from; + socklen_t fromlen; + FILE *file; + volatile int convert; /* true if converting crlf -> lf */ + u_short dp_opcode, dp_block; - startclock(); - dp = w_init(); - ap = (struct tftphdr *)ackbuf; - convert = !strcmp(mode, "netascii"); - file = fdopen(fd, convert ?"wt":"wb"); - block = 1; - firsttrip = 1; - amount = 0; + startclock(); + dp = w_init(); + ap = (struct tftphdr *)ackbuf; + convert = !strcmp(mode, "netascii"); + file = fdopen(fd, convert ? "wt" : "wb"); + block = 1; + firsttrip = 1; + amount = 0; - bsd_signal(SIGALRM, timer); - do { - if (firsttrip) { - size = makerequest(RRQ, name, ap, mode); - firsttrip = 0; - } else { - ap->th_opcode = htons((u_short)ACK); - ap->th_block = htons((u_short)block); - size = 4; - block++; - } - timeout = 0; - (void) sigsetjmp(timeoutbuf,1); -send_ack: - if (trace) - tpacket("sent", ap, size); - if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr, - sizeof(peeraddr)) != size) { - alarm(0); - perror("tftp: sendto"); - goto abort; - } - write_behind(file, convert); - for ( ; ; ) { - alarm(rexmtval); - do { - fromlen = sizeof(from); - n = recvfrom(f, dp, PKTSIZE, 0, - (struct sockaddr *)&from, &fromlen); - } while (n <= 0); - alarm(0); - if (n < 0) { - perror("tftp: recvfrom"); - goto abort; - } - peeraddr.sin_port = from.sin_port; /* added */ - if (trace) - tpacket("received", dp, n); - /* should verify client address */ - dp_opcode = ntohs((u_short)dp->th_opcode); - dp_block = ntohs((u_short)dp->th_block); - if (dp_opcode == ERROR) { - printf("Error code %d: %s\n", dp_block, dp->th_msg); - goto abort; - } - if (dp_opcode == DATA) { - int j; + bsd_signal(SIGALRM, timer); + do { + if (firsttrip) { + size = makerequest(RRQ, name, ap, mode); + firsttrip = 0; + } else { + ap->th_opcode = htons((u_short) ACK); + ap->th_block = htons((u_short) block); + size = 4; + block++; + } + timeout = 0; + (void)sigsetjmp(timeoutbuf, 1); + send_ack: + if (trace) + tpacket("sent", ap, size); + if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr, + sizeof(peeraddr)) != size) { + alarm(0); + perror("tftp: sendto"); + goto abort; + } + write_behind(file, convert); + for (;;) { + alarm(rexmtval); + do { + fromlen = sizeof(from); + n = recvfrom(f, dp, PKTSIZE, 0, + (struct sockaddr *)&from, &fromlen); + } while (n <= 0); + alarm(0); + if (n < 0) { + perror("tftp: recvfrom"); + goto abort; + } + peeraddr.sin_port = from.sin_port; /* added */ + if (trace) + tpacket("received", dp, n); + /* should verify client address */ + dp_opcode = ntohs((u_short) dp->th_opcode); + dp_block = ntohs((u_short) dp->th_block); + if (dp_opcode == ERROR) { + printf("Error code %d: %s\n", dp_block, dp->th_msg); + goto abort; + } + if (dp_opcode == DATA) { + int j; - if (dp_block == block) { - break; /* have next packet */ - } - /* On an error, try to synchronize - * both sides. - */ - j = synchnet(f); - if (j && trace) { - printf("discarded %d packets\n", j); - } - if (dp_block == (block-1)) { - goto send_ack; /* resend ack */ - } - } - } - /* size = write(fd, dp->th_data, n - 4); */ - size = writeit(file, &dp, n - 4, convert); - if (size < 0) { - nak(errno + 100, NULL); - break; - } - amount += size; - } while (size == SEGSIZE); -abort: /* ok to ack, since user */ - ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ - ap->th_block = htons((u_short)block); - (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr, - sizeof(peeraddr)); - write_behind(file, convert); /* flush last buffer */ - fclose(file); - stopclock(); - if (amount > 0) - printstats("Received", amount); + if (dp_block == block) { + break; /* have next packet */ + } + /* On an error, try to synchronize + * both sides. + */ + j = synchnet(f); + if (j && trace) { + printf("discarded %d packets\n", j); + } + if (dp_block == (block - 1)) { + goto send_ack; /* resend ack */ + } + } + } + /* size = write(fd, dp->th_data, n - 4); */ + size = writeit(file, &dp, n - 4, convert); + if (size < 0) { + nak(errno + 100, NULL); + break; + } + amount += size; + } while (size == SEGSIZE); + abort: /* ok to ack, since user */ + ap->th_opcode = htons((u_short) ACK); /* has seen err msg */ + ap->th_block = htons((u_short) block); + (void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr, + sizeof(peeraddr)); + write_behind(file, convert); /* flush last buffer */ + fclose(file); + stopclock(); + if (amount > 0) + printstats("Received", amount); } static int makerequest(int request, const char *name, - struct tftphdr *tp, const char *mode) + struct tftphdr *tp, const char *mode) { - char *cp; + char *cp; - tp->th_opcode = htons((u_short)request); - cp = (char *) &(tp->th_stuff); - strcpy(cp, name); - cp += strlen(name); - *cp++ = '\0'; - strcpy(cp, mode); - cp += strlen(mode); - *cp++ = '\0'; - return (cp - (char *)tp); + tp->th_opcode = htons((u_short) request); + cp = (char *)&(tp->th_stuff); + strcpy(cp, name); + cp += strlen(name); + *cp++ = '\0'; + strcpy(cp, mode); + cp += strlen(mode); + *cp++ = '\0'; + return (cp - (char *)tp); } -static const char * const errmsgs[] = -{ - "Undefined error code", /* 0 - EUNDEF */ - "File not found", /* 1 - ENOTFOUND */ - "Access denied", /* 2 - EACCESS */ - "Disk full or allocation exceeded", /* 3 - ENOSPACE */ - "Illegal TFTP operation", /* 4 - EBADOP */ - "Unknown transfer ID", /* 5 - EBADID */ - "File already exists", /* 6 - EEXISTS */ - "No such user", /* 7 - ENOUSER */ - "Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */ +static const char *const errmsgs[] = { + "Undefined error code", /* 0 - EUNDEF */ + "File not found", /* 1 - ENOTFOUND */ + "Access denied", /* 2 - EACCESS */ + "Disk full or allocation exceeded", /* 3 - ENOSPACE */ + "Illegal TFTP operation", /* 4 - EBADOP */ + "Unknown transfer ID", /* 5 - EBADID */ + "File already exists", /* 6 - EEXISTS */ + "No such user", /* 7 - ENOUSER */ + "Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */ }; + #define ERR_CNT (sizeof(errmsgs)/sizeof(const char *)) /* @@ -327,121 +322,115 @@ static const char * const errmsgs[] = * standard TFTP codes, or a UNIX errno * offset by 100. */ -static void -nak(int error, const char *msg) +static void nak(int error, const char *msg) { - struct tftphdr *tp; - int length; - - tp = (struct tftphdr *)ackbuf; - tp->th_opcode = htons((u_short)ERROR); - tp->th_code = htons((u_short)error); + struct tftphdr *tp; + int length; - if ( error >= 100 ) { - /* This is a Unix errno+100 */ - if ( !msg ) - msg = strerror(error - 100); - error = EUNDEF; - } else { - if ( (unsigned)error >= ERR_CNT ) - error = EUNDEF; - - if ( !msg ) - msg = errmsgs[error]; - } + tp = (struct tftphdr *)ackbuf; + tp->th_opcode = htons((u_short) ERROR); + tp->th_code = htons((u_short) error); - tp->th_code = htons((u_short)error); + if (error >= 100) { + /* This is a Unix errno+100 */ + if (!msg) + msg = strerror(error - 100); + error = EUNDEF; + } else { + if ((unsigned)error >= ERR_CNT) + error = EUNDEF; - length = strlen(msg)+1; - memcpy(tp->th_msg, msg, length); - length += 4; /* Add space for header */ + if (!msg) + msg = errmsgs[error]; + } - if (trace) - tpacket("sent", tp, length); - if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr, - sizeof(peeraddr)) != length) - perror("nak"); + tp->th_code = htons((u_short) error); + + length = strlen(msg) + 1; + memcpy(tp->th_msg, msg, length); + length += 4; /* Add space for header */ + + if (trace) + tpacket("sent", tp, length); + if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr, + sizeof(peeraddr)) != length) + perror("nak"); } -static void -tpacket(const char *s, struct tftphdr *tp, int n) +static void tpacket(const char *s, struct tftphdr *tp, int n) { - static const char *opcodes[] = - { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" }; - char *cp, *file; - u_short op = ntohs((u_short)tp->th_opcode); + static const char *opcodes[] = + { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" }; + char *cp, *file; + u_short op = ntohs((u_short) tp->th_opcode); - if (op < RRQ || op > ERROR) - printf("%s opcode=%x ", s, op); - else - printf("%s %s ", s, opcodes[op]); - switch (op) { + if (op < RRQ || op > ERROR) + printf("%s opcode=%x ", s, op); + else + printf("%s %s ", s, opcodes[op]); + switch (op) { - case RRQ: - case WRQ: - n -= 2; - file = cp = (char *) &(tp->th_stuff); - cp = strchr(cp, '\0'); - printf("\n", file, cp + 1); - break; + case RRQ: + case WRQ: + n -= 2; + file = cp = (char *)&(tp->th_stuff); + cp = strchr(cp, '\0'); + printf("\n", file, cp + 1); + break; - case DATA: - printf("\n", ntohs(tp->th_block), n - 4); - break; + case DATA: + printf("\n", ntohs(tp->th_block), n - 4); + break; - case ACK: - printf("\n", ntohs(tp->th_block)); - break; + case ACK: + printf("\n", ntohs(tp->th_block)); + break; - case ERROR: - printf("\n", ntohs(tp->th_code), tp->th_msg); - break; - } + case ERROR: + printf("\n", ntohs(tp->th_code), tp->th_msg); + break; + } } struct timeval tstart; struct timeval tstop; -static void -startclock(void) +static void startclock(void) { - (void)gettimeofday(&tstart, NULL); + (void)gettimeofday(&tstart, NULL); } -static void -stopclock(void) +static void stopclock(void) { - (void)gettimeofday(&tstop, NULL); + (void)gettimeofday(&tstop, NULL); } -static void -printstats(const char *direction, unsigned long amount) +static void printstats(const char *direction, unsigned long amount) { - double delta; + double delta; - delta = (tstop.tv_sec+(tstop.tv_usec/100000.0)) - - (tstart.tv_sec+(tstart.tv_usec/100000.0)); - if (verbose) { - printf("%s %lu bytes in %.1f seconds", direction, amount, delta); - printf(" [%.0f bit/s]", (amount*8.)/delta); - putchar('\n'); - } + delta = (tstop.tv_sec + (tstop.tv_usec / 100000.0)) - + (tstart.tv_sec + (tstart.tv_usec / 100000.0)); + if (verbose) { + printf("%s %lu bytes in %.1f seconds", direction, amount, delta); + printf(" [%.0f bit/s]", (amount * 8.) / delta); + putchar('\n'); + } } -static void -timer(int sig) +static void timer(int sig) { - int save_errno = errno; + int save_errno = errno; - (void)sig; /* Shut up unused warning */ + (void)sig; /* Shut up unused warning */ - timeout += rexmtval; - if (timeout >= maxtimeout) { - printf("Transfer timed out.\n"); - errno = save_errno; - siglongjmp(toplevel, -1); - } - errno = save_errno; - siglongjmp(timeoutbuf, 1); + timeout += rexmtval; + if (timeout >= maxtimeout) { + printf("Transfer timed out.\n"); + errno = save_errno; + siglongjmp(toplevel, -1); + } + errno = save_errno; + siglongjmp(timeoutbuf, 1); } diff --git a/tftpd/misc.c b/tftpd/misc.c index 4f88978..07684dd 100644 --- a/tftpd/misc.c +++ b/tftpd/misc.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- * - * + * * Copyright 2001-2007 H. Peter Anvin - All Rights Reserved * * This program is free software available under the same license @@ -14,7 +14,7 @@ * Minor help routines. */ -#include "config.h" /* Must be included first! */ +#include "config.h" /* Must be included first! */ #include #include "tftpd.h" @@ -22,19 +22,19 @@ * Set the signal handler and flags. Basically a user-friendly * wrapper around sigaction(). */ -void set_signal(int signum, void (*handler)(int), int flags) +void set_signal(int signum, void (*handler) (int), int flags) { - struct sigaction sa; + struct sigaction sa; - memset(&sa, 0, sizeof sa); - sa.sa_handler = handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = flags; - - if ( sigaction(signum, &sa, NULL) ) { - syslog(LOG_ERR, "sigaction: %m"); - exit(EX_OSERR); - } + memset(&sa, 0, sizeof sa); + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = flags; + + if (sigaction(signum, &sa, NULL)) { + syslog(LOG_ERR, "sigaction: %m"); + exit(EX_OSERR); + } } /* @@ -42,14 +42,14 @@ void set_signal(int signum, void (*handler)(int), int flags) */ void *tfmalloc(size_t size) { - void *p = malloc(size); + void *p = malloc(size); - if ( !p ) { - syslog(LOG_ERR, "malloc: %m"); - exit(EX_OSERR); - } + if (!p) { + syslog(LOG_ERR, "malloc: %m"); + exit(EX_OSERR); + } - return p; + return p; } /* @@ -57,13 +57,12 @@ void *tfmalloc(size_t size) */ char *tfstrdup(const char *str) { - char *p = strdup(str); + char *p = strdup(str); - if ( !p ) { - syslog(LOG_ERR, "strdup: %m"); - exit(EX_OSERR); - } + if (!p) { + syslog(LOG_ERR, "strdup: %m"); + exit(EX_OSERR); + } - return p; + return p; } - diff --git a/tftpd/recvfrom.c b/tftpd/recvfrom.c index ba8d648..fee6d03 100644 --- a/tftpd/recvfrom.c +++ b/tftpd/recvfrom.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- * - * + * * Copyright 2001-2006 H. Peter Anvin - All Rights Reserved * * This program is free software available under the same license @@ -17,11 +17,11 @@ * */ -#include "config.h" /* Must be included first! */ +#include "config.h" /* Must be included first! */ #include "recvfrom.h" #include "common/tftpsubs.h" #ifdef HAVE_MACHINE_PARAM_H -#include /* Needed on some versions of FreeBSD */ +#include /* Needed on some versions of FreeBSD */ #endif #if defined(HAVE_RECVMSG) && defined(HAVE_MSGHDR_MSG_CONTROL) @@ -33,12 +33,12 @@ # ifdef __linux__ /* Assume this version of glibc simply lacks the definition */ struct in_pktinfo { - int ipi_ifindex; - struct in_addr ipi_spec_dst; - struct in_addr ipi_addr; + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; }; # else -# undef IP_PKTINFO /* No definition, no way to get it */ +# undef IP_PKTINFO /* No definition, no way to get it */ # endif # endif #endif @@ -57,141 +57,141 @@ struct in_pktinfo { */ static int address_is_local(const struct sockaddr_in *addr) { - struct sockaddr_in sin; - int sockfd = -1; - int e; - int rv = 0; - socklen_t addrlen; + struct sockaddr_in sin; + int sockfd = -1; + int e; + int rv = 0; + socklen_t addrlen; - /* Multicast or universal broadcast address? */ - if (ntohl(addr->sin_addr.s_addr) >= (224UL << 24)) - return 0; + /* Multicast or universal broadcast address? */ + if (ntohl(addr->sin_addr.s_addr) >= (224UL << 24)) + return 0; - sockfd = socket(PF_INET, SOCK_DGRAM, 0); - if (sockfd < 0) - goto err; + sockfd = socket(PF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + goto err; - if (connect(sockfd, (const struct sockaddr *)addr, sizeof *addr)) - goto err; + if (connect(sockfd, (const struct sockaddr *)addr, sizeof *addr)) + goto err; - addrlen = sizeof sin; - if (getsockname(sockfd, (struct sockaddr *)&sin, &addrlen)) - goto err; + addrlen = sizeof sin; + if (getsockname(sockfd, (struct sockaddr *)&sin, &addrlen)) + goto err; - rv = sin.sin_addr.s_addr == addr->sin_addr.s_addr; + rv = sin.sin_addr.s_addr == addr->sin_addr.s_addr; - err: - e = errno; - - if (sockfd >= 0) - close(sockfd); + err: + e = errno; - errno = e; - return rv; + if (sockfd >= 0) + close(sockfd); + + errno = e; + return rv; } - int myrecvfrom(int s, void *buf, int len, unsigned int flags, - struct sockaddr *from, socklen_t *fromlen, - struct sockaddr_in *myaddr) + struct sockaddr *from, socklen_t * fromlen, + struct sockaddr_in *myaddr) { - struct msghdr msg; - struct iovec iov; - int n; - struct cmsghdr *cmptr; - union { - struct cmsghdr cm; + struct msghdr msg; + struct iovec iov; + int n; + struct cmsghdr *cmptr; + union { + struct cmsghdr cm; #ifdef IP_PKTINFO - char control[CMSG_SPACE(sizeof(struct in_addr)) + - CMSG_SPACE(sizeof(struct in_pktinfo))]; + char control[CMSG_SPACE(sizeof(struct in_addr)) + + CMSG_SPACE(sizeof(struct in_pktinfo))]; #else - char control[CMSG_SPACE(sizeof(struct in_addr))]; + char control[CMSG_SPACE(sizeof(struct in_addr))]; #endif - } control_un; - int on = 1; + } control_un; + int on = 1; #ifdef IP_PKTINFO - struct in_pktinfo pktinfo; + struct in_pktinfo pktinfo; #endif - /* Try to enable getting the return address */ + /* Try to enable getting the return address */ #ifdef IP_RECVDSTADDR - setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)); + setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)); #endif #ifdef IP_PKTINFO - setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); + setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); #endif - bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */ - msg.msg_control = control_un.control; - msg.msg_controllen = sizeof(control_un.control); - msg.msg_flags = 0; + bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */ + msg.msg_control = control_un.control; + msg.msg_controllen = sizeof(control_un.control); + msg.msg_flags = 0; - msg.msg_name = from; - msg.msg_namelen = *fromlen; - iov.iov_base = buf; - iov.iov_len = len; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + msg.msg_name = from; + msg.msg_namelen = *fromlen; + iov.iov_base = buf; + iov.iov_len = len; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; - if ( (n = recvmsg(s, &msg, flags)) < 0 ) - return n; /* Error */ + if ((n = recvmsg(s, &msg, flags)) < 0) + return n; /* Error */ - *fromlen = msg.msg_namelen; + *fromlen = msg.msg_namelen; + + if (myaddr) { + bzero(myaddr, sizeof(struct sockaddr_in)); + myaddr->sin_family = AF_INET; + + if (msg.msg_controllen < sizeof(struct cmsghdr) || + (msg.msg_flags & MSG_CTRUNC)) + return n; /* No information available */ + + for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; + cmptr = CMSG_NXTHDR(&msg, cmptr)) { + +#ifdef IP_RECVDSTADDR + if (cmptr->cmsg_level == IPPROTO_IP && + cmptr->cmsg_type == IP_RECVDSTADDR) { + memcpy(&myaddr->sin_addr, CMSG_DATA(cmptr), + sizeof(struct in_addr)); + } +#endif + +#ifdef IP_PKTINFO + if (cmptr->cmsg_level == IPPROTO_IP && + cmptr->cmsg_type == IP_PKTINFO) { + memcpy(&pktinfo, CMSG_DATA(cmptr), + sizeof(struct in_pktinfo)); + memcpy(&myaddr->sin_addr, &pktinfo.ipi_addr, + sizeof(struct in_addr)); + } +#endif + + } + } + + /* If the address is not a valid local address, then bind to any address... */ + if (address_is_local(myaddr) != 1) + myaddr->sin_addr.s_addr = INADDR_ANY; + + return n; +} + +#else /* pointless... */ + +int +myrecvfrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, int *fromlen, struct sockaddr_in *myaddr) +{ + /* There is no way we can get the local address, fudge it */ - if ( myaddr ) { bzero(myaddr, sizeof(struct sockaddr_in)); myaddr->sin_family = AF_INET; - if ( msg.msg_controllen < sizeof(struct cmsghdr) || - (msg.msg_flags & MSG_CTRUNC) ) - return n; /* No information available */ + myaddr->sin_port = htons(IPPORT_TFTP); + bzero(&myaddr->sin_addr, sizeof(myaddr->sin_addr)); - for ( cmptr = CMSG_FIRSTHDR(&msg) ; cmptr != NULL ; - cmptr = CMSG_NXTHDR(&msg, cmptr) ) { - -#ifdef IP_RECVDSTADDR - if ( cmptr->cmsg_level == IPPROTO_IP && - cmptr->cmsg_type == IP_RECVDSTADDR ) { - memcpy(&myaddr->sin_addr, CMSG_DATA(cmptr), - sizeof(struct in_addr)); - } -#endif - -#ifdef IP_PKTINFO - if ( cmptr->cmsg_level == IPPROTO_IP && - cmptr->cmsg_type == IP_PKTINFO ) { - memcpy(&pktinfo, CMSG_DATA(cmptr), sizeof(struct in_pktinfo)); - memcpy(&myaddr->sin_addr, &pktinfo.ipi_addr, sizeof(struct in_addr)); - } -#endif - - } - } - - /* If the address is not a valid local address, then bind to any address... */ - if (address_is_local(myaddr) != 1) - myaddr->sin_addr.s_addr = INADDR_ANY; - - return n; -} - -#else /* pointless... */ - -int -myrecvfrom(int s, void *buf, int len, unsigned int flags, - struct sockaddr *from, int *fromlen, - struct sockaddr_in *myaddr) -{ - /* There is no way we can get the local address, fudge it */ - - bzero(myaddr, sizeof(struct sockaddr_in)); - myaddr->sin_family = AF_INET; - - myaddr->sin_port = htons(IPPORT_TFTP); - bzero(&myaddr->sin_addr, sizeof(myaddr->sin_addr)); - - return recvfrom(s,buf,len,flags,from,fromlen); + return recvfrom(s, buf, len, flags, from, fromlen); } #endif diff --git a/tftpd/recvfrom.h b/tftpd/recvfrom.h index 35ad05b..fda65c0 100644 --- a/tftpd/recvfrom.h +++ b/tftpd/recvfrom.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- * - * + * * Copyright 2001-2006 H. Peter Anvin - All Rights Reserved * * This program is free software available under the same license @@ -19,5 +19,5 @@ int myrecvfrom(int s, void *buf, int len, unsigned int flags, - struct sockaddr *from, socklen_t *fromlen, - struct sockaddr_in *myaddr); + struct sockaddr *from, socklen_t * fromlen, + struct sockaddr_in *myaddr); diff --git a/tftpd/remap.c b/tftpd/remap.c index bb10fd0..cdb9062 100644 --- a/tftpd/remap.c +++ b/tftpd/remap.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- * - * + * * Copyright 2001-2007 H. Peter Anvin - All Rights Reserved * * This program is free software available under the same license @@ -14,7 +14,7 @@ * Perform regular-expression based filename remapping. */ -#include "config.h" /* Must be included first! */ +#include "config.h" /* Must be included first! */ #include #include #include @@ -23,123 +23,131 @@ #include "remap.h" #define DEADMAN_MAX_STEPS 1024 /* Timeout after this many steps */ -#define MAXLINE 16384 /* Truncate a line at this many bytes */ +#define MAXLINE 16384 /* Truncate a line at this many bytes */ -#define RULE_REWRITE 0x01 /* This is a rewrite rule */ -#define RULE_GLOBAL 0x02 /* Global rule (repeat until no match) */ -#define RULE_EXIT 0x04 /* Exit after matching this rule */ -#define RULE_RESTART 0x08 /* Restart at the top after matching this rule */ -#define RULE_ABORT 0x10 /* Terminate processing with an error */ -#define RULE_GETONLY 0x20 /* Applicable to GET only */ -#define RULE_PUTONLY 0x40 /* Applicable to PUT only */ -#define RULE_INVERSE 0x80 /* Execute if regex *doesn't* match */ +#define RULE_REWRITE 0x01 /* This is a rewrite rule */ +#define RULE_GLOBAL 0x02 /* Global rule (repeat until no match) */ +#define RULE_EXIT 0x04 /* Exit after matching this rule */ +#define RULE_RESTART 0x08 /* Restart at the top after matching this rule */ +#define RULE_ABORT 0x10 /* Terminate processing with an error */ +#define RULE_GETONLY 0x20 /* Applicable to GET only */ +#define RULE_PUTONLY 0x40 /* Applicable to PUT only */ +#define RULE_INVERSE 0x80 /* Execute if regex *doesn't* match */ struct rule { - struct rule *next; - int nrule; - int rule_flags; - regex_t rx; - const char *pattern; + struct rule *next; + int nrule; + int rule_flags; + regex_t rx; + const char *pattern; }; static int xform_null(int c) { - return c; + return c; } static int xform_toupper(int c) { - return toupper(c); + return toupper(c); } static int xform_tolower(int c) { - return tolower(c); + return tolower(c); } /* Do \-substitution. Call with string == NULL to get length only. */ -static int genmatchstring(char *string, const char *pattern, const char *input, - const regmatch_t *pmatch, match_pattern_callback macrosub) +static int genmatchstring(char *string, const char *pattern, + const char *input, const regmatch_t * pmatch, + match_pattern_callback macrosub) { - int (*xform)(int) = xform_null; - int len = 0; - int n, mlen, sublen; - int endbytes; + int (*xform) (int) = xform_null; + int len = 0; + int n, mlen, sublen; + int endbytes; - /* Get section before match; note pmatch[0] is the whole match */ - endbytes = strlen(input) - pmatch[0].rm_eo; - len = pmatch[0].rm_so + endbytes; - if ( string ) { - memcpy(string, input, pmatch[0].rm_so); - string += pmatch[0].rm_so; - } - - /* Transform matched section */ - while ( *pattern ) { - mlen = 0; - - if ( *pattern == '\\' && pattern[1] != '\0' ) { - char macro = pattern[1]; - switch ( macro ) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - n = pattern[1] - '0'; - - if ( pmatch[n].rm_so != -1 ) { - mlen = pmatch[n].rm_eo - pmatch[n].rm_so; - len += mlen; - if ( string ) { - const char *p = input+pmatch[n].rm_so; - while ( mlen-- ) - *string++ = xform(*p++); - } - } - break; - - case 'L': - xform = xform_tolower; - break; - - case 'U': - xform = xform_toupper; - break; - - case 'E': - xform = xform_null; - break; - - default: - if ( macrosub && - (sublen = macrosub(macro, string)) >= 0 ) { - while ( sublen-- ) { - len++; - if ( string ) { - *string = xform(*string); - string++; - } - } - } else { - len++; - if ( string ) - *string++ = xform(pattern[1]); - } - } - pattern += 2; - } else { - len++; - if ( string ) - *string++ = xform(*pattern); - pattern++; + /* Get section before match; note pmatch[0] is the whole match */ + endbytes = strlen(input) - pmatch[0].rm_eo; + len = pmatch[0].rm_so + endbytes; + if (string) { + memcpy(string, input, pmatch[0].rm_so); + string += pmatch[0].rm_so; } - } - /* Copy section after match */ - if ( string ) { - memcpy(string, input+pmatch[0].rm_eo, endbytes); - string[endbytes] = '\0'; - } + /* Transform matched section */ + while (*pattern) { + mlen = 0; - return len; + if (*pattern == '\\' && pattern[1] != '\0') { + char macro = pattern[1]; + switch (macro) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = pattern[1] - '0'; + + if (pmatch[n].rm_so != -1) { + mlen = pmatch[n].rm_eo - pmatch[n].rm_so; + len += mlen; + if (string) { + const char *p = input + pmatch[n].rm_so; + while (mlen--) + *string++ = xform(*p++); + } + } + break; + + case 'L': + xform = xform_tolower; + break; + + case 'U': + xform = xform_toupper; + break; + + case 'E': + xform = xform_null; + break; + + default: + if (macrosub && (sublen = macrosub(macro, string)) >= 0) { + while (sublen--) { + len++; + if (string) { + *string = xform(*string); + string++; + } + } + } else { + len++; + if (string) + *string++ = xform(pattern[1]); + } + } + pattern += 2; + } else { + len++; + if (string) + *string++ = xform(*pattern); + pattern++; + } + } + + /* Copy section after match */ + if (string) { + memcpy(string, input + pmatch[0].rm_eo, endbytes); + string[endbytes] = '\0'; + } + + return len; } /* @@ -149,277 +157,284 @@ static int genmatchstring(char *string, const char *pattern, const char *input, */ static int readescstring(char *buf, char **str) { - char *p = *str; - int wasbs = 0, len = 0; + char *p = *str; + int wasbs = 0, len = 0; - while ( *p && isspace(*p) ) - p++; + while (*p && isspace(*p)) + p++; + + if (!*p) { + *buf = '\0'; + *str = p; + return 0; + } + + while (*p) { + if (!wasbs && (isspace(*p) || *p == '#')) { + *buf = '\0'; + *str = p; + return len; + } + /* Important: two backslashes leave us in the !wasbs state! */ + wasbs = !wasbs && (*p == '\\'); + *buf++ = *p++; + len++; + } - if ( ! *p ) { *buf = '\0'; *str = p; - return 0; - } - - while ( *p ) { - if ( !wasbs && (isspace(*p) || *p == '#') ) { - *buf = '\0'; - *str = p; - return len; - } - /* Important: two backslashes leave us in the !wasbs state! */ - wasbs = !wasbs && ( *p == '\\' ); - *buf++ = *p++; - len++; - } - - *buf = '\0'; - *str = p; - return len; + return len; } /* Parse a line into a set of instructions */ static int parseline(char *line, struct rule *r, int lineno) { - char buffer[MAXLINE]; - char *p; - int rv; - int rxflags = REG_EXTENDED; - static int nrule; + char buffer[MAXLINE]; + char *p; + int rv; + int rxflags = REG_EXTENDED; + static int nrule; - memset(r, 0, sizeof *r); - r->nrule = nrule; + memset(r, 0, sizeof *r); + r->nrule = nrule; - if ( !readescstring(buffer, &line) ) - return 0; /* No rule found */ + if (!readescstring(buffer, &line)) + return 0; /* No rule found */ - for ( p = buffer ; *p ; p++ ) { - switch(*p) { - case 'r': - r->rule_flags |= RULE_REWRITE; - break; - case 'g': - r->rule_flags |= RULE_GLOBAL; - break; - case 'e': - r->rule_flags |= RULE_EXIT; - break; - case 's': - r->rule_flags |= RULE_RESTART; - break; - case 'a': - r->rule_flags |= RULE_ABORT; - break; - case 'i': - rxflags |= REG_ICASE; - break; - case 'G': - r->rule_flags |= RULE_GETONLY; - break; - case 'P': - r->rule_flags |= RULE_PUTONLY; - break; - case '~': - r->rule_flags |= RULE_INVERSE; - break; - default: - syslog(LOG_ERR, "Remap command \"%s\" on line %d contains invalid char \"%c\"", - buffer, lineno, *p); - return -1; /* Error */ - break; + for (p = buffer; *p; p++) { + switch (*p) { + case 'r': + r->rule_flags |= RULE_REWRITE; + break; + case 'g': + r->rule_flags |= RULE_GLOBAL; + break; + case 'e': + r->rule_flags |= RULE_EXIT; + break; + case 's': + r->rule_flags |= RULE_RESTART; + break; + case 'a': + r->rule_flags |= RULE_ABORT; + break; + case 'i': + rxflags |= REG_ICASE; + break; + case 'G': + r->rule_flags |= RULE_GETONLY; + break; + case 'P': + r->rule_flags |= RULE_PUTONLY; + break; + case '~': + r->rule_flags |= RULE_INVERSE; + break; + default: + syslog(LOG_ERR, + "Remap command \"%s\" on line %d contains invalid char \"%c\"", + buffer, lineno, *p); + return -1; /* Error */ + break; + } } - } - /* RULE_GLOBAL only applies when RULE_REWRITE specified */ - if ( !(r->rule_flags & RULE_REWRITE) ) - r->rule_flags &= ~RULE_GLOBAL; + /* RULE_GLOBAL only applies when RULE_REWRITE specified */ + if (!(r->rule_flags & RULE_REWRITE)) + r->rule_flags &= ~RULE_GLOBAL; - if ( (r->rule_flags & (RULE_INVERSE|RULE_REWRITE)) == - (RULE_INVERSE|RULE_REWRITE) ) { - syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n", lineno, line); - return -1; /* Error */ - } + if ((r->rule_flags & (RULE_INVERSE | RULE_REWRITE)) == + (RULE_INVERSE | RULE_REWRITE)) { + syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n", + lineno, line); + return -1; /* Error */ + } - /* Read and compile the regex */ - if ( !readescstring(buffer, &line) ) { - syslog(LOG_ERR, "No regex on remap line %d: %s\n", lineno, line); - return -1; /* Error */ - } + /* Read and compile the regex */ + if (!readescstring(buffer, &line)) { + syslog(LOG_ERR, "No regex on remap line %d: %s\n", lineno, line); + return -1; /* Error */ + } - if ( (rv = regcomp(&r->rx, buffer, rxflags)) != 0 ) { - char errbuf[BUFSIZ]; - regerror(rv, &r->rx, errbuf, BUFSIZ); - syslog(LOG_ERR, "Bad regex in remap line %d: %s\n", lineno, errbuf); - return -1; /* Error */ - } + if ((rv = regcomp(&r->rx, buffer, rxflags)) != 0) { + char errbuf[BUFSIZ]; + regerror(rv, &r->rx, errbuf, BUFSIZ); + syslog(LOG_ERR, "Bad regex in remap line %d: %s\n", lineno, + errbuf); + return -1; /* Error */ + } - /* Read the rewrite pattern, if any */ - if ( readescstring(buffer, &line) ) { - r->pattern = tfstrdup(buffer); - } else { - r->pattern = ""; - } + /* Read the rewrite pattern, if any */ + if (readescstring(buffer, &line)) { + r->pattern = tfstrdup(buffer); + } else { + r->pattern = ""; + } - nrule++; - return 1; /* Rule found */ + nrule++; + return 1; /* Rule found */ } /* Read a rule file */ -struct rule *parserulefile(FILE *f) +struct rule *parserulefile(FILE * f) { - char line[MAXLINE]; - struct rule *first_rule = NULL; - struct rule **last_rule = &first_rule; - struct rule *this_rule = tfmalloc(sizeof(struct rule)); - int rv; - int lineno = 0; - int err = 0; + char line[MAXLINE]; + struct rule *first_rule = NULL; + struct rule **last_rule = &first_rule; + struct rule *this_rule = tfmalloc(sizeof(struct rule)); + int rv; + int lineno = 0; + int err = 0; - while ( lineno++, fgets(line, MAXLINE, f) ) { - rv = parseline(line, this_rule, lineno); - if ( rv < 0 ) - err = 1; - if ( rv > 0 ) { - *last_rule = this_rule; - last_rule = &this_rule->next; - this_rule = tfmalloc(sizeof(struct rule)); + while (lineno++, fgets(line, MAXLINE, f)) { + rv = parseline(line, this_rule, lineno); + if (rv < 0) + err = 1; + if (rv > 0) { + *last_rule = this_rule; + last_rule = &this_rule->next; + this_rule = tfmalloc(sizeof(struct rule)); + } } - } - free(this_rule); /* Last one is always unused */ + free(this_rule); /* Last one is always unused */ - if ( err ) { - /* Bail on error, we have already logged an error message */ - exit(EX_CONFIG); - } + if (err) { + /* Bail on error, we have already logged an error message */ + exit(EX_CONFIG); + } - return first_rule; + return first_rule; } /* Destroy a rule file data structure */ void freerules(struct rule *r) { - struct rule *next; + struct rule *next; - while ( r ) { - next = r->next; + while (r) { + next = r->next; - regfree(&r->rx); + regfree(&r->rx); - /* "" patterns aren't allocated by malloc() */ - if ( r->pattern && *r->pattern ) - free((void *)r->pattern); - - free(r); + /* "" patterns aren't allocated by malloc() */ + if (r->pattern && *r->pattern) + free((void *)r->pattern); - r = next; - } + free(r); + + r = next; + } } /* Execute a rule set on a string; returns a malloc'd new string. */ char *rewrite_string(const char *input, const struct rule *rules, - int is_put, match_pattern_callback macrosub, - const char **errmsg) + int is_put, match_pattern_callback macrosub, + const char **errmsg) { - char *current = tfstrdup(input); - char *newstr; - const struct rule *ruleptr = rules; - regmatch_t pmatch[10]; - int len; - int was_match = 0; - int deadman = DEADMAN_MAX_STEPS; + char *current = tfstrdup(input); + char *newstr; + const struct rule *ruleptr = rules; + regmatch_t pmatch[10]; + int len; + int was_match = 0; + int deadman = DEADMAN_MAX_STEPS; - /* Default error */ - *errmsg = "Remap table failure"; + /* Default error */ + *errmsg = "Remap table failure"; - if ( verbosity >= 3 ) { - syslog(LOG_INFO, "remap: input: %s", current); - } - - for ( ruleptr = rules ; ruleptr ; ruleptr = ruleptr->next ) { - if ( ((ruleptr->rule_flags & RULE_GETONLY) && is_put) || - ((ruleptr->rule_flags & RULE_PUTONLY) && !is_put) ) { - continue; /* Rule not applicable, try next */ + if (verbosity >= 3) { + syslog(LOG_INFO, "remap: input: %s", current); } - if ( ! deadman-- ) { - syslog(LOG_WARNING, "remap: Breaking loop, input = %s, last = %s", - input, current); - free(current); - return NULL; /* Did not terminate! */ + for (ruleptr = rules; ruleptr; ruleptr = ruleptr->next) { + if (((ruleptr->rule_flags & RULE_GETONLY) && is_put) || + ((ruleptr->rule_flags & RULE_PUTONLY) && !is_put)) { + continue; /* Rule not applicable, try next */ + } + + if (!deadman--) { + syslog(LOG_WARNING, + "remap: Breaking loop, input = %s, last = %s", input, + current); + free(current); + return NULL; /* Did not terminate! */ + } + + do { + if (regexec(&ruleptr->rx, current, 10, pmatch, 0) == + (ruleptr->rule_flags & RULE_INVERSE ? REG_NOMATCH : 0)) { + /* Match on this rule */ + was_match = 1; + + if (ruleptr->rule_flags & RULE_INVERSE) { + /* No actual match, so clear out the pmatch array */ + int i; + for (i = 0; i < 10; i++) + pmatch[i].rm_so = pmatch[i].rm_eo = -1; + } + + if (ruleptr->rule_flags & RULE_ABORT) { + if (verbosity >= 3) { + syslog(LOG_INFO, "remap: rule %d: abort: %s", + ruleptr->nrule, current); + } + if (ruleptr->pattern[0]) { + /* Custom error message */ + len = + genmatchstring(NULL, ruleptr->pattern, current, + pmatch, macrosub); + newstr = tfmalloc(len + 1); + genmatchstring(newstr, ruleptr->pattern, current, + pmatch, macrosub); + *errmsg = newstr; + } else { + *errmsg = NULL; + } + free(current); + return (NULL); + } + + if (ruleptr->rule_flags & RULE_REWRITE) { + len = genmatchstring(NULL, ruleptr->pattern, current, + pmatch, macrosub); + newstr = tfmalloc(len + 1); + genmatchstring(newstr, ruleptr->pattern, current, + pmatch, macrosub); + free(current); + current = newstr; + if (verbosity >= 3) { + syslog(LOG_INFO, "remap: rule %d: rewrite: %s", + ruleptr->nrule, current); + } + } + } else { + break; /* No match, terminate unconditionally */ + } + /* If the rule is global, keep going until no match */ + } while (ruleptr->rule_flags & RULE_GLOBAL); + + if (was_match) { + was_match = 0; + + if (ruleptr->rule_flags & RULE_EXIT) { + if (verbosity >= 3) { + syslog(LOG_INFO, "remap: rule %d: exit", + ruleptr->nrule); + } + return current; /* Exit here, we're done */ + } else if (ruleptr->rule_flags & RULE_RESTART) { + ruleptr = rules; /* Start from the top */ + if (verbosity >= 3) { + syslog(LOG_INFO, "remap: rule %d: restart", + ruleptr->nrule); + } + } + } } - do { - if ( regexec(&ruleptr->rx, current, 10, pmatch, 0) == - (ruleptr->rule_flags & RULE_INVERSE ? REG_NOMATCH : 0) ) { - /* Match on this rule */ - was_match = 1; - - if ( ruleptr->rule_flags & RULE_INVERSE ) { - /* No actual match, so clear out the pmatch array */ - int i; - for ( i = 0 ; i < 10 ; i++ ) - pmatch[i].rm_so = pmatch[i].rm_eo = -1; - } - - if ( ruleptr->rule_flags & RULE_ABORT ) { - if ( verbosity >= 3 ) { - syslog(LOG_INFO, "remap: rule %d: abort: %s", - ruleptr->nrule, current); - } - if ( ruleptr->pattern[0] ) { - /* Custom error message */ - len = genmatchstring(NULL, ruleptr->pattern, current, - pmatch, macrosub); - newstr = tfmalloc(len+1); - genmatchstring(newstr, ruleptr->pattern, current, - pmatch, macrosub); - *errmsg = newstr; - } else { - *errmsg = NULL; - } - free(current); - return(NULL); - } - - if ( ruleptr->rule_flags & RULE_REWRITE ) { - len = genmatchstring(NULL, ruleptr->pattern, current, - pmatch, macrosub); - newstr = tfmalloc(len+1); - genmatchstring(newstr, ruleptr->pattern, current, - pmatch, macrosub); - free(current); - current = newstr; - if ( verbosity >= 3 ) { - syslog(LOG_INFO, "remap: rule %d: rewrite: %s", - ruleptr->nrule, current); - } - } - } else { - break; /* No match, terminate unconditionally */ - } - /* If the rule is global, keep going until no match */ - } while ( ruleptr->rule_flags & RULE_GLOBAL ); - - if ( was_match ) { - was_match = 0; - - if ( ruleptr->rule_flags & RULE_EXIT ) { - if ( verbosity >= 3 ) { - syslog(LOG_INFO, "remap: rule %d: exit", ruleptr->nrule); - } - return current; /* Exit here, we're done */ - } else if ( ruleptr->rule_flags & RULE_RESTART ) { - ruleptr = rules; /* Start from the top */ - if ( verbosity >= 3 ) { - syslog(LOG_INFO, "remap: rule %d: restart", ruleptr->nrule); - } - } + if (verbosity >= 3) { + syslog(LOG_INFO, "remap: done"); } - } - - if ( verbosity >= 3 ) { - syslog(LOG_INFO, "remap: done"); - } - return current; + return current; } diff --git a/tftpd/remap.h b/tftpd/remap.h index a00094c..3830b5c 100644 --- a/tftpd/remap.h +++ b/tftpd/remap.h @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- * - * + * * Copyright 2001-2007 H. Peter Anvin - All Rights Reserved * * This program is free software available under the same license @@ -26,7 +26,7 @@ struct rule; macro character is passed as the first argument; the output buffer, if any, is passed as the second argument. The function should return the number of characters output, or -1 on failure. */ -typedef int (*match_pattern_callback)(char, char *); +typedef int (*match_pattern_callback) (char, char *); /* Read a rule file */ struct rule *parserulefile(FILE *); @@ -36,8 +36,7 @@ void freerules(struct rule *); /* Execute a rule set on a string; returns a malloc'd new string. */ char *rewrite_string(const char *, const struct rule *, int, - match_pattern_callback, const char **); - -#endif /* WITH_REGEX */ -#endif /* TFTPD_REMAP_H */ + match_pattern_callback, const char **); +#endif /* WITH_REGEX */ +#endif /* TFTPD_REMAP_H */ diff --git a/tftpd/tftpd.c b/tftpd/tftpd.c index 92a6889..92b7c67 100644 --- a/tftpd/tftpd.c +++ b/tftpd/tftpd.c @@ -33,19 +33,9 @@ * SUCH DAMAGE. */ -#include "config.h" /* Must be included first */ +#include "config.h" /* Must be included first */ #include "tftpd.h" -#ifndef lint -static const char *copyright UNUSED = -"@(#) Copyright (c) 1983 Regents of the University of California.\n\ - All rights reserved.\n"; -/*static char sccsid[] = "from: @(#)tftpd.c 5.13 (Berkeley) 2/26/91";*/ -/*static char rcsid[] = "$OpenBSD: tftpd.c,v 1.13 1999/06/23 17:01:36 deraadt Exp $: tftpd.c,v 1.6 1997/02/16 23:49:21 deraadt Exp $";*/ -static const char *rcsid UNUSED = -"tftp-hpa $Id$"; -#endif /* not lint */ - /* * Trivial file transfer protocol server. * @@ -65,49 +55,49 @@ static const char *rcsid UNUSED = #include "remap.h" #ifdef HAVE_SYS_FILIO_H -#include /* Necessary for FIONBIO on Solaris */ +#include /* Necessary for FIONBIO on Solaris */ #endif #ifdef HAVE_TCPWRAPPERS #include -int deny_severity = LOG_WARNING; -int allow_severity = -1; /* Don't log at all */ +int deny_severity = LOG_WARNING; +int allow_severity = -1; /* Don't log at all */ struct request_info wrap_request; #endif -#define TIMEOUT 1000000 /* Default timeout (us) */ -#define TRIES 6 /* Number of attempts to send each packet */ +#define TIMEOUT 1000000 /* Default timeout (us) */ +#define TRIES 6 /* Number of attempts to send each packet */ #define TIMEOUT_LIMIT ((1 << TRIES)-1) -const char *__progname; -int peer; -unsigned long timeout = TIMEOUT; /* Current timeout value */ -unsigned long rexmtval = TIMEOUT; /* Basic timeout value */ -unsigned long maxtimeout = TIMEOUT_LIMIT*TIMEOUT; -int timeout_quit = 0; -sigjmp_buf timeoutbuf; +const char *__progname; +int peer; +unsigned long timeout = TIMEOUT; /* Current timeout value */ +unsigned long rexmtval = TIMEOUT; /* Basic timeout value */ +unsigned long maxtimeout = TIMEOUT_LIMIT * TIMEOUT; +int timeout_quit = 0; +sigjmp_buf timeoutbuf; #define PKTSIZE MAX_SEGSIZE+4 -char buf[PKTSIZE]; -char ackbuf[PKTSIZE]; -unsigned int max_blksize = MAX_SEGSIZE; +char buf[PKTSIZE]; +char ackbuf[PKTSIZE]; +unsigned int max_blksize = MAX_SEGSIZE; struct sockaddr_in from; -socklen_t fromlen; -off_t tsize; -int tsize_ok; +socklen_t fromlen; +off_t tsize; +int tsize_ok; -int ndirs; -const char **dirs; +int ndirs; +const char **dirs; -int secure = 0; -int cancreate = 0; -int unixperms = 0; -int portrange = 0; -unsigned int portrange_from, portrange_to; -int verbosity = 0; +int secure = 0; +int cancreate = 0; +int unixperms = 0; +int portrange = 0; +unsigned int portrange_from, portrange_to; +int verbosity = 0; struct formats; #ifdef WITH_REGEX @@ -127,91 +117,80 @@ int set_timeout(char *, char **); int set_utimeout(char *, char **); struct options { - const char *o_opt; - int (*o_fnc)(char *, char **); + const char *o_opt; + int (*o_fnc) (char *, char **); } options[] = { - { "blksize", set_blksize }, - { "blksize2", set_blksize2 }, - { "tsize", set_tsize }, - { "timeout", set_timeout }, - { "utimeout", set_utimeout }, - { NULL, NULL } + { + "blksize", set_blksize}, { + "blksize2", set_blksize2}, { + "tsize", set_tsize}, { + "timeout", set_timeout}, { + "utimeout", set_utimeout}, { + NULL, NULL} }; /* Simple handler for SIGHUP */ static volatile sig_atomic_t caught_sighup = 0; static void handle_sighup(int sig) { - (void)sig; /* Suppress unused warning */ - caught_sighup = 1; + (void)sig; /* Suppress unused warning */ + caught_sighup = 1; } - /* Handle timeout signal or timeout event */ -void -timer(int sig) +void timer(int sig) { - (void)sig; /* Suppress unused warning */ - timeout <<= 1; - if (timeout >= maxtimeout || timeout_quit) - exit(0); - siglongjmp(timeoutbuf, 1); + (void)sig; /* Suppress unused warning */ + timeout <<= 1; + if (timeout >= maxtimeout || timeout_quit) + exit(0); + siglongjmp(timeoutbuf, 1); } -static void -usage(void) -{ - syslog(LOG_ERR, "Usage: %s [-vcl][-a address][-m mappings][-u user][-t inetd_timeout][-T pkt_timeout][-r option...] [-s] [directory ...]", - __progname); - exit(EX_USAGE); -} - - #ifdef WITH_REGEX -static struct rule * -read_remap_rules(const char *file) +static struct rule *read_remap_rules(const char *file) { - FILE *f; - struct rule *rulep; + FILE *f; + struct rule *rulep; - f = fopen(file, "rt"); - if ( !f ) { - syslog(LOG_ERR, "Cannot open map file: %s: %m", file); - exit(EX_NOINPUT); - } - rulep = parserulefile(f); - fclose(f); + f = fopen(file, "rt"); + if (!f) { + syslog(LOG_ERR, "Cannot open map file: %s: %m", file); + exit(EX_NOINPUT); + } + rulep = parserulefile(f); + fclose(f); - return rulep; + return rulep; } #endif -static void -set_socket_nonblock(int fd, int flag) +static void set_socket_nonblock(int fd, int flag) { - int err; - int flags; + int err; + int flags; #if defined(HAVE_FCNTL) && defined(HAVE_O_NONBLOCK_DEFINITION) - /* Posixly correct */ - err = ((flags = fcntl(fd, F_GETFL, 0)) < 0) || - (fcntl(fd, F_SETFL, flag ? flags|O_NONBLOCK : flags&~O_NONBLOCK) < 0); + /* Posixly correct */ + err = ((flags = fcntl(fd, F_GETFL, 0)) < 0) || + (fcntl + (fd, F_SETFL, + flag ? flags | O_NONBLOCK : flags & ~O_NONBLOCK) < 0); #else - flags = flag ? 1 : 0; - err = (ioctl(fd, FIONBIO, &flags) < 0); + flags = flag ? 1 : 0; + err = (ioctl(fd, FIONBIO, &flags) < 0); #endif - if ( err ) { - syslog(LOG_ERR, "Cannot set nonblock flag on socket: %m"); - exit(EX_OSERR); - } + if (err) { + syslog(LOG_ERR, "Cannot set nonblock flag on socket: %m"); + exit(EX_OSERR); + } } -static void -pmtu_discovery_off(int fd) +static void pmtu_discovery_off(int fd) { #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) - int pmtu = IP_PMTUDISC_DONT; + int pmtu = IP_PMTUDISC_DONT; - setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu)); + setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu)); #endif } @@ -220,617 +199,630 @@ pmtu_discovery_off(int fd) * to account for time spent waiting. */ static int recv_time(int s, void *rbuf, int len, unsigned int flags, - unsigned long *timeout_us_p) + unsigned long *timeout_us_p) { - fd_set fdset; - struct timeval tmv, t0, t1; - int rv, err; - unsigned long timeout_us = *timeout_us_p; - unsigned long timeout_left, dt; + fd_set fdset; + struct timeval tmv, t0, t1; + int rv, err; + unsigned long timeout_us = *timeout_us_p; + unsigned long timeout_left, dt; - gettimeofday(&t0, NULL); - timeout_left = timeout_us; + gettimeofday(&t0, NULL); + timeout_left = timeout_us; - for ( ; ; ) { - FD_ZERO(&fdset); - FD_SET(s, &fdset); - - do { - tmv.tv_sec = timeout_left / 1000000; - tmv.tv_usec = timeout_left % 1000000; - - rv = select(s+1, &fdset, NULL, NULL, &tmv); - err = errno; + for (;;) { + FD_ZERO(&fdset); + FD_SET(s, &fdset); - gettimeofday(&t1, NULL); + do { + tmv.tv_sec = timeout_left / 1000000; + tmv.tv_usec = timeout_left % 1000000; - dt = (t1.tv_sec - t0.tv_sec)*1000000 + (t1.tv_usec - t0.tv_usec); - *timeout_us_p = timeout_left = ( dt >= timeout_us ) ? 1 : (timeout_us - dt); - } while ( rv == -1 && err == EINTR ); - - if ( rv == 0 ) { - timer(0); /* Should not return */ - return -1; + rv = select(s + 1, &fdset, NULL, NULL, &tmv); + err = errno; + + gettimeofday(&t1, NULL); + + dt = (t1.tv_sec - t0.tv_sec) * 1000000 + (t1.tv_usec - + t0.tv_usec); + *timeout_us_p = timeout_left = + (dt >= timeout_us) ? 1 : (timeout_us - dt); + } while (rv == -1 && err == EINTR); + + if (rv == 0) { + timer(0); /* Should not return */ + return -1; + } + + set_socket_nonblock(s, 1); + rv = recv(s, rbuf, len, flags); + err = errno; + set_socket_nonblock(s, 0); + + if (rv < 0) { + if (E_WOULD_BLOCK(err) || err == EINTR) { + continue; /* Once again, with feeling... */ + } else { + errno = err; + return rv; + } + } else { + return rv; + } } - - set_socket_nonblock(s, 1); - rv = recv(s, rbuf, len, flags); - err = errno; - set_socket_nonblock(s, 0); - - if ( rv < 0 ) { - if ( E_WOULD_BLOCK(err) || err == EINTR ) { - continue; /* Once again, with feeling... */ - } else { - errno = err; - return rv; - } - } else { - return rv; - } - } } - -int -main(int argc, char **argv) +int main(int argc, char **argv) { - struct tftphdr *tp; - struct passwd *pw; - struct options *opt; - struct sockaddr_in myaddr; - struct sockaddr_in bindaddr; - int n; - int fd = 0; - int standalone = 0; /* Standalone (listen) mode */ - int nodaemon = 0; /* Do not detach process */ - char *address = NULL; /* Address to listen to */ - pid_t pid; - mode_t my_umask = 0; - int spec_umask = 0; - int c; - int setrv; - int waittime = 900; /* Default time to wait for a connect*/ - const char *user = "nobody"; /* Default user */ - char *p, *ep; + struct tftphdr *tp; + struct passwd *pw; + struct options *opt; + struct sockaddr_in myaddr; + struct sockaddr_in bindaddr; + int n; + int fd = 0; + int standalone = 0; /* Standalone (listen) mode */ + int nodaemon = 0; /* Do not detach process */ + char *address = NULL; /* Address to listen to */ + pid_t pid; + mode_t my_umask = 0; + int spec_umask = 0; + int c; + int setrv; + int waittime = 900; /* Default time to wait for a connect */ + const char *user = "nobody"; /* Default user */ + char *p, *ep; #ifdef WITH_REGEX - char *rewrite_file = NULL; + char *rewrite_file = NULL; #endif - u_short tp_opcode; + u_short tp_opcode; - /* basename() is way too much of a pain from a portability standpoint */ + /* basename() is way too much of a pain from a portability standpoint */ - p = strrchr(argv[0], '/'); - __progname = (p && p[1]) ? p+1 : argv[0]; - - openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON); + p = strrchr(argv[0], '/'); + __progname = (p && p[1]) ? p + 1 : argv[0]; - srand(time(NULL) ^ getpid()); - - while ((c = getopt(argc, argv, "cspvVlLa:B:u:U:r:t:T:R:m:")) != -1) - switch (c) { - case 'c': - cancreate = 1; - break; - case 's': - secure = 1; - break; - case 'p': - unixperms = 1; - break; - case 'l': - standalone = 1; - break; - case 'L': - standalone = 1; - nodaemon = 1; - break; - case 'a': - address = optarg; - break; - case 't': - waittime = atoi(optarg); - break; - case 'B': - { - char *vp; - max_blksize = (unsigned int)strtoul(optarg, &vp, 10); - if ( max_blksize < 512 || max_blksize > MAX_SEGSIZE || *vp ) { - syslog(LOG_ERR, "Bad maximum blocksize value (range 512-%d): %s", - MAX_SEGSIZE, optarg); - exit(EX_USAGE); - } - } - break; - case 'T': - { - char *vp; - unsigned long tov = strtoul(optarg, &vp, 10); - if ( tov < 10000UL || tov > 255000000UL || *vp ) { - syslog(LOG_ERR, "Bad timeout value: %s", optarg); - exit(EX_USAGE); - } - rexmtval = timeout = tov; - maxtimeout = rexmtval*TIMEOUT_LIMIT; - } - break; - case 'R': - { - if ( sscanf(optarg, "%u:%u", &portrange_from, &portrange_to) != 2 || - portrange_from > portrange_to || portrange_to >= 65535 ) { - syslog(LOG_ERR, "Bad port range: %s", optarg); - exit(EX_USAGE); - } - portrange = 1; - } - break; - case 'u': - user = optarg; - break; - case 'U': - my_umask = strtoul(optarg, &ep, 8); - if ( *ep ) { - syslog(LOG_ERR, "Invalid umask: %s", optarg); - exit(EX_USAGE); - } - spec_umask = 1; - break; - case 'r': - for ( opt = options ; opt->o_opt ; opt++ ) { - if ( !strcasecmp(optarg, opt->o_opt) ) { - opt->o_opt = ""; /* Don't support this option */ - break; - } - } - if ( !opt->o_opt ) { - syslog(LOG_ERR, "Unknown option: %s", optarg); - exit(EX_USAGE); - } - break; + openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); + + srand(time(NULL) ^ getpid()); + + while ((c = getopt(argc, argv, "cspvVlLa:B:u:U:r:t:T:R:m:")) != -1) + switch (c) { + case 'c': + cancreate = 1; + break; + case 's': + secure = 1; + break; + case 'p': + unixperms = 1; + break; + case 'l': + standalone = 1; + break; + case 'L': + standalone = 1; + nodaemon = 1; + break; + case 'a': + address = optarg; + break; + case 't': + waittime = atoi(optarg); + break; + case 'B': + { + char *vp; + max_blksize = (unsigned int)strtoul(optarg, &vp, 10); + if (max_blksize < 512 || max_blksize > MAX_SEGSIZE || *vp) { + syslog(LOG_ERR, + "Bad maximum blocksize value (range 512-%d): %s", + MAX_SEGSIZE, optarg); + exit(EX_USAGE); + } + } + break; + case 'T': + { + char *vp; + unsigned long tov = strtoul(optarg, &vp, 10); + if (tov < 10000UL || tov > 255000000UL || *vp) { + syslog(LOG_ERR, "Bad timeout value: %s", optarg); + exit(EX_USAGE); + } + rexmtval = timeout = tov; + maxtimeout = rexmtval * TIMEOUT_LIMIT; + } + break; + case 'R': + { + if (sscanf(optarg, "%u:%u", &portrange_from, &portrange_to) + != 2 || portrange_from > portrange_to + || portrange_to >= 65535) { + syslog(LOG_ERR, "Bad port range: %s", optarg); + exit(EX_USAGE); + } + portrange = 1; + } + break; + case 'u': + user = optarg; + break; + case 'U': + my_umask = strtoul(optarg, &ep, 8); + if (*ep) { + syslog(LOG_ERR, "Invalid umask: %s", optarg); + exit(EX_USAGE); + } + spec_umask = 1; + break; + case 'r': + for (opt = options; opt->o_opt; opt++) { + if (!strcasecmp(optarg, opt->o_opt)) { + opt->o_opt = ""; /* Don't support this option */ + break; + } + } + if (!opt->o_opt) { + syslog(LOG_ERR, "Unknown option: %s", optarg); + exit(EX_USAGE); + } + break; #ifdef WITH_REGEX - case 'm': - if ( rewrite_file ) { - syslog(LOG_ERR, "Multiple -m options"); - exit(EX_USAGE); - } - rewrite_file = optarg; - break; + case 'm': + if (rewrite_file) { + syslog(LOG_ERR, "Multiple -m options"); + exit(EX_USAGE); + } + rewrite_file = optarg; + break; #endif - case 'v': - verbosity++; - break; - case 'V': - /* Print configuration to stdout and exit */ - printf("%s\n", TFTPD_CONFIG_STR); - exit(0); - break; - default: - usage(); - break; + case 'v': + verbosity++; + break; + case 'V': + /* Print configuration to stdout and exit */ + printf("%s\n", TFTPD_CONFIG_STR); + exit(0); + break; + default: + syslog(LOG_ERR, "Unknown option: '%c'", optopt); + break; + } + + dirs = xmalloc((argc - optind + 1) * sizeof(char *)); + for (ndirs = 0; optind != argc; optind++) + dirs[ndirs++] = argv[optind]; + + dirs[ndirs] = NULL; + + if (secure) { + if (ndirs == 0) { + syslog(LOG_ERR, "no -s directory"); + exit(EX_USAGE); + } + if (ndirs > 1) { + syslog(LOG_ERR, "too many -s directories"); + exit(EX_USAGE); + } + if (chdir(dirs[0])) { + syslog(LOG_ERR, "%s: %m", dirs[0]); + exit(EX_NOINPUT); + } } - dirs = xmalloc((argc-optind+1)*sizeof(char *)); - for ( ndirs = 0 ; optind != argc ; optind++ ) - dirs[ndirs++] = argv[optind]; + pw = getpwnam(user); + if (!pw) { + syslog(LOG_ERR, "no user %s: %m", user); + exit(EX_NOUSER); + } - dirs[ndirs] = NULL; - - if (secure) { - if (ndirs == 0) { - syslog(LOG_ERR, "no -s directory"); - exit(EX_USAGE); - } - if (ndirs > 1) { - syslog(LOG_ERR, "too many -s directories"); - exit(EX_USAGE); - } - if (chdir(dirs[0])) { - syslog(LOG_ERR, "%s: %m", dirs[0]); - exit(EX_NOINPUT); - } - } - - pw = getpwnam(user); - if (!pw) { - syslog(LOG_ERR, "no user %s: %m", user); - exit(EX_NOUSER); - } + if (spec_umask || !unixperms) + umask(my_umask); - if ( spec_umask || !unixperms ) - umask(my_umask); - - /* Note: on Cygwin, select() on a nonblocking socket becomes - a nonblocking select. */ + /* Note: on Cygwin, select() on a nonblocking socket becomes + a nonblocking select. */ #ifndef __CYGWIN__ - set_socket_nonblock(fd, 1); -#endif - -#ifdef WITH_REGEX - if ( rewrite_file ) - rewrite_rules = read_remap_rules(rewrite_file); -#endif - - /* If we're running standalone, set up the input port */ - if ( standalone ) { - fd = socket(PF_INET, SOCK_DGRAM, 0); - - memset(&bindaddr, 0, sizeof bindaddr); - bindaddr.sin_family = AF_INET; - bindaddr.sin_addr.s_addr = INADDR_ANY; - bindaddr.sin_port = htons(IPPORT_TFTP); - - if ( address ) { - char *portptr, *eportptr; - struct hostent *hostent; - struct servent *servent; - unsigned long port; - - address = tfstrdup(address); - portptr = strrchr(address, ':'); - if ( portptr ) - *portptr++ = '\0'; - - if ( *address ) { - hostent = gethostbyname(address); - if ( !hostent || hostent->h_addrtype != AF_INET ) { - syslog(LOG_ERR, "cannot resolve local bind address: %s", address); - exit(EX_NOINPUT); - } - memcpy(&bindaddr.sin_addr, hostent->h_addr, hostent->h_length); - } else { - /* Default to using INADDR_ANY */ - } - - if ( portptr && *portptr ) { - servent = getservbyname(portptr, "udp"); - if ( servent ) { - bindaddr.sin_port = servent->s_port; - } else if ( (port = strtoul(portptr, &eportptr, 0)) && !*eportptr ) { - bindaddr.sin_port = htons(port); - } else if ( !strcmp(portptr, "tftp") ) { - /* It's TFTP, we're OK */ - } else { - syslog(LOG_ERR, "cannot resolve local bind port: %s", portptr); - exit(EX_NOINPUT); - } - } - } - - if (bind(fd, (struct sockaddr *)&bindaddr, sizeof bindaddr) < 0) { - syslog(LOG_ERR, "cannot bind to local socket: %m"); - exit(EX_OSERR); - } - - /* Daemonize this process */ - /* Note: when running in secure mode (-s), we must not chroot, since - we are already in the proper directory. */ - if (!nodaemon && daemon(secure, 0) < 0) { - syslog(LOG_ERR, "cannot daemonize: %m"); - exit(EX_OSERR); - } - } else { - /* 0 is our socket descriptor */ - close(1); close(2); - } - - /* Disable path MTU discovery */ - pmtu_discovery_off(0); - - /* This means we don't want to wait() for children */ -#ifdef SA_NOCLDWAIT - set_signal(SIGCHLD, SIG_IGN, SA_NOCLDSTOP|SA_NOCLDWAIT); -#else - set_signal(SIGCHLD, SIG_IGN, SA_NOCLDSTOP); -#endif - - /* Take SIGHUP and use it to set a variable. This - is polled synchronously to make sure we don't - lose packets as a result. */ - set_signal(SIGHUP, handle_sighup, 0); - - while ( 1 ) { - fd_set readset; - struct timeval tv_waittime; - int rv; - - if ( caught_sighup ) { - caught_sighup = 0; - if ( standalone ) { -#ifdef WITH_REGEX - if ( rewrite_file ) { - freerules(rewrite_rules); - rewrite_rules = read_remap_rules(rewrite_file); - } -#endif - } else { - /* Return to inetd for respawn */ - exit(0); - } - } - - FD_ZERO(&readset); - FD_SET(fd, &readset); - tv_waittime.tv_sec = waittime; - tv_waittime.tv_usec = 0; - -#ifdef __CYGWIN__ - /* On Cygwin, select() on a nonblocking socket returns immediately, - with a rv of 0! */ - set_socket_nonblock(fd, 0); -#endif - - /* Never time out if we're in standalone mode */ - rv = select(fd+1, &readset, NULL, NULL, standalone ? NULL : &tv_waittime); - if ( rv == -1 && errno == EINTR ) - continue; /* Signal caught, reloop */ - if ( rv == -1 ) { - syslog(LOG_ERR, "select loop: %m"); - exit(EX_IOERR); - } else if ( rv == 0 ) { - exit(0); /* Timeout, return to inetd */ - } - -#ifdef __CYGWIN__ set_socket_nonblock(fd, 1); -#endif - - fromlen = sizeof (from); - n = myrecvfrom(fd, buf, sizeof (buf), 0, - (struct sockaddr *)&from, &fromlen, - &myaddr); - - if ( n < 0 ) { - if ( E_WOULD_BLOCK(errno) || errno == EINTR ) { - continue; /* Again, from the top */ - } else { - syslog(LOG_ERR, "recvfrom: %m"); - exit(EX_IOERR); - } - } - - if ( from.sin_family != AF_INET ) { - syslog(LOG_ERR, "received address was not AF_INET, please check your inetd config"); - exit(EX_PROTOCOL); - } - - if ( standalone && myaddr.sin_addr.s_addr == INADDR_ANY ) { - /* myrecvfrom() didn't capture the source address; but we might - have bound to a specific address, if so we should use it */ - memcpy(&myaddr.sin_addr, &bindaddr.sin_addr, sizeof bindaddr.sin_addr); - } - - /* - * Now that we have read the request packet from the UDP - * socket, we fork and go back to listening to the socket. - */ - pid = fork(); - if (pid < 0) { - syslog(LOG_ERR, "fork: %m"); - exit(EX_OSERR); /* Return to inetd, just in case */ - } else if ( pid == 0 ) - break; /* Child exit, parent loop */ - } - - /* Child process: handle the actual request here */ - - /* Ignore SIGHUP */ - set_signal(SIGHUP, SIG_IGN, 0); - -#ifdef HAVE_TCPWRAPPERS - /* Verify if this was a legal request for us. This has to be - done before the chroot, while /etc is still accessible. */ - request_init(&wrap_request, - RQ_DAEMON, __progname, - RQ_FILE, fd, - RQ_CLIENT_SIN, &from, - RQ_SERVER_SIN, &myaddr, - 0); - sock_methods(&wrap_request); - if ( hosts_access(&wrap_request) == 0 ) { - if ( deny_severity != -1 ) - syslog(deny_severity, "connection refused from %s", - inet_ntoa(from.sin_addr)); - exit(EX_NOPERM); /* Access denied */ - } else if ( allow_severity != -1 ) { - syslog(allow_severity, "connect from %s", - inet_ntoa(from.sin_addr)); - } #endif - /* Close file descriptors we don't need */ - close(fd); - - /* Get a socket. This has to be done before the chroot(), since - some systems require access to /dev to create a socket. */ - - peer = socket(AF_INET, SOCK_DGRAM, 0); - if (peer < 0) { - syslog(LOG_ERR, "socket: %m"); - exit(EX_IOERR); - } +#ifdef WITH_REGEX + if (rewrite_file) + rewrite_rules = read_remap_rules(rewrite_file); +#endif - /* Set up the supplementary group access list if possible */ - /* /etc/group still need to be accessible at this point */ + /* If we're running standalone, set up the input port */ + if (standalone) { + fd = socket(PF_INET, SOCK_DGRAM, 0); + + memset(&bindaddr, 0, sizeof bindaddr); + bindaddr.sin_family = AF_INET; + bindaddr.sin_addr.s_addr = INADDR_ANY; + bindaddr.sin_port = htons(IPPORT_TFTP); + + if (address) { + char *portptr, *eportptr; + struct hostent *hostent; + struct servent *servent; + unsigned long port; + + address = tfstrdup(address); + portptr = strrchr(address, ':'); + if (portptr) + *portptr++ = '\0'; + + if (*address) { + hostent = gethostbyname(address); + if (!hostent || hostent->h_addrtype != AF_INET) { + syslog(LOG_ERR, + "cannot resolve local bind address: %s", + address); + exit(EX_NOINPUT); + } + memcpy(&bindaddr.sin_addr, hostent->h_addr, + hostent->h_length); + } else { + /* Default to using INADDR_ANY */ + } + + if (portptr && *portptr) { + servent = getservbyname(portptr, "udp"); + if (servent) { + bindaddr.sin_port = servent->s_port; + } else if ((port = strtoul(portptr, &eportptr, 0)) + && !*eportptr) { + bindaddr.sin_port = htons(port); + } else if (!strcmp(portptr, "tftp")) { + /* It's TFTP, we're OK */ + } else { + syslog(LOG_ERR, "cannot resolve local bind port: %s", + portptr); + exit(EX_NOINPUT); + } + } + } + + if (bind(fd, (struct sockaddr *)&bindaddr, sizeof bindaddr) < 0) { + syslog(LOG_ERR, "cannot bind to local socket: %m"); + exit(EX_OSERR); + } + + /* Daemonize this process */ + /* Note: when running in secure mode (-s), we must not chroot, since + we are already in the proper directory. */ + if (!nodaemon && daemon(secure, 0) < 0) { + syslog(LOG_ERR, "cannot daemonize: %m"); + exit(EX_OSERR); + } + } else { + /* 0 is our socket descriptor */ + close(1); + close(2); + } + + /* Disable path MTU discovery */ + pmtu_discovery_off(0); + + /* This means we don't want to wait() for children */ +#ifdef SA_NOCLDWAIT + set_signal(SIGCHLD, SIG_IGN, SA_NOCLDSTOP | SA_NOCLDWAIT); +#else + set_signal(SIGCHLD, SIG_IGN, SA_NOCLDSTOP); +#endif + + /* Take SIGHUP and use it to set a variable. This + is polled synchronously to make sure we don't + lose packets as a result. */ + set_signal(SIGHUP, handle_sighup, 0); + + while (1) { + fd_set readset; + struct timeval tv_waittime; + int rv; + + if (caught_sighup) { + caught_sighup = 0; + if (standalone) { +#ifdef WITH_REGEX + if (rewrite_file) { + freerules(rewrite_rules); + rewrite_rules = read_remap_rules(rewrite_file); + } +#endif + } else { + /* Return to inetd for respawn */ + exit(0); + } + } + + FD_ZERO(&readset); + FD_SET(fd, &readset); + tv_waittime.tv_sec = waittime; + tv_waittime.tv_usec = 0; + +#ifdef __CYGWIN__ + /* On Cygwin, select() on a nonblocking socket returns immediately, + with a rv of 0! */ + set_socket_nonblock(fd, 0); +#endif + + /* Never time out if we're in standalone mode */ + rv = select(fd + 1, &readset, NULL, NULL, + standalone ? NULL : &tv_waittime); + if (rv == -1 && errno == EINTR) + continue; /* Signal caught, reloop */ + if (rv == -1) { + syslog(LOG_ERR, "select loop: %m"); + exit(EX_IOERR); + } else if (rv == 0) { + exit(0); /* Timeout, return to inetd */ + } +#ifdef __CYGWIN__ + set_socket_nonblock(fd, 1); +#endif + + fromlen = sizeof(from); + n = myrecvfrom(fd, buf, sizeof(buf), 0, + (struct sockaddr *)&from, &fromlen, &myaddr); + + if (n < 0) { + if (E_WOULD_BLOCK(errno) || errno == EINTR) { + continue; /* Again, from the top */ + } else { + syslog(LOG_ERR, "recvfrom: %m"); + exit(EX_IOERR); + } + } + + if (from.sin_family != AF_INET) { + syslog(LOG_ERR, + "received address was not AF_INET, please check your inetd config"); + exit(EX_PROTOCOL); + } + + if (standalone && myaddr.sin_addr.s_addr == INADDR_ANY) { + /* myrecvfrom() didn't capture the source address; but we might + have bound to a specific address, if so we should use it */ + memcpy(&myaddr.sin_addr, &bindaddr.sin_addr, + sizeof bindaddr.sin_addr); + } + + /* + * Now that we have read the request packet from the UDP + * socket, we fork and go back to listening to the socket. + */ + pid = fork(); + if (pid < 0) { + syslog(LOG_ERR, "fork: %m"); + exit(EX_OSERR); /* Return to inetd, just in case */ + } else if (pid == 0) + break; /* Child exit, parent loop */ + } + + /* Child process: handle the actual request here */ + + /* Ignore SIGHUP */ + set_signal(SIGHUP, SIG_IGN, 0); + +#ifdef HAVE_TCPWRAPPERS + /* Verify if this was a legal request for us. This has to be + done before the chroot, while /etc is still accessible. */ + request_init(&wrap_request, + RQ_DAEMON, __progname, + RQ_FILE, fd, + RQ_CLIENT_SIN, &from, RQ_SERVER_SIN, &myaddr, 0); + sock_methods(&wrap_request); + if (hosts_access(&wrap_request) == 0) { + if (deny_severity != -1) + syslog(deny_severity, "connection refused from %s", + inet_ntoa(from.sin_addr)); + exit(EX_NOPERM); /* Access denied */ + } else if (allow_severity != -1) { + syslog(allow_severity, "connect from %s", + inet_ntoa(from.sin_addr)); + } +#endif + + /* Close file descriptors we don't need */ + close(fd); + + /* Get a socket. This has to be done before the chroot(), since + some systems require access to /dev to create a socket. */ + + peer = socket(AF_INET, SOCK_DGRAM, 0); + if (peer < 0) { + syslog(LOG_ERR, "socket: %m"); + exit(EX_IOERR); + } + + /* Set up the supplementary group access list if possible */ + /* /etc/group still need to be accessible at this point */ #ifdef HAVE_INITGROUPS - setrv = initgroups(user, pw->pw_gid); - if ( setrv ) { - syslog(LOG_ERR, "cannot set groups for user %s", user); - exit(EX_OSERR); - } + setrv = initgroups(user, pw->pw_gid); + if (setrv) { + syslog(LOG_ERR, "cannot set groups for user %s", user); + exit(EX_OSERR); + } #else #ifdef HAVE_SETGROUPS - if ( setgroups(0, NULL) ) { - syslog(LOG_ERR, "cannot clear group list"); - } -#endif -#endif - - /* Chroot and drop privileges */ - if (secure) { - if (chroot(".")) { - syslog(LOG_ERR, "chroot: %m"); - exit(EX_OSERR); + if (setgroups(0, NULL)) { + syslog(LOG_ERR, "cannot clear group list"); } +#endif +#endif + + /* Chroot and drop privileges */ + if (secure) { + if (chroot(".")) { + syslog(LOG_ERR, "chroot: %m"); + exit(EX_OSERR); + } #ifdef __CYGWIN__ - chdir("/"); /* Cygwin chroot() bug workaround */ + chdir("/"); /* Cygwin chroot() bug workaround */ #endif - } - + } #ifdef HAVE_SETREGID - setrv = setregid(pw->pw_gid, pw->pw_gid); + setrv = setregid(pw->pw_gid, pw->pw_gid); #else - setrv = setegid(pw->pw_gid) || setgid(pw->pw_gid); + setrv = setegid(pw->pw_gid) || setgid(pw->pw_gid); #endif - + #ifdef HAVE_SETREUID - setrv = setrv || setreuid(pw->pw_uid, pw->pw_uid); + setrv = setrv || setreuid(pw->pw_uid, pw->pw_uid); #else - /* Important: setuid() must come first */ - setrv = setrv || setuid(pw->pw_uid) || - (geteuid() != pw->pw_uid && seteuid(pw->pw_uid)); + /* Important: setuid() must come first */ + setrv = setrv || setuid(pw->pw_uid) || + (geteuid() != pw->pw_uid && seteuid(pw->pw_uid)); #endif - - if ( setrv ) { - syslog(LOG_ERR, "cannot drop privileges: %m"); - exit(EX_OSERR); - } - - /* Other basic setup */ - from.sin_family = AF_INET; - - /* Process the request... */ - if (pick_port_bind(peer, &myaddr, portrange_from, portrange_to) < 0) { - syslog(LOG_ERR, "bind: %m"); - exit(EX_IOERR); - } - - if (connect(peer, (struct sockaddr *)&from, sizeof from) < 0) { - syslog(LOG_ERR, "connect: %m"); - exit(EX_IOERR); - } - /* Disable path MTU discovery */ - pmtu_discovery_off(0); + if (setrv) { + syslog(LOG_ERR, "cannot drop privileges: %m"); + exit(EX_OSERR); + } - tp = (struct tftphdr *)buf; - tp_opcode = ntohs(tp->th_opcode); - if (tp_opcode == RRQ || tp_opcode == WRQ) - tftp(tp, n); - exit(0); + /* Other basic setup */ + from.sin_family = AF_INET; + + /* Process the request... */ + if (pick_port_bind(peer, &myaddr, portrange_from, portrange_to) < 0) { + syslog(LOG_ERR, "bind: %m"); + exit(EX_IOERR); + } + + if (connect(peer, (struct sockaddr *)&from, sizeof from) < 0) { + syslog(LOG_ERR, "connect: %m"); + exit(EX_IOERR); + } + + /* Disable path MTU discovery */ + pmtu_discovery_off(0); + + tp = (struct tftphdr *)buf; + tp_opcode = ntohs(tp->th_opcode); + if (tp_opcode == RRQ || tp_opcode == WRQ) + tftp(tp, n); + exit(0); } -char *rewrite_access(char *, int, const char **); -int validate_access(char *, int, struct formats *, const char **); -void tftp_sendfile(struct formats *, struct tftphdr *, int); -void tftp_recvfile(struct formats *, struct tftphdr *, int); +char *rewrite_access(char *, int, const char **); +int validate_access(char *, int, struct formats *, const char **); +void tftp_sendfile(struct formats *, struct tftphdr *, int); +void tftp_recvfile(struct formats *, struct tftphdr *, int); struct formats { - const char *f_mode; - char *(*f_rewrite)(char *, int, const char **); - int (*f_validate)(char *, int, struct formats *, const char **); - void (*f_send)(struct formats *, struct tftphdr *, int); - void (*f_recv)(struct formats *, struct tftphdr *, int); - int f_convert; + const char *f_mode; + char *(*f_rewrite) (char *, int, const char **); + int (*f_validate) (char *, int, struct formats *, const char **); + void (*f_send) (struct formats *, struct tftphdr *, int); + void (*f_recv) (struct formats *, struct tftphdr *, int); + int f_convert; } formats[] = { - { "netascii", rewrite_access, validate_access, tftp_sendfile, tftp_recvfile, 1 }, - { "octet", rewrite_access, validate_access, tftp_sendfile, tftp_recvfile, 0 }, - { NULL, NULL, NULL, NULL, NULL, 0 } + { + "netascii", rewrite_access, validate_access, tftp_sendfile, + tftp_recvfile, 1}, { + "octet", rewrite_access, validate_access, tftp_sendfile, + tftp_recvfile, 0}, { + NULL, NULL, NULL, NULL, NULL, 0} }; /* * Handle initial connection protocol. */ -int -tftp(struct tftphdr *tp, int size) +int tftp(struct tftphdr *tp, int size) { - char *cp, *end; - int argn, ecode; - struct formats *pf = NULL; - char *origfilename; - char *filename, *mode = NULL; - const char *errmsgptr; - u_short tp_opcode = ntohs(tp->th_opcode); - - char *val = NULL, *opt = NULL; - char *ap = ackbuf + 2; + char *cp, *end; + int argn, ecode; + struct formats *pf = NULL; + char *origfilename; + char *filename, *mode = NULL; + const char *errmsgptr; + u_short tp_opcode = ntohs(tp->th_opcode); - ((struct tftphdr *)ackbuf)->th_opcode = htons(OACK); - - origfilename = cp = (char *) &(tp->th_stuff); - argn = 0; - - end = (char *)tp + size; + char *val = NULL, *opt = NULL; + char *ap = ackbuf + 2; - while ( cp < end && *cp ) { - do { - cp++; - } while (cp < end && *cp); - - if ( *cp ) { - nak(EBADOP, "Request not null-terminated"); - exit(0); + ((struct tftphdr *)ackbuf)->th_opcode = htons(OACK); + + origfilename = cp = (char *)&(tp->th_stuff); + argn = 0; + + end = (char *)tp + size; + + while (cp < end && *cp) { + do { + cp++; + } while (cp < end && *cp); + + if (*cp) { + nak(EBADOP, "Request not null-terminated"); + exit(0); + } + + argn++; + if (argn == 1) { + mode = ++cp; + } else if (argn == 2) { + for (cp = mode; *cp; cp++) + *cp = tolower(*cp); + for (pf = formats; pf->f_mode; pf++) { + if (!strcmp(pf->f_mode, mode)) + break; + } + if (!pf->f_mode) { + nak(EBADOP, "Unknown mode"); + exit(0); + } + if (!(filename = + (*pf->f_rewrite) (origfilename, tp_opcode, + &errmsgptr))) { + nak(EACCESS, errmsgptr); /* File denied by mapping rule */ + exit(0); + } + if (verbosity >= 1) { + if (filename == origfilename + || !strcmp(filename, origfilename)) + syslog(LOG_NOTICE, "%s from %s filename %s\n", + tp_opcode == WRQ ? "WRQ" : "RRQ", + inet_ntoa(from.sin_addr), filename); + else + syslog(LOG_NOTICE, + "%s from %s filename %s remapped to %s\n", + tp_opcode == WRQ ? "WRQ" : "RRQ", + inet_ntoa(from.sin_addr), origfilename, + filename); + } + ecode = + (*pf->f_validate) (filename, tp_opcode, pf, &errmsgptr); + if (ecode) { + nak(ecode, errmsgptr); + exit(0); + } + opt = ++cp; + } else if (argn & 1) { + val = ++cp; + } else { + do_opt(opt, val, &ap); + opt = ++cp; + } } - - argn++; - if (argn == 1) { - mode = ++cp; - } else if (argn == 2) { - for (cp = mode; *cp; cp++) - *cp = tolower(*cp); - for (pf = formats; pf->f_mode; pf++) { - if (!strcmp(pf->f_mode, mode)) - break; - } - if (!pf->f_mode) { - nak(EBADOP, "Unknown mode"); - exit(0); - } - if ( !(filename = - (*pf->f_rewrite)(origfilename, tp_opcode, &errmsgptr)) ) { - nak(EACCESS, errmsgptr); /* File denied by mapping rule */ - exit(0); - } - if ( verbosity >= 1 ) { - if ( filename == origfilename || !strcmp(filename, origfilename) ) - syslog(LOG_NOTICE, "%s from %s filename %s\n", - tp_opcode == WRQ ? "WRQ" : "RRQ", - inet_ntoa(from.sin_addr), filename); - else - syslog(LOG_NOTICE, "%s from %s filename %s remapped to %s\n", - tp_opcode == WRQ ? "WRQ" : "RRQ", - inet_ntoa(from.sin_addr), origfilename, filename); - } - ecode = (*pf->f_validate)(filename, tp_opcode, pf, &errmsgptr); - if (ecode) { - nak(ecode, errmsgptr); - exit(0); - } - opt = ++cp; - } else if ( argn & 1 ) { - val = ++cp; + + if (!pf) { + nak(EBADOP, "Missing mode"); + exit(0); + } + + if (ap != (ackbuf + 2)) { + if (tp_opcode == WRQ) + (*pf->f_recv) (pf, (struct tftphdr *)ackbuf, ap - ackbuf); + else + (*pf->f_send) (pf, (struct tftphdr *)ackbuf, ap - ackbuf); } else { - do_opt(opt, val, &ap); - opt = ++cp; + if (tp_opcode == WRQ) + (*pf->f_recv) (pf, NULL, 0); + else + (*pf->f_send) (pf, NULL, 0); } - } - - if (!pf) { - nak(EBADOP, "Missing mode"); - exit(0); - } - - if ( ap != (ackbuf+2) ) { - if ( tp_opcode == WRQ ) - (*pf->f_recv)(pf, (struct tftphdr *)ackbuf, ap-ackbuf); - else - (*pf->f_send)(pf, (struct tftphdr *)ackbuf, ap-ackbuf); - } else { - if (tp_opcode == WRQ) - (*pf->f_recv)(pf, NULL, 0); - else - (*pf->f_send)(pf, NULL, 0); - } - exit(0); /* Request completed */ + exit(0); /* Request completed */ } static int blksize_set; @@ -838,66 +830,64 @@ static int blksize_set; /* * Set a non-standard block size (c.f. RFC2348) */ -int -set_blksize(char *val, char **ret) +int set_blksize(char *val, char **ret) { - static char b_ret[6]; - unsigned int sz; - char *vend; - - sz = (unsigned int)strtoul(val, &vend, 10); - - if ( blksize_set || *vend ) - return 0; - - if (sz < 8) - return(0); - else if (sz > max_blksize) - sz = max_blksize; - - segsize = sz; - sprintf(*ret = b_ret, "%u", sz); - - blksize_set = 1; - - return(1); + static char b_ret[6]; + unsigned int sz; + char *vend; + + sz = (unsigned int)strtoul(val, &vend, 10); + + if (blksize_set || *vend) + return 0; + + if (sz < 8) + return (0); + else if (sz > max_blksize) + sz = max_blksize; + + segsize = sz; + sprintf(*ret = b_ret, "%u", sz); + + blksize_set = 1; + + return (1); } /* * Set a power-of-two block size (nonstandard) */ -int -set_blksize2(char *val, char **ret) +int set_blksize2(char *val, char **ret) { - static char b_ret[6]; - unsigned int sz; - char *vend; - - sz = (unsigned int)strtoul(val, &vend, 10); - - if ( blksize_set || *vend ) - return 0; - - if (sz < 8) - return(0); - else if (sz > max_blksize) - sz = max_blksize; - - /* Convert to a power of two */ - if ( sz & (sz-1) ) { - unsigned int sz1 = 1; - /* Not a power of two - need to convert */ - while ( sz >>= 1 ) - sz1 <<= 1; - sz = sz1; - } - - segsize = sz; - sprintf(*ret = b_ret, "%u", sz); - - blksize_set = 1; - - return(1); + static char b_ret[6]; + unsigned int sz; + char *vend; + + sz = (unsigned int)strtoul(val, &vend, 10); + + if (blksize_set || *vend) + return 0; + + if (sz < 8) + return (0); + else if (sz > max_blksize) + sz = max_blksize; + + /* Convert to a power of two */ + if (sz & (sz - 1)) { + unsigned int sz1 = 1; + /* Not a power of two - need to convert */ + while (sz >>= 1) + sz1 <<= 1; + sz = sz1; + } + + segsize = sz; + sprintf(*ret = b_ret, "%u", sz); + + blksize_set = 1; + + return (1); } /* @@ -905,23 +895,22 @@ set_blksize2(char *val, char **ret) * For netascii mode, we don't know the size ahead of time; * so reject the option. */ -int -set_tsize(char *val, char **ret) +int set_tsize(char *val, char **ret) { - static char b_ret[sizeof(uintmax_t)*CHAR_BIT/3+2]; - uintmax_t sz; - char *vend; + static char b_ret[sizeof(uintmax_t) * CHAR_BIT / 3 + 2]; + uintmax_t sz; + char *vend; - sz = strtoumax(val, &vend, 10); - - if ( !tsize_ok || *vend ) - return 0; - - if (sz == 0) - sz = (uintmax_t)tsize; + sz = strtoumax(val, &vend, 10); - sprintf(*ret = b_ret, "%"PRIuMAX, sz); - return(1); + if (!tsize_ok || *vend) + return 0; + + if (sz == 0) + sz = (uintmax_t) tsize; + + sprintf(*ret = b_ret, "%" PRIuMAX, sz); + return (1); } /* @@ -929,76 +918,74 @@ set_tsize(char *val, char **ret) * to be the (default) retransmission timeout, but being an * integer in seconds it seems a bit limited. */ -int -set_timeout(char *val, char **ret) +int set_timeout(char *val, char **ret) { - static char b_ret[4]; - unsigned long to; - char *vend; + static char b_ret[4]; + unsigned long to; + char *vend; - to = strtoul(val, &vend, 10); + to = strtoul(val, &vend, 10); - if ( to < 1 || to > 255 || *vend ) - return 0; - - rexmtval = timeout = to*1000000UL; - maxtimeout = rexmtval*TIMEOUT_LIMIT; - - sprintf(*ret = b_ret, "%lu", to); - return(1); + if (to < 1 || to > 255 || *vend) + return 0; + + rexmtval = timeout = to * 1000000UL; + maxtimeout = rexmtval * TIMEOUT_LIMIT; + + sprintf(*ret = b_ret, "%lu", to); + return (1); } /* Similar, but in microseconds. We allow down to 10 ms. */ -int -set_utimeout(char *val, char **ret) +int set_utimeout(char *val, char **ret) { - static char b_ret[4]; - unsigned long to; - char *vend; + static char b_ret[4]; + unsigned long to; + char *vend; - to = strtoul(val, &vend, 10); + to = strtoul(val, &vend, 10); - if ( to < 10000UL || to > 255000000UL || *vend ) - return 0; - - rexmtval = timeout = to; - maxtimeout = rexmtval*TIMEOUT_LIMIT; - - sprintf(*ret = b_ret, "%lu", to); - return(1); + if (to < 10000UL || to > 255000000UL || *vend) + return 0; + + rexmtval = timeout = to; + maxtimeout = rexmtval * TIMEOUT_LIMIT; + + sprintf(*ret = b_ret, "%lu", to); + return (1); } + /* * Parse RFC2347 style options */ -void -do_opt(char *opt, char *val, char **ap) +void do_opt(char *opt, char *val, char **ap) { - struct options *po; - char *ret; - - /* Global option-parsing variables initialization */ - blksize_set = 0; - - if ( !*opt ) + struct options *po; + char *ret; + + /* Global option-parsing variables initialization */ + blksize_set = 0; + + if (!*opt) + return; + + for (po = options; po->o_opt; po++) + if (!strcasecmp(po->o_opt, opt)) { + if (po->o_fnc(val, &ret)) { + if (*ap + strlen(opt) + strlen(ret) + 2 >= + ackbuf + sizeof(ackbuf)) { + nak(EOPTNEG, "Insufficient space for options"); + exit(0); + } + *ap = strrchr(strcpy(strrchr(strcpy(*ap, opt), '\0') + 1, + ret), '\0') + 1; + } else { + nak(EOPTNEG, "Unsupported option(s) requested"); + exit(0); + } + break; + } return; - - for (po = options; po->o_opt; po++) - if (!strcasecmp(po->o_opt, opt)) { - if (po->o_fnc(val, &ret)) { - if (*ap + strlen(opt) + strlen(ret) + 2 >= - ackbuf + sizeof(ackbuf)) { - nak(EOPTNEG, "Insufficient space for options"); - exit(0); - } - *ap = strrchr(strcpy(strrchr(strcpy(*ap, opt),'\0') + 1, - ret),'\0') + 1; - } else { - nak(EOPTNEG, "Unsupported option(s) requested"); - exit(0); - } - break; - } - return; } #ifdef WITH_REGEX @@ -1010,52 +997,50 @@ do_opt(char *opt, char *val, char **ap) * * Return -1 on failure. */ -int -rewrite_macros(char macro, char *output); +int rewrite_macros(char macro, char *output); -int -rewrite_macros(char macro, char *output) +int rewrite_macros(char macro, char *output) { - char *p; + char *p; - switch (macro) { - case 'i': - p = inet_ntoa(from.sin_addr); - if ( output ) - strcpy(output, p); - return strlen(p); - - case 'x': - if ( output ) - sprintf(output, "%08lX", (unsigned long)ntohl(from.sin_addr.s_addr)); - return 8; + switch (macro) { + case 'i': + p = inet_ntoa(from.sin_addr); + if (output) + strcpy(output, p); + return strlen(p); - default: - return -1; - } + case 'x': + if (output) + sprintf(output, "%08lX", + (unsigned long)ntohl(from.sin_addr.s_addr)); + return 8; + + default: + return -1; + } } /* * Modify the filename, if applicable. If it returns NULL, deny the access. */ -char * -rewrite_access(char *filename, int mode, const char **msg) +char *rewrite_access(char *filename, int mode, const char **msg) { - if ( rewrite_rules ) { - char *newname = rewrite_string(filename, rewrite_rules, mode != RRQ, - rewrite_macros, msg); - filename = newname; - } - return filename; + if (rewrite_rules) { + char *newname = + rewrite_string(filename, rewrite_rules, mode != RRQ, + rewrite_macros, msg); + filename = newname; + } + return filename; } #else -char * -rewrite_access(char *filename, int mode, const char **msg) +char *rewrite_access(char *filename, int mode, const char **msg) { - (void)mode; /* Avoid warning */ - (void)msg; - return filename; + (void)mode; /* Avoid warning */ + (void)msg; + return filename; } #endif @@ -1073,316 +1058,313 @@ FILE *file; */ int validate_access(char *filename, int mode, - struct formats *pf, const char **errmsg) + struct formats *pf, const char **errmsg) { - struct stat stbuf; - int i, len; - int fd, wmode, rmode; - char *cp; - const char **dirp; - char stdio_mode[3]; - - tsize_ok = 0; - *errmsg = NULL; - - if (!secure) { - if (*filename != '/') { - *errmsg = "Only absolute filenames allowed"; - return (EACCESS); + struct stat stbuf; + int i, len; + int fd, wmode, rmode; + char *cp; + const char **dirp; + char stdio_mode[3]; + + tsize_ok = 0; + *errmsg = NULL; + + if (!secure) { + if (*filename != '/') { + *errmsg = "Only absolute filenames allowed"; + return (EACCESS); + } + + /* + * prevent tricksters from getting around the directory + * restrictions + */ + len = strlen(filename); + for (i = 1; i < len - 3; i++) { + cp = filename + i; + if (*cp == '.' && memcmp(cp - 1, "/../", 4) == 0) { + *errmsg = "Reverse path not allowed"; + return (EACCESS); + } + } + + for (dirp = dirs; *dirp; dirp++) + if (strncmp(filename, *dirp, strlen(*dirp)) == 0) + break; + if (*dirp == 0 && dirp != dirs) { + *errmsg = "Forbidden directory"; + return (EACCESS); + } } /* - * prevent tricksters from getting around the directory - * restrictions + * We use different a different permissions scheme if `cancreate' is + * set. */ - len = strlen(filename); - for ( i = 1 ; i < len-3 ; i++ ) { - cp = filename + i; - if ( *cp == '.' && memcmp(cp-1, "/../", 4) == 0 ) { - *errmsg = "Reverse path not allowed"; - return(EACCESS); - } + wmode = O_WRONLY | + (cancreate ? O_CREAT : 0) | + (unixperms ? O_TRUNC : 0) | (pf->f_convert ? O_TEXT : O_BINARY); + rmode = O_RDONLY | (pf->f_convert ? O_TEXT : O_BINARY); + + fd = open(filename, mode == RRQ ? rmode : wmode, 0666); + if (fd < 0) { + switch (errno) { + case ENOENT: + case ENOTDIR: + return ENOTFOUND; + case ENOSPC: + return ENOSPACE; + case EEXIST: + return EEXISTS; + default: + return errno + 100; + } } - for (dirp = dirs; *dirp; dirp++) - if (strncmp(filename, *dirp, strlen(*dirp)) == 0) - break; - if (*dirp==0 && dirp!=dirs) { - *errmsg = "Forbidden directory"; - return (EACCESS); - } - } - - /* - * We use different a different permissions scheme if `cancreate' is - * set. - */ - wmode = O_WRONLY | - (cancreate ? O_CREAT : 0) | - (unixperms ? O_TRUNC : 0) | - (pf->f_convert ? O_TEXT : O_BINARY); - rmode = O_RDONLY | - (pf->f_convert ? O_TEXT : O_BINARY); + if (fstat(fd, &stbuf) < 0) + exit(EX_OSERR); /* This shouldn't happen */ - fd = open(filename, mode == RRQ ? rmode : wmode, 0666); - if (fd < 0) { - switch (errno) { - case ENOENT: - case ENOTDIR: - return ENOTFOUND; - case ENOSPC: - return ENOSPACE; - case EEXIST: - return EEXISTS; - default: - return errno+100; - } - } + if (mode == RRQ) { + if (!unixperms && (stbuf.st_mode & (S_IREAD >> 6)) == 0) { + *errmsg = "File must have global read permissions"; + return (EACCESS); + } + tsize = stbuf.st_size; + /* We don't know the tsize if conversion is needed */ + tsize_ok = !pf->f_convert; + } else { + if (!unixperms) { + if ((stbuf.st_mode & (S_IWRITE >> 6)) == 0) { + *errmsg = "File must have global write permissions"; + return (EACCESS); + } - if ( fstat(fd, &stbuf) < 0 ) - exit(EX_OSERR); /* This shouldn't happen */ - - if (mode == RRQ) { - if ( !unixperms && (stbuf.st_mode & (S_IREAD >> 6)) == 0 ) { - *errmsg = "File must have global read permissions"; - return (EACCESS); - } - tsize = stbuf.st_size; - /* We don't know the tsize if conversion is needed */ - tsize_ok = !pf->f_convert; - } else { - if ( !unixperms ) { - if ( (stbuf.st_mode & (S_IWRITE >> 6)) == 0 ) { - *errmsg = "File must have global write permissions"; - return (EACCESS); - } - - /* We didn't get to truncate the file at open() time */ + /* We didn't get to truncate the file at open() time */ #ifdef HAVE_FTRUNCATE - if ( ftruncate(fd, (off_t)0) ) { - *errmsg = "Cannot reset file size"; - return(EACCESS); - } + if (ftruncate(fd, (off_t) 0)) { + *errmsg = "Cannot reset file size"; + return (EACCESS); + } #endif + } + tsize = 0; + tsize_ok = 1; } - tsize = 0; - tsize_ok = 1; - } - stdio_mode[0] = (mode == RRQ) ? 'r':'w'; - stdio_mode[1] = (pf->f_convert) ? 't':'b'; - stdio_mode[2] = '\0'; + stdio_mode[0] = (mode == RRQ) ? 'r' : 'w'; + stdio_mode[1] = (pf->f_convert) ? 't' : 'b'; + stdio_mode[2] = '\0'; - file = fdopen(fd, stdio_mode); - if (file == NULL) - exit(EX_OSERR); /* Internal error */ + file = fdopen(fd, stdio_mode); + if (file == NULL) + exit(EX_OSERR); /* Internal error */ - return (0); + return (0); } /* * Send the requested file. */ -void -tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen) +void tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen) { - struct tftphdr *dp; - struct tftphdr *ap; /* ack packet */ - static u_short block = 1; /* Static to avoid longjmp funnies */ - u_short ap_opcode, ap_block; - unsigned long r_timeout; - int size, n; - - if (oap) { - timeout = rexmtval; - (void)sigsetjmp(timeoutbuf,1); - oack: - r_timeout = timeout; - if (send(peer, oap, oacklen, 0) != oacklen) { - syslog(LOG_WARNING, "tftpd: oack: %m\n"); - goto abort; - } - for ( ; ; ) { - n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, &r_timeout); - if (n < 0) { - syslog(LOG_WARNING, "tftpd: read: %m\n"); - goto abort; - } - ap = (struct tftphdr *)ackbuf; - ap_opcode = ntohs((u_short)ap->th_opcode); - ap_block = ntohs((u_short)ap->th_block); - - if (ap_opcode == ERROR) { - syslog(LOG_WARNING, "tftp: client does not accept options\n"); - goto abort; - } - if (ap_opcode == ACK) { - if (ap_block == 0) - break; - /* Resynchronize with the other side */ - (void)synchnet(peer); - goto oack; - } - } - } + struct tftphdr *dp; + struct tftphdr *ap; /* ack packet */ + static u_short block = 1; /* Static to avoid longjmp funnies */ + u_short ap_opcode, ap_block; + unsigned long r_timeout; + int size, n; - dp = r_init(); - do { - size = readit(file, &dp, pf->f_convert); - if (size < 0) { - nak(errno + 100, NULL); - goto abort; + if (oap) { + timeout = rexmtval; + (void)sigsetjmp(timeoutbuf, 1); + oack: + r_timeout = timeout; + if (send(peer, oap, oacklen, 0) != oacklen) { + syslog(LOG_WARNING, "tftpd: oack: %m\n"); + goto abort; + } + for (;;) { + n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, &r_timeout); + if (n < 0) { + syslog(LOG_WARNING, "tftpd: read: %m\n"); + goto abort; + } + ap = (struct tftphdr *)ackbuf; + ap_opcode = ntohs((u_short) ap->th_opcode); + ap_block = ntohs((u_short) ap->th_block); + + if (ap_opcode == ERROR) { + syslog(LOG_WARNING, + "tftp: client does not accept options\n"); + goto abort; + } + if (ap_opcode == ACK) { + if (ap_block == 0) + break; + /* Resynchronize with the other side */ + (void)synchnet(peer); + goto oack; + } + } } - dp->th_opcode = htons((u_short)DATA); - dp->th_block = htons((u_short)block); - timeout = rexmtval; - (void) sigsetjmp(timeoutbuf,1); - - r_timeout = timeout; - if (send(peer, dp, size + 4, 0) != size + 4) { - syslog(LOG_WARNING, "tftpd: write: %m"); - goto abort; - } - read_ahead(file, pf->f_convert); - for ( ; ; ) { - n = recv_time(peer, ackbuf, sizeof (ackbuf), 0, &r_timeout); - if (n < 0) { - syslog(LOG_WARNING, "tftpd: read(ack): %m"); - goto abort; - } - ap = (struct tftphdr *)ackbuf; - ap_opcode = ntohs((u_short)ap->th_opcode); - ap_block = ntohs((u_short)ap->th_block); - - if (ap_opcode == ERROR) - goto abort; - - if (ap_opcode == ACK) { - if (ap_block == block) { - break; - } - /* Re-synchronize with the other side */ - (void) synchnet(peer); - /* - * RFC1129/RFC1350: We MUST NOT re-send the DATA - * packet in response to an invalid ACK. Doing so - * would cause the Sorcerer's Apprentice bug. - */ - } - - } - block++; - } while (size == segsize); - abort: - (void) fclose(file); + + dp = r_init(); + do { + size = readit(file, &dp, pf->f_convert); + if (size < 0) { + nak(errno + 100, NULL); + goto abort; + } + dp->th_opcode = htons((u_short) DATA); + dp->th_block = htons((u_short) block); + timeout = rexmtval; + (void)sigsetjmp(timeoutbuf, 1); + + r_timeout = timeout; + if (send(peer, dp, size + 4, 0) != size + 4) { + syslog(LOG_WARNING, "tftpd: write: %m"); + goto abort; + } + read_ahead(file, pf->f_convert); + for (;;) { + n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, &r_timeout); + if (n < 0) { + syslog(LOG_WARNING, "tftpd: read(ack): %m"); + goto abort; + } + ap = (struct tftphdr *)ackbuf; + ap_opcode = ntohs((u_short) ap->th_opcode); + ap_block = ntohs((u_short) ap->th_block); + + if (ap_opcode == ERROR) + goto abort; + + if (ap_opcode == ACK) { + if (ap_block == block) { + break; + } + /* Re-synchronize with the other side */ + (void)synchnet(peer); + /* + * RFC1129/RFC1350: We MUST NOT re-send the DATA + * packet in response to an invalid ACK. Doing so + * would cause the Sorcerer's Apprentice bug. + */ + } + + } + block++; + } while (size == segsize); + abort: + (void)fclose(file); } /* Bail out signal handler */ -void -justquit(int sig) +void justquit(int sig) { - (void)sig; /* Suppress unused warning */ - exit(0); + (void)sig; /* Suppress unused warning */ + exit(0); } - /* * Receive a file. */ -void -tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen) +void tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen) { - struct tftphdr *dp; - int n, size; - /* These are "static" to avoid longjmp funnies */ - static struct tftphdr *ap; /* ack buffer */ - static u_short block = 0; - static int acksize; - u_short dp_opcode, dp_block; - unsigned long r_timeout; + struct tftphdr *dp; + int n, size; + /* These are "static" to avoid longjmp funnies */ + static struct tftphdr *ap; /* ack buffer */ + static u_short block = 0; + static int acksize; + u_short dp_opcode, dp_block; + unsigned long r_timeout; - dp = w_init(); - do { - timeout = rexmtval; - - if (!block && oap) { - ap = (struct tftphdr *)ackbuf; - acksize = oacklen; - } else { - ap = (struct tftphdr *)ackbuf; - ap->th_opcode = htons((u_short)ACK); - ap->th_block = htons((u_short)block); - acksize = 4; - } - block++; - (void) sigsetjmp(timeoutbuf,1); - send_ack: - r_timeout = timeout; - if (send(peer, ackbuf, acksize, 0) != acksize) { - syslog(LOG_WARNING, "tftpd: write(ack): %m"); - goto abort; - } + dp = w_init(); + do { + timeout = rexmtval; + + if (!block && oap) { + ap = (struct tftphdr *)ackbuf; + acksize = oacklen; + } else { + ap = (struct tftphdr *)ackbuf; + ap->th_opcode = htons((u_short) ACK); + ap->th_block = htons((u_short) block); + acksize = 4; + } + block++; + (void)sigsetjmp(timeoutbuf, 1); + send_ack: + r_timeout = timeout; + if (send(peer, ackbuf, acksize, 0) != acksize) { + syslog(LOG_WARNING, "tftpd: write(ack): %m"); + goto abort; + } + write_behind(file, pf->f_convert); + for (;;) { + n = recv_time(peer, dp, PKTSIZE, 0, &r_timeout); + if (n < 0) { /* really? */ + syslog(LOG_WARNING, "tftpd: read: %m"); + goto abort; + } + dp_opcode = ntohs((u_short) dp->th_opcode); + dp_block = ntohs((u_short) dp->th_block); + if (dp_opcode == ERROR) + goto abort; + if (dp_opcode == DATA) { + if (dp_block == block) { + break; /* normal */ + } + /* Re-synchronize with the other side */ + (void)synchnet(peer); + if (dp_block == (block - 1)) + goto send_ack; /* rexmit */ + } + } + /* size = write(file, dp->th_data, n - 4); */ + size = writeit(file, &dp, n - 4, pf->f_convert); + if (size != (n - 4)) { /* ahem */ + if (size < 0) + nak(errno + 100, NULL); + else + nak(ENOSPACE, NULL); + goto abort; + } + } while (size == segsize); write_behind(file, pf->f_convert); - for ( ; ; ) { - n = recv_time(peer, dp, PKTSIZE, 0, &r_timeout); - if (n < 0) { /* really? */ - syslog(LOG_WARNING, "tftpd: read: %m"); - goto abort; - } - dp_opcode = ntohs((u_short)dp->th_opcode); - dp_block = ntohs((u_short)dp->th_block); - if (dp_opcode == ERROR) - goto abort; - if (dp_opcode == DATA) { - if (dp_block == block) { - break; /* normal */ - } - /* Re-synchronize with the other side */ - (void) synchnet(peer); - if (dp_block == (block-1)) - goto send_ack; /* rexmit */ - } - } - /* size = write(file, dp->th_data, n - 4); */ - size = writeit(file, &dp, n - 4, pf->f_convert); - if (size != (n-4)) { /* ahem */ - if (size < 0) nak(errno + 100, NULL); - else nak(ENOSPACE, NULL); - goto abort; - } - } while (size == segsize); - write_behind(file, pf->f_convert); - (void) fclose(file); /* close data file */ - - ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ - ap->th_block = htons((u_short)(block)); - (void) send(peer, ackbuf, 4, 0); - - timeout_quit = 1; /* just quit on timeout */ - n = recv_time(peer, buf, sizeof (buf), 0, &timeout); /* normally times out and quits */ - timeout_quit = 0; + (void)fclose(file); /* close data file */ - if (n >= 4 && /* if read some data */ - dp_opcode == DATA && /* and got a data block */ - block == dp_block) { /* then my last ack was lost */ - (void) send(peer, ackbuf, 4, 0); /* resend final ack */ - } - abort: - return; + ap->th_opcode = htons((u_short) ACK); /* send the "final" ack */ + ap->th_block = htons((u_short) (block)); + (void)send(peer, ackbuf, 4, 0); + + timeout_quit = 1; /* just quit on timeout */ + n = recv_time(peer, buf, sizeof(buf), 0, &timeout); /* normally times out and quits */ + timeout_quit = 0; + + if (n >= 4 && /* if read some data */ + dp_opcode == DATA && /* and got a data block */ + block == dp_block) { /* then my last ack was lost */ + (void)send(peer, ackbuf, 4, 0); /* resend final ack */ + } + abort: + return; } -static const char * const errmsgs[] = -{ - "Undefined error code", /* 0 - EUNDEF */ - "File not found", /* 1 - ENOTFOUND */ - "Access denied", /* 2 - EACCESS */ - "Disk full or allocation exceeded", /* 3 - ENOSPACE */ - "Illegal TFTP operation", /* 4 - EBADOP */ - "Unknown transfer ID", /* 5 - EBADID */ - "File already exists", /* 6 - EEXISTS */ - "No such user", /* 7 - ENOUSER */ - "Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */ +static const char *const errmsgs[] = { + "Undefined error code", /* 0 - EUNDEF */ + "File not found", /* 1 - ENOTFOUND */ + "Access denied", /* 2 - EACCESS */ + "Disk full or allocation exceeded", /* 3 - ENOSPACE */ + "Illegal TFTP operation", /* 4 - EBADOP */ + "Unknown transfer ID", /* 5 - EBADID */ + "File already exists", /* 6 - EEXISTS */ + "No such user", /* 7 - ENOUSER */ + "Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */ }; + #define ERR_CNT (sizeof(errmsgs)/sizeof(const char *)) /* @@ -1391,39 +1373,38 @@ static const char * const errmsgs[] = * standard TFTP codes, or a UNIX errno * offset by 100. */ -static void -nak(int error, const char *msg) +static void nak(int error, const char *msg) { - struct tftphdr *tp; - int length; - - tp = (struct tftphdr *)buf; - tp->th_opcode = htons((u_short)ERROR); + struct tftphdr *tp; + int length; - if ( error >= 100 ) { - /* This is a Unix errno+100 */ - if ( !msg ) - msg = strerror(error - 100); - error = EUNDEF; - } else { - if ( (unsigned)error >= ERR_CNT ) - error = EUNDEF; + tp = (struct tftphdr *)buf; + tp->th_opcode = htons((u_short) ERROR); - if ( !msg ) - msg = errmsgs[error]; - } + if (error >= 100) { + /* This is a Unix errno+100 */ + if (!msg) + msg = strerror(error - 100); + error = EUNDEF; + } else { + if ((unsigned)error >= ERR_CNT) + error = EUNDEF; - tp->th_code = htons((u_short)error); + if (!msg) + msg = errmsgs[error]; + } - length = strlen(msg)+1; - memcpy(tp->th_msg, msg, length); - length += 4; /* Add space for header */ - - if ( verbosity >= 2 ) { - syslog(LOG_INFO, "sending NAK (%d, %s) to %s", - error, tp->th_msg, inet_ntoa(from.sin_addr)); - } - - if (send(peer, buf, length, 0) != length) - syslog(LOG_WARNING, "nak: %m"); + tp->th_code = htons((u_short) error); + + length = strlen(msg) + 1; + memcpy(tp->th_msg, msg, length); + length += 4; /* Add space for header */ + + if (verbosity >= 2) { + syslog(LOG_INFO, "sending NAK (%d, %s) to %s", + error, tp->th_msg, inet_ntoa(from.sin_addr)); + } + + if (send(peer, buf, length, 0) != length) + syslog(LOG_WARNING, "nak: %m"); } diff --git a/tftpd/tftpd.h b/tftpd/tftpd.h index 789ee94..4413729 100644 --- a/tftpd/tftpd.h +++ b/tftpd/tftpd.h @@ -1,6 +1,6 @@ /* $Id$ */ /* ----------------------------------------------------------------------- * - * + * * Copyright 2001 H. Peter Anvin - All Rights Reserved * * This program is free software available under the same license