1 /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/ppolicy.c,v 1.75.2.14 2008/07/10 00:55:07 quanah Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2004-2008 The OpenLDAP Foundation.
5 * Portions Copyright 2004-2005 Howard Chu, Symas Corporation.
6 * Portions Copyright 2004 Hewlett-Packard Company.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
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>.
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.
25 /* This file implements "Password Policy for LDAP Directories",
26 * based on draft behera-ldap-password-policy-09
29 #ifdef SLAPD_OVER_PPOLICY
35 #define LIBLTDL_DLL_IMPORT /* Win32: don't re-export libltdl's symbols */
40 #include <ac/string.h>
44 #ifndef MODULE_NAME_SZ
45 #define MODULE_NAME_SZ 256
48 /* Per-instance configuration information */
49 typedef struct pp_info
{
50 struct berval def_policy
; /* DN of default policy subentry */
51 int use_lockout
; /* send AccountLocked result? */
52 int hash_passwords
; /* transparently hash cleartext pwds */
55 /* Our per-connection info - note, it is not per-instance, it is
56 * used by all instances
58 typedef struct pw_conn
{
59 struct berval dn
; /* DN of restricted user */
62 static pw_conn
*pwcons
;
63 static int ppolicy_cid
;
66 typedef struct pass_policy
{
67 AttributeDescription
*ad
; /* attribute to which the policy applies */
68 int pwdMinAge
; /* minimum time (seconds) until passwd can change */
69 int pwdMaxAge
; /* time in seconds until pwd will expire after change */
70 int pwdInHistory
; /* number of previous passwords kept */
71 int pwdCheckQuality
; /* 0 = don't check quality, 1 = check if possible,
72 2 = check mandatory; fail if not possible */
73 int pwdMinLength
; /* minimum number of chars in password */
74 int pwdExpireWarning
; /* number of seconds that warning controls are
75 sent before a password expires */
76 int pwdGraceAuthNLimit
; /* number of times you can log in with an
78 int pwdLockout
; /* 0 = do not lockout passwords, 1 = lock them out */
79 int pwdLockoutDuration
; /* time in seconds a password is locked out for */
80 int pwdMaxFailure
; /* number of failed binds allowed before lockout */
81 int pwdFailureCountInterval
; /* number of seconds before failure
83 int pwdMustChange
; /* 0 = users can use admin set password
84 1 = users must change password after admin set */
85 int pwdAllowUserChange
; /* 0 = users cannot change their passwords
86 1 = users can change them */
87 int pwdSafeModify
; /* 0 = old password doesn't need to come
88 with password change request
89 1 = password change must supply existing pwd */
90 char pwdCheckModule
[MODULE_NAME_SZ
]; /* name of module to dynamically
91 load to check password */
94 typedef struct pw_hist
{
95 time_t t
; /* timestamp of history entry */
96 struct berval pw
; /* old password hash */
97 struct berval bv
; /* text of entire entry */
101 /* Operational attributes */
102 static AttributeDescription
*ad_pwdChangedTime
, *ad_pwdAccountLockedTime
,
103 *ad_pwdFailureTime
, *ad_pwdHistory
, *ad_pwdGraceUseTime
, *ad_pwdReset
,
104 *ad_pwdPolicySubentry
;
106 static struct schema_info
{
108 AttributeDescription
**ad
;
110 { "( 1.3.6.1.4.1.42.2.27.8.1.16 "
111 "NAME ( 'pwdChangedTime' ) "
112 "DESC 'The time the password was last changed' "
113 "EQUALITY generalizedTimeMatch "
114 "ORDERING generalizedTimeOrderingMatch "
115 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
116 "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
117 &ad_pwdChangedTime
},
118 { "( 1.3.6.1.4.1.42.2.27.8.1.17 "
119 "NAME ( 'pwdAccountLockedTime' ) "
120 "DESC 'The time an user account was locked' "
121 "EQUALITY generalizedTimeMatch "
122 "ORDERING generalizedTimeOrderingMatch "
123 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
126 /* Not until Relax control is released */
127 "NO-USER-MODIFICATION "
129 "USAGE directoryOperation )",
130 &ad_pwdAccountLockedTime
},
131 { "( 1.3.6.1.4.1.42.2.27.8.1.19 "
132 "NAME ( 'pwdFailureTime' ) "
133 "DESC 'The timestamps of the last consecutive authentication failures' "
134 "EQUALITY generalizedTimeMatch "
135 "ORDERING generalizedTimeOrderingMatch "
136 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
137 "NO-USER-MODIFICATION USAGE directoryOperation )",
138 &ad_pwdFailureTime
},
139 { "( 1.3.6.1.4.1.42.2.27.8.1.20 "
140 "NAME ( 'pwdHistory' ) "
141 "DESC 'The history of users passwords' "
142 "EQUALITY octetStringMatch "
143 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 "
144 "NO-USER-MODIFICATION USAGE directoryOperation )",
146 { "( 1.3.6.1.4.1.42.2.27.8.1.21 "
147 "NAME ( 'pwdGraceUseTime' ) "
148 "DESC 'The timestamps of the grace login once the password has expired' "
149 "EQUALITY generalizedTimeMatch "
150 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
151 "NO-USER-MODIFICATION USAGE directoryOperation )",
152 &ad_pwdGraceUseTime
},
153 { "( 1.3.6.1.4.1.42.2.27.8.1.22 "
154 "NAME ( 'pwdReset' ) "
155 "DESC 'The indication that the password has been reset' "
156 "EQUALITY booleanMatch "
157 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
158 "SINGLE-VALUE USAGE directoryOperation )",
160 { "( 1.3.6.1.4.1.42.2.27.8.1.23 "
161 "NAME ( 'pwdPolicySubentry' ) "
162 "DESC 'The pwdPolicy subentry in effect for this object' "
163 "EQUALITY distinguishedNameMatch "
164 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
167 /* Not until Relax control is released */
168 "NO-USER-MODIFICATION "
170 "USAGE directoryOperation )",
171 &ad_pwdPolicySubentry
},
175 /* User attributes */
176 static AttributeDescription
*ad_pwdMinAge
, *ad_pwdMaxAge
, *ad_pwdInHistory
,
177 *ad_pwdCheckQuality
, *ad_pwdMinLength
, *ad_pwdMaxFailure
,
178 *ad_pwdGraceAuthNLimit
, *ad_pwdExpireWarning
, *ad_pwdLockoutDuration
,
179 *ad_pwdFailureCountInterval
, *ad_pwdCheckModule
, *ad_pwdLockout
,
180 *ad_pwdMustChange
, *ad_pwdAllowUserChange
, *ad_pwdSafeModify
,
183 #define TAB(name) { #name, &ad_##name }
185 static struct schema_info pwd_UsSchema
[] = {
190 TAB(pwdCheckQuality
),
193 TAB(pwdGraceAuthNLimit
),
194 TAB(pwdExpireWarning
),
196 TAB(pwdLockoutDuration
),
197 TAB(pwdFailureCountInterval
),
200 TAB(pwdAllowUserChange
),
205 static ldap_pvt_thread_mutex_t chk_syntax_mutex
;
209 PPOLICY_HASH_CLEARTEXT
,
213 static ConfigDriver ppolicy_cf_default
;
215 static ConfigTable ppolicycfg
[] = {
216 { "ppolicy_default", "policyDN", 2, 2, 0,
217 ARG_DN
|ARG_QUOTE
|ARG_MAGIC
|PPOLICY_DEFAULT
, ppolicy_cf_default
,
218 "( OLcfgOvAt:12.1 NAME 'olcPPolicyDefault' "
219 "DESC 'DN of a pwdPolicy object for uncustomized objects' "
220 "SYNTAX OMsDN SINGLE-VALUE )", NULL
, NULL
},
221 { "ppolicy_hash_cleartext", "on|off", 1, 2, 0,
222 ARG_ON_OFF
|ARG_OFFSET
|PPOLICY_HASH_CLEARTEXT
,
223 (void *)offsetof(pp_info
,hash_passwords
),
224 "( OLcfgOvAt:12.2 NAME 'olcPPolicyHashCleartext' "
225 "DESC 'Hash passwords on add or modify' "
226 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL
, NULL
},
227 { "ppolicy_use_lockout", "on|off", 1, 2, 0,
228 ARG_ON_OFF
|ARG_OFFSET
|PPOLICY_USE_LOCKOUT
,
229 (void *)offsetof(pp_info
,use_lockout
),
230 "( OLcfgOvAt:12.3 NAME 'olcPPolicyUseLockout' "
231 "DESC 'Warn clients with AccountLocked' "
232 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL
, NULL
},
233 { NULL
, NULL
, 0, 0, 0, ARG_IGNORED
}
236 static ConfigOCs ppolicyocs
[] = {
237 { "( OLcfgOvOc:12.1 "
238 "NAME 'olcPPolicyConfig' "
239 "DESC 'Password Policy configuration' "
240 "SUP olcOverlayConfig "
241 "MAY ( olcPPolicyDefault $ olcPPolicyHashCleartext $ "
242 "olcPPolicyUseLockout ) )",
243 Cft_Overlay
, ppolicycfg
},
248 ppolicy_cf_default( ConfigArgs
*c
)
250 slap_overinst
*on
= (slap_overinst
*)c
->bi
;
251 pp_info
*pi
= (pp_info
*)on
->on_bi
.bi_private
;
252 int rc
= ARG_BAD_CONF
;
254 assert ( c
->type
== PPOLICY_DEFAULT
);
255 Debug(LDAP_DEBUG_TRACE
, "==> ppolicy_cf_default\n", 0, 0, 0);
258 case SLAP_CONFIG_EMIT
:
259 Debug(LDAP_DEBUG_TRACE
, "==> ppolicy_cf_default emit\n", 0, 0, 0);
261 if ( !BER_BVISEMPTY( &pi
->def_policy
)) {
262 rc
= value_add_one( &c
->rvalue_vals
,
265 rc
= value_add_one( &c
->rvalue_nvals
,
269 case LDAP_MOD_DELETE
:
270 Debug(LDAP_DEBUG_TRACE
, "==> ppolicy_cf_default delete\n", 0, 0, 0);
271 if ( pi
->def_policy
.bv_val
) {
272 ber_memfree ( pi
->def_policy
.bv_val
);
273 pi
->def_policy
.bv_val
= NULL
;
275 pi
->def_policy
.bv_len
= 0;
278 case SLAP_CONFIG_ADD
:
279 /* fallthrough to LDAP_MOD_ADD */
281 Debug(LDAP_DEBUG_TRACE
, "==> ppolicy_cf_default add\n", 0, 0, 0);
282 if ( pi
->def_policy
.bv_val
) {
283 ber_memfree ( pi
->def_policy
.bv_val
);
285 pi
->def_policy
= c
->value_ndn
;
286 ber_memfree( c
->value_dn
.bv_val
);
287 BER_BVZERO( &c
->value_dn
);
288 BER_BVZERO( &c
->value_ndn
);
299 parse_time( char *atm
)
302 struct lutil_timet tt
;
303 time_t ret
= (time_t)-1;
305 if ( lutil_parsetime( atm
, &tm
) == 0) {
306 lutil_tm2time( &tm
, &tt
);
313 account_locked( Operation
*op
, Entry
*e
,
314 PassPolicy
*pp
, Modifications
**mod
)
320 if ( (la
= attr_find( e
->e_attrs
, ad_pwdAccountLockedTime
)) != NULL
) {
321 BerVarray vals
= la
->a_nvals
;
324 * there is a lockout stamp - we now need to know if it's
327 if (vals
[0].bv_val
!= NULL
) {
331 if (!pp
->pwdLockoutDuration
)
334 if ((then
= parse_time( vals
[0].bv_val
)) == (time_t)0)
337 now
= slap_get_time();
339 if (now
< then
+ pp
->pwdLockoutDuration
)
342 m
= ch_calloc( sizeof(Modifications
), 1 );
343 m
->sml_op
= LDAP_MOD_DELETE
;
345 m
->sml_type
= ad_pwdAccountLockedTime
->ad_cname
;
346 m
->sml_desc
= ad_pwdAccountLockedTime
;
355 /* IMPLICIT TAGS, all context-specific */
356 #define PPOLICY_WARNING 0xa0L /* constructed + 0 */
357 #define PPOLICY_ERROR 0x81L /* primitive + 1 */
359 #define PPOLICY_EXPIRE 0x80L /* primitive + 0 */
360 #define PPOLICY_GRACE 0x81L /* primitive + 1 */
362 static const char ppolicy_ctrl_oid
[] = LDAP_CONTROL_PASSWORDPOLICYRESPONSE
;
365 create_passcontrol( int exptime
, int grace
, LDAPPasswordPolicyError err
)
367 char berbuf
[LBER_ELEMENT_SIZEOF
], bb2
[LBER_ELEMENT_SIZEOF
];
368 BerElement
*ber
= (BerElement
*)berbuf
, *b2
= (BerElement
*)bb2
;
372 c
= ch_calloc( sizeof( LDAPControl
), 1 );
376 c
->ldctl_oid
= (char *)ppolicy_ctrl_oid
;
377 c
->ldctl_iscritical
= 0;
378 BER_BVZERO( &c
->ldctl_value
);
380 ber_init2( ber
, NULL
, LBER_USE_DER
);
381 ber_printf( ber
, "{" /*}*/ );
383 if ( exptime
>= 0 ) {
384 ber_init2( b2
, NULL
, LBER_USE_DER
);
385 ber_printf( b2
, "ti", PPOLICY_EXPIRE
, exptime
);
386 ber_flatten2( b2
, &bv
, 1 );
387 (void)ber_free_buf(b2
);
388 ber_printf( ber
, "tO", PPOLICY_WARNING
, &bv
);
389 ch_free( bv
.bv_val
);
390 } else if ( grace
> 0 ) {
391 ber_init2( b2
, NULL
, LBER_USE_DER
);
392 ber_printf( b2
, "ti", PPOLICY_GRACE
, grace
);
393 ber_flatten2( b2
, &bv
, 1 );
394 (void)ber_free_buf(b2
);
395 ber_printf( ber
, "tO", PPOLICY_WARNING
, &bv
);
396 ch_free( bv
.bv_val
);
399 if (err
!= PP_noError
) {
400 ber_printf( ber
, "te", PPOLICY_ERROR
, err
);
402 ber_printf( ber
, /*{*/ "N}" );
404 if (ber_flatten2( ber
, &(c
->ldctl_value
), 1 ) == LBER_DEFAULT
) {
408 (void)ber_free_buf(ber
);
412 static LDAPControl
**
413 add_passcontrol( Operation
*op
, SlapReply
*rs
, LDAPControl
*ctrl
)
415 LDAPControl
**ctrls
, **oldctrls
= rs
->sr_ctrls
;
420 for ( ; oldctrls
[n
]; n
++ )
425 ctrls
= op
->o_tmpcalloc( sizeof( LDAPControl
* ), n
, op
->o_tmpmemctx
);
429 for ( ; oldctrls
[n
]; n
++ ) {
430 ctrls
[n
] = oldctrls
[n
];
436 rs
->sr_ctrls
= ctrls
;
442 ppolicy_get( Operation
*op
, Entry
*e
, PassPolicy
*pp
)
444 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
445 pp_info
*pi
= on
->on_bi
.bi_private
;
454 memset( pp
, 0, sizeof(PassPolicy
) );
456 pp
->ad
= slap_schema
.si_ad_userPassword
;
458 /* Users can change their own password by default */
459 pp
->pwdAllowUserChange
= 1;
461 if ((a
= attr_find( e
->e_attrs
, ad_pwdPolicySubentry
)) == NULL
) {
463 * entry has no password policy assigned - use default
465 vals
= &pi
->def_policy
;
470 if (vals
[0].bv_val
== NULL
) {
471 Debug( LDAP_DEBUG_ANY
,
472 "ppolicy_get: NULL value for policySubEntry\n", 0, 0, 0 );
477 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
478 rc
= be_entry_get_rw( op
, vals
, NULL
, NULL
, 0, &pe
);
479 op
->o_bd
->bd_info
= (BackendInfo
*)on
;
481 if ( rc
) goto defaultpol
;
483 #if 0 /* Only worry about userPassword for now */
484 if ((a
= attr_find( pe
->e_attrs
, ad_pwdAttribute
)))
485 slap_bv2ad( &a
->a_vals
[0], &pp
->ad
, &text
);
488 if ( ( a
= attr_find( pe
->e_attrs
, ad_pwdMinAge
) )
489 && lutil_atoi( &pp
->pwdMinAge
, a
->a_vals
[0].bv_val
) != 0 )
491 if ( ( a
= attr_find( pe
->e_attrs
, ad_pwdMaxAge
) )
492 && lutil_atoi( &pp
->pwdMaxAge
, a
->a_vals
[0].bv_val
) != 0 )
494 if ( ( a
= attr_find( pe
->e_attrs
, ad_pwdInHistory
) )
495 && lutil_atoi( &pp
->pwdInHistory
, a
->a_vals
[0].bv_val
) != 0 )
497 if ( ( a
= attr_find( pe
->e_attrs
, ad_pwdCheckQuality
) )
498 && lutil_atoi( &pp
->pwdCheckQuality
, a
->a_vals
[0].bv_val
) != 0 )
500 if ( ( a
= attr_find( pe
->e_attrs
, ad_pwdMinLength
) )
501 && lutil_atoi( &pp
->pwdMinLength
, a
->a_vals
[0].bv_val
) != 0 )
503 if ( ( a
= attr_find( pe
->e_attrs
, ad_pwdMaxFailure
) )
504 && lutil_atoi( &pp
->pwdMaxFailure
, a
->a_vals
[0].bv_val
) != 0 )
506 if ( ( a
= attr_find( pe
->e_attrs
, ad_pwdGraceAuthNLimit
) )
507 && lutil_atoi( &pp
->pwdGraceAuthNLimit
, a
->a_vals
[0].bv_val
) != 0 )
509 if ( ( a
= attr_find( pe
->e_attrs
, ad_pwdExpireWarning
) )
510 && lutil_atoi( &pp
->pwdExpireWarning
, a
->a_vals
[0].bv_val
) != 0 )
512 if ( ( a
= attr_find( pe
->e_attrs
, ad_pwdFailureCountInterval
) )
513 && lutil_atoi( &pp
->pwdFailureCountInterval
, a
->a_vals
[0].bv_val
) != 0 )
515 if ( ( a
= attr_find( pe
->e_attrs
, ad_pwdLockoutDuration
) )
516 && lutil_atoi( &pp
->pwdLockoutDuration
, a
->a_vals
[0].bv_val
) != 0 )
519 if ( ( a
= attr_find( pe
->e_attrs
, ad_pwdCheckModule
) ) ) {
520 strncpy( pp
->pwdCheckModule
, a
->a_vals
[0].bv_val
,
521 sizeof(pp
->pwdCheckModule
) );
522 pp
->pwdCheckModule
[sizeof(pp
->pwdCheckModule
)-1] = '\0';
525 if ((a
= attr_find( pe
->e_attrs
, ad_pwdLockout
)))
526 pp
->pwdLockout
= bvmatch( &a
->a_nvals
[0], &slap_true_bv
);
527 if ((a
= attr_find( pe
->e_attrs
, ad_pwdMustChange
)))
528 pp
->pwdMustChange
= bvmatch( &a
->a_nvals
[0], &slap_true_bv
);
529 if ((a
= attr_find( pe
->e_attrs
, ad_pwdAllowUserChange
)))
530 pp
->pwdAllowUserChange
= bvmatch( &a
->a_nvals
[0], &slap_true_bv
);
531 if ((a
= attr_find( pe
->e_attrs
, ad_pwdSafeModify
)))
532 pp
->pwdSafeModify
= bvmatch( &a
->a_nvals
[0], &slap_true_bv
);
534 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
535 be_entry_release_r( op
, pe
);
536 op
->o_bd
->bd_info
= (BackendInfo
*)on
;
541 Debug( LDAP_DEBUG_TRACE
,
542 "ppolicy_get: using default policy\n", 0, 0, 0 );
547 password_scheme( struct berval
*cred
, struct berval
*sch
)
551 assert( cred
!= NULL
);
558 if ((cred
->bv_len
== 0) || (cred
->bv_val
== NULL
) ||
559 (cred
->bv_val
[0] != '{')) return LDAP_OTHER
;
561 for(e
= 1; cred
->bv_val
[e
] && cred
->bv_val
[e
] != '}'; e
++);
562 if (cred
->bv_val
[e
]) {
564 rc
= lutil_passwd_scheme( cred
->bv_val
);
567 sch
->bv_val
= cred
->bv_val
;
577 check_password_quality( struct berval
*cred
, PassPolicy
*pp
, LDAPPasswordPolicyError
*err
, Entry
*e
)
579 int rc
= LDAP_SUCCESS
, ok
= LDAP_SUCCESS
;
580 char *ptr
= cred
->bv_val
;
583 assert( cred
!= NULL
);
584 assert( pp
!= NULL
);
586 if ((cred
->bv_len
== 0) || (pp
->pwdMinLength
> cred
->bv_len
)) {
587 rc
= LDAP_CONSTRAINT_VIOLATION
;
588 if ( err
) *err
= PP_passwordTooShort
;
593 * We need to know if the password is already hashed - if so
594 * what scheme is it. The reason being that the "hash" of
595 * {cleartext} still allows us to check the password.
597 rc
= password_scheme( cred
, &sch
);
598 if (rc
== LDAP_SUCCESS
) {
599 if ((sch
.bv_val
) && (strncasecmp( sch
.bv_val
, "{cleartext}",
600 sch
.bv_len
) == 0)) {
602 * We can check the cleartext "hash"
604 ptr
= cred
->bv_val
+ sch
.bv_len
;
606 /* everything else, we can't check */
607 if (pp
->pwdCheckQuality
== 2) {
608 rc
= LDAP_CONSTRAINT_VIOLATION
;
609 if (err
) *err
= PP_insufficientPasswordQuality
;
613 * We can't check the syntax of the password, but it's not
614 * mandatory (according to the policy), so we return success.
623 if (pp
->pwdCheckModule
[0]) {
628 if ((mod
= lt_dlopen( pp
->pwdCheckModule
)) == NULL
) {
631 Debug(LDAP_DEBUG_ANY
,
632 "check_password_quality: lt_dlopen failed: (%s) %s.\n",
633 pp
->pwdCheckModule
, err
, 0 );
634 ok
= LDAP_OTHER
; /* internal error */
636 int (*prog
)( char *passwd
, char **text
, Entry
*ent
);
638 if ((prog
= lt_dlsym( mod
, "check_password" )) == NULL
) {
641 Debug(LDAP_DEBUG_ANY
,
642 "check_password_quality: lt_dlsym failed: (%s) %s.\n",
643 pp
->pwdCheckModule
, err
, 0 );
648 ldap_pvt_thread_mutex_lock( &chk_syntax_mutex
);
649 ok
= prog( cred
->bv_val
, &txt
, e
);
650 ldap_pvt_thread_mutex_unlock( &chk_syntax_mutex
);
651 if (ok
!= LDAP_SUCCESS
) {
652 Debug(LDAP_DEBUG_ANY
,
653 "check_password_quality: module error: (%s) %s.[%d]\n",
654 pp
->pwdCheckModule
, txt
? txt
: "", ok
);
662 Debug(LDAP_DEBUG_ANY
, "check_password_quality: external modules not "
663 "supported. pwdCheckModule ignored.\n", 0, 0, 0);
664 #endif /* SLAPD_MODULES */
668 if (ok
!= LDAP_SUCCESS
) {
669 rc
= LDAP_CONSTRAINT_VIOLATION
;
670 if (err
) *err
= PP_insufficientPasswordQuality
;
677 parse_pwdhistory( struct berval
*bv
, char **oid
, time_t *oldtime
, struct berval
*oldpw
)
680 struct berval nv
, npw
;
683 assert (bv
&& (bv
->bv_len
> 0) && (bv
->bv_val
) && oldtime
&& oldpw
);
688 *oldtime
= (time_t)-1;
691 ber_dupbv( &nv
, bv
);
693 /* first get the time field */
694 for ( i
= 0; (i
< nv
.bv_len
) && (nv
.bv_val
[i
] != '#'); i
++ )
696 if ( i
== nv
.bv_len
) {
697 goto exit_failure
; /* couldn't locate the '#' separator */
699 nv
.bv_val
[i
++] = '\0'; /* terminate the string & move to next field */
701 *oldtime
= parse_time( ptr
);
702 if (*oldtime
== (time_t)-1) {
706 /* get the OID field */
707 for (ptr
= &(nv
.bv_val
[i
]); (i
< nv
.bv_len
) && (nv
.bv_val
[i
] != '#'); i
++ )
709 if ( i
== nv
.bv_len
) {
710 goto exit_failure
; /* couldn't locate the '#' separator */
712 nv
.bv_val
[i
++] = '\0'; /* terminate the string & move to next field */
714 *oid
= ber_strdup( ptr
);
717 /* get the length field */
718 for ( ptr
= &(nv
.bv_val
[i
]); (i
< nv
.bv_len
) && (nv
.bv_val
[i
] != '#'); i
++ )
720 if ( i
== nv
.bv_len
) {
721 goto exit_failure
; /* couldn't locate the '#' separator */
723 nv
.bv_val
[i
++] = '\0'; /* terminate the string & move to next field */
724 oldpw
->bv_len
= strtol( ptr
, NULL
, 10 );
725 if (errno
== ERANGE
) {
729 /* lastly, get the octets of the string */
730 for ( j
= i
, ptr
= &(nv
.bv_val
[i
]); i
< nv
.bv_len
; i
++ )
732 if ( i
- j
!= oldpw
->bv_len
) {
733 goto exit_failure
; /* length is wrong */
737 npw
.bv_len
= oldpw
->bv_len
;
738 ber_dupbv( oldpw
, &npw
);
739 ber_memfree( nv
.bv_val
);
748 if ( oldpw
->bv_val
) {
749 ber_memfree( oldpw
->bv_val
);
752 ber_memfree( nv
.bv_val
);
758 add_to_pwd_history( pw_hist
**l
, time_t t
,
759 struct berval
*oldpw
, struct berval
*bv
)
761 pw_hist
*p
, *p1
, *p2
;
765 p
= ch_malloc( sizeof( pw_hist
));
767 ber_dupbv( &p
->bv
, bv
);
772 /* degenerate case */
777 * advance p1 and p2 such that p1 is the node before the
778 * new one, and p2 is the node after it
780 for (p1
= NULL
, p2
= *l
; p2
&& p2
->t
<= t
; p1
= p2
, p2
=p2
->next
);
782 if (p1
== NULL
) { *l
= p
; return; }
786 #ifndef MAX_PWD_HISTORY_SZ
787 #define MAX_PWD_HISTORY_SZ 1024
788 #endif /* MAX_PWD_HISTORY_SZ */
791 make_pwd_history_value( char *timebuf
, struct berval
*bv
, Attribute
*pa
)
793 char str
[ MAX_PWD_HISTORY_SZ
];
796 snprintf( str
, MAX_PWD_HISTORY_SZ
,
797 "%s#%s#%lu#", timebuf
,
798 pa
->a_desc
->ad_type
->sat_syntax
->ssyn_oid
,
799 (unsigned long) pa
->a_nvals
[0].bv_len
);
800 str
[MAX_PWD_HISTORY_SZ
-1] = 0;
804 * We have to assume that the string is a string of octets,
805 * not readable characters. In reality, yes, it probably is
806 * a readable (ie, base64) string, but we can't count on that
807 * Hence, while the first 3 fields of the password history
808 * are definitely readable (a timestamp, an OID and an integer
809 * length), the remaining octets of the actual password
810 * are deemed to be binary data.
812 AC_MEMCPY( str
+ nlen
, pa
->a_nvals
[0].bv_val
, pa
->a_nvals
[0].bv_len
);
813 nlen
+= pa
->a_nvals
[0].bv_len
;
814 bv
->bv_val
= ch_malloc( nlen
+ 1 );
815 AC_MEMCPY( bv
->bv_val
, str
, nlen
);
816 bv
->bv_val
[nlen
] = '\0';
821 free_pwd_history_list( pw_hist
**l
)
828 pw_hist
*pp
= p
->next
;
838 typedef struct ppbind
{
841 LDAPControl
**oldctrls
;
843 LDAPPasswordPolicyError pErr
;
848 ctrls_cleanup( Operation
*op
, SlapReply
*rs
, LDAPControl
**oldctrls
)
852 assert( rs
->sr_ctrls
!= NULL
);
853 assert( rs
->sr_ctrls
[0] != NULL
);
855 for ( n
= 0; rs
->sr_ctrls
[n
]; n
++ ) {
856 if ( rs
->sr_ctrls
[n
]->ldctl_oid
== ppolicy_ctrl_oid
) {
857 ch_free( rs
->sr_ctrls
[n
]->ldctl_value
.bv_val
);
858 ch_free( rs
->sr_ctrls
[n
] );
859 rs
->sr_ctrls
[n
] = (LDAPControl
*)(-1);
864 if ( rs
->sr_ctrls
[n
] == NULL
) {
868 op
->o_tmpfree( rs
->sr_ctrls
, op
->o_tmpmemctx
);
870 rs
->sr_ctrls
= oldctrls
;
874 ppolicy_ctrls_cleanup( Operation
*op
, SlapReply
*rs
)
876 ppbind
*ppb
= op
->o_callback
->sc_private
;
877 if ( ppb
->send_ctrl
) {
878 ctrls_cleanup( op
, rs
, ppb
->oldctrls
);
880 return SLAP_CB_CONTINUE
;
884 ppolicy_bind_response( Operation
*op
, SlapReply
*rs
)
886 ppbind
*ppb
= op
->o_callback
->sc_private
;
887 slap_overinst
*on
= ppb
->on
;
888 Modifications
*mod
= ppb
->mod
, *m
;
890 int ngut
= -1, warn
= -1, age
, rc
;
892 time_t now
, pwtime
= (time_t)-1;
893 char nowstr
[ LDAP_LUTIL_GENTIME_BUFSIZE
];
894 struct berval timestamp
;
895 BackendInfo
*bi
= op
->o_bd
->bd_info
;
898 /* If we already know it's locked, just get on with it */
899 if ( ppb
->pErr
!= PP_noError
) {
903 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
904 rc
= be_entry_get_rw( op
, &op
->o_req_ndn
, NULL
, NULL
, 0, &e
);
905 op
->o_bd
->bd_info
= bi
;
907 if ( rc
!= LDAP_SUCCESS
) {
908 return SLAP_CB_CONTINUE
;
911 now
= slap_get_time(); /* stored for later consideration */
912 timestamp
.bv_val
= nowstr
;
913 timestamp
.bv_len
= sizeof(nowstr
);
914 slap_timestamp( &now
, ×tamp
);
916 if ( rs
->sr_err
== LDAP_INVALID_CREDENTIALS
) {
919 m
= ch_calloc( sizeof(Modifications
), 1 );
920 m
->sml_op
= LDAP_MOD_ADD
;
922 m
->sml_type
= ad_pwdFailureTime
->ad_cname
;
923 m
->sml_desc
= ad_pwdFailureTime
;
925 m
->sml_values
= ch_calloc( sizeof(struct berval
), 2 );
926 m
->sml_nvalues
= ch_calloc( sizeof(struct berval
), 2 );
928 ber_dupbv( &m
->sml_values
[0], ×tamp
);
929 ber_dupbv( &m
->sml_nvalues
[0], ×tamp
);
934 * Count the pwdFailureTimes - if it's
935 * greater than the policy pwdMaxFailure,
936 * then lock the account.
938 if ((a
= attr_find( e
->e_attrs
, ad_pwdFailureTime
)) != NULL
) {
939 for(i
=0; a
->a_nvals
[i
].bv_val
; i
++) {
942 * If the interval is 0, then failures
943 * stay on the record until explicitly
944 * reset by successful authentication.
946 if (ppb
->pp
.pwdFailureCountInterval
== 0) {
949 parse_time(a
->a_nvals
[i
].bv_val
) +
950 ppb
->pp
.pwdFailureCountInterval
) {
955 * We only count those failures
956 * which are not due to expire.
961 if ((ppb
->pp
.pwdMaxFailure
> 0) &&
962 (fc
>= ppb
->pp
.pwdMaxFailure
- 1)) {
965 * We subtract 1 from the failure max
966 * because the new failure entry hasn't
967 * made it to the entry yet.
969 m
= ch_calloc( sizeof(Modifications
), 1 );
970 m
->sml_op
= LDAP_MOD_REPLACE
;
972 m
->sml_type
= ad_pwdAccountLockedTime
->ad_cname
;
973 m
->sml_desc
= ad_pwdAccountLockedTime
;
975 m
->sml_values
= ch_calloc( sizeof(struct berval
), 2 );
976 m
->sml_nvalues
= ch_calloc( sizeof(struct berval
), 2 );
977 ber_dupbv( &m
->sml_values
[0], ×tamp
);
978 ber_dupbv( &m
->sml_nvalues
[0], ×tamp
);
982 } else if ( rs
->sr_err
== LDAP_SUCCESS
) {
983 if ((a
= attr_find( e
->e_attrs
, ad_pwdChangedTime
)) != NULL
)
984 pwtime
= parse_time( a
->a_nvals
[0].bv_val
);
986 /* delete all pwdFailureTimes */
987 if ( attr_find( e
->e_attrs
, ad_pwdFailureTime
)) {
988 m
= ch_calloc( sizeof(Modifications
), 1 );
989 m
->sml_op
= LDAP_MOD_DELETE
;
991 m
->sml_type
= ad_pwdFailureTime
->ad_cname
;
992 m
->sml_desc
= ad_pwdFailureTime
;
998 * check to see if the password must be changed
1000 if ( ppb
->pp
.pwdMustChange
&&
1001 (a
= attr_find( e
->e_attrs
, ad_pwdReset
)) &&
1002 bvmatch( &a
->a_nvals
[0], &slap_true_bv
) )
1005 * need to inject client controls here to give
1006 * more information. For the moment, we ensure
1007 * that we are disallowed from doing anything
1008 * other than change password.
1010 ber_dupbv( &pwcons
[op
->o_conn
->c_conn_idx
].dn
,
1011 &op
->o_conn
->c_ndn
);
1013 ppb
->pErr
= PP_changeAfterReset
;
1017 * the password does not need to be changed, so
1018 * we now check whether the password has expired.
1020 * We can skip this bit if passwords don't age in
1021 * the policy. Also, if there was no pwdChangedTime
1022 * attribute in the entry, the password never expires.
1024 if (ppb
->pp
.pwdMaxAge
== 0) goto grace
;
1026 if (pwtime
!= (time_t)-1) {
1028 * Check: was the last change time of
1029 * the password older than the maximum age
1030 * allowed. (Ignore case 2 from I-D, it's just silly.)
1032 if (now
- pwtime
> ppb
->pp
.pwdMaxAge
) pwExpired
= 1;
1037 if (!pwExpired
) goto check_expiring_password
;
1039 if ((a
= attr_find( e
->e_attrs
, ad_pwdGraceUseTime
)) == NULL
)
1040 ngut
= ppb
->pp
.pwdGraceAuthNLimit
;
1042 for(ngut
=0; a
->a_nvals
[ngut
].bv_val
; ngut
++);
1043 ngut
= ppb
->pp
.pwdGraceAuthNLimit
- ngut
;
1047 * ngut is the number of remaining grace logins
1049 Debug( LDAP_DEBUG_ANY
,
1050 "ppolicy_bind: Entry %s has an expired password: %d grace logins\n",
1051 e
->e_name
.bv_val
, ngut
, 0);
1054 ppb
->pErr
= PP_passwordExpired
;
1055 rs
->sr_err
= LDAP_INVALID_CREDENTIALS
;
1060 * Add a grace user time to the entry
1062 m
= ch_calloc( sizeof(Modifications
), 1 );
1063 m
->sml_op
= LDAP_MOD_ADD
;
1065 m
->sml_type
= ad_pwdGraceUseTime
->ad_cname
;
1066 m
->sml_desc
= ad_pwdGraceUseTime
;
1068 m
->sml_values
= ch_calloc( sizeof(struct berval
), 2 );
1069 m
->sml_nvalues
= ch_calloc( sizeof(struct berval
), 2 );
1070 ber_dupbv( &m
->sml_values
[0], ×tamp
);
1071 ber_dupbv( &m
->sml_nvalues
[0], ×tamp
);
1075 check_expiring_password
:
1077 * Now we need to check to see
1078 * if it is about to expire, and if so, should the user
1079 * be warned about it in the password policy control.
1081 * If the password has expired, and we're in the grace period, then
1082 * we don't need to do this bit. Similarly, if we don't have password
1083 * aging, then there's no need to do this bit either.
1085 if ((ppb
->pp
.pwdMaxAge
< 1) || (pwExpired
) || (ppb
->pp
.pwdExpireWarning
< 1))
1088 age
= (int)(now
- pwtime
);
1091 * We know that there is a password Change Time attribute - if
1092 * there wasn't, then the pwdExpired value would be true, unless
1093 * there is no password aging - and if there is no password aging,
1094 * then this section isn't called anyway - you can't have an
1095 * expiring password if there's no limit to expire.
1097 if (ppb
->pp
.pwdMaxAge
- age
< ppb
->pp
.pwdExpireWarning
) {
1099 * Set the warning value.
1101 warn
= ppb
->pp
.pwdMaxAge
- age
; /* seconds left until expiry */
1102 if (warn
< 0) warn
= 0; /* something weird here - why is pwExpired not set? */
1104 Debug( LDAP_DEBUG_ANY
,
1105 "ppolicy_bind: Setting warning for password expiry for %s = %d seconds\n",
1106 op
->o_req_dn
.bv_val
, warn
, 0 );
1111 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
1112 be_entry_release_r( op
, e
);
1116 Operation op2
= *op
;
1117 SlapReply r2
= { REP_RESULT
};
1118 slap_callback cb
= { NULL
, slap_null_cb
, NULL
, NULL
};
1120 /* FIXME: Need to handle replication of some (but not all)
1121 * of the operational attributes...
1123 op2
.o_tag
= LDAP_REQ_MODIFY
;
1124 op2
.o_callback
= &cb
;
1125 op2
.orm_modlist
= mod
;
1126 op2
.o_dn
= op
->o_bd
->be_rootdn
;
1127 op2
.o_ndn
= op
->o_bd
->be_rootndn
;
1128 op2
.o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
1129 rc
= op
->o_bd
->be_modify( &op2
, &r2
);
1130 slap_mods_free( mod
, 1 );
1133 if ( ppb
->send_ctrl
) {
1134 LDAPControl
*ctrl
= NULL
;
1135 pp_info
*pi
= on
->on_bi
.bi_private
;
1137 /* Do we really want to tell that the account is locked? */
1138 if ( ppb
->pErr
== PP_accountLocked
&& !pi
->use_lockout
) {
1139 ppb
->pErr
= PP_noError
;
1141 ctrl
= create_passcontrol( warn
, ngut
, ppb
->pErr
);
1142 ppb
->oldctrls
= add_passcontrol( op
, rs
, ctrl
);
1143 op
->o_callback
->sc_cleanup
= ppolicy_ctrls_cleanup
;
1145 op
->o_bd
->bd_info
= bi
;
1146 return SLAP_CB_CONTINUE
;
1150 ppolicy_bind( Operation
*op
, SlapReply
*rs
)
1152 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
1154 /* Reset lockout status on all Bind requests */
1155 if ( !BER_BVISEMPTY( &pwcons
[op
->o_conn
->c_conn_idx
].dn
)) {
1156 ch_free( pwcons
[op
->o_conn
->c_conn_idx
].dn
.bv_val
);
1157 BER_BVZERO( &pwcons
[op
->o_conn
->c_conn_idx
].dn
);
1160 /* Root bypasses policy */
1161 if ( !be_isroot_dn( op
->o_bd
, &op
->o_req_ndn
)) {
1167 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
1168 rc
= be_entry_get_rw( op
, &op
->o_req_ndn
, NULL
, NULL
, 0, &e
);
1170 if ( rc
!= LDAP_SUCCESS
) {
1171 return SLAP_CB_CONTINUE
;
1174 cb
= op
->o_tmpcalloc( sizeof(ppbind
)+sizeof(slap_callback
),
1175 1, op
->o_tmpmemctx
);
1176 ppb
= (ppbind
*)(cb
+1);
1178 ppb
->pErr
= PP_noError
;
1180 /* Setup a callback so we can munge the result */
1182 cb
->sc_response
= ppolicy_bind_response
;
1183 cb
->sc_next
= op
->o_callback
->sc_next
;
1184 cb
->sc_private
= ppb
;
1185 op
->o_callback
->sc_next
= cb
;
1187 /* Did we receive a password policy request control? */
1188 if ( op
->o_ctrlflag
[ppolicy_cid
] ) {
1192 op
->o_bd
->bd_info
= (BackendInfo
*)on
;
1193 ppolicy_get( op
, e
, &ppb
->pp
);
1195 rc
= account_locked( op
, e
, &ppb
->pp
, &ppb
->mod
);
1197 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
1198 be_entry_release_r( op
, e
);
1201 /* This will be the Draft 8 response, Unwilling is bogus */
1202 ppb
->pErr
= PP_accountLocked
;
1203 send_ldap_error( op
, rs
, LDAP_INVALID_CREDENTIALS
, NULL
);
1209 return SLAP_CB_CONTINUE
;
1212 /* Reset the restricted info for the next session on this connection */
1214 ppolicy_connection_destroy( BackendDB
*bd
, Connection
*conn
)
1216 if ( !BER_BVISEMPTY( &pwcons
[conn
->c_conn_idx
].dn
)) {
1217 ch_free( pwcons
[conn
->c_conn_idx
].dn
.bv_val
);
1218 BER_BVZERO( &pwcons
[conn
->c_conn_idx
].dn
);
1220 return SLAP_CB_CONTINUE
;
1223 /* Check if this connection is restricted */
1229 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
1232 /* Did we receive a password policy request control? */
1233 if ( op
->o_ctrlflag
[ppolicy_cid
] ) {
1237 if ( op
->o_conn
&& !BER_BVISEMPTY( &pwcons
[op
->o_conn
->c_conn_idx
].dn
)) {
1238 LDAPControl
**oldctrls
;
1239 /* if the current authcDN doesn't match the one we recorded,
1240 * then an intervening Bind has succeeded and the restriction
1241 * no longer applies. (ITS#4516)
1243 if ( !dn_match( &op
->o_conn
->c_ndn
,
1244 &pwcons
[op
->o_conn
->c_conn_idx
].dn
)) {
1245 ch_free( pwcons
[op
->o_conn
->c_conn_idx
].dn
.bv_val
);
1246 BER_BVZERO( &pwcons
[op
->o_conn
->c_conn_idx
].dn
);
1247 return SLAP_CB_CONTINUE
;
1250 Debug( LDAP_DEBUG_TRACE
,
1251 "connection restricted to password changing only\n", 0, 0, 0);
1253 LDAPControl
*ctrl
= NULL
;
1254 ctrl
= create_passcontrol( -1, -1, PP_changeAfterReset
);
1255 oldctrls
= add_passcontrol( op
, rs
, ctrl
);
1257 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
1258 send_ldap_error( op
, rs
, LDAP_INSUFFICIENT_ACCESS
,
1259 "Operations are restricted to bind/unbind/abandon/StartTLS/modify password" );
1261 ctrls_cleanup( op
, rs
, oldctrls
);
1266 return SLAP_CB_CONTINUE
;
1274 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
1275 pp_info
*pi
= on
->on_bi
.bi_private
;
1280 if ( ppolicy_restrict( op
, rs
) != SLAP_CB_CONTINUE
)
1283 /* If this is a replica, assume the master checked everything */
1284 if ( be_shadow_update( op
))
1285 return SLAP_CB_CONTINUE
;
1287 /* Check for password in entry */
1288 if ((pa
= attr_find( op
->oq_add
.rs_e
->e_attrs
,
1289 slap_schema
.si_ad_userPassword
)))
1291 assert( pa
->a_vals
!= NULL
);
1292 assert( !BER_BVISNULL( &pa
->a_vals
[ 0 ] ) );
1294 if ( !BER_BVISNULL( &pa
->a_vals
[ 1 ] ) ) {
1295 send_ldap_error( op
, rs
, LDAP_CONSTRAINT_VIOLATION
, "Password policy only allows one password value" );
1300 * new entry contains a password - if we're not the root user
1301 * then we need to check that the password fits in with the
1302 * security policy for the new entry.
1304 ppolicy_get( op
, op
->ora_e
, &pp
);
1305 if (pp
.pwdCheckQuality
> 0 && !be_isroot( op
)) {
1306 struct berval
*bv
= &(pa
->a_vals
[0]);
1307 int rc
, send_ctrl
= 0;
1308 LDAPPasswordPolicyError pErr
= PP_noError
;
1310 /* Did we receive a password policy request control? */
1311 if ( op
->o_ctrlflag
[ppolicy_cid
] ) {
1314 rc
= check_password_quality( bv
, &pp
, &pErr
, op
->ora_e
);
1315 if (rc
!= LDAP_SUCCESS
) {
1316 LDAPControl
**oldctrls
= NULL
;
1317 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
1319 LDAPControl
*ctrl
= NULL
;
1320 ctrl
= create_passcontrol( -1, -1, pErr
);
1321 oldctrls
= add_passcontrol( op
, rs
, ctrl
);
1323 send_ldap_error( op
, rs
, rc
, "Password fails quality checking policy" );
1325 ctrls_cleanup( op
, rs
, oldctrls
);
1331 * A controversial bit. We hash cleartext
1332 * passwords provided via add and modify operations
1333 * You're not really supposed to do this, since
1334 * the X.500 model says "store attributes" as they
1335 * get provided. By default, this is what we do
1337 * But if the hash_passwords flag is set, we hash
1338 * any cleartext password attribute values via the
1339 * default password hashing scheme.
1341 if ((pi
->hash_passwords
) &&
1342 (password_scheme( &(pa
->a_vals
[0]), NULL
) != LDAP_SUCCESS
)) {
1345 slap_passwd_hash( &(pa
->a_vals
[0]), &hpw
, &txt
);
1346 if (hpw
.bv_val
== NULL
) {
1348 * hashing didn't work. Emit an error.
1350 rs
->sr_err
= LDAP_OTHER
;
1352 send_ldap_error( op
, rs
, LDAP_OTHER
, "Password hashing failed" );
1356 memset( pa
->a_vals
[0].bv_val
, 0, pa
->a_vals
[0].bv_len
);
1357 ber_memfree( pa
->a_vals
[0].bv_val
);
1358 pa
->a_vals
[0].bv_val
= hpw
.bv_val
;
1359 pa
->a_vals
[0].bv_len
= hpw
.bv_len
;
1362 /* If password aging is in effect, set the pwdChangedTime */
1363 if ( pp
.pwdMaxAge
|| pp
.pwdMinAge
) {
1364 struct berval timestamp
;
1365 char timebuf
[ LDAP_LUTIL_GENTIME_BUFSIZE
];
1366 time_t now
= slap_get_time();
1368 timestamp
.bv_val
= timebuf
;
1369 timestamp
.bv_len
= sizeof(timebuf
);
1370 slap_timestamp( &now
, ×tamp
);
1372 attr_merge_one( op
->ora_e
, ad_pwdChangedTime
, ×tamp
, ×tamp
);
1375 return SLAP_CB_CONTINUE
;
1379 ppolicy_mod_cb( Operation
*op
, SlapReply
*rs
)
1381 slap_callback
*sc
= op
->o_callback
;
1382 op
->o_callback
= sc
->sc_next
;
1383 if ( rs
->sr_err
== LDAP_SUCCESS
) {
1384 ch_free( pwcons
[op
->o_conn
->c_conn_idx
].dn
.bv_val
);
1385 BER_BVZERO( &pwcons
[op
->o_conn
->c_conn_idx
].dn
);
1387 op
->o_tmpfree( sc
, op
->o_tmpmemctx
);
1388 return SLAP_CB_CONTINUE
;
1392 ppolicy_modify( Operation
*op
, SlapReply
*rs
)
1394 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
1395 pp_info
*pi
= on
->on_bi
.bi_private
;
1396 int i
, rc
, mod_pw_only
, pwmod
, pwmop
= -1, deladd
,
1399 Modifications
*mods
= NULL
, *modtail
= NULL
,
1400 *ml
, *delmod
, *addmod
;
1401 Attribute
*pa
, *ha
, at
;
1403 pw_hist
*tl
= NULL
, *p
;
1404 int zapReset
, send_ctrl
= 0;
1406 struct berval newpw
= BER_BVNULL
, oldpw
= BER_BVNULL
,
1408 LDAPPasswordPolicyError pErr
= PP_noError
;
1409 LDAPControl
**oldctrls
= NULL
;
1411 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
1412 rc
= be_entry_get_rw( op
, &op
->o_req_ndn
, NULL
, NULL
, 0, &e
);
1413 op
->o_bd
->bd_info
= (BackendInfo
*)on
;
1415 if ( rc
!= LDAP_SUCCESS
) return SLAP_CB_CONTINUE
;
1417 /* If this is a replica, we may need to tweak some of the
1418 * master's modifications. Otherwise, just pass it through.
1420 if ( be_shadow_update( op
)) {
1421 Modifications
**prev
;
1422 int got_del_grace
= 0, got_del_lock
= 0, got_pw
= 0, got_del_fail
= 0;
1423 Attribute
*a_grace
, *a_lock
, *a_fail
;
1425 a_grace
= attr_find( e
->e_attrs
, ad_pwdGraceUseTime
);
1426 a_lock
= attr_find( e
->e_attrs
, ad_pwdAccountLockedTime
);
1427 a_fail
= attr_find( e
->e_attrs
, ad_pwdFailureTime
);
1429 for( prev
= &op
->orm_modlist
, ml
= *prev
; ml
; ml
= *prev
) {
1431 if ( ml
->sml_desc
== slap_schema
.si_ad_userPassword
)
1434 /* If we're deleting an attr that didn't exist,
1435 * drop this delete op
1437 if ( ml
->sml_op
== LDAP_MOD_DELETE
) {
1440 if ( ml
->sml_desc
== ad_pwdGraceUseTime
) {
1445 if ( ml
->sml_desc
== ad_pwdAccountLockedTime
) {
1450 if ( ml
->sml_desc
== ad_pwdFailureTime
) {
1456 *prev
= ml
->sml_next
;
1457 ml
->sml_next
= NULL
;
1458 slap_mods_free( ml
, 1 );
1462 prev
= &ml
->sml_next
;
1465 /* If we're resetting the password, make sure grace, accountlock,
1466 * and failure also get removed.
1469 if ( a_grace
&& !got_del_grace
) {
1470 ml
= (Modifications
*) ch_malloc( sizeof( Modifications
) );
1471 ml
->sml_op
= LDAP_MOD_DELETE
;
1472 ml
->sml_flags
= SLAP_MOD_INTERNAL
;
1473 ml
->sml_type
.bv_val
= NULL
;
1474 ml
->sml_desc
= ad_pwdGraceUseTime
;
1475 ml
->sml_numvals
= 0;
1476 ml
->sml_values
= NULL
;
1477 ml
->sml_nvalues
= NULL
;
1478 ml
->sml_next
= NULL
;
1480 prev
= &ml
->sml_next
;
1482 if ( a_lock
&& !got_del_lock
) {
1483 ml
= (Modifications
*) ch_malloc( sizeof( Modifications
) );
1484 ml
->sml_op
= LDAP_MOD_DELETE
;
1485 ml
->sml_flags
= SLAP_MOD_INTERNAL
;
1486 ml
->sml_type
.bv_val
= NULL
;
1487 ml
->sml_desc
= ad_pwdAccountLockedTime
;
1488 ml
->sml_numvals
= 0;
1489 ml
->sml_values
= NULL
;
1490 ml
->sml_nvalues
= NULL
;
1491 ml
->sml_next
= NULL
;
1494 if ( a_fail
&& !got_del_fail
) {
1495 ml
= (Modifications
*) ch_malloc( sizeof( Modifications
) );
1496 ml
->sml_op
= LDAP_MOD_DELETE
;
1497 ml
->sml_flags
= SLAP_MOD_INTERNAL
;
1498 ml
->sml_type
.bv_val
= NULL
;
1499 ml
->sml_desc
= ad_pwdFailureTime
;
1500 ml
->sml_numvals
= 0;
1501 ml
->sml_values
= NULL
;
1502 ml
->sml_nvalues
= NULL
;
1503 ml
->sml_next
= NULL
;
1507 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
1508 be_entry_release_r( op
, e
);
1509 return SLAP_CB_CONTINUE
;
1512 /* Did we receive a password policy request control? */
1513 if ( op
->o_ctrlflag
[ppolicy_cid
] ) {
1517 /* See if this is a pwdModify exop. If so, we can
1518 * access the plaintext passwords from that request.
1523 for ( sc
= op
->o_callback
; sc
; sc
=sc
->sc_next
) {
1524 if ( sc
->sc_response
== slap_null_cb
&&
1526 req_pwdexop_s
*qpw
= sc
->sc_private
;
1527 newpw
= qpw
->rs_new
;
1528 oldpw
= qpw
->rs_old
;
1534 ppolicy_get( op
, e
, &pp
);
1536 for ( ml
= op
->orm_modlist
,
1537 pwmod
= 0, mod_pw_only
= 1,
1538 deladd
= 0, delmod
= NULL
,
1541 ml
!= NULL
; modtail
= ml
, ml
= ml
->sml_next
)
1543 if ( ml
->sml_desc
== pp
.ad
) {
1546 if ((deladd
== 0) && (ml
->sml_op
== LDAP_MOD_DELETE
) &&
1547 (ml
->sml_values
) && !BER_BVISNULL( &ml
->sml_values
[0] ))
1553 if ((ml
->sml_op
== LDAP_MOD_ADD
) ||
1554 (ml
->sml_op
== LDAP_MOD_REPLACE
))
1556 if ( ml
->sml_values
&& !BER_BVISNULL( &ml
->sml_values
[0] )) {
1560 /* FIXME: there's no easy way to ensure
1561 * that add does not cause multiple
1562 * userPassword values; one way (that
1563 * would be consistent with the single
1564 * password constraint) would be to turn
1565 * add into replace); another would be
1568 * Let's check at least that a single value
1571 if ( addmod
|| !BER_BVISNULL( &ml
->sml_values
[ 1 ] ) ) {
1572 rs
->sr_err
= LDAP_CONSTRAINT_VIOLATION
;
1573 rs
->sr_text
= "Password policy only allows one password value";
1574 goto return_results
;
1579 /* replace can have no values, add cannot */
1580 assert( ml
->sml_op
== LDAP_MOD_REPLACE
);
1584 } else if ( !(ml
->sml_flags
& SLAP_MOD_INTERNAL
) && !is_at_operational( ml
->sml_desc
->ad_type
) ) {
1586 /* modifying something other than password */
1590 * If there is a request to explicitly add a pwdReset
1591 * attribute, then we suppress the normal behaviour on
1592 * password change, which is to remove the pwdReset
1595 * This enables an administrator to assign a new password
1596 * and place a "must reset" flag on the entry, which will
1597 * stay until the user explicitly changes his/her password.
1599 if (ml
->sml_desc
== ad_pwdReset
) {
1600 if ((ml
->sml_op
== LDAP_MOD_ADD
) ||
1601 (ml
->sml_op
== LDAP_MOD_REPLACE
))
1606 if (!BER_BVISEMPTY( &pwcons
[op
->o_conn
->c_conn_idx
].dn
) && !mod_pw_only
) {
1607 if ( dn_match( &op
->o_conn
->c_ndn
,
1608 &pwcons
[op
->o_conn
->c_conn_idx
].dn
)) {
1609 Debug( LDAP_DEBUG_TRACE
,
1610 "connection restricted to password changing only\n", 0, 0, 0 );
1611 rs
->sr_err
= LDAP_INSUFFICIENT_ACCESS
;
1612 rs
->sr_text
= "Operations are restricted to bind/unbind/abandon/StartTLS/modify password";
1613 pErr
= PP_changeAfterReset
;
1614 goto return_results
;
1616 ch_free( pwcons
[op
->o_conn
->c_conn_idx
].dn
.bv_val
);
1617 BER_BVZERO( &pwcons
[op
->o_conn
->c_conn_idx
].dn
);
1622 * if we have a "safe password modify policy", then we need to check if we're doing
1623 * a delete (with the old password), followed by an add (with the new password).
1625 * If we got just a delete with nothing else, just let it go. We also skip all the checks if
1626 * the root user is bound. Root can do anything, including avoid the policies.
1629 if (!pwmod
) goto do_modify
;
1632 * Build the password history list in ascending time order
1633 * We need this, even if the user is root, in order to maintain
1634 * the pwdHistory operational attributes properly.
1636 if (addmod
&& pp
.pwdInHistory
> 0 && (ha
= attr_find( e
->e_attrs
, ad_pwdHistory
))) {
1637 struct berval oldpw
;
1640 for(i
=0; ha
->a_nvals
[i
].bv_val
; i
++) {
1641 rc
= parse_pwdhistory( &(ha
->a_nvals
[i
]), NULL
,
1644 if (rc
!= LDAP_SUCCESS
) continue; /* invalid history entry */
1647 add_to_pwd_history( &tl
, oldtime
, &oldpw
,
1648 &(ha
->a_nvals
[i
]) );
1649 oldpw
.bv_val
= NULL
;
1653 for(p
=tl
; p
; p
=p
->next
, hsize
++); /* count history size */
1656 if (be_isroot( op
)) goto do_modify
;
1658 if (!pp
.pwdAllowUserChange
) {
1659 rs
->sr_err
= LDAP_INSUFFICIENT_ACCESS
;
1660 rs
->sr_text
= "User alteration of password is not allowed";
1661 pErr
= PP_passwordModNotAllowed
;
1662 goto return_results
;
1665 /* Just deleting? */
1667 /* skip everything else */
1672 /* This is a pwdModify exop that provided the old pw.
1673 * We need to create a Delete mod for this old pw and
1674 * let the matching value get found later
1676 if (pp
.pwdSafeModify
&& oldpw
.bv_val
) {
1677 ml
= (Modifications
*)ch_calloc( sizeof( Modifications
), 1 );
1678 ml
->sml_op
= LDAP_MOD_DELETE
;
1679 ml
->sml_flags
= SLAP_MOD_INTERNAL
;
1680 ml
->sml_desc
= pp
.ad
;
1681 ml
->sml_type
= pp
.ad
->ad_cname
;
1682 ml
->sml_numvals
= 1;
1683 ml
->sml_values
= (BerVarray
) ch_malloc( 2 * sizeof( struct berval
) );
1684 ber_dupbv( &ml
->sml_values
[0], &oldpw
);
1685 BER_BVZERO( &ml
->sml_values
[1] );
1686 ml
->sml_next
= op
->orm_modlist
;
1687 op
->orm_modlist
= ml
;
1692 if (pp
.pwdSafeModify
&& deladd
!= 2) {
1693 Debug( LDAP_DEBUG_TRACE
,
1694 "change password must use DELETE followed by ADD/REPLACE\n",
1696 rs
->sr_err
= LDAP_INSUFFICIENT_ACCESS
;
1697 rs
->sr_text
= "Must supply old password to be changed as well as new one";
1698 pErr
= PP_mustSupplyOldPassword
;
1699 goto return_results
;
1702 /* Check age, but only if pwdReset is not TRUE */
1703 pa
= attr_find( e
->e_attrs
, ad_pwdReset
);
1704 if ((!pa
|| !bvmatch( &pa
->a_nvals
[0], &slap_true_bv
)) &&
1706 time_t pwtime
= (time_t)-1, now
;
1709 if ((pa
= attr_find( e
->e_attrs
, ad_pwdChangedTime
)) != NULL
)
1710 pwtime
= parse_time( pa
->a_nvals
[0].bv_val
);
1711 now
= slap_get_time();
1712 age
= (int)(now
- pwtime
);
1713 if ((pwtime
!= (time_t)-1) && (age
< pp
.pwdMinAge
)) {
1714 rs
->sr_err
= LDAP_CONSTRAINT_VIOLATION
;
1715 rs
->sr_text
= "Password is too young to change";
1716 pErr
= PP_passwordTooYoung
;
1717 goto return_results
;
1721 /* pa is used in password history check below, be sure it's set */
1722 if ((pa
= attr_find( e
->e_attrs
, pp
.ad
)) != NULL
&& delmod
) {
1724 * we have a password to check
1728 bv
= oldpw
.bv_val
? &oldpw
: delmod
->sml_values
;
1729 /* FIXME: no access checking? */
1730 rc
= slap_passwd_check( op
, NULL
, pa
, bv
, &txt
);
1731 if (rc
!= LDAP_SUCCESS
) {
1732 Debug( LDAP_DEBUG_TRACE
,
1733 "old password check failed: %s\n", txt
, 0, 0 );
1735 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
1736 rs
->sr_text
= "Must supply correct old password to change to new one";
1737 pErr
= PP_mustSupplyOldPassword
;
1738 goto return_results
;
1744 * replace the delete value with the (possibly hashed)
1745 * value which is currently in the password.
1747 for ( i
= 0; !BER_BVISNULL( &delmod
->sml_values
[i
] ); i
++ ) {
1748 free( delmod
->sml_values
[i
].bv_val
);
1749 BER_BVZERO( &delmod
->sml_values
[i
] );
1751 free( delmod
->sml_values
);
1752 delmod
->sml_values
= ch_calloc( sizeof(struct berval
), 2 );
1753 BER_BVZERO( &delmod
->sml_values
[1] );
1754 ber_dupbv( &(delmod
->sml_values
[0]), &(pa
->a_nvals
[0]) );
1758 bv
= newpw
.bv_val
? &newpw
: &addmod
->sml_values
[0];
1759 if (pp
.pwdCheckQuality
> 0) {
1761 rc
= check_password_quality( bv
, &pp
, &pErr
, e
);
1762 if (rc
!= LDAP_SUCCESS
) {
1764 rs
->sr_text
= "Password fails quality checking policy";
1765 goto return_results
;
1769 /* If pwdInHistory is zero, passwords may be reused */
1770 if (pa
&& pp
.pwdInHistory
> 0) {
1772 * Last check - the password history.
1774 /* FIXME: no access checking? */
1775 if (slap_passwd_check( op
, NULL
, pa
, bv
, &txt
) == LDAP_SUCCESS
) {
1777 * This is bad - it means that the user is attempting
1778 * to set the password to the same as the old one.
1780 rs
->sr_err
= LDAP_CONSTRAINT_VIOLATION
;
1781 rs
->sr_text
= "Password is not being changed from existing value";
1782 pErr
= PP_passwordInHistory
;
1783 goto return_results
;
1787 * Iterate through the password history, and fail on any
1792 cr
[1].bv_val
= NULL
;
1793 for(p
=tl
; p
; p
=p
->next
) {
1795 /* FIXME: no access checking? */
1796 rc
= slap_passwd_check( op
, NULL
, &at
, bv
, &txt
);
1798 if (rc
!= LDAP_SUCCESS
) continue;
1800 rs
->sr_err
= LDAP_CONSTRAINT_VIOLATION
;
1801 rs
->sr_text
= "Password is in history of old passwords";
1802 pErr
= PP_passwordInHistory
;
1803 goto return_results
;
1809 struct berval timestamp
;
1810 char timebuf
[ LDAP_LUTIL_GENTIME_BUFSIZE
];
1811 time_t now
= slap_get_time();
1813 /* If the conn is restricted, set a callback to clear it
1814 * if the pwmod succeeds
1816 if (!BER_BVISEMPTY( &pwcons
[op
->o_conn
->c_conn_idx
].dn
)) {
1817 slap_callback
*sc
= op
->o_tmpcalloc( 1, sizeof( slap_callback
),
1819 sc
->sc_next
= op
->o_callback
;
1820 /* Must use sc_response to insure we reset on success, before
1821 * the client sees the response. Must use sc_cleanup to insure
1822 * that it gets cleaned up if sc_response is not called.
1824 sc
->sc_response
= ppolicy_mod_cb
;
1825 sc
->sc_cleanup
= ppolicy_mod_cb
;
1826 op
->o_callback
= sc
;
1830 * keep the necessary pwd.. operational attributes
1834 timestamp
.bv_val
= timebuf
;
1835 timestamp
.bv_len
= sizeof(timebuf
);
1836 slap_timestamp( &now
, ×tamp
);
1838 mods
= (Modifications
*) ch_calloc( sizeof( Modifications
), 1 );
1839 mods
->sml_desc
= ad_pwdChangedTime
;
1840 if (pwmop
!= LDAP_MOD_DELETE
) {
1841 mods
->sml_op
= LDAP_MOD_REPLACE
;
1842 mods
->sml_numvals
= 1;
1843 mods
->sml_values
= (BerVarray
) ch_malloc( 2 * sizeof( struct berval
) );
1844 ber_dupbv( &mods
->sml_values
[0], ×tamp
);
1845 BER_BVZERO( &mods
->sml_values
[1] );
1846 assert( !BER_BVISNULL( &mods
->sml_values
[0] ) );
1849 mods
->sml_op
= LDAP_MOD_DELETE
;
1851 mods
->sml_flags
= SLAP_MOD_INTERNAL
;
1852 mods
->sml_next
= NULL
;
1853 modtail
->sml_next
= mods
;
1856 if (attr_find(e
->e_attrs
, ad_pwdGraceUseTime
)) {
1857 mods
= (Modifications
*) ch_calloc( sizeof( Modifications
), 1 );
1858 mods
->sml_op
= LDAP_MOD_DELETE
;
1859 mods
->sml_desc
= ad_pwdGraceUseTime
;
1860 mods
->sml_flags
= SLAP_MOD_INTERNAL
;
1861 mods
->sml_next
= NULL
;
1862 modtail
->sml_next
= mods
;
1866 if (attr_find(e
->e_attrs
, ad_pwdAccountLockedTime
)) {
1867 mods
= (Modifications
*) ch_calloc( sizeof( Modifications
), 1 );
1868 mods
->sml_op
= LDAP_MOD_DELETE
;
1869 mods
->sml_desc
= ad_pwdAccountLockedTime
;
1870 mods
->sml_flags
= SLAP_MOD_INTERNAL
;
1871 mods
->sml_next
= NULL
;
1872 modtail
->sml_next
= mods
;
1876 if (attr_find(e
->e_attrs
, ad_pwdFailureTime
)) {
1877 mods
= (Modifications
*) ch_calloc( sizeof( Modifications
), 1 );
1878 mods
->sml_op
= LDAP_MOD_DELETE
;
1879 mods
->sml_desc
= ad_pwdFailureTime
;
1880 mods
->sml_flags
= SLAP_MOD_INTERNAL
;
1881 mods
->sml_next
= NULL
;
1882 modtail
->sml_next
= mods
;
1886 /* Delete the pwdReset attribute, since it's being reset */
1887 if ((zapReset
) && (attr_find(e
->e_attrs
, ad_pwdReset
))) {
1888 mods
= (Modifications
*) ch_calloc( sizeof( Modifications
), 1 );
1889 mods
->sml_op
= LDAP_MOD_DELETE
;
1890 mods
->sml_desc
= ad_pwdReset
;
1891 mods
->sml_flags
= SLAP_MOD_INTERNAL
;
1892 mods
->sml_next
= NULL
;
1893 modtail
->sml_next
= mods
;
1897 if (pp
.pwdInHistory
> 0) {
1898 if (hsize
>= pp
.pwdInHistory
) {
1900 * We use the >= operator, since we are going to add
1901 * the existing password attribute value into the
1902 * history - thus the cardinality of history values is
1903 * about to rise by one.
1905 * If this would push it over the limit of history
1906 * values (remembering - the password policy could have
1907 * changed since the password was last altered), we must
1908 * delete at least 1 value from the pwdHistory list.
1910 * In fact, we delete '(#pwdHistory attrs - max pwd
1911 * history length) + 1' values, starting with the oldest.
1912 * This is easily evaluated, since the linked list is
1913 * created in ascending time order.
1915 mods
= (Modifications
*) ch_calloc( sizeof( Modifications
), 1 );
1916 mods
->sml_op
= LDAP_MOD_DELETE
;
1917 mods
->sml_flags
= SLAP_MOD_INTERNAL
;
1918 mods
->sml_desc
= ad_pwdHistory
;
1919 mods
->sml_numvals
= hsize
- pp
.pwdInHistory
+ 1;
1920 mods
->sml_values
= ch_calloc( sizeof( struct berval
),
1921 hsize
- pp
.pwdInHistory
+ 2 );
1922 BER_BVZERO( &mods
->sml_values
[ hsize
- pp
.pwdInHistory
+ 1 ] );
1923 for(i
=0,p
=tl
; i
< (hsize
- pp
.pwdInHistory
+ 1); i
++, p
=p
->next
) {
1924 BER_BVZERO( &mods
->sml_values
[i
] );
1925 ber_dupbv( &(mods
->sml_values
[i
]), &p
->bv
);
1927 mods
->sml_next
= NULL
;
1928 modtail
->sml_next
= mods
;
1931 free_pwd_history_list( &tl
);
1934 * Now add the existing password into the history list.
1935 * This will be executed even if the operation is to delete
1936 * the password entirely.
1938 * This isn't in the spec explicitly, but it seems to make
1939 * sense that the password history list is the list of all
1940 * previous passwords - even if they were deleted. Thus, if
1941 * someone tries to add a historical password at some future
1942 * point, it will fail.
1944 if ((pa
= attr_find( e
->e_attrs
, pp
.ad
)) != NULL
) {
1945 mods
= (Modifications
*) ch_malloc( sizeof( Modifications
) );
1946 mods
->sml_op
= LDAP_MOD_ADD
;
1947 mods
->sml_flags
= SLAP_MOD_INTERNAL
;
1948 mods
->sml_type
.bv_val
= NULL
;
1949 mods
->sml_desc
= ad_pwdHistory
;
1950 mods
->sml_nvalues
= NULL
;
1951 mods
->sml_numvals
= 1;
1952 mods
->sml_values
= ch_calloc( sizeof( struct berval
), 2 );
1953 mods
->sml_values
[ 1 ].bv_val
= NULL
;
1954 mods
->sml_values
[ 1 ].bv_len
= 0;
1955 make_pwd_history_value( timebuf
, &mods
->sml_values
[0], pa
);
1956 mods
->sml_next
= NULL
;
1957 modtail
->sml_next
= mods
;
1961 Debug( LDAP_DEBUG_TRACE
,
1962 "ppolicy_modify: password attr lookup failed\n", 0, 0, 0 );
1967 * Controversial bit here. If the new password isn't hashed
1968 * (ie, is cleartext), we probably should hash it according
1969 * to the default hash. The reason for this is that we want
1970 * to use the policy if possible, but if we hash the password
1971 * before, then we're going to run into trouble when it
1972 * comes time to check the password.
1974 * Now, the right thing to do is to use the extended password
1975 * modify operation, but not all software can do this,
1976 * therefore it makes sense to hash the new password, now
1977 * we know it passes the policy requirements.
1979 * Of course, if the password is already hashed, then we
1983 if ((pi
->hash_passwords
) && (addmod
) && !newpw
.bv_val
&&
1984 (password_scheme( &(addmod
->sml_values
[0]), NULL
) != LDAP_SUCCESS
))
1986 struct berval hpw
, bv
;
1988 slap_passwd_hash( &(addmod
->sml_values
[0]), &hpw
, &txt
);
1989 if (hpw
.bv_val
== NULL
) {
1991 * hashing didn't work. Emit an error.
1993 rs
->sr_err
= LDAP_OTHER
;
1995 goto return_results
;
1997 bv
= addmod
->sml_values
[0];
1998 /* clear and discard the clear password */
1999 memset(bv
.bv_val
, 0, bv
.bv_len
);
2000 ber_memfree(bv
.bv_val
);
2001 addmod
->sml_values
[0] = hpw
;
2004 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
2005 be_entry_release_r( op
, e
);
2006 return SLAP_CB_CONTINUE
;
2009 free_pwd_history_list( &tl
);
2010 op
->o_bd
->bd_info
= (BackendInfo
*)on
->on_info
;
2011 be_entry_release_r( op
, e
);
2013 LDAPControl
*ctrl
= NULL
;
2015 ctrl
= create_passcontrol( -1, -1, pErr
);
2016 oldctrls
= add_passcontrol( op
, rs
, ctrl
);
2018 send_ldap_result( op
, rs
);
2020 ctrls_cleanup( op
, rs
, oldctrls
);
2031 if ( !BER_BVISNULL( &ctrl
->ldctl_value
) ) {
2032 rs
->sr_text
= "passwordPolicyRequest control value not absent";
2033 return LDAP_PROTOCOL_ERROR
;
2035 op
->o_ctrlflag
[ppolicy_cid
] = ctrl
->ldctl_iscritical
2036 ? SLAP_CONTROL_CRITICAL
2037 : SLAP_CONTROL_NONCRITICAL
;
2039 return LDAP_SUCCESS
;
2049 AttributeDescription
*ad
= NULL
;
2053 code
= slap_bv2ad( val
, &ad
, &err
);
2055 ber_dupbv_x( out
, &ad
->ad_type
->sat_cname
, ctx
);
2069 AttributeDescription
*ad
= NULL
;
2073 code
= slap_bv2ad( val
, &ad
, &err
);
2075 ber_str2bv_x( ad
->ad_type
->sat_oid
, 0, 1, out
, ctx
);
2086 slap_overinst
*on
= (slap_overinst
*) be
->bd_info
;
2088 /* Has User Schema been initialized yet? */
2089 if ( !pwd_UsSchema
[0].ad
[0] ) {
2093 for (i
=0; pwd_UsSchema
[i
].def
; i
++) {
2094 code
= slap_str2ad( pwd_UsSchema
[i
].def
, pwd_UsSchema
[i
].ad
, &err
);
2097 snprintf( cr
->msg
, sizeof(cr
->msg
),
2098 "User Schema load failed for attribute \"%s\". Error code %d: %s",
2099 pwd_UsSchema
[i
].def
, code
, err
);
2100 fprintf( stderr
, "%s\n", cr
->msg
);
2109 syn
= ch_malloc( sizeof( Syntax
));
2110 *syn
= *ad_pwdAttribute
->ad_type
->sat_syntax
;
2111 syn
->ssyn_pretty
= attrPretty
;
2112 ad_pwdAttribute
->ad_type
->sat_syntax
= syn
;
2114 mr
= ch_malloc( sizeof( MatchingRule
));
2115 *mr
= *ad_pwdAttribute
->ad_type
->sat_equality
;
2116 mr
->smr_normalize
= attrNormalize
;
2117 ad_pwdAttribute
->ad_type
->sat_equality
= mr
;
2121 on
->on_bi
.bi_private
= ch_calloc( sizeof(pp_info
), 1 );
2123 if ( dtblsize
&& !pwcons
) {
2124 /* accommodate for c_conn_idx == -1 */
2125 pwcons
= ch_calloc( sizeof(pw_conn
), dtblsize
+ 1 );
2139 return overlay_register_control( be
, LDAP_CONTROL_PASSWORDPOLICYREQUEST
);
2148 slap_overinst
*on
= (slap_overinst
*) be
->bd_info
;
2149 pp_info
*pi
= on
->on_bi
.bi_private
;
2151 /* Perhaps backover should provide bi_destroy hooks... */
2153 if ( ov_count
<=0 && pwcons
) {
2158 free( pi
->def_policy
.bv_val
);
2164 static char *extops
[] = {
2165 LDAP_EXOP_MODIFY_PASSWD
,
2169 static slap_overinst ppolicy
;
2171 int ppolicy_initialize()
2175 for (i
=0; pwd_OpSchema
[i
].def
; i
++) {
2176 code
= register_at( pwd_OpSchema
[i
].def
, pwd_OpSchema
[i
].ad
, 0 );
2178 Debug( LDAP_DEBUG_ANY
,
2179 "ppolicy_initialize: register_at failed\n", 0, 0, 0 );
2182 /* Allow Manager to set these as needed */
2183 if ( is_at_no_user_mod( (*pwd_OpSchema
[i
].ad
)->ad_type
)) {
2184 (*pwd_OpSchema
[i
].ad
)->ad_type
->sat_flags
|=
2189 code
= register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST
,
2190 SLAP_CTRL_ADD
|SLAP_CTRL_BIND
|SLAP_CTRL_MODIFY
|SLAP_CTRL_HIDE
, extops
,
2191 ppolicy_parseCtrl
, &ppolicy_cid
);
2192 if ( code
!= LDAP_SUCCESS
) {
2193 fprintf( stderr
, "Failed to register control %d\n", code
);
2197 ldap_pvt_thread_mutex_init( &chk_syntax_mutex
);
2199 ppolicy
.on_bi
.bi_type
= "ppolicy";
2200 ppolicy
.on_bi
.bi_db_init
= ppolicy_db_init
;
2201 ppolicy
.on_bi
.bi_db_open
= ppolicy_db_open
;
2202 ppolicy
.on_bi
.bi_db_close
= ppolicy_close
;
2204 ppolicy
.on_bi
.bi_op_add
= ppolicy_add
;
2205 ppolicy
.on_bi
.bi_op_bind
= ppolicy_bind
;
2206 ppolicy
.on_bi
.bi_op_compare
= ppolicy_restrict
;
2207 ppolicy
.on_bi
.bi_op_delete
= ppolicy_restrict
;
2208 ppolicy
.on_bi
.bi_op_modify
= ppolicy_modify
;
2209 ppolicy
.on_bi
.bi_op_search
= ppolicy_restrict
;
2210 ppolicy
.on_bi
.bi_connection_destroy
= ppolicy_connection_destroy
;
2212 ppolicy
.on_bi
.bi_cf_ocs
= ppolicyocs
;
2213 code
= config_register_schema( ppolicycfg
, ppolicyocs
);
2214 if ( code
) return code
;
2216 return overlay_register( &ppolicy
);
2219 #if SLAPD_OVER_PPOLICY == SLAPD_MOD_DYNAMIC
2220 int init_module(int argc
, char *argv
[]) {
2221 return ppolicy_initialize();
2225 #endif /* defined(SLAPD_OVER_PPOLICY) */