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