From af27b7032e36fb8735c17d9b1a0020ee3e18057d Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Fri, 14 Aug 2015 15:19:46 +0100 Subject: [PATCH] ITS#8185 add pwdMaxRecordedFailure Limit the number of pwdFailureTime stamps to record, regardless of lockout settings. --- doc/man/man5/slapo-ppolicy.5 | 23 ++++++++++- servers/slapd/overlays/ppolicy.c | 59 ++++++++++++++++++++++++++++- servers/slapd/schema/ppolicy.ldif | 5 ++- servers/slapd/schema/ppolicy.schema | 17 ++++++++- 4 files changed, 100 insertions(+), 4 deletions(-) diff --git a/doc/man/man5/slapo-ppolicy.5 b/doc/man/man5/slapo-ppolicy.5 index 9703621993..3e75790ae1 100644 --- a/doc/man/man5/slapo-ppolicy.5 +++ b/doc/man/man5/slapo-ppolicy.5 @@ -104,7 +104,7 @@ object class. The definition of that class is as follows: pwdLockout $ pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $ pwdMustChange $ pwdAllowUserChange $ - pwdSafeModify ) ) + pwdSafeModify 4 pwdMaxRecordedFailure ) ) .RE This implementation also provides an additional @@ -365,6 +365,25 @@ and SINGLE\-VALUE ) .RE +.B pwdMaxRecordedFailure +.P +This attribute contains the maximum number of failed bind +attempts to store in a user's entry. +If +.B pwdMaxRecordedFailure +is not present, or its value is zero (0), then it defaults +to the value of +.BR pwdMaxFailure . +If that value is also 0, the default is 5. +.LP +.RS 4 +( 1.3.6.1.4.1.42.2.27.8.1.16 + NAME 'pwdMaxRecordedFailure' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE\-VALUE ) +.RE + .B pwdFailureCountInterval .P This attribute contains the number of seconds after which old @@ -641,6 +660,8 @@ account may be locked. password policy attribute.) Excess timestamps beyond those allowed by .B pwdMaxFailure +or +.B pwdMaxRecordedFailure may also be purged. If a successful authentication is made to this DN (i.e. to this user account), then .B pwdFailureTime diff --git a/servers/slapd/overlays/ppolicy.c b/servers/slapd/overlays/ppolicy.c index ad229c5f1e..51343fcdbf 100644 --- a/servers/slapd/overlays/ppolicy.c +++ b/servers/slapd/overlays/ppolicy.c @@ -45,6 +45,10 @@ #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 */ @@ -79,6 +83,7 @@ typedef struct pass_policy { 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 @@ -179,7 +184,7 @@ static AttributeDescription *ad_pwdMinAge, *ad_pwdMaxAge, *ad_pwdInHistory, *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 } @@ -527,6 +532,9 @@ ppolicy_get( Operation *op, Entry *e, PassPolicy *pp ) 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; @@ -555,6 +563,11 @@ ppolicy_get( Operation *op, Entry *e, PassPolicy *pp ) 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; @@ -999,6 +1012,50 @@ ppolicy_bind_response( Operation *op, SlapReply *rs ) * 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), 2 ); + m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); + for (i=0; isml_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 ); + m->sml_nvalues = ch_calloc( sizeof(struct berval), m->sml_numvals ); + for (i=0; isml_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) && diff --git a/servers/slapd/schema/ppolicy.ldif b/servers/slapd/schema/ppolicy.ldif index 8b37196277..1aa9c33b3f 100644 --- a/servers/slapd/schema/ppolicy.ldif +++ b/servers/slapd/schema/ppolicy.ldif @@ -75,10 +75,13 @@ olcAttributeTypes: {14}( 1.3.6.1.4.1.42.2.27.8.1.15 NAME 'pwdSafeModify' EQUAL olcAttributeTypes: {15}( 1.3.6.1.4.1.4754.1.99.1 NAME 'pwdCheckModule' DESC 'L oadable module that instantiates "check_password() function' EQUALITY caseExa ctIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) +olcAttributeTypes: {16}( 1.3.6.1.4.1.42.2.27.8.1.16 NAME 'pwdMaxRecordedFailur + e' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1. + 1466.115.121.1.27 SINGLE-VALUE ) olcObjectClasses: {0}( 1.3.6.1.4.1.4754.2.99.1 NAME 'pwdPolicyChecker' SUP top AUXILIARY MAY pwdCheckModule ) olcObjectClasses: {1}( 1.3.6.1.4.1.42.2.27.8.2.1 NAME 'pwdPolicy' SUP top AUXI LIARY MUST pwdAttribute MAY ( pwdMinAge $ pwdMaxAge $ pwdInHistory $ pwdCheck Quality $ pwdMinLength $ pwdExpireWarning $ pwdGraceAuthNLimit $ pwdLockout $ pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $ pwdMustChange - $ pwdAllowUserChange $ pwdSafeModify ) ) + $ pwdAllowUserChange $ pwdSafeModify $ pwdMaxRecordedFailure ) ) diff --git a/servers/slapd/schema/ppolicy.schema b/servers/slapd/schema/ppolicy.schema index 18bb1e60bf..6d27e3bfa2 100644 --- a/servers/slapd/schema/ppolicy.schema +++ b/servers/slapd/schema/ppolicy.schema @@ -325,6 +325,20 @@ attributetype ( 1.3.6.1.4.1.42.2.27.8.1.15 SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) +#ITS#8185 pwdMaxRecordedFailure +# +# This attribute specifies the maximum number of consecutive failed bind +# attempts to record. If this attribute is not present, or if the value +# is 0, it defaults to the value of pwdMaxFailure. If that value is also +# 0, this value defaults to 5. + +attributetype ( 1.3.6.1.4.1.42.2.27.8.1.16 + NAME 'pwdMaxRecordedFailure' + EQUALITY integerMatch + ORDERING integerOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) + # HP extensions # # pwdCheckModule @@ -366,7 +380,8 @@ objectclass ( 1.3.6.1.4.1.42.2.27.8.2.1 MAY ( pwdMinAge $ pwdMaxAge $ pwdInHistory $ pwdCheckQuality $ pwdMinLength $ pwdExpireWarning $ pwdGraceAuthNLimit $ pwdLockout $ pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $ - pwdMustChange $ pwdAllowUserChange $ pwdSafeModify ) ) + pwdMustChange $ pwdAllowUserChange $ pwdSafeModify $ + pwdMaxRecordedFailure ) ) #5.3 Attribute Types for Password Policy State Information # -- 2.39.2