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