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