[Exim] ldap lookups with starttls

Top Page
Delete this message
Reply to this message
Author: cboye
Date:  
To: exim-users
Subject: [Exim] ldap lookups with starttls
--
Hello.
The following patch against src/lookups/ldap.c makes it possible to use
ldap connections over ssl (with startssl or direct ssl connection with
ldaps://). For this you must have openldap-2 or greater.

Christian Boye



--
--- ldap.c.orig    Wed Dec 19 12:50:29 2001
+++ ldap.c    Sat Jan  5 19:21:39 2002
@@ -13,6 +13,9 @@
 #include "../exim.h"
 #include "ldap.h"


+#if LDAP_VENDOR_VERSION > 20000
+#define OPENLDAP2
+#endif

 /* We can't just compile this code and allow the library mechanism to omit the
 functions if they are not wanted, because we need to have the LDAP headers
@@ -117,6 +120,7 @@
   password      password for authentication, or NULL
   sizelimit     max number of entries returned, or 0 for no limit
   timelimit     max time to wait, or 0 for no limit
+  starttls      use starttls mechanism for ldap connection


 Returns:        OK or FAIL or DEFER
                 FAIL is given only if a lookup was performed successfully, but
@@ -126,7 +130,7 @@
 static int
 perform_ldap_search(char *ldap_url, char *server, int s_port, int search_type,
   char **res, char **errmsg, BOOL *defer_break, char *user, char *password,
-  int sizelimit, int timelimit)
+  int sizelimit, int timelimit, int starttls)
 {
 LDAPURLDesc  *ludp = NULL;
 LDAPMessage  *result;
@@ -155,10 +159,10 @@


 DEBUG(9)
   debug_printf("perform_ldap_search: ldap%s URL =\"%s\" server=%s port=%d "
-    "sizelimit=%d timelimit=%d\n",
+    "sizelimit=%d timelimit=%d starttls=%d\n",
     (search_type == SEARCH_LDAP_MULTIPLE)? "m" :
     (search_type == SEARCH_LDAP_DN)? "dn" : "",
-    ldap_url, server, s_port, sizelimit, timelimit);
+    ldap_url, server, s_port, sizelimit, timelimit, starttls);


/* Check if LDAP thinks the URL is a valid LDAP URL */

@@ -220,7 +224,8 @@

 if (lcp == NULL)
   {
-  LDAP *ld = ldap_open(host, (port != 0)? port : LDAP_PORT);
+  int version;
+  LDAP *ld = ldap_init(host, (port != 0)? port : LDAP_PORT);
   if (ld == NULL)
     {
     *errmsg = string_sprintf("failed to open connection to LDAP server %s:%d "
@@ -230,6 +235,34 @@


DEBUG(9) debug_printf("Opened connection to LDAP server %s:%d\n", host, port);

+#ifdef OPENLDAP2
+  if ((strncasecmp(ldap_url, "ldaps://", 8) == 0) || (starttls != 0))
+    {
+    DEBUG(9) debug_printf("Get ldap protocol version");
+    if ((rc = ldap_get_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version))
+      != LDAP_SUCCESS)
+      {
+      *errmsg = string_sprintf("Cannot get ldap option - LDAP error %s: %s",
+        rc, ldap_err2string(rc));
+      goto RETURN_ERROR;
+      }
+    DEBUG(9) debug_printf("Setting ldap protocol to version 3");
+    if (version < LDAP_VERSION3)
+      {
+      version = LDAP_VERSION3;
+      ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+      }
+    DEBUG(9) debug_printf("Try to start TLS connection");
+    if ((rc = ldap_start_tls_s(ld, NULL, NULL))
+      != LDAP_SUCCESS)
+      {
+      *errnsg = string_sprintf("Cannot start TLS connection - LDAP error %s: %s",
+        rc, ldap_err2string(rc));
+      goto RETURN_ERROR;
+      }
+    }
+#endif
+
   lcp = store_malloc(sizeof(LDAP_CONNECTION));
   lcp->host = (host == NULL)? NULL : string_copy_malloc(host);
   lcp->bound = FALSE;
@@ -260,7 +293,7 @@
       strcmp(lcp->password, password) != 0))
   {
   DEBUG(9) debug_printf("Binding with user=%s password=%s\n", user, password);
-  if ((rc = ldap_bind_s(lcp->ld, user, password, LDAP_AUTH_SIMPLE))
+  if ((rc = ldap_simple_bind_s(lcp->ld, user, password))
        != LDAP_SUCCESS)
     {
     *errmsg = string_sprintf("failed to bind the LDAP connection to server "
@@ -549,7 +582,7 @@


Parameter data in addition to the URL can be passed as preceding text in the
string, as items of the form XXX=yyy. The URL itself can be detected because it
-must begin "ldap:///".
+must begin "ldap://" or "ldaps://".

 Arguments:
   ldap_url      the URL to be looked up, optionally preceded by other parameter
@@ -569,6 +602,7 @@
 BOOL defer_break = FALSE;
 int timelimit = LDAP_NO_LIMIT;
 int sizelimit = LDAP_NO_LIMIT;
+int starttls = 0;
 int sep = 0;
 char *url = ldap_url;
 char *user = NULL;
@@ -576,11 +610,12 @@
 char *server, *list;
 char buffer[512];


-/* Until the string begins "ldap://", search for the other parameter settings
-that are recognized. They are of the form NAME=VALUE, with the value being
-optionally double-quoted. There must still be a space after it, however. */
+/* Until the string begins "ldap://" or "ldaps://", search for the other
+parameter settings that are recognized. They are of the form NAME=VALUE,
+with the value being optionally double-quoted. There must still be a space
+after it, however. */

-while (strncmp(url, "ldap://", 7) != 0)
+while ((strncmp(url, "ldap://", 7) != 0) && (strncmp(url, "ldaps://", 8) != 0))
   {
   char *name = url;
   while (*url != 0 && *url != '=') url++;
@@ -594,6 +629,7 @@
       else if (strncmpic(name, "PASS=", namelen) == 0) password = value;
       else if (strncmpic(name, "SIZE=", namelen) == 0) sizelimit = atoi(value);
       else if (strncmpic(name, "TIME=", namelen) == 0) timelimit = atoi(value);
+      else if (strncmpic(name, "TLS=" , namelen) == 0) starttls  = atoi(value);
       else
         {
         *errmsg =
@@ -609,15 +645,15 @@
   return DEFER;
   }


-DEBUG(9) debug_printf("LDAP parameters: user=%s pass=%s size=%d time=%d\n",
- user, password, sizelimit, timelimit);
+DEBUG(9) debug_printf("LDAP parameters: user=%s pass=%s size=%d time=%d tls=%d\n",
+ user, password, sizelimit, timelimit, starttls);

/* No default servers, or URL contains a server name */

-if (ldap_default_servers == NULL || strncmpic(url, "ldap:///", 8) != 0)
+if (ldap_default_servers == NULL || ((strncmpic(url, "ldap:///", 8) != 0) && (strncmpic(url, "ldaps:///", 9) != 0)))
   {
   return perform_ldap_search(url, NULL, 0, search_type, res, errmsg,
-    &defer_break, user, password, sizelimit, timelimit);
+    &defer_break, user, password, sizelimit, timelimit, starttls);
   }


/* Loop through the default servers until OK or FAIL */
--