1/*	$NetBSD$	*/
2
3/* OpenLDAP: pkg/ldap/servers/slapd/overlays/ppolicy.c,v 1.75.2.31 2010/06/10 17:37:40 quanah Exp */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 2004-2010 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 = cred->bv_val;
593	struct berval sch;
594
595	assert( cred != NULL );
596	assert( pp != NULL );
597	assert( txt != NULL );
598
599	*txt = NULL;
600
601	if ((cred->bv_len == 0) || (pp->pwdMinLength > cred->bv_len)) {
602		rc = LDAP_CONSTRAINT_VIOLATION;
603		if ( err ) *err = PP_passwordTooShort;
604		return rc;
605	}
606
607        /*
608         * We need to know if the password is already hashed - if so
609         * what scheme is it. The reason being that the "hash" of
610         * {cleartext} still allows us to check the password.
611         */
612	rc = password_scheme( cred, &sch );
613	if (rc == LDAP_SUCCESS) {
614		if ((sch.bv_val) && (strncasecmp( sch.bv_val, "{cleartext}",
615			sch.bv_len ) == 0)) {
616			/*
617			 * We can check the cleartext "hash"
618			 */
619			ptr = cred->bv_val + sch.bv_len;
620		} else {
621			/* everything else, we can't check */
622			if (pp->pwdCheckQuality == 2) {
623				rc = LDAP_CONSTRAINT_VIOLATION;
624				if (err) *err = PP_insufficientPasswordQuality;
625				return rc;
626			}
627			/*
628			 * We can't check the syntax of the password, but it's not
629			 * mandatory (according to the policy), so we return success.
630			 */
631
632			return LDAP_SUCCESS;
633		}
634	}
635
636	rc = LDAP_SUCCESS;
637
638	if (pp->pwdCheckModule[0]) {
639#ifdef SLAPD_MODULES
640		lt_dlhandle mod;
641		const char *err;
642
643		if ((mod = lt_dlopen( pp->pwdCheckModule )) == NULL) {
644			err = lt_dlerror();
645
646			Debug(LDAP_DEBUG_ANY,
647			"check_password_quality: lt_dlopen failed: (%s) %s.\n",
648				pp->pwdCheckModule, err, 0 );
649			ok = LDAP_OTHER; /* internal error */
650		} else {
651			/* FIXME: the error message ought to be passed thru a
652			 * struct berval, with preallocated buffer and size
653			 * passed in. Module can still allocate a buffer for
654			 * it if the provided one is too small.
655			 */
656			int (*prog)( char *passwd, char **text, Entry *ent );
657
658			if ((prog = lt_dlsym( mod, "check_password" )) == NULL) {
659				err = lt_dlerror();
660
661				Debug(LDAP_DEBUG_ANY,
662					"check_password_quality: lt_dlsym failed: (%s) %s.\n",
663					pp->pwdCheckModule, err, 0 );
664				ok = LDAP_OTHER;
665			} else {
666				ldap_pvt_thread_mutex_lock( &chk_syntax_mutex );
667				ok = prog( ptr, txt, e );
668				ldap_pvt_thread_mutex_unlock( &chk_syntax_mutex );
669				if (ok != LDAP_SUCCESS) {
670					Debug(LDAP_DEBUG_ANY,
671						"check_password_quality: module error: (%s) %s.[%d]\n",
672						pp->pwdCheckModule, *txt ? *txt : "", ok );
673				}
674			}
675
676			lt_dlclose( mod );
677		}
678#else
679	Debug(LDAP_DEBUG_ANY, "check_password_quality: external modules not "
680		"supported. pwdCheckModule ignored.\n", 0, 0, 0);
681#endif /* SLAPD_MODULES */
682	}
683
684
685	if (ok != LDAP_SUCCESS) {
686		rc = LDAP_CONSTRAINT_VIOLATION;
687		if (err) *err = PP_insufficientPasswordQuality;
688	}
689
690	return rc;
691}
692
693static int
694parse_pwdhistory( struct berval *bv, char **oid, time_t *oldtime, struct berval *oldpw )
695{
696	char *ptr;
697	struct berval nv, npw;
698	ber_len_t i, j;
699
700	assert (bv && (bv->bv_len > 0) && (bv->bv_val) && oldtime && oldpw );
701
702	if ( oid ) {
703		*oid = 0;
704	}
705	*oldtime = (time_t)-1;
706	BER_BVZERO( oldpw );
707
708	ber_dupbv( &nv, bv );
709
710	/* first get the time field */
711	for ( i = 0; (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ )
712		;
713	if ( i == nv.bv_len ) {
714		goto exit_failure; /* couldn't locate the '#' separator */
715	}
716	nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */
717	ptr = nv.bv_val;
718	*oldtime = parse_time( ptr );
719	if (*oldtime == (time_t)-1) {
720		goto exit_failure;
721	}
722
723	/* get the OID field */
724	for (ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ )
725		;
726	if ( i == nv.bv_len ) {
727		goto exit_failure; /* couldn't locate the '#' separator */
728	}
729	nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */
730	if ( oid ) {
731		*oid = ber_strdup( ptr );
732	}
733
734	/* get the length field */
735	for ( ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ )
736		;
737	if ( i == nv.bv_len ) {
738		goto exit_failure; /* couldn't locate the '#' separator */
739	}
740	nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */
741	oldpw->bv_len = strtol( ptr, NULL, 10 );
742	if (errno == ERANGE) {
743		goto exit_failure;
744	}
745
746	/* lastly, get the octets of the string */
747	for ( j = i, ptr = &(nv.bv_val[i]); i < nv.bv_len; i++ )
748		;
749	if ( i - j != oldpw->bv_len) {
750		goto exit_failure; /* length is wrong */
751	}
752
753	npw.bv_val = ptr;
754	npw.bv_len = oldpw->bv_len;
755	ber_dupbv( oldpw, &npw );
756	ber_memfree( nv.bv_val );
757
758	return LDAP_SUCCESS;
759
760exit_failure:;
761	if ( oid && *oid ) {
762		ber_memfree(*oid);
763		*oid = NULL;
764	}
765	if ( oldpw->bv_val ) {
766		ber_memfree( oldpw->bv_val);
767		BER_BVZERO( oldpw );
768	}
769	ber_memfree( nv.bv_val );
770
771	return LDAP_OTHER;
772}
773
774static void
775add_to_pwd_history( pw_hist **l, time_t t,
776                    struct berval *oldpw, struct berval *bv )
777{
778	pw_hist *p, *p1, *p2;
779
780	if (!l) return;
781
782	p = ch_malloc( sizeof( pw_hist ));
783	p->pw = *oldpw;
784	ber_dupbv( &p->bv, bv );
785	p->t = t;
786	p->next = NULL;
787
788	if (*l == NULL) {
789		/* degenerate case */
790		*l = p;
791		return;
792	}
793	/*
794	 * advance p1 and p2 such that p1 is the node before the
795	 * new one, and p2 is the node after it
796	 */
797	for (p1 = NULL, p2 = *l; p2 && p2->t <= t; p1 = p2, p2=p2->next );
798	p->next = p2;
799	if (p1 == NULL) { *l = p; return; }
800	p1->next = p;
801}
802
803#ifndef MAX_PWD_HISTORY_SZ
804#define MAX_PWD_HISTORY_SZ 1024
805#endif /* MAX_PWD_HISTORY_SZ */
806
807static void
808make_pwd_history_value( char *timebuf, struct berval *bv, Attribute *pa )
809{
810	char str[ MAX_PWD_HISTORY_SZ ];
811	int nlen;
812
813	snprintf( str, MAX_PWD_HISTORY_SZ,
814		  "%s#%s#%lu#", timebuf,
815		  pa->a_desc->ad_type->sat_syntax->ssyn_oid,
816		  (unsigned long) pa->a_nvals[0].bv_len );
817	str[MAX_PWD_HISTORY_SZ-1] = 0;
818	nlen = strlen(str);
819
820        /*
821         * We have to assume that the string is a string of octets,
822         * not readable characters. In reality, yes, it probably is
823         * a readable (ie, base64) string, but we can't count on that
824         * Hence, while the first 3 fields of the password history
825         * are definitely readable (a timestamp, an OID and an integer
826         * length), the remaining octets of the actual password
827         * are deemed to be binary data.
828         */
829	AC_MEMCPY( str + nlen, pa->a_nvals[0].bv_val, pa->a_nvals[0].bv_len );
830	nlen += pa->a_nvals[0].bv_len;
831	bv->bv_val = ch_malloc( nlen + 1 );
832	AC_MEMCPY( bv->bv_val, str, nlen );
833	bv->bv_val[nlen] = '\0';
834	bv->bv_len = nlen;
835}
836
837static void
838free_pwd_history_list( pw_hist **l )
839{
840	pw_hist *p;
841
842	if (!l) return;
843	p = *l;
844	while (p) {
845		pw_hist *pp = p->next;
846
847		free(p->pw.bv_val);
848		free(p->bv.bv_val);
849		free(p);
850		p = pp;
851	}
852	*l = NULL;
853}
854
855typedef struct ppbind {
856	slap_overinst *on;
857	int send_ctrl;
858	int set_restrict;
859	LDAPControl **oldctrls;
860	Modifications *mod;
861	LDAPPasswordPolicyError pErr;
862	PassPolicy pp;
863} ppbind;
864
865static void
866ctrls_cleanup( Operation *op, SlapReply *rs, LDAPControl **oldctrls )
867{
868	int n;
869
870	assert( rs->sr_ctrls != NULL );
871	assert( rs->sr_ctrls[0] != NULL );
872
873	for ( n = 0; rs->sr_ctrls[n]; n++ ) {
874		if ( rs->sr_ctrls[n]->ldctl_oid == ppolicy_ctrl_oid ) {
875			op->o_tmpfree( rs->sr_ctrls[n], op->o_tmpmemctx );
876			rs->sr_ctrls[n] = (LDAPControl *)(-1);
877			break;
878		}
879	}
880
881	if ( rs->sr_ctrls[n] == NULL ) {
882		/* missed? */
883	}
884
885	op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
886
887	rs->sr_ctrls = oldctrls;
888}
889
890static int
891ppolicy_ctrls_cleanup( Operation *op, SlapReply *rs )
892{
893	ppbind *ppb = op->o_callback->sc_private;
894	if ( ppb->send_ctrl ) {
895		ctrls_cleanup( op, rs, ppb->oldctrls );
896	}
897	return SLAP_CB_CONTINUE;
898}
899
900static int
901ppolicy_bind_response( Operation *op, SlapReply *rs )
902{
903	ppbind *ppb = op->o_callback->sc_private;
904	slap_overinst *on = ppb->on;
905	Modifications *mod = ppb->mod, *m;
906	int pwExpired = 0;
907	int ngut = -1, warn = -1, age, rc;
908	Attribute *a;
909	time_t now, pwtime = (time_t)-1;
910	char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
911	struct berval timestamp;
912	BackendInfo *bi = op->o_bd->bd_info;
913	Entry *e;
914
915	/* If we already know it's locked, just get on with it */
916	if ( ppb->pErr != PP_noError ) {
917		goto locked;
918	}
919
920	op->o_bd->bd_info = (BackendInfo *)on->on_info;
921	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
922	op->o_bd->bd_info = bi;
923
924	if ( rc != LDAP_SUCCESS ) {
925		return SLAP_CB_CONTINUE;
926	}
927
928	now = slap_get_time(); /* stored for later consideration */
929	timestamp.bv_val = nowstr;
930	timestamp.bv_len = sizeof(nowstr);
931	slap_timestamp( &now, &timestamp );
932
933	if ( rs->sr_err == LDAP_INVALID_CREDENTIALS ) {
934		int i = 0, fc = 0;
935
936		m = ch_calloc( sizeof(Modifications), 1 );
937		m->sml_op = LDAP_MOD_ADD;
938		m->sml_flags = 0;
939		m->sml_type = ad_pwdFailureTime->ad_cname;
940		m->sml_desc = ad_pwdFailureTime;
941		m->sml_numvals = 1;
942		m->sml_values = ch_calloc( sizeof(struct berval), 2 );
943		m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
944
945		ber_dupbv( &m->sml_values[0], &timestamp );
946		ber_dupbv( &m->sml_nvalues[0], &timestamp );
947		m->sml_next = mod;
948		mod = m;
949
950		/*
951		 * Count the pwdFailureTimes - if it's
952		 * greater than the policy pwdMaxFailure,
953		 * then lock the account.
954		 */
955		if ((a = attr_find( e->e_attrs, ad_pwdFailureTime )) != NULL) {
956			for(i=0; a->a_nvals[i].bv_val; i++) {
957
958				/*
959				 * If the interval is 0, then failures
960				 * stay on the record until explicitly
961				 * reset by successful authentication.
962				 */
963				if (ppb->pp.pwdFailureCountInterval == 0) {
964					fc++;
965				} else if (now <=
966							parse_time(a->a_nvals[i].bv_val) +
967							ppb->pp.pwdFailureCountInterval) {
968
969					fc++;
970				}
971				/*
972				 * We only count those failures
973				 * which are not due to expire.
974				 */
975			}
976		}
977
978		if ((ppb->pp.pwdMaxFailure > 0) &&
979			(fc >= ppb->pp.pwdMaxFailure - 1)) {
980
981			/*
982			 * We subtract 1 from the failure max
983			 * because the new failure entry hasn't
984			 * made it to the entry yet.
985			 */
986			m = ch_calloc( sizeof(Modifications), 1 );
987			m->sml_op = LDAP_MOD_REPLACE;
988			m->sml_flags = 0;
989			m->sml_type = ad_pwdAccountLockedTime->ad_cname;
990			m->sml_desc = ad_pwdAccountLockedTime;
991			m->sml_numvals = 1;
992			m->sml_values = ch_calloc( sizeof(struct berval), 2 );
993			m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
994			ber_dupbv( &m->sml_values[0], &timestamp );
995			ber_dupbv( &m->sml_nvalues[0], &timestamp );
996			m->sml_next = mod;
997			mod = m;
998		}
999	} else if ( rs->sr_err == LDAP_SUCCESS ) {
1000		if ((a = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL)
1001			pwtime = parse_time( a->a_nvals[0].bv_val );
1002
1003		/* delete all pwdFailureTimes */
1004		if ( attr_find( e->e_attrs, ad_pwdFailureTime )) {
1005			m = ch_calloc( sizeof(Modifications), 1 );
1006			m->sml_op = LDAP_MOD_DELETE;
1007			m->sml_flags = 0;
1008			m->sml_type = ad_pwdFailureTime->ad_cname;
1009			m->sml_desc = ad_pwdFailureTime;
1010			m->sml_next = mod;
1011			mod = m;
1012		}
1013
1014		/*
1015		 * check to see if the password must be changed
1016		 */
1017		if ( ppb->pp.pwdMustChange &&
1018			(a = attr_find( e->e_attrs, ad_pwdReset )) &&
1019			bvmatch( &a->a_nvals[0], &slap_true_bv ) )
1020		{
1021			/*
1022			 * need to inject client controls here to give
1023			 * more information. For the moment, we ensure
1024			 * that we are disallowed from doing anything
1025			 * other than change password.
1026			 */
1027			if ( ppb->set_restrict ) {
1028				ber_dupbv( &pwcons[op->o_conn->c_conn_idx].dn,
1029					&op->o_conn->c_ndn );
1030			}
1031
1032			ppb->pErr = PP_changeAfterReset;
1033
1034		} else {
1035			/*
1036			 * the password does not need to be changed, so
1037			 * we now check whether the password has expired.
1038			 *
1039			 * We can skip this bit if passwords don't age in
1040			 * the policy. Also, if there was no pwdChangedTime
1041			 * attribute in the entry, the password never expires.
1042			 */
1043			if (ppb->pp.pwdMaxAge == 0) goto grace;
1044
1045			if (pwtime != (time_t)-1) {
1046				/*
1047				 * Check: was the last change time of
1048				 * the password older than the maximum age
1049				 * allowed. (Ignore case 2 from I-D, it's just silly.)
1050				 */
1051				if (now - pwtime > ppb->pp.pwdMaxAge ) pwExpired = 1;
1052			}
1053		}
1054
1055grace:
1056		if (!pwExpired) goto check_expiring_password;
1057
1058		if ((a = attr_find( e->e_attrs, ad_pwdGraceUseTime )) == NULL)
1059			ngut = ppb->pp.pwdGraceAuthNLimit;
1060		else {
1061			for(ngut=0; a->a_nvals[ngut].bv_val; ngut++);
1062			ngut = ppb->pp.pwdGraceAuthNLimit - ngut;
1063		}
1064
1065		/*
1066		 * ngut is the number of remaining grace logins
1067		 */
1068		Debug( LDAP_DEBUG_ANY,
1069			"ppolicy_bind: Entry %s has an expired password: %d grace logins\n",
1070			e->e_name.bv_val, ngut, 0);
1071
1072		if (ngut < 1) {
1073			ppb->pErr = PP_passwordExpired;
1074			rs->sr_err = LDAP_INVALID_CREDENTIALS;
1075			goto done;
1076		}
1077
1078		/*
1079		 * Add a grace user time to the entry
1080		 */
1081		m = ch_calloc( sizeof(Modifications), 1 );
1082		m->sml_op = LDAP_MOD_ADD;
1083		m->sml_flags = 0;
1084		m->sml_type = ad_pwdGraceUseTime->ad_cname;
1085		m->sml_desc = ad_pwdGraceUseTime;
1086		m->sml_numvals = 1;
1087		m->sml_values = ch_calloc( sizeof(struct berval), 2 );
1088		m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
1089		ber_dupbv( &m->sml_values[0], &timestamp );
1090		ber_dupbv( &m->sml_nvalues[0], &timestamp );
1091		m->sml_next = mod;
1092		mod = m;
1093
1094check_expiring_password:
1095		/*
1096		 * Now we need to check to see
1097		 * if it is about to expire, and if so, should the user
1098		 * be warned about it in the password policy control.
1099		 *
1100		 * If the password has expired, and we're in the grace period, then
1101		 * we don't need to do this bit. Similarly, if we don't have password
1102		 * aging, then there's no need to do this bit either.
1103		 */
1104		if ((ppb->pp.pwdMaxAge < 1) || (pwExpired) || (ppb->pp.pwdExpireWarning < 1))
1105			goto done;
1106
1107		age = (int)(now - pwtime);
1108
1109		/*
1110		 * We know that there is a password Change Time attribute - if
1111		 * there wasn't, then the pwdExpired value would be true, unless
1112		 * there is no password aging - and if there is no password aging,
1113		 * then this section isn't called anyway - you can't have an
1114		 * expiring password if there's no limit to expire.
1115		 */
1116		if (ppb->pp.pwdMaxAge - age < ppb->pp.pwdExpireWarning ) {
1117			/*
1118			 * Set the warning value.
1119			 */
1120			warn = ppb->pp.pwdMaxAge - age; /* seconds left until expiry */
1121			if (warn < 0) warn = 0; /* something weird here - why is pwExpired not set? */
1122
1123			Debug( LDAP_DEBUG_ANY,
1124				"ppolicy_bind: Setting warning for password expiry for %s = %d seconds\n",
1125				op->o_req_dn.bv_val, warn, 0 );
1126		}
1127	}
1128
1129done:
1130	op->o_bd->bd_info = (BackendInfo *)on->on_info;
1131	be_entry_release_r( op, e );
1132
1133locked:
1134	if ( mod ) {
1135		Operation op2 = *op;
1136		SlapReply r2 = { REP_RESULT };
1137		slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
1138		pp_info *pi = on->on_bi.bi_private;
1139		LDAPControl c, *ca[2];
1140
1141		op2.o_tag = LDAP_REQ_MODIFY;
1142		op2.o_callback = &cb;
1143		op2.orm_modlist = mod;
1144		op2.orm_no_opattrs = 0;
1145		op2.o_dn = op->o_bd->be_rootdn;
1146		op2.o_ndn = op->o_bd->be_rootndn;
1147
1148		/* If this server is a shadow and forward_updates is true,
1149		 * use the frontend to perform this modify. That will trigger
1150		 * the update referral, which can then be forwarded by the
1151		 * chain overlay. Obviously the updateref and chain overlay
1152		 * must be configured appropriately for this to be useful.
1153		 */
1154		if ( SLAP_SHADOW( op->o_bd ) && pi->forward_updates ) {
1155			op2.o_bd = frontendDB;
1156
1157			/* Must use Relax control since these are no-user-mod */
1158			op2.o_relax = SLAP_CONTROL_CRITICAL;
1159			op2.o_ctrls = ca;
1160			ca[0] = &c;
1161			ca[1] = NULL;
1162			BER_BVZERO( &c.ldctl_value );
1163			c.ldctl_iscritical = 1;
1164			c.ldctl_oid = LDAP_CONTROL_RELAX;
1165		} else {
1166			op2.o_bd->bd_info = (BackendInfo *)on->on_info;
1167		}
1168		rc = op2.o_bd->be_modify( &op2, &r2 );
1169		slap_mods_free( mod, 1 );
1170	}
1171
1172	if ( ppb->send_ctrl ) {
1173		LDAPControl *ctrl = NULL;
1174		pp_info *pi = on->on_bi.bi_private;
1175
1176		/* Do we really want to tell that the account is locked? */
1177		if ( ppb->pErr == PP_accountLocked && !pi->use_lockout ) {
1178			ppb->pErr = PP_noError;
1179		}
1180		ctrl = create_passcontrol( op, warn, ngut, ppb->pErr );
1181		ppb->oldctrls = add_passcontrol( op, rs, ctrl );
1182		op->o_callback->sc_cleanup = ppolicy_ctrls_cleanup;
1183	}
1184	op->o_bd->bd_info = bi;
1185	return SLAP_CB_CONTINUE;
1186}
1187
1188static int
1189ppolicy_bind( Operation *op, SlapReply *rs )
1190{
1191	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1192
1193	/* Reset lockout status on all Bind requests */
1194	if ( !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
1195		ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1196		BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1197	}
1198
1199	/* Root bypasses policy */
1200	if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn )) {
1201		Entry *e;
1202		int rc;
1203		ppbind *ppb;
1204		slap_callback *cb;
1205
1206		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1207		rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1208
1209		if ( rc != LDAP_SUCCESS ) {
1210			return SLAP_CB_CONTINUE;
1211		}
1212
1213		cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback),
1214			1, op->o_tmpmemctx );
1215		ppb = (ppbind *)(cb+1);
1216		ppb->on = on;
1217		ppb->pErr = PP_noError;
1218		ppb->set_restrict = 1;
1219
1220		/* Setup a callback so we can munge the result */
1221
1222		cb->sc_response = ppolicy_bind_response;
1223		cb->sc_next = op->o_callback->sc_next;
1224		cb->sc_private = ppb;
1225		op->o_callback->sc_next = cb;
1226
1227		/* Did we receive a password policy request control? */
1228		if ( op->o_ctrlflag[ppolicy_cid] ) {
1229			ppb->send_ctrl = 1;
1230		}
1231
1232		op->o_bd->bd_info = (BackendInfo *)on;
1233		ppolicy_get( op, e, &ppb->pp );
1234
1235		rc = account_locked( op, e, &ppb->pp, &ppb->mod );
1236
1237		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1238		be_entry_release_r( op, e );
1239
1240		if ( rc ) {
1241			ppb->pErr = PP_accountLocked;
1242			send_ldap_error( op, rs, LDAP_INVALID_CREDENTIALS, NULL );
1243			return rs->sr_err;
1244		}
1245
1246	}
1247
1248	return SLAP_CB_CONTINUE;
1249}
1250
1251/* Reset the restricted info for the next session on this connection */
1252static int
1253ppolicy_connection_destroy( BackendDB *bd, Connection *conn )
1254{
1255	if ( !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) {
1256		ch_free( pwcons[conn->c_conn_idx].dn.bv_val );
1257		BER_BVZERO( &pwcons[conn->c_conn_idx].dn );
1258	}
1259	return SLAP_CB_CONTINUE;
1260}
1261
1262/* Check if this connection is restricted */
1263static int
1264ppolicy_restrict(
1265	Operation *op,
1266	SlapReply *rs )
1267{
1268	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1269	int send_ctrl = 0;
1270
1271	/* Did we receive a password policy request control? */
1272	if ( op->o_ctrlflag[ppolicy_cid] ) {
1273		send_ctrl = 1;
1274	}
1275
1276	if ( op->o_conn && !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
1277		LDAPControl **oldctrls;
1278		/* if the current authcDN doesn't match the one we recorded,
1279		 * then an intervening Bind has succeeded and the restriction
1280		 * no longer applies. (ITS#4516)
1281		 */
1282		if ( !dn_match( &op->o_conn->c_ndn,
1283				&pwcons[op->o_conn->c_conn_idx].dn )) {
1284			ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1285			BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1286			return SLAP_CB_CONTINUE;
1287		}
1288
1289		Debug( LDAP_DEBUG_TRACE,
1290			"connection restricted to password changing only\n", 0, 0, 0);
1291		if ( send_ctrl ) {
1292			LDAPControl *ctrl = NULL;
1293			ctrl = create_passcontrol( op, -1, -1, PP_changeAfterReset );
1294			oldctrls = add_passcontrol( op, rs, ctrl );
1295		}
1296		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1297		send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS,
1298			"Operations are restricted to bind/unbind/abandon/StartTLS/modify password" );
1299		if ( send_ctrl ) {
1300			ctrls_cleanup( op, rs, oldctrls );
1301		}
1302		return rs->sr_err;
1303	}
1304
1305	return SLAP_CB_CONTINUE;
1306}
1307
1308static int
1309ppolicy_compare_response(
1310	Operation *op,
1311	SlapReply *rs )
1312{
1313	/* map compare responses to bind responses */
1314	if ( rs->sr_err == LDAP_COMPARE_TRUE )
1315		rs->sr_err = LDAP_SUCCESS;
1316	else if ( rs->sr_err == LDAP_COMPARE_FALSE )
1317		rs->sr_err = LDAP_INVALID_CREDENTIALS;
1318
1319	ppolicy_bind_response( op, rs );
1320
1321	/* map back to compare */
1322	if ( rs->sr_err == LDAP_SUCCESS )
1323		rs->sr_err = LDAP_COMPARE_TRUE;
1324	else if ( rs->sr_err == LDAP_INVALID_CREDENTIALS )
1325		rs->sr_err = LDAP_COMPARE_FALSE;
1326
1327	return SLAP_CB_CONTINUE;
1328}
1329
1330static int
1331ppolicy_compare(
1332	Operation *op,
1333	SlapReply *rs )
1334{
1335	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1336
1337	if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE )
1338		return rs->sr_err;
1339
1340	/* Did we receive a password policy request control?
1341	 * Are we testing the userPassword?
1342	 */
1343	if ( op->o_ctrlflag[ppolicy_cid] &&
1344		op->orc_ava->aa_desc == slap_schema.si_ad_userPassword ) {
1345		Entry *e;
1346		int rc;
1347		ppbind *ppb;
1348		slap_callback *cb;
1349
1350		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1351		rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1352
1353		if ( rc != LDAP_SUCCESS ) {
1354			return SLAP_CB_CONTINUE;
1355		}
1356
1357		cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback),
1358			1, op->o_tmpmemctx );
1359		ppb = (ppbind *)(cb+1);
1360		ppb->on = on;
1361		ppb->pErr = PP_noError;
1362		ppb->send_ctrl = 1;
1363		/* failures here don't lockout the connection */
1364		ppb->set_restrict = 0;
1365
1366		/* Setup a callback so we can munge the result */
1367
1368		cb->sc_response = ppolicy_compare_response;
1369		cb->sc_next = op->o_callback->sc_next;
1370		cb->sc_private = ppb;
1371		op->o_callback->sc_next = cb;
1372
1373		op->o_bd->bd_info = (BackendInfo *)on;
1374		ppolicy_get( op, e, &ppb->pp );
1375
1376		rc = account_locked( op, e, &ppb->pp, &ppb->mod );
1377
1378		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1379		be_entry_release_r( op, e );
1380
1381		if ( rc ) {
1382			ppb->pErr = PP_accountLocked;
1383			send_ldap_error( op, rs, LDAP_COMPARE_FALSE, NULL );
1384			return rs->sr_err;
1385		}
1386	}
1387	return SLAP_CB_CONTINUE;
1388}
1389
1390static int
1391ppolicy_add(
1392	Operation *op,
1393	SlapReply *rs )
1394{
1395	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1396	pp_info *pi = on->on_bi.bi_private;
1397	PassPolicy pp;
1398	Attribute *pa;
1399	const char *txt;
1400
1401	if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE )
1402		return rs->sr_err;
1403
1404	/* If this is a replica, assume the master checked everything */
1405	if ( be_shadow_update( op ))
1406		return SLAP_CB_CONTINUE;
1407
1408	/* Check for password in entry */
1409	if ((pa = attr_find( op->oq_add.rs_e->e_attrs,
1410		slap_schema.si_ad_userPassword )))
1411	{
1412		assert( pa->a_vals != NULL );
1413		assert( !BER_BVISNULL( &pa->a_vals[ 0 ] ) );
1414
1415		if ( !BER_BVISNULL( &pa->a_vals[ 1 ] ) ) {
1416			send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, "Password policy only allows one password value" );
1417			return rs->sr_err;
1418		}
1419
1420		/*
1421		 * new entry contains a password - if we're not the root user
1422		 * then we need to check that the password fits in with the
1423		 * security policy for the new entry.
1424		 */
1425		ppolicy_get( op, op->ora_e, &pp );
1426		if (pp.pwdCheckQuality > 0 && !be_isroot( op )) {
1427			struct berval *bv = &(pa->a_vals[0]);
1428			int rc, send_ctrl = 0;
1429			LDAPPasswordPolicyError pErr = PP_noError;
1430			char *txt;
1431
1432			/* Did we receive a password policy request control? */
1433			if ( op->o_ctrlflag[ppolicy_cid] ) {
1434				send_ctrl = 1;
1435			}
1436			rc = check_password_quality( bv, &pp, &pErr, op->ora_e, &txt );
1437			if (rc != LDAP_SUCCESS) {
1438				LDAPControl **oldctrls = NULL;
1439				op->o_bd->bd_info = (BackendInfo *)on->on_info;
1440				if ( send_ctrl ) {
1441					LDAPControl *ctrl = NULL;
1442					ctrl = create_passcontrol( op, -1, -1, pErr );
1443					oldctrls = add_passcontrol( op, rs, ctrl );
1444				}
1445				send_ldap_error( op, rs, rc, txt ? txt : "Password fails quality checking policy" );
1446				if ( txt ) {
1447					free( txt );
1448				}
1449				if ( send_ctrl ) {
1450					ctrls_cleanup( op, rs, oldctrls );
1451				}
1452				return rs->sr_err;
1453			}
1454		}
1455			/*
1456			 * A controversial bit. We hash cleartext
1457			 * passwords provided via add and modify operations
1458			 * You're not really supposed to do this, since
1459			 * the X.500 model says "store attributes" as they
1460			 * get provided. By default, this is what we do
1461			 *
1462			 * But if the hash_passwords flag is set, we hash
1463			 * any cleartext password attribute values via the
1464			 * default password hashing scheme.
1465			 */
1466		if ((pi->hash_passwords) &&
1467			(password_scheme( &(pa->a_vals[0]), NULL ) != LDAP_SUCCESS)) {
1468			struct berval hpw;
1469
1470			slap_passwd_hash( &(pa->a_vals[0]), &hpw, &txt );
1471			if (hpw.bv_val == NULL) {
1472				/*
1473				 * hashing didn't work. Emit an error.
1474				 */
1475				rs->sr_err = LDAP_OTHER;
1476				rs->sr_text = txt;
1477				send_ldap_error( op, rs, LDAP_OTHER, "Password hashing failed" );
1478				return rs->sr_err;
1479			}
1480
1481			memset( pa->a_vals[0].bv_val, 0, pa->a_vals[0].bv_len);
1482			ber_memfree( pa->a_vals[0].bv_val );
1483			pa->a_vals[0].bv_val = hpw.bv_val;
1484			pa->a_vals[0].bv_len = hpw.bv_len;
1485		}
1486
1487		/* If password aging is in effect, set the pwdChangedTime */
1488		if ( pp.pwdMaxAge || pp.pwdMinAge ) {
1489			struct berval timestamp;
1490			char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
1491			time_t now = slap_get_time();
1492
1493			timestamp.bv_val = timebuf;
1494			timestamp.bv_len = sizeof(timebuf);
1495			slap_timestamp( &now, &timestamp );
1496
1497			attr_merge_one( op->ora_e, ad_pwdChangedTime, &timestamp, &timestamp );
1498		}
1499	}
1500	return SLAP_CB_CONTINUE;
1501}
1502
1503static int
1504ppolicy_mod_cb( Operation *op, SlapReply *rs )
1505{
1506	slap_callback *sc = op->o_callback;
1507	op->o_callback = sc->sc_next;
1508	if ( rs->sr_err == LDAP_SUCCESS ) {
1509		ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1510		BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1511	}
1512	op->o_tmpfree( sc, op->o_tmpmemctx );
1513	return SLAP_CB_CONTINUE;
1514}
1515
1516static int
1517ppolicy_modify( Operation *op, SlapReply *rs )
1518{
1519	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
1520	pp_info			*pi = on->on_bi.bi_private;
1521	int			i, rc, mod_pw_only, pwmod, pwmop = -1, deladd,
1522				hsize = 0;
1523	PassPolicy		pp;
1524	Modifications		*mods = NULL, *modtail = NULL,
1525				*ml, *delmod, *addmod;
1526	Attribute		*pa, *ha, at;
1527	const char		*txt;
1528	pw_hist			*tl = NULL, *p;
1529	int			zapReset, send_ctrl = 0, free_txt = 0;
1530	Entry			*e;
1531	struct berval		newpw = BER_BVNULL, oldpw = BER_BVNULL,
1532				*bv, cr[2];
1533	LDAPPasswordPolicyError pErr = PP_noError;
1534	LDAPControl		*ctrl = NULL;
1535	LDAPControl 		**oldctrls = NULL;
1536	int			is_pwdexop = 0;
1537
1538	op->o_bd->bd_info = (BackendInfo *)on->on_info;
1539	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1540	op->o_bd->bd_info = (BackendInfo *)on;
1541
1542	if ( rc != LDAP_SUCCESS ) return SLAP_CB_CONTINUE;
1543
1544	/* If this is a replica, we may need to tweak some of the
1545	 * master's modifications. Otherwise, just pass it through.
1546	 */
1547	if ( be_shadow_update( op )) {
1548		Modifications **prev;
1549		int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0;
1550		Attribute *a_grace, *a_lock, *a_fail;
1551
1552		a_grace = attr_find( e->e_attrs, ad_pwdGraceUseTime );
1553		a_lock = attr_find( e->e_attrs, ad_pwdAccountLockedTime );
1554		a_fail = attr_find( e->e_attrs, ad_pwdFailureTime );
1555
1556		for( prev = &op->orm_modlist, ml = *prev; ml; ml = *prev ) {
1557
1558			if ( ml->sml_desc == slap_schema.si_ad_userPassword )
1559				got_pw = 1;
1560
1561			/* If we're deleting an attr that didn't exist,
1562			 * drop this delete op
1563			 */
1564			if ( ml->sml_op == LDAP_MOD_DELETE ) {
1565				int drop = 0;
1566
1567				if ( ml->sml_desc == ad_pwdGraceUseTime ) {
1568					got_del_grace = 1;
1569					if ( !a_grace )
1570						drop = 1;
1571				} else
1572				if ( ml->sml_desc == ad_pwdAccountLockedTime ) {
1573					got_del_lock = 1;
1574					if ( !a_lock )
1575						drop = 1;
1576				} else
1577				if ( ml->sml_desc == ad_pwdFailureTime ) {
1578					got_del_fail = 1;
1579					if ( !a_fail )
1580						drop = 1;
1581				}
1582				if ( drop ) {
1583					*prev = ml->sml_next;
1584					ml->sml_next = NULL;
1585					slap_mods_free( ml, 1 );
1586					continue;
1587				}
1588			}
1589			prev = &ml->sml_next;
1590		}
1591
1592		/* If we're resetting the password, make sure grace, accountlock,
1593		 * and failure also get removed.
1594		 */
1595		if ( got_pw ) {
1596			if ( a_grace && !got_del_grace ) {
1597				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1598				ml->sml_op = LDAP_MOD_DELETE;
1599				ml->sml_flags = SLAP_MOD_INTERNAL;
1600				ml->sml_type.bv_val = NULL;
1601				ml->sml_desc = ad_pwdGraceUseTime;
1602				ml->sml_numvals = 0;
1603				ml->sml_values = NULL;
1604				ml->sml_nvalues = NULL;
1605				ml->sml_next = NULL;
1606				*prev = ml;
1607				prev = &ml->sml_next;
1608			}
1609			if ( a_lock && !got_del_lock ) {
1610				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1611				ml->sml_op = LDAP_MOD_DELETE;
1612				ml->sml_flags = SLAP_MOD_INTERNAL;
1613				ml->sml_type.bv_val = NULL;
1614				ml->sml_desc = ad_pwdAccountLockedTime;
1615				ml->sml_numvals = 0;
1616				ml->sml_values = NULL;
1617				ml->sml_nvalues = NULL;
1618				ml->sml_next = NULL;
1619				*prev = ml;
1620			}
1621			if ( a_fail && !got_del_fail ) {
1622				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1623				ml->sml_op = LDAP_MOD_DELETE;
1624				ml->sml_flags = SLAP_MOD_INTERNAL;
1625				ml->sml_type.bv_val = NULL;
1626				ml->sml_desc = ad_pwdFailureTime;
1627				ml->sml_numvals = 0;
1628				ml->sml_values = NULL;
1629				ml->sml_nvalues = NULL;
1630				ml->sml_next = NULL;
1631				*prev = ml;
1632			}
1633		}
1634		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1635		be_entry_release_r( op, e );
1636		return SLAP_CB_CONTINUE;
1637	}
1638
1639	/* Did we receive a password policy request control? */
1640	if ( op->o_ctrlflag[ppolicy_cid] ) {
1641		send_ctrl = 1;
1642	}
1643
1644	/* See if this is a pwdModify exop. If so, we can
1645	 * access the plaintext passwords from that request.
1646	 */
1647	{
1648		slap_callback *sc;
1649
1650		for ( sc = op->o_callback; sc; sc=sc->sc_next ) {
1651			if ( sc->sc_response == slap_null_cb &&
1652				sc->sc_private ) {
1653				req_pwdexop_s *qpw = sc->sc_private;
1654				newpw = qpw->rs_new;
1655				oldpw = qpw->rs_old;
1656				is_pwdexop = 1;
1657			   	break;
1658			}
1659		}
1660	}
1661
1662	ppolicy_get( op, e, &pp );
1663
1664	for ( ml = op->orm_modlist,
1665			pwmod = 0, mod_pw_only = 1,
1666			deladd = 0, delmod = NULL,
1667			addmod = NULL,
1668			zapReset = 1;
1669		ml != NULL; modtail = ml, ml = ml->sml_next )
1670	{
1671		if ( ml->sml_desc == pp.ad ) {
1672			pwmod = 1;
1673			pwmop = ml->sml_op;
1674			if ((deladd == 0) && (ml->sml_op == LDAP_MOD_DELETE) &&
1675				(ml->sml_values) && !BER_BVISNULL( &ml->sml_values[0] ))
1676			{
1677				deladd = 1;
1678				delmod = ml;
1679			}
1680
1681			if ((ml->sml_op == LDAP_MOD_ADD) ||
1682				(ml->sml_op == LDAP_MOD_REPLACE))
1683			{
1684				if ( ml->sml_values && !BER_BVISNULL( &ml->sml_values[0] )) {
1685					if ( deladd == 1 )
1686						deladd = 2;
1687
1688					/* FIXME: there's no easy way to ensure
1689					 * that add does not cause multiple
1690					 * userPassword values; one way (that
1691					 * would be consistent with the single
1692					 * password constraint) would be to turn
1693					 * add into replace); another would be
1694					 * to disallow add.
1695					 *
1696					 * Let's check at least that a single value
1697					 * is being added
1698					 */
1699					if ( addmod || !BER_BVISNULL( &ml->sml_values[ 1 ] ) ) {
1700						rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1701						rs->sr_text = "Password policy only allows one password value";
1702						goto return_results;
1703					}
1704
1705					addmod = ml;
1706				} else {
1707					/* replace can have no values, add cannot */
1708					assert( ml->sml_op == LDAP_MOD_REPLACE );
1709				}
1710			}
1711
1712		} else if ( !(ml->sml_flags & SLAP_MOD_INTERNAL) && !is_at_operational( ml->sml_desc->ad_type ) ) {
1713			mod_pw_only = 0;
1714			/* modifying something other than password */
1715		}
1716
1717		/*
1718		 * If there is a request to explicitly add a pwdReset
1719		 * attribute, then we suppress the normal behaviour on
1720		 * password change, which is to remove the pwdReset
1721		 * attribute.
1722		 *
1723		 * This enables an administrator to assign a new password
1724		 * and place a "must reset" flag on the entry, which will
1725		 * stay until the user explicitly changes his/her password.
1726		 */
1727		if (ml->sml_desc == ad_pwdReset ) {
1728			if ((ml->sml_op == LDAP_MOD_ADD) ||
1729				(ml->sml_op == LDAP_MOD_REPLACE))
1730				zapReset = 0;
1731		}
1732	}
1733
1734	if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) {
1735		if ( dn_match( &op->o_conn->c_ndn,
1736				&pwcons[op->o_conn->c_conn_idx].dn )) {
1737			Debug( LDAP_DEBUG_TRACE,
1738				"connection restricted to password changing only\n", 0, 0, 0 );
1739			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1740			rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password";
1741			pErr = PP_changeAfterReset;
1742			goto return_results;
1743		} else {
1744			ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1745			BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1746		}
1747	}
1748
1749	/*
1750	 * if we have a "safe password modify policy", then we need to check if we're doing
1751	 * a delete (with the old password), followed by an add (with the new password).
1752	 *
1753	 * If we got just a delete with nothing else, just let it go. We also skip all the checks if
1754	 * the root user is bound. Root can do anything, including avoid the policies.
1755	 */
1756
1757	if (!pwmod) goto do_modify;
1758
1759	/*
1760	 * Build the password history list in ascending time order
1761	 * We need this, even if the user is root, in order to maintain
1762	 * the pwdHistory operational attributes properly.
1763	 */
1764	if (addmod && pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) {
1765		struct berval oldpw;
1766		time_t oldtime;
1767
1768		for(i=0; ha->a_nvals[i].bv_val; i++) {
1769			rc = parse_pwdhistory( &(ha->a_nvals[i]), NULL,
1770				&oldtime, &oldpw );
1771
1772			if (rc != LDAP_SUCCESS) continue; /* invalid history entry */
1773
1774			if (oldpw.bv_val) {
1775				add_to_pwd_history( &tl, oldtime, &oldpw,
1776					&(ha->a_nvals[i]) );
1777				oldpw.bv_val = NULL;
1778				oldpw.bv_len = 0;
1779			}
1780		}
1781		for(p=tl; p; p=p->next, hsize++); /* count history size */
1782	}
1783
1784	if (be_isroot( op )) goto do_modify;
1785
1786	if (!pp.pwdAllowUserChange) {
1787		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1788		rs->sr_text = "User alteration of password is not allowed";
1789		pErr = PP_passwordModNotAllowed;
1790		goto return_results;
1791	}
1792
1793	/* Just deleting? */
1794	if (!addmod) {
1795		/* skip everything else */
1796		pwmod = 0;
1797		goto do_modify;
1798	}
1799
1800	/* This is a pwdModify exop that provided the old pw.
1801	 * We need to create a Delete mod for this old pw and
1802	 * let the matching value get found later
1803	 */
1804	if (pp.pwdSafeModify && oldpw.bv_val ) {
1805		ml = (Modifications *)ch_calloc( sizeof( Modifications ), 1 );
1806		ml->sml_op = LDAP_MOD_DELETE;
1807		ml->sml_flags = SLAP_MOD_INTERNAL;
1808		ml->sml_desc = pp.ad;
1809		ml->sml_type = pp.ad->ad_cname;
1810		ml->sml_numvals = 1;
1811		ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1812		ber_dupbv( &ml->sml_values[0], &oldpw );
1813		BER_BVZERO( &ml->sml_values[1] );
1814		ml->sml_next = op->orm_modlist;
1815		op->orm_modlist = ml;
1816		delmod = ml;
1817		deladd = 2;
1818	}
1819
1820	if (pp.pwdSafeModify && deladd != 2) {
1821		Debug( LDAP_DEBUG_TRACE,
1822			"change password must use DELETE followed by ADD/REPLACE\n",
1823			0, 0, 0 );
1824		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1825		rs->sr_text = "Must supply old password to be changed as well as new one";
1826		pErr = PP_mustSupplyOldPassword;
1827		goto return_results;
1828	}
1829
1830	/* Check age, but only if pwdReset is not TRUE */
1831	pa = attr_find( e->e_attrs, ad_pwdReset );
1832	if ((!pa || !bvmatch( &pa->a_nvals[0], &slap_true_bv )) &&
1833		pp.pwdMinAge > 0) {
1834		time_t pwtime = (time_t)-1, now;
1835		int age;
1836
1837		if ((pa = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL)
1838			pwtime = parse_time( pa->a_nvals[0].bv_val );
1839		now = slap_get_time();
1840		age = (int)(now - pwtime);
1841		if ((pwtime != (time_t)-1) && (age < pp.pwdMinAge)) {
1842			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1843			rs->sr_text = "Password is too young to change";
1844			pErr = PP_passwordTooYoung;
1845			goto return_results;
1846		}
1847	}
1848
1849	/* pa is used in password history check below, be sure it's set */
1850	if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL && delmod) {
1851		/*
1852		 * we have a password to check
1853		 */
1854		bv = oldpw.bv_val ? &oldpw : delmod->sml_values;
1855		/* FIXME: no access checking? */
1856		rc = slap_passwd_check( op, NULL, pa, bv, &txt );
1857		if (rc != LDAP_SUCCESS) {
1858			Debug( LDAP_DEBUG_TRACE,
1859				"old password check failed: %s\n", txt, 0, 0 );
1860
1861			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1862			rs->sr_text = "Must supply correct old password to change to new one";
1863			pErr = PP_mustSupplyOldPassword;
1864			goto return_results;
1865
1866		} else {
1867			int i;
1868
1869			/*
1870			 * replace the delete value with the (possibly hashed)
1871			 * value which is currently in the password.
1872			 */
1873			for ( i = 0; !BER_BVISNULL( &delmod->sml_values[i] ); i++ ) {
1874				free( delmod->sml_values[i].bv_val );
1875				BER_BVZERO( &delmod->sml_values[i] );
1876			}
1877			free( delmod->sml_values );
1878			delmod->sml_values = ch_calloc( sizeof(struct berval), 2 );
1879			BER_BVZERO( &delmod->sml_values[1] );
1880			ber_dupbv( &(delmod->sml_values[0]),  &(pa->a_nvals[0]) );
1881		}
1882	}
1883
1884	bv = newpw.bv_val ? &newpw : &addmod->sml_values[0];
1885	if (pp.pwdCheckQuality > 0) {
1886
1887		rc = check_password_quality( bv, &pp, &pErr, e, (char **)&txt );
1888		if (rc != LDAP_SUCCESS) {
1889			rs->sr_err = rc;
1890			if ( txt ) {
1891				rs->sr_text = txt;
1892				free_txt = 1;
1893			} else {
1894				rs->sr_text = "Password fails quality checking policy";
1895			}
1896			goto return_results;
1897		}
1898	}
1899
1900	/* If pwdInHistory is zero, passwords may be reused */
1901	if (pa && pp.pwdInHistory > 0) {
1902		/*
1903		 * Last check - the password history.
1904		 */
1905		/* FIXME: no access checking? */
1906		if (slap_passwd_check( op, NULL, pa, bv, &txt ) == LDAP_SUCCESS) {
1907			/*
1908			 * This is bad - it means that the user is attempting
1909			 * to set the password to the same as the old one.
1910			 */
1911			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1912			rs->sr_text = "Password is not being changed from existing value";
1913			pErr = PP_passwordInHistory;
1914			goto return_results;
1915		}
1916
1917		/*
1918		 * Iterate through the password history, and fail on any
1919		 * password matches.
1920		 */
1921		at = *pa;
1922		at.a_vals = cr;
1923		cr[1].bv_val = NULL;
1924		for(p=tl; p; p=p->next) {
1925			cr[0] = p->pw;
1926			/* FIXME: no access checking? */
1927			rc = slap_passwd_check( op, NULL, &at, bv, &txt );
1928
1929			if (rc != LDAP_SUCCESS) continue;
1930
1931			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1932			rs->sr_text = "Password is in history of old passwords";
1933			pErr = PP_passwordInHistory;
1934			goto return_results;
1935		}
1936	}
1937
1938do_modify:
1939	if (pwmod) {
1940		struct berval timestamp;
1941		char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
1942		time_t now = slap_get_time();
1943
1944		/* If the conn is restricted, set a callback to clear it
1945		 * if the pwmod succeeds
1946		 */
1947		if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
1948			slap_callback *sc = op->o_tmpcalloc( 1, sizeof( slap_callback ),
1949				op->o_tmpmemctx );
1950			sc->sc_next = op->o_callback;
1951			/* Must use sc_response to insure we reset on success, before
1952			 * the client sees the response. Must use sc_cleanup to insure
1953			 * that it gets cleaned up if sc_response is not called.
1954			 */
1955			sc->sc_response = ppolicy_mod_cb;
1956			sc->sc_cleanup = ppolicy_mod_cb;
1957			op->o_callback = sc;
1958		}
1959
1960		/*
1961		 * keep the necessary pwd.. operational attributes
1962		 * up to date.
1963		 */
1964
1965		timestamp.bv_val = timebuf;
1966		timestamp.bv_len = sizeof(timebuf);
1967		slap_timestamp( &now, &timestamp );
1968
1969		mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
1970		mods->sml_desc = ad_pwdChangedTime;
1971		if (pwmop != LDAP_MOD_DELETE) {
1972			mods->sml_op = LDAP_MOD_REPLACE;
1973			mods->sml_numvals = 1;
1974			mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1975			ber_dupbv( &mods->sml_values[0], &timestamp );
1976			BER_BVZERO( &mods->sml_values[1] );
1977			assert( !BER_BVISNULL( &mods->sml_values[0] ) );
1978
1979		} else {
1980			mods->sml_op = LDAP_MOD_DELETE;
1981		}
1982		mods->sml_flags = SLAP_MOD_INTERNAL;
1983		mods->sml_next = NULL;
1984		modtail->sml_next = mods;
1985		modtail = mods;
1986
1987		if (attr_find(e->e_attrs, ad_pwdGraceUseTime )) {
1988			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
1989			mods->sml_op = LDAP_MOD_DELETE;
1990			mods->sml_desc = ad_pwdGraceUseTime;
1991			mods->sml_flags = SLAP_MOD_INTERNAL;
1992			mods->sml_next = NULL;
1993			modtail->sml_next = mods;
1994			modtail = mods;
1995		}
1996
1997		if (attr_find(e->e_attrs, ad_pwdAccountLockedTime )) {
1998			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
1999			mods->sml_op = LDAP_MOD_DELETE;
2000			mods->sml_desc = ad_pwdAccountLockedTime;
2001			mods->sml_flags = SLAP_MOD_INTERNAL;
2002			mods->sml_next = NULL;
2003			modtail->sml_next = mods;
2004			modtail = mods;
2005		}
2006
2007		if (attr_find(e->e_attrs, ad_pwdFailureTime )) {
2008			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2009			mods->sml_op = LDAP_MOD_DELETE;
2010			mods->sml_desc = ad_pwdFailureTime;
2011			mods->sml_flags = SLAP_MOD_INTERNAL;
2012			mods->sml_next = NULL;
2013			modtail->sml_next = mods;
2014			modtail = mods;
2015		}
2016
2017		/* Delete the pwdReset attribute, since it's being reset */
2018		if ((zapReset) && (attr_find(e->e_attrs, ad_pwdReset ))) {
2019			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2020			mods->sml_op = LDAP_MOD_DELETE;
2021			mods->sml_desc = ad_pwdReset;
2022			mods->sml_flags = SLAP_MOD_INTERNAL;
2023			mods->sml_next = NULL;
2024			modtail->sml_next = mods;
2025			modtail = mods;
2026		}
2027
2028		if (pp.pwdInHistory > 0) {
2029			if (hsize >= pp.pwdInHistory) {
2030				/*
2031				 * We use the >= operator, since we are going to add
2032				 * the existing password attribute value into the
2033				 * history - thus the cardinality of history values is
2034				 * about to rise by one.
2035				 *
2036				 * If this would push it over the limit of history
2037				 * values (remembering - the password policy could have
2038				 * changed since the password was last altered), we must
2039				 * delete at least 1 value from the pwdHistory list.
2040				 *
2041				 * In fact, we delete '(#pwdHistory attrs - max pwd
2042				 * history length) + 1' values, starting with the oldest.
2043				 * This is easily evaluated, since the linked list is
2044				 * created in ascending time order.
2045				 */
2046				mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2047				mods->sml_op = LDAP_MOD_DELETE;
2048				mods->sml_flags = SLAP_MOD_INTERNAL;
2049				mods->sml_desc = ad_pwdHistory;
2050				mods->sml_numvals = hsize - pp.pwdInHistory + 1;
2051				mods->sml_values = ch_calloc( sizeof( struct berval ),
2052					hsize - pp.pwdInHistory + 2 );
2053				BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] );
2054				for(i=0,p=tl; i < (hsize - pp.pwdInHistory + 1); i++, p=p->next) {
2055					BER_BVZERO( &mods->sml_values[i] );
2056					ber_dupbv( &(mods->sml_values[i]), &p->bv );
2057				}
2058				mods->sml_next = NULL;
2059				modtail->sml_next = mods;
2060				modtail = mods;
2061			}
2062			free_pwd_history_list( &tl );
2063
2064			/*
2065			 * Now add the existing password into the history list.
2066			 * This will be executed even if the operation is to delete
2067			 * the password entirely.
2068			 *
2069			 * This isn't in the spec explicitly, but it seems to make
2070			 * sense that the password history list is the list of all
2071			 * previous passwords - even if they were deleted. Thus, if
2072			 * someone tries to add a historical password at some future
2073			 * point, it will fail.
2074			 */
2075			if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL) {
2076				mods = (Modifications *) ch_malloc( sizeof( Modifications ) );
2077				mods->sml_op = LDAP_MOD_ADD;
2078				mods->sml_flags = SLAP_MOD_INTERNAL;
2079				mods->sml_type.bv_val = NULL;
2080				mods->sml_desc = ad_pwdHistory;
2081				mods->sml_nvalues = NULL;
2082				mods->sml_numvals = 1;
2083				mods->sml_values = ch_calloc( sizeof( struct berval ), 2 );
2084				mods->sml_values[ 1 ].bv_val = NULL;
2085				mods->sml_values[ 1 ].bv_len = 0;
2086				make_pwd_history_value( timebuf, &mods->sml_values[0], pa );
2087				mods->sml_next = NULL;
2088				modtail->sml_next = mods;
2089				modtail = mods;
2090
2091			} else {
2092				Debug( LDAP_DEBUG_TRACE,
2093				"ppolicy_modify: password attr lookup failed\n", 0, 0, 0 );
2094			}
2095		}
2096
2097		/*
2098		 * Controversial bit here. If the new password isn't hashed
2099		 * (ie, is cleartext), we probably should hash it according
2100		 * to the default hash. The reason for this is that we want
2101		 * to use the policy if possible, but if we hash the password
2102		 * before, then we're going to run into trouble when it
2103		 * comes time to check the password.
2104		 *
2105		 * Now, the right thing to do is to use the extended password
2106		 * modify operation, but not all software can do this,
2107		 * therefore it makes sense to hash the new password, now
2108		 * we know it passes the policy requirements.
2109		 *
2110		 * Of course, if the password is already hashed, then we
2111		 * leave it alone.
2112		 */
2113
2114		if ((pi->hash_passwords) && (addmod) && !newpw.bv_val &&
2115			(password_scheme( &(addmod->sml_values[0]), NULL ) != LDAP_SUCCESS))
2116		{
2117			struct berval hpw, bv;
2118
2119			slap_passwd_hash( &(addmod->sml_values[0]), &hpw, &txt );
2120			if (hpw.bv_val == NULL) {
2121					/*
2122					 * hashing didn't work. Emit an error.
2123					 */
2124				rs->sr_err = LDAP_OTHER;
2125				rs->sr_text = txt;
2126				goto return_results;
2127			}
2128			bv = addmod->sml_values[0];
2129				/* clear and discard the clear password */
2130			memset(bv.bv_val, 0, bv.bv_len);
2131			ber_memfree(bv.bv_val);
2132			addmod->sml_values[0] = hpw;
2133		}
2134	}
2135	op->o_bd->bd_info = (BackendInfo *)on->on_info;
2136	be_entry_release_r( op, e );
2137	return SLAP_CB_CONTINUE;
2138
2139return_results:
2140	free_pwd_history_list( &tl );
2141	op->o_bd->bd_info = (BackendInfo *)on->on_info;
2142	be_entry_release_r( op, e );
2143	if ( send_ctrl ) {
2144		ctrl = create_passcontrol( op, -1, -1, pErr );
2145		oldctrls = add_passcontrol( op, rs, ctrl );
2146	}
2147	send_ldap_result( op, rs );
2148	if ( free_txt ) {
2149		free( (char *)txt );
2150		rs->sr_text = NULL;
2151	}
2152	if ( send_ctrl ) {
2153		if ( is_pwdexop ) {
2154			if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
2155				op->o_tmpfree( oldctrls, op->o_tmpmemctx );
2156			}
2157			oldctrls = NULL;
2158			rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
2159
2160		} else {
2161			ctrls_cleanup( op, rs, oldctrls );
2162		}
2163	}
2164	return rs->sr_err;
2165}
2166
2167static int
2168ppolicy_parseCtrl(
2169	Operation *op,
2170	SlapReply *rs,
2171	LDAPControl *ctrl )
2172{
2173	if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
2174		rs->sr_text = "passwordPolicyRequest control value not absent";
2175		return LDAP_PROTOCOL_ERROR;
2176	}
2177	op->o_ctrlflag[ppolicy_cid] = ctrl->ldctl_iscritical
2178		? SLAP_CONTROL_CRITICAL
2179		: SLAP_CONTROL_NONCRITICAL;
2180
2181	return LDAP_SUCCESS;
2182}
2183
2184static int
2185attrPretty(
2186	Syntax *syntax,
2187	struct berval *val,
2188	struct berval *out,
2189	void *ctx )
2190{
2191	AttributeDescription *ad = NULL;
2192	const char *err;
2193	int code;
2194
2195	code = slap_bv2ad( val, &ad, &err );
2196	if ( !code ) {
2197		ber_dupbv_x( out, &ad->ad_type->sat_cname, ctx );
2198	}
2199	return code;
2200}
2201
2202static int
2203attrNormalize(
2204	slap_mask_t use,
2205	Syntax *syntax,
2206	MatchingRule *mr,
2207	struct berval *val,
2208	struct berval *out,
2209	void *ctx )
2210{
2211	AttributeDescription *ad = NULL;
2212	const char *err;
2213	int code;
2214
2215	code = slap_bv2ad( val, &ad, &err );
2216	if ( !code ) {
2217		ber_str2bv_x( ad->ad_type->sat_oid, 0, 1, out, ctx );
2218	}
2219	return code;
2220}
2221
2222static int
2223ppolicy_db_init(
2224	BackendDB *be,
2225	ConfigReply *cr
2226)
2227{
2228	slap_overinst *on = (slap_overinst *) be->bd_info;
2229
2230	if ( SLAP_ISGLOBALOVERLAY( be ) ) {
2231		/* do not allow slapo-ppolicy to be global by now (ITS#5858) */
2232		if ( cr ){
2233			snprintf( cr->msg, sizeof(cr->msg),
2234				"slapo-ppolicy cannot be global" );
2235			Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 );
2236		}
2237		return 1;
2238	}
2239
2240	/* Has User Schema been initialized yet? */
2241	if ( !pwd_UsSchema[0].ad[0] ) {
2242		const char *err;
2243		int i, code;
2244
2245		for (i=0; pwd_UsSchema[i].def; i++) {
2246			code = slap_str2ad( pwd_UsSchema[i].def, pwd_UsSchema[i].ad, &err );
2247			if ( code ) {
2248				if ( cr ){
2249					snprintf( cr->msg, sizeof(cr->msg),
2250						"User Schema load failed for attribute \"%s\". Error code %d: %s",
2251						pwd_UsSchema[i].def, code, err );
2252					Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 );
2253				}
2254				return code;
2255			}
2256		}
2257		{
2258			Syntax *syn;
2259			MatchingRule *mr;
2260
2261			syn = ch_malloc( sizeof( Syntax ));
2262			*syn = *ad_pwdAttribute->ad_type->sat_syntax;
2263			syn->ssyn_pretty = attrPretty;
2264			ad_pwdAttribute->ad_type->sat_syntax = syn;
2265
2266			mr = ch_malloc( sizeof( MatchingRule ));
2267			*mr = *ad_pwdAttribute->ad_type->sat_equality;
2268			mr->smr_normalize = attrNormalize;
2269			ad_pwdAttribute->ad_type->sat_equality = mr;
2270		}
2271	}
2272
2273	on->on_bi.bi_private = ch_calloc( sizeof(pp_info), 1 );
2274
2275	if ( dtblsize && !pwcons ) {
2276		/* accommodate for c_conn_idx == -1 */
2277		pwcons = ch_calloc( sizeof(pw_conn), dtblsize + 1 );
2278		pwcons++;
2279	}
2280
2281	return 0;
2282}
2283
2284static int
2285ppolicy_db_open(
2286	BackendDB *be,
2287	ConfigReply *cr
2288)
2289{
2290	ov_count++;
2291	return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
2292}
2293
2294static int
2295ppolicy_close(
2296	BackendDB *be,
2297	ConfigReply *cr
2298)
2299{
2300	slap_overinst *on = (slap_overinst *) be->bd_info;
2301	pp_info *pi = on->on_bi.bi_private;
2302
2303	/* Perhaps backover should provide bi_destroy hooks... */
2304	ov_count--;
2305	if ( ov_count <=0 && pwcons ) {
2306		pwcons--;
2307		free( pwcons );
2308		pwcons = NULL;
2309	}
2310	free( pi->def_policy.bv_val );
2311	free( pi );
2312
2313	return 0;
2314}
2315
2316static char *extops[] = {
2317	LDAP_EXOP_MODIFY_PASSWD,
2318	NULL
2319};
2320
2321static slap_overinst ppolicy;
2322
2323int ppolicy_initialize()
2324{
2325	int i, code;
2326
2327	for (i=0; pwd_OpSchema[i].def; i++) {
2328		code = register_at( pwd_OpSchema[i].def, pwd_OpSchema[i].ad, 0 );
2329		if ( code ) {
2330			Debug( LDAP_DEBUG_ANY,
2331				"ppolicy_initialize: register_at failed\n", 0, 0, 0 );
2332			return code;
2333		}
2334		/* Allow Manager to set these as needed */
2335		if ( is_at_no_user_mod( (*pwd_OpSchema[i].ad)->ad_type )) {
2336			(*pwd_OpSchema[i].ad)->ad_type->sat_flags |=
2337				SLAP_AT_MANAGEABLE;
2338		}
2339	}
2340
2341	code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
2342		SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, extops,
2343		ppolicy_parseCtrl, &ppolicy_cid );
2344	if ( code != LDAP_SUCCESS ) {
2345		Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code, 0, 0 );
2346		return code;
2347	}
2348
2349	ldap_pvt_thread_mutex_init( &chk_syntax_mutex );
2350
2351	ppolicy.on_bi.bi_type = "ppolicy";
2352	ppolicy.on_bi.bi_db_init = ppolicy_db_init;
2353	ppolicy.on_bi.bi_db_open = ppolicy_db_open;
2354	ppolicy.on_bi.bi_db_close = ppolicy_close;
2355
2356	ppolicy.on_bi.bi_op_add = ppolicy_add;
2357	ppolicy.on_bi.bi_op_bind = ppolicy_bind;
2358	ppolicy.on_bi.bi_op_compare = ppolicy_compare;
2359	ppolicy.on_bi.bi_op_delete = ppolicy_restrict;
2360	ppolicy.on_bi.bi_op_modify = ppolicy_modify;
2361	ppolicy.on_bi.bi_op_search = ppolicy_restrict;
2362	ppolicy.on_bi.bi_connection_destroy = ppolicy_connection_destroy;
2363
2364	ppolicy.on_bi.bi_cf_ocs = ppolicyocs;
2365	code = config_register_schema( ppolicycfg, ppolicyocs );
2366	if ( code ) return code;
2367
2368	return overlay_register( &ppolicy );
2369}
2370
2371#if SLAPD_OVER_PPOLICY == SLAPD_MOD_DYNAMIC
2372int init_module(int argc, char *argv[]) {
2373	return ppolicy_initialize();
2374}
2375#endif
2376
2377#endif	/* defined(SLAPD_OVER_PPOLICY) */
2378