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