1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 2004-2011 The OpenLDAP Foundation.
5 * Portions Copyright 2004-2005 Howard Chu, Symas Corporation.
6 * Portions Copyright 2004 Hewlett-Packard Company.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
11 * Public License.
12 *
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
16 */
17/* ACKNOWLEDGEMENTS:
18 * This work was developed by Howard Chu for inclusion in
19 * OpenLDAP Software, based on prior work by Neil Dunbar (HP).
20 * This work was sponsored by the Hewlett-Packard Company.
21 */
22
23#include "portable.h"
24
25/* This file implements "Password Policy for LDAP Directories",
26 * based on draft behera-ldap-password-policy-09
27 */
28
29#ifdef SLAPD_OVER_PPOLICY
30
31#include <ldap.h>
32#include "lutil.h"
33#include "slap.h"
34#ifdef SLAPD_MODULES
35#define LIBLTDL_DLL_IMPORT	/* Win32: don't re-export libltdl's symbols */
36#include <ltdl.h>
37#endif
38#include <ac/errno.h>
39#include <ac/time.h>
40#include <ac/string.h>
41#include <ac/ctype.h>
42#include "config.h"
43
44#ifndef MODULE_NAME_SZ
45#define MODULE_NAME_SZ 256
46#endif
47
48/* Per-instance configuration information */
49typedef struct pp_info {
50	struct berval def_policy;	/* DN of default policy subentry */
51	int use_lockout;		/* send AccountLocked result? */
52	int hash_passwords;		/* transparently hash cleartext pwds */
53	int forward_updates;	/* use frontend for policy state updates */
54} pp_info;
55
56/* Our per-connection info - note, it is not per-instance, it is
57 * used by all instances
58 */
59typedef struct pw_conn {
60	struct berval dn;	/* DN of restricted user */
61} pw_conn;
62
63static pw_conn *pwcons;
64static int ppolicy_cid;
65static int ov_count;
66
67typedef struct pass_policy {
68	AttributeDescription *ad; /* attribute to which the policy applies */
69	int pwdMinAge; /* minimum time (seconds) until passwd can change */
70	int pwdMaxAge; /* time in seconds until pwd will expire after change */
71	int pwdInHistory; /* number of previous passwords kept */
72	int pwdCheckQuality; /* 0 = don't check quality, 1 = check if possible,
73						   2 = check mandatory; fail if not possible */
74	int pwdMinLength; /* minimum number of chars in password */
75	int pwdExpireWarning; /* number of seconds that warning controls are
76							sent before a password expires */
77	int pwdGraceAuthNLimit; /* number of times you can log in with an
78							expired password */
79	int pwdLockout; /* 0 = do not lockout passwords, 1 = lock them out */
80	int pwdLockoutDuration; /* time in seconds a password is locked out for */
81	int pwdMaxFailure; /* number of failed binds allowed before lockout */
82	int pwdFailureCountInterval; /* number of seconds before failure
83									counts are zeroed */
84	int pwdMustChange; /* 0 = users can use admin set password
85							1 = users must change password after admin set */
86	int pwdAllowUserChange; /* 0 = users cannot change their passwords
87								1 = users can change them */
88	int pwdSafeModify; /* 0 = old password doesn't need to come
89								with password change request
90							1 = password change must supply existing pwd */
91	char pwdCheckModule[MODULE_NAME_SZ]; /* name of module to dynamically
92										    load to check password */
93} PassPolicy;
94
95typedef struct pw_hist {
96	time_t t;	/* timestamp of history entry */
97	struct berval pw;	/* old password hash */
98	struct berval bv;	/* text of entire entry */
99	struct pw_hist *next;
100} pw_hist;
101
102/* Operational attributes */
103static AttributeDescription *ad_pwdChangedTime, *ad_pwdAccountLockedTime,
104	*ad_pwdFailureTime, *ad_pwdHistory, *ad_pwdGraceUseTime, *ad_pwdReset,
105	*ad_pwdPolicySubentry;
106
107static struct schema_info {
108	char *def;
109	AttributeDescription **ad;
110} pwd_OpSchema[] = {
111	{	"( 1.3.6.1.4.1.42.2.27.8.1.16 "
112		"NAME ( 'pwdChangedTime' ) "
113		"DESC 'The time the password was last changed' "
114		"EQUALITY generalizedTimeMatch "
115		"ORDERING generalizedTimeOrderingMatch "
116		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
117		"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
118		&ad_pwdChangedTime },
119	{	"( 1.3.6.1.4.1.42.2.27.8.1.17 "
120		"NAME ( 'pwdAccountLockedTime' ) "
121		"DESC 'The time an user account was locked' "
122		"EQUALITY generalizedTimeMatch "
123		"ORDERING generalizedTimeOrderingMatch "
124		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
125		"SINGLE-VALUE "
126#if 0
127		/* Not until Relax control is released */
128		"NO-USER-MODIFICATION "
129#endif
130		"USAGE directoryOperation )",
131		&ad_pwdAccountLockedTime },
132	{	"( 1.3.6.1.4.1.42.2.27.8.1.19 "
133		"NAME ( 'pwdFailureTime' ) "
134		"DESC 'The timestamps of the last consecutive authentication failures' "
135		"EQUALITY generalizedTimeMatch "
136		"ORDERING generalizedTimeOrderingMatch "
137		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
138		"NO-USER-MODIFICATION USAGE directoryOperation )",
139		&ad_pwdFailureTime },
140	{	"( 1.3.6.1.4.1.42.2.27.8.1.20 "
141		"NAME ( 'pwdHistory' ) "
142		"DESC 'The history of users passwords' "
143		"EQUALITY octetStringMatch "
144		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 "
145		"NO-USER-MODIFICATION USAGE directoryOperation )",
146		&ad_pwdHistory },
147	{	"( 1.3.6.1.4.1.42.2.27.8.1.21 "
148		"NAME ( 'pwdGraceUseTime' ) "
149		"DESC 'The timestamps of the grace login once the password has expired' "
150		"EQUALITY generalizedTimeMatch "
151		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
152		"NO-USER-MODIFICATION USAGE directoryOperation )",
153		&ad_pwdGraceUseTime },
154	{	"( 1.3.6.1.4.1.42.2.27.8.1.22 "
155		"NAME ( 'pwdReset' ) "
156		"DESC 'The indication that the password has been reset' "
157		"EQUALITY booleanMatch "
158		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
159		"SINGLE-VALUE USAGE directoryOperation )",
160		&ad_pwdReset },
161	{	"( 1.3.6.1.4.1.42.2.27.8.1.23 "
162		"NAME ( 'pwdPolicySubentry' ) "
163		"DESC 'The pwdPolicy subentry in effect for this object' "
164		"EQUALITY distinguishedNameMatch "
165		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
166		"SINGLE-VALUE "
167#if 0
168		/* Not until Relax control is released */
169		"NO-USER-MODIFICATION "
170#endif
171		"USAGE directoryOperation )",
172		&ad_pwdPolicySubentry },
173	{ NULL, NULL }
174};
175
176/* User attributes */
177static AttributeDescription *ad_pwdMinAge, *ad_pwdMaxAge, *ad_pwdInHistory,
178	*ad_pwdCheckQuality, *ad_pwdMinLength, *ad_pwdMaxFailure,
179	*ad_pwdGraceAuthNLimit, *ad_pwdExpireWarning, *ad_pwdLockoutDuration,
180	*ad_pwdFailureCountInterval, *ad_pwdCheckModule, *ad_pwdLockout,
181	*ad_pwdMustChange, *ad_pwdAllowUserChange, *ad_pwdSafeModify,
182	*ad_pwdAttribute;
183
184#define TAB(name)	{ #name, &ad_##name }
185
186static struct schema_info pwd_UsSchema[] = {
187	TAB(pwdAttribute),
188	TAB(pwdMinAge),
189	TAB(pwdMaxAge),
190	TAB(pwdInHistory),
191	TAB(pwdCheckQuality),
192	TAB(pwdMinLength),
193	TAB(pwdMaxFailure),
194	TAB(pwdGraceAuthNLimit),
195	TAB(pwdExpireWarning),
196	TAB(pwdLockout),
197	TAB(pwdLockoutDuration),
198	TAB(pwdFailureCountInterval),
199	TAB(pwdCheckModule),
200	TAB(pwdMustChange),
201	TAB(pwdAllowUserChange),
202	TAB(pwdSafeModify),
203	{ NULL, NULL }
204};
205
206static ldap_pvt_thread_mutex_t chk_syntax_mutex;
207
208enum {
209	PPOLICY_DEFAULT = 1,
210	PPOLICY_HASH_CLEARTEXT,
211	PPOLICY_USE_LOCKOUT
212};
213
214static ConfigDriver ppolicy_cf_default;
215
216static ConfigTable ppolicycfg[] = {
217	{ "ppolicy_default", "policyDN", 2, 2, 0,
218	  ARG_DN|ARG_QUOTE|ARG_MAGIC|PPOLICY_DEFAULT, ppolicy_cf_default,
219	  "( OLcfgOvAt:12.1 NAME 'olcPPolicyDefault' "
220	  "DESC 'DN of a pwdPolicy object for uncustomized objects' "
221	  "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
222	{ "ppolicy_hash_cleartext", "on|off", 1, 2, 0,
223	  ARG_ON_OFF|ARG_OFFSET|PPOLICY_HASH_CLEARTEXT,
224	  (void *)offsetof(pp_info,hash_passwords),
225	  "( OLcfgOvAt:12.2 NAME 'olcPPolicyHashCleartext' "
226	  "DESC 'Hash passwords on add or modify' "
227	  "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
228	{ "ppolicy_forward_updates", "on|off", 1, 2, 0,
229	  ARG_ON_OFF|ARG_OFFSET,
230	  (void *)offsetof(pp_info,forward_updates),
231	  "( OLcfgOvAt:12.4 NAME 'olcPPolicyForwardUpdates' "
232	  "DESC 'Allow policy state updates to be forwarded via updateref' "
233	  "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
234	{ "ppolicy_use_lockout", "on|off", 1, 2, 0,
235	  ARG_ON_OFF|ARG_OFFSET|PPOLICY_USE_LOCKOUT,
236	  (void *)offsetof(pp_info,use_lockout),
237	  "( OLcfgOvAt:12.3 NAME 'olcPPolicyUseLockout' "
238	  "DESC 'Warn clients with AccountLocked' "
239	  "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
240	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
241};
242
243static ConfigOCs ppolicyocs[] = {
244	{ "( OLcfgOvOc:12.1 "
245	  "NAME 'olcPPolicyConfig' "
246	  "DESC 'Password Policy configuration' "
247	  "SUP olcOverlayConfig "
248	  "MAY ( olcPPolicyDefault $ olcPPolicyHashCleartext $ "
249	  "olcPPolicyUseLockout $ olcPPolicyForwardUpdates ) )",
250	  Cft_Overlay, ppolicycfg },
251	{ NULL, 0, NULL }
252};
253
254static int
255ppolicy_cf_default( ConfigArgs *c )
256{
257	slap_overinst *on = (slap_overinst *)c->bi;
258	pp_info *pi = (pp_info *)on->on_bi.bi_private;
259	int rc = ARG_BAD_CONF;
260
261	assert ( c->type == PPOLICY_DEFAULT );
262	Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default\n", 0, 0, 0);
263
264	switch ( c->op ) {
265	case SLAP_CONFIG_EMIT:
266		Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default emit\n", 0, 0, 0);
267		rc = 0;
268		if ( !BER_BVISEMPTY( &pi->def_policy )) {
269			rc = value_add_one( &c->rvalue_vals,
270					    &pi->def_policy );
271			if ( rc ) return rc;
272			rc = value_add_one( &c->rvalue_nvals,
273					    &pi->def_policy );
274		}
275		break;
276	case LDAP_MOD_DELETE:
277		Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default delete\n", 0, 0, 0);
278		if ( pi->def_policy.bv_val ) {
279			ber_memfree ( pi->def_policy.bv_val );
280			pi->def_policy.bv_val = NULL;
281		}
282		pi->def_policy.bv_len = 0;
283		rc = 0;
284		break;
285	case SLAP_CONFIG_ADD:
286		/* fallthrough to LDAP_MOD_ADD */
287	case LDAP_MOD_ADD:
288		Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default add\n", 0, 0, 0);
289		if ( pi->def_policy.bv_val ) {
290			ber_memfree ( pi->def_policy.bv_val );
291		}
292		pi->def_policy = c->value_ndn;
293		ber_memfree( c->value_dn.bv_val );
294		BER_BVZERO( &c->value_dn );
295		BER_BVZERO( &c->value_ndn );
296		rc = 0;
297		break;
298	default:
299		abort ();
300	}
301
302	return rc;
303}
304
305static time_t
306parse_time( char *atm )
307{
308	struct lutil_tm tm;
309	struct lutil_timet tt;
310	time_t ret = (time_t)-1;
311
312	if ( lutil_parsetime( atm, &tm ) == 0) {
313		lutil_tm2time( &tm, &tt );
314		ret = tt.tt_sec;
315	}
316	return ret;
317}
318
319static int
320account_locked( Operation *op, Entry *e,
321		PassPolicy *pp, Modifications **mod )
322{
323	Attribute       *la;
324
325	assert(mod != NULL);
326
327	if ( !pp->pwdLockout )
328		return 0;
329
330	if ( (la = attr_find( e->e_attrs, ad_pwdAccountLockedTime )) != NULL ) {
331		BerVarray vals = la->a_nvals;
332
333		/*
334		 * there is a lockout stamp - we now need to know if it's
335		 * a valid one.
336		 */
337		if (vals[0].bv_val != NULL) {
338			time_t then, now;
339			Modifications *m;
340
341			if (!pp->pwdLockoutDuration)
342				return 1;
343
344			if ((then = parse_time( vals[0].bv_val )) == (time_t)0)
345				return 1;
346
347			now = slap_get_time();
348
349			if (now < then + pp->pwdLockoutDuration)
350				return 1;
351
352			m = ch_calloc( sizeof(Modifications), 1 );
353			m->sml_op = LDAP_MOD_DELETE;
354			m->sml_flags = 0;
355			m->sml_type = ad_pwdAccountLockedTime->ad_cname;
356			m->sml_desc = ad_pwdAccountLockedTime;
357			m->sml_next = *mod;
358			*mod = m;
359		}
360	}
361
362	return 0;
363}
364
365/* IMPLICIT TAGS, all context-specific */
366#define PPOLICY_WARNING 0xa0L	/* constructed + 0 */
367#define PPOLICY_ERROR 0x81L		/* primitive + 1 */
368
369#define PPOLICY_EXPIRE 0x80L	/* primitive + 0 */
370#define PPOLICY_GRACE  0x81L	/* primitive + 1 */
371
372static const char ppolicy_ctrl_oid[] = LDAP_CONTROL_PASSWORDPOLICYRESPONSE;
373
374static LDAPControl *
375create_passcontrol( Operation *op, int exptime, int grace, LDAPPasswordPolicyError err )
376{
377	BerElementBuffer berbuf, bb2;
378	BerElement *ber = (BerElement *) &berbuf, *b2 = (BerElement *) &bb2;
379	LDAPControl c = { 0 }, *cp;
380	struct berval bv;
381
382	BER_BVZERO( &c.ldctl_value );
383
384	ber_init2( ber, NULL, LBER_USE_DER );
385	ber_printf( ber, "{" /*}*/ );
386
387	if ( exptime >= 0 ) {
388		ber_init2( b2, NULL, LBER_USE_DER );
389		ber_printf( b2, "ti", PPOLICY_EXPIRE, exptime );
390		ber_flatten2( b2, &bv, 1 );
391		(void)ber_free_buf(b2);
392		ber_printf( ber, "tO", PPOLICY_WARNING, &bv );
393		ch_free( bv.bv_val );
394	} else if ( grace > 0 ) {
395		ber_init2( b2, NULL, LBER_USE_DER );
396		ber_printf( b2, "ti", PPOLICY_GRACE, grace );
397		ber_flatten2( b2, &bv, 1 );
398		(void)ber_free_buf(b2);
399		ber_printf( ber, "tO", PPOLICY_WARNING, &bv );
400		ch_free( bv.bv_val );
401	}
402
403	if (err != PP_noError ) {
404		ber_printf( ber, "te", PPOLICY_ERROR, err );
405	}
406	ber_printf( ber, /*{*/ "N}" );
407
408	if (ber_flatten2( ber, &c.ldctl_value, 0 ) == -1) {
409		return NULL;
410	}
411	cp = op->o_tmpalloc( sizeof( LDAPControl ) + c.ldctl_value.bv_len, op->o_tmpmemctx );
412	cp->ldctl_oid = (char *)ppolicy_ctrl_oid;
413	cp->ldctl_iscritical = 0;
414	cp->ldctl_value.bv_val = (char *)&cp[1];
415	cp->ldctl_value.bv_len = c.ldctl_value.bv_len;
416	AC_MEMCPY( cp->ldctl_value.bv_val, c.ldctl_value.bv_val, c.ldctl_value.bv_len );
417	(void)ber_free_buf(ber);
418
419	return cp;
420}
421
422static LDAPControl **
423add_passcontrol( Operation *op, SlapReply *rs, LDAPControl *ctrl )
424{
425	LDAPControl **ctrls, **oldctrls = rs->sr_ctrls;
426	int n;
427
428	n = 0;
429	if ( oldctrls ) {
430		for ( ; oldctrls[n]; n++ )
431			;
432	}
433	n += 2;
434
435	ctrls = op->o_tmpcalloc( sizeof( LDAPControl * ), n, op->o_tmpmemctx );
436
437	n = 0;
438	if ( oldctrls ) {
439		for ( ; oldctrls[n]; n++ ) {
440			ctrls[n] = oldctrls[n];
441		}
442	}
443	ctrls[n] = ctrl;
444	ctrls[n+1] = NULL;
445
446	rs->sr_ctrls = ctrls;
447
448	return oldctrls;
449}
450
451static void
452ppolicy_get( Operation *op, Entry *e, PassPolicy *pp )
453{
454	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
455	pp_info *pi = on->on_bi.bi_private;
456	Attribute *a;
457	BerVarray vals;
458	int rc;
459	Entry *pe = NULL;
460#if 0
461	const char *text;
462#endif
463
464	memset( pp, 0, sizeof(PassPolicy) );
465
466	pp->ad = slap_schema.si_ad_userPassword;
467
468	/* Users can change their own password by default */
469    	pp->pwdAllowUserChange = 1;
470
471	if ((a = attr_find( e->e_attrs, ad_pwdPolicySubentry )) == NULL) {
472		/*
473		 * entry has no password policy assigned - use default
474		 */
475		vals = &pi->def_policy;
476		if ( !vals->bv_val )
477			goto defaultpol;
478	} else {
479		vals = a->a_nvals;
480		if (vals[0].bv_val == NULL) {
481			Debug( LDAP_DEBUG_ANY,
482				"ppolicy_get: NULL value for policySubEntry\n", 0, 0, 0 );
483			goto defaultpol;
484		}
485	}
486
487	op->o_bd->bd_info = (BackendInfo *)on->on_info;
488	rc = be_entry_get_rw( op, vals, NULL, NULL, 0, &pe );
489	op->o_bd->bd_info = (BackendInfo *)on;
490
491	if ( rc ) goto defaultpol;
492
493#if 0	/* Only worry about userPassword for now */
494	if ((a = attr_find( pe->e_attrs, ad_pwdAttribute )))
495		slap_bv2ad( &a->a_vals[0], &pp->ad, &text );
496#endif
497
498	if ( ( a = attr_find( pe->e_attrs, ad_pwdMinAge ) )
499			&& lutil_atoi( &pp->pwdMinAge, a->a_vals[0].bv_val ) != 0 )
500		goto defaultpol;
501	if ( ( a = attr_find( pe->e_attrs, ad_pwdMaxAge ) )
502			&& lutil_atoi( &pp->pwdMaxAge, a->a_vals[0].bv_val ) != 0 )
503		goto defaultpol;
504	if ( ( a = attr_find( pe->e_attrs, ad_pwdInHistory ) )
505			&& lutil_atoi( &pp->pwdInHistory, a->a_vals[0].bv_val ) != 0 )
506		goto defaultpol;
507	if ( ( a = attr_find( pe->e_attrs, ad_pwdCheckQuality ) )
508			&& lutil_atoi( &pp->pwdCheckQuality, a->a_vals[0].bv_val ) != 0 )
509		goto defaultpol;
510	if ( ( a = attr_find( pe->e_attrs, ad_pwdMinLength ) )
511			&& lutil_atoi( &pp->pwdMinLength, a->a_vals[0].bv_val ) != 0 )
512		goto defaultpol;
513	if ( ( a = attr_find( pe->e_attrs, ad_pwdMaxFailure ) )
514			&& lutil_atoi( &pp->pwdMaxFailure, a->a_vals[0].bv_val ) != 0 )
515		goto defaultpol;
516	if ( ( a = attr_find( pe->e_attrs, ad_pwdGraceAuthNLimit ) )
517			&& lutil_atoi( &pp->pwdGraceAuthNLimit, a->a_vals[0].bv_val ) != 0 )
518		goto defaultpol;
519	if ( ( a = attr_find( pe->e_attrs, ad_pwdExpireWarning ) )
520			&& lutil_atoi( &pp->pwdExpireWarning, a->a_vals[0].bv_val ) != 0 )
521		goto defaultpol;
522	if ( ( a = attr_find( pe->e_attrs, ad_pwdFailureCountInterval ) )
523			&& lutil_atoi( &pp->pwdFailureCountInterval, a->a_vals[0].bv_val ) != 0 )
524		goto defaultpol;
525	if ( ( a = attr_find( pe->e_attrs, ad_pwdLockoutDuration ) )
526			&& lutil_atoi( &pp->pwdLockoutDuration, a->a_vals[0].bv_val ) != 0 )
527		goto defaultpol;
528
529	if ( ( a = attr_find( pe->e_attrs, ad_pwdCheckModule ) ) ) {
530		strncpy( pp->pwdCheckModule, a->a_vals[0].bv_val,
531			sizeof(pp->pwdCheckModule) );
532		pp->pwdCheckModule[sizeof(pp->pwdCheckModule)-1] = '\0';
533	}
534
535	if ((a = attr_find( pe->e_attrs, ad_pwdLockout )))
536    		pp->pwdLockout = bvmatch( &a->a_nvals[0], &slap_true_bv );
537	if ((a = attr_find( pe->e_attrs, ad_pwdMustChange )))
538    		pp->pwdMustChange = bvmatch( &a->a_nvals[0], &slap_true_bv );
539	if ((a = attr_find( pe->e_attrs, ad_pwdAllowUserChange )))
540	    	pp->pwdAllowUserChange = bvmatch( &a->a_nvals[0], &slap_true_bv );
541	if ((a = attr_find( pe->e_attrs, ad_pwdSafeModify )))
542	    	pp->pwdSafeModify = bvmatch( &a->a_nvals[0], &slap_true_bv );
543
544	op->o_bd->bd_info = (BackendInfo *)on->on_info;
545	be_entry_release_r( op, pe );
546	op->o_bd->bd_info = (BackendInfo *)on;
547
548	return;
549
550defaultpol:
551	Debug( LDAP_DEBUG_TRACE,
552		"ppolicy_get: using default policy\n", 0, 0, 0 );
553	return;
554}
555
556static int
557password_scheme( struct berval *cred, struct berval *sch )
558{
559	int e;
560
561	assert( cred != NULL );
562
563	if (sch) {
564		sch->bv_val = NULL;
565		sch->bv_len = 0;
566	}
567
568	if ((cred->bv_len == 0) || (cred->bv_val == NULL) ||
569		(cred->bv_val[0] != '{')) return LDAP_OTHER;
570
571	for(e = 1; cred->bv_val[e] && cred->bv_val[e] != '}'; e++);
572	if (cred->bv_val[e]) {
573		int rc;
574		rc = lutil_passwd_scheme( cred->bv_val );
575		if (rc) {
576			if (sch) {
577				sch->bv_val = cred->bv_val;
578				sch->bv_len = e;
579			}
580			return LDAP_SUCCESS;
581		}
582	}
583	return LDAP_OTHER;
584}
585
586static int
587check_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyError *err, Entry *e, char **txt )
588{
589	int rc = LDAP_SUCCESS, ok = LDAP_SUCCESS;
590	char *ptr;
591	struct berval sch;
592
593	assert( cred != NULL );
594	assert( pp != NULL );
595	assert( txt != NULL );
596
597	ptr = cred->bv_val;
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			/* If not forwarding, don't update opattrs and don't replicate */
1167			if ( SLAP_SINGLE_SHADOW( op->o_bd )) {
1168				op2.orm_no_opattrs = 1;
1169				op2.o_dont_replicate = 1;
1170			}
1171			op2.o_bd->bd_info = (BackendInfo *)on->on_info;
1172		}
1173		rc = op2.o_bd->be_modify( &op2, &r2 );
1174		slap_mods_free( mod, 1 );
1175	}
1176
1177	if ( ppb->send_ctrl ) {
1178		LDAPControl *ctrl = NULL;
1179		pp_info *pi = on->on_bi.bi_private;
1180
1181		/* Do we really want to tell that the account is locked? */
1182		if ( ppb->pErr == PP_accountLocked && !pi->use_lockout ) {
1183			ppb->pErr = PP_noError;
1184		}
1185		ctrl = create_passcontrol( op, warn, ngut, ppb->pErr );
1186		ppb->oldctrls = add_passcontrol( op, rs, ctrl );
1187		op->o_callback->sc_cleanup = ppolicy_ctrls_cleanup;
1188	}
1189	op->o_bd->bd_info = bi;
1190	return SLAP_CB_CONTINUE;
1191}
1192
1193static int
1194ppolicy_bind( Operation *op, SlapReply *rs )
1195{
1196	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1197
1198	/* Reset lockout status on all Bind requests */
1199	if ( !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
1200		ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1201		BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1202	}
1203
1204	/* Root bypasses policy */
1205	if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn )) {
1206		Entry *e;
1207		int rc;
1208		ppbind *ppb;
1209		slap_callback *cb;
1210
1211		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1212		rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1213
1214		if ( rc != LDAP_SUCCESS ) {
1215			return SLAP_CB_CONTINUE;
1216		}
1217
1218		cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback),
1219			1, op->o_tmpmemctx );
1220		ppb = (ppbind *)(cb+1);
1221		ppb->on = on;
1222		ppb->pErr = PP_noError;
1223		ppb->set_restrict = 1;
1224
1225		/* Setup a callback so we can munge the result */
1226
1227		cb->sc_response = ppolicy_bind_response;
1228		cb->sc_next = op->o_callback->sc_next;
1229		cb->sc_private = ppb;
1230		op->o_callback->sc_next = cb;
1231
1232		/* Did we receive a password policy request control? */
1233		if ( op->o_ctrlflag[ppolicy_cid] ) {
1234			ppb->send_ctrl = 1;
1235		}
1236
1237		op->o_bd->bd_info = (BackendInfo *)on;
1238		ppolicy_get( op, e, &ppb->pp );
1239
1240		rc = account_locked( op, e, &ppb->pp, &ppb->mod );
1241
1242		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1243		be_entry_release_r( op, e );
1244
1245		if ( rc ) {
1246			ppb->pErr = PP_accountLocked;
1247			send_ldap_error( op, rs, LDAP_INVALID_CREDENTIALS, NULL );
1248			return rs->sr_err;
1249		}
1250
1251	}
1252
1253	return SLAP_CB_CONTINUE;
1254}
1255
1256/* Reset the restricted info for the next session on this connection */
1257static int
1258ppolicy_connection_destroy( BackendDB *bd, Connection *conn )
1259{
1260	if ( !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) {
1261		ch_free( pwcons[conn->c_conn_idx].dn.bv_val );
1262		BER_BVZERO( &pwcons[conn->c_conn_idx].dn );
1263	}
1264	return SLAP_CB_CONTINUE;
1265}
1266
1267/* Check if this connection is restricted */
1268static int
1269ppolicy_restrict(
1270	Operation *op,
1271	SlapReply *rs )
1272{
1273	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1274	int send_ctrl = 0;
1275
1276	/* Did we receive a password policy request control? */
1277	if ( op->o_ctrlflag[ppolicy_cid] ) {
1278		send_ctrl = 1;
1279	}
1280
1281	if ( op->o_conn && !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
1282		LDAPControl **oldctrls;
1283		/* if the current authcDN doesn't match the one we recorded,
1284		 * then an intervening Bind has succeeded and the restriction
1285		 * no longer applies. (ITS#4516)
1286		 */
1287		if ( !dn_match( &op->o_conn->c_ndn,
1288				&pwcons[op->o_conn->c_conn_idx].dn )) {
1289			ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1290			BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1291			return SLAP_CB_CONTINUE;
1292		}
1293
1294		Debug( LDAP_DEBUG_TRACE,
1295			"connection restricted to password changing only\n", 0, 0, 0);
1296		if ( send_ctrl ) {
1297			LDAPControl *ctrl = NULL;
1298			ctrl = create_passcontrol( op, -1, -1, PP_changeAfterReset );
1299			oldctrls = add_passcontrol( op, rs, ctrl );
1300		}
1301		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1302		send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS,
1303			"Operations are restricted to bind/unbind/abandon/StartTLS/modify password" );
1304		if ( send_ctrl ) {
1305			ctrls_cleanup( op, rs, oldctrls );
1306		}
1307		return rs->sr_err;
1308	}
1309
1310	return SLAP_CB_CONTINUE;
1311}
1312
1313static int
1314ppolicy_compare_response(
1315	Operation *op,
1316	SlapReply *rs )
1317{
1318	/* map compare responses to bind responses */
1319	if ( rs->sr_err == LDAP_COMPARE_TRUE )
1320		rs->sr_err = LDAP_SUCCESS;
1321	else if ( rs->sr_err == LDAP_COMPARE_FALSE )
1322		rs->sr_err = LDAP_INVALID_CREDENTIALS;
1323
1324	ppolicy_bind_response( op, rs );
1325
1326	/* map back to compare */
1327	if ( rs->sr_err == LDAP_SUCCESS )
1328		rs->sr_err = LDAP_COMPARE_TRUE;
1329	else if ( rs->sr_err == LDAP_INVALID_CREDENTIALS )
1330		rs->sr_err = LDAP_COMPARE_FALSE;
1331
1332	return SLAP_CB_CONTINUE;
1333}
1334
1335static int
1336ppolicy_compare(
1337	Operation *op,
1338	SlapReply *rs )
1339{
1340	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1341
1342	if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE )
1343		return rs->sr_err;
1344
1345	/* Did we receive a password policy request control?
1346	 * Are we testing the userPassword?
1347	 */
1348	if ( op->o_ctrlflag[ppolicy_cid] &&
1349		op->orc_ava->aa_desc == slap_schema.si_ad_userPassword ) {
1350		Entry *e;
1351		int rc;
1352		ppbind *ppb;
1353		slap_callback *cb;
1354
1355		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1356		rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1357
1358		if ( rc != LDAP_SUCCESS ) {
1359			return SLAP_CB_CONTINUE;
1360		}
1361
1362		cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback),
1363			1, op->o_tmpmemctx );
1364		ppb = (ppbind *)(cb+1);
1365		ppb->on = on;
1366		ppb->pErr = PP_noError;
1367		ppb->send_ctrl = 1;
1368		/* failures here don't lockout the connection */
1369		ppb->set_restrict = 0;
1370
1371		/* Setup a callback so we can munge the result */
1372
1373		cb->sc_response = ppolicy_compare_response;
1374		cb->sc_next = op->o_callback->sc_next;
1375		cb->sc_private = ppb;
1376		op->o_callback->sc_next = cb;
1377
1378		op->o_bd->bd_info = (BackendInfo *)on;
1379		ppolicy_get( op, e, &ppb->pp );
1380
1381		rc = account_locked( op, e, &ppb->pp, &ppb->mod );
1382
1383		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1384		be_entry_release_r( op, e );
1385
1386		if ( rc ) {
1387			ppb->pErr = PP_accountLocked;
1388			send_ldap_error( op, rs, LDAP_COMPARE_FALSE, NULL );
1389			return rs->sr_err;
1390		}
1391	}
1392	return SLAP_CB_CONTINUE;
1393}
1394
1395static int
1396ppolicy_add(
1397	Operation *op,
1398	SlapReply *rs )
1399{
1400	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1401	pp_info *pi = on->on_bi.bi_private;
1402	PassPolicy pp;
1403	Attribute *pa;
1404	const char *txt;
1405
1406	if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE )
1407		return rs->sr_err;
1408
1409	/* If this is a replica, assume the master checked everything */
1410	if ( be_shadow_update( op ))
1411		return SLAP_CB_CONTINUE;
1412
1413	/* Check for password in entry */
1414	if ((pa = attr_find( op->oq_add.rs_e->e_attrs,
1415		slap_schema.si_ad_userPassword )))
1416	{
1417		assert( pa->a_vals != NULL );
1418		assert( !BER_BVISNULL( &pa->a_vals[ 0 ] ) );
1419
1420		if ( !BER_BVISNULL( &pa->a_vals[ 1 ] ) ) {
1421			send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, "Password policy only allows one password value" );
1422			return rs->sr_err;
1423		}
1424
1425		/*
1426		 * new entry contains a password - if we're not the root user
1427		 * then we need to check that the password fits in with the
1428		 * security policy for the new entry.
1429		 */
1430		ppolicy_get( op, op->ora_e, &pp );
1431		if (pp.pwdCheckQuality > 0 && !be_isroot( op )) {
1432			struct berval *bv = &(pa->a_vals[0]);
1433			int rc, send_ctrl = 0;
1434			LDAPPasswordPolicyError pErr = PP_noError;
1435			char *txt;
1436
1437			/* Did we receive a password policy request control? */
1438			if ( op->o_ctrlflag[ppolicy_cid] ) {
1439				send_ctrl = 1;
1440			}
1441			rc = check_password_quality( bv, &pp, &pErr, op->ora_e, &txt );
1442			if (rc != LDAP_SUCCESS) {
1443				LDAPControl **oldctrls = NULL;
1444				op->o_bd->bd_info = (BackendInfo *)on->on_info;
1445				if ( send_ctrl ) {
1446					LDAPControl *ctrl = NULL;
1447					ctrl = create_passcontrol( op, -1, -1, pErr );
1448					oldctrls = add_passcontrol( op, rs, ctrl );
1449				}
1450				send_ldap_error( op, rs, rc, txt ? txt : "Password fails quality checking policy" );
1451				if ( txt ) {
1452					free( txt );
1453				}
1454				if ( send_ctrl ) {
1455					ctrls_cleanup( op, rs, oldctrls );
1456				}
1457				return rs->sr_err;
1458			}
1459		}
1460			/*
1461			 * A controversial bit. We hash cleartext
1462			 * passwords provided via add and modify operations
1463			 * You're not really supposed to do this, since
1464			 * the X.500 model says "store attributes" as they
1465			 * get provided. By default, this is what we do
1466			 *
1467			 * But if the hash_passwords flag is set, we hash
1468			 * any cleartext password attribute values via the
1469			 * default password hashing scheme.
1470			 */
1471		if ((pi->hash_passwords) &&
1472			(password_scheme( &(pa->a_vals[0]), NULL ) != LDAP_SUCCESS)) {
1473			struct berval hpw;
1474
1475			slap_passwd_hash( &(pa->a_vals[0]), &hpw, &txt );
1476			if (hpw.bv_val == NULL) {
1477				/*
1478				 * hashing didn't work. Emit an error.
1479				 */
1480				rs->sr_err = LDAP_OTHER;
1481				rs->sr_text = txt;
1482				send_ldap_error( op, rs, LDAP_OTHER, "Password hashing failed" );
1483				return rs->sr_err;
1484			}
1485
1486			memset( pa->a_vals[0].bv_val, 0, pa->a_vals[0].bv_len);
1487			ber_memfree( pa->a_vals[0].bv_val );
1488			pa->a_vals[0].bv_val = hpw.bv_val;
1489			pa->a_vals[0].bv_len = hpw.bv_len;
1490		}
1491
1492		/* If password aging is in effect, set the pwdChangedTime */
1493		if ( pp.pwdMaxAge || pp.pwdMinAge ) {
1494			struct berval timestamp;
1495			char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
1496			time_t now = slap_get_time();
1497
1498			timestamp.bv_val = timebuf;
1499			timestamp.bv_len = sizeof(timebuf);
1500			slap_timestamp( &now, &timestamp );
1501
1502			attr_merge_one( op->ora_e, ad_pwdChangedTime, &timestamp, &timestamp );
1503		}
1504	}
1505	return SLAP_CB_CONTINUE;
1506}
1507
1508static int
1509ppolicy_mod_cb( Operation *op, SlapReply *rs )
1510{
1511	slap_callback *sc = op->o_callback;
1512	op->o_callback = sc->sc_next;
1513	if ( rs->sr_err == LDAP_SUCCESS ) {
1514		ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1515		BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1516	}
1517	op->o_tmpfree( sc, op->o_tmpmemctx );
1518	return SLAP_CB_CONTINUE;
1519}
1520
1521static int
1522ppolicy_modify( Operation *op, SlapReply *rs )
1523{
1524	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
1525	pp_info			*pi = on->on_bi.bi_private;
1526	int			i, rc, mod_pw_only, pwmod, pwmop = -1, deladd,
1527				hsize = 0;
1528	PassPolicy		pp;
1529	Modifications		*mods = NULL, *modtail = NULL,
1530				*ml, *delmod, *addmod;
1531	Attribute		*pa, *ha, at;
1532	const char		*txt;
1533	pw_hist			*tl = NULL, *p;
1534	int			zapReset, send_ctrl = 0, free_txt = 0;
1535	Entry			*e;
1536	struct berval		newpw = BER_BVNULL, oldpw = BER_BVNULL,
1537				*bv, cr[2];
1538	LDAPPasswordPolicyError pErr = PP_noError;
1539	LDAPControl		*ctrl = NULL;
1540	LDAPControl 		**oldctrls = NULL;
1541	int			is_pwdexop = 0;
1542
1543	op->o_bd->bd_info = (BackendInfo *)on->on_info;
1544	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1545	op->o_bd->bd_info = (BackendInfo *)on;
1546
1547	if ( rc != LDAP_SUCCESS ) return SLAP_CB_CONTINUE;
1548
1549	/* If this is a replica, we may need to tweak some of the
1550	 * master's modifications. Otherwise, just pass it through.
1551	 */
1552	if ( be_shadow_update( op )) {
1553		Modifications **prev;
1554		int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0;
1555		Attribute *a_grace, *a_lock, *a_fail;
1556
1557		a_grace = attr_find( e->e_attrs, ad_pwdGraceUseTime );
1558		a_lock = attr_find( e->e_attrs, ad_pwdAccountLockedTime );
1559		a_fail = attr_find( e->e_attrs, ad_pwdFailureTime );
1560
1561		for( prev = &op->orm_modlist, ml = *prev; ml; ml = *prev ) {
1562
1563			if ( ml->sml_desc == slap_schema.si_ad_userPassword )
1564				got_pw = 1;
1565
1566			/* If we're deleting an attr that didn't exist,
1567			 * drop this delete op
1568			 */
1569			if ( ml->sml_op == LDAP_MOD_DELETE ) {
1570				int drop = 0;
1571
1572				if ( ml->sml_desc == ad_pwdGraceUseTime ) {
1573					got_del_grace = 1;
1574					if ( !a_grace )
1575						drop = 1;
1576				} else
1577				if ( ml->sml_desc == ad_pwdAccountLockedTime ) {
1578					got_del_lock = 1;
1579					if ( !a_lock )
1580						drop = 1;
1581				} else
1582				if ( ml->sml_desc == ad_pwdFailureTime ) {
1583					got_del_fail = 1;
1584					if ( !a_fail )
1585						drop = 1;
1586				}
1587				if ( drop ) {
1588					*prev = ml->sml_next;
1589					ml->sml_next = NULL;
1590					slap_mods_free( ml, 1 );
1591					continue;
1592				}
1593			}
1594			prev = &ml->sml_next;
1595		}
1596
1597		/* If we're resetting the password, make sure grace, accountlock,
1598		 * and failure also get removed.
1599		 */
1600		if ( got_pw ) {
1601			if ( a_grace && !got_del_grace ) {
1602				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1603				ml->sml_op = LDAP_MOD_DELETE;
1604				ml->sml_flags = SLAP_MOD_INTERNAL;
1605				ml->sml_type.bv_val = NULL;
1606				ml->sml_desc = ad_pwdGraceUseTime;
1607				ml->sml_numvals = 0;
1608				ml->sml_values = NULL;
1609				ml->sml_nvalues = NULL;
1610				ml->sml_next = NULL;
1611				*prev = ml;
1612				prev = &ml->sml_next;
1613			}
1614			if ( a_lock && !got_del_lock ) {
1615				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1616				ml->sml_op = LDAP_MOD_DELETE;
1617				ml->sml_flags = SLAP_MOD_INTERNAL;
1618				ml->sml_type.bv_val = NULL;
1619				ml->sml_desc = ad_pwdAccountLockedTime;
1620				ml->sml_numvals = 0;
1621				ml->sml_values = NULL;
1622				ml->sml_nvalues = NULL;
1623				ml->sml_next = NULL;
1624				*prev = ml;
1625			}
1626			if ( a_fail && !got_del_fail ) {
1627				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1628				ml->sml_op = LDAP_MOD_DELETE;
1629				ml->sml_flags = SLAP_MOD_INTERNAL;
1630				ml->sml_type.bv_val = NULL;
1631				ml->sml_desc = ad_pwdFailureTime;
1632				ml->sml_numvals = 0;
1633				ml->sml_values = NULL;
1634				ml->sml_nvalues = NULL;
1635				ml->sml_next = NULL;
1636				*prev = ml;
1637			}
1638		}
1639		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1640		be_entry_release_r( op, e );
1641		return SLAP_CB_CONTINUE;
1642	}
1643
1644	/* Did we receive a password policy request control? */
1645	if ( op->o_ctrlflag[ppolicy_cid] ) {
1646		send_ctrl = 1;
1647	}
1648
1649	/* See if this is a pwdModify exop. If so, we can
1650	 * access the plaintext passwords from that request.
1651	 */
1652	{
1653		slap_callback *sc;
1654
1655		for ( sc = op->o_callback; sc; sc=sc->sc_next ) {
1656			if ( sc->sc_response == slap_null_cb &&
1657				sc->sc_private ) {
1658				req_pwdexop_s *qpw = sc->sc_private;
1659				newpw = qpw->rs_new;
1660				oldpw = qpw->rs_old;
1661				is_pwdexop = 1;
1662			   	break;
1663			}
1664		}
1665	}
1666
1667	ppolicy_get( op, e, &pp );
1668
1669	for ( ml = op->orm_modlist,
1670			pwmod = 0, mod_pw_only = 1,
1671			deladd = 0, delmod = NULL,
1672			addmod = NULL,
1673			zapReset = 1;
1674		ml != NULL; modtail = ml, ml = ml->sml_next )
1675	{
1676		if ( ml->sml_desc == pp.ad ) {
1677			pwmod = 1;
1678			pwmop = ml->sml_op;
1679			if ((deladd == 0) && (ml->sml_op == LDAP_MOD_DELETE) &&
1680				(ml->sml_values) && !BER_BVISNULL( &ml->sml_values[0] ))
1681			{
1682				deladd = 1;
1683				delmod = ml;
1684			}
1685
1686			if ((ml->sml_op == LDAP_MOD_ADD) ||
1687				(ml->sml_op == LDAP_MOD_REPLACE))
1688			{
1689				if ( ml->sml_values && !BER_BVISNULL( &ml->sml_values[0] )) {
1690					if ( deladd == 1 )
1691						deladd = 2;
1692
1693					/* FIXME: there's no easy way to ensure
1694					 * that add does not cause multiple
1695					 * userPassword values; one way (that
1696					 * would be consistent with the single
1697					 * password constraint) would be to turn
1698					 * add into replace); another would be
1699					 * to disallow add.
1700					 *
1701					 * Let's check at least that a single value
1702					 * is being added
1703					 */
1704					if ( addmod || !BER_BVISNULL( &ml->sml_values[ 1 ] ) ) {
1705						rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1706						rs->sr_text = "Password policy only allows one password value";
1707						goto return_results;
1708					}
1709
1710					addmod = ml;
1711				} else {
1712					/* replace can have no values, add cannot */
1713					assert( ml->sml_op == LDAP_MOD_REPLACE );
1714				}
1715			}
1716
1717		} else if ( !(ml->sml_flags & SLAP_MOD_INTERNAL) && !is_at_operational( ml->sml_desc->ad_type ) ) {
1718			mod_pw_only = 0;
1719			/* modifying something other than password */
1720		}
1721
1722		/*
1723		 * If there is a request to explicitly add a pwdReset
1724		 * attribute, then we suppress the normal behaviour on
1725		 * password change, which is to remove the pwdReset
1726		 * attribute.
1727		 *
1728		 * This enables an administrator to assign a new password
1729		 * and place a "must reset" flag on the entry, which will
1730		 * stay until the user explicitly changes his/her password.
1731		 */
1732		if (ml->sml_desc == ad_pwdReset ) {
1733			if ((ml->sml_op == LDAP_MOD_ADD) ||
1734				(ml->sml_op == LDAP_MOD_REPLACE))
1735				zapReset = 0;
1736		}
1737	}
1738
1739	if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) {
1740		if ( dn_match( &op->o_conn->c_ndn,
1741				&pwcons[op->o_conn->c_conn_idx].dn )) {
1742			Debug( LDAP_DEBUG_TRACE,
1743				"connection restricted to password changing only\n", 0, 0, 0 );
1744			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1745			rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password";
1746			pErr = PP_changeAfterReset;
1747			goto return_results;
1748		} else {
1749			ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1750			BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1751		}
1752	}
1753
1754	/*
1755	 * if we have a "safe password modify policy", then we need to check if we're doing
1756	 * a delete (with the old password), followed by an add (with the new password).
1757	 *
1758	 * If we got just a delete with nothing else, just let it go. We also skip all the checks if
1759	 * the root user is bound. Root can do anything, including avoid the policies.
1760	 */
1761
1762	if (!pwmod) goto do_modify;
1763
1764	/*
1765	 * Build the password history list in ascending time order
1766	 * We need this, even if the user is root, in order to maintain
1767	 * the pwdHistory operational attributes properly.
1768	 */
1769	if (addmod && pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) {
1770		struct berval oldpw;
1771		time_t oldtime;
1772
1773		for(i=0; ha->a_nvals[i].bv_val; i++) {
1774			rc = parse_pwdhistory( &(ha->a_nvals[i]), NULL,
1775				&oldtime, &oldpw );
1776
1777			if (rc != LDAP_SUCCESS) continue; /* invalid history entry */
1778
1779			if (oldpw.bv_val) {
1780				add_to_pwd_history( &tl, oldtime, &oldpw,
1781					&(ha->a_nvals[i]) );
1782				oldpw.bv_val = NULL;
1783				oldpw.bv_len = 0;
1784			}
1785		}
1786		for(p=tl; p; p=p->next, hsize++); /* count history size */
1787	}
1788
1789	if (be_isroot( op )) goto do_modify;
1790
1791	/* NOTE: according to draft-behera-ldap-password-policy
1792	 * pwdAllowUserChange == FALSE must only prevent pwd changes
1793	 * by the user the pwd belongs to (ITS#7021) */
1794	if (!pp.pwdAllowUserChange && dn_match(&op->o_req_ndn, &op->o_ndn)) {
1795		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1796		rs->sr_text = "User alteration of password is not allowed";
1797		pErr = PP_passwordModNotAllowed;
1798		goto return_results;
1799	}
1800
1801	/* Just deleting? */
1802	if (!addmod) {
1803		/* skip everything else */
1804		pwmod = 0;
1805		goto do_modify;
1806	}
1807
1808	/* This is a pwdModify exop that provided the old pw.
1809	 * We need to create a Delete mod for this old pw and
1810	 * let the matching value get found later
1811	 */
1812	if (pp.pwdSafeModify && oldpw.bv_val ) {
1813		ml = (Modifications *)ch_calloc( sizeof( Modifications ), 1 );
1814		ml->sml_op = LDAP_MOD_DELETE;
1815		ml->sml_flags = SLAP_MOD_INTERNAL;
1816		ml->sml_desc = pp.ad;
1817		ml->sml_type = pp.ad->ad_cname;
1818		ml->sml_numvals = 1;
1819		ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1820		ber_dupbv( &ml->sml_values[0], &oldpw );
1821		BER_BVZERO( &ml->sml_values[1] );
1822		ml->sml_next = op->orm_modlist;
1823		op->orm_modlist = ml;
1824		delmod = ml;
1825		deladd = 2;
1826	}
1827
1828	if (pp.pwdSafeModify && deladd != 2) {
1829		Debug( LDAP_DEBUG_TRACE,
1830			"change password must use DELETE followed by ADD/REPLACE\n",
1831			0, 0, 0 );
1832		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1833		rs->sr_text = "Must supply old password to be changed as well as new one";
1834		pErr = PP_mustSupplyOldPassword;
1835		goto return_results;
1836	}
1837
1838	/* Check age, but only if pwdReset is not TRUE */
1839	pa = attr_find( e->e_attrs, ad_pwdReset );
1840	if ((!pa || !bvmatch( &pa->a_nvals[0], &slap_true_bv )) &&
1841		pp.pwdMinAge > 0) {
1842		time_t pwtime = (time_t)-1, now;
1843		int age;
1844
1845		if ((pa = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL)
1846			pwtime = parse_time( pa->a_nvals[0].bv_val );
1847		now = slap_get_time();
1848		age = (int)(now - pwtime);
1849		if ((pwtime != (time_t)-1) && (age < pp.pwdMinAge)) {
1850			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1851			rs->sr_text = "Password is too young to change";
1852			pErr = PP_passwordTooYoung;
1853			goto return_results;
1854		}
1855	}
1856
1857	/* pa is used in password history check below, be sure it's set */
1858	if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL && delmod) {
1859		/*
1860		 * we have a password to check
1861		 */
1862		bv = oldpw.bv_val ? &oldpw : delmod->sml_values;
1863		/* FIXME: no access checking? */
1864		rc = slap_passwd_check( op, NULL, pa, bv, &txt );
1865		if (rc != LDAP_SUCCESS) {
1866			Debug( LDAP_DEBUG_TRACE,
1867				"old password check failed: %s\n", txt, 0, 0 );
1868
1869			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1870			rs->sr_text = "Must supply correct old password to change to new one";
1871			pErr = PP_mustSupplyOldPassword;
1872			goto return_results;
1873
1874		} else {
1875			int i;
1876
1877			/*
1878			 * replace the delete value with the (possibly hashed)
1879			 * value which is currently in the password.
1880			 */
1881			for ( i = 0; !BER_BVISNULL( &delmod->sml_values[i] ); i++ ) {
1882				free( delmod->sml_values[i].bv_val );
1883				BER_BVZERO( &delmod->sml_values[i] );
1884			}
1885			free( delmod->sml_values );
1886			delmod->sml_values = ch_calloc( sizeof(struct berval), 2 );
1887			BER_BVZERO( &delmod->sml_values[1] );
1888			ber_dupbv( &(delmod->sml_values[0]),  &(pa->a_nvals[0]) );
1889		}
1890	}
1891
1892	bv = newpw.bv_val ? &newpw : &addmod->sml_values[0];
1893	if (pp.pwdCheckQuality > 0) {
1894
1895		rc = check_password_quality( bv, &pp, &pErr, e, (char **)&txt );
1896		if (rc != LDAP_SUCCESS) {
1897			rs->sr_err = rc;
1898			if ( txt ) {
1899				rs->sr_text = txt;
1900				free_txt = 1;
1901			} else {
1902				rs->sr_text = "Password fails quality checking policy";
1903			}
1904			goto return_results;
1905		}
1906	}
1907
1908	/* If pwdInHistory is zero, passwords may be reused */
1909	if (pa && pp.pwdInHistory > 0) {
1910		/*
1911		 * Last check - the password history.
1912		 */
1913		/* FIXME: no access checking? */
1914		if (slap_passwd_check( op, NULL, pa, bv, &txt ) == LDAP_SUCCESS) {
1915			/*
1916			 * This is bad - it means that the user is attempting
1917			 * to set the password to the same as the old one.
1918			 */
1919			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1920			rs->sr_text = "Password is not being changed from existing value";
1921			pErr = PP_passwordInHistory;
1922			goto return_results;
1923		}
1924
1925		/*
1926		 * Iterate through the password history, and fail on any
1927		 * password matches.
1928		 */
1929		at = *pa;
1930		at.a_vals = cr;
1931		cr[1].bv_val = NULL;
1932		for(p=tl; p; p=p->next) {
1933			cr[0] = p->pw;
1934			/* FIXME: no access checking? */
1935			rc = slap_passwd_check( op, NULL, &at, bv, &txt );
1936
1937			if (rc != LDAP_SUCCESS) continue;
1938
1939			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1940			rs->sr_text = "Password is in history of old passwords";
1941			pErr = PP_passwordInHistory;
1942			goto return_results;
1943		}
1944	}
1945
1946do_modify:
1947	if (pwmod) {
1948		struct berval timestamp;
1949		char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
1950		time_t now = slap_get_time();
1951
1952		/* If the conn is restricted, set a callback to clear it
1953		 * if the pwmod succeeds
1954		 */
1955		if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
1956			slap_callback *sc = op->o_tmpcalloc( 1, sizeof( slap_callback ),
1957				op->o_tmpmemctx );
1958			sc->sc_next = op->o_callback;
1959			/* Must use sc_response to insure we reset on success, before
1960			 * the client sees the response. Must use sc_cleanup to insure
1961			 * that it gets cleaned up if sc_response is not called.
1962			 */
1963			sc->sc_response = ppolicy_mod_cb;
1964			sc->sc_cleanup = ppolicy_mod_cb;
1965			op->o_callback = sc;
1966		}
1967
1968		/*
1969		 * keep the necessary pwd.. operational attributes
1970		 * up to date.
1971		 */
1972
1973		timestamp.bv_val = timebuf;
1974		timestamp.bv_len = sizeof(timebuf);
1975		slap_timestamp( &now, &timestamp );
1976
1977		mods = NULL;
1978		if (pwmop != LDAP_MOD_DELETE) {
1979			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
1980			mods->sml_op = LDAP_MOD_REPLACE;
1981			mods->sml_numvals = 1;
1982			mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1983			ber_dupbv( &mods->sml_values[0], &timestamp );
1984			BER_BVZERO( &mods->sml_values[1] );
1985			assert( !BER_BVISNULL( &mods->sml_values[0] ) );
1986		} else if (attr_find(e->e_attrs, ad_pwdChangedTime )) {
1987			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
1988			mods->sml_op = LDAP_MOD_DELETE;
1989		}
1990		if (mods) {
1991			mods->sml_desc = ad_pwdChangedTime;
1992			mods->sml_flags = SLAP_MOD_INTERNAL;
1993			mods->sml_next = NULL;
1994			modtail->sml_next = mods;
1995			modtail = mods;
1996		}
1997
1998		if (attr_find(e->e_attrs, ad_pwdGraceUseTime )) {
1999			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2000			mods->sml_op = LDAP_MOD_DELETE;
2001			mods->sml_desc = ad_pwdGraceUseTime;
2002			mods->sml_flags = SLAP_MOD_INTERNAL;
2003			mods->sml_next = NULL;
2004			modtail->sml_next = mods;
2005			modtail = mods;
2006		}
2007
2008		if (attr_find(e->e_attrs, ad_pwdAccountLockedTime )) {
2009			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2010			mods->sml_op = LDAP_MOD_DELETE;
2011			mods->sml_desc = ad_pwdAccountLockedTime;
2012			mods->sml_flags = SLAP_MOD_INTERNAL;
2013			mods->sml_next = NULL;
2014			modtail->sml_next = mods;
2015			modtail = mods;
2016		}
2017
2018		if (attr_find(e->e_attrs, ad_pwdFailureTime )) {
2019			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2020			mods->sml_op = LDAP_MOD_DELETE;
2021			mods->sml_desc = ad_pwdFailureTime;
2022			mods->sml_flags = SLAP_MOD_INTERNAL;
2023			mods->sml_next = NULL;
2024			modtail->sml_next = mods;
2025			modtail = mods;
2026		}
2027
2028		/* Delete the pwdReset attribute, since it's being reset */
2029		if ((zapReset) && (attr_find(e->e_attrs, ad_pwdReset ))) {
2030			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2031			mods->sml_op = LDAP_MOD_DELETE;
2032			mods->sml_desc = ad_pwdReset;
2033			mods->sml_flags = SLAP_MOD_INTERNAL;
2034			mods->sml_next = NULL;
2035			modtail->sml_next = mods;
2036			modtail = mods;
2037		}
2038
2039		if (pp.pwdInHistory > 0) {
2040			if (hsize >= pp.pwdInHistory) {
2041				/*
2042				 * We use the >= operator, since we are going to add
2043				 * the existing password attribute value into the
2044				 * history - thus the cardinality of history values is
2045				 * about to rise by one.
2046				 *
2047				 * If this would push it over the limit of history
2048				 * values (remembering - the password policy could have
2049				 * changed since the password was last altered), we must
2050				 * delete at least 1 value from the pwdHistory list.
2051				 *
2052				 * In fact, we delete '(#pwdHistory attrs - max pwd
2053				 * history length) + 1' values, starting with the oldest.
2054				 * This is easily evaluated, since the linked list is
2055				 * created in ascending time order.
2056				 */
2057				mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2058				mods->sml_op = LDAP_MOD_DELETE;
2059				mods->sml_flags = SLAP_MOD_INTERNAL;
2060				mods->sml_desc = ad_pwdHistory;
2061				mods->sml_numvals = hsize - pp.pwdInHistory + 1;
2062				mods->sml_values = ch_calloc( sizeof( struct berval ),
2063					hsize - pp.pwdInHistory + 2 );
2064				BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] );
2065				for(i=0,p=tl; i < (hsize - pp.pwdInHistory + 1); i++, p=p->next) {
2066					BER_BVZERO( &mods->sml_values[i] );
2067					ber_dupbv( &(mods->sml_values[i]), &p->bv );
2068				}
2069				mods->sml_next = NULL;
2070				modtail->sml_next = mods;
2071				modtail = mods;
2072			}
2073			free_pwd_history_list( &tl );
2074
2075			/*
2076			 * Now add the existing password into the history list.
2077			 * This will be executed even if the operation is to delete
2078			 * the password entirely.
2079			 *
2080			 * This isn't in the spec explicitly, but it seems to make
2081			 * sense that the password history list is the list of all
2082			 * previous passwords - even if they were deleted. Thus, if
2083			 * someone tries to add a historical password at some future
2084			 * point, it will fail.
2085			 */
2086			if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL) {
2087				mods = (Modifications *) ch_malloc( sizeof( Modifications ) );
2088				mods->sml_op = LDAP_MOD_ADD;
2089				mods->sml_flags = SLAP_MOD_INTERNAL;
2090				mods->sml_type.bv_val = NULL;
2091				mods->sml_desc = ad_pwdHistory;
2092				mods->sml_nvalues = NULL;
2093				mods->sml_numvals = 1;
2094				mods->sml_values = ch_calloc( sizeof( struct berval ), 2 );
2095				mods->sml_values[ 1 ].bv_val = NULL;
2096				mods->sml_values[ 1 ].bv_len = 0;
2097				make_pwd_history_value( timebuf, &mods->sml_values[0], pa );
2098				mods->sml_next = NULL;
2099				modtail->sml_next = mods;
2100				modtail = mods;
2101
2102			} else {
2103				Debug( LDAP_DEBUG_TRACE,
2104				"ppolicy_modify: password attr lookup failed\n", 0, 0, 0 );
2105			}
2106		}
2107
2108		/*
2109		 * Controversial bit here. If the new password isn't hashed
2110		 * (ie, is cleartext), we probably should hash it according
2111		 * to the default hash. The reason for this is that we want
2112		 * to use the policy if possible, but if we hash the password
2113		 * before, then we're going to run into trouble when it
2114		 * comes time to check the password.
2115		 *
2116		 * Now, the right thing to do is to use the extended password
2117		 * modify operation, but not all software can do this,
2118		 * therefore it makes sense to hash the new password, now
2119		 * we know it passes the policy requirements.
2120		 *
2121		 * Of course, if the password is already hashed, then we
2122		 * leave it alone.
2123		 */
2124
2125		if ((pi->hash_passwords) && (addmod) && !newpw.bv_val &&
2126			(password_scheme( &(addmod->sml_values[0]), NULL ) != LDAP_SUCCESS))
2127		{
2128			struct berval hpw, bv;
2129
2130			slap_passwd_hash( &(addmod->sml_values[0]), &hpw, &txt );
2131			if (hpw.bv_val == NULL) {
2132					/*
2133					 * hashing didn't work. Emit an error.
2134					 */
2135				rs->sr_err = LDAP_OTHER;
2136				rs->sr_text = txt;
2137				goto return_results;
2138			}
2139			bv = addmod->sml_values[0];
2140				/* clear and discard the clear password */
2141			memset(bv.bv_val, 0, bv.bv_len);
2142			ber_memfree(bv.bv_val);
2143			addmod->sml_values[0] = hpw;
2144		}
2145	}
2146	op->o_bd->bd_info = (BackendInfo *)on->on_info;
2147	be_entry_release_r( op, e );
2148	return SLAP_CB_CONTINUE;
2149
2150return_results:
2151	free_pwd_history_list( &tl );
2152	op->o_bd->bd_info = (BackendInfo *)on->on_info;
2153	be_entry_release_r( op, e );
2154	if ( send_ctrl ) {
2155		ctrl = create_passcontrol( op, -1, -1, pErr );
2156		oldctrls = add_passcontrol( op, rs, ctrl );
2157	}
2158	send_ldap_result( op, rs );
2159	if ( free_txt ) {
2160		free( (char *)txt );
2161		rs->sr_text = NULL;
2162	}
2163	if ( send_ctrl ) {
2164		if ( is_pwdexop ) {
2165			if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
2166				op->o_tmpfree( oldctrls, op->o_tmpmemctx );
2167			}
2168			oldctrls = NULL;
2169			rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
2170
2171		} else {
2172			ctrls_cleanup( op, rs, oldctrls );
2173		}
2174	}
2175	return rs->sr_err;
2176}
2177
2178static int
2179ppolicy_parseCtrl(
2180	Operation *op,
2181	SlapReply *rs,
2182	LDAPControl *ctrl )
2183{
2184	if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
2185		rs->sr_text = "passwordPolicyRequest control value not absent";
2186		return LDAP_PROTOCOL_ERROR;
2187	}
2188	op->o_ctrlflag[ppolicy_cid] = ctrl->ldctl_iscritical
2189		? SLAP_CONTROL_CRITICAL
2190		: SLAP_CONTROL_NONCRITICAL;
2191
2192	return LDAP_SUCCESS;
2193}
2194
2195static int
2196attrPretty(
2197	Syntax *syntax,
2198	struct berval *val,
2199	struct berval *out,
2200	void *ctx )
2201{
2202	AttributeDescription *ad = NULL;
2203	const char *err;
2204	int code;
2205
2206	code = slap_bv2ad( val, &ad, &err );
2207	if ( !code ) {
2208		ber_dupbv_x( out, &ad->ad_type->sat_cname, ctx );
2209	}
2210	return code;
2211}
2212
2213static int
2214attrNormalize(
2215	slap_mask_t use,
2216	Syntax *syntax,
2217	MatchingRule *mr,
2218	struct berval *val,
2219	struct berval *out,
2220	void *ctx )
2221{
2222	AttributeDescription *ad = NULL;
2223	const char *err;
2224	int code;
2225
2226	code = slap_bv2ad( val, &ad, &err );
2227	if ( !code ) {
2228		ber_str2bv_x( ad->ad_type->sat_oid, 0, 1, out, ctx );
2229	}
2230	return code;
2231}
2232
2233static int
2234ppolicy_db_init(
2235	BackendDB *be,
2236	ConfigReply *cr
2237)
2238{
2239	slap_overinst *on = (slap_overinst *) be->bd_info;
2240
2241	if ( SLAP_ISGLOBALOVERLAY( be ) ) {
2242		/* do not allow slapo-ppolicy to be global by now (ITS#5858) */
2243		if ( cr ){
2244			snprintf( cr->msg, sizeof(cr->msg),
2245				"slapo-ppolicy cannot be global" );
2246			Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 );
2247		}
2248		return 1;
2249	}
2250
2251	/* Has User Schema been initialized yet? */
2252	if ( !pwd_UsSchema[0].ad[0] ) {
2253		const char *err;
2254		int i, code;
2255
2256		for (i=0; pwd_UsSchema[i].def; i++) {
2257			code = slap_str2ad( pwd_UsSchema[i].def, pwd_UsSchema[i].ad, &err );
2258			if ( code ) {
2259				if ( cr ){
2260					snprintf( cr->msg, sizeof(cr->msg),
2261						"User Schema load failed for attribute \"%s\". Error code %d: %s",
2262						pwd_UsSchema[i].def, code, err );
2263					Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 );
2264				}
2265				return code;
2266			}
2267		}
2268		{
2269			Syntax *syn;
2270			MatchingRule *mr;
2271
2272			syn = ch_malloc( sizeof( Syntax ));
2273			*syn = *ad_pwdAttribute->ad_type->sat_syntax;
2274			syn->ssyn_pretty = attrPretty;
2275			ad_pwdAttribute->ad_type->sat_syntax = syn;
2276
2277			mr = ch_malloc( sizeof( MatchingRule ));
2278			*mr = *ad_pwdAttribute->ad_type->sat_equality;
2279			mr->smr_normalize = attrNormalize;
2280			ad_pwdAttribute->ad_type->sat_equality = mr;
2281		}
2282	}
2283
2284	on->on_bi.bi_private = ch_calloc( sizeof(pp_info), 1 );
2285
2286	if ( dtblsize && !pwcons ) {
2287		/* accommodate for c_conn_idx == -1 */
2288		pwcons = ch_calloc( sizeof(pw_conn), dtblsize + 1 );
2289		pwcons++;
2290	}
2291
2292	return 0;
2293}
2294
2295static int
2296ppolicy_db_open(
2297	BackendDB *be,
2298	ConfigReply *cr
2299)
2300{
2301	ov_count++;
2302	return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
2303}
2304
2305static int
2306ppolicy_close(
2307	BackendDB *be,
2308	ConfigReply *cr
2309)
2310{
2311	slap_overinst *on = (slap_overinst *) be->bd_info;
2312	pp_info *pi = on->on_bi.bi_private;
2313
2314#ifdef SLAP_CONFIG_DELETE
2315	overlay_unregister_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
2316#endif /* SLAP_CONFIG_DELETE */
2317
2318	/* Perhaps backover should provide bi_destroy hooks... */
2319	ov_count--;
2320	if ( ov_count <=0 && pwcons ) {
2321		pwcons--;
2322		free( pwcons );
2323		pwcons = NULL;
2324	}
2325	free( pi->def_policy.bv_val );
2326	free( pi );
2327
2328	return 0;
2329}
2330
2331static char *extops[] = {
2332	LDAP_EXOP_MODIFY_PASSWD,
2333	NULL
2334};
2335
2336static slap_overinst ppolicy;
2337
2338int ppolicy_initialize()
2339{
2340	int i, code;
2341
2342	for (i=0; pwd_OpSchema[i].def; i++) {
2343		code = register_at( pwd_OpSchema[i].def, pwd_OpSchema[i].ad, 0 );
2344		if ( code ) {
2345			Debug( LDAP_DEBUG_ANY,
2346				"ppolicy_initialize: register_at failed\n", 0, 0, 0 );
2347			return code;
2348		}
2349		/* Allow Manager to set these as needed */
2350		if ( is_at_no_user_mod( (*pwd_OpSchema[i].ad)->ad_type )) {
2351			(*pwd_OpSchema[i].ad)->ad_type->sat_flags |=
2352				SLAP_AT_MANAGEABLE;
2353		}
2354	}
2355
2356	code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
2357		SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, extops,
2358		ppolicy_parseCtrl, &ppolicy_cid );
2359	if ( code != LDAP_SUCCESS ) {
2360		Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code, 0, 0 );
2361		return code;
2362	}
2363
2364	ldap_pvt_thread_mutex_init( &chk_syntax_mutex );
2365
2366	ppolicy.on_bi.bi_type = "ppolicy";
2367	ppolicy.on_bi.bi_db_init = ppolicy_db_init;
2368	ppolicy.on_bi.bi_db_open = ppolicy_db_open;
2369	ppolicy.on_bi.bi_db_close = ppolicy_close;
2370
2371	ppolicy.on_bi.bi_op_add = ppolicy_add;
2372	ppolicy.on_bi.bi_op_bind = ppolicy_bind;
2373	ppolicy.on_bi.bi_op_compare = ppolicy_compare;
2374	ppolicy.on_bi.bi_op_delete = ppolicy_restrict;
2375	ppolicy.on_bi.bi_op_modify = ppolicy_modify;
2376	ppolicy.on_bi.bi_op_search = ppolicy_restrict;
2377	ppolicy.on_bi.bi_connection_destroy = ppolicy_connection_destroy;
2378
2379	ppolicy.on_bi.bi_cf_ocs = ppolicyocs;
2380	code = config_register_schema( ppolicycfg, ppolicyocs );
2381	if ( code ) return code;
2382
2383	return overlay_register( &ppolicy );
2384}
2385
2386#if SLAPD_OVER_PPOLICY == SLAPD_MOD_DYNAMIC
2387int init_module(int argc, char *argv[]) {
2388	return ppolicy_initialize();
2389}
2390#endif
2391
2392#endif	/* defined(SLAPD_OVER_PPOLICY) */
2393