]> git.netwichtig.de Git - user/henk/code/exim.git/blobdiff - src/src/lookups/ldap.c
Update all copyright messages to cover 1995 - 2009. Remove tab from exim_checkaccess.src
[user/henk/code/exim.git] / src / src / lookups / ldap.c
index 313640e9ec57a2d0486b4eb15b5111343f05a779..936fe36ea95d908533bc9be1450ed80cdc0c9610 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/lookups/ldap.c,v 1.10 2006/02/07 11:19:01 ph10 Exp $ */
+/* $Cambridge: exim/src/src/lookups/ldap.c,v 1.15 2009/11/16 19:50:38 nm4 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2006 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Many thanks to Stuart Lynne for contributing the original code for this
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Many thanks to Stuart Lynne for contributing the original code for this
@@ -31,7 +31,12 @@ static void dummy(int x) { dummy(x-1); }
 #else
 
 
 #else
 
 
-/* Include LDAP headers */
+/* Include LDAP headers. The code below uses some "old" LDAP interfaces that
+are deprecated in OpenLDAP. I don't know their status in other LDAP
+implementations. LDAP_DEPRECATED causes their prototypes to be defined in
+ldap.h. */
+
+#define LDAP_DEPRECATED 1
 
 #include <lber.h>
 #include <ldap.h>
 
 #include <lber.h>
 #include <ldap.h>
@@ -132,6 +137,7 @@ Arguments:
   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}
   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}
+  referrals     the referral option, which is LDAP_OPT_ON or LDAP_OPT_OFF
 
 Returns:        OK or FAIL or DEFER
                 FAIL is given only if a lookup was performed successfully, but
 
 Returns:        OK or FAIL or DEFER
                 FAIL is given only if a lookup was performed successfully, but
@@ -141,7 +147,7 @@ Returns:        OK or FAIL or DEFER
 static int
 perform_ldap_search(uschar *ldap_url, uschar *server, int s_port, int search_type,
   uschar **res, uschar **errmsg, BOOL *defer_break, uschar *user, uschar *password,
 static int
 perform_ldap_search(uschar *ldap_url, uschar *server, int s_port, int search_type,
   uschar **res, uschar **errmsg, BOOL *defer_break, uschar *user, uschar *password,
-  int sizelimit, int timelimit, int tcplimit, int dereference)
+  int sizelimit, int timelimit, int tcplimit, int dereference, void *referrals)
 {
 LDAPURLDesc     *ludp = NULL;
 LDAPMessage     *result = NULL;
 {
 LDAPURLDesc     *ludp = NULL;
 LDAPMessage     *result = NULL;
@@ -551,6 +557,14 @@ an LDAP library without LDAP_OPT_DEREF. */
 ldap_set_option(lcp->ld, LDAP_OPT_DEREF, (void *)&dereference);
 #endif
 
 ldap_set_option(lcp->ld, LDAP_OPT_DEREF, (void *)&dereference);
 #endif
 
+/* Similarly for the referral setting; should the library follow referrals that
+the LDAP server returns? The conditional is just in case someone uses a library
+without it. */
+
+#if defined(LDAP_OPT_REFERRALS)
+ldap_set_option(lcp->ld, LDAP_OPT_REFERRALS, referrals);
+#endif
+
 /* Start the search on the server. */
 
 DEBUG(D_lookup) debug_printf("Start search\n");
 /* Start the search on the server. */
 
 DEBUG(D_lookup) debug_printf("Start search\n");
@@ -839,18 +853,27 @@ We need to parse the message to find out exactly what's happened. */
   (1) If we get LDAP_SIZELIMIT_EXCEEDED, just carry on, to return the
       truncated result list.
 
   (1) If we get LDAP_SIZELIMIT_EXCEEDED, just carry on, to return the
       truncated result list.
 
-  (2) The range of errors defined by LDAP_NAME_ERROR generally mean "that
+  (2) If we get LDAP_RES_SEARCH_REFERENCE, also just carry on. This was a
+      submitted patch that is reported to "do the right thing" with Solaris
+      LDAP libraries. (The problem it addresses apparently does not occur with
+      Open LDAP.)
+
+  (3) The range of errors defined by LDAP_NAME_ERROR generally mean "that
       object does not, or cannot, exist in the database". For those cases we
       fail the lookup.
 
       object does not, or cannot, exist in the database". For those cases we
       fail the lookup.
 
-  (3) All other non-successes here are treated as some kind of problem with
+  (4) All other non-successes here are treated as some kind of problem with
       the lookup, so return DEFER (which is the default in error_yield).
 */
 
 DEBUG(D_lookup) debug_printf("ldap_parse_result yielded %d: %s\n",
   rc, ldap_err2string(rc));
 
       the lookup, so return DEFER (which is the default in error_yield).
 */
 
 DEBUG(D_lookup) debug_printf("ldap_parse_result yielded %d: %s\n",
   rc, ldap_err2string(rc));
 
-if (rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED)
+if (rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
+    #ifdef LDAP_RES_SEARCH_REFERENCE
+    && rc != LDAP_RES_SEARCH_REFERENCE
+    #endif
+    )
   {
   *errmsg = string_sprintf("LDAP search failed - error %d: %s%s%s%s%s",
     rc,
   {
   *errmsg = string_sprintf("LDAP search failed - error %d: %s%s%s%s%s",
     rc,
@@ -972,8 +995,9 @@ BOOL defer_break = FALSE;
 int timelimit = LDAP_NO_LIMIT;
 int sizelimit = LDAP_NO_LIMIT;
 int tcplimit = 0;
 int timelimit = LDAP_NO_LIMIT;
 int sizelimit = LDAP_NO_LIMIT;
 int tcplimit = 0;
-int dereference = LDAP_DEREF_NEVER;
 int sep = 0;
 int sep = 0;
+int dereference = LDAP_DEREF_NEVER;
+void* referrals = LDAP_OPT_ON;
 uschar *url = ldap_url;
 uschar *p;
 uschar *user = NULL;
 uschar *url = ldap_url;
 uschar *p;
 uschar *user = NULL;
@@ -1027,7 +1051,29 @@ while (strncmpic(url, US"ldap", 4) != 0)
         DEBUG(D_lookup) debug_printf("%s\n", *errmsg);
         return DEFER;
         }
         DEBUG(D_lookup) debug_printf("%s\n", *errmsg);
         return DEFER;
         }
+      #endif
 
 
+      #ifdef LDAP_OPT_REFERRALS
+      else if (strncmpic(name, US"REFERRALS=", namelen) == 0)
+        {
+        if (strcmpic(value, US"follow") == 0) referrals = LDAP_OPT_ON;
+        else if (strcmpic(value, US"nofollow") == 0) referrals = LDAP_OPT_OFF;
+        else
+          {
+          *errmsg = string_sprintf("LDAP option REFERRALS is not \"follow\" "
+            "or \"nofollow\"");
+          DEBUG(D_lookup) debug_printf("%s\n", *errmsg);
+          return DEFER;
+          }
+        }
+      #else
+      else if (strncmpic(name, US"REFERRALS=", namelen) == 0)
+        {
+        *errmsg = string_sprintf("LDAP_OP_REFERRALS not defined in this LDAP "
+          "library - cannot use \"referrals\"");
+        DEBUG(D_lookup) debug_printf("%s\n", *errmsg);
+        return DEFER;
+        }
       #endif
 
       else
       #endif
 
       else
@@ -1076,8 +1122,8 @@ if (user != NULL)
 
 DEBUG(D_lookup)
   debug_printf("LDAP parameters: user=%s pass=%s size=%d time=%d connect=%d "
 
 DEBUG(D_lookup)
   debug_printf("LDAP parameters: user=%s pass=%s size=%d time=%d connect=%d "
-    "dereference=%d\n", user, password, sizelimit, timelimit, tcplimit,
-    dereference);
+    "dereference=%d referrals=%s\n", user, password, sizelimit, timelimit,
+    tcplimit, dereference, (referrals == LDAP_OPT_ON)? "on" : "off");
 
 /* If the request is just to check authentication, some credentials must
 be given. The password must not be empty because LDAP binds with an empty
 
 /* If the request is just to check authentication, some credentials must
 be given. The password must not be empty because LDAP binds with an empty
@@ -1114,7 +1160,8 @@ if (Ustrncmp(p, "://", 3) != 0)
 if (eldap_default_servers == NULL || p[3] != '/')
   {
   return perform_ldap_search(url, NULL, 0, search_type, res, errmsg,
 if (eldap_default_servers == NULL || p[3] != '/')
   {
   return perform_ldap_search(url, NULL, 0, search_type, res, errmsg,
-    &defer_break, user, password, sizelimit, timelimit, tcplimit, dereference);
+    &defer_break, user, password, sizelimit, timelimit, tcplimit, dereference,
+    referrals);
   }
 
 /* Loop through the default servers until OK or FAIL */
   }
 
 /* Loop through the default servers until OK or FAIL */
@@ -1131,7 +1178,8 @@ while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL
     port = Uatoi(colon+1);
     }
   rc = perform_ldap_search(url, server, port, search_type, res, errmsg,
     port = Uatoi(colon+1);
     }
   rc = perform_ldap_search(url, server, port, search_type, res, errmsg,
-    &defer_break, user, password, sizelimit, timelimit, tcplimit, dereference);
+    &defer_break, user, password, sizelimit, timelimit, tcplimit, dereference,
+    referrals);
   if (rc != DEFER || defer_break) return rc;
   }
 
   if (rc != DEFER || defer_break) return rc;
   }