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