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