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