Home | History | Annotate | Line # | Download | only in overlays
ppolicy.c revision 1.1
      1 /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/ppolicy.c,v 1.75.2.11 2008/02/13 01:58:56 quanah Exp $ */
      2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      3  *
      4  * Copyright 2004-2008 The OpenLDAP Foundation.
      5  * Portions Copyright 2004-2005 Howard Chu, Symas Corporation.
      6  * Portions Copyright 2004 Hewlett-Packard Company.
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted only as authorized by the OpenLDAP
     11  * Public License.
     12  *
     13  * A copy of this license is available in the file LICENSE in the
     14  * top-level directory of the distribution or, alternatively, at
     15  * <http://www.OpenLDAP.org/license.html>.
     16  */
     17 /* ACKNOWLEDGEMENTS:
     18  * This work was developed by Howard Chu for inclusion in
     19  * OpenLDAP Software, based on prior work by Neil Dunbar (HP).
     20  * This work was sponsored by the Hewlett-Packard Company.
     21  */
     22 
     23 #include "portable.h"
     24 
     25 /* This file implements "Password Policy for LDAP Directories",
     26  * based on draft behera-ldap-password-policy-09
     27  */
     28 
     29 #ifdef SLAPD_OVER_PPOLICY
     30 
     31 #include <ldap.h>
     32 #include "lutil.h"
     33 #include "slap.h"
     34 #ifdef SLAPD_MODULES
     35 #define LIBLTDL_DLL_IMPORT	/* Win32: don't re-export libltdl's symbols */
     36 #include <ltdl.h>
     37 #endif
     38 #include <ac/errno.h>
     39 #include <ac/time.h>
     40 #include <ac/string.h>
     41 #include <ac/ctype.h>
     42 #include "config.h"
     43 
     44 #ifndef MODULE_NAME_SZ
     45 #define MODULE_NAME_SZ 256
     46 #endif
     47 
     48 /* Per-instance configuration information */
     49 typedef struct pp_info {
     50 	struct berval def_policy;	/* DN of default policy subentry */
     51 	int use_lockout;		/* send AccountLocked result? */
     52 	int hash_passwords;		/* transparently hash cleartext pwds */
     53 } pp_info;
     54 
     55 /* Our per-connection info - note, it is not per-instance, it is
     56  * used by all instances
     57  */
     58 typedef struct pw_conn {
     59 	struct berval dn;	/* DN of restricted user */
     60 } pw_conn;
     61 
     62 static pw_conn *pwcons;
     63 static int ppolicy_cid;
     64 static int ov_count;
     65 
     66 typedef struct pass_policy {
     67 	AttributeDescription *ad; /* attribute to which the policy applies */
     68 	int pwdMinAge; /* minimum time (seconds) until passwd can change */
     69 	int pwdMaxAge; /* time in seconds until pwd will expire after change */
     70 	int pwdInHistory; /* number of previous passwords kept */
     71 	int pwdCheckQuality; /* 0 = don't check quality, 1 = check if possible,
     72 						   2 = check mandatory; fail if not possible */
     73 	int pwdMinLength; /* minimum number of chars in password */
     74 	int pwdExpireWarning; /* number of seconds that warning controls are
     75 							sent before a password expires */
     76 	int pwdGraceAuthNLimit; /* number of times you can log in with an
     77 							expired password */
     78 	int pwdLockout; /* 0 = do not lockout passwords, 1 = lock them out */
     79 	int pwdLockoutDuration; /* time in seconds a password is locked out for */
     80 	int pwdMaxFailure; /* number of failed binds allowed before lockout */
     81 	int pwdFailureCountInterval; /* number of seconds before failure
     82 									counts are zeroed */
     83 	int pwdMustChange; /* 0 = users can use admin set password
     84 							1 = users must change password after admin set */
     85 	int pwdAllowUserChange; /* 0 = users cannot change their passwords
     86 								1 = users can change them */
     87 	int pwdSafeModify; /* 0 = old password doesn't need to come
     88 								with password change request
     89 							1 = password change must supply existing pwd */
     90 	char pwdCheckModule[MODULE_NAME_SZ]; /* name of module to dynamically
     91 										    load to check password */
     92 } PassPolicy;
     93 
     94 typedef struct pw_hist {
     95 	time_t t;	/* timestamp of history entry */
     96 	struct berval pw;	/* old password hash */
     97 	struct berval bv;	/* text of entire entry */
     98 	struct pw_hist *next;
     99 } pw_hist;
    100 
    101 /* Operational attributes */
    102 static AttributeDescription *ad_pwdChangedTime, *ad_pwdAccountLockedTime,
    103 	*ad_pwdFailureTime, *ad_pwdHistory, *ad_pwdGraceUseTime, *ad_pwdReset,
    104 	*ad_pwdPolicySubentry;
    105 
    106 static struct schema_info {
    107 	char *def;
    108 	AttributeDescription **ad;
    109 } pwd_OpSchema[] = {
    110 	{	"( 1.3.6.1.4.1.42.2.27.8.1.16 "
    111 		"NAME ( 'pwdChangedTime' ) "
    112 		"DESC 'The time the password was last changed' "
    113 		"EQUALITY generalizedTimeMatch "
    114 		"ORDERING generalizedTimeOrderingMatch "
    115 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
    116 		"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
    117 		&ad_pwdChangedTime },
    118 	{	"( 1.3.6.1.4.1.42.2.27.8.1.17 "
    119 		"NAME ( 'pwdAccountLockedTime' ) "
    120 		"DESC 'The time an user account was locked' "
    121 		"EQUALITY generalizedTimeMatch "
    122 		"ORDERING generalizedTimeOrderingMatch "
    123 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
    124 		"SINGLE-VALUE "
    125 #if 0
    126 		/* Not until Relax control is released */
    127 		"NO-USER-MODIFICATION "
    128 #endif
    129 		"USAGE directoryOperation )",
    130 		&ad_pwdAccountLockedTime },
    131 	{	"( 1.3.6.1.4.1.42.2.27.8.1.19 "
    132 		"NAME ( 'pwdFailureTime' ) "
    133 		"DESC 'The timestamps of the last consecutive authentication failures' "
    134 		"EQUALITY generalizedTimeMatch "
    135 		"ORDERING generalizedTimeOrderingMatch "
    136 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
    137 		"NO-USER-MODIFICATION USAGE directoryOperation )",
    138 		&ad_pwdFailureTime },
    139 	{	"( 1.3.6.1.4.1.42.2.27.8.1.20 "
    140 		"NAME ( 'pwdHistory' ) "
    141 		"DESC 'The history of users passwords' "
    142 		"EQUALITY octetStringMatch "
    143 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 "
    144 		"NO-USER-MODIFICATION USAGE directoryOperation )",
    145 		&ad_pwdHistory },
    146 	{	"( 1.3.6.1.4.1.42.2.27.8.1.21 "
    147 		"NAME ( 'pwdGraceUseTime' ) "
    148 		"DESC 'The timestamps of the grace login once the password has expired' "
    149 		"EQUALITY generalizedTimeMatch "
    150 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
    151 		"NO-USER-MODIFICATION USAGE directoryOperation )",
    152 		&ad_pwdGraceUseTime },
    153 	{	"( 1.3.6.1.4.1.42.2.27.8.1.22 "
    154 		"NAME ( 'pwdReset' ) "
    155 		"DESC 'The indication that the password has been reset' "
    156 		"EQUALITY booleanMatch "
    157 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
    158 		"SINGLE-VALUE USAGE directoryOperation )",
    159 		&ad_pwdReset },
    160 	{	"( 1.3.6.1.4.1.42.2.27.8.1.23 "
    161 		"NAME ( 'pwdPolicySubentry' ) "
    162 		"DESC 'The pwdPolicy subentry in effect for this object' "
    163 		"EQUALITY distinguishedNameMatch "
    164 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
    165 		"SINGLE-VALUE "
    166 #if 0
    167 		/* Not until Relax control is released */
    168 		"NO-USER-MODIFICATION "
    169 #endif
    170 		"USAGE directoryOperation )",
    171 		&ad_pwdPolicySubentry },
    172 	{ NULL, NULL }
    173 };
    174 
    175 /* User attributes */
    176 static AttributeDescription *ad_pwdMinAge, *ad_pwdMaxAge, *ad_pwdInHistory,
    177 	*ad_pwdCheckQuality, *ad_pwdMinLength, *ad_pwdMaxFailure,
    178 	*ad_pwdGraceAuthNLimit, *ad_pwdExpireWarning, *ad_pwdLockoutDuration,
    179 	*ad_pwdFailureCountInterval, *ad_pwdCheckModule, *ad_pwdLockout,
    180 	*ad_pwdMustChange, *ad_pwdAllowUserChange, *ad_pwdSafeModify,
    181 	*ad_pwdAttribute;
    182 
    183 #define TAB(name)	{ #name, &ad_##name }
    184 
    185 static struct schema_info pwd_UsSchema[] = {
    186 	TAB(pwdAttribute),
    187 	TAB(pwdMinAge),
    188 	TAB(pwdMaxAge),
    189 	TAB(pwdInHistory),
    190 	TAB(pwdCheckQuality),
    191 	TAB(pwdMinLength),
    192 	TAB(pwdMaxFailure),
    193 	TAB(pwdGraceAuthNLimit),
    194 	TAB(pwdExpireWarning),
    195 	TAB(pwdLockout),
    196 	TAB(pwdLockoutDuration),
    197 	TAB(pwdFailureCountInterval),
    198 	TAB(pwdCheckModule),
    199 	TAB(pwdMustChange),
    200 	TAB(pwdAllowUserChange),
    201 	TAB(pwdSafeModify),
    202 	{ NULL, NULL }
    203 };
    204 
    205 static ldap_pvt_thread_mutex_t chk_syntax_mutex;
    206 
    207 enum {
    208 	PPOLICY_DEFAULT = 1,
    209 	PPOLICY_HASH_CLEARTEXT,
    210 	PPOLICY_USE_LOCKOUT
    211 };
    212 
    213 static ConfigDriver ppolicy_cf_default;
    214 
    215 static ConfigTable ppolicycfg[] = {
    216 	{ "ppolicy_default", "policyDN", 2, 2, 0,
    217 	  ARG_DN|ARG_MAGIC|PPOLICY_DEFAULT, ppolicy_cf_default,
    218 	  "( OLcfgOvAt:12.1 NAME 'olcPPolicyDefault' "
    219 	  "DESC 'DN of a pwdPolicy object for uncustomized objects' "
    220 	  "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
    221 	{ "ppolicy_hash_cleartext", "on|off", 1, 2, 0,
    222 	  ARG_ON_OFF|ARG_OFFSET|PPOLICY_HASH_CLEARTEXT,
    223 	  (void *)offsetof(pp_info,hash_passwords),
    224 	  "( OLcfgOvAt:12.2 NAME 'olcPPolicyHashCleartext' "
    225 	  "DESC 'Hash passwords on add or modify' "
    226 	  "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
    227 	{ "ppolicy_use_lockout", "on|off", 1, 2, 0,
    228 	  ARG_ON_OFF|ARG_OFFSET|PPOLICY_USE_LOCKOUT,
    229 	  (void *)offsetof(pp_info,use_lockout),
    230 	  "( OLcfgOvAt:12.3 NAME 'olcPPolicyUseLockout' "
    231 	  "DESC 'Warn clients with AccountLocked' "
    232 	  "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
    233 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
    234 };
    235 
    236 static ConfigOCs ppolicyocs[] = {
    237 	{ "( OLcfgOvOc:12.1 "
    238 	  "NAME 'olcPPolicyConfig' "
    239 	  "DESC 'Password Policy configuration' "
    240 	  "SUP olcOverlayConfig "
    241 	  "MAY ( olcPPolicyDefault $ olcPPolicyHashCleartext $ "
    242 	  "olcPPolicyUseLockout ) )",
    243 	  Cft_Overlay, ppolicycfg },
    244 	{ NULL, 0, NULL }
    245 };
    246 
    247 static int
    248 ppolicy_cf_default( ConfigArgs *c )
    249 {
    250 	slap_overinst *on = (slap_overinst *)c->bi;
    251 	pp_info *pi = (pp_info *)on->on_bi.bi_private;
    252 	int rc = ARG_BAD_CONF;
    253 
    254 	assert ( c->type == PPOLICY_DEFAULT );
    255 	Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default\n", 0, 0, 0);
    256 
    257 	switch ( c->op ) {
    258 	case SLAP_CONFIG_EMIT:
    259 		Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default emit\n", 0, 0, 0);
    260 		rc = 0;
    261 		if ( !BER_BVISEMPTY( &pi->def_policy )) {
    262 			rc = value_add_one( &c->rvalue_vals,
    263 					    &pi->def_policy );
    264 			if ( rc ) return rc;
    265 			rc = value_add_one( &c->rvalue_nvals,
    266 					    &pi->def_policy );
    267 		}
    268 		break;
    269 	case LDAP_MOD_DELETE:
    270 		Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default delete\n", 0, 0, 0);
    271 		if ( pi->def_policy.bv_val ) {
    272 			ber_memfree ( pi->def_policy.bv_val );
    273 			pi->def_policy.bv_val = NULL;
    274 		}
    275 		pi->def_policy.bv_len = 0;
    276 		rc = 0;
    277 		break;
    278 	case SLAP_CONFIG_ADD:
    279 		/* fallthrough to LDAP_MOD_ADD */
    280 	case LDAP_MOD_ADD:
    281 		Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default add\n", 0, 0, 0);
    282 		if ( pi->def_policy.bv_val ) {
    283 			ber_memfree ( pi->def_policy.bv_val );
    284 		}
    285 		pi->def_policy = c->value_ndn;
    286 		ber_memfree( c->value_dn.bv_val );
    287 		BER_BVZERO( &c->value_dn );
    288 		BER_BVZERO( &c->value_ndn );
    289 		rc = 0;
    290 		break;
    291 	default:
    292 		abort ();
    293 	}
    294 
    295 	return rc;
    296 }
    297 
    298 static time_t
    299 parse_time( char *atm )
    300 {
    301 	struct lutil_tm tm;
    302 	struct lutil_timet tt;
    303 	time_t ret = (time_t)-1;
    304 
    305 	if ( lutil_parsetime( atm, &tm ) == 0) {
    306 		lutil_tm2time( &tm, &tt );
    307 		ret = tt.tt_sec;
    308 	}
    309 	return ret;
    310 }
    311 
    312 static int
    313 account_locked( Operation *op, Entry *e,
    314 		PassPolicy *pp, Modifications **mod )
    315 {
    316 	Attribute       *la;
    317 
    318 	assert(mod != NULL);
    319 
    320 	if ( (la = attr_find( e->e_attrs, ad_pwdAccountLockedTime )) != NULL ) {
    321 		BerVarray vals = la->a_nvals;
    322 
    323 		/*
    324 		 * there is a lockout stamp - we now need to know if it's
    325 		 * a valid one.
    326 		 */
    327 		if (vals[0].bv_val != NULL) {
    328 			time_t then, now;
    329 			Modifications *m;
    330 
    331 			if (!pp->pwdLockoutDuration)
    332 				return 1;
    333 
    334 			if ((then = parse_time( vals[0].bv_val )) == (time_t)0)
    335 				return 1;
    336 
    337 			now = slap_get_time();
    338 
    339 			if (now < then + pp->pwdLockoutDuration)
    340 				return 1;
    341 
    342 			m = ch_calloc( sizeof(Modifications), 1 );
    343 			m->sml_op = LDAP_MOD_DELETE;
    344 			m->sml_flags = 0;
    345 			m->sml_type = ad_pwdAccountLockedTime->ad_cname;
    346 			m->sml_desc = ad_pwdAccountLockedTime;
    347 			m->sml_next = *mod;
    348 			*mod = m;
    349 		}
    350 	}
    351 
    352 	return 0;
    353 }
    354 
    355 /* IMPLICIT TAGS, all context-specific */
    356 #define PPOLICY_WARNING 0xa0L	/* constructed + 0 */
    357 #define PPOLICY_ERROR 0x81L		/* primitive + 1 */
    358 
    359 #define PPOLICY_EXPIRE 0x80L	/* primitive + 0 */
    360 #define PPOLICY_GRACE  0x81L	/* primitive + 1 */
    361 
    362 static const char ppolicy_ctrl_oid[] = LDAP_CONTROL_PASSWORDPOLICYRESPONSE;
    363 
    364 static LDAPControl *
    365 create_passcontrol( int exptime, int grace, LDAPPasswordPolicyError err )
    366 {
    367 	char berbuf[LBER_ELEMENT_SIZEOF], bb2[LBER_ELEMENT_SIZEOF];
    368 	BerElement *ber = (BerElement *)berbuf, *b2 = (BerElement *)bb2;
    369 	LDAPControl *c;
    370 	struct berval bv;
    371 
    372 	c = ch_calloc( sizeof( LDAPControl ), 1 );
    373 	if ( c == NULL ) {
    374 		return NULL;
    375 	}
    376 	c->ldctl_oid = (char *)ppolicy_ctrl_oid;
    377 	c->ldctl_iscritical = 0;
    378 	BER_BVZERO( &c->ldctl_value );
    379 
    380 	ber_init2( ber, NULL, LBER_USE_DER );
    381 	ber_printf( ber, "{" /*}*/ );
    382 
    383 	if ( exptime >= 0 ) {
    384 		ber_init2( b2, NULL, LBER_USE_DER );
    385 		ber_printf( b2, "ti", PPOLICY_EXPIRE, exptime );
    386 		ber_flatten2( b2, &bv, 1 );
    387 		(void)ber_free_buf(b2);
    388 		ber_printf( ber, "tO", PPOLICY_WARNING, &bv );
    389 		ch_free( bv.bv_val );
    390 	} else if ( grace > 0 ) {
    391 		ber_init2( b2, NULL, LBER_USE_DER );
    392 		ber_printf( b2, "ti", PPOLICY_GRACE, grace );
    393 		ber_flatten2( b2, &bv, 1 );
    394 		(void)ber_free_buf(b2);
    395 		ber_printf( ber, "tO", PPOLICY_WARNING, &bv );
    396 		ch_free( bv.bv_val );
    397 	}
    398 
    399 	if (err != PP_noError ) {
    400 		ber_printf( ber, "te", PPOLICY_ERROR, err );
    401 	}
    402 	ber_printf( ber, /*{*/ "N}" );
    403 
    404 	if (ber_flatten2( ber, &(c->ldctl_value), 1 ) == LBER_DEFAULT) {
    405 		ch_free(c);
    406 		c = NULL;
    407 	}
    408 	(void)ber_free_buf(ber);
    409 	return c;
    410 }
    411 
    412 static LDAPControl **
    413 add_passcontrol( Operation *op, SlapReply *rs, LDAPControl *ctrl )
    414 {
    415 	LDAPControl **ctrls, **oldctrls = rs->sr_ctrls;
    416 	int n;
    417 
    418 	n = 0;
    419 	if ( oldctrls ) {
    420 		for ( ; oldctrls[n]; n++ )
    421 			;
    422 	}
    423 	n += 2;
    424 
    425 	ctrls = op->o_tmpcalloc( sizeof( LDAPControl * ), n, op->o_tmpmemctx );
    426 
    427 	n = 0;
    428 	if ( oldctrls ) {
    429 		for ( ; oldctrls[n]; n++ ) {
    430 			ctrls[n] = oldctrls[n];
    431 		}
    432 	}
    433 	ctrls[n] = ctrl;
    434 	ctrls[n+1] = NULL;
    435 
    436 	rs->sr_ctrls = ctrls;
    437 
    438 	return oldctrls;
    439 }
    440 
    441 static void
    442 ppolicy_get( Operation *op, Entry *e, PassPolicy *pp )
    443 {
    444 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
    445 	pp_info *pi = on->on_bi.bi_private;
    446 	Attribute *a;
    447 	BerVarray vals;
    448 	int rc;
    449 	Entry *pe = NULL;
    450 #if 0
    451 	const char *text;
    452 #endif
    453 
    454 	memset( pp, 0, sizeof(PassPolicy) );
    455 
    456 	pp->ad = slap_schema.si_ad_userPassword;
    457 
    458 	/* Users can change their own password by default */
    459     	pp->pwdAllowUserChange = 1;
    460 
    461 	if ((a = attr_find( e->e_attrs, ad_pwdPolicySubentry )) == NULL) {
    462 		/*
    463 		 * entry has no password policy assigned - use default
    464 		 */
    465 		vals = &pi->def_policy;
    466 		if ( !vals->bv_val )
    467 			goto defaultpol;
    468 	} else {
    469 		vals = a->a_nvals;
    470 		if (vals[0].bv_val == NULL) {
    471 			Debug( LDAP_DEBUG_ANY,
    472 				"ppolicy_get: NULL value for policySubEntry\n", 0, 0, 0 );
    473 			goto defaultpol;
    474 		}
    475 	}
    476 
    477 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
    478 	rc = be_entry_get_rw( op, vals, NULL, NULL, 0, &pe );
    479 	op->o_bd->bd_info = (BackendInfo *)on;
    480 
    481 	if ( rc ) goto defaultpol;
    482 
    483 #if 0	/* Only worry about userPassword for now */
    484 	if ((a = attr_find( pe->e_attrs, ad_pwdAttribute )))
    485 		slap_bv2ad( &a->a_vals[0], &pp->ad, &text );
    486 #endif
    487 
    488 	if ( ( a = attr_find( pe->e_attrs, ad_pwdMinAge ) )
    489 			&& lutil_atoi( &pp->pwdMinAge, a->a_vals[0].bv_val ) != 0 )
    490 		goto defaultpol;
    491 	if ( ( a = attr_find( pe->e_attrs, ad_pwdMaxAge ) )
    492 			&& lutil_atoi( &pp->pwdMaxAge, a->a_vals[0].bv_val ) != 0 )
    493 		goto defaultpol;
    494 	if ( ( a = attr_find( pe->e_attrs, ad_pwdInHistory ) )
    495 			&& lutil_atoi( &pp->pwdInHistory, a->a_vals[0].bv_val ) != 0 )
    496 		goto defaultpol;
    497 	if ( ( a = attr_find( pe->e_attrs, ad_pwdCheckQuality ) )
    498 			&& lutil_atoi( &pp->pwdCheckQuality, a->a_vals[0].bv_val ) != 0 )
    499 		goto defaultpol;
    500 	if ( ( a = attr_find( pe->e_attrs, ad_pwdMinLength ) )
    501 			&& lutil_atoi( &pp->pwdMinLength, a->a_vals[0].bv_val ) != 0 )
    502 		goto defaultpol;
    503 	if ( ( a = attr_find( pe->e_attrs, ad_pwdMaxFailure ) )
    504 			&& lutil_atoi( &pp->pwdMaxFailure, a->a_vals[0].bv_val ) != 0 )
    505 		goto defaultpol;
    506 	if ( ( a = attr_find( pe->e_attrs, ad_pwdGraceAuthNLimit ) )
    507 			&& lutil_atoi( &pp->pwdGraceAuthNLimit, a->a_vals[0].bv_val ) != 0 )
    508 		goto defaultpol;
    509 	if ( ( a = attr_find( pe->e_attrs, ad_pwdExpireWarning ) )
    510 			&& lutil_atoi( &pp->pwdExpireWarning, a->a_vals[0].bv_val ) != 0 )
    511 		goto defaultpol;
    512 	if ( ( a = attr_find( pe->e_attrs, ad_pwdFailureCountInterval ) )
    513 			&& lutil_atoi( &pp->pwdFailureCountInterval, a->a_vals[0].bv_val ) != 0 )
    514 		goto defaultpol;
    515 	if ( ( a = attr_find( pe->e_attrs, ad_pwdLockoutDuration ) )
    516 			&& lutil_atoi( &pp->pwdLockoutDuration, a->a_vals[0].bv_val ) != 0 )
    517 		goto defaultpol;
    518 
    519 	if ( ( a = attr_find( pe->e_attrs, ad_pwdCheckModule ) ) ) {
    520 		strncpy( pp->pwdCheckModule, a->a_vals[0].bv_val,
    521 			sizeof(pp->pwdCheckModule) );
    522 		pp->pwdCheckModule[sizeof(pp->pwdCheckModule)-1] = '\0';
    523 	}
    524 
    525 	if ((a = attr_find( pe->e_attrs, ad_pwdLockout )))
    526     		pp->pwdLockout = bvmatch( &a->a_nvals[0], &slap_true_bv );
    527 	if ((a = attr_find( pe->e_attrs, ad_pwdMustChange )))
    528     		pp->pwdMustChange = bvmatch( &a->a_nvals[0], &slap_true_bv );
    529 	if ((a = attr_find( pe->e_attrs, ad_pwdAllowUserChange )))
    530 	    	pp->pwdAllowUserChange = bvmatch( &a->a_nvals[0], &slap_true_bv );
    531 	if ((a = attr_find( pe->e_attrs, ad_pwdSafeModify )))
    532 	    	pp->pwdSafeModify = bvmatch( &a->a_nvals[0], &slap_true_bv );
    533 
    534 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
    535 	be_entry_release_r( op, pe );
    536 	op->o_bd->bd_info = (BackendInfo *)on;
    537 
    538 	return;
    539 
    540 defaultpol:
    541 	Debug( LDAP_DEBUG_TRACE,
    542 		"ppolicy_get: using default policy\n", 0, 0, 0 );
    543 	return;
    544 }
    545 
    546 static int
    547 password_scheme( struct berval *cred, struct berval *sch )
    548 {
    549 	int e;
    550 
    551 	assert( cred != NULL );
    552 
    553 	if (sch) {
    554 		sch->bv_val = NULL;
    555 		sch->bv_len = 0;
    556 	}
    557 
    558 	if ((cred->bv_len == 0) || (cred->bv_val == NULL) ||
    559 		(cred->bv_val[0] != '{')) return LDAP_OTHER;
    560 
    561 	for(e = 1; cred->bv_val[e] && cred->bv_val[e] != '}'; e++);
    562 	if (cred->bv_val[e]) {
    563 		int rc;
    564 		rc = lutil_passwd_scheme( cred->bv_val );
    565 		if (rc) {
    566 			if (sch) {
    567 				sch->bv_val = cred->bv_val;
    568 				sch->bv_len = e;
    569 			}
    570 			return LDAP_SUCCESS;
    571 		}
    572 	}
    573 	return LDAP_OTHER;
    574 }
    575 
    576 static int
    577 check_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyError *err, Entry *e )
    578 {
    579 	int rc = LDAP_SUCCESS, ok = LDAP_SUCCESS;
    580 	char *ptr = cred->bv_val;
    581 	struct berval sch;
    582 
    583 	assert( cred != NULL );
    584 	assert( pp != NULL );
    585 
    586 	if ((cred->bv_len == 0) || (pp->pwdMinLength > cred->bv_len)) {
    587 		rc = LDAP_CONSTRAINT_VIOLATION;
    588 		if ( err ) *err = PP_passwordTooShort;
    589 		return rc;
    590 	}
    591 
    592         /*
    593          * We need to know if the password is already hashed - if so
    594          * what scheme is it. The reason being that the "hash" of
    595          * {cleartext} still allows us to check the password.
    596          */
    597 	rc = password_scheme( cred, &sch );
    598 	if (rc == LDAP_SUCCESS) {
    599 		if ((sch.bv_val) && (strncasecmp( sch.bv_val, "{cleartext}",
    600 			sch.bv_len ) == 0)) {
    601 			/*
    602 			 * We can check the cleartext "hash"
    603 			 */
    604 			ptr = cred->bv_val + sch.bv_len;
    605 		} else {
    606 			/* everything else, we can't check */
    607 			if (pp->pwdCheckQuality == 2) {
    608 				rc = LDAP_CONSTRAINT_VIOLATION;
    609 				if (err) *err = PP_insufficientPasswordQuality;
    610 				return rc;
    611 			}
    612 			/*
    613 			 * We can't check the syntax of the password, but it's not
    614 			 * mandatory (according to the policy), so we return success.
    615 			 */
    616 
    617 			return LDAP_SUCCESS;
    618 		}
    619 	}
    620 
    621 	rc = LDAP_SUCCESS;
    622 
    623 	if (pp->pwdCheckModule[0]) {
    624 #ifdef SLAPD_MODULES
    625 		lt_dlhandle mod;
    626 		const char *err;
    627 
    628 		if ((mod = lt_dlopen( pp->pwdCheckModule )) == NULL) {
    629 			err = lt_dlerror();
    630 
    631 			Debug(LDAP_DEBUG_ANY,
    632 			"check_password_quality: lt_dlopen failed: (%s) %s.\n",
    633 				pp->pwdCheckModule, err, 0 );
    634 			ok = LDAP_OTHER; /* internal error */
    635 		} else {
    636 			int (*prog)( char *passwd, char **text, Entry *ent );
    637 
    638 			if ((prog = lt_dlsym( mod, "check_password" )) == NULL) {
    639 				err = lt_dlerror();
    640 
    641 				Debug(LDAP_DEBUG_ANY,
    642 					"check_password_quality: lt_dlsym failed: (%s) %s.\n",
    643 					pp->pwdCheckModule, err, 0 );
    644 				ok = LDAP_OTHER;
    645 			} else {
    646 				char *txt = NULL;
    647 
    648 				ldap_pvt_thread_mutex_lock( &chk_syntax_mutex );
    649 				ok = prog( cred->bv_val, &txt, e );
    650 				ldap_pvt_thread_mutex_unlock( &chk_syntax_mutex );
    651 				if (ok != LDAP_SUCCESS) {
    652 					Debug(LDAP_DEBUG_ANY,
    653 						"check_password_quality: module error: (%s) %s.[%d]\n",
    654 						pp->pwdCheckModule, txt ? txt : "", ok );
    655 					free(txt);
    656 				}
    657 			}
    658 
    659 			lt_dlclose( mod );
    660 		}
    661 #else
    662 	Debug(LDAP_DEBUG_ANY, "check_password_quality: external modules not "
    663 		"supported. pwdCheckModule ignored.\n", 0, 0, 0);
    664 #endif /* SLAPD_MODULES */
    665 	}
    666 
    667 
    668 	if (ok != LDAP_SUCCESS) {
    669 		rc = LDAP_CONSTRAINT_VIOLATION;
    670 		if (err) *err = PP_insufficientPasswordQuality;
    671 	}
    672 
    673 	return rc;
    674 }
    675 
    676 static int
    677 parse_pwdhistory( struct berval *bv, char **oid, time_t *oldtime, struct berval *oldpw )
    678 {
    679 	char *ptr;
    680 	struct berval nv, npw;
    681 	int i, j;
    682 
    683 	assert (bv && (bv->bv_len > 0) && (bv->bv_val) && oldtime && oldpw );
    684 
    685 	if ( oid ) {
    686 		*oid = 0;
    687 	}
    688 	*oldtime = (time_t)-1;
    689 	BER_BVZERO( oldpw );
    690 
    691 	ber_dupbv( &nv, bv );
    692 
    693 	/* first get the time field */
    694 	for ( i = 0; (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ )
    695 		;
    696 	if ( i == nv.bv_len ) {
    697 		goto exit_failure; /* couldn't locate the '#' separator */
    698 	}
    699 	nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */
    700 	ptr = nv.bv_val;
    701 	*oldtime = parse_time( ptr );
    702 	if (*oldtime == (time_t)-1) {
    703 		goto exit_failure;
    704 	}
    705 
    706 	/* get the OID field */
    707 	for (ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ )
    708 		;
    709 	if ( i == nv.bv_len ) {
    710 		goto exit_failure; /* couldn't locate the '#' separator */
    711 	}
    712 	nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */
    713 	if ( oid ) {
    714 		*oid = ber_strdup( ptr );
    715 	}
    716 
    717 	/* get the length field */
    718 	for ( ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ )
    719 		;
    720 	if ( i == nv.bv_len ) {
    721 		goto exit_failure; /* couldn't locate the '#' separator */
    722 	}
    723 	nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */
    724 	oldpw->bv_len = strtol( ptr, NULL, 10 );
    725 	if (errno == ERANGE) {
    726 		goto exit_failure;
    727 	}
    728 
    729 	/* lastly, get the octets of the string */
    730 	for ( j = i, ptr = &(nv.bv_val[i]); i < nv.bv_len; i++ )
    731 		;
    732 	if ( i - j != oldpw->bv_len) {
    733 		goto exit_failure; /* length is wrong */
    734 	}
    735 
    736 	npw.bv_val = ptr;
    737 	npw.bv_len = oldpw->bv_len;
    738 	ber_dupbv( oldpw, &npw );
    739 	ber_memfree( nv.bv_val );
    740 
    741 	return LDAP_SUCCESS;
    742 
    743 exit_failure:;
    744 	if ( oid && *oid ) {
    745 		ber_memfree(*oid);
    746 		*oid = NULL;
    747 	}
    748 	if ( oldpw->bv_val ) {
    749 		ber_memfree( oldpw->bv_val);
    750 		BER_BVZERO( oldpw );
    751 	}
    752 	ber_memfree( nv.bv_val );
    753 
    754 	return LDAP_OTHER;
    755 }
    756 
    757 static void
    758 add_to_pwd_history( pw_hist **l, time_t t,
    759                     struct berval *oldpw, struct berval *bv )
    760 {
    761 	pw_hist *p, *p1, *p2;
    762 
    763 	if (!l) return;
    764 
    765 	p = ch_malloc( sizeof( pw_hist ));
    766 	p->pw = *oldpw;
    767 	ber_dupbv( &p->bv, bv );
    768 	p->t = t;
    769 	p->next = NULL;
    770 
    771 	if (*l == NULL) {
    772 		/* degenerate case */
    773 		*l = p;
    774 		return;
    775 	}
    776 	/*
    777 	 * advance p1 and p2 such that p1 is the node before the
    778 	 * new one, and p2 is the node after it
    779 	 */
    780 	for (p1 = NULL, p2 = *l; p2 && p2->t <= t; p1 = p2, p2=p2->next );
    781 	p->next = p2;
    782 	if (p1 == NULL) { *l = p; return; }
    783 	p1->next = p;
    784 }
    785 
    786 #ifndef MAX_PWD_HISTORY_SZ
    787 #define MAX_PWD_HISTORY_SZ 1024
    788 #endif /* MAX_PWD_HISTORY_SZ */
    789 
    790 static void
    791 make_pwd_history_value( char *timebuf, struct berval *bv, Attribute *pa )
    792 {
    793 	char str[ MAX_PWD_HISTORY_SZ ];
    794 	int nlen;
    795 
    796 	snprintf( str, MAX_PWD_HISTORY_SZ,
    797 		  "%s#%s#%lu#", timebuf,
    798 		  pa->a_desc->ad_type->sat_syntax->ssyn_oid,
    799 		  (unsigned long) pa->a_nvals[0].bv_len );
    800 	str[MAX_PWD_HISTORY_SZ-1] = 0;
    801 	nlen = strlen(str);
    802 
    803         /*
    804          * We have to assume that the string is a string of octets,
    805          * not readable characters. In reality, yes, it probably is
    806          * a readable (ie, base64) string, but we can't count on that
    807          * Hence, while the first 3 fields of the password history
    808          * are definitely readable (a timestamp, an OID and an integer
    809          * length), the remaining octets of the actual password
    810          * are deemed to be binary data.
    811          */
    812 	AC_MEMCPY( str + nlen, pa->a_nvals[0].bv_val, pa->a_nvals[0].bv_len );
    813 	nlen += pa->a_nvals[0].bv_len;
    814 	bv->bv_val = ch_malloc( nlen + 1 );
    815 	AC_MEMCPY( bv->bv_val, str, nlen );
    816 	bv->bv_val[nlen] = '\0';
    817 	bv->bv_len = nlen;
    818 }
    819 
    820 static void
    821 free_pwd_history_list( pw_hist **l )
    822 {
    823 	pw_hist *p;
    824 
    825 	if (!l) return;
    826 	p = *l;
    827 	while (p) {
    828 		pw_hist *pp = p->next;
    829 
    830 		free(p->pw.bv_val);
    831 		free(p->bv.bv_val);
    832 		free(p);
    833 		p = pp;
    834 	}
    835 	*l = NULL;
    836 }
    837 
    838 typedef struct ppbind {
    839 	slap_overinst *on;
    840 	int send_ctrl;
    841 	LDAPControl **oldctrls;
    842 	Modifications *mod;
    843 	LDAPPasswordPolicyError pErr;
    844 	PassPolicy pp;
    845 } ppbind;
    846 
    847 static void
    848 ctrls_cleanup( Operation *op, SlapReply *rs, LDAPControl **oldctrls )
    849 {
    850 	int n;
    851 
    852 	assert( rs->sr_ctrls != NULL );
    853 	assert( rs->sr_ctrls[0] != NULL );
    854 
    855 	for ( n = 0; rs->sr_ctrls[n]; n++ ) {
    856 		if ( rs->sr_ctrls[n]->ldctl_oid == ppolicy_ctrl_oid ) {
    857 			ch_free( rs->sr_ctrls[n]->ldctl_value.bv_val );
    858 			ch_free( rs->sr_ctrls[n] );
    859 			rs->sr_ctrls[n] = (LDAPControl *)(-1);
    860 			break;
    861 		}
    862 	}
    863 
    864 	if ( rs->sr_ctrls[n] == NULL ) {
    865 		/* missed? */
    866 	}
    867 
    868 	op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
    869 
    870 	rs->sr_ctrls = oldctrls;
    871 }
    872 
    873 static int
    874 ppolicy_ctrls_cleanup( Operation *op, SlapReply *rs )
    875 {
    876 	ppbind *ppb = op->o_callback->sc_private;
    877 	if ( ppb->send_ctrl ) {
    878 		ctrls_cleanup( op, rs, ppb->oldctrls );
    879 	}
    880 	return SLAP_CB_CONTINUE;
    881 }
    882 
    883 static int
    884 ppolicy_bind_response( Operation *op, SlapReply *rs )
    885 {
    886 	ppbind *ppb = op->o_callback->sc_private;
    887 	slap_overinst *on = ppb->on;
    888 	Modifications *mod = ppb->mod, *m;
    889 	int pwExpired = 0;
    890 	int ngut = -1, warn = -1, age, rc;
    891 	Attribute *a;
    892 	time_t now, pwtime = (time_t)-1;
    893 	char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
    894 	struct berval timestamp;
    895 	BackendInfo *bi = op->o_bd->bd_info;
    896 	Entry *e;
    897 
    898 	/* If we already know it's locked, just get on with it */
    899 	if ( ppb->pErr != PP_noError ) {
    900 		goto locked;
    901 	}
    902 
    903 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
    904 	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
    905 	op->o_bd->bd_info = bi;
    906 
    907 	if ( rc != LDAP_SUCCESS ) {
    908 		return SLAP_CB_CONTINUE;
    909 	}
    910 
    911 	now = slap_get_time(); /* stored for later consideration */
    912 	timestamp.bv_val = nowstr;
    913 	timestamp.bv_len = sizeof(nowstr);
    914 	slap_timestamp( &now, &timestamp );
    915 
    916 	if ( rs->sr_err == LDAP_INVALID_CREDENTIALS ) {
    917 		int i = 0, fc = 0;
    918 
    919 		m = ch_calloc( sizeof(Modifications), 1 );
    920 		m->sml_op = LDAP_MOD_ADD;
    921 		m->sml_flags = 0;
    922 		m->sml_type = ad_pwdFailureTime->ad_cname;
    923 		m->sml_desc = ad_pwdFailureTime;
    924 		m->sml_numvals = 1;
    925 		m->sml_values = ch_calloc( sizeof(struct berval), 2 );
    926 		m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
    927 
    928 		ber_dupbv( &m->sml_values[0], &timestamp );
    929 		ber_dupbv( &m->sml_nvalues[0], &timestamp );
    930 		m->sml_next = mod;
    931 		mod = m;
    932 
    933 		/*
    934 		 * Count the pwdFailureTimes - if it's
    935 		 * greater than the policy pwdMaxFailure,
    936 		 * then lock the account.
    937 		 */
    938 		if ((a = attr_find( e->e_attrs, ad_pwdFailureTime )) != NULL) {
    939 			for(i=0; a->a_nvals[i].bv_val; i++) {
    940 
    941 				/*
    942 				 * If the interval is 0, then failures
    943 				 * stay on the record until explicitly
    944 				 * reset by successful authentication.
    945 				 */
    946 				if (ppb->pp.pwdFailureCountInterval == 0) {
    947 					fc++;
    948 				} else if (now <=
    949 							parse_time(a->a_nvals[i].bv_val) +
    950 							ppb->pp.pwdFailureCountInterval) {
    951 
    952 					fc++;
    953 				}
    954 				/*
    955 				 * We only count those failures
    956 				 * which are not due to expire.
    957 				 */
    958 			}
    959 		}
    960 
    961 		if ((ppb->pp.pwdMaxFailure > 0) &&
    962 			(fc >= ppb->pp.pwdMaxFailure - 1)) {
    963 
    964 			/*
    965 			 * We subtract 1 from the failure max
    966 			 * because the new failure entry hasn't
    967 			 * made it to the entry yet.
    968 			 */
    969 			m = ch_calloc( sizeof(Modifications), 1 );
    970 			m->sml_op = LDAP_MOD_REPLACE;
    971 			m->sml_flags = 0;
    972 			m->sml_type = ad_pwdAccountLockedTime->ad_cname;
    973 			m->sml_desc = ad_pwdAccountLockedTime;
    974 			m->sml_numvals = 1;
    975 			m->sml_values = ch_calloc( sizeof(struct berval), 2 );
    976 			m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
    977 			ber_dupbv( &m->sml_values[0], &timestamp );
    978 			ber_dupbv( &m->sml_nvalues[0], &timestamp );
    979 			m->sml_next = mod;
    980 			mod = m;
    981 		}
    982 	} else if ( rs->sr_err == LDAP_SUCCESS ) {
    983 		if ((a = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL)
    984 			pwtime = parse_time( a->a_nvals[0].bv_val );
    985 
    986 		/* delete all pwdFailureTimes */
    987 		if ( attr_find( e->e_attrs, ad_pwdFailureTime )) {
    988 			m = ch_calloc( sizeof(Modifications), 1 );
    989 			m->sml_op = LDAP_MOD_DELETE;
    990 			m->sml_flags = 0;
    991 			m->sml_type = ad_pwdFailureTime->ad_cname;
    992 			m->sml_desc = ad_pwdFailureTime;
    993 			m->sml_next = mod;
    994 			mod = m;
    995 		}
    996 
    997 		/*
    998 		 * check to see if the password must be changed
    999 		 */
   1000 		if ( ppb->pp.pwdMustChange &&
   1001 			(a = attr_find( e->e_attrs, ad_pwdReset )) &&
   1002 			bvmatch( &a->a_nvals[0], &slap_true_bv ) )
   1003 		{
   1004 			/*
   1005 			 * need to inject client controls here to give
   1006 			 * more information. For the moment, we ensure
   1007 			 * that we are disallowed from doing anything
   1008 			 * other than change password.
   1009 			 */
   1010 			ber_dupbv( &pwcons[op->o_conn->c_conn_idx].dn,
   1011 				&op->o_conn->c_ndn );
   1012 
   1013 			ppb->pErr = PP_changeAfterReset;
   1014 
   1015 		} else {
   1016 			/*
   1017 			 * the password does not need to be changed, so
   1018 			 * we now check whether the password has expired.
   1019 			 *
   1020 			 * We can skip this bit if passwords don't age in
   1021 			 * the policy. Also, if there was no pwdChangedTime
   1022 			 * attribute in the entry, the password never expires.
   1023 			 */
   1024 			if (ppb->pp.pwdMaxAge == 0) goto grace;
   1025 
   1026 			if (pwtime != (time_t)-1) {
   1027 				/*
   1028 				 * Check: was the last change time of
   1029 				 * the password older than the maximum age
   1030 				 * allowed. (Ignore case 2 from I-D, it's just silly.)
   1031 				 */
   1032 				if (now - pwtime > ppb->pp.pwdMaxAge ) pwExpired = 1;
   1033 			}
   1034 		}
   1035 
   1036 grace:
   1037 		if (!pwExpired) goto check_expiring_password;
   1038 
   1039 		if ((a = attr_find( e->e_attrs, ad_pwdGraceUseTime )) == NULL)
   1040 			ngut = ppb->pp.pwdGraceAuthNLimit;
   1041 		else {
   1042 			for(ngut=0; a->a_nvals[ngut].bv_val; ngut++);
   1043 			ngut = ppb->pp.pwdGraceAuthNLimit - ngut;
   1044 		}
   1045 
   1046 		/*
   1047 		 * ngut is the number of remaining grace logins
   1048 		 */
   1049 		Debug( LDAP_DEBUG_ANY,
   1050 			"ppolicy_bind: Entry %s has an expired password: %d grace logins\n",
   1051 			e->e_name.bv_val, ngut, 0);
   1052 
   1053 		if (ngut < 1) {
   1054 			ppb->pErr = PP_passwordExpired;
   1055 			rs->sr_err = LDAP_INVALID_CREDENTIALS;
   1056 			goto done;
   1057 		}
   1058 
   1059 		/*
   1060 		 * Add a grace user time to the entry
   1061 		 */
   1062 		m = ch_calloc( sizeof(Modifications), 1 );
   1063 		m->sml_op = LDAP_MOD_ADD;
   1064 		m->sml_flags = 0;
   1065 		m->sml_type = ad_pwdGraceUseTime->ad_cname;
   1066 		m->sml_desc = ad_pwdGraceUseTime;
   1067 		m->sml_numvals = 1;
   1068 		m->sml_values = ch_calloc( sizeof(struct berval), 2 );
   1069 		m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
   1070 		ber_dupbv( &m->sml_values[0], &timestamp );
   1071 		ber_dupbv( &m->sml_nvalues[0], &timestamp );
   1072 		m->sml_next = mod;
   1073 		mod = m;
   1074 
   1075 check_expiring_password:
   1076 		/*
   1077 		 * Now we need to check to see
   1078 		 * if it is about to expire, and if so, should the user
   1079 		 * be warned about it in the password policy control.
   1080 		 *
   1081 		 * If the password has expired, and we're in the grace period, then
   1082 		 * we don't need to do this bit. Similarly, if we don't have password
   1083 		 * aging, then there's no need to do this bit either.
   1084 		 */
   1085 		if ((ppb->pp.pwdMaxAge < 1) || (pwExpired) || (ppb->pp.pwdExpireWarning < 1))
   1086 			goto done;
   1087 
   1088 		age = (int)(now - pwtime);
   1089 
   1090 		/*
   1091 		 * We know that there is a password Change Time attribute - if
   1092 		 * there wasn't, then the pwdExpired value would be true, unless
   1093 		 * there is no password aging - and if there is no password aging,
   1094 		 * then this section isn't called anyway - you can't have an
   1095 		 * expiring password if there's no limit to expire.
   1096 		 */
   1097 		if (ppb->pp.pwdMaxAge - age < ppb->pp.pwdExpireWarning ) {
   1098 			/*
   1099 			 * Set the warning value.
   1100 			 */
   1101 			warn = ppb->pp.pwdMaxAge - age; /* seconds left until expiry */
   1102 			if (warn < 0) warn = 0; /* something weird here - why is pwExpired not set? */
   1103 
   1104 			Debug( LDAP_DEBUG_ANY,
   1105 				"ppolicy_bind: Setting warning for password expiry for %s = %d seconds\n",
   1106 				op->o_req_dn.bv_val, warn, 0 );
   1107 		}
   1108 	}
   1109 
   1110 done:
   1111 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
   1112 	be_entry_release_r( op, e );
   1113 
   1114 locked:
   1115 	if ( mod ) {
   1116 		Operation op2 = *op;
   1117 		SlapReply r2 = { REP_RESULT };
   1118 		slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
   1119 
   1120 		/* FIXME: Need to handle replication of some (but not all)
   1121 		 * of the operational attributes...
   1122 		 */
   1123 		op2.o_tag = LDAP_REQ_MODIFY;
   1124 		op2.o_callback = &cb;
   1125 		op2.orm_modlist = mod;
   1126 		op2.o_dn = op->o_bd->be_rootdn;
   1127 		op2.o_ndn = op->o_bd->be_rootndn;
   1128 		op2.o_bd->bd_info = (BackendInfo *)on->on_info;
   1129 		rc = op->o_bd->be_modify( &op2, &r2 );
   1130 		slap_mods_free( mod, 1 );
   1131 	}
   1132 
   1133 	if ( ppb->send_ctrl ) {
   1134 		LDAPControl *ctrl = NULL;
   1135 		pp_info *pi = on->on_bi.bi_private;
   1136 
   1137 		/* Do we really want to tell that the account is locked? */
   1138 		if ( ppb->pErr == PP_accountLocked && !pi->use_lockout ) {
   1139 			ppb->pErr = PP_noError;
   1140 		}
   1141 		ctrl = create_passcontrol( warn, ngut, ppb->pErr );
   1142 		ppb->oldctrls = add_passcontrol( op, rs, ctrl );
   1143 		op->o_callback->sc_cleanup = ppolicy_ctrls_cleanup;
   1144 	}
   1145 	op->o_bd->bd_info = bi;
   1146 	return SLAP_CB_CONTINUE;
   1147 }
   1148 
   1149 static int
   1150 ppolicy_bind( Operation *op, SlapReply *rs )
   1151 {
   1152 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
   1153 
   1154 	/* Reset lockout status on all Bind requests */
   1155 	if ( !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
   1156 		ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
   1157 		BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
   1158 	}
   1159 
   1160 	/* Root bypasses policy */
   1161 	if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn )) {
   1162 		Entry *e;
   1163 		int rc;
   1164 		ppbind *ppb;
   1165 		slap_callback *cb;
   1166 
   1167 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
   1168 		rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
   1169 
   1170 		if ( rc != LDAP_SUCCESS ) {
   1171 			return SLAP_CB_CONTINUE;
   1172 		}
   1173 
   1174 		cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback),
   1175 			1, op->o_tmpmemctx );
   1176 		ppb = (ppbind *)(cb+1);
   1177 		ppb->on = on;
   1178 		ppb->pErr = PP_noError;
   1179 
   1180 		/* Setup a callback so we can munge the result */
   1181 
   1182 		cb->sc_response = ppolicy_bind_response;
   1183 		cb->sc_next = op->o_callback->sc_next;
   1184 		cb->sc_private = ppb;
   1185 		op->o_callback->sc_next = cb;
   1186 
   1187 		/* Did we receive a password policy request control? */
   1188 		if ( op->o_ctrlflag[ppolicy_cid] ) {
   1189 			ppb->send_ctrl = 1;
   1190 		}
   1191 
   1192 		op->o_bd->bd_info = (BackendInfo *)on;
   1193 		ppolicy_get( op, e, &ppb->pp );
   1194 
   1195 		rc = account_locked( op, e, &ppb->pp, &ppb->mod );
   1196 
   1197 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
   1198 		be_entry_release_r( op, e );
   1199 
   1200 		if ( rc ) {
   1201 			/* This will be the Draft 8 response, Unwilling is bogus */
   1202 			ppb->pErr = PP_accountLocked;
   1203 			send_ldap_error( op, rs, LDAP_INVALID_CREDENTIALS, NULL );
   1204 			return rs->sr_err;
   1205 		}
   1206 
   1207 	}
   1208 
   1209 	return SLAP_CB_CONTINUE;
   1210 }
   1211 
   1212 /* Reset the restricted info for the next session on this connection */
   1213 static int
   1214 ppolicy_connection_destroy( BackendDB *bd, Connection *conn )
   1215 {
   1216 	if ( !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) {
   1217 		ch_free( pwcons[conn->c_conn_idx].dn.bv_val );
   1218 		BER_BVZERO( &pwcons[conn->c_conn_idx].dn );
   1219 	}
   1220 	return SLAP_CB_CONTINUE;
   1221 }
   1222 
   1223 /* Check if this connection is restricted */
   1224 static int
   1225 ppolicy_restrict(
   1226 	Operation *op,
   1227 	SlapReply *rs )
   1228 {
   1229 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
   1230 	int send_ctrl = 0;
   1231 
   1232 	/* Did we receive a password policy request control? */
   1233 	if ( op->o_ctrlflag[ppolicy_cid] ) {
   1234 		send_ctrl = 1;
   1235 	}
   1236 
   1237 	if ( op->o_conn && !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
   1238 		LDAPControl **oldctrls;
   1239 		/* if the current authcDN doesn't match the one we recorded,
   1240 		 * then an intervening Bind has succeeded and the restriction
   1241 		 * no longer applies. (ITS#4516)
   1242 		 */
   1243 		if ( !dn_match( &op->o_conn->c_ndn,
   1244 				&pwcons[op->o_conn->c_conn_idx].dn )) {
   1245 			ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
   1246 			BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
   1247 			return SLAP_CB_CONTINUE;
   1248 		}
   1249 
   1250 		Debug( LDAP_DEBUG_TRACE,
   1251 			"connection restricted to password changing only\n", 0, 0, 0);
   1252 		if ( send_ctrl ) {
   1253 			LDAPControl *ctrl = NULL;
   1254 			ctrl = create_passcontrol( -1, -1, PP_changeAfterReset );
   1255 			oldctrls = add_passcontrol( op, rs, ctrl );
   1256 		}
   1257 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
   1258 		send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS,
   1259 			"Operations are restricted to bind/unbind/abandon/StartTLS/modify password" );
   1260 		if ( send_ctrl ) {
   1261 			ctrls_cleanup( op, rs, oldctrls );
   1262 		}
   1263 		return rs->sr_err;
   1264 	}
   1265 
   1266 	return SLAP_CB_CONTINUE;
   1267 }
   1268 
   1269 static int
   1270 ppolicy_add(
   1271 	Operation *op,
   1272 	SlapReply *rs )
   1273 {
   1274 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
   1275 	pp_info *pi = on->on_bi.bi_private;
   1276 	PassPolicy pp;
   1277 	Attribute *pa;
   1278 	const char *txt;
   1279 
   1280 	if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE )
   1281 		return rs->sr_err;
   1282 
   1283 	/* If this is a replica, assume the master checked everything */
   1284 	if ( be_shadow_update( op ))
   1285 		return SLAP_CB_CONTINUE;
   1286 
   1287 	/* Check for password in entry */
   1288 	if ((pa = attr_find( op->oq_add.rs_e->e_attrs,
   1289 		slap_schema.si_ad_userPassword )))
   1290 	{
   1291 		assert( pa->a_vals != NULL );
   1292 		assert( !BER_BVISNULL( &pa->a_vals[ 0 ] ) );
   1293 
   1294 		if ( !BER_BVISNULL( &pa->a_vals[ 1 ] ) ) {
   1295 			send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, "Password policy only allows one password value" );
   1296 			return rs->sr_err;
   1297 		}
   1298 
   1299 		/*
   1300 		 * new entry contains a password - if we're not the root user
   1301 		 * then we need to check that the password fits in with the
   1302 		 * security policy for the new entry.
   1303 		 */
   1304 		ppolicy_get( op, op->ora_e, &pp );
   1305 		if (pp.pwdCheckQuality > 0 && !be_isroot( op )) {
   1306 			struct berval *bv = &(pa->a_vals[0]);
   1307 			int rc, send_ctrl = 0;
   1308 			LDAPPasswordPolicyError pErr = PP_noError;
   1309 
   1310 			/* Did we receive a password policy request control? */
   1311 			if ( op->o_ctrlflag[ppolicy_cid] ) {
   1312 				send_ctrl = 1;
   1313 			}
   1314 			rc = check_password_quality( bv, &pp, &pErr, op->ora_e );
   1315 			if (rc != LDAP_SUCCESS) {
   1316 				LDAPControl **oldctrls = NULL;
   1317 				op->o_bd->bd_info = (BackendInfo *)on->on_info;
   1318 				if ( send_ctrl ) {
   1319 					LDAPControl *ctrl = NULL;
   1320 					ctrl = create_passcontrol( -1, -1, pErr );
   1321 					oldctrls = add_passcontrol( op, rs, ctrl );
   1322 				}
   1323 				send_ldap_error( op, rs, rc, "Password fails quality checking policy" );
   1324 				if ( send_ctrl ) {
   1325 					ctrls_cleanup( op, rs, oldctrls );
   1326 				}
   1327 				return rs->sr_err;
   1328 			}
   1329 		}
   1330 			/*
   1331 			 * A controversial bit. We hash cleartext
   1332 			 * passwords provided via add and modify operations
   1333 			 * You're not really supposed to do this, since
   1334 			 * the X.500 model says "store attributes" as they
   1335 			 * get provided. By default, this is what we do
   1336 			 *
   1337 			 * But if the hash_passwords flag is set, we hash
   1338 			 * any cleartext password attribute values via the
   1339 			 * default password hashing scheme.
   1340 			 */
   1341 		if ((pi->hash_passwords) &&
   1342 			(password_scheme( &(pa->a_vals[0]), NULL ) != LDAP_SUCCESS)) {
   1343 			struct berval hpw;
   1344 
   1345 			slap_passwd_hash( &(pa->a_vals[0]), &hpw, &txt );
   1346 			if (hpw.bv_val == NULL) {
   1347 				/*
   1348 				 * hashing didn't work. Emit an error.
   1349 				 */
   1350 				rs->sr_err = LDAP_OTHER;
   1351 				rs->sr_text = txt;
   1352 				send_ldap_error( op, rs, LDAP_OTHER, "Password hashing failed" );
   1353 				return rs->sr_err;
   1354 			}
   1355 
   1356 			memset( pa->a_vals[0].bv_val, 0, pa->a_vals[0].bv_len);
   1357 			ber_memfree( pa->a_vals[0].bv_val );
   1358 			pa->a_vals[0].bv_val = hpw.bv_val;
   1359 			pa->a_vals[0].bv_len = hpw.bv_len;
   1360 		}
   1361 
   1362 		/* If password aging is in effect, set the pwdChangedTime */
   1363 		if ( pp.pwdMaxAge || pp.pwdMinAge ) {
   1364 			struct berval timestamp;
   1365 			char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
   1366 			time_t now = slap_get_time();
   1367 
   1368 			timestamp.bv_val = timebuf;
   1369 			timestamp.bv_len = sizeof(timebuf);
   1370 			slap_timestamp( &now, &timestamp );
   1371 
   1372 			attr_merge_one( op->ora_e, ad_pwdChangedTime, &timestamp, &timestamp );
   1373 		}
   1374 	}
   1375 	return SLAP_CB_CONTINUE;
   1376 }
   1377 
   1378 static int
   1379 ppolicy_mod_cb( Operation *op, SlapReply *rs )
   1380 {
   1381 	slap_callback *sc = op->o_callback;
   1382 	op->o_callback = sc->sc_next;
   1383 	if ( rs->sr_err == LDAP_SUCCESS ) {
   1384 		ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
   1385 		BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
   1386 	}
   1387 	op->o_tmpfree( sc, op->o_tmpmemctx );
   1388 	return SLAP_CB_CONTINUE;
   1389 }
   1390 
   1391 static int
   1392 ppolicy_modify( Operation *op, SlapReply *rs )
   1393 {
   1394 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
   1395 	pp_info			*pi = on->on_bi.bi_private;
   1396 	int			i, rc, mod_pw_only, pwmod, pwmop = -1, deladd,
   1397 				hsize = 0;
   1398 	PassPolicy		pp;
   1399 	Modifications		*mods = NULL, *modtail = NULL,
   1400 				*ml, *delmod, *addmod;
   1401 	Attribute		*pa, *ha, at;
   1402 	const char		*txt;
   1403 	pw_hist			*tl = NULL, *p;
   1404 	int			zapReset, send_ctrl = 0;
   1405 	Entry			*e;
   1406 	struct berval		newpw = BER_BVNULL, oldpw = BER_BVNULL,
   1407 				*bv, cr[2];
   1408 	LDAPPasswordPolicyError pErr = PP_noError;
   1409 	LDAPControl 		**oldctrls = NULL;
   1410 
   1411 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
   1412 	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
   1413 	op->o_bd->bd_info = (BackendInfo *)on;
   1414 
   1415 	if ( rc != LDAP_SUCCESS ) return SLAP_CB_CONTINUE;
   1416 
   1417 	/* If this is a replica, we may need to tweak some of the
   1418 	 * master's modifications. Otherwise, just pass it through.
   1419 	 */
   1420 	if ( be_shadow_update( op )) {
   1421 		Modifications **prev;
   1422 		int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0;
   1423 		Attribute *a_grace, *a_lock, *a_fail;
   1424 
   1425 		a_grace = attr_find( e->e_attrs, ad_pwdGraceUseTime );
   1426 		a_lock = attr_find( e->e_attrs, ad_pwdAccountLockedTime );
   1427 		a_fail = attr_find( e->e_attrs, ad_pwdFailureTime );
   1428 
   1429 		for( prev = &op->orm_modlist, ml = *prev; ml; ml = *prev ) {
   1430 
   1431 			if ( ml->sml_desc == slap_schema.si_ad_userPassword )
   1432 				got_pw = 1;
   1433 
   1434 			/* If we're deleting an attr that didn't exist,
   1435 			 * drop this delete op
   1436 			 */
   1437 			if ( ml->sml_op == LDAP_MOD_DELETE ) {
   1438 				int drop = 0;
   1439 
   1440 				if ( ml->sml_desc == ad_pwdGraceUseTime ) {
   1441 					got_del_grace = 1;
   1442 					if ( !a_grace )
   1443 						drop = 1;
   1444 				} else
   1445 				if ( ml->sml_desc == ad_pwdAccountLockedTime ) {
   1446 					got_del_lock = 1;
   1447 					if ( !a_lock )
   1448 						drop = 1;
   1449 				} else
   1450 				if ( ml->sml_desc == ad_pwdFailureTime ) {
   1451 					got_del_fail = 1;
   1452 					if ( !a_fail )
   1453 						drop = 1;
   1454 				}
   1455 				if ( drop ) {
   1456 					*prev = ml->sml_next;
   1457 					ml->sml_next = NULL;
   1458 					slap_mods_free( ml, 1 );
   1459 					continue;
   1460 				}
   1461 			}
   1462 			prev = &ml->sml_next;
   1463 		}
   1464 
   1465 		/* If we're resetting the password, make sure grace, accountlock,
   1466 		 * and failure also get removed.
   1467 		 */
   1468 		if ( got_pw ) {
   1469 			if ( a_grace && !got_del_grace ) {
   1470 				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
   1471 				ml->sml_op = LDAP_MOD_DELETE;
   1472 				ml->sml_flags = SLAP_MOD_INTERNAL;
   1473 				ml->sml_type.bv_val = NULL;
   1474 				ml->sml_desc = ad_pwdGraceUseTime;
   1475 				ml->sml_numvals = 0;
   1476 				ml->sml_values = NULL;
   1477 				ml->sml_nvalues = NULL;
   1478 				ml->sml_next = NULL;
   1479 				*prev = ml;
   1480 				prev = &ml->sml_next;
   1481 			}
   1482 			if ( a_lock && !got_del_lock ) {
   1483 				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
   1484 				ml->sml_op = LDAP_MOD_DELETE;
   1485 				ml->sml_flags = SLAP_MOD_INTERNAL;
   1486 				ml->sml_type.bv_val = NULL;
   1487 				ml->sml_desc = ad_pwdAccountLockedTime;
   1488 				ml->sml_numvals = 0;
   1489 				ml->sml_values = NULL;
   1490 				ml->sml_nvalues = NULL;
   1491 				ml->sml_next = NULL;
   1492 				*prev = ml;
   1493 			}
   1494 			if ( a_fail && !got_del_fail ) {
   1495 				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
   1496 				ml->sml_op = LDAP_MOD_DELETE;
   1497 				ml->sml_flags = SLAP_MOD_INTERNAL;
   1498 				ml->sml_type.bv_val = NULL;
   1499 				ml->sml_desc = ad_pwdFailureTime;
   1500 				ml->sml_numvals = 0;
   1501 				ml->sml_values = NULL;
   1502 				ml->sml_nvalues = NULL;
   1503 				ml->sml_next = NULL;
   1504 				*prev = ml;
   1505 			}
   1506 		}
   1507 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
   1508 		be_entry_release_r( op, e );
   1509 		return SLAP_CB_CONTINUE;
   1510 	}
   1511 
   1512 	/* Did we receive a password policy request control? */
   1513 	if ( op->o_ctrlflag[ppolicy_cid] ) {
   1514 		send_ctrl = 1;
   1515 	}
   1516 
   1517 	/* See if this is a pwdModify exop. If so, we can
   1518 	 * access the plaintext passwords from that request.
   1519 	 */
   1520 	{
   1521 		slap_callback *sc;
   1522 
   1523 		for ( sc = op->o_callback; sc; sc=sc->sc_next ) {
   1524 			if ( sc->sc_response == slap_null_cb &&
   1525 				sc->sc_private ) {
   1526 				req_pwdexop_s *qpw = sc->sc_private;
   1527 				newpw = qpw->rs_new;
   1528 				oldpw = qpw->rs_old;
   1529 			   	break;
   1530 			}
   1531 		}
   1532 	}
   1533 
   1534 	ppolicy_get( op, e, &pp );
   1535 
   1536 	for ( ml = op->orm_modlist,
   1537 			pwmod = 0, mod_pw_only = 1,
   1538 			deladd = 0, delmod = NULL,
   1539 			addmod = NULL,
   1540 			zapReset = 1;
   1541 		ml != NULL; modtail = ml, ml = ml->sml_next )
   1542 	{
   1543 		if ( ml->sml_desc == pp.ad ) {
   1544 			pwmod = 1;
   1545 			pwmop = ml->sml_op;
   1546 			if ((deladd == 0) && (ml->sml_op == LDAP_MOD_DELETE) &&
   1547 				(ml->sml_values) && !BER_BVISNULL( &ml->sml_values[0] ))
   1548 			{
   1549 				deladd = 1;
   1550 				delmod = ml;
   1551 			}
   1552 
   1553 			if ((ml->sml_op == LDAP_MOD_ADD) ||
   1554 				(ml->sml_op == LDAP_MOD_REPLACE))
   1555 			{
   1556 				if ( ml->sml_values && !BER_BVISNULL( &ml->sml_values[0] )) {
   1557 					if ( deladd == 1 )
   1558 						deladd = 2;
   1559 
   1560 					/* FIXME: there's no easy way to ensure
   1561 					 * that add does not cause multiple
   1562 					 * userPassword values; one way (that
   1563 					 * would be consistent with the single
   1564 					 * password constraint) would be to turn
   1565 					 * add into replace); another would be
   1566 					 * to disallow add.
   1567 					 *
   1568 					 * Let's check at least that a single value
   1569 					 * is being added
   1570 					 */
   1571 					if ( addmod || !BER_BVISNULL( &ml->sml_values[ 1 ] ) ) {
   1572 						rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
   1573 						rs->sr_text = "Password policy only allows one password value";
   1574 						goto return_results;
   1575 					}
   1576 
   1577 					addmod = ml;
   1578 				} else {
   1579 					/* replace can have no values, add cannot */
   1580 					assert( ml->sml_op == LDAP_MOD_REPLACE );
   1581 				}
   1582 			}
   1583 
   1584 		} else if ( !is_at_operational( ml->sml_desc->ad_type ) ) {
   1585 			mod_pw_only = 0;
   1586 			/* modifying something other than password */
   1587 		}
   1588 
   1589 		/*
   1590 		 * If there is a request to explicitly add a pwdReset
   1591 		 * attribute, then we suppress the normal behaviour on
   1592 		 * password change, which is to remove the pwdReset
   1593 		 * attribute.
   1594 		 *
   1595 		 * This enables an administrator to assign a new password
   1596 		 * and place a "must reset" flag on the entry, which will
   1597 		 * stay until the user explicitly changes his/her password.
   1598 		 */
   1599 		if (ml->sml_desc == ad_pwdReset ) {
   1600 			if ((ml->sml_op == LDAP_MOD_ADD) ||
   1601 				(ml->sml_op == LDAP_MOD_REPLACE))
   1602 				zapReset = 0;
   1603 		}
   1604 	}
   1605 
   1606 	if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) {
   1607 		if ( dn_match( &op->o_conn->c_ndn,
   1608 				&pwcons[op->o_conn->c_conn_idx].dn )) {
   1609 			Debug( LDAP_DEBUG_TRACE,
   1610 				"connection restricted to password changing only\n", 0, 0, 0 );
   1611 			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
   1612 			rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password";
   1613 			pErr = PP_changeAfterReset;
   1614 			goto return_results;
   1615 		} else {
   1616 			ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
   1617 			BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
   1618 		}
   1619 	}
   1620 
   1621 	/*
   1622 	 * if we have a "safe password modify policy", then we need to check if we're doing
   1623 	 * a delete (with the old password), followed by an add (with the new password).
   1624 	 *
   1625 	 * If we got just a delete with nothing else, just let it go. We also skip all the checks if
   1626 	 * the root user is bound. Root can do anything, including avoid the policies.
   1627 	 */
   1628 
   1629 	if (!pwmod) goto do_modify;
   1630 
   1631 	/*
   1632 	 * Build the password history list in ascending time order
   1633 	 * We need this, even if the user is root, in order to maintain
   1634 	 * the pwdHistory operational attributes properly.
   1635 	 */
   1636 	if (addmod && pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) {
   1637 		struct berval oldpw;
   1638 		time_t oldtime;
   1639 
   1640 		for(i=0; ha->a_nvals[i].bv_val; i++) {
   1641 			rc = parse_pwdhistory( &(ha->a_nvals[i]), NULL,
   1642 				&oldtime, &oldpw );
   1643 
   1644 			if (rc != LDAP_SUCCESS) continue; /* invalid history entry */
   1645 
   1646 			if (oldpw.bv_val) {
   1647 				add_to_pwd_history( &tl, oldtime, &oldpw,
   1648 					&(ha->a_nvals[i]) );
   1649 				oldpw.bv_val = NULL;
   1650 				oldpw.bv_len = 0;
   1651 			}
   1652 		}
   1653 		for(p=tl; p; p=p->next, hsize++); /* count history size */
   1654 	}
   1655 
   1656 	if (be_isroot( op )) goto do_modify;
   1657 
   1658 	if (!pp.pwdAllowUserChange) {
   1659 		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
   1660 		rs->sr_text = "User alteration of password is not allowed";
   1661 		pErr = PP_passwordModNotAllowed;
   1662 		goto return_results;
   1663 	}
   1664 
   1665 	/* Just deleting? */
   1666 	if (!addmod) {
   1667 		/* skip everything else */
   1668 		pwmod = 0;
   1669 		goto do_modify;
   1670 	}
   1671 
   1672 	/* This is a pwdModify exop that provided the old pw.
   1673 	 * We need to create a Delete mod for this old pw and
   1674 	 * let the matching value get found later
   1675 	 */
   1676 	if (pp.pwdSafeModify && oldpw.bv_val ) {
   1677 		ml = (Modifications *)ch_calloc( sizeof( Modifications ), 1 );
   1678 		ml->sml_op = LDAP_MOD_DELETE;
   1679 		ml->sml_flags = SLAP_MOD_INTERNAL;
   1680 		ml->sml_desc = pp.ad;
   1681 		ml->sml_type = pp.ad->ad_cname;
   1682 		ml->sml_numvals = 1;
   1683 		ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
   1684 		ber_dupbv( &ml->sml_values[0], &oldpw );
   1685 		BER_BVZERO( &ml->sml_values[1] );
   1686 		ml->sml_next = op->orm_modlist;
   1687 		op->orm_modlist = ml;
   1688 		delmod = ml;
   1689 		deladd = 2;
   1690 	}
   1691 
   1692 	if (pp.pwdSafeModify && deladd != 2) {
   1693 		Debug( LDAP_DEBUG_TRACE,
   1694 			"change password must use DELETE followed by ADD/REPLACE\n",
   1695 			0, 0, 0 );
   1696 		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
   1697 		rs->sr_text = "Must supply old password to be changed as well as new one";
   1698 		pErr = PP_mustSupplyOldPassword;
   1699 		goto return_results;
   1700 	}
   1701 
   1702 	/* Check age, but only if pwdReset is not TRUE */
   1703 	pa = attr_find( e->e_attrs, ad_pwdReset );
   1704 	if ((!pa || !bvmatch( &pa->a_nvals[0], &slap_true_bv )) &&
   1705 		pp.pwdMinAge > 0) {
   1706 		time_t pwtime = (time_t)-1, now;
   1707 		int age;
   1708 
   1709 		if ((pa = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL)
   1710 			pwtime = parse_time( pa->a_nvals[0].bv_val );
   1711 		now = slap_get_time();
   1712 		age = (int)(now - pwtime);
   1713 		if ((pwtime != (time_t)-1) && (age < pp.pwdMinAge)) {
   1714 			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
   1715 			rs->sr_text = "Password is too young to change";
   1716 			pErr = PP_passwordTooYoung;
   1717 			goto return_results;
   1718 		}
   1719 	}
   1720 
   1721 	/* pa is used in password history check below, be sure it's set */
   1722 	if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL && delmod) {
   1723 		/*
   1724 		 * we have a password to check
   1725 		 */
   1726 		const char *txt;
   1727 
   1728 		bv = oldpw.bv_val ? &oldpw : delmod->sml_values;
   1729 		/* FIXME: no access checking? */
   1730 		rc = slap_passwd_check( op, NULL, pa, bv, &txt );
   1731 		if (rc != LDAP_SUCCESS) {
   1732 			Debug( LDAP_DEBUG_TRACE,
   1733 				"old password check failed: %s\n", txt, 0, 0 );
   1734 
   1735 			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
   1736 			rs->sr_text = "Must supply correct old password to change to new one";
   1737 			pErr = PP_mustSupplyOldPassword;
   1738 			goto return_results;
   1739 
   1740 		} else {
   1741 			int i;
   1742 
   1743 			/*
   1744 			 * replace the delete value with the (possibly hashed)
   1745 			 * value which is currently in the password.
   1746 			 */
   1747 			for ( i = 0; !BER_BVISNULL( &delmod->sml_values[i] ); i++ ) {
   1748 				free( delmod->sml_values[i].bv_val );
   1749 				BER_BVZERO( &delmod->sml_values[i] );
   1750 			}
   1751 			free( delmod->sml_values );
   1752 			delmod->sml_values = ch_calloc( sizeof(struct berval), 2 );
   1753 			BER_BVZERO( &delmod->sml_values[1] );
   1754 			ber_dupbv( &(delmod->sml_values[0]),  &(pa->a_nvals[0]) );
   1755 		}
   1756 	}
   1757 
   1758 	bv = newpw.bv_val ? &newpw : &addmod->sml_values[0];
   1759 	if (pp.pwdCheckQuality > 0) {
   1760 
   1761 		rc = check_password_quality( bv, &pp, &pErr, e );
   1762 		if (rc != LDAP_SUCCESS) {
   1763 			rs->sr_err = rc;
   1764 			rs->sr_text = "Password fails quality checking policy";
   1765 			goto return_results;
   1766 		}
   1767 	}
   1768 
   1769 	/* If pwdInHistory is zero, passwords may be reused */
   1770 	if (pa && pp.pwdInHistory > 0) {
   1771 		/*
   1772 		 * Last check - the password history.
   1773 		 */
   1774 		/* FIXME: no access checking? */
   1775 		if (slap_passwd_check( op, NULL, pa, bv, &txt ) == LDAP_SUCCESS) {
   1776 			/*
   1777 			 * This is bad - it means that the user is attempting
   1778 			 * to set the password to the same as the old one.
   1779 			 */
   1780 			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
   1781 			rs->sr_text = "Password is not being changed from existing value";
   1782 			pErr = PP_passwordInHistory;
   1783 			goto return_results;
   1784 		}
   1785 
   1786 		/*
   1787 		 * Iterate through the password history, and fail on any
   1788 		 * password matches.
   1789 		 */
   1790 		at = *pa;
   1791 		at.a_vals = cr;
   1792 		cr[1].bv_val = NULL;
   1793 		for(p=tl; p; p=p->next) {
   1794 			cr[0] = p->pw;
   1795 			/* FIXME: no access checking? */
   1796 			rc = slap_passwd_check( op, NULL, &at, bv, &txt );
   1797 
   1798 			if (rc != LDAP_SUCCESS) continue;
   1799 
   1800 			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
   1801 			rs->sr_text = "Password is in history of old passwords";
   1802 			pErr = PP_passwordInHistory;
   1803 			goto return_results;
   1804 		}
   1805 	}
   1806 
   1807 do_modify:
   1808 	if (pwmod) {
   1809 		struct berval timestamp;
   1810 		char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
   1811 		time_t now = slap_get_time();
   1812 
   1813 		/* If the conn is restricted, set a callback to clear it
   1814 		 * if the pwmod succeeds
   1815 		 */
   1816 		if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
   1817 			slap_callback *sc = op->o_tmpcalloc( 1, sizeof( slap_callback ),
   1818 				op->o_tmpmemctx );
   1819 			sc->sc_next = op->o_callback;
   1820 			/* Must use sc_response to insure we reset on success, before
   1821 			 * the client sees the response. Must use sc_cleanup to insure
   1822 			 * that it gets cleaned up if sc_response is not called.
   1823 			 */
   1824 			sc->sc_response = ppolicy_mod_cb;
   1825 			sc->sc_cleanup = ppolicy_mod_cb;
   1826 			op->o_callback = sc;
   1827 		}
   1828 
   1829 		/*
   1830 		 * keep the necessary pwd.. operational attributes
   1831 		 * up to date.
   1832 		 */
   1833 
   1834 		timestamp.bv_val = timebuf;
   1835 		timestamp.bv_len = sizeof(timebuf);
   1836 		slap_timestamp( &now, &timestamp );
   1837 
   1838 		mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
   1839 		mods->sml_desc = ad_pwdChangedTime;
   1840 		if (pwmop != LDAP_MOD_DELETE) {
   1841 			mods->sml_op = LDAP_MOD_REPLACE;
   1842 			mods->sml_numvals = 1;
   1843 			mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
   1844 			ber_dupbv( &mods->sml_values[0], &timestamp );
   1845 			BER_BVZERO( &mods->sml_values[1] );
   1846 			assert( !BER_BVISNULL( &mods->sml_values[0] ) );
   1847 
   1848 		} else {
   1849 			mods->sml_op = LDAP_MOD_DELETE;
   1850 		}
   1851 		mods->sml_flags = SLAP_MOD_INTERNAL;
   1852 		mods->sml_next = NULL;
   1853 		modtail->sml_next = mods;
   1854 		modtail = mods;
   1855 
   1856 		if (attr_find(e->e_attrs, ad_pwdGraceUseTime )) {
   1857 			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
   1858 			mods->sml_op = LDAP_MOD_DELETE;
   1859 			mods->sml_desc = ad_pwdGraceUseTime;
   1860 			mods->sml_flags = SLAP_MOD_INTERNAL;
   1861 			mods->sml_next = NULL;
   1862 			modtail->sml_next = mods;
   1863 			modtail = mods;
   1864 		}
   1865 
   1866 		if (attr_find(e->e_attrs, ad_pwdAccountLockedTime )) {
   1867 			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
   1868 			mods->sml_op = LDAP_MOD_DELETE;
   1869 			mods->sml_desc = ad_pwdAccountLockedTime;
   1870 			mods->sml_flags = SLAP_MOD_INTERNAL;
   1871 			mods->sml_next = NULL;
   1872 			modtail->sml_next = mods;
   1873 			modtail = mods;
   1874 		}
   1875 
   1876 		if (attr_find(e->e_attrs, ad_pwdFailureTime )) {
   1877 			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
   1878 			mods->sml_op = LDAP_MOD_DELETE;
   1879 			mods->sml_desc = ad_pwdFailureTime;
   1880 			mods->sml_flags = SLAP_MOD_INTERNAL;
   1881 			mods->sml_next = NULL;
   1882 			modtail->sml_next = mods;
   1883 			modtail = mods;
   1884 		}
   1885 
   1886 		/* Delete the pwdReset attribute, since it's being reset */
   1887 		if ((zapReset) && (attr_find(e->e_attrs, ad_pwdReset ))) {
   1888 			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
   1889 			mods->sml_op = LDAP_MOD_DELETE;
   1890 			mods->sml_desc = ad_pwdReset;
   1891 			mods->sml_flags = SLAP_MOD_INTERNAL;
   1892 			mods->sml_next = NULL;
   1893 			modtail->sml_next = mods;
   1894 			modtail = mods;
   1895 		}
   1896 
   1897 		if (pp.pwdInHistory > 0) {
   1898 			if (hsize >= pp.pwdInHistory) {
   1899 				/*
   1900 				 * We use the >= operator, since we are going to add
   1901 				 * the existing password attribute value into the
   1902 				 * history - thus the cardinality of history values is
   1903 				 * about to rise by one.
   1904 				 *
   1905 				 * If this would push it over the limit of history
   1906 				 * values (remembering - the password policy could have
   1907 				 * changed since the password was last altered), we must
   1908 				 * delete at least 1 value from the pwdHistory list.
   1909 				 *
   1910 				 * In fact, we delete '(#pwdHistory attrs - max pwd
   1911 				 * history length) + 1' values, starting with the oldest.
   1912 				 * This is easily evaluated, since the linked list is
   1913 				 * created in ascending time order.
   1914 				 */
   1915 				mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
   1916 				mods->sml_op = LDAP_MOD_DELETE;
   1917 				mods->sml_flags = SLAP_MOD_INTERNAL;
   1918 				mods->sml_desc = ad_pwdHistory;
   1919 				mods->sml_numvals = hsize - pp.pwdInHistory + 1;
   1920 				mods->sml_values = ch_calloc( sizeof( struct berval ),
   1921 					hsize - pp.pwdInHistory + 2 );
   1922 				BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] );
   1923 				for(i=0,p=tl; i < (hsize - pp.pwdInHistory + 1); i++, p=p->next) {
   1924 					BER_BVZERO( &mods->sml_values[i] );
   1925 					ber_dupbv( &(mods->sml_values[i]), &p->bv );
   1926 				}
   1927 				mods->sml_next = NULL;
   1928 				modtail->sml_next = mods;
   1929 				modtail = mods;
   1930 			}
   1931 			free_pwd_history_list( &tl );
   1932 
   1933 			/*
   1934 			 * Now add the existing password into the history list.
   1935 			 * This will be executed even if the operation is to delete
   1936 			 * the password entirely.
   1937 			 *
   1938 			 * This isn't in the spec explicitly, but it seems to make
   1939 			 * sense that the password history list is the list of all
   1940 			 * previous passwords - even if they were deleted. Thus, if
   1941 			 * someone tries to add a historical password at some future
   1942 			 * point, it will fail.
   1943 			 */
   1944 			if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL) {
   1945 				mods = (Modifications *) ch_malloc( sizeof( Modifications ) );
   1946 				mods->sml_op = LDAP_MOD_ADD;
   1947 				mods->sml_flags = SLAP_MOD_INTERNAL;
   1948 				mods->sml_type.bv_val = NULL;
   1949 				mods->sml_desc = ad_pwdHistory;
   1950 				mods->sml_nvalues = NULL;
   1951 				mods->sml_numvals = 1;
   1952 				mods->sml_values = ch_calloc( sizeof( struct berval ), 2 );
   1953 				mods->sml_values[ 1 ].bv_val = NULL;
   1954 				mods->sml_values[ 1 ].bv_len = 0;
   1955 				make_pwd_history_value( timebuf, &mods->sml_values[0], pa );
   1956 				mods->sml_next = NULL;
   1957 				modtail->sml_next = mods;
   1958 				modtail = mods;
   1959 
   1960 			} else {
   1961 				Debug( LDAP_DEBUG_TRACE,
   1962 				"ppolicy_modify: password attr lookup failed\n", 0, 0, 0 );
   1963 			}
   1964 		}
   1965 
   1966 		/*
   1967 		 * Controversial bit here. If the new password isn't hashed
   1968 		 * (ie, is cleartext), we probably should hash it according
   1969 		 * to the default hash. The reason for this is that we want
   1970 		 * to use the policy if possible, but if we hash the password
   1971 		 * before, then we're going to run into trouble when it
   1972 		 * comes time to check the password.
   1973 		 *
   1974 		 * Now, the right thing to do is to use the extended password
   1975 		 * modify operation, but not all software can do this,
   1976 		 * therefore it makes sense to hash the new password, now
   1977 		 * we know it passes the policy requirements.
   1978 		 *
   1979 		 * Of course, if the password is already hashed, then we
   1980 		 * leave it alone.
   1981 		 */
   1982 
   1983 		if ((pi->hash_passwords) && (addmod) && !newpw.bv_val &&
   1984 			(password_scheme( &(addmod->sml_values[0]), NULL ) != LDAP_SUCCESS))
   1985 		{
   1986 			struct berval hpw, bv;
   1987 
   1988 			slap_passwd_hash( &(addmod->sml_values[0]), &hpw, &txt );
   1989 			if (hpw.bv_val == NULL) {
   1990 					/*
   1991 					 * hashing didn't work. Emit an error.
   1992 					 */
   1993 				rs->sr_err = LDAP_OTHER;
   1994 				rs->sr_text = txt;
   1995 				goto return_results;
   1996 			}
   1997 			bv = addmod->sml_values[0];
   1998 				/* clear and discard the clear password */
   1999 			memset(bv.bv_val, 0, bv.bv_len);
   2000 			ber_memfree(bv.bv_val);
   2001 			addmod->sml_values[0] = hpw;
   2002 		}
   2003 	}
   2004 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
   2005 	be_entry_release_r( op, e );
   2006 	return SLAP_CB_CONTINUE;
   2007 
   2008 return_results:
   2009 	free_pwd_history_list( &tl );
   2010 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
   2011 	be_entry_release_r( op, e );
   2012 	if ( send_ctrl ) {
   2013 		LDAPControl *ctrl = NULL;
   2014 
   2015 		ctrl = create_passcontrol( -1, -1, pErr );
   2016 		oldctrls = add_passcontrol( op, rs, ctrl );
   2017 	}
   2018 	send_ldap_result( op, rs );
   2019 	if ( send_ctrl ) {
   2020 		ctrls_cleanup( op, rs, oldctrls );
   2021 	}
   2022 	return rs->sr_err;
   2023 }
   2024 
   2025 static int
   2026 ppolicy_parseCtrl(
   2027 	Operation *op,
   2028 	SlapReply *rs,
   2029 	LDAPControl *ctrl )
   2030 {
   2031 	if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
   2032 		rs->sr_text = "passwordPolicyRequest control value not absent";
   2033 		return LDAP_PROTOCOL_ERROR;
   2034 	}
   2035 	op->o_ctrlflag[ppolicy_cid] = ctrl->ldctl_iscritical
   2036 		? SLAP_CONTROL_CRITICAL
   2037 		: SLAP_CONTROL_NONCRITICAL;
   2038 
   2039 	return LDAP_SUCCESS;
   2040 }
   2041 
   2042 static int
   2043 attrPretty(
   2044 	Syntax *syntax,
   2045 	struct berval *val,
   2046 	struct berval *out,
   2047 	void *ctx )
   2048 {
   2049 	AttributeDescription *ad = NULL;
   2050 	const char *err;
   2051 	int code;
   2052 
   2053 	code = slap_bv2ad( val, &ad, &err );
   2054 	if ( !code ) {
   2055 		ber_dupbv_x( out, &ad->ad_type->sat_cname, ctx );
   2056 	}
   2057 	return code;
   2058 }
   2059 
   2060 static int
   2061 attrNormalize(
   2062 	slap_mask_t use,
   2063 	Syntax *syntax,
   2064 	MatchingRule *mr,
   2065 	struct berval *val,
   2066 	struct berval *out,
   2067 	void *ctx )
   2068 {
   2069 	AttributeDescription *ad = NULL;
   2070 	const char *err;
   2071 	int code;
   2072 
   2073 	code = slap_bv2ad( val, &ad, &err );
   2074 	if ( !code ) {
   2075 		ber_str2bv_x( ad->ad_type->sat_oid, 0, 1, out, ctx );
   2076 	}
   2077 	return code;
   2078 }
   2079 
   2080 static int
   2081 ppolicy_db_init(
   2082 	BackendDB *be,
   2083 	ConfigReply *cr
   2084 )
   2085 {
   2086 	slap_overinst *on = (slap_overinst *) be->bd_info;
   2087 
   2088 	/* Has User Schema been initialized yet? */
   2089 	if ( !pwd_UsSchema[0].ad[0] ) {
   2090 		const char *err;
   2091 		int i, code;
   2092 
   2093 		for (i=0; pwd_UsSchema[i].def; i++) {
   2094 			code = slap_str2ad( pwd_UsSchema[i].def, pwd_UsSchema[i].ad, &err );
   2095 			if ( code ) {
   2096 				fprintf( stderr, "User Schema Load failed %d: %s\n", code, err );
   2097 				return code;
   2098 			}
   2099 		}
   2100 		{
   2101 			Syntax *syn;
   2102 			MatchingRule *mr;
   2103 
   2104 			syn = ch_malloc( sizeof( Syntax ));
   2105 			*syn = *ad_pwdAttribute->ad_type->sat_syntax;
   2106 			syn->ssyn_pretty = attrPretty;
   2107 			ad_pwdAttribute->ad_type->sat_syntax = syn;
   2108 
   2109 			mr = ch_malloc( sizeof( MatchingRule ));
   2110 			*mr = *ad_pwdAttribute->ad_type->sat_equality;
   2111 			mr->smr_normalize = attrNormalize;
   2112 			ad_pwdAttribute->ad_type->sat_equality = mr;
   2113 		}
   2114 	}
   2115 
   2116 	on->on_bi.bi_private = ch_calloc( sizeof(pp_info), 1 );
   2117 
   2118 	if ( dtblsize && !pwcons ) {
   2119 		/* accommodate for c_conn_idx == -1 */
   2120 		pwcons = ch_calloc( sizeof(pw_conn), dtblsize + 1 );
   2121 		pwcons++;
   2122 	}
   2123 
   2124 	return 0;
   2125 }
   2126 
   2127 static int
   2128 ppolicy_db_open(
   2129 	BackendDB *be,
   2130 	ConfigReply *cr
   2131 )
   2132 {
   2133 	ov_count++;
   2134 	return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
   2135 }
   2136 
   2137 static int
   2138 ppolicy_close(
   2139 	BackendDB *be,
   2140 	ConfigReply *cr
   2141 )
   2142 {
   2143 	slap_overinst *on = (slap_overinst *) be->bd_info;
   2144 	pp_info *pi = on->on_bi.bi_private;
   2145 
   2146 	/* Perhaps backover should provide bi_destroy hooks... */
   2147 	ov_count--;
   2148 	if ( ov_count <=0 && pwcons ) {
   2149 		pwcons--;
   2150 		free( pwcons );
   2151 		pwcons = NULL;
   2152 	}
   2153 	free( pi->def_policy.bv_val );
   2154 	free( pi );
   2155 
   2156 	return 0;
   2157 }
   2158 
   2159 static char *extops[] = {
   2160 	LDAP_EXOP_MODIFY_PASSWD,
   2161 	NULL
   2162 };
   2163 
   2164 static slap_overinst ppolicy;
   2165 
   2166 int ppolicy_initialize()
   2167 {
   2168 	int i, code;
   2169 
   2170 	for (i=0; pwd_OpSchema[i].def; i++) {
   2171 		code = register_at( pwd_OpSchema[i].def, pwd_OpSchema[i].ad, 0 );
   2172 		if ( code ) {
   2173 			Debug( LDAP_DEBUG_ANY,
   2174 				"ppolicy_initialize: register_at failed\n", 0, 0, 0 );
   2175 			return code;
   2176 		}
   2177 		/* Allow Manager to set these as needed */
   2178 		if ( is_at_no_user_mod( (*pwd_OpSchema[i].ad)->ad_type )) {
   2179 			(*pwd_OpSchema[i].ad)->ad_type->sat_flags |=
   2180 				SLAP_AT_MANAGEABLE;
   2181 		}
   2182 	}
   2183 
   2184 	code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
   2185 		SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, extops,
   2186 		ppolicy_parseCtrl, &ppolicy_cid );
   2187 	if ( code != LDAP_SUCCESS ) {
   2188 		fprintf( stderr, "Failed to register control %d\n", code );
   2189 		return code;
   2190 	}
   2191 
   2192 	ldap_pvt_thread_mutex_init( &chk_syntax_mutex );
   2193 
   2194 	ppolicy.on_bi.bi_type = "ppolicy";
   2195 	ppolicy.on_bi.bi_db_init = ppolicy_db_init;
   2196 	ppolicy.on_bi.bi_db_open = ppolicy_db_open;
   2197 	ppolicy.on_bi.bi_db_close = ppolicy_close;
   2198 
   2199 	ppolicy.on_bi.bi_op_add = ppolicy_add;
   2200 	ppolicy.on_bi.bi_op_bind = ppolicy_bind;
   2201 	ppolicy.on_bi.bi_op_compare = ppolicy_restrict;
   2202 	ppolicy.on_bi.bi_op_delete = ppolicy_restrict;
   2203 	ppolicy.on_bi.bi_op_modify = ppolicy_modify;
   2204 	ppolicy.on_bi.bi_op_search = ppolicy_restrict;
   2205 	ppolicy.on_bi.bi_connection_destroy = ppolicy_connection_destroy;
   2206 
   2207 	ppolicy.on_bi.bi_cf_ocs = ppolicyocs;
   2208 	code = config_register_schema( ppolicycfg, ppolicyocs );
   2209 	if ( code ) return code;
   2210 
   2211 	return overlay_register( &ppolicy );
   2212 }
   2213 
   2214 #if SLAPD_OVER_PPOLICY == SLAPD_MOD_DYNAMIC
   2215 int init_module(int argc, char *argv[]) {
   2216 	return ppolicy_initialize();
   2217 }
   2218 #endif
   2219 
   2220 #endif	/* defined(SLAPD_OVER_PPOLICY) */
   2221