From ded4fb157ef9a0bf121d7f116a0299d84b684f90 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 3 Jul 2026 15:49:45 +1000 Subject: [PATCH] wildmatch: fold bracket-expression pattern chars under force_lower_case dowild()'s literal path folds the pattern char, but the [class]/[a-z] path compared unfolded pattern bytes against the (folded) text, so iwildmatch() was still case-asymmetric for character classes and ranges -- e.g. a daemon 'hosts deny = [A-Z]*.EVIL.COM' failed to match a lower-case host (access-control fail-open, same class as the literal case). Fold p_ch for the escaped-member, range-endpoint and plain-member comparisons; the range start (prev_ch) picks up the folded value too. Only active under force_lower_case (iwildmatch), so case-sensitive wildmatch() is unchanged. Reported-by: Leonid Bugaev (cherry picked from commit d443e8dc9336e517821493fc3bcf556dd5a158ca) --- lib/wildmatch.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/wildmatch.c b/lib/wildmatch.c index f3a1731e..c8e1cc8f 100644 --- a/lib/wildmatch.c +++ b/lib/wildmatch.c @@ -150,6 +150,8 @@ static int dowild(const uchar *p, const uchar *text, const uchar*const *a) p_ch = *++p; if (!p_ch) return ABORT_ALL; + if (force_lower_case && ISUPPER(p_ch)) + p_ch = tolower(p_ch); if (t_ch == p_ch) matched = TRUE; } else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') { @@ -159,6 +161,8 @@ static int dowild(const uchar *p, const uchar *text, const uchar*const *a) if (!p_ch) return ABORT_ALL; } + if (force_lower_case && ISUPPER(p_ch)) + p_ch = tolower(p_ch); if (t_ch <= p_ch && t_ch >= prev_ch) matched = TRUE; p_ch = 0; /* This makes "prev_ch" get set to 0. */ @@ -216,8 +220,12 @@ static int dowild(const uchar *p, const uchar *text, const uchar*const *a) } else /* malformed [:class:] string */ return ABORT_ALL; p_ch = 0; /* This makes "prev_ch" get set to 0. */ - } else if (t_ch == p_ch) - matched = TRUE; + } else { + if (force_lower_case && ISUPPER(p_ch)) + p_ch = tolower(p_ch); + if (t_ch == p_ch) + matched = TRUE; + } } while (prev_ch = p_ch, (p_ch = *++p) != ']'); if (matched == special || t_ch == '/') return FALSE;