summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhpa <hpa>2004-09-14 22:38:46 +0000
committerhpa <hpa>2004-09-14 22:38:46 +0000
commit17b5188b655164c1ff711b070bf6021b6d3a3a74 (patch)
tree142511c8153d864197474a5a05322065afd85d34
parentbc8e3b32ee5048db22833454af2623e953a2a200 (diff)
downloadtftp-hpa-17b5188b655164c1ff711b070bf6021b6d3a3a74.tar.gz
- Fix bug in the handling of timeouts.
- Add support for \U..\E and \L..\E. - Add support for inverse rules.
-rw-r--r--CHANGES7
-rw-r--r--tftpd/remap.c78
-rw-r--r--tftpd/tftpd.8.in22
-rw-r--r--tftpd/tftpd.c11
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;