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