Przeglądaj źródła

Ticket #183 - passwordMaxFailure should lockout password one sooner - and should be configurable to avoid regressions

Bug Description:  DS doesn't return error LDAP_CONSTRAINT_VIOLATION until after the retry limit is exceeded

Fix Description:  DS has essentially locked the account, but we didn't log the error until
                  the next bind.  Added a new config option "passwordLegacyPolicy: on|off"
                  that will trigger the error LDAP_CONSTRAINT_VIOLATION, if "legacy" is off,
                  when the limit is actually reached.  The default is to continue to do
                  things the "old" way, or legacy "on".

https://fedorahosted.org/389/ticket/183

reviewed by: Noriko (Thanks!)
Mark Reynolds 13 lat temu
rodzic
commit
396c9320f5

+ 30 - 0
ldap/servers/slapd/libglobs.c

@@ -373,6 +373,9 @@ static struct config_get_and_set {
 	{CONFIG_PW_ISGLOBAL_ATTRIBUTE, config_set_pw_is_global_policy,
 		NULL, 0,
 		(void**)&global_slapdFrontendConfig.pw_is_global_policy, CONFIG_ON_OFF, NULL},
+	{CONFIG_PW_IS_LEGACY, config_set_pw_is_legacy_policy,
+		NULL, 0,
+		(void**)&global_slapdFrontendConfig.pw_policy.pw_is_legacy, CONFIG_ON_OFF, NULL},
 	{CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE, NULL,
 		log_set_numlogsperdir, SLAPD_AUDIT_LOG,
 		(void**)&global_slapdFrontendConfig.auditlog_maxnumlogs, CONFIG_INT, NULL},
@@ -1017,6 +1020,7 @@ FrontendConfig_init () {
   cfg->pw_policy.pw_lockduration = 3600;     /* 60 minutes   */
   cfg->pw_policy.pw_resetfailurecount = 600; /* 10 minutes   */ 
   cfg->pw_policy.pw_gracelimit = 0;
+  cfg->pw_policy.pw_is_legacy = LDAP_ON;
   cfg->pw_is_global_policy = LDAP_OFF;
 
   cfg->accesslog_logging_enabled = LDAP_ON;
@@ -2416,6 +2420,20 @@ config_set_pw_is_global_policy( const char *attrname, char *value, char *errorbu
   return retVal;
 }
 
+int
+config_set_pw_is_legacy_policy( const char *attrname, char *value, char *errorbuf, int apply ) {
+  int retVal = LDAP_SUCCESS;
+  slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+  retVal = config_set_onoff ( attrname,
+							  value,
+							  &(slapdFrontendConfig->pw_policy.pw_is_legacy),
+							  errorbuf,
+							  apply);
+
+  return retVal;
+}
+
 int
 config_set_pw_exp( const char *attrname, char *value, char *errorbuf, int apply ) {
   int retVal = LDAP_SUCCESS;
@@ -4234,6 +4252,18 @@ config_get_pw_is_global_policy() {
   return retVal; 
 }
 
+int
+config_get_pw_is_legacy_policy() {
+  slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+  int retVal;
+
+  CFG_LOCK_READ(slapdFrontendConfig);
+  retVal = slapdFrontendConfig->pw_policy.pw_is_legacy;
+  CFG_UNLOCK_READ(slapdFrontendConfig);
+
+  return retVal;
+}
+
 int
 config_get_pw_exp() {
   slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();

+ 1 - 0
ldap/servers/slapd/proto-slap.h

@@ -340,6 +340,7 @@ int config_set_pw_unlock(const char *attrname,  char *value, char *errorbuf, int
 int config_set_pw_lockduration(const char *attrname,  char *value, char *errorbuf, int apply );
 int config_set_pw_resetfailurecount(const char *attrname,  char *value, char *errorbuf, int apply );
 int config_set_pw_is_global_policy(const char *attrname,  char *value, char *errorbuf, int apply );
+int config_set_pw_is_legacy_policy(const char *attrname,  char *value, char *errorbuf, int apply );
 int config_set_pw_gracelimit(const char *attrname,  char *value, char *errorbuf, int apply );
 int config_set_useroc(const char *attrname,  char *value, char *errorbuf, int apply );
 int config_set_return_exact_case(const char *attrname,  char *value, char *errorbuf, int apply );

+ 1 - 1
ldap/servers/slapd/pw.h

@@ -96,6 +96,6 @@ int check_pw_storagescheme_value( const char *attr_name, char *value, long minva
  * Public functions from pw_retry.c:
  */
 Slapi_Entry *get_entry ( Slapi_PBlock *pb, const char *dn );
-void set_retry_cnt_mods ( Slapi_PBlock *pb, Slapi_Mods *smods, int count);
+int set_retry_cnt_mods ( Slapi_PBlock *pb, Slapi_Mods *smods, int count);
 
 #endif /* _SLAPD_PW_H_ */

+ 23 - 15
ldap/servers/slapd/pw_retry.c

@@ -50,8 +50,8 @@
 /* prototypes                                                               */
 /****************************************************************************/
 /* Slapi_Entry *get_entry ( Slapi_PBlock *pb, const char *dn ); */
-static void set_retry_cnt ( Slapi_PBlock *pb, int count);
-static void set_retry_cnt_and_time ( Slapi_PBlock *pb, int count, time_t cur_time);
+static int set_retry_cnt ( Slapi_PBlock *pb, int count);
+static int set_retry_cnt_and_time ( Slapi_PBlock *pb, int count, time_t cur_time);
 
 /*
  * update_pw_retry() is called when bind operation fails 
@@ -72,6 +72,7 @@ int update_pw_retry ( Slapi_PBlock *pb )
 	char            *cur_time_str = NULL;
 	char *retryCountResetTime;
 	int passwordRetryCount;
+	int rc = 0;
 
     /* get the entry */
     e = get_entry ( pb, NULL );
@@ -93,18 +94,18 @@ int update_pw_retry ( Slapi_PBlock *pb )
         {
             /* set passwordRetryCount to 1 */
             /* reset retryCountResetTime */
-			set_retry_cnt_and_time ( pb, 1, cur_time );
+			rc = set_retry_cnt_and_time ( pb, 1, cur_time );
 			slapi_ch_free((void **) &cur_time_str );
 			slapi_entry_free( e );
-            return ( 0 ); /* success */
+            return ( rc ); /* success */
         } else {
 			slapi_ch_free((void **) &cur_time_str );
 		}
     } else {
 		/* initialize passwordRetryCount and retryCountResetTime */
-		set_retry_cnt_and_time ( pb, 1, cur_time );
+		rc = set_retry_cnt_and_time ( pb, 1, cur_time );
 		slapi_entry_free( e );
-        return ( 0 ); /* success */
+        return ( rc ); /* success */
 	}
 	passwordRetryCount = slapi_entry_attr_get_int(e, "passwordRetryCount"); 
     if (passwordRetryCount >= 0)
@@ -112,24 +113,25 @@ int update_pw_retry ( Slapi_PBlock *pb )
         retry_cnt = passwordRetryCount + 1;
    		if ( retry_cnt == 1 ) {
         	/* set retryCountResetTime */
-        	set_retry_cnt_and_time ( pb, retry_cnt, cur_time );
+        	rc = set_retry_cnt_and_time ( pb, retry_cnt, cur_time );
 		} else {
 			/* set passwordRetryCount to retry_cnt */
-			set_retry_cnt ( pb, retry_cnt );
+			rc = set_retry_cnt ( pb, retry_cnt );
 		}
     }	
 	slapi_entry_free( e );
-	return 0; /* success */
+	return rc; /* success */
 }
 
 static
-void set_retry_cnt_and_time ( Slapi_PBlock *pb, int count, time_t cur_time ) {
+int set_retry_cnt_and_time ( Slapi_PBlock *pb, int count, time_t cur_time ) {
 	const char  *dn = NULL;
 	Slapi_DN    *sdn = NULL;
 	Slapi_Mods	smods;
 	time_t      reset_time;
 	char		*timestr;
 	passwdPolicy *pwpolicy = NULL;
+	int rc = 0;
 
 	slapi_pblock_get( pb, SLAPI_TARGET_SDN, &sdn );
 	dn = slapi_sdn_get_dn(sdn);
@@ -144,14 +146,16 @@ void set_retry_cnt_and_time ( Slapi_PBlock *pb, int count, time_t cur_time ) {
 	slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "retryCountResetTime", timestr);
 	slapi_ch_free((void **)&timestr);
 
-	set_retry_cnt_mods(pb, &smods, count);
+	rc = set_retry_cnt_mods(pb, &smods, count);
 	
 	pw_apply_mods(sdn, &smods);
 	slapi_mods_done(&smods);
 	delete_passwdPolicy(&pwpolicy);
+
+	return rc;
 }
 
-void set_retry_cnt_mods(Slapi_PBlock *pb, Slapi_Mods *smods, int count)
+int set_retry_cnt_mods(Slapi_PBlock *pb, Slapi_Mods *smods, int count)
 {
 	char 		*timestr;
 	time_t		unlock_time;
@@ -159,6 +163,7 @@ void set_retry_cnt_mods(Slapi_PBlock *pb, Slapi_Mods *smods, int count)
 	const char *dn = NULL; 
 	Slapi_DN *sdn = NULL; 
 	passwdPolicy *pwpolicy = NULL;
+	int rc = 0;
 
 	slapi_pblock_get( pb, SLAPI_TARGET_SDN, &sdn );
 	dn = slapi_sdn_get_dn(sdn);
@@ -182,23 +187,26 @@ void set_retry_cnt_mods(Slapi_PBlock *pb, Slapi_Mods *smods, int count)
 			timestr= format_genTime ( unlock_time );
 			slapi_mods_add_string(smods, LDAP_MOD_REPLACE, "accountUnlockTime", timestr);
 			slapi_ch_free((void **)&timestr);
+			rc = LDAP_CONSTRAINT_VIOLATION;
 		}
 	}
 	delete_passwdPolicy(&pwpolicy);
-	return;
+	return rc;
 }
 
 static
-void set_retry_cnt ( Slapi_PBlock *pb, int count)
+int set_retry_cnt ( Slapi_PBlock *pb, int count)
 {
 	Slapi_DN *sdn = NULL; 
 	Slapi_Mods	smods;
+	int rc = 0;
 	
 	slapi_pblock_get( pb, SLAPI_TARGET_SDN, &sdn );
 	slapi_mods_init(&smods, 0);
-	set_retry_cnt_mods(pb, &smods, count);
+	rc = set_retry_cnt_mods(pb, &smods, count);
 	pw_apply_mods(sdn, &smods);
 	slapi_mods_done(&smods);
+	return rc;
 }
 
 

+ 9 - 1
ldap/servers/slapd/result.c

@@ -377,7 +377,15 @@ send_ldap_result_ext(
 		dn = slapi_sdn_get_dn(sdn);
 		pwpolicy = new_passwdPolicy(pb, dn);
 		if (pwpolicy && (pwpolicy->pw_lockout == 1)) {
-			update_pw_retry ( pb );
+			if(update_pw_retry( pb ) == LDAP_CONSTRAINT_VIOLATION && !pwpolicy->pw_is_legacy){
+				/*
+				 * If we are not using the legacy pw policy behavior,
+				 * convert the error 49 to 19 (constraint violation)
+				 * and log a message
+				 */
+				err = LDAP_CONSTRAINT_VIOLATION;
+				text = "Invalid credentials, you now have exceeded the password retry limit.";
+			}
 		}
 	}
         

+ 2 - 0
ldap/servers/slapd/slap.h

@@ -1952,6 +1952,7 @@ typedef struct _slapdEntryPoints {
 #define CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE "passwordResetFailureCount"
 #define CONFIG_PW_ISGLOBAL_ATTRIBUTE "passwordIsGlobalPolicy"
 #define CONFIG_PW_GRACELIMIT_ATTRIBUTE "passwordGraceLimit"
+#define CONFIG_PW_IS_LEGACY "passwordLegacyPolicy"
 #define CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE "nsslapd-accesslog-logbuffering"
 #define CONFIG_CSNLOGGING_ATTRIBUTE "nsslapd-csnlogging"
 #define CONFIG_RETURN_EXACT_CASE_ATTRIBUTE "nsslapd-return-exact-case"
@@ -2039,6 +2040,7 @@ typedef struct passwordpolicyarray {
   long pw_lockduration;
   long pw_resetfailurecount;
   int pw_gracelimit;
+  int pw_is_legacy;
   struct pw_scheme *pw_storagescheme;
 } passwdPolicy;