]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/ppolicy.c
pass ConfigReply into overlay_config() to allow progating error messages
[openldap] / servers / slapd / overlays / ppolicy.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2004-2008 The OpenLDAP Foundation.
5  * Portions Copyright 2004-2005 Howard Chu, Symas Corporation.
6  * Portions Copyright 2004 Hewlett-Packard Company.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was developed by Howard Chu for inclusion in
19  * OpenLDAP Software, based on prior work by Neil Dunbar (HP).
20  * This work was sponsored by the Hewlett-Packard Company.
21  */
22
23 #include "portable.h"
24
25 /* This file implements "Password Policy for LDAP Directories",
26  * based on draft behera-ldap-password-policy-09
27  */
28
29 #ifdef SLAPD_OVER_PPOLICY
30
31 #include <ldap.h>
32 #include "lutil.h"
33 #include "slap.h"
34 #ifdef SLAPD_MODULES
35 #define LIBLTDL_DLL_IMPORT      /* Win32: don't re-export libltdl's symbols */
36 #include <ltdl.h>
37 #endif
38 #include <ac/errno.h>
39 #include <ac/time.h>
40 #include <ac/string.h>
41 #include <ac/ctype.h>
42 #include "config.h"
43
44 #ifndef MODULE_NAME_SZ
45 #define MODULE_NAME_SZ 256
46 #endif
47
48 /* Per-instance configuration information */
49 typedef struct pp_info {
50         struct berval def_policy;       /* DN of default policy subentry */
51         int use_lockout;                /* send AccountLocked result? */
52         int hash_passwords;             /* transparently hash cleartext pwds */
53 } pp_info;
54
55 /* Our per-connection info - note, it is not per-instance, it is 
56  * used by all instances
57  */
58 typedef struct pw_conn {
59         struct berval dn;       /* DN of restricted user */
60 } pw_conn;
61
62 static pw_conn *pwcons;
63 static int ppolicy_cid;
64 static int ov_count;
65
66 typedef struct pass_policy {
67         AttributeDescription *ad; /* attribute to which the policy applies */
68         int pwdMinAge; /* minimum time (seconds) until passwd can change */
69         int pwdMaxAge; /* time in seconds until pwd will expire after change */
70         int pwdInHistory; /* number of previous passwords kept */
71         int pwdCheckQuality; /* 0 = don't check quality, 1 = check if possible,
72                                                    2 = check mandatory; fail if not possible */
73         int pwdMinLength; /* minimum number of chars in password */
74         int pwdExpireWarning; /* number of seconds that warning controls are
75                                                         sent before a password expires */
76         int pwdGraceAuthNLimit; /* number of times you can log in with an
77                                                         expired password */
78         int pwdLockout; /* 0 = do not lockout passwords, 1 = lock them out */
79         int pwdLockoutDuration; /* time in seconds a password is locked out for */
80         int pwdMaxFailure; /* number of failed binds allowed before lockout */
81         int pwdFailureCountInterval; /* number of seconds before failure
82                                                                         counts are zeroed */
83         int pwdMustChange; /* 0 = users can use admin set password
84                                                         1 = users must change password after admin set */
85         int pwdAllowUserChange; /* 0 = users cannot change their passwords
86                                                                 1 = users can change them */
87         int pwdSafeModify; /* 0 = old password doesn't need to come
88                                                                 with password change request
89                                                         1 = password change must supply existing pwd */
90         char pwdCheckModule[MODULE_NAME_SZ]; /* name of module to dynamically
91                                                                                     load to check password */
92 } PassPolicy;
93
94 typedef struct pw_hist {
95         time_t t;       /* timestamp of history entry */
96         struct berval pw;       /* old password hash */
97         struct berval bv;       /* text of entire entry */
98         struct pw_hist *next;
99 } pw_hist;
100
101 /* Operational attributes */
102 static AttributeDescription *ad_pwdChangedTime, *ad_pwdAccountLockedTime,
103         *ad_pwdFailureTime, *ad_pwdHistory, *ad_pwdGraceUseTime, *ad_pwdReset,
104         *ad_pwdPolicySubentry;
105
106 static struct schema_info {
107         char *def;
108         AttributeDescription **ad;
109 } pwd_OpSchema[] = {
110         {       "( 1.3.6.1.4.1.42.2.27.8.1.16 "
111                 "NAME ( 'pwdChangedTime' ) "
112                 "DESC 'The time the password was last changed' "
113                 "EQUALITY generalizedTimeMatch "
114                 "ORDERING generalizedTimeOrderingMatch "
115                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
116                 "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
117                 &ad_pwdChangedTime },
118         {       "( 1.3.6.1.4.1.42.2.27.8.1.17 "
119                 "NAME ( 'pwdAccountLockedTime' ) "
120                 "DESC 'The time an user account was locked' "
121                 "EQUALITY generalizedTimeMatch "
122                 "ORDERING generalizedTimeOrderingMatch "
123                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
124                 "SINGLE-VALUE "
125 #if 0
126                 /* Not until Relax control is released */
127                 "NO-USER-MODIFICATION "
128 #endif
129                 "USAGE directoryOperation )",
130                 &ad_pwdAccountLockedTime },
131         {       "( 1.3.6.1.4.1.42.2.27.8.1.19 "
132                 "NAME ( 'pwdFailureTime' ) "
133                 "DESC 'The timestamps of the last consecutive authentication failures' "
134                 "EQUALITY generalizedTimeMatch "
135                 "ORDERING generalizedTimeOrderingMatch "
136                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
137                 "NO-USER-MODIFICATION USAGE directoryOperation )",
138                 &ad_pwdFailureTime },
139         {       "( 1.3.6.1.4.1.42.2.27.8.1.20 "
140                 "NAME ( 'pwdHistory' ) "
141                 "DESC 'The history of users passwords' "
142                 "EQUALITY octetStringMatch "
143                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 "
144                 "NO-USER-MODIFICATION USAGE directoryOperation )",
145                 &ad_pwdHistory },
146         {       "( 1.3.6.1.4.1.42.2.27.8.1.21 "
147                 "NAME ( 'pwdGraceUseTime' ) "
148                 "DESC 'The timestamps of the grace login once the password has expired' "
149                 "EQUALITY generalizedTimeMatch "
150                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
151                 "NO-USER-MODIFICATION USAGE directoryOperation )",
152                 &ad_pwdGraceUseTime }, 
153         {       "( 1.3.6.1.4.1.42.2.27.8.1.22 "
154                 "NAME ( 'pwdReset' ) "
155                 "DESC 'The indication that the password has been reset' "
156                 "EQUALITY booleanMatch "
157                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
158                 "SINGLE-VALUE USAGE directoryOperation )",
159                 &ad_pwdReset },
160         {       "( 1.3.6.1.4.1.42.2.27.8.1.23 "
161                 "NAME ( 'pwdPolicySubentry' ) "
162                 "DESC 'The pwdPolicy subentry in effect for this object' "
163                 "EQUALITY distinguishedNameMatch "
164                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
165                 "SINGLE-VALUE "
166 #if 0
167                 /* Not until Relax control is released */
168                 "NO-USER-MODIFICATION "
169 #endif
170                 "USAGE directoryOperation )",
171                 &ad_pwdPolicySubentry },
172         { NULL, NULL }
173 };
174
175 /* User attributes */
176 static AttributeDescription *ad_pwdMinAge, *ad_pwdMaxAge, *ad_pwdInHistory,
177         *ad_pwdCheckQuality, *ad_pwdMinLength, *ad_pwdMaxFailure, 
178         *ad_pwdGraceAuthNLimit, *ad_pwdExpireWarning, *ad_pwdLockoutDuration,
179         *ad_pwdFailureCountInterval, *ad_pwdCheckModule, *ad_pwdLockout,
180         *ad_pwdMustChange, *ad_pwdAllowUserChange, *ad_pwdSafeModify,
181         *ad_pwdAttribute;
182
183 #define TAB(name)       { #name, &ad_##name }
184
185 static struct schema_info pwd_UsSchema[] = {
186         TAB(pwdAttribute),
187         TAB(pwdMinAge),
188         TAB(pwdMaxAge),
189         TAB(pwdInHistory),
190         TAB(pwdCheckQuality),
191         TAB(pwdMinLength),
192         TAB(pwdMaxFailure),
193         TAB(pwdGraceAuthNLimit),
194         TAB(pwdExpireWarning),
195         TAB(pwdLockout),
196         TAB(pwdLockoutDuration),
197         TAB(pwdFailureCountInterval),
198         TAB(pwdCheckModule),
199         TAB(pwdMustChange),
200         TAB(pwdAllowUserChange),
201         TAB(pwdSafeModify),
202         { NULL, NULL }
203 };
204
205 static ldap_pvt_thread_mutex_t chk_syntax_mutex;
206
207 enum {
208         PPOLICY_DEFAULT = 1,
209         PPOLICY_HASH_CLEARTEXT,
210         PPOLICY_USE_LOCKOUT
211 };
212
213 static ConfigDriver ppolicy_cf_default;
214
215 static ConfigTable ppolicycfg[] = {
216         { "ppolicy_default", "policyDN", 2, 2, 0,
217           ARG_DN|ARG_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( int exptime, int grace, LDAPPasswordPolicyError err )
366 {
367         char berbuf[LBER_ELEMENT_SIZEOF], bb2[LBER_ELEMENT_SIZEOF];
368         BerElement *ber = (BerElement *)berbuf, *b2 = (BerElement *)bb2;
369         LDAPControl *c;
370         struct berval bv;
371
372         c = ch_calloc( sizeof( LDAPControl ), 1 );
373         if ( c == NULL ) {
374                 return NULL;
375         }
376         c->ldctl_oid = (char *)ppolicy_ctrl_oid;
377         c->ldctl_iscritical = 0;
378         BER_BVZERO( &c->ldctl_value );
379
380         ber_init2( ber, NULL, LBER_USE_DER );
381         ber_printf( ber, "{" /*}*/ );
382
383         if ( exptime >= 0 ) {
384                 ber_init2( b2, NULL, LBER_USE_DER );
385                 ber_printf( b2, "ti", PPOLICY_EXPIRE, exptime );
386                 ber_flatten2( b2, &bv, 1 );
387                 (void)ber_free_buf(b2);
388                 ber_printf( ber, "tO", PPOLICY_WARNING, &bv );
389                 ch_free( bv.bv_val );
390         } else if ( grace > 0 ) {
391                 ber_init2( b2, NULL, LBER_USE_DER );
392                 ber_printf( b2, "ti", PPOLICY_GRACE, grace );
393                 ber_flatten2( b2, &bv, 1 );
394                 (void)ber_free_buf(b2);
395                 ber_printf( ber, "tO", PPOLICY_WARNING, &bv );
396                 ch_free( bv.bv_val );
397         }
398
399         if (err != PP_noError ) {
400                 ber_printf( ber, "te", PPOLICY_ERROR, err );
401         }
402         ber_printf( ber, /*{*/ "N}" );
403
404         if (ber_flatten2( ber, &(c->ldctl_value), 1 ) == LBER_DEFAULT) {
405                 ch_free(c);
406                 c = NULL;
407         }
408         (void)ber_free_buf(ber);
409         return c;
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         int 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                         ch_free( rs->sr_ctrls[n]->ldctl_value.bv_val );
858                         ch_free( rs->sr_ctrls[n] );
859                         rs->sr_ctrls[n] = (LDAPControl *)(-1);
860                         break;
861                 }
862         }
863
864         if ( rs->sr_ctrls[n] == NULL ) {
865                 /* missed? */
866         }
867
868         op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
869
870         rs->sr_ctrls = oldctrls;
871 }
872
873 static int
874 ppolicy_ctrls_cleanup( Operation *op, SlapReply *rs )
875 {
876         ppbind *ppb = op->o_callback->sc_private;
877         if ( ppb->send_ctrl ) {
878                 ctrls_cleanup( op, rs, ppb->oldctrls );
879         }
880         return SLAP_CB_CONTINUE;
881 }
882
883 static int
884 ppolicy_bind_response( Operation *op, SlapReply *rs )
885 {
886         ppbind *ppb = op->o_callback->sc_private;
887         slap_overinst *on = ppb->on;
888         Modifications *mod = ppb->mod, *m;
889         int pwExpired = 0;
890         int ngut = -1, warn = -1, age, rc;
891         Attribute *a;
892         time_t now, pwtime = (time_t)-1;
893         char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
894         struct berval timestamp;
895         BackendInfo *bi = op->o_bd->bd_info;
896         Entry *e;
897
898         /* If we already know it's locked, just get on with it */
899         if ( ppb->pErr != PP_noError ) {
900                 goto locked;
901         }
902
903         op->o_bd->bd_info = (BackendInfo *)on->on_info;
904         rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
905         op->o_bd->bd_info = bi;
906
907         if ( rc != LDAP_SUCCESS ) {
908                 return SLAP_CB_CONTINUE;
909         }
910
911         now = slap_get_time(); /* stored for later consideration */
912         timestamp.bv_val = nowstr;
913         timestamp.bv_len = sizeof(nowstr);
914         slap_timestamp( &now, &timestamp );
915
916         if ( rs->sr_err == LDAP_INVALID_CREDENTIALS ) {
917                 int i = 0, fc = 0;
918
919                 m = ch_calloc( sizeof(Modifications), 1 );
920                 m->sml_op = LDAP_MOD_ADD;
921                 m->sml_flags = 0;
922                 m->sml_type = ad_pwdFailureTime->ad_cname;
923                 m->sml_desc = ad_pwdFailureTime;
924                 m->sml_numvals = 1;
925                 m->sml_values = ch_calloc( sizeof(struct berval), 2 );
926                 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
927
928                 ber_dupbv( &m->sml_values[0], &timestamp );
929                 ber_dupbv( &m->sml_nvalues[0], &timestamp );
930                 m->sml_next = mod;
931                 mod = m;
932
933                 /*
934                  * Count the pwdFailureTimes - if it's
935                  * greater than the policy pwdMaxFailure,
936                  * then lock the account.
937                  */
938                 if ((a = attr_find( e->e_attrs, ad_pwdFailureTime )) != NULL) {
939                         for(i=0; a->a_nvals[i].bv_val; i++) {
940
941                                 /*
942                                  * If the interval is 0, then failures
943                                  * stay on the record until explicitly
944                                  * reset by successful authentication.
945                                  */
946                                 if (ppb->pp.pwdFailureCountInterval == 0) {
947                                         fc++;
948                                 } else if (now <=
949                                                         parse_time(a->a_nvals[i].bv_val) +
950                                                         ppb->pp.pwdFailureCountInterval) {
951
952                                         fc++;
953                                 }
954                                 /*
955                                  * We only count those failures
956                                  * which are not due to expire.
957                                  */
958                         }
959                 }
960                 
961                 if ((ppb->pp.pwdMaxFailure > 0) &&
962                         (fc >= ppb->pp.pwdMaxFailure - 1)) {
963
964                         /*
965                          * We subtract 1 from the failure max
966                          * because the new failure entry hasn't
967                          * made it to the entry yet.
968                          */
969                         m = ch_calloc( sizeof(Modifications), 1 );
970                         m->sml_op = LDAP_MOD_REPLACE;
971                         m->sml_flags = 0;
972                         m->sml_type = ad_pwdAccountLockedTime->ad_cname;
973                         m->sml_desc = ad_pwdAccountLockedTime;
974                         m->sml_numvals = 1;
975                         m->sml_values = ch_calloc( sizeof(struct berval), 2 );
976                         m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
977                         ber_dupbv( &m->sml_values[0], &timestamp );
978                         ber_dupbv( &m->sml_nvalues[0], &timestamp );
979                         m->sml_next = mod;
980                         mod = m;
981                 }
982         } else if ( rs->sr_err == LDAP_SUCCESS ) {
983                 if ((a = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL)
984                         pwtime = parse_time( a->a_nvals[0].bv_val );
985
986                 /* delete all pwdFailureTimes */
987                 if ( attr_find( e->e_attrs, ad_pwdFailureTime )) {
988                         m = ch_calloc( sizeof(Modifications), 1 );
989                         m->sml_op = LDAP_MOD_DELETE;
990                         m->sml_flags = 0;
991                         m->sml_type = ad_pwdFailureTime->ad_cname;
992                         m->sml_desc = ad_pwdFailureTime;
993                         m->sml_next = mod;
994                         mod = m;
995                 }
996
997                 /*
998                  * check to see if the password must be changed
999                  */
1000                 if ( ppb->pp.pwdMustChange &&
1001                         (a = attr_find( e->e_attrs, ad_pwdReset )) &&
1002                         bvmatch( &a->a_nvals[0], &slap_true_bv ) )
1003                 {
1004                         /*
1005                          * need to inject client controls here to give
1006                          * more information. For the moment, we ensure
1007                          * that we are disallowed from doing anything
1008                          * other than change password.
1009                          */
1010                         ber_dupbv( &pwcons[op->o_conn->c_conn_idx].dn,
1011                                 &op->o_conn->c_ndn );
1012
1013                         ppb->pErr = PP_changeAfterReset;
1014
1015                 } else {
1016                         /*
1017                          * the password does not need to be changed, so
1018                          * we now check whether the password has expired.
1019                          *
1020                          * We can skip this bit if passwords don't age in
1021                          * the policy. Also, if there was no pwdChangedTime
1022                          * attribute in the entry, the password never expires.
1023                          */
1024                         if (ppb->pp.pwdMaxAge == 0) goto grace;
1025
1026                         if (pwtime != (time_t)-1) {
1027                                 /*
1028                                  * Check: was the last change time of
1029                                  * the password older than the maximum age
1030                                  * allowed. (Ignore case 2 from I-D, it's just silly.)
1031                                  */
1032                                 if (now - pwtime > ppb->pp.pwdMaxAge ) pwExpired = 1;
1033                         }
1034                 }
1035
1036 grace:
1037                 if (!pwExpired) goto check_expiring_password;
1038                 
1039                 if ((a = attr_find( e->e_attrs, ad_pwdGraceUseTime )) == NULL)
1040                         ngut = ppb->pp.pwdGraceAuthNLimit;
1041                 else {
1042                         for(ngut=0; a->a_nvals[ngut].bv_val; ngut++);
1043                         ngut = ppb->pp.pwdGraceAuthNLimit - ngut;
1044                 }
1045
1046                 /*
1047                  * ngut is the number of remaining grace logins
1048                  */
1049                 Debug( LDAP_DEBUG_ANY,
1050                         "ppolicy_bind: Entry %s has an expired password: %d grace logins\n",
1051                         e->e_name.bv_val, ngut, 0);
1052                 
1053                 if (ngut < 1) {
1054                         ppb->pErr = PP_passwordExpired;
1055                         rs->sr_err = LDAP_INVALID_CREDENTIALS;
1056                         goto done;
1057                 }
1058
1059                 /*
1060                  * Add a grace user time to the entry
1061                  */
1062                 m = ch_calloc( sizeof(Modifications), 1 );
1063                 m->sml_op = LDAP_MOD_ADD;
1064                 m->sml_flags = 0;
1065                 m->sml_type = ad_pwdGraceUseTime->ad_cname;
1066                 m->sml_desc = ad_pwdGraceUseTime;
1067                 m->sml_numvals = 1;
1068                 m->sml_values = ch_calloc( sizeof(struct berval), 2 );
1069                 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
1070                 ber_dupbv( &m->sml_values[0], &timestamp );
1071                 ber_dupbv( &m->sml_nvalues[0], &timestamp );
1072                 m->sml_next = mod;
1073                 mod = m;
1074
1075 check_expiring_password:
1076                 /*
1077                  * Now we need to check to see
1078                  * if it is about to expire, and if so, should the user
1079                  * be warned about it in the password policy control.
1080                  *
1081                  * If the password has expired, and we're in the grace period, then
1082                  * we don't need to do this bit. Similarly, if we don't have password
1083                  * aging, then there's no need to do this bit either.
1084                  */
1085                 if ((ppb->pp.pwdMaxAge < 1) || (pwExpired) || (ppb->pp.pwdExpireWarning < 1))
1086                         goto done;
1087
1088                 age = (int)(now - pwtime);
1089                 
1090                 /*
1091                  * We know that there is a password Change Time attribute - if
1092                  * there wasn't, then the pwdExpired value would be true, unless
1093                  * there is no password aging - and if there is no password aging,
1094                  * then this section isn't called anyway - you can't have an
1095                  * expiring password if there's no limit to expire.
1096                  */
1097                 if (ppb->pp.pwdMaxAge - age < ppb->pp.pwdExpireWarning ) {
1098                         /*
1099                          * Set the warning value.
1100                          */
1101                         warn = ppb->pp.pwdMaxAge - age; /* seconds left until expiry */
1102                         if (warn < 0) warn = 0; /* something weird here - why is pwExpired not set? */
1103                         
1104                         Debug( LDAP_DEBUG_ANY,
1105                                 "ppolicy_bind: Setting warning for password expiry for %s = %d seconds\n",
1106                                 op->o_req_dn.bv_val, warn, 0 );
1107                 }
1108         }
1109
1110 done:
1111         op->o_bd->bd_info = (BackendInfo *)on->on_info;
1112         be_entry_release_r( op, e );
1113
1114 locked:
1115         if ( mod ) {
1116                 Operation op2 = *op;
1117                 SlapReply r2 = { REP_RESULT };
1118                 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
1119
1120                 /* FIXME: Need to handle replication of some (but not all)
1121                  * of the operational attributes...
1122                  */
1123                 op2.o_tag = LDAP_REQ_MODIFY;
1124                 op2.o_callback = &cb;
1125                 op2.orm_modlist = mod;
1126                 op2.o_dn = op->o_bd->be_rootdn;
1127                 op2.o_ndn = op->o_bd->be_rootndn;
1128                 op2.o_bd->bd_info = (BackendInfo *)on->on_info;
1129                 rc = op->o_bd->be_modify( &op2, &r2 );
1130                 slap_mods_free( mod, 1 );
1131         }
1132
1133         if ( ppb->send_ctrl ) {
1134                 LDAPControl *ctrl = NULL;
1135                 pp_info *pi = on->on_bi.bi_private;
1136
1137                 /* Do we really want to tell that the account is locked? */
1138                 if ( ppb->pErr == PP_accountLocked && !pi->use_lockout ) {
1139                         ppb->pErr = PP_noError;
1140                 }
1141                 ctrl = create_passcontrol( warn, ngut, ppb->pErr );
1142                 ppb->oldctrls = add_passcontrol( op, rs, ctrl );
1143                 op->o_callback->sc_cleanup = ppolicy_ctrls_cleanup;
1144         }
1145         op->o_bd->bd_info = bi;
1146         return SLAP_CB_CONTINUE;
1147 }
1148
1149 static int
1150 ppolicy_bind( Operation *op, SlapReply *rs )
1151 {
1152         slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1153
1154         /* Reset lockout status on all Bind requests */
1155         if ( !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
1156                 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1157                 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1158         }
1159
1160         /* Root bypasses policy */
1161         if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn )) {
1162                 Entry *e;
1163                 int rc;
1164                 ppbind *ppb;
1165                 slap_callback *cb;
1166
1167                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1168                 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1169
1170                 if ( rc != LDAP_SUCCESS ) {
1171                         return SLAP_CB_CONTINUE;
1172                 }
1173
1174                 cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback),
1175                         1, op->o_tmpmemctx );
1176                 ppb = (ppbind *)(cb+1);
1177                 ppb->on = on;
1178                 ppb->pErr = PP_noError;
1179
1180                 /* Setup a callback so we can munge the result */
1181
1182                 cb->sc_response = ppolicy_bind_response;
1183                 cb->sc_next = op->o_callback->sc_next;
1184                 cb->sc_private = ppb;
1185                 op->o_callback->sc_next = cb;
1186
1187                 /* Did we receive a password policy request control? */
1188                 if ( op->o_ctrlflag[ppolicy_cid] ) {
1189                         ppb->send_ctrl = 1;
1190                 }
1191
1192                 op->o_bd->bd_info = (BackendInfo *)on;
1193                 ppolicy_get( op, e, &ppb->pp );
1194
1195                 rc = account_locked( op, e, &ppb->pp, &ppb->mod );
1196
1197                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1198                 be_entry_release_r( op, e );
1199
1200                 if ( rc ) {
1201                         /* This will be the Draft 8 response, Unwilling is bogus */
1202                         ppb->pErr = PP_accountLocked;
1203                         send_ldap_error( op, rs, LDAP_INVALID_CREDENTIALS, NULL );
1204                         return rs->sr_err;
1205                 }
1206
1207         }
1208
1209         return SLAP_CB_CONTINUE;
1210 }
1211
1212 /* Reset the restricted info for the next session on this connection */
1213 static int
1214 ppolicy_connection_destroy( BackendDB *bd, Connection *conn )
1215 {
1216         if ( !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) {
1217                 ch_free( pwcons[conn->c_conn_idx].dn.bv_val );
1218                 BER_BVZERO( &pwcons[conn->c_conn_idx].dn );
1219         }
1220         return SLAP_CB_CONTINUE;
1221 }
1222
1223 /* Check if this connection is restricted */
1224 static int
1225 ppolicy_restrict(
1226         Operation *op,
1227         SlapReply *rs )
1228 {
1229         slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1230         int send_ctrl = 0;
1231
1232         /* Did we receive a password policy request control? */
1233         if ( op->o_ctrlflag[ppolicy_cid] ) {
1234                 send_ctrl = 1;
1235         }
1236
1237         if ( op->o_conn && !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
1238                 LDAPControl **oldctrls;
1239                 /* if the current authcDN doesn't match the one we recorded,
1240                  * then an intervening Bind has succeeded and the restriction
1241                  * no longer applies. (ITS#4516)
1242                  */
1243                 if ( !dn_match( &op->o_conn->c_ndn,
1244                                 &pwcons[op->o_conn->c_conn_idx].dn )) {
1245                         ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1246                         BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1247                         return SLAP_CB_CONTINUE;
1248                 }
1249
1250                 Debug( LDAP_DEBUG_TRACE,
1251                         "connection restricted to password changing only\n", 0, 0, 0);
1252                 if ( send_ctrl ) {
1253                         LDAPControl *ctrl = NULL;
1254                         ctrl = create_passcontrol( -1, -1, PP_changeAfterReset );
1255                         oldctrls = add_passcontrol( op, rs, ctrl );
1256                 }
1257                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1258                 send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS, 
1259                         "Operations are restricted to bind/unbind/abandon/StartTLS/modify password" );
1260                 if ( send_ctrl ) {
1261                         ctrls_cleanup( op, rs, oldctrls );
1262                 }
1263                 return rs->sr_err;
1264         }
1265
1266         return SLAP_CB_CONTINUE;
1267 }
1268
1269 static int
1270 ppolicy_add(
1271         Operation *op,
1272         SlapReply *rs )
1273 {
1274         slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1275         pp_info *pi = on->on_bi.bi_private;
1276         PassPolicy pp;
1277         Attribute *pa;
1278         const char *txt;
1279
1280         if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE )
1281                 return rs->sr_err;
1282
1283         /* If this is a replica, assume the master checked everything */
1284         if ( be_shadow_update( op ))
1285                 return SLAP_CB_CONTINUE;
1286
1287         /* Check for password in entry */
1288         if ((pa = attr_find( op->oq_add.rs_e->e_attrs,
1289                 slap_schema.si_ad_userPassword )))
1290         {
1291                 assert( pa->a_vals != NULL );
1292                 assert( !BER_BVISNULL( &pa->a_vals[ 0 ] ) );
1293
1294                 if ( !BER_BVISNULL( &pa->a_vals[ 1 ] ) ) {
1295                         send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, "Password policy only allows one password value" );
1296                         return rs->sr_err;
1297                 }
1298
1299                 /*
1300                  * new entry contains a password - if we're not the root user
1301                  * then we need to check that the password fits in with the
1302                  * security policy for the new entry.
1303                  */
1304                 ppolicy_get( op, op->ora_e, &pp );
1305                 if (pp.pwdCheckQuality > 0 && !be_isroot( op )) {
1306                         struct berval *bv = &(pa->a_vals[0]);
1307                         int rc, send_ctrl = 0;
1308                         LDAPPasswordPolicyError pErr = PP_noError;
1309
1310                         /* Did we receive a password policy request control? */
1311                         if ( op->o_ctrlflag[ppolicy_cid] ) {
1312                                 send_ctrl = 1;
1313                         }
1314                         rc = check_password_quality( bv, &pp, &pErr, op->ora_e );
1315                         if (rc != LDAP_SUCCESS) {
1316                                 LDAPControl **oldctrls = NULL;
1317                                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1318                                 if ( send_ctrl ) {
1319                                         LDAPControl *ctrl = NULL;
1320                                         ctrl = create_passcontrol( -1, -1, pErr );
1321                                         oldctrls = add_passcontrol( op, rs, ctrl );
1322                                 }
1323                                 send_ldap_error( op, rs, rc, "Password fails quality checking policy" );
1324                                 if ( send_ctrl ) {
1325                                         ctrls_cleanup( op, rs, oldctrls );
1326                                 }
1327                                 return rs->sr_err;
1328                         }
1329                 }
1330                         /*
1331                          * A controversial bit. We hash cleartext
1332                          * passwords provided via add and modify operations
1333                          * You're not really supposed to do this, since
1334                          * the X.500 model says "store attributes" as they
1335                          * get provided. By default, this is what we do
1336                          *
1337                          * But if the hash_passwords flag is set, we hash
1338                          * any cleartext password attribute values via the
1339                          * default password hashing scheme.
1340                          */
1341                 if ((pi->hash_passwords) &&
1342                         (password_scheme( &(pa->a_vals[0]), NULL ) != LDAP_SUCCESS)) {
1343                         struct berval hpw;
1344
1345                         slap_passwd_hash( &(pa->a_vals[0]), &hpw, &txt );
1346                         if (hpw.bv_val == NULL) {
1347                                 /*
1348                                  * hashing didn't work. Emit an error.
1349                                  */
1350                                 rs->sr_err = LDAP_OTHER;
1351                                 rs->sr_text = txt;
1352                                 send_ldap_error( op, rs, LDAP_OTHER, "Password hashing failed" );
1353                                 return rs->sr_err;
1354                         }
1355
1356                         memset( pa->a_vals[0].bv_val, 0, pa->a_vals[0].bv_len);
1357                         ber_memfree( pa->a_vals[0].bv_val );
1358                         pa->a_vals[0].bv_val = hpw.bv_val;
1359                         pa->a_vals[0].bv_len = hpw.bv_len;
1360                 }
1361
1362                 /* If password aging is in effect, set the pwdChangedTime */
1363                 if ( pp.pwdMaxAge || pp.pwdMinAge ) {
1364                         struct berval timestamp;
1365                         char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
1366                         time_t now = slap_get_time();
1367
1368                         timestamp.bv_val = timebuf;
1369                         timestamp.bv_len = sizeof(timebuf);
1370                         slap_timestamp( &now, &timestamp );
1371
1372                         attr_merge_one( op->ora_e, ad_pwdChangedTime, &timestamp, &timestamp );
1373                 }
1374         }
1375         return SLAP_CB_CONTINUE;
1376 }
1377
1378 static int
1379 ppolicy_mod_cb( Operation *op, SlapReply *rs )
1380 {
1381         slap_callback *sc = op->o_callback;
1382         op->o_callback = sc->sc_next;
1383         if ( rs->sr_err == LDAP_SUCCESS ) {
1384                 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1385                 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1386         }
1387         op->o_tmpfree( sc, op->o_tmpmemctx );
1388         return SLAP_CB_CONTINUE;
1389 }
1390
1391 static int
1392 ppolicy_modify( Operation *op, SlapReply *rs )
1393 {
1394         slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
1395         pp_info                 *pi = on->on_bi.bi_private;
1396         int                     i, rc, mod_pw_only, pwmod, pwmop = -1, deladd,
1397                                 hsize = 0;
1398         PassPolicy              pp;
1399         Modifications           *mods = NULL, *modtail = NULL,
1400                                 *ml, *delmod, *addmod;
1401         Attribute               *pa, *ha, at;
1402         const char              *txt;
1403         pw_hist                 *tl = NULL, *p;
1404         int                     zapReset, send_ctrl = 0;
1405         Entry                   *e;
1406         struct berval           newpw = BER_BVNULL, oldpw = BER_BVNULL,
1407                                 *bv, cr[2];
1408         LDAPPasswordPolicyError pErr = PP_noError;
1409         LDAPControl             **oldctrls = NULL;
1410
1411         op->o_bd->bd_info = (BackendInfo *)on->on_info;
1412         rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1413         op->o_bd->bd_info = (BackendInfo *)on;
1414
1415         if ( rc != LDAP_SUCCESS ) return SLAP_CB_CONTINUE;
1416
1417         /* If this is a replica, we may need to tweak some of the
1418          * master's modifications. Otherwise, just pass it through.
1419          */
1420         if ( be_shadow_update( op )) {
1421                 Modifications **prev;
1422                 int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0;
1423                 Attribute *a_grace, *a_lock, *a_fail;
1424
1425                 a_grace = attr_find( e->e_attrs, ad_pwdGraceUseTime );
1426                 a_lock = attr_find( e->e_attrs, ad_pwdAccountLockedTime );
1427                 a_fail = attr_find( e->e_attrs, ad_pwdFailureTime );
1428
1429                 for( prev = &op->orm_modlist, ml = *prev; ml; ml = *prev ) {
1430
1431                         if ( ml->sml_desc == slap_schema.si_ad_userPassword )
1432                                 got_pw = 1;
1433
1434                         /* If we're deleting an attr that didn't exist,
1435                          * drop this delete op
1436                          */
1437                         if ( ml->sml_op == LDAP_MOD_DELETE ) {
1438                                 int drop = 0;
1439
1440                                 if ( ml->sml_desc == ad_pwdGraceUseTime ) {
1441                                         got_del_grace = 1;
1442                                         if ( !a_grace )
1443                                                 drop = 1;
1444                                 } else
1445                                 if ( ml->sml_desc == ad_pwdAccountLockedTime ) {
1446                                         got_del_lock = 1;
1447                                         if ( !a_lock )
1448                                                 drop = 1;
1449                                 } else
1450                                 if ( ml->sml_desc == ad_pwdFailureTime ) {
1451                                         got_del_fail = 1;
1452                                         if ( !a_fail )
1453                                                 drop = 1;
1454                                 }
1455                                 if ( drop ) {
1456                                         *prev = ml->sml_next;
1457                                         ml->sml_next = NULL;
1458                                         slap_mods_free( ml, 1 );
1459                                         continue;
1460                                 }
1461                         }
1462                         prev = &ml->sml_next;
1463                 }
1464
1465                 /* If we're resetting the password, make sure grace, accountlock,
1466                  * and failure also get removed.
1467                  */
1468                 if ( got_pw ) {
1469                         if ( a_grace && !got_del_grace ) {
1470                                 ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1471                                 ml->sml_op = LDAP_MOD_DELETE;
1472                                 ml->sml_flags = SLAP_MOD_INTERNAL;
1473                                 ml->sml_type.bv_val = NULL;
1474                                 ml->sml_desc = ad_pwdGraceUseTime;
1475                                 ml->sml_numvals = 0;
1476                                 ml->sml_values = NULL;
1477                                 ml->sml_nvalues = NULL;
1478                                 ml->sml_next = NULL;
1479                                 *prev = ml;
1480                                 prev = &ml->sml_next;
1481                         }
1482                         if ( a_lock && !got_del_lock ) {
1483                                 ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1484                                 ml->sml_op = LDAP_MOD_DELETE;
1485                                 ml->sml_flags = SLAP_MOD_INTERNAL;
1486                                 ml->sml_type.bv_val = NULL;
1487                                 ml->sml_desc = ad_pwdAccountLockedTime;
1488                                 ml->sml_numvals = 0;
1489                                 ml->sml_values = NULL;
1490                                 ml->sml_nvalues = NULL;
1491                                 ml->sml_next = NULL;
1492                                 *prev = ml;
1493                         }
1494                         if ( a_fail && !got_del_fail ) {
1495                                 ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
1496                                 ml->sml_op = LDAP_MOD_DELETE;
1497                                 ml->sml_flags = SLAP_MOD_INTERNAL;
1498                                 ml->sml_type.bv_val = NULL;
1499                                 ml->sml_desc = ad_pwdFailureTime;
1500                                 ml->sml_numvals = 0;
1501                                 ml->sml_values = NULL;
1502                                 ml->sml_nvalues = NULL;
1503                                 ml->sml_next = NULL;
1504                                 *prev = ml;
1505                         }
1506                 }
1507                 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1508                 be_entry_release_r( op, e );
1509                 return SLAP_CB_CONTINUE;
1510         }
1511
1512         /* Did we receive a password policy request control? */
1513         if ( op->o_ctrlflag[ppolicy_cid] ) {
1514                 send_ctrl = 1;
1515         }
1516
1517         /* See if this is a pwdModify exop. If so, we can
1518          * access the plaintext passwords from that request.
1519          */
1520         {
1521                 slap_callback *sc;
1522
1523                 for ( sc = op->o_callback; sc; sc=sc->sc_next ) {
1524                         if ( sc->sc_response == slap_null_cb &&
1525                                 sc->sc_private ) {
1526                                 req_pwdexop_s *qpw = sc->sc_private;
1527                                 newpw = qpw->rs_new;
1528                                 oldpw = qpw->rs_old;
1529                                 break;
1530                         }
1531                 }
1532         }
1533
1534         ppolicy_get( op, e, &pp );
1535
1536         for ( ml = op->orm_modlist,
1537                         pwmod = 0, mod_pw_only = 1,
1538                         deladd = 0, delmod = NULL,
1539                         addmod = NULL,
1540                         zapReset = 1;
1541                 ml != NULL; modtail = ml, ml = ml->sml_next )
1542         {
1543                 if ( ml->sml_desc == pp.ad ) {
1544                         pwmod = 1;
1545                         pwmop = ml->sml_op;
1546                         if ((deladd == 0) && (ml->sml_op == LDAP_MOD_DELETE) &&
1547                                 (ml->sml_values) && !BER_BVISNULL( &ml->sml_values[0] ))
1548                         {
1549                                 deladd = 1;
1550                                 delmod = ml;
1551                         }
1552
1553                         if ((ml->sml_op == LDAP_MOD_ADD) ||
1554                                 (ml->sml_op == LDAP_MOD_REPLACE))
1555                         {
1556                                 if ( ml->sml_values && !BER_BVISNULL( &ml->sml_values[0] )) {
1557                                         if ( deladd == 1 )
1558                                                 deladd = 2;
1559
1560                                         /* FIXME: there's no easy way to ensure
1561                                          * that add does not cause multiple
1562                                          * userPassword values; one way (that 
1563                                          * would be consistent with the single
1564                                          * password constraint) would be to turn
1565                                          * add into replace); another would be
1566                                          * to disallow add.
1567                                          *
1568                                          * Let's check at least that a single value
1569                                          * is being added
1570                                          */
1571                                         if ( addmod || !BER_BVISNULL( &ml->sml_values[ 1 ] ) ) {
1572                                                 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 
1573                                                 rs->sr_text = "Password policy only allows one password value";
1574                                                 goto return_results;
1575                                         }
1576
1577                                         addmod = ml;
1578                                 } else {
1579                                         /* replace can have no values, add cannot */
1580                                         assert( ml->sml_op == LDAP_MOD_REPLACE );
1581                                 }
1582                         }
1583
1584                 } else if ( !is_at_operational( ml->sml_desc->ad_type ) ) {
1585                         mod_pw_only = 0;
1586                         /* modifying something other than password */
1587                 }
1588
1589                 /*
1590                  * If there is a request to explicitly add a pwdReset
1591                  * attribute, then we suppress the normal behaviour on
1592                  * password change, which is to remove the pwdReset
1593                  * attribute.
1594                  *
1595                  * This enables an administrator to assign a new password
1596                  * and place a "must reset" flag on the entry, which will
1597                  * stay until the user explicitly changes his/her password.
1598                  */
1599                 if (ml->sml_desc == ad_pwdReset ) {
1600                         if ((ml->sml_op == LDAP_MOD_ADD) ||
1601                                 (ml->sml_op == LDAP_MOD_REPLACE))
1602                                 zapReset = 0;
1603                 }
1604         }
1605         
1606         if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) {
1607                 if ( dn_match( &op->o_conn->c_ndn,
1608                                 &pwcons[op->o_conn->c_conn_idx].dn )) {
1609                         Debug( LDAP_DEBUG_TRACE,
1610                                 "connection restricted to password changing only\n", 0, 0, 0 );
1611                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 
1612                         rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password";
1613                         pErr = PP_changeAfterReset;
1614                         goto return_results;
1615                 } else {
1616                         ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1617                         BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1618                 }
1619         }
1620
1621         /*
1622          * if we have a "safe password modify policy", then we need to check if we're doing
1623          * a delete (with the old password), followed by an add (with the new password).
1624          *
1625          * If we got just a delete with nothing else, just let it go. We also skip all the checks if
1626          * the root user is bound. Root can do anything, including avoid the policies.
1627          */
1628
1629         if (!pwmod) goto do_modify;
1630
1631         /*
1632          * Build the password history list in ascending time order
1633          * We need this, even if the user is root, in order to maintain
1634          * the pwdHistory operational attributes properly.
1635          */
1636         if (addmod && pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) {
1637                 struct berval oldpw;
1638                 time_t oldtime;
1639
1640                 for(i=0; ha->a_nvals[i].bv_val; i++) {
1641                         rc = parse_pwdhistory( &(ha->a_nvals[i]), NULL,
1642                                 &oldtime, &oldpw );
1643
1644                         if (rc != LDAP_SUCCESS) continue; /* invalid history entry */
1645
1646                         if (oldpw.bv_val) {
1647                                 add_to_pwd_history( &tl, oldtime, &oldpw,
1648                                         &(ha->a_nvals[i]) );
1649                                 oldpw.bv_val = NULL;
1650                                 oldpw.bv_len = 0;
1651                         }
1652                 }
1653                 for(p=tl; p; p=p->next, hsize++); /* count history size */
1654         }
1655
1656         if (be_isroot( op )) goto do_modify;
1657
1658         if (!pp.pwdAllowUserChange) {
1659                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1660                 rs->sr_text = "User alteration of password is not allowed";
1661                 pErr = PP_passwordModNotAllowed;
1662                 goto return_results;
1663         }
1664
1665         /* Just deleting? */
1666         if (!addmod) {
1667                 /* skip everything else */
1668                 pwmod = 0;
1669                 goto do_modify;
1670         }
1671
1672         /* This is a pwdModify exop that provided the old pw.
1673          * We need to create a Delete mod for this old pw and 
1674          * let the matching value get found later
1675          */
1676         if (pp.pwdSafeModify && oldpw.bv_val ) {
1677                 ml = (Modifications *)ch_calloc( sizeof( Modifications ), 1 );
1678                 ml->sml_op = LDAP_MOD_DELETE;
1679                 ml->sml_flags = SLAP_MOD_INTERNAL;
1680                 ml->sml_desc = pp.ad;
1681                 ml->sml_type = pp.ad->ad_cname;
1682                 ml->sml_numvals = 1;
1683                 ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1684                 ber_dupbv( &ml->sml_values[0], &oldpw );
1685                 BER_BVZERO( &ml->sml_values[1] );
1686                 ml->sml_next = op->orm_modlist;
1687                 op->orm_modlist = ml;
1688                 delmod = ml;
1689                 deladd = 2;
1690         }
1691
1692         if (pp.pwdSafeModify && deladd != 2) {
1693                 Debug( LDAP_DEBUG_TRACE,
1694                         "change password must use DELETE followed by ADD/REPLACE\n",
1695                         0, 0, 0 );
1696                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1697                 rs->sr_text = "Must supply old password to be changed as well as new one";
1698                 pErr = PP_mustSupplyOldPassword;
1699                 goto return_results;
1700         }
1701
1702         /* Check age, but only if pwdReset is not TRUE */
1703         pa = attr_find( e->e_attrs, ad_pwdReset );
1704         if ((!pa || !bvmatch( &pa->a_nvals[0], &slap_true_bv )) &&
1705                 pp.pwdMinAge > 0) {
1706                 time_t pwtime = (time_t)-1, now;
1707                 int age;
1708
1709                 if ((pa = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL)
1710                         pwtime = parse_time( pa->a_nvals[0].bv_val );
1711                 now = slap_get_time();
1712                 age = (int)(now - pwtime);
1713                 if ((pwtime != (time_t)-1) && (age < pp.pwdMinAge)) {
1714                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1715                         rs->sr_text = "Password is too young to change";
1716                         pErr = PP_passwordTooYoung;
1717                         goto return_results;
1718                 }
1719         }
1720
1721         /* pa is used in password history check below, be sure it's set */
1722         if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL && delmod) {
1723                 /*
1724                  * we have a password to check
1725                  */
1726                 const char *txt;
1727                 
1728                 bv = oldpw.bv_val ? &oldpw : delmod->sml_values;
1729                 /* FIXME: no access checking? */
1730                 rc = slap_passwd_check( op, NULL, pa, bv, &txt );
1731                 if (rc != LDAP_SUCCESS) {
1732                         Debug( LDAP_DEBUG_TRACE,
1733                                 "old password check failed: %s\n", txt, 0, 0 );
1734                         
1735                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1736                         rs->sr_text = "Must supply correct old password to change to new one";
1737                         pErr = PP_mustSupplyOldPassword;
1738                         goto return_results;
1739
1740                 } else {
1741                         int i;
1742                         
1743                         /*
1744                          * replace the delete value with the (possibly hashed)
1745                          * value which is currently in the password.
1746                          */
1747                         for ( i = 0; !BER_BVISNULL( &delmod->sml_values[i] ); i++ ) {
1748                                 free( delmod->sml_values[i].bv_val );
1749                                 BER_BVZERO( &delmod->sml_values[i] );
1750                         }
1751                         free( delmod->sml_values );
1752                         delmod->sml_values = ch_calloc( sizeof(struct berval), 2 );
1753                         BER_BVZERO( &delmod->sml_values[1] );
1754                         ber_dupbv( &(delmod->sml_values[0]),  &(pa->a_nvals[0]) );
1755                 }
1756         }
1757
1758         bv = newpw.bv_val ? &newpw : &addmod->sml_values[0];
1759         if (pp.pwdCheckQuality > 0) {
1760
1761                 rc = check_password_quality( bv, &pp, &pErr, e );
1762                 if (rc != LDAP_SUCCESS) {
1763                         rs->sr_err = rc;
1764                         rs->sr_text = "Password fails quality checking policy";
1765                         goto return_results;
1766                 }
1767         }
1768
1769         /* If pwdInHistory is zero, passwords may be reused */
1770         if (pa && pp.pwdInHistory > 0) {
1771                 /*
1772                  * Last check - the password history.
1773                  */
1774                 /* FIXME: no access checking? */
1775                 if (slap_passwd_check( op, NULL, pa, bv, &txt ) == LDAP_SUCCESS) {
1776                         /*
1777                          * This is bad - it means that the user is attempting
1778                          * to set the password to the same as the old one.
1779                          */
1780                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1781                         rs->sr_text = "Password is not being changed from existing value";
1782                         pErr = PP_passwordInHistory;
1783                         goto return_results;
1784                 }
1785         
1786                 /*
1787                  * Iterate through the password history, and fail on any
1788                  * password matches.
1789                  */
1790                 at = *pa;
1791                 at.a_vals = cr;
1792                 cr[1].bv_val = NULL;
1793                 for(p=tl; p; p=p->next) {
1794                         cr[0] = p->pw;
1795                         /* FIXME: no access checking? */
1796                         rc = slap_passwd_check( op, NULL, &at, bv, &txt );
1797                         
1798                         if (rc != LDAP_SUCCESS) continue;
1799                         
1800                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
1801                         rs->sr_text = "Password is in history of old passwords";
1802                         pErr = PP_passwordInHistory;
1803                         goto return_results;
1804                 }
1805         }
1806
1807 do_modify:
1808         if (pwmod) {
1809                 struct berval timestamp;
1810                 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
1811                 time_t now = slap_get_time();
1812
1813                 /* If the conn is restricted, set a callback to clear it
1814                  * if the pwmod succeeds
1815                  */
1816                 if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
1817                         slap_callback *sc = op->o_tmpcalloc( 1, sizeof( slap_callback ),
1818                                 op->o_tmpmemctx );
1819                         sc->sc_next = op->o_callback;
1820                         /* Must use sc_response to insure we reset on success, before
1821                          * the client sees the response. Must use sc_cleanup to insure
1822                          * that it gets cleaned up if sc_response is not called.
1823                          */
1824                         sc->sc_response = ppolicy_mod_cb;
1825                         sc->sc_cleanup = ppolicy_mod_cb;
1826                         op->o_callback = sc;
1827                 }
1828
1829                 /*
1830                  * keep the necessary pwd.. operational attributes
1831                  * up to date.
1832                  */
1833
1834                 timestamp.bv_val = timebuf;
1835                 timestamp.bv_len = sizeof(timebuf);
1836                 slap_timestamp( &now, &timestamp );
1837
1838                 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
1839                 mods->sml_desc = ad_pwdChangedTime;
1840                 if (pwmop != LDAP_MOD_DELETE) {
1841                         mods->sml_op = LDAP_MOD_REPLACE;
1842                         mods->sml_numvals = 1;
1843                         mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
1844                         ber_dupbv( &mods->sml_values[0], &timestamp );
1845                         BER_BVZERO( &mods->sml_values[1] );
1846                         assert( !BER_BVISNULL( &mods->sml_values[0] ) );
1847
1848                 } else {
1849                         mods->sml_op = LDAP_MOD_DELETE;
1850                 }
1851                 mods->sml_flags = SLAP_MOD_INTERNAL;
1852                 mods->sml_next = NULL;
1853                 modtail->sml_next = mods;
1854                 modtail = mods;
1855
1856                 if (attr_find(e->e_attrs, ad_pwdGraceUseTime )) {
1857                         mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
1858                         mods->sml_op = LDAP_MOD_DELETE;
1859                         mods->sml_desc = ad_pwdGraceUseTime;
1860                         mods->sml_flags = SLAP_MOD_INTERNAL;
1861                         mods->sml_next = NULL;
1862                         modtail->sml_next = mods;
1863                         modtail = mods;
1864                 }
1865
1866                 if (attr_find(e->e_attrs, ad_pwdAccountLockedTime )) {
1867                         mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
1868                         mods->sml_op = LDAP_MOD_DELETE;
1869                         mods->sml_desc = ad_pwdAccountLockedTime;
1870                         mods->sml_flags = SLAP_MOD_INTERNAL;
1871                         mods->sml_next = NULL;
1872                         modtail->sml_next = mods;
1873                         modtail = mods;
1874                 }
1875
1876                 if (attr_find(e->e_attrs, ad_pwdFailureTime )) {
1877                         mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
1878                         mods->sml_op = LDAP_MOD_DELETE;
1879                         mods->sml_desc = ad_pwdFailureTime;
1880                         mods->sml_flags = SLAP_MOD_INTERNAL;
1881                         mods->sml_next = NULL;
1882                         modtail->sml_next = mods;
1883                         modtail = mods;
1884                 }
1885
1886                 /* Delete the pwdReset attribute, since it's being reset */
1887                 if ((zapReset) && (attr_find(e->e_attrs, ad_pwdReset ))) {
1888                         mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
1889                         mods->sml_op = LDAP_MOD_DELETE;
1890                         mods->sml_desc = ad_pwdReset;
1891                         mods->sml_flags = SLAP_MOD_INTERNAL;
1892                         mods->sml_next = NULL;
1893                         modtail->sml_next = mods;
1894                         modtail = mods;
1895                 }
1896
1897                 if (pp.pwdInHistory > 0) {
1898                         if (hsize >= pp.pwdInHistory) {
1899                                 /*
1900                                  * We use the >= operator, since we are going to add
1901                                  * the existing password attribute value into the
1902                                  * history - thus the cardinality of history values is
1903                                  * about to rise by one.
1904                                  *
1905                                  * If this would push it over the limit of history
1906                                  * values (remembering - the password policy could have
1907                                  * changed since the password was last altered), we must
1908                                  * delete at least 1 value from the pwdHistory list.
1909                                  *
1910                                  * In fact, we delete '(#pwdHistory attrs - max pwd
1911                                  * history length) + 1' values, starting with the oldest.
1912                                  * This is easily evaluated, since the linked list is
1913                                  * created in ascending time order.
1914                                  */
1915                                 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
1916                                 mods->sml_op = LDAP_MOD_DELETE;
1917                                 mods->sml_flags = SLAP_MOD_INTERNAL;
1918                                 mods->sml_desc = ad_pwdHistory;
1919                                 mods->sml_numvals = hsize - pp.pwdInHistory + 1;
1920                                 mods->sml_values = ch_calloc( sizeof( struct berval ),
1921                                         hsize - pp.pwdInHistory + 2 );
1922                                 BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] );
1923                                 for(i=0,p=tl; i < (hsize - pp.pwdInHistory + 1); i++, p=p->next) {
1924                                         BER_BVZERO( &mods->sml_values[i] );
1925                                         ber_dupbv( &(mods->sml_values[i]), &p->bv );
1926                                 }
1927                                 mods->sml_next = NULL;
1928                                 modtail->sml_next = mods;
1929                                 modtail = mods;
1930                         }
1931                         free_pwd_history_list( &tl );
1932
1933                         /*
1934                          * Now add the existing password into the history list.
1935                          * This will be executed even if the operation is to delete
1936                          * the password entirely.
1937                          *
1938                          * This isn't in the spec explicitly, but it seems to make
1939                          * sense that the password history list is the list of all
1940                          * previous passwords - even if they were deleted. Thus, if
1941                          * someone tries to add a historical password at some future
1942                          * point, it will fail.
1943                          */
1944                         if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL) {
1945                                 mods = (Modifications *) ch_malloc( sizeof( Modifications ) );
1946                                 mods->sml_op = LDAP_MOD_ADD;
1947                                 mods->sml_flags = SLAP_MOD_INTERNAL;
1948                                 mods->sml_type.bv_val = NULL;
1949                                 mods->sml_desc = ad_pwdHistory;
1950                                 mods->sml_nvalues = NULL;
1951                                 mods->sml_numvals = 1;
1952                                 mods->sml_values = ch_calloc( sizeof( struct berval ), 2 );
1953                                 mods->sml_values[ 1 ].bv_val = NULL;
1954                                 mods->sml_values[ 1 ].bv_len = 0;
1955                                 make_pwd_history_value( timebuf, &mods->sml_values[0], pa );
1956                                 mods->sml_next = NULL;
1957                                 modtail->sml_next = mods;
1958                                 modtail = mods;
1959
1960                         } else {
1961                                 Debug( LDAP_DEBUG_TRACE,
1962                                 "ppolicy_modify: password attr lookup failed\n", 0, 0, 0 );
1963                         }
1964                 }
1965
1966                 /*
1967                  * Controversial bit here. If the new password isn't hashed
1968                  * (ie, is cleartext), we probably should hash it according
1969                  * to the default hash. The reason for this is that we want
1970                  * to use the policy if possible, but if we hash the password
1971                  * before, then we're going to run into trouble when it
1972                  * comes time to check the password.
1973                  *
1974                  * Now, the right thing to do is to use the extended password
1975                  * modify operation, but not all software can do this,
1976                  * therefore it makes sense to hash the new password, now
1977                  * we know it passes the policy requirements.
1978                  *
1979                  * Of course, if the password is already hashed, then we
1980                  * leave it alone.
1981                  */
1982
1983                 if ((pi->hash_passwords) && (addmod) && !newpw.bv_val && 
1984                         (password_scheme( &(addmod->sml_values[0]), NULL ) != LDAP_SUCCESS))
1985                 {
1986                         struct berval hpw, bv;
1987                         
1988                         slap_passwd_hash( &(addmod->sml_values[0]), &hpw, &txt );
1989                         if (hpw.bv_val == NULL) {
1990                                         /*
1991                                          * hashing didn't work. Emit an error.
1992                                          */
1993                                 rs->sr_err = LDAP_OTHER;
1994                                 rs->sr_text = txt;
1995                                 goto return_results;
1996                         }
1997                         bv = addmod->sml_values[0];
1998                                 /* clear and discard the clear password */
1999                         memset(bv.bv_val, 0, bv.bv_len);
2000                         ber_memfree(bv.bv_val);
2001                         addmod->sml_values[0] = hpw;
2002                 }
2003         }
2004         op->o_bd->bd_info = (BackendInfo *)on->on_info;
2005         be_entry_release_r( op, e );
2006         return SLAP_CB_CONTINUE;
2007
2008 return_results:
2009         free_pwd_history_list( &tl );
2010         op->o_bd->bd_info = (BackendInfo *)on->on_info;
2011         be_entry_release_r( op, e );
2012         if ( send_ctrl ) {
2013                 LDAPControl *ctrl = NULL;
2014
2015                 ctrl = create_passcontrol( -1, -1, pErr );
2016                 oldctrls = add_passcontrol( op, rs, ctrl );
2017         }
2018         send_ldap_result( op, rs );
2019         if ( send_ctrl ) {
2020                 ctrls_cleanup( op, rs, oldctrls );
2021         }
2022         return rs->sr_err;
2023 }
2024
2025 static int
2026 ppolicy_parseCtrl(
2027         Operation *op,
2028         SlapReply *rs,
2029         LDAPControl *ctrl )
2030 {
2031         if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
2032                 rs->sr_text = "passwordPolicyRequest control value not absent";
2033                 return LDAP_PROTOCOL_ERROR;
2034         }
2035         op->o_ctrlflag[ppolicy_cid] = ctrl->ldctl_iscritical
2036                 ? SLAP_CONTROL_CRITICAL
2037                 : SLAP_CONTROL_NONCRITICAL;
2038
2039         return LDAP_SUCCESS;
2040 }
2041
2042 static int
2043 attrPretty(
2044         Syntax *syntax,
2045         struct berval *val,
2046         struct berval *out,
2047         void *ctx )
2048 {
2049         AttributeDescription *ad = NULL;
2050         const char *err;
2051         int code;
2052
2053         code = slap_bv2ad( val, &ad, &err );
2054         if ( !code ) {
2055                 ber_dupbv_x( out, &ad->ad_type->sat_cname, ctx );
2056         }
2057         return code;
2058 }
2059
2060 static int
2061 attrNormalize(
2062         slap_mask_t use,
2063         Syntax *syntax,
2064         MatchingRule *mr,
2065         struct berval *val,
2066         struct berval *out,
2067         void *ctx )
2068 {
2069         AttributeDescription *ad = NULL;
2070         const char *err;
2071         int code;
2072
2073         code = slap_bv2ad( val, &ad, &err );
2074         if ( !code ) {
2075                 ber_str2bv_x( ad->ad_type->sat_oid, 0, 1, out, ctx );
2076         }
2077         return code;
2078 }
2079
2080 static int
2081 ppolicy_db_init(
2082         BackendDB *be,
2083         ConfigReply *cr
2084 )
2085 {
2086         slap_overinst *on = (slap_overinst *) be->bd_info;
2087
2088         /* Has User Schema been initialized yet? */
2089         if ( !pwd_UsSchema[0].ad[0] ) {
2090                 const char *err;
2091                 int i, code;
2092
2093                 for (i=0; pwd_UsSchema[i].def; i++) {
2094                         code = slap_str2ad( pwd_UsSchema[i].def, pwd_UsSchema[i].ad, &err );
2095                         if ( code ) {
2096                                 if ( cr ){
2097                                         snprintf( cr->msg, sizeof(cr->msg), 
2098                                                 "User Schema load failed for attribute \"%s\". Error code %d: %s",
2099                                                 pwd_UsSchema[i].def, code, err );
2100                                         fprintf( stderr, "%s\n", cr->msg );
2101                                 }
2102                                 return code;
2103                         }
2104                 }
2105                 {
2106                         Syntax *syn;
2107                         MatchingRule *mr;
2108
2109                         syn = ch_malloc( sizeof( Syntax ));
2110                         *syn = *ad_pwdAttribute->ad_type->sat_syntax;
2111                         syn->ssyn_pretty = attrPretty;
2112                         ad_pwdAttribute->ad_type->sat_syntax = syn;
2113
2114                         mr = ch_malloc( sizeof( MatchingRule ));
2115                         *mr = *ad_pwdAttribute->ad_type->sat_equality;
2116                         mr->smr_normalize = attrNormalize;
2117                         ad_pwdAttribute->ad_type->sat_equality = mr;
2118                 }
2119         }
2120
2121         on->on_bi.bi_private = ch_calloc( sizeof(pp_info), 1 );
2122
2123         if ( dtblsize && !pwcons ) {
2124                 /* accommodate for c_conn_idx == -1 */
2125                 pwcons = ch_calloc( sizeof(pw_conn), dtblsize + 1 );
2126                 pwcons++;
2127         }
2128
2129         return 0;
2130 }
2131
2132 static int
2133 ppolicy_db_open(
2134         BackendDB *be,
2135         ConfigReply *cr
2136 )
2137 {
2138         ov_count++;
2139         return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
2140 }
2141
2142 static int
2143 ppolicy_close(
2144         BackendDB *be,
2145         ConfigReply *cr
2146 )
2147 {
2148         slap_overinst *on = (slap_overinst *) be->bd_info;
2149         pp_info *pi = on->on_bi.bi_private;
2150
2151         /* Perhaps backover should provide bi_destroy hooks... */
2152         ov_count--;
2153         if ( ov_count <=0 && pwcons ) {
2154                 pwcons--;
2155                 free( pwcons );
2156                 pwcons = NULL;
2157         }
2158         free( pi->def_policy.bv_val );
2159         free( pi );
2160
2161         return 0;
2162 }
2163
2164 static char *extops[] = {
2165         LDAP_EXOP_MODIFY_PASSWD,
2166         NULL
2167 };
2168
2169 static slap_overinst ppolicy;
2170
2171 int ppolicy_initialize()
2172 {
2173         int i, code;
2174
2175         for (i=0; pwd_OpSchema[i].def; i++) {
2176                 code = register_at( pwd_OpSchema[i].def, pwd_OpSchema[i].ad, 0 );
2177                 if ( code ) {
2178                         Debug( LDAP_DEBUG_ANY,
2179                                 "ppolicy_initialize: register_at failed\n", 0, 0, 0 );
2180                         return code;
2181                 }
2182                 /* Allow Manager to set these as needed */
2183                 if ( is_at_no_user_mod( (*pwd_OpSchema[i].ad)->ad_type )) {
2184                         (*pwd_OpSchema[i].ad)->ad_type->sat_flags |=
2185                                 SLAP_AT_MANAGEABLE;
2186                 }
2187         }
2188
2189         code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
2190                 SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, extops,
2191                 ppolicy_parseCtrl, &ppolicy_cid );
2192         if ( code != LDAP_SUCCESS ) {
2193                 fprintf( stderr, "Failed to register control %d\n", code );
2194                 return code;
2195         }
2196
2197         ldap_pvt_thread_mutex_init( &chk_syntax_mutex );
2198
2199         ppolicy.on_bi.bi_type = "ppolicy";
2200         ppolicy.on_bi.bi_db_init = ppolicy_db_init;
2201         ppolicy.on_bi.bi_db_open = ppolicy_db_open;
2202         ppolicy.on_bi.bi_db_close = ppolicy_close;
2203
2204         ppolicy.on_bi.bi_op_add = ppolicy_add;
2205         ppolicy.on_bi.bi_op_bind = ppolicy_bind;
2206         ppolicy.on_bi.bi_op_compare = ppolicy_restrict;
2207         ppolicy.on_bi.bi_op_delete = ppolicy_restrict;
2208         ppolicy.on_bi.bi_op_modify = ppolicy_modify;
2209         ppolicy.on_bi.bi_op_search = ppolicy_restrict;
2210         ppolicy.on_bi.bi_connection_destroy = ppolicy_connection_destroy;
2211
2212         ppolicy.on_bi.bi_cf_ocs = ppolicyocs;
2213         code = config_register_schema( ppolicycfg, ppolicyocs );
2214         if ( code ) return code;
2215
2216         return overlay_register( &ppolicy );
2217 }
2218
2219 #if SLAPD_OVER_PPOLICY == SLAPD_MOD_DYNAMIC
2220 int init_module(int argc, char *argv[]) {
2221         return ppolicy_initialize();
2222 }
2223 #endif
2224
2225 #endif  /* defined(SLAPD_OVER_PPOLICY) */