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