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