ppolicy.c revision 1.1.1.7
1/* $NetBSD: ppolicy.c,v 1.1.1.7 2018/02/06 01:53:16 christos Exp $ */ 2 3/* $OpenLDAP$ */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 2004-2017 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.1.1.7 2018/02/06 01:53:16 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 */ 58typedef 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 */ 68typedef struct pw_conn { 69 struct berval dn; /* DN of restricted user */ 70} pw_conn; 71 72static pw_conn *pwcons; 73static int ppolicy_cid; 74static int ov_count; 75 76typedef 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 105typedef 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 */ 113static AttributeDescription *ad_pwdChangedTime, *ad_pwdAccountLockedTime, 114 *ad_pwdFailureTime, *ad_pwdHistory, *ad_pwdGraceUseTime, *ad_pwdReset, 115 *ad_pwdPolicySubentry; 116 117static 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 */ 187static 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 196static 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 217static ldap_pvt_thread_mutex_t chk_syntax_mutex; 218 219enum { 220 PPOLICY_DEFAULT = 1, 221 PPOLICY_HASH_CLEARTEXT, 222 PPOLICY_USE_LOCKOUT 223}; 224 225static ConfigDriver ppolicy_cf_default; 226 227static 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 254static 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 265static int 266ppolicy_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 316static time_t 317parse_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 330static int 331account_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 383static const char ppolicy_ctrl_oid[] = LDAP_CONTROL_PASSWORDPOLICYRESPONSE; 384 385static LDAPControl * 386create_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 ); 437fail: 438 (void)ber_free_buf(ber); 439 440 return cp; 441} 442 443static LDAPControl ** 444add_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 472static void 473ppolicy_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 486static void 487ppolicy_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 588defaultpol: 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 603static int 604password_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 633static int 634check_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 740static int 741parse_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 807exit_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 821static void 822add_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 854static void 855make_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 884static void 885free_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 902typedef 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 912static void 913ctrls_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 937static int 938ppolicy_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 947static int 948ppolicy_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 1158grace: 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 1197check_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 1232done: 1233 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1234 be_entry_release_r( op, e ); 1235 1236locked: 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 1296static int 1297ppolicy_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_next = op->o_callback->sc_next; 1332 cb->sc_private = ppb; 1333 op->o_callback->sc_next = cb; 1334 1335 /* Did we receive a password policy request control? */ 1336 if ( op->o_ctrlflag[ppolicy_cid] ) { 1337 ppb->send_ctrl = 1; 1338 } 1339 1340 op->o_bd->bd_info = (BackendInfo *)on; 1341 ppolicy_get( op, e, &ppb->pp ); 1342 1343 rc = account_locked( op, e, &ppb->pp, &ppb->mod ); 1344 1345 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1346 be_entry_release_r( op, e ); 1347 1348 if ( rc ) { 1349 ppb->pErr = PP_accountLocked; 1350 send_ldap_error( op, rs, LDAP_INVALID_CREDENTIALS, NULL ); 1351 return rs->sr_err; 1352 } 1353 1354 } 1355 1356 return SLAP_CB_CONTINUE; 1357} 1358 1359/* Reset the restricted info for the next session on this connection */ 1360static int 1361ppolicy_connection_destroy( BackendDB *bd, Connection *conn ) 1362{ 1363 if ( pwcons && !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) { 1364 ch_free( pwcons[conn->c_conn_idx].dn.bv_val ); 1365 BER_BVZERO( &pwcons[conn->c_conn_idx].dn ); 1366 } 1367 return SLAP_CB_CONTINUE; 1368} 1369 1370/* Check if this connection is restricted */ 1371static int 1372ppolicy_restrict( 1373 Operation *op, 1374 SlapReply *rs ) 1375{ 1376 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1377 int send_ctrl = 0; 1378 1379 /* Did we receive a password policy request control? */ 1380 if ( op->o_ctrlflag[ppolicy_cid] ) { 1381 send_ctrl = 1; 1382 } 1383 1384 if ( op->o_conn && !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { 1385 LDAPControl **oldctrls; 1386 /* if the current authcDN doesn't match the one we recorded, 1387 * then an intervening Bind has succeeded and the restriction 1388 * no longer applies. (ITS#4516) 1389 */ 1390 if ( !dn_match( &op->o_conn->c_ndn, 1391 &pwcons[op->o_conn->c_conn_idx].dn )) { 1392 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 1393 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 1394 return SLAP_CB_CONTINUE; 1395 } 1396 1397 Debug( LDAP_DEBUG_TRACE, 1398 "connection restricted to password changing only\n", 0, 0, 0); 1399 if ( send_ctrl ) { 1400 LDAPControl *ctrl = NULL; 1401 ctrl = create_passcontrol( op, -1, -1, PP_changeAfterReset ); 1402 oldctrls = add_passcontrol( op, rs, ctrl ); 1403 } 1404 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1405 send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS, 1406 "Operations are restricted to bind/unbind/abandon/StartTLS/modify password" ); 1407 if ( send_ctrl ) { 1408 ctrls_cleanup( op, rs, oldctrls ); 1409 } 1410 return rs->sr_err; 1411 } 1412 1413 return SLAP_CB_CONTINUE; 1414} 1415 1416static int 1417ppolicy_compare_response( 1418 Operation *op, 1419 SlapReply *rs ) 1420{ 1421 /* map compare responses to bind responses */ 1422 if ( rs->sr_err == LDAP_COMPARE_TRUE ) 1423 rs->sr_err = LDAP_SUCCESS; 1424 else if ( rs->sr_err == LDAP_COMPARE_FALSE ) 1425 rs->sr_err = LDAP_INVALID_CREDENTIALS; 1426 1427 ppolicy_bind_response( op, rs ); 1428 1429 /* map back to compare */ 1430 if ( rs->sr_err == LDAP_SUCCESS ) 1431 rs->sr_err = LDAP_COMPARE_TRUE; 1432 else if ( rs->sr_err == LDAP_INVALID_CREDENTIALS ) 1433 rs->sr_err = LDAP_COMPARE_FALSE; 1434 1435 return SLAP_CB_CONTINUE; 1436} 1437 1438static int 1439ppolicy_compare( 1440 Operation *op, 1441 SlapReply *rs ) 1442{ 1443 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1444 1445 if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE ) 1446 return rs->sr_err; 1447 1448 /* Did we receive a password policy request control? 1449 * Are we testing the userPassword? 1450 */ 1451 if ( op->o_ctrlflag[ppolicy_cid] && 1452 op->orc_ava->aa_desc == slap_schema.si_ad_userPassword ) { 1453 Entry *e; 1454 int rc; 1455 ppbind *ppb; 1456 slap_callback *cb; 1457 1458 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1459 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 1460 1461 if ( rc != LDAP_SUCCESS ) { 1462 return SLAP_CB_CONTINUE; 1463 } 1464 1465 cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback), 1466 1, op->o_tmpmemctx ); 1467 ppb = (ppbind *)(cb+1); 1468 ppb->on = on; 1469 ppb->pErr = PP_noError; 1470 ppb->send_ctrl = 1; 1471 /* failures here don't lockout the connection */ 1472 ppb->set_restrict = 0; 1473 1474 /* Setup a callback so we can munge the result */ 1475 1476 cb->sc_response = ppolicy_compare_response; 1477 cb->sc_next = op->o_callback->sc_next; 1478 cb->sc_private = ppb; 1479 op->o_callback->sc_next = cb; 1480 1481 op->o_bd->bd_info = (BackendInfo *)on; 1482 ppolicy_get( op, e, &ppb->pp ); 1483 1484 rc = account_locked( op, e, &ppb->pp, &ppb->mod ); 1485 1486 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1487 be_entry_release_r( op, e ); 1488 1489 if ( rc ) { 1490 ppb->pErr = PP_accountLocked; 1491 send_ldap_error( op, rs, LDAP_COMPARE_FALSE, NULL ); 1492 return rs->sr_err; 1493 } 1494 } 1495 return SLAP_CB_CONTINUE; 1496} 1497 1498static int 1499ppolicy_add( 1500 Operation *op, 1501 SlapReply *rs ) 1502{ 1503 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1504 pp_info *pi = on->on_bi.bi_private; 1505 PassPolicy pp; 1506 Attribute *pa; 1507 const char *txt; 1508 1509 if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE ) 1510 return rs->sr_err; 1511 1512 /* If this is a replica, assume the master checked everything */ 1513 if ( be_shadow_update( op )) 1514 return SLAP_CB_CONTINUE; 1515 1516 /* Check for password in entry */ 1517 if ((pa = attr_find( op->oq_add.rs_e->e_attrs, 1518 slap_schema.si_ad_userPassword ))) 1519 { 1520 assert( pa->a_vals != NULL ); 1521 assert( !BER_BVISNULL( &pa->a_vals[ 0 ] ) ); 1522 1523 if ( !BER_BVISNULL( &pa->a_vals[ 1 ] ) ) { 1524 send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, "Password policy only allows one password value" ); 1525 return rs->sr_err; 1526 } 1527 1528 /* 1529 * new entry contains a password - if we're not the root user 1530 * then we need to check that the password fits in with the 1531 * security policy for the new entry. 1532 */ 1533 ppolicy_get( op, op->ora_e, &pp ); 1534 if (pp.pwdCheckQuality > 0 && !be_isroot( op )) { 1535 struct berval *bv = &(pa->a_vals[0]); 1536 int rc, send_ctrl = 0; 1537 LDAPPasswordPolicyError pErr = PP_noError; 1538 char *txt; 1539 1540 /* Did we receive a password policy request control? */ 1541 if ( op->o_ctrlflag[ppolicy_cid] ) { 1542 send_ctrl = 1; 1543 } 1544 rc = check_password_quality( bv, &pp, &pErr, op->ora_e, &txt ); 1545 if (rc != LDAP_SUCCESS) { 1546 LDAPControl **oldctrls = NULL; 1547 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1548 if ( send_ctrl ) { 1549 LDAPControl *ctrl = NULL; 1550 ctrl = create_passcontrol( op, -1, -1, pErr ); 1551 oldctrls = add_passcontrol( op, rs, ctrl ); 1552 } 1553 send_ldap_error( op, rs, rc, txt ? txt : "Password fails quality checking policy" ); 1554 if ( txt ) { 1555 free( txt ); 1556 } 1557 if ( send_ctrl ) { 1558 ctrls_cleanup( op, rs, oldctrls ); 1559 } 1560 return rs->sr_err; 1561 } 1562 } 1563 /* 1564 * A controversial bit. We hash cleartext 1565 * passwords provided via add and modify operations 1566 * You're not really supposed to do this, since 1567 * the X.500 model says "store attributes" as they 1568 * get provided. By default, this is what we do 1569 * 1570 * But if the hash_passwords flag is set, we hash 1571 * any cleartext password attribute values via the 1572 * default password hashing scheme. 1573 */ 1574 if ((pi->hash_passwords) && 1575 (password_scheme( &(pa->a_vals[0]), NULL ) != LDAP_SUCCESS)) { 1576 struct berval hpw; 1577 1578 slap_passwd_hash( &(pa->a_vals[0]), &hpw, &txt ); 1579 if (hpw.bv_val == NULL) { 1580 /* 1581 * hashing didn't work. Emit an error. 1582 */ 1583 rs->sr_err = LDAP_OTHER; 1584 rs->sr_text = txt; 1585 send_ldap_error( op, rs, LDAP_OTHER, "Password hashing failed" ); 1586 return rs->sr_err; 1587 } 1588 1589 memset( pa->a_vals[0].bv_val, 0, pa->a_vals[0].bv_len); 1590 ber_memfree( pa->a_vals[0].bv_val ); 1591 pa->a_vals[0].bv_val = hpw.bv_val; 1592 pa->a_vals[0].bv_len = hpw.bv_len; 1593 } 1594 1595 /* If password aging is in effect, set the pwdChangedTime */ 1596 if ( pp.pwdMaxAge || pp.pwdMinAge ) { 1597 struct berval timestamp; 1598 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 1599 time_t now = slap_get_time(); 1600 1601 timestamp.bv_val = timebuf; 1602 timestamp.bv_len = sizeof(timebuf); 1603 slap_timestamp( &now, ×tamp ); 1604 1605 attr_merge_one( op->ora_e, ad_pwdChangedTime, ×tamp, ×tamp ); 1606 } 1607 } 1608 return SLAP_CB_CONTINUE; 1609} 1610 1611static int 1612ppolicy_mod_cb( Operation *op, SlapReply *rs ) 1613{ 1614 slap_callback *sc = op->o_callback; 1615 op->o_callback = sc->sc_next; 1616 if ( rs->sr_err == LDAP_SUCCESS ) { 1617 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 1618 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 1619 } 1620 op->o_tmpfree( sc, op->o_tmpmemctx ); 1621 return SLAP_CB_CONTINUE; 1622} 1623 1624static int 1625ppolicy_modify( Operation *op, SlapReply *rs ) 1626{ 1627 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1628 pp_info *pi = on->on_bi.bi_private; 1629 int i, rc, mod_pw_only, pwmod, pwmop = -1, deladd, 1630 hsize = 0; 1631 PassPolicy pp; 1632 Modifications *mods = NULL, *modtail = NULL, 1633 *ml, *delmod, *addmod; 1634 Attribute *pa, *ha, at; 1635 const char *txt; 1636 pw_hist *tl = NULL, *p; 1637 int zapReset, send_ctrl = 0, free_txt = 0; 1638 Entry *e; 1639 struct berval newpw = BER_BVNULL, oldpw = BER_BVNULL, 1640 *bv, cr[2]; 1641 LDAPPasswordPolicyError pErr = PP_noError; 1642 LDAPControl *ctrl = NULL; 1643 LDAPControl **oldctrls = NULL; 1644 int is_pwdexop = 0; 1645 int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0; 1646 int got_changed = 0, got_history = 0; 1647 1648 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1649 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 1650 op->o_bd->bd_info = (BackendInfo *)on; 1651 1652 if ( rc != LDAP_SUCCESS ) return SLAP_CB_CONTINUE; 1653 1654 /* If this is a replica, we may need to tweak some of the 1655 * master's modifications. Otherwise, just pass it through. 1656 */ 1657 if ( be_shadow_update( op )) { 1658 Modifications **prev; 1659 Attribute *a_grace, *a_lock, *a_fail; 1660 1661 a_grace = attr_find( e->e_attrs, ad_pwdGraceUseTime ); 1662 a_lock = attr_find( e->e_attrs, ad_pwdAccountLockedTime ); 1663 a_fail = attr_find( e->e_attrs, ad_pwdFailureTime ); 1664 1665 for( prev = &op->orm_modlist, ml = *prev; ml; ml = *prev ) { 1666 1667 if ( ml->sml_desc == slap_schema.si_ad_userPassword ) 1668 got_pw = 1; 1669 1670 /* If we're deleting an attr that didn't exist, 1671 * drop this delete op 1672 */ 1673 if ( ml->sml_op == LDAP_MOD_DELETE ) { 1674 int drop = 0; 1675 1676 if ( ml->sml_desc == ad_pwdGraceUseTime ) { 1677 if ( !a_grace || got_del_grace ) { 1678 drop = 1; 1679 } else { 1680 got_del_grace = 1; 1681 } 1682 } else 1683 if ( ml->sml_desc == ad_pwdAccountLockedTime ) { 1684 if ( !a_lock || got_del_lock ) { 1685 drop = 1; 1686 } else { 1687 got_del_lock = 1; 1688 } 1689 } else 1690 if ( ml->sml_desc == ad_pwdFailureTime ) { 1691 if ( !a_fail || got_del_fail ) { 1692 drop = 1; 1693 } else { 1694 got_del_fail = 1; 1695 } 1696 } 1697 if ( drop ) { 1698 *prev = ml->sml_next; 1699 ml->sml_next = NULL; 1700 slap_mods_free( ml, 1 ); 1701 continue; 1702 } 1703 } 1704 prev = &ml->sml_next; 1705 } 1706 1707 /* If we're resetting the password, make sure grace, accountlock, 1708 * and failure also get removed. 1709 */ 1710 if ( got_pw ) { 1711 if ( a_grace && !got_del_grace ) { 1712 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 1713 ml->sml_op = LDAP_MOD_DELETE; 1714 ml->sml_flags = SLAP_MOD_INTERNAL; 1715 ml->sml_type.bv_val = NULL; 1716 ml->sml_desc = ad_pwdGraceUseTime; 1717 ml->sml_numvals = 0; 1718 ml->sml_values = NULL; 1719 ml->sml_nvalues = NULL; 1720 ml->sml_next = NULL; 1721 *prev = ml; 1722 prev = &ml->sml_next; 1723 } 1724 if ( a_lock && !got_del_lock ) { 1725 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 1726 ml->sml_op = LDAP_MOD_DELETE; 1727 ml->sml_flags = SLAP_MOD_INTERNAL; 1728 ml->sml_type.bv_val = NULL; 1729 ml->sml_desc = ad_pwdAccountLockedTime; 1730 ml->sml_numvals = 0; 1731 ml->sml_values = NULL; 1732 ml->sml_nvalues = NULL; 1733 ml->sml_next = NULL; 1734 *prev = ml; 1735 } 1736 if ( a_fail && !got_del_fail ) { 1737 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 1738 ml->sml_op = LDAP_MOD_DELETE; 1739 ml->sml_flags = SLAP_MOD_INTERNAL; 1740 ml->sml_type.bv_val = NULL; 1741 ml->sml_desc = ad_pwdFailureTime; 1742 ml->sml_numvals = 0; 1743 ml->sml_values = NULL; 1744 ml->sml_nvalues = NULL; 1745 ml->sml_next = NULL; 1746 *prev = ml; 1747 } 1748 } 1749 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1750 be_entry_release_r( op, e ); 1751 return SLAP_CB_CONTINUE; 1752 } 1753 1754 /* Did we receive a password policy request control? */ 1755 if ( op->o_ctrlflag[ppolicy_cid] ) { 1756 send_ctrl = 1; 1757 } 1758 1759 /* See if this is a pwdModify exop. If so, we can 1760 * access the plaintext passwords from that request. 1761 */ 1762 { 1763 slap_callback *sc; 1764 1765 for ( sc = op->o_callback; sc; sc=sc->sc_next ) { 1766 if ( sc->sc_response == slap_null_cb && 1767 sc->sc_private ) { 1768 req_pwdexop_s *qpw = sc->sc_private; 1769 newpw = qpw->rs_new; 1770 oldpw = qpw->rs_old; 1771 is_pwdexop = 1; 1772 break; 1773 } 1774 } 1775 } 1776 1777 ppolicy_get( op, e, &pp ); 1778 1779 for ( ml = op->orm_modlist, 1780 pwmod = 0, mod_pw_only = 1, 1781 deladd = 0, delmod = NULL, 1782 addmod = NULL, 1783 zapReset = 1; 1784 ml != NULL; modtail = ml, ml = ml->sml_next ) 1785 { 1786 if ( ml->sml_desc == pp.ad ) { 1787 pwmod = 1; 1788 pwmop = ml->sml_op; 1789 if ((deladd == 0) && (ml->sml_op == LDAP_MOD_DELETE) && 1790 (ml->sml_values) && !BER_BVISNULL( &ml->sml_values[0] )) 1791 { 1792 deladd = 1; 1793 delmod = ml; 1794 } 1795 1796 if ((ml->sml_op == LDAP_MOD_ADD) || 1797 (ml->sml_op == LDAP_MOD_REPLACE)) 1798 { 1799 if ( ml->sml_values && !BER_BVISNULL( &ml->sml_values[0] )) { 1800 if ( deladd == 1 ) 1801 deladd = 2; 1802 1803 /* FIXME: there's no easy way to ensure 1804 * that add does not cause multiple 1805 * userPassword values; one way (that 1806 * would be consistent with the single 1807 * password constraint) would be to turn 1808 * add into replace); another would be 1809 * to disallow add. 1810 * 1811 * Let's check at least that a single value 1812 * is being added 1813 */ 1814 if ( addmod || !BER_BVISNULL( &ml->sml_values[ 1 ] ) ) { 1815 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 1816 rs->sr_text = "Password policy only allows one password value"; 1817 goto return_results; 1818 } 1819 1820 addmod = ml; 1821 } else { 1822 /* replace can have no values, add cannot */ 1823 assert( ml->sml_op == LDAP_MOD_REPLACE ); 1824 } 1825 } 1826 1827 } else if ( !(ml->sml_flags & SLAP_MOD_INTERNAL) && !is_at_operational( ml->sml_desc->ad_type ) ) { 1828 mod_pw_only = 0; 1829 /* modifying something other than password */ 1830 } 1831 1832 /* 1833 * If there is a request to explicitly add a pwdReset 1834 * attribute, then we suppress the normal behaviour on 1835 * password change, which is to remove the pwdReset 1836 * attribute. 1837 * 1838 * This enables an administrator to assign a new password 1839 * and place a "must reset" flag on the entry, which will 1840 * stay until the user explicitly changes his/her password. 1841 */ 1842 if (ml->sml_desc == ad_pwdReset ) { 1843 if ((ml->sml_op == LDAP_MOD_ADD) || 1844 (ml->sml_op == LDAP_MOD_REPLACE)) 1845 zapReset = 0; 1846 } 1847 if ( ml->sml_op == LDAP_MOD_DELETE ) { 1848 if ( ml->sml_desc == ad_pwdGraceUseTime ) { 1849 got_del_grace = 1; 1850 } else if ( ml->sml_desc == ad_pwdAccountLockedTime ) { 1851 got_del_lock = 1; 1852 } else if ( ml->sml_desc == ad_pwdFailureTime ) { 1853 got_del_fail = 1; 1854 } 1855 } 1856 if ( ml->sml_desc == ad_pwdChangedTime ) { 1857 got_changed = 1; 1858 } else if (ml->sml_desc == ad_pwdHistory ) { 1859 got_history = 1; 1860 } 1861 } 1862 1863 if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) { 1864 if ( dn_match( &op->o_conn->c_ndn, 1865 &pwcons[op->o_conn->c_conn_idx].dn )) { 1866 Debug( LDAP_DEBUG_TRACE, 1867 "connection restricted to password changing only\n", 0, 0, 0 ); 1868 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1869 rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password"; 1870 pErr = PP_changeAfterReset; 1871 goto return_results; 1872 } else { 1873 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 1874 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 1875 } 1876 } 1877 1878 /* 1879 * if we have a "safe password modify policy", then we need to check if we're doing 1880 * a delete (with the old password), followed by an add (with the new password). 1881 * 1882 * If we got just a delete with nothing else, just let it go. We also skip all the checks if 1883 * the root user is bound. Root can do anything, including avoid the policies. 1884 */ 1885 1886 if (!pwmod) goto do_modify; 1887 1888 /* 1889 * Build the password history list in ascending time order 1890 * We need this, even if the user is root, in order to maintain 1891 * the pwdHistory operational attributes properly. 1892 */ 1893 if (addmod && pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) { 1894 struct berval oldpw; 1895 time_t oldtime; 1896 1897 for(i=0; ha->a_nvals[i].bv_val; i++) { 1898 rc = parse_pwdhistory( &(ha->a_nvals[i]), NULL, 1899 &oldtime, &oldpw ); 1900 1901 if (rc != LDAP_SUCCESS) continue; /* invalid history entry */ 1902 1903 if (oldpw.bv_val) { 1904 add_to_pwd_history( &tl, oldtime, &oldpw, 1905 &(ha->a_nvals[i]) ); 1906 oldpw.bv_val = NULL; 1907 oldpw.bv_len = 0; 1908 } 1909 } 1910 for(p=tl; p; p=p->next, hsize++); /* count history size */ 1911 } 1912 1913 if (be_isroot( op )) goto do_modify; 1914 1915 /* NOTE: according to draft-behera-ldap-password-policy 1916 * pwdAllowUserChange == FALSE must only prevent pwd changes 1917 * by the user the pwd belongs to (ITS#7021) */ 1918 if (!pp.pwdAllowUserChange && dn_match(&op->o_req_ndn, &op->o_ndn)) { 1919 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1920 rs->sr_text = "User alteration of password is not allowed"; 1921 pErr = PP_passwordModNotAllowed; 1922 goto return_results; 1923 } 1924 1925 /* Just deleting? */ 1926 if (!addmod) { 1927 /* skip everything else */ 1928 pwmod = 0; 1929 goto do_modify; 1930 } 1931 1932 /* This is a pwdModify exop that provided the old pw. 1933 * We need to create a Delete mod for this old pw and 1934 * let the matching value get found later 1935 */ 1936 if (pp.pwdSafeModify && oldpw.bv_val ) { 1937 ml = (Modifications *)ch_calloc( sizeof( Modifications ), 1 ); 1938 ml->sml_op = LDAP_MOD_DELETE; 1939 ml->sml_flags = SLAP_MOD_INTERNAL; 1940 ml->sml_desc = pp.ad; 1941 ml->sml_type = pp.ad->ad_cname; 1942 ml->sml_numvals = 1; 1943 ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 1944 ber_dupbv( &ml->sml_values[0], &oldpw ); 1945 BER_BVZERO( &ml->sml_values[1] ); 1946 ml->sml_next = op->orm_modlist; 1947 op->orm_modlist = ml; 1948 delmod = ml; 1949 deladd = 2; 1950 } 1951 1952 if (pp.pwdSafeModify && deladd != 2) { 1953 Debug( LDAP_DEBUG_TRACE, 1954 "change password must use DELETE followed by ADD/REPLACE\n", 1955 0, 0, 0 ); 1956 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1957 rs->sr_text = "Must supply old password to be changed as well as new one"; 1958 pErr = PP_mustSupplyOldPassword; 1959 goto return_results; 1960 } 1961 1962 /* Check age, but only if pwdReset is not TRUE */ 1963 pa = attr_find( e->e_attrs, ad_pwdReset ); 1964 if ((!pa || !bvmatch( &pa->a_nvals[0], &slap_true_bv )) && 1965 pp.pwdMinAge > 0) { 1966 time_t pwtime = (time_t)-1, now; 1967 int age; 1968 1969 if ((pa = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL) 1970 pwtime = parse_time( pa->a_nvals[0].bv_val ); 1971 now = slap_get_time(); 1972 age = (int)(now - pwtime); 1973 if ((pwtime != (time_t)-1) && (age < pp.pwdMinAge)) { 1974 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 1975 rs->sr_text = "Password is too young to change"; 1976 pErr = PP_passwordTooYoung; 1977 goto return_results; 1978 } 1979 } 1980 1981 /* pa is used in password history check below, be sure it's set */ 1982 if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL && delmod) { 1983 /* 1984 * we have a password to check 1985 */ 1986 bv = oldpw.bv_val ? &oldpw : delmod->sml_values; 1987 /* FIXME: no access checking? */ 1988 rc = slap_passwd_check( op, NULL, pa, bv, &txt ); 1989 if (rc != LDAP_SUCCESS) { 1990 Debug( LDAP_DEBUG_TRACE, 1991 "old password check failed: %s\n", txt, 0, 0 ); 1992 1993 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1994 rs->sr_text = "Must supply correct old password to change to new one"; 1995 pErr = PP_mustSupplyOldPassword; 1996 goto return_results; 1997 1998 } else { 1999 int i; 2000 2001 /* 2002 * replace the delete value with the (possibly hashed) 2003 * value which is currently in the password. 2004 */ 2005 for ( i = 0; !BER_BVISNULL( &delmod->sml_values[i] ); i++ ) { 2006 free( delmod->sml_values[i].bv_val ); 2007 BER_BVZERO( &delmod->sml_values[i] ); 2008 } 2009 free( delmod->sml_values ); 2010 delmod->sml_values = ch_calloc( sizeof(struct berval), 2 ); 2011 BER_BVZERO( &delmod->sml_values[1] ); 2012 ber_dupbv( &(delmod->sml_values[0]), &(pa->a_nvals[0]) ); 2013 } 2014 } 2015 2016 bv = newpw.bv_val ? &newpw : &addmod->sml_values[0]; 2017 if (pp.pwdCheckQuality > 0) { 2018 2019 rc = check_password_quality( bv, &pp, &pErr, e, (char **)&txt ); 2020 if (rc != LDAP_SUCCESS) { 2021 rs->sr_err = rc; 2022 if ( txt ) { 2023 rs->sr_text = txt; 2024 free_txt = 1; 2025 } else { 2026 rs->sr_text = "Password fails quality checking policy"; 2027 } 2028 goto return_results; 2029 } 2030 } 2031 2032 /* If pwdInHistory is zero, passwords may be reused */ 2033 if (pa && pp.pwdInHistory > 0) { 2034 /* 2035 * Last check - the password history. 2036 */ 2037 /* FIXME: no access checking? */ 2038 if (slap_passwd_check( op, NULL, pa, bv, &txt ) == LDAP_SUCCESS) { 2039 /* 2040 * This is bad - it means that the user is attempting 2041 * to set the password to the same as the old one. 2042 */ 2043 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 2044 rs->sr_text = "Password is not being changed from existing value"; 2045 pErr = PP_passwordInHistory; 2046 goto return_results; 2047 } 2048 2049 /* 2050 * Iterate through the password history, and fail on any 2051 * password matches. 2052 */ 2053 at = *pa; 2054 at.a_vals = cr; 2055 cr[1].bv_val = NULL; 2056 for(p=tl; p; p=p->next) { 2057 cr[0] = p->pw; 2058 /* FIXME: no access checking? */ 2059 rc = slap_passwd_check( op, NULL, &at, bv, &txt ); 2060 2061 if (rc != LDAP_SUCCESS) continue; 2062 2063 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 2064 rs->sr_text = "Password is in history of old passwords"; 2065 pErr = PP_passwordInHistory; 2066 goto return_results; 2067 } 2068 } 2069 2070do_modify: 2071 if (pwmod) { 2072 struct berval timestamp; 2073 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 2074 time_t now = slap_get_time(); 2075 2076 /* If the conn is restricted, set a callback to clear it 2077 * if the pwmod succeeds 2078 */ 2079 if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { 2080 slap_callback *sc = op->o_tmpcalloc( 1, sizeof( slap_callback ), 2081 op->o_tmpmemctx ); 2082 sc->sc_next = op->o_callback; 2083 /* Must use sc_response to insure we reset on success, before 2084 * the client sees the response. Must use sc_cleanup to insure 2085 * that it gets cleaned up if sc_response is not called. 2086 */ 2087 sc->sc_response = ppolicy_mod_cb; 2088 sc->sc_cleanup = ppolicy_mod_cb; 2089 op->o_callback = sc; 2090 } 2091 2092 /* 2093 * keep the necessary pwd.. operational attributes 2094 * up to date. 2095 */ 2096 2097 if (!got_changed) { 2098 timestamp.bv_val = timebuf; 2099 timestamp.bv_len = sizeof(timebuf); 2100 slap_timestamp( &now, ×tamp ); 2101 2102 mods = NULL; 2103 if (pwmop != LDAP_MOD_DELETE) { 2104 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2105 mods->sml_op = LDAP_MOD_REPLACE; 2106 mods->sml_numvals = 1; 2107 mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 2108 ber_dupbv( &mods->sml_values[0], ×tamp ); 2109 BER_BVZERO( &mods->sml_values[1] ); 2110 assert( !BER_BVISNULL( &mods->sml_values[0] ) ); 2111 } else if (attr_find(e->e_attrs, ad_pwdChangedTime )) { 2112 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2113 mods->sml_op = LDAP_MOD_DELETE; 2114 } 2115 if (mods) { 2116 mods->sml_desc = ad_pwdChangedTime; 2117 mods->sml_flags = SLAP_MOD_INTERNAL; 2118 mods->sml_next = NULL; 2119 modtail->sml_next = mods; 2120 modtail = mods; 2121 } 2122 } 2123 2124 if (!got_del_grace && attr_find(e->e_attrs, ad_pwdGraceUseTime )) { 2125 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2126 mods->sml_op = LDAP_MOD_DELETE; 2127 mods->sml_desc = ad_pwdGraceUseTime; 2128 mods->sml_flags = SLAP_MOD_INTERNAL; 2129 mods->sml_next = NULL; 2130 modtail->sml_next = mods; 2131 modtail = mods; 2132 } 2133 2134 if (!got_del_lock && attr_find(e->e_attrs, ad_pwdAccountLockedTime )) { 2135 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2136 mods->sml_op = LDAP_MOD_DELETE; 2137 mods->sml_desc = ad_pwdAccountLockedTime; 2138 mods->sml_flags = SLAP_MOD_INTERNAL; 2139 mods->sml_next = NULL; 2140 modtail->sml_next = mods; 2141 modtail = mods; 2142 } 2143 2144 if (!got_del_fail && attr_find(e->e_attrs, ad_pwdFailureTime )) { 2145 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2146 mods->sml_op = LDAP_MOD_DELETE; 2147 mods->sml_desc = ad_pwdFailureTime; 2148 mods->sml_flags = SLAP_MOD_INTERNAL; 2149 mods->sml_next = NULL; 2150 modtail->sml_next = mods; 2151 modtail = mods; 2152 } 2153 2154 /* Delete the pwdReset attribute, since it's being reset */ 2155 if ((zapReset) && (attr_find(e->e_attrs, ad_pwdReset ))) { 2156 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2157 mods->sml_op = LDAP_MOD_DELETE; 2158 mods->sml_desc = ad_pwdReset; 2159 mods->sml_flags = SLAP_MOD_INTERNAL; 2160 mods->sml_next = NULL; 2161 modtail->sml_next = mods; 2162 modtail = mods; 2163 } 2164 2165 if (!got_history && pp.pwdInHistory > 0) { 2166 if (hsize >= pp.pwdInHistory) { 2167 /* 2168 * We use the >= operator, since we are going to add 2169 * the existing password attribute value into the 2170 * history - thus the cardinality of history values is 2171 * about to rise by one. 2172 * 2173 * If this would push it over the limit of history 2174 * values (remembering - the password policy could have 2175 * changed since the password was last altered), we must 2176 * delete at least 1 value from the pwdHistory list. 2177 * 2178 * In fact, we delete '(#pwdHistory attrs - max pwd 2179 * history length) + 1' values, starting with the oldest. 2180 * This is easily evaluated, since the linked list is 2181 * created in ascending time order. 2182 */ 2183 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2184 mods->sml_op = LDAP_MOD_DELETE; 2185 mods->sml_flags = SLAP_MOD_INTERNAL; 2186 mods->sml_desc = ad_pwdHistory; 2187 mods->sml_numvals = hsize - pp.pwdInHistory + 1; 2188 mods->sml_values = ch_calloc( sizeof( struct berval ), 2189 hsize - pp.pwdInHistory + 2 ); 2190 BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] ); 2191 for(i=0,p=tl; i < (hsize - pp.pwdInHistory + 1); i++, p=p->next) { 2192 BER_BVZERO( &mods->sml_values[i] ); 2193 ber_dupbv( &(mods->sml_values[i]), &p->bv ); 2194 } 2195 mods->sml_next = NULL; 2196 modtail->sml_next = mods; 2197 modtail = mods; 2198 } 2199 free_pwd_history_list( &tl ); 2200 2201 /* 2202 * Now add the existing password into the history list. 2203 * This will be executed even if the operation is to delete 2204 * the password entirely. 2205 * 2206 * This isn't in the spec explicitly, but it seems to make 2207 * sense that the password history list is the list of all 2208 * previous passwords - even if they were deleted. Thus, if 2209 * someone tries to add a historical password at some future 2210 * point, it will fail. 2211 */ 2212 if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL) { 2213 mods = (Modifications *) ch_malloc( sizeof( Modifications ) ); 2214 mods->sml_op = LDAP_MOD_ADD; 2215 mods->sml_flags = SLAP_MOD_INTERNAL; 2216 mods->sml_type.bv_val = NULL; 2217 mods->sml_desc = ad_pwdHistory; 2218 mods->sml_nvalues = NULL; 2219 mods->sml_numvals = 1; 2220 mods->sml_values = ch_calloc( sizeof( struct berval ), 2 ); 2221 mods->sml_values[ 1 ].bv_val = NULL; 2222 mods->sml_values[ 1 ].bv_len = 0; 2223 make_pwd_history_value( timebuf, &mods->sml_values[0], pa ); 2224 mods->sml_next = NULL; 2225 modtail->sml_next = mods; 2226 modtail = mods; 2227 2228 } else { 2229 Debug( LDAP_DEBUG_TRACE, 2230 "ppolicy_modify: password attr lookup failed\n", 0, 0, 0 ); 2231 } 2232 } 2233 2234 /* 2235 * Controversial bit here. If the new password isn't hashed 2236 * (ie, is cleartext), we probably should hash it according 2237 * to the default hash. The reason for this is that we want 2238 * to use the policy if possible, but if we hash the password 2239 * before, then we're going to run into trouble when it 2240 * comes time to check the password. 2241 * 2242 * Now, the right thing to do is to use the extended password 2243 * modify operation, but not all software can do this, 2244 * therefore it makes sense to hash the new password, now 2245 * we know it passes the policy requirements. 2246 * 2247 * Of course, if the password is already hashed, then we 2248 * leave it alone. 2249 */ 2250 2251 if ((pi->hash_passwords) && (addmod) && !newpw.bv_val && 2252 (password_scheme( &(addmod->sml_values[0]), NULL ) != LDAP_SUCCESS)) 2253 { 2254 struct berval hpw, bv; 2255 2256 slap_passwd_hash( &(addmod->sml_values[0]), &hpw, &txt ); 2257 if (hpw.bv_val == NULL) { 2258 /* 2259 * hashing didn't work. Emit an error. 2260 */ 2261 rs->sr_err = LDAP_OTHER; 2262 rs->sr_text = txt; 2263 goto return_results; 2264 } 2265 bv = addmod->sml_values[0]; 2266 /* clear and discard the clear password */ 2267 memset(bv.bv_val, 0, bv.bv_len); 2268 ber_memfree(bv.bv_val); 2269 addmod->sml_values[0] = hpw; 2270 } 2271 } 2272 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2273 be_entry_release_r( op, e ); 2274 return SLAP_CB_CONTINUE; 2275 2276return_results: 2277 free_pwd_history_list( &tl ); 2278 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2279 be_entry_release_r( op, e ); 2280 if ( send_ctrl ) { 2281 ctrl = create_passcontrol( op, -1, -1, pErr ); 2282 oldctrls = add_passcontrol( op, rs, ctrl ); 2283 } 2284 send_ldap_result( op, rs ); 2285 if ( free_txt ) { 2286 free( (char *)txt ); 2287 rs->sr_text = NULL; 2288 } 2289 if ( send_ctrl ) { 2290 if ( is_pwdexop ) { 2291 if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) { 2292 op->o_tmpfree( oldctrls, op->o_tmpmemctx ); 2293 } 2294 oldctrls = NULL; 2295 rs->sr_flags |= REP_CTRLS_MUSTBEFREED; 2296 2297 } else { 2298 ctrls_cleanup( op, rs, oldctrls ); 2299 } 2300 } 2301 return rs->sr_err; 2302} 2303 2304static int 2305ppolicy_parseCtrl( 2306 Operation *op, 2307 SlapReply *rs, 2308 LDAPControl *ctrl ) 2309{ 2310 if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) { 2311 rs->sr_text = "passwordPolicyRequest control value not absent"; 2312 return LDAP_PROTOCOL_ERROR; 2313 } 2314 op->o_ctrlflag[ppolicy_cid] = ctrl->ldctl_iscritical 2315 ? SLAP_CONTROL_CRITICAL 2316 : SLAP_CONTROL_NONCRITICAL; 2317 2318 return LDAP_SUCCESS; 2319} 2320 2321static int 2322attrPretty( 2323 Syntax *syntax, 2324 struct berval *val, 2325 struct berval *out, 2326 void *ctx ) 2327{ 2328 AttributeDescription *ad = NULL; 2329 const char *err; 2330 int code; 2331 2332 code = slap_bv2ad( val, &ad, &err ); 2333 if ( !code ) { 2334 ber_dupbv_x( out, &ad->ad_type->sat_cname, ctx ); 2335 } 2336 return code; 2337} 2338 2339static int 2340attrNormalize( 2341 slap_mask_t use, 2342 Syntax *syntax, 2343 MatchingRule *mr, 2344 struct berval *val, 2345 struct berval *out, 2346 void *ctx ) 2347{ 2348 AttributeDescription *ad = NULL; 2349 const char *err; 2350 int code; 2351 2352 code = slap_bv2ad( val, &ad, &err ); 2353 if ( !code ) { 2354 ber_str2bv_x( ad->ad_type->sat_oid, 0, 1, out, ctx ); 2355 } 2356 return code; 2357} 2358 2359static int 2360ppolicy_db_init( 2361 BackendDB *be, 2362 ConfigReply *cr 2363) 2364{ 2365 slap_overinst *on = (slap_overinst *) be->bd_info; 2366 2367 if ( SLAP_ISGLOBALOVERLAY( be ) ) { 2368 /* do not allow slapo-ppolicy to be global by now (ITS#5858) */ 2369 if ( cr ){ 2370 snprintf( cr->msg, sizeof(cr->msg), 2371 "slapo-ppolicy cannot be global" ); 2372 Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 ); 2373 } 2374 return 1; 2375 } 2376 2377 /* Has User Schema been initialized yet? */ 2378 if ( !pwd_UsSchema[0].ad[0] ) { 2379 const char *err; 2380 int i, code; 2381 2382 for (i=0; pwd_UsSchema[i].def; i++) { 2383 code = slap_str2ad( pwd_UsSchema[i].def, pwd_UsSchema[i].ad, &err ); 2384 if ( code ) { 2385 if ( cr ){ 2386 snprintf( cr->msg, sizeof(cr->msg), 2387 "User Schema load failed for attribute \"%s\". Error code %d: %s", 2388 pwd_UsSchema[i].def, code, err ); 2389 Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 ); 2390 } 2391 return code; 2392 } 2393 } 2394 { 2395 Syntax *syn; 2396 MatchingRule *mr; 2397 2398 syn = ch_malloc( sizeof( Syntax )); 2399 *syn = *ad_pwdAttribute->ad_type->sat_syntax; 2400 syn->ssyn_pretty = attrPretty; 2401 ad_pwdAttribute->ad_type->sat_syntax = syn; 2402 2403 mr = ch_malloc( sizeof( MatchingRule )); 2404 *mr = *ad_pwdAttribute->ad_type->sat_equality; 2405 mr->smr_normalize = attrNormalize; 2406 ad_pwdAttribute->ad_type->sat_equality = mr; 2407 } 2408 } 2409 2410 on->on_bi.bi_private = ch_calloc( sizeof(pp_info), 1 ); 2411 2412 if ( dtblsize && !pwcons ) { 2413 /* accommodate for c_conn_idx == -1 */ 2414 pwcons = ch_calloc( sizeof(pw_conn), dtblsize + 1 ); 2415 pwcons++; 2416 } 2417 2418 ov_count++; 2419 2420 return 0; 2421} 2422 2423static int 2424ppolicy_db_open( 2425 BackendDB *be, 2426 ConfigReply *cr 2427) 2428{ 2429 return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST ); 2430} 2431 2432static int 2433ppolicy_db_close( 2434 BackendDB *be, 2435 ConfigReply *cr 2436) 2437{ 2438#ifdef SLAP_CONFIG_DELETE 2439 overlay_unregister_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST ); 2440#endif /* SLAP_CONFIG_DELETE */ 2441 2442 return 0; 2443} 2444 2445static int 2446ppolicy_db_destroy( 2447 BackendDB *be, 2448 ConfigReply *cr 2449) 2450{ 2451 slap_overinst *on = (slap_overinst *) be->bd_info; 2452 pp_info *pi = on->on_bi.bi_private; 2453 2454 on->on_bi.bi_private = NULL; 2455 free( pi->def_policy.bv_val ); 2456 free( pi ); 2457 2458 ov_count--; 2459 if ( ov_count <=0 && pwcons ) { 2460 pw_conn *pwc = pwcons; 2461 pwcons = NULL; 2462 pwc--; 2463 ch_free( pwc ); 2464 } 2465 return 0; 2466} 2467 2468static char *extops[] = { 2469 LDAP_EXOP_MODIFY_PASSWD, 2470 NULL 2471}; 2472 2473static slap_overinst ppolicy; 2474 2475int ppolicy_initialize() 2476{ 2477 int i, code; 2478 2479 for (i=0; pwd_OpSchema[i].def; i++) { 2480 code = register_at( pwd_OpSchema[i].def, pwd_OpSchema[i].ad, 0 ); 2481 if ( code ) { 2482 Debug( LDAP_DEBUG_ANY, 2483 "ppolicy_initialize: register_at failed\n", 0, 0, 0 ); 2484 return code; 2485 } 2486 /* Allow Manager to set these as needed */ 2487 if ( is_at_no_user_mod( (*pwd_OpSchema[i].ad)->ad_type )) { 2488 (*pwd_OpSchema[i].ad)->ad_type->sat_flags |= 2489 SLAP_AT_MANAGEABLE; 2490 } 2491 } 2492 2493 code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST, 2494 SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, extops, 2495 ppolicy_parseCtrl, &ppolicy_cid ); 2496 if ( code != LDAP_SUCCESS ) { 2497 Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code, 0, 0 ); 2498 return code; 2499 } 2500 2501 ldap_pvt_thread_mutex_init( &chk_syntax_mutex ); 2502 2503 ppolicy.on_bi.bi_type = "ppolicy"; 2504 ppolicy.on_bi.bi_db_init = ppolicy_db_init; 2505 ppolicy.on_bi.bi_db_open = ppolicy_db_open; 2506 ppolicy.on_bi.bi_db_close = ppolicy_db_close; 2507 ppolicy.on_bi.bi_db_destroy = ppolicy_db_destroy; 2508 2509 ppolicy.on_bi.bi_op_add = ppolicy_add; 2510 ppolicy.on_bi.bi_op_bind = ppolicy_bind; 2511 ppolicy.on_bi.bi_op_compare = ppolicy_compare; 2512 ppolicy.on_bi.bi_op_delete = ppolicy_restrict; 2513 ppolicy.on_bi.bi_op_modify = ppolicy_modify; 2514 ppolicy.on_bi.bi_op_search = ppolicy_restrict; 2515 ppolicy.on_bi.bi_connection_destroy = ppolicy_connection_destroy; 2516 2517 ppolicy.on_bi.bi_cf_ocs = ppolicyocs; 2518 code = config_register_schema( ppolicycfg, ppolicyocs ); 2519 if ( code ) return code; 2520 2521 return overlay_register( &ppolicy ); 2522} 2523 2524#if SLAPD_OVER_PPOLICY == SLAPD_MOD_DYNAMIC 2525int init_module(int argc, char *argv[]) { 2526 return ppolicy_initialize(); 2527} 2528#endif 2529 2530#endif /* defined(SLAPD_OVER_PPOLICY) */ 2531