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