]> git.pld-linux.org Git - packages/postfix.git/blob - postfix-dict_ldap.patch
- backported dict_ldap from 2.1RC1 snapshot so that it could work with
[packages/postfix.git] / postfix-dict_ldap.patch
1 --- postfix-2.0.19.old/src/util/dict_ldap.c     2002-10-17 02:26:41.000000000 +0200
2 +++ postfix-2.0.19.new/src/util/dict_ldap.c     2004-04-10 21:08:37.000000000 +0200
3 @@ -26,7 +26,9 @@
4  /* .PP
5  /*     Configuration parameters:
6  /* .IP \fIldapsource_\fRserver_host
7 -/*     The host at which all LDAP queries are directed.
8 +/*     List of hosts at which all LDAP queries are directed.
9 +/*     The host names can also be LDAP URLs if the LDAP client library used
10 +/*     is OpenLDAP.
11  /* .IP \fIldapsource_\fRserver_port
12  /*     The port the LDAP server listens on.
13  /* .IP \fIldapsource_\fRsearch_base
14 @@ -57,14 +59,56 @@
15  /*     If you must bind to the server, do it with this distinguished name ...
16  /* .IP \fIldapsource_\fRbind_pw
17  /*     \&... and this password.
18 -/* .IP \fIldapsource_\fRcache
19 +/* .IP \fIldapsource_\fRcache (no longer supported)
20  /*     Whether or not to turn on client-side caching.
21 -/* .IP \fIldapsource_\fRcache_expiry
22 +/* .IP \fIldapsource_\fRcache_expiry (no longer supported)
23  /*     If you do cache results, expire them after this many seconds.
24 -/* .IP \fIldapsource_\fRcache_size
25 +/* .IP \fIldapsource_\fRcache_size (no longer supported)
26  /*     The cache size in bytes. Does nothing if the cache is off, of course.
27 +/* .IP \fIldapsource_\fRrecursion_limit
28 +/*     Maximum recursion depth when expanding DN or URL references.
29 +/*     Queries which exceed the recursion limit fail with
30 +/*     dict_errno = DICT_ERR_RETRY.
31 +/* .IP \fIldapsource_\fRexpansion_limit
32 +/*     Limit (if any) on the total number of lookup result values. Lookups which
33 +/*     exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that
34 +/*     each value of a multivalued result attribute counts as one result.
35 +/* .IP \fIldapsource_\fRsize_limit
36 +/*     Limit on the number of entries returned by individual LDAP queries.
37 +/*     Queries which exceed the limit fail with dict_errno=DICT_ERR_RETRY.
38 +/*     This is an *entry* count, for any single query performed during the
39 +/*     possibly recursive lookup.
40 +/* .IP \fIldapsource_\fRchase_referrals
41 +/*     Controls whether LDAP referrals are obeyed.
42  /* .IP \fIldapsource_\fRdereference
43  /*     How to handle LDAP aliases. See ldap.h or ldap_open(3) man page.
44 +/* .IP \fIldapsource_\fRversion
45 +/*     Specifies the LDAP protocol version to use.  Default is version
46 +/*     \fI2\fR.
47 +/* .IP \fIldapsource_\fRstart_tls
48 +/*     Whether or not to issue STARTTLS upon connection to the server.
49 +/*     At this time, STARTTLS and LDAP SSL are only available if the
50 +/*     LDAP client library used is OpenLDAP.  Default is \fIno\fR.
51 +/* .IP \fIldapsource_\fRtls_ca_cert_file
52 +/*     File containing certificates for all of the X509 Certificate
53 +/*     Authorities the client will recognize.  Takes precedence over
54 +/*     tls_ca_cert_dir.
55 +/* .IP \fIldapsource_\fRtls_ca_cert_dir
56 +/*     Directory containing X509 Certificate Authority certificates
57 +/*     in separate individual files.
58 +/* .IP \fIldapsource_\fRtls_cert
59 +/*     File containing client's X509 certificate.
60 +/* .IP \fIldapsource_\fRtls_key
61 +/*     File containing the private key corresponding to
62 +/*     tls_cert.
63 +/* .IP \fIldapsource_\fRtls_require_cert
64 +/*     Whether or not to request server's X509 certificate and check its
65 +/*     validity.
66 +/* .IP \fIldapsource_\fRtls_random_file
67 +/*     Path of a file to obtain random bits from when /dev/[u]random is
68 +/*     not available. Generally set to the name of the EGD/PRNGD socket.
69 +/* .IP \fIldapsource_\fRtls_cipher_suite
70 +/*     Cipher suite to use in SSL/TLS negotiations.
71  /* .IP \fIldapsource_\fRdebuglevel
72  /*     Debug level.  See 'loglevel' option in slapd.conf(5) man page.
73  /*      Currently only in openldap libraries (and derivatives).
74 @@ -102,6 +146,8 @@
75  #include <lber.h>
76  #include <ldap.h>
77  #include <string.h>
78 +#include <ctype.h>
79 +#include <unistd.h>
80  
81   /*
82    * Older APIs have weird memory freeing behavior.
83 @@ -126,12 +172,22 @@
84  #include "mymalloc.h"
85  #include "vstring.h"
86  #include "dict.h"
87 +#include "stringops.h"
88 +#include "binhash.h"
89 +
90  #include "dict_ldap.h"
91  
92  /* AAARGH!! */
93  
94  #include "../global/mail_conf.h"
95  
96 +#include "dict_ldap.h"
97 +
98 +typedef struct {
99 +    LDAP   *conn_ld;
100 +    int     conn_refcount;
101 +} LDAP_CONN;
102 +
103  /*
104   * Structure containing all the configuration parameters for a given
105   * LDAP source, plus its connection handle.
106 @@ -152,17 +208,33 @@
107      char   *bind_dn;
108      char   *bind_pw;
109      int     timeout;
110 -    int     cache;
111 -    long    cache_expiry;
112 -    long    cache_size;
113      int     dereference;
114 +    long    recursion_limit;
115 +    long    expansion_limit;
116 +    long    size_limit;
117      int     chase_referrals;
118      int     debuglevel;
119      int     version;
120 +#ifdef LDAP_API_FEATURE_X_OPENLDAP
121 +    int     ldap_ssl;
122 +    int     start_tls;
123 +    int     tls_require_cert;
124 +    char   *tls_ca_cert_file;
125 +    char   *tls_ca_cert_dir;
126 +    char   *tls_cert;
127 +    char   *tls_key;
128 +    char   *tls_random_file;
129 +    char   *tls_cipher_suite;
130 +#endif
131 +    BINHASH_INFO *ht;                  /* hash entry for LDAP connection */
132      LDAP   *ld;
133  } DICT_LDAP;
134  
135 -#ifndef LDAP_OPT_NETWORK_TIMEOUT
136 +#define DICT_LDAP_CONN(d) ((LDAP_CONN *)((d)->ht->value))
137 +
138 +static BINHASH *conn_hash = 0;
139 +
140 +#if defined(LDAP_API_FEATURE_X_OPENLDAP) || !defined(LDAP_OPT_NETWORK_TIMEOUT)
141  /*
142   * LDAP connection timeout support.
143   */
144 @@ -178,8 +250,17 @@
145  static void dict_ldap_logprint(LDAP_CONST char *data)
146  {
147      char   *myname = "dict_ldap_debug";
148 +    char   *buf,
149 +           *p;
150  
151 -    msg_info("%s: %s", myname, data);
152 +    buf = mystrdup(data);
153 +    if (*buf) {
154 +       p = buf + strlen(buf) - 1;
155 +       while (p - buf >= 0 && ISSPACE(*p))
156 +           *p-- = 0;
157 +    }
158 +    msg_info("%s: %s", myname, buf);
159 +    myfree(buf);
160  }
161  
162  
163 @@ -225,24 +306,97 @@
164      return (ldap_result2error(dict_ldap->ld, res, 1));
165  }
166  
167 +#ifdef LDAP_API_FEATURE_X_OPENLDAP
168 +static void dict_ldap_set_tls_options(DICT_LDAP *dict_ldap)
169 +{
170 +    char   *myname = "dict_ldap_set_tls_options";
171 +    int     rc;
172 +
173 +    if (dict_ldap->start_tls || dict_ldap->ldap_ssl) {
174 +       if (*dict_ldap->tls_random_file) {
175 +           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
176 +                              dict_ldap->tls_random_file)) != LDAP_SUCCESS)
177 +               msg_warn("%s: Unable to set tls_random_file to %s: %d: %s",
178 +                        myname, dict_ldap->tls_random_file,
179 +                        rc, ldap_err2string(rc));
180 +       }
181 +       if (*dict_ldap->tls_ca_cert_file) {
182 +           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
183 +                             dict_ldap->tls_ca_cert_file)) != LDAP_SUCCESS)
184 +               msg_warn("%s: Unable to set tls_ca_cert_file to %s: %d: %s",
185 +                        myname, dict_ldap->tls_ca_cert_file,
186 +                        rc, ldap_err2string(rc));
187 +       }
188 +       if (*dict_ldap->tls_ca_cert_dir) {
189 +           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTDIR,
190 +                              dict_ldap->tls_ca_cert_dir)) != LDAP_SUCCESS)
191 +               msg_warn("%s: Unable to set tls_ca_cert_dir to %s: %d: %s",
192 +                        myname, dict_ldap->tls_ca_cert_dir,
193 +                        rc, ldap_err2string(rc));
194 +       }
195 +       if (*dict_ldap->tls_cert) {
196 +           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE,
197 +                                     dict_ldap->tls_cert)) != LDAP_SUCCESS)
198 +               msg_warn("%s: Unable to set tls_cert to %s: %d: %s",
199 +                        myname, dict_ldap->tls_cert,
200 +                        rc, ldap_err2string(rc));
201 +       }
202 +       if (*dict_ldap->tls_key) {
203 +           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE,
204 +                                     dict_ldap->tls_key)) != LDAP_SUCCESS)
205 +               msg_warn("%s: Unable to set tls_key to %s: %d: %s",
206 +                        myname, dict_ldap->tls_key,
207 +                        rc, ldap_err2string(rc));
208 +       }
209 +       if (*dict_ldap->tls_cipher_suite) {
210 +           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
211 +                             dict_ldap->tls_cipher_suite)) != LDAP_SUCCESS)
212 +               msg_warn("%s: Unable to set tls_cipher_suite to %s: %d: %s",
213 +                        myname, dict_ldap->tls_cipher_suite,
214 +                        rc, ldap_err2string(rc));
215 +       }
216 +       if (dict_ldap->tls_require_cert) {
217 +           if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
218 +                          &(dict_ldap->tls_require_cert))) != LDAP_SUCCESS)
219 +               msg_warn("%s: Unable to set tls_require_cert to %d: %d: %s",
220 +                        myname, dict_ldap->tls_require_cert,
221 +                        rc, ldap_err2string(rc));
222 +       }
223 +    }
224 +}
225 +
226 +#endif
227 +
228 +
229  /* Establish a connection to the LDAP server. */
230  static int dict_ldap_connect(DICT_LDAP *dict_ldap)
231  {
232      char   *myname = "dict_ldap_connect";
233      int     rc = 0;
234  
235 -#ifdef LDAP_API_FEATURE_X_MEMCACHE
236 -    LDAPMemCache *dircache;
237 -
238 -#endif
239 -
240  #ifdef LDAP_OPT_NETWORK_TIMEOUT
241      struct timeval mytimeval;
242  
243 -#else
244 +#endif
245 +
246 +#if defined(LDAP_API_FEATURE_X_OPENLDAP) || !defined(LDAP_OPT_NETWORK_TIMEOUT)
247      void    (*saved_alarm) (int);
248  
249  #endif
250 +#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
251 +    if (dict_ldap->debuglevel > 0 &&
252 +       ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN,
253 +                    (LDAP_CONST *) dict_ldap_logprint) != LBER_OPT_SUCCESS)
254 +       msg_warn("%s: Unable to set ber logprint function.", myname);
255 +#if defined(LBER_OPT_DEBUG_LEVEL)
256 +    if (ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL,
257 +                      &(dict_ldap->debuglevel)) != LBER_OPT_SUCCESS)
258 +       msg_warn("%s: Unable to set BER debug level.", myname);
259 +#endif
260 +    if (ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL,
261 +                       &(dict_ldap->debuglevel)) != LDAP_OPT_SUCCESS)
262 +       msg_warn("%s: Unable to set LDAP debug level.", myname);
263 +#endif
264  
265      dict_errno = 0;
266  
267 @@ -251,8 +405,13 @@
268                  dict_ldap->server_host);
269  
270  #ifdef LDAP_OPT_NETWORK_TIMEOUT
271 +#ifdef LDAP_API_FEATURE_X_OPENLDAP
272 +    dict_ldap_set_tls_options(dict_ldap);
273 +    ldap_initialize(&(dict_ldap->ld), dict_ldap->server_host);
274 +#else
275      dict_ldap->ld = ldap_init(dict_ldap->server_host,
276                               (int) dict_ldap->server_port);
277 +#endif
278      if (dict_ldap->ld == NULL) {
279         msg_warn("%s: Unable to init LDAP server %s",
280                  myname, dict_ldap->server_host);
281 @@ -308,12 +467,22 @@
282                             &dict_ldap->version) != LDAP_OPT_SUCCESS)
283             msg_warn("%s: Unable to get LDAP protocol version", myname);
284         else
285 -           msg_warn("%s: Actual Protocol version used is %d.",
286 +           msg_info("%s: Actual Protocol version used is %d.",
287                      myname, dict_ldap->version);
288      }
289  #endif
290  
291      /*
292 +     * Limit the number of entries returned by each query.
293 +     */
294 +    if (dict_ldap->size_limit) {
295 +       if (ldap_set_option(dict_ldap->ld, LDAP_OPT_SIZELIMIT,
296 +                           &dict_ldap->size_limit) != LDAP_OPT_SUCCESS)
297 +           msg_warn("%s: %s: Unable to set query result size limit to %ld.",
298 +                    myname, dict_ldap->ldapsource, dict_ldap->size_limit);
299 +    }
300 +
301 +    /*
302       * Configure alias dereferencing for this connection. Thanks to Mike
303       * Mattice for this, and to Hery Rakotoarisoa for the v3 update.
304       */
305 @@ -321,16 +490,6 @@
306                         &(dict_ldap->dereference)) != LDAP_OPT_SUCCESS)
307         msg_warn("%s: Unable to set dereference option.", myname);
308  
309 -#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
310 -    if (dict_ldap->debuglevel > 0 &&
311 -       ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN,
312 -                    (LDAP_CONST *) dict_ldap_logprint) != LBER_OPT_SUCCESS)
313 -       msg_warn("%s: Unable to set ber logprint function.", myname);
314 -    if (ldap_set_option(dict_ldap->ld, LDAP_OPT_DEBUG_LEVEL,
315 -                       &(dict_ldap->debuglevel)) != LDAP_OPT_SUCCESS)
316 -       msg_warn("%s: Unable to set LDAP debug level.", myname);
317 -#endif
318 -
319      /* Chase referrals. */
320  
321      /*
322 @@ -348,6 +507,36 @@
323      }
324  #endif
325  
326 +#ifdef LDAP_API_FEATURE_X_OPENLDAP
327 +    if (dict_ldap->start_tls) {
328 +       if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) {
329 +           msg_warn("%s: Error setting signal handler for STARTTLS timeout: %m",
330 +                    myname);
331 +           dict_errno = DICT_ERR_RETRY;
332 +           return (-1);
333 +       }
334 +       alarm(dict_ldap->timeout);
335 +       if (setjmp(env) == 0)
336 +           rc = ldap_start_tls_s(dict_ldap->ld, NULL, NULL);
337 +       else
338 +           rc = LDAP_TIMEOUT;
339 +       alarm(0);
340 +
341 +       if (signal(SIGALRM, saved_alarm) == SIG_ERR) {
342 +           msg_warn("%s: Error resetting signal handler after STARTTLS: %m",
343 +                    myname);
344 +           dict_errno = DICT_ERR_RETRY;
345 +           return (-1);
346 +       }
347 +       if (rc != LDAP_SUCCESS) {
348 +           msg_error("%s: Unable to set STARTTLS: %d: %s", myname,
349 +                     rc, ldap_err2string(rc));
350 +           dict_errno = DICT_ERR_RETRY;
351 +           return (-1);
352 +       }
353 +    }
354 +#endif
355 +
356      /*
357       * If this server requires a bind, do so. Thanks to Sam Tardieu for
358       * noticing that the original bind call was broken.
359 @@ -370,52 +559,9 @@
360             msg_info("%s: Successful bind to server %s as %s ",
361                      myname, dict_ldap->server_host, dict_ldap->bind_dn);
362      }
363 +    /* Save connection handle in shared container */
364 +    DICT_LDAP_CONN(dict_ldap)->conn_ld = dict_ldap->ld;
365  
366 -    /*
367 -     * Set up client-side caching if it's configured.
368 -     */
369 -    if (dict_ldap->cache) {
370 -       if (msg_verbose)
371 -           msg_info
372 -               ("%s: Enabling %ld-byte cache for %s with %ld-second expiry",
373 -                myname, dict_ldap->cache_size, dict_ldap->ldapsource,
374 -                dict_ldap->cache_expiry);
375 -
376 -#ifdef LDAP_API_FEATURE_X_MEMCACHE
377 -       rc = ldap_memcache_init(dict_ldap->cache_expiry, dict_ldap->cache_size,
378 -                               NULL, NULL, &dircache);
379 -       if (rc != LDAP_SUCCESS) {
380 -           msg_warn
381 -               ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
382 -                myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
383 -       } else {
384 -           rc = ldap_memcache_set(dict_ldap->ld, dircache);
385 -           if (rc != LDAP_SUCCESS) {
386 -               msg_warn
387 -                   ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
388 -                    myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
389 -           } else {
390 -               if (msg_verbose)
391 -                   msg_info("%s: Caching enabled for %s",
392 -                            myname, dict_ldap->ldapsource);
393 -           }
394 -       }
395 -#else
396 -
397 -       rc = ldap_enable_cache(dict_ldap->ld, dict_ldap->cache_expiry,
398 -                              dict_ldap->cache_size);
399 -       if (rc != LDAP_SUCCESS) {
400 -           msg_warn
401 -               ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
402 -                myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
403 -       } else {
404 -           if (msg_verbose)
405 -               msg_info("%s: Caching enabled for %s",
406 -                        myname, dict_ldap->ldapsource);
407 -       }
408 -
409 -#endif
410 -    }
411      if (msg_verbose)
412         msg_info("%s: Cached connection handle for LDAP source %s",
413                  myname, dict_ldap->ldapsource);
414 @@ -424,9 +570,65 @@
415  }
416  
417  /*
418 + * Locate or allocate connection cache entry.
419 + */
420 +static void dict_ldap_conn_find(DICT_LDAP *dict_ldap)
421 +{
422 +    VSTRING *keybuf = vstring_alloc(10);
423 +    char   *key;
424 +    int     len;
425 +
426 +#ifdef LDAP_API_FEATURE_X_OPENLDAP
427 +    int     sslon = dict_ldap->start_tls || dict_ldap->ldap_ssl;
428 +
429 +#endif
430 +    LDAP_CONN *conn;
431 +
432 +#define ADDSTR(vp, s) vstring_memcat((vp), (s), strlen((s))+1)
433 +#define ADDINT(vp, i) vstring_sprintf_append((vp), "%lu", (unsigned long)(i))
434 +
435 +    ADDSTR(keybuf, dict_ldap->server_host);
436 +    ADDINT(keybuf, dict_ldap->server_port);
437 +    ADDINT(keybuf, dict_ldap->bind);
438 +    ADDSTR(keybuf, dict_ldap->bind ? dict_ldap->bind_dn : "");
439 +    ADDSTR(keybuf, dict_ldap->bind ? dict_ldap->bind_pw : "");
440 +    ADDINT(keybuf, dict_ldap->dereference);
441 +    ADDINT(keybuf, dict_ldap->chase_referrals);
442 +    ADDINT(keybuf, dict_ldap->debuglevel);
443 +    ADDINT(keybuf, dict_ldap->version);
444 +#ifdef LDAP_API_FEATURE_X_OPENLDAP
445 +    ADDINT(keybuf, dict_ldap->ldap_ssl);
446 +    ADDINT(keybuf, dict_ldap->start_tls);
447 +    ADDINT(keybuf, sslon ? dict_ldap->tls_require_cert : 0);
448 +    ADDSTR(keybuf, sslon ? dict_ldap->tls_ca_cert_file : "");
449 +    ADDSTR(keybuf, sslon ? dict_ldap->tls_ca_cert_dir : "");
450 +    ADDSTR(keybuf, sslon ? dict_ldap->tls_cert : "");
451 +    ADDSTR(keybuf, sslon ? dict_ldap->tls_key : "");
452 +    ADDSTR(keybuf, sslon ? dict_ldap->tls_random_file : "");
453 +    ADDSTR(keybuf, sslon ? dict_ldap->tls_cipher_suite : "");
454 +#endif
455 +
456 +    key = vstring_str(keybuf);
457 +    len = VSTRING_LEN(keybuf);
458 +
459 +    if (conn_hash == 0)
460 +       conn_hash = binhash_create(0);
461 +
462 +    if ((dict_ldap->ht = binhash_locate(conn_hash, key, len)) == 0) {
463 +       conn = (LDAP_CONN *) mymalloc(sizeof(LDAP_CONN));
464 +       conn->conn_ld = 0;
465 +       conn->conn_refcount = 0;
466 +       dict_ldap->ht = binhash_enter(conn_hash, key, len, (char *) conn);
467 +    }
468 +    ++DICT_LDAP_CONN(dict_ldap)->conn_refcount;
469 +
470 +    vstring_free(keybuf);
471 +}
472 +
473 +/*
474   * expand a filter (lookup or result)
475   */
476 -static void dict_ldap_expand_filter(char *filter, char *value, VSTRING *out)
477 +static void dict_ldap_expand_filter(char *ldapsource, char *filter, char *value, VSTRING *out)
478  {
479      char   *myname = "dict_ldap_expand_filter";
480      char   *sub,
481 @@ -462,8 +664,8 @@
482                 break;
483             default:
484                 msg_warn
485 -                   ("%s: Invalid filter substitution format '%%%c'!",
486 -                    myname, *(sub + 1));
487 +                   ("%s: %s: Invalid filter substitution format '%%%c'!",
488 +                    myname, ldapsource, *(sub + 1));
489                 /* fall through */
490             case 's':
491                 vstring_strcat(out, u);
492 @@ -486,6 +688,9 @@
493  static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
494                                          VSTRING *result)
495  {
496 +    static int recursion = 0;
497 +    static int expansion;
498 +    long    entries = 0;
499      long    i = 0;
500      int     rc = 0;
501      LDAPMessage *resloop = 0;
502 @@ -500,13 +705,27 @@
503      tv.tv_sec = dict_ldap->timeout;
504      tv.tv_usec = 0;
505  
506 +    if (++recursion == 1)
507 +       expansion = 0;
508 +
509      if (msg_verbose)
510 -       msg_info("%s: Search found %d match(es)", myname,
511 +       msg_info("%s[%d]: Search found %d match(es)", myname, recursion,
512                  ldap_count_entries(dict_ldap->ld, res));
513  
514      for (entry = ldap_first_entry(dict_ldap->ld, res); entry != NULL;
515          entry = ldap_next_entry(dict_ldap->ld, entry)) {
516         ber = NULL;
517 +
518 +       /*
519 +        * LDAP should not, but may produce more than the requested maximum
520 +        * number of entries.
521 +        */
522 +       if (dict_errno == 0 && ++entries > dict_ldap->size_limit
523 +           && dict_ldap->size_limit) {
524 +           msg_warn("%s[%d]: %s: Query size limit (%ld) exceeded", myname,
525 +                  recursion, dict_ldap->ldapsource, dict_ldap->size_limit);
526 +           dict_errno = DICT_ERR_RETRY;
527 +       }
528         for (attr = ldap_first_attribute(dict_ldap->ld, entry, &ber);
529              attr != NULL;
530              ldap_memfree(attr), attr = ldap_next_attribute(dict_ldap->ld,
531 @@ -514,17 +733,38 @@
532             vals = ldap_get_values(dict_ldap->ld, entry, attr);
533             if (vals == NULL) {
534                 if (msg_verbose)
535 -                   msg_info("%s: Entry doesn't have any values for %s",
536 -                            myname, attr);
537 +                   msg_info("%s[%d]: Entry doesn't have any values for %s",
538 +                            myname, recursion, attr);
539                 continue;
540             }
541 +
542 +           /*
543 +            * If we previously encountered an error, we still continue
544 +            * through the loop, to avoid memory leaks, but we don't waste
545 +            * time accumulating any further results.
546 +            *
547 +            * XXX: There may be a more efficient way to exit the loop with no
548 +            * leaks, but it will likely be more fragile and not worth the
549 +            * extra code.
550 +            */
551 +           if (dict_errno != 0 || vals[0] == 0) {
552 +               ldap_value_free(vals);
553 +               continue;
554 +           }
555 +
556 +           /*
557 +            * The "result_attributes" list enumerates all the requested
558 +            * attributes, first the ordinary result attribtutes and then the
559 +            * special result attributes that hold DN or LDAP URL values.
560 +            *
561 +            * The number of ordinary attributes is "num_attributes".
562 +            *
563 +            * We compute the attribute type (ordinary or special) from its
564 +            * index on the "result_attributes" list.
565 +            */
566             for (i = 0; dict_ldap->result_attributes->argv[i]; i++) {
567 -               if (strcasecmp(dict_ldap->result_attributes->argv[i],
568 -                              attr) == 0) {
569 -                   if (msg_verbose)
570 -                       msg_info("%s: search returned %ld value(s) for requested result attribute %s", myname, i, attr);
571 +               if (strcasecmp(dict_ldap->result_attributes->argv[i], attr) == 0)
572                     break;
573 -               }
574             }
575  
576             /*
577 @@ -532,20 +772,38 @@
578              * recursing (for dn or url attributes).
579              */
580             if (i < dict_ldap->num_attributes) {
581 +               /* Ordinary result attribute */
582                 for (i = 0; vals[i] != NULL; i++) {
583 +                   if (++expansion > dict_ldap->expansion_limit &&
584 +                       dict_ldap->expansion_limit) {
585 +                       msg_warn("%s[%d]: %s: Expansion limit exceeded at"
586 +                              " result attribute %s=%s", myname, recursion,
587 +                                dict_ldap->ldapsource, attr, vals[i]);
588 +                       dict_errno = DICT_ERR_RETRY;
589 +                       break;
590 +                   }
591                     if (VSTRING_LEN(result) > 0)
592                         vstring_strcat(result, ",");
593                     if (dict_ldap->result_filter == NULL)
594                         vstring_strcat(result, vals[i]);
595                     else
596 -                       dict_ldap_expand_filter(dict_ldap->result_filter,
597 +                       dict_ldap_expand_filter(dict_ldap->ldapsource,
598 +                                               dict_ldap->result_filter,
599                                                 vals[i], result);
600                 }
601 -           } else if (dict_ldap->result_attributes->argv[i]) {
602 +               if (dict_errno != 0)
603 +                   continue;
604 +               if (msg_verbose)
605 +                   msg_info("%s[%d]: search returned %ld value(s) for"
606 +                            " requested result attribute %s",
607 +                            myname, recursion, i, attr);
608 +           } else if (recursion < dict_ldap->recursion_limit
609 +                      && dict_ldap->result_attributes->argv[i]) {
610 +               /* Special result attribute */
611                 for (i = 0; vals[i] != NULL; i++) {
612                     if (ldap_is_ldap_url(vals[i])) {
613                         if (msg_verbose)
614 -                           msg_info("%s: looking up URL %s", myname,
615 +                           msg_info("%s[%d]: looking up URL %s", myname, recursion,
616                                      vals[i]);
617                         rc = ldap_url_parse(vals[i], &url);
618                         if (rc == 0) {
619 @@ -557,7 +815,7 @@
620                         }
621                     } else {
622                         if (msg_verbose)
623 -                           msg_info("%s: looking up DN %s", myname, vals[i]);
624 +                           msg_info("%s[%d]: looking up DN %s", myname, recursion, vals[i]);
625                         rc = ldap_search_st(dict_ldap->ld, vals[i],
626                                             LDAP_SCOPE_BASE, "objectclass=*",
627                                          dict_ldap->result_attributes->argv,
628 @@ -573,11 +831,11 @@
629                          * Go ahead and treat this as though the DN existed
630                          * and just didn't have any result attributes.
631                          */
632 -                       msg_warn("%s: DN %s not found, skipping ", myname,
633 -                                vals[i]);
634 +                       msg_warn("%s[%d]: DN %s not found, skipping ", myname,
635 +                                recursion, vals[i]);
636                         break;
637                     default:
638 -                       msg_warn("%s: search error %d: %s ", myname, rc,
639 +                       msg_warn("%s[%d]: search error %d: %s ", myname, recursion, rc,
640                                  ldap_err2string(rc));
641                         dict_errno = DICT_ERR_RETRY;
642                         break;
643 @@ -585,7 +843,21 @@
644  
645                     if (resloop != 0)
646                         ldap_msgfree(resloop);
647 +                   if (dict_errno != 0)
648 +                       break;
649                 }
650 +               if (dict_errno != 0)
651 +                   continue;
652 +               if (msg_verbose)
653 +                   msg_info("%s[%d]: search returned %ld value(s) for"
654 +                            " special result attribute %s",
655 +                            myname, recursion, i, attr);
656 +           } else if (recursion >= dict_ldap->recursion_limit
657 +                      && dict_ldap->result_attributes->argv[i]) {
658 +               msg_warn("%s[%d]: %s: Recursion limit exceeded"
659 +                        " for special attribute %s=%s",
660 +                  myname, recursion, dict_ldap->ldapsource, attr, vals[0]);
661 +               dict_errno = DICT_ERR_RETRY;
662             }
663             ldap_value_free(vals);
664         }
665 @@ -593,7 +865,8 @@
666             ber_free(ber, 0);
667      }
668      if (msg_verbose)
669 -       msg_info("%s: Leaving %s", myname, myname);
670 +       msg_info("%s[%d]: Leaving %s", myname, recursion, myname);
671 +    --recursion;
672  }
673  
674  /* dict_ldap_lookup - find database entry */
675 @@ -608,6 +881,7 @@
676      VSTRING *escaped_name = 0,
677             *filter_buf = 0;
678      int     rc = 0;
679 +    int     sizelimit;
680      char   *sub,
681             *end;
682  
683 @@ -624,11 +898,8 @@
684      if (dict_ldap->domain) {
685         const char *p = strrchr(name, '@');
686  
687 -       if (p != 0)
688 -           p = p + 1;
689 -       else
690 -           p = name;
691 -       if (match_list_match(dict_ldap->domain, p) == 0) {
692 +       if (p == 0 || p == name ||
693 +           match_list_match(dict_ldap->domain, ++p) == 0) {
694             if (msg_verbose)
695                 msg_info("%s: domain of %s not found in domain list", myname,
696                          name);
697 @@ -644,6 +915,13 @@
698      vstring_strcpy(result, "");
699  
700      /*
701 +     * Because the connection may be shared and invalidated via queries for
702 +     * another map, update private copy of "ld" from shared connection
703 +     * container.
704 +     */
705 +    dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld;
706 +
707 +    /*
708       * Connect to the LDAP server, if necessary.
709       */
710      if (dict_ldap->ld == NULL) {
711 @@ -663,6 +941,18 @@
712         msg_info("%s: Using existing connection for LDAP source %s",
713                  myname, dict_ldap->ldapsource);
714  
715 +    /*
716 +     * Connection caching, means that the connection handle may have the
717 +     * wrong size limit. Re-adjust before each query. This is cheap, just
718 +     * sets a field in the ldap connection handle. We also do this in the
719 +     * connect code, because we sometimes reconnect (below) in the middle of
720 +     * a query.
721 +     */
722 +    sizelimit = dict_ldap->size_limit ? dict_ldap->size_limit : LDAP_NO_LIMIT;
723 +    if (ldap_set_option(dict_ldap->ld, LDAP_OPT_SIZELIMIT, &sizelimit)
724 +       != LDAP_OPT_SUCCESS)
725 +       msg_warn("%s: %s: Unable to set query result size limit to %ld.",
726 +                myname, dict_ldap->ldapsource, dict_ldap->size_limit);
727  
728      /*
729       * Prepare the query.
730 @@ -720,11 +1010,11 @@
731         /*
732          * No, log the fact and continue.
733          */
734 -       msg_warn("%s: Fixed query_filter %s is probably useless", myname,
735 -                dict_ldap->query_filter);
736 +       msg_warn("%s: %s: Fixed query_filter %s is probably useless", myname,
737 +                dict_ldap->ldapsource, dict_ldap->query_filter);
738         vstring_strcpy(filter_buf, dict_ldap->query_filter);
739      } else {
740 -       dict_ldap_expand_filter(dict_ldap->query_filter,
741 +       dict_ldap_expand_filter(dict_ldap->ldapsource, dict_ldap->query_filter,
742                                 vstring_str(escaped_name), filter_buf);
743      }
744  
745 @@ -747,7 +1037,7 @@
746                      myname, dict_ldap->ldapsource);
747  
748         ldap_unbind(dict_ldap->ld);
749 -       dict_ldap->ld = NULL;
750 +       dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
751         dict_ldap_connect(dict_ldap);
752  
753         /*
754 @@ -799,7 +1089,7 @@
755          * next lookup.
756          */
757         ldap_unbind(dict_ldap->ld);
758 -       dict_ldap->ld = NULL;
759 +        dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
760  
761         /*
762          * And tell the caller to try again later.
763 @@ -830,9 +1120,18 @@
764  {
765      char   *myname = "dict_ldap_close";
766      DICT_LDAP *dict_ldap = (DICT_LDAP *) dict;
767 +    LDAP_CONN *conn = DICT_LDAP_CONN(dict_ldap);
768 +    BINHASH_INFO *ht = dict_ldap->ht;
769  
770 -    if (dict_ldap->ld)
771 -       ldap_unbind(dict_ldap->ld);
772 +    if (--conn->conn_refcount == 0) {
773 +       if (conn->conn_ld) {
774 +           if (msg_verbose)
775 +               msg_info("%s: Closed connection handle for LDAP source %s",
776 +                        myname, dict_ldap->ldapsource);
777 +           ldap_unbind(conn->conn_ld);
778 +       }
779 +       binhash_delete(conn_hash, ht->key, ht->key_len, myfree);
780 +    }
781  
782      myfree(dict_ldap->ldapsource);
783      myfree(dict_ldap->server_host);
784 @@ -845,19 +1144,32 @@
785      argv_free(dict_ldap->result_attributes);
786      myfree(dict_ldap->bind_dn);
787      myfree(dict_ldap->bind_pw);
788 +#ifdef LDAP_API_FEATURE_X_OPENLDAP
789 +    myfree(dict_ldap->tls_ca_cert_file);
790 +    myfree(dict_ldap->tls_ca_cert_dir);
791 +    myfree(dict_ldap->tls_cert);
792 +    myfree(dict_ldap->tls_key);
793 +    myfree(dict_ldap->tls_random_file);
794 +    myfree(dict_ldap->tls_cipher_suite);
795 +#endif
796      dict_free(dict);
797  }
798  
799  /* dict_ldap_open - create association with data base */
800  
801 -DICT   *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
802 +DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
803  {
804      char   *myname = "dict_ldap_open";
805      DICT_LDAP *dict_ldap;
806      VSTRING *config_param;
807 +    VSTRING *url_list;
808 +    char   *s;
809 +    char   *h;
810      char   *domainlist;
811 +    char   *server_host;
812      char   *scope;
813      char   *attr;
814 +    int    tmp;
815  
816      if (msg_verbose)
817         msg_info("%s: Using LDAP source %s", myname, ldapsource);
818 @@ -870,15 +1182,14 @@
819  
820      dict_ldap->ldapsource = mystrdup(ldapsource);
821  
822 +    dict_ldap->ld = NULL;
823 +
824      config_param = vstring_alloc(15);
825      vstring_sprintf(config_param, "%s_server_host", ldapsource);
826  
827 -    dict_ldap->server_host =
828 +    server_host =
829         mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
830 -                                           "localhost", 0, 0));
831 -    if (msg_verbose)
832 -       msg_info("%s: %s is %s", myname, vstring_str(config_param),
833 -                dict_ldap->server_host);
834 +                                           "localhost", 1, 0));
835  
836      /*
837       * get configured value of "ldapsource_server_port"; default to LDAP_PORT
838 @@ -892,11 +1203,87 @@
839                  dict_ldap->server_port);
840  
841      /*
842 +     * Define LDAP Version.
843 +     */
844 +    vstring_sprintf(config_param, "%s_version", ldapsource);
845 +    dict_ldap->version = get_mail_conf_int(vstring_str(config_param), 2, 2, 0);
846 +    switch (dict_ldap->version) {
847 +    case 2:
848 +        dict_ldap->version = LDAP_VERSION2;
849 +        break;
850 +    case 3:
851 +        dict_ldap->version = LDAP_VERSION3;
852 +        break;
853 +    default:
854 +        msg_warn("%s: Unknown version %d.", myname, dict_ldap->version);
855 +        dict_ldap->version = LDAP_VERSION2;
856 +    }
857 +
858 +#if defined(LDAP_API_FEATURE_X_OPENLDAP)
859 +    dict_ldap->ldap_ssl = 0;
860 +#endif
861 +
862 +    url_list = vstring_alloc(32);
863 +    s = server_host;
864 +    while ((h = mystrtok(&s, " \t\n\r,")) != NULL) {
865 +#if defined(LDAP_API_FEATURE_X_OPENLDAP)
866 +
867 +       /*
868 +        * Convert (host, port) pairs to LDAP URLs
869 +        */
870 +       if (ldap_is_ldap_url(h)) {
871 +           LDAPURLDesc *url_desc;
872 +           int     rc;
873 +
874 +           if ((rc = ldap_url_parse(h, &url_desc)) != 0) {
875 +               msg_error("%s: error parsing URL %s: %d: %s; skipping", myname,
876 +                         h, rc, ldap_err2string(rc));
877 +               continue;
878 +           }
879 +           if (strcasecmp(url_desc->lud_scheme, "ldap") != 0 &&
880 +               dict_ldap->version != LDAP_VERSION3) {
881 +               msg_warn("%s: URL scheme %s requires protocol version 3", myname,
882 +                        url_desc->lud_scheme);
883 +               dict_ldap->version = LDAP_VERSION3;
884 +           }
885 +           if (strcasecmp(url_desc->lud_scheme, "ldaps") == 0)
886 +               dict_ldap->ldap_ssl = 1;
887 +           ldap_free_urldesc(url_desc);
888 +           vstring_sprintf_append(url_list, " %s", h);
889 +       } else {
890 +           if (strrchr(h, ':'))
891 +               vstring_sprintf_append(url_list, " ldap://%s", h);
892 +           else
893 +               vstring_sprintf_append(url_list, " ldap://%s:%d", h,
894 +                                      dict_ldap->server_port);
895 +       }
896 +#else
897 +       vstring_sprintf_append(url_list, " %s", h);
898 +#endif
899 +    }
900 +
901 +     dict_ldap->server_host =
902 +       mystrdup(VSTRING_LEN(url_list) > 0 ? vstring_str(url_list) + 1 : "");
903 +
904 +#if defined(LDAP_API_FEATURE_X_OPENLDAP)
905 +    /*
906 +     * With URL scheme, clear port to normalize connection cache key
907 +     */
908 +
909 +     dict_ldap->server_port = LDAP_PORT;
910 +
911 +       msg_info("%s: %s server_host URL is %s", myname, ldapsource,
912 +                dict_ldap->server_host);
913 +#endif
914 +    myfree(server_host);
915 +    vstring_free(url_list);
916 +
917 +    /*
918       * Scope handling thanks to Carsten Hoeger of SuSE.
919       */
920      vstring_sprintf(config_param, "%s_scope", ldapsource);
921      scope =
922 -       (char *) get_mail_conf_str(vstring_str(config_param), "sub", 0, 0);
923 +       (char *) get_mail_conf_str(vstring_str(config_param), "sub", 1, 0);
924  
925      if (strcasecmp(scope, "one") == 0) {
926         dict_ldap->scope = LDAP_SCOPE_ONELEVEL;
927 @@ -910,12 +1297,15 @@
928             msg_info("%s: %s is LDAP_SCOPE_BASE", myname,
929                      vstring_str(config_param));
930  
931 -    } else {
932 +    } else if (strcasecmp(scope, "sub") == 0) {
933         dict_ldap->scope = LDAP_SCOPE_SUBTREE;
934         if (msg_verbose)
935             msg_info("%s: %s is LDAP_SCOPE_SUBTREE", myname,
936                      vstring_str(config_param));
937 -
938 +    } else {
939 +       dict_ldap->scope = LDAP_SCOPE_SUBTREE;
940 +        msg_warn("%s: %s: Unrecognized value %s specified for scope; using sub",
941 +                 myname, vstring_str(config_param), scope);
942      }
943  
944      myfree(scope);
945 @@ -992,6 +1382,8 @@
946         msg_info("%s: %s is %s", myname, vstring_str(config_param), attr);;
947      dict_ldap->result_attributes = argv_split(attr, " ,\t\r\n");
948      dict_ldap->num_attributes = dict_ldap->result_attributes->argc;
949 +    
950 +    myfree(attr);
951  
952      vstring_sprintf(config_param, "%s_special_result_attribute", ldapsource);
953      attr = mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
954 @@ -1003,6 +1395,8 @@
955         argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n");
956      }
957  
958 +     myfree(attr);
959 +
960      /*
961       * get configured value of "ldapsource_bind"; default to true
962       */
963 @@ -1040,31 +1434,60 @@
964       * get configured value of "ldapsource_cache"; default to false
965       */
966      vstring_sprintf(config_param, "%s_cache", ldapsource);
967 -    dict_ldap->cache = get_mail_conf_bool(vstring_str(config_param), 0);
968 -    if (msg_verbose)
969 -       msg_info("%s: %s is %d", myname, vstring_str(config_param),
970 -                dict_ldap->cache);
971 +    tmp = get_mail_conf_bool(vstring_str(config_param), 0);
972 +    if (tmp)
973 +       msg_warn("%s: %s ignoring cache", myname, vstring_str(config_param));
974  
975      /*
976       * get configured value of "ldapsource_cache_expiry"; default to 30
977       * seconds
978       */
979      vstring_sprintf(config_param, "%s_cache_expiry", ldapsource);
980 -    dict_ldap->cache_expiry = get_mail_conf_int(vstring_str(config_param),
981 -                                               30, 0, 0);
982 -    if (msg_verbose)
983 -       msg_info("%s: %s is %ld", myname, vstring_str(config_param),
984 -                dict_ldap->cache_expiry);
985 +    tmp = get_mail_conf_int(vstring_str(config_param), -1, 0, 0);
986 +
987 +    if (tmp >= 0)
988 +       msg_warn("%s: %s ignoring cache_expiry", myname, vstring_str(config_param));
989  
990      /*
991       * get configured value of "ldapsource_cache_size"; default to 32k
992       */
993      vstring_sprintf(config_param, "%s_cache_size", ldapsource);
994 -    dict_ldap->cache_size = get_mail_conf_int(vstring_str(config_param),
995 -                                             32768, 0, 0);
996 +    tmp = get_mail_conf_int(vstring_str(config_param),
997 +                                             -1, 0, 0);
998 +    if (tmp >= 0)
999 +       msg_warn("%s: %s ignoring cache_size", myname, vstring_str(config_param));
1000 +
1001 +    /*
1002 +     * get configured value of "recursion_limit"; default to 1000
1003 +     */
1004 +    vstring_sprintf(config_param, "%s_recursion_limit", ldapsource);
1005 +    dict_ldap->recursion_limit = get_mail_conf_int(vstring_str(config_param),
1006 +                                               1000, 1, 0);
1007 +
1008 +    if (msg_verbose)
1009 +        msg_info("%s: %s is %ld", myname, vstring_str(config_param),
1010 +                 dict_ldap->recursion_limit);
1011 +    
1012 +    /*
1013 +     * Define LDAP Version.
1014 +     * get configured value of "expansion_limit"; default to 0
1015 +     */
1016 +
1017 +    vstring_sprintf(config_param, "%s_expansion_limit", ldapsource);
1018 +    dict_ldap->expansion_limit = get_mail_conf_int(vstring_str(config_param),
1019 +                                                0, 0, 0);
1020 +    if (msg_verbose)
1021 +        msg_info("%s: %s is %ld", myname, vstring_str(config_param),
1022 +                 dict_ldap->expansion_limit);
1023 +    /*
1024 +     * get configured value of "size_limit"; default to expansion_limit
1025 +     */
1026 +    vstring_sprintf(config_param, "%s_size_limit", ldapsource);
1027 +    dict_ldap->size_limit = get_mail_conf_int(vstring_str(config_param),
1028 +                                        dict_ldap->expansion_limit, 0, 0);
1029      if (msg_verbose)
1030 -       msg_info("%s: %s is %ld", myname, vstring_str(config_param),
1031 -                dict_ldap->cache_size);
1032 +        msg_info("%s: %s is %ld", myname, vstring_str(config_param),
1033 +                 dict_ldap->size_limit);
1034  
1035      /*
1036       * Alias dereferencing suggested by Mike Mattice.
1037 @@ -1074,29 +1497,11 @@
1038                                                0);
1039  
1040      /*
1041 -     * Define LDAP Version.
1042 -     */
1043 -    vstring_sprintf(config_param, "%s_version", ldapsource);
1044 -    dict_ldap->version = get_mail_conf_int(vstring_str(config_param), 2, 0,
1045 -                                          0);
1046 -    switch (dict_ldap->version) {
1047 -    case 2:
1048 -       dict_ldap->version = LDAP_VERSION2;
1049 -       break;
1050 -    case 3:
1051 -       dict_ldap->version = LDAP_VERSION3;
1052 -       break;
1053 -    default:
1054 -       msg_warn("%s: Unknown version %d.", myname, dict_ldap->version);
1055 -       dict_ldap->version = LDAP_VERSION2;
1056 -    }
1057 -
1058 -    /*
1059       * Make sure only valid options for alias dereferencing are used.
1060       */
1061      if (dict_ldap->dereference < 0 || dict_ldap->dereference > 3) {
1062 -       msg_warn("%s: Unrecognized value %d specified for %s; using 0",
1063 -                myname, dict_ldap->dereference, vstring_str(config_param));
1064 +       msg_warn("%s: %s: Unrecognized value %d specified for %s; using 0",
1065 +                myname, ldapsource, dict_ldap->dereference, vstring_str(config_param));
1066         dict_ldap->dereference = 0;
1067      }
1068      if (msg_verbose)
1069 @@ -1110,6 +1515,68 @@
1070         msg_info("%s: %s is %d", myname, vstring_str(config_param),
1071                  dict_ldap->chase_referrals);
1072  
1073 +#ifdef LDAP_API_FEATURE_X_OPENLDAP
1074 +
1075 +    /*
1076 +     * TLS options
1077 +     */
1078 +    /* get configured value of "start_tls"; default to no */
1079 +    vstring_sprintf(config_param, "%s_start_tls", ldapsource);
1080 +    dict_ldap->start_tls = get_mail_conf_bool(vstring_str(config_param), 0);
1081 +    if (dict_ldap->start_tls && dict_ldap->version < LDAP_VERSION3) {
1082 +       msg_warn("%s: %s start_tls requires protocol version 3",
1083 +                myname, ldapsource);
1084 +       dict_ldap->version = LDAP_VERSION3;
1085 +    }
1086 +
1087 +    /* get configured value of "tls_require_cert"; default to no */
1088 +    vstring_sprintf(config_param, "%s_tls_require_cert", ldapsource);
1089 +    dict_ldap->tls_require_cert = get_mail_conf_bool(vstring_str(config_param), 0);
1090 +
1091 +    /* get configured value of "tls_ca_cert_file"; default "" */
1092 +    vstring_sprintf(config_param, "%s_tls_ca_cert_file", ldapsource);
1093 +    dict_ldap->tls_ca_cert_file = mystrdup((char *)
1094 +                                  get_mail_conf_str(vstring_str
1095 +                                                    (config_param), "", 0,
1096 +                                                    0));
1097 +
1098 +    /* get configured value of "tls_ca_cert_dir"; default "" */
1099 +    vstring_sprintf(config_param, "%s_tls_ca_cert_dir", ldapsource);
1100 +    dict_ldap->tls_ca_cert_dir = mystrdup((char *)
1101 +                                  get_mail_conf_str(vstring_str
1102 +                                                    (config_param), "", 0,
1103 +                                                    0));
1104 +
1105 +    /* get configured value of "tls_cert"; default "" */
1106 +    vstring_sprintf(config_param, "%s_tls_cert", ldapsource);
1107 +    dict_ldap->tls_cert = mystrdup((char *)
1108 +                                  get_mail_conf_str(vstring_str
1109 +                                                    (config_param), "", 0,
1110 +                                                    0));
1111 +
1112 +    /* get configured value of "tls_key"; default "" */
1113 +    vstring_sprintf(config_param, "%s_tls_key", ldapsource);
1114 +    dict_ldap->tls_key = mystrdup((char *)
1115 +                                  get_mail_conf_str(vstring_str
1116 +                                                    (config_param), "", 0,
1117 +                                                    0));
1118 +
1119 +    /* get configured value of "tls_random_file"; default "" */
1120 +    vstring_sprintf(config_param, "%s_tls_random_file", ldapsource);
1121 +    dict_ldap->tls_random_file = mystrdup((char *)
1122 +                                  get_mail_conf_str(vstring_str
1123 +                                                    (config_param), "", 0,
1124 +                                                    0));
1125 +
1126 +    /* get configured value of "tls_cipher_suite"; default "" */
1127 +    vstring_sprintf(config_param, "%s_tls_cipher_suite", ldapsource);
1128 +    dict_ldap->tls_cipher_suite = mystrdup((char *)
1129 +                                  get_mail_conf_str(vstring_str
1130 +                                                    (config_param), "", 0,
1131 +                                                    0));
1132 +#endif
1133 +
1134 +
1135      /*
1136       * Debug level.
1137       */
1138 @@ -1122,21 +1589,13 @@
1139                  dict_ldap->debuglevel);
1140  #endif
1141  
1142 -    dict_ldap_connect(dict_ldap);
1143 -
1144      /*
1145 -     * if dict_ldap_connect() set dict_errno, free dict_ldap and abort.
1146 +     * Find or allocate shared LDAP connection container.
1147       */
1148 -    if (dict_errno) {
1149 -       if (dict_ldap->ld)
1150 -           ldap_unbind(dict_ldap->ld);
1151 -
1152 -       myfree((char *) dict_ldap);
1153 -       return (0);
1154 -    }
1155 +    dict_ldap_conn_find(dict_ldap);
1156  
1157      /*
1158 -     * Otherwise, we're all set. Return the new dict_ldap structure.
1159 +     * Return the new dict_ldap structure.
1160       */
1161      return (DICT_DEBUG (&dict_ldap->dict));
1162  }
This page took 0.111913 seconds and 4 git commands to generate.