forked from mirrors/tftp-hpa-google
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.
This commit is contained in:
parent
62533e7441
commit
22accddda0
18 changed files with 2794 additions and 2820 deletions
|
@ -41,9 +41,8 @@
|
||||||
#ifndef lint
|
#ifndef lint
|
||||||
/* static char sccsid[] = "@(#)tftpsubs.c 8.1 (Berkeley) 6/6/93"; */
|
/* 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 char rcsid[] = "$OpenBSD: tftpsubs.c,v 1.2 1996/06/26 05:40:36 deraadt Exp $"; */
|
||||||
static const char *rcsid UNUSED =
|
static const char *rcsid UNUSED = "tftp-hpa: $Id$";
|
||||||
"tftp-hpa: $Id$";
|
#endif /* not lint */
|
||||||
#endif /* not lint */
|
|
||||||
|
|
||||||
/* Simple minded read-ahead/write-behind subroutines for tftp user and
|
/* Simple minded read-ahead/write-behind subroutines for tftp user and
|
||||||
server. Written originally with multiple buffers in mind, but current
|
server. Written originally with multiple buffers in mind, but current
|
||||||
|
@ -58,127 +57,130 @@ static const char *rcsid UNUSED =
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
#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 {
|
struct bf {
|
||||||
int counter; /* size of data in buffer, or flag */
|
int counter; /* size of data in buffer, or flag */
|
||||||
char buf[PKTSIZE]; /* room for data packet */
|
char buf[PKTSIZE]; /* room for data packet */
|
||||||
} bfs[2];
|
} bfs[2];
|
||||||
|
|
||||||
/* Values for bf.counter */
|
/* Values for bf.counter */
|
||||||
#define BF_ALLOC -3 /* alloc'd but not yet filled */
|
#define BF_ALLOC -3 /* alloc'd but not yet filled */
|
||||||
#define BF_FREE -2 /* free */
|
#define BF_FREE -2 /* free */
|
||||||
/* [-1 .. segsize] = size of data in the data buffer */
|
/* [-1 .. segsize] = size of data in the data buffer */
|
||||||
|
|
||||||
static int nextone; /* index of next buffer to use */
|
static int nextone; /* index of next buffer to use */
|
||||||
static int current; /* index of buffer in use */
|
static int current; /* index of buffer in use */
|
||||||
|
|
||||||
/* control flags for crlf conversions */
|
/* control flags for crlf conversions */
|
||||||
int newline = 0; /* fillbuf: in middle of newline expansion */
|
int newline = 0; /* fillbuf: in middle of newline expansion */
|
||||||
int prevchar = -1; /* putbuf: previous char (cr check) */
|
int prevchar = -1; /* putbuf: previous char (cr check) */
|
||||||
|
|
||||||
static struct tftphdr *rw_init(int);
|
static struct tftphdr *rw_init(int);
|
||||||
|
|
||||||
struct tftphdr *w_init() { return rw_init(0); } /* write-behind */
|
struct tftphdr *w_init()
|
||||||
struct tftphdr *r_init() { return rw_init(1); } /* read-ahead */
|
{
|
||||||
|
return rw_init(0);
|
||||||
|
} /* write-behind */
|
||||||
|
|
||||||
|
struct tftphdr *r_init()
|
||||||
|
{
|
||||||
|
return rw_init(1);
|
||||||
|
} /* read-ahead */
|
||||||
|
|
||||||
/* init for either read-ahead or write-behind */
|
/* init for either read-ahead or write-behind */
|
||||||
/* x == zero for write-behind, one for read-head */
|
/* x == zero for write-behind, one for read-head */
|
||||||
static struct tftphdr *
|
static struct tftphdr *rw_init(int x)
|
||||||
rw_init(int x)
|
|
||||||
{
|
{
|
||||||
newline = 0; /* init crlf flag */
|
newline = 0; /* init crlf flag */
|
||||||
prevchar = -1;
|
prevchar = -1;
|
||||||
bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
|
bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
|
||||||
current = 0;
|
current = 0;
|
||||||
bfs[1].counter = BF_FREE;
|
bfs[1].counter = BF_FREE;
|
||||||
nextone = x; /* ahead or behind? */
|
nextone = x; /* ahead or behind? */
|
||||||
return (struct tftphdr *)bfs[0].buf;
|
return (struct tftphdr *)bfs[0].buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Have emptied current buffer by sending to net and getting ack.
|
/* Have emptied current buffer by sending to net and getting ack.
|
||||||
Free it and return next buffer filled with data.
|
Free it and return next buffer filled with data.
|
||||||
*/
|
*/
|
||||||
int
|
int readit(FILE * file, struct tftphdr **dpp, int convert)
|
||||||
readit(FILE *file, struct tftphdr **dpp, int convert)
|
|
||||||
{
|
{
|
||||||
struct bf *b;
|
struct bf *b;
|
||||||
|
|
||||||
bfs[current].counter = BF_FREE; /* free old one */
|
bfs[current].counter = BF_FREE; /* free old one */
|
||||||
current = !current; /* "incr" current */
|
current = !current; /* "incr" current */
|
||||||
|
|
||||||
b = &bfs[current]; /* look at new buffer */
|
b = &bfs[current]; /* look at new buffer */
|
||||||
if (b->counter == BF_FREE) /* if it's empty */
|
if (b->counter == BF_FREE) /* if it's empty */
|
||||||
read_ahead(file, convert); /* fill it */
|
read_ahead(file, convert); /* fill it */
|
||||||
/* assert(b->counter != BF_FREE);*//* check */
|
/* assert(b->counter != BF_FREE);*//* check */
|
||||||
*dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
|
*dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
|
||||||
return b->counter;
|
return b->counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fill the input buffer, doing ascii conversions if requested
|
* fill the input buffer, doing ascii conversions if requested
|
||||||
* conversions are lf -> cr,lf and cr -> cr, nul
|
* conversions are lf -> cr,lf and cr -> cr, nul
|
||||||
*/
|
*/
|
||||||
void
|
void read_ahead(FILE * file, int convert)
|
||||||
read_ahead(FILE *file, int convert)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char *p;
|
char *p;
|
||||||
int c;
|
int c;
|
||||||
struct bf *b;
|
struct bf *b;
|
||||||
struct tftphdr *dp;
|
struct tftphdr *dp;
|
||||||
|
|
||||||
b = &bfs[nextone]; /* look at "next" buffer */
|
b = &bfs[nextone]; /* look at "next" buffer */
|
||||||
if (b->counter != BF_FREE) /* nop if not free */
|
if (b->counter != BF_FREE) /* nop if not free */
|
||||||
return;
|
return;
|
||||||
nextone = !nextone; /* "incr" next buffer ptr */
|
nextone = !nextone; /* "incr" next buffer ptr */
|
||||||
|
|
||||||
dp = (struct tftphdr *)b->buf;
|
dp = (struct tftphdr *)b->buf;
|
||||||
|
|
||||||
if (convert == 0) {
|
if (convert == 0) {
|
||||||
b->counter = read(fileno(file), dp->th_data, segsize);
|
b->counter = read(fileno(file), dp->th_data, segsize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = dp->th_data;
|
p = dp->th_data;
|
||||||
for (i = 0 ; i < segsize; i++) {
|
for (i = 0; i < segsize; i++) {
|
||||||
if (newline) {
|
if (newline) {
|
||||||
if (prevchar == '\n')
|
if (prevchar == '\n')
|
||||||
c = '\n'; /* lf to cr,lf */
|
c = '\n'; /* lf to cr,lf */
|
||||||
else c = '\0'; /* cr to cr,nul */
|
else
|
||||||
newline = 0;
|
c = '\0'; /* cr to cr,nul */
|
||||||
}
|
newline = 0;
|
||||||
else {
|
} else {
|
||||||
c = getc(file);
|
c = getc(file);
|
||||||
if (c == EOF) break;
|
if (c == EOF)
|
||||||
if (c == '\n' || c == '\r') {
|
break;
|
||||||
prevchar = c;
|
if (c == '\n' || c == '\r') {
|
||||||
c = '\r';
|
prevchar = c;
|
||||||
newline = 1;
|
c = '\r';
|
||||||
}
|
newline = 1;
|
||||||
}
|
}
|
||||||
*p++ = c;
|
}
|
||||||
}
|
*p++ = c;
|
||||||
b->counter = (int)(p - dp->th_data);
|
}
|
||||||
|
b->counter = (int)(p - dp->th_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update count associated with the buffer, get new buffer
|
/* Update count associated with the buffer, get new buffer
|
||||||
from the queue. Calls write_behind only if next buffer not
|
from the queue. Calls write_behind only if next buffer not
|
||||||
available.
|
available.
|
||||||
*/
|
*/
|
||||||
int
|
int writeit(FILE * file, struct tftphdr **dpp, int ct, int convert)
|
||||||
writeit(FILE *file, struct tftphdr **dpp, int ct, int convert)
|
|
||||||
{
|
{
|
||||||
bfs[current].counter = ct; /* set size of data to write */
|
bfs[current].counter = ct; /* set size of data to write */
|
||||||
current = !current; /* switch to other buffer */
|
current = !current; /* switch to other buffer */
|
||||||
if (bfs[current].counter != BF_FREE) /* if not free */
|
if (bfs[current].counter != BF_FREE) /* if not free */
|
||||||
(void)write_behind(file, convert); /* flush it */
|
(void)write_behind(file, convert); /* flush it */
|
||||||
bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
|
bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
|
||||||
*dpp = (struct tftphdr *)bfs[current].buf;
|
*dpp = (struct tftphdr *)bfs[current].buf;
|
||||||
return ct; /* this is a lie of course */
|
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
|
* 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.
|
* CR followed by anything else. In this case we leave it alone.
|
||||||
*/
|
*/
|
||||||
int
|
int write_behind(FILE * file, int convert)
|
||||||
write_behind(FILE *file, int convert)
|
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
int count;
|
int count;
|
||||||
int ct;
|
int ct;
|
||||||
char *p;
|
char *p;
|
||||||
int c; /* current character */
|
int c; /* current character */
|
||||||
struct bf *b;
|
struct bf *b;
|
||||||
struct tftphdr *dp;
|
struct tftphdr *dp;
|
||||||
|
|
||||||
b = &bfs[nextone];
|
b = &bfs[nextone];
|
||||||
if (b->counter < -1) /* anything to flush? */
|
if (b->counter < -1) /* anything to flush? */
|
||||||
return 0; /* just nop if nothing to do */
|
return 0; /* just nop if nothing to do */
|
||||||
|
|
||||||
count = b->counter; /* remember byte count */
|
count = b->counter; /* remember byte count */
|
||||||
b->counter = BF_FREE; /* reset flag */
|
b->counter = BF_FREE; /* reset flag */
|
||||||
dp = (struct tftphdr *)b->buf;
|
dp = (struct tftphdr *)b->buf;
|
||||||
nextone = !nextone; /* incr for next time */
|
nextone = !nextone; /* incr for next time */
|
||||||
buf = dp->th_data;
|
buf = dp->th_data;
|
||||||
|
|
||||||
if (count <= 0) return -1; /* nak logic? */
|
if (count <= 0)
|
||||||
|
return -1; /* nak logic? */
|
||||||
|
|
||||||
if (convert == 0)
|
if (convert == 0)
|
||||||
return write(fileno(file), buf, count);
|
return write(fileno(file), buf, count);
|
||||||
|
|
||||||
p = buf;
|
p = buf;
|
||||||
ct = count;
|
ct = count;
|
||||||
while (ct--) { /* loop over the buffer */
|
while (ct--) { /* loop over the buffer */
|
||||||
c = *p++; /* pick up a character */
|
c = *p++; /* pick up a character */
|
||||||
if (prevchar == '\r') { /* if prev char was cr */
|
if (prevchar == '\r') { /* if prev char was cr */
|
||||||
if (c == '\n') /* if have cr,lf then just */
|
if (c == '\n') /* if have cr,lf then just */
|
||||||
fseek(file, -1, 1); /* smash lf on top of the cr */
|
fseek(file, -1, 1); /* smash lf on top of the cr */
|
||||||
else
|
else if (c == '\0') /* if have cr,nul then */
|
||||||
if (c == '\0') /* if have cr,nul then */
|
goto skipit; /* just skip over the putc */
|
||||||
goto skipit; /* just skip over the putc */
|
/* else just fall through and allow it */
|
||||||
/* else just fall through and allow it */
|
}
|
||||||
}
|
putc(c, file);
|
||||||
putc(c, file);
|
skipit:
|
||||||
skipit:
|
prevchar = c;
|
||||||
prevchar = c;
|
}
|
||||||
}
|
return count;
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* When an error has occurred, it is possible that the two sides
|
/* 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
|
* 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.
|
* response to packet N is really their response to packet N-1.
|
||||||
|
@ -244,69 +244,69 @@ skipit:
|
||||||
* when trace is active).
|
* when trace is active).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int synchnet(int f)
|
||||||
synchnet(int f) /* socket to flush */
|
{ /* socket to flush */
|
||||||
{
|
int pktcount = 0;
|
||||||
int pktcount = 0;
|
char rbuf[PKTSIZE];
|
||||||
char rbuf[PKTSIZE];
|
struct sockaddr_in from;
|
||||||
struct sockaddr_in from;
|
socklen_t fromlen;
|
||||||
socklen_t fromlen;
|
fd_set socketset;
|
||||||
fd_set socketset;
|
struct timeval notime;
|
||||||
struct timeval notime;
|
|
||||||
|
|
||||||
while ( 1 ) {
|
while (1) {
|
||||||
notime.tv_sec = notime.tv_usec = 0;
|
notime.tv_sec = notime.tv_usec = 0;
|
||||||
|
|
||||||
FD_ZERO(&socketset);
|
FD_ZERO(&socketset);
|
||||||
FD_SET(f, &socketset);
|
FD_SET(f, &socketset);
|
||||||
|
|
||||||
if ( select(f, &socketset, NULL, NULL, ¬ime) <= 0 )
|
if (select(f, &socketset, NULL, NULL, ¬ime) <= 0)
|
||||||
break; /* Nothing to read */
|
break; /* Nothing to read */
|
||||||
|
|
||||||
/* Otherwise drain the packet */
|
/* Otherwise drain the packet */
|
||||||
pktcount++;
|
pktcount++;
|
||||||
fromlen = sizeof from;
|
fromlen = sizeof from;
|
||||||
(void) recvfrom(f, rbuf, sizeof (rbuf), 0,
|
(void)recvfrom(f, rbuf, sizeof(rbuf), 0,
|
||||||
(struct sockaddr *)&from, &fromlen);
|
(struct sockaddr *)&from, &fromlen);
|
||||||
}
|
|
||||||
|
|
||||||
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++;
|
return pktcount; /* Return packets drained */
|
||||||
if ( port > port_range_to )
|
}
|
||||||
port = port_range_from;
|
|
||||||
} while ( port != firstport );
|
int pick_port_bind(int sockfd, struct sockaddr_in *myaddr,
|
||||||
|
unsigned int port_range_from,
|
||||||
return -1;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,18 +50,19 @@
|
||||||
struct tftphdr;
|
struct tftphdr;
|
||||||
|
|
||||||
struct tftphdr *r_init(void);
|
struct tftphdr *r_init(void);
|
||||||
void read_ahead(FILE *, int);
|
void read_ahead(FILE *, int);
|
||||||
int readit(FILE *, struct tftphdr **, int);
|
int readit(FILE *, struct tftphdr **, int);
|
||||||
|
|
||||||
int synchnet(int);
|
int synchnet(int);
|
||||||
|
|
||||||
struct tftphdr *w_init(void);
|
struct tftphdr *w_init(void);
|
||||||
int write_behind(FILE *, int);
|
int write_behind(FILE *, int);
|
||||||
int writeit(FILE *, struct tftphdr **, int, int);
|
int writeit(FILE *, struct tftphdr **, int, int);
|
||||||
|
|
||||||
extern int segsize;
|
extern int segsize;
|
||||||
#define MAX_SEGSIZE 65464
|
#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
|
#endif
|
||||||
|
|
4
config.h
4
config.h
|
@ -19,7 +19,7 @@
|
||||||
#define CONFIG_H 1
|
#define CONFIG_H 1
|
||||||
|
|
||||||
/* Must be included before we include any system headers! */
|
/* Must be included before we include any system headers! */
|
||||||
#include "aconfig.h" /* autogenerated configuration header */
|
#include "aconfig.h" /* autogenerated configuration header */
|
||||||
|
|
||||||
/* Standard includes */
|
/* Standard includes */
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ void *xmalloc(size_t);
|
||||||
char *xstrdup(const char *);
|
char *xstrdup(const char *);
|
||||||
|
|
||||||
#ifndef HAVE_BSD_SIGNAL
|
#ifndef HAVE_BSD_SIGNAL
|
||||||
void (*bsd_signal(int, void (*)(int)))(int);
|
void (*bsd_signal(int, void (*)(int))) (int);
|
||||||
#endif
|
#endif
|
||||||
#ifndef HAVE_DUP2
|
#ifndef HAVE_DUP2
|
||||||
int dup2(int, int);
|
int dup2(int, int);
|
||||||
|
|
|
@ -6,23 +6,22 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
void (*bsd_signal(int signum, void (*handler)(int)))(int)
|
void (*bsd_signal(int signum, void (*handler) (int))) (int) {
|
||||||
{
|
struct sigaction action, oldaction;
|
||||||
struct sigaction action, oldaction;
|
|
||||||
|
|
||||||
memset(&action, 0, sizeof action);
|
memset(&action, 0, sizeof action);
|
||||||
action.sa_handler = handler;
|
action.sa_handler = handler;
|
||||||
sigemptyset(&action.sa_mask);
|
sigemptyset(&action.sa_mask);
|
||||||
sigaddset(&action.sa_mask, signum);
|
sigaddset(&action.sa_mask, signum);
|
||||||
action.sa_flags = SA_RESTART;
|
action.sa_flags = SA_RESTART;
|
||||||
|
|
||||||
if (sigaction(signum, &action, &oldaction) == -1) {
|
if (sigaction(signum, &action, &oldaction) == -1) {
|
||||||
#ifdef SIG_ERR
|
#ifdef SIG_ERR
|
||||||
return SIG_ERR;
|
return SIG_ERR;
|
||||||
#else
|
#else
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return oldaction.sa_handler;
|
return oldaction.sa_handler;
|
||||||
}
|
}
|
||||||
|
|
41
lib/daemon.c
41
lib/daemon.c
|
@ -6,32 +6,31 @@
|
||||||
|
|
||||||
int daemon(int nochdir, int noclose)
|
int daemon(int nochdir, int noclose)
|
||||||
{
|
{
|
||||||
int nullfd;
|
int nullfd;
|
||||||
pid_t f;
|
pid_t f;
|
||||||
|
|
||||||
if (!nochdir) {
|
if (!nochdir) {
|
||||||
if (chdir("/"))
|
if (chdir("/"))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!noclose) {
|
if (!noclose) {
|
||||||
if ((nullfd = open("/dev/null", O_RDWR)) < 0 ||
|
if ((nullfd = open("/dev/null", O_RDWR)) < 0 ||
|
||||||
dup2(nullfd, 0) < 0 ||
|
dup2(nullfd, 0) < 0 ||
|
||||||
dup2(nullfd, 1) < 0 ||
|
dup2(nullfd, 1) < 0 || dup2(nullfd, 2) < 0)
|
||||||
dup2(nullfd, 2) < 0)
|
return -1;
|
||||||
return -1;
|
close(nullfd);
|
||||||
close(nullfd);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
f = fork();
|
f = fork();
|
||||||
if (f < 0)
|
if (f < 0)
|
||||||
return -1;
|
return -1;
|
||||||
else if (f > 0)
|
else if (f > 0)
|
||||||
_exit(0);
|
_exit(0);
|
||||||
|
|
||||||
#ifdef HAVE_SETSID
|
#ifdef HAVE_SETSID
|
||||||
return setsid();
|
return setsid();
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
18
lib/dup2.c
18
lib/dup2.c
|
@ -8,18 +8,16 @@
|
||||||
|
|
||||||
int dup2(int oldfd, int newfd)
|
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) {
|
if (rv >= 0 && rv != newfd) {
|
||||||
rv = dup2(oldfd, newfd);
|
rv = dup2(oldfd, newfd);
|
||||||
close(nfd);
|
close(nfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,12 @@
|
||||||
|
|
||||||
void *xmalloc(size_t size)
|
void *xmalloc(size_t size)
|
||||||
{
|
{
|
||||||
void *p = malloc(size);
|
void *p = malloc(size);
|
||||||
|
|
||||||
if ( !p ) {
|
if (!p) {
|
||||||
fprintf(stderr, "Out of memory!\n");
|
fprintf(stderr, "Out of memory!\n");
|
||||||
exit(128);
|
exit(128);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,12 @@
|
||||||
|
|
||||||
char *xstrdup(const char *s)
|
char *xstrdup(const char *s)
|
||||||
{
|
{
|
||||||
char *p = strdup(s);
|
char *p = strdup(s);
|
||||||
|
|
||||||
if ( !p ) {
|
if (!p) {
|
||||||
fprintf(stderr, "Out of memory!\n");
|
fprintf(stderr, "Out of memory!\n");
|
||||||
exit(128);
|
exit(128);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#ifndef RECVFILE_H
|
#ifndef RECVFILE_H
|
||||||
#define RECVFILE_H
|
#define RECVFILE_H
|
||||||
|
|
||||||
void tftp_recvfile (int, const char *, const char *);
|
void tftp_recvfile(int, const char *, const char *);
|
||||||
void tftp_sendfile (int, const char *, const char *);
|
void tftp_sendfile(int, const char *, const char *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
1334
tftp/main.c
1334
tftp/main.c
File diff suppressed because it is too large
Load diff
625
tftp/tftp.c
625
tftp/tftp.c
|
@ -39,9 +39,8 @@
|
||||||
#ifndef lint
|
#ifndef lint
|
||||||
/* static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; */
|
/* 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 char rcsid[] = "$OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt Exp $"; */
|
||||||
static const char *rcsid UNUSED =
|
static const char *rcsid UNUSED = "tftp-hpa $Id$";
|
||||||
"tftp-hpa $Id$";
|
#endif /* not lint */
|
||||||
#endif /* not lint */
|
|
||||||
|
|
||||||
/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
|
/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
|
||||||
|
|
||||||
|
@ -50,18 +49,18 @@ static const char *rcsid UNUSED =
|
||||||
*/
|
*/
|
||||||
#include "extern.h"
|
#include "extern.h"
|
||||||
|
|
||||||
extern struct sockaddr_in peeraddr; /* filled in by main */
|
extern struct sockaddr_in peeraddr; /* filled in by main */
|
||||||
extern int f; /* the opened socket */
|
extern int f; /* the opened socket */
|
||||||
extern int trace;
|
extern int trace;
|
||||||
extern int verbose;
|
extern int verbose;
|
||||||
extern int rexmtval;
|
extern int rexmtval;
|
||||||
extern int maxtimeout;
|
extern int maxtimeout;
|
||||||
|
|
||||||
#define PKTSIZE SEGSIZE+4
|
#define PKTSIZE SEGSIZE+4
|
||||||
char ackbuf[PKTSIZE];
|
char ackbuf[PKTSIZE];
|
||||||
int timeout;
|
int timeout;
|
||||||
sigjmp_buf toplevel;
|
sigjmp_buf toplevel;
|
||||||
sigjmp_buf timeoutbuf;
|
sigjmp_buf timeoutbuf;
|
||||||
|
|
||||||
static void nak(int, const char *);
|
static void nak(int, const char *);
|
||||||
static int makerequest(int, const char *, struct tftphdr *, 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.
|
* Send the requested file.
|
||||||
*/
|
*/
|
||||||
void
|
void tftp_sendfile(int fd, const char *name, const char *mode)
|
||||||
tftp_sendfile(int fd, const char *name, const char *mode)
|
|
||||||
{
|
{
|
||||||
struct tftphdr *ap; /* data and ack packets */
|
struct tftphdr *ap; /* data and ack packets */
|
||||||
struct tftphdr *dp;
|
struct tftphdr *dp;
|
||||||
int n;
|
int n;
|
||||||
volatile int is_request;
|
volatile int is_request;
|
||||||
volatile u_short block;
|
volatile u_short block;
|
||||||
volatile int size, convert;
|
volatile int size, convert;
|
||||||
volatile off_t amount;
|
volatile off_t amount;
|
||||||
struct sockaddr_in from;
|
struct sockaddr_in from;
|
||||||
socklen_t fromlen;
|
socklen_t fromlen;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
u_short ap_opcode, ap_block;
|
u_short ap_opcode, ap_block;
|
||||||
|
|
||||||
startclock(); /* start stat's clock */
|
startclock(); /* start stat's clock */
|
||||||
dp = r_init(); /* reset fillbuf/read-ahead code */
|
dp = r_init(); /* reset fillbuf/read-ahead code */
|
||||||
ap = (struct tftphdr *)ackbuf;
|
ap = (struct tftphdr *)ackbuf;
|
||||||
convert = !strcmp(mode, "netascii");
|
convert = !strcmp(mode, "netascii");
|
||||||
file = fdopen(fd, convert ? "rt" : "rb");
|
file = fdopen(fd, convert ? "rt" : "rb");
|
||||||
block = 0;
|
block = 0;
|
||||||
is_request = 1; /* First packet is the actual WRQ */
|
is_request = 1; /* First packet is the actual WRQ */
|
||||||
amount = 0;
|
amount = 0;
|
||||||
|
|
||||||
bsd_signal(SIGALRM, timer);
|
bsd_signal(SIGALRM, timer);
|
||||||
do {
|
do {
|
||||||
if (is_request) {
|
if (is_request) {
|
||||||
size = makerequest(WRQ, name, dp, mode) - 4;
|
size = makerequest(WRQ, name, dp, mode) - 4;
|
||||||
} else {
|
} else {
|
||||||
/* size = read(fd, dp->th_data, SEGSIZE); */
|
/* size = read(fd, dp->th_data, SEGSIZE); */
|
||||||
size = readit(file, &dp, convert);
|
size = readit(file, &dp, convert);
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
nak(errno + 100, NULL);
|
nak(errno + 100, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dp->th_opcode = htons((u_short)DATA);
|
dp->th_opcode = htons((u_short) DATA);
|
||||||
dp->th_block = htons((u_short)block);
|
dp->th_block = htons((u_short) block);
|
||||||
}
|
}
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
(void) sigsetjmp(timeoutbuf,1);
|
(void)sigsetjmp(timeoutbuf, 1);
|
||||||
|
|
||||||
if (trace)
|
if (trace)
|
||||||
tpacket("sent", dp, size + 4);
|
tpacket("sent", dp, size + 4);
|
||||||
n = sendto(f, dp, size + 4, 0,
|
n = sendto(f, dp, size + 4, 0,
|
||||||
(struct sockaddr *)&peeraddr, sizeof(peeraddr));
|
(struct sockaddr *)&peeraddr, sizeof(peeraddr));
|
||||||
if (n != size + 4) {
|
if (n != size + 4) {
|
||||||
perror("tftp: sendto");
|
perror("tftp: sendto");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
read_ahead(file, convert);
|
read_ahead(file, convert);
|
||||||
for ( ; ; ) {
|
for (;;) {
|
||||||
alarm(rexmtval);
|
alarm(rexmtval);
|
||||||
do {
|
do {
|
||||||
fromlen = sizeof(from);
|
fromlen = sizeof(from);
|
||||||
n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
|
n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
|
||||||
(struct sockaddr *)&from, &fromlen);
|
(struct sockaddr *)&from, &fromlen);
|
||||||
} while (n <= 0);
|
} while (n <= 0);
|
||||||
alarm(0);
|
alarm(0);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
perror("tftp: recvfrom");
|
perror("tftp: recvfrom");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
peeraddr.sin_port = from.sin_port; /* added */
|
peeraddr.sin_port = from.sin_port; /* added */
|
||||||
if (trace)
|
if (trace)
|
||||||
tpacket("received", ap, n);
|
tpacket("received", ap, n);
|
||||||
/* should verify packet came from server */
|
/* should verify packet came from server */
|
||||||
ap_opcode = ntohs((u_short)ap->th_opcode);
|
ap_opcode = ntohs((u_short) ap->th_opcode);
|
||||||
ap_block = ntohs((u_short)ap->th_block);
|
ap_block = ntohs((u_short) ap->th_block);
|
||||||
if (ap_opcode == ERROR) {
|
if (ap_opcode == ERROR) {
|
||||||
printf("Error code %d: %s\n", ap_block,
|
printf("Error code %d: %s\n", ap_block, ap->th_msg);
|
||||||
ap->th_msg);
|
goto abort;
|
||||||
goto abort;
|
}
|
||||||
}
|
if (ap_opcode == ACK) {
|
||||||
if (ap_opcode == ACK) {
|
int j;
|
||||||
int j;
|
|
||||||
|
|
||||||
if (ap_block == block) {
|
if (ap_block == block) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* On an error, try to synchronize
|
/* On an error, try to synchronize
|
||||||
* both sides.
|
* both sides.
|
||||||
*/
|
*/
|
||||||
j = synchnet(f);
|
j = synchnet(f);
|
||||||
if (j && trace) {
|
if (j && trace) {
|
||||||
printf("discarded %d packets\n",
|
printf("discarded %d packets\n", j);
|
||||||
j);
|
}
|
||||||
}
|
/*
|
||||||
/*
|
* RFC1129/RFC1350: We MUST NOT re-send the DATA
|
||||||
* RFC1129/RFC1350: We MUST NOT re-send the DATA
|
* packet in response to an invalid ACK. Doing so
|
||||||
* packet in response to an invalid ACK. Doing so
|
* would cause the Sorcerer's Apprentice bug.
|
||||||
* would cause the Sorcerer's Apprentice bug.
|
*/
|
||||||
*/
|
}
|
||||||
}
|
}
|
||||||
}
|
if (!is_request)
|
||||||
if ( !is_request )
|
amount += size;
|
||||||
amount += size;
|
is_request = 0;
|
||||||
is_request = 0;
|
block++;
|
||||||
block++;
|
} while (size == SEGSIZE || block == 1);
|
||||||
} while (size == SEGSIZE || block == 1);
|
abort:
|
||||||
abort:
|
fclose(file);
|
||||||
fclose(file);
|
stopclock();
|
||||||
stopclock();
|
if (amount > 0)
|
||||||
if (amount > 0)
|
printstats("Sent", amount);
|
||||||
printstats("Sent", amount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Receive a file.
|
* Receive a file.
|
||||||
*/
|
*/
|
||||||
void
|
void tftp_recvfile(int fd, const char *name, const char *mode)
|
||||||
tftp_recvfile(int fd, const char *name, const char *mode)
|
|
||||||
{
|
{
|
||||||
struct tftphdr *ap;
|
struct tftphdr *ap;
|
||||||
struct tftphdr *dp;
|
struct tftphdr *dp;
|
||||||
int n;
|
int n;
|
||||||
volatile u_short block;
|
volatile u_short block;
|
||||||
volatile int size, firsttrip;
|
volatile int size, firsttrip;
|
||||||
volatile unsigned long amount;
|
volatile unsigned long amount;
|
||||||
struct sockaddr_in from;
|
struct sockaddr_in from;
|
||||||
socklen_t fromlen;
|
socklen_t fromlen;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
volatile int convert; /* true if converting crlf -> lf */
|
volatile int convert; /* true if converting crlf -> lf */
|
||||||
u_short dp_opcode, dp_block;
|
u_short dp_opcode, dp_block;
|
||||||
|
|
||||||
startclock();
|
startclock();
|
||||||
dp = w_init();
|
dp = w_init();
|
||||||
ap = (struct tftphdr *)ackbuf;
|
ap = (struct tftphdr *)ackbuf;
|
||||||
convert = !strcmp(mode, "netascii");
|
convert = !strcmp(mode, "netascii");
|
||||||
file = fdopen(fd, convert ?"wt":"wb");
|
file = fdopen(fd, convert ? "wt" : "wb");
|
||||||
block = 1;
|
block = 1;
|
||||||
firsttrip = 1;
|
firsttrip = 1;
|
||||||
amount = 0;
|
amount = 0;
|
||||||
|
|
||||||
bsd_signal(SIGALRM, timer);
|
bsd_signal(SIGALRM, timer);
|
||||||
do {
|
do {
|
||||||
if (firsttrip) {
|
if (firsttrip) {
|
||||||
size = makerequest(RRQ, name, ap, mode);
|
size = makerequest(RRQ, name, ap, mode);
|
||||||
firsttrip = 0;
|
firsttrip = 0;
|
||||||
} else {
|
} else {
|
||||||
ap->th_opcode = htons((u_short)ACK);
|
ap->th_opcode = htons((u_short) ACK);
|
||||||
ap->th_block = htons((u_short)block);
|
ap->th_block = htons((u_short) block);
|
||||||
size = 4;
|
size = 4;
|
||||||
block++;
|
block++;
|
||||||
}
|
}
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
(void) sigsetjmp(timeoutbuf,1);
|
(void)sigsetjmp(timeoutbuf, 1);
|
||||||
send_ack:
|
send_ack:
|
||||||
if (trace)
|
if (trace)
|
||||||
tpacket("sent", ap, size);
|
tpacket("sent", ap, size);
|
||||||
if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr,
|
if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr,
|
||||||
sizeof(peeraddr)) != size) {
|
sizeof(peeraddr)) != size) {
|
||||||
alarm(0);
|
alarm(0);
|
||||||
perror("tftp: sendto");
|
perror("tftp: sendto");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
write_behind(file, convert);
|
write_behind(file, convert);
|
||||||
for ( ; ; ) {
|
for (;;) {
|
||||||
alarm(rexmtval);
|
alarm(rexmtval);
|
||||||
do {
|
do {
|
||||||
fromlen = sizeof(from);
|
fromlen = sizeof(from);
|
||||||
n = recvfrom(f, dp, PKTSIZE, 0,
|
n = recvfrom(f, dp, PKTSIZE, 0,
|
||||||
(struct sockaddr *)&from, &fromlen);
|
(struct sockaddr *)&from, &fromlen);
|
||||||
} while (n <= 0);
|
} while (n <= 0);
|
||||||
alarm(0);
|
alarm(0);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
perror("tftp: recvfrom");
|
perror("tftp: recvfrom");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
peeraddr.sin_port = from.sin_port; /* added */
|
peeraddr.sin_port = from.sin_port; /* added */
|
||||||
if (trace)
|
if (trace)
|
||||||
tpacket("received", dp, n);
|
tpacket("received", dp, n);
|
||||||
/* should verify client address */
|
/* should verify client address */
|
||||||
dp_opcode = ntohs((u_short)dp->th_opcode);
|
dp_opcode = ntohs((u_short) dp->th_opcode);
|
||||||
dp_block = ntohs((u_short)dp->th_block);
|
dp_block = ntohs((u_short) dp->th_block);
|
||||||
if (dp_opcode == ERROR) {
|
if (dp_opcode == ERROR) {
|
||||||
printf("Error code %d: %s\n", dp_block, dp->th_msg);
|
printf("Error code %d: %s\n", dp_block, dp->th_msg);
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
if (dp_opcode == DATA) {
|
if (dp_opcode == DATA) {
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
if (dp_block == block) {
|
if (dp_block == block) {
|
||||||
break; /* have next packet */
|
break; /* have next packet */
|
||||||
}
|
}
|
||||||
/* On an error, try to synchronize
|
/* On an error, try to synchronize
|
||||||
* both sides.
|
* both sides.
|
||||||
*/
|
*/
|
||||||
j = synchnet(f);
|
j = synchnet(f);
|
||||||
if (j && trace) {
|
if (j && trace) {
|
||||||
printf("discarded %d packets\n", j);
|
printf("discarded %d packets\n", j);
|
||||||
}
|
}
|
||||||
if (dp_block == (block-1)) {
|
if (dp_block == (block - 1)) {
|
||||||
goto send_ack; /* resend ack */
|
goto send_ack; /* resend ack */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* size = write(fd, dp->th_data, n - 4); */
|
/* size = write(fd, dp->th_data, n - 4); */
|
||||||
size = writeit(file, &dp, n - 4, convert);
|
size = writeit(file, &dp, n - 4, convert);
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
nak(errno + 100, NULL);
|
nak(errno + 100, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
amount += size;
|
amount += size;
|
||||||
} while (size == SEGSIZE);
|
} while (size == SEGSIZE);
|
||||||
abort: /* ok to ack, since user */
|
abort: /* ok to ack, since user */
|
||||||
ap->th_opcode = htons((u_short)ACK); /* has seen err msg */
|
ap->th_opcode = htons((u_short) ACK); /* has seen err msg */
|
||||||
ap->th_block = htons((u_short)block);
|
ap->th_block = htons((u_short) block);
|
||||||
(void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,
|
(void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,
|
||||||
sizeof(peeraddr));
|
sizeof(peeraddr));
|
||||||
write_behind(file, convert); /* flush last buffer */
|
write_behind(file, convert); /* flush last buffer */
|
||||||
fclose(file);
|
fclose(file);
|
||||||
stopclock();
|
stopclock();
|
||||||
if (amount > 0)
|
if (amount > 0)
|
||||||
printstats("Received", amount);
|
printstats("Received", amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
makerequest(int request, const char *name,
|
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);
|
tp->th_opcode = htons((u_short) request);
|
||||||
cp = (char *) &(tp->th_stuff);
|
cp = (char *)&(tp->th_stuff);
|
||||||
strcpy(cp, name);
|
strcpy(cp, name);
|
||||||
cp += strlen(name);
|
cp += strlen(name);
|
||||||
*cp++ = '\0';
|
*cp++ = '\0';
|
||||||
strcpy(cp, mode);
|
strcpy(cp, mode);
|
||||||
cp += strlen(mode);
|
cp += strlen(mode);
|
||||||
*cp++ = '\0';
|
*cp++ = '\0';
|
||||||
return (cp - (char *)tp);
|
return (cp - (char *)tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * const errmsgs[] =
|
static const char *const errmsgs[] = {
|
||||||
{
|
"Undefined error code", /* 0 - EUNDEF */
|
||||||
"Undefined error code", /* 0 - EUNDEF */
|
"File not found", /* 1 - ENOTFOUND */
|
||||||
"File not found", /* 1 - ENOTFOUND */
|
"Access denied", /* 2 - EACCESS */
|
||||||
"Access denied", /* 2 - EACCESS */
|
"Disk full or allocation exceeded", /* 3 - ENOSPACE */
|
||||||
"Disk full or allocation exceeded", /* 3 - ENOSPACE */
|
"Illegal TFTP operation", /* 4 - EBADOP */
|
||||||
"Illegal TFTP operation", /* 4 - EBADOP */
|
"Unknown transfer ID", /* 5 - EBADID */
|
||||||
"Unknown transfer ID", /* 5 - EBADID */
|
"File already exists", /* 6 - EEXISTS */
|
||||||
"File already exists", /* 6 - EEXISTS */
|
"No such user", /* 7 - ENOUSER */
|
||||||
"No such user", /* 7 - ENOUSER */
|
"Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */
|
||||||
"Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ERR_CNT (sizeof(errmsgs)/sizeof(const char *))
|
#define ERR_CNT (sizeof(errmsgs)/sizeof(const char *))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -327,121 +322,115 @@ static const char * const errmsgs[] =
|
||||||
* standard TFTP codes, or a UNIX errno
|
* standard TFTP codes, or a UNIX errno
|
||||||
* offset by 100.
|
* offset by 100.
|
||||||
*/
|
*/
|
||||||
static void
|
static void nak(int error, const char *msg)
|
||||||
nak(int error, const char *msg)
|
|
||||||
{
|
{
|
||||||
struct tftphdr *tp;
|
struct tftphdr *tp;
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
tp = (struct tftphdr *)ackbuf;
|
tp = (struct tftphdr *)ackbuf;
|
||||||
tp->th_opcode = htons((u_short)ERROR);
|
tp->th_opcode = htons((u_short) ERROR);
|
||||||
tp->th_code = htons((u_short)error);
|
tp->th_code = htons((u_short) error);
|
||||||
|
|
||||||
if ( error >= 100 ) {
|
if (error >= 100) {
|
||||||
/* This is a Unix errno+100 */
|
/* This is a Unix errno+100 */
|
||||||
if ( !msg )
|
if (!msg)
|
||||||
msg = strerror(error - 100);
|
msg = strerror(error - 100);
|
||||||
error = EUNDEF;
|
error = EUNDEF;
|
||||||
} else {
|
} else {
|
||||||
if ( (unsigned)error >= ERR_CNT )
|
if ((unsigned)error >= ERR_CNT)
|
||||||
error = EUNDEF;
|
error = EUNDEF;
|
||||||
|
|
||||||
if ( !msg )
|
if (!msg)
|
||||||
msg = errmsgs[error];
|
msg = errmsgs[error];
|
||||||
}
|
}
|
||||||
|
|
||||||
tp->th_code = htons((u_short)error);
|
tp->th_code = htons((u_short) error);
|
||||||
|
|
||||||
length = strlen(msg)+1;
|
length = strlen(msg) + 1;
|
||||||
memcpy(tp->th_msg, msg, length);
|
memcpy(tp->th_msg, msg, length);
|
||||||
length += 4; /* Add space for header */
|
length += 4; /* Add space for header */
|
||||||
|
|
||||||
if (trace)
|
if (trace)
|
||||||
tpacket("sent", tp, length);
|
tpacket("sent", tp, length);
|
||||||
if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
|
if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
|
||||||
sizeof(peeraddr)) != length)
|
sizeof(peeraddr)) != length)
|
||||||
perror("nak");
|
perror("nak");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void tpacket(const char *s, struct tftphdr *tp, int n)
|
||||||
tpacket(const char *s, struct tftphdr *tp, int n)
|
|
||||||
{
|
{
|
||||||
static const char *opcodes[] =
|
static const char *opcodes[] =
|
||||||
{ "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
|
{ "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
|
||||||
char *cp, *file;
|
char *cp, *file;
|
||||||
u_short op = ntohs((u_short)tp->th_opcode);
|
u_short op = ntohs((u_short) tp->th_opcode);
|
||||||
|
|
||||||
if (op < RRQ || op > ERROR)
|
if (op < RRQ || op > ERROR)
|
||||||
printf("%s opcode=%x ", s, op);
|
printf("%s opcode=%x ", s, op);
|
||||||
else
|
else
|
||||||
printf("%s %s ", s, opcodes[op]);
|
printf("%s %s ", s, opcodes[op]);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
|
||||||
case RRQ:
|
case RRQ:
|
||||||
case WRQ:
|
case WRQ:
|
||||||
n -= 2;
|
n -= 2;
|
||||||
file = cp = (char *) &(tp->th_stuff);
|
file = cp = (char *)&(tp->th_stuff);
|
||||||
cp = strchr(cp, '\0');
|
cp = strchr(cp, '\0');
|
||||||
printf("<file=%s, mode=%s>\n", file, cp + 1);
|
printf("<file=%s, mode=%s>\n", file, cp + 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DATA:
|
case DATA:
|
||||||
printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
|
printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACK:
|
case ACK:
|
||||||
printf("<block=%d>\n", ntohs(tp->th_block));
|
printf("<block=%d>\n", ntohs(tp->th_block));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ERROR:
|
case ERROR:
|
||||||
printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
|
printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval tstart;
|
struct timeval tstart;
|
||||||
struct timeval tstop;
|
struct timeval tstop;
|
||||||
|
|
||||||
static void
|
static void startclock(void)
|
||||||
startclock(void)
|
|
||||||
{
|
{
|
||||||
(void)gettimeofday(&tstart, NULL);
|
(void)gettimeofday(&tstart, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void stopclock(void)
|
||||||
stopclock(void)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
(void)gettimeofday(&tstop, NULL);
|
(void)gettimeofday(&tstop, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void printstats(const char *direction, unsigned long amount)
|
||||||
printstats(const char *direction, unsigned long amount)
|
|
||||||
{
|
{
|
||||||
double delta;
|
double delta;
|
||||||
|
|
||||||
delta = (tstop.tv_sec+(tstop.tv_usec/100000.0)) -
|
delta = (tstop.tv_sec + (tstop.tv_usec / 100000.0)) -
|
||||||
(tstart.tv_sec+(tstart.tv_usec/100000.0));
|
(tstart.tv_sec + (tstart.tv_usec / 100000.0));
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
|
printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
|
||||||
printf(" [%.0f bit/s]", (amount*8.)/delta);
|
printf(" [%.0f bit/s]", (amount * 8.) / delta);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void timer(int sig)
|
||||||
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;
|
timeout += rexmtval;
|
||||||
if (timeout >= maxtimeout) {
|
if (timeout >= maxtimeout) {
|
||||||
printf("Transfer timed out.\n");
|
printf("Transfer timed out.\n");
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
siglongjmp(toplevel, -1);
|
siglongjmp(toplevel, -1);
|
||||||
}
|
}
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
siglongjmp(timeoutbuf, 1);
|
siglongjmp(timeoutbuf, 1);
|
||||||
}
|
}
|
||||||
|
|
47
tftpd/misc.c
47
tftpd/misc.c
|
@ -14,7 +14,7 @@
|
||||||
* Minor help routines.
|
* Minor help routines.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h" /* Must be included first! */
|
#include "config.h" /* Must be included first! */
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include "tftpd.h"
|
#include "tftpd.h"
|
||||||
|
|
||||||
|
@ -22,19 +22,19 @@
|
||||||
* Set the signal handler and flags. Basically a user-friendly
|
* Set the signal handler and flags. Basically a user-friendly
|
||||||
* wrapper around sigaction().
|
* 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);
|
memset(&sa, 0, sizeof sa);
|
||||||
sa.sa_handler = handler;
|
sa.sa_handler = handler;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_flags = flags;
|
sa.sa_flags = flags;
|
||||||
|
|
||||||
if ( sigaction(signum, &sa, NULL) ) {
|
if (sigaction(signum, &sa, NULL)) {
|
||||||
syslog(LOG_ERR, "sigaction: %m");
|
syslog(LOG_ERR, "sigaction: %m");
|
||||||
exit(EX_OSERR);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -42,14 +42,14 @@ void set_signal(int signum, void (*handler)(int), int flags)
|
||||||
*/
|
*/
|
||||||
void *tfmalloc(size_t size)
|
void *tfmalloc(size_t size)
|
||||||
{
|
{
|
||||||
void *p = malloc(size);
|
void *p = malloc(size);
|
||||||
|
|
||||||
if ( !p ) {
|
if (!p) {
|
||||||
syslog(LOG_ERR, "malloc: %m");
|
syslog(LOG_ERR, "malloc: %m");
|
||||||
exit(EX_OSERR);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -57,13 +57,12 @@ void *tfmalloc(size_t size)
|
||||||
*/
|
*/
|
||||||
char *tfstrdup(const char *str)
|
char *tfstrdup(const char *str)
|
||||||
{
|
{
|
||||||
char *p = strdup(str);
|
char *p = strdup(str);
|
||||||
|
|
||||||
if ( !p ) {
|
if (!p) {
|
||||||
syslog(LOG_ERR, "strdup: %m");
|
syslog(LOG_ERR, "strdup: %m");
|
||||||
exit(EX_OSERR);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
218
tftpd/recvfrom.c
218
tftpd/recvfrom.c
|
@ -17,11 +17,11 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h" /* Must be included first! */
|
#include "config.h" /* Must be included first! */
|
||||||
#include "recvfrom.h"
|
#include "recvfrom.h"
|
||||||
#include "common/tftpsubs.h"
|
#include "common/tftpsubs.h"
|
||||||
#ifdef HAVE_MACHINE_PARAM_H
|
#ifdef HAVE_MACHINE_PARAM_H
|
||||||
#include <machine/param.h> /* Needed on some versions of FreeBSD */
|
#include <machine/param.h> /* Needed on some versions of FreeBSD */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_RECVMSG) && defined(HAVE_MSGHDR_MSG_CONTROL)
|
#if defined(HAVE_RECVMSG) && defined(HAVE_MSGHDR_MSG_CONTROL)
|
||||||
|
@ -33,12 +33,12 @@
|
||||||
# ifdef __linux__
|
# ifdef __linux__
|
||||||
/* Assume this version of glibc simply lacks the definition */
|
/* Assume this version of glibc simply lacks the definition */
|
||||||
struct in_pktinfo {
|
struct in_pktinfo {
|
||||||
int ipi_ifindex;
|
int ipi_ifindex;
|
||||||
struct in_addr ipi_spec_dst;
|
struct in_addr ipi_spec_dst;
|
||||||
struct in_addr ipi_addr;
|
struct in_addr ipi_addr;
|
||||||
};
|
};
|
||||||
# else
|
# else
|
||||||
# undef IP_PKTINFO /* No definition, no way to get it */
|
# undef IP_PKTINFO /* No definition, no way to get it */
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,141 +57,141 @@ struct in_pktinfo {
|
||||||
*/
|
*/
|
||||||
static int address_is_local(const struct sockaddr_in *addr)
|
static int address_is_local(const struct sockaddr_in *addr)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
int sockfd = -1;
|
int sockfd = -1;
|
||||||
int e;
|
int e;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
|
|
||||||
/* Multicast or universal broadcast address? */
|
/* Multicast or universal broadcast address? */
|
||||||
if (ntohl(addr->sin_addr.s_addr) >= (224UL << 24))
|
if (ntohl(addr->sin_addr.s_addr) >= (224UL << 24))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sockfd = socket(PF_INET, SOCK_DGRAM, 0);
|
sockfd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
if (sockfd < 0)
|
if (sockfd < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (connect(sockfd, (const struct sockaddr *)addr, sizeof *addr))
|
if (connect(sockfd, (const struct sockaddr *)addr, sizeof *addr))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
addrlen = sizeof sin;
|
addrlen = sizeof sin;
|
||||||
if (getsockname(sockfd, (struct sockaddr *)&sin, &addrlen))
|
if (getsockname(sockfd, (struct sockaddr *)&sin, &addrlen))
|
||||||
goto err;
|
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:
|
err:
|
||||||
e = errno;
|
e = errno;
|
||||||
|
|
||||||
if (sockfd >= 0)
|
if (sockfd >= 0)
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
|
|
||||||
errno = e;
|
errno = e;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
||||||
struct sockaddr *from, socklen_t *fromlen,
|
struct sockaddr *from, socklen_t * fromlen,
|
||||||
struct sockaddr_in *myaddr)
|
struct sockaddr_in *myaddr)
|
||||||
{
|
{
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
int n;
|
int n;
|
||||||
struct cmsghdr *cmptr;
|
struct cmsghdr *cmptr;
|
||||||
union {
|
union {
|
||||||
struct cmsghdr cm;
|
struct cmsghdr cm;
|
||||||
#ifdef IP_PKTINFO
|
#ifdef IP_PKTINFO
|
||||||
char control[CMSG_SPACE(sizeof(struct in_addr)) +
|
char control[CMSG_SPACE(sizeof(struct in_addr)) +
|
||||||
CMSG_SPACE(sizeof(struct in_pktinfo))];
|
CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||||
#else
|
#else
|
||||||
char control[CMSG_SPACE(sizeof(struct in_addr))];
|
char control[CMSG_SPACE(sizeof(struct in_addr))];
|
||||||
#endif
|
#endif
|
||||||
} control_un;
|
} control_un;
|
||||||
int on = 1;
|
int on = 1;
|
||||||
#ifdef IP_PKTINFO
|
#ifdef IP_PKTINFO
|
||||||
struct in_pktinfo pktinfo;
|
struct in_pktinfo pktinfo;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Try to enable getting the return address */
|
/* Try to enable getting the return address */
|
||||||
#ifdef IP_RECVDSTADDR
|
#ifdef IP_RECVDSTADDR
|
||||||
setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
|
setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
|
||||||
#endif
|
#endif
|
||||||
#ifdef IP_PKTINFO
|
#ifdef IP_PKTINFO
|
||||||
setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
|
setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */
|
bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */
|
||||||
msg.msg_control = control_un.control;
|
msg.msg_control = control_un.control;
|
||||||
msg.msg_controllen = sizeof(control_un.control);
|
msg.msg_controllen = sizeof(control_un.control);
|
||||||
msg.msg_flags = 0;
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
msg.msg_name = from;
|
msg.msg_name = from;
|
||||||
msg.msg_namelen = *fromlen;
|
msg.msg_namelen = *fromlen;
|
||||||
iov.iov_base = buf;
|
iov.iov_base = buf;
|
||||||
iov.iov_len = len;
|
iov.iov_len = len;
|
||||||
msg.msg_iov = &iov;
|
msg.msg_iov = &iov;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
if ( (n = recvmsg(s, &msg, flags)) < 0 )
|
if ((n = recvmsg(s, &msg, flags)) < 0)
|
||||||
return n; /* Error */
|
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));
|
bzero(myaddr, sizeof(struct sockaddr_in));
|
||||||
myaddr->sin_family = AF_INET;
|
myaddr->sin_family = AF_INET;
|
||||||
|
|
||||||
if ( msg.msg_controllen < sizeof(struct cmsghdr) ||
|
myaddr->sin_port = htons(IPPORT_TFTP);
|
||||||
(msg.msg_flags & MSG_CTRUNC) )
|
bzero(&myaddr->sin_addr, sizeof(myaddr->sin_addr));
|
||||||
return n; /* No information available */
|
|
||||||
|
|
||||||
for ( cmptr = CMSG_FIRSTHDR(&msg) ; cmptr != NULL ;
|
return recvfrom(s, buf, len, flags, from, fromlen);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,5 +19,5 @@
|
||||||
|
|
||||||
int
|
int
|
||||||
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
||||||
struct sockaddr *from, socklen_t *fromlen,
|
struct sockaddr *from, socklen_t * fromlen,
|
||||||
struct sockaddr_in *myaddr);
|
struct sockaddr_in *myaddr);
|
||||||
|
|
651
tftpd/remap.c
651
tftpd/remap.c
|
@ -14,7 +14,7 @@
|
||||||
* Perform regular-expression based filename remapping.
|
* Perform regular-expression based filename remapping.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h" /* Must be included first! */
|
#include "config.h" /* Must be included first! */
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
@ -23,123 +23,131 @@
|
||||||
#include "remap.h"
|
#include "remap.h"
|
||||||
|
|
||||||
#define DEADMAN_MAX_STEPS 1024 /* Timeout after this many steps */
|
#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_REWRITE 0x01 /* This is a rewrite rule */
|
||||||
#define RULE_GLOBAL 0x02 /* Global rule (repeat until no match) */
|
#define RULE_GLOBAL 0x02 /* Global rule (repeat until no match) */
|
||||||
#define RULE_EXIT 0x04 /* Exit after matching this rule */
|
#define RULE_EXIT 0x04 /* Exit after matching this rule */
|
||||||
#define RULE_RESTART 0x08 /* Restart at the top 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_ABORT 0x10 /* Terminate processing with an error */
|
||||||
#define RULE_GETONLY 0x20 /* Applicable to GET only */
|
#define RULE_GETONLY 0x20 /* Applicable to GET only */
|
||||||
#define RULE_PUTONLY 0x40 /* Applicable to PUT only */
|
#define RULE_PUTONLY 0x40 /* Applicable to PUT only */
|
||||||
#define RULE_INVERSE 0x80 /* Execute if regex *doesn't* match */
|
#define RULE_INVERSE 0x80 /* Execute if regex *doesn't* match */
|
||||||
|
|
||||||
struct rule {
|
struct rule {
|
||||||
struct rule *next;
|
struct rule *next;
|
||||||
int nrule;
|
int nrule;
|
||||||
int rule_flags;
|
int rule_flags;
|
||||||
regex_t rx;
|
regex_t rx;
|
||||||
const char *pattern;
|
const char *pattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int xform_null(int c)
|
static int xform_null(int c)
|
||||||
{
|
{
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xform_toupper(int c)
|
static int xform_toupper(int c)
|
||||||
{
|
{
|
||||||
return toupper(c);
|
return toupper(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xform_tolower(int c)
|
static int xform_tolower(int c)
|
||||||
{
|
{
|
||||||
return tolower(c);
|
return tolower(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do \-substitution. Call with string == NULL to get length only. */
|
/* Do \-substitution. Call with string == NULL to get length only. */
|
||||||
static int genmatchstring(char *string, const char *pattern, const char *input,
|
static int genmatchstring(char *string, const char *pattern,
|
||||||
const regmatch_t *pmatch, match_pattern_callback macrosub)
|
const char *input, const regmatch_t * pmatch,
|
||||||
|
match_pattern_callback macrosub)
|
||||||
{
|
{
|
||||||
int (*xform)(int) = xform_null;
|
int (*xform) (int) = xform_null;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int n, mlen, sublen;
|
int n, mlen, sublen;
|
||||||
int endbytes;
|
int endbytes;
|
||||||
|
|
||||||
/* Get section before match; note pmatch[0] is the whole match */
|
/* Get section before match; note pmatch[0] is the whole match */
|
||||||
endbytes = strlen(input) - pmatch[0].rm_eo;
|
endbytes = strlen(input) - pmatch[0].rm_eo;
|
||||||
len = pmatch[0].rm_so + endbytes;
|
len = pmatch[0].rm_so + endbytes;
|
||||||
if ( string ) {
|
if (string) {
|
||||||
memcpy(string, input, pmatch[0].rm_so);
|
memcpy(string, input, pmatch[0].rm_so);
|
||||||
string += 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++;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy section after match */
|
/* Transform matched section */
|
||||||
if ( string ) {
|
while (*pattern) {
|
||||||
memcpy(string, input+pmatch[0].rm_eo, endbytes);
|
mlen = 0;
|
||||||
string[endbytes] = '\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)
|
static int readescstring(char *buf, char **str)
|
||||||
{
|
{
|
||||||
char *p = *str;
|
char *p = *str;
|
||||||
int wasbs = 0, len = 0;
|
int wasbs = 0, len = 0;
|
||||||
|
|
||||||
while ( *p && isspace(*p) )
|
while (*p && isspace(*p))
|
||||||
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';
|
*buf = '\0';
|
||||||
*str = p;
|
*str = p;
|
||||||
return 0;
|
return len;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse a line into a set of instructions */
|
/* Parse a line into a set of instructions */
|
||||||
static int parseline(char *line, struct rule *r, int lineno)
|
static int parseline(char *line, struct rule *r, int lineno)
|
||||||
{
|
{
|
||||||
char buffer[MAXLINE];
|
char buffer[MAXLINE];
|
||||||
char *p;
|
char *p;
|
||||||
int rv;
|
int rv;
|
||||||
int rxflags = REG_EXTENDED;
|
int rxflags = REG_EXTENDED;
|
||||||
static int nrule;
|
static int nrule;
|
||||||
|
|
||||||
memset(r, 0, sizeof *r);
|
memset(r, 0, sizeof *r);
|
||||||
r->nrule = nrule;
|
r->nrule = nrule;
|
||||||
|
|
||||||
if ( !readescstring(buffer, &line) )
|
if (!readescstring(buffer, &line))
|
||||||
return 0; /* No rule found */
|
return 0; /* No rule found */
|
||||||
|
|
||||||
for ( p = buffer ; *p ; p++ ) {
|
for (p = buffer; *p; p++) {
|
||||||
switch(*p) {
|
switch (*p) {
|
||||||
case 'r':
|
case 'r':
|
||||||
r->rule_flags |= RULE_REWRITE;
|
r->rule_flags |= RULE_REWRITE;
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
r->rule_flags |= RULE_GLOBAL;
|
r->rule_flags |= RULE_GLOBAL;
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
r->rule_flags |= RULE_EXIT;
|
r->rule_flags |= RULE_EXIT;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
r->rule_flags |= RULE_RESTART;
|
r->rule_flags |= RULE_RESTART;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
r->rule_flags |= RULE_ABORT;
|
r->rule_flags |= RULE_ABORT;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
rxflags |= REG_ICASE;
|
rxflags |= REG_ICASE;
|
||||||
break;
|
break;
|
||||||
case 'G':
|
case 'G':
|
||||||
r->rule_flags |= RULE_GETONLY;
|
r->rule_flags |= RULE_GETONLY;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
r->rule_flags |= RULE_PUTONLY;
|
r->rule_flags |= RULE_PUTONLY;
|
||||||
break;
|
break;
|
||||||
case '~':
|
case '~':
|
||||||
r->rule_flags |= RULE_INVERSE;
|
r->rule_flags |= RULE_INVERSE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
syslog(LOG_ERR, "Remap command \"%s\" on line %d contains invalid char \"%c\"",
|
syslog(LOG_ERR,
|
||||||
buffer, lineno, *p);
|
"Remap command \"%s\" on line %d contains invalid char \"%c\"",
|
||||||
return -1; /* Error */
|
buffer, lineno, *p);
|
||||||
break;
|
return -1; /* Error */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* RULE_GLOBAL only applies when RULE_REWRITE specified */
|
/* RULE_GLOBAL only applies when RULE_REWRITE specified */
|
||||||
if ( !(r->rule_flags & RULE_REWRITE) )
|
if (!(r->rule_flags & RULE_REWRITE))
|
||||||
r->rule_flags &= ~RULE_GLOBAL;
|
r->rule_flags &= ~RULE_GLOBAL;
|
||||||
|
|
||||||
if ( (r->rule_flags & (RULE_INVERSE|RULE_REWRITE)) ==
|
if ((r->rule_flags & (RULE_INVERSE | RULE_REWRITE)) ==
|
||||||
(RULE_INVERSE|RULE_REWRITE) ) {
|
(RULE_INVERSE | RULE_REWRITE)) {
|
||||||
syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n", lineno, line);
|
syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n",
|
||||||
return -1; /* Error */
|
lineno, line);
|
||||||
}
|
return -1; /* Error */
|
||||||
|
}
|
||||||
|
|
||||||
/* Read and compile the regex */
|
/* Read and compile the regex */
|
||||||
if ( !readescstring(buffer, &line) ) {
|
if (!readescstring(buffer, &line)) {
|
||||||
syslog(LOG_ERR, "No regex on remap line %d: %s\n", lineno, line);
|
syslog(LOG_ERR, "No regex on remap line %d: %s\n", lineno, line);
|
||||||
return -1; /* Error */
|
return -1; /* Error */
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (rv = regcomp(&r->rx, buffer, rxflags)) != 0 ) {
|
if ((rv = regcomp(&r->rx, buffer, rxflags)) != 0) {
|
||||||
char errbuf[BUFSIZ];
|
char errbuf[BUFSIZ];
|
||||||
regerror(rv, &r->rx, errbuf, BUFSIZ);
|
regerror(rv, &r->rx, errbuf, BUFSIZ);
|
||||||
syslog(LOG_ERR, "Bad regex in remap line %d: %s\n", lineno, errbuf);
|
syslog(LOG_ERR, "Bad regex in remap line %d: %s\n", lineno,
|
||||||
return -1; /* Error */
|
errbuf);
|
||||||
}
|
return -1; /* Error */
|
||||||
|
}
|
||||||
|
|
||||||
/* Read the rewrite pattern, if any */
|
/* Read the rewrite pattern, if any */
|
||||||
if ( readescstring(buffer, &line) ) {
|
if (readescstring(buffer, &line)) {
|
||||||
r->pattern = tfstrdup(buffer);
|
r->pattern = tfstrdup(buffer);
|
||||||
} else {
|
} else {
|
||||||
r->pattern = "";
|
r->pattern = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
nrule++;
|
nrule++;
|
||||||
return 1; /* Rule found */
|
return 1; /* Rule found */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read a rule file */
|
/* Read a rule file */
|
||||||
struct rule *parserulefile(FILE *f)
|
struct rule *parserulefile(FILE * f)
|
||||||
{
|
{
|
||||||
char line[MAXLINE];
|
char line[MAXLINE];
|
||||||
struct rule *first_rule = NULL;
|
struct rule *first_rule = NULL;
|
||||||
struct rule **last_rule = &first_rule;
|
struct rule **last_rule = &first_rule;
|
||||||
struct rule *this_rule = tfmalloc(sizeof(struct rule));
|
struct rule *this_rule = tfmalloc(sizeof(struct rule));
|
||||||
int rv;
|
int rv;
|
||||||
int lineno = 0;
|
int lineno = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
while ( lineno++, fgets(line, MAXLINE, f) ) {
|
while (lineno++, fgets(line, MAXLINE, f)) {
|
||||||
rv = parseline(line, this_rule, lineno);
|
rv = parseline(line, this_rule, lineno);
|
||||||
if ( rv < 0 )
|
if (rv < 0)
|
||||||
err = 1;
|
err = 1;
|
||||||
if ( rv > 0 ) {
|
if (rv > 0) {
|
||||||
*last_rule = this_rule;
|
*last_rule = this_rule;
|
||||||
last_rule = &this_rule->next;
|
last_rule = &this_rule->next;
|
||||||
this_rule = tfmalloc(sizeof(struct rule));
|
this_rule = tfmalloc(sizeof(struct rule));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
free(this_rule); /* Last one is always unused */
|
free(this_rule); /* Last one is always unused */
|
||||||
|
|
||||||
if ( err ) {
|
if (err) {
|
||||||
/* Bail on error, we have already logged an error message */
|
/* Bail on error, we have already logged an error message */
|
||||||
exit(EX_CONFIG);
|
exit(EX_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
return first_rule;
|
return first_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Destroy a rule file data structure */
|
/* Destroy a rule file data structure */
|
||||||
void freerules(struct rule *r)
|
void freerules(struct rule *r)
|
||||||
{
|
{
|
||||||
struct rule *next;
|
struct rule *next;
|
||||||
|
|
||||||
while ( r ) {
|
while (r) {
|
||||||
next = r->next;
|
next = r->next;
|
||||||
|
|
||||||
regfree(&r->rx);
|
regfree(&r->rx);
|
||||||
|
|
||||||
/* "" patterns aren't allocated by malloc() */
|
/* "" patterns aren't allocated by malloc() */
|
||||||
if ( r->pattern && *r->pattern )
|
if (r->pattern && *r->pattern)
|
||||||
free((void *)r->pattern);
|
free((void *)r->pattern);
|
||||||
|
|
||||||
free(r);
|
free(r);
|
||||||
|
|
||||||
r = next;
|
r = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Execute a rule set on a string; returns a malloc'd new string. */
|
/* Execute a rule set on a string; returns a malloc'd new string. */
|
||||||
char *rewrite_string(const char *input, const struct rule *rules,
|
char *rewrite_string(const char *input, const struct rule *rules,
|
||||||
int is_put, match_pattern_callback macrosub,
|
int is_put, match_pattern_callback macrosub,
|
||||||
const char **errmsg)
|
const char **errmsg)
|
||||||
{
|
{
|
||||||
char *current = tfstrdup(input);
|
char *current = tfstrdup(input);
|
||||||
char *newstr;
|
char *newstr;
|
||||||
const struct rule *ruleptr = rules;
|
const struct rule *ruleptr = rules;
|
||||||
regmatch_t pmatch[10];
|
regmatch_t pmatch[10];
|
||||||
int len;
|
int len;
|
||||||
int was_match = 0;
|
int was_match = 0;
|
||||||
int deadman = DEADMAN_MAX_STEPS;
|
int deadman = DEADMAN_MAX_STEPS;
|
||||||
|
|
||||||
/* Default error */
|
/* Default error */
|
||||||
*errmsg = "Remap table failure";
|
*errmsg = "Remap table failure";
|
||||||
|
|
||||||
if ( verbosity >= 3 ) {
|
if (verbosity >= 3) {
|
||||||
syslog(LOG_INFO, "remap: input: %s", current);
|
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 ( ! deadman-- ) {
|
for (ruleptr = rules; ruleptr; ruleptr = ruleptr->next) {
|
||||||
syslog(LOG_WARNING, "remap: Breaking loop, input = %s, last = %s",
|
if (((ruleptr->rule_flags & RULE_GETONLY) && is_put) ||
|
||||||
input, current);
|
((ruleptr->rule_flags & RULE_PUTONLY) && !is_put)) {
|
||||||
free(current);
|
continue; /* Rule not applicable, try next */
|
||||||
return NULL; /* Did not terminate! */
|
}
|
||||||
|
|
||||||
|
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 (verbosity >= 3) {
|
||||||
if ( regexec(&ruleptr->rx, current, 10, pmatch, 0) ==
|
syslog(LOG_INFO, "remap: done");
|
||||||
(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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
return current;
|
||||||
|
|
||||||
if ( verbosity >= 3 ) {
|
|
||||||
syslog(LOG_INFO, "remap: done");
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ struct rule;
|
||||||
macro character is passed as the first argument; the output buffer,
|
macro character is passed as the first argument; the output buffer,
|
||||||
if any, is passed as the second argument. The function should return
|
if any, is passed as the second argument. The function should return
|
||||||
the number of characters output, or -1 on failure. */
|
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 */
|
/* Read a rule file */
|
||||||
struct rule *parserulefile(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. */
|
/* Execute a rule set on a string; returns a malloc'd new string. */
|
||||||
char *rewrite_string(const char *, const struct rule *, int,
|
char *rewrite_string(const char *, const struct rule *, int,
|
||||||
match_pattern_callback, const char **);
|
match_pattern_callback, const char **);
|
||||||
|
|
||||||
#endif /* WITH_REGEX */
|
|
||||||
#endif /* TFTPD_REMAP_H */
|
|
||||||
|
|
||||||
|
#endif /* WITH_REGEX */
|
||||||
|
#endif /* TFTPD_REMAP_H */
|
||||||
|
|
2067
tftpd/tftpd.c
2067
tftpd/tftpd.c
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue