From 57044bc5df5b4a850cd41953b51345ab42399377 Mon Sep 17 00:00:00 2001 From: hpa Date: Fri, 16 Nov 2001 23:38:29 +0000 Subject: [PATCH] Interpret the \i and \x escape sequences to insert the IP of the requesting host --- CHANGES | 5 ++++- tftpd/remap.c | 29 ++++++++++++++++++++--------- tftpd/remap.h | 13 ++++++++----- tftpd/tftpd.8 | 36 ++++++++++++++++++++++++++++++------ tftpd/tftpd.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 108 insertions(+), 26 deletions(-) diff --git a/CHANGES b/CHANGES index 7813a96..f2d3880 100644 --- a/CHANGES +++ b/CHANGES @@ -5,7 +5,10 @@ Changes in 0.27: Alan Sundell for helping out with this platform! Make the AIX 4.3 platform work again. Thanks to Josef Siemes - for helping me out with this platform! + for helping out with this platform! + + Allow replacement patterns to include the IP address of the + requesting host (\i). Changes in 0.26: diff --git a/tftpd/remap.c b/tftpd/remap.c index ee93c98..786699f 100644 --- a/tftpd/remap.c +++ b/tftpd/remap.c @@ -43,7 +43,8 @@ struct rule { }; /* 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) +static int genmatchstring(char *string, const char *pattern, const char *input, + const regmatch_t *pmatch, match_pattern_callback macrosub) { int len = 0; int n, mlen; @@ -60,11 +61,8 @@ static int genmatchstring(char *string, const char *pattern, const char *input, /* Transform matched section */ while ( *pattern ) { if ( *pattern == '\\' && pattern[1] != '\0' ) { - if ( pattern[1] < '0' || pattern[1] > '9' ) { - len++; - if ( string ) - *string++ = pattern[1]; - } else { + char macro = pattern[1]; + if ( macro >= '0' && macro <= '9' ) { n = pattern[1] - '0'; if ( pmatch[n].rm_so != -1 ) { @@ -75,6 +73,16 @@ static int genmatchstring(char *string, const char *pattern, const char *input, string += mlen; } } + } else { + int sublen; + if ( macrosub && + (sublen = macrosub(macro, string)) >= 0 ) { + len += sublen; + } else { + len++; + if ( string ) + *string++ = pattern[1]; + } } pattern += 2; } else { @@ -257,7 +265,8 @@ void freerules(struct rule *r) } /* Execute a rule set on a string; returns a malloc'd new string. */ -char *rewrite_string(const char *input, const struct rule *rules, int is_put) +char *rewrite_string(const char *input, const struct rule *rules, + int is_put, match_pattern_callback macrosub) { char *current = tfstrdup(input); char *newstr; @@ -299,9 +308,11 @@ char *rewrite_string(const char *input, const struct rule *rules, int is_put) } if ( ruleptr->rule_flags & RULE_REWRITE ) { - len = genmatchstring(NULL, ruleptr->pattern, current, pmatch); + len = genmatchstring(NULL, ruleptr->pattern, current, + pmatch, macrosub); newstr = tfmalloc(len+1); - genmatchstring(newstr, ruleptr->pattern, current, pmatch); + genmatchstring(newstr, ruleptr->pattern, current, + pmatch, macrosub); free(current); current = newstr; if ( verbosity >= 3 ) { diff --git a/tftpd/remap.h b/tftpd/remap.h index a562df5..123b7d7 100644 --- a/tftpd/remap.h +++ b/tftpd/remap.h @@ -18,15 +18,17 @@ #ifndef TFTPD_REMAP_H #define TFTPD_REMAP_H -#include -#include -#include "../config.h" - /* Opaque type */ struct rule; #ifdef WITH_REGEX +/* This is called when we encounter a substitution like \i. The + macro character is passed as the first argument; the output buffer, + if any, is passed as the second argument. The function should return + the number of characters output, or -1 on failure. */ +typedef int (*match_pattern_callback)(char, char *); + /* Read a rule file */ struct rule *parserulefile(FILE *); @@ -34,7 +36,8 @@ struct rule *parserulefile(FILE *); void freerules(struct rule *); /* Execute a rule set on a string; returns a malloc'd new string. */ -char *rewrite_string(const char *, const struct rule *, int); +char *rewrite_string(const char *, const struct rule *, int, + match_pattern_callback); #endif /* WITH_REGEX */ #endif /* TFTPD_REMAP_H */ diff --git a/tftpd/tftpd.8 b/tftpd/tftpd.8 index ebfbd4b..45f4a45 100644 --- a/tftpd/tftpd.8 +++ b/tftpd/tftpd.8 @@ -177,12 +177,7 @@ Replace the substring matched by .I regex by the .IR "replacement pattern" . -The escape sequence -\\0 -can be used to copy the entire matched string, and the sequences -\\1 to \\9 -copies parenthesized subexpressions. To specify a backslash, white -space or hash mark, you need to \\-escape it. +The replacement pattern may contain escape sequences; see below. .TP .B g Repeat this rule until it no longer matches. This is always used with @@ -210,6 +205,35 @@ This rule applies to GET (RRQ) requests only. .B P This rule applies to PUT (WRQ) requests only. .PP +The following escape sequences are recognized as part of the +.IR "replacement pattern" : +.TP +\fB\\0\fP +The entire string matched by the +.IR regex . +.TP +\fB\\1\fP to \fB\\9\fP +Match the first nine parentensized subexpressions, \\( ... \\) of the +.I regex +pattern. +.TP +\fB\\i\fP +The IP address of the requesting host, in dotted-quad notation +(e.g. 192.0.2.169). +.TP +\fB\\x\fP +The IP address of the requesting host, in hexadecimal notation +(e.g. C00002A9). +.TP +\fB\\\fP +Literal backslash. +.TP +\fB\\\fP\fIwhitespace\fP +Literal whitespace. +.TP +\fB\\#\fI +Literal hash mark. +.PP If the mapping file is changed, you need to send .B SIGHUP to any outstanding diff --git a/tftpd/tftpd.c b/tftpd/tftpd.c index 53f607d..21a7685 100644 --- a/tftpd/tftpd.c +++ b/tftpd/tftpd.c @@ -779,23 +779,64 @@ do_opt(char *opt, char *val, char **ap) return; } +#ifdef WITH_REGEX + +/* + * This is called by the remap engine when it encounters macros such + * as \i. It should write the output in "output" if non-NULL, and + * return the length of the output (generated or not). + * + * Return -1 on failure. + */ +int +rewrite_macros(char macro, char *output); + +int +rewrite_macros(char macro, char *output) +{ + char *p; + + switch (macro) { + case 'i': + p = inet_ntoa(from.sin_addr); + if ( output ) + strcpy(output, p); + return strlen(p); + + case 'x': + if ( output ) + sprintf(output, "%08X", + ntohl(from.sin_addr.s_addr)); + return 8; + + default: + return -1; + } +} + /* * Modify the filename, if applicable. If it returns NULL, deny the access. */ char * rewrite_access(char *filename, int mode) { -#ifdef WITH_REGEX if ( rewrite_rules ) { - char *newname = rewrite_string(filename, rewrite_rules, mode != RRQ); + char *newname = rewrite_string(filename, rewrite_rules, + mode != RRQ, rewrite_macros); filename = newname; } -#else - (void)mode; /* Suppress unused warning */ -#endif return filename; } +#else +char * +rewrite_access(char *filename, int mode) +{ + (void)mode; /* Avoid warning */ + return filename; +} +#endif + FILE *file; /* * Validate file access. Since we