[Pkg-apache-commits] r1315 - in /branches/lenny-apr: changelog patches/00list patches/028_fnmatch_CVE-2011-0419.dpatch
sf at alioth.debian.org
sf at alioth.debian.org
Thu May 19 05:36:15 UTC 2011
Author: sf
Date: Thu May 19 05:36:07 2011
New Revision: 1315
URL: http://svn.debian.org/wsvn/pkg-apache/?sc=1&rev=1315
Log:
add changes from 1.2.12-5+lenny3
Added:
branches/lenny-apr/patches/028_fnmatch_CVE-2011-0419.dpatch
Modified:
branches/lenny-apr/changelog
branches/lenny-apr/patches/00list
Modified: branches/lenny-apr/changelog
URL: http://svn.debian.org/wsvn/pkg-apache/branches/lenny-apr/changelog?rev=1315&op=diff
==============================================================================
--- branches/lenny-apr/changelog (original)
+++ branches/lenny-apr/changelog Thu May 19 05:36:07 2011
@@ -1,3 +1,10 @@
+apr (1.2.12-5+lenny3) oldstable-security; urgency=high
+
+ * Fix DoS in apr_fnmatch (CVE-2011-0419) which can be exploited via
+ Apache HTTPD's mod_autoindex.
+
+ -- Stefan Fritsch <sf at debian.org> Fri, 14 May 2011 09:46:15 +0200
+
apr (1.2.12-5+lenny2) stable; urgency=low
* Set FD_CLOEXEC flag on file descriptors. Not doing so caused Apache httpd
Modified: branches/lenny-apr/patches/00list
URL: http://svn.debian.org/wsvn/pkg-apache/branches/lenny-apr/patches/00list?rev=1315&op=diff
==============================================================================
--- branches/lenny-apr/patches/00list (original)
+++ branches/lenny-apr/patches/00list Thu May 19 05:36:07 2011
@@ -7,3 +7,4 @@
022_hurd_path_max.dpatch
023_fix_doxygen.dpatch
024_cloexec.dpatch
+028_fnmatch_CVE-2011-0419.dpatch
Added: branches/lenny-apr/patches/028_fnmatch_CVE-2011-0419.dpatch
URL: http://svn.debian.org/wsvn/pkg-apache/branches/lenny-apr/patches/028_fnmatch_CVE-2011-0419.dpatch?rev=1315&op=file
==============================================================================
--- branches/lenny-apr/patches/028_fnmatch_CVE-2011-0419.dpatch (added)
+++ branches/lenny-apr/patches/028_fnmatch_CVE-2011-0419.dpatch Thu May 19 05:36:07 2011
@@ -1,0 +1,762 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: merge apr_fnmatch from apr 1.4.4 to fix DoS CVE-2011-0419
+ at DPATCH@
+ apr_array_header_t **result,
+--- a/test/testfnmatch.c 2007-11-18 01:35:57.000000000 +0100
++++ a/test/testfnmatch.c 2011-05-03 06:39:57.000000000 +0200
+@@ -25,6 +25,114 @@
+
+ #define NUM_FILES (5)
+
++#define APR_FNM_BITS 15
++#define APR_FNM_FAILBIT 256
++
++#define FAILS_IF(X) 0, X
++#define SUCCEEDS_IF(X) X, 256
++#define SUCCEEDS 0, 256
++#define FAILS 256, 0
++
++static struct pattern_s {
++ const char *pattern;
++ const char *string;
++ int require_flags;
++ int fail_flags;
++} patterns[] = {
++
++/* Pattern, String to Test, Flags to Match */
++ {"", "test", FAILS},
++ {"", "*", FAILS},
++ {"test", "*", FAILS},
++ {"test", "test", SUCCEEDS},
++
++ /* Remember C '\\' is a single backslash in pattern */
++ {"te\\st", "test", FAILS_IF(APR_FNM_NOESCAPE)},
++ {"te\\\\st", "te\\st", FAILS_IF(APR_FNM_NOESCAPE)},
++ {"te\\*t", "te*t", FAILS_IF(APR_FNM_NOESCAPE)},
++ {"te\\*t", "test", FAILS},
++ {"te\\?t", "te?t", FAILS_IF(APR_FNM_NOESCAPE)},
++ {"te\\?t", "test", FAILS},
++
++ {"tesT", "test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)},
++ {"test", "Test", SUCCEEDS_IF(APR_FNM_CASE_BLIND)},
++ {"tEst", "teSt", SUCCEEDS_IF(APR_FNM_CASE_BLIND)},
++
++ {"?est", "test", SUCCEEDS},
++ {"te?t", "test", SUCCEEDS},
++ {"tes?", "test", SUCCEEDS},
++ {"test?", "test", FAILS},
++
++ {"*", "", SUCCEEDS},
++ {"*", "test", SUCCEEDS},
++ {"*test", "test", SUCCEEDS},
++ {"*est", "test", SUCCEEDS},
++ {"*st", "test", SUCCEEDS},
++ {"t*t", "test", SUCCEEDS},
++ {"te*t", "test", SUCCEEDS},
++ {"te*st", "test", SUCCEEDS},
++ {"te*", "test", SUCCEEDS},
++ {"tes*", "test", SUCCEEDS},
++ {"test*", "test", SUCCEEDS},
++
++ {"test/this", "test/", FAILS},
++ {"test/", "test/this", FAILS},
++ {"test*/this", "test/this", SUCCEEDS},
++ {"test/*this", "test/this", SUCCEEDS},
++
++ {".*", ".this", SUCCEEDS},
++ {"*", ".this", FAILS_IF(APR_FNM_PERIOD)},
++ {"?this", ".this", FAILS_IF(APR_FNM_PERIOD)},
++ {"[.]this", ".this", FAILS_IF(APR_FNM_PERIOD)},
++
++ {"test/this", "test/this", SUCCEEDS},
++ {"test?this", "test/this", FAILS_IF(APR_FNM_PATHNAME)},
++ {"test*this", "test/this", FAILS_IF(APR_FNM_PATHNAME)},
++ {"test[/]this", "test/this", FAILS_IF(APR_FNM_PATHNAME)},
++
++ {"test/.*", "test/.this", SUCCEEDS},
++ {"test/*", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)},
++ {"test/?this", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)},
++ {"test/[.]this", "test/.this", FAILS_IF(APR_FNM_PERIOD | APR_FNM_PATHNAME)},
++
++ {NULL, NULL, 0}
++};
++
++
++
++static void test_fnmatch(abts_case *tc, void *data)
++{
++ struct pattern_s *test = patterns;
++ char buf[80];
++ int i = APR_FNM_BITS + 1;
++ int res;
++
++ for (test = patterns; test->pattern; ++test)
++ {
++ for (i = 0; i <= APR_FNM_BITS; ++i)
++ {
++ res = apr_fnmatch(test->pattern, test->string, i);
++ if (((i & test->require_flags) != test->require_flags)
++ || ((i & test->fail_flags) == test->fail_flags)) {
++ if (res != APR_FNM_NOMATCH)
++ break;
++ }
++ else {
++ if (res != 0)
++ break;
++ }
++ }
++ if (i <= APR_FNM_BITS)
++ break;
++ }
++
++ if (i <= APR_FNM_BITS) {
++ sprintf(buf, "apr_fnmatch(\"%s\", \"%s\", %d) returns %d\n",
++ test->pattern, test->string, i, res);
++ abts_fail(tc, buf, __LINE__);
++ }
++}
++
+ static void test_glob(abts_case *tc, void *data)
+ {
+ int i;
+@@ -68,6 +176,7 @@
+ {
+ suite = ADD_SUITE(suite)
+
++ abts_run_test(suite, test_fnmatch, NULL);
+ abts_run_test(suite, test_glob, NULL);
+ abts_run_test(suite, test_glob_currdir, NULL);
+
+--- a/strings/apr_fnmatch.c 2004-11-24 23:51:51.000000000 +0100
++++ a/strings/apr_fnmatch.c 2011-05-03 06:51:24.000000000 +0200
+@@ -1,50 +1,58 @@
+-/*
+- * Copyright (c) 1989, 1993, 1994
+- * The Regents of the University of California. All rights reserved.
+- *
+- * This code is derived from software contributed to Berkeley by
+- * Guido van Rossum.
+- *
+- * Redistribution and use in source and binary forms, with or without
+- * modification, are permitted provided that the following conditions
+- * are met:
+- * 1. Redistributions of source code must retain the above copyright
+- * notice, this list of conditions and the following disclaimer.
+- * 2. Redistributions in binary form must reproduce the above copyright
+- * notice, this list of conditions and the following disclaimer in the
+- * documentation and/or other materials provided with the distribution.
+- * 3. All advertising materials mentioning features or use of this software
+- * must display the following acknowledgement:
+- * This product includes software developed by the University of
+- * California, Berkeley and its contributors.
+- * 4. Neither the name of the University nor the names of its contributors
+- * may be used to endorse or promote products derived from this software
+- * without specific prior written permission.
+- *
+- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+- * SUCH DAMAGE.
+- */
++/* Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements. See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
+
+-#if defined(LIBC_SCCS) && !defined(lint)
+-static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
+-#endif /* LIBC_SCCS and not lint */
+-
+-/*
+- * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
+- * Compares a filename or pathname to a pattern.
++/* Derived from The Open Group Base Specifications Issue 7, IEEE Std 1003.1-2008
++ * as described in;
++ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html
++ *
++ * Filename pattern matches defined in section 2.13, "Pattern Matching Notation"
++ * from chapter 2. "Shell Command Language"
++ * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13
++ * where; 1. A bracket expression starting with an unquoted <circumflex> '^'
++ * character CONTINUES to specify a non-matching list; 2. an explicit <period> '.'
++ * in a bracket expression matching list, e.g. "[.abc]" does NOT match a leading
++ * <period> in a filename; 3. a <left-square-bracket> '[' which does not introduce
++ * a valid bracket expression is treated as an ordinary character; 4. a differing
++ * number of consecutive slashes within pattern and string will NOT match;
++ * 5. a trailing '\' in FNM_ESCAPE mode is treated as an ordinary '\' character.
++ *
++ * Bracket expansion defined in section 9.3.5, "RE Bracket Expression",
++ * from chapter 9, "Regular Expressions"
++ * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03_05
++ * with no support for collating symbols, equivalence class expressions or
++ * character class expressions. A partial range expression with a leading
++ * hyphen following a valid range expression will match only the ordinary
++ * <hyphen> and the ending character (e.g. "[a-m-z]" will match characters
++ * 'a' through 'm', a <hyphen> '-', or a 'z').
++ *
++ * NOTE: Only POSIX/C single byte locales are correctly supported at this time.
++ * Notably, non-POSIX locales with FNM_CASEFOLD produce undefined results,
++ * particularly in ranges of mixed case (e.g. "[A-z]") or spanning alpha and
++ * nonalpha characters within a range.
++ *
++ * XXX comments below indicate porting required for multi-byte character sets
++ * and non-POSIX locale collation orders; requires mbr* APIs to track shift
++ * state of pattern and string (rewinding pattern and string repeatedly).
++ *
++ * Certain parts of the code assume 0x00-0x3F are unique with any MBCS (e.g.
++ * UTF-8, SHIFT-JIS, etc). Any implementation allowing '\' as an alternate
++ * path delimiter must be aware that 0x5C is NOT unique within SHIFT-JIS.
+ */
+-#ifndef WIN32
+-#include "apr_private.h"
+-#endif
++
+ #include "apr_file_info.h"
+ #include "apr_fnmatch.h"
+ #include "apr_tables.h"
+@@ -55,196 +63,355 @@
+ # include <ctype.h>
+ #endif
+
+-#define EOS '\0'
+-
+-static const char *rangematch(const char *, int, int);
+
+-APR_DECLARE(apr_status_t) apr_fnmatch(const char *pattern, const char *string, int flags)
++/* Most MBCS/collation/case issues handled here. Wildcard '*' is not handled.
++ * EOS '\0' and the FNM_PATHNAME '/' delimiters are not advanced over,
++ * however the "\/" sequence is advanced to '/'.
++ *
++ * Both pattern and string are **char to support pointer increment of arbitrary
++ * multibyte characters for the given locale, in a later iteration of this code
++ */
++static APR_INLINE int fnmatch_ch(const char **pattern, const char **string, int flags)
+ {
+- const char *stringstart;
+- char c, test;
+-
+- for (stringstart = string;;) {
+- switch (c = *pattern++) {
+- case EOS:
+- return (*string == EOS ? APR_SUCCESS : APR_FNM_NOMATCH);
+- case '?':
+- if (*string == EOS) {
+- return (APR_FNM_NOMATCH);
+- }
+- if (*string == '/' && (flags & APR_FNM_PATHNAME)) {
+- return (APR_FNM_NOMATCH);
+- }
+- if (*string == '.' && (flags & APR_FNM_PERIOD) &&
+- (string == stringstart ||
+- ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) {
+- return (APR_FNM_NOMATCH);
+- }
+- ++string;
+- break;
+- case '*':
+- c = *pattern;
+- /* Collapse multiple stars. */
+- while (c == '*') {
+- c = *++pattern;
+- }
+-
+- if (*string == '.' && (flags & APR_FNM_PERIOD) &&
+- (string == stringstart ||
+- ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) {
+- return (APR_FNM_NOMATCH);
+- }
+-
+- /* Optimize for pattern with * at end or before /. */
+- if (c == EOS) {
+- if (flags & APR_FNM_PATHNAME) {
+- return (strchr(string, '/') == NULL ? APR_SUCCESS : APR_FNM_NOMATCH);
+- }
+- else {
+- return (APR_SUCCESS);
+- }
+- }
+- else if (c == '/' && flags & APR_FNM_PATHNAME) {
+- if ((string = strchr(string, '/')) == NULL) {
+- return (APR_FNM_NOMATCH);
+- }
+- break;
+- }
+-
+- /* General case, use recursion. */
+- while ((test = *string) != EOS) {
+- if (!apr_fnmatch(pattern, string, flags & ~APR_FNM_PERIOD)) {
+- return (APR_SUCCESS);
+- }
+- if (test == '/' && flags & APR_FNM_PATHNAME) {
+- break;
+- }
+- ++string;
+- }
+- return (APR_FNM_NOMATCH);
+- case '[':
+- if (*string == EOS) {
+- return (APR_FNM_NOMATCH);
+- }
+- if (*string == '/' && flags & APR_FNM_PATHNAME) {
+- return (APR_FNM_NOMATCH);
+- }
+- if (*string == '.' && (flags & APR_FNM_PERIOD) &&
+- (string == stringstart ||
+- ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) {
+- return (APR_FNM_NOMATCH);
+- }
+- if ((pattern = rangematch(pattern, *string, flags)) == NULL) {
+- return (APR_FNM_NOMATCH);
+- }
+- ++string;
+- break;
+- case '\\':
+- if (!(flags & APR_FNM_NOESCAPE)) {
+- if ((c = *pattern++) == EOS) {
+- c = '\\';
+- --pattern;
+- }
+- }
+- /* FALLTHROUGH */
+- default:
+- if (flags & APR_FNM_CASE_BLIND) {
+- if (apr_tolower(c) != apr_tolower(*string)) {
+- return (APR_FNM_NOMATCH);
+- }
+- }
+- else if (c != *string) {
+- return (APR_FNM_NOMATCH);
+- }
+- string++;
+- break;
+- }
+- /* NOTREACHED */
++ const char * const mismatch = *pattern;
++ const int nocase = !!(flags & APR_FNM_CASE_BLIND);
++ const int escape = !(flags & APR_FNM_NOESCAPE);
++ const int slash = !!(flags & APR_FNM_PATHNAME);
++ int result = APR_FNM_NOMATCH;
++ const char *startch;
++ int negate;
++
++ if (**pattern == '[')
++ {
++ ++*pattern;
++
++ /* Handle negation, either leading ! or ^ operators (never both) */
++ negate = ((**pattern == '!') || (**pattern == '^'));
++ if (negate)
++ ++*pattern;
++
++ while (**pattern)
++ {
++ /* ']' is an ordinary character at the start of the range pattern */
++ if ((**pattern == ']') && (*pattern > mismatch)) {
++ ++*pattern;
++ /* XXX: Fix for MBCS character width */
++ ++*string;
++ return (result ^ negate);
++ }
++
++ if (escape && (**pattern == '\\')) {
++ ++*pattern;
++
++ /* Patterns must be terminated with ']', not EOS */
++ if (!**pattern)
++ break;
++ }
++
++ /* Patterns must be terminated with ']' not '/' */
++ if (slash && (**pattern == '/'))
++ break;
++
++ /* Look at only well-formed range patterns; ']' is allowed only if escaped,
++ * while '/' is not allowed at all in FNM_PATHNAME mode.
++ */
++ /* XXX: Fix for locale/MBCS character width */
++ if (((*pattern)[1] == '-') && (*pattern)[2]
++ && ((escape && ((*pattern)[2] != '\\'))
++ ? (((*pattern)[2] != ']') && (!slash || ((*pattern)[2] != '/')))
++ : (((*pattern)[3]) && (!slash || ((*pattern)[3] != '/'))))) {
++ startch = *pattern;
++ *pattern += (escape && ((*pattern)[2] == '\\')) ? 3 : 2;
++
++ /* XXX: handle locale/MBCS comparison, advance by MBCS char width */
++ if ((**string >= *startch) && (**string <= **pattern))
++ result = 0;
++ else if (nocase && (isupper(**string) || isupper(*startch)
++ || isupper(**pattern))
++ && (tolower(**string) >= tolower(*startch))
++ && (tolower(**string) <= tolower(**pattern)))
++ result = 0;
++
++ ++*pattern;
++ continue;
++ }
++
++ /* XXX: handle locale/MBCS comparison, advance by MBCS char width */
++ if ((**string == **pattern))
++ result = 0;
++ else if (nocase && (isupper(**string) || isupper(**pattern))
++ && (tolower(**string) == tolower(**pattern)))
++ result = 0;
++
++ ++*pattern;
++ }
++
++ /* NOT a properly balanced [expr] pattern; Rewind to test '[' literal */
++ *pattern = mismatch;
++ result = APR_FNM_NOMATCH;
+ }
++ else if (**pattern == '?') {
++ /* Optimize '?' match before unescaping **pattern */
++ if (!**string || (slash && (**string == '/')))
++ return APR_FNM_NOMATCH;
++ result = 0;
++ goto fnmatch_ch_success;
++ }
++ else if (escape && (**pattern == '\\') && (*pattern)[1]) {
++ ++*pattern;
++ }
++
++ /* XXX: handle locale/MBCS comparison, advance by the MBCS char width */
++ if (**string == **pattern)
++ result = 0;
++ else if (nocase && (isupper(**string) || isupper(**pattern))
++ && (tolower(**string) == tolower(**pattern)))
++ result = 0;
++
++ /* Refuse to advance over trailing slash or nulls
++ */
++ if (!**string || !**pattern || (slash && ((**string == '/') || (**pattern == '/'))))
++ return result;
++
++fnmatch_ch_success:
++ ++*pattern;
++ ++*string;
++ return result;
+ }
+
+-static const char *rangematch(const char *pattern, int test, int flags)
+-{
+- int negate, ok;
+- char c, c2;
+
+- /*
+- * A bracket expression starting with an unquoted circumflex
+- * character produces unspecified results (IEEE 1003.2-1992,
+- * 3.13.2). This implementation treats it like '!', for
+- * consistency with the regular expression syntax.
+- * J.T. Conklin (conklin at ngai.kaleida.com)
++APR_DECLARE(int) apr_fnmatch(const char *pattern, const char *string, int flags)
++{
++ static const char dummystring[2] = {' ', 0};
++ const int escape = !(flags & APR_FNM_NOESCAPE);
++ const int slash = !!(flags & APR_FNM_PATHNAME);
++ const char *strendseg;
++ const char *dummyptr;
++ const char *matchptr;
++ int wild;
++ /* For '*' wild processing only; surpress 'used before initialization'
++ * warnings with dummy initialization values;
+ */
+- if ((negate = (*pattern == '!' || *pattern == '^'))) {
+- ++pattern;
++ const char *strstartseg = NULL;
++ const char *mismatch = NULL;
++ int matchlen = 0;
++
++ while (*pattern)
++ {
++ /* Match balanced slashes, starting a new segment pattern
++ */
++ if (slash && escape && (*pattern == '\\') && (pattern[1] == '/'))
++ ++pattern;
++ if (slash && (*pattern == '/') && (*string == '/')) {
++ ++pattern;
++ ++string;
++ }
++
++ /* At the beginning of each segment, validate leading period behavior.
++ */
++ if ((flags & APR_FNM_PERIOD) && (*string == '.'))
++ {
++ if (*pattern == '.')
++ ++pattern;
++ else if (escape && (*pattern == '\\') && (pattern[1] == '.'))
++ pattern += 2;
++ else
++ return APR_FNM_NOMATCH;
++ ++string;
++ }
++
++ /* Determine the end of string segment
++ *
++ * Presumes '/' character is unique, not composite in any MBCS encoding
++ */
++ if (slash) {
++ strendseg = strchr(string, '/');
++ if (!strendseg)
++ strendseg = strchr(string, '\0');
++ }
++ else {
++ strendseg = strchr(string, '\0');
++ }
++
++ /* Allow pattern '*' to be consumed even with no remaining string to match
++ */
++ while (*pattern && !(slash && ((*pattern == '/')
++ || (escape && (*pattern == '\\')
++ && (pattern[1] == '/'))))
++ && ((string < strendseg)
++ || ((*pattern == '*') && (string == strendseg))))
++ {
++ /* Reduce groups of '*' and '?' to n '?' matches
++ * followed by one '*' test for simplicity
++ */
++ for (wild = 0; ((*pattern == '*') || (*pattern == '?')); ++pattern)
++ {
++ if (*pattern == '*') {
++ wild = 1;
++ }
++ else if (string < strendseg) { /* && (*pattern == '?') */
++ /* XXX: Advance 1 char for MBCS locale */
++ ++string;
++ }
++ else { /* (string >= strendseg) && (*pattern == '?') */
++ return APR_FNM_NOMATCH;
++ }
++ }
++
++ if (wild)
++ {
++ strstartseg = string;
++ mismatch = pattern;
++
++ /* Count fixed (non '*') char matches remaining in pattern
++ * excluding '/' (or "\/") and '*'
++ */
++ for (matchptr = pattern, matchlen = 0; 1; ++matchlen)
++ {
++ if ((*matchptr == '\0')
++ || (slash && ((*matchptr == '/')
++ || (escape && (*matchptr == '\\')
++ && (matchptr[1] == '/')))))
++ {
++ /* Compare precisely this many trailing string chars,
++ * the resulting match needs no wildcard loop
++ */
++ /* XXX: Adjust for MBCS */
++ if (string + matchlen > strendseg)
++ return APR_FNM_NOMATCH;
++
++ string = strendseg - matchlen;
++ wild = 0;
++ break;
++ }
++
++ if (*matchptr == '*')
++ {
++ /* Ensure at least this many trailing string chars remain
++ * for the first comparison
++ */
++ /* XXX: Adjust for MBCS */
++ if (string + matchlen > strendseg)
++ return APR_FNM_NOMATCH;
++
++ /* Begin first wild comparison at the current position */
++ break;
++ }
++
++ /* Skip forward in pattern by a single character match
++ * Use a dummy fnmatch_ch() test to count one "[range]" escape
++ */
++ /* XXX: Adjust for MBCS */
++ if (escape && (*matchptr == '\\') && matchptr[1]) {
++ matchptr += 2;
++ }
++ else if (*matchptr == '[') {
++ dummyptr = dummystring;
++ fnmatch_ch(&matchptr, &dummyptr, flags);
++ }
++ else {
++ ++matchptr;
++ }
++ }
++ }
++
++ /* Incrementally match string against the pattern
++ */
++ while (*pattern && (string < strendseg))
++ {
++ /* Success; begin a new wild pattern search
++ */
++ if (*pattern == '*')
++ break;
++
++ if (slash && ((*string == '/') || (*pattern == '/')
++ || (escape && (*pattern == '\\')
++ && (pattern[1] == '/'))))
++ break;
++
++ /* Compare ch's (the pattern is advanced over "\/" to the '/',
++ * but slashes will mismatch, and are not consumed)
++ */
++ if (!fnmatch_ch(&pattern, &string, flags))
++ continue;
++
++ /* Failed to match, loop against next char offset of string segment
++ * until not enough string chars remain to match the fixed pattern
++ */
++ if (wild) {
++ /* XXX: Advance 1 char for MBCS locale */
++ string = ++strstartseg;
++ if (string + matchlen > strendseg)
++ return APR_FNM_NOMATCH;
++
++ pattern = mismatch;
++ continue;
++ }
++ else
++ return APR_FNM_NOMATCH;
++ }
++ }
++
++ if (*string && (!slash || (*string != '/')))
++ return APR_FNM_NOMATCH;
++
++ if (*pattern && (!slash || ((*pattern != '/')
++ && (!escape || (*pattern != '\\')
++ || (pattern[1] != '/')))))
++ return APR_FNM_NOMATCH;
+ }
+
+- for (ok = 0; (c = *pattern++) != ']';) {
+- if (c == '\\' && !(flags & APR_FNM_NOESCAPE)) {
+- c = *pattern++;
+- }
+- if (c == EOS) {
+- return (NULL);
+- }
+- if (*pattern == '-' && (c2 = *(pattern + 1)) != EOS && c2 != ']') {
+- pattern += 2;
+- if (c2 == '\\' && !(flags & APR_FNM_NOESCAPE)) {
+- c2 = *pattern++;
+- }
+- if (c2 == EOS) {
+- return (NULL);
+- }
+- if ((c <= test && test <= c2)
+- || ((flags & APR_FNM_CASE_BLIND)
+- && ((apr_tolower(c) <= apr_tolower(test))
+- && (apr_tolower(test) <= apr_tolower(c2))))) {
+- ok = 1;
+- }
+- }
+- else if ((c == test)
+- || ((flags & APR_FNM_CASE_BLIND)
+- && (apr_tolower(c) == apr_tolower(test)))) {
+- ok = 1;
+- }
+- }
+- return (ok == negate ? NULL : pattern);
++ /* pattern is at EOS; if string is also, declare success
++ */
++ if (!*string)
++ return 0;
++
++ /* pattern didn't match to the end of string */
++ return APR_FNM_NOMATCH;
+ }
+
+
+-/* This function is an Apache addition */
+-/* return non-zero if pattern has any glob chars in it */
++/* This function is an Apache addition
++ * return non-zero if pattern has any glob chars in it
++ * @bug Function does not distinguish for FNM_PATHNAME mode, which renders
++ * a false positive for test[/]this (which is not a range, but
++ * seperate test[ and ]this segments and no glob.)
++ * @bug Function does not distinguish for non-FNM_ESCAPE mode.
++ * @bug Function does not parse []] correctly
++ * Solution may be to use fnmatch_ch() to walk the patterns?
++ */
+ APR_DECLARE(int) apr_fnmatch_test(const char *pattern)
+ {
+ int nesting;
+
+ nesting = 0;
+ while (*pattern) {
+- switch (*pattern) {
+- case '?':
+- case '*':
+- return 1;
+-
+- case '\\':
+- if (*pattern++ == '\0') {
+- return 0;
+- }
+- break;
+-
+- case '[': /* '[' is only a glob if it has a matching ']' */
+- ++nesting;
+- break;
+-
+- case ']':
+- if (nesting) {
+- return 1;
+- }
+- break;
+- }
+- ++pattern;
+- }
++ switch (*pattern) {
++ case '?':
++ case '*':
++ return 1;
++
++ case '\\':
++ if (*++pattern == '\0') {
++ return 0;
++ }
++ break;
++
++ case '[': /* '[' is only a glob if it has a matching ']' */
++ ++nesting;
++ break;
++
++ case ']':
++ if (nesting) {
++ return 1;
++ }
++ break;
++ }
++ ++pattern; }
+ return 0;
+ }
+
++
+ /* Find all files matching the specified pattern */
+ APR_DECLARE(apr_status_t) apr_match_glob(const char *pattern,
+ apr_array_header_t **result,
More information about the Pkg-apache-commits
mailing list