]> git.pld-linux.org Git - packages/postfix.git/commitdiff
- not needed for postfix 2.1.x
authorJacek Konieczny <jajcus@pld-linux.org>
Fri, 23 Jul 2004 07:23:37 +0000 (07:23 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    postfix-dict_ldap.patch -> 1.3
    postfix-ns-mx-acl.patch -> 1.2
    postfix-pgsql.patch -> 1.4

postfix-dict_ldap.patch [deleted file]
postfix-ns-mx-acl.patch [deleted file]
postfix-pgsql.patch [deleted file]

diff --git a/postfix-dict_ldap.patch b/postfix-dict_ldap.patch
deleted file mode 100644 (file)
index 185d098..0000000
+++ /dev/null
@@ -1,1162 +0,0 @@
---- postfix-2.0.19.old/src/util/dict_ldap.c    2002-10-17 02:26:41.000000000 +0200
-+++ postfix-2.0.19.new/src/util/dict_ldap.c    2004-04-10 21:08:37.000000000 +0200
-@@ -26,7 +26,9 @@
- /* .PP
- /*    Configuration parameters:
- /* .IP \fIldapsource_\fRserver_host
--/*    The host at which all LDAP queries are directed.
-+/*    List of hosts at which all LDAP queries are directed.
-+/*    The host names can also be LDAP URLs if the LDAP client library used
-+/*    is OpenLDAP.
- /* .IP \fIldapsource_\fRserver_port
- /*    The port the LDAP server listens on.
- /* .IP \fIldapsource_\fRsearch_base
-@@ -57,14 +59,56 @@
- /*    If you must bind to the server, do it with this distinguished name ...
- /* .IP \fIldapsource_\fRbind_pw
- /*    \&... and this password.
--/* .IP \fIldapsource_\fRcache
-+/* .IP \fIldapsource_\fRcache (no longer supported)
- /*    Whether or not to turn on client-side caching.
--/* .IP \fIldapsource_\fRcache_expiry
-+/* .IP \fIldapsource_\fRcache_expiry (no longer supported)
- /*    If you do cache results, expire them after this many seconds.
--/* .IP \fIldapsource_\fRcache_size
-+/* .IP \fIldapsource_\fRcache_size (no longer supported)
- /*    The cache size in bytes. Does nothing if the cache is off, of course.
-+/* .IP \fIldapsource_\fRrecursion_limit
-+/*    Maximum recursion depth when expanding DN or URL references.
-+/*    Queries which exceed the recursion limit fail with
-+/*    dict_errno = DICT_ERR_RETRY.
-+/* .IP \fIldapsource_\fRexpansion_limit
-+/*    Limit (if any) on the total number of lookup result values. Lookups which
-+/*    exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that
-+/*    each value of a multivalued result attribute counts as one result.
-+/* .IP \fIldapsource_\fRsize_limit
-+/*    Limit on the number of entries returned by individual LDAP queries.
-+/*    Queries which exceed the limit fail with dict_errno=DICT_ERR_RETRY.
-+/*    This is an *entry* count, for any single query performed during the
-+/*    possibly recursive lookup.
-+/* .IP \fIldapsource_\fRchase_referrals
-+/*    Controls whether LDAP referrals are obeyed.
- /* .IP \fIldapsource_\fRdereference
- /*    How to handle LDAP aliases. See ldap.h or ldap_open(3) man page.
-+/* .IP \fIldapsource_\fRversion
-+/*    Specifies the LDAP protocol version to use.  Default is version
-+/*    \fI2\fR.
-+/* .IP \fIldapsource_\fRstart_tls
-+/*    Whether or not to issue STARTTLS upon connection to the server.
-+/*    At this time, STARTTLS and LDAP SSL are only available if the
-+/*    LDAP client library used is OpenLDAP.  Default is \fIno\fR.
-+/* .IP \fIldapsource_\fRtls_ca_cert_file
-+/*    File containing certificates for all of the X509 Certificate
-+/*    Authorities the client will recognize.  Takes precedence over
-+/*    tls_ca_cert_dir.
-+/* .IP \fIldapsource_\fRtls_ca_cert_dir
-+/*    Directory containing X509 Certificate Authority certificates
-+/*    in separate individual files.
-+/* .IP \fIldapsource_\fRtls_cert
-+/*    File containing client's X509 certificate.
-+/* .IP \fIldapsource_\fRtls_key
-+/*    File containing the private key corresponding to
-+/*    tls_cert.
-+/* .IP \fIldapsource_\fRtls_require_cert
-+/*    Whether or not to request server's X509 certificate and check its
-+/*    validity.
-+/* .IP \fIldapsource_\fRtls_random_file
-+/*    Path of a file to obtain random bits from when /dev/[u]random is
-+/*    not available. Generally set to the name of the EGD/PRNGD socket.
-+/* .IP \fIldapsource_\fRtls_cipher_suite
-+/*    Cipher suite to use in SSL/TLS negotiations.
- /* .IP \fIldapsource_\fRdebuglevel
- /*    Debug level.  See 'loglevel' option in slapd.conf(5) man page.
- /*      Currently only in openldap libraries (and derivatives).
-@@ -102,6 +146,8 @@
- #include <lber.h>
- #include <ldap.h>
- #include <string.h>
-+#include <ctype.h>
-+#include <unistd.h>
-  /*
-   * Older APIs have weird memory freeing behavior.
-@@ -126,12 +172,22 @@
- #include "mymalloc.h"
- #include "vstring.h"
- #include "dict.h"
-+#include "stringops.h"
-+#include "binhash.h"
-+
- #include "dict_ldap.h"
- /* AAARGH!! */
- #include "../global/mail_conf.h"
-+#include "dict_ldap.h"
-+
-+typedef struct {
-+    LDAP   *conn_ld;
-+    int     conn_refcount;
-+} LDAP_CONN;
-+
- /*
-  * Structure containing all the configuration parameters for a given
-  * LDAP source, plus its connection handle.
-@@ -152,17 +208,33 @@
-     char   *bind_dn;
-     char   *bind_pw;
-     int     timeout;
--    int     cache;
--    long    cache_expiry;
--    long    cache_size;
-     int     dereference;
-+    long    recursion_limit;
-+    long    expansion_limit;
-+    long    size_limit;
-     int     chase_referrals;
-     int     debuglevel;
-     int     version;
-+#ifdef LDAP_API_FEATURE_X_OPENLDAP
-+    int     ldap_ssl;
-+    int     start_tls;
-+    int     tls_require_cert;
-+    char   *tls_ca_cert_file;
-+    char   *tls_ca_cert_dir;
-+    char   *tls_cert;
-+    char   *tls_key;
-+    char   *tls_random_file;
-+    char   *tls_cipher_suite;
-+#endif
-+    BINHASH_INFO *ht;                  /* hash entry for LDAP connection */
-     LDAP   *ld;
- } DICT_LDAP;
--#ifndef LDAP_OPT_NETWORK_TIMEOUT
-+#define DICT_LDAP_CONN(d) ((LDAP_CONN *)((d)->ht->value))
-+
-+static BINHASH *conn_hash = 0;
-+
-+#if defined(LDAP_API_FEATURE_X_OPENLDAP) || !defined(LDAP_OPT_NETWORK_TIMEOUT)
- /*
-  * LDAP connection timeout support.
-  */
-@@ -178,8 +250,17 @@
- static void dict_ldap_logprint(LDAP_CONST char *data)
- {
-     char   *myname = "dict_ldap_debug";
-+    char   *buf,
-+           *p;
--    msg_info("%s: %s", myname, data);
-+    buf = mystrdup(data);
-+    if (*buf) {
-+       p = buf + strlen(buf) - 1;
-+       while (p - buf >= 0 && ISSPACE(*p))
-+           *p-- = 0;
-+    }
-+    msg_info("%s: %s", myname, buf);
-+    myfree(buf);
- }
-@@ -225,24 +306,97 @@
-     return (ldap_result2error(dict_ldap->ld, res, 1));
- }
-+#ifdef LDAP_API_FEATURE_X_OPENLDAP
-+static void dict_ldap_set_tls_options(DICT_LDAP *dict_ldap)
-+{
-+    char   *myname = "dict_ldap_set_tls_options";
-+    int     rc;
-+
-+    if (dict_ldap->start_tls || dict_ldap->ldap_ssl) {
-+       if (*dict_ldap->tls_random_file) {
-+           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
-+                              dict_ldap->tls_random_file)) != LDAP_SUCCESS)
-+               msg_warn("%s: Unable to set tls_random_file to %s: %d: %s",
-+                        myname, dict_ldap->tls_random_file,
-+                        rc, ldap_err2string(rc));
-+       }
-+       if (*dict_ldap->tls_ca_cert_file) {
-+           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
-+                             dict_ldap->tls_ca_cert_file)) != LDAP_SUCCESS)
-+               msg_warn("%s: Unable to set tls_ca_cert_file to %s: %d: %s",
-+                        myname, dict_ldap->tls_ca_cert_file,
-+                        rc, ldap_err2string(rc));
-+       }
-+       if (*dict_ldap->tls_ca_cert_dir) {
-+           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTDIR,
-+                              dict_ldap->tls_ca_cert_dir)) != LDAP_SUCCESS)
-+               msg_warn("%s: Unable to set tls_ca_cert_dir to %s: %d: %s",
-+                        myname, dict_ldap->tls_ca_cert_dir,
-+                        rc, ldap_err2string(rc));
-+       }
-+       if (*dict_ldap->tls_cert) {
-+           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE,
-+                                     dict_ldap->tls_cert)) != LDAP_SUCCESS)
-+               msg_warn("%s: Unable to set tls_cert to %s: %d: %s",
-+                        myname, dict_ldap->tls_cert,
-+                        rc, ldap_err2string(rc));
-+       }
-+       if (*dict_ldap->tls_key) {
-+           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE,
-+                                     dict_ldap->tls_key)) != LDAP_SUCCESS)
-+               msg_warn("%s: Unable to set tls_key to %s: %d: %s",
-+                        myname, dict_ldap->tls_key,
-+                        rc, ldap_err2string(rc));
-+       }
-+       if (*dict_ldap->tls_cipher_suite) {
-+           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
-+                             dict_ldap->tls_cipher_suite)) != LDAP_SUCCESS)
-+               msg_warn("%s: Unable to set tls_cipher_suite to %s: %d: %s",
-+                        myname, dict_ldap->tls_cipher_suite,
-+                        rc, ldap_err2string(rc));
-+       }
-+       if (dict_ldap->tls_require_cert) {
-+           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
-+                          &(dict_ldap->tls_require_cert))) != LDAP_SUCCESS)
-+               msg_warn("%s: Unable to set tls_require_cert to %d: %d: %s",
-+                        myname, dict_ldap->tls_require_cert,
-+                        rc, ldap_err2string(rc));
-+       }
-+    }
-+}
-+
-+#endif
-+
-+
- /* Establish a connection to the LDAP server. */
- static int dict_ldap_connect(DICT_LDAP *dict_ldap)
- {
-     char   *myname = "dict_ldap_connect";
-     int     rc = 0;
--#ifdef LDAP_API_FEATURE_X_MEMCACHE
--    LDAPMemCache *dircache;
--
--#endif
--
- #ifdef LDAP_OPT_NETWORK_TIMEOUT
-     struct timeval mytimeval;
--#else
-+#endif
-+
-+#if defined(LDAP_API_FEATURE_X_OPENLDAP) || !defined(LDAP_OPT_NETWORK_TIMEOUT)
-     void    (*saved_alarm) (int);
- #endif
-+#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
-+    if (dict_ldap->debuglevel > 0 &&
-+       ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN,
-+                    (LDAP_CONST *) dict_ldap_logprint) != LBER_OPT_SUCCESS)
-+       msg_warn("%s: Unable to set ber logprint function.", myname);
-+#if defined(LBER_OPT_DEBUG_LEVEL)
-+    if (ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL,
-+                      &(dict_ldap->debuglevel)) != LBER_OPT_SUCCESS)
-+       msg_warn("%s: Unable to set BER debug level.", myname);
-+#endif
-+    if (ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL,
-+                       &(dict_ldap->debuglevel)) != LDAP_OPT_SUCCESS)
-+       msg_warn("%s: Unable to set LDAP debug level.", myname);
-+#endif
-     dict_errno = 0;
-@@ -251,8 +405,13 @@
-                dict_ldap->server_host);
- #ifdef LDAP_OPT_NETWORK_TIMEOUT
-+#ifdef LDAP_API_FEATURE_X_OPENLDAP
-+    dict_ldap_set_tls_options(dict_ldap);
-+    ldap_initialize(&(dict_ldap->ld), dict_ldap->server_host);
-+#else
-     dict_ldap->ld = ldap_init(dict_ldap->server_host,
-                             (int) dict_ldap->server_port);
-+#endif
-     if (dict_ldap->ld == NULL) {
-       msg_warn("%s: Unable to init LDAP server %s",
-                myname, dict_ldap->server_host);
-@@ -308,12 +467,22 @@
-                           &dict_ldap->version) != LDAP_OPT_SUCCESS)
-           msg_warn("%s: Unable to get LDAP protocol version", myname);
-       else
--          msg_warn("%s: Actual Protocol version used is %d.",
-+          msg_info("%s: Actual Protocol version used is %d.",
-                    myname, dict_ldap->version);
-     }
- #endif
-     /*
-+     * Limit the number of entries returned by each query.
-+     */
-+    if (dict_ldap->size_limit) {
-+       if (ldap_set_option(dict_ldap->ld, LDAP_OPT_SIZELIMIT,
-+                           &dict_ldap->size_limit) != LDAP_OPT_SUCCESS)
-+           msg_warn("%s: %s: Unable to set query result size limit to %ld.",
-+                    myname, dict_ldap->ldapsource, dict_ldap->size_limit);
-+    }
-+
-+    /*
-      * Configure alias dereferencing for this connection. Thanks to Mike
-      * Mattice for this, and to Hery Rakotoarisoa for the v3 update.
-      */
-@@ -321,16 +490,6 @@
-                       &(dict_ldap->dereference)) != LDAP_OPT_SUCCESS)
-       msg_warn("%s: Unable to set dereference option.", myname);
--#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
--    if (dict_ldap->debuglevel > 0 &&
--      ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN,
--                   (LDAP_CONST *) dict_ldap_logprint) != LBER_OPT_SUCCESS)
--      msg_warn("%s: Unable to set ber logprint function.", myname);
--    if (ldap_set_option(dict_ldap->ld, LDAP_OPT_DEBUG_LEVEL,
--                      &(dict_ldap->debuglevel)) != LDAP_OPT_SUCCESS)
--      msg_warn("%s: Unable to set LDAP debug level.", myname);
--#endif
--
-     /* Chase referrals. */
-     /*
-@@ -348,6 +507,36 @@
-     }
- #endif
-+#ifdef LDAP_API_FEATURE_X_OPENLDAP
-+    if (dict_ldap->start_tls) {
-+       if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) {
-+           msg_warn("%s: Error setting signal handler for STARTTLS timeout: %m",
-+                    myname);
-+           dict_errno = DICT_ERR_RETRY;
-+           return (-1);
-+       }
-+       alarm(dict_ldap->timeout);
-+       if (setjmp(env) == 0)
-+           rc = ldap_start_tls_s(dict_ldap->ld, NULL, NULL);
-+       else
-+           rc = LDAP_TIMEOUT;
-+       alarm(0);
-+
-+       if (signal(SIGALRM, saved_alarm) == SIG_ERR) {
-+           msg_warn("%s: Error resetting signal handler after STARTTLS: %m",
-+                    myname);
-+           dict_errno = DICT_ERR_RETRY;
-+           return (-1);
-+       }
-+       if (rc != LDAP_SUCCESS) {
-+           msg_error("%s: Unable to set STARTTLS: %d: %s", myname,
-+                     rc, ldap_err2string(rc));
-+           dict_errno = DICT_ERR_RETRY;
-+           return (-1);
-+       }
-+    }
-+#endif
-+
-     /*
-      * If this server requires a bind, do so. Thanks to Sam Tardieu for
-      * noticing that the original bind call was broken.
-@@ -370,52 +559,9 @@
-           msg_info("%s: Successful bind to server %s as %s ",
-                    myname, dict_ldap->server_host, dict_ldap->bind_dn);
-     }
-+    /* Save connection handle in shared container */
-+    DICT_LDAP_CONN(dict_ldap)->conn_ld = dict_ldap->ld;
--    /*
--     * Set up client-side caching if it's configured.
--     */
--    if (dict_ldap->cache) {
--      if (msg_verbose)
--          msg_info
--              ("%s: Enabling %ld-byte cache for %s with %ld-second expiry",
--               myname, dict_ldap->cache_size, dict_ldap->ldapsource,
--               dict_ldap->cache_expiry);
--
--#ifdef LDAP_API_FEATURE_X_MEMCACHE
--      rc = ldap_memcache_init(dict_ldap->cache_expiry, dict_ldap->cache_size,
--                              NULL, NULL, &dircache);
--      if (rc != LDAP_SUCCESS) {
--          msg_warn
--              ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
--               myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
--      } else {
--          rc = ldap_memcache_set(dict_ldap->ld, dircache);
--          if (rc != LDAP_SUCCESS) {
--              msg_warn
--                  ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
--                   myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
--          } else {
--              if (msg_verbose)
--                  msg_info("%s: Caching enabled for %s",
--                           myname, dict_ldap->ldapsource);
--          }
--      }
--#else
--
--      rc = ldap_enable_cache(dict_ldap->ld, dict_ldap->cache_expiry,
--                             dict_ldap->cache_size);
--      if (rc != LDAP_SUCCESS) {
--          msg_warn
--              ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
--               myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
--      } else {
--          if (msg_verbose)
--              msg_info("%s: Caching enabled for %s",
--                       myname, dict_ldap->ldapsource);
--      }
--
--#endif
--    }
-     if (msg_verbose)
-       msg_info("%s: Cached connection handle for LDAP source %s",
-                myname, dict_ldap->ldapsource);
-@@ -424,9 +570,65 @@
- }
- /*
-+ * Locate or allocate connection cache entry.
-+ */
-+static void dict_ldap_conn_find(DICT_LDAP *dict_ldap)
-+{
-+    VSTRING *keybuf = vstring_alloc(10);
-+    char   *key;
-+    int     len;
-+
-+#ifdef LDAP_API_FEATURE_X_OPENLDAP
-+    int     sslon = dict_ldap->start_tls || dict_ldap->ldap_ssl;
-+
-+#endif
-+    LDAP_CONN *conn;
-+
-+#define ADDSTR(vp, s) vstring_memcat((vp), (s), strlen((s))+1)
-+#define ADDINT(vp, i) vstring_sprintf_append((vp), "%lu", (unsigned long)(i))
-+
-+    ADDSTR(keybuf, dict_ldap->server_host);
-+    ADDINT(keybuf, dict_ldap->server_port);
-+    ADDINT(keybuf, dict_ldap->bind);
-+    ADDSTR(keybuf, dict_ldap->bind ? dict_ldap->bind_dn : "");
-+    ADDSTR(keybuf, dict_ldap->bind ? dict_ldap->bind_pw : "");
-+    ADDINT(keybuf, dict_ldap->dereference);
-+    ADDINT(keybuf, dict_ldap->chase_referrals);
-+    ADDINT(keybuf, dict_ldap->debuglevel);
-+    ADDINT(keybuf, dict_ldap->version);
-+#ifdef LDAP_API_FEATURE_X_OPENLDAP
-+    ADDINT(keybuf, dict_ldap->ldap_ssl);
-+    ADDINT(keybuf, dict_ldap->start_tls);
-+    ADDINT(keybuf, sslon ? dict_ldap->tls_require_cert : 0);
-+    ADDSTR(keybuf, sslon ? dict_ldap->tls_ca_cert_file : "");
-+    ADDSTR(keybuf, sslon ? dict_ldap->tls_ca_cert_dir : "");
-+    ADDSTR(keybuf, sslon ? dict_ldap->tls_cert : "");
-+    ADDSTR(keybuf, sslon ? dict_ldap->tls_key : "");
-+    ADDSTR(keybuf, sslon ? dict_ldap->tls_random_file : "");
-+    ADDSTR(keybuf, sslon ? dict_ldap->tls_cipher_suite : "");
-+#endif
-+
-+    key = vstring_str(keybuf);
-+    len = VSTRING_LEN(keybuf);
-+
-+    if (conn_hash == 0)
-+       conn_hash = binhash_create(0);
-+
-+    if ((dict_ldap->ht = binhash_locate(conn_hash, key, len)) == 0) {
-+       conn = (LDAP_CONN *) mymalloc(sizeof(LDAP_CONN));
-+       conn->conn_ld = 0;
-+       conn->conn_refcount = 0;
-+       dict_ldap->ht = binhash_enter(conn_hash, key, len, (char *) conn);
-+    }
-+    ++DICT_LDAP_CONN(dict_ldap)->conn_refcount;
-+
-+    vstring_free(keybuf);
-+}
-+
-+/*
-  * expand a filter (lookup or result)
-  */
--static void dict_ldap_expand_filter(char *filter, char *value, VSTRING *out)
-+static void dict_ldap_expand_filter(char *ldapsource, char *filter, char *value, VSTRING *out)
- {
-     char   *myname = "dict_ldap_expand_filter";
-     char   *sub,
-@@ -462,8 +664,8 @@
-               break;
-           default:
-               msg_warn
--                  ("%s: Invalid filter substitution format '%%%c'!",
--                   myname, *(sub + 1));
-+                  ("%s: %s: Invalid filter substitution format '%%%c'!",
-+                   myname, ldapsource, *(sub + 1));
-               /* fall through */
-           case 's':
-               vstring_strcat(out, u);
-@@ -486,6 +688,9 @@
- static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
-                                        VSTRING *result)
- {
-+    static int recursion = 0;
-+    static int expansion;
-+    long    entries = 0;
-     long    i = 0;
-     int     rc = 0;
-     LDAPMessage *resloop = 0;
-@@ -500,13 +705,27 @@
-     tv.tv_sec = dict_ldap->timeout;
-     tv.tv_usec = 0;
-+    if (++recursion == 1)
-+       expansion = 0;
-+
-     if (msg_verbose)
--      msg_info("%s: Search found %d match(es)", myname,
-+      msg_info("%s[%d]: Search found %d match(es)", myname, recursion,
-                ldap_count_entries(dict_ldap->ld, res));
-     for (entry = ldap_first_entry(dict_ldap->ld, res); entry != NULL;
-        entry = ldap_next_entry(dict_ldap->ld, entry)) {
-       ber = NULL;
-+
-+       /*
-+        * LDAP should not, but may produce more than the requested maximum
-+        * number of entries.
-+        */
-+       if (dict_errno == 0 && ++entries > dict_ldap->size_limit
-+           && dict_ldap->size_limit) {
-+           msg_warn("%s[%d]: %s: Query size limit (%ld) exceeded", myname,
-+                  recursion, dict_ldap->ldapsource, dict_ldap->size_limit);
-+           dict_errno = DICT_ERR_RETRY;
-+       }
-       for (attr = ldap_first_attribute(dict_ldap->ld, entry, &ber);
-            attr != NULL;
-            ldap_memfree(attr), attr = ldap_next_attribute(dict_ldap->ld,
-@@ -514,17 +733,38 @@
-           vals = ldap_get_values(dict_ldap->ld, entry, attr);
-           if (vals == NULL) {
-               if (msg_verbose)
--                  msg_info("%s: Entry doesn't have any values for %s",
--                           myname, attr);
-+                  msg_info("%s[%d]: Entry doesn't have any values for %s",
-+                           myname, recursion, attr);
-               continue;
-           }
-+
-+           /*
-+            * If we previously encountered an error, we still continue
-+            * through the loop, to avoid memory leaks, but we don't waste
-+            * time accumulating any further results.
-+            *
-+            * XXX: There may be a more efficient way to exit the loop with no
-+            * leaks, but it will likely be more fragile and not worth the
-+            * extra code.
-+            */
-+           if (dict_errno != 0 || vals[0] == 0) {
-+               ldap_value_free(vals);
-+               continue;
-+           }
-+
-+           /*
-+            * The "result_attributes" list enumerates all the requested
-+            * attributes, first the ordinary result attribtutes and then the
-+            * special result attributes that hold DN or LDAP URL values.
-+            *
-+            * The number of ordinary attributes is "num_attributes".
-+            *
-+            * We compute the attribute type (ordinary or special) from its
-+            * index on the "result_attributes" list.
-+            */
-           for (i = 0; dict_ldap->result_attributes->argv[i]; i++) {
--              if (strcasecmp(dict_ldap->result_attributes->argv[i],
--                             attr) == 0) {
--                  if (msg_verbose)
--                      msg_info("%s: search returned %ld value(s) for requested result attribute %s", myname, i, attr);
-+              if (strcasecmp(dict_ldap->result_attributes->argv[i], attr) == 0)
-                   break;
--              }
-           }
-           /*
-@@ -532,20 +772,38 @@
-            * recursing (for dn or url attributes).
-            */
-           if (i < dict_ldap->num_attributes) {
-+              /* Ordinary result attribute */
-               for (i = 0; vals[i] != NULL; i++) {
-+                   if (++expansion > dict_ldap->expansion_limit &&
-+                       dict_ldap->expansion_limit) {
-+                       msg_warn("%s[%d]: %s: Expansion limit exceeded at"
-+                              " result attribute %s=%s", myname, recursion,
-+                                dict_ldap->ldapsource, attr, vals[i]);
-+                       dict_errno = DICT_ERR_RETRY;
-+                       break;
-+                   }
-                   if (VSTRING_LEN(result) > 0)
-                       vstring_strcat(result, ",");
-                   if (dict_ldap->result_filter == NULL)
-                       vstring_strcat(result, vals[i]);
-                   else
--                      dict_ldap_expand_filter(dict_ldap->result_filter,
-+                      dict_ldap_expand_filter(dict_ldap->ldapsource,
-+                                              dict_ldap->result_filter,
-                                               vals[i], result);
-               }
--          } else if (dict_ldap->result_attributes->argv[i]) {
-+               if (dict_errno != 0)
-+                   continue;
-+               if (msg_verbose)
-+                   msg_info("%s[%d]: search returned %ld value(s) for"
-+                            " requested result attribute %s",
-+                            myname, recursion, i, attr);
-+           } else if (recursion < dict_ldap->recursion_limit
-+                      && dict_ldap->result_attributes->argv[i]) {
-+               /* Special result attribute */
-               for (i = 0; vals[i] != NULL; i++) {
-                   if (ldap_is_ldap_url(vals[i])) {
-                       if (msg_verbose)
--                          msg_info("%s: looking up URL %s", myname,
-+                          msg_info("%s[%d]: looking up URL %s", myname, recursion,
-                                    vals[i]);
-                       rc = ldap_url_parse(vals[i], &url);
-                       if (rc == 0) {
-@@ -557,7 +815,7 @@
-                       }
-                   } else {
-                       if (msg_verbose)
--                          msg_info("%s: looking up DN %s", myname, vals[i]);
-+                          msg_info("%s[%d]: looking up DN %s", myname, recursion, vals[i]);
-                       rc = ldap_search_st(dict_ldap->ld, vals[i],
-                                           LDAP_SCOPE_BASE, "objectclass=*",
-                                        dict_ldap->result_attributes->argv,
-@@ -573,11 +831,11 @@
-                        * Go ahead and treat this as though the DN existed
-                        * and just didn't have any result attributes.
-                        */
--                      msg_warn("%s: DN %s not found, skipping ", myname,
--                               vals[i]);
-+                      msg_warn("%s[%d]: DN %s not found, skipping ", myname,
-+                               recursion, vals[i]);
-                       break;
-                   default:
--                      msg_warn("%s: search error %d: %s ", myname, rc,
-+                      msg_warn("%s[%d]: search error %d: %s ", myname, recursion, rc,
-                                ldap_err2string(rc));
-                       dict_errno = DICT_ERR_RETRY;
-                       break;
-@@ -585,7 +843,21 @@
-                   if (resloop != 0)
-                       ldap_msgfree(resloop);
-+                   if (dict_errno != 0)
-+                       break;
-               }
-+               if (dict_errno != 0)
-+                   continue;
-+               if (msg_verbose)
-+                   msg_info("%s[%d]: search returned %ld value(s) for"
-+                            " special result attribute %s",
-+                            myname, recursion, i, attr);
-+           } else if (recursion >= dict_ldap->recursion_limit
-+                      && dict_ldap->result_attributes->argv[i]) {
-+               msg_warn("%s[%d]: %s: Recursion limit exceeded"
-+                        " for special attribute %s=%s",
-+                  myname, recursion, dict_ldap->ldapsource, attr, vals[0]);
-+               dict_errno = DICT_ERR_RETRY;
-           }
-           ldap_value_free(vals);
-       }
-@@ -593,7 +865,8 @@
-           ber_free(ber, 0);
-     }
-     if (msg_verbose)
--      msg_info("%s: Leaving %s", myname, myname);
-+      msg_info("%s[%d]: Leaving %s", myname, recursion, myname);
-+    --recursion;
- }
- /* dict_ldap_lookup - find database entry */
-@@ -608,6 +881,7 @@
-     VSTRING *escaped_name = 0,
-            *filter_buf = 0;
-     int     rc = 0;
-+    int     sizelimit;
-     char   *sub,
-            *end;
-@@ -624,11 +898,8 @@
-     if (dict_ldap->domain) {
-       const char *p = strrchr(name, '@');
--      if (p != 0)
--          p = p + 1;
--      else
--          p = name;
--      if (match_list_match(dict_ldap->domain, p) == 0) {
-+       if (p == 0 || p == name ||
-+           match_list_match(dict_ldap->domain, ++p) == 0) {
-           if (msg_verbose)
-               msg_info("%s: domain of %s not found in domain list", myname,
-                        name);
-@@ -644,6 +915,13 @@
-     vstring_strcpy(result, "");
-     /*
-+     * Because the connection may be shared and invalidated via queries for
-+     * another map, update private copy of "ld" from shared connection
-+     * container.
-+     */
-+    dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld;
-+
-+    /*
-      * Connect to the LDAP server, if necessary.
-      */
-     if (dict_ldap->ld == NULL) {
-@@ -663,6 +941,18 @@
-       msg_info("%s: Using existing connection for LDAP source %s",
-                myname, dict_ldap->ldapsource);
-+    /*
-+     * Connection caching, means that the connection handle may have the
-+     * wrong size limit. Re-adjust before each query. This is cheap, just
-+     * sets a field in the ldap connection handle. We also do this in the
-+     * connect code, because we sometimes reconnect (below) in the middle of
-+     * a query.
-+     */
-+    sizelimit = dict_ldap->size_limit ? dict_ldap->size_limit : LDAP_NO_LIMIT;
-+    if (ldap_set_option(dict_ldap->ld, LDAP_OPT_SIZELIMIT, &sizelimit)
-+       != LDAP_OPT_SUCCESS)
-+       msg_warn("%s: %s: Unable to set query result size limit to %ld.",
-+                myname, dict_ldap->ldapsource, dict_ldap->size_limit);
-     /*
-      * Prepare the query.
-@@ -720,11 +1010,11 @@
-       /*
-        * No, log the fact and continue.
-        */
--      msg_warn("%s: Fixed query_filter %s is probably useless", myname,
--               dict_ldap->query_filter);
-+      msg_warn("%s: %s: Fixed query_filter %s is probably useless", myname,
-+               dict_ldap->ldapsource, dict_ldap->query_filter);
-       vstring_strcpy(filter_buf, dict_ldap->query_filter);
-     } else {
--      dict_ldap_expand_filter(dict_ldap->query_filter,
-+      dict_ldap_expand_filter(dict_ldap->ldapsource, dict_ldap->query_filter,
-                               vstring_str(escaped_name), filter_buf);
-     }
-@@ -747,7 +1037,7 @@
-                    myname, dict_ldap->ldapsource);
-       ldap_unbind(dict_ldap->ld);
--      dict_ldap->ld = NULL;
-+      dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
-       dict_ldap_connect(dict_ldap);
-       /*
-@@ -799,7 +1089,7 @@
-        * next lookup.
-        */
-       ldap_unbind(dict_ldap->ld);
--      dict_ldap->ld = NULL;
-+       dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
-       /*
-        * And tell the caller to try again later.
-@@ -830,9 +1120,18 @@
- {
-     char   *myname = "dict_ldap_close";
-     DICT_LDAP *dict_ldap = (DICT_LDAP *) dict;
-+    LDAP_CONN *conn = DICT_LDAP_CONN(dict_ldap);
-+    BINHASH_INFO *ht = dict_ldap->ht;
--    if (dict_ldap->ld)
--      ldap_unbind(dict_ldap->ld);
-+    if (--conn->conn_refcount == 0) {
-+       if (conn->conn_ld) {
-+           if (msg_verbose)
-+               msg_info("%s: Closed connection handle for LDAP source %s",
-+                        myname, dict_ldap->ldapsource);
-+           ldap_unbind(conn->conn_ld);
-+       }
-+       binhash_delete(conn_hash, ht->key, ht->key_len, myfree);
-+    }
-     myfree(dict_ldap->ldapsource);
-     myfree(dict_ldap->server_host);
-@@ -845,19 +1144,32 @@
-     argv_free(dict_ldap->result_attributes);
-     myfree(dict_ldap->bind_dn);
-     myfree(dict_ldap->bind_pw);
-+#ifdef LDAP_API_FEATURE_X_OPENLDAP
-+    myfree(dict_ldap->tls_ca_cert_file);
-+    myfree(dict_ldap->tls_ca_cert_dir);
-+    myfree(dict_ldap->tls_cert);
-+    myfree(dict_ldap->tls_key);
-+    myfree(dict_ldap->tls_random_file);
-+    myfree(dict_ldap->tls_cipher_suite);
-+#endif
-     dict_free(dict);
- }
- /* dict_ldap_open - create association with data base */
--DICT   *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
-+DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
- {
-     char   *myname = "dict_ldap_open";
-     DICT_LDAP *dict_ldap;
-     VSTRING *config_param;
-+    VSTRING *url_list;
-+    char   *s;
-+    char   *h;
-     char   *domainlist;
-+    char   *server_host;
-     char   *scope;
-     char   *attr;
-+    int    tmp;
-     if (msg_verbose)
-       msg_info("%s: Using LDAP source %s", myname, ldapsource);
-@@ -870,15 +1182,14 @@
-     dict_ldap->ldapsource = mystrdup(ldapsource);
-+    dict_ldap->ld = NULL;
-+
-     config_param = vstring_alloc(15);
-     vstring_sprintf(config_param, "%s_server_host", ldapsource);
--    dict_ldap->server_host =
-+    server_host =
-       mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
--                                          "localhost", 0, 0));
--    if (msg_verbose)
--      msg_info("%s: %s is %s", myname, vstring_str(config_param),
--               dict_ldap->server_host);
-+                                          "localhost", 1, 0));
-     /*
-      * get configured value of "ldapsource_server_port"; default to LDAP_PORT
-@@ -892,11 +1203,87 @@
-                dict_ldap->server_port);
-     /*
-+     * Define LDAP Version.
-+     */
-+    vstring_sprintf(config_param, "%s_version", ldapsource);
-+    dict_ldap->version = get_mail_conf_int(vstring_str(config_param), 2, 2, 0);
-+    switch (dict_ldap->version) {
-+    case 2:
-+        dict_ldap->version = LDAP_VERSION2;
-+        break;
-+    case 3:
-+        dict_ldap->version = LDAP_VERSION3;
-+        break;
-+    default:
-+        msg_warn("%s: Unknown version %d.", myname, dict_ldap->version);
-+        dict_ldap->version = LDAP_VERSION2;
-+    }
-+
-+#if defined(LDAP_API_FEATURE_X_OPENLDAP)
-+    dict_ldap->ldap_ssl = 0;
-+#endif
-+
-+    url_list = vstring_alloc(32);
-+    s = server_host;
-+    while ((h = mystrtok(&s, " \t\n\r,")) != NULL) {
-+#if defined(LDAP_API_FEATURE_X_OPENLDAP)
-+
-+       /*
-+        * Convert (host, port) pairs to LDAP URLs
-+        */
-+       if (ldap_is_ldap_url(h)) {
-+           LDAPURLDesc *url_desc;
-+           int     rc;
-+
-+           if ((rc = ldap_url_parse(h, &url_desc)) != 0) {
-+               msg_error("%s: error parsing URL %s: %d: %s; skipping", myname,
-+                         h, rc, ldap_err2string(rc));
-+               continue;
-+           }
-+           if (strcasecmp(url_desc->lud_scheme, "ldap") != 0 &&
-+               dict_ldap->version != LDAP_VERSION3) {
-+               msg_warn("%s: URL scheme %s requires protocol version 3", myname,
-+                        url_desc->lud_scheme);
-+               dict_ldap->version = LDAP_VERSION3;
-+           }
-+           if (strcasecmp(url_desc->lud_scheme, "ldaps") == 0)
-+               dict_ldap->ldap_ssl = 1;
-+           ldap_free_urldesc(url_desc);
-+           vstring_sprintf_append(url_list, " %s", h);
-+       } else {
-+           if (strrchr(h, ':'))
-+               vstring_sprintf_append(url_list, " ldap://%s", h);
-+           else
-+               vstring_sprintf_append(url_list, " ldap://%s:%d", h,
-+                                      dict_ldap->server_port);
-+       }
-+#else
-+       vstring_sprintf_append(url_list, " %s", h);
-+#endif
-+    }
-+
-+     dict_ldap->server_host =
-+       mystrdup(VSTRING_LEN(url_list) > 0 ? vstring_str(url_list) + 1 : "");
-+
-+#if defined(LDAP_API_FEATURE_X_OPENLDAP)
-+    /*
-+     * With URL scheme, clear port to normalize connection cache key
-+     */
-+
-+     dict_ldap->server_port = LDAP_PORT;
-+     if (msg_verbose)
-+       msg_info("%s: %s server_host URL is %s", myname, ldapsource,
-+                dict_ldap->server_host);
-+#endif
-+    myfree(server_host);
-+    vstring_free(url_list);
-+
-+    /*
-      * Scope handling thanks to Carsten Hoeger of SuSE.
-      */
-     vstring_sprintf(config_param, "%s_scope", ldapsource);
-     scope =
--      (char *) get_mail_conf_str(vstring_str(config_param), "sub", 0, 0);
-+      (char *) get_mail_conf_str(vstring_str(config_param), "sub", 1, 0);
-     if (strcasecmp(scope, "one") == 0) {
-       dict_ldap->scope = LDAP_SCOPE_ONELEVEL;
-@@ -910,12 +1297,15 @@
-           msg_info("%s: %s is LDAP_SCOPE_BASE", myname,
-                    vstring_str(config_param));
--    } else {
-+    } else if (strcasecmp(scope, "sub") == 0) {
-       dict_ldap->scope = LDAP_SCOPE_SUBTREE;
-       if (msg_verbose)
-           msg_info("%s: %s is LDAP_SCOPE_SUBTREE", myname,
-                    vstring_str(config_param));
--
-+    } else {
-+      dict_ldap->scope = LDAP_SCOPE_SUBTREE;
-+        msg_warn("%s: %s: Unrecognized value %s specified for scope; using sub",
-+                 myname, vstring_str(config_param), scope);
-     }
-     myfree(scope);
-@@ -992,6 +1382,8 @@
-       msg_info("%s: %s is %s", myname, vstring_str(config_param), attr);;
-     dict_ldap->result_attributes = argv_split(attr, " ,\t\r\n");
-     dict_ldap->num_attributes = dict_ldap->result_attributes->argc;
-+    
-+    myfree(attr);
-     vstring_sprintf(config_param, "%s_special_result_attribute", ldapsource);
-     attr = mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
-@@ -1003,6 +1395,8 @@
-       argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n");
-     }
-+     myfree(attr);
-+
-     /*
-      * get configured value of "ldapsource_bind"; default to true
-      */
-@@ -1040,31 +1434,60 @@
-      * get configured value of "ldapsource_cache"; default to false
-      */
-     vstring_sprintf(config_param, "%s_cache", ldapsource);
--    dict_ldap->cache = get_mail_conf_bool(vstring_str(config_param), 0);
--    if (msg_verbose)
--      msg_info("%s: %s is %d", myname, vstring_str(config_param),
--               dict_ldap->cache);
-+    tmp = get_mail_conf_bool(vstring_str(config_param), 0);
-+    if (tmp)
-+      msg_warn("%s: %s ignoring cache", myname, vstring_str(config_param));
-     /*
-      * get configured value of "ldapsource_cache_expiry"; default to 30
-      * seconds
-      */
-     vstring_sprintf(config_param, "%s_cache_expiry", ldapsource);
--    dict_ldap->cache_expiry = get_mail_conf_int(vstring_str(config_param),
--                                              30, 0, 0);
--    if (msg_verbose)
--      msg_info("%s: %s is %ld", myname, vstring_str(config_param),
--               dict_ldap->cache_expiry);
-+    tmp = get_mail_conf_int(vstring_str(config_param), -1, 0, 0);
-+
-+    if (tmp >= 0)
-+       msg_warn("%s: %s ignoring cache_expiry", myname, vstring_str(config_param));
-     /*
-      * get configured value of "ldapsource_cache_size"; default to 32k
-      */
-     vstring_sprintf(config_param, "%s_cache_size", ldapsource);
--    dict_ldap->cache_size = get_mail_conf_int(vstring_str(config_param),
--                                            32768, 0, 0);
-+    tmp = get_mail_conf_int(vstring_str(config_param),
-+                                            -1, 0, 0);
-+    if (tmp >= 0)
-+       msg_warn("%s: %s ignoring cache_size", myname, vstring_str(config_param));
-+
-+    /*
-+     * get configured value of "recursion_limit"; default to 1000
-+     */
-+    vstring_sprintf(config_param, "%s_recursion_limit", ldapsource);
-+    dict_ldap->recursion_limit = get_mail_conf_int(vstring_str(config_param),
-+                                              1000, 1, 0);
-+
-+    if (msg_verbose)
-+        msg_info("%s: %s is %ld", myname, vstring_str(config_param),
-+                 dict_ldap->recursion_limit);
-+    
-+    /*
-+     * Define LDAP Version.
-+     * get configured value of "expansion_limit"; default to 0
-+     */
-+
-+    vstring_sprintf(config_param, "%s_expansion_limit", ldapsource);
-+    dict_ldap->expansion_limit = get_mail_conf_int(vstring_str(config_param),
-+                                                0, 0, 0);
-+    if (msg_verbose)
-+        msg_info("%s: %s is %ld", myname, vstring_str(config_param),
-+                 dict_ldap->expansion_limit);
-+    /*
-+     * get configured value of "size_limit"; default to expansion_limit
-+     */
-+    vstring_sprintf(config_param, "%s_size_limit", ldapsource);
-+    dict_ldap->size_limit = get_mail_conf_int(vstring_str(config_param),
-+                                        dict_ldap->expansion_limit, 0, 0);
-     if (msg_verbose)
--      msg_info("%s: %s is %ld", myname, vstring_str(config_param),
--               dict_ldap->cache_size);
-+        msg_info("%s: %s is %ld", myname, vstring_str(config_param),
-+                 dict_ldap->size_limit);
-     /*
-      * Alias dereferencing suggested by Mike Mattice.
-@@ -1074,29 +1497,11 @@
-                                              0);
-     /*
--     * Define LDAP Version.
--     */
--    vstring_sprintf(config_param, "%s_version", ldapsource);
--    dict_ldap->version = get_mail_conf_int(vstring_str(config_param), 2, 0,
--                                         0);
--    switch (dict_ldap->version) {
--    case 2:
--      dict_ldap->version = LDAP_VERSION2;
--      break;
--    case 3:
--      dict_ldap->version = LDAP_VERSION3;
--      break;
--    default:
--      msg_warn("%s: Unknown version %d.", myname, dict_ldap->version);
--      dict_ldap->version = LDAP_VERSION2;
--    }
--
--    /*
-      * Make sure only valid options for alias dereferencing are used.
-      */
-     if (dict_ldap->dereference < 0 || dict_ldap->dereference > 3) {
--      msg_warn("%s: Unrecognized value %d specified for %s; using 0",
--               myname, dict_ldap->dereference, vstring_str(config_param));
-+      msg_warn("%s: %s: Unrecognized value %d specified for %s; using 0",
-+               myname, ldapsource, dict_ldap->dereference, vstring_str(config_param));
-       dict_ldap->dereference = 0;
-     }
-     if (msg_verbose)
-@@ -1110,6 +1515,68 @@
-       msg_info("%s: %s is %d", myname, vstring_str(config_param),
-                dict_ldap->chase_referrals);
-+#ifdef LDAP_API_FEATURE_X_OPENLDAP
-+
-+    /*
-+     * TLS options
-+     */
-+    /* get configured value of "start_tls"; default to no */
-+    vstring_sprintf(config_param, "%s_start_tls", ldapsource);
-+    dict_ldap->start_tls = get_mail_conf_bool(vstring_str(config_param), 0);
-+    if (dict_ldap->start_tls && dict_ldap->version < LDAP_VERSION3) {
-+       msg_warn("%s: %s start_tls requires protocol version 3",
-+                myname, ldapsource);
-+       dict_ldap->version = LDAP_VERSION3;
-+    }
-+
-+    /* get configured value of "tls_require_cert"; default to no */
-+    vstring_sprintf(config_param, "%s_tls_require_cert", ldapsource);
-+    dict_ldap->tls_require_cert = get_mail_conf_bool(vstring_str(config_param), 0);
-+
-+    /* get configured value of "tls_ca_cert_file"; default "" */
-+    vstring_sprintf(config_param, "%s_tls_ca_cert_file", ldapsource);
-+    dict_ldap->tls_ca_cert_file = mystrdup((char *)
-+                                  get_mail_conf_str(vstring_str
-+                                                    (config_param), "", 0,
-+                                                    0));
-+
-+    /* get configured value of "tls_ca_cert_dir"; default "" */
-+    vstring_sprintf(config_param, "%s_tls_ca_cert_dir", ldapsource);
-+    dict_ldap->tls_ca_cert_dir = mystrdup((char *)
-+                                  get_mail_conf_str(vstring_str
-+                                                    (config_param), "", 0,
-+                                                    0));
-+
-+    /* get configured value of "tls_cert"; default "" */
-+    vstring_sprintf(config_param, "%s_tls_cert", ldapsource);
-+    dict_ldap->tls_cert = mystrdup((char *)
-+                                  get_mail_conf_str(vstring_str
-+                                                    (config_param), "", 0,
-+                                                    0));
-+
-+    /* get configured value of "tls_key"; default "" */
-+    vstring_sprintf(config_param, "%s_tls_key", ldapsource);
-+    dict_ldap->tls_key = mystrdup((char *)
-+                                  get_mail_conf_str(vstring_str
-+                                                    (config_param), "", 0,
-+                                                    0));
-+
-+    /* get configured value of "tls_random_file"; default "" */
-+    vstring_sprintf(config_param, "%s_tls_random_file", ldapsource);
-+    dict_ldap->tls_random_file = mystrdup((char *)
-+                                  get_mail_conf_str(vstring_str
-+                                                    (config_param), "", 0,
-+                                                    0));
-+
-+    /* get configured value of "tls_cipher_suite"; default "" */
-+    vstring_sprintf(config_param, "%s_tls_cipher_suite", ldapsource);
-+    dict_ldap->tls_cipher_suite = mystrdup((char *)
-+                                  get_mail_conf_str(vstring_str
-+                                                    (config_param), "", 0,
-+                                                    0));
-+#endif
-+
-+
-     /*
-      * Debug level.
-      */
-@@ -1122,21 +1589,13 @@
-                dict_ldap->debuglevel);
- #endif
--    dict_ldap_connect(dict_ldap);
--
-     /*
--     * if dict_ldap_connect() set dict_errno, free dict_ldap and abort.
-+     * Find or allocate shared LDAP connection container.
-      */
--    if (dict_errno) {
--      if (dict_ldap->ld)
--          ldap_unbind(dict_ldap->ld);
--
--      myfree((char *) dict_ldap);
--      return (0);
--    }
-+    dict_ldap_conn_find(dict_ldap);
-     /*
--     * Otherwise, we're all set. Return the new dict_ldap structure.
-+     * Return the new dict_ldap structure.
-      */
-     return (DICT_DEBUG (&dict_ldap->dict));
- }
diff --git a/postfix-ns-mx-acl.patch b/postfix-ns-mx-acl.patch
deleted file mode 100644 (file)
index 6c29adc..0000000
+++ /dev/null
@@ -1,478 +0,0 @@
-This is an unofficial patch for Postfix stable release 2.0 that
-back-ports a new feature from the after-2.0 snapshot releases.
-
-This feature can be used to block mail from so-called spammer
-havens, from sender addresses that resolve to Verisign's wild-card
-mail responder, or from domains that claim to have mail servers in
-reserved networks such as 127.0.0.1.
-
-This patch is a revised version; the first implementation of the
-check_{helo,sender,recipient}_ns_access feature did not correctly
-look up name server records and caused mail to be deferred with a
-450 status code; the second revision no longer defers mail when
-some NS or MX host lookup fails.
-
------------------
-
-The check_{helo,sender,recipient}_{ns,mx}_access maptype:mapname
-restriction applies the specified access table to the NS or MX
-hosts of the host/domain given in HELO, EHLO, MAIL FROM or RCPT TO
-commands.
-
-    /etc/postfix/main.cf:
-        smtpd_mumble_restrictions =
-            ...
-            reject_unknown_sender_domain
-            check_sender_mx_access hash:/etc/postfix/mx_access
-            ...
-
-    /etc/postfix/mx_access:
-        spammer.haven.tld reject spammer mx host
-        64.94.110.11      reject mail server in verisign wild-card domain
-        127               reject mail server in loopback network
-        0                 reject mail server in broadcast network
-
-The following entries block mail from domains that claim to have
-have mail servers or domain servers in reserved networks.
-
-        10                reject mail server in RFC 1918 private network
-        169.254           reject mail server in link local network
-        172.16            reject mail server in RFC 1918 private network
-        ...similar entries for 172.17...172.31
-        192.0.2           reject mail server in TEST-NET network
-        192.168           reject mail server in RFC 1918 private network
-        224               reject mail server in class D multicast network
-        ...similar entries for 225...239
-        240               reject mail server in class E reserved network
-        ...similar entries for 241...247
-        248               reject mail server in reserved network
-        ...similar entries for 249...255
-
-diff -cr /tmp/postfix-2.0.16/conf/sample-smtpd.cf ./conf/sample-smtpd.cf
-*** /tmp/postfix-2.0.16/conf/sample-smtpd.cf   Tue Aug 12 12:28:46 2003
---- ./conf/sample-smtpd.cf     Fri Sep 19 11:17:34 2003
-***************
-*** 311,316 ****
---- 311,321 ----
-  #   check_helo_access maptype:mapname
-  #    look up HELO hostname or parent domains.
-  #    see access(5) for possible lookup results.
-+ #   check_helo_mx_access maptype:mapname
-+ #   check_helo_ns_access maptype:mapname
-+ #    look up the helo hostname MX hosts (or name servers) and apply the
-+ #    specified access table to those hosts.
-+ #    Note: the OK result is not allowed here for security reasons.
-  #   reject: reject the request. Place this at the end of a restriction.
-  #   permit: permit the request. Place this at the end of a restriction.
-  #   warn_if_reject: next restriction logs a warning instead of rejecting.
-***************
-*** 343,348 ****
---- 348,358 ----
-  #   check_sender_access maptype:mapname
-  #    look up sender address, parent domain, or localpart@.
-  #    see access(5) for possible lookup results.
-+ #   check_sender_mx_access maptype:mapname
-+ #   check_sender_ns_access maptype:mapname
-+ #    look up sender address MX hosts (or name servers) and apply the
-+ #    specified access table to those hosts.
-+ #    Note: the OK result is not allowed here for security reasons.
-  #   reject_sender_login_mismatch: reject if $smtpd_sender_login_maps specifies
-  #    a MAIL FROM address owner, but the client is not (SASL) logged in as
-  #    that MAIL FROM address owner; or if the client is (SASL) logged in, but
-***************
-*** 409,414 ****
---- 419,429 ----
-  #   check_recipient_access maptype:mapname
-  #    look up recipient address, parent domain, or localpart@.
-  #    see access(5) for possible lookup results.
-+ #   check_recipient_mx_access maptype:mapname
-+ #   check_recipient_ns_access maptype:mapname
-+ #    look up the recipient address MX hosts (or name servers) and apply the
-+ #    specified access table to those hosts.
-+ #    Note: the OK result is not allowed here for security reasons.
-  #   reject_non_fqdn_recipient: reject recipient address that is not in FQDN form
-  #   reject: reject the request. Place this at the end of a restriction.
-  #   permit: permit the request. Place this at the end of a restriction.
-diff -cr /tmp/postfix-2.0.16/html/uce.html ./html/uce.html
-*** /tmp/postfix-2.0.16/html/uce.html  Mon Aug 25 09:54:11 2003
---- ./html/uce.html    Fri Sep 19 11:17:34 2003
-***************
-*** 567,572 ****
---- 567,588 ----
-  
-  <p>
-  
-+ <a name="check_helo_ns_access">
-+ 
-+ <dt> <b>check_helo_ns_access</b> <i>maptype</i>:<i>mapname</i>
-+ 
-+ <a name="check_helo_mx_access">
-+ 
-+ <dt> <b>check_helo_mx_access</b> <i>maptype</i>:<i>mapname</i>
-+ 
-+ <dd> Apply the specified <a href="access.5.html">access database</a>
-+ to the DNS (or MX) servers for the host or domain name given with
-+ the HELO (or EHLO) command.
-+ 
-+ <dd> Note: an OK result is not allowed for safety reasons.
-+ 
-+ <p>
-+ 
-  <dt> <b><a href="#permit">permit</a></b>
-  
-  <dt> <b><a href="#defer">defer</a></b>
-***************
-*** 714,719 ****
---- 730,751 ----
-  
-  <p>
-  
-+ <a name="check_sender_ns_access">
-+ 
-+ <dt> <b>check_sender_ns_access</b> <i>maptype</i>:<i>mapname</i>
-+ 
-+ <a name="check_sender_mx_access">
-+ 
-+ <dt> <b>check_sender_mx_access</b> <i>maptype</i>:<i>mapname</i>
-+ 
-+ <dd> Apply the specified <a href="access.5.html">access database</a>
-+ to the DNS (or MX) servers for the host or domain name given with
-+ the MAIL FROM command.
-+ 
-+ <dd> Note: an OK result is not allowed for safety reasons.
-+ 
-+ <p>
-+ 
-  <a name="reject_non_fqdn_sender">
-  
-  <dt> <b>reject_non_fqdn_sender</b> <dd> Reject the request when
-***************
-*** 921,926 ****
---- 953,974 ----
-  <dt> <i>maptype</i>:<i>mapname</i> <dd> Search the named <a
-  href="access.5.html">access database</a> for the resolved destination
-  address, recipient domain or parent domain, or <i>localpart</i>@. 
-+ 
-+ <p>
-+ 
-+ <a name="check_recipient_ns_access">
-+ 
-+ <dt> <b>check_recipient_ns_access</b> <i>maptype</i>:<i>mapname</i>
-+ 
-+ <a name="check_recipient_mx_access">
-+ 
-+ <dt> <b>check_recipient_mx_access</b> <i>maptype</i>:<i>mapname</i>
-+ 
-+ <dd> Apply the specified <a href="access.5.html">access database</a>
-+ to the DNS servers (or MX hosts) for the host or domain name given
-+ with the RCPT TO command.
-+ 
-+ <dd> Note: an OK result is not allowed for safety reasons.
-  
-  <p>
-  
-diff -cr /tmp/postfix-2.0.16/src/dns/dns_lookup.c ./src/dns/dns_lookup.c
-*** /tmp/postfix-2.0.16/src/dns/dns_lookup.c   Sun Dec  8 09:09:11 2002
---- ./src/dns/dns_lookup.c     Fri Sep 19 11:17:34 2003
-***************
-*** 509,514 ****
---- 509,515 ----
-           vstring_sprintf(why,
-                  "Name service error for %s: invalid host or domain name",
-                           name);
-+      h_errno = HOST_NOT_FOUND;
-       return (DNS_NOTFOUND);
-      }
-  
-***************
-*** 520,525 ****
---- 521,527 ----
-           vstring_sprintf(why,
-                  "Name service error for %s: invalid host or domain name",
-                           name);
-+      h_errno = HOST_NOT_FOUND;
-       return (DNS_NOTFOUND);
-      }
-  
-diff -cr /tmp/postfix-2.0.16/src/global/mail_params.h ./src/global/mail_params.h
-*** /tmp/postfix-2.0.16/src/global/mail_params.h       Mon Mar  3 17:07:03 2003
---- ./src/global/mail_params.h Fri Sep 19 11:17:35 2003
-***************
-*** 1249,1254 ****
---- 1249,1261 ----
-  #define CHECK_RECIP_ACL              "check_recipient_access"
-  #define CHECK_ETRN_ACL               "check_etrn_access"
-  
-+ #define CHECK_HELO_MX_ACL    "check_helo_mx_access"
-+ #define CHECK_SENDER_MX_ACL  "check_sender_mx_access"
-+ #define CHECK_RECIP_MX_ACL   "check_recipient_mx_access"
-+ #define CHECK_HELO_NS_ACL    "check_helo_ns_access"
-+ #define CHECK_SENDER_NS_ACL  "check_sender_ns_access"
-+ #define CHECK_RECIP_NS_ACL   "check_recipient_ns_access"
-+ 
-  #define WARN_IF_REJECT               "warn_if_reject"
-  
-  #define REJECT_RBL           "reject_rbl"    /* LaMont compatibility */
-diff -cr /tmp/postfix-2.0.16/src/smtpd/smtpd_check.c ./src/smtpd/smtpd_check.c
-*** /tmp/postfix-2.0.16/src/smtpd/smtpd_check.c        Tue Aug 12 10:53:25 2003
---- ./src/smtpd/smtpd_check.c  Fri Sep 19 11:17:52 2003
-***************
-*** 86,91 ****
---- 86,103 ----
-  /* .IP "check_recipient_access maptype:mapname"
-  /*   Look up the resolved recipient address in the named access table,
-  /*   any parent domains of the recipient domain, and the localpart@.
-+ /* .IP "check_helo_mx_access maptype:mapname"
-+ /* .IP "check_sender_mx_access maptype:mapname"
-+ /* .IP "check_recipient_mx_access maptype:mapname"
-+ /*   Apply the specified access table to the MX server host name and IP
-+ /*   addresses for the helo hostname, sender, or recipient, respectively.
-+ /*   If no MX record is found the A record is used instead.
-+ /* .IP "check_helo_ns_access maptype:mapname"
-+ /* .IP "check_sender_ns_access maptype:mapname"
-+ /* .IP "check_recipient_ns_access maptype:mapname"
-+ /*   Apply the specified access table to the DNS server host name and IP
-+ /*   addresses for the helo hostname, sender, or recipient, respectively.
-+ /*   If no NS record is found, the parent domain is used instead.
-  /* .IP "check_recipient_maps"
-  /*   Reject recipients not listed as valid local, virtual or relay
-  /*   recipients.
-***************
-*** 455,460 ****
---- 467,484 ----
-      else \
-       (void) smtpd_check_reject((state), (class), (fmt), (a1), (a2)); \
-      } while (0)
-+ #define DEFER_IF_PERMIT3(state, class, fmt, a1, a2, a3) do { \
-+     if ((state)->warn_if_reject == 0) \
-+      defer_if(&(state)->defer_if_permit, (class), (fmt), (a1), (a2), (a3)); \
-+     else \
-+      (void) smtpd_check_reject((state), (class), (fmt), (a1), (a2), (a3)); \
-+     } while (0)
-+ #define DEFER_IF_PERMIT4(state, class, fmt, a1, a2, a3, a4) do { \
-+     if ((state)->warn_if_reject == 0) \
-+      defer_if(&(state)->defer_if_permit, (class), (fmt), (a1), (a2), (a3), (a4)); \
-+     else \
-+      (void) smtpd_check_reject((state), (class), (fmt), (a1), (a2), (a3), (a4)); \
-+     } while (0)
-  
-   /*
-    * Cached RBL lookup state.
-***************
-*** 2005,2010 ****
---- 2029,2151 ----
-      return (SMTPD_CHECK_DUNNO);
-  }
-  
-+ /* check_server_access - access control by server host name or address */
-+ 
-+ static int check_server_access(SMTPD_STATE *state, const char *table,
-+                                     const char *name,
-+                                     int type,
-+                                     const char *reply_name,
-+                                     const char *reply_class,
-+                                     const char *def_acl)
-+ {
-+     const char *myname = "check_server_access";
-+     const char *domain;
-+     int     dns_status;
-+     DNS_RR *server_list;
-+     DNS_RR *server;
-+     int     found = 0;
-+     struct in_addr addr;
-+     struct hostent *hp;
-+     char   *addr_string;
-+     int     status;
-+     char  **cpp;
-+     static DNS_FIXED fixed;
-+ 
-+     /*
-+      * Sanity check.
-+      */
-+     if (type != T_MX && type != T_NS)
-+      msg_panic("%s: unexpected resource type \"%s\" in request",
-+                myname, dns_strtype(type));
-+ 
-+     if (msg_verbose)
-+      msg_info("%s: %s %s", myname, dns_strtype(type), name);
-+ 
-+     /*
-+      * Skip over local-part.
-+      */
-+     if ((domain = strrchr(name, '@')) != 0)
-+      domain += 1;
-+     else
-+      domain = name;
-+ 
-+     /*
-+      * If the domain name does not exist then we apply no restriction.
-+      * 
-+      * If the domain name exists but no MX record exists, fabricate an MX record
-+      * that points to the domain name itself.
-+      * 
-+      * If the domain name exists but no NS record exists, look up parent domain
-+      * NS records.
-+      */
-+     dns_status = dns_lookup(domain, type, 0, &server_list,
-+                          (VSTRING *) 0, (VSTRING *) 0);
-+     if (dns_status == DNS_NOTFOUND && h_errno == NO_DATA) {
-+      if (type == T_MX) {
-+          server_list = dns_rr_create(domain, &fixed, 0,
-+                                      domain, strlen(domain) + 1);
-+          dns_status = DNS_OK;
-+      } else if (type == T_NS) {
-+          while ((domain = strchr(domain, '.')) != 0 && domain[1]) {
-+              domain += 1;
-+              dns_status = dns_lookup(domain, type, 0, &server_list,
-+                                      (VSTRING *) 0, (VSTRING *) 0);
-+              if (dns_status != DNS_NOTFOUND || h_errno != NO_DATA)
-+                  break;
-+          }
-+      }
-+     }
-+     if (dns_status != DNS_OK) {
-+      msg_warn("Unable to look up %s host for %s", dns_strtype(type),
-+               domain && domain[1] ? domain : reply_name);
-+      return (SMTPD_CHECK_DUNNO);
-+     }
-+ 
-+     /*
-+      * No bare returns after this point or we have a memory leak.
-+      */
-+ #define CHECK_SERVER_RETURN(x) { dns_rr_free(server_list); return(x); }
-+ 
-+     /*
-+      * Check the hostnames first, then the addresses.
-+      */
-+     for (server = server_list; server != 0; server = server->next) {
-+      if ((hp = gethostbyname((char *) server->data)) == 0) {
-+          msg_warn("Unable to look up %s host %s for %s %s",
-+                   dns_strtype(type), (char *) server->data,
-+                   reply_class, reply_name);
-+          continue;
-+      }
-+      if (hp->h_addrtype != AF_INET || hp->h_length != sizeof(addr)) {
-+          if (msg_verbose)
-+              msg_warn("address type %d length %d for %s",
-+                     hp->h_addrtype, hp->h_length, (char *) server->data);
-+          continue;                           /* XXX */
-+      }
-+      if (msg_verbose)
-+          msg_info("%s: %s hostname check: %s",
-+                   myname, dns_strtype(type), (char *) server->data);
-+      if ((status = check_domain_access(state, table, (char *) server->data,
-+                                    FULL, &found, reply_name, reply_class,
-+                                        def_acl)) != 0 || found)
-+          CHECK_SERVER_RETURN(status);
-+      if (msg_verbose)
-+          msg_info("%s: %s host address check: %s",
-+                   myname, dns_strtype(type), (char *) server->data);
-+      for (cpp = hp->h_addr_list; *cpp; cpp++) {
-+          memcpy((char *) &addr, *cpp, sizeof(addr));
-+          addr_string = mystrdup(inet_ntoa(addr));
-+          status = check_addr_access(state, table, addr_string, FULL,
-+                                     &found, reply_name, reply_class,
-+                                     def_acl);
-+          myfree(addr_string);
-+          if (status != 0 || found)
-+              CHECK_SERVER_RETURN(status);
-+      }
-+     }
-+     CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO);
-+ }
-+ 
-  /* check_mail_access - OK/FAIL based on mail address lookup */
-  
-  static int check_mail_access(SMTPD_STATE *state, const char *table,
-***************
-*** 2568,2573 ****
---- 2709,2728 ----
-      }
-  }
-  
-+ /* forbid_whitelist - disallow whitelisting */
-+ 
-+ static void forbid_whitelist(SMTPD_STATE *state, const char *name,
-+                                   int status, const char *target)
-+ {
-+     if (status == SMTPD_CHECK_OK) {
-+      msg_warn("restriction %s returns OK for %s", name, target);
-+      msg_warn("this is not allowed for security reasons");
-+      msg_warn("use DUNNO instead of OK if you want to make an exception");
-+      longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
-+                                       "451 Server configuration error"));
-+     }
-+ }
-+ 
-  /* generic_checks - generic restrictions */
-  
-  static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
-***************
-*** 2722,2727 ****
---- 2877,2896 ----
-                                  state->helo_name, SMTPD_NAME_HELO)) == 0)
-                   status = SMTPD_CHECK_OK;
-           }
-+      } else if (is_map_command(state, name, CHECK_HELO_NS_ACL, &cpp)) {
-+          if (state->helo_name) {
-+              status = check_server_access(state, *cpp, state->helo_name,
-+                                           T_NS, state->helo_name,
-+                                           SMTPD_NAME_HELO, def_acl);
-+              forbid_whitelist(state, name, status, state->helo_name);
-+          }
-+      } else if (is_map_command(state, name, CHECK_HELO_MX_ACL, &cpp)) {
-+          if (state->helo_name) {
-+              status = check_server_access(state, *cpp, state->helo_name,
-+                                           T_MX, state->helo_name,
-+                                           SMTPD_NAME_HELO, def_acl);
-+              forbid_whitelist(state, name, status, state->helo_name);
-+          }
-       } else if (strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) {
-           if (state->helo_name) {
-               if (*state->helo_name != '[')
-***************
-*** 2760,2765 ****
---- 2929,2948 ----
-       } else if (strcasecmp(name, REJECT_SENDER_LOGIN_MISMATCH) == 0) {
-           if (state->sender && *state->sender)
-               status = reject_sender_login_mismatch(state, state->sender);
-+      } else if (is_map_command(state, name, CHECK_SENDER_NS_ACL, &cpp)) {
-+          if (state->sender && *state->sender) {
-+              status = check_server_access(state, *cpp, state->sender,
-+                                           T_NS, state->sender,
-+                                           SMTPD_NAME_SENDER, def_acl);
-+              forbid_whitelist(state, name, status, state->sender);
-+          }
-+      } else if (is_map_command(state, name, CHECK_SENDER_MX_ACL, &cpp)) {
-+          if (state->sender && *state->sender) {
-+              status = check_server_access(state, *cpp, state->sender,
-+                                           T_MX, state->sender,
-+                                           SMTPD_NAME_SENDER, def_acl);
-+              forbid_whitelist(state, name, status, state->sender);
-+          }
-       } else if (strcasecmp(name, REJECT_RHSBL_SENDER) == 0) {
-           if (cpp[1] == 0)
-               msg_warn("restriction %s requires domain name argument", name);
-***************
-*** 2812,2817 ****
---- 2995,3014 ----
-           if (state->recipient)
-               status = reject_non_fqdn_address(state, state->recipient,
-                                   state->recipient, SMTPD_NAME_RECIPIENT);
-+      } else if (is_map_command(state, name, CHECK_RECIP_NS_ACL, &cpp)) {
-+          if (state->recipient && *state->recipient) {
-+              status = check_server_access(state, *cpp, state->recipient,
-+                                           T_NS, state->recipient,
-+                                           SMTPD_NAME_RECIPIENT, def_acl);
-+              forbid_whitelist(state, name, status, state->recipient);
-+          }
-+      } else if (is_map_command(state, name, CHECK_RECIP_MX_ACL, &cpp)) {
-+          if (state->recipient && *state->recipient) {
-+              status = check_server_access(state, *cpp, state->recipient,
-+                                           T_MX, state->recipient,
-+                                           SMTPD_NAME_RECIPIENT, def_acl);
-+              forbid_whitelist(state, name, status, state->recipient);
-+          }
-       } else if (strcasecmp(name, REJECT_RHSBL_RECIPIENT) == 0) {
-           if (cpp[1] == 0)
-               msg_warn("restriction %s requires domain name argument", name);
diff --git a/postfix-pgsql.patch b/postfix-pgsql.patch
deleted file mode 100644 (file)
index 596624c..0000000
+++ /dev/null
@@ -1,916 +0,0 @@
---- postfix-2.0.16.orig/PGSQL_README   1970-01-01 01:00:00.000000000 +0100
-+++ postfix-2.0.16/PGSQL_README        2003-11-08 20:11:44.000000000 +0100
-@@ -0,0 +1,88 @@
-+[Code contributed by Mathieu Arnold]
-+
-+We've written code to add a pgsql map type.  It utilizes the pgsql 
-+client library, which can be obtained from:
-+
-+                 http://www.postgresql.org/
-+
-+In order to build postfix with pgsql map support, you will need to add 
-+-DHAS_PGSQL and -I for the directory containing the postgres headers, and 
-+the libpq library (and libcrypt) to AUXLIBS, for example:
-+
-+make -f Makefile.init makefiles \
-+      'CCARGS=-DHAS_PGSQL -I/some/where/include/postgresql' \
-+      'AUXLIBS=/some/where/lib/postgres/libpq.a -lcrypt'
-+
-+then, just run 'make'.
-+
-+Postfix installations which may benefit from using pgsql map types
-+include sites that have a need for instantaneous updates of
-+forwarding, and sites that may benefit from having mail exchangers
-+reference a networked database, possibly working in conjunction with a
-+customer database of sorts.
-+
-+Once postfix is built with pgsql support, you can specify a map type
-+in main.cf like this:
-+
-+alias_maps = pgsql:/etc/postfix/pgsql-aliases.cf
-+
-+The file /etc/postfix/pgsql-aliases.cf specifies lots of information
-+telling postfix how to reference the postgresql database.  An example
-+postgresql map config file follows:
-+
-+#
-+# postgresql config file for alias lookups on postfix
-+# comments are ok.
-+#
-+
-+# the user name and password to log into the pgsql server
-+user = someone
-+password = some_passwordd 
-+
-+# the database name on the servers
-+dbname = customer_database
-+
-+# the table name
-+table = mxaliases
-+
-+#
-+select_field = forw_addr
-+where_field = alias
-+
-+# you may specify additional_conditions here
-+additional_conditions = and status = 'paid'
-+
-+# the above variables will result in a query of
-+# the form: 
-+# select forw_addr from mxaliases where alias = '$lookup' and status = 'paid'
-+# ($lookup is escaped so if it contains single quotes or other odd
-+# characters, it will not cause a parse error in the sql).
-+#
-+# the hosts that postfix will try to connect to
-+# and query from (in the order listed)
-+hosts = host1.some.domain host2.some.domain
-+
-+# end postgresql config file
-+
-+Some notes:
-+
-+This configuration interface setup allows for multiple postgresql
-+databases: you can use one for a virtual table, one for an access
-+table, and one for an aliases table if you want.
-+
-+Since sites that have a need for multiple mail exchangers may enjoy
-+the convenience of using a networked mailer database, but do not want 
-+to introduce a single point of failure to their system, we've included 
-+the ability to have postfix reference multiple hosts for access to a
-+single pgsql map.  This will work if sites set up mirrored pgsql
-+databases on two or more hosts.  Whenever queries fail with an error
-+at one host, the rest of the hosts will be tried in order.  Each host
-+that is in an error state will undergo a reconnection attempt every so 
-+often, and if no pgsql server hosts are reachable, then mail will be
-+deferred until atleast one of those hosts is reachable.
-+
-+Performance of postfix with pgsql has not been thoroughly tested,
-+however, we have found it to be stable.  Busy mail servers using pgsql
-+maps will generate lots of concurrent pgsql clients, so the pgsql
-+server(s) should be run with this fact in mind.  Any further
-+performance information, in addition to any feedback is most welcome.
---- postfix-2.0.16.orig/src/util/dict_open.c   2003-11-08 20:10:08.000000000 +0100
-+++ postfix-2.0.16/src/util/dict_open.c        2003-11-08 20:11:44.000000000 +0100
-@@ -178,6 +178,7 @@
- #include <dict_ni.h>
- #include <dict_ldap.h>
- #include <dict_mysql.h>
-+#include <dict_pgsql.h>
- #include <dict_pcre.h>
- #include <dict_regexp.h>
- #include <dict_static.h>
-@@ -230,6 +231,9 @@
- #ifdef HAS_MYSQL
-     DICT_TYPE_MYSQL, dict_mysql_open,
- #endif
-+#ifdef HAS_PGSQL
-+    DICT_TYPE_PGSQL, dict_pgsql_open,
-+#endif
- #ifndef MAX_DYNAMIC_MAPS
- #ifdef HAS_PCRE
-     DICT_TYPE_PCRE, dict_pcre_open,
---- postfix-2.0.16.orig/src/util/dict_pgsql.c  1970-01-01 01:00:00.000000000 +0100
-+++ postfix-2.0.16/src/util/dict_pgsql.c       2003-11-08 20:11:44.000000000 +0100
-@@ -0,0 +1,675 @@
-+
-+/*++
-+/* NAME
-+/*    dict_pgsql 3
-+/* SUMMARY
-+/*    dictionary manager interface to db files
-+/* SYNOPSIS
-+/*    #include <dict.h>
-+/*    #include <dict_pgsql.h>
-+/*
-+/*    DICT    *dict_pgsql_open(name, dummy, unused_dict_flags)
-+/*    const char      *name;
-+/*    int     dummy;
-+/*    int     unused_dict_flags;
-+/* DESCRIPTION
-+/*    dict_pgsql_open() creates a dictionary of type 'pg'.  This
-+/*    dictionary is an interface for the postfix key->value mappings
-+/*    to pgsql.  The result is a pointer to the installed dictionary,
-+/*    or a null pointer in case of problems.
-+/*
-+/*    The pgsql dictionary can manage multiple connections to different
-+/*    sql servers on different hosts.  It assumes that the underlying data
-+/*    on each host is identical (mirrored) and maintains one connection
-+/*    at any given time.  If any connection fails,  any other available
-+/*    ones will be opened and used.  The intent of this feature is to eliminate
-+/*    a single point of failure for mail systems that would otherwise rely
-+/*    on a single pgsql server.
-+/*
-+/*    Arguments:
-+/* .IP name
-+/*    The path of the PostgreSQL configuration file.  The file encodes a number of
-+/*    pieces of information: username, password, databasename, table,
-+/*    select_field, where_field, and hosts.  For example, if you want the map to
-+/*    reference databases of the name "your_db" and execute a query like this:
-+/*    select forw_addr from aliases where alias like '<some username>' against
-+/*    any database called "vmailer_info" located on hosts host1.some.domain and
-+/*    host2.some.domain, logging in as user "vmailer" and password "passwd" then
-+/*    the configuration file should read:
-+/*
-+/*    user = vmailer
-+/*    password = passwd
-+/*    DBname = vmailer_info
-+/*    table = aliases
-+/*    select_field = forw_addr
-+/*    where_field = alias
-+/*    hosts = host1.some.domain host2.some.domain
-+/*
-+/* .IP other_name
-+/*    reference for outside use.
-+/* .IP unusued_flags
-+/*    unused flags
-+/* SEE ALSO
-+/*    dict(3) generic dictionary manager
-+/* AUTHOR(S)
-+/*      Mathieu Arnold
-+/*      Absolight
-+/*      mat@absolight.com
-+/*      
-+/*      based on dict_mysql by
-+/*      
-+/*    Scott Cotton
-+/*    IC Group, Inc.
-+/*    scott@icgroup.com
-+/*
-+/*    Joshua Marcus
-+/*    IC Group, Inc.
-+/*    josh@icgroup.com
-+/*--*/
-+
-+/* System library. */
-+#include "sys_defs.h"
-+
-+#ifdef HAS_PGSQL
-+#include <sys/socket.h>
-+#include <netinet/in.h>
-+#include <arpa/inet.h>
-+#include <netdb.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <stdlib.h>
-+#include <syslog.h>
-+#include <time.h>
-+#include <libpq-fe.h>
-+
-+/* Utility library. */
-+#include "dict.h"
-+#include "msg.h"
-+#include "mymalloc.h"
-+#include "dict_pgsql.h"
-+#include "argv.h"
-+#include "vstring.h"
-+#include "split_at.h"
-+#include "find_inet.h"
-+
-+/* need some structs to help organize things */
-+typedef struct
-+{
-+    PGconn *db;
-+    char   *hostname;
-+    int     stat;                     /* STATUNTRIED | STATFAIL | STATCUR */
-+    time_t  ts;                               /* used for attempting reconnection
-+                                       * every so often if a host is down */
-+} HOST;
-+
-+typedef struct
-+{
-+    int     len_hosts;                        /* number of hosts */
-+    HOST   *db_hosts;                 /* the hosts on which the databases
-+                                       * reside */
-+} PLPGSQL;
-+
-+typedef struct
-+{
-+    char   *username;
-+    char   *password;
-+    char   *dbname;
-+    char   *table;
-+    char   *select_field;
-+    char   *where_field;
-+    char   *additional_conditions;
-+    char  **hostnames;
-+    int     len_hosts;
-+} PGSQL_NAME;
-+
-+typedef struct
-+{
-+    DICT    dict;
-+    PLPGSQL *pldb;
-+    PGSQL_NAME *name;
-+} DICT_PGSQL;
-+
-+#define STATACTIVE 0
-+#define STATFAIL 1
-+#define STATUNTRIED 2
-+#define RETRY_CONN_INTV 60                    /* 1 minute */
-+
-+/* internal function declarations */
-+static PLPGSQL *plpgsql_init (char *hostnames[], int);
-+static PGresult *plpgsql_query (PLPGSQL *, const char *, char *, char *,
-+
-+                              char *);
-+static void plpgsql_dealloc (PLPGSQL *);
-+static void plpgsql_down_host (HOST *);
-+static void plpgsql_connect_single (HOST *, char *, char *, char *);
-+static int plpgsql_ready_reconn (HOST *);
-+static const char *dict_pgsql_lookup (DICT *, const char *);
-+DICT   *dict_pgsql_open (const char *, int, int);
-+static void dict_pgsql_close (DICT *);
-+static PGSQL_NAME *pgsqlname_parse (const char *);
-+static HOST host_init (char *);
-+void    pgsql_escape_string (char *escaped, const char *name, int len);
-+
-+
-+
-+/**********************************************************************
-+ * public interface dict_pgsql_lookup
-+ * find database entry return 0 if no alias found, set dict_errno
-+ * on errors to DICT_ERRBO_RETRY and set dict_errno to 0 on success
-+ *********************************************************************/
-+static const char *dict_pgsql_lookup (DICT *dict, const char *name)
-+{
-+    PGresult *query_res;
-+    char   *field;
-+    DICT_PGSQL *dict_pgsql;
-+    PLPGSQL *pldb;
-+    static VSTRING *result;
-+    static VSTRING *query = 0;
-+    int     i,
-+            j,
-+            numrows;
-+    char   *name_escaped = 0;
-+
-+    dict_pgsql = (DICT_PGSQL *) dict;
-+    pldb = dict_pgsql->pldb;
-+    /* initialization  for query */
-+    query = vstring_alloc (24);
-+    vstring_strcpy (query, "");
-+    if (
-+      (name_escaped =
-+       (char *) mymalloc ((sizeof (char) * (strlen (name) * 2) + 1))) ==
-+      NULL)
-+      {
-+        msg_fatal ("dict_pgsql_lookup: out of memory.");
-+      }
-+    /* prepare the query */
-+    pgsql_escape_string (name_escaped, name, (unsigned int) strlen (name));
-+    vstring_sprintf (query, "select %s from %s where %s = '%s' %s",
-+                   dict_pgsql->name->select_field, dict_pgsql->name->table,
-+                   dict_pgsql->name->where_field, name_escaped,
-+                   dict_pgsql->name->additional_conditions);
-+    if (msg_verbose)
-+      msg_info ("dict_pgsql_lookup using sql query: %s",
-+                vstring_str (query));
-+    /* free mem associated with preparing the query */
-+    myfree (name_escaped);
-+    /* do the query - set dict_errno & cleanup if there's an error */
-+    if ((query_res = plpgsql_query (pldb,
-+                                  vstring_str (query),
-+                                  dict_pgsql->name->dbname,
-+                                  dict_pgsql->name->username,
-+                                  dict_pgsql->name->password)) == 0)
-+      {
-+        dict_errno = DICT_ERR_RETRY;
-+        vstring_free (query);
-+        return 0;
-+      }
-+    dict_errno = 0;
-+    /* free the vstring query */
-+    vstring_free (query);
-+    numrows = PQntuples (query_res);
-+    if (msg_verbose)
-+      msg_info ("dict_pgsql_lookup: retrieved %d rows", numrows);
-+    if (numrows == 0)
-+      {
-+        PQclear (query_res);
-+        return 0;
-+      }
-+    if (result == 0)
-+      result = vstring_alloc (10);
-+    vstring_strcpy (result, "");
-+    for (i = 0; i < numrows; i++)
-+      {
-+        if (i > 0)
-+            vstring_strcat (result, ",");
-+        for (j = 0; j < PQnfields (query_res); j++)
-+          {
-+              if (j > 0)
-+                  vstring_strcat (result, ",");
-+              field = PQgetvalue (query_res, i, j);
-+              vstring_strcat (result, field);
-+              if (msg_verbose > 1)
-+                  msg_info ("dict_pgsql_lookup: retrieved field: %d: %s", j,
-+                            field);
-+          }
-+      }
-+    PQclear (query_res);
-+    return vstring_str (result);
-+}
-+
-+/*
-+ * plpgsql_query - process a PGSQL query.  Return PGresult* on success.
-+ *                 On failure, log failure and try other db instances.
-+ *                 on failure of all db instances, return 0;
-+ *                 close unnecessary active connections
-+ */
-+
-+static PGresult *plpgsql_query (PLPGSQL * PLDB,
-+                              const char *query,
-+                              char *dbname, char *username, char *password)
-+{
-+    int     i;
-+    HOST   *host;
-+    PGresult *res = 0;
-+    ExecStatusType status;
-+
-+    for (i = 0; i < PLDB->len_hosts; i++)
-+      {
-+        /* can't deal with typing or reading PLDB->db_hosts[i] over & over */
-+        host = &(PLDB->db_hosts[i]);
-+        if (msg_verbose > 1)
-+            msg_info ("dict_pgsql: trying host %s stat %d, last res %p",
-+                      host->hostname, host->stat, res);
-+
-+        /* answer already found */
-+        if (res != 0 && host->stat == STATACTIVE)
-+          {
-+              if (msg_verbose)
-+                  msg_info
-+                      ("dict_pgsql: closing unnessary connection to %s",
-+                       host->hostname);
-+              plpgsql_down_host (host);
-+          }
-+        /* try to connect for the first time if we don't have a result yet */
-+        if (res == 0 && host->stat == STATUNTRIED)
-+          {
-+              if (msg_verbose)
-+                  msg_info ("dict_pgsql: attempting to connect to host %s",
-+                            host->hostname);
-+              plpgsql_connect_single (host, dbname, username, password);
-+          }
-+
-+        /*
-+         * try to reconnect if we don't have an answer and the host had a
-+         * prob in the past and it's time for it to reconnect
-+         */
-+        if (res == 0 && host->stat == STATFAIL
-+            && host->ts < time ((time_t *) 0))
-+          {
-+              if (msg_verbose)
-+                  msg_info
-+                      ("dict_pgsql: attempting to reconnect to host %s",
-+                       host->hostname);
-+              plpgsql_connect_single (host, dbname, username, password);
-+          }
-+
-+        /*
-+         * if we don't have a result and the current host is marked active,
-+         * try the query.  If the query fails, mark the host STATFAIL
-+         */
-+        if (res == 0 && host->stat == STATACTIVE)
-+          {
-+              res = PQexec (host->db, query);
-+              status = PQresultStatus (res);
-+              if (res
-+                  && (status = PGRES_COMMAND_OK
-+                      || status == PGRES_TUPLES_OK))
-+                {
-+                    if (msg_verbose)
-+                        msg_info
-+                            ("dict_pgsql: successful query from host %s",
-+                             host->hostname);
-+                }
-+              else
-+                {
-+                    msg_warn ("%s", PQerrorMessage (host->db));
-+                    plpgsql_down_host (host);
-+                }
-+          }
-+      }
-+    return res;
-+}
-+
-+/*
-+ * plpgsql_connect_single -
-+ * used to reconnect to a single database when one is down or none is
-+ * connected yet. Log all errors and set the stat field of host accordingly
-+ */
-+static void
-+plpgsql_connect_single (HOST *host, char *dbname, char *username,
-+                      char *password)
-+{
-+    char   *destination = host->hostname;
-+    char   *hostname = 0;
-+    char   *service;
-+    VSTRING *conninfo = vstring_alloc (100);
-+    char   *conn;
-+    unsigned port = 0;
-+
-+    /*
-+     * Ad-hoc parsing code.  Expect "unix:pathname" or "inet:host:port", where
-+     * both "inet:" and ":port" are optional.
-+     */
-+    if (strncmp (destination, "unix:", 5) == 0)
-+      {
-+        vstring_sprintf_append (conninfo, "host=%s ", destination + 5);
-+      }
-+    else
-+      {
-+        if (strncmp (destination, "inet:", 5) == 0)
-+            destination += 5;
-+        hostname = mystrdup (destination);
-+        if ((service = split_at (hostname, ':')) != 0)
-+          {
-+              port = ntohs (find_inet_port (service, "tcp"));
-+              vstring_sprintf_append (conninfo, "host='%s' port='%d'",
-+                                      hostname, port);
-+          }
-+        else
-+          {
-+              vstring_sprintf_append (conninfo, "host='%s'", hostname);
-+          }
-+      }
-+
-+    vstring_sprintf_append (conninfo, " dbname='%s' user='%s' password='%s'", dbname,
-+                          username, password);
-+    conn = vstring_export (conninfo);
-+
-+    host->db = PQconnectdb (conn);
-+
-+    if ((host->db != NULL) && (PQstatus (host->db) == CONNECTION_OK))
-+      {
-+        if (msg_verbose)
-+            msg_info ("dict_pgsql: successful connection to host %s",
-+                      host->hostname);
-+        host->stat = STATACTIVE;
-+      }
-+    else
-+      {
-+        msg_warn ("%s", PQerrorMessage (host->db));
-+        plpgsql_down_host (host);
-+      }
-+    if (hostname)
-+      myfree (hostname);
-+    myfree (conn);
-+}
-+
-+/*
-+ * plpgsql_down_host - mark a HOST down update ts if marked down
-+ * for the first time so that we'll know when to retry the connection
-+ */
-+static void plpgsql_down_host (HOST *host)
-+{
-+    if (host->stat != STATFAIL)
-+      {
-+        host->ts = time ((time_t *) 0) + RETRY_CONN_INTV;
-+        host->stat = STATFAIL;
-+      }
-+    PQfinish (host->db);
-+    host->db = 0;
-+}
-+
-+/**********************************************************************
-+ * public interface dict_pgsql_open
-+ *    create association with database with appropriate values
-+ *    parse the map's config file
-+ *    allocate memory
-+ **********************************************************************/
-+DICT   *dict_pgsql_open (const char *name, int unused_open_flags,
-+                       int dict_flags)
-+{
-+    DICT_PGSQL *dict_pgsql;
-+    int     connections;
-+
-+    dict_pgsql = (DICT_PGSQL *) dict_alloc (DICT_TYPE_PGSQL, name,
-+                                          sizeof (DICT_PGSQL));
-+    dict_pgsql->dict.lookup = dict_pgsql_lookup;
-+    dict_pgsql->dict.close = dict_pgsql_close;
-+    dict_pgsql->dict.flags = dict_flags | DICT_FLAG_FIXED;
-+    dict_pgsql->name = pgsqlname_parse (name);
-+    dict_pgsql->pldb = plpgsql_init (dict_pgsql->name->hostnames,
-+                                   dict_pgsql->name->len_hosts);
-+    if (dict_pgsql->pldb == NULL)
-+      msg_fatal ("couldn't intialize pldb!\n");
-+    dict_register (name, (DICT *) dict_pgsql);
-+    return (DICT_DEBUG (&dict_pgsql->dict));
-+}
-+
-+/* pgsqlname_parse - parse pgsql configuration file */
-+static PGSQL_NAME *pgsqlname_parse (const char *pgsqlcf_path)
-+{
-+    int     i;
-+    char   *nameval;
-+    char   *hosts;
-+    PGSQL_NAME *name = (PGSQL_NAME *) mymalloc (sizeof (PGSQL_NAME));
-+    ARGV   *hosts_argv;
-+    VSTRING *opt_dict_name;
-+
-+    /*
-+     * setup a dict containing info in the pgsql cf file. the dict has a
-+     * name, and a path.  The name must be distinct from the path, or the
-+     * dict interface gets confused.  The name must be distinct for two
-+     * different paths, or the configuration info will cache across different
-+     * pgsql maps, which can be confusing.
-+     */
-+    opt_dict_name = vstring_alloc (64);
-+    vstring_sprintf (opt_dict_name, "pgsql opt dict %s", pgsqlcf_path);
-+    dict_load_file (vstring_str (opt_dict_name), pgsqlcf_path);
-+    /* pgsql username lookup */
-+    if (
-+      (nameval =
-+       (char *) dict_lookup (vstring_str (opt_dict_name), "user")) == NULL)
-+      name->username = mystrdup ("");
-+    else
-+      name->username = mystrdup (nameval);
-+    if (msg_verbose)
-+      msg_info ("pgsqlname_parse(): set username to '%s'", name->username);
-+    /* password lookup */
-+    if (
-+      (nameval =
-+       (char *) dict_lookup (vstring_str (opt_dict_name),
-+                             "password")) == NULL)
-+      name->password = mystrdup ("");
-+    else
-+      name->password = mystrdup (nameval);
-+    if (msg_verbose)
-+      msg_info ("pgsqlname_parse(): set password to '%s'", name->password);
-+
-+    /* database name lookup */
-+    if (
-+      (nameval =
-+       (char *) dict_lookup (vstring_str (opt_dict_name),
-+                             "dbname")) == NULL)
-+
-+
-+
-+      msg_fatal ("%s: pgsql options file does not include database name",
-+                 pgsqlcf_path);
-+    else
-+      name->dbname = mystrdup (nameval);
-+    if (msg_verbose)
-+      msg_info ("pgsqlname_parse(): set database name to '%s'",
-+                name->dbname);
-+
-+    /* table lookup */
-+    if (
-+      (nameval =
-+       (char *) dict_lookup (vstring_str (opt_dict_name), "table")) == NULL)
-+      msg_fatal ("%s: pgsql options file does not include table name",
-+                 pgsqlcf_path);
-+    else
-+      name->table = mystrdup (nameval);
-+    if (msg_verbose)
-+      msg_info ("pgsqlname_parse(): set table name to '%s'", name->table);
-+
-+    /* select field lookup */
-+    if (
-+      (nameval =
-+       (char *) dict_lookup (vstring_str (opt_dict_name),
-+                             "select_field")) == NULL)
-+
-+
-+
-+      msg_fatal ("%s: pgsql options file does not include select field",
-+                 pgsqlcf_path);
-+    else
-+      name->select_field = mystrdup (nameval);
-+    if (msg_verbose)
-+      msg_info ("pgsqlname_parse(): set select_field to '%s'",
-+                name->select_field);
-+
-+    /* where field lookup */
-+    if (
-+      (nameval =
-+       (char *) dict_lookup (vstring_str (opt_dict_name),
-+                             "where_field")) == NULL)
-+      msg_fatal ("%s: pgsql options file does not include where field",
-+                 pgsqlcf_path);
-+    else
-+      name->where_field = mystrdup (nameval);
-+    if (msg_verbose)
-+      msg_info ("pgsqlname_parse(): set where_field to '%s'",
-+                name->where_field);
-+
-+    /* additional conditions */
-+    if (
-+      (nameval =
-+       (char *) dict_lookup (vstring_str (opt_dict_name),
-+                             "additional_conditions")) == NULL)
-+      name->additional_conditions = mystrdup ("");
-+    else
-+      name->additional_conditions = mystrdup (nameval);
-+    if (msg_verbose)
-+      msg_info ("pgsqlname_parse(): set additional_conditions to '%s'",
-+                name->additional_conditions);
-+
-+    /* pgsql server hosts */
-+    if (
-+      (nameval =
-+       (char *) dict_lookup (vstring_str (opt_dict_name), "hosts")) == NULL)
-+      hosts = mystrdup ("");
-+    else
-+      hosts = mystrdup (nameval);
-+    /* coo argv interface */
-+    hosts_argv = argv_split (hosts, " ,\t\r\n");
-+
-+    if (hosts_argv->argc == 0)
-+      {                                               /* no hosts specified,
-+                                               * default to 'localhost' */
-+        if (msg_verbose)
-+            msg_info
-+                ("pgsqlname_parse(): no hostnames specified, defaulting to 'localhost'");
-+        argv_add (hosts_argv, "localhost", ARGV_END);
-+        argv_terminate (hosts_argv);
-+      }
-+    name->len_hosts = hosts_argv->argc;
-+    name->hostnames =
-+
-+      (char **) mymalloc ((sizeof (char *)) * name->len_hosts);
-+    i = 0;
-+    for (i = 0; hosts_argv->argv[i] != NULL; i++)
-+      {
-+        name->hostnames[i] = mystrdup (hosts_argv->argv[i]);
-+        if (msg_verbose)
-+            msg_info
-+                ("pgsqlname_parse(): adding host '%s' to list of pgsql server hosts",
-+                 name->hostnames[i]);
-+      }
-+    myfree (hosts);
-+    vstring_free (opt_dict_name);
-+    argv_free (hosts_argv);
-+    return name;
-+}
-+
-+
-+/*
-+ * plpgsql_init - initalize a PGSQL database.
-+ *                Return NULL on failure, or a PLPGSQL * on success.
-+ */
-+static PLPGSQL *plpgsql_init (char *hostnames[], int len_hosts)
-+{
-+    PLPGSQL *PLDB;
-+    int     i;
-+    HOST    host;
-+
-+    if ((PLDB = (PLPGSQL *) mymalloc (sizeof (PLPGSQL))) == NULL)
-+      {
-+        msg_fatal ("mymalloc of pldb failed");
-+      }
-+    PLDB->len_hosts = len_hosts;
-+    if ((PLDB->db_hosts = (HOST *) mymalloc (sizeof (HOST) * len_hosts))
-+      == NULL)
-+      return NULL;
-+
-+    for (i = 0; i < len_hosts; i++)
-+      {
-+        PLDB->db_hosts[i] = host_init (hostnames[i]);
-+      }
-+    return PLDB;
-+}
-+
-+
-+/* host_init - initialize HOST structure */
-+static HOST host_init (char *hostname)
-+{
-+    HOST    host;
-+
-+    host.stat = STATUNTRIED;
-+    host.hostname = mystrdup (hostname);
-+    host.db = 0;
-+    host.ts = 0;
-+    return host;
-+}
-+
-+/**********************************************************************
-+ * public interface dict_pgsql_close
-+ * unregister, disassociate from database, freeing appropriate memory
-+ **********************************************************************/
-+static void dict_pgsql_close (DICT *dict)
-+{
-+    int     i;
-+    DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
-+
-+    plpgsql_dealloc (dict_pgsql->pldb);
-+    myfree (dict_pgsql->name->username);
-+    myfree (dict_pgsql->name->password);
-+    myfree (dict_pgsql->name->dbname);
-+    myfree (dict_pgsql->name->table);
-+    myfree (dict_pgsql->name->select_field);
-+    myfree (dict_pgsql->name->where_field);
-+    myfree (dict_pgsql->name->additional_conditions);
-+    for (i = 0; i < dict_pgsql->name->len_hosts; i++)
-+      {
-+        myfree (dict_pgsql->name->hostnames[i]);
-+      }
-+    myfree ((char *) dict_pgsql->name->hostnames);
-+    myfree ((char *) dict_pgsql->name);
-+    dict_free (dict);
-+}
-+
-+/* plpgsql_dealloc - free memory associated with PLPGSQL close databases */
-+static void plpgsql_dealloc (PLPGSQL * PLDB)
-+{
-+    int     i;
-+
-+    for (i = 0; i < PLDB->len_hosts; i++)
-+      {
-+        if (PLDB->db_hosts[i].db)
-+            PQfinish (PLDB->db_hosts[i].db);
-+        myfree (PLDB->db_hosts[i].hostname);
-+      }
-+    myfree ((char *) PLDB->db_hosts);
-+    myfree ((char *) (PLDB));
-+}
-+
-+/* pgsql_escape_string - replace mysql_escape_string */
-+void    pgsql_escape_string (char *escaped, const char *name, int len)
-+{
-+    int     i,
-+            j;
-+
-+    for (i = 0, j = 0; i <= len; i++, j++)
-+      {
-+        if ((name[i] == '\'') || (name[i] == '\\'))
-+          {
-+              escaped[j] = '\\';
-+              j++;
-+          }
-+        escaped[j] = name[i];
-+      }
-+}
-+
-+
-+
-+#endif
-+
---- postfix-2.0.16.orig/src/util/dict_pgsql.h  1970-01-01 01:00:00.000000000 +0100
-+++ postfix-2.0.16/src/util/dict_pgsql.h       2003-11-08 20:11:44.000000000 +0100
-@@ -0,0 +1,41 @@
-+#ifndef _DICT_PGSQL_H_INCLUDED_
-+#define _DICT_PGSQL_H_INCLUDED_
-+
-+/*++
-+/* NAME
-+/*    dict_pgsql 3h
-+/* SUMMARY
-+/*    dictionary manager interface to pgsql databases
-+/* SYNOPSIS
-+/*    #include <dict_pgsql.h>
-+/* DESCRIPTION
-+/* .nf
-+
-+ /*
-+  * Utility library.
-+  */
-+#include <dict.h>
-+
-+ /*
-+  * External interface.
-+  */
-+#define DICT_TYPE_PGSQL       "pgsql"
-+
-+extern DICT *dict_pgsql_open (const char *, int, int);
-+
-+/* LICENSE
-+/* .ad
-+/* .fi
-+/*    The Secure Mailer license must be distributed with this software.
-+/* AUTHOR(S)
-+/*    Scott Cotton
-+/*    IC Group, Inc.
-+/*    scott@icgroup.com
-+/*
-+/*    Joshua Marcus
-+/*    IC Group, Inc.
-+/*    josh@icgroup.com
-+/*--*/
-+
-+#endif
-+
---- postfix-2.0.16.orig/src/util/Makefile.in   2003-11-08 20:10:08.000000000 +0100
-+++ postfix-2.0.16/src/util/Makefile.in        2003-11-08 20:12:29.000000000 +0100
-@@ -4,7 +4,7 @@
-       chroot_uid.c clean_env.c close_on_exec.c concatenate.c ctable.c \
-       dict.c dict_alloc.c dict_db.c dict_dbm.c dict_debug.c dict_env.c \
-       dict_ht.c dict_mysql.c dict_ni.c dict_nis.c \
--      dict_nisplus.c dict_open.c dict_pcre.c dict_regexp.c dict_static.c \
-+      dict_nisplus.c dict_open.c dict_pcre.c dict_pgsql.c dict_regexp.c dict_static.c \
-       dict_tcp.c dict_unix.c dir_forest.c doze.c duplex_pipe.c \
-       environ.c events.c exec_command.c fifo_listen.c fifo_trigger.c \
-       file_limit.c find_inet.c fsspace.c fullname.c get_domainname.c \
-@@ -60,7 +60,7 @@
- HDRS  = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
-       connect.h ctable.h dict.h dict_db.h dict_dbm.h dict_env.h \
-       dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \
--      dict_nisplus.h dict_pcre.h dict_regexp.h dict_static.h dict_tcp.h \
-+      dict_nisplus.h dict_pcre.h dict_pgsql.h dict_regexp.h dict_static.h dict_tcp.h \
-       dict_unix.h dir_forest.h events.h exec_command.h find_inet.h \
-       fsspace.h fullname.h get_domainname.h get_hostname.h hex_quote.h \
-       htable.h inet_addr_host.h inet_addr_list.h inet_addr_local.h \
-@@ -86,6 +86,7 @@
- INCL  =
- PCRESO  = dict_pcre.so
- MYSQLSO = dict_mysql.so
-+PGSQLSO = dict_pgsql.so
- LIB   = libutil.a
- TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
-       fifo_rdonly_bug fifo_rdwr_bug fifo_trigger fsspace fullname \
-@@ -98,7 +99,7 @@
- LIB_DIR       = ../../lib
- INC_DIR       = ../../include
--LIBS    = $(LIB_DIR)/$(LIB) $(LIB_DIR)/$(PCRESO) $(LIB_DIR)/$(MYSQLSO)
-+LIBS    = $(LIB_DIR)/$(LIB) $(LIB_DIR)/$(PCRESO) $(LIB_DIR)/$(MYSQLSO) $(LIB_DIR)/$(PGSQLSO)
- .c.o:;        $(CC) -fPIC $(CFLAGS) -c $*.c
-@@ -115,6 +116,9 @@
- $(MYSQLSO): dict_mysql.o
-       gcc -shared -Wl,-soname,dict_mysql.so -o $@ $? -lmysqlclient -L. -lutil
-+$(PGSQLSO): dict_pgsql.o
-+      gcc -shared -Wl,-soname,dict_pgsql.so -o $@ $? -lpq -lcrypt -L. -lutil
-+
- $(LIB):       $(OBJS)
-       gcc -shared -Wl,-soname,libpostfix-util.so.1 -o $(LIB) $(OBJS) -ldl
-@@ -127,6 +131,9 @@
- $(LIB_DIR)/$(MYSQLSO): $(MYSQLSO)
-       cp $(MYSQLSO) $(LIB_DIR)
-+$(LIB_DIR)/$(PGSQLSO): $(PGSQLSO)
-+      cp $(PGSQLSO) $(LIB_DIR)
-+
- update: $(LIBS) $(HDRS)
-       -for i in $(HDRS); \
-       do \
-@@ -149,7 +156,7 @@
-       lint $(SRCS)
- clean:
--      rm -f *.o $(LIB) $(PCRESO) $(MYSQLSO) *core $(TESTPROG) \
-+      rm -f *.o $(LIB) $(PCRESO) $(MYSQLSO) $(PGSQLSO) *core $(TESTPROG) \
-               junk $(MAKES) *.tmp
-       rm -rf printfck
-@@ -591,6 +598,8 @@
- dict_ldap.o: sys_defs.h
- dict_mysql.o: dict_mysql.c
- dict_mysql.o: sys_defs.h
-+dict_pgsql.o: dict_pgsql.c
-+dict_pgsql.o: sys_defs.h
- dict_ni.o: dict_ni.c
- dict_ni.o: sys_defs.h
- dict_nis.o: dict_nis.c
-@@ -632,6 +641,7 @@
- dict_open.o: dict_ni.h
- dict_open.o: dict_ldap.h
- dict_open.o: dict_mysql.h
-+dict_open.o: dict_pgsql.h
- dict_open.o: dict_pcre.h
- dict_open.o: dict_regexp.h
- dict_open.o: dict_static.h
This page took 0.520066 seconds and 4 git commands to generate.