ppolicy.c revision 1.1.1.6
1/*	$NetBSD: ppolicy.c,v 1.1.1.6 2017/02/09 01:47:02 christos Exp $	*/
2
3/* $OpenLDAP$ */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 2004-2016 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.1.1.6 2017/02/09 01:47:02 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 */
58typedef 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 */
68typedef struct pw_conn {
69	struct berval dn;	/* DN of restricted user */
70} pw_conn;
71
72static pw_conn *pwcons;
73static int ppolicy_cid;
74static int ov_count;
75
76typedef 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
105typedef 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 */
113static AttributeDescription *ad_pwdChangedTime, *ad_pwdAccountLockedTime,
114	*ad_pwdFailureTime, *ad_pwdHistory, *ad_pwdGraceUseTime, *ad_pwdReset,
115	*ad_pwdPolicySubentry;
116
117static 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 */
187static 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
196static 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
217static ldap_pvt_thread_mutex_t chk_syntax_mutex;
218
219enum {
220	PPOLICY_DEFAULT = 1,
221	PPOLICY_HASH_CLEARTEXT,
222	PPOLICY_USE_LOCKOUT
223};
224
225static ConfigDriver ppolicy_cf_default;
226
227static 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
254static 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
265static int
266ppolicy_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
316static time_t
317parse_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
330static int
331account_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
383static const char ppolicy_ctrl_oid[] = LDAP_CONTROL_PASSWORDPOLICYRESPONSE;
384
385static LDAPControl *
386create_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 );
437fail:
438	(void)ber_free_buf(ber);
439
440	return cp;
441}
442
443static LDAPControl **
444add_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
472static void
473ppolicy_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
486static void
487ppolicy_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
588defaultpol:
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
603static int
604password_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
633static int
634check_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
740static int
741parse_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
807exit_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
821static void
822add_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
854static void
855make_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
884static void
885free_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
902typedef 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
912static void
913ctrls_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
937static int
938ppolicy_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
947static int
948ppolicy_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
1158grace:
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
1197check_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
1232done:
1233	op->o_bd->bd_info = (BackendInfo *)on->on_info;
1234	be_entry_release_r( op, e );
1235
1236locked:
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
1296static int
1297ppolicy_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_next = op->o_callback->sc_next;
1332		cb->sc_private = ppb;
1333		op->o_callback->sc_next = cb;
1334
1335		/* Did we receive a password policy request control? */
1336		if ( op->o_ctrlflag[ppolicy_cid] ) {
1337			ppb->send_ctrl = 1;
1338		}
1339
1340		op->o_bd->bd_info = (BackendInfo *)on;
1341		ppolicy_get( op, e, &ppb->pp );
1342
1343		rc = account_locked( op, e, &ppb->pp, &ppb->mod );
1344
1345		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1346		be_entry_release_r( op, e );
1347
1348		if ( rc ) {
1349			ppb->pErr = PP_accountLocked;
1350			send_ldap_error( op, rs, LDAP_INVALID_CREDENTIALS, NULL );
1351			return rs->sr_err;
1352		}
1353
1354	}
1355
1356	return SLAP_CB_CONTINUE;
1357}
1358
1359/* Reset the restricted info for the next session on this connection */
1360static int
1361ppolicy_connection_destroy( BackendDB *bd, Connection *conn )
1362{
1363	if ( pwcons && !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) {
1364		ch_free( pwcons[conn->c_conn_idx].dn.bv_val );
1365		BER_BVZERO( &pwcons[conn->c_conn_idx].dn );
1366	}
1367	return SLAP_CB_CONTINUE;
1368}
1369
1370/* Check if this connection is restricted */
1371static int
1372ppolicy_restrict(
1373	Operation *op,
1374	SlapReply *rs )
1375{
1376	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1377	int send_ctrl = 0;
1378
1379	/* Did we receive a password policy request control? */
1380	if ( op->o_ctrlflag[ppolicy_cid] ) {
1381		send_ctrl = 1;
1382	}
1383
1384	if ( op->o_conn && !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
1385		LDAPControl **oldctrls;
1386		/* if the current authcDN doesn't match the one we recorded,
1387		 * then an intervening Bind has succeeded and the restriction
1388		 * no longer applies. (ITS#4516)
1389		 */
1390		if ( !dn_match( &op->o_conn->c_ndn,
1391				&pwcons[op->o_conn->c_conn_idx].dn )) {
1392			ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1393			BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1394			return SLAP_CB_CONTINUE;
1395		}
1396
1397		Debug( LDAP_DEBUG_TRACE,
1398			"connection restricted to password changing only\n", 0, 0, 0);
1399		if ( send_ctrl ) {
1400			LDAPControl *ctrl = NULL;
1401			ctrl = create_passcontrol( op, -1, -1, PP_changeAfterReset );
1402			oldctrls = add_passcontrol( op, rs, ctrl );
1403		}
1404		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1405		send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS,
1406			"Operations are restricted to bind/unbind/abandon/StartTLS/modify password" );
1407		if ( send_ctrl ) {
1408			ctrls_cleanup( op, rs, oldctrls );
1409		}
1410		return rs->sr_err;
1411	}
1412
1413	return SLAP_CB_CONTINUE;
1414}
1415
1416static int
1417ppolicy_compare_response(
1418	Operation *op,
1419	SlapReply *rs )
1420{
1421	/* map compare responses to bind responses */
1422	if ( rs->sr_err == LDAP_COMPARE_TRUE )
1423		rs->sr_err = LDAP_SUCCESS;
1424	else if ( rs->sr_err == LDAP_COMPARE_FALSE )
1425		rs->sr_err = LDAP_INVALID_CREDENTIALS;
1426
1427	ppolicy_bind_response( op, rs );
1428
1429	/* map back to compare */
1430	if ( rs->sr_err == LDAP_SUCCESS )
1431		rs->sr_err = LDAP_COMPARE_TRUE;
1432	else if ( rs->sr_err == LDAP_INVALID_CREDENTIALS )
1433		rs->sr_err = LDAP_COMPARE_FALSE;
1434
1435	return SLAP_CB_CONTINUE;
1436}
1437
1438static int
1439ppolicy_compare(
1440	Operation *op,
1441	SlapReply *rs )
1442{
1443	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1444
1445	if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE )
1446		return rs->sr_err;
1447
1448	/* Did we receive a password policy request control?
1449	 * Are we testing the userPassword?
1450	 */
1451	if ( op->o_ctrlflag[ppolicy_cid] &&
1452		op->orc_ava->aa_desc == slap_schema.si_ad_userPassword ) {
1453		Entry *e;
1454		int rc;
1455		ppbind *ppb;
1456		slap_callback *cb;
1457
1458		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1459		rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1460
1461		if ( rc != LDAP_SUCCESS ) {
1462			return SLAP_CB_CONTINUE;
1463		}
1464
1465		cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback),
1466			1, op->o_tmpmemctx );
1467		ppb = (ppbind *)(cb+1);
1468		ppb->on = on;
1469		ppb->pErr = PP_noError;
1470		ppb->send_ctrl = 1;
1471		/* failures here don't lockout the connection */
1472		ppb->set_restrict = 0;
1473
1474		/* Setup a callback so we can munge the result */
1475
1476		cb->sc_response = ppolicy_compare_response;
1477		cb->sc_next = op->o_callback->sc_next;
1478		cb->sc_private = ppb;
1479		op->o_callback->sc_next = cb;
1480
1481		op->o_bd->bd_info = (BackendInfo *)on;
1482		ppolicy_get( op, e, &ppb->pp );
1483
1484		rc = account_locked( op, e, &ppb->pp, &ppb->mod );
1485
1486		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1487		be_entry_release_r( op, e );
1488
1489		if ( rc ) {
1490			ppb->pErr = PP_accountLocked;
1491			send_ldap_error( op, rs, LDAP_COMPARE_FALSE, NULL );
1492			return rs->sr_err;
1493		}
1494	}
1495	return SLAP_CB_CONTINUE;
1496}
1497
1498static int
1499ppolicy_add(
1500	Operation *op,
1501	SlapReply *rs )
1502{
1503	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1504	pp_info *pi = on->on_bi.bi_private;
1505	PassPolicy pp;
1506	Attribute *pa;
1507	const char *txt;
1508
1509	if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE )
1510		return rs->sr_err;
1511
1512	/* If this is a replica, assume the master checked everything */
1513	if ( be_shadow_update( op ))
1514		return SLAP_CB_CONTINUE;
1515
1516	/* Check for password in entry */
1517	if ((pa = attr_find( op->oq_add.rs_e->e_attrs,
1518		slap_schema.si_ad_userPassword )))
1519	{
1520		assert( pa->a_vals != NULL );
1521		assert( !BER_BVISNULL( &pa->a_vals[ 0 ] ) );
1522
1523		if ( !BER_BVISNULL( &pa->a_vals[ 1 ] ) ) {
1524			send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, "Password policy only allows one password value" );
1525			return rs->sr_err;
1526		}
1527
1528		/*
1529		 * new entry contains a password - if we're not the root user
1530		 * then we need to check that the password fits in with the
1531		 * security policy for the new entry.
1532		 */
1533		ppolicy_get( op, op->ora_e, &pp );
1534		if (pp.pwdCheckQuality > 0 && !be_isroot( op )) {
1535			struct berval *bv = &(pa->a_vals[0]);
1536			int rc, send_ctrl = 0;
1537			LDAPPasswordPolicyError pErr = PP_noError;
1538			char *txt;
1539
1540			/* Did we receive a password policy request control? */
1541			if ( op->o_ctrlflag[ppolicy_cid] ) {
1542				send_ctrl = 1;
1543			}
1544			rc = check_password_quality( bv, &pp, &pErr, op->ora_e, &txt );
1545			if (rc != LDAP_SUCCESS) {
1546				LDAPControl **oldctrls = NULL;
1547				op->o_bd->bd_info = (BackendInfo *)on->on_info;
1548				if ( send_ctrl ) {
1549					LDAPControl *ctrl = NULL;
1550					ctrl = create_passcontrol( op, -1, -1, pErr );
1551					oldctrls = add_passcontrol( op, rs, ctrl );
1552				}
1553				send_ldap_error( op, rs, rc, txt ? txt : "Password fails quality checking policy" );
1554				if ( txt ) {
1555					free( txt );
1556				}
1557				if ( send_ctrl ) {
1558					ctrls_cleanup( op, rs, oldctrls );
1559				}
1560				return rs->sr_err;
1561			}
1562		}
1563			/*
1564			 * A controversial bit. We hash cleartext
1565			 * passwords provided via add and modify operations
1566			 * You're not really supposed to do this, since
1567			 * the X.500 model says "store attributes" as they
1568			 * get provided. By default, this is what we do
1569			 *
1570			 * But if the hash_passwords flag is set, we hash
1571			 * any cleartext password attribute values via the
1572			 * default password hashing scheme.
1573			 */
1574		if ((pi->hash_passwords) &&
1575			(password_scheme( &(pa->a_vals[0]), NULL ) != LDAP_SUCCESS)) {
1576			struct berval hpw;
1577
1578			slap_passwd_hash( &(pa->a_vals[0]), &hpw, &txt );
1579			if (hpw.bv_val == NULL) {
1580				/*
1581				 * hashing didn't work. Emit an error.
1582				 */
1583				rs->sr_err = LDAP_OTHER;
1584				rs->sr_text = txt;
1585				send_ldap_error( op, rs, LDAP_OTHER, "Password hashing failed" );
1586				return rs->sr_err;
1587			}
1588
1589			memset( pa->a_vals[0].bv_val, 0, pa->a_vals[0].bv_len);
1590			ber_memfree( pa->a_vals[0].bv_val );
1591			pa->a_vals[0].bv_val = hpw.bv_val;
1592			pa->a_vals[0].bv_len = hpw.bv_len;
1593		}
1594
1595		/* If password aging is in effect, set the pwdChangedTime */
1596		if ( pp.pwdMaxAge || pp.pwdMinAge ) {
1597			struct berval timestamp;
1598			char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
1599			time_t now = slap_get_time();
1600
1601			timestamp.bv_val = timebuf;
1602			timestamp.bv_len = sizeof(timebuf);
1603			slap_timestamp( &now, &timestamp );
1604
1605			attr_merge_one( op->ora_e, ad_pwdChangedTime, &timestamp, &timestamp );
1606		}
1607	}
1608	return SLAP_CB_CONTINUE;
1609}
1610
1611static int
1612ppolicy_mod_cb( Operation *op, SlapReply *rs )
1613{
1614	slap_callback *sc = op->o_callback;
1615	op->o_callback = sc->sc_next;
1616	if ( rs->sr_err == LDAP_SUCCESS ) {
1617		ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1618		BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1619	}
1620	op->o_tmpfree( sc, op->o_tmpmemctx );
1621	return SLAP_CB_CONTINUE;
1622}
1623
1624static int
1625ppolicy_modify( Operation *op, SlapReply *rs )
1626{
1627	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
1628	pp_info			*pi = on->on_bi.bi_private;
1629	int			i, rc, mod_pw_only, pwmod, pwmop = -1, deladd,
1630				hsize = 0;
1631	PassPolicy		pp;
1632	Modifications		*mods = NULL, *modtail = NULL,
1633				*ml, *delmod, *addmod;
1634	Attribute		*pa, *ha, at;
1635	const char		*txt;
1636	pw_hist			*tl = NULL, *p;
1637	int			zapReset, send_ctrl = 0, free_txt = 0;
1638	Entry			*e;
1639	struct berval		newpw = BER_BVNULL, oldpw = BER_BVNULL,
1640				*bv, cr[2];
1641	LDAPPasswordPolicyError pErr = PP_noError;
1642	LDAPControl		*ctrl = NULL;
1643	LDAPControl 		**oldctrls = NULL;
1644	int			is_pwdexop = 0;
1645	int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0;
1646	int got_changed = 0, got_history = 0;
1647
1648	op->o_bd->bd_info = (BackendInfo *)on->on_info;
1649	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1650	op->o_bd->bd_info = (BackendInfo *)on;
1651
1652	if ( rc != LDAP_SUCCESS ) return SLAP_CB_CONTINUE;
1653
1654	/* If this is a replica, we may need to tweak some of the
1655	 * master's modifications. Otherwise, just pass it through.
1656	 */
1657	if ( be_shadow_update( op )) {
1658		Modifications **prev;
1659		Attribute *a_grace, *a_lock, *a_fail;
1660
1661		a_grace = attr_find( e->e_attrs, ad_pwdGraceUseTime );
1662		a_lock = attr_find( e->e_attrs, ad_pwdAccountLockedTime );
1663		a_fail = attr_find( e->e_attrs, ad_pwdFailureTime );
1664
1665		for( prev = &op->orm_modlist, ml = *prev; ml; ml = *prev ) {
1666
1667			if ( ml->sml_desc == slap_schema.si_ad_userPassword )
1668				got_pw = 1;
1669
1670			/* If we're deleting an attr that didn't exist,
1671			 * drop this delete op
1672			 */
1673			if ( ml->sml_op == LDAP_MOD_DELETE ) {
1674				int drop = 0;
1675
1676				if ( ml->sml_desc == ad_pwdGraceUseTime ) {
1677					if ( !a_grace || got_del_grace ) {
1678						drop = 1;
1679					} else {
1680						got_del_grace = 1;
1681					}
1682				} else
1683				if ( ml->sml_desc == ad_pwdAccountLockedTime ) {
1684					if ( !a_lock || got_del_lock ) {
1685						drop = 1;
1686					} else {
1687						got_del_lock = 1;
1688					}
1689				} else
1690				if ( ml->sml_desc == ad_pwdFailureTime ) {
1691					if ( !a_fail || got_del_fail ) {
1692						drop = 1;
1693					} else {
1694						got_del_fail = 1;
1695					}
1696				}
1697				if ( drop ) {
1698					*prev = ml->sml_next;
1699					ml->sml_next = NULL;
1700					slap_mods_free( ml, 1 );
1701					continue;
1702				}
1703			}
1704			prev = &ml->sml_next;
1705		}
1706
1707		/* If we're resetting the password, make sure grace, accountlock,
1708		 * and failure also get removed.
1709		 */
1710		if ( got_pw ) {
1711			if ( a_grace && !got_del_grace ) {
1712				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1713				ml->sml_op = LDAP_MOD_DELETE;
1714				ml->sml_flags = SLAP_MOD_INTERNAL;
1715				ml->sml_type.bv_val = NULL;
1716				ml->sml_desc = ad_pwdGraceUseTime;
1717				ml->sml_numvals = 0;
1718				ml->sml_values = NULL;
1719				ml->sml_nvalues = NULL;
1720				ml->sml_next = NULL;
1721				*prev = ml;
1722				prev = &ml->sml_next;
1723			}
1724			if ( a_lock && !got_del_lock ) {
1725				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1726				ml->sml_op = LDAP_MOD_DELETE;
1727				ml->sml_flags = SLAP_MOD_INTERNAL;
1728				ml->sml_type.bv_val = NULL;
1729				ml->sml_desc = ad_pwdAccountLockedTime;
1730				ml->sml_numvals = 0;
1731				ml->sml_values = NULL;
1732				ml->sml_nvalues = NULL;
1733				ml->sml_next = NULL;
1734				*prev = ml;
1735			}
1736			if ( a_fail && !got_del_fail ) {
1737				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1738				ml->sml_op = LDAP_MOD_DELETE;
1739				ml->sml_flags = SLAP_MOD_INTERNAL;
1740				ml->sml_type.bv_val = NULL;
1741				ml->sml_desc = ad_pwdFailureTime;
1742				ml->sml_numvals = 0;
1743				ml->sml_values = NULL;
1744				ml->sml_nvalues = NULL;
1745				ml->sml_next = NULL;
1746				*prev = ml;
1747			}
1748		}
1749		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1750		be_entry_release_r( op, e );
1751		return SLAP_CB_CONTINUE;
1752	}
1753
1754	/* Did we receive a password policy request control? */
1755	if ( op->o_ctrlflag[ppolicy_cid] ) {
1756		send_ctrl = 1;
1757	}
1758
1759	/* See if this is a pwdModify exop. If so, we can
1760	 * access the plaintext passwords from that request.
1761	 */
1762	{
1763		slap_callback *sc;
1764
1765		for ( sc = op->o_callback; sc; sc=sc->sc_next ) {
1766			if ( sc->sc_response == slap_null_cb &&
1767				sc->sc_private ) {
1768				req_pwdexop_s *qpw = sc->sc_private;
1769				newpw = qpw->rs_new;
1770				oldpw = qpw->rs_old;
1771				is_pwdexop = 1;
1772			   	break;
1773			}
1774		}
1775	}
1776
1777	ppolicy_get( op, e, &pp );
1778
1779	for ( ml = op->orm_modlist,
1780			pwmod = 0, mod_pw_only = 1,
1781			deladd = 0, delmod = NULL,
1782			addmod = NULL,
1783			zapReset = 1;
1784		ml != NULL; modtail = ml, ml = ml->sml_next )
1785	{
1786		if ( ml->sml_desc == pp.ad ) {
1787			pwmod = 1;
1788			pwmop = ml->sml_op;
1789			if ((deladd == 0) && (ml->sml_op == LDAP_MOD_DELETE) &&
1790				(ml->sml_values) && !BER_BVISNULL( &ml->sml_values[0] ))
1791			{
1792				deladd = 1;
1793				delmod = ml;
1794			}
1795
1796			if ((ml->sml_op == LDAP_MOD_ADD) ||
1797				(ml->sml_op == LDAP_MOD_REPLACE))
1798			{
1799				if ( ml->sml_values && !BER_BVISNULL( &ml->sml_values[0] )) {
1800					if ( deladd == 1 )
1801						deladd = 2;
1802
1803					/* FIXME: there's no easy way to ensure
1804					 * that add does not cause multiple
1805					 * userPassword values; one way (that
1806					 * would be consistent with the single
1807					 * password constraint) would be to turn
1808					 * add into replace); another would be
1809					 * to disallow add.
1810					 *
1811					 * Let's check at least that a single value
1812					 * is being added
1813					 */
1814					if ( addmod || !BER_BVISNULL( &ml->sml_values[ 1 ] ) ) {
1815						rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1816						rs->sr_text = "Password policy only allows one password value";
1817						goto return_results;
1818					}
1819
1820					addmod = ml;
1821				} else {
1822					/* replace can have no values, add cannot */
1823					assert( ml->sml_op == LDAP_MOD_REPLACE );
1824				}
1825			}
1826
1827		} else if ( !(ml->sml_flags & SLAP_MOD_INTERNAL) && !is_at_operational( ml->sml_desc->ad_type ) ) {
1828			mod_pw_only = 0;
1829			/* modifying something other than password */
1830		}
1831
1832		/*
1833		 * If there is a request to explicitly add a pwdReset
1834		 * attribute, then we suppress the normal behaviour on
1835		 * password change, which is to remove the pwdReset
1836		 * attribute.
1837		 *
1838		 * This enables an administrator to assign a new password
1839		 * and place a "must reset" flag on the entry, which will
1840		 * stay until the user explicitly changes his/her password.
1841		 */
1842		if (ml->sml_desc == ad_pwdReset ) {
1843			if ((ml->sml_op == LDAP_MOD_ADD) ||
1844				(ml->sml_op == LDAP_MOD_REPLACE))
1845				zapReset = 0;
1846		}
1847		if ( ml->sml_op == LDAP_MOD_DELETE ) {
1848			if ( ml->sml_desc == ad_pwdGraceUseTime ) {
1849				got_del_grace = 1;
1850			} else if ( ml->sml_desc == ad_pwdAccountLockedTime ) {
1851				got_del_lock = 1;
1852			} else if ( ml->sml_desc == ad_pwdFailureTime ) {
1853				got_del_fail = 1;
1854			}
1855		}
1856		if ( ml->sml_desc == ad_pwdChangedTime ) {
1857			got_changed = 1;
1858		} else if (ml->sml_desc == ad_pwdHistory ) {
1859			got_history = 1;
1860		}
1861	}
1862
1863	if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) {
1864		if ( dn_match( &op->o_conn->c_ndn,
1865				&pwcons[op->o_conn->c_conn_idx].dn )) {
1866			Debug( LDAP_DEBUG_TRACE,
1867				"connection restricted to password changing only\n", 0, 0, 0 );
1868			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1869			rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password";
1870			pErr = PP_changeAfterReset;
1871			goto return_results;
1872		} else {
1873			ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1874			BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1875		}
1876	}
1877
1878	/*
1879	 * if we have a "safe password modify policy", then we need to check if we're doing
1880	 * a delete (with the old password), followed by an add (with the new password).
1881	 *
1882	 * If we got just a delete with nothing else, just let it go. We also skip all the checks if
1883	 * the root user is bound. Root can do anything, including avoid the policies.
1884	 */
1885
1886	if (!pwmod) goto do_modify;
1887
1888	/*
1889	 * Build the password history list in ascending time order
1890	 * We need this, even if the user is root, in order to maintain
1891	 * the pwdHistory operational attributes properly.
1892	 */
1893	if (addmod && pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) {
1894		struct berval oldpw;
1895		time_t oldtime;
1896
1897		for(i=0; ha->a_nvals[i].bv_val; i++) {
1898			rc = parse_pwdhistory( &(ha->a_nvals[i]), NULL,
1899				&oldtime, &oldpw );
1900
1901			if (rc != LDAP_SUCCESS) continue; /* invalid history entry */
1902
1903			if (oldpw.bv_val) {
1904				add_to_pwd_history( &tl, oldtime, &oldpw,
1905					&(ha->a_nvals[i]) );
1906				oldpw.bv_val = NULL;
1907				oldpw.bv_len = 0;
1908			}
1909		}
1910		for(p=tl; p; p=p->next, hsize++); /* count history size */
1911	}
1912
1913	if (be_isroot( op )) goto do_modify;
1914
1915	/* NOTE: according to draft-behera-ldap-password-policy
1916	 * pwdAllowUserChange == FALSE must only prevent pwd changes
1917	 * by the user the pwd belongs to (ITS#7021) */
1918	if (!pp.pwdAllowUserChange && dn_match(&op->o_req_ndn, &op->o_ndn)) {
1919		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1920		rs->sr_text = "User alteration of password is not allowed";
1921		pErr = PP_passwordModNotAllowed;
1922		goto return_results;
1923	}
1924
1925	/* Just deleting? */
1926	if (!addmod) {
1927		/* skip everything else */
1928		pwmod = 0;
1929		goto do_modify;
1930	}
1931
1932	/* This is a pwdModify exop that provided the old pw.
1933	 * We need to create a Delete mod for this old pw and
1934	 * let the matching value get found later
1935	 */
1936	if (pp.pwdSafeModify && oldpw.bv_val ) {
1937		ml = (Modifications *)ch_calloc( sizeof( Modifications ), 1 );
1938		ml->sml_op = LDAP_MOD_DELETE;
1939		ml->sml_flags = SLAP_MOD_INTERNAL;
1940		ml->sml_desc = pp.ad;
1941		ml->sml_type = pp.ad->ad_cname;
1942		ml->sml_numvals = 1;
1943		ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1944		ber_dupbv( &ml->sml_values[0], &oldpw );
1945		BER_BVZERO( &ml->sml_values[1] );
1946		ml->sml_next = op->orm_modlist;
1947		op->orm_modlist = ml;
1948		delmod = ml;
1949		deladd = 2;
1950	}
1951
1952	if (pp.pwdSafeModify && deladd != 2) {
1953		Debug( LDAP_DEBUG_TRACE,
1954			"change password must use DELETE followed by ADD/REPLACE\n",
1955			0, 0, 0 );
1956		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1957		rs->sr_text = "Must supply old password to be changed as well as new one";
1958		pErr = PP_mustSupplyOldPassword;
1959		goto return_results;
1960	}
1961
1962	/* Check age, but only if pwdReset is not TRUE */
1963	pa = attr_find( e->e_attrs, ad_pwdReset );
1964	if ((!pa || !bvmatch( &pa->a_nvals[0], &slap_true_bv )) &&
1965		pp.pwdMinAge > 0) {
1966		time_t pwtime = (time_t)-1, now;
1967		int age;
1968
1969		if ((pa = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL)
1970			pwtime = parse_time( pa->a_nvals[0].bv_val );
1971		now = slap_get_time();
1972		age = (int)(now - pwtime);
1973		if ((pwtime != (time_t)-1) && (age < pp.pwdMinAge)) {
1974			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1975			rs->sr_text = "Password is too young to change";
1976			pErr = PP_passwordTooYoung;
1977			goto return_results;
1978		}
1979	}
1980
1981	/* pa is used in password history check below, be sure it's set */
1982	if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL && delmod) {
1983		/*
1984		 * we have a password to check
1985		 */
1986		bv = oldpw.bv_val ? &oldpw : delmod->sml_values;
1987		/* FIXME: no access checking? */
1988		rc = slap_passwd_check( op, NULL, pa, bv, &txt );
1989		if (rc != LDAP_SUCCESS) {
1990			Debug( LDAP_DEBUG_TRACE,
1991				"old password check failed: %s\n", txt, 0, 0 );
1992
1993			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1994			rs->sr_text = "Must supply correct old password to change to new one";
1995			pErr = PP_mustSupplyOldPassword;
1996			goto return_results;
1997
1998		} else {
1999			int i;
2000
2001			/*
2002			 * replace the delete value with the (possibly hashed)
2003			 * value which is currently in the password.
2004			 */
2005			for ( i = 0; !BER_BVISNULL( &delmod->sml_values[i] ); i++ ) {
2006				free( delmod->sml_values[i].bv_val );
2007				BER_BVZERO( &delmod->sml_values[i] );
2008			}
2009			free( delmod->sml_values );
2010			delmod->sml_values = ch_calloc( sizeof(struct berval), 2 );
2011			BER_BVZERO( &delmod->sml_values[1] );
2012			ber_dupbv( &(delmod->sml_values[0]),  &(pa->a_nvals[0]) );
2013		}
2014	}
2015
2016	bv = newpw.bv_val ? &newpw : &addmod->sml_values[0];
2017	if (pp.pwdCheckQuality > 0) {
2018
2019		rc = check_password_quality( bv, &pp, &pErr, e, (char **)&txt );
2020		if (rc != LDAP_SUCCESS) {
2021			rs->sr_err = rc;
2022			if ( txt ) {
2023				rs->sr_text = txt;
2024				free_txt = 1;
2025			} else {
2026				rs->sr_text = "Password fails quality checking policy";
2027			}
2028			goto return_results;
2029		}
2030	}
2031
2032	/* If pwdInHistory is zero, passwords may be reused */
2033	if (pa && pp.pwdInHistory > 0) {
2034		/*
2035		 * Last check - the password history.
2036		 */
2037		/* FIXME: no access checking? */
2038		if (slap_passwd_check( op, NULL, pa, bv, &txt ) == LDAP_SUCCESS) {
2039			/*
2040			 * This is bad - it means that the user is attempting
2041			 * to set the password to the same as the old one.
2042			 */
2043			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
2044			rs->sr_text = "Password is not being changed from existing value";
2045			pErr = PP_passwordInHistory;
2046			goto return_results;
2047		}
2048
2049		/*
2050		 * Iterate through the password history, and fail on any
2051		 * password matches.
2052		 */
2053		at = *pa;
2054		at.a_vals = cr;
2055		cr[1].bv_val = NULL;
2056		for(p=tl; p; p=p->next) {
2057			cr[0] = p->pw;
2058			/* FIXME: no access checking? */
2059			rc = slap_passwd_check( op, NULL, &at, bv, &txt );
2060
2061			if (rc != LDAP_SUCCESS) continue;
2062
2063			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
2064			rs->sr_text = "Password is in history of old passwords";
2065			pErr = PP_passwordInHistory;
2066			goto return_results;
2067		}
2068	}
2069
2070do_modify:
2071	if (pwmod) {
2072		struct berval timestamp;
2073		char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
2074		time_t now = slap_get_time();
2075
2076		/* If the conn is restricted, set a callback to clear it
2077		 * if the pwmod succeeds
2078		 */
2079		if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
2080			slap_callback *sc = op->o_tmpcalloc( 1, sizeof( slap_callback ),
2081				op->o_tmpmemctx );
2082			sc->sc_next = op->o_callback;
2083			/* Must use sc_response to insure we reset on success, before
2084			 * the client sees the response. Must use sc_cleanup to insure
2085			 * that it gets cleaned up if sc_response is not called.
2086			 */
2087			sc->sc_response = ppolicy_mod_cb;
2088			sc->sc_cleanup = ppolicy_mod_cb;
2089			op->o_callback = sc;
2090		}
2091
2092		/*
2093		 * keep the necessary pwd.. operational attributes
2094		 * up to date.
2095		 */
2096
2097		if (!got_changed) {
2098			timestamp.bv_val = timebuf;
2099			timestamp.bv_len = sizeof(timebuf);
2100			slap_timestamp( &now, &timestamp );
2101
2102			mods = NULL;
2103			if (pwmop != LDAP_MOD_DELETE) {
2104				mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2105				mods->sml_op = LDAP_MOD_REPLACE;
2106				mods->sml_numvals = 1;
2107				mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
2108				ber_dupbv( &mods->sml_values[0], &timestamp );
2109				BER_BVZERO( &mods->sml_values[1] );
2110				assert( !BER_BVISNULL( &mods->sml_values[0] ) );
2111			} else if (attr_find(e->e_attrs, ad_pwdChangedTime )) {
2112				mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2113				mods->sml_op = LDAP_MOD_DELETE;
2114			}
2115			if (mods) {
2116				mods->sml_desc = ad_pwdChangedTime;
2117				mods->sml_flags = SLAP_MOD_INTERNAL;
2118				mods->sml_next = NULL;
2119				modtail->sml_next = mods;
2120				modtail = mods;
2121			}
2122		}
2123
2124		if (!got_del_grace && attr_find(e->e_attrs, ad_pwdGraceUseTime )) {
2125			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2126			mods->sml_op = LDAP_MOD_DELETE;
2127			mods->sml_desc = ad_pwdGraceUseTime;
2128			mods->sml_flags = SLAP_MOD_INTERNAL;
2129			mods->sml_next = NULL;
2130			modtail->sml_next = mods;
2131			modtail = mods;
2132		}
2133
2134		if (!got_del_lock && attr_find(e->e_attrs, ad_pwdAccountLockedTime )) {
2135			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2136			mods->sml_op = LDAP_MOD_DELETE;
2137			mods->sml_desc = ad_pwdAccountLockedTime;
2138			mods->sml_flags = SLAP_MOD_INTERNAL;
2139			mods->sml_next = NULL;
2140			modtail->sml_next = mods;
2141			modtail = mods;
2142		}
2143
2144		if (!got_del_fail && attr_find(e->e_attrs, ad_pwdFailureTime )) {
2145			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2146			mods->sml_op = LDAP_MOD_DELETE;
2147			mods->sml_desc = ad_pwdFailureTime;
2148			mods->sml_flags = SLAP_MOD_INTERNAL;
2149			mods->sml_next = NULL;
2150			modtail->sml_next = mods;
2151			modtail = mods;
2152		}
2153
2154		/* Delete the pwdReset attribute, since it's being reset */
2155		if ((zapReset) && (attr_find(e->e_attrs, ad_pwdReset ))) {
2156			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2157			mods->sml_op = LDAP_MOD_DELETE;
2158			mods->sml_desc = ad_pwdReset;
2159			mods->sml_flags = SLAP_MOD_INTERNAL;
2160			mods->sml_next = NULL;
2161			modtail->sml_next = mods;
2162			modtail = mods;
2163		}
2164
2165		if (!got_history && pp.pwdInHistory > 0) {
2166			if (hsize >= pp.pwdInHistory) {
2167				/*
2168				 * We use the >= operator, since we are going to add
2169				 * the existing password attribute value into the
2170				 * history - thus the cardinality of history values is
2171				 * about to rise by one.
2172				 *
2173				 * If this would push it over the limit of history
2174				 * values (remembering - the password policy could have
2175				 * changed since the password was last altered), we must
2176				 * delete at least 1 value from the pwdHistory list.
2177				 *
2178				 * In fact, we delete '(#pwdHistory attrs - max pwd
2179				 * history length) + 1' values, starting with the oldest.
2180				 * This is easily evaluated, since the linked list is
2181				 * created in ascending time order.
2182				 */
2183				mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2184				mods->sml_op = LDAP_MOD_DELETE;
2185				mods->sml_flags = SLAP_MOD_INTERNAL;
2186				mods->sml_desc = ad_pwdHistory;
2187				mods->sml_numvals = hsize - pp.pwdInHistory + 1;
2188				mods->sml_values = ch_calloc( sizeof( struct berval ),
2189					hsize - pp.pwdInHistory + 2 );
2190				BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] );
2191				for(i=0,p=tl; i < (hsize - pp.pwdInHistory + 1); i++, p=p->next) {
2192					BER_BVZERO( &mods->sml_values[i] );
2193					ber_dupbv( &(mods->sml_values[i]), &p->bv );
2194				}
2195				mods->sml_next = NULL;
2196				modtail->sml_next = mods;
2197				modtail = mods;
2198			}
2199			free_pwd_history_list( &tl );
2200
2201			/*
2202			 * Now add the existing password into the history list.
2203			 * This will be executed even if the operation is to delete
2204			 * the password entirely.
2205			 *
2206			 * This isn't in the spec explicitly, but it seems to make
2207			 * sense that the password history list is the list of all
2208			 * previous passwords - even if they were deleted. Thus, if
2209			 * someone tries to add a historical password at some future
2210			 * point, it will fail.
2211			 */
2212			if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL) {
2213				mods = (Modifications *) ch_malloc( sizeof( Modifications ) );
2214				mods->sml_op = LDAP_MOD_ADD;
2215				mods->sml_flags = SLAP_MOD_INTERNAL;
2216				mods->sml_type.bv_val = NULL;
2217				mods->sml_desc = ad_pwdHistory;
2218				mods->sml_nvalues = NULL;
2219				mods->sml_numvals = 1;
2220				mods->sml_values = ch_calloc( sizeof( struct berval ), 2 );
2221				mods->sml_values[ 1 ].bv_val = NULL;
2222				mods->sml_values[ 1 ].bv_len = 0;
2223				make_pwd_history_value( timebuf, &mods->sml_values[0], pa );
2224				mods->sml_next = NULL;
2225				modtail->sml_next = mods;
2226				modtail = mods;
2227
2228			} else {
2229				Debug( LDAP_DEBUG_TRACE,
2230				"ppolicy_modify: password attr lookup failed\n", 0, 0, 0 );
2231			}
2232		}
2233
2234		/*
2235		 * Controversial bit here. If the new password isn't hashed
2236		 * (ie, is cleartext), we probably should hash it according
2237		 * to the default hash. The reason for this is that we want
2238		 * to use the policy if possible, but if we hash the password
2239		 * before, then we're going to run into trouble when it
2240		 * comes time to check the password.
2241		 *
2242		 * Now, the right thing to do is to use the extended password
2243		 * modify operation, but not all software can do this,
2244		 * therefore it makes sense to hash the new password, now
2245		 * we know it passes the policy requirements.
2246		 *
2247		 * Of course, if the password is already hashed, then we
2248		 * leave it alone.
2249		 */
2250
2251		if ((pi->hash_passwords) && (addmod) && !newpw.bv_val &&
2252			(password_scheme( &(addmod->sml_values[0]), NULL ) != LDAP_SUCCESS))
2253		{
2254			struct berval hpw, bv;
2255
2256			slap_passwd_hash( &(addmod->sml_values[0]), &hpw, &txt );
2257			if (hpw.bv_val == NULL) {
2258					/*
2259					 * hashing didn't work. Emit an error.
2260					 */
2261				rs->sr_err = LDAP_OTHER;
2262				rs->sr_text = txt;
2263				goto return_results;
2264			}
2265			bv = addmod->sml_values[0];
2266				/* clear and discard the clear password */
2267			memset(bv.bv_val, 0, bv.bv_len);
2268			ber_memfree(bv.bv_val);
2269			addmod->sml_values[0] = hpw;
2270		}
2271	}
2272	op->o_bd->bd_info = (BackendInfo *)on->on_info;
2273	be_entry_release_r( op, e );
2274	return SLAP_CB_CONTINUE;
2275
2276return_results:
2277	free_pwd_history_list( &tl );
2278	op->o_bd->bd_info = (BackendInfo *)on->on_info;
2279	be_entry_release_r( op, e );
2280	if ( send_ctrl ) {
2281		ctrl = create_passcontrol( op, -1, -1, pErr );
2282		oldctrls = add_passcontrol( op, rs, ctrl );
2283	}
2284	send_ldap_result( op, rs );
2285	if ( free_txt ) {
2286		free( (char *)txt );
2287		rs->sr_text = NULL;
2288	}
2289	if ( send_ctrl ) {
2290		if ( is_pwdexop ) {
2291			if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
2292				op->o_tmpfree( oldctrls, op->o_tmpmemctx );
2293			}
2294			oldctrls = NULL;
2295			rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
2296
2297		} else {
2298			ctrls_cleanup( op, rs, oldctrls );
2299		}
2300	}
2301	return rs->sr_err;
2302}
2303
2304static int
2305ppolicy_parseCtrl(
2306	Operation *op,
2307	SlapReply *rs,
2308	LDAPControl *ctrl )
2309{
2310	if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
2311		rs->sr_text = "passwordPolicyRequest control value not absent";
2312		return LDAP_PROTOCOL_ERROR;
2313	}
2314	op->o_ctrlflag[ppolicy_cid] = ctrl->ldctl_iscritical
2315		? SLAP_CONTROL_CRITICAL
2316		: SLAP_CONTROL_NONCRITICAL;
2317
2318	return LDAP_SUCCESS;
2319}
2320
2321static int
2322attrPretty(
2323	Syntax *syntax,
2324	struct berval *val,
2325	struct berval *out,
2326	void *ctx )
2327{
2328	AttributeDescription *ad = NULL;
2329	const char *err;
2330	int code;
2331
2332	code = slap_bv2ad( val, &ad, &err );
2333	if ( !code ) {
2334		ber_dupbv_x( out, &ad->ad_type->sat_cname, ctx );
2335	}
2336	return code;
2337}
2338
2339static int
2340attrNormalize(
2341	slap_mask_t use,
2342	Syntax *syntax,
2343	MatchingRule *mr,
2344	struct berval *val,
2345	struct berval *out,
2346	void *ctx )
2347{
2348	AttributeDescription *ad = NULL;
2349	const char *err;
2350	int code;
2351
2352	code = slap_bv2ad( val, &ad, &err );
2353	if ( !code ) {
2354		ber_str2bv_x( ad->ad_type->sat_oid, 0, 1, out, ctx );
2355	}
2356	return code;
2357}
2358
2359static int
2360ppolicy_db_init(
2361	BackendDB *be,
2362	ConfigReply *cr
2363)
2364{
2365	slap_overinst *on = (slap_overinst *) be->bd_info;
2366
2367	if ( SLAP_ISGLOBALOVERLAY( be ) ) {
2368		/* do not allow slapo-ppolicy to be global by now (ITS#5858) */
2369		if ( cr ){
2370			snprintf( cr->msg, sizeof(cr->msg),
2371				"slapo-ppolicy cannot be global" );
2372			Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 );
2373		}
2374		return 1;
2375	}
2376
2377	/* Has User Schema been initialized yet? */
2378	if ( !pwd_UsSchema[0].ad[0] ) {
2379		const char *err;
2380		int i, code;
2381
2382		for (i=0; pwd_UsSchema[i].def; i++) {
2383			code = slap_str2ad( pwd_UsSchema[i].def, pwd_UsSchema[i].ad, &err );
2384			if ( code ) {
2385				if ( cr ){
2386					snprintf( cr->msg, sizeof(cr->msg),
2387						"User Schema load failed for attribute \"%s\". Error code %d: %s",
2388						pwd_UsSchema[i].def, code, err );
2389					Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 );
2390				}
2391				return code;
2392			}
2393		}
2394		{
2395			Syntax *syn;
2396			MatchingRule *mr;
2397
2398			syn = ch_malloc( sizeof( Syntax ));
2399			*syn = *ad_pwdAttribute->ad_type->sat_syntax;
2400			syn->ssyn_pretty = attrPretty;
2401			ad_pwdAttribute->ad_type->sat_syntax = syn;
2402
2403			mr = ch_malloc( sizeof( MatchingRule ));
2404			*mr = *ad_pwdAttribute->ad_type->sat_equality;
2405			mr->smr_normalize = attrNormalize;
2406			ad_pwdAttribute->ad_type->sat_equality = mr;
2407		}
2408	}
2409
2410	on->on_bi.bi_private = ch_calloc( sizeof(pp_info), 1 );
2411
2412	if ( dtblsize && !pwcons ) {
2413		/* accommodate for c_conn_idx == -1 */
2414		pwcons = ch_calloc( sizeof(pw_conn), dtblsize + 1 );
2415		pwcons++;
2416	}
2417
2418	ov_count++;
2419
2420	return 0;
2421}
2422
2423static int
2424ppolicy_db_open(
2425	BackendDB *be,
2426	ConfigReply *cr
2427)
2428{
2429	return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
2430}
2431
2432static int
2433ppolicy_db_close(
2434	BackendDB *be,
2435	ConfigReply *cr
2436)
2437{
2438#ifdef SLAP_CONFIG_DELETE
2439	overlay_unregister_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
2440#endif /* SLAP_CONFIG_DELETE */
2441
2442	return 0;
2443}
2444
2445static int
2446ppolicy_db_destroy(
2447	BackendDB *be,
2448	ConfigReply *cr
2449)
2450{
2451	slap_overinst *on = (slap_overinst *) be->bd_info;
2452	pp_info *pi = on->on_bi.bi_private;
2453
2454	on->on_bi.bi_private = NULL;
2455	free( pi->def_policy.bv_val );
2456	free( pi );
2457
2458	ov_count--;
2459	if ( ov_count <=0 && pwcons ) {
2460		pw_conn *pwc = pwcons;
2461		pwcons = NULL;
2462		pwc--;
2463		ch_free( pwc );
2464	}
2465	return 0;
2466}
2467
2468static char *extops[] = {
2469	LDAP_EXOP_MODIFY_PASSWD,
2470	NULL
2471};
2472
2473static slap_overinst ppolicy;
2474
2475int ppolicy_initialize()
2476{
2477	int i, code;
2478
2479	for (i=0; pwd_OpSchema[i].def; i++) {
2480		code = register_at( pwd_OpSchema[i].def, pwd_OpSchema[i].ad, 0 );
2481		if ( code ) {
2482			Debug( LDAP_DEBUG_ANY,
2483				"ppolicy_initialize: register_at failed\n", 0, 0, 0 );
2484			return code;
2485		}
2486		/* Allow Manager to set these as needed */
2487		if ( is_at_no_user_mod( (*pwd_OpSchema[i].ad)->ad_type )) {
2488			(*pwd_OpSchema[i].ad)->ad_type->sat_flags |=
2489				SLAP_AT_MANAGEABLE;
2490		}
2491	}
2492
2493	code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
2494		SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, extops,
2495		ppolicy_parseCtrl, &ppolicy_cid );
2496	if ( code != LDAP_SUCCESS ) {
2497		Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code, 0, 0 );
2498		return code;
2499	}
2500
2501	ldap_pvt_thread_mutex_init( &chk_syntax_mutex );
2502
2503	ppolicy.on_bi.bi_type = "ppolicy";
2504	ppolicy.on_bi.bi_db_init = ppolicy_db_init;
2505	ppolicy.on_bi.bi_db_open = ppolicy_db_open;
2506	ppolicy.on_bi.bi_db_close = ppolicy_db_close;
2507	ppolicy.on_bi.bi_db_destroy = ppolicy_db_destroy;
2508
2509	ppolicy.on_bi.bi_op_add = ppolicy_add;
2510	ppolicy.on_bi.bi_op_bind = ppolicy_bind;
2511	ppolicy.on_bi.bi_op_compare = ppolicy_compare;
2512	ppolicy.on_bi.bi_op_delete = ppolicy_restrict;
2513	ppolicy.on_bi.bi_op_modify = ppolicy_modify;
2514	ppolicy.on_bi.bi_op_search = ppolicy_restrict;
2515	ppolicy.on_bi.bi_connection_destroy = ppolicy_connection_destroy;
2516
2517	ppolicy.on_bi.bi_cf_ocs = ppolicyocs;
2518	code = config_register_schema( ppolicycfg, ppolicyocs );
2519	if ( code ) return code;
2520
2521	return overlay_register( &ppolicy );
2522}
2523
2524#if SLAPD_OVER_PPOLICY == SLAPD_MOD_DYNAMIC
2525int init_module(int argc, char *argv[]) {
2526	return ppolicy_initialize();
2527}
2528#endif
2529
2530#endif	/* defined(SLAPD_OVER_PPOLICY) */
2531