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