From 17b5188b655164c1ff711b070bf6021b6d3a3a74 Mon Sep 17 00:00:00 2001 From: hpa Date: Tue, 14 Sep 2004 22:38:46 +0000 Subject: [PATCH] - Fix bug in the handling of timeouts. - Add support for \U..\E and \L..\E. - Add support for inverse rules. --- CHANGES | 7 +++++ tftpd/remap.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++--------- tftpd/tftpd.8.in | 22 ++++++++++++++-- tftpd/tftpd.c | 11 +++++--- 4 files changed, 101 insertions(+), 17 deletions(-) diff --git a/CHANGES b/CHANGES index 298f10b..171a7ef 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,12 @@ $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: Portability fixes. diff --git a/tftpd/remap.c b/tftpd/remap.c index 0faa7b8..229ece5 100644 --- a/tftpd/remap.c +++ b/tftpd/remap.c @@ -1,7 +1,7 @@ /* $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 * as the "OpenBSD" operating system, distributed at @@ -33,6 +33,7 @@ #define RULE_ABORT 0x10 /* Terminate processing with an error */ #define RULE_GETONLY 0x20 /* Applicable to GET only */ #define RULE_PUTONLY 0x40 /* Applicable to PUT only */ +#define RULE_INVERSE 0x80 /* Execute if regex *doesn't* match */ struct rule { struct rule *next; @@ -42,12 +43,28 @@ struct rule { 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. */ static int genmatchstring(char *string, const char *pattern, const char *input, const regmatch_t *pmatch, match_pattern_callback macrosub) { + int (*xform)(int) = xform_null; int len = 0; - int n, mlen; + int n, mlen, sublen; int endbytes; /* 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 */ while ( *pattern ) { + mlen = 0; + if ( *pattern == '\\' && pattern[1] != '\0' ) { 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'; if ( pmatch[n].rm_so != -1 ) { @@ -73,24 +94,41 @@ static int genmatchstring(char *string, const char *pattern, const char *input, string += mlen; } } - } else { - int sublen; + 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 ) { - len += sublen; - if ( string ) - string += sublen; + while ( sublen-- ) { + len++; + if ( string ) { + *string = xform(*string); + string++; + } + } } else { len++; if ( string ) - *string++ = pattern[1]; + *string++ = xform(pattern[1]); } } pattern += 2; } else { len++; if ( string ) - *string++ = *pattern; + *string++ = xform(*pattern); pattern++; } } @@ -181,6 +219,9 @@ static int parseline(char *line, struct rule *r, int lineno) case 'P': r->rule_flags |= RULE_PUTONLY; break; + case '~': + r->rule_flags |= RULE_INVERSE; + break; default: syslog(LOG_ERR, "Remap command \"%s\" on line %d contains invalid char \"%c\"", buffer, lineno, *p); @@ -193,6 +234,11 @@ static int parseline(char *line, struct rule *r, int lineno) if ( !(r->rule_flags & RULE_REWRITE) ) 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 */ if ( !readescstring(buffer, &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 { - 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 */ 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", diff --git a/tftpd/tftpd.8.in b/tftpd/tftpd.8.in index d3ee998..644639b 100644 --- a/tftpd/tftpd.8.in +++ b/tftpd/tftpd.8.in @@ -31,7 +31,7 @@ .\" 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 .B tftpd \- IPv4 Trivial File Transfer Protocol server @@ -261,6 +261,15 @@ This rule applies to GET (RRQ) requests only. .TP .B P 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 The following escape sequences are recognized as part of the .IR "replacement pattern" : @@ -289,8 +298,17 @@ Literal backslash. \fB\\\fP\fIwhitespace\fP Literal whitespace. .TP -\fB\\#\fI +\fB\\#\fP 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 If the mapping file is changed, you need to send .B SIGHUP diff --git a/tftpd/tftpd.c b/tftpd/tftpd.c index fbadadf..9c26726 100644 --- a/tftpd/tftpd.c +++ b/tftpd/tftpd.c @@ -1180,18 +1180,20 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen) struct tftphdr *ap; /* ack packet */ static u_short block = 1; /* Static to avoid longjmp funnies */ u_short ap_opcode, ap_block; + unsigned long r_timeout; int size, n; if (oap) { timeout = rexmtval; (void)sigsetjmp(timeoutbuf,1); oack: + r_timeout = timeout; if (send(peer, oap, oacklen, 0) != oacklen) { syslog(LOG_WARNING, "tftpd: oack: %m\n"); goto abort; } for ( ; ; ) { - n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, &timeout); + n = recv_time(peer, ackbuf, sizeof(ackbuf), 0, &r_timeout); if (n < 0) { syslog(LOG_WARNING, "tftpd: read: %m\n"); goto abort; @@ -1226,13 +1228,14 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen) timeout = rexmtval; (void) sigsetjmp(timeoutbuf,1); + r_timeout = timeout; if (send(peer, dp, size + 4, 0) != size + 4) { syslog(LOG_WARNING, "tftpd: write: %m"); goto abort; } read_ahead(file, pf->f_convert); for ( ; ; ) { - n = recv_time(peer, ackbuf, sizeof (ackbuf), 0, &timeout); + n = recv_time(peer, ackbuf, sizeof (ackbuf), 0, &r_timeout); if (n < 0) { syslog(LOG_WARNING, "tftpd: read(ack): %m"); goto abort; @@ -1286,6 +1289,7 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen) static u_short block = 0; static int acksize; u_short dp_opcode, dp_block; + unsigned long r_timeout; dp = w_init(); do { @@ -1303,13 +1307,14 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen) block++; (void) sigsetjmp(timeoutbuf,1); send_ack: + r_timeout = timeout; if (send(peer, ackbuf, acksize, 0) != acksize) { syslog(LOG_WARNING, "tftpd: write(ack): %m"); goto abort; } write_behind(file, pf->f_convert); for ( ; ; ) { - n = recv_time(peer, dp, PKTSIZE, 0, &timeout); + n = recv_time(peer, dp, PKTSIZE, 0, &r_timeout); if (n < 0) { /* really? */ syslog(LOG_WARNING, "tftpd: read: %m"); goto abort; -- 2.11.4.GIT