17c431e5c7e7d43270dff8cd81d2eeb99435268e
[exim.git] / src / src / lookups / ldap.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2020 - 2022 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-only */
9
10 /* Many thanks to Stuart Lynne for contributing the original code for this
11 driver. Further contributions from Michael Haardt, Brian Candler, Barry
12 Pederson, Peter Savitch and Christian Kellner. Particular thanks to Brian for
13 researching how to handle the different kinds of error. */
14
15
16 #include "../exim.h"
17 #include "lf_functions.h"
18
19
20 /* Include LDAP headers. The code below uses some "old" LDAP interfaces that
21 are deprecated in OpenLDAP. I don't know their status in other LDAP
22 implementations. LDAP_DEPRECATED causes their prototypes to be defined in
23 ldap.h. */
24
25 #define LDAP_DEPRECATED 1
26
27 #include <lber.h>
28 #include <ldap.h>
29
30
31 /* Annoyingly, the different LDAP libraries handle errors in different ways,
32 and some other things too. There doesn't seem to be an automatic way of
33 distinguishing between them. Local/Makefile should contain a setting of
34 LDAP_LIB_TYPE, which in turn causes appropriate macros to be defined for the
35 different kinds. Those that matter are:
36
37 LDAP_LIB_NETSCAPE
38 LDAP_LIB_SOLARIS   with synonym LDAP_LIB_SOLARIS7
39 LDAP_LIB_OPENLDAP2
40
41 These others may be defined, but are in fact the default, so are not tested:
42
43 LDAP_LIB_UMICHIGAN
44 LDAP_LIB_OPENLDAP1
45 */
46
47 #if defined(LDAP_LIB_SOLARIS7) && ! defined(LDAP_LIB_SOLARIS)
48 #define LDAP_LIB_SOLARIS
49 #endif
50
51
52 /* Just in case LDAP_NO_LIMIT is not defined by some of these libraries. */
53
54 #ifndef LDAP_NO_LIMIT
55 #define LDAP_NO_LIMIT 0
56 #endif
57
58
59 /* Just in case LDAP_DEREF_NEVER is not defined */
60
61 #ifndef LDAP_DEREF_NEVER
62 #define LDAP_DEREF_NEVER 0
63 #endif
64
65
66 /* Four types of LDAP search are implemented */
67
68 #define SEARCH_LDAP_MULTIPLE 0       /* Get attributes from multiple entries */
69 #define SEARCH_LDAP_SINGLE 1         /* Get attributes from one entry only */
70 #define SEARCH_LDAP_DN 2             /* Get just the DN from one entry */
71 #define SEARCH_LDAP_AUTH 3           /* Just checking for authentication */
72
73 /* In all 4 cases, the DN is left in $ldap_dn (which post-dates the
74 SEARCH_LDAP_DN lookup). */
75
76
77 /* Structure and anchor for caching connections. */
78
79 typedef struct ldap_connection {
80   struct ldap_connection *next;
81   uschar *host;
82   uschar *user;
83   uschar *password;
84   BOOL  bound;
85   int   port;
86   BOOL  is_start_tls_called;
87   LDAP *ld;
88 } LDAP_CONNECTION;
89
90 static LDAP_CONNECTION *ldap_connections = NULL;
91
92
93
94 /*************************************************
95 *         Internal search function               *
96 *************************************************/
97
98 /* This is the function that actually does the work. It is called (indirectly
99 via control_ldap_search) from eldap_find(), eldapauth_find(), eldapdn_find(),
100 and eldapm_find(), with a difference in the "search_type" argument.
101
102 The case of eldapauth_find() is special in that all it does is do
103 authentication, returning OK or FAIL as appropriate. This isn't used as a
104 lookup. Instead, it is called from expand.c as an expansion condition test.
105
106 The DN from a successful lookup is placed in $ldap_dn. This feature postdates
107 the provision of the SEARCH_LDAP_DN facility for returning just the DN as the
108 data.
109
110 Arguments:
111   ldap_url      the URL to be looked up
112   server        server host name, when URL contains none
113   s_port        server port, used when URL contains no name
114   search_type   SEARCH_LDAP_MULTIPLE allows values from multiple entries
115                 SEARCH_LDAP_SINGLE allows values from one entry only
116                 SEARCH_LDAP_DN gets the DN from one entry
117   res           set to point at the result (not used for ldapauth)
118   errmsg        set to point a message if result is not OK
119   defer_break   set TRUE if no more servers to be tried after a DEFER
120   user          user name for authentication, or NULL
121   password      password for authentication, or NULL
122   sizelimit     max number of entries returned, or 0 for no limit
123   timelimit     max time to wait, or 0 for no limit
124   tcplimit      max time for network activity, e.g. connect, or 0 for OS default
125   deference     the dereference option, which is one of
126                   LDAP_DEREF_{NEVER,SEARCHING,FINDING,ALWAYS}
127   referrals     the referral option, which is LDAP_OPT_ON or LDAP_OPT_OFF
128
129 Returns:        OK or FAIL or DEFER
130                 FAIL is given only if a lookup was performed successfully, but
131                 returned no data.
132 */
133
134 static int
135 perform_ldap_search(const uschar *ldap_url, uschar *server, int s_port,
136   int search_type, uschar **res, uschar **errmsg, BOOL *defer_break,
137   uschar *user, uschar *password, int sizelimit, int timelimit, int tcplimit,
138   int dereference, void *referrals)
139 {
140 LDAPURLDesc     *ludp = NULL;
141 LDAPMessage     *result = NULL;
142 BerElement      *ber;
143 LDAP_CONNECTION *lcp;
144
145 struct timeval timeout;
146 struct timeval *timeoutptr = NULL;
147
148 gstring * data = NULL;
149 uschar *dn = NULL;
150 uschar *host;
151 uschar **values;
152 uschar **firstval;
153 uschar porttext[16];
154
155 uschar *error1 = NULL;   /* string representation of errcode (static) */
156 uschar *error2 = NULL;   /* error message from the server */
157 uschar *matched = NULL;  /* partially matched DN */
158
159 int    attrs_requested = 0;
160 int    error_yield = DEFER;
161 int    msgid;
162 int    rc, ldap_rc, ldap_parse_rc;
163 int    port;
164 int    rescount = 0;
165 BOOL   attribute_found = FALSE;
166 BOOL   ldapi = FALSE;
167
168 DEBUG(D_lookup) debug_printf_indent("perform_ldap_search:"
169     " ldap%s URL = \"%s\" server=%s port=%d "
170     "sizelimit=%d timelimit=%d tcplimit=%d\n",
171     search_type == SEARCH_LDAP_MULTIPLE ? "m" :
172     search_type == SEARCH_LDAP_DN       ? "dn" :
173     search_type == SEARCH_LDAP_AUTH     ? "auth" : "",
174     ldap_url, server, s_port, sizelimit, timelimit, tcplimit);
175
176 /* Check if LDAP thinks the URL is a valid LDAP URL. We assume that if the LDAP
177 library that is in use doesn't recognize, say, "ldapi", it will barf here. */
178
179 if (!ldap_is_ldap_url(CS ldap_url))
180   {
181   *errmsg = string_sprintf("ldap_is_ldap_url: not an LDAP url \"%s\"\n",
182     ldap_url);
183   goto RETURN_ERROR_BREAK;
184   }
185
186 /* Parse the URL */
187
188 if ((rc = ldap_url_parse(CS ldap_url, &ludp)) != 0)
189   {
190   *errmsg = string_sprintf("ldap_url_parse: (error %d) parsing \"%s\"\n", rc,
191     ldap_url);
192   goto RETURN_ERROR_BREAK;
193   }
194
195 /* If the host name is empty, take it from the separate argument, if one is
196 given. OpenLDAP 2.0.6 sets an unset hostname to "" rather than empty, but
197 expects NULL later in ldap_init() to mean "default", annoyingly. In OpenLDAP
198 2.0.11 this has changed (it uses NULL). */
199
200 if ((!ludp->lud_host || !ludp->lud_host[0]) && server)
201   {
202   host = server;
203   port = s_port;
204   }
205 else
206   {
207   host = US ludp->lud_host;
208   if (host && !host[0]) host = NULL;
209   port = ludp->lud_port;
210   }
211
212 DEBUG(D_lookup) debug_printf_indent("after ldap_url_parse: host=%s port=%d\n",
213   host, port);
214
215 if (port == 0) port = LDAP_PORT;      /* Default if none given */
216 sprintf(CS porttext, ":%d", port);    /* For messages */
217
218 /* If the "host name" is actually a path, we are going to connect using a Unix
219 socket, regardless of whether "ldapi" was actually specified or not. This means
220 that a Unix socket can be declared in eldap_default_servers, and "traditional"
221 LDAP queries using just "ldap" can be used ("ldaps" is similarly overridden).
222 The path may start with "/" or it may already be escaped as "%2F" if it was
223 actually declared that way in eldap_default_servers. (I did it that way the
224 first time.) If the host name is not a path, the use of "ldapi" causes an
225 error, except in the default case. (But lud_scheme doesn't seem to exist in
226 older libraries.) */
227
228 if (host)
229   {
230   if ((host[0] == '/' || Ustrncmp(host, "%2F", 3) == 0))
231     {
232     ldapi = TRUE;
233     porttext[0] = 0;    /* Remove port from messages */
234     }
235
236 #if defined LDAP_LIB_OPENLDAP2
237   else if (strncmp(ludp->lud_scheme, "ldapi", 5) == 0)
238     {
239     *errmsg = string_sprintf("ldapi requires an absolute path (\"%s\" given)",
240       host);
241     goto RETURN_ERROR;
242     }
243 #endif
244   }
245
246 /* Count the attributes; we need this later to tell us how to format results */
247
248 for (uschar ** attrp = USS ludp->lud_attrs; attrp && *attrp; attrp++)
249   attrs_requested++;
250
251 /* See if we can find a cached connection to this host. The port is not
252 relevant for ldapi. The host name pointer is set to NULL if no host was given
253 (implying the library default), rather than to the empty string. Note that in
254 this case, there is no difference between ldap and ldapi. */
255
256 for (lcp = ldap_connections; lcp; lcp = lcp->next)
257   {
258   if ((host == NULL) != (lcp->host == NULL) ||
259       (host != NULL && strcmpic(lcp->host, host) != 0))
260     continue;
261   if (ldapi || port == lcp->port) break;
262   }
263
264 /* Use this network timeout in any requests. */
265
266 if (tcplimit > 0)
267   {
268   timeout.tv_sec = tcplimit;
269   timeout.tv_usec = 0;
270   timeoutptr = &timeout;
271   }
272
273 /* If no cached connection found, we must open a connection to the server. If
274 the server name is actually an absolute path, we set ldapi=TRUE above. This
275 requests connection via a Unix socket. However, as far as I know, only OpenLDAP
276 supports the use of sockets, and the use of ldap_initialize(). */
277
278 if (!lcp)
279   {
280   LDAP *ld;
281
282 #ifdef LDAP_OPT_X_TLS_NEWCTX
283   int  am_server = 0;
284   LDAP *ldsetctx;
285 #else
286   LDAP *ldsetctx = NULL;
287 #endif
288
289
290   /* --------------------------- OpenLDAP ------------------------ */
291
292   /* There seems to be a preference under OpenLDAP for ldap_initialize()
293   instead of ldap_init(), though I have as yet been unable to find
294   documentation that says this. (OpenLDAP documentation is sparse to
295   non-existent). So we handle OpenLDAP differently here. Also, support for
296   ldapi seems to be OpenLDAP-only at present. */
297
298 #ifdef LDAP_LIB_OPENLDAP2
299
300   /* We now need an empty string for the default host. Get some store in which
301   to build a URL for ldap_initialize(). In the ldapi case, it can't be bigger
302   than (9 + 3*Ustrlen(shost)), whereas in the other cases it can't be bigger
303   than the host name + "ldaps:///" plus : and a port number, say 20 + the
304   length of the host name. What we get should accommodate both, easily. */
305
306   uschar * shost = host ? host : US"";
307   rmark reset_point = store_mark();
308   gstring * g;
309
310   /* Handle connection via Unix socket ("ldapi"). We build a basic LDAP URI to
311   contain the path name, with slashes escaped as %2F. */
312
313   if (ldapi)
314     {
315     g = string_catn(NULL, US"ldapi://", 8);
316     for (uschar ch; (ch = *shost); shost++)
317       g = ch == '/' ? string_catn(g, US"%2F", 3) : string_catn(g, shost, 1);
318     }
319
320   /* This is not an ldapi call. Just build a URI with the protocol type, host
321   name, and port. */
322
323   else
324     {
325     uschar * init_ptr = Ustrchr(ldap_url, '/');
326     g = string_catn(NULL, ldap_url, init_ptr - ldap_url);
327     g = string_fmt_append(g, "//%s:%d/", shost, port);
328     }
329   string_from_gstring(g);
330
331   /* Call ldap_initialize() and check the result */
332
333   DEBUG(D_lookup) debug_printf_indent("ldap_initialize with URL %s\n", g->s);
334   if ((rc = ldap_initialize(&ld, CS g->s)) != LDAP_SUCCESS)
335     {
336     *errmsg = string_sprintf("ldap_initialize: (error %d) URL \"%s\"\n",
337       rc, g->s);
338     goto RETURN_ERROR;
339     }
340   store_reset(reset_point);   /* Might as well save memory when we can */
341
342
343   /* ------------------------- Not OpenLDAP ---------------------- */
344
345   /* For libraries other than OpenLDAP, use ldap_init(). */
346
347 #else   /* LDAP_LIB_OPENLDAP2 */
348   ld = ldap_init(CS host, port);
349 #endif  /* LDAP_LIB_OPENLDAP2 */
350
351   /* -------------------------------------------------------------- */
352
353
354   /* Handle failure to initialize */
355
356   if (!ld)
357     {
358     *errmsg = string_sprintf("failed to initialize for LDAP server %s%s - %s",
359       host, porttext, strerror(errno));
360     goto RETURN_ERROR;
361     }
362
363 #ifdef LDAP_OPT_X_TLS_NEWCTX
364   ldsetctx = ld;
365 #endif
366
367   /* Set the TCP connect time limit if available. This is something that is
368   in Netscape SDK v4.1; I don't know about other libraries. */
369
370 #ifdef LDAP_X_OPT_CONNECT_TIMEOUT
371   if (tcplimit > 0)
372     {
373     int timeout1000 = tcplimit*1000;
374     ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, (void *)&timeout1000);
375     }
376   else
377     {
378     int notimeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
379     ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, (void *)&notimeout);
380     }
381 #endif
382
383   /* Set the TCP connect timeout. This works with OpenLDAP 2.2.14. */
384
385 #ifdef LDAP_OPT_NETWORK_TIMEOUT
386   if (tcplimit > 0)
387     ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, (void *)timeoutptr);
388 #endif
389
390   /* I could not get TLS to work until I set the version to 3. That version
391   seems to be the default nowadays. The RFC is dated 1997, so I would hope
392   that all the LDAP libraries support it. Therefore, if eldap_version hasn't
393   been set, go for v3 if we can. */
394
395   if (eldap_version < 0)
396     {
397 #ifdef LDAP_VERSION3
398     eldap_version = LDAP_VERSION3;
399 #else
400     eldap_version = 2;
401 #endif
402     }
403
404 #ifdef LDAP_OPT_PROTOCOL_VERSION
405   ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void *)&eldap_version);
406 #endif
407
408   DEBUG(D_lookup) debug_printf_indent("initialized for LDAP (v%d) server %s%s\n",
409     eldap_version, host, porttext);
410
411   /* If not using ldapi and TLS is available, set appropriate TLS options: hard
412   for "ldaps" and soft otherwise. */
413
414 #ifdef LDAP_OPT_X_TLS
415   if (!ldapi)
416     {
417     int tls_option;
418 # ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
419     if (eldap_require_cert)
420       {
421       tls_option =
422         Ustrcmp(eldap_require_cert, "hard")     == 0 ? LDAP_OPT_X_TLS_HARD
423         : Ustrcmp(eldap_require_cert, "demand") == 0 ? LDAP_OPT_X_TLS_DEMAND
424         : Ustrcmp(eldap_require_cert, "allow")  == 0 ? LDAP_OPT_X_TLS_ALLOW
425         : Ustrcmp(eldap_require_cert, "try")    == 0 ? LDAP_OPT_X_TLS_TRY
426         : LDAP_OPT_X_TLS_NEVER;
427
428       DEBUG(D_lookup) debug_printf_indent(
429         "Require certificate overrides LDAP_OPT_X_TLS option (%d)\n",
430         tls_option);
431       }
432     else
433 # endif  /* LDAP_OPT_X_TLS_REQUIRE_CERT */
434     if (strncmp(ludp->lud_scheme, "ldaps", 5) == 0)
435       {
436       tls_option = LDAP_OPT_X_TLS_HARD;
437       DEBUG(D_lookup)
438         debug_printf_indent("LDAP_OPT_X_TLS_HARD set due to ldaps:// URI\n");
439       }
440     else
441       {
442       tls_option = LDAP_OPT_X_TLS_TRY;
443       DEBUG(D_lookup)
444         debug_printf_indent("LDAP_OPT_X_TLS_TRY set due to ldap:// URI\n");
445       }
446     ldap_set_option(ld, LDAP_OPT_X_TLS, (void *)&tls_option);
447     }
448 #endif  /* LDAP_OPT_X_TLS */
449
450 #ifdef LDAP_OPT_X_TLS_CACERTFILE
451   if (eldap_ca_cert_file)
452     ldap_set_option(ldsetctx, LDAP_OPT_X_TLS_CACERTFILE, eldap_ca_cert_file);
453 #endif
454 #ifdef LDAP_OPT_X_TLS_CACERTDIR
455   if (eldap_ca_cert_dir)
456     ldap_set_option(ldsetctx, LDAP_OPT_X_TLS_CACERTDIR, eldap_ca_cert_dir);
457 #endif
458 #ifdef LDAP_OPT_X_TLS_CERTFILE
459   if (eldap_cert_file)
460     ldap_set_option(ldsetctx, LDAP_OPT_X_TLS_CERTFILE, eldap_cert_file);
461 #endif
462 #ifdef LDAP_OPT_X_TLS_KEYFILE
463   if (eldap_cert_key)
464     ldap_set_option(ldsetctx, LDAP_OPT_X_TLS_KEYFILE, eldap_cert_key);
465 #endif
466 #ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
467   if (eldap_cipher_suite)
468     ldap_set_option(ldsetctx, LDAP_OPT_X_TLS_CIPHER_SUITE, eldap_cipher_suite);
469 #endif
470 #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
471   if (eldap_require_cert)
472     {
473     int cert_option =
474       Ustrcmp(eldap_require_cert, "hard")     == 0 ? LDAP_OPT_X_TLS_HARD
475       : Ustrcmp(eldap_require_cert, "demand") == 0 ? LDAP_OPT_X_TLS_DEMAND
476       : Ustrcmp(eldap_require_cert, "allow")  == 0 ? LDAP_OPT_X_TLS_ALLOW
477       : Ustrcmp(eldap_require_cert, "try")    == 0 ? LDAP_OPT_X_TLS_TRY
478       : LDAP_OPT_X_TLS_NEVER;
479
480     /* This ldap handle is set at compile time based on client libs. Older
481      * versions want it to be global and newer versions can force a reload
482      * of the TLS context (to reload these settings we are changing from the
483      * default that loaded at instantiation). */
484     rc = ldap_set_option(ldsetctx, LDAP_OPT_X_TLS_REQUIRE_CERT, &cert_option);
485     if (rc)
486       DEBUG(D_lookup)
487         debug_printf_indent("Unable to set TLS require cert_option(%d) globally: %s\n",
488           cert_option, ldap_err2string(rc));
489     }
490 #endif
491 #ifdef LDAP_OPT_X_TLS_NEWCTX
492   if ((rc = ldap_set_option(ldsetctx, LDAP_OPT_X_TLS_NEWCTX, &am_server)))
493     DEBUG(D_lookup)
494       debug_printf_indent("Unable to reload TLS context %d: %s\n",
495                    rc, ldap_err2string(rc));
496   #endif
497
498   /* Now add this connection to the chain of cached connections */
499
500   lcp = store_get(sizeof(LDAP_CONNECTION), GET_UNTAINTED);
501   lcp->host = host ? string_copy(host) : NULL;
502   lcp->bound = FALSE;
503   lcp->user = NULL;
504   lcp->password = NULL;
505   lcp->port = port;
506   lcp->ld = ld;
507   lcp->next = ldap_connections;
508   lcp->is_start_tls_called = FALSE;
509   ldap_connections = lcp;
510   }
511
512 /* Found cached connection */
513
514 else
515   DEBUG(D_lookup)
516     debug_printf_indent("re-using cached connection to LDAP server %s%s\n",
517       host, porttext);
518
519 /* Bind with the user/password supplied, or an anonymous bind if these values
520 are NULL, unless a cached connection is already bound with the same values. */
521
522 if (  !lcp->bound
523    || !lcp->user && user
524    || lcp->user && !user
525    || lcp->user && user && Ustrcmp(lcp->user, user) != 0
526    || !lcp->password && password
527    || lcp->password && !password
528    || lcp->password && password && Ustrcmp(lcp->password, password) != 0
529    )
530   {
531   DEBUG(D_lookup) debug_printf_indent("%sbinding with user=%s password=%s\n",
532     lcp->bound ? "re-" : "", user, password);
533
534   if (eldap_start_tls && !lcp->is_start_tls_called && !ldapi)
535     {
536 #if defined(LDAP_OPT_X_TLS) && !defined(LDAP_LIB_SOLARIS)
537     /* The Oracle LDAP libraries (LDAP_LIB_TYPE=SOLARIS) don't support this.
538      * Note: moreover, they appear to now define LDAP_OPT_X_TLS and still not
539      *       export an ldap_start_tls_s symbol.
540      */
541     if ( (rc = ldap_start_tls_s(lcp->ld, NULL, NULL)) != LDAP_SUCCESS)
542       {
543       *errmsg = string_sprintf("failed to initiate TLS processing on an "
544           "LDAP session to server %s%s - ldap_start_tls_s() returned %d:"
545           " %s", host, porttext, rc, ldap_err2string(rc));
546       goto RETURN_ERROR;
547       }
548     lcp->is_start_tls_called = TRUE;
549 #else
550     DEBUG(D_lookup) debug_printf_indent("TLS initiation not supported with this Exim"
551       " and your LDAP library.\n");
552 #endif
553     }
554   if ((msgid = ldap_bind(lcp->ld, CS user, CS password, LDAP_AUTH_SIMPLE))
555        == -1)
556     {
557     *errmsg = string_sprintf("failed to bind the LDAP connection to server "
558       "%s%s - ldap_bind() returned -1", host, porttext);
559     goto RETURN_ERROR;
560     }
561
562   if ((rc = ldap_result(lcp->ld, msgid, 1, timeoutptr, &result)) <= 0)
563     {
564     *errmsg = string_sprintf("failed to bind the LDAP connection to server "
565       "%s%s - LDAP error: %s", host, porttext,
566       rc == -1 ? "result retrieval failed" : "timeout" );
567     result = NULL;
568     goto RETURN_ERROR;
569     }
570
571   rc = ldap_result2error(lcp->ld, result, 0);
572
573   /* Invalid credentials when just checking credentials returns FAIL. This
574   stops any further servers being tried. */
575
576   if (search_type == SEARCH_LDAP_AUTH && rc == LDAP_INVALID_CREDENTIALS)
577     {
578     DEBUG(D_lookup)
579       debug_printf_indent("Invalid credentials: ldapauth returns FAIL\n");
580     error_yield = FAIL;
581     goto RETURN_ERROR_NOMSG;
582     }
583
584   /* Otherwise we have a problem that doesn't stop further servers from being
585   tried. */
586
587   if (rc != LDAP_SUCCESS)
588     {
589     *errmsg = string_sprintf("failed to bind the LDAP connection to server "
590       "%s%s - LDAP error %d: %s", host, porttext, rc, ldap_err2string(rc));
591     goto RETURN_ERROR;
592     }
593
594   /* Successful bind */
595
596   lcp->bound = TRUE;
597   lcp->user = !user ? NULL : string_copy(user);
598   lcp->password = !password ? NULL : string_copy(password);
599
600   ldap_msgfree(result);
601   result = NULL;
602   }
603
604 /* If we are just checking credentials, return OK. */
605
606 if (search_type == SEARCH_LDAP_AUTH)
607   {
608   DEBUG(D_lookup) debug_printf_indent("Bind succeeded: ldapauth returns OK\n");
609   goto RETURN_OK;
610   }
611
612 /* Before doing the search, set the time and size limits (if given). Here again
613 the different implementations of LDAP have chosen to do things differently. */
614
615 #if defined(LDAP_OPT_SIZELIMIT)
616 ldap_set_option(lcp->ld, LDAP_OPT_SIZELIMIT, (void *)&sizelimit);
617 ldap_set_option(lcp->ld, LDAP_OPT_TIMELIMIT, (void *)&timelimit);
618 #else
619 lcp->ld->ld_sizelimit = sizelimit;
620 lcp->ld->ld_timelimit = timelimit;
621 #endif
622
623 /* Similarly for dereferencing aliases. Don't know if this is possible on
624 an LDAP library without LDAP_OPT_DEREF. */
625
626 #if defined(LDAP_OPT_DEREF)
627 ldap_set_option(lcp->ld, LDAP_OPT_DEREF, (void *)&dereference);
628 #endif
629
630 /* Similarly for the referral setting; should the library follow referrals that
631 the LDAP server returns? The conditional is just in case someone uses a library
632 without it. */
633
634 #if defined(LDAP_OPT_REFERRALS)
635 ldap_set_option(lcp->ld, LDAP_OPT_REFERRALS, referrals);
636 #endif
637
638 /* Start the search on the server. */
639
640 DEBUG(D_lookup) debug_printf_indent("Start search\n");
641
642 msgid = ldap_search(lcp->ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter,
643   ludp->lud_attrs, 0);
644
645 if (msgid == -1)
646   {
647 #if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2
648   int err;
649   ldap_get_option(lcp->ld, LDAP_OPT_ERROR_NUMBER, &err);
650   *errmsg = string_sprintf("ldap_search failed: %d, %s", err,
651     ldap_err2string(err));
652 #else
653   *errmsg = string_sprintf("ldap_search failed");
654 #endif
655
656   goto RETURN_ERROR;
657   }
658
659 /* Loop to pick up results as they come in, setting a timeout if one was
660 given. */
661
662 while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) ==
663         LDAP_RES_SEARCH_ENTRY)
664   {
665   LDAPMessage  *e;
666   int valuecount;   /* We can see an attr spread across several
667                     entries. If B is derived from A and we request
668                     A and the directory contains both, A and B,
669                     then we get two entries, one for A and one for B.
670                     Here we just count the values per entry */
671
672   DEBUG(D_lookup) debug_printf_indent("LDAP result loop\n");
673
674   for(e = ldap_first_entry(lcp->ld, result), valuecount = 0;
675       e;
676       e = ldap_next_entry(lcp->ld, e))
677     {
678     uschar *new_dn;
679     BOOL insert_space = FALSE;
680
681     DEBUG(D_lookup) debug_printf_indent("LDAP entry loop\n");
682
683     rescount++;   /* Count results */
684
685     /* Results for multiple entries values are separated by newlines. */
686
687     if (data) data = string_catn(data, US"\n", 1);
688
689     /* Get the DN from the last result. */
690
691     if ((new_dn = US ldap_get_dn(lcp->ld, e)))
692       {
693       if (dn)
694         {
695 #if defined LDAP_LIB_NETSCAPE || defined LDAP_LIB_OPENLDAP2
696         ldap_memfree(dn);
697 #else   /* OPENLDAP 1, UMich, Solaris */
698         free(dn);
699 #endif
700         }
701       /* Save for later */
702       dn = new_dn;
703       }
704
705     /* If the data we want is actually the DN rather than any attribute values,
706     (an "ldapdn" search) add it to the data string. If there are multiple
707     entries, the DNs will be concatenated, but we test for this case below, as
708     for SEARCH_LDAP_SINGLE, and give an error. */
709
710     if (search_type == SEARCH_LDAP_DN)  /* Do not amalgamate these into one */
711       {                                 /* condition, because of the else */
712       if (new_dn)                       /* below, that's for the first only */
713         {
714         data = string_cat(data, new_dn);
715         (void) string_from_gstring(data);
716         attribute_found = TRUE;
717         }
718       }
719
720     /* Otherwise, loop through the entry, grabbing attribute values. If there's
721     only one attribute being retrieved, no attribute name is given, and the
722     result is not quoted. Multiple values are separated by (comma).
723     If more than one attribute is being retrieved, the data is given as a
724     sequence of name=value pairs, separated by (space), with the value always in quotes.
725     If there are multiple values, they are given within the quotes, comma separated. */
726
727     else for (uschar * attr = US ldap_first_attribute(lcp->ld, e, &ber);
728               attr; attr = US ldap_next_attribute(lcp->ld, e, ber))
729       {
730       DEBUG(D_lookup) debug_printf_indent("LDAP attr loop\n");
731
732       /* In case of attrs_requested == 1 we just count the values, in all other cases
733       (0, >1) we count the values per attribute */
734       if (attrs_requested != 1) valuecount = 0;
735
736       if (attr[0] != 0)
737         {
738         /* Get array of values for this attribute. */
739
740         if ((firstval = values = USS ldap_get_values(lcp->ld, e, CS attr)))
741           {
742           if (attrs_requested != 1)
743             {
744             if (insert_space)
745               data = string_catn(data, US" ", 1);
746             else
747               insert_space = TRUE;
748             data = string_cat(data, attr);
749             data = string_catn(data, US"=\"", 2);
750             }
751
752           while (*values)
753             {
754             uschar *value = *values;
755             int len = Ustrlen(value);
756             ++valuecount;
757
758             DEBUG(D_lookup) debug_printf_indent("LDAP value loop %s:%s\n", attr, value);
759
760             /* In case we requested one attribute only but got several times
761             into that attr loop, we need to append the additional values.
762             (This may happen if you derive attributeTypes B and C from A and
763             then query for A.) In all other cases we detect the different
764             attribute and append only every non first value. */
765
766             if (data && valuecount > 1)
767               data = string_catn(data, US",", 1);
768
769             /* For multiple attributes, the data is in quotes. We must escape
770             internal quotes, backslashes, newlines, and must double commas. */
771
772             if (attrs_requested != 1)
773               for (int j = 0; j < len; j++)
774                 {
775                 if (value[j] == '\n')
776                   data = string_catn(data, US"\\n", 2);
777                 else if (value[j] == ',')
778                   data = string_catn(data, US",,", 2);
779                 else
780                   {
781                   if (value[j] == '\"' || value[j] == '\\')
782                     data = string_catn(data, US"\\", 1);
783                   data = string_catn(data, value+j, 1);
784                   }
785                 }
786
787             /* For single attributes, just double commas */
788
789             else
790               for (int j = 0; j < len; j++)
791                 if (value[j] == ',')
792                   data = string_catn(data, US",,", 2);
793                 else
794                   data = string_catn(data, value+j, 1);
795
796
797             /* Move on to the next value */
798
799             values++;
800             attribute_found = TRUE;
801             }
802
803           /* Closing quote at the end of the data for a named attribute. */
804
805           if (attrs_requested != 1)
806             data = string_catn(data, US"\"", 1);
807
808           /* Free the values */
809
810           ldap_value_free(CSS firstval);
811           }
812         }
813
814 #if defined LDAP_LIB_NETSCAPE || defined LDAP_LIB_OPENLDAP2
815
816       /* Netscape and OpenLDAP2 LDAP's attrs are dynamically allocated and need
817       to be freed. UMich LDAP stores them in static storage and does not require
818       this. */
819
820       ldap_memfree(attr);
821 #endif
822       }        /* End "for" loop for extracting attributes from an entry */
823     }          /* End "for" loop for extracting entries from a result */
824
825   /* Free the result */
826
827   ldap_msgfree(result);
828   result = NULL;
829   }            /* End "while" loop for multiple results */
830
831 /* Terminate the dynamic string that we have built and reclaim unused store.
832 In the odd case of a single attribute with zero-length value, allocate
833 an empty string. */
834
835 if (!data) data = string_get(1);
836 (void) string_from_gstring(data);
837 gstring_release_unused(data);
838
839 /* Copy the last dn into eldap_dn */
840
841 if (dn)
842   {
843   eldap_dn = string_copy(dn);
844 #if defined LDAP_LIB_NETSCAPE || defined LDAP_LIB_OPENLDAP2
845   ldap_memfree(dn);
846 #else   /* OPENLDAP 1, UMich, Solaris */
847   free(dn);
848 #endif
849   }
850
851 DEBUG(D_lookup) debug_printf_indent("search ended by ldap_result yielding %d\n",rc);
852
853 if (rc == 0)
854   {
855   *errmsg = US"ldap_result timed out";
856   goto RETURN_ERROR;
857   }
858
859 /* A return code of -1 seems to mean "ldap_result failed internally or couldn't
860 provide you with a message". Other error states seem to exist where
861 ldap_result() didn't give us any message from the server at all, leaving result
862 set to NULL. Apparently, "the error parameters of the LDAP session handle will
863 be set accordingly". That's the best we can do to retrieve an error status; we
864 can't use functions like ldap_result2error because they parse a message from
865 the server, which we didn't get.
866
867 Annoyingly, the different implementations of LDAP have gone for different
868 methods of handling error codes and generating error messages. */
869
870 if (rc == -1 || !result)
871   {
872   int err;
873   DEBUG(D_lookup) debug_printf_indent("ldap_result failed\n");
874
875 #if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2
876     ldap_get_option(lcp->ld, LDAP_OPT_ERROR_NUMBER, &err);
877     *errmsg = string_sprintf("ldap_result failed: %d, %s",
878       err, ldap_err2string(err));
879
880 #elif defined LDAP_LIB_NETSCAPE
881     /* Dubious (surely 'matched' is spurious here?) */
882     (void)ldap_get_lderrno(lcp->ld, &matched, &error1);
883     *errmsg = string_sprintf("ldap_result failed: %s (%s)", error1, matched);
884
885 #else                             /* UMich LDAP aka OpenLDAP 1.x */
886     *errmsg = string_sprintf("ldap_result failed: %d, %s",
887       lcp->ld->ld_errno, ldap_err2string(lcp->ld->ld_errno));
888 #endif
889
890   goto RETURN_ERROR;
891   }
892
893 /* A return code that isn't -1 doesn't necessarily mean there were no problems
894 with the search. The message must be an LDAP_RES_SEARCH_RESULT or
895 LDAP_RES_SEARCH_REFERENCE or else it's something we can't handle. Some versions
896 of LDAP do not define LDAP_RES_SEARCH_REFERENCE (LDAP v1 is one, it seems). So
897 we don't provide that functionality when we can't. :-) */
898
899 if (rc != LDAP_RES_SEARCH_RESULT
900 #ifdef LDAP_RES_SEARCH_REFERENCE
901     && rc != LDAP_RES_SEARCH_REFERENCE
902 #endif
903    )
904   {
905   *errmsg = string_sprintf("ldap_result returned unexpected code %d", rc);
906   goto RETURN_ERROR;
907   }
908
909 /* We have a result message from the server. This doesn't yet mean all is well.
910 We need to parse the message to find out exactly what's happened. */
911
912 #if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2
913   ldap_rc = rc;
914   ldap_parse_rc = ldap_parse_result(lcp->ld, result, &rc, CSS &matched,
915     CSS &error2, NULL, NULL, 0);
916   DEBUG(D_lookup) debug_printf_indent("ldap_parse_result: %d\n", ldap_parse_rc);
917   if (ldap_parse_rc < 0 &&
918       (ldap_parse_rc != LDAP_NO_RESULTS_RETURNED
919       #ifdef LDAP_RES_SEARCH_REFERENCE
920       || ldap_rc != LDAP_RES_SEARCH_REFERENCE
921       #endif
922      ))
923     {
924     *errmsg = string_sprintf("ldap_parse_result failed %d", ldap_parse_rc);
925     goto RETURN_ERROR;
926     }
927   error1 = US ldap_err2string(rc);
928
929 #elif defined LDAP_LIB_NETSCAPE
930   /* Dubious (it doesn't reference 'result' at all!) */
931   rc = ldap_get_lderrno(lcp->ld, &matched, &error1);
932
933 #else                             /* UMich LDAP aka OpenLDAP 1.x */
934   rc = ldap_result2error(lcp->ld, result, 0);
935   error1 = ldap_err2string(rc);
936   error2 = lcp->ld->ld_error;
937   matched = lcp->ld->ld_matched;
938 #endif
939
940 /* Process the status as follows:
941
942   (1) If we get LDAP_SIZELIMIT_EXCEEDED, just carry on, to return the
943       truncated result list.
944
945   (2) If we get LDAP_RES_SEARCH_REFERENCE, also just carry on. This was a
946       submitted patch that is reported to "do the right thing" with Solaris
947       LDAP libraries. (The problem it addresses apparently does not occur with
948       Open LDAP.)
949
950   (3) The range of errors defined by LDAP_NAME_ERROR generally mean "that
951       object does not, or cannot, exist in the database". For those cases we
952       fail the lookup.
953
954   (4) All other non-successes here are treated as some kind of problem with
955       the lookup, so return DEFER (which is the default in error_yield).
956 */
957
958 DEBUG(D_lookup) debug_printf_indent("ldap_parse_result yielded %d: %s\n",
959   rc, ldap_err2string(rc));
960
961 if (rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
962     #ifdef LDAP_RES_SEARCH_REFERENCE
963     && rc != LDAP_RES_SEARCH_REFERENCE
964     #endif
965     )
966   {
967   *errmsg = string_sprintf("LDAP search failed - error %d: %s%s%s%s%s",
968     rc,
969     error1 ?                  error1  : US"",
970     error2 && error2[0] ?     US"/"   : US"",
971     error2 ?                  error2  : US"",
972     matched && matched[0] ?   US"/"   : US"",
973     matched ?                 matched : US"");
974
975 #if defined LDAP_NAME_ERROR
976   if (LDAP_NAME_ERROR(rc))
977 #elif defined NAME_ERROR    /* OPENLDAP1 calls it this */
978   if (NAME_ERROR(rc))
979 #else
980   if (rc == LDAP_NO_SUCH_OBJECT)
981 #endif
982
983     {
984     DEBUG(D_lookup) debug_printf_indent("lookup failure forced\n");
985     error_yield = FAIL;
986     }
987   goto RETURN_ERROR;
988   }
989
990 /* The search succeeded. Check if we have too many results */
991
992 if (search_type != SEARCH_LDAP_MULTIPLE && rescount > 1)
993   {
994   *errmsg = string_sprintf("LDAP search: more than one entry (%d) was returned "
995     "(filter not specific enough?)", rescount);
996   goto RETURN_ERROR_BREAK;
997   }
998
999 /* Check if we have too few (zero) entries */
1000
1001 if (rescount < 1)
1002   {
1003   *errmsg = US"LDAP search: no results";
1004   error_yield = FAIL;
1005   goto RETURN_ERROR_BREAK;
1006   }
1007
1008 /* If an entry was found, but it had no attributes, we behave as if no entries
1009 were found, that is, the lookup failed. */
1010
1011 if (!attribute_found)
1012   {
1013   *errmsg = US"LDAP search: found no attributes";
1014   error_yield = FAIL;
1015   goto RETURN_ERROR;
1016   }
1017
1018 /* Otherwise, it's all worked */
1019
1020 DEBUG(D_lookup) debug_printf_indent("LDAP search: returning: %s\n", data->s);
1021 *res = data->s;
1022
1023 RETURN_OK:
1024 if (result) ldap_msgfree(result);
1025 ldap_free_urldesc(ludp);
1026 return OK;
1027
1028 /* Error returns */
1029
1030 RETURN_ERROR_BREAK:
1031 *defer_break = TRUE;
1032
1033 RETURN_ERROR:
1034 DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg);
1035
1036 RETURN_ERROR_NOMSG:
1037 if (result) ldap_msgfree(result);
1038 if (ludp) ldap_free_urldesc(ludp);
1039
1040 #if defined LDAP_LIB_OPENLDAP2
1041   if (error2)  ldap_memfree(error2);
1042   if (matched) ldap_memfree(matched);
1043 #endif
1044
1045 return error_yield;
1046 }
1047
1048
1049
1050 /*************************************************
1051 *        Internal search control function        *
1052 *************************************************/
1053
1054 /* This function is called from eldap_find(), eldapauth_find(), eldapdn_find(),
1055 and eldapm_find() with a difference in the "search_type" argument. It controls
1056 calls to perform_ldap_search() which actually does the work. We call that
1057 repeatedly for certain types of defer in the case when the URL contains no host
1058 name and eldap_default_servers is set to a list of servers to try. This gives
1059 more control than just passing over a list of hosts to ldap_open() because it
1060 handles other kinds of defer as well as just a failure to open. Note that the
1061 URL is defined to contain either zero or one "hostport" only.
1062
1063 Parameter data in addition to the URL can be passed as preceding text in the
1064 string, as items of the form XXX=yyy. The URL itself can be detected because it
1065 must begin "ldapx://", where x is empty, s, or i.
1066
1067 Arguments:
1068   ldap_url      the URL to be looked up, optionally preceded by other parameter
1069                 settings
1070   search_type   SEARCH_LDAP_MULTIPLE allows values from multiple entries
1071                 SEARCH_LDAP_SINGLE allows values from one entry only
1072                 SEARCH_LDAP_DN gets the DN from one entry
1073   res           set to point at the result
1074   errmsg        set to point a message if result is not OK
1075
1076 Returns:        OK or FAIL or DEFER
1077 */
1078
1079 static int
1080 control_ldap_search(const uschar *ldap_url, int search_type, uschar **res,
1081   uschar **errmsg)
1082 {
1083 BOOL defer_break = FALSE;
1084 int timelimit = LDAP_NO_LIMIT;
1085 int sizelimit = LDAP_NO_LIMIT;
1086 int tcplimit = 0;
1087 int sep = 0;
1088 int dereference = LDAP_DEREF_NEVER;
1089 void* referrals = LDAP_OPT_ON;
1090 const uschar *url = ldap_url;
1091 const uschar *p;
1092 uschar *user = NULL;
1093 uschar *password = NULL;
1094 uschar *local_servers = NULL;
1095 const uschar *list;
1096
1097 while (isspace(*url)) url++;
1098
1099 /* Until the string begins "ldap", search for the other parameter settings that
1100 are recognized. They are of the form NAME=VALUE, with the value being
1101 optionally double-quoted. There must still be a space after it, however. No
1102 NAME has the value "ldap". */
1103
1104 while (strncmpic(url, US"ldap", 4) != 0)
1105   {
1106   const uschar *name = url;
1107   while (*url && *url != '=') url++;
1108   if (*url == '=')
1109     {
1110     int namelen;
1111     uschar *value;
1112     namelen = ++url - name;
1113     value = string_dequote(&url);
1114     if (isspace(*url))
1115       {
1116       if (strncmpic(name, US"USER=", namelen) == 0) user = value;
1117       else if (strncmpic(name, US"PASS=", namelen) == 0) password = value;
1118       else if (strncmpic(name, US"SIZE=", namelen) == 0) sizelimit = Uatoi(value);
1119       else if (strncmpic(name, US"TIME=", namelen) == 0) timelimit = Uatoi(value);
1120       else if (strncmpic(name, US"CONNECT=", namelen) == 0) tcplimit = Uatoi(value);
1121       else if (strncmpic(name, US"NETTIME=", namelen) == 0) tcplimit = Uatoi(value);
1122       else if (strncmpic(name, US"SERVERS=", namelen) == 0) local_servers = value;
1123
1124       /* Don't know if all LDAP libraries have LDAP_OPT_DEREF */
1125
1126       #ifdef LDAP_OPT_DEREF
1127       else if (strncmpic(name, US"DEREFERENCE=", namelen) == 0)
1128         {
1129         if (strcmpic(value, US"never") == 0) dereference = LDAP_DEREF_NEVER;
1130         else if (strcmpic(value, US"searching") == 0)
1131           dereference = LDAP_DEREF_SEARCHING;
1132         else if (strcmpic(value, US"finding") == 0)
1133           dereference = LDAP_DEREF_FINDING;
1134         if (strcmpic(value, US"always") == 0) dereference = LDAP_DEREF_ALWAYS;
1135         }
1136       #else
1137       else if (strncmpic(name, US"DEREFERENCE=", namelen) == 0)
1138         {
1139         *errmsg = string_sprintf("LDAP_OP_DEREF not defined in this LDAP "
1140           "library - cannot use \"dereference\"");
1141         DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg);
1142         return DEFER;
1143         }
1144       #endif
1145
1146       #ifdef LDAP_OPT_REFERRALS
1147       else if (strncmpic(name, US"REFERRALS=", namelen) == 0)
1148         {
1149         if (strcmpic(value, US"follow") == 0) referrals = LDAP_OPT_ON;
1150         else if (strcmpic(value, US"nofollow") == 0) referrals = LDAP_OPT_OFF;
1151         else
1152           {
1153           *errmsg = US"LDAP option REFERRALS is not \"follow\" or \"nofollow\"";
1154           DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg);
1155           return DEFER;
1156           }
1157         }
1158       #else
1159       else if (strncmpic(name, US"REFERRALS=", namelen) == 0)
1160         {
1161         *errmsg = string_sprintf("LDAP_OP_REFERRALS not defined in this LDAP "
1162           "library - cannot use \"referrals\"");
1163         DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg);
1164         return DEFER;
1165         }
1166       #endif
1167
1168       else
1169         {
1170         *errmsg =
1171           string_sprintf("unknown parameter \"%.*s\" precedes LDAP URL",
1172             namelen, name);
1173         DEBUG(D_lookup) debug_printf_indent("LDAP query error: %s\n", *errmsg);
1174         return DEFER;
1175         }
1176       while (isspace(*url)) url++;
1177       continue;
1178       }
1179     }
1180   *errmsg = US"malformed parameter setting precedes LDAP URL";
1181   DEBUG(D_lookup) debug_printf_indent("LDAP query error: %s\n", *errmsg);
1182   return DEFER;
1183   }
1184
1185 /* If user is set, de-URL-quote it. Some LDAP libraries do this for themselves,
1186 but it seems that not all behave like this. The DN for the user is often the
1187 result of ${quote_ldap_dn:...} quoting, which does apply URL quoting, because
1188 that is needed when the DN is used as a base DN in a query. Sigh. This is all
1189 far too complicated. */
1190
1191 if (user)
1192   {
1193   uschar *t = user;
1194   for (uschar * s = user; *s != 0; s++)
1195     {
1196     int c, d;
1197     if (*s == '%' && isxdigit(c=s[1]) && isxdigit(d=s[2]))
1198       {
1199       c = tolower(c);
1200       d = tolower(d);
1201       *t++ =
1202         (((c >= 'a')? (10 + c - 'a') : c - '0') << 4) |
1203          ((d >= 'a')? (10 + d - 'a') : d - '0');
1204       s += 2;
1205       }
1206     else *t++ = *s;
1207     }
1208   *t = 0;
1209   }
1210
1211 DEBUG(D_lookup)
1212   debug_printf_indent("LDAP parameters: user=%s pass=%s size=%d time=%d connect=%d "
1213     "dereference=%d referrals=%s\n", user, password, sizelimit, timelimit,
1214     tcplimit, dereference, referrals == LDAP_OPT_ON ? "on" : "off");
1215
1216 /* If the request is just to check authentication, some credentials must
1217 be given. The password must not be empty because LDAP binds with an empty
1218 password are considered anonymous, and will succeed on most installations. */
1219
1220 if (search_type == SEARCH_LDAP_AUTH)
1221   {
1222   if (!user || !password)
1223     {
1224     *errmsg = US"ldapauth lookups must specify the username and password";
1225     return DEFER;
1226     }
1227   if (!*password)
1228     {
1229     DEBUG(D_lookup) debug_printf_indent("Empty password: ldapauth returns FAIL\n");
1230     return FAIL;
1231     }
1232   }
1233
1234 /* Check for valid ldap url starters */
1235
1236 p = url + 4;
1237 if (tolower(*p) == 's' || tolower(*p) == 'i') p++;
1238 if (Ustrncmp(p, "://", 3) != 0)
1239   {
1240   *errmsg = string_sprintf("LDAP URL does not start with \"ldap://\", "
1241     "\"ldaps://\", or \"ldapi://\" (it starts with \"%.16s...\")", url);
1242   DEBUG(D_lookup) debug_printf_indent("LDAP query error: %s\n", *errmsg);
1243   return DEFER;
1244   }
1245
1246 /* No default servers, or URL contains a server name: just one attempt */
1247
1248 if (!eldap_default_servers && !local_servers  || p[3] != '/')
1249   return perform_ldap_search(url, NULL, 0, search_type, res, errmsg,
1250     &defer_break, user, password, sizelimit, timelimit, tcplimit, dereference,
1251     referrals);
1252
1253 /* Loop through the servers until OK or FAIL. Use local_servers list
1254 if defined in the lookup, otherwise use the global default list */
1255
1256 list = local_servers ? local_servers : eldap_default_servers;
1257 for (uschar * server; server = string_nextinlist(&list, &sep, NULL, 0); )
1258   {
1259   int rc, port = 0;
1260   uschar *colon = Ustrchr(server, ':');
1261   if (colon)
1262     {
1263     *colon = 0;
1264     port = Uatoi(colon+1);
1265     }
1266   rc = perform_ldap_search(url, server, port, search_type, res, errmsg,
1267     &defer_break, user, password, sizelimit, timelimit, tcplimit, dereference,
1268     referrals);
1269   if (rc != DEFER || defer_break) return rc;
1270   }
1271
1272 return DEFER;
1273 }
1274
1275
1276
1277 /*************************************************
1278 *               Find entry point                 *
1279 *************************************************/
1280
1281 /* See local README for interface description. The different kinds of search
1282 are handled by a common function, with a flag to differentiate between them.
1283 The handle and filename arguments are not used. */
1284
1285 static int
1286 eldap_find(void * handle, const uschar * filename, const uschar * ldap_url,
1287   int length, uschar ** result, uschar ** errmsg, uint * do_cache,
1288   const uschar * opts)
1289 {
1290 return(control_ldap_search(ldap_url, SEARCH_LDAP_SINGLE, result, errmsg));
1291 }
1292
1293 static int
1294 eldapm_find(void * handle, const uschar * filename, const uschar * ldap_url,
1295   int length, uschar ** result, uschar ** errmsg, uint * do_cache,
1296   const uschar * opts)
1297 {
1298 return(control_ldap_search(ldap_url, SEARCH_LDAP_MULTIPLE, result, errmsg));
1299 }
1300
1301 static int
1302 eldapdn_find(void * handle, const uschar * filename, const uschar * ldap_url,
1303   int length, uschar ** result, uschar ** errmsg, uint * do_cache,
1304   const uschar * opts)
1305 {
1306 return(control_ldap_search(ldap_url, SEARCH_LDAP_DN, result, errmsg));
1307 }
1308
1309 int
1310 eldapauth_find(void * handle, const uschar * filename, const uschar * ldap_url,
1311   int length, uschar ** result, uschar ** errmsg, uint * do_cache)
1312 {
1313 return(control_ldap_search(ldap_url, SEARCH_LDAP_AUTH, result, errmsg));
1314 }
1315
1316
1317
1318 /*************************************************
1319 *              Open entry point                  *
1320 *************************************************/
1321
1322 /* See local README for interface description. */
1323
1324 static void *
1325 eldap_open(const uschar * filename, uschar ** errmsg)
1326 {
1327 return (void *)(1);    /* Just return something non-null */
1328 }
1329
1330
1331
1332 /*************************************************
1333 *               Tidy entry point                 *
1334 *************************************************/
1335
1336 /* See local README for interface description.
1337 Make sure that eldap_dn does not refer to reclaimed or worse, freed store */
1338
1339 static void
1340 eldap_tidy(void)
1341 {
1342 eldap_dn = NULL;
1343
1344 for (LDAP_CONNECTION *lcp; lcp = ldap_connections; ldap_connections = lcp->next)
1345   {
1346   DEBUG(D_lookup) debug_printf_indent("unbind LDAP connection to %s:%d\n",
1347     lcp->host, lcp->port);
1348   if(lcp->bound) ldap_unbind(lcp->ld);
1349   }
1350 }
1351
1352
1353
1354 /*************************************************
1355 *               Quote entry point                *
1356 *************************************************/
1357
1358 /* LDAP quoting is unbelievably messy. For a start, two different levels of
1359 quoting have to be done: LDAP quoting, and URL quoting. The current
1360 specification is the result of a suggestion by Brian Candler. It recognizes
1361 two separate cases:
1362
1363 (1) For text that appears in a search filter, the following escapes are
1364     required (see RFC 2254):
1365
1366       *    ->   \2A
1367       (    ->   \28
1368       )    ->   \29
1369       \    ->   \5C
1370      NULL  ->   \00
1371
1372     Then the entire filter text must be URL-escaped. This kind of quoting is
1373     implemented by ${quote_ldap:....}. Note that we can never have a NULL
1374     in the input string, because that's a terminator.
1375
1376 (2) For a DN that is part of a URL (i.e. the base DN), the characters
1377
1378       , + " \ < > ;
1379
1380     must be quoted by backslashing. See RFC 2253. Leading and trailing spaces
1381     must be escaped, as must a leading #. Then the string must be URL-quoted.
1382     This type of quoting is implemented by ${quote_ldap_dn:....}.
1383
1384 For URL quoting, the only characters that need not be quoted are the
1385 alphamerics and
1386
1387   ! $ ' ( ) * + - . _
1388
1389 All the others must be hexified and preceded by %. This includes the
1390 backslashes used for LDAP quoting.
1391
1392 For a DN that is given in the USER parameter for authentication, we need the
1393 same initial quoting as (2) but in this case, the result must NOT be
1394 URL-escaped, because it isn't a URL. The way this is handled is by
1395 de-URL-quoting the text when processing the USER parameter in
1396 control_ldap_search() above. That means that the same quote operator can be
1397 used. This has the additional advantage that spaces in the DN won't cause
1398 parsing problems. For example:
1399
1400   USER=cn=${quote_ldap_dn:$1},%20dc=example,%20dc=com
1401
1402 should be safe if there are spaces in $1.
1403
1404
1405 Arguments:
1406   s          the string to be quoted
1407   opt        additional option text or NULL if none
1408              only "dn" is recognized
1409   idx        lookup type index
1410
1411 Returns:     the processed string or NULL for a bad option
1412 */
1413
1414
1415
1416 /* The characters in this string, together with alphanumerics, never need
1417 quoting in any way. */
1418
1419 #define ALWAYS_LITERAL  "!$'-._"
1420
1421 /* The special characters in this string do not need to be URL-quoted. The set
1422 is a bit larger than the general literals. */
1423
1424 #define URL_NONQUOTE    ALWAYS_LITERAL "()*+"
1425
1426 /* The following macros define the characters that are quoted by quote_ldap and
1427 quote_ldap_dn, respectively. */
1428
1429 #define LDAP_QUOTE      "*()\\"
1430 #define LDAP_DN_QUOTE   ",+\"\\<>;"
1431
1432
1433
1434 static uschar *
1435 eldap_quote(uschar * s, uschar * opt, unsigned idx)
1436 {
1437 int c, count = 0, len = 0;
1438 BOOL dn = FALSE;
1439 uschar * t = s, * quoted;
1440
1441 /* Test for a DN quotation. */
1442
1443 if (opt)
1444   {
1445   if (Ustrcmp(opt, "dn") != 0) return NULL;    /* No others recognized */
1446   dn = TRUE;
1447   }
1448
1449 /* Compute how much extra store we need for the string. This doesn't have to be
1450 exact as long as it isn't an underestimate. The worst case is the addition of 5
1451 extra bytes for a single character. This occurs for certain characters in DNs,
1452 where, for example, < turns into %5C%3C. For simplicity, we just add 5 for each
1453 possibly escaped character. The really fast way would be just to test for
1454 non-alphanumerics, but it is probably better to spot a few others that are
1455 never escaped, because if there are no specials at all, we can avoid copying
1456 the string.
1457 XXX No longer true; we always copy, to support quoted-enforcement */
1458
1459 while ((c = *t++))
1460   {
1461   len++;
1462   if (!isalnum(c) && Ustrchr(ALWAYS_LITERAL, c) == NULL) count += 5;
1463   }
1464 /*if (count == 0) return s;*/
1465
1466 /* Get sufficient store to hold the quoted string */
1467
1468 t = quoted = store_get_quoted(len + count + 1, s, idx);
1469
1470 /* Handle plain quote_ldap */
1471
1472 if (!dn)
1473   {
1474   while ((c = *s++))
1475     {
1476     if (!isalnum(c))
1477       {
1478       if (Ustrchr(LDAP_QUOTE, c) != NULL)
1479         {
1480         sprintf(CS t, "%%5C%02X", c);        /* e.g. * => %5C2A */
1481         t += 5;
1482         continue;
1483         }
1484       if (Ustrchr(URL_NONQUOTE, c) == NULL)  /* e.g. ] => %5D */
1485         {
1486         sprintf(CS t, "%%%02X", c);
1487         t += 3;
1488         continue;
1489         }
1490       }
1491     *t++ = c;                                /* unquoted character */
1492     }
1493   }
1494
1495 /* Handle quote_ldap_dn */
1496
1497 else
1498   {
1499   uschar * ss = s + len;
1500
1501   /* Find the last char before any trailing spaces */
1502
1503   while (ss > s && ss[-1] == ' ') ss--;
1504
1505   /* Quote leading spaces and sharps */
1506
1507   for (; s < ss; s++)
1508     {
1509     if (*s != ' ' && *s != '#') break;
1510     sprintf(CS t, "%%5C%%%02X", *s);
1511     t += 6;
1512     }
1513
1514   /* Handle the rest of the string, up to the trailing spaces */
1515
1516   while (s < ss)
1517     {
1518     c = *s++;
1519     if (!isalnum(c))
1520       {
1521       if (Ustrchr(LDAP_DN_QUOTE, c) != NULL)
1522         {
1523         Ustrncpy(t, US"%5C", 3);               /* insert \ where needed */
1524         t += 3;                              /* fall through to check URL */
1525         }
1526       if (Ustrchr(URL_NONQUOTE, c) == NULL)  /* e.g. ] => %5D */
1527         {
1528         sprintf(CS t, "%%%02X", c);
1529         t += 3;
1530         continue;
1531         }
1532       }
1533     *t++ = c;    /* unquoted character, or non-URL quoted after %5C */
1534     }
1535
1536   /* Handle the trailing spaces */
1537
1538   while (*ss++ != 0)
1539     {
1540     Ustrncpy(t, US"%5C%20", 6);
1541     t += 6;
1542     }
1543   }
1544
1545 /* Terminate the new string and return */
1546
1547 *t = 0;
1548 return quoted;
1549 }
1550
1551
1552
1553 /*************************************************
1554 *         Version reporting entry point          *
1555 *************************************************/
1556
1557 /* See local README for interface description. */
1558
1559 #include "../version.h"
1560
1561 gstring *
1562 ldap_version_report(gstring * g)
1563 {
1564 #ifdef DYNLOOKUP
1565 g = string_fmt_append(g, "Library version: LDAP: Exim version %s\n", EXIM_VERSION_STR);
1566 #endif
1567 return g;
1568 }
1569
1570
1571 static lookup_info ldap_lookup_info = {
1572   .name = US"ldap",                     /* lookup name */
1573   .type = lookup_querystyle,            /* query-style lookup */
1574   .open = eldap_open,                   /* open function */
1575   .check = NULL,                        /* check function */
1576   .find = eldap_find,                   /* find function */
1577   .close = NULL,                        /* no close function */
1578   .tidy = eldap_tidy,                   /* tidy function */
1579   .quote = eldap_quote,                 /* quoting function */
1580   .version_report = ldap_version_report            /* version reporting */
1581 };
1582
1583 static lookup_info ldapdn_lookup_info = {
1584   .name = US"ldapdn",                   /* lookup name */
1585   .type = lookup_querystyle,            /* query-style lookup */
1586   .open = eldap_open,                   /* sic */    /* open function */
1587   .check = NULL,                        /* check function */
1588   .find = eldapdn_find,                 /* find function */
1589   .close = NULL,                        /* no close function */
1590   .tidy = eldap_tidy,                   /* sic */    /* tidy function */
1591   .quote = eldap_quote,                 /* sic */    /* quoting function */
1592   .version_report = NULL                           /* no version reporting (redundant) */
1593 };
1594
1595 static lookup_info ldapm_lookup_info = {
1596   .name = US"ldapm",                    /* lookup name */
1597   .type = lookup_querystyle,            /* query-style lookup */
1598   .open = eldap_open,                   /* sic */    /* open function */
1599   .check = NULL,                        /* check function */
1600   .find = eldapm_find,                  /* find function */
1601   .close = NULL,                        /* no close function */
1602   .tidy = eldap_tidy,                   /* sic */    /* tidy function */
1603   .quote = eldap_quote,                 /* sic */    /* quoting function */
1604   .version_report = NULL                           /* no version reporting (redundant) */
1605 };
1606
1607 #ifdef DYNLOOKUP
1608 #define ldap_lookup_module_info _lookup_module_info
1609 #endif
1610
1611 static lookup_info *_lookup_list[] = { &ldap_lookup_info, &ldapdn_lookup_info, &ldapm_lookup_info };
1612 lookup_module_info ldap_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 3 };
1613
1614 /* End of lookups/ldap.c */