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