lists.arthurdejong.org
RSS feed

nss-pam-ldapd branch master updated. 0.8.12-99-gf56f926

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

nss-pam-ldapd branch master updated. 0.8.12-99-gf56f926



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  f56f9267469fe6556fc946036db003b5ca85a7eb (commit)
       via  5fce062a92b4838d976a412f88781ca12168ff77 (commit)
       via  37151df22e5cdf31c92b15157fe8a18e061ee2fb (commit)
       via  1c2ab50ab32ca1ececeba7bd45429a3bee1a8d05 (commit)
       via  f2c49e6ac286174584dceeaf8552d3cef45f94d7 (commit)
      from  117327e5e97ac87d64e4fb0809141d9f40665d7b (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=f56f9267469fe6556fc946036db003b5ca85a7eb

commit f56f9267469fe6556fc946036db003b5ca85a7eb
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Mar 1 22:38:57 2013 +0100

    return the password policy bind information via PAM

diff --git a/nslcd/myldap.c b/nslcd/myldap.c
index db58e9a..c564f4b 100644
--- a/nslcd/myldap.c
+++ b/nslcd/myldap.c
@@ -1037,6 +1037,17 @@ void myldap_set_credentials(MYLDAP_SESSION *session, 
const char *dn,
   session->bindpw[sizeof(session->bindpw) - 1] = '\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)
+{
+  if (response != NULL)
+    *response = session->policy_response;
+  if (message != NULL)
+    *message = session->policy_message;
+}
+
 static int do_try_search(MYLDAP_SEARCH *search)
 {
   int rc;
diff --git a/nslcd/myldap.h b/nslcd/myldap.h
index b2ae841..9367b43 100644
--- a/nslcd/myldap.h
+++ b/nslcd/myldap.h
@@ -72,6 +72,11 @@ MUST_USE MYLDAP_SESSION *myldap_create_session(void);
 void 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);
+
 /* Closes all pending searches and deallocates any memory that is allocated
    with these searches. This does not close the session. */
 void myldap_session_cleanup(MYLDAP_SESSION *session);
diff --git a/nslcd/pam.c b/nslcd/pam.c
index 40e0069..bdd8729 100644
--- a/nslcd/pam.c
+++ b/nslcd/pam.c
@@ -41,13 +41,15 @@
 
 /* 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)
+static int try_bind(const char *userdn, const char *password,
+                    int *authzrc, char *authzmsg, size_t authzmsgsz)
 {
   MYLDAP_SESSION *session;
   MYLDAP_SEARCH *search;
   MYLDAP_ENTRY *entry;
   static const char *attrs[2];
   int rc;
+  const char *msg;
   /* set up a new connection */
   session = myldap_create_session();
   if (session == NULL)
@@ -75,6 +77,13 @@ static int try_bind(const char *userdn, const char *password)
       log_log(LOG_WARNING, "%s: lookup failed: %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);
+    log_log(LOG_WARNING, "%s: %s", userdn, authzmsg);
+  }
   /* close the session */
   myldap_session_close(session);
   /* return results */
@@ -311,7 +320,7 @@ 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);
+  rc = try_bind(userdn, password, &authzrc, authzmsg, sizeof(authzmsg));
   if (rc == LDAP_SUCCESS)
     log_log(LOG_DEBUG, "bind successful");
   /* map result code */
@@ -322,7 +331,7 @@ int nslcd_pam_authc(TFILE *fp, MYLDAP_SESSION *session, 
uid_t calleruid)
     default:                       rc = NSLCD_PAM_AUTH_ERR;
   }
   /* perform shadow attribute checks */
-  if (*username != '\0')
+  if ((*username != '\0') && (authzrc == NSLCD_PAM_SUCCESS))
     authzrc = check_shadow(session, username, authzmsg, sizeof(authzmsg), 1, 
0);
   /* write response */
   WRITE_INT32(fp, NSLCD_RESULT_BEGIN);

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

commit 5fce062a92b4838d976a412f88781ca12168ff77
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Jan 4 22:38:33 2013 +0100

    provide a basic replacement implementation of ldap_passwordpolicy_err2txt() 
for systems that don't have it

diff --git a/compat/Makefile.am b/compat/Makefile.am
index 5c8ec76..7391fee 100644
--- a/compat/Makefile.am
+++ b/compat/Makefile.am
@@ -28,7 +28,7 @@ EXTRA_DIST = getopt_long.c getopt_long.h \
              strndup.c strndup.h \
              nss_compat.h socket.h \
              ldap_compat.h pagectrl.c ldap_passwd_s.c ldap_initialize.c \
-             ldap_parse_passwordpolicy_control.c \
+             ldap_parse_passwordpolicy_control.c ldap_passwordpolicy_err2txt.c 
\
              pam_compat.h pam_get_authtok.c pam_prompt.c
 
 libcompat_a_SOURCES = getpeercred.c getpeercred.h
diff --git a/compat/ldap_compat.h b/compat/ldap_compat.h
index cf460d1..6e9c6b1 100644
--- a/compat/ldap_compat.h
+++ b/compat/ldap_compat.h
@@ -76,6 +76,10 @@ int ldap_parse_passwordpolicy_control(LDAP *ld, LDAPControl 
*ctrl,
                                       LDAPPasswordPolicyError *errorp);
 #endif /* HAVE_LDAP_PARSE_PASSWORDPOLICY_CONTROL */
 
+#ifndef HAVE_LDAP_PASSWORDPOLICY_ERR2TXT
+const char *ldap_passwordpolicy_err2txt(LDAPPasswordPolicyError error);
+#endif /* HAVE_LDAP_PASSWORDPOLICY_ERR2TXT */
+
 /* compatibility definition */
 #ifndef LDAP_SASL_QUIET
 #define LDAP_SASL_QUIET 2U
diff --git a/compat/ldap_passwordpolicy_err2txt.c 
b/compat/ldap_passwordpolicy_err2txt.c
new file mode 100644
index 0000000..09bd0ea
--- /dev/null
+++ b/compat/ldap_passwordpolicy_err2txt.c
@@ -0,0 +1,48 @@
+/*
+   ldap_passwordpolicy_err2txt.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"
+
+const char *ldap_passwordpolicy_err2txt(LDAPPasswordPolicyError error)
+{
+  switch (error)
+  {
+    case PP_passwordExpired:        return "Password expired";
+    case PP_accountLocked:          return "Account locked";
+    case PP_changeAfterReset:       return "Change after reset";
+    case PP_passwordModNotAllowed:  return "Password modification not allowed";
+    case PP_mustSupplyOldPassword:  return "Must supply old password";
+    case PP_insufficientPasswordQuality: return "Insufficient password 
quality";
+    case PP_passwordTooShort:       return "Password too short";
+    case PP_passwordTooYoung:       return "Password too young";
+    case PP_passwordInHistory:      return "Password in history";
+    case PP_noError:                return "No error";
+    default:                        return "Unknown error";
+  }
+}
diff --git a/configure.ac b/configure.ac
index 2e9fce6..b55816a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -727,6 +727,7 @@ then
   AC_REPLACE_FUNCS(ldap_passwd_s)
   AC_REPLACE_FUNCS(ldap_initialize)
   AC_REPLACE_FUNCS(ldap_parse_passwordpolicy_control)
+  AC_REPLACE_FUNCS(ldap_passwordpolicy_err2txt)
 
   # check the number of arguments that ldap_set_rebind_proc() uses
   AC_CACHE_CHECK(

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

commit 37151df22e5cdf31c92b15157fe8a18e061ee2fb
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Jan 4 22:30:47 2013 +0100

    provide a replacement implementation of ldap_parse_passwordpolicy_control() 
for systems that don't have it

diff --git a/compat/Makefile.am b/compat/Makefile.am
index 07b5d80..5c8ec76 100644
--- a/compat/Makefile.am
+++ b/compat/Makefile.am
@@ -1,6 +1,6 @@
 # Makefile.am - use automake to generate Makefile.in
 #
-# Copyright (C) 2008, 2009, 2010, 2011, 2012 Arthur de Jong
+# Copyright (C) 2008, 2009, 2010, 2011, 2012, 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
@@ -28,6 +28,7 @@ EXTRA_DIST = getopt_long.c getopt_long.h \
              strndup.c strndup.h \
              nss_compat.h socket.h \
              ldap_compat.h pagectrl.c ldap_passwd_s.c ldap_initialize.c \
+             ldap_parse_passwordpolicy_control.c \
              pam_compat.h pam_get_authtok.c pam_prompt.c
 
 libcompat_a_SOURCES = getpeercred.c getpeercred.h
diff --git a/compat/ldap_compat.h b/compat/ldap_compat.h
index 00d8af4..cf460d1 100644
--- a/compat/ldap_compat.h
+++ b/compat/ldap_compat.h
@@ -57,6 +57,25 @@ int ldap_passwd_s(LDAP *ld, struct berval *user, struct 
berval *oldpw,
                   LDAPControl **sctrls, LDAPControl **cctrls);
 #endif /* not HAVE_LDAP_PASSWD_S */
 
+#ifndef HAVE_LDAP_PARSE_PASSWORDPOLICY_CONTROL
+/* definition lifted from ldap.h */
+typedef enum passpolicyerror_enum {
+  PP_passwordExpired = 0,
+  PP_accountLocked = 1,
+  PP_changeAfterReset = 2,
+  PP_passwordModNotAllowed = 3,
+  PP_mustSupplyOldPassword = 4,
+  PP_insufficientPasswordQuality = 5,
+  PP_passwordTooShort = 6,
+  PP_passwordTooYoung = 7,
+  PP_passwordInHistory = 8,
+  PP_noError = 65535
+} LDAPPasswordPolicyError;
+int ldap_parse_passwordpolicy_control(LDAP *ld, LDAPControl *ctrl,
+                                      ber_int_t *expirep, ber_int_t *gracep,
+                                      LDAPPasswordPolicyError *errorp);
+#endif /* HAVE_LDAP_PARSE_PASSWORDPOLICY_CONTROL */
+
 /* compatibility definition */
 #ifndef LDAP_SASL_QUIET
 #define LDAP_SASL_QUIET 2U
diff --git a/compat/ldap_parse_passwordpolicy_control.c 
b/compat/ldap_parse_passwordpolicy_control.c
new file mode 100644
index 0000000..88a0d6a
--- /dev/null
+++ b/compat/ldap_parse_passwordpolicy_control.c
@@ -0,0 +1,103 @@
+/*
+   ldap_parse_passwordpolicy_control.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"
+
+#ifndef PPOLICY_WARNING
+#define PPOLICY_WARNING 160
+#endif
+#ifndef PPOLICY_ERROR
+#define PPOLICY_ERROR 129
+#endif
+#ifndef PPOLICY_EXPIRE
+#define PPOLICY_EXPIRE 128
+#endif
+#ifndef PPOLICY_GRACE
+#define PPOLICY_GRACE 129
+#endif
+
+/* based on Openldap and pam_ldap implementations */
+
+int ldap_parse_passwordpolicy_control(LDAP UNUSED(*ld), LDAPControl *ctrl,
+                                      ber_int_t *expirep, ber_int_t *gracep,
+                                      LDAPPasswordPolicyError *errorp)
+{
+  BerElement *ber;
+  ber_tag_t tag;
+  ber_len_t berLen;
+  char *last;
+  int err = PP_noError;
+  /* get a BerElement from the control */
+  ber = ber_init(&ctrl->ldctl_value);
+  if (ber == NULL)
+    return LDAP_LOCAL_ERROR;
+  /* go over tags */
+  for(tag = ber_first_element(ber, &berLen, &last); tag != LBER_DEFAULT; tag = 
ber_next_element(ber, &berLen, last))
+  {
+    switch (tag)
+    {
+      case PPOLICY_WARNING:
+        ber_skip_tag(ber, &berLen);
+        tag = ber_peek_tag(ber, &berLen);
+        switch (tag)
+        {
+          case PPOLICY_EXPIRE:
+            if (ber_get_int(ber, expirep) == LBER_DEFAULT)
+            {
+              ber_free(ber, 1);
+              return LDAP_DECODING_ERROR;
+            }
+            break;
+          case PPOLICY_GRACE:
+            if (ber_get_int(ber, gracep) == LBER_DEFAULT)
+            {
+              ber_free(ber, 1);
+              return LDAP_DECODING_ERROR;
+            }
+            break;
+          default:
+            ber_free(ber, 1);
+            return LDAP_DECODING_ERROR;
+        }
+        break;
+      case PPOLICY_ERROR:
+        if (ber_get_enum(ber, &err) == LBER_DEFAULT)
+        {
+          ber_free(ber, 1);
+          return LDAP_DECODING_ERROR;
+        }
+        break;
+      default:
+        ber_free(ber, 1);
+        return LDAP_DECODING_ERROR;
+    }
+  }
+  ber_free(ber, 1);
+  return LDAP_SUCCESS;
+}
diff --git a/configure.ac b/configure.ac
index a7d03f7..2e9fce6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -726,6 +726,7 @@ then
   # replace other ldap functions
   AC_REPLACE_FUNCS(ldap_passwd_s)
   AC_REPLACE_FUNCS(ldap_initialize)
+  AC_REPLACE_FUNCS(ldap_parse_passwordpolicy_control)
 
   # check the number of arguments that ldap_set_rebind_proc() uses
   AC_CACHE_CHECK(

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

commit 1c2ab50ab32ca1ececeba7bd45429a3bee1a8d05
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Mar 1 22:39:38 2013 +0100

    request and parse password policy controls when doing user authentication 
in nslcd

diff --git a/compat/ldap_compat.h b/compat/ldap_compat.h
index 55e75a5..00d8af4 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 Arthur de Jong
+   Copyright (C) 2009, 2010, 2012, 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
@@ -70,4 +70,18 @@ int ldap_passwd_s(LDAP *ld, struct berval *user, struct 
berval *oldpw,
 #endif /* LDAP_OPT_ERROR_STRING */
 #endif /* not LDAP_OPT_DIAGNOSTIC_MESSAGE */
 
+/* provide replacement oid definitions */
+#ifndef LDAP_CONTROL_PWEXPIRED
+#define LDAP_CONTROL_PWEXPIRED "2.16.840.1.113730.3.4.4"
+#endif /* LDAP_CONTROL_PWEXPIRED */
+#ifndef LDAP_CONTROL_PWEXPIRING
+#define LDAP_CONTROL_PWEXPIRING "2.16.840.1.113730.3.4.5"
+#endif /* LDAP_CONTROL_PWEXPIRING */
+#ifndef LDAP_CONTROL_PASSWORDPOLICYREQUEST
+#define LDAP_CONTROL_PASSWORDPOLICYREQUEST "1.3.6.1.4.1.42.2.27.8.5.1"
+#endif /* LDAP_CONTROL_PASSWORDPOLICYREQUEST */
+#ifndef LDAP_CONTROL_PASSWORDPOLICYRESPONSE
+#define LDAP_CONTROL_PASSWORDPOLICYRESPONSE "1.3.6.1.4.1.42.2.27.8.5.1"
+#endif /* LDAP_CONTROL_PASSWORDPOLICYRESPONSE */
+
 #endif /* COMPAT__LDAP_COMPAT_H */
diff --git a/configure.ac b/configure.ac
index 793d52b..a7d03f7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -704,6 +704,8 @@ then
   AC_CHECK_FUNCS(ldap_parse_result ldap_memfree ldap_controls_free 
ldap_control_free)
   AC_CHECK_FUNCS(ldap_explode_dn ldap_explode_rdn ldap_set_option 
ldap_get_option)
   AC_CHECK_FUNCS(ldap_abandon ldap_simple_bind_s ldap_unbind 
ldap_set_rebind_proc)
+  AC_CHECK_FUNCS(ldap_sasl_bind ldap_sasl_bind_s ldap_control_find)
+  AC_CHECK_FUNCS(ldap_parse_passwordpolicy_control ldap_passwordpolicy_err2txt)
   AC_CHECK_FUNCS(ldap_initialize ldap_search_ext ldap_start_tls_s)
   AC_CHECK_FUNCS(ldap_create_control ldap_extended_operation_s)
   AC_CHECK_FUNCS(ldap_domain2hostlist ldap_domain2dn)
diff --git a/nslcd/myldap.c b/nslcd/myldap.c
index 014d414..db58e9a 100644
--- a/nslcd/myldap.c
+++ b/nslcd/myldap.c
@@ -84,16 +84,20 @@
 struct ldap_session {
   /* the connection */
   LDAP *ld;
-  /* the username to bind with */
-  char binddn[256];
-  /* the password to bind with if any */
-  char bindpw[64];
   /* timestamp of last activity */
   time_t lastactivity;
   /* index into uris: currently connected LDAP uri */
   int current_uri;
   /* a list of searches registered with this session */
   struct myldap_search *searches[MAX_SEARCHES_IN_SESSION];
+  /* the username to bind with */
+  char binddn[256];
+  /* the password to bind with if any */
+  char bindpw[64];
+  /* the authentication result (NSLCD_PAM_* code) */
+  int policy_response;
+  /* the authentication message */
+  char policy_message[1024];
 };
 
 /* A search description set as returned by myldap_search(). */
@@ -305,12 +309,14 @@ static MYLDAP_SESSION *myldap_session_new(void)
   }
   /* initialize the session */
   session->ld = NULL;
-  session->binddn[0] = '\0';
-  session->bindpw[0] = '\0';
   session->lastactivity = 0;
   session->current_uri = 0;
   for (i = 0; i < MAX_SEARCHES_IN_SESSION; i++)
     session->searches[i] = NULL;
+  session->binddn[0] = '\0';
+  session->bindpw[0] = '\0';
+  session->policy_response = NSLCD_PAM_SUCCESS;
+  session->policy_message[0] = '\0';
   /* return the new session */
   return session;
 }
@@ -394,6 +400,196 @@ static int do_sasl_interact(LDAP UNUSED(*ld), unsigned 
UNUSED(flags),
     return rc;                                                              \
   }
 
+#if defined(HAVE_LDAP_SASL_BIND) && defined(LDAP_SASL_SIMPLE)
+static void handle_ppasswd_controls(MYLDAP_SESSION *session, LDAP *ld, 
LDAPControl **ctrls)
+{
+  int i;
+  int rc;
+  /* clear policy response information in session */
+  session->policy_response = NSLCD_PAM_SUCCESS;
+  strncpy(session->policy_message, "", sizeof(session->policy_message));
+  for (i = 0; ctrls[i] != NULL; i++)
+  {
+    if (strcmp(ctrls[i]->ldctl_oid, LDAP_CONTROL_PWEXPIRED) == 0)
+    {
+      /* check for expired control: force the user to change their password */
+      log_log(LOG_DEBUG, "got LDAP_CONTROL_PWEXPIRED (password expired, user 
should change)");
+      if (session->policy_response == NSLCD_PAM_SUCCESS)
+        session->policy_response = NSLCD_PAM_NEW_AUTHTOK_REQD;
+    }
+    else if (strcmp(ctrls[i]->ldctl_oid, LDAP_CONTROL_PWEXPIRING) == 0)
+    {
+      /* check for password expiration warning control: the password is about
+         to expire (returns the number of seconds remaining until the password
+         expires) */
+      char seconds[32];
+      long int sec;
+      mysnprintf(seconds, sizeof(seconds), "%.*s", 
(int)ctrls[i]->ldctl_value.bv_len,
+                 ctrls[i]->ldctl_value.bv_val);
+      sec = atol(seconds);
+      log_log(LOG_DEBUG, "got LDAP_CONTROL_PWEXPIRING (password will expire in 
%ld seconds)",
+              sec);
+      /* return this warning to PAM */
+      if (session->policy_response == NSLCD_PAM_SUCCESS)
+      {
+        session->policy_response = NSLCD_PAM_NEW_AUTHTOK_REQD;
+        mysnprintf(session->policy_message, sizeof(session->policy_message),
+                   "password will expire in %ld seconds",  sec);
+      }
+    }
+    else if (strcmp(ctrls[i]->ldctl_oid, LDAP_CONTROL_PASSWORDPOLICYRESPONSE) 
== 0)
+    {
+      /* check for password policy control */
+      int expire = 0, grace = 0;
+      LDAPPasswordPolicyError error = -1;
+      rc = ldap_parse_passwordpolicy_control(ld, ctrls[i], &expire, &grace, 
&error);
+      if (rc != LDAP_SUCCESS)
+        myldap_err(LOG_WARNING, ld, rc, "ldap_parse_passwordpolicy_control() 
failed (ignored)");
+      else
+      {
+        /* log returned control information */
+        if (error != PP_noError)
+          log_log(LOG_DEBUG, "got LDAP_CONTROL_PASSWORDPOLICYRESPONSE (%s)",
+                  ldap_passwordpolicy_err2txt(error));
+        if (expire >= 0)
+          log_log(LOG_DEBUG, "got LDAP_CONTROL_PASSWORDPOLICYRESPONSE 
(password will expire in %d seconds)",
+                  expire);
+        if (grace >= 0)
+          log_log(LOG_DEBUG, "got LDAP_CONTROL_PASSWORDPOLICYRESPONSE (%d 
grace logins left)",
+                  grace);
+        /* return this information to PAM */
+        if ((error == PP_passwordExpired) &&
+            ((session->policy_response == NSLCD_PAM_SUCCESS) ||
+             (session->policy_response == NSLCD_PAM_NEW_AUTHTOK_REQD)))
+        {
+          session->policy_response = NSLCD_PAM_AUTHTOK_EXPIRED;
+          mysnprintf(session->policy_message, sizeof(session->policy_message),
+                     "%s", ldap_passwordpolicy_err2txt(error));
+        }
+        else if ((error == PP_accountLocked) &&
+                 ((session->policy_response == NSLCD_PAM_SUCCESS) ||
+                  (session->policy_response == NSLCD_PAM_NEW_AUTHTOK_REQD)))
+        {
+          session->policy_response = NSLCD_PAM_ACCT_EXPIRED;
+          mysnprintf(session->policy_message, sizeof(session->policy_message),
+                     "%s", ldap_passwordpolicy_err2txt(error));
+        }
+        else if ((error == PP_changeAfterReset) &&
+                 (session->policy_response == NSLCD_PAM_SUCCESS))
+        {
+          session->policy_response = NSLCD_PAM_NEW_AUTHTOK_REQD;
+          mysnprintf(session->policy_message, sizeof(session->policy_message),
+                     "%s", ldap_passwordpolicy_err2txt(error));
+        }
+        else if ((error != PP_noError) &&
+                 ((session->policy_response == NSLCD_PAM_SUCCESS) ||
+                  (session->policy_response == NSLCD_PAM_NEW_AUTHTOK_REQD)))
+        {
+          session->policy_response = NSLCD_PAM_PERM_DENIED;
+          mysnprintf(session->policy_message, sizeof(session->policy_message),
+                     "%s", ldap_passwordpolicy_err2txt(error));
+        }
+        else if ((expire >= 0) &&
+                 ((session->policy_response == NSLCD_PAM_SUCCESS) ||
+                  (session->policy_response == NSLCD_PAM_NEW_AUTHTOK_REQD)))
+        {
+          session->policy_response = NSLCD_PAM_NEW_AUTHTOK_REQD;
+          mysnprintf(session->policy_message, sizeof(session->policy_message),
+                     "Password will expire in %d seconds", expire);
+        }
+        else if ((grace >= 0) &&
+                 (session->policy_response == NSLCD_PAM_SUCCESS))
+        {
+          session->policy_response = NSLCD_PAM_NEW_AUTHTOK_REQD;
+          mysnprintf(session->policy_message, sizeof(session->policy_message),
+                     "Password expired, %d grace logins left", grace);
+        }
+      }
+    }
+    /* ignore any other controls */
+  }
+}
+
+static int do_ppolicy_bind(MYLDAP_SESSION *session, LDAP *ld, const char *uri)
+{
+  int rc, parserc;
+  struct berval cred;
+  LDAPControl passwd_policy_req;
+  LDAPControl *requestctrls[2];
+  LDAPControl **responsectrls;
+  int msgid;
+  struct timeval timeout;
+  LDAPMessage *result;
+  /* build password policy request control */
+  passwd_policy_req.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
+  passwd_policy_req.ldctl_value.bv_val = NULL; /* none */
+  passwd_policy_req.ldctl_value.bv_len = 0;
+  passwd_policy_req.ldctl_iscritical = 0; /* not critical */
+  requestctrls[0] = &passwd_policy_req;
+  requestctrls[1] = NULL;
+  /* build password berval */
+  cred.bv_val = (char *)session->bindpw;
+  cred.bv_len = (session->bindpw == NULL) ? 0 : strlen(session->bindpw);
+  /* do a SASL simple bind with the binddn and bindpw */
+  log_log(LOG_DEBUG, "ldap_sasl_bind(\"%s\",%s) (uri=\"%s\")", session->binddn,
+          ((session->bindpw != NULL) && (session->bindpw[0] != '\0')) ? 
"\"***\"" : "\"\"", uri);
+  rc = ldap_sasl_bind(ld, session->binddn, LDAP_SASL_SIMPLE, &cred, 
requestctrls, NULL, &msgid);
+  if (rc != LDAP_SUCCESS)
+    return rc;
+  if (msgid == -1)
+  {
+    myldap_err(LOG_WARNING, ld, rc,"ldap_sasl_bind() failed (msgid=-1, 
uri=%s)", uri);
+    return LDAP_OPERATIONS_ERROR;
+  }
+  /* get the result from the bind operation */
+  timeout.tv_sec = nslcd_cfg->bind_timelimit;
+  timeout.tv_usec = 0;
+  result = NULL;
+  rc = ldap_result(ld, msgid, LDAP_MSG_ALL, &timeout, &result);
+  if (rc == -1) /* some error */
+  {
+    if (ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
+      rc = LDAP_UNAVAILABLE;
+    myldap_err(LOG_ERR, ld, rc, "ldap_result() failed");
+    if (result != NULL)
+      ldap_msgfree(result);
+    return LDAP_LOCAL_ERROR;
+  }
+  if (rc == 0) /* the timeout expired */
+  {
+    log_log(LOG_ERR, "ldap_result() timed out");
+    if (result != NULL)
+      ldap_msgfree(result);
+    return LDAP_TIMEOUT;
+  }
+  /* parse the result from the bind operation (frees result, get controls) */
+  responsectrls = NULL;
+  parserc = ldap_parse_result(ld, result, &rc, NULL, NULL, NULL, 
&responsectrls, 1);
+  if (parserc != LDAP_SUCCESS)
+  {
+    myldap_err(LOG_ERR, ld, parserc, "ldap_parse_result() failed");
+    if (responsectrls != NULL)
+      ldap_controls_free(responsectrls);
+    return parserc;
+  }
+  if (rc != LDAP_SUCCESS)
+  {
+    myldap_err(LOG_ERR, ld, rc, "ldap_parse_result() failed");
+    if (responsectrls != NULL)
+      ldap_controls_free(responsectrls);
+    return rc;
+  }
+  /* check the returned controls */
+  if (responsectrls != NULL)
+  {
+    handle_ppasswd_controls(session, ld, responsectrls);
+    /* free controls */
+    ldap_controls_free(responsectrls);
+  }
+  return LDAP_SUCCESS;
+}
+#endif /* no SASL, so no ppolicy */
+
 /* This function performs the authentication phase of opening a connection.
    The binddn and bindpw parameters may be used to override the authentication
    mechanism defined in the configuration.  This returns an LDAP result
@@ -424,12 +620,16 @@ static int do_bind(MYLDAP_SESSION *session, LDAP *ld, 
const char *uri)
   /* check if the binddn and bindpw are overwritten in the session */
   if ((session->binddn != NULL) && (session->binddn[0] != '\0'))
   {
+#if defined(HAVE_LDAP_SASL_BIND) && defined(LDAP_SASL_SIMPLE)
+    return do_ppolicy_bind(session, ld, uri);
+#else /* no SASL, so no ppolicy */
     /* do a simple bind */
     log_log(LOG_DEBUG, "ldap_simple_bind_s(\"%s\",%s) (uri=\"%s\")",
             session->binddn,
             ((session->bindpw != NULL) && (session->bindpw[0] != '\0')) ? 
"\"***\"" : "\"\"",
             uri);
     return ldap_simple_bind_s(ld, session->binddn, session->bindpw);
+#endif
   }
   /* perform SASL bind if requested and available on platform */
 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S

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

commit f2c49e6ac286174584dceeaf8552d3cef45f94d7
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Jan 18 20:40:54 2013 +0100

    pass the session along to the do_bind() function

diff --git a/nslcd/myldap.c b/nslcd/myldap.c
index 19407bf..014d414 100644
--- a/nslcd/myldap.c
+++ b/nslcd/myldap.c
@@ -398,8 +398,7 @@ static int do_sasl_interact(LDAP UNUSED(*ld), unsigned 
UNUSED(flags),
    The binddn and bindpw parameters may be used to override the authentication
    mechanism defined in the configuration.  This returns an LDAP result
    code. */
-static int do_bind(LDAP *ld, const char *binddn, const char *bindpw,
-                   const char *uri)
+static int do_bind(MYLDAP_SESSION *session, LDAP *ld, const char *uri)
 {
   int rc;
 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
@@ -423,12 +422,14 @@ static int do_bind(LDAP *ld, const char *binddn, const 
char *bindpw,
   }
 #endif /* LDAP_OPT_X_TLS */
   /* check if the binddn and bindpw are overwritten in the session */
-  if ((binddn != NULL) && (binddn[0] != '\0'))
+  if ((session->binddn != NULL) && (session->binddn[0] != '\0'))
   {
     /* do a simple bind */
     log_log(LOG_DEBUG, "ldap_simple_bind_s(\"%s\",%s) (uri=\"%s\")",
-            binddn, ((bindpw != NULL) && (bindpw[0] != '\0')) ? "\"***\"" : 
"\"\"", uri);
-    return ldap_simple_bind_s(ld, binddn, bindpw);
+            session->binddn,
+            ((session->bindpw != NULL) && (session->bindpw[0] != '\0')) ? 
"\"***\"" : "\"\"",
+            uri);
+    return ldap_simple_bind_s(ld, session->binddn, session->bindpw);
   }
   /* perform SASL bind if requested and available on platform */
 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
@@ -498,7 +499,7 @@ static int do_rebind(LDAP *ld, LDAP_CONST char *url,
 {
   MYLDAP_SESSION *session = (MYLDAP_SESSION *)arg;
   log_log(LOG_DEBUG, "rebinding to %s", url);
-  return do_bind(ld, session->binddn, session->bindpw, url);
+  return do_bind(session, ld, url);
 }
 #else /* not recent OpenLDAP */
 static int do_rebind(LDAP *ld, char **dnp, char **passwdp, int *authmethodp,
@@ -810,8 +811,7 @@ static int do_open(MYLDAP_SESSION *session)
   }
   /* bind to the server */
   errno = 0;
-  rc = do_bind(session->ld, session->binddn, session->bindpw,
-               nslcd_cfg->uris[session->current_uri].uri);
+  rc = do_bind(session, session->ld, 
nslcd_cfg->uris[session->current_uri].uri);
   if (rc != LDAP_SUCCESS)
   {
     /* log actual LDAP error code */

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

Summary of changes:
 compat/Makefile.am                         |    3 +-
 compat/ldap_compat.h                       |   39 +++++-
 compat/ldap_parse_passwordpolicy_control.c |  103 ++++++++++++
 compat/ldap_passwordpolicy_err2txt.c       |   48 ++++++
 configure.ac                               |    4 +
 nslcd/myldap.c                             |  239 ++++++++++++++++++++++++++--
 nslcd/myldap.h                             |    5 +
 nslcd/pam.c                                |   15 ++-
 8 files changed, 437 insertions(+), 19 deletions(-)
 create mode 100644 compat/ldap_parse_passwordpolicy_control.c
 create mode 100644 compat/ldap_passwordpolicy_err2txt.c


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/