Re: [Exim] Exim 3.16 with latest Openldap?

Top Page
Delete this message
Reply to this message
Author: michael
Date:  
To: ph10
CC: exim-users
Subject: Re: [Exim] Exim 3.16 with latest Openldap?
> > All in all, there is work to be done. I can post a patch, but I can not
> > recommend Philip to apply it without someone with access to the latest
> > OpenLDAP reviewing and testing it. Anybody?
>
> Send me the patch. I'll dig around for the latest OpenLDAP and do some
> experiments. Maybe not immediately, but in due course.


Ok, here it is. It changes the following things:

o Do not auto-detect the library API, because it won't work with OpenLDAP 2.x,
which requires to select the Solaris API.
o Only pick up messages with the ID of the started query, but pick up all
of them. Do so asynchronously and process results as they come in.
Count the number of results and do error checking after the last result
(if any) has been processed and taken off the wire.
o Do not use ldap_url_search, but parse the URL and then use ldap_search.
o Add a few debugging messages to indicate where things break, if they do.

I would appreciate a general review of the code, fixing the indentation :) and
verifying that multiple results and no results are really processed correctly
in all situations.

You can get the latest OpenLDAP release from CVS by:

CVSROOT=:pserver:anonymous@???:/repo/OpenLDAP
cvs login # Password is OpenLDAP
cvs checkout -r OPENLDAP_REL_ENG_2 ldap
cvs logout

Note: This is not a stable release, it's the latest code. It is not
recommended to use it in production, although it works much better than
the last stable release for me, but that's probably me.

Michael
----------------------------------------------------------------------
--- ldap.c.orig    Mon Aug  7 22:44:16 2000
+++ ldap.c    Tue Aug  8 09:26:34 2000
@@ -32,19 +32,6 @@
 #include <ldap.h>



-/* Annoyingly, the different LDAP libraries handle errors in different ways.
-There doesn't seem to be an automatic way of distinguishing between them. Check
-if the user set LDAP_LIB_TYPE (which causes a specific macro to be set), and if
-not set, use the original heuristic that distinguishes UMich LDAP from the rest
-and guess Netscape if not UMich. */
-
-#ifndef LDAP_LIB_DEFINED
-  #ifdef LDAP_OPT_SIZELIMIT        /* UMich does not have this */
-  #define LDAP_NETSCAPE
-  #endif
-#endif
-
-
 /* Structure and anchor for caching connections. */


typedef struct ldap_connection {
@@ -106,10 +93,12 @@
char **values;
char **firstval;
int attr_count = 0;
+int msgid;
int rc;
int port;
int ptr = 0;
int size = 0;
+int rescount = 0;
BOOL add_newline = FALSE;
BOOL attribute_found = FALSE;

@@ -143,7 +132,7 @@
/* If the host name is empty, take it from the separate argument, if
one is given. */

-if (ludp->lud_host == NULL && server != NULL)
+if ((ludp->lud_host == NULL || ludp->lud_host[0]=='\0') && server != NULL)
   {
   host = server;
   port = s_port;
@@ -209,10 +198,6 @@
     host, port);
   }


-/* Finished with the broken-down URL */
-
-ldap_free_urldesc(ludp);
-
/* Bind with the user/password supplied, or an anonymous bind if these values
are NULL, unless a cached connection is already bound with the same values. */

@@ -243,7 +228,7 @@
/* Before doing the search, set the time and size limits (if given). Here again
the different implementations of LDAP have chosen to do things differently. */

-#if defined LDAP_LIB_NETSCAPE
+#if defined(LDAP_OPT_SIZELIMIT)
if (sizelimit > 0)
ldap_set_option(lcp->ld, LDAP_OPT_SIZELIMIT, (void *)&sizelimit);
if (timelimit > 0)
@@ -257,59 +242,20 @@
succeeds, wait for results - this will time out if no results are available
in a reasonable time. */

-if (ldap_url_search(lcp->ld, ldap_url, 0) == -1 ||
-    (rc = ldap_result(lcp->ld, LDAP_RES_ANY, 1, NULL, &result)) == -1)
-  {
-  char *matched, *error;
-
-  /* Annoyingly, the different implementations of LDAP have gone for different
-  methods of handling error codes and generating error messages. */
-
-  #if defined LDAP_LIB_SOLARIS7     /* Solaris 7 LDAP */
-    *errmsg = string_sprintf("ldap search failed: %s",
-      ldap_err2string(ldap_result2error(lcp->ld, result, 0)));
-  #elif defined LDAP_LIB_NETSCAPE   /* Netscape SDK */
-    (void)ldap_get_lderrno(lcp->ld, &matched, &error);
-    *errmsg = string_sprintf("ldap search failed: %s (%s)", error, matched);
-  #else                             /* UMich LDAP */
-    matched = lcp->ld->ld_matched;
-    error = lcp->ld->ld_error;
-    *errmsg = string_sprintf("ldap search failed: %s (%s)", error, matched);
-  #endif
-
-  DEBUG(9) debug_printf("%s\n", *errmsg);
-  *defer_break = TRUE;
-  return DEFER;
-  }
-
-if (rc == 0)
-  {
-  *errmsg = string_sprintf("LDAP search timed out");
-  DEBUG(9) debug_printf("%s\n", *errmsg);
-  *defer_break = FALSE;
-  return DEFER;
-  }
-
-/* Check if we have too many entries */
+    DEBUG(9) debug_printf("Start search\n");


-rc = ldap_count_entries(lcp->ld, result);
-if (single && rc > 1)
+if ((msgid = ldap_search(lcp->ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter, ludp->lud_attrs, 0)) == -1)
   {
-  *errmsg = string_sprintf("LDAP search: too many (%d) results "
-    "(filter not specific enough)", rc);
-  DEBUG(9) debug_printf("%s\n", *errmsg);
-  *defer_break = TRUE;
-  return DEFER;
+    *errmsg = string_sprintf("ldap search initiation failed");
+    DEBUG(9) debug_printf("%s\n", *errmsg);
+    *defer_break = TRUE;
+    ldap_free_urldesc(ludp);
+    return DEFER;
   }


-/* Check if we have too few (zero) entries */
+/* Finished with the broken-down URL */

-if (rc < 1)
- {
- *errmsg = string_sprintf("LDAP search: no results");
- DEBUG(9) debug_printf("%s\n", *errmsg);
- return FAIL;
- }
+ldap_free_urldesc(ludp);

/* Initialize chunk of store in which to return the answer. */

@@ -317,17 +263,23 @@
ptr = 0;
data = store_get(size);

+while ((rc = ldap_result(lcp->ld, msgid, 0, NULL, &result))==LDAP_RES_SEARCH_ENTRY)
+{
+DEBUG(9) debug_printf("search gave %d\n",rc);
+
/* Loop through returned entries; we have already checked above for zero
entries. */

 for(e = ldap_first_entry(lcp->ld, result);
-    e != NULLMSG;
+    e != (LDAPMessage*)0;
     e = ldap_next_entry(lcp->ld, e))
   {
   BOOL add_comma = FALSE;


DEBUG(9) debug_printf("LDAP entry loop\n");

+ ++rescount;
+
/* Results for multiple entries values are separated by newlines. */

   if (add_newline)
@@ -342,6 +294,7 @@
        attr != NULL;
        attr = ldap_next_attribute(lcp->ld, e, ber))
     {
+
     if (attr[0])
       {
       /* Get array of values for this attribute. */
@@ -388,6 +341,53 @@


   if (ber != NULL) ber_free(ber, 0);
 #endif
+  }
+  ldap_msgfree(result);
+}
+
+
+if (rc == -1)
+  {
+  char *matched, *error;
+
+  /* Annoyingly, the different implementations of LDAP have gone for different
+  methods of handling error codes and generating error messages. */
+
+DEBUG(9) debug_printf("search failed\n");
+
+  #if defined LDAP_LIB_SOLARIS7     /* Solaris 7 LDAP */
+    *errmsg = string_sprintf("ldap search failed: %s",
+      ldap_err2string(ldap_result2error(lcp->ld, result, 0)));
+  #elif defined LDAP_LIB_NETSCAPE   /* Netscape SDK */
+    (void)ldap_get_lderrno(lcp->ld, &matched, &error);
+    *errmsg = string_sprintf("ldap search failed: %s (%s)", error, matched);
+  #else                             /* UMich LDAP */
+    matched = lcp->ld->ld_matched;
+    error = lcp->ld->ld_error;
+    *errmsg = string_sprintf("ldap search failed: %s (%s)", error, matched);
+  #endif
+
+  DEBUG(9) debug_printf("%s\n", *errmsg);
+  *defer_break = TRUE;
+  return DEFER;
+  }
+
+if (single && rescount > 1)
+  {
+  *errmsg = string_sprintf("LDAP search: too many (%d) results "
+    "(filter not specific enough)", rescount);
+  DEBUG(9) debug_printf("%s\n", *errmsg);
+  *defer_break = TRUE;
+  return DEFER;
+  }
+
+/* Check if we have too few (zero) entries */
+
+if (rescount < 1)
+  {
+  *errmsg = string_sprintf("LDAP search: no results");
+  DEBUG(9) debug_printf("%s\n", *errmsg);
+  return FAIL;
   }


/* If an entry was found, but it had no attributes, we behave as if no entries