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