Browse Source

Bug 470684 - Pam_passthru plugin doesn't verify account activation

https://bugzilla.redhat.com/show_bug.cgi?id=470684
Resolves: bug 470684
Bug Description: Pam passthrough doesn't verify account activation
Reviewed by: rmeggins
Branch: HEAD
Fix Description: The check_account_lock() has been renamed to
slapi_check_account_lock() and moved into libslapd.so so any plugins
can use it. The account_inactivation_only parameter has been replaced
by check_password_policy. A new parameter send_result has been added
to determine whether to send LDAP results.

The pam_passthru plugin has been modified to use this function to
check account activation when the pamIDMapMethod is set to ENTRY.
The plugin will not check password policy.
Endi S. Dewata 15 years ago
parent
commit
1ef0ec98b6

+ 15 - 2
ldap/servers/plugins/pam_passthru/pam_ptimpl.c

@@ -106,7 +106,7 @@ derive_from_bind_dn(Slapi_PBlock *pb, char *binddn, MyStrBuf *pam_id)
 }
 
 static char *
-derive_from_bind_entry(Slapi_PBlock *pb, char *binddn, MyStrBuf *pam_id, char *map_ident_attr)
+derive_from_bind_entry(Slapi_PBlock *pb, char *binddn, MyStrBuf *pam_id, char *map_ident_attr, int *locked)
 {
 	char buf[BUFSIZ];
 	Slapi_Entry *entry = NULL;
@@ -128,6 +128,12 @@ derive_from_bind_entry(Slapi_PBlock *pb, char *binddn, MyStrBuf *pam_id, char *m
 						"Could not find entry for BIND dn %s\n",
 						escape_string(binddn, buf));
 		init_my_str_buf(pam_id, NULL);
+	} else if (slapi_check_account_lock( pb, entry, 0, 0, 0 ) == 1) {
+		slapi_log_error(SLAPI_LOG_FATAL, PAM_PASSTHRU_PLUGIN_SUBSYSTEM,
+						"Account %s inactivated.\n",
+						escape_string(binddn, buf));
+		init_my_str_buf(pam_id, NULL);
+		*locked = 1;
 	} else {
 		char *val = slapi_entry_attr_get_charptr(entry, map_ident_attr);
 		init_my_str_buf(pam_id, val);
@@ -266,17 +272,24 @@ do_one_pam_auth(
 	struct pam_conv my_pam_conv = {pam_conv_func, NULL};
 	char buf[BUFSIZ]; /* for error messages */
 	char *errmsg = NULL; /* free with PR_smprintf_free */
+	int locked = 0;
 
 	slapi_pblock_get( pb, SLAPI_BIND_TARGET, &binddn );
 
 	if (method == PAMPT_MAP_METHOD_RDN) {
 		derive_from_bind_dn(pb, binddn, &pam_id);
 	} else if (method == PAMPT_MAP_METHOD_ENTRY) {
-		derive_from_bind_entry(pb, binddn, &pam_id, map_ident_attr);
+		derive_from_bind_entry(pb, binddn, &pam_id, map_ident_attr, &locked);
 	} else {
 		init_my_str_buf(&pam_id, binddn);
 	}
 
+	if (locked) {
+		errmsg = PR_smprintf("Account inactivated. Contact system administrator.");
+		retcode = LDAP_UNWILLING_TO_PERFORM; /* user inactivated */
+		goto done; /* skip the pam stuff */
+	}
+
 	if (!pam_id.str) {
 		errmsg = PR_smprintf("Bind DN [%s] is invalid or not found",
 							 escape_string(binddn, buf));

+ 4 - 4
ldap/servers/slapd/bind.c

@@ -441,8 +441,8 @@ do_bind( Slapi_PBlock *pb )
             if (!isroot ) {
             /* check if the account is locked */
                 bind_target_entry = get_entry(pb, pb->pb_conn->c_external_dn);
-                if ( bind_target_entry != NULL && check_account_lock(pb, bind_target_entry,
-                     pw_response_requested, 0 /*not account_inactivation_only*/ ) == 1) {
+                if ( bind_target_entry != NULL && slapi_check_account_lock(pb, bind_target_entry,
+                     pw_response_requested, 1 /*check password policy*/, 1 /*send ldap result*/) == 1) {
                     /* call postop plugins */
                     plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
                     goto free_and_return;
@@ -642,10 +642,10 @@ do_bind( Slapi_PBlock *pb )
              *
              */
 			
-			/* get the entry now, so that we can give it to check_account_lock and reslimit_update_from_dn */
+			/* get the entry now, so that we can give it to slapi_check_account_lock and reslimit_update_from_dn */
             if (! slapi_be_is_flag_set(be, SLAPI_BE_FLAG_REMOTE_DATA)) {
 				bind_target_entry = get_entry(pb,  slapi_sdn_get_ndn(&sdn));
-				rc = check_account_lock ( pb, bind_target_entry, pw_response_requested,0);
+				rc = slapi_check_account_lock ( pb, bind_target_entry, pw_response_requested, 1, 1);
             }
 
             slapi_pblock_set( pb, SLAPI_PLUGIN, be->be_database );

+ 6 - 4
ldap/servers/slapd/daemon.c

@@ -1922,11 +1922,12 @@ slapd_bind_local_user(Connection *conn)
 				if(entries[0] && 0 == entries[1])
 				{
 					/* observe account locking */
-					ret = check_account_lock(
+					ret = slapi_check_account_lock(
 						0,  /* pb not req */
 						entries[0],
 						0, /* no response control */
-						1  /* inactivation only */
+						0, /* don't check password policy */
+						0  /* don't send ldap result */
 						);
 
 					if(0 == ret)
@@ -1981,11 +1982,12 @@ entry_map_free:
 
 				if(0 == ret && e)
 				{
-					ret = check_account_lock(
+					ret = slapi_check_account_lock(
 						0, /* pb not req */
 						e,
 						0, /* no response control */
-						1  /* inactivation only */
+						0, /* don't check password policy */
+						0  /* don't send ldap result */
 						);
 
 					if(1 == ret)

+ 1 - 0
ldap/servers/slapd/libslapd.def

@@ -1198,3 +1198,4 @@ EXPORTS
         config_get_pw_maxrepeats @1205
 	config_get_pw_mincategories @1206
 	config_get_pw_mintokenlength @1207
+	slapi_check_account_lock @1208

+ 138 - 0
ldap/servers/slapd/pw.c

@@ -1982,3 +1982,141 @@ check_pw_storagescheme_value( const char *attr_name, char *value, long minval, l
 	return retVal;
 }
 
+/* check_account_lock is called before bind opeation; this could be a pre-op. */
+int
+slapi_check_account_lock ( Slapi_PBlock *pb, Slapi_Entry * bind_target_entry, int pwresponse_req, int check_password_policy, int send_result) {
+
+	time_t		unlock_time;
+	time_t		cur_time;
+	char		*cur_time_str = NULL;
+	char *accountUnlockTime;
+	passwdPolicy *pwpolicy = NULL;
+	char *dn = NULL;
+
+	/* kexcoff: account inactivation */
+	int rc = 0;
+	Slapi_ValueSet *values = NULL;
+	int type_name_disposition = 0;
+	char *actual_type_name = NULL;
+	int attr_free_flags = 0;
+	/* kexcoff - end */
+
+	if ( bind_target_entry == NULL ) 
+		return -1;
+
+	if(check_password_policy)
+	{
+		dn = slapi_entry_get_ndn(bind_target_entry);
+		pwpolicy = new_passwdPolicy(pb, dn);
+	}
+
+	/* kexcoff: account inactivation */
+	/* check if the entry is locked by nsAccountLock attribute - account inactivation feature */
+
+	rc = slapi_vattr_values_get(bind_target_entry, "nsAccountLock", 
+								&values, 
+								&type_name_disposition, &actual_type_name,
+								SLAPI_VIRTUALATTRS_REQUEST_POINTERS,
+								&attr_free_flags);
+	if ( rc == 0 )
+	{
+		Slapi_Value *v = NULL;	
+		const struct berval *bvp = NULL;
+
+		if ( (slapi_valueset_first_value( values, &v ) != -1) &&
+				( bvp = slapi_value_get_berval( v )) != NULL )
+		{
+			if ( (bvp != NULL) && (strcasecmp(bvp->bv_val, "true") == 0) )
+			{
+				/* account inactivated */
+				if (check_password_policy && pwresponse_req) {
+					slapi_pwpolicy_make_response_control ( pb, -1, -1,
+							LDAP_PWPOLICY_ACCTLOCKED );
+				}
+				if (send_result)
+					send_ldap_result ( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+							"Account inactivated. Contact system administrator.",
+							0, NULL );
+				slapi_vattr_values_free(&values, &actual_type_name, attr_free_flags);
+				goto locked;
+			}
+		} /* else, account "activated", keep on the process */
+
+		if ( values != NULL )
+			slapi_vattr_values_free(&values, &actual_type_name, attr_free_flags);
+	}
+	/* kexcoff - end */
+
+	/*
+	 * Check if the password policy has to be checked or not
+	 */
+	if ( !check_password_policy || pwpolicy->pw_lockout == 0 ) {
+		goto notlocked;
+	}
+
+	/*
+	 * Check the attribute of the password policy
+	 */
+
+	/* check if account is locked out.  If so, send result and return 1 */
+	{
+		unsigned int maxfailure= pwpolicy->pw_maxfailure;
+		/* It's locked if passwordRetryCount >= maxfailure */
+		if ( slapi_entry_attr_get_uint(bind_target_entry,"passwordRetryCount") < maxfailure )
+		{
+			/* Not locked */
+			goto notlocked;	
+		}
+	}
+
+	/* locked but maybe it's time to unlock it */
+	accountUnlockTime= slapi_entry_attr_get_charptr(bind_target_entry, "accountUnlockTime");
+	if (accountUnlockTime != NULL)
+	{
+		unlock_time = parse_genTime(accountUnlockTime);
+		slapi_ch_free((void **) &accountUnlockTime );
+
+		if ( pwpolicy->pw_unlock == 0 && 
+			unlock_time == NO_TIME ) {
+
+	        /* account is locked forever. contact admin to reset */
+			if (pwresponse_req) {
+				slapi_pwpolicy_make_response_control ( pb, -1, -1,
+						LDAP_PWPOLICY_ACCTLOCKED );
+			}
+			if (send_result)
+				send_ldap_result ( pb, LDAP_CONSTRAINT_VIOLATION, NULL,
+						"Exceed password retry limit. Contact system administrator to reset.",
+						0, NULL );
+			goto locked;
+		}
+		cur_time = current_time();
+		cur_time_str = format_genTime( cur_time);
+		if ( difftime ( parse_genTime( cur_time_str ), unlock_time )  < 0 ) {
+
+			/* account is locked, cannot do anything */	
+			if (pwresponse_req) {
+				slapi_pwpolicy_make_response_control ( pb, -1, -1,
+						LDAP_PWPOLICY_ACCTLOCKED );
+			}
+			if (send_result)
+				send_ldap_result ( pb, LDAP_CONSTRAINT_VIOLATION, NULL,
+						"Exceed password retry limit. Please try later.",
+						0, NULL );
+			slapi_ch_free((void **) &cur_time_str );
+			goto locked;
+		} 
+		slapi_ch_free((void **) &cur_time_str );
+	}
+
+notlocked:
+	/* account is not locked. */
+        if(check_password_policy)
+		delete_passwdPolicy(&pwpolicy);
+	return ( 0 );	
+locked:
+	if(check_password_policy)
+		delete_passwdPolicy(&pwpolicy);
+	return (1);
+
+}

+ 0 - 136
ldap/servers/slapd/pw_mgmt.c

@@ -291,142 +291,6 @@ skip:
 	return( 0 );
 }
 
-/* check_account_lock is called before bind opeation; this could be a pre-op. */
-int
-check_account_lock ( Slapi_PBlock *pb, Slapi_Entry * bind_target_entry, int pwresponse_req, int account_inactivation_only) {
-
-	time_t		unlock_time;
-	time_t		cur_time;
-	char		*cur_time_str = NULL;
-	char *accountUnlockTime;
-	passwdPolicy *pwpolicy = NULL;
-	char *dn = NULL;
-
-	/* kexcoff: account inactivation */
-	int rc = 0;
-	Slapi_ValueSet *values = NULL;
-	int type_name_disposition = 0;
-	char *actual_type_name = NULL;
-	int attr_free_flags = 0;
-	/* kexcoff - end */
-
-	if ( bind_target_entry == NULL ) 
-		return -1;
-
-	if(!account_inactivation_only)
-	{
-		dn = slapi_entry_get_ndn(bind_target_entry);
-		pwpolicy = new_passwdPolicy(pb, dn);
-	}
-
-	/* kexcoff: account inactivation */
-	/* check if the entry is locked by nsAccountLock attribute - account inactivation feature */
-
-	rc = slapi_vattr_values_get(bind_target_entry, "nsAccountLock", 
-								&values, 
-								&type_name_disposition, &actual_type_name,
-								SLAPI_VIRTUALATTRS_REQUEST_POINTERS,
-								&attr_free_flags);
-	if ( rc == 0 )
-	{
-		Slapi_Value *v = NULL;	
-		const struct berval *bvp = NULL;
-
-		if ( (slapi_valueset_first_value( values, &v ) != -1) &&
-				( bvp = slapi_value_get_berval( v )) != NULL )
-		{
-			if ( (bvp != NULL) && (strcasecmp(bvp->bv_val, "true") == 0) )
-			{
-				/* account inactivated */
-				if (!account_inactivation_only && pwresponse_req) {
-					slapi_pwpolicy_make_response_control ( pb, -1, -1,
-							LDAP_PWPOLICY_ACCTLOCKED );
-				}
-				if(!account_inactivation_only)
-					send_ldap_result ( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
-							"Account inactivated. Contact system administrator.",
-							0, NULL );
-				slapi_vattr_values_free(&values, &actual_type_name, attr_free_flags);
-				goto locked;
-			}
-		} /* else, account "activated", keep on the process */
-
-		if ( values != NULL )
-			slapi_vattr_values_free(&values, &actual_type_name, attr_free_flags);
-	}
-	/* kexcoff - end */
-
-	/*
-	 * Check if the password policy has to be checked or not
-	 */
-	if ( account_inactivation_only || pwpolicy->pw_lockout == 0 ) {
-		goto notlocked;
-	}
-
-	/*
-	 * Check the attribute of the password policy
-	 */
-
-	/* check if account is locked out.  If so, send result and return 1 */
-	{
-		unsigned int maxfailure= pwpolicy->pw_maxfailure;
-		/* It's locked if passwordRetryCount >= maxfailure */
-		if ( slapi_entry_attr_get_uint(bind_target_entry,"passwordRetryCount") < maxfailure )
-		{
-			/* Not locked */
-			goto notlocked;	
-		}
-	}
-
-	/* locked but maybe it's time to unlock it */
-	accountUnlockTime= slapi_entry_attr_get_charptr(bind_target_entry, "accountUnlockTime");
-	if (accountUnlockTime != NULL)
-	{
-		unlock_time = parse_genTime(accountUnlockTime);
-		slapi_ch_free((void **) &accountUnlockTime );
-
-		if ( pwpolicy->pw_unlock == 0 && 
-			unlock_time == NO_TIME ) {
-
-	        /* account is locked forever. contact admin to reset */
-			if (pwresponse_req) {
-				slapi_pwpolicy_make_response_control ( pb, -1, -1,
-						LDAP_PWPOLICY_ACCTLOCKED );
-			}
-	        send_ldap_result ( pb, LDAP_CONSTRAINT_VIOLATION, NULL,
-	                "Exceed password retry limit. Contact system administrator to reset."
-	                , 0, NULL );
-			goto locked;
-		}
-		cur_time = current_time();
-		cur_time_str = format_genTime( cur_time);
-		if ( difftime ( parse_genTime( cur_time_str ), unlock_time )  < 0 ) {
-
-			/* account is locked, cannot do anything */	
-			if (pwresponse_req) {
-				slapi_pwpolicy_make_response_control ( pb, -1, -1,
-						LDAP_PWPOLICY_ACCTLOCKED );
-			}
-			send_ldap_result ( pb, LDAP_CONSTRAINT_VIOLATION, NULL,
-				"Exceed password retry limit. Please try later."				, 0, NULL );
-			slapi_ch_free((void **) &cur_time_str );
-			goto locked;
-		} 
-		slapi_ch_free((void **) &cur_time_str );
-	}
-
-notlocked:
-	/* account is not locked. */
-        if(!account_inactivation_only)
-		delete_passwdPolicy(&pwpolicy);
-	return ( 0 );	
-locked:
-	if(!account_inactivation_only)
-		delete_passwdPolicy(&pwpolicy);
-	return (1);
-
-}
-
 void
 pw_init ( void ) {
 	slapdFrontendConfig_t *slapdFrontendConfig;

+ 1 - 1
ldap/servers/slapd/saslbind.c

@@ -936,7 +936,7 @@ void ids_sasl_check_bind(Slapi_PBlock *pb)
             {
                 break;
             } 
-            if ( check_account_lock(pb, bind_target_entry, pwresponse_requested, 0) == 1) {
+            if ( slapi_check_account_lock(pb, bind_target_entry, pwresponse_requested, 1, 1) == 1) {
                 slapi_entry_free(bind_target_entry);
                 break;
             }

+ 2 - 0
ldap/servers/slapd/slapi-plugin.h

@@ -5953,6 +5953,8 @@ int slapi_set_plugin_default_config(const char *type, Slapi_Value *value);
  *     */
 int slapi_get_plugin_default_config(char *type, Slapi_ValueSet **valueset);
 
+int slapi_check_account_lock( Slapi_PBlock *pb, Slapi_Entry *bind_target_entry, int pwresponse_req, int check_password_policy, int send_result);
+
 #ifdef __cplusplus
 }
 #endif