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