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