forked from mirrors/tftp-hpa-google
- Fix bug in the handling of timeouts.
- Add support for \U..\E and \L..\E. - Add support for inverse rules.
This commit is contained in:
parent
bc8e3b32ee
commit
17b5188b65
4 changed files with 101 additions and 17 deletions
7
CHANGES
7
CHANGES
|
@ -1,5 +1,12 @@
|
||||||
$Id$
|
$Id$
|
||||||
|
|
||||||
|
Changes in 0.39:
|
||||||
|
Support Perl-style \U...\E and \L...\E, as well as allow
|
||||||
|
matching rules to be inverted (execute if rule *doesn't*
|
||||||
|
match.)
|
||||||
|
|
||||||
|
Fix a timeout bug.
|
||||||
|
|
||||||
Changes in 0.38:
|
Changes in 0.38:
|
||||||
Portability fixes.
|
Portability fixes.
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
/* ----------------------------------------------------------------------- *
|
/* ----------------------------------------------------------------------- *
|
||||||
*
|
*
|
||||||
* Copyright 2001-2002 H. Peter Anvin - All Rights Reserved
|
* Copyright 2001-2004 H. Peter Anvin - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software available under the same license
|
* This program is free software available under the same license
|
||||||
* as the "OpenBSD" operating system, distributed at
|
* as the "OpenBSD" operating system, distributed at
|
||||||
|
@ -33,6 +33,7 @@
|
||||||
#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 */
|
||||||
|
|
||||||
struct rule {
|
struct rule {
|
||||||
struct rule *next;
|
struct rule *next;
|
||||||
|
@ -42,12 +43,28 @@ struct rule {
|
||||||
const char *pattern;
|
const char *pattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int xform_null(int c)
|
||||||
|
{
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xform_toupper(int c)
|
||||||
|
{
|
||||||
|
return toupper(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xform_tolower(int 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 char *input,
|
||||||
const regmatch_t *pmatch, match_pattern_callback macrosub)
|
const regmatch_t *pmatch, match_pattern_callback macrosub)
|
||||||
{
|
{
|
||||||
|
int (*xform)(int) = xform_null;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int n, mlen;
|
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 */
|
||||||
|
@ -60,9 +77,13 @@ static int genmatchstring(char *string, const char *pattern, const char *input,
|
||||||
|
|
||||||
/* Transform matched section */
|
/* Transform matched section */
|
||||||
while ( *pattern ) {
|
while ( *pattern ) {
|
||||||
|
mlen = 0;
|
||||||
|
|
||||||
if ( *pattern == '\\' && pattern[1] != '\0' ) {
|
if ( *pattern == '\\' && pattern[1] != '\0' ) {
|
||||||
char macro = pattern[1];
|
char macro = pattern[1];
|
||||||
if ( macro >= '0' && macro <= '9' ) {
|
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';
|
n = pattern[1] - '0';
|
||||||
|
|
||||||
if ( pmatch[n].rm_so != -1 ) {
|
if ( pmatch[n].rm_so != -1 ) {
|
||||||
|
@ -73,24 +94,41 @@ static int genmatchstring(char *string, const char *pattern, const char *input,
|
||||||
string += mlen;
|
string += mlen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
break;
|
||||||
int sublen;
|
|
||||||
|
case 'L':
|
||||||
|
xform = xform_tolower;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'U':
|
||||||
|
xform = xform_toupper;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
xform = xform_null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
if ( macrosub &&
|
if ( macrosub &&
|
||||||
(sublen = macrosub(macro, string)) >= 0 ) {
|
(sublen = macrosub(macro, string)) >= 0 ) {
|
||||||
len += sublen;
|
while ( sublen-- ) {
|
||||||
if ( string )
|
len++;
|
||||||
string += sublen;
|
if ( string ) {
|
||||||
|
*string = xform(*string);
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
len++;
|
len++;
|
||||||
if ( string )
|
if ( string )
|
||||||
*string++ = pattern[1];
|
*string++ = xform(pattern[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pattern += 2;
|
pattern += 2;
|
||||||
} else {
|
} else {
|
||||||
len++;
|
len++;
|
||||||
if ( string )
|
if ( string )
|
||||||
*string++ = *pattern;
|
*string++ = xform(*pattern);
|
||||||
pattern++;
|
pattern++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,6 +219,9 @@ static int parseline(char *line, struct rule *r, int lineno)
|
||||||
case 'P':
|
case 'P':
|
||||||
r->rule_flags |= RULE_PUTONLY;
|
r->rule_flags |= RULE_PUTONLY;
|
||||||
break;
|
break;
|
||||||
|
case '~':
|
||||||
|
r->rule_flags |= RULE_INVERSE;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
syslog(LOG_ERR, "Remap command \"%s\" on line %d contains invalid char \"%c\"",
|
syslog(LOG_ERR, "Remap command \"%s\" on line %d contains invalid char \"%c\"",
|
||||||
buffer, lineno, *p);
|
buffer, lineno, *p);
|
||||||
|
@ -193,6 +234,11 @@ static int parseline(char *line, struct rule *r, int lineno)
|
||||||
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) ) {
|
||||||
|
syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n", 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);
|
||||||
|
@ -303,10 +349,18 @@ char *rewrite_string(const char *input, const struct rule *rules,
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if ( regexec(&ruleptr->rx, current, 10, pmatch, 0) == 0 ) {
|
if ( regexec(&ruleptr->rx, current, 10, pmatch, 0) ==
|
||||||
|
(ruleptr->rule_flags & RULE_INVERSE ? REG_NOMATCH : 0) ) {
|
||||||
/* Match on this rule */
|
/* Match on this rule */
|
||||||
was_match = 1;
|
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 ( ruleptr->rule_flags & RULE_ABORT ) {
|
||||||
if ( verbosity >= 3 ) {
|
if ( verbosity >= 3 ) {
|
||||||
syslog(LOG_INFO, "remap: rule %d: abort: %s",
|
syslog(LOG_INFO, "remap: rule %d: abort: %s",
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
.\" SUCH DAMAGE.
|
.\" SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\"----------------------------------------------------------------------- */
|
.\"----------------------------------------------------------------------- */
|
||||||
.TH TFTPD 8 "23 October 2002" "tftp-hpa @@VERSION@@" "System Manager's Manual"
|
.TH TFTPD 8 "3 September 2004" "tftp-hpa @@VERSION@@" "System Manager's Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
.B tftpd
|
.B tftpd
|
||||||
\- IPv4 Trivial File Transfer Protocol server
|
\- IPv4 Trivial File Transfer Protocol server
|
||||||
|
@ -261,6 +261,15 @@ This rule applies to GET (RRQ) requests only.
|
||||||
.TP
|
.TP
|
||||||
.B P
|
.B P
|
||||||
This rule applies to PUT (WRQ) requests only.
|
This rule applies to PUT (WRQ) requests only.
|
||||||
|
.TP
|
||||||
|
.B ~
|
||||||
|
Inverse the sense of this rule, i.e. execute the
|
||||||
|
.I operation
|
||||||
|
only if the
|
||||||
|
.I regex
|
||||||
|
.I doesn't
|
||||||
|
match. Cannot used together with
|
||||||
|
.BR r .
|
||||||
.PP
|
.PP
|
||||||
The following escape sequences are recognized as part of the
|
The following escape sequences are recognized as part of the
|
||||||
.IR "replacement pattern" :
|
.IR "replacement pattern" :
|
||||||
|
@ -289,8 +298,17 @@ Literal backslash.
|
||||||
\fB\\\fP\fIwhitespace\fP
|
\fB\\\fP\fIwhitespace\fP
|
||||||
Literal whitespace.
|
Literal whitespace.
|
||||||
.TP
|
.TP
|
||||||
\fB\\#\fI
|
\fB\\#\fP
|
||||||
Literal hash mark.
|
Literal hash mark.
|
||||||
|
.TP
|
||||||
|
\fB\\U\fP
|
||||||
|
Turns all subsequent letters to upper case.
|
||||||
|
.TP
|
||||||
|
\fB\\L\fP
|
||||||
|
Turns all subsequent letters to lower case.
|
||||||
|
.TP
|
||||||
|
\fB\\E\fP
|
||||||
|
Cancels the effect of \fB\\U\fP or \fB\\L\fP.
|
||||||
.PP
|
.PP
|
||||||
If the mapping file is changed, you need to send
|
If the mapping file is changed, you need to send
|
||||||
.B SIGHUP
|
.B SIGHUP
|
||||||
|
|
|
@ -1180,18 +1180,20 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
||||||
struct tftphdr *ap; /* ack packet */
|
struct tftphdr *ap; /* ack packet */
|
||||||
static u_short block = 1; /* Static to avoid longjmp funnies */
|
static u_short block = 1; /* Static to avoid longjmp funnies */
|
||||||
u_short ap_opcode, ap_block;
|
u_short ap_opcode, ap_block;
|
||||||
|
unsigned long r_timeout;
|
||||||
int size, n;
|
int size, n;
|
||||||
|
|
||||||
if (oap) {
|
if (oap) {
|
||||||
timeout = rexmtval;
|
timeout = rexmtval;
|
||||||
(void)sigsetjmp(timeoutbuf,1);
|
(void)sigsetjmp(timeoutbuf,1);
|
||||||
oack:
|
oack:
|
||||||
|
r_timeout = timeout;
|
||||||
if (send(peer, oap, oacklen, 0) != oacklen) {
|
if (send(peer, oap, oacklen, 0) != oacklen) {
|
||||||
syslog(LOG_WARNING, "tftpd: oack: %m\n");
|
syslog(LOG_WARNING, "tftpd: oack: %m\n");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
for ( ; ; ) {
|
for ( ; ; ) {
|
||||||
n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, &timeout);
|
n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, &r_timeout);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
syslog(LOG_WARNING, "tftpd: read: %m\n");
|
syslog(LOG_WARNING, "tftpd: read: %m\n");
|
||||||
goto abort;
|
goto abort;
|
||||||
|
@ -1226,13 +1228,14 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
||||||
timeout = rexmtval;
|
timeout = rexmtval;
|
||||||
(void) sigsetjmp(timeoutbuf,1);
|
(void) sigsetjmp(timeoutbuf,1);
|
||||||
|
|
||||||
|
r_timeout = timeout;
|
||||||
if (send(peer, dp, size + 4, 0) != size + 4) {
|
if (send(peer, dp, size + 4, 0) != size + 4) {
|
||||||
syslog(LOG_WARNING, "tftpd: write: %m");
|
syslog(LOG_WARNING, "tftpd: write: %m");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
read_ahead(file, pf->f_convert);
|
read_ahead(file, pf->f_convert);
|
||||||
for ( ; ; ) {
|
for ( ; ; ) {
|
||||||
n = recv_time(peer, ackbuf, sizeof (ackbuf), 0, &timeout);
|
n = recv_time(peer, ackbuf, sizeof (ackbuf), 0, &r_timeout);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
syslog(LOG_WARNING, "tftpd: read(ack): %m");
|
syslog(LOG_WARNING, "tftpd: read(ack): %m");
|
||||||
goto abort;
|
goto abort;
|
||||||
|
@ -1286,6 +1289,7 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
||||||
static u_short block = 0;
|
static u_short block = 0;
|
||||||
static int acksize;
|
static int acksize;
|
||||||
u_short dp_opcode, dp_block;
|
u_short dp_opcode, dp_block;
|
||||||
|
unsigned long r_timeout;
|
||||||
|
|
||||||
dp = w_init();
|
dp = w_init();
|
||||||
do {
|
do {
|
||||||
|
@ -1303,13 +1307,14 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
||||||
block++;
|
block++;
|
||||||
(void) sigsetjmp(timeoutbuf,1);
|
(void) sigsetjmp(timeoutbuf,1);
|
||||||
send_ack:
|
send_ack:
|
||||||
|
r_timeout = timeout;
|
||||||
if (send(peer, ackbuf, acksize, 0) != acksize) {
|
if (send(peer, ackbuf, acksize, 0) != acksize) {
|
||||||
syslog(LOG_WARNING, "tftpd: write(ack): %m");
|
syslog(LOG_WARNING, "tftpd: write(ack): %m");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
write_behind(file, pf->f_convert);
|
write_behind(file, pf->f_convert);
|
||||||
for ( ; ; ) {
|
for ( ; ; ) {
|
||||||
n = recv_time(peer, dp, PKTSIZE, 0, &timeout);
|
n = recv_time(peer, dp, PKTSIZE, 0, &r_timeout);
|
||||||
if (n < 0) { /* really? */
|
if (n < 0) { /* really? */
|
||||||
syslog(LOG_WARNING, "tftpd: read: %m");
|
syslog(LOG_WARNING, "tftpd: read: %m");
|
||||||
goto abort;
|
goto abort;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue