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