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