lists.arthurdejong.org
RSS feed

nss-pam-ldapd branch master updated. 0.9.7-19-g43862ba

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

nss-pam-ldapd branch master updated. 0.9.7-19-g43862ba



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  43862ba26cf97aaa62b54651ec1624aee44ac17a (commit)
       via  5141b09d0a6eb023725183528302de096ac25070 (commit)
       via  0cafb084aa05368daa2e69ccf42540643bc36bb7 (commit)
       via  9564dd0c2de567efd4a5fe2b0de796f7e5f135f7 (commit)
       via  f72aaa2b11d691e47d1c80e2ac6f0da7007a4385 (commit)
       via  5d11cb864777d8319d0c1005a72165a282a2f69b (commit)
       via  bcc3a0829c75078f3d1aa92c6e1297a94f924f2c (commit)
      from  ebc0f7673000e8681ea3d4d7a81bf2cd8c3be509 (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 -----------------------------------------------------------------
https://arthurdejong.org/git/nss-pam-ldapd/commit/?id=43862ba26cf97aaa62b54651ec1624aee44ac17a

commit 43862ba26cf97aaa62b54651ec1624aee44ac17a
Merge: ebc0f76 5141b09
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Thu Jun 15 23:12:04 2017 +0200

    Add pam_authc_search option
    
    This option can be used to configure the search operation that should be
    performed after authentication.


https://arthurdejong.org/git/nss-pam-ldapd/commit/?id=5141b09d0a6eb023725183528302de096ac25070

commit 5141b09d0a6eb023725183528302de096ac25070
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Thu Jun 15 22:05:11 2017 +0200

    Allow skipping post-authentication search altogether

diff --git a/man/nslcd.conf.5.xml b/man/nslcd.conf.5.xml
index 605263b..c373ca5 100644
--- a/man/nslcd.conf.5.xml
+++ b/man/nslcd.conf.5.xml
@@ -845,6 +845,13 @@
         The value <literal>BASE</literal> may be used to force the default
         search for the user DN.
       </para>
+      <para>
+        The value <literal>NONE</literal> may be used to indicate that no
+        search should be performed after BIND.
+        Note that some <acronym>LDAP</acronym> servers do not always return a
+        correct error code as a result of a failed BIND operation (e.g. when
+        an empty password is supplied).
+      </para>
      </listitem>
     </varlistentry>
 
diff --git a/nslcd/pam.c b/nslcd/pam.c
index 6c27bb8..7772959 100644
--- a/nslcd/pam.c
+++ b/nslcd/pam.c
@@ -203,7 +203,7 @@ static int try_bind(const char *userdn, const char 
*password,
           rc = LDAP_NO_RESULTS_RETURNED;
       }
     }
-    else
+    else if (strcasecmp(nslcd_cfg->pam_authc_search, "NONE") != 0)
     {
       /* build the search filter */
       dict = search_vars_new(userdn, username, service, ruser, rhost, tty);

https://arthurdejong.org/git/nss-pam-ldapd/commit/?id=0cafb084aa05368daa2e69ccf42540643bc36bb7

commit 0cafb084aa05368daa2e69ccf42540643bc36bb7
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Wed Jun 14 23:50:46 2017 +0200

    Implement myldap_bind() function
    
    This function integrates the myldap_set_credentials() and
    myldap_get_policy_response() and performs the bind operation witout
    actually performing a search.
    
    The function performs a "fake" search that returns after performing the
    LDAP BIND operation.
    
    This replaces a number of dummy search operations that were there to
    ensure that the connection was open. This allows us to skip the search
    operation after authentication.

diff --git a/nslcd/myldap.c b/nslcd/myldap.c
index dddb0d7..6b98a21 100644
--- a/nslcd/myldap.c
+++ b/nslcd/myldap.c
@@ -5,7 +5,7 @@
 
    Copyright (C) 1997-2006 Luke Howard
    Copyright (C) 2006-2007 West Consulting
-   Copyright (C) 2006-2015 Arthur de Jong
+   Copyright (C) 2006-2017 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,10 @@
 /* the maximum number of dn's to log to the debug log for each search */
 #define MAX_DEBUG_LOG_DNS 10
 
+/* a fake scope that is used to not perform an actual search but only
+   simulate the handling of the search (used for authentication) */
+#define MYLDAP_SCOPE_BINDONLY 0x1972  /* magic number: should never be a real 
scope */
+
 /* This refers to a current LDAP session that contains the connection
    information. */
 struct ldap_session {
@@ -1121,42 +1125,44 @@ static int do_open(MYLDAP_SESSION *session)
   return LDAP_SUCCESS;
 }
 
-/* Set alternative credentials for the session. */
-int myldap_set_credentials(MYLDAP_SESSION *session, const char *dn,
-                            const char *password)
+/* Perform a simple bind operation and return the ppolicy results. */
+int myldap_bind(MYLDAP_SESSION *session, const char *dn, const char *password,
+                int *response, const char **message)
 {
+  MYLDAP_SEARCH *search;
+  static const char *attrs[2];
+  int rc;
   /* error out when buffers are too small */
   if (strlen(dn) >= sizeof(session->binddn))
   {
-    log_log(LOG_ERR,
-            "myldap_set_credentials(): binddn buffer too small (%lu required)",
+    log_log(LOG_ERR, "myldap_bind(): binddn buffer too small (%lu required)",
             (unsigned long) strlen(dn));
-    return -1;
+    return LDAP_LOCAL_ERROR;
   }
   if (strlen(password) >= sizeof(session->bindpw))
   {
-    log_log(LOG_ERR,
-            "myldap_set_credentials(): bindpw buffer too small (%lu required)",
+    log_log(LOG_ERR, "myldap_bind(): bindpw buffer too small (%lu required)",
             (unsigned long) strlen(password));
-    return -1;
+    return LDAP_LOCAL_ERROR;
   }
   /* copy dn and password into session */
   strncpy(session->binddn, dn, sizeof(session->binddn));
   session->binddn[sizeof(session->binddn) - 1] = '\0';
   strncpy(session->bindpw, password, sizeof(session->bindpw));
   session->bindpw[sizeof(session->bindpw) - 1] = '\0';
-  return 0;
-}
-
-/* Get bind ppolicy results from the last bind operation. This function
-   returns a NSLCD_PAM_* code and optional message. */
-void myldap_get_policy_response(MYLDAP_SESSION *session, int *response,
-                                const char **message)
-{
+  /* construct a fake search to trigger the BIND operation */
+  attrs[0] = "dn";
+  attrs[1] = NULL;
+  search = myldap_search(session, session->binddn, MYLDAP_SCOPE_BINDONLY,
+                         "(objectClass=*)", attrs, &rc);
+  if (search != NULL)
+    myldap_search_close(search);
+  /* return ppolicy results */
   if (response != NULL)
     *response = session->policy_response;
   if (message != NULL)
     *message = session->policy_message;
+  return rc;
 }
 
 /* perform a search operation, the connection is assumed to be open */
@@ -1334,7 +1340,8 @@ static int do_retry_search(MYLDAP_SEARCH *search)
         pthread_mutex_unlock(&uris_mutex);
         /* ensure that we have an open connection and start a search */
         rc = do_open(search->session);
-        if (rc == LDAP_SUCCESS)
+        /* perform the actual search, unless we were only binding */
+        if ((rc == LDAP_SUCCESS) && (search->scope != MYLDAP_SCOPE_BINDONLY))
           rc = do_try_search(search);
         /* if we are authenticating a user and get an error regarding failed
            password we should error out instead of trying all servers */
diff --git a/nslcd/myldap.h b/nslcd/myldap.h
index e54ae52..62c9350 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-2014 Arthur de Jong
+   Copyright (C) 2007-2017 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
@@ -68,14 +68,12 @@ typedef struct myldap_entry MYLDAP_ENTRY;
    uses the configuration to find the URLs to attempt connections to. */
 MUST_USE MYLDAP_SESSION *myldap_create_session(void);
 
-/* Set alternative credentials for the session. Returns 0 on success. */
-MUST_USE int myldap_set_credentials(MYLDAP_SESSION *session, const char *dn,
-                                    const char *password);
-
-/* Get bind ppolicy results from the last bind operation. This function
-   returns a NSLCD_PAM_* code and optional message. */
-void myldap_get_policy_response(MYLDAP_SESSION *session, int *response,
-                                const char **message);
+/* Perform a simple bind operation and return the ppolicy results.
+   This function returns an LDAP status code while response is an NSLCD_PAM_*
+   code with accompanying message. */
+MUST_USE int myldap_bind(MYLDAP_SESSION *session, const char *dn,
+                         const char *password,
+                         int *response, const char **message);
 
 /* Closes all pending searches and deallocates any memory that is allocated
    with these searches. This does not close the session. */
diff --git a/nslcd/pam.c b/nslcd/pam.c
index 58be0de..6c27bb8 100644
--- a/nslcd/pam.c
+++ b/nslcd/pam.c
@@ -173,7 +173,7 @@ static int try_bind(const char *userdn, const char 
*password,
   MYLDAP_SEARCH *search;
   MYLDAP_ENTRY *entry;
   static const char *attrs[2];
-  int rc = LDAP_SUCCESS;
+  int rc;
   const char *msg;
   DICT *dict;
   char filter[BUFLEN_FILTER];
@@ -182,58 +182,55 @@ static int try_bind(const char *userdn, const char 
*password,
   session = myldap_create_session();
   if (session == NULL)
     return LDAP_UNAVAILABLE;
-  /* set up credentials for the session */
-  if (myldap_set_credentials(session, userdn, password))
-  {
-    myldap_session_close(session);
-    return LDAP_LOCAL_ERROR;
-  }
-  /* perform a search to trigger the BIND operation */
-  attrs[0] = "dn";
-  attrs[1] = NULL;
-  if (strcasecmp(nslcd_cfg->pam_authc_search, "BASE") == 0)
-  {
-    /* do a simple search to check userdn existence */
-    search = myldap_search(session, userdn, LDAP_SCOPE_BASE,
-                           "(objectClass=*)", attrs, &rc);
-    if ((search == NULL) && (rc == LDAP_SUCCESS))
-      rc = LDAP_LOCAL_ERROR;
-    if (rc == LDAP_SUCCESS)
-    {
-      entry = myldap_get_entry(search, &rc);
-      if ((entry == NULL) && (rc == LDAP_SUCCESS))
-        rc = LDAP_NO_RESULTS_RETURNED;
-    }
-  }
-  else
+  /* perform a BIND operation with user credentials */
+  rc = myldap_bind(session, userdn, password, authzrc, &msg);
+  if (rc == LDAP_SUCCESS)
   {
-    /* build the search filter */
-    dict = search_vars_new(userdn, username, service, ruser, rhost, tty);
-    if (dict == NULL)
+    /* perform a search to trigger the BIND operation */
+    attrs[0] = "dn";
+    attrs[1] = NULL;
+    if (strcasecmp(nslcd_cfg->pam_authc_search, "BASE") == 0)
     {
-      myldap_session_close(session);
-      return LDAP_LOCAL_ERROR;
+      /* do a simple search to check userdn existence */
+      search = myldap_search(session, userdn, LDAP_SCOPE_BASE,
+                             "(objectClass=*)", attrs, &rc);
+      if ((search == NULL) && (rc == LDAP_SUCCESS))
+        rc = LDAP_LOCAL_ERROR;
+      if (rc == LDAP_SUCCESS)
+      {
+        entry = myldap_get_entry(search, &rc);
+        if ((entry == NULL) && (rc == LDAP_SUCCESS))
+          rc = LDAP_NO_RESULTS_RETURNED;
+      }
     }
-    res = expr_parse(nslcd_cfg->pam_authc_search, filter, sizeof(filter),
-                     search_var_get, (void *)dict);
-    if (res == NULL)
+    else
     {
+      /* build the search filter */
+      dict = search_vars_new(userdn, username, service, ruser, rhost, tty);
+      if (dict == NULL)
+      {
+        myldap_session_close(session);
+        return LDAP_LOCAL_ERROR;
+      }
+      res = expr_parse(nslcd_cfg->pam_authc_search, filter, sizeof(filter),
+                       search_var_get, (void *)dict);
+      if (res == NULL)
+      {
+        search_vars_free(dict);
+        myldap_session_close(session);
+        log_log(LOG_ERR, "invalid pam_authc_search \"%s\"",
+                nslcd_cfg->pam_authc_search);
+        return LDAP_LOCAL_ERROR;
+      }
+      /* perform a search for each search base */
+      rc = do_searches(session, "pam_authc_search", filter);
+      /* free search variables */
       search_vars_free(dict);
-      myldap_session_close(session);
-      log_log(LOG_ERR, "invalid pam_authc_search \"%s\"",
-              nslcd_cfg->pam_authc_search);
-      return LDAP_LOCAL_ERROR;
     }
-    /* perform a search for each search base */
-    rc = do_searches(session, "pam_authc_search", filter);
-    /* free search variables */
-    search_vars_free(dict);
   }
-  /* check search result */
+  /* log any authentication, search or authorsiation messages */
   if (rc != LDAP_SUCCESS)
     log_log(LOG_WARNING, "%s: %s", userdn, ldap_err2string(rc));
-  /* get any policy response from the bind */
-  myldap_get_policy_response(session, authzrc, &msg);
   if ((msg != NULL) && (msg[0] != '\0'))
   {
     mysnprintf(authzmsg, authzmsgsz - 1, "%s", msg);
@@ -738,15 +735,9 @@ static int try_pwmod(MYLDAP_SESSION *oldsession,
   session = myldap_create_session();
   if (session == NULL)
     return LDAP_UNAVAILABLE;
-  /* set up credentials for the session */
-  if (myldap_set_credentials(session, binddn, oldpassword))
-  {
-    myldap_session_close(session);
-    return LDAP_LOCAL_ERROR;
-  }
-  /* perform search for own object (just to do any kind of search) */
-  if ((lookup_dn2uid(session, userdn, &rc, buffer, sizeof(buffer)) != NULL) &&
-      (rc == LDAP_SUCCESS))
+  /* perform a BIND operation */
+  rc = myldap_bind(session, binddn, oldpassword, NULL, NULL);
+  if (rc == LDAP_SUCCESS)
   {
     /* if doing password modification as admin, don't pass old password along 
*/
     if ((nslcd_cfg->rootpwmoddn != NULL) &&
@@ -756,16 +747,6 @@ static int try_pwmod(MYLDAP_SESSION *oldsession,
     rc = myldap_passwd(session, userdn, oldpassword, newpassword);
     if (rc == LDAP_SUCCESS)
     {
-      /* if user modifies own password, update credentials for the session */
-      if (binddn == userdn)
-        if (myldap_set_credentials(session, binddn, newpassword))
-        {
-          rc = LDAP_LOCAL_ERROR;
-          log_log(LOG_WARNING, "%s: shadowLastChange: modification failed: %s",
-                  userdn, ldap_err2string(rc));
-          myldap_session_close(session);
-          return rc;
-        }
       /* try to update the shadowLastChange attribute */
       if (update_lastchange(session, userdn) != LDAP_SUCCESS)
         /* retry with the normal session */
diff --git a/nslcd/usermod.c b/nslcd/usermod.c
index e0de4d4..ad82e7d 100644
--- a/nslcd/usermod.c
+++ b/nslcd/usermod.c
@@ -2,7 +2,7 @@
    usermod.c - routines for changing user information such as full name,
                login shell, etc
 
-   Copyright (C) 2013-2014 Arthur de Jong
+   Copyright (C) 2013-2017 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
@@ -104,11 +104,10 @@ static int is_valid_shell(const char *shell)
   return valid;
 }
 
-static MYLDAP_SESSION *get_session(const char *binddn, const char *userdn,
-                                   const char *password, int *rcp)
+static MYLDAP_SESSION *get_session(const char *binddn, const char *password,
+                                   int *rcp)
 {
   MYLDAP_SESSION *session;
-  char buffer[BUFLEN_DN];
   /* set up a new connection */
   session = myldap_create_session();
   if (session == NULL)
@@ -116,13 +115,9 @@ static MYLDAP_SESSION *get_session(const char *binddn, 
const char *userdn,
     *rcp = LDAP_UNAVAILABLE;
     return NULL;
   }
-  /* set up credentials for the session */
-  if (myldap_set_credentials(session, binddn, password))
-    return NULL;
-  /* perform search for own object (just to do any kind of search to set
-     up the connection with fail-over) */
-  if ((lookup_dn2uid(session, userdn, rcp, buffer, sizeof(buffer)) == NULL) ||
-      (*rcp != LDAP_SUCCESS))
+  /* check that we can bind */
+  *rcp = myldap_bind(session, binddn, password, NULL, NULL);
+  if (*rcp != LDAP_SUCCESS)
   {
     myldap_session_close(session);
     return NULL;
@@ -274,7 +269,7 @@ int nslcd_usermod(TFILE *fp, MYLDAP_SESSION *session, uid_t 
calleruid)
     shell = NULL;
   }
   /* perform requested changes */
-  newsession = get_session(binddn, myldap_get_dn(entry), password, &rc);
+  newsession = get_session(binddn, password, &rc);
   if (newsession != NULL)
   {
     rc = change(newsession, myldap_get_dn(entry), homedir, shell);

https://arthurdejong.org/git/nss-pam-ldapd/commit/?id=9564dd0c2de567efd4a5fe2b0de796f7e5f135f7

commit 9564dd0c2de567efd4a5fe2b0de796f7e5f135f7
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Wed Jun 14 23:17:07 2017 +0200

    Implement handling of pam_authc_search option
    
    This allows performing a different, configurable search from the default
    BASE search after the BIND operation.

diff --git a/nslcd/pam.c b/nslcd/pam.c
index 2188888..58be0de 100644
--- a/nslcd/pam.c
+++ b/nslcd/pam.c
@@ -165,14 +165,19 @@ static int do_searches(MYLDAP_SESSION *session, const 
char *option,
 /* set up a connection and try to bind with the specified DN and password,
    returns an LDAP result code */
 static int try_bind(const char *userdn, const char *password,
+                    const char *username, const char *service,
+                    const char *ruser, const char *rhost, const char *tty,
                     int *authzrc, char *authzmsg, size_t authzmsgsz)
 {
   MYLDAP_SESSION *session;
   MYLDAP_SEARCH *search;
   MYLDAP_ENTRY *entry;
   static const char *attrs[2];
-  int rc;
+  int rc = LDAP_SUCCESS;
   const char *msg;
+  DICT *dict;
+  char filter[BUFLEN_FILTER];
+  const char *res;
   /* set up a new connection */
   session = myldap_create_session();
   if (session == NULL)
@@ -183,27 +188,50 @@ static int try_bind(const char *userdn, const char 
*password,
     myldap_session_close(session);
     return LDAP_LOCAL_ERROR;
   }
-  /* perform search for own object (just to do any kind of search) */
+  /* perform a search to trigger the BIND operation */
   attrs[0] = "dn";
   attrs[1] = NULL;
-  search = myldap_search(session, userdn, LDAP_SCOPE_BASE,
-                         "(objectClass=*)", attrs, &rc);
-  if ((search == NULL) || (rc != LDAP_SUCCESS))
+  if (strcasecmp(nslcd_cfg->pam_authc_search, "BASE") == 0)
   {
-    if (rc == LDAP_SUCCESS)
+    /* do a simple search to check userdn existence */
+    search = myldap_search(session, userdn, LDAP_SCOPE_BASE,
+                           "(objectClass=*)", attrs, &rc);
+    if ((search == NULL) && (rc == LDAP_SUCCESS))
       rc = LDAP_LOCAL_ERROR;
-    log_log(LOG_WARNING, "%s: %s", userdn, ldap_err2string(rc));
+    if (rc == LDAP_SUCCESS)
+    {
+      entry = myldap_get_entry(search, &rc);
+      if ((entry == NULL) && (rc == LDAP_SUCCESS))
+        rc = LDAP_NO_RESULTS_RETURNED;
+    }
   }
   else
   {
-    entry = myldap_get_entry(search, &rc);
-    if ((entry == NULL) || (rc != LDAP_SUCCESS))
+    /* build the search filter */
+    dict = search_vars_new(userdn, username, service, ruser, rhost, tty);
+    if (dict == NULL)
     {
-      if (rc == LDAP_SUCCESS)
-        rc = LDAP_NO_RESULTS_RETURNED;
-      log_log(LOG_WARNING, "%s: %s", userdn, ldap_err2string(rc));
+      myldap_session_close(session);
+      return LDAP_LOCAL_ERROR;
     }
+    res = expr_parse(nslcd_cfg->pam_authc_search, filter, sizeof(filter),
+                     search_var_get, (void *)dict);
+    if (res == NULL)
+    {
+      search_vars_free(dict);
+      myldap_session_close(session);
+      log_log(LOG_ERR, "invalid pam_authc_search \"%s\"",
+              nslcd_cfg->pam_authc_search);
+      return LDAP_LOCAL_ERROR;
+    }
+    /* perform a search for each search base */
+    rc = do_searches(session, "pam_authc_search", filter);
+    /* free search variables */
+    search_vars_free(dict);
   }
+  /* check search result */
+  if (rc != LDAP_SUCCESS)
+    log_log(LOG_WARNING, "%s: %s", userdn, ldap_err2string(rc));
   /* get any policy response from the bind */
   myldap_get_policy_response(session, authzrc, &msg);
   if ((msg != NULL) && (msg[0] != '\0'))
@@ -450,7 +478,8 @@ int nslcd_pam_authc(TFILE *fp, MYLDAP_SESSION *session, 
uid_t calleruid)
     update_username(entry, username, sizeof(username));
   }
   /* try authentication */
-  rc = try_bind(userdn, password, &authzrc, authzmsg, sizeof(authzmsg));
+  rc = try_bind(userdn, password, username, service, ruser, rhost, tty,
+                &authzrc, authzmsg, sizeof(authzmsg));
   if (rc == LDAP_SUCCESS)
     log_log(LOG_DEBUG, "bind successful");
   /* map result code */

https://arthurdejong.org/git/nss-pam-ldapd/commit/?id=f72aaa2b11d691e47d1c80e2ac6f0da7007a4385

commit f72aaa2b11d691e47d1c80e2ac6f0da7007a4385
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Wed Jun 14 22:45:15 2017 +0200

    Document pam_authc_search option

diff --git a/man/nslcd.conf.5.xml b/man/nslcd.conf.5.xml
index 0acb1f9..605263b 100644
--- a/man/nslcd.conf.5.xml
+++ b/man/nslcd.conf.5.xml
@@ -6,7 +6,7 @@
    nslcd.conf.5.xml - docbook manual page for nslcd.conf
 
    Copyright (C) 1997-2005 Luke Howard
-   Copyright (C) 2007-2016 Arthur de Jong
+   Copyright (C) 2007-2017 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
@@ -825,6 +825,29 @@
      </listitem>
     </varlistentry>
 
+    <varlistentry id="pam_authc_search"> <!-- since 0.9.8 -->
+     <term><option>pam_authc_search</option>
+           <replaceable>FILTER</replaceable></term>
+     <listitem>
+      <para>
+       By default <command>nslcd</command> performs an
+       <acronym>LDAP</acronym> search with the user's credentials after BIND
+       (authentication) to ensure that the BIND operation was successful.
+       The default search is a simple check to see if the user's DN exists.
+      </para>
+      <para>
+        A search filter can be specified that will be used instead.
+        The same substitutions as with the <option>pam_authz_search</option>
+        option will be performed and the search should at least return one
+        entry.
+      </para>
+      <para>
+        The value <literal>BASE</literal> may be used to force the default
+        search for the user DN.
+      </para>
+     </listitem>
+    </varlistentry>
+
     <varlistentry id="pam_authz_search"> <!-- since 0.7.4 -->
      <term><option>pam_authz_search</option>
            <replaceable>FILTER</replaceable></term>

https://arthurdejong.org/git/nss-pam-ldapd/commit/?id=5d11cb864777d8319d0c1005a72165a282a2f69b

commit 5d11cb864777d8319d0c1005a72165a282a2f69b
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Wed Jun 14 22:42:20 2017 +0200

    Add pam_authc_search option parsing

diff --git a/nslcd/cfg.c b/nslcd/cfg.c
index c24d79a..2b832e2 100644
--- a/nslcd/cfg.c
+++ b/nslcd/cfg.c
@@ -5,7 +5,7 @@
 
    Copyright (C) 1997-2005 Luke Howard
    Copyright (C) 2007 West Consulting
-   Copyright (C) 2007-2015 Arthur de Jong
+   Copyright (C) 2007-2017 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
@@ -989,31 +989,19 @@ static void handle_validnames(const char *filename, int 
lnr,
   free(value);
 }
 
-static void handle_pam_authz_search(
+static void check_search_variables(
                 const char *filename, int lnr,
-                const char *keyword, char *line, struct ldap_config *cfg)
+                const char *expression)
 {
   SET *set;
   const char **list;
   int i;
-  check_argumentcount(filename, lnr, keyword, (line != NULL) && (*line != 
'\0'));
-  /* find free spot for search filter */
-  for (i = 0; (i < NSS_LDAP_CONFIG_MAX_AUTHZ_SEARCHES) && 
(cfg->pam_authz_searches[i] != NULL);
-       i++)
-    /* nothing */ ;
-  if (i >= NSS_LDAP_CONFIG_MAX_AUTHZ_SEARCHES)
-  {
-    log_log(LOG_ERR, "%s:%d: maximum number of pam_authz_search options (%d) 
exceeded",
-            filename, lnr, NSS_LDAP_CONFIG_MAX_AUTHZ_SEARCHES);
-    exit(EXIT_FAILURE);
-  }
-  cfg->pam_authz_searches[i] = xstrdup(line);
-  /* check the variables used in the expression */
-  set = expr_vars(cfg->pam_authz_searches[i], NULL);
+  set = expr_vars(expression, NULL);
   list = set_tolist(set);
   if (list == NULL)
   {
-    log_log(LOG_CRIT, "malloc() failed to allocate memory");
+    log_log(LOG_CRIT,
+            "check_search_variables(): malloc() failed to allocate memory");
     exit(EXIT_FAILURE);
   }
   for (i = 0; list[i] != NULL; i++)
@@ -1025,7 +1013,8 @@ static void handle_pam_authz_search(
         (strcmp(list[i], "tty") != 0) &&
         (strcmp(list[i], "hostname") != 0) &&
         (strcmp(list[i], "fqdn") != 0) &&
-        (strcmp(list[i], "dn") != 0) && (strcmp(list[i], "uid") != 0))
+        (strcmp(list[i], "dn") != 0) &&
+        (strcmp(list[i], "uid") != 0))
     {
       log_log(LOG_ERR, "%s:%d: unknown variable $%s", filename, lnr, list[i]);
       exit(EXIT_FAILURE);
@@ -1036,6 +1025,37 @@ static void handle_pam_authz_search(
   free(list);
 }
 
+static void handle_pam_authc_search(
+                const char *filename, int lnr,
+                const char *keyword, char *line, struct ldap_config *cfg)
+{
+  check_argumentcount(filename, lnr, keyword, (line != NULL) && (*line != 
'\0'));
+  cfg->pam_authc_search = xstrdup(line);
+  /* check the variables used in the expression */
+  check_search_variables(filename, lnr, cfg->pam_authc_search);
+}
+
+static void handle_pam_authz_search(
+                const char *filename, int lnr,
+                const char *keyword, char *line, struct ldap_config *cfg)
+{
+  int i;
+  check_argumentcount(filename, lnr, keyword, (line != NULL) && (*line != 
'\0'));
+  /* find free spot for search filter */
+  for (i = 0; (i < NSS_LDAP_CONFIG_MAX_AUTHZ_SEARCHES) && 
(cfg->pam_authz_searches[i] != NULL);
+       i++)
+    /* nothing */ ;
+  if (i >= NSS_LDAP_CONFIG_MAX_AUTHZ_SEARCHES)
+  {
+    log_log(LOG_ERR, "%s:%d: maximum number of pam_authz_search options (%d) 
exceeded",
+            filename, lnr, NSS_LDAP_CONFIG_MAX_AUTHZ_SEARCHES);
+    exit(EXIT_FAILURE);
+  }
+  cfg->pam_authz_searches[i] = xstrdup(line);
+  /* check the variables used in the expression */
+  check_search_variables(filename, lnr, cfg->pam_authz_searches[i]);
+}
+
 static void handle_pam_password_prohibit_message(
                 const char *filename, int lnr,
                 const char *keyword, char *line, struct ldap_config *cfg)
@@ -1227,6 +1247,7 @@ static void cfg_defaults(struct ldap_config *cfg)
                     "/^[a-z0-9._@$()]([a-z0-9._@$() 
\\~-]*[a-z0-9._@$()~-])?$/i",
                     cfg);
   cfg->ignorecase = 0;
+  cfg->pam_authc_search = "BASE";
   for (i = 0; i < NSS_LDAP_CONFIG_MAX_AUTHZ_SEARCHES; i++)
     cfg->pam_authz_searches[i] = NULL;
   cfg->pam_password_prohibit_message = NULL;
@@ -1578,6 +1599,10 @@ static void cfg_read(const char *filename, struct 
ldap_config *cfg)
       cfg->ignorecase = get_boolean(filename, lnr, keyword, &line);
       get_eol(filename, lnr, keyword, &line);
     }
+    else if (strcasecmp(keyword, "pam_authc_search") == 0)
+    {
+      handle_pam_authc_search(filename, lnr, keyword, line, cfg);
+    }
     else if (strcasecmp(keyword, "pam_authz_search") == 0)
     {
       handle_pam_authz_search(filename, lnr, keyword, line, cfg);
@@ -1844,6 +1869,7 @@ static void cfg_dump(void)
   log_log(LOG_DEBUG, "CFG: nss_disable_enumeration %s", 
print_boolean(nslcd_cfg->nss_disable_enumeration));
   log_log(LOG_DEBUG, "CFG: validnames %s", nslcd_cfg->validnames_str);
   log_log(LOG_DEBUG, "CFG: ignorecase %s", 
print_boolean(nslcd_cfg->ignorecase));
+  log_log(LOG_DEBUG, "CFG: pam_authc_search %s", nslcd_cfg->pam_authc_search);
   for (i = 0; i < NSS_LDAP_CONFIG_MAX_AUTHZ_SEARCHES; i++)
     if (nslcd_cfg->pam_authz_searches[i] != NULL)
       log_log(LOG_DEBUG, "CFG: pam_authz_search %s", 
nslcd_cfg->pam_authz_searches[i]);
diff --git a/nslcd/cfg.h b/nslcd/cfg.h
index 8e39705..652185e 100644
--- a/nslcd/cfg.h
+++ b/nslcd/cfg.h
@@ -5,7 +5,7 @@
 
    Copyright (C) 1997-2005 Luke Howard
    Copyright (C) 2007 West Consulting
-   Copyright (C) 2007-2015 Arthur de Jong
+   Copyright (C) 2007-2017 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
@@ -130,6 +130,7 @@ struct ldap_config {
   regex_t validnames; /* the regular expression to determine valid names */
   char *validnames_str; /* string version of validnames regexp */
   int ignorecase; /* whether or not case should be ignored in lookups */
+  char *pam_authc_search; /* the search that should be performed 
post-authentication */
   char *pam_authz_searches[NSS_LDAP_CONFIG_MAX_AUTHZ_SEARCHES]; /* the 
searches that should be performed to do autorisation checks */
   char *pam_password_prohibit_message;   /* whether password changing should 
be denied and user prompted with this message */
   char reconnect_invalidate[LM_NONE];  /* set to 1 if the corresponding map 
should be invalidated */
diff --git a/nslcd/pam.c b/nslcd/pam.c
index 8f0dfbe..2188888 100644
--- a/nslcd/pam.c
+++ b/nslcd/pam.c
@@ -80,7 +80,7 @@ static DICT *search_vars_new(const char *dn, const char 
*username,
     return NULL;
   }
   /* NOTE: any variables added here also need to be added to
-           cfg.c:handle_pam_authz_search() */
+           cfg.c:check_search_variables() */
   search_var_add(dict, "username", username);
   search_var_add(dict, "service", service);
   search_var_add(dict, "ruser", ruser);

https://arthurdejong.org/git/nss-pam-ldapd/commit/?id=bcc3a0829c75078f3d1aa92c6e1297a94f924f2c

commit bcc3a0829c75078f3d1aa92c6e1297a94f924f2c
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Wed Jun 14 21:33:37 2017 +0200

    Reorganise PAM search var building functions
    
    This moves the autzsearch_var_add(), autzsearch_vars_free(),
    autzsearch_var_get() and do_autzsearches() functions to the top of the
    file using more generic names and introduces search_vars_new() in
    prepartion of other similar searches.
    
    This also renames the remaining authzsearch functions to authz_search to
    be consistent with the pam_authz_search option.

diff --git a/nslcd/pam.c b/nslcd/pam.c
index 6184ec2..8f0dfbe 100644
--- a/nslcd/pam.c
+++ b/nslcd/pam.c
@@ -2,7 +2,7 @@
    pam.c - pam processing routines
 
    Copyright (C) 2009 Howard Chu
-   Copyright (C) 2009-2014 Arthur de Jong
+   Copyright (C) 2009-2017 Arthur de Jong
    Copyright (C) 2015 Nokia Solutions and Networks
 
    This library is free software; you can redistribute it and/or
@@ -40,6 +40,128 @@
 #include "common/dict.h"
 #include "common/expr.h"
 
+static void search_var_add(DICT *dict, const char *name, const char *value)
+{
+  size_t sz;
+  char *escaped_value;
+  /* allocate memory for escaped string */
+  sz = ((strlen(value) + 8) * 120) / 100;
+  escaped_value = (char *)malloc(sz);
+  if (escaped_value == NULL)
+  {
+    log_log(LOG_CRIT, "search_var_add(): malloc() failed to allocate memory");
+    return;
+  }
+  /* perform escaping of the value */
+  if (myldap_escape(value, escaped_value, sz))
+  {
+    log_log(LOG_ERR, "search_var_add(): escaped_value buffer too small");
+    free(escaped_value);
+    return;
+  }
+  /* add to dict */
+  dict_put(dict, name, escaped_value);
+}
+
+/* build a dictionary with variables that can be used in searches */
+static DICT *search_vars_new(const char *dn, const char *username,
+                             const char *service, const char *ruser,
+                             const char *rhost, const char *tty)
+{
+  char hostname[BUFLEN_HOSTNAME];
+  /* allocating this on the stack is OK because search_var_add()
+     will allocate new memory for the value */
+  const char *fqdn;
+  DICT *dict;
+  dict = dict_new();
+  if (dict == NULL)
+  {
+    log_log(LOG_CRIT, "search_vars_new(): dict_new() failed to allocate 
memory");
+    return NULL;
+  }
+  /* NOTE: any variables added here also need to be added to
+           cfg.c:handle_pam_authz_search() */
+  search_var_add(dict, "username", username);
+  search_var_add(dict, "service", service);
+  search_var_add(dict, "ruser", ruser);
+  search_var_add(dict, "rhost", rhost);
+  search_var_add(dict, "tty", tty);
+  if (gethostname(hostname, sizeof(hostname)) == 0)
+    search_var_add(dict, "hostname", hostname);
+  if ((fqdn = getfqdn()) != NULL)
+    search_var_add(dict, "fqdn", fqdn);
+  search_var_add(dict, "dn", dn);
+  search_var_add(dict, "uid", username);
+  return dict;
+}
+
+static void search_vars_free(DICT *dict)
+{
+  int i;
+  const char **keys;
+  void *value;
+  /* go over all keys and free all the values
+     (they were allocated in search_var_add) */
+  /* loop over dictionary contents */
+  keys = dict_keys(dict);
+  for (i = 0; keys[i] != NULL; i++)
+  {
+    value = dict_get(dict, keys[i]);
+    if (value)
+      free(value);
+  }
+  free(keys);
+  /* after this values from the dict should obviously no longer be used */
+  dict_free(dict);
+}
+
+static const char *search_var_get(const char *name, void *expander_attr)
+{
+  DICT *dict = (DICT *)expander_attr;
+  return (const char *)dict_get(dict, name);
+  /* TODO: if not set use entry to get attribute name (entry can be an
+           element in the dict) */
+}
+
+/* search all search bases using the provided filter */
+static int do_searches(MYLDAP_SESSION *session, const char *option,
+                       const char *filter)
+{
+  int i;
+  int rc;
+  const char *base;
+  static const char *attrs[2];
+  MYLDAP_SEARCH *search;
+  MYLDAP_ENTRY *entry;
+  /* prepare the search */
+  attrs[0] = "dn";
+  attrs[1] = NULL;
+  /* perform a search for each search base */
+  log_log(LOG_DEBUG, "trying %s \"%s\"", option, filter);
+  for (i = 0; (base = nslcd_cfg->bases[i]) != NULL; i++)
+  {
+    /* do the LDAP search */
+    search = myldap_search(session, base, LDAP_SCOPE_SUBTREE, filter, attrs, 
&rc);
+    if (search == NULL)
+    {
+      log_log(LOG_ERR, "%s \"%s\" failed: %s",
+              option, filter, ldap_err2string(rc));
+      return rc;
+    }
+    /* try to get an entry */
+    entry = myldap_get_entry(search, &rc);
+    if (entry != NULL)
+    {
+      log_log(LOG_DEBUG, "%s found \"%s\"", option, myldap_get_dn(entry));
+      return LDAP_SUCCESS;
+    }
+  }
+  log_log(LOG_ERR, "%s \"%s\" found no matches", option, filter);
+  if (rc == LDAP_SUCCESS)
+    rc = LDAP_NO_SUCH_OBJECT;
+  return rc;
+}
+
 /* set up a connection and try to bind with the specified DN and password,
    returns an LDAP result code */
 static int try_bind(const char *userdn, const char *password,
@@ -352,103 +474,12 @@ int nslcd_pam_authc(TFILE *fp, MYLDAP_SESSION *session, 
uid_t calleruid)
   return 0;
 }
 
-static void autzsearch_var_add(DICT *dict, const char *name,
-                               const char *value)
-{
-  size_t sz;
-  char *escaped_value;
-  /* allocate memory for escaped string */
-  sz = ((strlen(value) + 8) * 120) / 100;
-  escaped_value = (char *)malloc(sz);
-  if (escaped_value == NULL)
-  {
-    log_log(LOG_CRIT, "autzsearch_var_add(): malloc() failed to allocate 
memory");
-    return;
-  }
-  /* perform escaping of the value */
-  if (myldap_escape(value, escaped_value, sz))
-  {
-    log_log(LOG_ERR, "autzsearch_var_add(): escaped_value buffer too small");
-    free(escaped_value);
-    return;
-  }
-  /* add to dict */
-  dict_put(dict, name, escaped_value);
-}
-
-static void autzsearch_vars_free(DICT *dict)
-{
-  int i;
-  const char **keys;
-  void *value;
-  /* go over all keys and free all the values
-     (they were allocated in autzsearch_var_add) */
-  /* loop over dictionary contents */
-  keys = dict_keys(dict);
-  for (i = 0; keys[i] != NULL; i++)
-  {
-    value = dict_get(dict, keys[i]);
-    if (value)
-      free(value);
-  }
-  free(keys);
-  /* after this values from the dict should obviously no longer be used */
-}
-
-static const char *autzsearch_var_get(const char *name, void *expander_attr)
-{
-  DICT *dict = (DICT *)expander_attr;
-  return (const char *)dict_get(dict, name);
-  /* TODO: if not set use entry to get attribute name (entry can be an
-           element in the dict) */
-}
-
-/* search all search bases using the provided filter */
-static int do_autzsearches(MYLDAP_SESSION *session, const char *filter)
-{
-  int i;
-  int rc;
-  const char *base;
-  static const char *attrs[2];
-  MYLDAP_SEARCH *search;
-  MYLDAP_ENTRY *entry;
-  /* prepare the search */
-  attrs[0] = "dn";
-  attrs[1] = NULL;
-  /* perform a search for each search base */
-  log_log(LOG_DEBUG, "trying pam_authz_search \"%s\"", filter);
-  for (i = 0; (base = nslcd_cfg->bases[i]) != NULL; i++)
-  {
-    /* do the LDAP search */
-    search = myldap_search(session, base, LDAP_SCOPE_SUBTREE, filter, attrs, 
&rc);
-    if (search == NULL)
-    {
-      log_log(LOG_ERR, "pam_authz_search \"%s\" failed: %s",
-              filter, ldap_err2string(rc));
-      return rc;
-    }
-    /* try to get an entry */
-    entry = myldap_get_entry(search, &rc);
-    if (entry != NULL)
-    {
-      log_log(LOG_DEBUG, "pam_authz_search found \"%s\"", 
myldap_get_dn(entry));
-      return LDAP_SUCCESS;
-    }
-  }
-  log_log(LOG_ERR, "pam_authz_search \"%s\" found no matches", filter);
-  if (rc == LDAP_SUCCESS)
-    rc = LDAP_NO_SUCH_OBJECT;
-  return rc;
-}
-
 /* perform an authorisation search, returns an LDAP status code */
-static int try_autzsearch(MYLDAP_SESSION *session, const char *dn,
-                          const char *username, const char *servicename,
+static int try_authz_search(MYLDAP_SESSION *session, const char *dn,
+                          const char *username, const char *service,
                           const char *ruser, const char *rhost,
                           const char *tty)
 {
-  char hostname[BUFLEN_HOSTNAME];
-  const char *fqdn;
   DICT *dict = NULL;
   char filter[BUFLEN_FILTER];
   int rc = LDAP_SUCCESS;
@@ -459,45 +490,29 @@ static int try_autzsearch(MYLDAP_SESSION *session, const 
char *dn,
   {
     if (dict == NULL)
     {
-      /* build the dictionary with variables
-         NOTE: any variables added here also need to be added to
-               cfg.c:parse_pam_authz_search_statement() */
-      dict = dict_new();
-      autzsearch_var_add(dict, "username", username);
-      autzsearch_var_add(dict, "service", servicename);
-      autzsearch_var_add(dict, "ruser", ruser);
-      autzsearch_var_add(dict, "rhost", rhost);
-      autzsearch_var_add(dict, "tty", tty);
-      if (gethostname(hostname, sizeof(hostname)) == 0)
-        autzsearch_var_add(dict, "hostname", hostname);
-      if ((fqdn = getfqdn()) != NULL)
-        autzsearch_var_add(dict, "fqdn", fqdn);
-      autzsearch_var_add(dict, "dn", dn);
-      autzsearch_var_add(dict, "uid", username);
+      dict = search_vars_new(dn, username, service, ruser, rhost, tty);
+      if (dict == NULL)
+        return LDAP_LOCAL_ERROR;
     }
     /* build the search filter */
     res = expr_parse(nslcd_cfg->pam_authz_searches[i],
                      filter, sizeof(filter),
-                     autzsearch_var_get, (void *)dict);
+                     search_var_get, (void *)dict);
     if (res == NULL)
     {
-      autzsearch_vars_free(dict);
-      dict_free(dict);
+      search_vars_free(dict);
       log_log(LOG_ERR, "invalid pam_authz_search \"%s\"",
               nslcd_cfg->pam_authz_searches[i]);
       return LDAP_LOCAL_ERROR;
     }
     /* perform the actual searches on all bases */
-    rc = do_autzsearches(session, filter);
+    rc = do_searches(session, "pam_authz_search", filter);
     if (rc != LDAP_SUCCESS)
       break;
   }
   /* we went over all pam_authz_search entries */
   if (dict != NULL)
-  {
-    autzsearch_vars_free(dict);
-    dict_free(dict);
-  }
+    search_vars_free(dict);
   return rc;
 }
 
@@ -535,7 +550,7 @@ int nslcd_pam_authz(TFILE *fp, MYLDAP_SESSION *session)
     return -1;
   }
   /* check authorisation search */
-  rc = try_autzsearch(session, myldap_get_dn(entry), username, service, ruser,
+  rc = try_authz_search(session, myldap_get_dn(entry), username, service, 
ruser,
                       rhost, tty);
   if (rc != LDAP_SUCCESS)
   {
diff --git a/pynslcd/pam.py b/pynslcd/pam.py
index 43d6a91..76e90a4 100644
--- a/pynslcd/pam.py
+++ b/pynslcd/pam.py
@@ -215,7 +215,7 @@ class PAMAuthorisationRequest(PAMRequest):
         self.fp.write_string(msg)
         self.fp.write_int32(constants.NSLCD_RESULT_END)
 
-    def check_authzsearch(self, parameters):
+    def check_authz_search(self, parameters):
         if not cfg.pam_authz_searches:
             return
         # escape all parameters
@@ -243,7 +243,7 @@ class PAMAuthorisationRequest(PAMRequest):
         self.validate(parameters)
         # check authorisation search
         try:
-            self.check_authzsearch(parameters)
+            self.check_authz_search(parameters)
         except StopIteration:
             self.write(constants.NSLCD_PAM_PERM_DENIED,
                        'LDAP authorisation check failed')

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

Summary of changes:
 man/nslcd.conf.5.xml |  32 ++++-
 nslcd/cfg.c          |  64 +++++++---
 nslcd/cfg.h          |   3 +-
 nslcd/myldap.c       |  45 ++++---
 nslcd/myldap.h       |  16 ++-
 nslcd/pam.c          | 349 +++++++++++++++++++++++++++------------------------
 nslcd/usermod.c      |  19 ++-
 pynslcd/pam.py       |   4 +-
 8 files changed, 307 insertions(+), 225 deletions(-)


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