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