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