1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2004-2021 The OpenLDAP Foundation.
5  * Portions Copyright 2004-2005 Howard Chu, Symas Corporation.
6  * Portions Copyright 2004 Hewlett-Packard Company.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was developed by Howard Chu for inclusion in
19  * OpenLDAP Software, based on prior work by Neil Dunbar (HP).
20  * This work was sponsored by the Hewlett-Packard Company.
21  */
22 
23 #include "portable.h"
24 
25 /* This file implements "Password Policy for LDAP Directories",
26  * based on draft behera-ldap-password-policy-09
27  */
28 
29 #ifdef SLAPD_OVER_PPOLICY
30 
31 #include <ldap.h>
32 #include "lutil.h"
33 #include "slap.h"
34 #ifdef SLAPD_MODULES
35 #define LIBLTDL_DLL_IMPORT	/* Win32: don't re-export libltdl's symbols */
36 #include <ltdl.h>
37 #endif
38 #include <ac/errno.h>
39 #include <ac/time.h>
40 #include <ac/string.h>
41 #include <ac/ctype.h>
42 #include "slap-config.h"
43 
44 #ifndef PPOLICY_DEFAULT_MAXRECORDED_FAILURE
45 #define PPOLICY_DEFAULT_MAXRECORDED_FAILURE	5
46 #endif
47 
48 		/* External password quality checking function.
49 		 * The error message must have a preallocated buffer and size
50 		 * passed in. Module can still allocate a buffer for
51 		 * it if the provided one is too small.
52 		 */
53 typedef	int (check_func)( char *passwd, struct berval *errmsg, Entry *ent, struct berval *arg );
54 #define ERRBUFSIZ	256
55 
56 /* Per-instance configuration information */
57 typedef struct pp_info {
58 	struct berval def_policy;	/* DN of default policy subentry */
59 	int use_lockout;		/* send AccountLocked result? */
60 	int hash_passwords;		/* transparently hash cleartext pwds */
61 	int forward_updates;	/* use frontend for policy state updates */
62 	int disable_write;
63 	int send_netscape_controls;	/* send netscape password controls */
64 	char *pwdCheckModule; /* name of module to dynamically
65 										    load to check password */
66 	lt_dlhandle	pwdCheckHandle;		/* handle from lt_dlopen */
67 	check_func *pwdCheckFunc;
68 	ldap_pvt_thread_mutex_t pwdFailureTime_mutex;
69 } pp_info;
70 
71 /* Our per-connection info - note, it is not per-instance, it is
72  * used by all instances
73  */
74 typedef struct pw_conn {
75 	struct berval dn;	/* DN of restricted user */
76 } pw_conn;
77 
78 static pw_conn *pwcons;
79 static int ppolicy_cid;
80 static int account_usability_cid;
81 static int ov_count;
82 
83 typedef struct pass_policy {
84 	AttributeDescription *ad; /* attribute to which the policy applies */
85 	int pwdMinAge; /* minimum time (seconds) until passwd can change */
86 	int pwdMaxAge; /* time in seconds until pwd will expire after change */
87 	int pwdMaxIdle; /* number of seconds since last successful bind before
88 					   passwd gets locked out */
89 	int pwdInHistory; /* number of previous passwords kept */
90 	int pwdCheckQuality; /* 0 = don't check quality, 1 = check if possible,
91 						   2 = check mandatory; fail if not possible */
92 	int pwdMinLength; /* minimum number of chars in password */
93 	int pwdMaxLength; /* maximum number of chars in password */
94 	int pwdExpireWarning; /* number of seconds that warning controls are
95 							sent before a password expires */
96 	int pwdGraceExpiry; /* number of seconds after expiry grace logins are
97 						   valid */
98 	int pwdGraceAuthNLimit; /* number of times you can log in with an
99 							expired password */
100 	int pwdLockout; /* 0 = do not lockout passwords, 1 = lock them out */
101 	int pwdLockoutDuration; /* time in seconds a password is locked out for */
102 	int pwdMinDelay; /* base bind delay in seconds on failure */
103 	int pwdMaxDelay; /* maximum bind delay in seconds */
104 	int pwdMaxFailure; /* number of failed binds allowed before lockout */
105 	int pwdMaxRecordedFailure;	/* number of failed binds to store */
106 	int pwdFailureCountInterval; /* number of seconds before failure
107 									counts are zeroed */
108 	int pwdMustChange; /* 0 = users can use admin set password
109 							1 = users must change password after admin set */
110 	int pwdAllowUserChange; /* 0 = users cannot change their passwords
111 								1 = users can change them */
112 	int pwdSafeModify; /* 0 = old password doesn't need to come
113 								with password change request
114 							1 = password change must supply existing pwd */
115 	int pwdUseCheckModule; /* 0 = do not use password check module, 1 = use */
116 	struct berval pwdCheckModuleArg; /* Optional argument to the password check
117 										module */
118 } PassPolicy;
119 
120 typedef struct pw_hist {
121 	time_t t;	/* timestamp of history entry */
122 	struct berval pw;	/* old password hash */
123 	struct berval bv;	/* text of entire entry */
124 	struct pw_hist *next;
125 } pw_hist;
126 
127 /* Operational attributes */
128 static AttributeDescription *ad_pwdChangedTime, *ad_pwdAccountLockedTime,
129 	*ad_pwdFailureTime, *ad_pwdHistory, *ad_pwdGraceUseTime, *ad_pwdReset,
130 	*ad_pwdPolicySubentry, *ad_pwdStartTime, *ad_pwdEndTime,
131 	*ad_pwdLastSuccess, *ad_pwdAccountTmpLockoutEnd;
132 
133 /* Policy attributes */
134 static AttributeDescription *ad_pwdMinAge, *ad_pwdMaxAge, *ad_pwdMaxIdle,
135 	*ad_pwdInHistory, *ad_pwdCheckQuality, *ad_pwdMinLength, *ad_pwdMaxLength,
136 	*ad_pwdMaxFailure, *ad_pwdGraceExpiry, *ad_pwdGraceAuthNLimit,
137 	*ad_pwdExpireWarning, *ad_pwdMinDelay, *ad_pwdMaxDelay,
138 	*ad_pwdLockoutDuration, *ad_pwdFailureCountInterval,
139 	*ad_pwdCheckModule, *ad_pwdCheckModuleArg, *ad_pwdUseCheckModule, *ad_pwdLockout,
140 	*ad_pwdMustChange, *ad_pwdAllowUserChange, *ad_pwdSafeModify,
141 	*ad_pwdAttribute, *ad_pwdMaxRecordedFailure;
142 
143 static struct schema_info {
144 	char *def;
145 	AttributeDescription **ad;
146 } pwd_OpSchema[] = {
147 	{	"( 1.3.6.1.4.1.42.2.27.8.1.16 "
148 		"NAME ( 'pwdChangedTime' ) "
149 		"DESC 'The time the password was last changed' "
150 		"EQUALITY generalizedTimeMatch "
151 		"ORDERING generalizedTimeOrderingMatch "
152 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
153 		"SINGLE-VALUE "
154 		"NO-USER-MODIFICATION "
155 		"USAGE directoryOperation )",
156 		&ad_pwdChangedTime },
157 	{	"( 1.3.6.1.4.1.42.2.27.8.1.17 "
158 		"NAME ( 'pwdAccountLockedTime' ) "
159 		"DESC 'The time an user account was locked' "
160 		"EQUALITY generalizedTimeMatch "
161 		"ORDERING generalizedTimeOrderingMatch "
162 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
163 		"SINGLE-VALUE "
164 #if 0 /* FIXME: ITS#9671 until we introduce a separate lockout flag? */
165 		"NO-USER-MODIFICATION "
166 #endif
167 		"USAGE directoryOperation )",
168 		&ad_pwdAccountLockedTime },
169 	{	"( 1.3.6.1.4.1.42.2.27.8.1.19 "
170 		"NAME ( 'pwdFailureTime' ) "
171 		"DESC 'The timestamps of the last consecutive authentication failures' "
172 		"EQUALITY generalizedTimeMatch "
173 		"ORDERING generalizedTimeOrderingMatch "
174 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
175 		"NO-USER-MODIFICATION "
176 		"USAGE directoryOperation )",
177 		&ad_pwdFailureTime },
178 	{	"( 1.3.6.1.4.1.42.2.27.8.1.20 "
179 		"NAME ( 'pwdHistory' ) "
180 		"DESC 'The history of users passwords' "
181 		"EQUALITY octetStringMatch "
182 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 "
183 		"NO-USER-MODIFICATION "
184 		"USAGE directoryOperation )",
185 		&ad_pwdHistory },
186 	{	"( 1.3.6.1.4.1.42.2.27.8.1.21 "
187 		"NAME ( 'pwdGraceUseTime' ) "
188 		"DESC 'The timestamps of the grace login once the password has expired' "
189 		"EQUALITY generalizedTimeMatch "
190 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
191 		"NO-USER-MODIFICATION "
192 		"USAGE directoryOperation )",
193 		&ad_pwdGraceUseTime },
194 	{	"( 1.3.6.1.4.1.42.2.27.8.1.22 "
195 		"NAME ( 'pwdReset' ) "
196 		"DESC 'The indication that the password has been reset' "
197 		"EQUALITY booleanMatch "
198 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
199 		"SINGLE-VALUE "
200 		"USAGE directoryOperation )",
201 		&ad_pwdReset },
202 	{	"( 1.3.6.1.4.1.42.2.27.8.1.23 "
203 		"NAME ( 'pwdPolicySubentry' ) "
204 		"DESC 'The pwdPolicy subentry in effect for this object' "
205 		"EQUALITY distinguishedNameMatch "
206 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
207 		"SINGLE-VALUE "
208 #if 0 /* ITS#9671: until we implement ITS#9343 or similar */
209 		"NO-USER-MODIFICATION "
210 #endif
211 		"USAGE directoryOperation )",
212 		&ad_pwdPolicySubentry },
213 	{	"( 1.3.6.1.4.1.42.2.27.8.1.27 "
214 		"NAME ( 'pwdStartTime' ) "
215 		"DESC 'The time the password becomes enabled' "
216 		"EQUALITY generalizedTimeMatch "
217 		"ORDERING generalizedTimeOrderingMatch "
218 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
219 		"SINGLE-VALUE "
220 		"USAGE directoryOperation )",
221 		&ad_pwdStartTime },
222 	{	"( 1.3.6.1.4.1.42.2.27.8.1.28 "
223 		"NAME ( 'pwdEndTime' ) "
224 		"DESC 'The time the password becomes disabled' "
225 		"EQUALITY generalizedTimeMatch "
226 		"ORDERING generalizedTimeOrderingMatch "
227 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
228 		"SINGLE-VALUE "
229 		"USAGE directoryOperation )",
230 		&ad_pwdEndTime },
231 	/* Defined in schema_prep.c now
232 	{	"( 1.3.6.1.4.1.42.2.27.8.1.29 "
233 		"NAME ( 'pwdLastSuccess' ) "
234 		"DESC 'The timestamp of the last successful authentication' "
235 		"EQUALITY generalizedTimeMatch "
236 		"ORDERING generalizedTimeOrderingMatch "
237 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
238 		"SINGLE-VALUE "
239 		"NO-USER-MODIFICATION "
240 		"USAGE directoryOperation )",
241 		&ad_pwdLastSuccess },
242 	*/
243 	{	"( 1.3.6.1.4.1.42.2.27.8.1.33 "
244 		"NAME ( 'pwdAccountTmpLockoutEnd' ) "
245 		"DESC 'Temporary lockout end' "
246 		"EQUALITY generalizedTimeMatch "
247 		"ORDERING generalizedTimeOrderingMatch "
248 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
249 		"SINGLE-VALUE "
250 		"NO-USER-MODIFICATION "
251 		"USAGE directoryOperation )",
252 		&ad_pwdAccountTmpLockoutEnd },
253 
254 	{	"( 1.3.6.1.4.1.42.2.27.8.1.1 "
255 		"NAME ( 'pwdAttribute' ) "
256 		"EQUALITY objectIdentifierMatch "
257 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
258 		&ad_pwdAttribute },
259 	{	"( 1.3.6.1.4.1.42.2.27.8.1.2 "
260 		"NAME ( 'pwdMinAge' ) "
261 		"EQUALITY integerMatch "
262 		"ORDERING integerOrderingMatch "
263 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
264 		"SINGLE-VALUE )",
265 		&ad_pwdMinAge },
266 	{	"( 1.3.6.1.4.1.42.2.27.8.1.3 "
267 		"NAME ( 'pwdMaxAge' ) "
268 		"EQUALITY integerMatch "
269 		"ORDERING integerOrderingMatch "
270 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
271 		"SINGLE-VALUE )",
272 		&ad_pwdMaxAge },
273 	{	"( 1.3.6.1.4.1.42.2.27.8.1.4 "
274 		"NAME ( 'pwdInHistory' ) "
275 		"EQUALITY integerMatch "
276 		"ORDERING integerOrderingMatch "
277 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
278 		"SINGLE-VALUE )",
279 		&ad_pwdInHistory },
280 	{	"( 1.3.6.1.4.1.42.2.27.8.1.5 "
281 		"NAME ( 'pwdCheckQuality' ) "
282 		"EQUALITY integerMatch "
283 		"ORDERING integerOrderingMatch "
284 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
285 		"SINGLE-VALUE )",
286 		&ad_pwdCheckQuality },
287 	{	"( 1.3.6.1.4.1.42.2.27.8.1.6 "
288 		"NAME ( 'pwdMinLength' ) "
289 		"EQUALITY integerMatch "
290 		"ORDERING integerOrderingMatch "
291 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
292 		"SINGLE-VALUE )",
293 		&ad_pwdMinLength },
294 	{	"( 1.3.6.1.4.1.42.2.27.8.1.31 "
295 		"NAME ( 'pwdMaxLength' ) "
296 		"EQUALITY integerMatch "
297 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
298 		"SINGLE-VALUE )",
299 		&ad_pwdMaxLength },
300 	{	"( 1.3.6.1.4.1.42.2.27.8.1.7 "
301 		"NAME ( 'pwdExpireWarning' ) "
302 		"EQUALITY integerMatch "
303 		"ORDERING integerOrderingMatch "
304 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
305 		"SINGLE-VALUE )",
306 		&ad_pwdExpireWarning },
307 	{	"( 1.3.6.1.4.1.42.2.27.8.1.8 "
308 		"NAME ( 'pwdGraceAuthNLimit' ) "
309 		"EQUALITY integerMatch "
310 		"ORDERING integerOrderingMatch "
311 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
312 		"SINGLE-VALUE )",
313 		&ad_pwdGraceAuthNLimit },
314 	{	"( 1.3.6.1.4.1.42.2.27.8.1.30 "
315 		"NAME ( 'pwdGraceExpiry' ) "
316 		"EQUALITY integerMatch "
317 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
318 		"SINGLE-VALUE )",
319 		&ad_pwdGraceExpiry },
320 	{	"( 1.3.6.1.4.1.42.2.27.8.1.9 "
321 		"NAME ( 'pwdLockout' ) "
322 		"EQUALITY booleanMatch "
323 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
324 		"SINGLE-VALUE )",
325 		&ad_pwdLockout },
326 	{	"( 1.3.6.1.4.1.42.2.27.8.1.10 "
327 		"NAME ( 'pwdLockoutDuration' ) "
328 		"EQUALITY integerMatch "
329 		"ORDERING integerOrderingMatch "
330 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
331 		"SINGLE-VALUE )",
332 		&ad_pwdLockoutDuration },
333 	{	"( 1.3.6.1.4.1.42.2.27.8.1.11 "
334 		"NAME ( 'pwdMaxFailure' ) "
335 		"EQUALITY integerMatch "
336 		"ORDERING integerOrderingMatch "
337 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
338 		"SINGLE-VALUE )",
339 		&ad_pwdMaxFailure },
340 	{	"( 1.3.6.1.4.1.42.2.27.8.1.12 "
341 		"NAME ( 'pwdFailureCountInterval' ) "
342 		"EQUALITY integerMatch "
343 		"ORDERING integerOrderingMatch "
344 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
345 		"SINGLE-VALUE )",
346 		&ad_pwdFailureCountInterval },
347 	{	"( 1.3.6.1.4.1.42.2.27.8.1.13 "
348 		"NAME ( 'pwdMustChange' ) "
349 		"EQUALITY booleanMatch "
350 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
351 		"SINGLE-VALUE )",
352 		&ad_pwdMustChange },
353 	{	"( 1.3.6.1.4.1.42.2.27.8.1.14 "
354 		"NAME ( 'pwdAllowUserChange' ) "
355 		"EQUALITY booleanMatch "
356 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
357 		"SINGLE-VALUE )",
358 		&ad_pwdAllowUserChange },
359 	{	"( 1.3.6.1.4.1.42.2.27.8.1.15 "
360 		"NAME ( 'pwdSafeModify' ) "
361 		"EQUALITY booleanMatch "
362 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
363 		"SINGLE-VALUE )",
364 		&ad_pwdSafeModify },
365 	{	"( 1.3.6.1.4.1.42.2.27.8.1.24 "
366 		"NAME ( 'pwdMinDelay' ) "
367 		"EQUALITY integerMatch "
368 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
369 		"SINGLE-VALUE )",
370 		&ad_pwdMinDelay },
371 	{	"( 1.3.6.1.4.1.42.2.27.8.1.25 "
372 		"NAME ( 'pwdMaxDelay' ) "
373 		"EQUALITY integerMatch "
374 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
375 		"SINGLE-VALUE )",
376 		&ad_pwdMaxDelay },
377 	{	"( 1.3.6.1.4.1.42.2.27.8.1.26 "
378 		"NAME ( 'pwdMaxIdle' ) "
379 		"EQUALITY integerMatch "
380 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
381 		"SINGLE-VALUE )",
382 		&ad_pwdMaxIdle },
383 	{	"( 1.3.6.1.4.1.42.2.27.8.1.32 "
384 		"NAME ( 'pwdMaxRecordedFailure' ) "
385 		"EQUALITY integerMatch "
386 		"ORDERING integerOrderingMatch "
387 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
388 		"SINGLE-VALUE )",
389 		&ad_pwdMaxRecordedFailure },
390 	{	"( 1.3.6.1.4.1.4754.1.99.1 "
391 		"NAME ( 'pwdCheckModule' ) "
392 		"EQUALITY caseExactIA5Match "
393 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 "
394 		"DESC 'Obsolete, no longer used' "
395 		"OBSOLETE "
396 		"SINGLE-VALUE )",
397 		&ad_pwdCheckModule },
398 	{	"( 1.3.6.1.4.1.4754.1.99.2 "
399 		"NAME ( 'pwdCheckModuleArg' ) "
400 		"EQUALITY octetStringMatch "
401 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 "
402 		"DESC 'Argument to pass to check_password() function' "
403 		"SINGLE-VALUE )",
404 		&ad_pwdCheckModuleArg },
405 	{	"( 1.3.6.1.4.1.4754.1.99.3 "
406 		"NAME ( 'pwdUseCheckModule' ) "
407 		"EQUALITY booleanMatch "
408 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
409 		"DESC 'Toggle use of the loaded pwdCheckModule' "
410 		"SINGLE-VALUE )",
411 		&ad_pwdUseCheckModule },
412 
413 	{ NULL, NULL }
414 };
415 
416 static char *pwd_ocs[] = {
417 	"( 1.3.6.1.4.1.4754.2.99.1 "
418 		"NAME 'pwdPolicyChecker' "
419 		"SUP top "
420 		"AUXILIARY "
421 		"MAY ( pwdCheckModule $ pwdCheckModuleArg $ pwdUseCheckModule ) )" ,
422 	"( 1.3.6.1.4.1.42.2.27.8.2.1 "
423 		"NAME 'pwdPolicy' "
424 		"SUP top "
425 		"AUXILIARY "
426 		"MUST ( pwdAttribute ) "
427 		"MAY ( pwdMinAge $ pwdMaxAge $ pwdInHistory $ pwdCheckQuality $ "
428 		"pwdMinLength $ pwdMaxLength $ pwdExpireWarning $ "
429 		"pwdGraceAuthNLimit $ pwdGraceExpiry $ pwdLockout $ "
430 		"pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $ "
431 		"pwdMustChange $ pwdAllowUserChange $ pwdSafeModify $ "
432 		"pwdMinDelay $ pwdMaxDelay $ pwdMaxIdle $ "
433 		"pwdMaxRecordedFailure ) )",
434 	NULL
435 };
436 
437 static ldap_pvt_thread_mutex_t chk_syntax_mutex;
438 
439 enum {
440 	PPOLICY_DEFAULT = 1,
441 	PPOLICY_HASH_CLEARTEXT,
442 	PPOLICY_USE_LOCKOUT,
443 	PPOLICY_DISABLE_WRITE,
444 	PPOLICY_CHECK_MODULE,
445 };
446 
447 static ConfigDriver ppolicy_cf_default, ppolicy_cf_checkmod;
448 
449 static ConfigTable ppolicycfg[] = {
450 	{ "ppolicy_default", "policyDN", 2, 2, 0,
451 	  ARG_DN|ARG_QUOTE|ARG_MAGIC|PPOLICY_DEFAULT, ppolicy_cf_default,
452 	  "( OLcfgOvAt:12.1 NAME 'olcPPolicyDefault' "
453 	  "DESC 'DN of a pwdPolicy object for uncustomized objects' "
454 	  "EQUALITY distinguishedNameMatch "
455 	  "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
456 	{ "ppolicy_hash_cleartext", "on|off", 1, 2, 0,
457 	  ARG_ON_OFF|ARG_OFFSET|PPOLICY_HASH_CLEARTEXT,
458 	  (void *)offsetof(pp_info,hash_passwords),
459 	  "( OLcfgOvAt:12.2 NAME 'olcPPolicyHashCleartext' "
460 	  "DESC 'Hash passwords on add or modify' "
461 	  "EQUALITY booleanMatch "
462 	  "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
463 	{ "ppolicy_forward_updates", "on|off", 1, 2, 0,
464 	  ARG_ON_OFF|ARG_OFFSET,
465 	  (void *)offsetof(pp_info,forward_updates),
466 	  "( OLcfgOvAt:12.4 NAME 'olcPPolicyForwardUpdates' "
467 	  "DESC 'Allow policy state updates to be forwarded via updateref' "
468 	  "EQUALITY booleanMatch "
469 	  "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
470 	{ "ppolicy_use_lockout", "on|off", 1, 2, 0,
471 	  ARG_ON_OFF|ARG_OFFSET|PPOLICY_USE_LOCKOUT,
472 	  (void *)offsetof(pp_info,use_lockout),
473 	  "( OLcfgOvAt:12.3 NAME 'olcPPolicyUseLockout' "
474 	  "DESC 'Warn clients with AccountLocked' "
475 	  "EQUALITY booleanMatch "
476 	  "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
477 	{ "ppolicy_disable_write", "on|off", 1, 2, 0,
478 	  ARG_ON_OFF|ARG_OFFSET|PPOLICY_DISABLE_WRITE,
479 	  (void *)offsetof(pp_info,disable_write),
480 	  "( OLcfgOvAt:12.5 NAME 'olcPPolicyDisableWrite' "
481 	  "DESC 'Prevent all policy overlay writes' "
482 	  "EQUALITY booleanMatch "
483 	  "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
484 	{ "ppolicy_send_netscape_controls", "on|off", 1, 2, 0,
485 	  ARG_ON_OFF|ARG_OFFSET,
486 	  (void *)offsetof(pp_info,send_netscape_controls),
487 	  "( OLcfgOvAt:12.6 NAME 'olcPPolicySendNetscapeControls' "
488 	  "DESC 'Send Netscape policy controls' "
489 	  "EQUALITY booleanMatch "
490 	  "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
491 	{ "ppolicy_check_module", "path", 2, 2, 0,
492 	  ARG_STRING|ARG_MAGIC|PPOLICY_CHECK_MODULE, ppolicy_cf_checkmod,
493 	  "( OLcfgOvAt:12.7 NAME 'olcPPolicyCheckModule' "
494 	  "DESC 'Loadable module that instantiates check_password() function' "
495 	  "EQUALITY caseExactIA5Match "
496 	  "SYNTAX OMsIA5String "
497 	  "SINGLE-VALUE )", NULL, NULL },
498 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
499 };
500 
501 static ConfigOCs ppolicyocs[] = {
502 	{ "( OLcfgOvOc:12.1 "
503 	  "NAME 'olcPPolicyConfig' "
504 	  "DESC 'Password Policy configuration' "
505 	  "SUP olcOverlayConfig "
506 	  "MAY ( olcPPolicyDefault $ olcPPolicyHashCleartext $ "
507 	  "olcPPolicyUseLockout $ olcPPolicyForwardUpdates $ "
508 	  "olcPPolicyDisableWrite $ olcPPolicySendNetscapeControls $ "
509 	  "olcPPolicyCheckModule ) )",
510 	  Cft_Overlay, ppolicycfg },
511 	{ NULL, 0, NULL }
512 };
513 
514 static int
ppolicy_cf_default(ConfigArgs * c)515 ppolicy_cf_default( ConfigArgs *c )
516 {
517 	slap_overinst *on = (slap_overinst *)c->bi;
518 	pp_info *pi = (pp_info *)on->on_bi.bi_private;
519 	int rc = ARG_BAD_CONF;
520 
521 	assert ( c->type == PPOLICY_DEFAULT );
522 	Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default\n" );
523 
524 	switch ( c->op ) {
525 	case SLAP_CONFIG_EMIT:
526 		Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default emit\n" );
527 		rc = 0;
528 		if ( !BER_BVISEMPTY( &pi->def_policy )) {
529 			rc = value_add_one( &c->rvalue_vals,
530 					    &pi->def_policy );
531 			if ( rc ) return rc;
532 			rc = value_add_one( &c->rvalue_nvals,
533 					    &pi->def_policy );
534 		}
535 		break;
536 	case LDAP_MOD_DELETE:
537 		Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default delete\n" );
538 		if ( pi->def_policy.bv_val ) {
539 			ber_memfree ( pi->def_policy.bv_val );
540 			pi->def_policy.bv_val = NULL;
541 		}
542 		pi->def_policy.bv_len = 0;
543 		rc = 0;
544 		break;
545 	case SLAP_CONFIG_ADD:
546 		/* fallthru to LDAP_MOD_ADD */
547 	case LDAP_MOD_ADD:
548 		Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default add\n" );
549 		if ( pi->def_policy.bv_val ) {
550 			ber_memfree ( pi->def_policy.bv_val );
551 		}
552 		pi->def_policy = c->value_ndn;
553 		ber_memfree( c->value_dn.bv_val );
554 		BER_BVZERO( &c->value_dn );
555 		BER_BVZERO( &c->value_ndn );
556 		rc = 0;
557 		break;
558 	default:
559 		abort ();
560 	}
561 
562 	return rc;
563 }
564 
565 static int
ppolicy_cf_checkmod(ConfigArgs * c)566 ppolicy_cf_checkmod( ConfigArgs *c )
567 {
568 	slap_overinst *on = (slap_overinst *)c->bi;
569 	pp_info *pi = (pp_info *)on->on_bi.bi_private;
570 	int rc = ARG_BAD_CONF;
571 
572 	assert ( c->type == PPOLICY_CHECK_MODULE );
573 	Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_checkmod\n" );
574 
575 	switch ( c->op ) {
576 	case SLAP_CONFIG_EMIT:
577 		if ( pi->pwdCheckModule ) {
578 			c->value_string = ch_strdup( pi->pwdCheckModule );
579 			rc = 0;
580 		}
581 		break;
582 	case LDAP_MOD_DELETE:
583 		if ( pi->pwdCheckHandle ) {
584 			lt_dlclose( pi->pwdCheckHandle );
585 			pi->pwdCheckHandle = NULL;
586 			pi->pwdCheckFunc = NULL;
587 		}
588 		ch_free( pi->pwdCheckModule );
589 		pi->pwdCheckModule = NULL;
590 		rc = 0;
591 		break;
592 	case SLAP_CONFIG_ADD:
593 		/* fallthru to LDAP_MOD_ADD */
594 	case LDAP_MOD_ADD:
595 		pi->pwdCheckHandle = lt_dlopen( c->value_string );
596 		if ( pi->pwdCheckHandle == NULL ) {
597 			const char *dlerr = lt_dlerror();
598 			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> lt_dlopen(%s) failed: %s",
599 				c->argv[0], c->value_string, dlerr );
600 			Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
601 		} else {
602 			if (( pi->pwdCheckFunc = lt_dlsym( pi->pwdCheckHandle, "check_password" )) == NULL) {
603 				const char *dlerr = lt_dlerror();
604 				snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> lt_dlsym(%s) failed: %s",
605 					c->argv[0], c->value_string, dlerr );
606 				Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
607 			} else {
608 				pi->pwdCheckModule = c->value_string;
609 				rc = 0;
610 			}
611 		}
612 		break;
613 	default:
614 		abort ();
615 	}
616 
617 	return rc;
618 }
619 
620 static time_t
parse_time(char * atm)621 parse_time( char *atm )
622 {
623 	struct lutil_tm tm;
624 	struct lutil_timet tt;
625 	time_t ret = (time_t)-1;
626 
627 	if ( lutil_parsetime( atm, &tm ) == 0) {
628 		lutil_tm2time( &tm, &tt );
629 		ret = tt.tt_sec;
630 	}
631 	return ret;
632 }
633 
634 static int
account_locked(Operation * op,Entry * e,PassPolicy * pp,Modifications ** mod)635 account_locked( Operation *op, Entry *e,
636 		PassPolicy *pp, Modifications **mod )
637 {
638 	Attribute       *la;
639 
640 	if ( (la = attr_find( e->e_attrs, ad_pwdStartTime )) != NULL ) {
641 		BerVarray vals = la->a_nvals;
642 		time_t then, now = op->o_time;
643 
644 		/*
645 		 * Password has a defined start of validity
646 		 */
647 		if ( vals[0].bv_val != NULL ) {
648 			if ( (then = parse_time( vals[0].bv_val )) == (time_t)-1 ) {
649 				return 1;
650 			}
651 			if ( now < then ) {
652 				return 1;
653 			}
654 		}
655 	}
656 
657 	if ( (la = attr_find( e->e_attrs, ad_pwdEndTime )) != NULL ) {
658 		BerVarray vals = la->a_nvals;
659 		time_t then, now = op->o_time;
660 
661 		/*
662 		 * Password has a defined end of validity
663 		 */
664 		if ( vals[0].bv_val != NULL ) {
665 			if ( (then = parse_time( vals[0].bv_val )) == (time_t)-1 ) {
666 				return 1;
667 			}
668 			if ( then <= now ) {
669 				return 1;
670 			}
671 		}
672 	}
673 
674 	if ( !pp->pwdLockout )
675 		return 0;
676 
677 	if ( (la = attr_find( e->e_attrs, ad_pwdAccountTmpLockoutEnd )) != NULL ) {
678 		BerVarray vals = la->a_nvals;
679 		time_t then, now = op->o_time;
680 
681 		/*
682 		 * We have temporarily locked the account after a failure
683 		 */
684 		if ( vals[0].bv_val != NULL ) {
685 			if ( (then = parse_time( vals[0].bv_val )) == (time_t)-1 ) {
686 				return 1;
687 			}
688 			if ( now < then ) {
689 				return 1;
690 			}
691 		}
692 	}
693 
694 	/* Only check if database maintains lastbind */
695 	if ( pp->pwdMaxIdle && SLAP_LASTBIND( op->o_bd ) ) {
696 		time_t lastbindtime = (time_t)-1;
697 
698 		la = attr_find( e->e_attrs, ad_pwdLastSuccess );
699 		if ( la == NULL ) {
700 			la = attr_find( e->e_attrs, ad_pwdChangedTime );
701 		}
702 		if ( la != NULL ) {
703 			lastbindtime = parse_time( la->a_nvals[0].bv_val );
704 		}
705 
706 		if ( lastbindtime != (time_t)-1 &&
707 				op->o_time > lastbindtime + pp->pwdMaxIdle ) {
708 			return 1;
709 		}
710 	}
711 
712 	if ( (la = attr_find( e->e_attrs, ad_pwdAccountLockedTime )) != NULL ) {
713 		BerVarray vals = la->a_nvals;
714 
715 		/*
716 		 * there is a lockout stamp - we now need to know if it's
717 		 * a valid one.
718 		 */
719 		if (vals[0].bv_val != NULL) {
720 			time_t then, now;
721 			Modifications *m;
722 
723 			if ((then = parse_time( vals[0].bv_val )) == (time_t)0)
724 				return 1;
725 
726 			now = slap_get_time();
727 
728 			/* Still in the future? not yet in effect */
729 			if (now < then)
730 				return 0;
731 
732 			if (!pp->pwdLockoutDuration)
733 				return 1;
734 
735 			if (now < then + pp->pwdLockoutDuration)
736 				return 1;
737 
738 			if ( mod != NULL ) {
739 				m = ch_calloc( sizeof(Modifications), 1 );
740 				m->sml_op = LDAP_MOD_DELETE;
741 				m->sml_flags = 0;
742 				m->sml_type = ad_pwdAccountLockedTime->ad_cname;
743 				m->sml_desc = ad_pwdAccountLockedTime;
744 				m->sml_next = *mod;
745 				*mod = m;
746 			}
747 		}
748 	}
749 
750 	return 0;
751 }
752 
753 /* IMPLICIT TAGS, all context-specific */
754 #define PPOLICY_WARNING 0xa0L	/* constructed + 0 */
755 #define PPOLICY_ERROR 0x81L		/* primitive + 1 */
756 
757 #define PPOLICY_EXPIRE 0x80L	/* primitive + 0 */
758 #define PPOLICY_GRACE  0x81L	/* primitive + 1 */
759 
760 static const char ppolicy_ctrl_oid[] = LDAP_CONTROL_PASSWORDPOLICYRESPONSE;
761 static const char ppolicy_account_ctrl_oid[] = LDAP_CONTROL_X_ACCOUNT_USABILITY;
762 static const char ppolicy_pwd_expired_oid[] = LDAP_CONTROL_X_PASSWORD_EXPIRED;
763 static const char ppolicy_pwd_expiring_oid[] = LDAP_CONTROL_X_PASSWORD_EXPIRING;
764 
765 static LDAPControl *
create_passcontrol(Operation * op,int exptime,int grace,LDAPPasswordPolicyError err)766 create_passcontrol( Operation *op, int exptime, int grace, LDAPPasswordPolicyError err )
767 {
768 	BerElementBuffer berbuf, bb2;
769 	BerElement *ber = (BerElement *) &berbuf, *b2 = (BerElement *) &bb2;
770 	LDAPControl c = { 0 }, *cp;
771 	struct berval bv;
772 	int rc;
773 
774 	BER_BVZERO( &c.ldctl_value );
775 
776 	ber_init2( ber, NULL, LBER_USE_DER );
777 	ber_printf( ber, "{" /*}*/ );
778 
779 	if ( exptime >= 0 ) {
780 		ber_init2( b2, NULL, LBER_USE_DER );
781 		ber_printf( b2, "ti", PPOLICY_EXPIRE, exptime );
782 		rc = ber_flatten2( b2, &bv, 1 );
783 		(void)ber_free_buf(b2);
784 		if (rc == -1) {
785 			cp = NULL;
786 			goto fail;
787 		}
788 		ber_printf( ber, "tO", PPOLICY_WARNING, &bv );
789 		ch_free( bv.bv_val );
790 	} else if ( grace >= 0 ) {
791 		ber_init2( b2, NULL, LBER_USE_DER );
792 		ber_printf( b2, "ti", PPOLICY_GRACE, grace );
793 		rc = ber_flatten2( b2, &bv, 1 );
794 		(void)ber_free_buf(b2);
795 		if (rc == -1) {
796 			cp = NULL;
797 			goto fail;
798 		}
799 		ber_printf( ber, "tO", PPOLICY_WARNING, &bv );
800 		ch_free( bv.bv_val );
801 	}
802 
803 	if (err != PP_noError ) {
804 		ber_printf( ber, "te", PPOLICY_ERROR, err );
805 	}
806 	ber_printf( ber, /*{*/ "N}" );
807 
808 	if (ber_flatten2( ber, &c.ldctl_value, 0 ) == -1) {
809 		return NULL;
810 	}
811 	cp = op->o_tmpalloc( sizeof( LDAPControl ) + c.ldctl_value.bv_len, op->o_tmpmemctx );
812 	cp->ldctl_oid = (char *)ppolicy_ctrl_oid;
813 	cp->ldctl_iscritical = 0;
814 	cp->ldctl_value.bv_val = (char *)&cp[1];
815 	cp->ldctl_value.bv_len = c.ldctl_value.bv_len;
816 	AC_MEMCPY( cp->ldctl_value.bv_val, c.ldctl_value.bv_val, c.ldctl_value.bv_len );
817 fail:
818 	(void)ber_free_buf(ber);
819 
820 	return cp;
821 }
822 
823 static LDAPControl *
create_passexpiry(Operation * op,int expired,int warn)824 create_passexpiry( Operation *op, int expired, int warn )
825 {
826 	LDAPControl *cp;
827 	char buf[sizeof("-2147483648")];
828 	struct berval bv = { .bv_val = buf, .bv_len = sizeof(buf) };
829 
830 	bv.bv_len = snprintf( bv.bv_val, bv.bv_len, "%d", warn );
831 
832 	cp = op->o_tmpalloc( sizeof( LDAPControl ) + bv.bv_len, op->o_tmpmemctx );
833 	if ( expired ) {
834 		cp->ldctl_oid = (char *)ppolicy_pwd_expired_oid;
835 	} else {
836 		cp->ldctl_oid = (char *)ppolicy_pwd_expiring_oid;
837 	}
838 	cp->ldctl_iscritical = 0;
839 	cp->ldctl_value.bv_val = (char *)&cp[1];
840 	cp->ldctl_value.bv_len = bv.bv_len;
841 	AC_MEMCPY( cp->ldctl_value.bv_val, bv.bv_val, bv.bv_len );
842 	return cp;
843 }
844 
845 static LDAPControl **
add_passcontrol(Operation * op,SlapReply * rs,LDAPControl * ctrl)846 add_passcontrol( Operation *op, SlapReply *rs, LDAPControl *ctrl )
847 {
848 	LDAPControl **ctrls, **oldctrls = rs->sr_ctrls;
849 	int n;
850 
851 	n = 0;
852 	if ( oldctrls ) {
853 		for ( ; oldctrls[n]; n++ )
854 			;
855 	}
856 	n += 2;
857 
858 	ctrls = op->o_tmpcalloc( sizeof( LDAPControl * ), n, op->o_tmpmemctx );
859 
860 	n = 0;
861 	if ( oldctrls ) {
862 		for ( ; oldctrls[n]; n++ ) {
863 			ctrls[n] = oldctrls[n];
864 		}
865 	}
866 	ctrls[n] = ctrl;
867 	ctrls[n+1] = NULL;
868 
869 	rs->sr_ctrls = ctrls;
870 
871 	return oldctrls;
872 }
873 
874 static void
add_account_control(Operation * op,SlapReply * rs,int available,int remaining,LDAPAccountUsabilityMoreInfo * more_info)875 add_account_control(
876 	Operation *op,
877 	SlapReply *rs,
878 	int available,
879 	int remaining,
880 	LDAPAccountUsabilityMoreInfo *more_info )
881 {
882 	BerElementBuffer berbuf;
883 	BerElement *ber = (BerElement *) &berbuf;
884 	LDAPControl c = { 0 }, *cp = NULL, **ctrls;
885 	int i = 0;
886 
887 	BER_BVZERO( &c.ldctl_value );
888 
889 	ber_init2( ber, NULL, LBER_USE_DER );
890 
891 	if ( available ) {
892 		ber_put_int( ber, remaining, LDAP_TAG_X_ACCOUNT_USABILITY_AVAILABLE );
893 	} else {
894 		assert( more_info != NULL );
895 
896 		ber_start_seq( ber, LDAP_TAG_X_ACCOUNT_USABILITY_NOT_AVAILABLE );
897 		ber_put_boolean( ber, more_info->inactive, LDAP_TAG_X_ACCOUNT_USABILITY_INACTIVE );
898 		ber_put_boolean( ber, more_info->reset, LDAP_TAG_X_ACCOUNT_USABILITY_RESET );
899 		ber_put_boolean( ber, more_info->expired, LDAP_TAG_X_ACCOUNT_USABILITY_EXPIRED );
900 		ber_put_int( ber, more_info->remaining_grace, LDAP_TAG_X_ACCOUNT_USABILITY_REMAINING_GRACE );
901 		ber_put_int( ber, more_info->seconds_before_unlock, LDAP_TAG_X_ACCOUNT_USABILITY_UNTIL_UNLOCK );
902 		ber_put_seq( ber );
903 	}
904 
905 	if (ber_flatten2( ber, &c.ldctl_value, 0 ) == -1) {
906 		goto fail;
907 	}
908 
909 	if ( rs->sr_ctrls != NULL ) {
910 		for ( ; rs->sr_ctrls[ i ] != NULL; i++ ) /* Count */;
911 	}
912 
913 	ctrls = op->o_tmprealloc( rs->sr_ctrls, sizeof(LDAPControl *)*( i + 2 ), op->o_tmpmemctx );
914 	if ( ctrls == NULL ) {
915 		goto fail;
916 	}
917 
918 	cp = op->o_tmpalloc( sizeof( LDAPControl ) + c.ldctl_value.bv_len, op->o_tmpmemctx );
919 	cp->ldctl_oid = (char *)ppolicy_account_ctrl_oid;
920 	cp->ldctl_iscritical = 0;
921 	cp->ldctl_value.bv_val = (char *)&cp[1];
922 	cp->ldctl_value.bv_len = c.ldctl_value.bv_len;
923 	AC_MEMCPY( cp->ldctl_value.bv_val, c.ldctl_value.bv_val, c.ldctl_value.bv_len );
924 
925 	ctrls[ i ] = cp;
926 	ctrls[ i + 1 ] = NULL;
927 	rs->sr_ctrls = ctrls;
928 
929 fail:
930 	(void)ber_free_buf(ber);
931 }
932 
933 static void
ppolicy_get_default(PassPolicy * pp)934 ppolicy_get_default( PassPolicy *pp )
935 {
936 	memset( pp, 0, sizeof(PassPolicy) );
937 
938 	pp->ad = slap_schema.si_ad_userPassword;
939 
940 	/* Users can change their own password by default */
941 	pp->pwdAllowUserChange = 1;
942 }
943 
944 
945 static int
ppolicy_get(Operation * op,Entry * e,PassPolicy * pp)946 ppolicy_get( Operation *op, Entry *e, PassPolicy *pp )
947 {
948 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
949 	pp_info *pi = on->on_bi.bi_private;
950 	BackendDB *bd, *bd_orig = op->o_bd;
951 	AttributeDescription *ad = NULL;
952 	Attribute *a;
953 	BerVarray vals;
954 	int rc = LDAP_SUCCESS;
955 	Entry *pe = NULL;
956 #if 0
957 	const char *text;
958 #endif
959 
960 	ppolicy_get_default( pp );
961 
962 	ad = ad_pwdPolicySubentry;
963 	if ( (a = attr_find( e->e_attrs, ad )) == NULL ) {
964 		/*
965 		 * entry has no password policy assigned - use default
966 		 */
967 		vals = &pi->def_policy;
968 		if ( !vals->bv_val )
969 			goto defaultpol;
970 	} else {
971 		vals = a->a_nvals;
972 		if (vals[0].bv_val == NULL) {
973 			Debug( LDAP_DEBUG_ANY,
974 				"ppolicy_get: NULL value for policySubEntry\n" );
975 			goto defaultpol;
976 		}
977 	}
978 
979 	op->o_bd = bd = select_backend( vals, 0 );
980 	if ( op->o_bd == NULL ) {
981 		op->o_bd = bd_orig;
982 		goto defaultpol;
983 	}
984 
985 	rc = be_entry_get_rw( op, vals, NULL, NULL, 0, &pe );
986 	op->o_bd = bd_orig;
987 
988 	if ( rc ) goto defaultpol;
989 
990 #if 0	/* Only worry about userPassword for now */
991 	if ((a = attr_find( pe->e_attrs, ad_pwdAttribute )))
992 		slap_bv2ad( &a->a_vals[0], &pp->ad, &text );
993 #endif
994 
995 	ad = ad_pwdMinAge;
996 	if ( (a = attr_find( pe->e_attrs, ad ))
997 			&& lutil_atoi( &pp->pwdMinAge, a->a_vals[0].bv_val ) != 0 ) {
998 		rc = LDAP_CONSTRAINT_VIOLATION;
999 		goto defaultpol;
1000 	}
1001 
1002 	ad = ad_pwdMaxAge;
1003 	if ( (a = attr_find( pe->e_attrs, ad ))
1004 			&& lutil_atoi( &pp->pwdMaxAge, a->a_vals[0].bv_val ) != 0 ) {
1005 		rc = LDAP_CONSTRAINT_VIOLATION;
1006 		goto defaultpol;
1007 	}
1008 
1009 	ad = ad_pwdMaxIdle;
1010 	if ( (a = attr_find( pe->e_attrs, ad ))
1011 			&& lutil_atoi( &pp->pwdMaxIdle, a->a_vals[0].bv_val ) != 0 ) {
1012 		rc = LDAP_CONSTRAINT_VIOLATION;
1013 		goto defaultpol;
1014 	}
1015 
1016 	ad = ad_pwdInHistory;
1017 	if ( (a = attr_find( pe->e_attrs, ad ))
1018 			&& lutil_atoi( &pp->pwdInHistory, a->a_vals[0].bv_val ) != 0 ) {
1019 		rc = LDAP_CONSTRAINT_VIOLATION;
1020 		goto defaultpol;
1021 	}
1022 
1023 	ad = ad_pwdCheckQuality;
1024 	if ( (a = attr_find( pe->e_attrs, ad ))
1025 			&& lutil_atoi( &pp->pwdCheckQuality, a->a_vals[0].bv_val ) != 0 ) {
1026 		rc = LDAP_CONSTRAINT_VIOLATION;
1027 		goto defaultpol;
1028 	}
1029 
1030 	ad = ad_pwdMinLength;
1031 	if ( (a = attr_find( pe->e_attrs, ad ))
1032 			&& lutil_atoi( &pp->pwdMinLength, a->a_vals[0].bv_val ) != 0 ) {
1033 		rc = LDAP_CONSTRAINT_VIOLATION;
1034 		goto defaultpol;
1035 	}
1036 
1037 	ad = ad_pwdMaxLength;
1038 	if ( (a = attr_find( pe->e_attrs, ad ))
1039 			&& lutil_atoi( &pp->pwdMaxLength, a->a_vals[0].bv_val ) != 0 ) {
1040 		rc = LDAP_CONSTRAINT_VIOLATION;
1041 		goto defaultpol;
1042 	}
1043 
1044 	ad = ad_pwdMaxFailure;
1045 	if ( (a = attr_find( pe->e_attrs, ad ))
1046 			&& lutil_atoi( &pp->pwdMaxFailure, a->a_vals[0].bv_val ) != 0 ) {
1047 		rc = LDAP_CONSTRAINT_VIOLATION;
1048 		goto defaultpol;
1049 	}
1050 
1051 	ad = ad_pwdMaxRecordedFailure;
1052 	if ( (a = attr_find( pe->e_attrs, ad ))
1053 			&& lutil_atoi( &pp->pwdMaxRecordedFailure, a->a_vals[0].bv_val ) != 0 ) {
1054 		rc = LDAP_CONSTRAINT_VIOLATION;
1055 		goto defaultpol;
1056 	}
1057 
1058 	ad = ad_pwdGraceExpiry;
1059 	if ( (a = attr_find( pe->e_attrs, ad ))
1060 			&& lutil_atoi( &pp->pwdGraceExpiry, a->a_vals[0].bv_val ) != 0 ) {
1061 		rc = LDAP_CONSTRAINT_VIOLATION;
1062 		goto defaultpol;
1063 	}
1064 
1065 	ad = ad_pwdGraceAuthNLimit;
1066 	if ( (a = attr_find( pe->e_attrs, ad ))
1067 			&& lutil_atoi( &pp->pwdGraceAuthNLimit, a->a_vals[0].bv_val ) != 0 ) {
1068 		rc = LDAP_CONSTRAINT_VIOLATION;
1069 		goto defaultpol;
1070 	}
1071 
1072 	ad = ad_pwdExpireWarning;
1073 	if ( (a = attr_find( pe->e_attrs, ad ))
1074 			&& lutil_atoi( &pp->pwdExpireWarning, a->a_vals[0].bv_val ) != 0 ) {
1075 		rc = LDAP_CONSTRAINT_VIOLATION;
1076 		goto defaultpol;
1077 	}
1078 
1079 	ad = ad_pwdFailureCountInterval;
1080 	if ( (a = attr_find( pe->e_attrs, ad ))
1081 			&& lutil_atoi( &pp->pwdFailureCountInterval, a->a_vals[0].bv_val ) != 0 ) {
1082 		rc = LDAP_CONSTRAINT_VIOLATION;
1083 		goto defaultpol;
1084 	}
1085 
1086 	ad = ad_pwdLockoutDuration;
1087 	if ( (a = attr_find( pe->e_attrs, ad ))
1088 			&& lutil_atoi( &pp->pwdLockoutDuration, a->a_vals[0].bv_val ) != 0 ) {
1089 		rc = LDAP_CONSTRAINT_VIOLATION;
1090 		goto defaultpol;
1091 	}
1092 
1093 	ad = ad_pwdMinDelay;
1094 	if ( (a = attr_find( pe->e_attrs, ad ))
1095 			&& lutil_atoi( &pp->pwdMinDelay, a->a_vals[0].bv_val ) != 0 ) {
1096 		rc = LDAP_CONSTRAINT_VIOLATION;
1097 		goto defaultpol;
1098 	}
1099 
1100 	ad = ad_pwdMaxDelay;
1101 	if ( (a = attr_find( pe->e_attrs, ad ))
1102 			&& lutil_atoi( &pp->pwdMaxDelay, a->a_vals[0].bv_val ) != 0 ) {
1103 		rc = LDAP_CONSTRAINT_VIOLATION;
1104 		goto defaultpol;
1105 	}
1106 
1107 	ad = ad_pwdCheckModule;
1108 	if ( attr_find( pe->e_attrs, ad )) {
1109 		Debug( LDAP_DEBUG_ANY, "ppolicy_get: "
1110 				"WARNING: Ignoring OBSOLETE attribute %s in policy %s.\n",
1111 				ad->ad_cname.bv_val, pe->e_name.bv_val );
1112 	}
1113 
1114 	ad = ad_pwdUseCheckModule;
1115 	if ( (a = attr_find( pe->e_attrs, ad )) )
1116 		pp->pwdUseCheckModule = bvmatch( &a->a_nvals[0], &slap_true_bv );
1117 
1118 	ad = ad_pwdCheckModuleArg;
1119 	if ( (a = attr_find( pe->e_attrs, ad )) ) {
1120 		ber_dupbv_x( &pp->pwdCheckModuleArg, &a->a_vals[0], op->o_tmpmemctx );
1121 	}
1122 
1123 	ad = ad_pwdLockout;
1124 	if ( (a = attr_find( pe->e_attrs, ad )) )
1125 		pp->pwdLockout = bvmatch( &a->a_nvals[0], &slap_true_bv );
1126 
1127 	ad = ad_pwdMustChange;
1128 	if ( (a = attr_find( pe->e_attrs, ad )) )
1129 		pp->pwdMustChange = bvmatch( &a->a_nvals[0], &slap_true_bv );
1130 
1131 	ad = ad_pwdAllowUserChange;
1132 	if ( (a = attr_find( pe->e_attrs, ad )) )
1133 		pp->pwdAllowUserChange = bvmatch( &a->a_nvals[0], &slap_true_bv );
1134 
1135 	ad = ad_pwdSafeModify;
1136 	if ( (a = attr_find( pe->e_attrs, ad )) )
1137 		pp->pwdSafeModify = bvmatch( &a->a_nvals[0], &slap_true_bv );
1138 
1139 	if ( pp->pwdMaxRecordedFailure < pp->pwdMaxFailure )
1140 		pp->pwdMaxRecordedFailure = pp->pwdMaxFailure;
1141 
1142 	if ( !pp->pwdMaxRecordedFailure && pp->pwdMinDelay )
1143 		pp->pwdMaxRecordedFailure = PPOLICY_DEFAULT_MAXRECORDED_FAILURE;
1144 
1145 	if ( pp->pwdMinDelay && !pp->pwdMaxDelay ) {
1146 		Debug( LDAP_DEBUG_ANY, "ppolicy_get: "
1147 				"pwdMinDelay was set but pwdMaxDelay wasn't, assuming they "
1148 				"are equal\n" );
1149 		pp->pwdMaxDelay = pp->pwdMinDelay;
1150 	}
1151 
1152 	op->o_bd = bd;
1153 	be_entry_release_r( op, pe );
1154 	op->o_bd = bd_orig;
1155 
1156 	return LDAP_SUCCESS;
1157 
1158 defaultpol:
1159 	if ( pe ) {
1160 		op->o_bd = bd;
1161 		be_entry_release_r( op, pe );
1162 		op->o_bd = bd_orig;
1163 	}
1164 
1165 	if ( rc && !BER_BVISNULL( vals ) ) {
1166 		Debug( LDAP_DEBUG_ANY, "ppolicy_get: "
1167 			"policy subentry %s missing or invalid at '%s', "
1168 			"no policy will be applied!\n",
1169 			vals->bv_val, ad ? ad->ad_cname.bv_val : "" );
1170 	} else {
1171 		Debug( LDAP_DEBUG_TRACE,
1172 			"ppolicy_get: using default policy\n" );
1173 	}
1174 
1175 	ppolicy_get_default( pp );
1176 
1177 	return -1;
1178 }
1179 
1180 static int
password_scheme(struct berval * cred,struct berval * sch)1181 password_scheme( struct berval *cred, struct berval *sch )
1182 {
1183 	int e;
1184 
1185 	assert( cred != NULL );
1186 
1187 	if (sch) {
1188 		sch->bv_val = NULL;
1189 		sch->bv_len = 0;
1190 	}
1191 
1192 	if ((cred->bv_len == 0) || (cred->bv_val == NULL) ||
1193 		(cred->bv_val[0] != '{')) return LDAP_OTHER;
1194 
1195 	for(e = 1; cred->bv_val[e] && cred->bv_val[e] != '}'; e++);
1196 	if (cred->bv_val[e]) {
1197 		int rc;
1198 		rc = lutil_passwd_scheme( cred->bv_val );
1199 		if (rc) {
1200 			if (sch) {
1201 				sch->bv_val = cred->bv_val;
1202 				sch->bv_len = e;
1203 			}
1204 			return LDAP_SUCCESS;
1205 		}
1206 	}
1207 	return LDAP_OTHER;
1208 }
1209 
1210 static int
check_password_quality(struct berval * cred,pp_info * pi,PassPolicy * pp,LDAPPasswordPolicyError * err,Entry * e,struct berval * errmsg)1211 check_password_quality( struct berval *cred, pp_info *pi, PassPolicy *pp, LDAPPasswordPolicyError *err,
1212 	Entry *e, struct berval *errmsg )
1213 {
1214 	int rc = LDAP_SUCCESS, ok = LDAP_SUCCESS;
1215 	char *ptr;
1216 	struct berval sch;
1217 
1218 	assert( cred != NULL );
1219 	assert( pp != NULL );
1220 	assert( errmsg != NULL );
1221 
1222 	ptr = errmsg->bv_val;
1223 	*ptr = '\0';
1224 
1225 	ptr = cred->bv_val;
1226 
1227 	if ((cred->bv_len == 0) || (pp->pwdMinLength > cred->bv_len)) {
1228 		rc = LDAP_CONSTRAINT_VIOLATION;
1229 		if ( err ) *err = PP_passwordTooShort;
1230 		return rc;
1231 	}
1232 
1233 	if ( pp->pwdMaxLength && cred->bv_len > pp->pwdMaxLength ) {
1234 		rc = LDAP_CONSTRAINT_VIOLATION;
1235 		if ( err ) *err = PP_passwordTooLong;
1236 		return rc;
1237 	}
1238 
1239         /*
1240          * We need to know if the password is already hashed - if so
1241          * what scheme is it. The reason being that the "hash" of
1242          * {cleartext} still allows us to check the password.
1243          */
1244 	rc = password_scheme( cred, &sch );
1245 	if (rc == LDAP_SUCCESS) {
1246 		if ((sch.bv_val) && (strncasecmp( sch.bv_val, "{cleartext}",
1247 			sch.bv_len ) == 0)) {
1248 			/*
1249 			 * We can check the cleartext "hash"
1250 			 */
1251 			ptr = cred->bv_val + sch.bv_len;
1252 		} else {
1253 			/* everything else, we can't check */
1254 			if (pp->pwdCheckQuality == 2) {
1255 				rc = LDAP_CONSTRAINT_VIOLATION;
1256 				if (err) *err = PP_insufficientPasswordQuality;
1257 				return rc;
1258 			}
1259 			/*
1260 			 * We can't check the syntax of the password, but it's not
1261 			 * mandatory (according to the policy), so we return success.
1262 			 */
1263 
1264 			return LDAP_SUCCESS;
1265 		}
1266 	}
1267 
1268 	rc = LDAP_SUCCESS;
1269 
1270 	if (pp->pwdUseCheckModule) {
1271 #ifdef SLAPD_MODULES
1272 		check_func *prog;
1273 
1274 		if ( !pi->pwdCheckFunc ) {
1275 			Debug(LDAP_DEBUG_ANY,
1276 				"check_password_quality: no CheckModule loaded\n" );
1277 			ok = LDAP_OTHER;
1278 		} else {
1279 			struct berval *arg = NULL;
1280 			if ( !BER_BVISNULL( &pp->pwdCheckModuleArg ) ) {
1281 				arg = &pp->pwdCheckModuleArg;
1282 			}
1283 
1284 			ldap_pvt_thread_mutex_lock( &chk_syntax_mutex );
1285 			ok = pi->pwdCheckFunc( ptr, errmsg, e, arg );
1286 			ldap_pvt_thread_mutex_unlock( &chk_syntax_mutex );
1287 			if (ok != LDAP_SUCCESS) {
1288 				Debug(LDAP_DEBUG_ANY,
1289 					"check_password_quality: module error: (%s) %s.[%d]\n",
1290 					pi->pwdCheckModule, errmsg->bv_val ? errmsg->bv_val : "", ok );
1291 			}
1292 		}
1293 #else
1294 		Debug(LDAP_DEBUG_ANY, "check_password_quality: external modules not "
1295 			"supported. pwdCheckModule ignored.\n" );
1296 #endif /* SLAPD_MODULES */
1297 	}
1298 
1299 	if (ok != LDAP_SUCCESS) {
1300 		rc = LDAP_CONSTRAINT_VIOLATION;
1301 		if (err) *err = PP_insufficientPasswordQuality;
1302 	}
1303 
1304 	return rc;
1305 }
1306 
1307 static int
parse_pwdhistory(struct berval * bv,char ** oid,time_t * oldtime,struct berval * oldpw)1308 parse_pwdhistory( struct berval *bv, char **oid, time_t *oldtime, struct berval *oldpw )
1309 {
1310 	char *ptr;
1311 	struct berval nv, npw;
1312 	ber_len_t i, j;
1313 
1314 	assert (bv && (bv->bv_len > 0) && (bv->bv_val) && oldtime && oldpw );
1315 
1316 	if ( oid ) {
1317 		*oid = 0;
1318 	}
1319 	*oldtime = (time_t)-1;
1320 	BER_BVZERO( oldpw );
1321 
1322 	ber_dupbv( &nv, bv );
1323 
1324 	/* first get the time field */
1325 	for ( i = 0; (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ )
1326 		;
1327 	if ( i == nv.bv_len ) {
1328 		goto exit_failure; /* couldn't locate the '#' separator */
1329 	}
1330 	nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */
1331 	ptr = nv.bv_val;
1332 	*oldtime = parse_time( ptr );
1333 	if (*oldtime == (time_t)-1) {
1334 		goto exit_failure;
1335 	}
1336 
1337 	/* get the OID field */
1338 	for (ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ )
1339 		;
1340 	if ( i == nv.bv_len ) {
1341 		goto exit_failure; /* couldn't locate the '#' separator */
1342 	}
1343 	nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */
1344 	if ( oid ) {
1345 		*oid = ber_strdup( ptr );
1346 	}
1347 
1348 	/* get the length field */
1349 	for ( ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ )
1350 		;
1351 	if ( i == nv.bv_len ) {
1352 		goto exit_failure; /* couldn't locate the '#' separator */
1353 	}
1354 	nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */
1355 	oldpw->bv_len = strtol( ptr, NULL, 10 );
1356 	if (errno == ERANGE) {
1357 		goto exit_failure;
1358 	}
1359 
1360 	/* lastly, get the octets of the string */
1361 	for ( j = i, ptr = &(nv.bv_val[i]); i < nv.bv_len; i++ )
1362 		;
1363 	if ( i - j != oldpw->bv_len) {
1364 		goto exit_failure; /* length is wrong */
1365 	}
1366 
1367 	npw.bv_val = ptr;
1368 	npw.bv_len = oldpw->bv_len;
1369 	ber_dupbv( oldpw, &npw );
1370 	ber_memfree( nv.bv_val );
1371 
1372 	return LDAP_SUCCESS;
1373 
1374 exit_failure:;
1375 	if ( oid && *oid ) {
1376 		ber_memfree(*oid);
1377 		*oid = NULL;
1378 	}
1379 	if ( oldpw->bv_val ) {
1380 		ber_memfree( oldpw->bv_val);
1381 		BER_BVZERO( oldpw );
1382 	}
1383 	ber_memfree( nv.bv_val );
1384 
1385 	return LDAP_OTHER;
1386 }
1387 
1388 static void
add_to_pwd_history(pw_hist ** l,time_t t,struct berval * oldpw,struct berval * bv)1389 add_to_pwd_history( pw_hist **l, time_t t,
1390                     struct berval *oldpw, struct berval *bv )
1391 {
1392 	pw_hist *p, *p1, *p2;
1393 
1394 	if (!l) return;
1395 
1396 	p = ch_malloc( sizeof( pw_hist ));
1397 	p->pw = *oldpw;
1398 	ber_dupbv( &p->bv, bv );
1399 	p->t = t;
1400 	p->next = NULL;
1401 
1402 	if (*l == NULL) {
1403 		/* degenerate case */
1404 		*l = p;
1405 		return;
1406 	}
1407 	/*
1408 	 * advance p1 and p2 such that p1 is the node before the
1409 	 * new one, and p2 is the node after it
1410 	 */
1411 	for (p1 = NULL, p2 = *l; p2 && p2->t <= t; p1 = p2, p2=p2->next );
1412 	p->next = p2;
1413 	if (p1 == NULL) { *l = p; return; }
1414 	p1->next = p;
1415 }
1416 
1417 #ifndef MAX_PWD_HISTORY_SZ
1418 #define MAX_PWD_HISTORY_SZ 1024
1419 #endif /* MAX_PWD_HISTORY_SZ */
1420 
1421 static void
make_pwd_history_value(char * timebuf,struct berval * bv,Attribute * pa)1422 make_pwd_history_value( char *timebuf, struct berval *bv, Attribute *pa )
1423 {
1424 	char str[ MAX_PWD_HISTORY_SZ ];
1425 	int nlen;
1426 
1427 	snprintf( str, MAX_PWD_HISTORY_SZ,
1428 		  "%s#%s#%lu#", timebuf,
1429 		  pa->a_desc->ad_type->sat_syntax->ssyn_oid,
1430 		  (unsigned long) pa->a_nvals[0].bv_len );
1431 	str[MAX_PWD_HISTORY_SZ-1] = 0;
1432 	nlen = strlen(str);
1433 
1434         /*
1435          * We have to assume that the string is a string of octets,
1436          * not readable characters. In reality, yes, it probably is
1437          * a readable (ie, base64) string, but we can't count on that
1438          * Hence, while the first 3 fields of the password history
1439          * are definitely readable (a timestamp, an OID and an integer
1440          * length), the remaining octets of the actual password
1441          * are deemed to be binary data.
1442          */
1443 	AC_MEMCPY( str + nlen, pa->a_nvals[0].bv_val, pa->a_nvals[0].bv_len );
1444 	nlen += pa->a_nvals[0].bv_len;
1445 	bv->bv_val = ch_malloc( nlen + 1 );
1446 	AC_MEMCPY( bv->bv_val, str, nlen );
1447 	bv->bv_val[nlen] = '\0';
1448 	bv->bv_len = nlen;
1449 }
1450 
1451 static void
free_pwd_history_list(pw_hist ** l)1452 free_pwd_history_list( pw_hist **l )
1453 {
1454 	pw_hist *p;
1455 
1456 	if (!l) return;
1457 	p = *l;
1458 	while (p) {
1459 		pw_hist *pp = p->next;
1460 
1461 		free(p->pw.bv_val);
1462 		free(p->bv.bv_val);
1463 		free(p);
1464 		p = pp;
1465 	}
1466 	*l = NULL;
1467 }
1468 
1469 typedef struct ppbind {
1470 	slap_overinst *on;
1471 	int send_ctrl;
1472 	int set_restrict;
1473 	LDAPControl **oldctrls;
1474 	Modifications *mod;
1475 	LDAPPasswordPolicyError pErr;
1476 	PassPolicy pp;
1477 } ppbind;
1478 
1479 static void
ctrls_cleanup(Operation * op,SlapReply * rs,LDAPControl ** oldctrls)1480 ctrls_cleanup( Operation *op, SlapReply *rs, LDAPControl **oldctrls )
1481 {
1482 	int n;
1483 
1484 	assert( rs->sr_ctrls != NULL );
1485 	assert( rs->sr_ctrls[0] != NULL );
1486 
1487 	for ( n = 0; rs->sr_ctrls[n]; n++ ) {
1488 		if ( rs->sr_ctrls[n]->ldctl_oid == ppolicy_ctrl_oid ||
1489 			rs->sr_ctrls[n]->ldctl_oid == ppolicy_pwd_expired_oid ||
1490 			rs->sr_ctrls[n]->ldctl_oid == ppolicy_pwd_expiring_oid ) {
1491 			op->o_tmpfree( rs->sr_ctrls[n], op->o_tmpmemctx );
1492 			rs->sr_ctrls[n] = (LDAPControl *)(-1);
1493 			break;
1494 		}
1495 	}
1496 
1497 	if ( rs->sr_ctrls[n] == NULL ) {
1498 		/* missed? */
1499 	}
1500 
1501 	op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
1502 
1503 	rs->sr_ctrls = oldctrls;
1504 }
1505 
1506 static int
ppolicy_ctrls_cleanup(Operation * op,SlapReply * rs)1507 ppolicy_ctrls_cleanup( Operation *op, SlapReply *rs )
1508 {
1509 	ppbind *ppb = op->o_callback->sc_private;
1510 	if ( ppb->send_ctrl ) {
1511 		ctrls_cleanup( op, rs, ppb->oldctrls );
1512 	}
1513 	return SLAP_CB_CONTINUE;
1514 }
1515 
1516 static int
ppolicy_bind_response(Operation * op,SlapReply * rs)1517 ppolicy_bind_response( Operation *op, SlapReply *rs )
1518 {
1519 	ppbind *ppb = op->o_callback->sc_private;
1520 	slap_overinst *on = ppb->on;
1521 	pp_info *pi = on->on_bi.bi_private;
1522 	Modifications *mod = ppb->mod, *m;
1523 	int pwExpired = 0;
1524 	int ngut = -1, warn = -1, fc = 0, age, rc;
1525 	Attribute *a;
1526 	time_t now, pwtime = (time_t)-1;
1527 	struct lutil_tm now_tm;
1528 	struct lutil_timet now_usec;
1529 	char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
1530 	char nowstr_usec[ LDAP_LUTIL_GENTIME_BUFSIZE+8 ];
1531 	struct berval timestamp, timestamp_usec;
1532 	BackendInfo *bi = op->o_bd->bd_info;
1533 	LDAPControl *ctrl = NULL;
1534 	Entry *e;
1535 
1536 	ldap_pvt_thread_mutex_lock( &pi->pwdFailureTime_mutex );
1537 	/* If we already know it's locked, just get on with it */
1538 	if ( ppb->pErr != PP_noError ) {
1539 		goto locked;
1540 	}
1541 
1542 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
1543 	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1544 	op->o_bd->bd_info = bi;
1545 
1546 	if ( rc != LDAP_SUCCESS ) {
1547 		ldap_pvt_thread_mutex_unlock( &pi->pwdFailureTime_mutex );
1548 		return SLAP_CB_CONTINUE;
1549 	}
1550 
1551 	/* ITS#7089 Skip lockout checks/modifications if password attribute missing */
1552 	if ( attr_find( e->e_attrs, ppb->pp.ad ) == NULL ) {
1553 		goto done;
1554 	}
1555 
1556 	ldap_pvt_gettime(&now_tm); /* stored for later consideration */
1557 	lutil_tm2time(&now_tm, &now_usec);
1558 	now = now_usec.tt_sec;
1559 	timestamp.bv_val = nowstr;
1560 	timestamp.bv_len = sizeof(nowstr);
1561 	slap_timestamp( &now, &timestamp );
1562 
1563 	/* Separate timestamp for pwdFailureTime with microsecond granularity */
1564 	strcpy(nowstr_usec, nowstr);
1565 	timestamp_usec.bv_val = nowstr_usec;
1566 	timestamp_usec.bv_len = timestamp.bv_len;
1567 	snprintf( timestamp_usec.bv_val + timestamp_usec.bv_len-1, sizeof(".123456Z"), ".%06dZ", now_usec.tt_nsec / 1000 );
1568 	timestamp_usec.bv_len += STRLENOF(".123456");
1569 
1570 	if ( rs->sr_err == LDAP_INVALID_CREDENTIALS && ppb->pp.pwdMaxRecordedFailure ) {
1571 		int i = 0;
1572 
1573 		m = ch_calloc( sizeof(Modifications), 1 );
1574 		m->sml_op = LDAP_MOD_ADD;
1575 		m->sml_flags = 0;
1576 		m->sml_type = ad_pwdFailureTime->ad_cname;
1577 		m->sml_desc = ad_pwdFailureTime;
1578 		m->sml_numvals = 1;
1579 		m->sml_values = ch_calloc( sizeof(struct berval), 2 );
1580 		m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
1581 
1582 		ber_dupbv( &m->sml_values[0], &timestamp_usec );
1583 		ber_dupbv( &m->sml_nvalues[0], &timestamp_usec );
1584 		m->sml_next = mod;
1585 		mod = m;
1586 
1587 		/*
1588 		 * Count the pwdFailureTimes - if it's
1589 		 * greater than the policy pwdMaxFailure,
1590 		 * then lock the account.
1591 		 */
1592 		if ((a = attr_find( e->e_attrs, ad_pwdFailureTime )) != NULL) {
1593 			for(i=0; a->a_nvals[i].bv_val; i++) {
1594 
1595 				/*
1596 				 * If the interval is 0, then failures
1597 				 * stay on the record until explicitly
1598 				 * reset by successful authentication.
1599 				 */
1600 				if (ppb->pp.pwdFailureCountInterval == 0) {
1601 					fc++;
1602 				} else if (now <=
1603 							parse_time(a->a_nvals[i].bv_val) +
1604 							ppb->pp.pwdFailureCountInterval) {
1605 
1606 					fc++;
1607 				}
1608 				/*
1609 				 * We only count those failures
1610 				 * which are not due to expire.
1611 				 */
1612 			}
1613 			/* Do we have too many timestamps? If so, delete some values.
1614 			 * We don't bother to sort the values here. OpenLDAP keeps the
1615 			 * values in order by default. Fundamentally, relying on the
1616 			 * information here is wrong anyway; monitoring systems should
1617 			 * be tracking Bind failures in syslog, not here.
1618 			 */
1619 			if (a->a_numvals >= ppb->pp.pwdMaxRecordedFailure) {
1620 				int j = ppb->pp.pwdMaxRecordedFailure-1;
1621 				/* If more than 2x, cheaper to perform a Replace */
1622 				if (a->a_numvals >= 2 * ppb->pp.pwdMaxRecordedFailure) {
1623 					struct berval v, nv;
1624 
1625 					/* Change the mod we constructed above */
1626 					m->sml_op = LDAP_MOD_REPLACE;
1627 					m->sml_numvals = ppb->pp.pwdMaxRecordedFailure;
1628 					v = m->sml_values[0];
1629 					nv = m->sml_nvalues[0];
1630 					ch_free(m->sml_values);
1631 					ch_free(m->sml_nvalues);
1632 					m->sml_values = ch_calloc( sizeof(struct berval), ppb->pp.pwdMaxRecordedFailure+1 );
1633 					m->sml_nvalues = ch_calloc( sizeof(struct berval), ppb->pp.pwdMaxRecordedFailure+1 );
1634 					for (i=0; i<j; i++) {
1635 						ber_dupbv(&m->sml_values[i], &a->a_vals[a->a_numvals-j+i]);
1636 						ber_dupbv(&m->sml_nvalues[i], &a->a_nvals[a->a_numvals-j+i]);
1637 					}
1638 					m->sml_values[i] = v;
1639 					m->sml_nvalues[i] = nv;
1640 				} else {
1641 				/* else just delete some */
1642 					m = ch_calloc( sizeof(Modifications), 1 );
1643 					m->sml_op = LDAP_MOD_DELETE;
1644 					m->sml_type = ad_pwdFailureTime->ad_cname;
1645 					m->sml_desc = ad_pwdFailureTime;
1646 					m->sml_numvals = a->a_numvals - j;
1647 					m->sml_values = ch_calloc( sizeof(struct berval), m->sml_numvals+1 );
1648 					m->sml_nvalues = ch_calloc( sizeof(struct berval), m->sml_numvals+1 );
1649 					for (i=0; i<m->sml_numvals; i++) {
1650 						ber_dupbv(&m->sml_values[i], &a->a_vals[i]);
1651 						ber_dupbv(&m->sml_nvalues[i], &a->a_nvals[i]);
1652 					}
1653 					m->sml_next = mod;
1654 					mod = m;
1655 				}
1656 			}
1657 		}
1658 
1659 		if ((ppb->pp.pwdMaxFailure > 0) &&
1660 			(fc >= ppb->pp.pwdMaxFailure - 1)) {
1661 
1662 			/*
1663 			 * We subtract 1 from the failure max
1664 			 * because the new failure entry hasn't
1665 			 * made it to the entry yet.
1666 			 */
1667 			m = ch_calloc( sizeof(Modifications), 1 );
1668 			m->sml_op = LDAP_MOD_REPLACE;
1669 			m->sml_flags = 0;
1670 			m->sml_type = ad_pwdAccountLockedTime->ad_cname;
1671 			m->sml_desc = ad_pwdAccountLockedTime;
1672 			m->sml_numvals = 1;
1673 			m->sml_values = ch_calloc( sizeof(struct berval), 2 );
1674 			m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
1675 			ber_dupbv( &m->sml_values[0], &timestamp );
1676 			ber_dupbv( &m->sml_nvalues[0], &timestamp );
1677 			m->sml_next = mod;
1678 			mod = m;
1679 		} else if ( ppb->pp.pwdMinDelay ) {
1680 			int waittime = ppb->pp.pwdMinDelay << fc;
1681 			time_t wait_end;
1682 			struct berval lockout_stamp;
1683 
1684 			if ( waittime > ppb->pp.pwdMaxDelay ) {
1685 				waittime = ppb->pp.pwdMaxDelay;
1686 			}
1687 			wait_end = now + waittime;
1688 
1689 			slap_timestamp( &wait_end, &lockout_stamp );
1690 
1691 			m = ch_calloc( sizeof(Modifications), 1 );
1692 			m->sml_op = LDAP_MOD_REPLACE;
1693 			m->sml_flags = 0;
1694 			m->sml_type = ad_pwdAccountTmpLockoutEnd->ad_cname;
1695 			m->sml_desc = ad_pwdAccountTmpLockoutEnd;
1696 			m->sml_numvals = 1;
1697 			m->sml_values = ch_calloc( sizeof(struct berval), 2 );
1698 			m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
1699 			ber_dupbv( &m->sml_values[0], &lockout_stamp );
1700 			ber_dupbv( &m->sml_nvalues[0], &lockout_stamp );
1701 			m->sml_next = mod;
1702 			mod = m;
1703 		}
1704 	} else if ( rs->sr_err == LDAP_SUCCESS ) {
1705 		if ((a = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL)
1706 			pwtime = parse_time( a->a_nvals[0].bv_val );
1707 
1708 		/* delete all pwdFailureTimes */
1709 		if ( attr_find( e->e_attrs, ad_pwdFailureTime )) {
1710 			m = ch_calloc( sizeof(Modifications), 1 );
1711 			m->sml_op = LDAP_MOD_DELETE;
1712 			m->sml_flags = 0;
1713 			m->sml_type = ad_pwdFailureTime->ad_cname;
1714 			m->sml_desc = ad_pwdFailureTime;
1715 			m->sml_next = mod;
1716 			mod = m;
1717 		}
1718 
1719 		/*
1720 		 * check to see if the password must be changed
1721 		 */
1722 		if ( ppb->pp.pwdMustChange &&
1723 			(a = attr_find( e->e_attrs, ad_pwdReset )) &&
1724 			bvmatch( &a->a_nvals[0], &slap_true_bv ) )
1725 		{
1726 			/*
1727 			 * need to inject client controls here to give
1728 			 * more information. For the moment, we ensure
1729 			 * that we are disallowed from doing anything
1730 			 * other than change password.
1731 			 */
1732 			if ( ppb->set_restrict ) {
1733 				ber_dupbv( &pwcons[op->o_conn->c_conn_idx].dn,
1734 					&op->o_conn->c_ndn );
1735 			}
1736 
1737 			ppb->pErr = PP_changeAfterReset;
1738 
1739 		} else {
1740 			/*
1741 			 * the password does not need to be changed, so
1742 			 * we now check whether the password has expired.
1743 			 *
1744 			 * We can skip this bit if passwords don't age in
1745 			 * the policy. Also, if there was no pwdChangedTime
1746 			 * attribute in the entry, the password never expires.
1747 			 */
1748 			if (ppb->pp.pwdMaxAge == 0) goto grace;
1749 
1750 			if (pwtime != (time_t)-1) {
1751 				/*
1752 				 * Check: was the last change time of
1753 				 * the password older than the maximum age
1754 				 * allowed. (Ignore case 2 from I-D, it's just silly.)
1755 				 */
1756 				if (now - pwtime > ppb->pp.pwdMaxAge ) pwExpired = 1;
1757 			}
1758 		}
1759 
1760 grace:
1761 		if (!pwExpired) goto check_expiring_password;
1762 
1763 		if ( ppb->pp.pwdGraceExpiry &&
1764 				now - pwtime > ppb->pp.pwdMaxAge + ppb->pp.pwdGraceExpiry ) {
1765 			/* Grace logins have expired now */
1766 			ngut = 0;
1767 		} else if ((a = attr_find( e->e_attrs, ad_pwdGraceUseTime )) == NULL) {
1768 			ngut = ppb->pp.pwdGraceAuthNLimit;
1769 		} else {
1770 			for(ngut=0; a->a_nvals[ngut].bv_val; ngut++);
1771 			ngut = ppb->pp.pwdGraceAuthNLimit - ngut;
1772 		}
1773 
1774 		/*
1775 		 * ngut is the number of remaining grace logins
1776 		 */
1777 		Debug( LDAP_DEBUG_ANY,
1778 			"ppolicy_bind: Entry %s has an expired password: %d grace logins\n",
1779 			e->e_name.bv_val, ngut );
1780 
1781 		ngut--;
1782 
1783 		if (ngut < 0) {
1784 			ppb->pErr = PP_passwordExpired;
1785 			rs->sr_err = LDAP_INVALID_CREDENTIALS;
1786 			goto done;
1787 		}
1788 
1789 		/*
1790 		 * Add a grace user time to the entry
1791 		 */
1792 		m = ch_calloc( sizeof(Modifications), 1 );
1793 		m->sml_op = LDAP_MOD_ADD;
1794 		m->sml_flags = 0;
1795 		m->sml_type = ad_pwdGraceUseTime->ad_cname;
1796 		m->sml_desc = ad_pwdGraceUseTime;
1797 		m->sml_numvals = 1;
1798 		m->sml_values = ch_calloc( sizeof(struct berval), 2 );
1799 		m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
1800 		ber_dupbv( &m->sml_values[0], &timestamp_usec );
1801 		ber_dupbv( &m->sml_nvalues[0], &timestamp_usec );
1802 		m->sml_next = mod;
1803 		mod = m;
1804 
1805 check_expiring_password:
1806 		/*
1807 		 * Now we need to check to see
1808 		 * if it is about to expire, and if so, should the user
1809 		 * be warned about it in the password policy control.
1810 		 *
1811 		 * If the password has expired, and we're in the grace period, then
1812 		 * we don't need to do this bit. Similarly, if we don't have password
1813 		 * aging, then there's no need to do this bit either.
1814 		 *
1815 		 * If pwdtime is -1 there is no password Change Time attribute on the
1816 		 * entry so we skip the expiry check.
1817 		 *
1818 		 */
1819 		if ((ppb->pp.pwdMaxAge < 1) || (pwExpired) || (ppb->pp.pwdExpireWarning < 1) ||
1820 			(pwtime == -1))
1821 			goto done;
1822 
1823 		age = (int)(now - pwtime);
1824 
1825 		/*
1826 		 * We know that there is a password Change Time attribute - if
1827 		 * there wasn't, then the pwdExpired value would be true, unless
1828 		 * there is no password aging - and if there is no password aging,
1829 		 * then this section isn't called anyway - you can't have an
1830 		 * expiring password if there's no limit to expire.
1831 		 */
1832 		if (ppb->pp.pwdMaxAge - age < ppb->pp.pwdExpireWarning ) {
1833 			/*
1834 			 * Set the warning value.
1835 			 */
1836 			warn = ppb->pp.pwdMaxAge - age; /* seconds left until expiry */
1837 			if (warn < 0) warn = 0; /* something weird here - why is pwExpired not set? */
1838 
1839 			Debug( LDAP_DEBUG_TRACE,
1840 				"ppolicy_bind: Setting warning for password expiry for %s = %d seconds\n",
1841 				op->o_req_dn.bv_val, warn );
1842 		}
1843 	}
1844 
1845 done:
1846 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
1847 	be_entry_release_r( op, e );
1848 
1849 locked:
1850 	if ( mod && !pi->disable_write ) {
1851 		Operation op2 = *op;
1852 		SlapReply r2 = { REP_RESULT };
1853 		slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
1854 		LDAPControl c, *ca[2];
1855 
1856 		op2.o_tag = LDAP_REQ_MODIFY;
1857 		op2.o_callback = &cb;
1858 		op2.orm_modlist = mod;
1859 		op2.orm_no_opattrs = 0;
1860 		op2.o_dn = op->o_bd->be_rootdn;
1861 		op2.o_ndn = op->o_bd->be_rootndn;
1862 
1863 		/* If this server is a shadow and forward_updates is true,
1864 		 * use the frontend to perform this modify. That will trigger
1865 		 * the update referral, which can then be forwarded by the
1866 		 * chain overlay. Obviously the updateref and chain overlay
1867 		 * must be configured appropriately for this to be useful.
1868 		 */
1869 		if ( SLAP_SHADOW( op->o_bd ) && pi->forward_updates ) {
1870 			op2.o_bd = frontendDB;
1871 
1872 			/* Must use Relax control since these are no-user-mod */
1873 			op2.o_relax = SLAP_CONTROL_CRITICAL;
1874 			op2.o_ctrls = ca;
1875 			ca[0] = &c;
1876 			ca[1] = NULL;
1877 			BER_BVZERO( &c.ldctl_value );
1878 			c.ldctl_iscritical = 1;
1879 			c.ldctl_oid = LDAP_CONTROL_RELAX;
1880 		} else {
1881 			/* If not forwarding, don't update opattrs and don't replicate */
1882 			if ( SLAP_SINGLE_SHADOW( op->o_bd )) {
1883 				op2.orm_no_opattrs = 1;
1884 				op2.o_dont_replicate = 1;
1885 			}
1886 			op2.o_bd->bd_info = (BackendInfo *)on->on_info;
1887 		}
1888 		rc = op2.o_bd->be_modify( &op2, &r2 );
1889 		if ( rc != LDAP_SUCCESS ) {
1890 			Debug( LDAP_DEBUG_ANY, "%s ppolicy_bind_response: "
1891 					"ppolicy state change failed with rc=%d text=%s\n",
1892 					op->o_log_prefix, rc, r2.sr_text );
1893 		}
1894 	}
1895 	if ( mod ) {
1896 		slap_mods_free( mod, 1 );
1897 	}
1898 
1899 	if ( ppb->send_ctrl ) {
1900 
1901 		/* Do we really want to tell that the account is locked? */
1902 		if ( ppb->pErr == PP_accountLocked && !pi->use_lockout ) {
1903 			ppb->pErr = PP_noError;
1904 		}
1905 		ctrl = create_passcontrol( op, warn, ngut, ppb->pErr );
1906 	} else if ( pi->send_netscape_controls ) {
1907 		if ( ppb->pErr != PP_noError || pwExpired ) {
1908 			ctrl = create_passexpiry( op, 1, 0 );
1909 		} else if ( warn > 0 ) {
1910 			ctrl = create_passexpiry( op, 0, warn );
1911 		}
1912 	}
1913 	if ( ctrl ) {
1914 		ppb->oldctrls = add_passcontrol( op, rs, ctrl );
1915 		op->o_callback->sc_cleanup = ppolicy_ctrls_cleanup;
1916 	}
1917 	op->o_bd->bd_info = bi;
1918 	ldap_pvt_thread_mutex_unlock( &pi->pwdFailureTime_mutex );
1919 	return SLAP_CB_CONTINUE;
1920 }
1921 
1922 static int
ppolicy_bind(Operation * op,SlapReply * rs)1923 ppolicy_bind( Operation *op, SlapReply *rs )
1924 {
1925 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1926 
1927 	/* Reset lockout status on all Bind requests */
1928 	if ( !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
1929 		ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
1930 		BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
1931 	}
1932 
1933 	/* Root bypasses policy */
1934 	if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn )) {
1935 		Entry *e;
1936 		int rc;
1937 		ppbind *ppb;
1938 		slap_callback *cb;
1939 
1940 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1941 		rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
1942 
1943 		if ( rc != LDAP_SUCCESS ) {
1944 			return SLAP_CB_CONTINUE;
1945 		}
1946 
1947 		cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback),
1948 			1, op->o_tmpmemctx );
1949 		ppb = (ppbind *)(cb+1);
1950 		ppb->on = on;
1951 		ppb->pErr = PP_noError;
1952 		ppb->set_restrict = 1;
1953 
1954 		/* Setup a callback so we can munge the result */
1955 
1956 		cb->sc_response = ppolicy_bind_response;
1957 		cb->sc_private = ppb;
1958 		overlay_callback_after_backover( op, cb, 1 );
1959 
1960 		/* Did we receive a password policy request control? */
1961 		if ( op->o_ctrlflag[ppolicy_cid] ) {
1962 			ppb->send_ctrl = 1;
1963 		}
1964 
1965 		op->o_bd->bd_info = (BackendInfo *)on;
1966 
1967 		if ( ppolicy_get( op, e, &ppb->pp ) == LDAP_SUCCESS ) {
1968 			rc = account_locked( op, e, &ppb->pp, &ppb->mod );
1969 		}
1970 
1971 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
1972 		be_entry_release_r( op, e );
1973 
1974 		if ( rc ) {
1975 			ppb->pErr = PP_accountLocked;
1976 			send_ldap_error( op, rs, LDAP_INVALID_CREDENTIALS, NULL );
1977 			return rs->sr_err;
1978 		}
1979 
1980 	}
1981 
1982 	return SLAP_CB_CONTINUE;
1983 }
1984 
1985 /* Reset the restricted info for the next session on this connection */
1986 static int
ppolicy_connection_destroy(BackendDB * bd,Connection * conn)1987 ppolicy_connection_destroy( BackendDB *bd, Connection *conn )
1988 {
1989 	if ( pwcons && !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) {
1990 		ch_free( pwcons[conn->c_conn_idx].dn.bv_val );
1991 		BER_BVZERO( &pwcons[conn->c_conn_idx].dn );
1992 	}
1993 	return SLAP_CB_CONTINUE;
1994 }
1995 
1996 /* Check if this connection is restricted */
1997 static int
ppolicy_restrict(Operation * op,SlapReply * rs)1998 ppolicy_restrict(
1999 	Operation *op,
2000 	SlapReply *rs )
2001 {
2002 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
2003 	int send_ctrl = 0;
2004 
2005 	/* Did we receive a password policy request control? */
2006 	if ( op->o_ctrlflag[ppolicy_cid] ) {
2007 		send_ctrl = 1;
2008 	}
2009 
2010 	if ( op->o_conn && !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
2011 		LDAPControl **oldctrls;
2012 		/* if the current authcDN doesn't match the one we recorded,
2013 		 * then an intervening Bind has succeeded and the restriction
2014 		 * no longer applies. (ITS#4516)
2015 		 */
2016 		if ( !dn_match( &op->o_conn->c_ndn,
2017 				&pwcons[op->o_conn->c_conn_idx].dn )) {
2018 			ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
2019 			BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
2020 			return SLAP_CB_CONTINUE;
2021 		}
2022 
2023 		Debug( LDAP_DEBUG_TRACE,
2024 			"connection restricted to password changing only\n" );
2025 		if ( send_ctrl ) {
2026 			LDAPControl *ctrl = NULL;
2027 			ctrl = create_passcontrol( op, -1, -1, PP_changeAfterReset );
2028 			oldctrls = add_passcontrol( op, rs, ctrl );
2029 		}
2030 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
2031 		send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS,
2032 			"Operations are restricted to bind/unbind/abandon/StartTLS/modify password" );
2033 		if ( send_ctrl ) {
2034 			ctrls_cleanup( op, rs, oldctrls );
2035 		}
2036 		return rs->sr_err;
2037 	}
2038 
2039 	return SLAP_CB_CONTINUE;
2040 }
2041 
2042 static int
ppolicy_account_usability_entry_cb(Operation * op,SlapReply * rs)2043 ppolicy_account_usability_entry_cb( Operation *op, SlapReply *rs )
2044 {
2045 	slap_overinst *on = op->o_callback->sc_private;
2046 	BackendInfo *bi = op->o_bd->bd_info;
2047 	LDAPControl *ctrl = NULL;
2048 	PassPolicy pp;
2049 	Attribute *a;
2050 	Entry *e = NULL;
2051 	time_t pwtime = 0, seconds_until_expiry = -1, now = op->o_time;
2052 	int isExpired = 0, grace = -1;
2053 
2054 	if ( rs->sr_type != REP_SEARCH ) {
2055 		return SLAP_CB_CONTINUE;
2056 	}
2057 
2058 	if ( be_entry_get_rw( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &e ) != LDAP_SUCCESS ) {
2059 		goto done;
2060 	}
2061 
2062 	op->o_bd->bd_info = (BackendInfo *)on;
2063 
2064 	if ( ppolicy_get( op, e, &pp ) != LDAP_SUCCESS ) {
2065 		/* TODO: If there is no policy, should we check if */
2066 		goto done;
2067 	}
2068 
2069 	if ( !access_allowed( op, e, pp.ad, NULL, ACL_COMPARE, NULL ) ) {
2070 		goto done;
2071 	}
2072 
2073 	if ( attr_find( e->e_attrs, pp.ad ) == NULL ) {
2074 		goto done;
2075 	}
2076 
2077 	if ((a = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL) {
2078 		pwtime = parse_time( a->a_nvals[0].bv_val );
2079 	}
2080 
2081 	if ( pp.pwdMaxAge && pwtime ) {
2082 		seconds_until_expiry = pwtime + pp.pwdMaxAge - now;
2083 		if ( seconds_until_expiry <= 0 ) isExpired = 1;
2084 		if ( pp.pwdGraceAuthNLimit ) {
2085 			if ( !pp.pwdGraceExpiry || seconds_until_expiry + pp.pwdGraceExpiry > 0 ) {
2086 				grace = pp.pwdGraceAuthNLimit;
2087 				if ( attr_find( e->e_attrs, ad_pwdGraceUseTime ) ) {
2088 					grace -= a->a_numvals;
2089 				}
2090 			}
2091 		}
2092 	}
2093 	if ( !isExpired && pp.pwdMaxIdle && (a = attr_find( e->e_attrs, ad_pwdLastSuccess )) ) {
2094 		time_t lastbindtime = pwtime;
2095 
2096 		if ( (a = attr_find( e->e_attrs, ad_pwdLastSuccess )) != NULL ) {
2097 			lastbindtime = parse_time( a->a_nvals[0].bv_val );
2098 		}
2099 
2100 		if ( lastbindtime ) {
2101 			int remaining_idle = lastbindtime + pp.pwdMaxIdle - now;
2102 			if ( remaining_idle <= 0 ) {
2103 				isExpired = 1;
2104 			} else if ( seconds_until_expiry == -1 || remaining_idle < seconds_until_expiry ) {
2105 				seconds_until_expiry = remaining_idle;
2106 			}
2107 		}
2108 	}
2109 
2110 	if ( isExpired || account_locked( op, e, &pp, NULL ) ) {
2111 		LDAPAccountUsabilityMoreInfo more_info = { 0, 0, 0, -1, -1 };
2112 		time_t then, lockoutEnd = 0;
2113 
2114 		if ( isExpired ) more_info.remaining_grace = grace;
2115 
2116 		if ( (a = attr_find( e->e_attrs, ad_pwdAccountLockedTime )) != NULL ) {
2117 			then = parse_time( a->a_vals[0].bv_val );
2118 			if ( then == 0 )
2119 				lockoutEnd = -1;
2120 
2121 			/* Still in the future? not yet in effect */
2122 			if ( now < then )
2123 				then = 0;
2124 
2125 			if ( !pp.pwdLockoutDuration )
2126 				lockoutEnd = -1;
2127 
2128 			if ( now < then + pp.pwdLockoutDuration )
2129 				lockoutEnd = then + pp.pwdLockoutDuration;
2130 		}
2131 
2132 		if ( (a = attr_find( e->e_attrs, ad_pwdAccountTmpLockoutEnd )) != NULL ) {
2133 			then = parse_time( a->a_vals[0].bv_val );
2134 			if ( lockoutEnd != -1 && then > lockoutEnd )
2135 				lockoutEnd = then;
2136 		}
2137 
2138 		if ( lockoutEnd > now ) {
2139 			more_info.inactive = 1;
2140 			more_info.seconds_before_unlock = lockoutEnd - now;
2141 		}
2142 
2143 		if ( pp.pwdMustChange &&
2144 			(a = attr_find( e->e_attrs, ad_pwdReset )) &&
2145 			bvmatch( &a->a_nvals[0], &slap_true_bv ) )
2146 		{
2147 			more_info.reset = 1;
2148 		}
2149 
2150 		add_account_control( op, rs, 0, -1, &more_info );
2151 	} else {
2152 		add_account_control( op, rs, 1, seconds_until_expiry, NULL );
2153 	}
2154 
2155 done:
2156 	op->o_bd->bd_info = bi;
2157 	if ( e ) {
2158 		be_entry_release_r( op, e );
2159 	}
2160 	return SLAP_CB_CONTINUE;
2161 }
2162 
2163 static int
ppolicy_search(Operation * op,SlapReply * rs)2164 ppolicy_search(
2165 	Operation *op,
2166 	SlapReply *rs )
2167 {
2168 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
2169 	int rc = ppolicy_restrict( op, rs );
2170 
2171 	if ( rc != SLAP_CB_CONTINUE ) {
2172 		return rc;
2173 	}
2174 
2175 	if ( op->o_ctrlflag[account_usability_cid] ) {
2176 		slap_callback *cb;
2177 
2178 		cb = op->o_tmpcalloc( sizeof(slap_callback), 1, op->o_tmpmemctx );
2179 
2180 		cb->sc_response = ppolicy_account_usability_entry_cb;
2181 		cb->sc_private = on;
2182 		overlay_callback_after_backover( op, cb, 1 );
2183 	}
2184 
2185 	return SLAP_CB_CONTINUE;
2186 }
2187 
2188 static int
ppolicy_compare_response(Operation * op,SlapReply * rs)2189 ppolicy_compare_response(
2190 	Operation *op,
2191 	SlapReply *rs )
2192 {
2193 	/* map compare responses to bind responses */
2194 	if ( rs->sr_err == LDAP_COMPARE_TRUE )
2195 		rs->sr_err = LDAP_SUCCESS;
2196 	else if ( rs->sr_err == LDAP_COMPARE_FALSE )
2197 		rs->sr_err = LDAP_INVALID_CREDENTIALS;
2198 
2199 	ppolicy_bind_response( op, rs );
2200 
2201 	/* map back to compare */
2202 	if ( rs->sr_err == LDAP_SUCCESS )
2203 		rs->sr_err = LDAP_COMPARE_TRUE;
2204 	else if ( rs->sr_err == LDAP_INVALID_CREDENTIALS )
2205 		rs->sr_err = LDAP_COMPARE_FALSE;
2206 
2207 	return SLAP_CB_CONTINUE;
2208 }
2209 
2210 static int
ppolicy_compare(Operation * op,SlapReply * rs)2211 ppolicy_compare(
2212 	Operation *op,
2213 	SlapReply *rs )
2214 {
2215 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
2216 
2217 	if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE )
2218 		return rs->sr_err;
2219 
2220 	/* Did we receive a password policy request control?
2221 	 * Are we testing the userPassword?
2222 	 */
2223 	if ( op->o_ctrlflag[ppolicy_cid] &&
2224 		op->orc_ava->aa_desc == slap_schema.si_ad_userPassword ) {
2225 		Entry *e;
2226 		int rc;
2227 		ppbind *ppb;
2228 		slap_callback *cb;
2229 
2230 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
2231 		rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
2232 
2233 		if ( rc != LDAP_SUCCESS ) {
2234 			return SLAP_CB_CONTINUE;
2235 		}
2236 
2237 		cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback),
2238 			1, op->o_tmpmemctx );
2239 		ppb = (ppbind *)(cb+1);
2240 		ppb->on = on;
2241 		ppb->pErr = PP_noError;
2242 		ppb->send_ctrl = 1;
2243 		/* failures here don't lockout the connection */
2244 		ppb->set_restrict = 0;
2245 
2246 		/* Setup a callback so we can munge the result */
2247 
2248 		cb->sc_response = ppolicy_compare_response;
2249 		cb->sc_private = ppb;
2250 		overlay_callback_after_backover( op, cb, 1 );
2251 
2252 		op->o_bd->bd_info = (BackendInfo *)on;
2253 
2254 		if ( ppolicy_get( op, e, &ppb->pp ) == LDAP_SUCCESS ) {
2255 			rc = account_locked( op, e, &ppb->pp, &ppb->mod );
2256 		}
2257 
2258 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
2259 		be_entry_release_r( op, e );
2260 
2261 		if ( rc ) {
2262 			ppb->pErr = PP_accountLocked;
2263 			send_ldap_error( op, rs, LDAP_COMPARE_FALSE, NULL );
2264 			return rs->sr_err;
2265 		}
2266 	}
2267 	return SLAP_CB_CONTINUE;
2268 }
2269 
2270 static int
ppolicy_add(Operation * op,SlapReply * rs)2271 ppolicy_add(
2272 	Operation *op,
2273 	SlapReply *rs )
2274 {
2275 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
2276 	pp_info *pi = on->on_bi.bi_private;
2277 	PassPolicy pp;
2278 	Attribute *pa;
2279 	const char *txt;
2280 
2281 	if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE )
2282 		return rs->sr_err;
2283 
2284 	/* If this is a replica, assume the provider checked everything */
2285 	if ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) )
2286 		return SLAP_CB_CONTINUE;
2287 
2288 	/* Check for password in entry */
2289 	if ((pa = attr_find( op->oq_add.rs_e->e_attrs,
2290 		slap_schema.si_ad_userPassword )))
2291 	{
2292 		assert( pa->a_vals != NULL );
2293 		assert( !BER_BVISNULL( &pa->a_vals[ 0 ] ) );
2294 
2295 		if ( !BER_BVISNULL( &pa->a_vals[ 1 ] ) ) {
2296 			send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, "Password policy only allows one password value" );
2297 			return rs->sr_err;
2298 		}
2299 
2300 		ppolicy_get( op, op->ora_e, &pp );
2301 
2302 		/*
2303 		 * new entry contains a password - if we're not the root user
2304 		 * then we need to check that the password fits in with the
2305 		 * security policy for the new entry.
2306 		 */
2307 
2308 		if (pp.pwdCheckQuality > 0 && !be_isroot( op )) {
2309 			struct berval *bv = &(pa->a_vals[0]);
2310 			int rc, send_ctrl = 0;
2311 			LDAPPasswordPolicyError pErr = PP_noError;
2312 			char errbuf[ERRBUFSIZ];
2313 			struct berval errmsg = BER_BVC( errbuf );
2314 
2315 			/* Did we receive a password policy request control? */
2316 			if ( op->o_ctrlflag[ppolicy_cid] ) {
2317 				send_ctrl = 1;
2318 			}
2319 			rc = check_password_quality( bv, pi, &pp, &pErr, op->ora_e, &errmsg );
2320 			if (rc != LDAP_SUCCESS) {
2321 				char *txt = errmsg.bv_val;
2322 				LDAPControl **oldctrls = NULL;
2323 				op->o_bd->bd_info = (BackendInfo *)on->on_info;
2324 				if ( send_ctrl ) {
2325 					LDAPControl *ctrl = NULL;
2326 					ctrl = create_passcontrol( op, -1, -1, pErr );
2327 					oldctrls = add_passcontrol( op, rs, ctrl );
2328 				}
2329 				send_ldap_error( op, rs, rc, txt && txt[0] ? txt : "Password fails quality checking policy" );
2330 				if ( txt != errbuf ) {
2331 					free( txt );
2332 				}
2333 				if ( send_ctrl ) {
2334 					ctrls_cleanup( op, rs, oldctrls );
2335 				}
2336 				return rs->sr_err;
2337 			}
2338 		}
2339 			/*
2340 			 * A controversial bit. We hash cleartext
2341 			 * passwords provided via add and modify operations
2342 			 * You're not really supposed to do this, since
2343 			 * the X.500 model says "store attributes" as they
2344 			 * get provided. By default, this is what we do
2345 			 *
2346 			 * But if the hash_passwords flag is set, we hash
2347 			 * any cleartext password attribute values via the
2348 			 * default password hashing scheme.
2349 			 */
2350 		if ((pi->hash_passwords) &&
2351 			(password_scheme( &(pa->a_vals[0]), NULL ) != LDAP_SUCCESS)) {
2352 			struct berval hpw;
2353 
2354 			slap_passwd_hash( &(pa->a_vals[0]), &hpw, &txt );
2355 			if (hpw.bv_val == NULL) {
2356 				/*
2357 				 * hashing didn't work. Emit an error.
2358 				 */
2359 				rs->sr_err = LDAP_OTHER;
2360 				rs->sr_text = txt;
2361 				send_ldap_error( op, rs, LDAP_OTHER, "Password hashing failed" );
2362 				return rs->sr_err;
2363 			}
2364 
2365 			memset( pa->a_vals[0].bv_val, 0, pa->a_vals[0].bv_len);
2366 			ber_memfree( pa->a_vals[0].bv_val );
2367 			pa->a_vals[0].bv_val = hpw.bv_val;
2368 			pa->a_vals[0].bv_len = hpw.bv_len;
2369 		}
2370 
2371 		/* If password aging is in effect, set the pwdChangedTime */
2372 		if ( pp.pwdMaxAge || pp.pwdMinAge ) {
2373 			struct berval timestamp;
2374 			char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
2375 			time_t now = slap_get_time();
2376 
2377 			timestamp.bv_val = timebuf;
2378 			timestamp.bv_len = sizeof(timebuf);
2379 			slap_timestamp( &now, &timestamp );
2380 
2381 			attr_merge_one( op->ora_e, ad_pwdChangedTime, &timestamp, &timestamp );
2382 		}
2383 	}
2384 	return SLAP_CB_CONTINUE;
2385 }
2386 
2387 static int
ppolicy_mod_cb(Operation * op,SlapReply * rs)2388 ppolicy_mod_cb( Operation *op, SlapReply *rs )
2389 {
2390 	slap_callback *sc = op->o_callback;
2391 	op->o_callback = sc->sc_next;
2392 	if ( rs->sr_err == LDAP_SUCCESS ) {
2393 		ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
2394 		BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
2395 	}
2396 	op->o_tmpfree( sc, op->o_tmpmemctx );
2397 	return SLAP_CB_CONTINUE;
2398 }
2399 
2400 static int
ppolicy_text_cleanup(Operation * op,SlapReply * rs)2401 ppolicy_text_cleanup( Operation *op, SlapReply *rs )
2402 {
2403 	slap_callback *sc = op->o_callback;
2404 
2405 	if ( rs->sr_text == sc->sc_private ) {
2406 		rs->sr_text = NULL;
2407 	}
2408 	free( sc->sc_private );
2409 
2410 	op->o_callback = sc->sc_next;
2411 	op->o_tmpfree( sc, op->o_tmpmemctx );
2412 	return SLAP_CB_CONTINUE;
2413 }
2414 
2415 static int
ppolicy_modify(Operation * op,SlapReply * rs)2416 ppolicy_modify( Operation *op, SlapReply *rs )
2417 {
2418 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
2419 	pp_info			*pi = on->on_bi.bi_private;
2420 	int			i, rc, mod_pw_only, pwmod = 0, pwmop = -1, deladd,
2421 				hsize = 0, hskip;
2422 	PassPolicy		pp;
2423 	Modifications		*mods = NULL, *modtail = NULL,
2424 				*ml, *delmod, *addmod;
2425 	Attribute		*pa, *ha, at;
2426 	const char		*txt;
2427 	char errbuf[ERRBUFSIZ];
2428 	pw_hist			*tl = NULL, *p;
2429 	int			zapReset, send_ctrl = 0, free_txt = 0;
2430 	Entry			*e;
2431 	struct berval		newpw = BER_BVNULL, oldpw = BER_BVNULL,
2432 				*bv, cr[2];
2433 	LDAPPasswordPolicyError pErr = PP_noError;
2434 	LDAPControl		*ctrl = NULL;
2435 	LDAPControl 		**oldctrls = NULL;
2436 	int			is_pwdexop = 0, is_pwdadmin = 0;
2437 	int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0,
2438 		got_del_success = 0;
2439 	int got_changed = 0, got_history = 0;
2440 	int have_policy = 0;
2441 
2442 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
2443 	rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
2444 	op->o_bd->bd_info = (BackendInfo *)on;
2445 
2446 	if ( rc != LDAP_SUCCESS ) return SLAP_CB_CONTINUE;
2447 	if ( pi->disable_write ) return SLAP_CB_CONTINUE;
2448 
2449 	/* If this is a replica, we may need to tweak some of the
2450 	 * provider's modifications. Otherwise, just pass it through.
2451 	 */
2452 	if ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) ) {
2453 		Modifications **prev;
2454 		Attribute *a_grace, *a_lock, *a_fail, *a_success;
2455 
2456 		a_grace = attr_find( e->e_attrs, ad_pwdGraceUseTime );
2457 		a_lock = attr_find( e->e_attrs, ad_pwdAccountLockedTime );
2458 		a_fail = attr_find( e->e_attrs, ad_pwdFailureTime );
2459 		a_success = attr_find( e->e_attrs, ad_pwdLastSuccess );
2460 
2461 		for( prev = &op->orm_modlist, ml = *prev; ml; ml = *prev ) {
2462 
2463 			if ( ml->sml_desc == slap_schema.si_ad_userPassword )
2464 				got_pw = 1;
2465 
2466 			/* If we're deleting an attr that didn't exist,
2467 			 * drop this delete op
2468 			 */
2469 			if ( ml->sml_op == LDAP_MOD_DELETE ||
2470 					ml->sml_op == SLAP_MOD_SOFTDEL ) {
2471 				int drop = 0;
2472 
2473 				if ( ml->sml_desc == ad_pwdGraceUseTime ) {
2474 					if ( !a_grace || got_del_grace ) {
2475 						drop = ml->sml_op == LDAP_MOD_DELETE;
2476 					} else {
2477 						got_del_grace = 1;
2478 					}
2479 				} else
2480 				if ( ml->sml_desc == ad_pwdAccountLockedTime ) {
2481 					if ( !a_lock || got_del_lock ) {
2482 						drop = ml->sml_op == LDAP_MOD_DELETE;
2483 					} else {
2484 						got_del_lock = 1;
2485 					}
2486 				} else
2487 				if ( ml->sml_desc == ad_pwdFailureTime ) {
2488 					if ( !a_fail || got_del_fail ) {
2489 						drop = ml->sml_op == LDAP_MOD_DELETE;
2490 					} else {
2491 						got_del_fail = 1;
2492 					}
2493 				}
2494 				if ( ml->sml_desc == ad_pwdLastSuccess ) {
2495 					if ( !a_success || got_del_success ) {
2496 						drop = ml->sml_op == LDAP_MOD_DELETE;
2497 					} else {
2498 						got_del_success = 1;
2499 					}
2500 				}
2501 				if ( drop ) {
2502 					*prev = ml->sml_next;
2503 					ml->sml_next = NULL;
2504 					slap_mods_free( ml, 1 );
2505 					continue;
2506 				}
2507 			}
2508 			prev = &ml->sml_next;
2509 		}
2510 
2511 		/* If we're resetting the password, make sure grace, accountlock,
2512 		 * success, and failure also get removed.
2513 		 */
2514 		if ( got_pw ) {
2515 			if ( a_grace && !got_del_grace ) {
2516 				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
2517 				ml->sml_op = LDAP_MOD_DELETE;
2518 				ml->sml_flags = SLAP_MOD_INTERNAL;
2519 				ml->sml_type.bv_val = NULL;
2520 				ml->sml_desc = ad_pwdGraceUseTime;
2521 				ml->sml_numvals = 0;
2522 				ml->sml_values = NULL;
2523 				ml->sml_nvalues = NULL;
2524 				ml->sml_next = NULL;
2525 				*prev = ml;
2526 				prev = &ml->sml_next;
2527 			}
2528 			if ( a_lock && !got_del_lock ) {
2529 				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
2530 				ml->sml_op = LDAP_MOD_DELETE;
2531 				ml->sml_flags = SLAP_MOD_INTERNAL;
2532 				ml->sml_type.bv_val = NULL;
2533 				ml->sml_desc = ad_pwdAccountLockedTime;
2534 				ml->sml_numvals = 0;
2535 				ml->sml_values = NULL;
2536 				ml->sml_nvalues = NULL;
2537 				ml->sml_next = NULL;
2538 				*prev = ml;
2539 			}
2540 			if ( a_fail && !got_del_fail ) {
2541 				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
2542 				ml->sml_op = LDAP_MOD_DELETE;
2543 				ml->sml_flags = SLAP_MOD_INTERNAL;
2544 				ml->sml_type.bv_val = NULL;
2545 				ml->sml_desc = ad_pwdFailureTime;
2546 				ml->sml_numvals = 0;
2547 				ml->sml_values = NULL;
2548 				ml->sml_nvalues = NULL;
2549 				ml->sml_next = NULL;
2550 				*prev = ml;
2551 			}
2552 			if ( a_success && !got_del_success ) {
2553 				ml = (Modifications *) ch_malloc( sizeof( Modifications ) );
2554 				ml->sml_op = LDAP_MOD_DELETE;
2555 				ml->sml_flags = SLAP_MOD_INTERNAL;
2556 				ml->sml_type.bv_val = NULL;
2557 				ml->sml_desc = ad_pwdLastSuccess;
2558 				ml->sml_numvals = 0;
2559 				ml->sml_values = NULL;
2560 				ml->sml_nvalues = NULL;
2561 				ml->sml_next = NULL;
2562 				*prev = ml;
2563 			}
2564 		}
2565 		op->o_bd->bd_info = (BackendInfo *)on->on_info;
2566 		be_entry_release_r( op, e );
2567 		return SLAP_CB_CONTINUE;
2568 	}
2569 
2570 	/* Did we receive a password policy request control? */
2571 	if ( op->o_ctrlflag[ppolicy_cid] ) {
2572 		send_ctrl = 1;
2573 	}
2574 
2575 	/* See if this is a pwdModify exop. If so, we can
2576 	 * access the plaintext passwords from that request.
2577 	 */
2578 	{
2579 		slap_callback *sc;
2580 
2581 		for ( sc = op->o_callback; sc; sc=sc->sc_next ) {
2582 			if ( sc->sc_response == slap_null_cb &&
2583 				sc->sc_private ) {
2584 				req_pwdexop_s *qpw = sc->sc_private;
2585 				newpw = qpw->rs_new;
2586 				oldpw = qpw->rs_old;
2587 				is_pwdexop = 1;
2588 			   	break;
2589 			}
2590 		}
2591 	}
2592 
2593 	/* ppolicy_hash_cleartext depends on pwmod being determined first */
2594 	if ( ppolicy_get( op, e, &pp ) == LDAP_SUCCESS ) {
2595 		have_policy = 1;
2596 	}
2597 
2598 	if ( access_allowed( op, e, pp.ad, NULL, ACL_MANAGE, NULL ) ) {
2599 		is_pwdadmin = 1;
2600 	}
2601 
2602 	for ( ml = op->orm_modlist,
2603 			pwmod = 0, mod_pw_only = 1,
2604 			deladd = 0, delmod = NULL,
2605 			addmod = NULL,
2606 			zapReset = 1;
2607 		ml != NULL; modtail = ml, ml = ml->sml_next )
2608 	{
2609 		if ( ml->sml_desc == pp.ad ) {
2610 			pwmod = 1;
2611 			pwmop = ml->sml_op;
2612 			if ((deladd == 0) && (ml->sml_op == LDAP_MOD_DELETE) &&
2613 				(ml->sml_values) && !BER_BVISNULL( &ml->sml_values[0] ))
2614 			{
2615 				deladd = 1;
2616 				delmod = ml;
2617 			}
2618 
2619 			if ((ml->sml_op == LDAP_MOD_ADD) ||
2620 				(ml->sml_op == LDAP_MOD_REPLACE))
2621 			{
2622 				if ( ml->sml_values && !BER_BVISNULL( &ml->sml_values[0] )) {
2623 					if ( deladd == 1 )
2624 						deladd = 2;
2625 
2626 					/* FIXME: there's no easy way to ensure
2627 					 * that add does not cause multiple
2628 					 * userPassword values; one way (that
2629 					 * would be consistent with the single
2630 					 * password constraint) would be to turn
2631 					 * add into replace); another would be
2632 					 * to disallow add.
2633 					 *
2634 					 * Let's check at least that a single value
2635 					 * is being added
2636 					 */
2637 					if ( addmod || !BER_BVISNULL( &ml->sml_values[ 1 ] ) ) {
2638 						rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
2639 						rs->sr_text = "Password policy only allows one password value";
2640 						goto return_results;
2641 					}
2642 
2643 					addmod = ml;
2644 				} else {
2645 					/* replace can have no values, add cannot */
2646 					assert( ml->sml_op == LDAP_MOD_REPLACE );
2647 				}
2648 			}
2649 
2650 		} else if ( !(ml->sml_flags & SLAP_MOD_INTERNAL) && !is_at_operational( ml->sml_desc->ad_type ) ) {
2651 			mod_pw_only = 0;
2652 			/* modifying something other than password */
2653 		}
2654 
2655 		/*
2656 		 * If there is a request to explicitly add a pwdReset
2657 		 * attribute, then we suppress the normal behaviour on
2658 		 * password change, which is to remove the pwdReset
2659 		 * attribute.
2660 		 *
2661 		 * This enables an administrator to assign a new password
2662 		 * and place a "must reset" flag on the entry, which will
2663 		 * stay until the user explicitly changes his/her password.
2664 		 */
2665 		if (ml->sml_desc == ad_pwdReset ) {
2666 			if ((ml->sml_op == LDAP_MOD_ADD) ||
2667 				(ml->sml_op == LDAP_MOD_REPLACE))
2668 				zapReset = 0;
2669 		}
2670 		if ( ml->sml_op == LDAP_MOD_DELETE ) {
2671 			if ( ml->sml_desc == ad_pwdGraceUseTime ) {
2672 				got_del_grace = 1;
2673 			} else if ( ml->sml_desc == ad_pwdAccountLockedTime ) {
2674 				got_del_lock = 1;
2675 			} else if ( ml->sml_desc == ad_pwdFailureTime ) {
2676 				got_del_fail = 1;
2677 			} else if ( ml->sml_desc == ad_pwdLastSuccess ) {
2678 				got_del_success = 1;
2679 			}
2680 		}
2681 		if ( ml->sml_desc == ad_pwdChangedTime ) {
2682 			got_changed = 1;
2683 		} else if (ml->sml_desc == ad_pwdHistory ) {
2684 			got_history = 1;
2685 		}
2686 	}
2687 
2688 	if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) {
2689 		if ( dn_match( &op->o_conn->c_ndn,
2690 				&pwcons[op->o_conn->c_conn_idx].dn )) {
2691 			Debug( LDAP_DEBUG_TRACE,
2692 				"connection restricted to password changing only\n" );
2693 			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
2694 			rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password";
2695 			pErr = PP_changeAfterReset;
2696 			goto return_results;
2697 		} else {
2698 			ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val );
2699 			BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn );
2700 		}
2701 	}
2702 
2703 	/*
2704 	 * if we have a "safe password modify policy", then we need to check if we're doing
2705 	 * a delete (with the old password), followed by an add (with the new password).
2706 	 *
2707 	 * If we got just a delete with nothing else, just let it go. We also skip all the checks if
2708 	 * the root user is bound. Root can do anything, including avoid the policies.
2709 	 */
2710 
2711 	if (!have_policy || !pwmod) goto do_modify;
2712 
2713 	/*
2714 	 * Build the password history list in ascending time order
2715 	 * We need this, even if the user is root, in order to maintain
2716 	 * the pwdHistory operational attributes properly.
2717 	 */
2718 	if (addmod && pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) {
2719 		struct berval oldpw;
2720 		time_t oldtime;
2721 
2722 		for(i=0; ha->a_nvals[i].bv_val; i++) {
2723 			rc = parse_pwdhistory( &(ha->a_nvals[i]), NULL,
2724 				&oldtime, &oldpw );
2725 
2726 			if (rc != LDAP_SUCCESS) continue; /* invalid history entry */
2727 
2728 			if (oldpw.bv_val) {
2729 				add_to_pwd_history( &tl, oldtime, &oldpw,
2730 					&(ha->a_nvals[i]) );
2731 				oldpw.bv_val = NULL;
2732 				oldpw.bv_len = 0;
2733 			}
2734 		}
2735 		for(p=tl; p; p=p->next, hsize++); /* count history size */
2736 	}
2737 
2738 	if (is_pwdadmin) goto do_modify;
2739 
2740 	/* NOTE: according to draft-behera-ldap-password-policy
2741 	 * pwdAllowUserChange == FALSE must only prevent pwd changes
2742 	 * by the user the pwd belongs to (ITS#7021) */
2743 	if (!pp.pwdAllowUserChange && dn_match(&op->o_req_ndn, &op->o_ndn)) {
2744 		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
2745 		rs->sr_text = "User alteration of password is not allowed";
2746 		pErr = PP_passwordModNotAllowed;
2747 		goto return_results;
2748 	}
2749 
2750 	/* Just deleting? */
2751 	if (!addmod) {
2752 		/* skip everything else */
2753 		pwmod = 0;
2754 		goto do_modify;
2755 	}
2756 
2757 	/* This is a pwdModify exop that provided the old pw.
2758 	 * We need to create a Delete mod for this old pw and
2759 	 * let the matching value get found later
2760 	 */
2761 	if (pp.pwdSafeModify && oldpw.bv_val ) {
2762 		ml = (Modifications *)ch_calloc( sizeof( Modifications ), 1 );
2763 		ml->sml_op = LDAP_MOD_DELETE;
2764 		ml->sml_flags = SLAP_MOD_INTERNAL;
2765 		ml->sml_desc = pp.ad;
2766 		ml->sml_type = pp.ad->ad_cname;
2767 		ml->sml_numvals = 1;
2768 		ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
2769 		ber_dupbv( &ml->sml_values[0], &oldpw );
2770 		BER_BVZERO( &ml->sml_values[1] );
2771 		ml->sml_next = op->orm_modlist;
2772 		op->orm_modlist = ml;
2773 		delmod = ml;
2774 		deladd = 2;
2775 	}
2776 
2777 	if (pp.pwdSafeModify && deladd != 2) {
2778 		Debug( LDAP_DEBUG_TRACE,
2779 			"change password must use DELETE followed by ADD/REPLACE\n" );
2780 		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
2781 		rs->sr_text = "Must supply old password to be changed as well as new one";
2782 		pErr = PP_mustSupplyOldPassword;
2783 		goto return_results;
2784 	}
2785 
2786 	/* Check age, but only if pwdReset is not TRUE */
2787 	pa = attr_find( e->e_attrs, ad_pwdReset );
2788 	if ((!pa || !bvmatch( &pa->a_nvals[0], &slap_true_bv )) &&
2789 		pp.pwdMinAge > 0) {
2790 		time_t pwtime = (time_t)-1, now;
2791 		int age;
2792 
2793 		if ((pa = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL)
2794 			pwtime = parse_time( pa->a_nvals[0].bv_val );
2795 		now = slap_get_time();
2796 		age = (int)(now - pwtime);
2797 		if ((pwtime != (time_t)-1) && (age < pp.pwdMinAge)) {
2798 			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
2799 			rs->sr_text = "Password is too young to change";
2800 			pErr = PP_passwordTooYoung;
2801 			goto return_results;
2802 		}
2803 	}
2804 
2805 	/* pa is used in password history check below, be sure it's set */
2806 	if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL && delmod) {
2807 		/*
2808 		 * we have a password to check
2809 		 */
2810 		bv = oldpw.bv_val ? &oldpw : delmod->sml_values;
2811 		/* FIXME: no access checking? */
2812 		rc = slap_passwd_check( op, NULL, pa, bv, &txt );
2813 		if (rc != LDAP_SUCCESS) {
2814 			Debug( LDAP_DEBUG_TRACE,
2815 				"old password check failed: %s\n", txt );
2816 
2817 			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
2818 			rs->sr_text = "Must supply correct old password to change to new one";
2819 			pErr = PP_mustSupplyOldPassword;
2820 			goto return_results;
2821 
2822 		} else {
2823 			int i;
2824 
2825 			/*
2826 			 * replace the delete value with the (possibly hashed)
2827 			 * value which is currently in the password.
2828 			 */
2829 			for ( i = 0; !BER_BVISNULL( &delmod->sml_values[i] ); i++ ) {
2830 				free( delmod->sml_values[i].bv_val );
2831 				BER_BVZERO( &delmod->sml_values[i] );
2832 			}
2833 			free( delmod->sml_values );
2834 			delmod->sml_values = ch_calloc( sizeof(struct berval), 2 );
2835 			BER_BVZERO( &delmod->sml_values[1] );
2836 			ber_dupbv( &(delmod->sml_values[0]),  &(pa->a_nvals[0]) );
2837 		}
2838 	}
2839 
2840 	bv = newpw.bv_val ? &newpw : &addmod->sml_values[0];
2841 	if (pp.pwdCheckQuality > 0) {
2842 		struct berval errmsg = BER_BVC( errbuf );
2843 
2844 		rc = check_password_quality( bv, pi, &pp, &pErr, e, &errmsg );
2845 		if (rc != LDAP_SUCCESS) {
2846 			rs->sr_err = rc;
2847 			txt = errmsg.bv_val;
2848 			if ( txt && txt[0] ) {
2849 				rs->sr_text = txt;
2850 				if ( txt != errbuf )
2851 					free_txt = 1;
2852 			} else {
2853 				rs->sr_text = "Password fails quality checking policy";
2854 			}
2855 			goto return_results;
2856 		}
2857 	}
2858 
2859 	/* If pwdInHistory is zero, passwords may be reused */
2860 	if (pa && pp.pwdInHistory > 0) {
2861 		/*
2862 		 * Last check - the password history.
2863 		 */
2864 		/* FIXME: no access checking? */
2865 		if (slap_passwd_check( op, NULL, pa, bv, &txt ) == LDAP_SUCCESS) {
2866 			/*
2867 			 * This is bad - it means that the user is attempting
2868 			 * to set the password to the same as the old one.
2869 			 */
2870 			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
2871 			rs->sr_text = "Password is not being changed from existing value";
2872 			pErr = PP_passwordInHistory;
2873 			goto return_results;
2874 		}
2875 
2876 		/* We need this when reduce pwdInHistory */
2877 		hskip = hsize - pp.pwdInHistory;
2878 
2879 		/*
2880 		 * Iterate through the password history, and fail on any
2881 		 * password matches.
2882 		 */
2883 		at = *pa;
2884 		at.a_vals = cr;
2885 		cr[1].bv_val = NULL;
2886 		for(p=tl; p; p=p->next) {
2887 			if(hskip > 0){
2888 				hskip--;
2889 				continue;
2890 			}
2891 			cr[0] = p->pw;
2892 			/* FIXME: no access checking? */
2893 			rc = slap_passwd_check( op, NULL, &at, bv, &txt );
2894 
2895 			if (rc != LDAP_SUCCESS) continue;
2896 
2897 			rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
2898 			rs->sr_text = "Password is in history of old passwords";
2899 			pErr = PP_passwordInHistory;
2900 			goto return_results;
2901 		}
2902 	}
2903 
2904 do_modify:
2905 	if (pwmod) {
2906 		struct berval timestamp;
2907 		char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
2908 		time_t now = slap_get_time();
2909 
2910 		/* If the conn is restricted, set a callback to clear it
2911 		 * if the pwmod succeeds
2912 		 */
2913 		if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) {
2914 			slap_callback *sc = op->o_tmpcalloc( 1, sizeof( slap_callback ),
2915 				op->o_tmpmemctx );
2916 			sc->sc_next = op->o_callback;
2917 			/* Must use sc_response to insure we reset on success, before
2918 			 * the client sees the response. Must use sc_cleanup to insure
2919 			 * that it gets cleaned up if sc_response is not called.
2920 			 */
2921 			sc->sc_response = ppolicy_mod_cb;
2922 			sc->sc_cleanup = ppolicy_mod_cb;
2923 			op->o_callback = sc;
2924 		}
2925 
2926 		/*
2927 		 * keep the necessary pwd.. operational attributes
2928 		 * up to date.
2929 		 */
2930 
2931 		if (!got_changed) {
2932 			timestamp.bv_val = timebuf;
2933 			timestamp.bv_len = sizeof(timebuf);
2934 			slap_timestamp( &now, &timestamp );
2935 
2936 			mods = NULL;
2937 			if (pwmop != LDAP_MOD_DELETE) {
2938 				mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2939 				mods->sml_op = LDAP_MOD_REPLACE;
2940 				mods->sml_numvals = 1;
2941 				mods->sml_values = (BerVarray) ch_calloc( sizeof( struct berval ), 2 );
2942 				mods->sml_nvalues = (BerVarray) ch_calloc( sizeof( struct berval ), 2 );
2943 
2944 				ber_dupbv( &mods->sml_values[0], &timestamp );
2945 				ber_dupbv( &mods->sml_nvalues[0], &timestamp );
2946 			} else if (attr_find(e->e_attrs, ad_pwdChangedTime )) {
2947 				mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2948 				mods->sml_op = LDAP_MOD_DELETE;
2949 			}
2950 			if (mods) {
2951 				mods->sml_desc = ad_pwdChangedTime;
2952 				mods->sml_flags = SLAP_MOD_INTERNAL;
2953 				mods->sml_next = NULL;
2954 				modtail->sml_next = mods;
2955 				modtail = mods;
2956 			}
2957 		}
2958 
2959 		if (!got_del_grace && attr_find(e->e_attrs, ad_pwdGraceUseTime )) {
2960 			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2961 			mods->sml_op = LDAP_MOD_DELETE;
2962 			mods->sml_desc = ad_pwdGraceUseTime;
2963 			mods->sml_flags = SLAP_MOD_INTERNAL;
2964 			mods->sml_next = NULL;
2965 			modtail->sml_next = mods;
2966 			modtail = mods;
2967 		}
2968 
2969 		if (!got_del_lock && attr_find(e->e_attrs, ad_pwdAccountLockedTime )) {
2970 			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2971 			mods->sml_op = LDAP_MOD_DELETE;
2972 			mods->sml_desc = ad_pwdAccountLockedTime;
2973 			mods->sml_flags = SLAP_MOD_INTERNAL;
2974 			mods->sml_next = NULL;
2975 			modtail->sml_next = mods;
2976 			modtail = mods;
2977 		}
2978 
2979 		if (!got_del_fail && attr_find(e->e_attrs, ad_pwdFailureTime )) {
2980 			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2981 			mods->sml_op = LDAP_MOD_DELETE;
2982 			mods->sml_desc = ad_pwdFailureTime;
2983 			mods->sml_flags = SLAP_MOD_INTERNAL;
2984 			mods->sml_next = NULL;
2985 			modtail->sml_next = mods;
2986 			modtail = mods;
2987 		}
2988 
2989 		if ( zapReset ) {
2990 			/*
2991 			 * ITS#7084 Is this a modification by the password
2992 			 * administrator? Then force a reset if configured.
2993 			 * Otherwise clear it.
2994 			 */
2995 			if ( pp.pwdMustChange && is_pwdadmin ) {
2996 				mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
2997 				mods->sml_op = LDAP_MOD_REPLACE;
2998 				mods->sml_desc = ad_pwdReset;
2999 				mods->sml_flags = SLAP_MOD_INTERNAL;
3000 				mods->sml_numvals = 1;
3001 				mods->sml_values = (BerVarray) ch_calloc( sizeof( struct berval ), 2 );
3002 				mods->sml_nvalues = (BerVarray) ch_calloc( sizeof( struct berval ), 2 );
3003 
3004 				ber_dupbv( &mods->sml_values[0], (struct berval *)&slap_true_bv );
3005 				ber_dupbv( &mods->sml_nvalues[0], (struct berval *)&slap_true_bv );
3006 
3007 				mods->sml_next = NULL;
3008 				modtail->sml_next = mods;
3009 				modtail = mods;
3010 			} else if ( attr_find( e->e_attrs, ad_pwdReset ) ) {
3011 				mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
3012 				mods->sml_op = LDAP_MOD_DELETE;
3013 				mods->sml_desc = ad_pwdReset;
3014 				mods->sml_flags = SLAP_MOD_INTERNAL;
3015 				mods->sml_next = NULL;
3016 				modtail->sml_next = mods;
3017 				modtail = mods;
3018 			}
3019 		}
3020 
3021 		/* TODO: do we remove pwdLastSuccess or set it to 'now'? */
3022 		if (!got_del_success && attr_find(e->e_attrs, ad_pwdLastSuccess )){
3023 			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
3024 			mods->sml_op = LDAP_MOD_DELETE;
3025 			mods->sml_flags = SLAP_MOD_INTERNAL;
3026 			mods->sml_desc = ad_pwdLastSuccess;
3027 			mods->sml_next = NULL;
3028 			modtail->sml_next = mods;
3029 			modtail = mods;
3030 		}
3031 
3032 		/* Delete all pwdInHistory attribute */
3033 		if (!got_history && pp.pwdInHistory == 0 &&
3034             attr_find(e->e_attrs, ad_pwdHistory )){
3035 			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
3036 			mods->sml_op = LDAP_MOD_DELETE;
3037 			mods->sml_flags = SLAP_MOD_INTERNAL;
3038 			mods->sml_desc = ad_pwdHistory;
3039 			mods->sml_next = NULL;
3040 			modtail->sml_next = mods;
3041 			modtail = mods;
3042 		}
3043 
3044 		if (!got_history && pp.pwdInHistory > 0){
3045 			if (hsize >= pp.pwdInHistory) {
3046 				/*
3047 				 * We use the >= operator, since we are going to add
3048 				 * the existing password attribute value into the
3049 				 * history - thus the cardinality of history values is
3050 				 * about to rise by one.
3051 				 *
3052 				 * If this would push it over the limit of history
3053 				 * values (remembering - the password policy could have
3054 				 * changed since the password was last altered), we must
3055 				 * delete at least 1 value from the pwdHistory list.
3056 				 *
3057 				 * In fact, we delete '(#pwdHistory attrs - max pwd
3058 				 * history length) + 1' values, starting with the oldest.
3059 				 * This is easily evaluated, since the linked list is
3060 				 * created in ascending time order.
3061 				 */
3062 				mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
3063 				mods->sml_op = LDAP_MOD_DELETE;
3064 				mods->sml_flags = SLAP_MOD_INTERNAL;
3065 				mods->sml_desc = ad_pwdHistory;
3066 				mods->sml_numvals = hsize - pp.pwdInHistory + 1;
3067 				mods->sml_values = ch_calloc( sizeof( struct berval ),
3068 					hsize - pp.pwdInHistory + 2 );
3069 				BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] );
3070 				for(i=0,p=tl; i < (hsize - pp.pwdInHistory + 1); i++, p=p->next) {
3071 					BER_BVZERO( &mods->sml_values[i] );
3072 					ber_dupbv( &(mods->sml_values[i]), &p->bv );
3073 				}
3074 				mods->sml_next = NULL;
3075 				modtail->sml_next = mods;
3076 				modtail = mods;
3077 			}
3078 			free_pwd_history_list( &tl );
3079 
3080 			/*
3081 			 * Now add the existing password into the history list.
3082 			 * This will be executed even if the operation is to delete
3083 			 * the password entirely.
3084 			 *
3085 			 * This isn't in the spec explicitly, but it seems to make
3086 			 * sense that the password history list is the list of all
3087 			 * previous passwords - even if they were deleted. Thus, if
3088 			 * someone tries to add a historical password at some future
3089 			 * point, it will fail.
3090 			 */
3091 			if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL) {
3092 				mods = (Modifications *) ch_malloc( sizeof( Modifications ) );
3093 				mods->sml_op = LDAP_MOD_ADD;
3094 				mods->sml_flags = SLAP_MOD_INTERNAL;
3095 				mods->sml_type.bv_val = NULL;
3096 				mods->sml_desc = ad_pwdHistory;
3097 				mods->sml_nvalues = NULL;
3098 				mods->sml_numvals = 1;
3099 				mods->sml_values = ch_calloc( sizeof( struct berval ), 2 );
3100 				mods->sml_values[ 1 ].bv_val = NULL;
3101 				mods->sml_values[ 1 ].bv_len = 0;
3102 				make_pwd_history_value( timebuf, &mods->sml_values[0], pa );
3103 				mods->sml_next = NULL;
3104 				modtail->sml_next = mods;
3105 				modtail = mods;
3106 
3107 			} else {
3108 				Debug( LDAP_DEBUG_TRACE,
3109 				"ppolicy_modify: password attr lookup failed\n" );
3110 			}
3111 		}
3112 
3113 		/*
3114 		 * Controversial bit here. If the new password isn't hashed
3115 		 * (ie, is cleartext), we probably should hash it according
3116 		 * to the default hash. The reason for this is that we want
3117 		 * to use the policy if possible, but if we hash the password
3118 		 * before, then we're going to run into trouble when it
3119 		 * comes time to check the password.
3120 		 *
3121 		 * Now, the right thing to do is to use the extended password
3122 		 * modify operation, but not all software can do this,
3123 		 * therefore it makes sense to hash the new password, now
3124 		 * we know it passes the policy requirements.
3125 		 *
3126 		 * Of course, if the password is already hashed, then we
3127 		 * leave it alone.
3128 		 */
3129 
3130 		if ((pi->hash_passwords) && (addmod) && !newpw.bv_val &&
3131 			(password_scheme( &(addmod->sml_values[0]), NULL ) != LDAP_SUCCESS))
3132 		{
3133 			struct berval hpw, bv;
3134 
3135 			slap_passwd_hash( &(addmod->sml_values[0]), &hpw, &txt );
3136 			if (hpw.bv_val == NULL) {
3137 					/*
3138 					 * hashing didn't work. Emit an error.
3139 					 */
3140 				rs->sr_err = LDAP_OTHER;
3141 				rs->sr_text = txt;
3142 				goto return_results;
3143 			}
3144 			bv = addmod->sml_values[0];
3145 				/* clear and discard the clear password */
3146 			memset(bv.bv_val, 0, bv.bv_len);
3147 			ber_memfree(bv.bv_val);
3148 			addmod->sml_values[0] = hpw;
3149 		}
3150 	} else {
3151 		/* ITS#8762 Make sure we drop pwdFailureTime if unlocking */
3152 		if (got_del_lock && !got_del_fail && attr_find(e->e_attrs, ad_pwdFailureTime )) {
3153 			mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 );
3154 			mods->sml_op = LDAP_MOD_DELETE;
3155 			mods->sml_desc = ad_pwdFailureTime;
3156 			mods->sml_flags = SLAP_MOD_INTERNAL;
3157 			mods->sml_next = NULL;
3158 			modtail->sml_next = mods;
3159 			modtail = mods;
3160 		}
3161 	}
3162 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
3163 	be_entry_release_r( op, e );
3164 	return SLAP_CB_CONTINUE;
3165 
3166 return_results:
3167 	free_pwd_history_list( &tl );
3168 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
3169 	be_entry_release_r( op, e );
3170 	if ( send_ctrl ) {
3171 		ctrl = create_passcontrol( op, -1, -1, pErr );
3172 		oldctrls = add_passcontrol( op, rs, ctrl );
3173 	}
3174 	send_ldap_result( op, rs );
3175 	if ( free_txt ) {
3176 		if ( is_pwdexop ) {
3177 			slap_callback *cb;
3178 			cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback),
3179 				1, op->o_tmpmemctx );
3180 
3181 			/* Setup a callback so we can free the text when sent */
3182 			cb->sc_cleanup = ppolicy_text_cleanup;
3183 			cb->sc_private = (void *)txt;
3184 			overlay_callback_after_backover( op, cb, 1 );
3185 		} else {
3186 			if ( rs->sr_text == txt ) {
3187 				rs->sr_text = NULL;
3188 			}
3189 			free( (char *)txt );
3190 		}
3191 	}
3192 	if ( send_ctrl ) {
3193 		if ( is_pwdexop ) {
3194 			if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
3195 				op->o_tmpfree( oldctrls, op->o_tmpmemctx );
3196 			}
3197 			oldctrls = NULL;
3198 			rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
3199 
3200 		} else {
3201 			ctrls_cleanup( op, rs, oldctrls );
3202 		}
3203 	}
3204 	return rs->sr_err;
3205 }
3206 
3207 static int
ppolicy_parseCtrl(Operation * op,SlapReply * rs,LDAPControl * ctrl)3208 ppolicy_parseCtrl(
3209 	Operation *op,
3210 	SlapReply *rs,
3211 	LDAPControl *ctrl )
3212 {
3213 	if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
3214 		rs->sr_text = "passwordPolicyRequest control value not absent";
3215 		return LDAP_PROTOCOL_ERROR;
3216 	}
3217 	op->o_ctrlflag[ppolicy_cid] = ctrl->ldctl_iscritical
3218 		? SLAP_CONTROL_CRITICAL
3219 		: SLAP_CONTROL_NONCRITICAL;
3220 
3221 	return LDAP_SUCCESS;
3222 }
3223 
3224 static int
ppolicy_au_parseCtrl(Operation * op,SlapReply * rs,LDAPControl * ctrl)3225 ppolicy_au_parseCtrl(
3226 	Operation *op,
3227 	SlapReply *rs,
3228 	LDAPControl *ctrl )
3229 {
3230 	if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
3231 		rs->sr_text = "account usability control value not absent";
3232 		return LDAP_PROTOCOL_ERROR;
3233 	}
3234 	op->o_ctrlflag[account_usability_cid] = ctrl->ldctl_iscritical
3235 		? SLAP_CONTROL_CRITICAL
3236 		: SLAP_CONTROL_NONCRITICAL;
3237 
3238 	return LDAP_SUCCESS;
3239 }
3240 
3241 static int
attrPretty(Syntax * syntax,struct berval * val,struct berval * out,void * ctx)3242 attrPretty(
3243 	Syntax *syntax,
3244 	struct berval *val,
3245 	struct berval *out,
3246 	void *ctx )
3247 {
3248 	AttributeDescription *ad = NULL;
3249 	const char *err;
3250 	int code;
3251 
3252 	code = slap_bv2ad( val, &ad, &err );
3253 	if ( !code ) {
3254 		ber_dupbv_x( out, &ad->ad_type->sat_cname, ctx );
3255 	}
3256 	return code;
3257 }
3258 
3259 static int
attrNormalize(slap_mask_t use,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * out,void * ctx)3260 attrNormalize(
3261 	slap_mask_t use,
3262 	Syntax *syntax,
3263 	MatchingRule *mr,
3264 	struct berval *val,
3265 	struct berval *out,
3266 	void *ctx )
3267 {
3268 	AttributeDescription *ad = NULL;
3269 	const char *err;
3270 	int code;
3271 
3272 	code = slap_bv2ad( val, &ad, &err );
3273 	if ( !code ) {
3274 		ber_str2bv_x( ad->ad_type->sat_oid, 0, 1, out, ctx );
3275 	}
3276 	return code;
3277 }
3278 
3279 static int
ppolicy_db_init(BackendDB * be,ConfigReply * cr)3280 ppolicy_db_init(
3281 	BackendDB *be,
3282 	ConfigReply *cr
3283 )
3284 {
3285 	slap_overinst *on = (slap_overinst *) be->bd_info;
3286 	pp_info *pi;
3287 
3288 	if ( SLAP_ISGLOBALOVERLAY( be ) ) {
3289 		/* do not allow slapo-ppolicy to be global by now (ITS#5858) */
3290 		if ( cr ){
3291 			snprintf( cr->msg, sizeof(cr->msg),
3292 				"slapo-ppolicy cannot be global" );
3293 			Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg );
3294 		}
3295 		return 1;
3296 	}
3297 
3298 	pi = on->on_bi.bi_private = ch_calloc( sizeof(pp_info), 1 );
3299 
3300 	if ( !pwcons ) {
3301 		/* accommodate for c_conn_idx == -1 */
3302 		pwcons = ch_calloc( sizeof(pw_conn), dtblsize + 1 );
3303 		pwcons++;
3304 	}
3305 
3306 	ov_count++;
3307 
3308 	ldap_pvt_thread_mutex_init( &pi->pwdFailureTime_mutex );
3309 
3310 	return 0;
3311 }
3312 
3313 static int
ppolicy_db_open(BackendDB * be,ConfigReply * cr)3314 ppolicy_db_open(
3315 	BackendDB *be,
3316 	ConfigReply *cr
3317 )
3318 {
3319 	int rc;
3320 
3321 	if ( (rc = overlay_register_control( be, LDAP_CONTROL_X_ACCOUNT_USABILITY )) != LDAP_SUCCESS ) {
3322 		return rc;
3323 	}
3324 	return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
3325 }
3326 
3327 static int
ppolicy_db_close(BackendDB * be,ConfigReply * cr)3328 ppolicy_db_close(
3329 	BackendDB *be,
3330 	ConfigReply *cr
3331 )
3332 {
3333 #ifdef SLAP_CONFIG_DELETE
3334 	overlay_unregister_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST );
3335 	overlay_unregister_control( be, LDAP_CONTROL_X_ACCOUNT_USABILITY );
3336 #endif /* SLAP_CONFIG_DELETE */
3337 
3338 	return 0;
3339 }
3340 
3341 static int
ppolicy_db_destroy(BackendDB * be,ConfigReply * cr)3342 ppolicy_db_destroy(
3343 	BackendDB *be,
3344 	ConfigReply *cr
3345 )
3346 {
3347 	slap_overinst *on = (slap_overinst *) be->bd_info;
3348 	pp_info *pi = on->on_bi.bi_private;
3349 
3350 	on->on_bi.bi_private = NULL;
3351 	ldap_pvt_thread_mutex_destroy( &pi->pwdFailureTime_mutex );
3352 	free( pi->def_policy.bv_val );
3353 	free( pi );
3354 
3355 	ov_count--;
3356 	if ( ov_count <=0 && pwcons ) {
3357 		pw_conn *pwc = pwcons;
3358 		pwcons = NULL;
3359 		pwc--;
3360 		ch_free( pwc );
3361 	}
3362 	return 0;
3363 }
3364 
3365 static char *extops[] = {
3366 	LDAP_EXOP_MODIFY_PASSWD,
3367 	NULL
3368 };
3369 
3370 static slap_overinst ppolicy;
3371 
ppolicy_initialize()3372 int ppolicy_initialize()
3373 {
3374 	int i, code;
3375 
3376 	for (i=0; pwd_OpSchema[i].def; i++) {
3377 		code = register_at( pwd_OpSchema[i].def, pwd_OpSchema[i].ad, 0 );
3378 		if ( code ) {
3379 			Debug( LDAP_DEBUG_ANY,
3380 				"ppolicy_initialize: register_at failed\n" );
3381 			return code;
3382 		}
3383 		/* Allow Manager to set these as needed */
3384 		if ( is_at_no_user_mod( (*pwd_OpSchema[i].ad)->ad_type )) {
3385 			(*pwd_OpSchema[i].ad)->ad_type->sat_flags |=
3386 				SLAP_AT_MANAGEABLE;
3387 		}
3388 	}
3389 	ad_pwdLastSuccess = slap_schema.si_ad_pwdLastSuccess;
3390 	{
3391 		Syntax *syn;
3392 		MatchingRule *mr;
3393 
3394 		syn = ch_malloc( sizeof( Syntax ));
3395 		*syn = *ad_pwdAttribute->ad_type->sat_syntax;
3396 		syn->ssyn_pretty = attrPretty;
3397 		ad_pwdAttribute->ad_type->sat_syntax = syn;
3398 
3399 		mr = ch_malloc( sizeof( MatchingRule ));
3400 		*mr = *ad_pwdAttribute->ad_type->sat_equality;
3401 		mr->smr_normalize = attrNormalize;
3402 		ad_pwdAttribute->ad_type->sat_equality = mr;
3403 	}
3404 
3405 	for (i=0; pwd_ocs[i]; i++) {
3406 		code = register_oc( pwd_ocs[i], NULL, 0 );
3407 		if ( code ) {
3408 			Debug( LDAP_DEBUG_ANY, "ppolicy_initialize: "
3409 				"register_oc failed\n" );
3410 			return code;
3411 		}
3412 	}
3413 
3414 	code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
3415 		SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY, extops,
3416 		ppolicy_parseCtrl, &ppolicy_cid );
3417 	if ( code != LDAP_SUCCESS ) {
3418 		Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code );
3419 		return code;
3420 	}
3421 
3422 	code = register_supported_control( LDAP_CONTROL_X_ACCOUNT_USABILITY,
3423 		SLAP_CTRL_SEARCH, NULL,
3424 		ppolicy_au_parseCtrl, &account_usability_cid );
3425 	if ( code != LDAP_SUCCESS ) {
3426 		Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code );
3427 		return code;
3428 	}
3429 
3430 	/* We don't expect to receive these controls, only send them */
3431 	code = register_supported_control( LDAP_CONTROL_X_PASSWORD_EXPIRED,
3432 		0, NULL, NULL, NULL );
3433 	if ( code != LDAP_SUCCESS ) {
3434 		Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code );
3435 		return code;
3436 	}
3437 
3438 	code = register_supported_control( LDAP_CONTROL_X_PASSWORD_EXPIRING,
3439 		0, NULL, NULL, NULL );
3440 	if ( code != LDAP_SUCCESS ) {
3441 		Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code );
3442 		return code;
3443 	}
3444 
3445 	ldap_pvt_thread_mutex_init( &chk_syntax_mutex );
3446 
3447 	ppolicy.on_bi.bi_type = "ppolicy";
3448 	ppolicy.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
3449 	ppolicy.on_bi.bi_db_init = ppolicy_db_init;
3450 	ppolicy.on_bi.bi_db_open = ppolicy_db_open;
3451 	ppolicy.on_bi.bi_db_close = ppolicy_db_close;
3452 	ppolicy.on_bi.bi_db_destroy = ppolicy_db_destroy;
3453 
3454 	ppolicy.on_bi.bi_op_add = ppolicy_add;
3455 	ppolicy.on_bi.bi_op_bind = ppolicy_bind;
3456 	ppolicy.on_bi.bi_op_compare = ppolicy_compare;
3457 	ppolicy.on_bi.bi_op_delete = ppolicy_restrict;
3458 	ppolicy.on_bi.bi_op_modify = ppolicy_modify;
3459 	ppolicy.on_bi.bi_op_search = ppolicy_search;
3460 	ppolicy.on_bi.bi_connection_destroy = ppolicy_connection_destroy;
3461 
3462 	ppolicy.on_bi.bi_cf_ocs = ppolicyocs;
3463 	code = config_register_schema( ppolicycfg, ppolicyocs );
3464 	if ( code ) return code;
3465 
3466 	return overlay_register( &ppolicy );
3467 }
3468 
3469 #if SLAPD_OVER_PPOLICY == SLAPD_MOD_DYNAMIC
init_module(int argc,char * argv[])3470 int init_module(int argc, char *argv[]) {
3471 	return ppolicy_initialize();
3472 }
3473 #endif
3474 
3475 #endif	/* defined(SLAPD_OVER_PPOLICY) */
3476