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