ppolicy.c revision 1.1.1.5
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 */
51typedef 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 */
61typedef struct pw_conn {
62	struct berval dn;	/* DN of restricted user */
63} pw_conn;
64
65static pw_conn *pwcons;
66static int ppolicy_cid;
67static int ov_count;
68
69typedef 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
97typedef 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 */
105static AttributeDescription *ad_pwdChangedTime, *ad_pwdAccountLockedTime,
106	*ad_pwdFailureTime, *ad_pwdHistory, *ad_pwdGraceUseTime, *ad_pwdReset,
107	*ad_pwdPolicySubentry;
108
109static 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 */
179static 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
188static 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
208static ldap_pvt_thread_mutex_t chk_syntax_mutex;
209
210enum {
211	PPOLICY_DEFAULT = 1,
212	PPOLICY_HASH_CLEARTEXT,
213	PPOLICY_USE_LOCKOUT
214};
215
216static ConfigDriver ppolicy_cf_default;
217
218static 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
245static 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
256static int
257ppolicy_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
307static time_t
308parse_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
321static int
322account_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
374static const char ppolicy_ctrl_oid[] = LDAP_CONTROL_PASSWORDPOLICYRESPONSE;
375
376static LDAPControl *
377create_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
424static LDAPControl **
425add_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
453static void
454ppolicy_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
552defaultpol:
553	Debug( LDAP_DEBUG_TRACE,
554		"ppolicy_get: using default policy\n", 0, 0, 0 );
555	return;
556}
557
558static int
559password_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
588static int
589check_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
695static int
696parse_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
762exit_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
776static void
777add_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
809static void
810make_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
839static void
840free_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
857typedef 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
867static void
868ctrls_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
892static int
893ppolicy_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
902static int
903ppolicy_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
1057grace:
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
1096check_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
1131done:
1132	op->o_bd->bd_info = (BackendInfo *)on->on_info;
1133	be_entry_release_r( op, e );
1134
1135locked:
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
1195static int
1196ppolicy_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 */
1259static int
1260ppolicy_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 */
1270static int
1271ppolicy_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
1315static int
1316ppolicy_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
1337static int
1338ppolicy_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
1397static int
1398ppolicy_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
1510static int
1511ppolicy_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
1523static int
1524ppolicy_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
1948do_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
2152return_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
2180static int
2181ppolicy_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
2197static int
2198attrPretty(
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
2215static int
2216attrNormalize(
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
2235static int
2236ppolicy_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
2297static int
2298ppolicy_db_open(
2299	BackendDB *be,
2300	ConfigReply *cr
2301)
2302{
2303	ov_count++;
2304	return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
2305}
2306
2307static int
2308ppolicy_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
2333static char *extops[] = {
2334	LDAP_EXOP_MODIFY_PASSWD,
2335	NULL
2336};
2337
2338static slap_overinst ppolicy;
2339
2340int 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
2389int init_module(int argc, char *argv[]) {
2390	return ppolicy_initialize();
2391}
2392#endif
2393
2394#endif	/* defined(SLAPD_OVER_PPOLICY) */
2395