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