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