From 351907e3f0021876abeba14ac47081cf2c21b50a Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 29 May 2024 17:28:53 -0700 Subject: [PATCH] tftpd: handle rule filter flags more cleanly Instead of a bunch of ad hoc tests, keep a bitmask of flags that would keep this rule from being executed. This also removes the ugly hack of converting the request mode between opcode and character encodings for really no good reason. Signed-off-by: H. Peter Anvin --- tftpd/remap.c | 38 ++++++++++++++++++++------------------ tftpd/remap.h | 2 +- tftpd/tftpd.c | 3 +-- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/tftpd/remap.c b/tftpd/remap.c index c7c8f85..16801c1 100644 --- a/tftpd/remap.c +++ b/tftpd/remap.c @@ -35,12 +35,13 @@ #define RULE_IPV6 0x80 /* IPv6 only */ #define RULE_HASFILE 0x100 /* Valid if rule results in a valid filename */ +#define RULE_RRQ 0x200 /* Get (read) only */ +#define RULE_WRQ 0x400 /* Put (write) only */ struct rule { struct rule *next; int nrule; - int rule_flags; - char rule_mode; + unsigned int rule_flags; regex_t rx; const char *pattern; }; @@ -164,7 +165,7 @@ static int readescstring(char *buf, char **str) int wasbs = 0, len = 0; while (*p && isspace(*p)) - p++; + p++; if (!*p) { *buf = '\0'; @@ -237,9 +238,11 @@ static int parseline(char *line, struct rule *r, int lineno) r->rule_flags |= RULE_IPV6; break; case 'G': + r->rule_flags |= RULE_RRQ; + break; case 'P': - r->rule_mode = *p; - break; + r->rule_flags |= RULE_WRQ; + break; default: syslog(LOG_ERR, "Remap command \"%s\" on line %d contains invalid char \"%c\"", @@ -346,7 +349,7 @@ void freerules(struct rule *r) /* Execute a rule set on a string; returns a malloc'd new string. */ char *rewrite_string(const struct formats *pf, const char *input, const struct rule *rules, - char mode, int af, match_pattern_callback macrosub, + int mode, int af, match_pattern_callback macrosub, const char **errmsg) { char *current = tfstrdup(input); @@ -357,6 +360,7 @@ char *rewrite_string(const struct formats *pf, int len; int was_match = 0; int deadman = DEADMAN_MAX_STEPS; + unsigned int bad_flags; /* Default error */ *errmsg = "Remap table failure"; @@ -365,15 +369,15 @@ char *rewrite_string(const struct formats *pf, syslog(LOG_INFO, "remap: input: %s", current); } + bad_flags = 0; + if (mode != RRQ) bad_flags |= RULE_RRQ; + if (mode != WRQ) bad_flags |= RULE_WRQ; + if (af != AF_INET) bad_flags |= RULE_IPV4; + if (af != AF_INET6) bad_flags |= RULE_IPV6; + for (ruleptr = rules; ruleptr; ruleptr = ruleptr->next) { - if (ruleptr->rule_mode && ruleptr->rule_mode != mode) - continue; /* Rule not applicable, try next */ - - if ((ruleptr->rule_flags & RULE_IPV4) && (af != AF_INET)) - continue; /* Rule not applicable, try next */ - - if ((ruleptr->rule_flags & RULE_IPV6) && (af != AF_INET6)) - continue; /* Rule not applicable, try next */ + if (ruleptr->rule_flags & bad_flags) + continue; /* This rule is excluded by flags */ if (!deadman--) { syslog(LOG_WARNING, @@ -424,8 +428,7 @@ char *rewrite_string(const struct formats *pf, genmatchstring(newstr, ruleptr->pattern, current, pmatch, macrosub); if ((ruleptr->rule_flags & RULE_HASFILE) && - pf->f_validate(newstr, mode == 'G' ? RRQ : WRQ, - pf, &accerr)) { + pf->f_validate(newstr, mode, pf, &accerr)) { if (verbosity >= 3) { syslog(LOG_INFO, "remap: rule %d: ignored rewrite (%s): %s", ruleptr->nrule, accerr, newstr); @@ -441,8 +444,7 @@ char *rewrite_string(const struct formats *pf, ruleptr->nrule, current); } } else if (ruleptr->rule_flags & RULE_HASFILE) { - if (pf->f_validate(current, mode == 'G' ? RRQ : WRQ, - pf, &accerr)) { + if (pf->f_validate(current, mode, pf, &accerr)) { if (verbosity >= 3) { syslog(LOG_INFO, "remap: rule %d: not exiting (%s)\n", ruleptr->nrule, accerr); diff --git a/tftpd/remap.h b/tftpd/remap.h index 2290aad..a9954ab 100644 --- a/tftpd/remap.h +++ b/tftpd/remap.h @@ -37,7 +37,7 @@ void freerules(struct rule *); /* Execute a rule set on a string; returns a malloc'd new string. */ struct formats; char *rewrite_string(const struct formats *, const char *, - const struct rule *, char, int, + const struct rule *, int, int, match_pattern_callback, const char **); #endif /* WITH_REGEX */ diff --git a/tftpd/tftpd.c b/tftpd/tftpd.c index 3349894..14182f3 100644 --- a/tftpd/tftpd.c +++ b/tftpd/tftpd.c @@ -1417,8 +1417,7 @@ static char *rewrite_access(const struct formats *pf, char *filename, { if (rewrite_rules) { char *newname = - rewrite_string(pf, filename, rewrite_rules, - mode != RRQ ? 'P' : 'G', af, + rewrite_string(pf, filename, rewrite_rules, mode, af, rewrite_macros, msg); filename = newname; }