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