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