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