OSDN Git Service

Add support for matching wildcard server certificates to the new SSL code.
authorMagnus Hagander <magnus@hagander.net>
Mon, 24 Nov 2008 09:15:16 +0000 (09:15 +0000)
committerMagnus Hagander <magnus@hagander.net>
Mon, 24 Nov 2008 09:15:16 +0000 (09:15 +0000)
This uses the function fnmatch() which is not available on all platforms
(notably Windows), so import the implementation from NetBSD into src/port.

configure
configure.in
src/include/fnmatchstub.h [new file with mode: 0644]
src/include/pg_config.h.in
src/interfaces/libpq/Makefile
src/interfaces/libpq/fe-secure.c
src/port/fnmatch.c [new file with mode: 0644]
src/tools/msvc/Mkvcbuild.pm

index eb88c4e..425c56e 100755 (executable)
--- a/configure
+++ b/configure
@@ -24821,6 +24821,98 @@ esac
 
 
 
+# Check for fnmatch()
+{ echo "$as_me:$LINENO: checking for working POSIX fnmatch" >&5
+echo $ECHO_N "checking for working POSIX fnmatch... $ECHO_C" >&6; }
+if test "${ac_cv_func_fnmatch_works+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # Some versions of Solaris, SCO, and the GNU C Library
+   # have a broken or incompatible fnmatch.
+   # So we run a test program.  If we are cross-compiling, take no chance.
+   # Thanks to John Oleynick, Franc,ois Pinard, and Paul Eggert for this test.
+   if test "$cross_compiling" = yes; then
+  ac_cv_func_fnmatch_works=cross
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <fnmatch.h>
+#         define y(a, b, c) (fnmatch (a, b, c) == 0)
+#         define n(a, b, c) (fnmatch (a, b, c) == FNM_NOMATCH)
+
+int
+main ()
+{
+return
+          (!(y ("a*", "abc", 0)
+             && n ("d*/*1", "d/s/1", FNM_PATHNAME)
+             && y ("a\\\\bc", "abc", 0)
+             && n ("a\\\\bc", "abc", FNM_NOESCAPE)
+             && y ("*x", ".x", 0)
+             && n ("*x", ".x", FNM_PERIOD)
+             && 1));
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_fnmatch_works=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_fnmatch_works=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_fnmatch_works" >&5
+echo "${ECHO_T}$ac_cv_func_fnmatch_works" >&6; }
+if test $ac_cv_func_fnmatch_works = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FNMATCH 1
+_ACEOF
+
+fi
+
+
+
+if test x"$ac_cv_func_fnmatch_works" != x"yes"; then
+   case " $LIBOBJS " in
+  *" fnmatch.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS fnmatch.$ac_objext"
+ ;;
+esac
+
+fi
 
 # Select semaphore implementation type.
 if test "$PORTNAME" != "win32"; then
index 64b8b4e..f8f507c 100644 (file)
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-dnl $PostgreSQL: pgsql/configure.in,v 1.572 2008/11/18 13:10:20 petere Exp $
+dnl $PostgreSQL: pgsql/configure.in,v 1.573 2008/11/24 09:15:15 mha Exp $
 dnl
 dnl Developers, please strive to achieve this order:
 dnl
@@ -1625,6 +1625,11 @@ fi
 # SunOS doesn't handle negative byte comparisons properly with +/- return
 AC_FUNC_MEMCMP
 
+# Check for fnmatch()
+AC_FUNC_FNMATCH
+if test x"$ac_cv_func_fnmatch_works" != x"yes"; then
+   AC_LIBOBJ(fnmatch)
+fi
 
 # Select semaphore implementation type.
 if test "$PORTNAME" != "win32"; then
diff --git a/src/include/fnmatchstub.h b/src/include/fnmatchstub.h
new file mode 100644 (file)
index 0000000..fb23d8f
--- /dev/null
@@ -0,0 +1,27 @@
+/*-------------------------------------------------------------------------
+ *
+ * fnmatchstub.h
+ *       Stubs for fnmatch() in port/fnmatch.c
+ *
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/fnmatchstub.h,v 1.1 2008/11/24 09:15:16 mha Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FNMATCHSTUB_H
+#define FNMATCHSTUB_H
+
+extern int fnmatch(const char *, const char *, int);
+#define FNM_NOMATCH            1               /* Match failed. */
+#define FNM_NOSYS              2               /* Function not implemented. */
+#define FNM_NOESCAPE   0x01    /* Disable backslash escaping. */
+#define FNM_PATHNAME   0x02    /* Slash must be matched by slash. */
+#define FNM_PERIOD             0x04    /* Period must be matched by period. */
+#define FNM_CASEFOLD   0x08    /* Pattern is matched case-insensitive */
+#define FNM_LEADING_DIR        0x10    /* Ignore /<tail> after Imatch. */
+
+
+#endif
index 9f6f21b..1064d15 100644 (file)
 /* Define to 1 if you have the `fdatasync' function. */
 #undef HAVE_FDATASYNC
 
+/* Define to 1 if your system has a working POSIX `fnmatch' function. */
+#undef HAVE_FNMATCH
+
 /* Define to 1 if you have the `fpclass' function. */
 #undef HAVE_FPCLASS
 
index 3d2646b..82a7fc2 100644 (file)
@@ -5,7 +5,7 @@
 # Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $PostgreSQL: pgsql/src/interfaces/libpq/Makefile,v 1.168 2008/10/01 15:35:32 mha Exp $
+# $PostgreSQL: pgsql/src/interfaces/libpq/Makefile,v 1.169 2008/11/24 09:15:16 mha Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -34,7 +34,7 @@ OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
        fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
        libpq-events.o \
        md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o \
-       $(filter crypt.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
+       $(filter crypt.o fnmatch.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
 
 ifeq ($(PORTNAME), cygwin)
 override shlib = cyg$(NAME)$(DLSUFFIX)
@@ -80,7 +80,7 @@ backend_src = $(top_srcdir)/src/backend
 # For port modules, this only happens if configure decides the module
 # is needed (see filter hack in OBJS, above).
 
-crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c pgsleep.c: % : $(top_srcdir)/src/port/%
+crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c pgsleep.c: % : $(top_srcdir)/src/port/%
        rm -f $@ && $(LN_S) $< .
 
 md5.c ip.c: % : $(backend_src)/libpq/%
@@ -123,7 +123,7 @@ uninstall: uninstall-lib
        rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample'
 
 clean distclean: clean-lib
-       rm -f $(OBJS) pg_config_paths.h crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
+       rm -f $(OBJS) pg_config_paths.h crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
 # Might be left over from a Win32 client-only build
        rm -f pg_config_paths.h
 
index 1cc7c5c..c72feeb 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.107 2008/11/13 09:45:25 mha Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.108 2008/11/24 09:15:16 mha Exp $
  *
  * NOTES
  *
 #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
 #include <openssl/engine.h>
 #endif
+
+/* fnmatch() needed for client certificate checking */
+#ifdef HAVE_FNMATCH
+#include <fnmatch.h>
+#else
+#include "fnmatchstub.h"
+#endif
 #endif   /* USE_SSL */
 
 
@@ -461,17 +468,20 @@ verify_peer_name_matches_certificate(PGconn *conn)
                 * Connect by hostname.
                 *
                 * XXX: Should support alternate names here
-                * XXX: Should support wildcard certificates here
                 */
-               if (pg_strcasecmp(conn->peer_cn, conn->pghost) != 0)
+               if (pg_strcasecmp(conn->peer_cn, conn->pghost) == 0)
+                       /* Exact name match */
+                       return true;
+               else if (fnmatch(conn->peer_cn, conn->pghost, FNM_NOESCAPE | FNM_CASEFOLD) == 0)
+                       /* Matched wildcard certificate */
+                       return true;
+               else
                {
                        printfPQExpBuffer(&conn->errorMessage,
                                                          libpq_gettext("server common name '%s' does not match hostname '%s'"),
                                                          conn->peer_cn, conn->pghost);
                        return false;
                }
-               else
-                       return true;
        }
 }
 
diff --git a/src/port/fnmatch.c b/src/port/fnmatch.c
new file mode 100644 (file)
index 0000000..c7fbc54
--- /dev/null
@@ -0,0 +1,198 @@
+/*-------------------------------------------------------------------------
+ *
+ * fnmatch.c
+ *        fnmatch() - wildcard matching function
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ *        $PostgreSQL: pgsql/src/port/fnmatch.c,v 1.1 2008/11/24 09:15:16 mha Exp $
+ *
+ * This file was taken from NetBSD and is used on platforms that don't
+ * provide fnmatch(). The NetBSD copyright terms follow.
+ *-------------------------------------------------------------------------
+ */
+
+/*     $NetBSD: fnmatch.c,v 1.21 2005/12/24 21:11:16 perry Exp $       */
+
+/*
+ * 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. 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.
+ */
+
+/*
+ * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
+ * Compares a filename or pathname to a pattern.
+ */
+
+#include "c.h"
+#include "fnmatchstub.h"
+
+#define        EOS     '\0'
+
+static const char *rangematch (const char *, int, int);
+
+static inline int
+foldcase(int ch, int flags)
+{
+
+       if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
+               return (tolower(ch));
+       return (ch);
+}
+
+#define        FOLDCASE(ch, flags)     foldcase((unsigned char)(ch), (flags))
+
+int
+fnmatch(pattern, string, flags)
+       const char *pattern, *string;
+       int flags;
+{
+       const char *stringstart;
+       char c, test;
+
+       for (stringstart = string;;)
+               switch (c = FOLDCASE(*pattern++, flags)) {
+               case EOS:
+                       if ((flags & FNM_LEADING_DIR) && *string == '/')
+                               return (0);
+                       return (*string == EOS ? 0 : FNM_NOMATCH);
+               case '?':
+                       if (*string == EOS)
+                               return (FNM_NOMATCH);
+                       if (*string == '/' && (flags & FNM_PATHNAME))
+                               return (FNM_NOMATCH);
+                       if (*string == '.' && (flags & FNM_PERIOD) &&
+                           (string == stringstart ||
+                           ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+                               return (FNM_NOMATCH);
+                       ++string;
+                       break;
+               case '*':
+                       c = FOLDCASE(*pattern, flags);
+                       /* Collapse multiple stars. */
+                       while (c == '*')
+                               c = FOLDCASE(*++pattern, flags);
+
+                       if (*string == '.' && (flags & FNM_PERIOD) &&
+                           (string == stringstart ||
+                           ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+                               return (FNM_NOMATCH);
+
+                       /* Optimize for pattern with * at end or before /. */
+                       if (c == EOS) {
+                               if (flags & FNM_PATHNAME)
+                                       return ((flags & FNM_LEADING_DIR) ||
+                                           strchr(string, '/') == NULL ?
+                                           0 : FNM_NOMATCH);
+                               else
+                                       return (0);
+                       } else if (c == '/' && flags & FNM_PATHNAME) {
+                               if ((string = strchr(string, '/')) == NULL)
+                                       return (FNM_NOMATCH);
+                               break;
+                       }
+
+                       /* General case, use recursion. */
+                       while ((test = FOLDCASE(*string, flags)) != EOS) {
+                               if (!fnmatch(pattern, string,
+                                            flags & ~FNM_PERIOD))
+                                       return (0);
+                               if (test == '/' && flags & FNM_PATHNAME)
+                                       break;
+                               ++string;
+                       }
+                       return (FNM_NOMATCH);
+               case '[':
+                       if (*string == EOS)
+                               return (FNM_NOMATCH);
+                       if (*string == '/' && flags & FNM_PATHNAME)
+                               return (FNM_NOMATCH);
+                       if ((pattern =
+                           rangematch(pattern, FOLDCASE(*string, flags),
+                                      flags)) == NULL)
+                               return (FNM_NOMATCH);
+                       ++string;
+                       break;
+               case '\\':
+                       if (!(flags & FNM_NOESCAPE)) {
+                               if ((c = FOLDCASE(*pattern++, flags)) == EOS) {
+                                       c = '\\';
+                                       --pattern;
+                               }
+                       }
+                       /* FALLTHROUGH */
+               default:
+                       if (c != FOLDCASE(*string++, flags))
+                               return (FNM_NOMATCH);
+                       break;
+               }
+       /* NOTREACHED */
+}
+
+static const char *
+rangematch(pattern, test, flags)
+       const char *pattern;
+       int test, 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@ngai.kaleida.com)
+        */
+       if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
+               ++pattern;
+       
+       for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
+               if (c == '\\' && !(flags & FNM_NOESCAPE))
+                       c = FOLDCASE(*pattern++, flags);
+               if (c == EOS)
+                       return (NULL);
+               if (*pattern == '-' 
+                   && (c2 = FOLDCASE(*(pattern+1), flags)) != EOS &&
+                       c2 != ']') {
+                       pattern += 2;
+                       if (c2 == '\\' && !(flags & FNM_NOESCAPE))
+                               c2 = FOLDCASE(*pattern++, flags);
+                       if (c2 == EOS)
+                               return (NULL);
+                       if (c <= test && test <= c2)
+                               ok = 1;
+               } else if (c == test)
+                       ok = 1;
+       }
+       return (ok == negate ? NULL : pattern);
+}
index b24b8f2..172ce6e 100644 (file)
@@ -3,7 +3,7 @@ package Mkvcbuild;
 #
 # Package that generates build files for msvc build
 #
-# $PostgreSQL: pgsql/src/tools/msvc/Mkvcbuild.pm,v 1.32 2008/11/14 22:12:37 mha Exp $
+# $PostgreSQL: pgsql/src/tools/msvc/Mkvcbuild.pm,v 1.33 2008/11/24 09:15:16 mha Exp $
 #
 use Carp;
 use Win32;
@@ -43,7 +43,7 @@ sub mkvcbuild
     $solution = new Solution($config);
 
     our @pgportfiles = qw(
-      chklocale.c crypt.c fseeko.c getrusage.c inet_aton.c random.c srandom.c
+      chklocale.c crypt.c fseeko.c fnmatch.c getrusage.c inet_aton.c random.c srandom.c
       unsetenv.c getaddrinfo.c gettimeofday.c kill.c open.c rand.c
       snprintf.c strlcat.c strlcpy.c copydir.c dirmod.c exec.c noblock.c path.c pipe.c
       pgsleep.c pgstrcasecmp.c qsort.c qsort_arg.c sprompt.c thread.c