/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 2004-2007 The OpenLDAP Foundation.
+ * Copyright 2004-2008 The OpenLDAP Foundation.
* Portions Copyright 2004-2005 Howard Chu, Symas Corporation.
* Portions Copyright 2004 Hewlett-Packard Company.
* All rights reserved.
static pw_conn *pwcons;
static int ppolicy_cid;
+static int ov_count;
typedef struct pass_policy {
AttributeDescription *ad; /* attribute to which the policy applies */
m->sml_flags = 0;
m->sml_type = ad_pwdFailureTime->ad_cname;
m->sml_desc = ad_pwdFailureTime;
+ m->sml_numvals = 1;
m->sml_values = ch_calloc( sizeof(struct berval), 2 );
m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
m->sml_flags = 0;
m->sml_type = ad_pwdAccountLockedTime->ad_cname;
m->sml_desc = ad_pwdAccountLockedTime;
+ m->sml_numvals = 1;
m->sml_values = ch_calloc( sizeof(struct berval), 2 );
m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
ber_dupbv( &m->sml_values[0], ×tamp );
m->sml_flags = 0;
m->sml_type = ad_pwdGraceUseTime->ad_cname;
m->sml_desc = ad_pwdGraceUseTime;
+ m->sml_numvals = 1;
m->sml_values = ch_calloc( sizeof(struct berval), 2 );
m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
ber_dupbv( &m->sml_values[0], ×tamp );
ml->sml_flags = SLAP_MOD_INTERNAL;
ml->sml_type.bv_val = NULL;
ml->sml_desc = ad_pwdGraceUseTime;
+ ml->sml_numvals = 0;
ml->sml_values = NULL;
ml->sml_nvalues = NULL;
ml->sml_next = NULL;
ml->sml_flags = SLAP_MOD_INTERNAL;
ml->sml_type.bv_val = NULL;
ml->sml_desc = ad_pwdAccountLockedTime;
+ ml->sml_numvals = 0;
ml->sml_values = NULL;
ml->sml_nvalues = NULL;
ml->sml_next = NULL;
ml->sml_flags = SLAP_MOD_INTERNAL;
ml->sml_type.bv_val = NULL;
ml->sml_desc = ad_pwdFailureTime;
+ ml->sml_numvals = 0;
ml->sml_values = NULL;
ml->sml_nvalues = NULL;
ml->sml_next = NULL;
delmod = ml;
}
- if ((deladd == 1) && ((ml->sml_op == LDAP_MOD_ADD) ||
- (ml->sml_op == LDAP_MOD_REPLACE)))
- {
- deladd = 2;
- }
-
if ((ml->sml_op == LDAP_MOD_ADD) ||
(ml->sml_op == LDAP_MOD_REPLACE))
{
- addmod = ml;
-
- /* FIXME: there's no easy way to ensure
- * that add does not cause multiple
- * userPassword values; one way (that
- * would be consistent with the single
- * password constraint) would be to turn
- * add into replace); another would be
- * to disallow add.
- *
- * Let's check at least that a single value
- * is being added
- */
- assert( addmod->sml_values != NULL );
- assert( !BER_BVISNULL( &addmod->sml_values[ 0 ] ) );
- if ( !BER_BVISNULL( &addmod->sml_values[ 1 ] ) ) {
- rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
- rs->sr_text = "Password policy only allows one password value";
- goto return_results;
+ if ( ml->sml_values && !BER_BVISNULL( &ml->sml_values[0] )) {
+ if ( deladd == 1 )
+ deladd = 2;
+
+ /* FIXME: there's no easy way to ensure
+ * that add does not cause multiple
+ * userPassword values; one way (that
+ * would be consistent with the single
+ * password constraint) would be to turn
+ * add into replace); another would be
+ * to disallow add.
+ *
+ * Let's check at least that a single value
+ * is being added
+ */
+ if ( addmod || !BER_BVISNULL( &ml->sml_values[ 1 ] ) ) {
+ rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
+ rs->sr_text = "Password policy only allows one password value";
+ goto return_results;
+ }
+
+ addmod = ml;
+ } else {
+ /* replace can have no values, add cannot */
+ assert( ml->sml_op == LDAP_MOD_REPLACE );
}
}
* if we have a "safe password modify policy", then we need to check if we're doing
* a delete (with the old password), followed by an add (with the new password).
*
- * If we don't have this, then we fail with an error. We also skip all the checks if
+ * If we got just a delete with nothing else, just let it go. We also skip all the checks if
* the root user is bound. Root can do anything, including avoid the policies.
*/
if (!pwmod) goto do_modify;
- /*
- * Did we get a valid add mod?
- */
-
- if (!addmod) {
- rs->sr_err = LDAP_OTHER;
- rs->sr_text = "Internal Error";
- Debug( LDAP_DEBUG_TRACE,
- "cannot locate modification supplying new password\n", 0, 0, 0 );
- goto return_results;
- }
-
/*
* Build the password history list in ascending time order
* We need this, even if the user is root, in order to maintain
* the pwdHistory operational attributes properly.
*/
- if (pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) {
+ if (addmod && pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) {
struct berval oldpw;
time_t oldtime;
if (be_isroot( op )) goto do_modify;
+ if (!pp.pwdAllowUserChange) {
+ rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+ rs->sr_text = "User alteration of password is not allowed";
+ pErr = PP_passwordModNotAllowed;
+ goto return_results;
+ }
+
+ /* Just deleting? */
+ if (!addmod) {
+ /* skip everything else */
+ pwmod = 0;
+ goto do_modify;
+ }
+
/* This is a pwdModify exop that provided the old pw.
* We need to create a Delete mod for this old pw and
* let the matching value get found later
ml->sml_flags = SLAP_MOD_INTERNAL;
ml->sml_desc = pp.ad;
ml->sml_type = pp.ad->ad_cname;
+ ml->sml_numvals = 1;
ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
ber_dupbv( &ml->sml_values[0], &oldpw );
BER_BVZERO( &ml->sml_values[1] );
goto return_results;
}
- if (!pp.pwdAllowUserChange) {
- rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
- rs->sr_text = "User alteration of password is not allowed";
- pErr = PP_passwordModNotAllowed;
- goto return_results;
- }
-
/* Check age, but only if pwdReset is not TRUE */
pa = attr_find( e->e_attrs, ad_pwdReset );
if ((!pa || !bvmatch( &pa->a_nvals[0], &slap_true_bv )) &&
}
}
- if (pa) {
+ /* If pwdInHistory is zero, passwords may be reused */
+ if (pa && pp.pwdInHistory > 0) {
/*
* Last check - the password history.
*/
goto return_results;
}
- if (pp.pwdInHistory < 1) goto do_modify;
-
/*
* Iterate through the password history, and fail on any
* password matches.
mods->sml_desc = ad_pwdChangedTime;
if (pwmop != LDAP_MOD_DELETE) {
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], ×tamp );
BER_BVZERO( &mods->sml_values[1] );
mods->sml_op = LDAP_MOD_DELETE;
mods->sml_flags = SLAP_MOD_INTERNAL;
mods->sml_desc = ad_pwdHistory;
+ mods->sml_numvals = hsize - pp.pwdInHistory + 1;
mods->sml_values = ch_calloc( sizeof( struct berval ),
hsize - pp.pwdInHistory + 2 );
BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] );
mods->sml_type.bv_val = NULL;
mods->sml_desc = ad_pwdHistory;
mods->sml_nvalues = NULL;
+ mods->sml_numvals = 1;
mods->sml_values = ch_calloc( sizeof( struct berval ), 2 );
mods->sml_values[ 1 ].bv_val = NULL;
mods->sml_values[ 1 ].bv_len = 0;
on->on_bi.bi_private = ch_calloc( sizeof(pp_info), 1 );
- if ( dtblsize && !pwcons )
- pwcons = ch_calloc(sizeof(pw_conn), dtblsize );
+ if ( dtblsize && !pwcons ) {
+ /* accommodate for c_conn_idx == -1 */
+ pwcons = ch_calloc( sizeof(pw_conn), dtblsize + 1 );
+ pwcons++;
+ }
return 0;
}
ConfigReply *cr
)
{
+ ov_count++;
return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
}
{
slap_overinst *on = (slap_overinst *) be->bd_info;
pp_info *pi = on->on_bi.bi_private;
-
- free( pwcons );
+
+ /* Perhaps backover should provide bi_destroy hooks... */
+ ov_count--;
+ if ( ov_count <=0 && pwcons ) {
+ pwcons--;
+ free( pwcons );
+ pwcons = NULL;
+ }
free( pi->def_policy.bv_val );
free( pi );