andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone

Blame SOURCES/0069-Ticket-49327-password-expired-control-not-sent-durin.patch

6f51e1
From 3ab8a78cd27cc8d2ad7a2b322a4fe73c43a3db08 Mon Sep 17 00:00:00 2001
6f51e1
From: Mark Reynolds <mreynolds@redhat.com>
6f51e1
Date: Thu, 14 Sep 2017 15:47:53 -0400
6f51e1
Subject: [PATCH] Ticket 49327 - password expired control not sent during grace
6f51e1
 logins
6f51e1
6f51e1
Bug Description:  When a password is expired, but within the grace login limit,
6f51e1
                  we should still send the expired control even though we allowed
6f51e1
                  the bind.
6f51e1
6f51e1
Fix Description:  new_new_passwd() returned a variety of result codes that required
6f51e1
                  the caller to set the response controls.  This was hard to read and
6f51e1
                  process.  Instead I added all the controls inside the function, and
6f51e1
                  return success or failure to the caller.
6f51e1
6f51e1
https://pagure.io/389-ds-base/issue/49327
6f51e1
6f51e1
Reviewed by: gparente & tbordaz (Thanks!!)
6f51e1
6f51e1
(cherry picked from commit fbd32c4e27af9f331ee3a42dec944895a6efe2ad)
6f51e1
---
6f51e1
 ldap/servers/plugins/replication/repl_extop.c |   5 +-
6f51e1
 ldap/servers/slapd/bind.c                     |  18 +-
6f51e1
 ldap/servers/slapd/proto-slap.h               |   3 +-
6f51e1
 ldap/servers/slapd/pw_mgmt.c                  | 453 +++++++++++++-------------
6f51e1
 ldap/servers/slapd/saslbind.c                 |  20 +-
6f51e1
 5 files changed, 238 insertions(+), 261 deletions(-)
6f51e1
6f51e1
diff --git a/ldap/servers/plugins/replication/repl_extop.c b/ldap/servers/plugins/replication/repl_extop.c
6f51e1
index a39d918..96ad7dd 100644
6f51e1
--- a/ldap/servers/plugins/replication/repl_extop.c
6f51e1
+++ b/ldap/servers/plugins/replication/repl_extop.c
6f51e1
@@ -1173,8 +1173,9 @@ send_response:
6f51e1
 			 * On the supplier, we need to close the connection so
6f51e1
 			 * that the RA will restart a new session in a clear state 
6f51e1
 			 */
6f51e1
-			slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "multimaster_extop_StartNSDS50ReplicationRequest - "
6f51e1
-				"already acquired replica: disconnect conn=%d\n", connid);
6f51e1
+			slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, 
6f51e1
+			              "multimaster_extop_StartNSDS50ReplicationRequest - "
6f51e1
+			              "already acquired replica: disconnect conn=%" PRIu64 "\n", connid);
6f51e1
 			slapi_disconnect_server(conn);
6f51e1
             
6f51e1
 		}
6f51e1
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
6f51e1
index d6c7668..e6cad7f 100644
6f51e1
--- a/ldap/servers/slapd/bind.c
6f51e1
+++ b/ldap/servers/slapd/bind.c
6f51e1
@@ -673,8 +673,7 @@ do_bind( Slapi_PBlock *pb )
6f51e1
             slapi_entry_free(referral);
6f51e1
             goto free_and_return;
6f51e1
         } else if (auto_bind || rc == SLAPI_BIND_SUCCESS || rc == SLAPI_BIND_ANONYMOUS) {
6f51e1
-            long t;
6f51e1
-            char* authtype = NULL;
6f51e1
+            char *authtype = NULL;
6f51e1
             /* rc is SLAPI_BIND_SUCCESS or SLAPI_BIND_ANONYMOUS */
6f51e1
             if(auto_bind) {
6f51e1
                 rc = SLAPI_BIND_SUCCESS;
6f51e1
@@ -761,19 +760,8 @@ do_bind( Slapi_PBlock *pb )
6f51e1
                                          slapi_ch_strdup(slapi_sdn_get_ndn(sdn)),
6f51e1
                                          NULL, NULL, NULL, bind_target_entry);
6f51e1
                     if (!slapi_be_is_flag_set(be, SLAPI_BE_FLAG_REMOTE_DATA)) {
6f51e1
-                        /* check if need new password before sending 
6f51e1
-                           the bind success result */
6f51e1
-                        myrc = need_new_pw(pb, &t, bind_target_entry, pw_response_requested);
6f51e1
-                        switch (myrc) {
6f51e1
-                        case 1:
6f51e1
-                            (void)slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
-                            break;
6f51e1
-                        case 2:
6f51e1
-                            (void)slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRING, t);
6f51e1
-                            break;
6f51e1
-                        default:
6f51e1
-                            break;
6f51e1
-                        }
6f51e1
+                        /* check if need new password before sending the bind success result */
6f51e1
+                        myrc = need_new_pw(pb, bind_target_entry, pw_response_requested);
6f51e1
                     }
6f51e1
                 }
6f51e1
                 if (auth_response_requested) {
6f51e1
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
6f51e1
index 9696ead..0ba61d7 100644
6f51e1
--- a/ldap/servers/slapd/proto-slap.h
6f51e1
+++ b/ldap/servers/slapd/proto-slap.h
6f51e1
@@ -972,7 +972,7 @@ int plugin_call_acl_verify_syntax ( Slapi_PBlock *pb, Slapi_Entry *e, char **err
6f51e1
  * pw_mgmt.c
6f51e1
  */
6f51e1
 void pw_init( void );
6f51e1
-int need_new_pw( Slapi_PBlock *pb, long *t,  Slapi_Entry *e, int pwresponse_req );
6f51e1
+int need_new_pw(Slapi_PBlock *pb, Slapi_Entry *e, int pwresponse_req);
6f51e1
 int update_pw_info( Slapi_PBlock *pb , char *old_pw );
6f51e1
 int check_pw_syntax( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals, 
6f51e1
 	char **old_pw, Slapi_Entry *e, int mod_op );
6f51e1
@@ -982,7 +982,6 @@ void get_old_pw( Slapi_PBlock *pb, const Slapi_DN *sdn, char **old_pw);
6f51e1
 int check_account_lock( Slapi_PBlock *pb, Slapi_Entry * bind_target_entry, int pwresponse_req, int account_inactivation_only /*no wire/no pw policy*/);
6f51e1
 int check_pw_minage( Slapi_PBlock *pb, const Slapi_DN *sdn, struct berval **vals) ;
6f51e1
 void add_password_attrs( Slapi_PBlock *pb, Operation *op, Slapi_Entry *e );
6f51e1
-
6f51e1
 int add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e);
6f51e1
 
6f51e1
 /*
6f51e1
diff --git a/ldap/servers/slapd/pw_mgmt.c b/ldap/servers/slapd/pw_mgmt.c
6f51e1
index 7252c08..b06e3f1 100644
6f51e1
--- a/ldap/servers/slapd/pw_mgmt.c
6f51e1
+++ b/ldap/servers/slapd/pw_mgmt.c
6f51e1
@@ -22,234 +22,239 @@
6f51e1
 /* prototypes                                                               */
6f51e1
 /****************************************************************************/
6f51e1
 
6f51e1
-/* need_new_pw() is called when non rootdn bind operation succeeds with authentication */ 
6f51e1
+/*
6f51e1
+ * need_new_pw() is called when non rootdn bind operation succeeds with authentication
6f51e1
+ *
6f51e1
+ * Return  0 - password is okay
6f51e1
+ * Return -1 - password is expired, abort bind
6f51e1
+ */
6f51e1
 int
6f51e1
-need_new_pw( Slapi_PBlock *pb, long *t, Slapi_Entry *e, int pwresponse_req )
6f51e1
+need_new_pw(Slapi_PBlock *pb, Slapi_Entry *e, int pwresponse_req)
6f51e1
 {
6f51e1
-	time_t 		cur_time, pw_exp_date;
6f51e1
-	Slapi_Mods smods;
6f51e1
-	double		diff_t = 0;
6f51e1
-	char 		*cur_time_str = NULL;
6f51e1
-	char *passwordExpirationTime = NULL;
6f51e1
-	char *timestring;
6f51e1
-	char *dn;
6f51e1
-	const Slapi_DN *sdn;
6f51e1
-	passwdPolicy *pwpolicy = NULL;
6f51e1
-	int	pwdGraceUserTime = 0;
6f51e1
-	char graceUserTime[8];
6f51e1
-
6f51e1
-	if (NULL == e) {
6f51e1
-		return (-1);
6f51e1
-	}
6f51e1
-	slapi_mods_init (&smods, 0);
6f51e1
-	sdn = slapi_entry_get_sdn_const( e );
6f51e1
-	dn = slapi_entry_get_ndn( e );
6f51e1
-	pwpolicy = new_passwdPolicy(pb, dn);
6f51e1
-
6f51e1
-	/* after the user binds with authentication, clear the retry count */
6f51e1
-	if ( pwpolicy->pw_lockout == 1)
6f51e1
-	{
6f51e1
-		if(slapi_entry_attr_get_int( e, "passwordRetryCount") > 0)
6f51e1
-		{
6f51e1
-			slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordRetryCount", "0");
6f51e1
-		}
6f51e1
-	}
6f51e1
-
6f51e1
-	cur_time = current_time();
6f51e1
-
6f51e1
-	/* get passwordExpirationTime attribute */
6f51e1
-	passwordExpirationTime= slapi_entry_attr_get_charptr(e, "passwordExpirationTime");
6f51e1
-
6f51e1
-	if (passwordExpirationTime == NULL)
6f51e1
-	{
6f51e1
-		/* password expiration date is not set.
6f51e1
-		 * This is ok for data that has been loaded via ldif2ldbm
6f51e1
-		 * Set expiration time if needed,
6f51e1
-		 * don't do further checking and return 0 */
6f51e1
-		if (pwpolicy->pw_exp == 1) {
6f51e1
-			pw_exp_date = time_plus_sec(cur_time, pwpolicy->pw_maxage);
6f51e1
-
6f51e1
-			timestring = format_genTime (pw_exp_date);
6f51e1
-			slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
6f51e1
-			slapi_ch_free_string(&timestring);
6f51e1
-			slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "0");
6f51e1
-			
6f51e1
-			pw_apply_mods(sdn, &smods);
6f51e1
-		} else if (pwpolicy->pw_lockout == 1) {
6f51e1
-			pw_apply_mods(sdn, &smods);
6f51e1
-		}
6f51e1
-		slapi_mods_done(&smods);
6f51e1
-		return ( 0 );
6f51e1
-	}
6f51e1
-
6f51e1
-	pw_exp_date = parse_genTime(passwordExpirationTime);
6f51e1
-
6f51e1
-	slapi_ch_free_string(&passwordExpirationTime);
6f51e1
-
6f51e1
-	/* Check if password has been reset */
6f51e1
-	if ( pw_exp_date == NO_TIME ) {
6f51e1
-
6f51e1
-		/* check if changing password is required */  
6f51e1
-		if ( pwpolicy->pw_must_change ) {
6f51e1
-			/* set c_needpw for this connection to be true.  this client 
6f51e1
-			   now can only change its own password */
6f51e1
-			pb->pb_conn->c_needpw = 1;
6f51e1
-			*t=0;
6f51e1
-			/* We need to include "changeafterreset" error in
6f51e1
-			 * passwordpolicy response control. So, we will not be
6f51e1
-			 * done here. We remember this scenario by (c_needpw=1)
6f51e1
-			 * and check it before sending the control from various
6f51e1
-			 * places. We will also add LDAP_CONTROL_PWEXPIRED control
6f51e1
-			 * as the return value used to be (1).
6f51e1
-			 */
6f51e1
-			goto skip;
6f51e1
-		}
6f51e1
-		/* Mark that first login occured */
6f51e1
-		pw_exp_date = NOT_FIRST_TIME;
6f51e1
-		timestring = format_genTime(pw_exp_date);
6f51e1
-		slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
6f51e1
-		slapi_ch_free_string(&timestring);
6f51e1
-	}
6f51e1
+    time_t cur_time, pw_exp_date;
6f51e1
+    Slapi_Mods smods;
6f51e1
+    double diff_t = 0;
6f51e1
+    char *cur_time_str = NULL;
6f51e1
+    char *passwordExpirationTime = NULL;
6f51e1
+    char *timestring;
6f51e1
+    char *dn;
6f51e1
+    const Slapi_DN *sdn;
6f51e1
+    passwdPolicy *pwpolicy = NULL;
6f51e1
+    int pwdGraceUserTime = 0;
6f51e1
+    char graceUserTime[16] = {0};
6f51e1
+    Connection *pb_conn = NULL;
6f51e1
+    long t;
6f51e1
+
6f51e1
+    if (NULL == e) {
6f51e1
+        return (-1);
6f51e1
+    }
6f51e1
+    slapi_mods_init(&smods, 0);
6f51e1
+    sdn = slapi_entry_get_sdn_const(e);
6f51e1
+    dn = slapi_entry_get_ndn(e);
6f51e1
+    pwpolicy = new_passwdPolicy(pb, dn);
6f51e1
+
6f51e1
+    /* after the user binds with authentication, clear the retry count */
6f51e1
+    if (pwpolicy->pw_lockout == 1) {
6f51e1
+        if (slapi_entry_attr_get_int(e, "passwordRetryCount") > 0) {
6f51e1
+            slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordRetryCount", "0");
6f51e1
+        }
6f51e1
+    }
6f51e1
+
6f51e1
+    cur_time = current_time();
6f51e1
+
6f51e1
+    /* get passwordExpirationTime attribute */
6f51e1
+    passwordExpirationTime = slapi_entry_attr_get_charptr(e, "passwordExpirationTime");
6f51e1
+
6f51e1
+    if (passwordExpirationTime == NULL) {
6f51e1
+        /* password expiration date is not set.
6f51e1
+         * This is ok for data that has been loaded via ldif2ldbm
6f51e1
+         * Set expiration time if needed,
6f51e1
+         * don't do further checking and return 0 */
6f51e1
+        if (pwpolicy->pw_exp == 1) {
6f51e1
+            pw_exp_date = time_plus_sec(cur_time, pwpolicy->pw_maxage);
6f51e1
+
6f51e1
+            timestring = format_genTime(pw_exp_date);
6f51e1
+            slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
6f51e1
+            slapi_ch_free_string(&timestring);
6f51e1
+            slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "0");
6f51e1
+
6f51e1
+            pw_apply_mods(sdn, &smods);
6f51e1
+        } else if (pwpolicy->pw_lockout == 1) {
6f51e1
+            pw_apply_mods(sdn, &smods);
6f51e1
+        }
6f51e1
+        slapi_mods_done(&smods);
6f51e1
+        return (0);
6f51e1
+    }
6f51e1
+
6f51e1
+    pw_exp_date = parse_genTime(passwordExpirationTime);
6f51e1
+
6f51e1
+    slapi_ch_free_string(&passwordExpirationTime);
6f51e1
+
6f51e1
+    slapi_pblock_get(pb, SLAPI_CONNECTION, &pb_conn);
6f51e1
+
6f51e1
+    /* Check if password has been reset */
6f51e1
+    if (pw_exp_date == NO_TIME) {
6f51e1
+
6f51e1
+        /* check if changing password is required */
6f51e1
+        if (pwpolicy->pw_must_change) {
6f51e1
+            /* set c_needpw for this connection to be true.  this client
6f51e1
+               now can only change its own password */
6f51e1
+            pb_conn->c_needpw = 1;
6f51e1
+            t = 0;
6f51e1
+            /* We need to include "changeafterreset" error in
6f51e1
+             * passwordpolicy response control. So, we will not be
6f51e1
+             * done here. We remember this scenario by (c_needpw=1)
6f51e1
+             * and check it before sending the control from various
6f51e1
+             * places. We will also add LDAP_CONTROL_PWEXPIRED control
6f51e1
+             * as the return value used to be (1).
6f51e1
+             */
6f51e1
+            goto skip;
6f51e1
+        }
6f51e1
+        /* Mark that first login occured */
6f51e1
+        pw_exp_date = NOT_FIRST_TIME;
6f51e1
+        timestring = format_genTime(pw_exp_date);
6f51e1
+        slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
6f51e1
+        slapi_ch_free_string(&timestring);
6f51e1
+    }
6f51e1
 
6f51e1
 skip:
6f51e1
-	/* if password never expires, don't need to go on; return 0 */
6f51e1
-	if ( pwpolicy->pw_exp == 0 ) {
6f51e1
-		/* check for "changeafterreset" condition */
6f51e1
-		if (pb->pb_conn->c_needpw == 1) {
6f51e1
-			if (pwresponse_req) {
6f51e1
-				slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_CHGAFTERRESET );
6f51e1
-			} 
6f51e1
-			slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
-		}
6f51e1
-		pw_apply_mods(sdn, &smods);
6f51e1
-		slapi_mods_done(&smods);
6f51e1
-		return ( 0 );
6f51e1
-	}
6f51e1
-
6f51e1
-	/* check if password expired.  If so, abort bind. */
6f51e1
-	cur_time_str = format_genTime ( cur_time );
6f51e1
-	if ((pw_exp_date != NO_TIME) && (pw_exp_date != NOT_FIRST_TIME) &&
6f51e1
-	    (diff_t = difftime(pw_exp_date, parse_genTime(cur_time_str))) <= 0) {
6f51e1
-		slapi_ch_free_string(&cur_time_str); /* only need this above */
6f51e1
-		/* password has expired. Check the value of 
6f51e1
-		 * passwordGraceUserTime and compare it
6f51e1
-		 * against the value of passwordGraceLimit */
6f51e1
-		pwdGraceUserTime = slapi_entry_attr_get_int( e, "passwordGraceUserTime");
6f51e1
-		if ( pwpolicy->pw_gracelimit > pwdGraceUserTime ) {
6f51e1
-			pwdGraceUserTime++;
6f51e1
-			sprintf ( graceUserTime, "%d", pwdGraceUserTime );
6f51e1
-			slapi_mods_add_string(&smods, LDAP_MOD_REPLACE,
6f51e1
-				"passwordGraceUserTime", graceUserTime);
6f51e1
-			pw_apply_mods(sdn, &smods);
6f51e1
-			slapi_mods_done(&smods);
6f51e1
-			if (pwresponse_req) {
6f51e1
-				/* check for "changeafterreset" condition */
6f51e1
-				if (pb->pb_conn->c_needpw == 1) {
6f51e1
-					slapi_pwpolicy_make_response_control( pb, -1, 
6f51e1
-						((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
6f51e1
-						LDAP_PWPOLICY_CHGAFTERRESET);
6f51e1
-				} else {
6f51e1
-					slapi_pwpolicy_make_response_control( pb, -1, 
6f51e1
-						((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
6f51e1
-						-1);
6f51e1
-				}
6f51e1
-			}
6f51e1
-			
6f51e1
-			if (pb->pb_conn->c_needpw == 1) {
6f51e1
-				slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
-			}
6f51e1
-			return ( 0 );
6f51e1
-		}
6f51e1
-
6f51e1
-		/* password expired and user exceeded limit of grace attemps.
6f51e1
-		 * Send result and also the control */
6f51e1
-		slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
-		if (pwresponse_req) {
6f51e1
-			slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED );
6f51e1
-		}
6f51e1
-		slapi_send_ldap_result ( pb, LDAP_INVALID_CREDENTIALS, NULL,
6f51e1
-			"password expired!", 0, NULL );
6f51e1
-		
6f51e1
-		/* abort bind */
6f51e1
-		/* pass pb to do_unbind().  pb->pb_op->o_opid and 
6f51e1
-		   pb->pb_op->o_tag are not right but I don't see 
6f51e1
-		   do_unbind() checking for those.   We might need to 
6f51e1
-		   create a pb for unbind operation.  Also do_unbind calls
6f51e1
-		   pre and post ops.  Maybe we don't want to call them */
6f51e1
-		if (pb->pb_conn && (LDAP_VERSION2 == pb->pb_conn->c_ldapversion)) {
6f51e1
-			/* We close the connection only with LDAPv2 connections */
6f51e1
-			disconnect_server( pb->pb_conn, pb->pb_op->o_connid,
6f51e1
-				pb->pb_op->o_opid, SLAPD_DISCONNECT_UNBIND, 0);
6f51e1
-		}
6f51e1
-		/* Apply current modifications */
6f51e1
-		pw_apply_mods(sdn, &smods);
6f51e1
-		slapi_mods_done(&smods);
6f51e1
-		return (-1);
6f51e1
-	}
6f51e1
-	slapi_ch_free((void **) &cur_time_str );
6f51e1
-
6f51e1
-	/* check if password is going to expire within "passwordWarning" */
6f51e1
-	/* Note that if pw_exp_date is NO_TIME or NOT_FIRST_TIME,
6f51e1
-	 * we must send warning first and this changes the expiration time.
6f51e1
-	 * This is done just below since diff_t is 0 
6f51e1
-	 */
6f51e1
-	if ( diff_t <= pwpolicy->pw_warning ) {
6f51e1
-		int pw_exp_warned = 0;
6f51e1
-		
6f51e1
-		pw_exp_warned = slapi_entry_attr_get_int( e, "passwordExpWarned");
6f51e1
-		if ( !pw_exp_warned ){
6f51e1
-			/* first time send out a warning */
6f51e1
-			/* reset the expiration time to current + warning time 
6f51e1
-			 * and set passwordExpWarned to true
6f51e1
-			 */
6f51e1
-			if (pb->pb_conn->c_needpw != 1) {
6f51e1
-				pw_exp_date = time_plus_sec(cur_time, pwpolicy->pw_warning);
6f51e1
-			}
6f51e1
-			
6f51e1
-			timestring = format_genTime(pw_exp_date);
6f51e1
-			slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
6f51e1
-			slapi_ch_free_string(&timestring);
6f51e1
-
6f51e1
-			slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "1");
6f51e1
-			
6f51e1
-			*t = pwpolicy->pw_warning;
6f51e1
-
6f51e1
-		} else {
6f51e1
-			*t = (long)diff_t; /* jcm: had to cast double to long */
6f51e1
-		}
6f51e1
-
6f51e1
-		pw_apply_mods(sdn, &smods);
6f51e1
-		slapi_mods_done(&smods);
6f51e1
-		if (pwresponse_req) {
6f51e1
-			/* check for "changeafterreset" condition */
6f51e1
-			if (pb->pb_conn->c_needpw == 1) {
6f51e1
-					slapi_pwpolicy_make_response_control( pb, *t, -1,
6f51e1
-						LDAP_PWPOLICY_CHGAFTERRESET);
6f51e1
-				} else {
6f51e1
-					slapi_pwpolicy_make_response_control( pb, *t, -1,
6f51e1
-						-1);
6f51e1
-				}
6f51e1
-		}
6f51e1
-
6f51e1
-		if (pb->pb_conn->c_needpw == 1) {
6f51e1
-			slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
-		}
6f51e1
-		return (2);
6f51e1
-	} else {
6f51e1
-		if (pwresponse_req && pwpolicy->pw_send_expiring) {
6f51e1
-			slapi_pwpolicy_make_response_control( pb, diff_t, -1, -1);
6f51e1
-			slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRING, diff_t);
6f51e1
-		}
6f51e1
-	}
6f51e1
-
6f51e1
-	pw_apply_mods(sdn, &smods);
6f51e1
-	slapi_mods_done(&smods);
6f51e1
-	/* Leftover from "changeafterreset" condition */
6f51e1
-	if (pb->pb_conn->c_needpw == 1) {
6f51e1
-		slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
-	}
6f51e1
-	/* passes checking, return 0 */
6f51e1
-	return( 0 );
6f51e1
+    /* if password never expires, don't need to go on; return 0 */
6f51e1
+    if (pwpolicy->pw_exp == 0) {
6f51e1
+        /* check for "changeafterreset" condition */
6f51e1
+        if (pb_conn->c_needpw == 1) {
6f51e1
+            if (pwresponse_req) {
6f51e1
+                slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_CHGAFTERRESET);
6f51e1
+            }
6f51e1
+            slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
+        }
6f51e1
+        pw_apply_mods(sdn, &smods);
6f51e1
+        slapi_mods_done(&smods);
6f51e1
+        return (0);
6f51e1
+    }
6f51e1
+
6f51e1
+    /* check if password expired.  If so, abort bind. */
6f51e1
+    cur_time_str = format_genTime(cur_time);
6f51e1
+    if ((pw_exp_date != NO_TIME) && (pw_exp_date != NOT_FIRST_TIME) &&
6f51e1
+        (diff_t = difftime(pw_exp_date, parse_genTime(cur_time_str))) <= 0) {
6f51e1
+        slapi_ch_free_string(&cur_time_str); /* only need this above */
6f51e1
+        /* password has expired. Check the value of
6f51e1
+         * passwordGraceUserTime and compare it
6f51e1
+         * against the value of passwordGraceLimit */
6f51e1
+        pwdGraceUserTime = slapi_entry_attr_get_int(e, "passwordGraceUserTime");
6f51e1
+        if (pwpolicy->pw_gracelimit > pwdGraceUserTime) {
6f51e1
+            pwdGraceUserTime++;
6f51e1
+            sprintf(graceUserTime, "%d", pwdGraceUserTime);
6f51e1
+            slapi_mods_add_string(&smods, LDAP_MOD_REPLACE,
6f51e1
+                                  "passwordGraceUserTime", graceUserTime);
6f51e1
+            pw_apply_mods(sdn, &smods);
6f51e1
+            slapi_mods_done(&smods);
6f51e1
+            if (pwresponse_req) {
6f51e1
+                /* check for "changeafterreset" condition */
6f51e1
+                if (pb_conn->c_needpw == 1) {
6f51e1
+                    slapi_pwpolicy_make_response_control(pb, -1,
6f51e1
+                                                         ((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
6f51e1
+                                                         LDAP_PWPOLICY_CHGAFTERRESET);
6f51e1
+                } else {
6f51e1
+                    slapi_pwpolicy_make_response_control(pb, -1,
6f51e1
+                                                         ((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
6f51e1
+                                                         -1);
6f51e1
+                }
6f51e1
+            }
6f51e1
+            slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
+            return (0);
6f51e1
+        }
6f51e1
+
6f51e1
+        /* password expired and user exceeded limit of grace attemps.
6f51e1
+         * Send result and also the control */
6f51e1
+        slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
+        if (pwresponse_req) {
6f51e1
+            slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED);
6f51e1
+        }
6f51e1
+        slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL,
6f51e1
+                               "password expired!", 0, NULL);
6f51e1
+
6f51e1
+        /* abort bind */
6f51e1
+        /* pass pb to do_unbind().  pb->pb_op->o_opid and
6f51e1
+           pb->pb_op->o_tag are not right but I don't see
6f51e1
+           do_unbind() checking for those.   We might need to
6f51e1
+           create a pb for unbind operation.  Also do_unbind calls
6f51e1
+           pre and post ops.  Maybe we don't want to call them */
6f51e1
+        if (pb_conn && (LDAP_VERSION2 == pb_conn->c_ldapversion)) {
6f51e1
+            Operation *pb_op = NULL;
6f51e1
+            slapi_pblock_get(pb, SLAPI_OPERATION, &pb_op);
6f51e1
+            /* We close the connection only with LDAPv2 connections */
6f51e1
+            disconnect_server(pb_conn, pb_op->o_connid,
6f51e1
+                              pb_op->o_opid, SLAPD_DISCONNECT_UNBIND, 0);
6f51e1
+        }
6f51e1
+        /* Apply current modifications */
6f51e1
+        pw_apply_mods(sdn, &smods);
6f51e1
+        slapi_mods_done(&smods);
6f51e1
+        return (-1);
6f51e1
+    }
6f51e1
+    slapi_ch_free((void **)&cur_time_str);
6f51e1
+
6f51e1
+    /* check if password is going to expire within "passwordWarning" */
6f51e1
+    /* Note that if pw_exp_date is NO_TIME or NOT_FIRST_TIME,
6f51e1
+     * we must send warning first and this changes the expiration time.
6f51e1
+     * This is done just below since diff_t is 0
6f51e1
+     */
6f51e1
+    if (diff_t <= pwpolicy->pw_warning) {
6f51e1
+        int pw_exp_warned = 0;
6f51e1
+
6f51e1
+        pw_exp_warned = slapi_entry_attr_get_int(e, "passwordExpWarned");
6f51e1
+        if (!pw_exp_warned) {
6f51e1
+            /* first time send out a warning */
6f51e1
+            /* reset the expiration time to current + warning time
6f51e1
+             * and set passwordExpWarned to true
6f51e1
+             */
6f51e1
+            if (pb_conn->c_needpw != 1) {
6f51e1
+                pw_exp_date = time_plus_sec(cur_time, pwpolicy->pw_warning);
6f51e1
+            }
6f51e1
+
6f51e1
+            timestring = format_genTime(pw_exp_date);
6f51e1
+            slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
6f51e1
+            slapi_ch_free_string(&timestring);
6f51e1
+
6f51e1
+            slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "1");
6f51e1
+
6f51e1
+            t = pwpolicy->pw_warning;
6f51e1
+
6f51e1
+        } else {
6f51e1
+            t = (long)diff_t; /* jcm: had to cast double to long */
6f51e1
+        }
6f51e1
+
6f51e1
+        pw_apply_mods(sdn, &smods);
6f51e1
+        slapi_mods_done(&smods);
6f51e1
+        if (pwresponse_req) {
6f51e1
+            /* check for "changeafterreset" condition */
6f51e1
+            if (pb_conn->c_needpw == 1) {
6f51e1
+                slapi_pwpolicy_make_response_control(pb, t, -1, LDAP_PWPOLICY_CHGAFTERRESET);
6f51e1
+            } else {
6f51e1
+                slapi_pwpolicy_make_response_control(pb, t, -1, -1);
6f51e1
+            }
6f51e1
+        }
6f51e1
+
6f51e1
+        if (pb_conn->c_needpw == 1) {
6f51e1
+            slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
+        } else {
6f51e1
+            slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRING, t);
6f51e1
+        }
6f51e1
+        return (0);
6f51e1
+    } else {
6f51e1
+        if (pwresponse_req && pwpolicy->pw_send_expiring) {
6f51e1
+            slapi_pwpolicy_make_response_control(pb, diff_t, -1, -1);
6f51e1
+            slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRING, diff_t);
6f51e1
+        }
6f51e1
+    }
6f51e1
+
6f51e1
+    pw_apply_mods(sdn, &smods);
6f51e1
+    slapi_mods_done(&smods);
6f51e1
+    /* Leftover from "changeafterreset" condition */
6f51e1
+    if (pb_conn->c_needpw == 1) {
6f51e1
+        slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
+    }
6f51e1
+    /* passes checking, return 0 */
6f51e1
+    return (0);
6f51e1
 }
6f51e1
 
6f51e1
 /* Called once from main */
6f51e1
diff --git a/ldap/servers/slapd/saslbind.c b/ldap/servers/slapd/saslbind.c
6f51e1
index dd0c4fb..134f5aa 100644
6f51e1
--- a/ldap/servers/slapd/saslbind.c
6f51e1
+++ b/ldap/servers/slapd/saslbind.c
6f51e1
@@ -859,7 +859,6 @@ ids_sasl_mech_supported(Slapi_PBlock *pb, const char *mech)
6f51e1
 void ids_sasl_check_bind(Slapi_PBlock *pb)
6f51e1
 {
6f51e1
     int rc, isroot;
6f51e1
-    long t;
6f51e1
     sasl_conn_t *sasl_conn;
6f51e1
     struct propctx *propctx;
6f51e1
     sasl_ssf_t *ssfp;
6f51e1
@@ -1096,23 +1095,8 @@ sasl_check_result:
6f51e1
         set_db_default_result_handlers(pb);
6f51e1
 
6f51e1
         /* check password expiry */
6f51e1
-        if (!isroot) {
6f51e1
-            int pwrc;
6f51e1
-
6f51e1
-            pwrc = need_new_pw(pb, &t, bind_target_entry, pwresponse_requested);
6f51e1
-            
6f51e1
-            switch (pwrc) {
6f51e1
-            case 1:
6f51e1
-                slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
6f51e1
-                break;
6f51e1
-            case 2:
6f51e1
-                slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRING, t);
6f51e1
-                break;
6f51e1
-            case -1:
6f51e1
-                goto out;
6f51e1
-            default:
6f51e1
-                break;
6f51e1
-            }
6f51e1
+        if (!isroot && need_new_pw(pb, bind_target_entry, pwresponse_requested) == -1) {
6f51e1
+            goto out;
6f51e1
         }
6f51e1
 
6f51e1
         /* attach the sasl data */
6f51e1
-- 
6f51e1
2.9.5
6f51e1