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