ppolicy.c revision 1.1.1.8
1/* $NetBSD: ppolicy.c,v 1.1.1.8 2019/08/08 13:31:40 christos Exp $ */ 2 3/* $OpenLDAP$ */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 2004-2019 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.8 2019/08/08 13:31:40 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 ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) ) 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, hskip; 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 ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) ) { 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 ml->sml_op == SLAP_MOD_SOFTDEL ) { 1675 int drop = 0; 1676 1677 if ( ml->sml_desc == ad_pwdGraceUseTime ) { 1678 if ( !a_grace || got_del_grace ) { 1679 drop = ml->sml_op == LDAP_MOD_DELETE; 1680 } else { 1681 got_del_grace = 1; 1682 } 1683 } else 1684 if ( ml->sml_desc == ad_pwdAccountLockedTime ) { 1685 if ( !a_lock || got_del_lock ) { 1686 drop = ml->sml_op == LDAP_MOD_DELETE; 1687 } else { 1688 got_del_lock = 1; 1689 } 1690 } else 1691 if ( ml->sml_desc == ad_pwdFailureTime ) { 1692 if ( !a_fail || got_del_fail ) { 1693 drop = ml->sml_op == LDAP_MOD_DELETE; 1694 } else { 1695 got_del_fail = 1; 1696 } 1697 } 1698 if ( drop ) { 1699 *prev = ml->sml_next; 1700 ml->sml_next = NULL; 1701 slap_mods_free( ml, 1 ); 1702 continue; 1703 } 1704 } 1705 prev = &ml->sml_next; 1706 } 1707 1708 /* If we're resetting the password, make sure grace, accountlock, 1709 * and failure also get removed. 1710 */ 1711 if ( got_pw ) { 1712 if ( a_grace && !got_del_grace ) { 1713 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 1714 ml->sml_op = LDAP_MOD_DELETE; 1715 ml->sml_flags = SLAP_MOD_INTERNAL; 1716 ml->sml_type.bv_val = NULL; 1717 ml->sml_desc = ad_pwdGraceUseTime; 1718 ml->sml_numvals = 0; 1719 ml->sml_values = NULL; 1720 ml->sml_nvalues = NULL; 1721 ml->sml_next = NULL; 1722 *prev = ml; 1723 prev = &ml->sml_next; 1724 } 1725 if ( a_lock && !got_del_lock ) { 1726 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 1727 ml->sml_op = LDAP_MOD_DELETE; 1728 ml->sml_flags = SLAP_MOD_INTERNAL; 1729 ml->sml_type.bv_val = NULL; 1730 ml->sml_desc = ad_pwdAccountLockedTime; 1731 ml->sml_numvals = 0; 1732 ml->sml_values = NULL; 1733 ml->sml_nvalues = NULL; 1734 ml->sml_next = NULL; 1735 *prev = ml; 1736 } 1737 if ( a_fail && !got_del_fail ) { 1738 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 1739 ml->sml_op = LDAP_MOD_DELETE; 1740 ml->sml_flags = SLAP_MOD_INTERNAL; 1741 ml->sml_type.bv_val = NULL; 1742 ml->sml_desc = ad_pwdFailureTime; 1743 ml->sml_numvals = 0; 1744 ml->sml_values = NULL; 1745 ml->sml_nvalues = NULL; 1746 ml->sml_next = NULL; 1747 *prev = ml; 1748 } 1749 } 1750 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1751 be_entry_release_r( op, e ); 1752 return SLAP_CB_CONTINUE; 1753 } 1754 1755 /* Did we receive a password policy request control? */ 1756 if ( op->o_ctrlflag[ppolicy_cid] ) { 1757 send_ctrl = 1; 1758 } 1759 1760 /* See if this is a pwdModify exop. If so, we can 1761 * access the plaintext passwords from that request. 1762 */ 1763 { 1764 slap_callback *sc; 1765 1766 for ( sc = op->o_callback; sc; sc=sc->sc_next ) { 1767 if ( sc->sc_response == slap_null_cb && 1768 sc->sc_private ) { 1769 req_pwdexop_s *qpw = sc->sc_private; 1770 newpw = qpw->rs_new; 1771 oldpw = qpw->rs_old; 1772 is_pwdexop = 1; 1773 break; 1774 } 1775 } 1776 } 1777 1778 ppolicy_get( op, e, &pp ); 1779 1780 for ( ml = op->orm_modlist, 1781 pwmod = 0, mod_pw_only = 1, 1782 deladd = 0, delmod = NULL, 1783 addmod = NULL, 1784 zapReset = 1; 1785 ml != NULL; modtail = ml, ml = ml->sml_next ) 1786 { 1787 if ( ml->sml_desc == pp.ad ) { 1788 pwmod = 1; 1789 pwmop = ml->sml_op; 1790 if ((deladd == 0) && (ml->sml_op == LDAP_MOD_DELETE) && 1791 (ml->sml_values) && !BER_BVISNULL( &ml->sml_values[0] )) 1792 { 1793 deladd = 1; 1794 delmod = ml; 1795 } 1796 1797 if ((ml->sml_op == LDAP_MOD_ADD) || 1798 (ml->sml_op == LDAP_MOD_REPLACE)) 1799 { 1800 if ( ml->sml_values && !BER_BVISNULL( &ml->sml_values[0] )) { 1801 if ( deladd == 1 ) 1802 deladd = 2; 1803 1804 /* FIXME: there's no easy way to ensure 1805 * that add does not cause multiple 1806 * userPassword values; one way (that 1807 * would be consistent with the single 1808 * password constraint) would be to turn 1809 * add into replace); another would be 1810 * to disallow add. 1811 * 1812 * Let's check at least that a single value 1813 * is being added 1814 */ 1815 if ( addmod || !BER_BVISNULL( &ml->sml_values[ 1 ] ) ) { 1816 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 1817 rs->sr_text = "Password policy only allows one password value"; 1818 goto return_results; 1819 } 1820 1821 addmod = ml; 1822 } else { 1823 /* replace can have no values, add cannot */ 1824 assert( ml->sml_op == LDAP_MOD_REPLACE ); 1825 } 1826 } 1827 1828 } else if ( !(ml->sml_flags & SLAP_MOD_INTERNAL) && !is_at_operational( ml->sml_desc->ad_type ) ) { 1829 mod_pw_only = 0; 1830 /* modifying something other than password */ 1831 } 1832 1833 /* 1834 * If there is a request to explicitly add a pwdReset 1835 * attribute, then we suppress the normal behaviour on 1836 * password change, which is to remove the pwdReset 1837 * attribute. 1838 * 1839 * This enables an administrator to assign a new password 1840 * and place a "must reset" flag on the entry, which will 1841 * stay until the user explicitly changes his/her password. 1842 */ 1843 if (ml->sml_desc == ad_pwdReset ) { 1844 if ((ml->sml_op == LDAP_MOD_ADD) || 1845 (ml->sml_op == LDAP_MOD_REPLACE)) 1846 zapReset = 0; 1847 } 1848 if ( ml->sml_op == LDAP_MOD_DELETE ) { 1849 if ( ml->sml_desc == ad_pwdGraceUseTime ) { 1850 got_del_grace = 1; 1851 } else if ( ml->sml_desc == ad_pwdAccountLockedTime ) { 1852 got_del_lock = 1; 1853 } else if ( ml->sml_desc == ad_pwdFailureTime ) { 1854 got_del_fail = 1; 1855 } 1856 } 1857 if ( ml->sml_desc == ad_pwdChangedTime ) { 1858 got_changed = 1; 1859 } else if (ml->sml_desc == ad_pwdHistory ) { 1860 got_history = 1; 1861 } 1862 } 1863 1864 if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) { 1865 if ( dn_match( &op->o_conn->c_ndn, 1866 &pwcons[op->o_conn->c_conn_idx].dn )) { 1867 Debug( LDAP_DEBUG_TRACE, 1868 "connection restricted to password changing only\n", 0, 0, 0 ); 1869 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1870 rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password"; 1871 pErr = PP_changeAfterReset; 1872 goto return_results; 1873 } else { 1874 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 1875 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 1876 } 1877 } 1878 1879 /* 1880 * if we have a "safe password modify policy", then we need to check if we're doing 1881 * a delete (with the old password), followed by an add (with the new password). 1882 * 1883 * If we got just a delete with nothing else, just let it go. We also skip all the checks if 1884 * the root user is bound. Root can do anything, including avoid the policies. 1885 */ 1886 1887 if (!pwmod) goto do_modify; 1888 1889 /* 1890 * Build the password history list in ascending time order 1891 * We need this, even if the user is root, in order to maintain 1892 * the pwdHistory operational attributes properly. 1893 */ 1894 if (addmod && pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) { 1895 struct berval oldpw; 1896 time_t oldtime; 1897 1898 for(i=0; ha->a_nvals[i].bv_val; i++) { 1899 rc = parse_pwdhistory( &(ha->a_nvals[i]), NULL, 1900 &oldtime, &oldpw ); 1901 1902 if (rc != LDAP_SUCCESS) continue; /* invalid history entry */ 1903 1904 if (oldpw.bv_val) { 1905 add_to_pwd_history( &tl, oldtime, &oldpw, 1906 &(ha->a_nvals[i]) ); 1907 oldpw.bv_val = NULL; 1908 oldpw.bv_len = 0; 1909 } 1910 } 1911 for(p=tl; p; p=p->next, hsize++); /* count history size */ 1912 } 1913 1914 if (be_isroot( op )) goto do_modify; 1915 1916 /* NOTE: according to draft-behera-ldap-password-policy 1917 * pwdAllowUserChange == FALSE must only prevent pwd changes 1918 * by the user the pwd belongs to (ITS#7021) */ 1919 if (!pp.pwdAllowUserChange && dn_match(&op->o_req_ndn, &op->o_ndn)) { 1920 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1921 rs->sr_text = "User alteration of password is not allowed"; 1922 pErr = PP_passwordModNotAllowed; 1923 goto return_results; 1924 } 1925 1926 /* Just deleting? */ 1927 if (!addmod) { 1928 /* skip everything else */ 1929 pwmod = 0; 1930 goto do_modify; 1931 } 1932 1933 /* This is a pwdModify exop that provided the old pw. 1934 * We need to create a Delete mod for this old pw and 1935 * let the matching value get found later 1936 */ 1937 if (pp.pwdSafeModify && oldpw.bv_val ) { 1938 ml = (Modifications *)ch_calloc( sizeof( Modifications ), 1 ); 1939 ml->sml_op = LDAP_MOD_DELETE; 1940 ml->sml_flags = SLAP_MOD_INTERNAL; 1941 ml->sml_desc = pp.ad; 1942 ml->sml_type = pp.ad->ad_cname; 1943 ml->sml_numvals = 1; 1944 ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 1945 ber_dupbv( &ml->sml_values[0], &oldpw ); 1946 BER_BVZERO( &ml->sml_values[1] ); 1947 ml->sml_next = op->orm_modlist; 1948 op->orm_modlist = ml; 1949 delmod = ml; 1950 deladd = 2; 1951 } 1952 1953 if (pp.pwdSafeModify && deladd != 2) { 1954 Debug( LDAP_DEBUG_TRACE, 1955 "change password must use DELETE followed by ADD/REPLACE\n", 1956 0, 0, 0 ); 1957 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1958 rs->sr_text = "Must supply old password to be changed as well as new one"; 1959 pErr = PP_mustSupplyOldPassword; 1960 goto return_results; 1961 } 1962 1963 /* Check age, but only if pwdReset is not TRUE */ 1964 pa = attr_find( e->e_attrs, ad_pwdReset ); 1965 if ((!pa || !bvmatch( &pa->a_nvals[0], &slap_true_bv )) && 1966 pp.pwdMinAge > 0) { 1967 time_t pwtime = (time_t)-1, now; 1968 int age; 1969 1970 if ((pa = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL) 1971 pwtime = parse_time( pa->a_nvals[0].bv_val ); 1972 now = slap_get_time(); 1973 age = (int)(now - pwtime); 1974 if ((pwtime != (time_t)-1) && (age < pp.pwdMinAge)) { 1975 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 1976 rs->sr_text = "Password is too young to change"; 1977 pErr = PP_passwordTooYoung; 1978 goto return_results; 1979 } 1980 } 1981 1982 /* pa is used in password history check below, be sure it's set */ 1983 if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL && delmod) { 1984 /* 1985 * we have a password to check 1986 */ 1987 bv = oldpw.bv_val ? &oldpw : delmod->sml_values; 1988 /* FIXME: no access checking? */ 1989 rc = slap_passwd_check( op, NULL, pa, bv, &txt ); 1990 if (rc != LDAP_SUCCESS) { 1991 Debug( LDAP_DEBUG_TRACE, 1992 "old password check failed: %s\n", txt, 0, 0 ); 1993 1994 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1995 rs->sr_text = "Must supply correct old password to change to new one"; 1996 pErr = PP_mustSupplyOldPassword; 1997 goto return_results; 1998 1999 } else { 2000 int i; 2001 2002 /* 2003 * replace the delete value with the (possibly hashed) 2004 * value which is currently in the password. 2005 */ 2006 for ( i = 0; !BER_BVISNULL( &delmod->sml_values[i] ); i++ ) { 2007 free( delmod->sml_values[i].bv_val ); 2008 BER_BVZERO( &delmod->sml_values[i] ); 2009 } 2010 free( delmod->sml_values ); 2011 delmod->sml_values = ch_calloc( sizeof(struct berval), 2 ); 2012 BER_BVZERO( &delmod->sml_values[1] ); 2013 ber_dupbv( &(delmod->sml_values[0]), &(pa->a_nvals[0]) ); 2014 } 2015 } 2016 2017 bv = newpw.bv_val ? &newpw : &addmod->sml_values[0]; 2018 if (pp.pwdCheckQuality > 0) { 2019 2020 rc = check_password_quality( bv, &pp, &pErr, e, (char **)&txt ); 2021 if (rc != LDAP_SUCCESS) { 2022 rs->sr_err = rc; 2023 if ( txt ) { 2024 rs->sr_text = txt; 2025 free_txt = 1; 2026 } else { 2027 rs->sr_text = "Password fails quality checking policy"; 2028 } 2029 goto return_results; 2030 } 2031 } 2032 2033 /* If pwdInHistory is zero, passwords may be reused */ 2034 if (pa && pp.pwdInHistory > 0) { 2035 /* 2036 * Last check - the password history. 2037 */ 2038 /* FIXME: no access checking? */ 2039 if (slap_passwd_check( op, NULL, pa, bv, &txt ) == LDAP_SUCCESS) { 2040 /* 2041 * This is bad - it means that the user is attempting 2042 * to set the password to the same as the old one. 2043 */ 2044 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 2045 rs->sr_text = "Password is not being changed from existing value"; 2046 pErr = PP_passwordInHistory; 2047 goto return_results; 2048 } 2049 2050 /* We need this when reduce pwdInHistory */ 2051 hskip = hsize - pp.pwdInHistory; 2052 2053 /* 2054 * Iterate through the password history, and fail on any 2055 * password matches. 2056 */ 2057 at = *pa; 2058 at.a_vals = cr; 2059 cr[1].bv_val = NULL; 2060 for(p=tl; p; p=p->next) { 2061 if(hskip > 0){ 2062 hskip--; 2063 continue; 2064 } 2065 cr[0] = p->pw; 2066 /* FIXME: no access checking? */ 2067 rc = slap_passwd_check( op, NULL, &at, bv, &txt ); 2068 2069 if (rc != LDAP_SUCCESS) continue; 2070 2071 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 2072 rs->sr_text = "Password is in history of old passwords"; 2073 pErr = PP_passwordInHistory; 2074 goto return_results; 2075 } 2076 } 2077 2078do_modify: 2079 if (pwmod) { 2080 struct berval timestamp; 2081 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 2082 time_t now = slap_get_time(); 2083 2084 /* If the conn is restricted, set a callback to clear it 2085 * if the pwmod succeeds 2086 */ 2087 if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { 2088 slap_callback *sc = op->o_tmpcalloc( 1, sizeof( slap_callback ), 2089 op->o_tmpmemctx ); 2090 sc->sc_next = op->o_callback; 2091 /* Must use sc_response to insure we reset on success, before 2092 * the client sees the response. Must use sc_cleanup to insure 2093 * that it gets cleaned up if sc_response is not called. 2094 */ 2095 sc->sc_response = ppolicy_mod_cb; 2096 sc->sc_cleanup = ppolicy_mod_cb; 2097 op->o_callback = sc; 2098 } 2099 2100 /* 2101 * keep the necessary pwd.. operational attributes 2102 * up to date. 2103 */ 2104 2105 if (!got_changed) { 2106 timestamp.bv_val = timebuf; 2107 timestamp.bv_len = sizeof(timebuf); 2108 slap_timestamp( &now, ×tamp ); 2109 2110 mods = NULL; 2111 if (pwmop != LDAP_MOD_DELETE) { 2112 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2113 mods->sml_op = LDAP_MOD_REPLACE; 2114 mods->sml_numvals = 1; 2115 mods->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 2116 ber_dupbv( &mods->sml_values[0], ×tamp ); 2117 BER_BVZERO( &mods->sml_values[1] ); 2118 assert( !BER_BVISNULL( &mods->sml_values[0] ) ); 2119 } else if (attr_find(e->e_attrs, ad_pwdChangedTime )) { 2120 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2121 mods->sml_op = LDAP_MOD_DELETE; 2122 } 2123 if (mods) { 2124 mods->sml_desc = ad_pwdChangedTime; 2125 mods->sml_flags = SLAP_MOD_INTERNAL; 2126 mods->sml_next = NULL; 2127 modtail->sml_next = mods; 2128 modtail = mods; 2129 } 2130 } 2131 2132 if (!got_del_grace && attr_find(e->e_attrs, ad_pwdGraceUseTime )) { 2133 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2134 mods->sml_op = LDAP_MOD_DELETE; 2135 mods->sml_desc = ad_pwdGraceUseTime; 2136 mods->sml_flags = SLAP_MOD_INTERNAL; 2137 mods->sml_next = NULL; 2138 modtail->sml_next = mods; 2139 modtail = mods; 2140 } 2141 2142 if (!got_del_lock && attr_find(e->e_attrs, ad_pwdAccountLockedTime )) { 2143 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2144 mods->sml_op = LDAP_MOD_DELETE; 2145 mods->sml_desc = ad_pwdAccountLockedTime; 2146 mods->sml_flags = SLAP_MOD_INTERNAL; 2147 mods->sml_next = NULL; 2148 modtail->sml_next = mods; 2149 modtail = mods; 2150 } 2151 2152 if (!got_del_fail && attr_find(e->e_attrs, ad_pwdFailureTime )) { 2153 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2154 mods->sml_op = LDAP_MOD_DELETE; 2155 mods->sml_desc = ad_pwdFailureTime; 2156 mods->sml_flags = SLAP_MOD_INTERNAL; 2157 mods->sml_next = NULL; 2158 modtail->sml_next = mods; 2159 modtail = mods; 2160 } 2161 2162 /* Delete the pwdReset attribute, since it's being reset */ 2163 if ((zapReset) && (attr_find(e->e_attrs, ad_pwdReset ))) { 2164 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2165 mods->sml_op = LDAP_MOD_DELETE; 2166 mods->sml_desc = ad_pwdReset; 2167 mods->sml_flags = SLAP_MOD_INTERNAL; 2168 mods->sml_next = NULL; 2169 modtail->sml_next = mods; 2170 modtail = mods; 2171 } 2172 2173 /* Delete all pwdInHistory attribute */ 2174 if (!got_history && pp.pwdInHistory == 0 && 2175 attr_find(e->e_attrs, ad_pwdHistory )){ 2176 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2177 mods->sml_op = LDAP_MOD_DELETE; 2178 mods->sml_flags = SLAP_MOD_INTERNAL; 2179 mods->sml_desc = ad_pwdHistory; 2180 mods->sml_next = NULL; 2181 modtail->sml_next = mods; 2182 modtail = mods; 2183 } 2184 2185 if (!got_history && pp.pwdInHistory > 0){ 2186 if (hsize >= pp.pwdInHistory) { 2187 /* 2188 * We use the >= operator, since we are going to add 2189 * the existing password attribute value into the 2190 * history - thus the cardinality of history values is 2191 * about to rise by one. 2192 * 2193 * If this would push it over the limit of history 2194 * values (remembering - the password policy could have 2195 * changed since the password was last altered), we must 2196 * delete at least 1 value from the pwdHistory list. 2197 * 2198 * In fact, we delete '(#pwdHistory attrs - max pwd 2199 * history length) + 1' values, starting with the oldest. 2200 * This is easily evaluated, since the linked list is 2201 * created in ascending time order. 2202 */ 2203 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2204 mods->sml_op = LDAP_MOD_DELETE; 2205 mods->sml_flags = SLAP_MOD_INTERNAL; 2206 mods->sml_desc = ad_pwdHistory; 2207 mods->sml_numvals = hsize - pp.pwdInHistory + 1; 2208 mods->sml_values = ch_calloc( sizeof( struct berval ), 2209 hsize - pp.pwdInHistory + 2 ); 2210 BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] ); 2211 for(i=0,p=tl; i < (hsize - pp.pwdInHistory + 1); i++, p=p->next) { 2212 BER_BVZERO( &mods->sml_values[i] ); 2213 ber_dupbv( &(mods->sml_values[i]), &p->bv ); 2214 } 2215 mods->sml_next = NULL; 2216 modtail->sml_next = mods; 2217 modtail = mods; 2218 } 2219 free_pwd_history_list( &tl ); 2220 2221 /* 2222 * Now add the existing password into the history list. 2223 * This will be executed even if the operation is to delete 2224 * the password entirely. 2225 * 2226 * This isn't in the spec explicitly, but it seems to make 2227 * sense that the password history list is the list of all 2228 * previous passwords - even if they were deleted. Thus, if 2229 * someone tries to add a historical password at some future 2230 * point, it will fail. 2231 */ 2232 if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL) { 2233 mods = (Modifications *) ch_malloc( sizeof( Modifications ) ); 2234 mods->sml_op = LDAP_MOD_ADD; 2235 mods->sml_flags = SLAP_MOD_INTERNAL; 2236 mods->sml_type.bv_val = NULL; 2237 mods->sml_desc = ad_pwdHistory; 2238 mods->sml_nvalues = NULL; 2239 mods->sml_numvals = 1; 2240 mods->sml_values = ch_calloc( sizeof( struct berval ), 2 ); 2241 mods->sml_values[ 1 ].bv_val = NULL; 2242 mods->sml_values[ 1 ].bv_len = 0; 2243 make_pwd_history_value( timebuf, &mods->sml_values[0], pa ); 2244 mods->sml_next = NULL; 2245 modtail->sml_next = mods; 2246 modtail = mods; 2247 2248 } else { 2249 Debug( LDAP_DEBUG_TRACE, 2250 "ppolicy_modify: password attr lookup failed\n", 0, 0, 0 ); 2251 } 2252 } 2253 2254 /* 2255 * Controversial bit here. If the new password isn't hashed 2256 * (ie, is cleartext), we probably should hash it according 2257 * to the default hash. The reason for this is that we want 2258 * to use the policy if possible, but if we hash the password 2259 * before, then we're going to run into trouble when it 2260 * comes time to check the password. 2261 * 2262 * Now, the right thing to do is to use the extended password 2263 * modify operation, but not all software can do this, 2264 * therefore it makes sense to hash the new password, now 2265 * we know it passes the policy requirements. 2266 * 2267 * Of course, if the password is already hashed, then we 2268 * leave it alone. 2269 */ 2270 2271 if ((pi->hash_passwords) && (addmod) && !newpw.bv_val && 2272 (password_scheme( &(addmod->sml_values[0]), NULL ) != LDAP_SUCCESS)) 2273 { 2274 struct berval hpw, bv; 2275 2276 slap_passwd_hash( &(addmod->sml_values[0]), &hpw, &txt ); 2277 if (hpw.bv_val == NULL) { 2278 /* 2279 * hashing didn't work. Emit an error. 2280 */ 2281 rs->sr_err = LDAP_OTHER; 2282 rs->sr_text = txt; 2283 goto return_results; 2284 } 2285 bv = addmod->sml_values[0]; 2286 /* clear and discard the clear password */ 2287 memset(bv.bv_val, 0, bv.bv_len); 2288 ber_memfree(bv.bv_val); 2289 addmod->sml_values[0] = hpw; 2290 } 2291 } 2292 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2293 be_entry_release_r( op, e ); 2294 return SLAP_CB_CONTINUE; 2295 2296return_results: 2297 free_pwd_history_list( &tl ); 2298 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2299 be_entry_release_r( op, e ); 2300 if ( send_ctrl ) { 2301 ctrl = create_passcontrol( op, -1, -1, pErr ); 2302 oldctrls = add_passcontrol( op, rs, ctrl ); 2303 } 2304 send_ldap_result( op, rs ); 2305 if ( free_txt ) { 2306 free( (char *)txt ); 2307 rs->sr_text = NULL; 2308 } 2309 if ( send_ctrl ) { 2310 if ( is_pwdexop ) { 2311 if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) { 2312 op->o_tmpfree( oldctrls, op->o_tmpmemctx ); 2313 } 2314 oldctrls = NULL; 2315 rs->sr_flags |= REP_CTRLS_MUSTBEFREED; 2316 2317 } else { 2318 ctrls_cleanup( op, rs, oldctrls ); 2319 } 2320 } 2321 return rs->sr_err; 2322} 2323 2324static int 2325ppolicy_parseCtrl( 2326 Operation *op, 2327 SlapReply *rs, 2328 LDAPControl *ctrl ) 2329{ 2330 if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) { 2331 rs->sr_text = "passwordPolicyRequest control value not absent"; 2332 return LDAP_PROTOCOL_ERROR; 2333 } 2334 op->o_ctrlflag[ppolicy_cid] = ctrl->ldctl_iscritical 2335 ? SLAP_CONTROL_CRITICAL 2336 : SLAP_CONTROL_NONCRITICAL; 2337 2338 return LDAP_SUCCESS; 2339} 2340 2341static int 2342attrPretty( 2343 Syntax *syntax, 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_dupbv_x( out, &ad->ad_type->sat_cname, ctx ); 2355 } 2356 return code; 2357} 2358 2359static int 2360attrNormalize( 2361 slap_mask_t use, 2362 Syntax *syntax, 2363 MatchingRule *mr, 2364 struct berval *val, 2365 struct berval *out, 2366 void *ctx ) 2367{ 2368 AttributeDescription *ad = NULL; 2369 const char *err; 2370 int code; 2371 2372 code = slap_bv2ad( val, &ad, &err ); 2373 if ( !code ) { 2374 ber_str2bv_x( ad->ad_type->sat_oid, 0, 1, out, ctx ); 2375 } 2376 return code; 2377} 2378 2379static int 2380ppolicy_db_init( 2381 BackendDB *be, 2382 ConfigReply *cr 2383) 2384{ 2385 slap_overinst *on = (slap_overinst *) be->bd_info; 2386 2387 if ( SLAP_ISGLOBALOVERLAY( be ) ) { 2388 /* do not allow slapo-ppolicy to be global by now (ITS#5858) */ 2389 if ( cr ){ 2390 snprintf( cr->msg, sizeof(cr->msg), 2391 "slapo-ppolicy cannot be global" ); 2392 Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 ); 2393 } 2394 return 1; 2395 } 2396 2397 /* Has User Schema been initialized yet? */ 2398 if ( !pwd_UsSchema[0].ad[0] ) { 2399 const char *err; 2400 int i, code; 2401 2402 for (i=0; pwd_UsSchema[i].def; i++) { 2403 code = slap_str2ad( pwd_UsSchema[i].def, pwd_UsSchema[i].ad, &err ); 2404 if ( code ) { 2405 if ( cr ){ 2406 snprintf( cr->msg, sizeof(cr->msg), 2407 "User Schema load failed for attribute \"%s\". Error code %d: %s", 2408 pwd_UsSchema[i].def, code, err ); 2409 Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 ); 2410 } 2411 return code; 2412 } 2413 } 2414 { 2415 Syntax *syn; 2416 MatchingRule *mr; 2417 2418 syn = ch_malloc( sizeof( Syntax )); 2419 *syn = *ad_pwdAttribute->ad_type->sat_syntax; 2420 syn->ssyn_pretty = attrPretty; 2421 ad_pwdAttribute->ad_type->sat_syntax = syn; 2422 2423 mr = ch_malloc( sizeof( MatchingRule )); 2424 *mr = *ad_pwdAttribute->ad_type->sat_equality; 2425 mr->smr_normalize = attrNormalize; 2426 ad_pwdAttribute->ad_type->sat_equality = mr; 2427 } 2428 } 2429 2430 on->on_bi.bi_private = ch_calloc( sizeof(pp_info), 1 ); 2431 2432 if ( dtblsize && !pwcons ) { 2433 /* accommodate for c_conn_idx == -1 */ 2434 pwcons = ch_calloc( sizeof(pw_conn), dtblsize + 1 ); 2435 pwcons++; 2436 } 2437 2438 ov_count++; 2439 2440 return 0; 2441} 2442 2443static int 2444ppolicy_db_open( 2445 BackendDB *be, 2446 ConfigReply *cr 2447) 2448{ 2449 return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST ); 2450} 2451 2452static int 2453ppolicy_db_close( 2454 BackendDB *be, 2455 ConfigReply *cr 2456) 2457{ 2458#ifdef SLAP_CONFIG_DELETE 2459 overlay_unregister_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST ); 2460#endif /* SLAP_CONFIG_DELETE */ 2461 2462 return 0; 2463} 2464 2465static int 2466ppolicy_db_destroy( 2467 BackendDB *be, 2468 ConfigReply *cr 2469) 2470{ 2471 slap_overinst *on = (slap_overinst *) be->bd_info; 2472 pp_info *pi = on->on_bi.bi_private; 2473 2474 on->on_bi.bi_private = NULL; 2475 free( pi->def_policy.bv_val ); 2476 free( pi ); 2477 2478 ov_count--; 2479 if ( ov_count <=0 && pwcons ) { 2480 pw_conn *pwc = pwcons; 2481 pwcons = NULL; 2482 pwc--; 2483 ch_free( pwc ); 2484 } 2485 return 0; 2486} 2487 2488static char *extops[] = { 2489 LDAP_EXOP_MODIFY_PASSWD, 2490 NULL 2491}; 2492 2493static slap_overinst ppolicy; 2494 2495int ppolicy_initialize() 2496{ 2497 int i, code; 2498 2499 for (i=0; pwd_OpSchema[i].def; i++) { 2500 code = register_at( pwd_OpSchema[i].def, pwd_OpSchema[i].ad, 0 ); 2501 if ( code ) { 2502 Debug( LDAP_DEBUG_ANY, 2503 "ppolicy_initialize: register_at failed\n", 0, 0, 0 ); 2504 return code; 2505 } 2506 /* Allow Manager to set these as needed */ 2507 if ( is_at_no_user_mod( (*pwd_OpSchema[i].ad)->ad_type )) { 2508 (*pwd_OpSchema[i].ad)->ad_type->sat_flags |= 2509 SLAP_AT_MANAGEABLE; 2510 } 2511 } 2512 2513 code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST, 2514 SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE, extops, 2515 ppolicy_parseCtrl, &ppolicy_cid ); 2516 if ( code != LDAP_SUCCESS ) { 2517 Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code, 0, 0 ); 2518 return code; 2519 } 2520 2521 ldap_pvt_thread_mutex_init( &chk_syntax_mutex ); 2522 2523 ppolicy.on_bi.bi_type = "ppolicy"; 2524 ppolicy.on_bi.bi_db_init = ppolicy_db_init; 2525 ppolicy.on_bi.bi_db_open = ppolicy_db_open; 2526 ppolicy.on_bi.bi_db_close = ppolicy_db_close; 2527 ppolicy.on_bi.bi_db_destroy = ppolicy_db_destroy; 2528 2529 ppolicy.on_bi.bi_op_add = ppolicy_add; 2530 ppolicy.on_bi.bi_op_bind = ppolicy_bind; 2531 ppolicy.on_bi.bi_op_compare = ppolicy_compare; 2532 ppolicy.on_bi.bi_op_delete = ppolicy_restrict; 2533 ppolicy.on_bi.bi_op_modify = ppolicy_modify; 2534 ppolicy.on_bi.bi_op_search = ppolicy_restrict; 2535 ppolicy.on_bi.bi_connection_destroy = ppolicy_connection_destroy; 2536 2537 ppolicy.on_bi.bi_cf_ocs = ppolicyocs; 2538 code = config_register_schema( ppolicycfg, ppolicyocs ); 2539 if ( code ) return code; 2540 2541 return overlay_register( &ppolicy ); 2542} 2543 2544#if SLAPD_OVER_PPOLICY == SLAPD_MOD_DYNAMIC 2545int init_module(int argc, char *argv[]) { 2546 return ppolicy_initialize(); 2547} 2548#endif 2549 2550#endif /* defined(SLAPD_OVER_PPOLICY) */ 2551