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