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