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