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