/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 2004-2015 The OpenLDAP Foundation.
+ * Copyright 2004-2017 The OpenLDAP Foundation.
* Portions Copyright 2004-2005 Howard Chu, Symas Corporation.
* Portions Copyright 2004 Hewlett-Packard Company.
* All rights reserved.
#define MODULE_NAME_SZ 256
#endif
+#ifndef PPOLICY_DEFAULT_MAXRECORDED_FAILURE
+#define PPOLICY_DEFAULT_MAXRECORDED_FAILURE 5
+#endif
+
/* Per-instance configuration information */
typedef struct pp_info {
struct berval def_policy; /* DN of default policy subentry */
int pwdLockout; /* 0 = do not lockout passwords, 1 = lock them out */
int pwdLockoutDuration; /* time in seconds a password is locked out for */
int pwdMaxFailure; /* number of failed binds allowed before lockout */
+ int pwdMaxRecordedFailure; /* number of failed binds to store */
int pwdFailureCountInterval; /* number of seconds before failure
counts are zeroed */
int pwdMustChange; /* 0 = users can use admin set password
*ad_pwdGraceAuthNLimit, *ad_pwdExpireWarning, *ad_pwdLockoutDuration,
*ad_pwdFailureCountInterval, *ad_pwdCheckModule, *ad_pwdLockout,
*ad_pwdMustChange, *ad_pwdAllowUserChange, *ad_pwdSafeModify,
- *ad_pwdAttribute;
+ *ad_pwdAttribute, *ad_pwdMaxRecordedFailure;
#define TAB(name) { #name, &ad_##name }
TAB(pwdCheckQuality),
TAB(pwdMinLength),
TAB(pwdMaxFailure),
+ TAB(pwdMaxRecordedFailure),
TAB(pwdGraceAuthNLimit),
TAB(pwdExpireWarning),
TAB(pwdLockout),
rc = 0;
break;
case SLAP_CONFIG_ADD:
- /* fallthrough to LDAP_MOD_ADD */
+ /* fallthru to LDAP_MOD_ADD */
case LDAP_MOD_ADD:
Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default add\n", 0, 0, 0);
if ( pi->def_policy.bv_val ) {
return oldctrls;
}
+static void
+ppolicy_get_default( PassPolicy *pp )
+{
+ memset( pp, 0, sizeof(PassPolicy) );
+
+ pp->ad = slap_schema.si_ad_userPassword;
+
+ /* Users can change their own password by default */
+ pp->pwdAllowUserChange = 1;
+ if ( !pp->pwdMaxRecordedFailure )
+ pp->pwdMaxRecordedFailure = PPOLICY_DEFAULT_MAXRECORDED_FAILURE;
+}
+
+
static void
ppolicy_get( Operation *op, Entry *e, PassPolicy *pp )
{
const char *text;
#endif
- memset( pp, 0, sizeof(PassPolicy) );
-
- pp->ad = slap_schema.si_ad_userPassword;
-
- /* Users can change their own password by default */
- pp->pwdAllowUserChange = 1;
+ ppolicy_get_default( pp );
if ((a = attr_find( e->e_attrs, ad_pwdPolicySubentry )) == NULL) {
/*
if ( ( a = attr_find( pe->e_attrs, ad_pwdMaxFailure ) )
&& lutil_atoi( &pp->pwdMaxFailure, a->a_vals[0].bv_val ) != 0 )
goto defaultpol;
+ if ( ( a = attr_find( pe->e_attrs, ad_pwdMaxRecordedFailure ) )
+ && lutil_atoi( &pp->pwdMaxRecordedFailure, a->a_vals[0].bv_val ) != 0 )
+ goto defaultpol;
if ( ( a = attr_find( pe->e_attrs, ad_pwdGraceAuthNLimit ) )
&& lutil_atoi( &pp->pwdGraceAuthNLimit, a->a_vals[0].bv_val ) != 0 )
goto defaultpol;
if ((a = attr_find( pe->e_attrs, ad_pwdSafeModify )))
pp->pwdSafeModify = bvmatch( &a->a_nvals[0], &slap_true_bv );
+ if ( pp->pwdMaxRecordedFailure < pp->pwdMaxFailure )
+ pp->pwdMaxRecordedFailure = pp->pwdMaxFailure;
+ if ( !pp->pwdMaxRecordedFailure )
+ pp->pwdMaxRecordedFailure = PPOLICY_DEFAULT_MAXRECORDED_FAILURE;
+
op->o_bd->bd_info = (BackendInfo *)on->on_info;
be_entry_release_r( op, pe );
op->o_bd->bd_info = (BackendInfo *)on;
return;
defaultpol:
+ if ( pe ) {
+ op->o_bd->bd_info = (BackendInfo *)on->on_info;
+ be_entry_release_r( op, pe );
+ op->o_bd->bd_info = (BackendInfo *)on;
+ }
+
Debug( LDAP_DEBUG_TRACE,
"ppolicy_get: using default policy\n", 0, 0, 0 );
+
+ ppolicy_get_default( pp );
+
return;
}
* which are not due to expire.
*/
}
+ /* Do we have too many timestamps? If so, delete some values.
+ * We don't bother to sort the values here. OpenLDAP keeps the
+ * values in order by default. Fundamentally, relying on the
+ * information here is wrong anyway; monitoring systems should
+ * be tracking Bind failures in syslog, not here.
+ */
+ if (a->a_numvals >= ppb->pp.pwdMaxRecordedFailure) {
+ int j = ppb->pp.pwdMaxRecordedFailure-1;
+ /* If more than 2x, cheaper to perform a Replace */
+ if (a->a_numvals >= 2 * ppb->pp.pwdMaxRecordedFailure) {
+ struct berval v, nv;
+
+ /* Change the mod we constructed above */
+ m->sml_op = LDAP_MOD_REPLACE;
+ m->sml_numvals = ppb->pp.pwdMaxRecordedFailure;
+ v = m->sml_values[0];
+ nv = m->sml_nvalues[0];
+ ch_free(m->sml_values);
+ ch_free(m->sml_nvalues);
+ m->sml_values = ch_calloc( sizeof(struct berval), ppb->pp.pwdMaxRecordedFailure+1 );
+ m->sml_nvalues = ch_calloc( sizeof(struct berval), ppb->pp.pwdMaxRecordedFailure+1 );
+ for (i=0; i<j; i++) {
+ ber_dupbv(&m->sml_values[i], &a->a_vals[a->a_numvals-j+i]);
+ ber_dupbv(&m->sml_nvalues[i], &a->a_nvals[a->a_numvals-j+i]);
+ }
+ m->sml_values[i] = v;
+ m->sml_nvalues[i] = nv;
+ } else {
+ /* else just delete some */
+ m = ch_calloc( sizeof(Modifications), 1 );
+ m->sml_op = LDAP_MOD_DELETE;
+ m->sml_type = ad_pwdFailureTime->ad_cname;
+ m->sml_desc = ad_pwdFailureTime;
+ m->sml_numvals = a->a_numvals - j;
+ m->sml_values = ch_calloc( sizeof(struct berval), m->sml_numvals+1 );
+ m->sml_nvalues = ch_calloc( sizeof(struct berval), m->sml_numvals+1 );
+ for (i=0; i<m->sml_numvals; i++) {
+ ber_dupbv(&m->sml_values[i], &a->a_vals[i]);
+ ber_dupbv(&m->sml_nvalues[i], &a->a_nvals[i]);
+ }
+ m->sml_next = mod;
+ mod = m;
+ }
+ }
}
if ((ppb->pp.pwdMaxFailure > 0) &&