Alex Miller's patch for LDAP_RES_SEARCH_REFERENCE.
[exim.git] / src / src / lookups / ldap.c
index c4777bc87b363f4d7bf2938425b6738b9a0d3f9c..043135e039127e687d8de8ce38a43ddf20248b3c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/lookups/ldap.c,v 1.2 2004/11/10 14:15:20 ph10 Exp $ */
+/* $Cambridge: exim/src/src/lookups/ldap.c,v 1.5 2004/12/21 12:00:59 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -129,7 +129,7 @@ Arguments:
   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
   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
-  tcplimit      max time to connect, or 0 for OS default
+  tcplimit      max time for network activity, e.g. connect, or 0 for OS default
   deference     the dereference option, which is one of
                   LDAP_DEREF_{NEVER,SEARCHING,FINDING,ALWAYS}
 
   deference     the dereference option, which is one of
                   LDAP_DEREF_{NEVER,SEARCHING,FINDING,ALWAYS}
 
@@ -167,7 +167,7 @@ uschar *matched = NULL;  /* partially matched DN */
 int    attr_count = 0;
 int    error_yield = DEFER;
 int    msgid;
 int    attr_count = 0;
 int    error_yield = DEFER;
 int    msgid;
-int    rc;
+int    rc, ldap_rc, ldap_parse_rc;
 int    port;
 int    ptr = 0;
 int    rescount = 0;
 int    port;
 int    ptr = 0;
 int    rescount = 0;
@@ -271,6 +271,15 @@ for (lcp = ldap_connections; lcp != NULL; lcp = lcp->next)
   if (ldapi || port == lcp->port) break;
   }
 
   if (ldapi || port == lcp->port) break;
   }
 
+/* Use this network timeout in any requests. */
+
+if (tcplimit > 0)
+  {
+  timeout.tv_sec = tcplimit;
+  timeout.tv_usec = 0;
+  timeoutptr = &timeout;
+  }
+
 /* If no cached connection found, we must open a connection to the server. If
 the server name is actually an absolute path, we set ldapi=TRUE above. This
 requests connection via a Unix socket. However, as far as I know, only OpenLDAP
 /* If no cached connection found, we must open a connection to the server. If
 the server name is actually an absolute path, we set ldapi=TRUE above. This
 requests connection via a Unix socket. However, as far as I know, only OpenLDAP
@@ -371,9 +380,14 @@ if (lcp == NULL)
   #ifdef LDAP_X_OPT_CONNECT_TIMEOUT
   if (tcplimit > 0)
     {
   #ifdef LDAP_X_OPT_CONNECT_TIMEOUT
   if (tcplimit > 0)
     {
-    unsigned int timeout1000 = tcplimit*1000;
+    int timeout1000 = tcplimit*1000;
     ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, (void *)&timeout1000);
     }
     ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, (void *)&timeout1000);
     }
+  else
+    {
+    int notimeout = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
+    ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, (void *)&notimeout);
+    }
   #endif
 
   /* Set the TCP connect timeout. This works with OpenLDAP 2.2.14. */
   #endif
 
   /* Set the TCP connect timeout. This works with OpenLDAP 2.2.14. */
@@ -447,15 +461,6 @@ else
       host, porttext);
   }
 
       host, porttext);
   }
 
-/* Whatever follows, obey this timeout in any requests. */
-
-if (tcplimit > 0)
-  {
-  timeout.tv_sec = tcplimit;
-  timeout.tv_usec = 0;
-  timeoutptr = &timeout;
-  }
-
 /* 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. */
 
 /* 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. */
 
@@ -474,7 +479,7 @@ if (!lcp->bound ||
        == -1)
     {
     *errmsg = string_sprintf("failed to bind the LDAP connection to server "
        == -1)
     {
     *errmsg = string_sprintf("failed to bind the LDAP connection to server "
-      "%s%s - LDAP error", host, porttext);
+      "%s%s - ldap_bind() returned -1", host, porttext);
     goto RETURN_ERROR;
     }
 
     goto RETURN_ERROR;
     }
 
@@ -774,10 +779,10 @@ if (rc == -1 || result == NULL)
   }
 
 /* A return code that isn't -1 doesn't necessarily mean there were no problems
   }
 
 /* A return code that isn't -1 doesn't necessarily mean there were no problems
-with the search. The message must be an LDAP_RES_SEARCH_RESULT or else it's
-something we can't handle. */
+with the search. The message must be an LDAP_RES_SEARCH_RESULT or 
+LDAP_RES_SEARCH_REFERENCE or else it's something we can't handle. */
 
 
-if (rc != LDAP_RES_SEARCH_RESULT)
+if (rc != LDAP_RES_SEARCH_RESULT && rc != LDAP_RES_SEARCH_REFERENCE)
   {
   *errmsg = string_sprintf("ldap_result returned unexpected code %d", rc);
   goto RETURN_ERROR;
   {
   *errmsg = string_sprintf("ldap_result returned unexpected code %d", rc);
   goto RETURN_ERROR;
@@ -786,11 +791,16 @@ if (rc != LDAP_RES_SEARCH_RESULT)
 /* We have a result message from the server. This doesn't yet mean all is well.
 We need to parse the message to find out exactly what's happened. */
 
 /* We have a result message from the server. This doesn't yet mean all is well.
 We need to parse the message to find out exactly what's happened. */
 
-  #if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2
-  if (ldap_parse_result(lcp->ld, result, &rc, CSS &matched, CSS &error2, NULL,
-      NULL, 0) < 0)
+#if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2
+  ldap_rc = rc;
+  ldap_parse_rc = ldap_parse_result(lcp->ld, result, &rc, CSS &matched, 
+    CSS &error2, NULL, NULL, 0);
+  DEBUG(D_lookup) debug_printf("ldap_parse_result: %d\n", ldap_parse_rc);
+  if (ldap_parse_rc < 0 && 
+      (ldap_parse_rc != LDAP_NO_RESULTS_RETURNED ||
+       ldap_rc != LDAP_RES_SEARCH_REFERENCE))
     {
     {
-    *errmsg = US"ldap_parse_result failed";
+    *errmsg = string_sprintf("ldap_parse_result failed %d", ldap_parse_rc);
     goto RETURN_ERROR;
     }
   error1 = US ldap_err2string(rc);
     goto RETURN_ERROR;
     }
   error1 = US ldap_err2string(rc);