lists.arthurdejong.org
RSS feed

nss-pam-ldapd branch master updated. 0.9.2-28-gc6c317e

[Date Prev][Date Next] [Thread Prev][Thread Next]

nss-pam-ldapd branch master updated. 0.9.2-28-gc6c317e



This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "nss-pam-ldapd".

The branch, master has been updated
       via  c6c317ec9efb8190bdc1834091c4761b60637e7f (commit)
       via  309b4bbbc040ce9f37ccf25399eacc5294bfc34f (commit)
       via  cecc02451efa40f0b6418b3fd6bca39448fb99a8 (commit)
       via  c973834328baa69dbd3352182431421b2b9a2319 (commit)
       via  3992e15ffd0a4f0d8130b6ac25163ab90d064c27 (commit)
       via  15ee2fce08794ec82d2a08b9c01339c0db0a4725 (commit)
       via  547e4792c580b67ec14595e23a08836825424171 (commit)
       via  c22eb0891e9174e43114b9dfa6b9240f98dbf489 (commit)
       via  f009c96b36f3bf00c091097cec9496752845e7c6 (commit)
       via  4f6dfdd636a6d5db649a70c781ef9b3901a1b760 (commit)
      from  be94912a9d236bbe3d5b0e17b771727b0054906d (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://arthurdejong.org/git/nss-pam-ldapd/commit/?id=c6c317ec9efb8190bdc1834091c4761b60637e7f

commit c6c317ec9efb8190bdc1834091c4761b60637e7f
Merge: be94912 309b4bb
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sun Jan 5 22:11:20 2014 +0100

    Implement deref control handling
    
    This uses the LDAP_CONTROL_X_DEREF control as described in
    draft-masarati-ldap-deref-00 to request the LDAP server to dereference
    group member attribute values to uid attribute values.
    
    This should reduce the number of searches that are required for
    expanding group members that use the member attribute.
    
    This mechanism could also be used to extract information on nested
    groups but the gains are less clear there.
    
    Not all LDAP servers support this control. In OpenLDAP, load the
    (currently undocumented) deref overlay and enable it for the database to
    take advantage of this improvement.
    
    There is a functional difference when using this control. Any returned
    deferred uid value returned by the LDAP server is accepted as a member.
    No checks are performed to see if the user matches the search base and
    search filters set for passwd entries.


http://arthurdejong.org/git/nss-pam-ldapd/commit/?id=309b4bbbc040ce9f37ccf25399eacc5294bfc34f

commit 309b4bbbc040ce9f37ccf25399eacc5294bfc34f
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sun Jan 5 18:02:44 2014 +0100

    Update documentation
    
    This documents the way the deref controls are used.

diff --git a/README b/README
index d5a996a..62184b9 100644
--- a/README
+++ b/README
@@ -15,7 +15,7 @@
 
    Copyright (C) 1997-2006 Luke Howard
    Copyright (C) 2006-2007 West Consulting
-   Copyright (C) 2006-2013 Arthur de Jong
+   Copyright (C) 2006-2014 Arthur de Jong
    Copyright (C) 2009 Howard Chu
    Copyright (C) 2010 Symas Corporation
 
@@ -344,18 +344,25 @@ group membership
 
 Currently, two ways of specifying group membership are supported. The first,
 by using the memberUid attribute, is the simplest and by far the fastest
-(takes the least number of lookups). This attribute maps to user names with
-the same values as the uid attribute would hold for posixAccount entries.
+(takes the least number of lookups). The attribute values are user names with
+the format as the uid attribute for posixAccount entries and are returned
+without further processing.
 
-The second method is to use DN values in the member attribute (attribute
-names can be changed by using the attribute mapping options as described in
-the manual page). This is potentially a lot slower because in the worst case
-every DN has to be looked up in the LDAP server to find the proper value for
-the uid attribute.
+The second method is to use DN values in the member attribute (attribute names
+can be changed by using the attribute mapping options as described in the
+manual page). This is potentially a lot slower because in the worst case every
+DN has to be looked up in the LDAP server to find the proper value for the uid
+attribute.
+
+If the LDAP server supports the deref control (provided by the deref overlay
+in OpenLDAP) the DN to uid expansing is performed by the LDAP server.
 
 If the DN value already contains a uid value (e.g. uid=arthur, dc=example,
-dc=com) the lookup is skipped and the value from the DN is used. A cache is
-maintained that saves the DN to uid translations for 15 minutes.
+dc=com) a further lookup is skipped and the uid value from the DN is used.
+
+For other DN values an extra lookup is performed to expand it to a uid. These
+lookups are cached and are configurable with the cache dn2uid configuration
+option.
 
 The member attribute may also contain the DN of another group entry. These
 nested groups are parsed recursively depending on the nss_nested_groups

http://arthurdejong.org/git/nss-pam-ldapd/commit/?id=cecc02451efa40f0b6418b3fd6bca39448fb99a8

commit cecc02451efa40f0b6418b3fd6bca39448fb99a8
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sun Jan 5 14:59:11 2014 +0100

    Use myldap_get_deref_values() to get member uids
    
    This uses information from the deref control (if available) to get the
    username for each of the members of the group. Any missing deref member
    attribute values will be seen as nested groups and will be traversed if
    nested group support is enabled.

diff --git a/nslcd/group.c b/nslcd/group.c
index da0653d..ffaeb80 100644
--- a/nslcd/group.c
+++ b/nslcd/group.c
@@ -234,6 +234,7 @@ static void getmembers(MYLDAP_ENTRY *entry, MYLDAP_SESSION 
*session,
   char buf[BUFLEN_NAME];
   int i;
   const char **values;
+  const char ***derefs;
   /* add the memberUid values */
   values = myldap_get_values(entry, attmap_group_memberUid);
   if (values != NULL)
@@ -246,6 +247,26 @@ static void getmembers(MYLDAP_ENTRY *entry, MYLDAP_SESSION 
*session,
   /* skip rest if attmap_group_member is blank */
   if (strcasecmp(attmap_group_member, "\"\"") == 0)
     return;
+  /* add deref'd entries if we have them*/
+  derefs = myldap_get_deref_values(entry, attmap_group_member, 
attmap_passwd_uid);
+  if (derefs != NULL)
+  {
+    /* add deref'd uid attributes */
+    for (i = 0; derefs[0][i] != NULL; i++)
+      set_add(members, derefs[0][i]);
+    /* add non-deref'd attribute values as subgroups */
+    for (i = 0; derefs[1][i] != NULL; i++)
+    {
+      if ((seen == NULL) || (!set_contains(seen, derefs[1][i])))
+      {
+        if (seen != NULL)
+          set_add(seen, derefs[1][i]);
+        if (subgroups != NULL)
+          set_add(subgroups, derefs[1][i]);
+      }
+    }
+    return; /* no need to parse the member attribute ourselves */
+  }
   /* add the member values */
   values = myldap_get_values(entry, attmap_group_member);
   if (values != NULL)

http://arthurdejong.org/git/nss-pam-ldapd/commit/?id=c973834328baa69dbd3352182431421b2b9a2319

commit c973834328baa69dbd3352182431421b2b9a2319
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sun Jan 5 14:15:21 2014 +0100

    Provide a myldap_get_deref_values() function
    
    This function looks for deref response controls (LDAP_CONTROL_X_DEREF)
    in the entry and returns the information from the dereferenced attribute
    in two lists: dereferenced values and attribute values that could not be
    dereferenced.

diff --git a/configure.ac b/configure.ac
index 907446e..cd776e0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -804,9 +804,10 @@ then
   AC_CHECK_FUNCS(ldap_get_values_len ldap_count_values_len ldap_value_free_len)
   AC_CHECK_FUNCS(ldap_err2string ldap_abandon)
   AC_CHECK_FUNCS(ldap_control_create ldap_create_control ldap_control_find)
-  AC_CHECK_FUNCS(ldap_controls_free ldap_control_free)
+  AC_CHECK_FUNCS(ldap_controls_free ldap_control_free ldap_get_entry_controls)
   AC_CHECK_FUNCS(ldap_parse_passwordpolicy_control ldap_passwordpolicy_err2txt)
   AC_CHECK_FUNCS(ldap_create_deref_control ldap_create_deref_control_value)
+  AC_CHECK_FUNCS(ldap_parse_deref_control ldap_derefresponse_free)
 
   # replace ldap_create_page_control() and ldap_parse_page_control()
   AC_CHECK_FUNCS(ldap_create_page_control ldap_parse_page_control,, 
[AC_LIBOBJ(pagectrl)])
diff --git a/nslcd/myldap.c b/nslcd/myldap.c
index 722109d..9e0bc6e 100644
--- a/nslcd/myldap.c
+++ b/nslcd/myldap.c
@@ -2080,6 +2080,154 @@ int myldap_has_objectclass(MYLDAP_ENTRY *entry, const 
char *objectclass)
   return 0;
 }
 
+#ifdef HAVE_LDAP_PARSE_DEREF_CONTROL
+const char ***myldap_get_deref_values(MYLDAP_ENTRY *entry,
+                const char *derefattr, const char *getattr)
+{
+  LDAPControl **entryctrls;
+  LDAPDerefRes *deref, *d;
+  LDAPDerefVal *a;
+  int i, pass;
+  int rc;
+  int found;
+  int counts[2];
+  size_t sizes[2], size;
+  char *buffer = NULL;
+  char ***results = NULL;
+  rc = ldap_get_entry_controls(entry->search->session->ld, entry->search->msg,
+                                &entryctrls);
+  if (rc != LDAP_SUCCESS)
+  {
+    myldap_err(LOG_WARNING, entry->search->session->ld, rc,
+               "ldap_get_entry_controls() failed");
+    return NULL;
+  }
+  if (entryctrls == NULL)
+    return NULL;
+  /* see if we can find a deref control */
+  rc = ldap_parse_deref_control(entry->search->session->ld, entryctrls,
+                                &deref);
+  if ((rc != LDAP_SUCCESS) || (deref == NULL))
+  {
+    if ((rc != LDAP_SUCCESS) && (rc != LDAP_CONTROL_NOT_FOUND))
+      myldap_err(LOG_WARNING, entry->search->session->ld, rc,
+                 "ldap_parse_deref_control() failed");
+    /* clear error flag */
+    rc = LDAP_SUCCESS;
+    if (ldap_set_option(entry->search->session->ld, LDAP_OPT_ERROR_NUMBER,
+                        &rc) != LDAP_SUCCESS)
+      log_log(LOG_WARNING, "failed to clear the error flag");
+    ldap_controls_free(entryctrls);
+    return NULL;
+  }
+  /* two passes: one to calculate size, one to store data */
+  for (pass=0; pass < 2; pass++)
+  {
+    /* reset counters and size */
+    for (i = 0; i < 2; i++)
+    {
+      counts[i] = 0;
+      sizes[i] = 0;
+    }
+    /* go over all deref'd attributes and find the one we're looking for */
+    for (d = deref; d != NULL; d = d->next)
+      if ((d->derefAttr != NULL) && (d->derefVal.bv_val != NULL) &&
+          (strcasecmp(derefattr, d->derefAttr) == 0))
+      {
+        /* we should have one d per original attribute value */
+        found = 0;
+        /* go over deref'd attribute values to find the ones we're looking for 
*/
+        for (a = d->attrVals; a != NULL; a = a->next)
+          if ((a->type != NULL) && (a->vals != NULL) &&
+              (strcasecmp(getattr, a->type) == 0))
+            for (i=0; a->vals[i].bv_val != NULL; i++)
+            {
+              found = 1;
+              if (results == NULL)
+              {
+                log_log(LOG_DEBUG, "deref %s %s=%s -> %s=%s",
+                        myldap_get_dn(entry),  d->derefAttr, 
d->derefVal.bv_val,
+                        a->type, a->vals[i].bv_val);
+                counts[0]++;
+                sizes[0] += strlen(a->vals[i].bv_val) + 1;
+              }
+              else
+              {
+                strcpy(buffer, a->vals[i].bv_val);
+                results[0][counts[0]++] = buffer;
+                buffer += strlen(buffer) + 1;
+              }
+            }
+        if (!found)
+        {
+          if (results == NULL)
+          {
+            log_log(LOG_DEBUG, "no %s deref %s %s=%s", getattr,
+                    myldap_get_dn(entry),  d->derefAttr, d->derefVal.bv_val);
+            counts[1]++;
+            sizes[1] += strlen(d->derefVal.bv_val) + 1;
+          }
+          else
+          {
+            strcpy(buffer, d->derefVal.bv_val);
+            results[1][counts[1]++] = buffer;
+            buffer += strlen(buffer) + 1;
+          }
+        }
+      }
+    /* allocate memory after first pass */
+    if (results == NULL)
+    {
+      size = sizeof(char **) * 3;
+      for (i = 0; i < 2; i++)
+        size += sizeof(char *) * (counts[i] + 1);
+      for (i = 0; i < 2; i++)
+        size += sizeof(char) * sizes[i];
+      buffer = (char *)malloc(size);
+      if (buffer == NULL)
+      {
+        log_log(LOG_CRIT, "myldap_get_deref_values(): malloc() failed to 
allocate memory");
+        return NULL;
+      }
+      /* allocate the list of lists */
+      results = (void *)buffer;
+      buffer += sizeof(char **) * 3;
+      /* allocate the lists */
+      for (i = 0; i < 2; i++)
+      {
+        results[i] = (char **)buffer;
+        buffer += sizeof(char *) * (counts[i] + 1);
+      }
+      results[i] = NULL;
+    }
+  }
+  /* NULL terminate the lists */
+  results[0][counts[0]] = NULL;
+  results[1][counts[1]] = NULL;
+  /* free control data */
+  ldap_derefresponse_free(deref);
+  ldap_controls_free(entryctrls);
+  /* store results so we can free it later on */
+  for (i = 0; i < MAX_BUFFERS_PER_ENTRY; i++)
+    if (entry->buffers[i] == NULL)
+    {
+      entry->buffers[i] = (void *)results;
+      return (const char ***)results;
+    }
+  /* we found no room to store the values */
+  log_log(LOG_ERR, "myldap_get_deref_values() couldn't store results, "
+          "increase MAX_BUFFERS_PER_ENTRY");
+  free(results);
+  return NULL;
+}
+#else /* not HAVE_LDAP_PARSE_DEREF_CONTROL */
+const char ***myldap_get_deref_values(MYLDAP_ENTRY UNUSED(*entry),
+                const char UNUSED(*derefattr), const char UNUSED(*getattr))
+{
+  return NULL;
+}
+#endif /* not HAVE_LDAP_PARSE_DEREF_CONTROL */
+
 int myldap_escape(const char *src, char *buffer, size_t buflen)
 {
   size_t pos = 0;
diff --git a/nslcd/myldap.h b/nslcd/myldap.h
index 8c4551a..c7358af 100644
--- a/nslcd/myldap.h
+++ b/nslcd/myldap.h
@@ -2,7 +2,7 @@
    myldap.h - simple interface to do LDAP requests
    This file is part of the nss-pam-ldapd library.
 
-   Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Arthur de Jong
+   Copyright (C) 2007-2014 Arthur de Jong
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -133,6 +133,13 @@ MUST_USE const char **myldap_get_values_len(MYLDAP_ENTRY 
*entry, const char *att
 /* Checks to see if the entry has the specified object class. */
 MUST_USE int myldap_has_objectclass(MYLDAP_ENTRY *entry, const char 
*objectclass);
 
+/* See if the entry has any deref controls attached to it and deref attr
+   derefattr to get the getattr values. Will return two lists of attribute
+   values. One list of deref'ed attribute values and one list of original
+   attribute values that could not be deref'ed. */
+MUST_USE const char ***myldap_get_deref_values(MYLDAP_ENTRY *entry,
+                const char *derefattr, const char *getattr);
+
 /* Get the RDN's value: eg. if the DN was cn=lukeh, ou=People, dc=example,
    dc=com getrdnvalue(entry, cn) would return lukeh. If the attribute was not
    found in the DN or if some error occurs NULL is returned. This method may

http://arthurdejong.org/git/nss-pam-ldapd/commit/?id=3992e15ffd0a4f0d8130b6ac25163ab90d064c27

commit 3992e15ffd0a4f0d8130b6ac25163ab90d064c27
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sun Jan 5 18:32:21 2014 +0100

    Skip member attributes in bymember search
    
    This changes the group by member searches to not request the member
    attributes. This will speed up result parsing by a fraction because less
    data is transferred but will also cause the deref control not to be
    added to these searches.

diff --git a/nslcd/group.c b/nslcd/group.c
index 1455930..da0653d 100644
--- a/nslcd/group.c
+++ b/nslcd/group.c
@@ -78,6 +78,9 @@ static const char *default_group_userPassword = "*"; /* 
unmatchable */
 /* the attribute list to request with searches */
 static const char **group_attrs = NULL;
 
+/* the attribute list for bymember searches (without member attributes) */
+static const char **group_bymember_attrs = NULL;
+
 /* create a search filter for searching a group entry
    by name, return -1 on errors */
 static int mkfilter_group_byname(const char *name,
@@ -181,6 +184,18 @@ void group_init(void)
     exit(EXIT_FAILURE);
   }
   set_free(set);
+  /* set up bymember attribute list */
+  set = set_new();
+  attmap_add_attributes(set, attmap_group_cn);
+  attmap_add_attributes(set, attmap_group_userPassword);
+  attmap_add_attributes(set, attmap_group_gidNumber);
+  group_bymember_attrs = set_tolist(set);
+  if (group_bymember_attrs == NULL)
+  {
+    log_log(LOG_CRIT, "malloc() failed to allocate memory");
+    exit(EXIT_FAILURE);
+  }
+  set_free(set);
 }
 
 static int do_write_group(TFILE *fp, MYLDAP_ENTRY *entry,
@@ -447,7 +462,7 @@ int nslcd_group_bymember(TFILE *fp, MYLDAP_SESSION *session)
   {
     /* do the LDAP search */
     search = myldap_search(session, base, group_scope, filter,
-                           group_attrs, NULL);
+                           group_bymember_attrs, NULL);
     if (search == NULL)
     {
       if (seen != NULL)
@@ -497,7 +512,7 @@ int nslcd_group_bymember(TFILE *fp, MYLDAP_SESSION *session)
       /* do the LDAP searches */
       for (i = 0; (base = group_bases[i]) != NULL; i++)
       {
-        search = myldap_search(session, base, group_scope, filter, 
group_attrs, NULL);
+        search = myldap_search(session, base, group_scope, filter, 
group_bymember_attrs, NULL);
         if (search != NULL)
         {
           while ((entry = myldap_get_entry(search, NULL)) != NULL)

http://arthurdejong.org/git/nss-pam-ldapd/commit/?id=15ee2fce08794ec82d2a08b9c01339c0db0a4725

commit 15ee2fce08794ec82d2a08b9c01339c0db0a4725
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sat Dec 28 10:51:06 2013 +0100

    Provide replacement ldap_create_deref_control()
    
    This adds a test for a bug in OpenLDAP that allocated a
    LDAP_CONTROL_PAGEDRESULTS control instead of a LDAP_CONTROL_X_DEREF
    control.

diff --git a/compat/Makefile.am b/compat/Makefile.am
index 361c9be..bc8e4cc 100644
--- a/compat/Makefile.am
+++ b/compat/Makefile.am
@@ -29,6 +29,7 @@ EXTRA_DIST = getopt_long.c getopt_long.h \
              nss_compat.h socket.h \
              ldap_compat.h pagectrl.c ldap_passwd_s.c ldap_initialize.c \
              ldap_parse_passwordpolicy_control.c ldap_passwordpolicy_err2txt.c 
\
+             derefctrl.c \
              pam_compat.h pam_get_authtok.c pam_prompt.c
 
 libcompat_a_SOURCES = getpeercred.c getpeercred.h
diff --git a/compat/derefctrl.c b/compat/derefctrl.c
new file mode 100644
index 0000000..9676c55
--- /dev/null
+++ b/compat/derefctrl.c
@@ -0,0 +1,50 @@
+/*
+   derefctrl.c - replacement function
+
+   Copyright (C) 2013 Arthur de Jong
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <lber.h>
+#include <ldap.h>
+#include <string.h>
+
+#include "compat/ldap_compat.h"
+#include "compat/attrs.h"
+
+#ifdef REPLACE_LDAP_CREATE_DEREF_CONTROL
+int replacement_ldap_create_deref_control(LDAP *ld, LDAPDerefSpec *ds,
+      int iscritical, LDAPControl **ctrlp)
+{
+  int rc;
+  struct berval value;
+  if (ctrlp == NULL)
+    return LDAP_PARAM_ERROR;
+  rc = ldap_create_deref_control_value(ld, ds, &value);
+  if (rc != LDAP_SUCCESS)
+    return rc;
+  rc = ldap_control_create(LDAP_CONTROL_X_DEREF, iscritical, &value, 0, ctrlp);
+  if (rc != LDAP_SUCCESS)
+  {
+    ber_memfree(value.bv_val);
+  }
+  return rc;
+}
+#endif /* REPLACE_LDAP_CREATE_DEREF_CONTROL */
diff --git a/compat/ldap_compat.h b/compat/ldap_compat.h
index 6e9c6b1..b69974f 100644
--- a/compat/ldap_compat.h
+++ b/compat/ldap_compat.h
@@ -1,7 +1,7 @@
 /*
    ldap_compat.h - provide a replacement definitions for some ldap functions
 
-   Copyright (C) 2009, 2010, 2012, 2013 Arthur de Jong
+   Copyright (C) 2009-2013 Arthur de Jong
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -80,6 +80,14 @@ int ldap_parse_passwordpolicy_control(LDAP *ld, LDAPControl 
*ctrl,
 const char *ldap_passwordpolicy_err2txt(LDAPPasswordPolicyError error);
 #endif /* HAVE_LDAP_PASSWORDPOLICY_ERR2TXT */
 
+#ifdef REPLACE_LDAP_CREATE_DEREF_CONTROL
+/* provide a replacement implementation of ldap_create_deref_control() */
+int replacement_ldap_create_deref_control(LDAP *ld, LDAPDerefSpec *ds,
+      int iscritical, LDAPControl **ctrlp);
+#define ldap_create_deref_control(ld, dc, iscritical, ctrlp) \
+      replacement_ldap_create_deref_control(ld, dc, iscritical, ctrlp)
+#endif /* REPLACE_LDAP_CREATE_DEREF_CONTROL */
+
 /* compatibility definition */
 #ifndef LDAP_SASL_QUIET
 #define LDAP_SASL_QUIET 2U
@@ -106,5 +114,8 @@ const char 
*ldap_passwordpolicy_err2txt(LDAPPasswordPolicyError error);
 #ifndef LDAP_CONTROL_PASSWORDPOLICYRESPONSE
 #define LDAP_CONTROL_PASSWORDPOLICYRESPONSE "1.3.6.1.4.1.42.2.27.8.5.1"
 #endif /* LDAP_CONTROL_PASSWORDPOLICYRESPONSE */
+#ifndef LDAP_CONTROL_X_DEREF
+#define LDAP_CONTROL_X_DEREF "1.3.6.1.4.1.4203.666.5.16"
+#endif /* LDAP_CONTROL_X_DEREF */
 
 #endif /* COMPAT__LDAP_COMPAT_H */
diff --git a/configure.ac b/configure.ac
index cecb358..907446e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -803,10 +803,10 @@ then
   AC_CHECK_FUNCS(ldap_get_values ldap_value_free)
   AC_CHECK_FUNCS(ldap_get_values_len ldap_count_values_len ldap_value_free_len)
   AC_CHECK_FUNCS(ldap_err2string ldap_abandon)
-  AC_CHECK_FUNCS(ldap_create_control ldap_control_find)
+  AC_CHECK_FUNCS(ldap_control_create ldap_create_control ldap_control_find)
   AC_CHECK_FUNCS(ldap_controls_free ldap_control_free)
   AC_CHECK_FUNCS(ldap_parse_passwordpolicy_control ldap_passwordpolicy_err2txt)
-  AC_CHECK_FUNCS(ldap_create_deref_control)
+  AC_CHECK_FUNCS(ldap_create_deref_control ldap_create_deref_control_value)
 
   # replace ldap_create_page_control() and ldap_parse_page_control()
   AC_CHECK_FUNCS(ldap_create_page_control ldap_parse_page_control,, 
[AC_LIBOBJ(pagectrl)])
@@ -861,6 +861,64 @@ then
               [Define to 1 if ldap_set_rebind_proc() returns void.])
   fi
 
+  # check for broken implementations of ldap_create_deref_control()
+  if test "x$ac_cv_func_ldap_create_deref_control" = "xyes"
+  then
+    # this bug cannot be determined on compile time so we run a
+    # small test program
+    AC_CACHE_CHECK(
+        [ldap_create_deref_control() implementation],
+        nslcd_cv_ldap_create_deref_control_working,
+            [AC_RUN_IFELSE(
+                [AC_LANG_PROGRAM([[
+                    #include <stdio.h>
+                    #include <lber.h>
+                    #include <ldap.h>
+                    ]], [[
+                    int rc;
+                    LDAP *ld;
+                    LDAPControl *ctrls[2] = {NULL, NULL};
+                    struct LDAPDerefSpec ds[2];
+                    char *attrs[2] = {"uid", NULL};
+                    ld = ldap_init("localhost", LDAP_PORT);
+                    if (ld == NULL)
+                    {
+                      fprintf(stderr, "ldap_init() failed\n");
+                      return 2;
+                    }
+                    ds[0].derefAttr = "member";
+                    ds[0].attributes = attrs;
+                    ds[1].derefAttr = NULL;
+                    rc = ldap_create_deref_control(ld, ds, 0, &ctrls[0]);
+                    if (rc != LDAP_SUCCESS)
+                    {
+                      fprintf(stderr, "ldap_create_deref_control() failed: 
%s\n",
+                              ldap_err2string(rc));
+                      return 2;
+                    }
+                    if (ldap_control_find(LDAP_CONTROL_X_DEREF, ctrls, NULL) 
!= NULL)
+                      return 0;
+                    if (ldap_control_find(LDAP_CONTROL_PAGEDRESULTS, ctrls, 
NULL) != NULL)
+                    {
+                      fprintf(stderr, "ldap_create_deref_control() created 
LDAP_CONTROL_PAGEDRESULTS control\n");
+                      return 3;
+                    }
+                    fprintf(stderr, "ldap_create_deref_control() created 
unknown control\n");
+                    return 2;
+                    ]])],
+                [nslcd_cv_ldap_create_deref_control_working=ok],
+                [if test "$?" -eq 3; then 
nslcd_cv_ldap_create_deref_control_working=broken
+                 else nslcd_cv_ldap_create_deref_control_working=unknown; fi],
+                [nslcd_cv_ldap_create_deref_control_working=cross])])
+    if test "x$nslcd_cv_ldap_create_deref_control_working" != "xok"
+    then
+      AC_MSG_NOTICE([using replacement ldap_create_deref_control()])
+      AC_LIBOBJ(derefctrl)
+      AC_DEFINE(REPLACE_LDAP_CREATE_DEREF_CONTROL, 1,
+                [Define to 1 if ldap_create_deref_control() is broken.])
+    fi
+  fi
+
   # save nslcd LIBS and CFLAGS and restore originals
   nslcd_CFLAGS="$CFLAGS"
   nslcd_LIBS="$LIBS"

http://arthurdejong.org/git/nss-pam-ldapd/commit/?id=547e4792c580b67ec14595e23a08836825424171

commit 547e4792c580b67ec14595e23a08836825424171
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sun Jan 5 18:16:58 2014 +0100

    Request attribute deref via search control
    
    This uses the LDAP_CONTROL_X_DEREF control as descibed in
    draft-masarati-ldap-deref-00 to request the LDAP server to dereference
    member attribute values to uid attribute values in order to avoid doing
    extra searches.
    
    This control is currently only added for group search by looking for the
    member attribute in the search.

diff --git a/configure.ac b/configure.ac
index 411c9e5..cecb358 100644
--- a/configure.ac
+++ b/configure.ac
@@ -806,6 +806,7 @@ then
   AC_CHECK_FUNCS(ldap_create_control ldap_control_find)
   AC_CHECK_FUNCS(ldap_controls_free ldap_control_free)
   AC_CHECK_FUNCS(ldap_parse_passwordpolicy_control ldap_passwordpolicy_err2txt)
+  AC_CHECK_FUNCS(ldap_create_deref_control)
 
   # replace ldap_create_page_control() and ldap_parse_page_control()
   AC_CHECK_FUNCS(ldap_create_page_control ldap_parse_page_control,, 
[AC_LIBOBJ(pagectrl)])
diff --git a/nslcd/myldap.c b/nslcd/myldap.c
index a57f2f9..722109d 100644
--- a/nslcd/myldap.c
+++ b/nslcd/myldap.c
@@ -72,6 +72,7 @@
 #include "cfg.h"
 #include "common/set.h"
 #include "compat/ldap_compat.h"
+#include "attmap.h"
 
 /* the maximum number of searches per session */
 #define MAX_SEARCHES_IN_SESSION 4
@@ -1055,7 +1056,12 @@ static int do_try_search(MYLDAP_SEARCH *search)
 {
   int ctrlidx = 0;
   int rc;
-  LDAPControl *serverctrls[2];
+  LDAPControl *serverctrls[3];
+#ifdef HAVE_LDAP_CREATE_DEREF_CONTROL
+  int i;
+  struct LDAPDerefSpec ds[2];
+  char *deref_attrs[2];
+#endif /* HAVE_LDAP_CREATE_DEREF_CONTROL */
   int msgid;
   /* ensure that we have an open connection */
   rc = do_open(search->session);
@@ -1078,6 +1084,33 @@ static int do_try_search(MYLDAP_SEARCH *search)
         return rc;
     }
   }
+#ifdef HAVE_LDAP_CREATE_DEREF_CONTROL
+  /* if doing group searches, add deref control to search request
+     (this is currently a bit of a hack and hard-coded for group searches
+     which are detected by requesting the attmap_group_member member
+     attribute) */
+  for (i = 0; search->attrs[i] != NULL; i++)
+    if (strcasecmp(search->attrs[i], attmap_group_member) == 0)
+    {
+      /* attributes from dereff'd entries */
+      deref_attrs[0] = (void *)attmap_passwd_uid;
+      deref_attrs[1] = NULL;
+      /* build deref control */
+      ds[0].derefAttr = (void *)attmap_group_member;
+      ds[0].attributes = deref_attrs;
+      ds[1].derefAttr = NULL;
+      ds[1].attributes = NULL;
+      rc = ldap_create_deref_control(search->session->ld, ds, 0, 
&serverctrls[ctrlidx]);
+      if (rc == LDAP_SUCCESS)
+        ctrlidx++;
+      else
+      {
+        myldap_err(LOG_WARNING, search->session->ld, rc,
+                   "ldap_create_deref_control() failed");
+        serverctrls[ctrlidx] = NULL;
+      }
+    }
+#endif /* HAVE_LDAP_CREATE_DEREF_CONTROL */
   /* NULL terminate control list */
   serverctrls[ctrlidx] = NULL;
   /* clear error flag (perhaps control setting failed) */

http://arthurdejong.org/git/nss-pam-ldapd/commit/?id=c22eb0891e9174e43114b9dfa6b9240f98dbf489

commit c22eb0891e9174e43114b9dfa6b9240f98dbf489
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sat Jan 4 19:47:58 2014 +0100

    Rename entry property to indicate storage type
    
    This changes entrye->rangedattributevalues to entry->buffers because the
    propery is not only used for ranged attribute values but for anything
    that can be freed with free().

diff --git a/nslcd/myldap.c b/nslcd/myldap.c
index 57c420c..a57f2f9 100644
--- a/nslcd/myldap.c
+++ b/nslcd/myldap.c
@@ -130,9 +130,9 @@ struct myldap_search {
    done per returned entry. */
 #define MAX_ATTRIBUTES_PER_ENTRY 16
 
-/* The maximum number of ranged attribute values that may be stoted
-   per entry. */
-#define MAX_RANGED_ATTRIBUTES_PER_ENTRY 8
+/* The maximum number of buffers (used for ranged attribute values and
+   values returned by bervalues_to_values()) that may be stored per entry. */
+#define MAX_BUFFERS_PER_ENTRY 8
 
 /* A single entry from the LDAP database as returned by
    myldap_get_entry(). */
@@ -146,8 +146,8 @@ struct myldap_entry {
   char **exploded_rdn;
   /* a cache of attribute to value list */
   char **attributevalues[MAX_ATTRIBUTES_PER_ENTRY];
-  /* a reference to ranged attribute values so we can free() them later on */
-  char **rangedattributevalues[MAX_RANGED_ATTRIBUTES_PER_ENTRY];
+  /* a reference to buffers so we can free() them later on */
+  char **buffers[MAX_BUFFERS_PER_ENTRY];
 };
 
 /* Flag to record first search operation */
@@ -206,8 +206,8 @@ static MYLDAP_ENTRY *myldap_entry_new(MYLDAP_SEARCH *search)
   entry->exploded_rdn = NULL;
   for (i = 0; i < MAX_ATTRIBUTES_PER_ENTRY; i++)
     entry->attributevalues[i] = NULL;
-  for (i = 0; i < MAX_RANGED_ATTRIBUTES_PER_ENTRY; i++)
-    entry->rangedattributevalues[i] = NULL;
+  for (i = 0; i < MAX_BUFFERS_PER_ENTRY; i++)
+    entry->buffers[i] = NULL;
   /* return the fresh entry */
   return entry;
 }
@@ -225,10 +225,10 @@ static void myldap_entry_free(MYLDAP_ENTRY *entry)
   for (i = 0; i < MAX_ATTRIBUTES_PER_ENTRY; i++)
     if (entry->attributevalues[i] != NULL)
       ldap_value_free(entry->attributevalues[i]);
-  /* free all ranged attribute values */
-  for (i = 0; i < MAX_RANGED_ATTRIBUTES_PER_ENTRY; i++)
-    if (entry->rangedattributevalues[i] != NULL)
-      free(entry->rangedattributevalues[i]);
+  /* free all buffers */
+  for (i = 0; i < MAX_BUFFERS_PER_ENTRY; i++)
+    if (entry->buffers[i] != NULL)
+      free(entry->buffers[i]);
   /* we don't need the result anymore, ditch it. */
   ldap_msgfree(entry->search->msg);
   entry->search->msg = NULL;
@@ -1769,14 +1769,14 @@ const char **myldap_get_values(MYLDAP_ENTRY *entry, 
const char *attr)
       if (values == NULL)
         return NULL;
       /* store values entry so we can free it later on */
-      for (i = 0; i < MAX_RANGED_ATTRIBUTES_PER_ENTRY; i++)
-        if (entry->rangedattributevalues[i] == NULL)
+      for (i = 0; i < MAX_BUFFERS_PER_ENTRY; i++)
+        if (entry->buffers[i] == NULL)
         {
-          entry->rangedattributevalues[i] = values;
-          return (const char **)entry->rangedattributevalues[i];
+          entry->buffers[i] = values;
+          return (const char **)entry->buffers[i];
         }
       /* we found no room to store the values */
-      log_log(LOG_ERR, "ldap_get_values() couldn't store results, increase 
MAX_RANGED_ATTRIBUTES_PER_ENTRY");
+      log_log(LOG_ERR, "ldap_get_values() couldn't store results, increase 
MAX_BUFFERS_PER_ENTRY");
       free(values);
       return NULL;
     }
@@ -1893,14 +1893,14 @@ const char **myldap_get_values_len(MYLDAP_ENTRY *entry, 
const char *attr)
   if (values == NULL)
     return NULL;
   /* store values entry so we can free it later on */
-  for (i = 0; i < MAX_RANGED_ATTRIBUTES_PER_ENTRY; i++)
-    if (entry->rangedattributevalues[i] == NULL)
+  for (i = 0; i < MAX_BUFFERS_PER_ENTRY; i++)
+    if (entry->buffers[i] == NULL)
     {
-      entry->rangedattributevalues[i] = (char **)values;
+      entry->buffers[i] = (char **)values;
       return values;
     }
   /* we found no room to store the values */
-  log_log(LOG_ERR, "myldap_get_values_len() couldn't store results, increase 
MAX_RANGED_ATTRIBUTES_PER_ENTRY");
+  log_log(LOG_ERR, "myldap_get_values_len() couldn't store results, increase 
MAX_BUFFERS_PER_ENTRY");
   free(values);
   return NULL;
 }

http://arthurdejong.org/git/nss-pam-ldapd/commit/?id=f009c96b36f3bf00c091097cec9496752845e7c6

commit f009c96b36f3bf00c091097cec9496752845e7c6
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Jan 3 21:25:32 2014 +0100

    Ignore missing page controls
    
    Since we could get arbitrray controls and are only interested in page
    controls we ignore failures to find page controls.

diff --git a/nslcd/myldap.c b/nslcd/myldap.c
index e2daf17..57c420c 100644
--- a/nslcd/myldap.c
+++ b/nslcd/myldap.c
@@ -1499,7 +1499,8 @@ MYLDAP_ENTRY *myldap_get_entry(MYLDAP_SEARCH *search, int 
*rcp)
                                        &count, &(search->cookie));
           if (rc != LDAP_SUCCESS)
           {
-            myldap_err(LOG_WARNING, search->session->ld, rc, 
"ldap_parse_page_control() failed");
+            if (rc != LDAP_CONTROL_NOT_FOUND)
+              myldap_err(LOG_WARNING, search->session->ld, rc, 
"ldap_parse_page_control() failed");
             /* clear error flag */
             rc = LDAP_SUCCESS;
             if (ldap_set_option(search->session->ld, LDAP_OPT_ERROR_NUMBER,

http://arthurdejong.org/git/nss-pam-ldapd/commit/?id=4f6dfdd636a6d5db649a70c781ef9b3901a1b760

commit 4f6dfdd636a6d5db649a70c781ef9b3901a1b760
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Jan 3 22:08:25 2014 +0100

    Use do_try_search() also for paged searches
    
    This also changes do_try_search() to support building continued paged
    controls and lays the groundwork for adding more search controls.

diff --git a/nslcd/myldap.c b/nslcd/myldap.c
index 620a3b7..e2daf17 100644
--- a/nslcd/myldap.c
+++ b/nslcd/myldap.c
@@ -4,8 +4,8 @@
    which has been forked into the nss-pam-ldapd library.
 
    Copyright (C) 1997-2006 Luke Howard
-   Copyright (C) 2006, 2007 West Consulting
-   Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Arthur de Jong
+   Copyright (C) 2006-2007 West Consulting
+   Copyright (C) 2006-2014 Arthur de Jong
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -1053,9 +1053,9 @@ void myldap_get_policy_response(MYLDAP_SESSION *session, 
int *response,
 
 static int do_try_search(MYLDAP_SEARCH *search)
 {
+  int ctrlidx = 0;
   int rc;
-  LDAPControl *serverCtrls[2];
-  LDAPControl **pServerCtrls;
+  LDAPControl *serverctrls[2];
   int msgid;
   /* ensure that we have an open connection */
   rc = do_open(search->session);
@@ -1065,35 +1065,36 @@ static int do_try_search(MYLDAP_SEARCH *search)
   if ((nslcd_cfg->pagesize > 0) && (search->scope != LDAP_SCOPE_BASE))
   {
     rc = ldap_create_page_control(search->session->ld, nslcd_cfg->pagesize,
-                                  NULL, 0, &serverCtrls[0]);
+                                  search->cookie, 0, &serverctrls[ctrlidx]);
     if (rc == LDAP_SUCCESS)
-    {
-      serverCtrls[1] = NULL;
-      pServerCtrls = serverCtrls;
-    }
+      ctrlidx++;
     else
     {
       myldap_err(LOG_WARNING, search->session->ld, rc,
                  "ldap_create_page_control() failed");
-      /* clear error flag */
-      rc = LDAP_SUCCESS;
-      if (ldap_set_option(search->session->ld, LDAP_OPT_ERROR_NUMBER, &rc) != 
LDAP_SUCCESS)
-        log_log(LOG_WARNING, "failed to clear the error flag");
-      pServerCtrls = NULL;
+      serverctrls[ctrlidx] = NULL;
+      /* if we were paging, failure building the second control is fatal */
+      if (search->cookie != NULL)
+        return rc;
     }
   }
-  else
-    pServerCtrls = NULL;
+  /* NULL terminate control list */
+  serverctrls[ctrlidx] = NULL;
+  /* clear error flag (perhaps control setting failed) */
+  if (ctrlidx > 0)
+  {
+    rc = LDAP_SUCCESS;
+    if (ldap_set_option(search->session->ld, LDAP_OPT_ERROR_NUMBER, &rc) != 
LDAP_SUCCESS)
+      log_log(LOG_WARNING, "failed to clear the error flag");
+  }
   /* perform the search */
   rc = ldap_search_ext(search->session->ld, search->base, search->scope,
                        search->filter, (char **)(search->attrs),
-                       0, pServerCtrls, NULL, NULL, LDAP_NO_LIMIT, &msgid);
+                       0, serverctrls[0] == NULL ? NULL : serverctrls,
+                       NULL, NULL, LDAP_NO_LIMIT, &msgid);
   /* free the controls if we had them */
-  if (pServerCtrls != NULL)
-  {
-    ldap_control_free(serverCtrls[0]);
-    serverCtrls[0] = NULL;
-  }
+  for (ctrlidx = 0; serverctrls[ctrlidx] != NULL; ctrlidx++)
+    ldap_control_free(serverctrls[ctrlidx]);
   /* handle errors */
   if (rc != LDAP_SUCCESS)
   {
@@ -1381,10 +1382,8 @@ MYLDAP_ENTRY *myldap_get_entry(MYLDAP_SEARCH *search, 
int *rcp)
 {
   int rc;
   int parserc;
-  int msgid;
   struct timeval tv, *tvp;
   LDAPControl **resultcontrols;
-  LDAPControl *serverctrls[2];
   ber_int_t count;
   /* check parameters */
   if ((search == NULL) || (search->session == NULL) || (search->session->ld == 
NULL))
@@ -1526,29 +1525,9 @@ MYLDAP_ENTRY *myldap_get_entry(MYLDAP_SEARCH *search, 
int *rcp)
           return NULL;
         }
         /* try the next page */
-        serverctrls[0] = NULL;
-        serverctrls[1] = NULL;
-        rc = ldap_create_page_control(search->session->ld, nslcd_cfg->pagesize,
-                                      search->cookie, 0, &serverctrls[0]);
-        if (rc != LDAP_SUCCESS)
-        {
-          if (serverctrls[0] != NULL)
-            ldap_control_free(serverctrls[0]);
-          myldap_err(LOG_WARNING, search->session->ld, rc, 
"ldap_create_page_control() failed");
-          myldap_search_close(search);
-          if (rcp != NULL)
-            *rcp = rc;
-          return NULL;
-        }
-        /* set up a new search for the next page */
-        rc = ldap_search_ext(search->session->ld,
-                             search->base, search->scope, search->filter,
-                             search->attrs, 0, serverctrls, NULL, NULL,
-                             LDAP_NO_LIMIT, &msgid);
-        ldap_control_free(serverctrls[0]);
+        rc = do_try_search(search);
         if (rc != LDAP_SUCCESS)
         {
-          myldap_err(LOG_WARNING, search->session->ld, rc, "ldap_search_ext() 
failed");
           /* close connection on connection problems */
           if ((rc == LDAP_UNAVAILABLE) || (rc == LDAP_SERVER_DOWN))
             do_close(search->session);
@@ -1557,7 +1536,6 @@ MYLDAP_ENTRY *myldap_get_entry(MYLDAP_SEARCH *search, int 
*rcp)
             *rcp = rc;
           return NULL;
         }
-        search->msgid = msgid;
         /* we continue with another pass */
         break;
       case LDAP_RES_SEARCH_REFERENCE:

-----------------------------------------------------------------------

Summary of changes:
 README                            |   27 ++--
 compat/Makefile.am                |    1 +
 compat/{strndup.c => derefctrl.c} |   33 +++--
 compat/ldap_compat.h              |   13 +-
 configure.ac                      |   64 +++++++-
 nslcd/group.c                     |   40 ++++-
 nslcd/myldap.c                    |  294 ++++++++++++++++++++++++++++---------
 nslcd/myldap.h                    |    9 +-
 8 files changed, 386 insertions(+), 95 deletions(-)
 copy compat/{strndup.c => derefctrl.c} (53%)


hooks/post-receive
-- 
nss-pam-ldapd
-- 
To unsubscribe send an email to
nss-pam-ldapd-commits-unsubscribe@lists.arthurdejong.org or see
http://lists.arthurdejong.org/nss-pam-ldapd-commits/