]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/ppolicy.c
ITS#8605 - spelling fixes
[openldap] / servers / slapd / overlays / ppolicy.c
index f8b73356e617320141819e613266bb44b577f61c..e13c33a86629945f9d6e7f571356bfbbbcbf12f7 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2004-2014 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 */
@@ -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 }
 
@@ -191,6 +196,7 @@ static struct schema_info pwd_UsSchema[] = {
        TAB(pwdCheckQuality),
        TAB(pwdMinLength),
        TAB(pwdMaxFailure),
+       TAB(pwdMaxRecordedFailure),
        TAB(pwdGraceAuthNLimit),
        TAB(pwdExpireWarning),
        TAB(pwdLockout),
@@ -283,7 +289,7 @@ ppolicy_cf_default( ConfigArgs *c )
                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 ) {
@@ -382,6 +388,7 @@ create_passcontrol( Operation *op, int exptime, int grace, LDAPPasswordPolicyErr
        BerElement *ber = (BerElement *) &berbuf, *b2 = (BerElement *) &bb2;
        LDAPControl c = { 0 }, *cp;
        struct berval bv;
+       int rc;
 
        BER_BVZERO( &c.ldctl_value );
 
@@ -391,15 +398,23 @@ create_passcontrol( Operation *op, int exptime, int grace, LDAPPasswordPolicyErr
        if ( exptime >= 0 ) {
                ber_init2( b2, NULL, LBER_USE_DER );
                ber_printf( b2, "ti", PPOLICY_EXPIRE, exptime );
-               ber_flatten2( b2, &bv, 1 );
+               rc = ber_flatten2( b2, &bv, 1 );
                (void)ber_free_buf(b2);
+               if (rc == -1) {
+                       cp = NULL;
+                       goto fail;
+               }
                ber_printf( ber, "tO", PPOLICY_WARNING, &bv );
                ch_free( bv.bv_val );
        } else if ( grace > 0 ) {
                ber_init2( b2, NULL, LBER_USE_DER );
                ber_printf( b2, "ti", PPOLICY_GRACE, grace );
-               ber_flatten2( b2, &bv, 1 );
+               rc = ber_flatten2( b2, &bv, 1 );
                (void)ber_free_buf(b2);
+               if (rc == -1) {
+                       cp = NULL;
+                       goto fail;
+               }
                ber_printf( ber, "tO", PPOLICY_WARNING, &bv );
                ch_free( bv.bv_val );
        }
@@ -418,6 +433,7 @@ create_passcontrol( Operation *op, int exptime, int grace, LDAPPasswordPolicyErr
        cp->ldctl_value.bv_val = (char *)&cp[1];
        cp->ldctl_value.bv_len = c.ldctl_value.bv_len;
        AC_MEMCPY( cp->ldctl_value.bv_val, c.ldctl_value.bv_val, c.ldctl_value.bv_len );
+fail:
        (void)ber_free_buf(ber);
        
        return cp;
@@ -452,6 +468,20 @@ add_passcontrol( Operation *op, SlapReply *rs, LDAPControl *ctrl )
        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 )
 {
@@ -465,12 +495,7 @@ 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) {
                /*
@@ -517,6 +542,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;
@@ -545,6 +573,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;
@@ -552,8 +585,17 @@ ppolicy_get( Operation *op, Entry *e, PassPolicy *pp )
        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;
 }
 
@@ -989,6 +1031,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), 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) &&
@@ -1273,7 +1359,7 @@ ppolicy_bind( Operation *op, SlapReply *rs )
 static int
 ppolicy_connection_destroy( BackendDB *bd, Connection *conn )
 {
-       if ( !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) {
+       if ( pwcons && !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) {
                ch_free( pwcons[conn->c_conn_idx].dn.bv_val );
                BER_BVZERO( &pwcons[conn->c_conn_idx].dn );
        }
@@ -1555,6 +1641,8 @@ ppolicy_modify( Operation *op, SlapReply *rs )
        LDAPControl             *ctrl = NULL;
        LDAPControl             **oldctrls = NULL;
        int                     is_pwdexop = 0;
+       int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0;
+       int got_changed = 0, got_history = 0;
 
        op->o_bd->bd_info = (BackendInfo *)on->on_info;
        rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
@@ -1567,7 +1655,6 @@ ppolicy_modify( Operation *op, SlapReply *rs )
         */
        if ( be_shadow_update( op )) {
                Modifications **prev;
-               int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0;
                Attribute *a_grace, *a_lock, *a_fail;
 
                a_grace = attr_find( e->e_attrs, ad_pwdGraceUseTime );
@@ -1586,19 +1673,25 @@ ppolicy_modify( Operation *op, SlapReply *rs )
                                int drop = 0;
 
                                if ( ml->sml_desc == ad_pwdGraceUseTime ) {
-                                       got_del_grace = 1;
-                                       if ( !a_grace )
+                                       if ( !a_grace || got_del_grace ) {
                                                drop = 1;
+                                       } else {
+                                               got_del_grace = 1;
+                                       }
                                } else
                                if ( ml->sml_desc == ad_pwdAccountLockedTime ) {
-                                       got_del_lock = 1;
-                                       if ( !a_lock )
+                                       if ( !a_lock || got_del_lock ) {
                                                drop = 1;
+                                       } else {
+                                               got_del_lock = 1;
+                                       }
                                } else
                                if ( ml->sml_desc == ad_pwdFailureTime ) {
-                                       got_del_fail = 1;
-                                       if ( !a_fail )
+                                       if ( !a_fail || got_del_fail ) {
                                                drop = 1;
+                                       } else {
+                                               got_del_fail = 1;
+                                       }
                                }
                                if ( drop ) {
                                        *prev = ml->sml_next;
@@ -1750,6 +1843,20 @@ ppolicy_modify( Operation *op, SlapReply *rs )
                                (ml->sml_op == LDAP_MOD_REPLACE))
                                zapReset = 0;
                }
+               if ( ml->sml_op == LDAP_MOD_DELETE ) {
+                       if ( ml->sml_desc == ad_pwdGraceUseTime ) {
+                               got_del_grace = 1;
+                       } else if ( ml->sml_desc == ad_pwdAccountLockedTime ) {
+                               got_del_lock = 1;
+                       } else if ( ml->sml_desc == ad_pwdFailureTime ) {
+                               got_del_fail = 1;
+                       }
+               }
+               if ( ml->sml_desc == ad_pwdChangedTime ) {
+                       got_changed = 1;
+               } else if (ml->sml_desc == ad_pwdHistory ) {
+                       got_history = 1;
+               }
        }
        
        if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) {
@@ -1986,32 +2093,34 @@ do_modify:
                 * up to date.
                 */
 
-               timestamp.bv_val = timebuf;
-               timestamp.bv_len = sizeof(timebuf);
-               slap_timestamp( &now, &timestamp );
+               if (!got_changed) {
+                       timestamp.bv_val = timebuf;
+                       timestamp.bv_len = sizeof(timebuf);
+                       slap_timestamp( &now, &timestamp );
 
-               mods = NULL;
-               if (pwmop != LDAP_MOD_DELETE) {
-                       mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
-                       mods->sml_op = LDAP_MOD_REPLACE;
-                       mods->sml_numvals = 1;
-                       mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
-                       ber_dupbv( &mods->sml_values[0], &timestamp );
-                       BER_BVZERO( &mods->sml_values[1] );
-                       assert( !BER_BVISNULL( &mods->sml_values[0] ) );
-               } else if (attr_find(e->e_attrs, ad_pwdChangedTime )) {
-                       mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
-                       mods->sml_op = LDAP_MOD_DELETE;
-               }
-               if (mods) {
-                       mods->sml_desc = ad_pwdChangedTime;
-                       mods->sml_flags = SLAP_MOD_INTERNAL;
-                       mods->sml_next = NULL;
-                       modtail->sml_next = mods;
-                       modtail = mods;
+                       mods = NULL;
+                       if (pwmop != LDAP_MOD_DELETE) {
+                               mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
+                               mods->sml_op = LDAP_MOD_REPLACE;
+                               mods->sml_numvals = 1;
+                               mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
+                               ber_dupbv( &mods->sml_values[0], &timestamp );
+                               BER_BVZERO( &mods->sml_values[1] );
+                               assert( !BER_BVISNULL( &mods->sml_values[0] ) );
+                       } else if (attr_find(e->e_attrs, ad_pwdChangedTime )) {
+                               mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
+                               mods->sml_op = LDAP_MOD_DELETE;
+                       }
+                       if (mods) {
+                               mods->sml_desc = ad_pwdChangedTime;
+                               mods->sml_flags = SLAP_MOD_INTERNAL;
+                               mods->sml_next = NULL;
+                               modtail->sml_next = mods;
+                               modtail = mods;
+                       }
                }
 
-               if (attr_find(e->e_attrs, ad_pwdGraceUseTime )) {
+               if (!got_del_grace && attr_find(e->e_attrs, ad_pwdGraceUseTime )) {
                        mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
                        mods->sml_op = LDAP_MOD_DELETE;
                        mods->sml_desc = ad_pwdGraceUseTime;
@@ -2021,7 +2130,7 @@ do_modify:
                        modtail = mods;
                }
 
-               if (attr_find(e->e_attrs, ad_pwdAccountLockedTime )) {
+               if (!got_del_lock && attr_find(e->e_attrs, ad_pwdAccountLockedTime )) {
                        mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
                        mods->sml_op = LDAP_MOD_DELETE;
                        mods->sml_desc = ad_pwdAccountLockedTime;
@@ -2031,7 +2140,7 @@ do_modify:
                        modtail = mods;
                }
 
-               if (attr_find(e->e_attrs, ad_pwdFailureTime )) {
+               if (!got_del_fail && attr_find(e->e_attrs, ad_pwdFailureTime )) {
                        mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
                        mods->sml_op = LDAP_MOD_DELETE;
                        mods->sml_desc = ad_pwdFailureTime;
@@ -2052,7 +2161,7 @@ do_modify:
                        modtail = mods;
                }
 
-               if (pp.pwdInHistory > 0) {
+               if (!got_history && pp.pwdInHistory > 0) {
                        if (hsize >= pp.pwdInHistory) {
                                /*
                                 * We use the >= operator, since we are going to add
@@ -2305,6 +2414,8 @@ ppolicy_db_init(
                pwcons++;
        }
 
+       ov_count++;
+
        return 0;
 }
 
@@ -2314,33 +2425,42 @@ ppolicy_db_open(
        ConfigReply *cr
 )
 {
-       ov_count++;
        return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
 }
 
 static int
-ppolicy_close(
+ppolicy_db_close(
        BackendDB *be,
        ConfigReply *cr
 )
 {
-       slap_overinst *on = (slap_overinst *) be->bd_info;
-       pp_info *pi = on->on_bi.bi_private;
-
 #ifdef SLAP_CONFIG_DELETE
        overlay_unregister_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
 #endif /* SLAP_CONFIG_DELETE */
 
-       /* Perhaps backover should provide bi_destroy hooks... */
+       return 0;
+}
+
+static int
+ppolicy_db_destroy(
+       BackendDB *be,
+       ConfigReply *cr
+)
+{
+       slap_overinst *on = (slap_overinst *) be->bd_info;
+       pp_info *pi = on->on_bi.bi_private;
+
+       on->on_bi.bi_private = NULL;
+       free( pi->def_policy.bv_val );
+       free( pi );
+
        ov_count--;
        if ( ov_count <=0 && pwcons ) {
-               pwcons--;
-               free( pwcons );
+               pw_conn *pwc = pwcons;
                pwcons = NULL;
+               pwc--;
+               ch_free( pwc );
        }
-       free( pi->def_policy.bv_val );
-       free( pi );
-
        return 0;
 }
 
@@ -2382,7 +2502,8 @@ int ppolicy_initialize()
        ppolicy.on_bi.bi_type = "ppolicy";
        ppolicy.on_bi.bi_db_init = ppolicy_db_init;
        ppolicy.on_bi.bi_db_open = ppolicy_db_open;
-       ppolicy.on_bi.bi_db_close = ppolicy_close;
+       ppolicy.on_bi.bi_db_close = ppolicy_db_close;
+       ppolicy.on_bi.bi_db_destroy = ppolicy_db_destroy;
 
        ppolicy.on_bi.bi_op_add = ppolicy_add;
        ppolicy.on_bi.bi_op_bind = ppolicy_bind;