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