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