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