Thread: Autoconf, libpq and replacement function

Autoconf, libpq and replacement function

From
Magnus Hagander
Date:
Hi!

I want to use the fnmatch() function in libpq, to support wildcard
certificate matching. This function is part of the standard
(http://www.opengroup.org/onlinepubs/000095399/functions/fnmatch.html),
but obviously not implemented on all platforms (naturally, it's missing
on win32, because that makes life harder..)

Anyway. NetBSD has an implementation of this at

http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/gen/fnmatch.c?rev=1.21&content-type=text/x-cvsweb-markup&only_with_tag=MAIN
that we can "steal" if we need.

How do I make this work with the autoconf magic? I see there is an
AC_CHECK_FNMATCH and AC_REPLACE_FNMATCH and so, but I have a feeling I
need to do something different since it's libpq?

(this might be very obvious how to do, but if it is, please excuse my
extreme autoconf-newbiesm)

//Magnus


Re: Autoconf, libpq and replacement function

From
Peter Eisentraut
Date:
Magnus Hagander wrote:
> How do I make this work with the autoconf magic? I see there is an
> AC_CHECK_FNMATCH and AC_REPLACE_FNMATCH and so, but I have a feeling I
> need to do something different since it's libpq?

AC_*_FNMATCH will figure out whether you need fnmatch(), so something 
involving those is necessary.

For libpq, check libpq's Makefile for, say, snprintf, to get an idea 
about the "something different".

Altogether, this might not be a trivial case.



Re: Autoconf, libpq and replacement function

From
Magnus Hagander
Date:
Peter Eisentraut wrote:
> Magnus Hagander wrote:
>> How do I make this work with the autoconf magic? I see there is an
>> AC_CHECK_FNMATCH and AC_REPLACE_FNMATCH and so, but I have a feeling I
>> need to do something different since it's libpq?
>
> AC_*_FNMATCH will figure out whether you need fnmatch(), so something
> involving those is necessary.
>
> For libpq, check libpq's Makefile for, say, snprintf, to get an idea
> about the "something different".
>
> Altogether, this might not be a trivial case.

Hmm. If I did it the right way, it actually didn't seem too hard once I
found a good example. Attached - does that seem reasonable?

(will add msvc code as well)

//Magnus
*** a/configure
--- b/configure
***************
*** 16930,16936 **** LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`



! for ac_func in crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul
unsetenv
  do
  as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
  { echo "$as_me:$LINENO: checking for $ac_func" >&5
--- 16930,16937 ----



!
! for ac_func in crypt fnmatch getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol
strtoulunsetenv 
  do
  as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
  { echo "$as_me:$LINENO: checking for $ac_func" >&5
*** a/configure.in
--- b/configure.in
***************
*** 1235,1241 **** fi
  pgac_save_LIBS="$LIBS"
  LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`

! AC_REPLACE_FUNCS([crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul
unsetenv])

  LIBS="$pgac_save_LIBS"

--- 1235,1241 ----
  pgac_save_LIBS="$LIBS"
  LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`

! AC_REPLACE_FUNCS([crypt fnmatch getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol
strtoulunsetenv]) 

  LIBS="$pgac_save_LIBS"

*** a/src/include/pg_config.h.in
--- b/src/include/pg_config.h.in
***************
*** 143,148 ****
--- 143,151 ----
  /* Define to 1 if you have the `fdatasync' function. */
  #undef HAVE_FDATASYNC

+ /* Define to 1 if you have the `fnmatch' function. */
+ #undef HAVE_FNMATCH
+
  /* Define to 1 if you have the `fpclass' function. */
  #undef HAVE_FPCLASS

*** a/src/include/port.h
--- b/src/include/port.h
***************
*** 393,398 **** extern void unsetenv(const char *name);
--- 393,409 ----
  extern void srandom(unsigned int seed);
  #endif

+ #ifdef HAVE_FNMATCH
+ 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
+
  /* thread.h */
  extern char *pqStrerror(int errnum, char *strerrbuf, size_t buflen);

*** a/src/interfaces/libpq/Makefile
--- b/src/interfaces/libpq/Makefile
***************
*** 34,40 **** 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))

  ifeq ($(PORTNAME), cygwin)
  override shlib = cyg$(NAME)$(DLSUFFIX)
--- 34,40 ----
      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 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,86 **** 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.cpgsleep.c: % : $(top_srcdir)/src/port/% 
      rm -f $@ && $(LN_S) $< .

  md5.c ip.c: % : $(backend_src)/libpq/%
--- 80,86 ----
  # For port modules, this only happens if configure decides the module
  # is needed (see filter hack in OBJS, above).

! crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c
win32error.cpgsleep.c: % : $(top_srcdir)/src/port/% 
      rm -f $@ && $(LN_S) $< .

  md5.c ip.c: % : $(backend_src)/libpq/%
***************
*** 123,129 **** 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.cstrlcpy.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

--- 123,129 ----
      rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample'

  clean distclean: clean-lib
!     rm -f $(OBJS) pg_config_paths.h crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c
snprintf.cstrerror.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

*** a/src/interfaces/libpq/fe-secure.c
--- b/src/interfaces/libpq/fe-secure.c
***************
*** 63,68 ****
--- 63,73 ----
  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
  #include <openssl/engine.h>
  #endif
+
+ /* fnmatch() needed for client certificate mapping */
+ #ifdef HAVE_FNMATCH
+ #include <fnmatch.h>
+ #endif
  #endif   /* USE_SSL */


***************
*** 461,477 **** 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)
          {
              printfPQExpBuffer(&conn->errorMessage,
                                libpq_gettext("server common name '%s' does not match hostname '%s'"),
                                conn->peer_cn, conn->pghost);
              return false;
          }
-         else
-             return true;
      }
  }

--- 466,485 ----
           * Connect by hostname.
           *
           * XXX: Should support alternate names here
           */
!         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;
          }
      }
  }

*** /dev/null
--- b/src/port/fnmatch.c
***************
*** 0 ****
--- 1,197 ----
+ /*-------------------------------------------------------------------------
+  *
+  * fnmatch.c
+  *        fnmatch() - wildcard matching function
+  *
+  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+  *
+  *
+  * IDENTIFICATION
+  *        $PostgreSQL$
+  *
+  * 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"
+
+ #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);
+ }

Re: Autoconf, libpq and replacement function

From
Magnus Hagander
Date:
Magnus Hagander wrote:
> Peter Eisentraut wrote:
>> Magnus Hagander wrote:
>>> How do I make this work with the autoconf magic? I see there is an
>>> AC_CHECK_FNMATCH and AC_REPLACE_FNMATCH and so, but I have a feeling I
>>> need to do something different since it's libpq?
>> AC_*_FNMATCH will figure out whether you need fnmatch(), so something
>> involving those is necessary.
>>
>> For libpq, check libpq's Makefile for, say, snprintf, to get an idea
>> about the "something different".
>>
>> Altogether, this might not be a trivial case.
>
> Hmm. If I did it the right way, it actually didn't seem too hard once I
> found a good example. Attached - does that seem reasonable?
>
> (will add msvc code as well)

That was easy. I also reversed the accidentally-reversed #ifdef in port.h.

//Mangus

*** a/configure
--- b/configure
***************
*** 16930,16936 **** LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`



! for ac_func in crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul
unsetenv
  do
  as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
  { echo "$as_me:$LINENO: checking for $ac_func" >&5
--- 16930,16937 ----



!
! for ac_func in crypt fnmatch getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol
strtoulunsetenv 
  do
  as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
  { echo "$as_me:$LINENO: checking for $ac_func" >&5
*** a/configure.in
--- b/configure.in
***************
*** 1235,1241 **** fi
  pgac_save_LIBS="$LIBS"
  LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`

! AC_REPLACE_FUNCS([crypt getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol strtoul
unsetenv])

  LIBS="$pgac_save_LIBS"

--- 1235,1241 ----
  pgac_save_LIBS="$LIBS"
  LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`

! AC_REPLACE_FUNCS([crypt fnmatch getopt getrusage inet_aton random rint srandom strdup strerror strlcat strlcpy strtol
strtoulunsetenv]) 

  LIBS="$pgac_save_LIBS"

*** a/src/include/pg_config.h.in
--- b/src/include/pg_config.h.in
***************
*** 143,148 ****
--- 143,151 ----
  /* Define to 1 if you have the `fdatasync' function. */
  #undef HAVE_FDATASYNC

+ /* Define to 1 if you have the `fnmatch' function. */
+ #undef HAVE_FNMATCH
+
  /* Define to 1 if you have the `fpclass' function. */
  #undef HAVE_FPCLASS

*** a/src/include/port.h
--- b/src/include/port.h
***************
*** 393,398 **** extern void unsetenv(const char *name);
--- 393,409 ----
  extern void srandom(unsigned int seed);
  #endif

+ #ifndef HAVE_FNMATCH
+ 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
+
  /* thread.h */
  extern char *pqStrerror(int errnum, char *strerrbuf, size_t buflen);

*** a/src/interfaces/libpq/Makefile
--- b/src/interfaces/libpq/Makefile
***************
*** 34,40 **** 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))

  ifeq ($(PORTNAME), cygwin)
  override shlib = cyg$(NAME)$(DLSUFFIX)
--- 34,40 ----
      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 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,86 **** 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.cpgsleep.c: % : $(top_srcdir)/src/port/% 
      rm -f $@ && $(LN_S) $< .

  md5.c ip.c: % : $(backend_src)/libpq/%
--- 80,86 ----
  # For port modules, this only happens if configure decides the module
  # is needed (see filter hack in OBJS, above).

! crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c
win32error.cpgsleep.c: % : $(top_srcdir)/src/port/% 
      rm -f $@ && $(LN_S) $< .

  md5.c ip.c: % : $(backend_src)/libpq/%
***************
*** 123,129 **** 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.cstrlcpy.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

--- 123,129 ----
      rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample'

  clean distclean: clean-lib
!     rm -f $(OBJS) pg_config_paths.h crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c
snprintf.cstrerror.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

*** a/src/interfaces/libpq/fe-secure.c
--- b/src/interfaces/libpq/fe-secure.c
***************
*** 63,68 ****
--- 63,73 ----
  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
  #include <openssl/engine.h>
  #endif
+
+ /* fnmatch() needed for client certificate mapping */
+ #ifdef HAVE_FNMATCH
+ #include <fnmatch.h>
+ #endif
  #endif   /* USE_SSL */


***************
*** 461,477 **** 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)
          {
              printfPQExpBuffer(&conn->errorMessage,
                                libpq_gettext("server common name '%s' does not match hostname '%s'"),
                                conn->peer_cn, conn->pghost);
              return false;
          }
-         else
-             return true;
      }
  }

--- 466,485 ----
           * Connect by hostname.
           *
           * XXX: Should support alternate names here
           */
!         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;
          }
      }
  }

*** /dev/null
--- b/src/port/fnmatch.c
***************
*** 0 ****
--- 1,197 ----
+ /*-------------------------------------------------------------------------
+  *
+  * fnmatch.c
+  *        fnmatch() - wildcard matching function
+  *
+  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+  *
+  *
+  * IDENTIFICATION
+  *        $PostgreSQL$
+  *
+  * 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"
+
+ #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);
+ }
*** a/src/tools/msvc/Mkvcbuild.pm
--- b/src/tools/msvc/Mkvcbuild.pm
***************
*** 43,49 **** sub mkvcbuild
      $solution = new Solution($config);

      our @pgportfiles = qw(
!       chklocale.c crypt.c fseeko.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
--- 43,49 ----
      $solution = new Solution($config);

      our @pgportfiles = qw(
!       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

Re: Autoconf, libpq and replacement function

From
Tom Lane
Date:
Magnus Hagander <magnus@hagander.net> writes:
> *** a/src/include/port.h
> --- b/src/include/port.h
> ***************
> *** 393,398 **** extern void unsetenv(const char *name);
> --- 393,409 ----
>   extern void srandom(unsigned int seed);
>   #endif 
> + #ifdef HAVE_FNMATCH
> + 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
> + 

Surely we must *not* be providing our own definitions of these symbols
when using a system version of fnmatch.

Also, judging from the comments in the autoconf manual, you'd better
use AC_FUNC_FNMATCH not just test whether the function exists.
        regards, tom lane


Re: Autoconf, libpq and replacement function

From
Magnus Hagander
Date:
Tom Lane wrote:
> Magnus Hagander <magnus@hagander.net> writes:
>> *** a/src/include/port.h
>> --- b/src/include/port.h
>> ***************
>> *** 393,398 **** extern void unsetenv(const char *name);
>> --- 393,409 ----
>>   extern void srandom(unsigned int seed);
>>   #endif
>   
>> + #ifdef HAVE_FNMATCH
>> + 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
>> + 
> 
> Surely we must *not* be providing our own definitions of these symbols
> when using a system version of fnmatch.

That's the define that I reversed in the second patch I sent. It's
supposed to be ifndef.


> Also, judging from the comments in the autoconf manual, you'd better
> use AC_FUNC_FNMATCH not just test whether the function exists.

Ok, will look at switching to that.

//Magnus


Re: Autoconf, libpq and replacement function

From
Tom Lane
Date:
Magnus Hagander <magnus@hagander.net> writes:
> Tom Lane wrote:
>> Surely we must *not* be providing our own definitions of these symbols
>> when using a system version of fnmatch.

> That's the define that I reversed in the second patch I sent. It's
> supposed to be ifndef.

Okay.

>> Also, judging from the comments in the autoconf manual, you'd better
>> use AC_FUNC_FNMATCH not just test whether the function exists.

> Ok, will look at switching to that.

Hmm ... actually there's still possibly an issue there: what if the
system provides a broken version of fnmatch?  AC_FUNC_FNMATCH will not
set HAVE_FNMATCH, and then we might end up with #define conflicts
anyway.

Since fnmatch and the #define's are supposed to be provided by
<fnmatch.h>, I think you should probably put the substitute definitions
in a substitute fnmatch.h, not port.h, to avoid that risk.
        regards, tom lane


Re: Autoconf, libpq and replacement function

From
Magnus Hagander
Date:
Tom Lane wrote:
> Magnus Hagander <magnus@hagander.net> writes:
>>> Also, judging from the comments in the autoconf manual, you'd better
>>> use AC_FUNC_FNMATCH not just test whether the function exists.
> 
>> Ok, will look at switching to that.
> 
> Hmm ... actually there's still possibly an issue there: what if the
> system provides a broken version of fnmatch?  AC_FUNC_FNMATCH will not
> set HAVE_FNMATCH, and then we might end up with #define conflicts
> anyway.
> 
> Since fnmatch and the #define's are supposed to be provided by
> <fnmatch.h>, I think you should probably put the substitute definitions
> in a substitute fnmatch.h, not port.h, to avoid that risk.

Do we have an example where we do that before? I assume there is some
autoconfy way to make that include file only "appear" in the include
path if the system one doesn't exist or is broken?

//Magnus


Re: Autoconf, libpq and replacement function

From
Tom Lane
Date:
Magnus Hagander <magnus@hagander.net> writes:
> Tom Lane wrote:
>> Since fnmatch and the #define's are supposed to be provided by
>> <fnmatch.h>, I think you should probably put the substitute definitions
>> in a substitute fnmatch.h, not port.h, to avoid that risk.

> Do we have an example where we do that before? I assume there is some
> autoconfy way to make that include file only "appear" in the include
> path if the system one doesn't exist or is broken?

Not really.  I'd suggest making the callers do something like
#ifdef HAVE_FNMATCH#include <fnmatch.h>#else#include "port/pg_fnmatch.h"#endif
        regards, tom lane


Re: Autoconf, libpq and replacement function

From
Magnus Hagander
Date:
Tom Lane wrote:
> Magnus Hagander <magnus@hagander.net> writes:
>> Tom Lane wrote:
>>> Since fnmatch and the #define's are supposed to be provided by
>>> <fnmatch.h>, I think you should probably put the substitute definitions
>>> in a substitute fnmatch.h, not port.h, to avoid that risk.
> 
>> Do we have an example where we do that before? I assume there is some
>> autoconfy way to make that include file only "appear" in the include
>> path if the system one doesn't exist or is broken?
> 
> Not really.  I'd suggest making the callers do something like
> 
>     #ifdef HAVE_FNMATCH
>     #include <fnmatch.h>
>     #else
>     #include "port/pg_fnmatch.h"
>     #endif

How's that actually different from the
#ifdef HAVE_FNMATCH
#include <fnmatch.h>        <-- happens in fe-secure.c
#else
#define ....                <-- happens in port.h
#endif

If HAVE_FNMATCH isn't set, we still have the same problem, no?

//Magnus


Re: Autoconf, libpq and replacement function

From
Tom Lane
Date:
Magnus Hagander <magnus@hagander.net> writes:
> Tom Lane wrote:
>> Not really.  I'd suggest making the callers do something like
>> 
>> #ifdef HAVE_FNMATCH
>> #include <fnmatch.h>
>> #else
>> #include "port/pg_fnmatch.h"
>> #endif

> How's that actually different from the
> #ifdef HAVE_FNMATCH
> #include <fnmatch.h>        <-- happens in fe-secure.c
> #else
> #define ....                <-- happens in port.h
> #endif

What's bothering me is that port.h gets included *everywhere*, and
might perhaps conflict with some indirect or accidental inclusion
of <fnmatch.h>.

It would also allow someone to forget the#ifdef HAVE_FNMATCH#include <fnmatch.h>#endif
part and have it still work, if they were testing on a broken platform.
It's better that both inclusions appear together instead of having the
alternative code paths effectively appear in two unrelated files.
        regards, tom lane


Re: Autoconf, libpq and replacement function

From
Magnus Hagander
Date:
Tom Lane wrote:
> Magnus Hagander <magnus@hagander.net> writes:
>> Tom Lane wrote:
>>> Not really.  I'd suggest making the callers do something like
>>>
>>> #ifdef HAVE_FNMATCH
>>> #include <fnmatch.h>
>>> #else
>>> #include "port/pg_fnmatch.h"
>>> #endif
> 
>> How's that actually different from the
>> #ifdef HAVE_FNMATCH
>> #include <fnmatch.h>        <-- happens in fe-secure.c
>> #else
>> #define ....                <-- happens in port.h
>> #endif
> 
> What's bothering me is that port.h gets included *everywhere*, and
> might perhaps conflict with some indirect or accidental inclusion
> of <fnmatch.h>.
> 
> It would also allow someone to forget the
>     #ifdef HAVE_FNMATCH
>     #include <fnmatch.h>
>     #endif
> part and have it still work, if they were testing on a broken platform.
> It's better that both inclusions appear together instead of having the
> alternative code paths effectively appear in two unrelated files.

Ok, I see your argument now.

AFAICS, we're not doing this for any other functions though - or am I
too tired and just looking in the wrong place? Or is that because
they're just function definitions and not #defines?

(I want to be sure to stick whatever new file there is in the same place..)

//Magnus


Re: Autoconf, libpq and replacement function

From
Tom Lane
Date:
Magnus Hagander <magnus@hagander.net> writes:
> AFAICS, we're not doing this for any other functions though - or am I
> too tired and just looking in the wrong place? Or is that because
> they're just function definitions and not #defines?
> (I want to be sure to stick whatever new file there is in the same place..)

src/include/rusagestub.h is doing things more or less this way.

Also, right now we have got

src/include/getaddrinfo.h
src/include/getopt_long.h

which really make me itch now that I am contemplating the possibility
that we try to use libc-supplied code for these functions along with
our own header definitions.

I think the reason we've avoided putting such stuff into include/port/
is that right now that directory consists exclusively of OS-specific
files.  Maybe we need another include subdirectory?
        regards, tom lane


Re: Autoconf, libpq and replacement function

From
Magnus Hagander
Date:
Tom Lane wrote:
> Magnus Hagander <magnus@hagander.net> writes:
>> AFAICS, we're not doing this for any other functions though - or am I
>> too tired and just looking in the wrong place? Or is that because
>> they're just function definitions and not #defines?
>> (I want to be sure to stick whatever new file there is in the same place..)
>
> src/include/rusagestub.h is doing things more or less this way.
>
> Also, right now we have got
>
> src/include/getaddrinfo.h
> src/include/getopt_long.h
>
> which really make me itch now that I am contemplating the possibility
> that we try to use libc-supplied code for these functions along with
> our own header definitions.
>
> I think the reason we've avoided putting such stuff into include/port/
> is that right now that directory consists exclusively of OS-specific
> files.  Maybe we need another include subdirectory?

Or in the same directly, called something else. Like fnmatchstub.h. See
attached, seems reasonable?

//Magnus

*** a/configure
--- b/configure
***************
*** 24821,24826 **** esac
--- 24821,24910 ----



+ # 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
+
+
+

  # Select semaphore implementation type.
  if test "$PORTNAME" != "win32"; then
*** a/configure.in
--- b/configure.in
***************
*** 1625,1630 **** fi
--- 1625,1632 ----
  # SunOS doesn't handle negative byte comparisons properly with +/- return
  AC_FUNC_MEMCMP

+ # Check for fnmatch()
+ AC_FUNC_FNMATCH

  # Select semaphore implementation type.
  if test "$PORTNAME" != "win32"; then
*** /dev/null
--- b/src/include/fnmatchstub.h
***************
*** 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$
+  *
+  *-------------------------------------------------------------------------
+  */
+ #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
*** a/src/include/pg_config.h.in
--- b/src/include/pg_config.h.in
***************
*** 143,148 ****
--- 143,151 ----
  /* 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

*** a/src/interfaces/libpq/Makefile
--- b/src/interfaces/libpq/Makefile
***************
*** 34,40 **** 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))

  ifeq ($(PORTNAME), cygwin)
  override shlib = cyg$(NAME)$(DLSUFFIX)
--- 34,40 ----
      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 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,86 **** 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.cpgsleep.c: % : $(top_srcdir)/src/port/% 
      rm -f $@ && $(LN_S) $< .

  md5.c ip.c: % : $(backend_src)/libpq/%
--- 80,86 ----
  # For port modules, this only happens if configure decides the module
  # is needed (see filter hack in OBJS, above).

! crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c
win32error.cpgsleep.c: % : $(top_srcdir)/src/port/% 
      rm -f $@ && $(LN_S) $< .

  md5.c ip.c: % : $(backend_src)/libpq/%
***************
*** 123,129 **** 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.cstrlcpy.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

--- 123,129 ----
      rm -f '$(DESTDIR)$(datadir)/pg_service.conf.sample'

  clean distclean: clean-lib
!     rm -f $(OBJS) pg_config_paths.h crypt.c fnmatch.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c
snprintf.cstrerror.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

*** a/src/interfaces/libpq/fe-secure.c
--- b/src/interfaces/libpq/fe-secure.c
***************
*** 63,68 ****
--- 63,75 ----
  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
  #include <openssl/engine.h>
  #endif
+
+ /* fnmatch() needed for client certificate mapping */
+ #ifdef HAVE_FNMATCH
+ #include <fnmatch.h>
+ #else
+ #include "fnmatchstub.h"
+ #endif
  #endif   /* USE_SSL */


***************
*** 461,477 **** 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)
          {
              printfPQExpBuffer(&conn->errorMessage,
                                libpq_gettext("server common name '%s' does not match hostname '%s'"),
                                conn->peer_cn, conn->pghost);
              return false;
          }
-         else
-             return true;
      }
  }

--- 468,487 ----
           * Connect by hostname.
           *
           * XXX: Should support alternate names here
           */
!         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;
          }
      }
  }

*** /dev/null
--- b/src/port/fnmatch.c
***************
*** 0 ****
--- 1,197 ----
+ /*-------------------------------------------------------------------------
+  *
+  * fnmatch.c
+  *        fnmatch() - wildcard matching function
+  *
+  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+  *
+  *
+  * IDENTIFICATION
+  *        $PostgreSQL$
+  *
+  * 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"
+
+ #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);
+ }
*** a/src/tools/msvc/Mkvcbuild.pm
--- b/src/tools/msvc/Mkvcbuild.pm
***************
*** 43,49 **** sub mkvcbuild
      $solution = new Solution($config);

      our @pgportfiles = qw(
!       chklocale.c crypt.c fseeko.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
--- 43,49 ----
      $solution = new Solution($config);

      our @pgportfiles = qw(
!       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

Re: Autoconf, libpq and replacement function

From
Tom Lane
Date:
Magnus Hagander <magnus@hagander.net> writes:
> Or in the same directly, called something else. Like fnmatchstub.h. See
> attached, seems reasonable?

Seems okay to me.  Note: in future, don't bother posting configure
diffs; nobody wants to look at that, just the changes in the autoconf
input files.
        regards, tom lane


Re: Autoconf, libpq and replacement function

From
Magnus Hagander
Date:
Tom Lane wrote:
> Magnus Hagander <magnus@hagander.net> writes:
>> Or in the same directly, called something else. Like fnmatchstub.h. See
>> attached, seems reasonable?
> 
> Seems okay to me.  Note: in future, don't bother posting configure
> diffs; nobody wants to look at that, just the changes in the autoconf
> input files.

Ok, will exclude it next time.

FYI, the if check in the configure (and configure.in) was backwards :-)
I posted the patch without testing it to get the "general idea" across.

Will run a set of test of the latest one on msvc as well, and then commit.

//magnus



Re: Autoconf, libpq and replacement function

From
Greg Stark
Date:
If you want people to stop posting configure diffs you should remove  
the damn configure file from CVS where it doesn't belong.

greg

On 21 Nov 2008, at 06:49 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

> Magnus Hagander <magnus@hagander.net> writes:
>> Or in the same directly, called something else. Like fnmatchstub.h.  
>> See
>> attached, seems reasonable?
>
> Seems okay to me.  Note: in future, don't bother posting configure
> diffs; nobody wants to look at that, just the changes in the autoconf
> input files.
>
>            regards, tom lane
>
> -- 
> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-hackers


Re: Autoconf, libpq and replacement function

From
Tom Lane
Date:
Greg Stark <greg.stark@enterprisedb.com> writes:
> If you want people to stop posting configure diffs you should remove  
> the damn configure file from CVS where it doesn't belong.

Well, that'd require everyone using CVS to have autoconf installed
--- and not just any autoconf, but the specific version.  Seems like
more pain than it's worth considering most people have little need to
fool with the configure script.
        regards, tom lane


Re: Autoconf, libpq and replacement function

From
Bruce Momjian
Date:
Tom Lane wrote:
> Magnus Hagander <magnus@hagander.net> writes:
> > Or in the same directly, called something else. Like fnmatchstub.h. See
> > attached, seems reasonable?
> 
> Seems okay to me.  Note: in future, don't bother posting configure
> diffs; nobody wants to look at that, just the changes in the autoconf
> input files.

Yea, it makes us ill, especially when it is the first diff in the patch.  ;-)

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


Re: Autoconf, libpq and replacement function

From
Peter Eisentraut
Date:
Tom Lane wrote:
> I'd suggest making the callers do something like
> 
>     #ifdef HAVE_FNMATCH
>     #include <fnmatch.h>
>     #else
>     #include "port/pg_fnmatch.h"
>     #endif

The way Autoconf suggests to organize this is to provide a fake 
fnmatch.h (they call it fnmatch_.h) and link it to fnmatch.h if it is 
needed.

This way, callers don't need to know the difference.


Re: Autoconf, libpq and replacement function

From
Peter Eisentraut
Date:
Tom Lane wrote:
> Also, right now we have got
> 
> src/include/getaddrinfo.h
> src/include/getopt_long.h
> 
> which really make me itch now that I am contemplating the possibility
> that we try to use libc-supplied code for these functions along with
> our own header definitions.

These particular header files look like they are robust enough to deal 
with this case.  But overall this isn't a great idea.

> I think the reason we've avoided putting such stuff into include/port/
> is that right now that directory consists exclusively of OS-specific
> files.  Maybe we need another include subdirectory?

I think the idea is rather that you don't need to change call sites to 
include the system header or our own.  The symlink approach I mentioned 
earlier might work.


Re: Autoconf, libpq and replacement function

From
Magnus Hagander
Date:
Peter Eisentraut wrote:
> Tom Lane wrote:
>> I think the reason we've avoided putting such stuff into include/port/
>> is that right now that directory consists exclusively of OS-specific
>> files.  Maybe we need another include subdirectory?
> 
> I think the idea is rather that you don't need to change call sites to
> include the system header or our own.  The symlink approach I mentioned
> earlier might work.

Anything that needs symlinks will need a set of workarounds on Windows,
having us manually do a copy of the files. We already do this in a
couple of cases, but relying more on it would make things even more
kludgy I think...

//Magnus


Re: Autoconf, libpq and replacement function

From
Peter Eisentraut
Date:
Magnus Hagander wrote:
> Anything that needs symlinks will need a set of workarounds on Windows,
> having us manually do a copy of the files. We already do this in a
> couple of cases, but relying more on it would make things even more
> kludgy I think...

Autoconf automatically uses cp if ln doesn't work.  This is already a 
solved problem that we currently use in several other situations.


Re: Autoconf, libpq and replacement function

From
Magnus Hagander
Date:
Peter Eisentraut wrote:
> Magnus Hagander wrote:
>> Anything that needs symlinks will need a set of workarounds on Windows,
>> having us manually do a copy of the files. We already do this in a
>> couple of cases, but relying more on it would make things even more
>> kludgy I think...
> 
> Autoconf automatically uses cp if ln doesn't work.  This is already a
> solved problem that we currently use in several other situations.

I was talking about the MSVC part of the build system.

//Magnus