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