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