Bug #2846


LDAP authentication vs. AD: problems with referrals

Added by nperraud almost 6 years ago. Updated almost 6 years ago.

Target version:



I was having difficulties setting up Lighttpd to authenticate users against a Windows 2008 domain controler (LDAP). Anonymous browsing is not permitted, but I'm not sure if that changes anything.

By default, the ldap_search_ext_s function, which is used in mod_authn_ldap_search, will follow LDAP refferals. The referral queries seem to be done anonymously, regardless if the first bind was authenticated (ref. ldap_set_option(3)).

In my case, the first, authenticated ldap search will succeed in finding the one user object that is expected, but the subsequent binds initiated to follow referrals fail. Even if not because of the failed binding, there wouldn't be a matching object in the referral scopes, and I expect that would be the case for most configurations in this context.

Because of the way LDAP authentication is currently (as of 1.4.48) implemented in mod_authn_ldap, the last referral query, resulting in either an error or empty result, seems to take over the first successful reply.

I fail to see a good reason to enable the following of LDAP referrals here, so disabling referral tracking by setting the following in mod_authn_ldap_host_init seems to solve the issue:

ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);


mod_authn_ldap.patch (761 Bytes) mod_authn_ldap.patch nperraud, 2017-12-07 09:36

Related issues 2 (0 open2 closed)

Related to Feature #2294: add ldap referrals supportMissing Feedback2011-02-03Actions
Related to Bug #2464: patch for intermittent ldap failuresFixed2012-12-19Actions
Actions #1

Updated by bjornfor almost 6 years ago

Same situation here. And I wrote a very similar patch today :-)

After testing the patch I got a tip from a co-worker that my base DN was too broad, i.e. "dc=example,dc=com", and with his help we changed it to something like "ou=users,dc=example,dc=com". With this more specific base DN, unpatched lighttpd works. (I use this now, but would prefer the broad base DN to work too. It seems e.g. Apache and Gogs can handle the broad base DN.)

Actions #2

Updated by bjornfor almost 6 years ago

Observation: Apache has a runtime option whether to follow referrals called LDAPReferrals, It defaults to "on". That makes me wonder if Apache does re-authentication with user/pw when following the referral. I found this snippet in $APACHE_SRC/modules/ldap/util_ldap.c, which seems to support this idea:

     if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) {
        /* Now that we have an ldap struct, add it to the referral list for rebinds. */
        rc = apr_ldap_rebind_add(ldc->rebind_pool, ldc->ldap, ldc->binddn, ldc->bindpw);

Gogs does not have any "referral" option (and no mention of "referral" in its documentation), but also works (unmodified) against our LDAP server. (I grepped for "referral" in its source code but didn't understand whether it followed them or not.)

Actions #3

Updated by gstrauss almost 6 years ago

  • Target version changed from 1.4.49 to 1.4.x
Actions #4

Updated by gstrauss almost 6 years ago

Actions #5

Updated by gstrauss almost 6 years ago

  • Related to Bug #2464: patch for intermittent ldap failures added
Actions #6

Updated by gstrauss almost 6 years ago

For those following this, please be aware there is a memory leak patch for mod_authn_ldap in git master, which will be part of lighttpd 1.4.49 (not yet released). See #2849

Actions #7

Updated by gstrauss almost 6 years ago

Untested patch which follows referrals and rebinds using authentication (not anonymous) for ldap searches, but disables referrals when binding only to verify user auth. Feedback appreciated.

--- a/src/mod_authn_ldap.c
+++ b/src/mod_authn_ldap.c
@@ -12,6 +12,7 @@

 typedef struct {
     LDAP *ldap;
+    server *srv;

     buffer *auth_ldap_hostname;
     buffer *auth_ldap_basedn;
@@ -450,6 +451,18 @@ static int mod_authn_ldap_bind(server *srv, LDAP *ld, const
 char *dn, const char
     return ret;

+static int mod_authn_ldap_rebind_proc (LDAP *ld, LDAP_CONST char *url, ber_tag_
t ldap_request, ber_int_t msgid, void *params) {
+    plugin_config *s = (plugin_config *)params;
+    UNUSED(url);
+    UNUSED(ldap_request);
+    UNUSED(msgid);
+    return !buffer_string_is_empty(s->auth_ldap_binddn)
+      ? mod_authn_ldap_bind(s->srv, ld,
+                            s->auth_ldap_binddn->ptr,
+                            s->auth_ldap_bindpw->ptr)
+      : mod_authn_ldap_bind(s->srv, ld, NULL, NULL);
 static LDAPMessage * mod_authn_ldap_search(server *srv, plugin_config *s, char *base, char *filter) {
     LDAPMessage *lm = NULL;
     char *attrs[] = { LDAP_NO_ATTRS, NULL };
@@ -484,11 +497,8 @@ static LDAPMessage * mod_authn_ldap_search(server *srv, plugin_config *s, char *
         return NULL;

-    ret = !buffer_string_is_empty(s->auth_ldap_binddn)
-      ? mod_authn_ldap_bind(srv, s->ldap,
-                            s->auth_ldap_binddn->ptr,
-                            s->auth_ldap_bindpw->ptr)
-      : mod_authn_ldap_bind(srv, s->ldap, NULL, NULL);
+    ldap_set_rebind_proc(s->ldap, mod_authn_ldap_rebind_proc, s);
+    ret = mod_authn_ldap_rebind_proc(s->ldap, NULL, 0, 0, s);
     if (LDAP_SUCCESS != ret) {
         s->ldap = NULL;
@@ -588,6 +598,8 @@ static handler_t mod_authn_ldap_basic(server *srv, connection *con, void *p_d, c
     handler_t rc;

     mod_authn_ldap_patch_connection(srv, con, p);
+    p->anon_conf->srv = srv;
+    p->conf.srv = srv;

     if (pw[0] == '\0' && !p->conf.auth_ldap_allow_empty_pw)
         return HANDLER_ERROR;
@@ -634,6 +646,17 @@ static handler_t mod_authn_ldap_basic(server *srv, connection *con, void *p_d, c
         return HANDLER_ERROR;

+    /* Disable referral tracking.  Target user should be in provided scope */
+    {
+        int ret = ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+        if (LDAP_OPT_SUCCESS != ret) {
+            mod_authn_ldap_err(srv,__FILE__,__LINE__,"ldap_set_option()",ret);
+            ldap_destroy(ld);
+            if (dn != p->ldap_filter->ptr) ldap_memfree(dn);
+            return HANDLER_ERROR;
+        }
+    }
     if (LDAP_SUCCESS != mod_authn_ldap_bind(srv, ld, dn, pw)) {
         if (dn != p->ldap_filter->ptr) ldap_memfree(dn);

Actions #8

Updated by gstrauss almost 6 years ago

  • Status changed from New to Patch Pending
  • Target version changed from 1.4.x to 1.4.49
Actions #9

Updated by gstrauss almost 6 years ago

  • Status changed from Patch Pending to Fixed
  • % Done changed from 0 to 100

Also available in: Atom