1 /* $NetBSD: ppolicy.c,v 1.3 2021/08/14 16:15:02 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 2004-2021 The OpenLDAP Foundation. 7 * Portions Copyright 2004-2005 Howard Chu, Symas Corporation. 8 * Portions Copyright 2004 Hewlett-Packard Company. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19 /* ACKNOWLEDGEMENTS: 20 * This work was developed by Howard Chu for inclusion in 21 * OpenLDAP Software, based on prior work by Neil Dunbar (HP). 22 * This work was sponsored by the Hewlett-Packard Company. 23 */ 24 25 #include <sys/cdefs.h> 26 __RCSID("$NetBSD: ppolicy.c,v 1.3 2021/08/14 16:15:02 christos Exp $"); 27 28 #include "portable.h" 29 30 /* This file implements "Password Policy for LDAP Directories", 31 * based on draft behera-ldap-password-policy-09 32 */ 33 34 #ifdef SLAPD_OVER_PPOLICY 35 36 #include <ldap.h> 37 #include "lutil.h" 38 #include "slap.h" 39 #ifdef SLAPD_MODULES 40 #define LIBLTDL_DLL_IMPORT /* Win32: don't re-export libltdl's symbols */ 41 #include <ltdl.h> 42 #endif 43 #include <ac/errno.h> 44 #include <ac/time.h> 45 #include <ac/string.h> 46 #include <ac/ctype.h> 47 #include "slap-config.h" 48 49 #ifndef MODULE_NAME_SZ 50 #define MODULE_NAME_SZ 256 51 #endif 52 53 #ifndef PPOLICY_DEFAULT_MAXRECORDED_FAILURE 54 #define PPOLICY_DEFAULT_MAXRECORDED_FAILURE 5 55 #endif 56 57 /* Per-instance configuration information */ 58 typedef struct pp_info { 59 struct berval def_policy; /* DN of default policy subentry */ 60 int use_lockout; /* send AccountLocked result? */ 61 int hash_passwords; /* transparently hash cleartext pwds */ 62 int forward_updates; /* use frontend for policy state updates */ 63 int disable_write; 64 int send_netscape_controls; /* send netscape password controls */ 65 ldap_pvt_thread_mutex_t pwdFailureTime_mutex; 66 } pp_info; 67 68 /* Our per-connection info - note, it is not per-instance, it is 69 * used by all instances 70 */ 71 typedef struct pw_conn { 72 struct berval dn; /* DN of restricted user */ 73 } pw_conn; 74 75 static pw_conn *pwcons; 76 static int ppolicy_cid; 77 static int account_usability_cid; 78 static int ov_count; 79 80 typedef struct pass_policy { 81 AttributeDescription *ad; /* attribute to which the policy applies */ 82 int pwdMinAge; /* minimum time (seconds) until passwd can change */ 83 int pwdMaxAge; /* time in seconds until pwd will expire after change */ 84 int pwdMaxIdle; /* number of seconds since last successful bind before 85 passwd gets locked out */ 86 int pwdInHistory; /* number of previous passwords kept */ 87 int pwdCheckQuality; /* 0 = don't check quality, 1 = check if possible, 88 2 = check mandatory; fail if not possible */ 89 int pwdMinLength; /* minimum number of chars in password */ 90 int pwdMaxLength; /* maximum number of chars in password */ 91 int pwdExpireWarning; /* number of seconds that warning controls are 92 sent before a password expires */ 93 int pwdGraceExpiry; /* number of seconds after expiry grace logins are 94 valid */ 95 int pwdGraceAuthNLimit; /* number of times you can log in with an 96 expired password */ 97 int pwdLockout; /* 0 = do not lockout passwords, 1 = lock them out */ 98 int pwdLockoutDuration; /* time in seconds a password is locked out for */ 99 int pwdMinDelay; /* base bind delay in seconds on failure */ 100 int pwdMaxDelay; /* maximum bind delay in seconds */ 101 int pwdMaxFailure; /* number of failed binds allowed before lockout */ 102 int pwdMaxRecordedFailure; /* number of failed binds to store */ 103 int pwdFailureCountInterval; /* number of seconds before failure 104 counts are zeroed */ 105 int pwdMustChange; /* 0 = users can use admin set password 106 1 = users must change password after admin set */ 107 int pwdAllowUserChange; /* 0 = users cannot change their passwords 108 1 = users can change them */ 109 int pwdSafeModify; /* 0 = old password doesn't need to come 110 with password change request 111 1 = password change must supply existing pwd */ 112 char pwdCheckModule[MODULE_NAME_SZ]; /* name of module to dynamically 113 load to check password */ 114 struct berval pwdCheckModuleArg; /* Optional argument to the password check 115 module */ 116 } PassPolicy; 117 118 typedef struct pw_hist { 119 time_t t; /* timestamp of history entry */ 120 struct berval pw; /* old password hash */ 121 struct berval bv; /* text of entire entry */ 122 struct pw_hist *next; 123 } pw_hist; 124 125 /* Operational attributes */ 126 static AttributeDescription *ad_pwdChangedTime, *ad_pwdAccountLockedTime, 127 *ad_pwdFailureTime, *ad_pwdHistory, *ad_pwdGraceUseTime, *ad_pwdReset, 128 *ad_pwdPolicySubentry, *ad_pwdStartTime, *ad_pwdEndTime, 129 *ad_pwdLastSuccess, *ad_pwdAccountTmpLockoutEnd; 130 131 /* Policy attributes */ 132 static AttributeDescription *ad_pwdMinAge, *ad_pwdMaxAge, *ad_pwdMaxIdle, 133 *ad_pwdInHistory, *ad_pwdCheckQuality, *ad_pwdMinLength, *ad_pwdMaxLength, 134 *ad_pwdMaxFailure, *ad_pwdGraceExpiry, *ad_pwdGraceAuthNLimit, 135 *ad_pwdExpireWarning, *ad_pwdMinDelay, *ad_pwdMaxDelay, 136 *ad_pwdLockoutDuration, *ad_pwdFailureCountInterval, 137 *ad_pwdCheckModule, *ad_pwdCheckModuleArg, *ad_pwdLockout, 138 *ad_pwdMustChange, *ad_pwdAllowUserChange, *ad_pwdSafeModify, 139 *ad_pwdAttribute, *ad_pwdMaxRecordedFailure; 140 141 static struct schema_info { 142 char *def; 143 AttributeDescription **ad; 144 } pwd_OpSchema[] = { 145 { "( 1.3.6.1.4.1.42.2.27.8.1.16 " 146 "NAME ( 'pwdChangedTime' ) " 147 "DESC 'The time the password was last changed' " 148 "EQUALITY generalizedTimeMatch " 149 "ORDERING generalizedTimeOrderingMatch " 150 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 151 "SINGLE-VALUE " 152 "NO-USER-MODIFICATION " 153 "USAGE directoryOperation )", 154 &ad_pwdChangedTime }, 155 { "( 1.3.6.1.4.1.42.2.27.8.1.17 " 156 "NAME ( 'pwdAccountLockedTime' ) " 157 "DESC 'The time an user account was locked' " 158 "EQUALITY generalizedTimeMatch " 159 "ORDERING generalizedTimeOrderingMatch " 160 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 161 "SINGLE-VALUE " 162 "NO-USER-MODIFICATION " 163 "USAGE directoryOperation )", 164 &ad_pwdAccountLockedTime }, 165 { "( 1.3.6.1.4.1.42.2.27.8.1.19 " 166 "NAME ( 'pwdFailureTime' ) " 167 "DESC 'The timestamps of the last consecutive authentication failures' " 168 "EQUALITY generalizedTimeMatch " 169 "ORDERING generalizedTimeOrderingMatch " 170 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 171 "NO-USER-MODIFICATION " 172 "USAGE directoryOperation )", 173 &ad_pwdFailureTime }, 174 { "( 1.3.6.1.4.1.42.2.27.8.1.20 " 175 "NAME ( 'pwdHistory' ) " 176 "DESC 'The history of users passwords' " 177 "EQUALITY octetStringMatch " 178 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 " 179 "NO-USER-MODIFICATION " 180 "USAGE directoryOperation )", 181 &ad_pwdHistory }, 182 { "( 1.3.6.1.4.1.42.2.27.8.1.21 " 183 "NAME ( 'pwdGraceUseTime' ) " 184 "DESC 'The timestamps of the grace login once the password has expired' " 185 "EQUALITY generalizedTimeMatch " 186 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 187 "NO-USER-MODIFICATION " 188 "USAGE directoryOperation )", 189 &ad_pwdGraceUseTime }, 190 { "( 1.3.6.1.4.1.42.2.27.8.1.22 " 191 "NAME ( 'pwdReset' ) " 192 "DESC 'The indication that the password has been reset' " 193 "EQUALITY booleanMatch " 194 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " 195 "SINGLE-VALUE " 196 "USAGE directoryOperation )", 197 &ad_pwdReset }, 198 { "( 1.3.6.1.4.1.42.2.27.8.1.23 " 199 "NAME ( 'pwdPolicySubentry' ) " 200 "DESC 'The pwdPolicy subentry in effect for this object' " 201 "EQUALITY distinguishedNameMatch " 202 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 " 203 "SINGLE-VALUE " 204 "NO-USER-MODIFICATION " 205 "USAGE directoryOperation )", 206 &ad_pwdPolicySubentry }, 207 { "( 1.3.6.1.4.1.42.2.27.8.1.27 " 208 "NAME ( 'pwdStartTime' ) " 209 "DESC 'The time the password becomes enabled' " 210 "EQUALITY generalizedTimeMatch " 211 "ORDERING generalizedTimeOrderingMatch " 212 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 213 "SINGLE-VALUE " 214 "NO-USER-MODIFICATION " 215 "USAGE directoryOperation )", 216 &ad_pwdStartTime }, 217 { "( 1.3.6.1.4.1.42.2.27.8.1.28 " 218 "NAME ( 'pwdEndTime' ) " 219 "DESC 'The time the password becomes disabled' " 220 "EQUALITY generalizedTimeMatch " 221 "ORDERING generalizedTimeOrderingMatch " 222 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 223 "SINGLE-VALUE " 224 "NO-USER-MODIFICATION " 225 "USAGE directoryOperation )", 226 &ad_pwdEndTime }, 227 /* Defined in schema_prep.c now 228 { "( 1.3.6.1.4.1.42.2.27.8.1.29 " 229 "NAME ( 'pwdLastSuccess' ) " 230 "DESC 'The timestamp of the last successful authentication' " 231 "EQUALITY generalizedTimeMatch " 232 "ORDERING generalizedTimeOrderingMatch " 233 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 234 "SINGLE-VALUE " 235 "NO-USER-MODIFICATION " 236 "USAGE directoryOperation )", 237 &ad_pwdLastSuccess }, 238 */ 239 { "( 1.3.6.1.4.1.42.2.27.8.1.33 " 240 "NAME ( 'pwdAccountTmpLockoutEnd' ) " 241 "DESC 'Temporary lockout end' " 242 "EQUALITY generalizedTimeMatch " 243 "ORDERING generalizedTimeOrderingMatch " 244 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " 245 "SINGLE-VALUE " 246 "NO-USER-MODIFICATION " 247 "USAGE directoryOperation )", 248 &ad_pwdAccountTmpLockoutEnd }, 249 250 { "( 1.3.6.1.4.1.42.2.27.8.1.1 " 251 "NAME ( 'pwdAttribute' ) " 252 "EQUALITY objectIdentifierMatch " 253 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", 254 &ad_pwdAttribute }, 255 { "( 1.3.6.1.4.1.42.2.27.8.1.2 " 256 "NAME ( 'pwdMinAge' ) " 257 "EQUALITY integerMatch " 258 "ORDERING integerOrderingMatch " 259 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 260 "SINGLE-VALUE )", 261 &ad_pwdMinAge }, 262 { "( 1.3.6.1.4.1.42.2.27.8.1.3 " 263 "NAME ( 'pwdMaxAge' ) " 264 "EQUALITY integerMatch " 265 "ORDERING integerOrderingMatch " 266 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 267 "SINGLE-VALUE )", 268 &ad_pwdMaxAge }, 269 { "( 1.3.6.1.4.1.42.2.27.8.1.4 " 270 "NAME ( 'pwdInHistory' ) " 271 "EQUALITY integerMatch " 272 "ORDERING integerOrderingMatch " 273 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 274 "SINGLE-VALUE )", 275 &ad_pwdInHistory }, 276 { "( 1.3.6.1.4.1.42.2.27.8.1.5 " 277 "NAME ( 'pwdCheckQuality' ) " 278 "EQUALITY integerMatch " 279 "ORDERING integerOrderingMatch " 280 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 281 "SINGLE-VALUE )", 282 &ad_pwdCheckQuality }, 283 { "( 1.3.6.1.4.1.42.2.27.8.1.6 " 284 "NAME ( 'pwdMinLength' ) " 285 "EQUALITY integerMatch " 286 "ORDERING integerOrderingMatch " 287 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 288 "SINGLE-VALUE )", 289 &ad_pwdMinLength }, 290 { "( 1.3.6.1.4.1.42.2.27.8.1.31 " 291 "NAME ( 'pwdMaxLength' ) " 292 "EQUALITY integerMatch " 293 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 294 "SINGLE-VALUE )", 295 &ad_pwdMaxLength }, 296 { "( 1.3.6.1.4.1.42.2.27.8.1.7 " 297 "NAME ( 'pwdExpireWarning' ) " 298 "EQUALITY integerMatch " 299 "ORDERING integerOrderingMatch " 300 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 301 "SINGLE-VALUE )", 302 &ad_pwdExpireWarning }, 303 { "( 1.3.6.1.4.1.42.2.27.8.1.8 " 304 "NAME ( 'pwdGraceAuthNLimit' ) " 305 "EQUALITY integerMatch " 306 "ORDERING integerOrderingMatch " 307 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 308 "SINGLE-VALUE )", 309 &ad_pwdGraceAuthNLimit }, 310 { "( 1.3.6.1.4.1.42.2.27.8.1.30 " 311 "NAME ( 'pwdGraceExpiry' ) " 312 "EQUALITY integerMatch " 313 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 314 "SINGLE-VALUE )", 315 &ad_pwdGraceExpiry }, 316 { "( 1.3.6.1.4.1.42.2.27.8.1.9 " 317 "NAME ( 'pwdLockout' ) " 318 "EQUALITY booleanMatch " 319 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " 320 "SINGLE-VALUE )", 321 &ad_pwdLockout }, 322 { "( 1.3.6.1.4.1.42.2.27.8.1.10 " 323 "NAME ( 'pwdLockoutDuration' ) " 324 "EQUALITY integerMatch " 325 "ORDERING integerOrderingMatch " 326 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 327 "SINGLE-VALUE )", 328 &ad_pwdLockoutDuration }, 329 { "( 1.3.6.1.4.1.42.2.27.8.1.11 " 330 "NAME ( 'pwdMaxFailure' ) " 331 "EQUALITY integerMatch " 332 "ORDERING integerOrderingMatch " 333 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 334 "SINGLE-VALUE )", 335 &ad_pwdMaxFailure }, 336 { "( 1.3.6.1.4.1.42.2.27.8.1.12 " 337 "NAME ( 'pwdFailureCountInterval' ) " 338 "EQUALITY integerMatch " 339 "ORDERING integerOrderingMatch " 340 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 341 "SINGLE-VALUE )", 342 &ad_pwdFailureCountInterval }, 343 { "( 1.3.6.1.4.1.42.2.27.8.1.13 " 344 "NAME ( 'pwdMustChange' ) " 345 "EQUALITY booleanMatch " 346 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " 347 "SINGLE-VALUE )", 348 &ad_pwdMustChange }, 349 { "( 1.3.6.1.4.1.42.2.27.8.1.14 " 350 "NAME ( 'pwdAllowUserChange' ) " 351 "EQUALITY booleanMatch " 352 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " 353 "SINGLE-VALUE )", 354 &ad_pwdAllowUserChange }, 355 { "( 1.3.6.1.4.1.42.2.27.8.1.15 " 356 "NAME ( 'pwdSafeModify' ) " 357 "EQUALITY booleanMatch " 358 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " 359 "SINGLE-VALUE )", 360 &ad_pwdSafeModify }, 361 { "( 1.3.6.1.4.1.42.2.27.8.1.24 " 362 "NAME ( 'pwdMinDelay' ) " 363 "EQUALITY integerMatch " 364 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 365 "SINGLE-VALUE )", 366 &ad_pwdMinDelay }, 367 { "( 1.3.6.1.4.1.42.2.27.8.1.25 " 368 "NAME ( 'pwdMaxDelay' ) " 369 "EQUALITY integerMatch " 370 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 371 "SINGLE-VALUE )", 372 &ad_pwdMaxDelay }, 373 { "( 1.3.6.1.4.1.42.2.27.8.1.26 " 374 "NAME ( 'pwdMaxIdle' ) " 375 "EQUALITY integerMatch " 376 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 377 "SINGLE-VALUE )", 378 &ad_pwdMaxIdle }, 379 { "( 1.3.6.1.4.1.42.2.27.8.1.32 " 380 "NAME ( 'pwdMaxRecordedFailure' ) " 381 "EQUALITY integerMatch " 382 "ORDERING integerOrderingMatch " 383 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 384 "SINGLE-VALUE )", 385 &ad_pwdMaxRecordedFailure }, 386 { "( 1.3.6.1.4.1.4754.1.99.1 " 387 "NAME ( 'pwdCheckModule' ) " 388 "EQUALITY caseExactIA5Match " 389 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 " 390 "DESC 'Loadable module that instantiates check_password() function' " 391 "SINGLE-VALUE )", 392 &ad_pwdCheckModule }, 393 { "( 1.3.6.1.4.1.4754.1.99.2 " 394 "NAME ( 'pwdCheckModuleArg' ) " 395 "EQUALITY octetStringMatch " 396 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 " 397 "DESC 'Argument to pass to check_password() function' " 398 "SINGLE-VALUE )", 399 &ad_pwdCheckModuleArg }, 400 401 { NULL, NULL } 402 }; 403 404 static char *pwd_ocs[] = { 405 "( 1.3.6.1.4.1.4754.2.99.1 " 406 "NAME 'pwdPolicyChecker' " 407 "SUP top " 408 "AUXILIARY " 409 "MAY ( pwdCheckModule $ pwdCheckModuleArg ) )" , 410 "( 1.3.6.1.4.1.42.2.27.8.2.1 " 411 "NAME 'pwdPolicy' " 412 "SUP top " 413 "AUXILIARY " 414 "MUST ( pwdAttribute ) " 415 "MAY ( pwdMinAge $ pwdMaxAge $ pwdInHistory $ pwdCheckQuality $ " 416 "pwdMinLength $ pwdMaxLength $ pwdExpireWarning $ " 417 "pwdGraceAuthNLimit $ pwdGraceExpiry $ pwdLockout $ " 418 "pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $ " 419 "pwdMustChange $ pwdAllowUserChange $ pwdSafeModify $ " 420 "pwdMinDelay $ pwdMaxDelay $ pwdMaxIdle $ " 421 "pwdMaxRecordedFailure ) )", 422 NULL 423 }; 424 425 static ldap_pvt_thread_mutex_t chk_syntax_mutex; 426 427 enum { 428 PPOLICY_DEFAULT = 1, 429 PPOLICY_HASH_CLEARTEXT, 430 PPOLICY_USE_LOCKOUT, 431 PPOLICY_DISABLE_WRITE, 432 }; 433 434 static ConfigDriver ppolicy_cf_default; 435 436 static ConfigTable ppolicycfg[] = { 437 { "ppolicy_default", "policyDN", 2, 2, 0, 438 ARG_DN|ARG_QUOTE|ARG_MAGIC|PPOLICY_DEFAULT, ppolicy_cf_default, 439 "( OLcfgOvAt:12.1 NAME 'olcPPolicyDefault' " 440 "DESC 'DN of a pwdPolicy object for uncustomized objects' " 441 "EQUALITY distinguishedNameMatch " 442 "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, 443 { "ppolicy_hash_cleartext", "on|off", 1, 2, 0, 444 ARG_ON_OFF|ARG_OFFSET|PPOLICY_HASH_CLEARTEXT, 445 (void *)offsetof(pp_info,hash_passwords), 446 "( OLcfgOvAt:12.2 NAME 'olcPPolicyHashCleartext' " 447 "DESC 'Hash passwords on add or modify' " 448 "EQUALITY booleanMatch " 449 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 450 { "ppolicy_forward_updates", "on|off", 1, 2, 0, 451 ARG_ON_OFF|ARG_OFFSET, 452 (void *)offsetof(pp_info,forward_updates), 453 "( OLcfgOvAt:12.4 NAME 'olcPPolicyForwardUpdates' " 454 "DESC 'Allow policy state updates to be forwarded via updateref' " 455 "EQUALITY booleanMatch " 456 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 457 { "ppolicy_use_lockout", "on|off", 1, 2, 0, 458 ARG_ON_OFF|ARG_OFFSET|PPOLICY_USE_LOCKOUT, 459 (void *)offsetof(pp_info,use_lockout), 460 "( OLcfgOvAt:12.3 NAME 'olcPPolicyUseLockout' " 461 "DESC 'Warn clients with AccountLocked' " 462 "EQUALITY booleanMatch " 463 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 464 { "ppolicy_disable_write", "on|off", 1, 2, 0, 465 ARG_ON_OFF|ARG_OFFSET|PPOLICY_DISABLE_WRITE, 466 (void *)offsetof(pp_info,disable_write), 467 "( OLcfgOvAt:12.5 NAME 'olcPPolicyDisableWrite' " 468 "DESC 'Prevent all policy overlay writes' " 469 "EQUALITY booleanMatch " 470 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 471 { "ppolicy_send_netscape_controls", "on|off", 1, 2, 0, 472 ARG_ON_OFF|ARG_OFFSET, 473 (void *)offsetof(pp_info,send_netscape_controls), 474 "( OLcfgOvAt:12.6 NAME 'olcPPolicySendNetscapeControls' " 475 "DESC 'Send Netscape policy controls' " 476 "EQUALITY booleanMatch " 477 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 478 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 479 }; 480 481 static ConfigOCs ppolicyocs[] = { 482 { "( OLcfgOvOc:12.1 " 483 "NAME 'olcPPolicyConfig' " 484 "DESC 'Password Policy configuration' " 485 "SUP olcOverlayConfig " 486 "MAY ( olcPPolicyDefault $ olcPPolicyHashCleartext $ " 487 "olcPPolicyUseLockout $ olcPPolicyForwardUpdates $ " 488 "olcPPolicyDisableWrite $ olcPPolicySendNetscapeControls ) )", 489 Cft_Overlay, ppolicycfg }, 490 { NULL, 0, NULL } 491 }; 492 493 static int 494 ppolicy_cf_default( ConfigArgs *c ) 495 { 496 slap_overinst *on = (slap_overinst *)c->bi; 497 pp_info *pi = (pp_info *)on->on_bi.bi_private; 498 int rc = ARG_BAD_CONF; 499 500 assert ( c->type == PPOLICY_DEFAULT ); 501 Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default\n" ); 502 503 switch ( c->op ) { 504 case SLAP_CONFIG_EMIT: 505 Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default emit\n" ); 506 rc = 0; 507 if ( !BER_BVISEMPTY( &pi->def_policy )) { 508 rc = value_add_one( &c->rvalue_vals, 509 &pi->def_policy ); 510 if ( rc ) return rc; 511 rc = value_add_one( &c->rvalue_nvals, 512 &pi->def_policy ); 513 } 514 break; 515 case LDAP_MOD_DELETE: 516 Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default delete\n" ); 517 if ( pi->def_policy.bv_val ) { 518 ber_memfree ( pi->def_policy.bv_val ); 519 pi->def_policy.bv_val = NULL; 520 } 521 pi->def_policy.bv_len = 0; 522 rc = 0; 523 break; 524 case SLAP_CONFIG_ADD: 525 /* fallthru to LDAP_MOD_ADD */ 526 case LDAP_MOD_ADD: 527 Debug(LDAP_DEBUG_TRACE, "==> ppolicy_cf_default add\n" ); 528 if ( pi->def_policy.bv_val ) { 529 ber_memfree ( pi->def_policy.bv_val ); 530 } 531 pi->def_policy = c->value_ndn; 532 ber_memfree( c->value_dn.bv_val ); 533 BER_BVZERO( &c->value_dn ); 534 BER_BVZERO( &c->value_ndn ); 535 rc = 0; 536 break; 537 default: 538 abort (); 539 } 540 541 return rc; 542 } 543 544 static time_t 545 parse_time( char *atm ) 546 { 547 struct lutil_tm tm; 548 struct lutil_timet tt; 549 time_t ret = (time_t)-1; 550 551 if ( lutil_parsetime( atm, &tm ) == 0) { 552 lutil_tm2time( &tm, &tt ); 553 ret = tt.tt_sec; 554 } 555 return ret; 556 } 557 558 static int 559 account_locked( Operation *op, Entry *e, 560 PassPolicy *pp, Modifications **mod ) 561 { 562 Attribute *la; 563 564 if ( (la = attr_find( e->e_attrs, ad_pwdStartTime )) != NULL ) { 565 BerVarray vals = la->a_nvals; 566 time_t then, now = op->o_time; 567 568 /* 569 * Password has a defined start of validity 570 */ 571 if ( vals[0].bv_val != NULL ) { 572 if ( (then = parse_time( vals[0].bv_val )) == (time_t)-1 ) { 573 return 1; 574 } 575 if ( now < then ) { 576 return 1; 577 } 578 } 579 } 580 581 if ( (la = attr_find( e->e_attrs, ad_pwdEndTime )) != NULL ) { 582 BerVarray vals = la->a_nvals; 583 time_t then, now = op->o_time; 584 585 /* 586 * Password has a defined end of validity 587 */ 588 if ( vals[0].bv_val != NULL ) { 589 if ( (then = parse_time( vals[0].bv_val )) == (time_t)-1 ) { 590 return 1; 591 } 592 if ( then <= now ) { 593 return 1; 594 } 595 } 596 } 597 598 if ( !pp->pwdLockout ) 599 return 0; 600 601 if ( (la = attr_find( e->e_attrs, ad_pwdAccountTmpLockoutEnd )) != NULL ) { 602 BerVarray vals = la->a_nvals; 603 time_t then, now = op->o_time; 604 605 /* 606 * We have temporarily locked the account after a failure 607 */ 608 if ( vals[0].bv_val != NULL ) { 609 if ( (then = parse_time( vals[0].bv_val )) == (time_t)-1 ) { 610 return 1; 611 } 612 if ( now < then ) { 613 return 1; 614 } 615 } 616 } 617 618 /* Only check if database maintains lastbind */ 619 if ( pp->pwdMaxIdle && SLAP_LASTBIND( op->o_bd ) ) { 620 time_t lastbindtime = (time_t)-1; 621 622 la = attr_find( e->e_attrs, ad_pwdLastSuccess ); 623 if ( la == NULL ) { 624 la = attr_find( e->e_attrs, ad_pwdChangedTime ); 625 } 626 if ( la != NULL ) { 627 lastbindtime = parse_time( la->a_nvals[0].bv_val ); 628 } 629 630 if ( lastbindtime != (time_t)-1 && 631 op->o_time > lastbindtime + pp->pwdMaxIdle ) { 632 return 1; 633 } 634 } 635 636 if ( (la = attr_find( e->e_attrs, ad_pwdAccountLockedTime )) != NULL ) { 637 BerVarray vals = la->a_nvals; 638 639 /* 640 * there is a lockout stamp - we now need to know if it's 641 * a valid one. 642 */ 643 if (vals[0].bv_val != NULL) { 644 time_t then, now; 645 Modifications *m; 646 647 if ((then = parse_time( vals[0].bv_val )) == (time_t)0) 648 return 1; 649 650 now = slap_get_time(); 651 652 /* Still in the future? not yet in effect */ 653 if (now < then) 654 return 0; 655 656 if (!pp->pwdLockoutDuration) 657 return 1; 658 659 if (now < then + pp->pwdLockoutDuration) 660 return 1; 661 662 if ( mod != NULL ) { 663 m = ch_calloc( sizeof(Modifications), 1 ); 664 m->sml_op = LDAP_MOD_DELETE; 665 m->sml_flags = 0; 666 m->sml_type = ad_pwdAccountLockedTime->ad_cname; 667 m->sml_desc = ad_pwdAccountLockedTime; 668 m->sml_next = *mod; 669 *mod = m; 670 } 671 } 672 } 673 674 return 0; 675 } 676 677 /* IMPLICIT TAGS, all context-specific */ 678 #define PPOLICY_WARNING 0xa0L /* constructed + 0 */ 679 #define PPOLICY_ERROR 0x81L /* primitive + 1 */ 680 681 #define PPOLICY_EXPIRE 0x80L /* primitive + 0 */ 682 #define PPOLICY_GRACE 0x81L /* primitive + 1 */ 683 684 static const char ppolicy_ctrl_oid[] = LDAP_CONTROL_PASSWORDPOLICYRESPONSE; 685 static const char ppolicy_account_ctrl_oid[] = LDAP_CONTROL_X_ACCOUNT_USABILITY; 686 static const char ppolicy_pwd_expired_oid[] = LDAP_CONTROL_X_PASSWORD_EXPIRED; 687 static const char ppolicy_pwd_expiring_oid[] = LDAP_CONTROL_X_PASSWORD_EXPIRING; 688 689 static LDAPControl * 690 create_passcontrol( Operation *op, int exptime, int grace, LDAPPasswordPolicyError err ) 691 { 692 BerElementBuffer berbuf, bb2; 693 BerElement *ber = (BerElement *) &berbuf, *b2 = (BerElement *) &bb2; 694 LDAPControl c = { 0 }, *cp; 695 struct berval bv; 696 int rc; 697 698 BER_BVZERO( &c.ldctl_value ); 699 700 ber_init2( ber, NULL, LBER_USE_DER ); 701 ber_printf( ber, "{" /*}*/ ); 702 703 if ( exptime >= 0 ) { 704 ber_init2( b2, NULL, LBER_USE_DER ); 705 ber_printf( b2, "ti", PPOLICY_EXPIRE, exptime ); 706 rc = ber_flatten2( b2, &bv, 1 ); 707 (void)ber_free_buf(b2); 708 if (rc == -1) { 709 cp = NULL; 710 goto fail; 711 } 712 ber_printf( ber, "tO", PPOLICY_WARNING, &bv ); 713 ch_free( bv.bv_val ); 714 } else if ( grace >= 0 ) { 715 ber_init2( b2, NULL, LBER_USE_DER ); 716 ber_printf( b2, "ti", PPOLICY_GRACE, grace ); 717 rc = ber_flatten2( b2, &bv, 1 ); 718 (void)ber_free_buf(b2); 719 if (rc == -1) { 720 cp = NULL; 721 goto fail; 722 } 723 ber_printf( ber, "tO", PPOLICY_WARNING, &bv ); 724 ch_free( bv.bv_val ); 725 } 726 727 if (err != PP_noError ) { 728 ber_printf( ber, "te", PPOLICY_ERROR, err ); 729 } 730 ber_printf( ber, /*{*/ "N}" ); 731 732 if (ber_flatten2( ber, &c.ldctl_value, 0 ) == -1) { 733 return NULL; 734 } 735 cp = op->o_tmpalloc( sizeof( LDAPControl ) + c.ldctl_value.bv_len, op->o_tmpmemctx ); 736 cp->ldctl_oid = (char *)ppolicy_ctrl_oid; 737 cp->ldctl_iscritical = 0; 738 cp->ldctl_value.bv_val = (char *)&cp[1]; 739 cp->ldctl_value.bv_len = c.ldctl_value.bv_len; 740 AC_MEMCPY( cp->ldctl_value.bv_val, c.ldctl_value.bv_val, c.ldctl_value.bv_len ); 741 fail: 742 (void)ber_free_buf(ber); 743 744 return cp; 745 } 746 747 static LDAPControl * 748 create_passexpiry( Operation *op, int expired, int warn ) 749 { 750 LDAPControl *cp; 751 char buf[sizeof("-2147483648")]; 752 struct berval bv = { .bv_val = buf, .bv_len = sizeof(buf) }; 753 754 bv.bv_len = snprintf( bv.bv_val, bv.bv_len, "%d", warn ); 755 756 cp = op->o_tmpalloc( sizeof( LDAPControl ) + bv.bv_len, op->o_tmpmemctx ); 757 if ( expired ) { 758 cp->ldctl_oid = (char *)ppolicy_pwd_expired_oid; 759 } else { 760 cp->ldctl_oid = (char *)ppolicy_pwd_expiring_oid; 761 } 762 cp->ldctl_iscritical = 0; 763 cp->ldctl_value.bv_val = (char *)&cp[1]; 764 cp->ldctl_value.bv_len = bv.bv_len; 765 AC_MEMCPY( cp->ldctl_value.bv_val, bv.bv_val, bv.bv_len ); 766 return cp; 767 } 768 769 static LDAPControl ** 770 add_passcontrol( Operation *op, SlapReply *rs, LDAPControl *ctrl ) 771 { 772 LDAPControl **ctrls, **oldctrls = rs->sr_ctrls; 773 int n; 774 775 n = 0; 776 if ( oldctrls ) { 777 for ( ; oldctrls[n]; n++ ) 778 ; 779 } 780 n += 2; 781 782 ctrls = op->o_tmpcalloc( sizeof( LDAPControl * ), n, op->o_tmpmemctx ); 783 784 n = 0; 785 if ( oldctrls ) { 786 for ( ; oldctrls[n]; n++ ) { 787 ctrls[n] = oldctrls[n]; 788 } 789 } 790 ctrls[n] = ctrl; 791 ctrls[n+1] = NULL; 792 793 rs->sr_ctrls = ctrls; 794 795 return oldctrls; 796 } 797 798 static void 799 add_account_control( 800 Operation *op, 801 SlapReply *rs, 802 int available, 803 int remaining, 804 LDAPAccountUsabilityMoreInfo *more_info ) 805 { 806 BerElementBuffer berbuf; 807 BerElement *ber = (BerElement *) &berbuf; 808 LDAPControl c = { 0 }, *cp = NULL, **ctrls; 809 int i = 0; 810 811 BER_BVZERO( &c.ldctl_value ); 812 813 ber_init2( ber, NULL, LBER_USE_DER ); 814 815 if ( available ) { 816 ber_put_int( ber, remaining, LDAP_TAG_X_ACCOUNT_USABILITY_AVAILABLE ); 817 } else { 818 assert( more_info != NULL ); 819 820 ber_start_seq( ber, LDAP_TAG_X_ACCOUNT_USABILITY_NOT_AVAILABLE ); 821 ber_put_boolean( ber, more_info->inactive, LDAP_TAG_X_ACCOUNT_USABILITY_INACTIVE ); 822 ber_put_boolean( ber, more_info->reset, LDAP_TAG_X_ACCOUNT_USABILITY_RESET ); 823 ber_put_boolean( ber, more_info->expired, LDAP_TAG_X_ACCOUNT_USABILITY_EXPIRED ); 824 ber_put_int( ber, more_info->remaining_grace, LDAP_TAG_X_ACCOUNT_USABILITY_REMAINING_GRACE ); 825 ber_put_int( ber, more_info->seconds_before_unlock, LDAP_TAG_X_ACCOUNT_USABILITY_UNTIL_UNLOCK ); 826 ber_put_seq( ber ); 827 } 828 829 if (ber_flatten2( ber, &c.ldctl_value, 0 ) == -1) { 830 goto fail; 831 } 832 833 if ( rs->sr_ctrls != NULL ) { 834 for ( ; rs->sr_ctrls[ i ] != NULL; i++ ) /* Count */; 835 } 836 837 ctrls = op->o_tmprealloc( rs->sr_ctrls, sizeof(LDAPControl *)*( i + 2 ), op->o_tmpmemctx ); 838 if ( ctrls == NULL ) { 839 goto fail; 840 } 841 842 cp = op->o_tmpalloc( sizeof( LDAPControl ) + c.ldctl_value.bv_len, op->o_tmpmemctx ); 843 cp->ldctl_oid = (char *)ppolicy_account_ctrl_oid; 844 cp->ldctl_iscritical = 0; 845 cp->ldctl_value.bv_val = (char *)&cp[1]; 846 cp->ldctl_value.bv_len = c.ldctl_value.bv_len; 847 AC_MEMCPY( cp->ldctl_value.bv_val, c.ldctl_value.bv_val, c.ldctl_value.bv_len ); 848 849 ctrls[ i ] = cp; 850 ctrls[ i + 1 ] = NULL; 851 rs->sr_ctrls = ctrls; 852 853 fail: 854 (void)ber_free_buf(ber); 855 } 856 857 static void 858 ppolicy_get_default( PassPolicy *pp ) 859 { 860 memset( pp, 0, sizeof(PassPolicy) ); 861 862 pp->ad = slap_schema.si_ad_userPassword; 863 864 /* Users can change their own password by default */ 865 pp->pwdAllowUserChange = 1; 866 } 867 868 869 static int 870 ppolicy_get( Operation *op, Entry *e, PassPolicy *pp ) 871 { 872 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 873 pp_info *pi = on->on_bi.bi_private; 874 BackendDB *bd, *bd_orig = op->o_bd; 875 AttributeDescription *ad = NULL; 876 Attribute *a; 877 BerVarray vals; 878 int rc = LDAP_SUCCESS; 879 Entry *pe = NULL; 880 #if 0 881 const char *text; 882 #endif 883 884 ppolicy_get_default( pp ); 885 886 ad = ad_pwdPolicySubentry; 887 if ( (a = attr_find( e->e_attrs, ad )) == NULL ) { 888 /* 889 * entry has no password policy assigned - use default 890 */ 891 vals = &pi->def_policy; 892 if ( !vals->bv_val ) 893 goto defaultpol; 894 } else { 895 vals = a->a_nvals; 896 if (vals[0].bv_val == NULL) { 897 Debug( LDAP_DEBUG_ANY, 898 "ppolicy_get: NULL value for policySubEntry\n" ); 899 goto defaultpol; 900 } 901 } 902 903 op->o_bd = bd = select_backend( vals, 0 ); 904 if ( op->o_bd == NULL ) { 905 op->o_bd = bd_orig; 906 goto defaultpol; 907 } 908 909 rc = be_entry_get_rw( op, vals, NULL, NULL, 0, &pe ); 910 op->o_bd = bd_orig; 911 912 if ( rc ) goto defaultpol; 913 914 #if 0 /* Only worry about userPassword for now */ 915 if ((a = attr_find( pe->e_attrs, ad_pwdAttribute ))) 916 slap_bv2ad( &a->a_vals[0], &pp->ad, &text ); 917 #endif 918 919 ad = ad_pwdMinAge; 920 if ( (a = attr_find( pe->e_attrs, ad )) 921 && lutil_atoi( &pp->pwdMinAge, a->a_vals[0].bv_val ) != 0 ) { 922 rc = LDAP_CONSTRAINT_VIOLATION; 923 goto defaultpol; 924 } 925 926 ad = ad_pwdMaxAge; 927 if ( (a = attr_find( pe->e_attrs, ad )) 928 && lutil_atoi( &pp->pwdMaxAge, a->a_vals[0].bv_val ) != 0 ) { 929 rc = LDAP_CONSTRAINT_VIOLATION; 930 goto defaultpol; 931 } 932 933 ad = ad_pwdMaxIdle; 934 if ( (a = attr_find( pe->e_attrs, ad )) 935 && lutil_atoi( &pp->pwdMaxIdle, a->a_vals[0].bv_val ) != 0 ) { 936 rc = LDAP_CONSTRAINT_VIOLATION; 937 goto defaultpol; 938 } 939 940 ad = ad_pwdInHistory; 941 if ( (a = attr_find( pe->e_attrs, ad )) 942 && lutil_atoi( &pp->pwdInHistory, a->a_vals[0].bv_val ) != 0 ) { 943 rc = LDAP_CONSTRAINT_VIOLATION; 944 goto defaultpol; 945 } 946 947 ad = ad_pwdCheckQuality; 948 if ( (a = attr_find( pe->e_attrs, ad )) 949 && lutil_atoi( &pp->pwdCheckQuality, a->a_vals[0].bv_val ) != 0 ) { 950 rc = LDAP_CONSTRAINT_VIOLATION; 951 goto defaultpol; 952 } 953 954 ad = ad_pwdMinLength; 955 if ( (a = attr_find( pe->e_attrs, ad )) 956 && lutil_atoi( &pp->pwdMinLength, a->a_vals[0].bv_val ) != 0 ) { 957 rc = LDAP_CONSTRAINT_VIOLATION; 958 goto defaultpol; 959 } 960 961 ad = ad_pwdMaxLength; 962 if ( (a = attr_find( pe->e_attrs, ad )) 963 && lutil_atoi( &pp->pwdMaxLength, a->a_vals[0].bv_val ) != 0 ) { 964 rc = LDAP_CONSTRAINT_VIOLATION; 965 goto defaultpol; 966 } 967 968 ad = ad_pwdMaxFailure; 969 if ( (a = attr_find( pe->e_attrs, ad )) 970 && lutil_atoi( &pp->pwdMaxFailure, a->a_vals[0].bv_val ) != 0 ) { 971 rc = LDAP_CONSTRAINT_VIOLATION; 972 goto defaultpol; 973 } 974 975 ad = ad_pwdMaxRecordedFailure; 976 if ( (a = attr_find( pe->e_attrs, ad )) 977 && lutil_atoi( &pp->pwdMaxRecordedFailure, a->a_vals[0].bv_val ) != 0 ) { 978 rc = LDAP_CONSTRAINT_VIOLATION; 979 goto defaultpol; 980 } 981 982 ad = ad_pwdGraceExpiry; 983 if ( (a = attr_find( pe->e_attrs, ad )) 984 && lutil_atoi( &pp->pwdGraceExpiry, a->a_vals[0].bv_val ) != 0 ) { 985 rc = LDAP_CONSTRAINT_VIOLATION; 986 goto defaultpol; 987 } 988 989 ad = ad_pwdGraceAuthNLimit; 990 if ( (a = attr_find( pe->e_attrs, ad )) 991 && lutil_atoi( &pp->pwdGraceAuthNLimit, a->a_vals[0].bv_val ) != 0 ) { 992 rc = LDAP_CONSTRAINT_VIOLATION; 993 goto defaultpol; 994 } 995 996 ad = ad_pwdExpireWarning; 997 if ( (a = attr_find( pe->e_attrs, ad )) 998 && lutil_atoi( &pp->pwdExpireWarning, a->a_vals[0].bv_val ) != 0 ) { 999 rc = LDAP_CONSTRAINT_VIOLATION; 1000 goto defaultpol; 1001 } 1002 1003 ad = ad_pwdFailureCountInterval; 1004 if ( (a = attr_find( pe->e_attrs, ad )) 1005 && lutil_atoi( &pp->pwdFailureCountInterval, a->a_vals[0].bv_val ) != 0 ) { 1006 rc = LDAP_CONSTRAINT_VIOLATION; 1007 goto defaultpol; 1008 } 1009 1010 ad = ad_pwdLockoutDuration; 1011 if ( (a = attr_find( pe->e_attrs, ad )) 1012 && lutil_atoi( &pp->pwdLockoutDuration, a->a_vals[0].bv_val ) != 0 ) { 1013 rc = LDAP_CONSTRAINT_VIOLATION; 1014 goto defaultpol; 1015 } 1016 1017 ad = ad_pwdMinDelay; 1018 if ( (a = attr_find( pe->e_attrs, ad )) 1019 && lutil_atoi( &pp->pwdMinDelay, a->a_vals[0].bv_val ) != 0 ) { 1020 rc = LDAP_CONSTRAINT_VIOLATION; 1021 goto defaultpol; 1022 } 1023 1024 ad = ad_pwdMaxDelay; 1025 if ( (a = attr_find( pe->e_attrs, ad )) 1026 && lutil_atoi( &pp->pwdMaxDelay, a->a_vals[0].bv_val ) != 0 ) { 1027 rc = LDAP_CONSTRAINT_VIOLATION; 1028 goto defaultpol; 1029 } 1030 1031 ad = ad_pwdCheckModule; 1032 if ( (a = attr_find( pe->e_attrs, ad )) ) { 1033 strncpy( pp->pwdCheckModule, a->a_vals[0].bv_val, 1034 sizeof(pp->pwdCheckModule) ); 1035 pp->pwdCheckModule[sizeof(pp->pwdCheckModule)-1] = '\0'; 1036 } 1037 1038 ad = ad_pwdCheckModuleArg; 1039 if ( (a = attr_find( pe->e_attrs, ad )) ) { 1040 ber_dupbv_x( &pp->pwdCheckModuleArg, &a->a_vals[0], op->o_tmpmemctx ); 1041 } 1042 1043 ad = ad_pwdLockout; 1044 if ( (a = attr_find( pe->e_attrs, ad )) ) 1045 pp->pwdLockout = bvmatch( &a->a_nvals[0], &slap_true_bv ); 1046 1047 ad = ad_pwdMustChange; 1048 if ( (a = attr_find( pe->e_attrs, ad )) ) 1049 pp->pwdMustChange = bvmatch( &a->a_nvals[0], &slap_true_bv ); 1050 1051 ad = ad_pwdAllowUserChange; 1052 if ( (a = attr_find( pe->e_attrs, ad )) ) 1053 pp->pwdAllowUserChange = bvmatch( &a->a_nvals[0], &slap_true_bv ); 1054 1055 ad = ad_pwdSafeModify; 1056 if ( (a = attr_find( pe->e_attrs, ad )) ) 1057 pp->pwdSafeModify = bvmatch( &a->a_nvals[0], &slap_true_bv ); 1058 1059 if ( pp->pwdMaxRecordedFailure < pp->pwdMaxFailure ) 1060 pp->pwdMaxRecordedFailure = pp->pwdMaxFailure; 1061 1062 if ( !pp->pwdMaxRecordedFailure && pp->pwdMinDelay ) 1063 pp->pwdMaxRecordedFailure = PPOLICY_DEFAULT_MAXRECORDED_FAILURE; 1064 1065 if ( pp->pwdMinDelay && !pp->pwdMaxDelay ) { 1066 Debug( LDAP_DEBUG_ANY, "ppolicy_get: " 1067 "pwdMinDelay was set but pwdMaxDelay wasn't, assuming they " 1068 "are equal\n" ); 1069 pp->pwdMaxDelay = pp->pwdMinDelay; 1070 } 1071 1072 op->o_bd = bd; 1073 be_entry_release_r( op, pe ); 1074 op->o_bd = bd_orig; 1075 1076 return LDAP_SUCCESS; 1077 1078 defaultpol: 1079 if ( pe ) { 1080 op->o_bd = bd; 1081 be_entry_release_r( op, pe ); 1082 op->o_bd = bd_orig; 1083 } 1084 1085 if ( rc && !BER_BVISNULL( vals ) ) { 1086 Debug( LDAP_DEBUG_ANY, "ppolicy_get: " 1087 "policy subentry %s missing or invalid at '%s', " 1088 "no policy will be applied!\n", 1089 vals->bv_val, ad ? ad->ad_cname.bv_val : "" ); 1090 } else { 1091 Debug( LDAP_DEBUG_TRACE, 1092 "ppolicy_get: using default policy\n" ); 1093 } 1094 1095 ppolicy_get_default( pp ); 1096 1097 return -1; 1098 } 1099 1100 static int 1101 password_scheme( struct berval *cred, struct berval *sch ) 1102 { 1103 int e; 1104 1105 assert( cred != NULL ); 1106 1107 if (sch) { 1108 sch->bv_val = NULL; 1109 sch->bv_len = 0; 1110 } 1111 1112 if ((cred->bv_len == 0) || (cred->bv_val == NULL) || 1113 (cred->bv_val[0] != '{')) return LDAP_OTHER; 1114 1115 for(e = 1; cred->bv_val[e] && cred->bv_val[e] != '}'; e++); 1116 if (cred->bv_val[e]) { 1117 int rc; 1118 rc = lutil_passwd_scheme( cred->bv_val ); 1119 if (rc) { 1120 if (sch) { 1121 sch->bv_val = cred->bv_val; 1122 sch->bv_len = e; 1123 } 1124 return LDAP_SUCCESS; 1125 } 1126 } 1127 return LDAP_OTHER; 1128 } 1129 1130 static int 1131 check_password_quality( struct berval *cred, PassPolicy *pp, LDAPPasswordPolicyError *err, Entry *e, char **txt ) 1132 { 1133 int rc = LDAP_SUCCESS, ok = LDAP_SUCCESS; 1134 char *ptr; 1135 struct berval sch; 1136 1137 assert( cred != NULL ); 1138 assert( pp != NULL ); 1139 assert( txt != NULL ); 1140 1141 ptr = cred->bv_val; 1142 1143 *txt = NULL; 1144 1145 if ((cred->bv_len == 0) || (pp->pwdMinLength > cred->bv_len)) { 1146 rc = LDAP_CONSTRAINT_VIOLATION; 1147 if ( err ) *err = PP_passwordTooShort; 1148 return rc; 1149 } 1150 1151 if ( pp->pwdMaxLength && cred->bv_len > pp->pwdMaxLength ) { 1152 rc = LDAP_CONSTRAINT_VIOLATION; 1153 if ( err ) *err = PP_passwordTooLong; 1154 return rc; 1155 } 1156 1157 /* 1158 * We need to know if the password is already hashed - if so 1159 * what scheme is it. The reason being that the "hash" of 1160 * {cleartext} still allows us to check the password. 1161 */ 1162 rc = password_scheme( cred, &sch ); 1163 if (rc == LDAP_SUCCESS) { 1164 if ((sch.bv_val) && (strncasecmp( sch.bv_val, "{cleartext}", 1165 sch.bv_len ) == 0)) { 1166 /* 1167 * We can check the cleartext "hash" 1168 */ 1169 ptr = cred->bv_val + sch.bv_len; 1170 } else { 1171 /* everything else, we can't check */ 1172 if (pp->pwdCheckQuality == 2) { 1173 rc = LDAP_CONSTRAINT_VIOLATION; 1174 if (err) *err = PP_insufficientPasswordQuality; 1175 return rc; 1176 } 1177 /* 1178 * We can't check the syntax of the password, but it's not 1179 * mandatory (according to the policy), so we return success. 1180 */ 1181 1182 return LDAP_SUCCESS; 1183 } 1184 } 1185 1186 rc = LDAP_SUCCESS; 1187 1188 if (pp->pwdCheckModule[0]) { 1189 #ifdef SLAPD_MODULES 1190 lt_dlhandle mod; 1191 const char *err; 1192 1193 if ((mod = lt_dlopen( pp->pwdCheckModule )) == NULL) { 1194 err = lt_dlerror(); 1195 1196 Debug(LDAP_DEBUG_ANY, 1197 "check_password_quality: lt_dlopen failed: (%s) %s.\n", 1198 pp->pwdCheckModule, err ); 1199 ok = LDAP_OTHER; /* internal error */ 1200 } else { 1201 /* FIXME: the error message ought to be passed thru a 1202 * struct berval, with preallocated buffer and size 1203 * passed in. Module can still allocate a buffer for 1204 * it if the provided one is too small. 1205 */ 1206 int (*prog)( char *passwd, char **text, Entry *ent, struct berval *arg ); 1207 1208 if ((prog = lt_dlsym( mod, "check_password" )) == NULL) { 1209 err = lt_dlerror(); 1210 1211 Debug(LDAP_DEBUG_ANY, 1212 "check_password_quality: lt_dlsym failed: (%s) %s.\n", 1213 pp->pwdCheckModule, err ); 1214 ok = LDAP_OTHER; 1215 } else { 1216 struct berval *arg = NULL; 1217 if ( !BER_BVISNULL( &pp->pwdCheckModuleArg ) ) { 1218 arg = &pp->pwdCheckModuleArg; 1219 } 1220 1221 ldap_pvt_thread_mutex_lock( &chk_syntax_mutex ); 1222 ok = prog( ptr, txt, e, arg ); 1223 ldap_pvt_thread_mutex_unlock( &chk_syntax_mutex ); 1224 if (ok != LDAP_SUCCESS) { 1225 Debug(LDAP_DEBUG_ANY, 1226 "check_password_quality: module error: (%s) %s.[%d]\n", 1227 pp->pwdCheckModule, *txt ? *txt : "", ok ); 1228 } 1229 } 1230 1231 lt_dlclose( mod ); 1232 } 1233 #else 1234 Debug(LDAP_DEBUG_ANY, "check_password_quality: external modules not " 1235 "supported. pwdCheckModule ignored.\n" ); 1236 #endif /* SLAPD_MODULES */ 1237 } 1238 1239 1240 if (ok != LDAP_SUCCESS) { 1241 rc = LDAP_CONSTRAINT_VIOLATION; 1242 if (err) *err = PP_insufficientPasswordQuality; 1243 } 1244 1245 return rc; 1246 } 1247 1248 static int 1249 parse_pwdhistory( struct berval *bv, char **oid, time_t *oldtime, struct berval *oldpw ) 1250 { 1251 char *ptr; 1252 struct berval nv, npw; 1253 ber_len_t i, j; 1254 1255 assert (bv && (bv->bv_len > 0) && (bv->bv_val) && oldtime && oldpw ); 1256 1257 if ( oid ) { 1258 *oid = 0; 1259 } 1260 *oldtime = (time_t)-1; 1261 BER_BVZERO( oldpw ); 1262 1263 ber_dupbv( &nv, bv ); 1264 1265 /* first get the time field */ 1266 for ( i = 0; (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ ) 1267 ; 1268 if ( i == nv.bv_len ) { 1269 goto exit_failure; /* couldn't locate the '#' separator */ 1270 } 1271 nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */ 1272 ptr = nv.bv_val; 1273 *oldtime = parse_time( ptr ); 1274 if (*oldtime == (time_t)-1) { 1275 goto exit_failure; 1276 } 1277 1278 /* get the OID field */ 1279 for (ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ ) 1280 ; 1281 if ( i == nv.bv_len ) { 1282 goto exit_failure; /* couldn't locate the '#' separator */ 1283 } 1284 nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */ 1285 if ( oid ) { 1286 *oid = ber_strdup( ptr ); 1287 } 1288 1289 /* get the length field */ 1290 for ( ptr = &(nv.bv_val[i]); (i < nv.bv_len) && (nv.bv_val[i] != '#'); i++ ) 1291 ; 1292 if ( i == nv.bv_len ) { 1293 goto exit_failure; /* couldn't locate the '#' separator */ 1294 } 1295 nv.bv_val[i++] = '\0'; /* terminate the string & move to next field */ 1296 oldpw->bv_len = strtol( ptr, NULL, 10 ); 1297 if (errno == ERANGE) { 1298 goto exit_failure; 1299 } 1300 1301 /* lastly, get the octets of the string */ 1302 for ( j = i, ptr = &(nv.bv_val[i]); i < nv.bv_len; i++ ) 1303 ; 1304 if ( i - j != oldpw->bv_len) { 1305 goto exit_failure; /* length is wrong */ 1306 } 1307 1308 npw.bv_val = ptr; 1309 npw.bv_len = oldpw->bv_len; 1310 ber_dupbv( oldpw, &npw ); 1311 ber_memfree( nv.bv_val ); 1312 1313 return LDAP_SUCCESS; 1314 1315 exit_failure:; 1316 if ( oid && *oid ) { 1317 ber_memfree(*oid); 1318 *oid = NULL; 1319 } 1320 if ( oldpw->bv_val ) { 1321 ber_memfree( oldpw->bv_val); 1322 BER_BVZERO( oldpw ); 1323 } 1324 ber_memfree( nv.bv_val ); 1325 1326 return LDAP_OTHER; 1327 } 1328 1329 static void 1330 add_to_pwd_history( pw_hist **l, time_t t, 1331 struct berval *oldpw, struct berval *bv ) 1332 { 1333 pw_hist *p, *p1, *p2; 1334 1335 if (!l) return; 1336 1337 p = ch_malloc( sizeof( pw_hist )); 1338 p->pw = *oldpw; 1339 ber_dupbv( &p->bv, bv ); 1340 p->t = t; 1341 p->next = NULL; 1342 1343 if (*l == NULL) { 1344 /* degenerate case */ 1345 *l = p; 1346 return; 1347 } 1348 /* 1349 * advance p1 and p2 such that p1 is the node before the 1350 * new one, and p2 is the node after it 1351 */ 1352 for (p1 = NULL, p2 = *l; p2 && p2->t <= t; p1 = p2, p2=p2->next ); 1353 p->next = p2; 1354 if (p1 == NULL) { *l = p; return; } 1355 p1->next = p; 1356 } 1357 1358 #ifndef MAX_PWD_HISTORY_SZ 1359 #define MAX_PWD_HISTORY_SZ 1024 1360 #endif /* MAX_PWD_HISTORY_SZ */ 1361 1362 static void 1363 make_pwd_history_value( char *timebuf, struct berval *bv, Attribute *pa ) 1364 { 1365 char str[ MAX_PWD_HISTORY_SZ ]; 1366 int nlen; 1367 1368 snprintf( str, MAX_PWD_HISTORY_SZ, 1369 "%s#%s#%lu#", timebuf, 1370 pa->a_desc->ad_type->sat_syntax->ssyn_oid, 1371 (unsigned long) pa->a_nvals[0].bv_len ); 1372 str[MAX_PWD_HISTORY_SZ-1] = 0; 1373 nlen = strlen(str); 1374 1375 /* 1376 * We have to assume that the string is a string of octets, 1377 * not readable characters. In reality, yes, it probably is 1378 * a readable (ie, base64) string, but we can't count on that 1379 * Hence, while the first 3 fields of the password history 1380 * are definitely readable (a timestamp, an OID and an integer 1381 * length), the remaining octets of the actual password 1382 * are deemed to be binary data. 1383 */ 1384 AC_MEMCPY( str + nlen, pa->a_nvals[0].bv_val, pa->a_nvals[0].bv_len ); 1385 nlen += pa->a_nvals[0].bv_len; 1386 bv->bv_val = ch_malloc( nlen + 1 ); 1387 AC_MEMCPY( bv->bv_val, str, nlen ); 1388 bv->bv_val[nlen] = '\0'; 1389 bv->bv_len = nlen; 1390 } 1391 1392 static void 1393 free_pwd_history_list( pw_hist **l ) 1394 { 1395 pw_hist *p; 1396 1397 if (!l) return; 1398 p = *l; 1399 while (p) { 1400 pw_hist *pp = p->next; 1401 1402 free(p->pw.bv_val); 1403 free(p->bv.bv_val); 1404 free(p); 1405 p = pp; 1406 } 1407 *l = NULL; 1408 } 1409 1410 typedef struct ppbind { 1411 slap_overinst *on; 1412 int send_ctrl; 1413 int set_restrict; 1414 LDAPControl **oldctrls; 1415 Modifications *mod; 1416 LDAPPasswordPolicyError pErr; 1417 PassPolicy pp; 1418 } ppbind; 1419 1420 static void 1421 ctrls_cleanup( Operation *op, SlapReply *rs, LDAPControl **oldctrls ) 1422 { 1423 int n; 1424 1425 assert( rs->sr_ctrls != NULL ); 1426 assert( rs->sr_ctrls[0] != NULL ); 1427 1428 for ( n = 0; rs->sr_ctrls[n]; n++ ) { 1429 if ( rs->sr_ctrls[n]->ldctl_oid == ppolicy_ctrl_oid || 1430 rs->sr_ctrls[n]->ldctl_oid == ppolicy_pwd_expired_oid || 1431 rs->sr_ctrls[n]->ldctl_oid == ppolicy_pwd_expiring_oid ) { 1432 op->o_tmpfree( rs->sr_ctrls[n], op->o_tmpmemctx ); 1433 rs->sr_ctrls[n] = (LDAPControl *)(-1); 1434 break; 1435 } 1436 } 1437 1438 if ( rs->sr_ctrls[n] == NULL ) { 1439 /* missed? */ 1440 } 1441 1442 op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx ); 1443 1444 rs->sr_ctrls = oldctrls; 1445 } 1446 1447 static int 1448 ppolicy_ctrls_cleanup( Operation *op, SlapReply *rs ) 1449 { 1450 ppbind *ppb = op->o_callback->sc_private; 1451 if ( ppb->send_ctrl ) { 1452 ctrls_cleanup( op, rs, ppb->oldctrls ); 1453 } 1454 return SLAP_CB_CONTINUE; 1455 } 1456 1457 static int 1458 ppolicy_bind_response( Operation *op, SlapReply *rs ) 1459 { 1460 ppbind *ppb = op->o_callback->sc_private; 1461 slap_overinst *on = ppb->on; 1462 pp_info *pi = on->on_bi.bi_private; 1463 Modifications *mod = ppb->mod, *m; 1464 int pwExpired = 0; 1465 int ngut = -1, warn = -1, fc = 0, age, rc; 1466 Attribute *a; 1467 time_t now, pwtime = (time_t)-1; 1468 struct lutil_tm now_tm; 1469 struct lutil_timet now_usec; 1470 char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 1471 char nowstr_usec[ LDAP_LUTIL_GENTIME_BUFSIZE+8 ]; 1472 struct berval timestamp, timestamp_usec; 1473 BackendInfo *bi = op->o_bd->bd_info; 1474 LDAPControl *ctrl = NULL; 1475 Entry *e; 1476 1477 ldap_pvt_thread_mutex_lock( &pi->pwdFailureTime_mutex ); 1478 /* If we already know it's locked, just get on with it */ 1479 if ( ppb->pErr != PP_noError ) { 1480 goto locked; 1481 } 1482 1483 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1484 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 1485 op->o_bd->bd_info = bi; 1486 1487 if ( rc != LDAP_SUCCESS ) { 1488 ldap_pvt_thread_mutex_unlock( &pi->pwdFailureTime_mutex ); 1489 return SLAP_CB_CONTINUE; 1490 } 1491 1492 /* ITS#7089 Skip lockout checks/modifications if password attribute missing */ 1493 if ( attr_find( e->e_attrs, ppb->pp.ad ) == NULL ) { 1494 goto done; 1495 } 1496 1497 ldap_pvt_gettime(&now_tm); /* stored for later consideration */ 1498 lutil_tm2time(&now_tm, &now_usec); 1499 now = now_usec.tt_sec; 1500 timestamp.bv_val = nowstr; 1501 timestamp.bv_len = sizeof(nowstr); 1502 slap_timestamp( &now, ×tamp ); 1503 1504 /* Separate timestamp for pwdFailureTime with microsecond granularity */ 1505 strcpy(nowstr_usec, nowstr); 1506 timestamp_usec.bv_val = nowstr_usec; 1507 timestamp_usec.bv_len = timestamp.bv_len; 1508 snprintf( timestamp_usec.bv_val + timestamp_usec.bv_len-1, sizeof(".123456Z"), ".%06dZ", now_usec.tt_nsec / 1000 ); 1509 timestamp_usec.bv_len += STRLENOF(".123456"); 1510 1511 if ( rs->sr_err == LDAP_INVALID_CREDENTIALS && ppb->pp.pwdMaxRecordedFailure ) { 1512 int i = 0; 1513 1514 m = ch_calloc( sizeof(Modifications), 1 ); 1515 m->sml_op = LDAP_MOD_ADD; 1516 m->sml_flags = 0; 1517 m->sml_type = ad_pwdFailureTime->ad_cname; 1518 m->sml_desc = ad_pwdFailureTime; 1519 m->sml_numvals = 1; 1520 m->sml_values = ch_calloc( sizeof(struct berval), 2 ); 1521 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); 1522 1523 ber_dupbv( &m->sml_values[0], ×tamp_usec ); 1524 ber_dupbv( &m->sml_nvalues[0], ×tamp_usec ); 1525 m->sml_next = mod; 1526 mod = m; 1527 1528 /* 1529 * Count the pwdFailureTimes - if it's 1530 * greater than the policy pwdMaxFailure, 1531 * then lock the account. 1532 */ 1533 if ((a = attr_find( e->e_attrs, ad_pwdFailureTime )) != NULL) { 1534 for(i=0; a->a_nvals[i].bv_val; i++) { 1535 1536 /* 1537 * If the interval is 0, then failures 1538 * stay on the record until explicitly 1539 * reset by successful authentication. 1540 */ 1541 if (ppb->pp.pwdFailureCountInterval == 0) { 1542 fc++; 1543 } else if (now <= 1544 parse_time(a->a_nvals[i].bv_val) + 1545 ppb->pp.pwdFailureCountInterval) { 1546 1547 fc++; 1548 } 1549 /* 1550 * We only count those failures 1551 * which are not due to expire. 1552 */ 1553 } 1554 /* Do we have too many timestamps? If so, delete some values. 1555 * We don't bother to sort the values here. OpenLDAP keeps the 1556 * values in order by default. Fundamentally, relying on the 1557 * information here is wrong anyway; monitoring systems should 1558 * be tracking Bind failures in syslog, not here. 1559 */ 1560 if (a->a_numvals >= ppb->pp.pwdMaxRecordedFailure) { 1561 int j = ppb->pp.pwdMaxRecordedFailure-1; 1562 /* If more than 2x, cheaper to perform a Replace */ 1563 if (a->a_numvals >= 2 * ppb->pp.pwdMaxRecordedFailure) { 1564 struct berval v, nv; 1565 1566 /* Change the mod we constructed above */ 1567 m->sml_op = LDAP_MOD_REPLACE; 1568 m->sml_numvals = ppb->pp.pwdMaxRecordedFailure; 1569 v = m->sml_values[0]; 1570 nv = m->sml_nvalues[0]; 1571 ch_free(m->sml_values); 1572 ch_free(m->sml_nvalues); 1573 m->sml_values = ch_calloc( sizeof(struct berval), ppb->pp.pwdMaxRecordedFailure+1 ); 1574 m->sml_nvalues = ch_calloc( sizeof(struct berval), ppb->pp.pwdMaxRecordedFailure+1 ); 1575 for (i=0; i<j; i++) { 1576 ber_dupbv(&m->sml_values[i], &a->a_vals[a->a_numvals-j+i]); 1577 ber_dupbv(&m->sml_nvalues[i], &a->a_nvals[a->a_numvals-j+i]); 1578 } 1579 m->sml_values[i] = v; 1580 m->sml_nvalues[i] = nv; 1581 } else { 1582 /* else just delete some */ 1583 m = ch_calloc( sizeof(Modifications), 1 ); 1584 m->sml_op = LDAP_MOD_DELETE; 1585 m->sml_type = ad_pwdFailureTime->ad_cname; 1586 m->sml_desc = ad_pwdFailureTime; 1587 m->sml_numvals = a->a_numvals - j; 1588 m->sml_values = ch_calloc( sizeof(struct berval), m->sml_numvals+1 ); 1589 m->sml_nvalues = ch_calloc( sizeof(struct berval), m->sml_numvals+1 ); 1590 for (i=0; i<m->sml_numvals; i++) { 1591 ber_dupbv(&m->sml_values[i], &a->a_vals[i]); 1592 ber_dupbv(&m->sml_nvalues[i], &a->a_nvals[i]); 1593 } 1594 m->sml_next = mod; 1595 mod = m; 1596 } 1597 } 1598 } 1599 1600 if ((ppb->pp.pwdMaxFailure > 0) && 1601 (fc >= ppb->pp.pwdMaxFailure - 1)) { 1602 1603 /* 1604 * We subtract 1 from the failure max 1605 * because the new failure entry hasn't 1606 * made it to the entry yet. 1607 */ 1608 m = ch_calloc( sizeof(Modifications), 1 ); 1609 m->sml_op = LDAP_MOD_REPLACE; 1610 m->sml_flags = 0; 1611 m->sml_type = ad_pwdAccountLockedTime->ad_cname; 1612 m->sml_desc = ad_pwdAccountLockedTime; 1613 m->sml_numvals = 1; 1614 m->sml_values = ch_calloc( sizeof(struct berval), 2 ); 1615 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); 1616 ber_dupbv( &m->sml_values[0], ×tamp ); 1617 ber_dupbv( &m->sml_nvalues[0], ×tamp ); 1618 m->sml_next = mod; 1619 mod = m; 1620 } else if ( ppb->pp.pwdMinDelay ) { 1621 int waittime = ppb->pp.pwdMinDelay << fc; 1622 time_t wait_end; 1623 struct berval lockout_stamp; 1624 1625 if ( waittime > ppb->pp.pwdMaxDelay ) { 1626 waittime = ppb->pp.pwdMaxDelay; 1627 } 1628 wait_end = now + waittime; 1629 1630 slap_timestamp( &wait_end, &lockout_stamp ); 1631 1632 m = ch_calloc( sizeof(Modifications), 1 ); 1633 m->sml_op = LDAP_MOD_REPLACE; 1634 m->sml_flags = 0; 1635 m->sml_type = ad_pwdAccountTmpLockoutEnd->ad_cname; 1636 m->sml_desc = ad_pwdAccountTmpLockoutEnd; 1637 m->sml_numvals = 1; 1638 m->sml_values = ch_calloc( sizeof(struct berval), 2 ); 1639 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); 1640 ber_dupbv( &m->sml_values[0], &lockout_stamp ); 1641 ber_dupbv( &m->sml_nvalues[0], &lockout_stamp ); 1642 m->sml_next = mod; 1643 mod = m; 1644 } 1645 } else if ( rs->sr_err == LDAP_SUCCESS ) { 1646 if ((a = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL) 1647 pwtime = parse_time( a->a_nvals[0].bv_val ); 1648 1649 /* delete all pwdFailureTimes */ 1650 if ( attr_find( e->e_attrs, ad_pwdFailureTime )) { 1651 m = ch_calloc( sizeof(Modifications), 1 ); 1652 m->sml_op = LDAP_MOD_DELETE; 1653 m->sml_flags = 0; 1654 m->sml_type = ad_pwdFailureTime->ad_cname; 1655 m->sml_desc = ad_pwdFailureTime; 1656 m->sml_next = mod; 1657 mod = m; 1658 } 1659 1660 /* 1661 * check to see if the password must be changed 1662 */ 1663 if ( ppb->pp.pwdMustChange && 1664 (a = attr_find( e->e_attrs, ad_pwdReset )) && 1665 bvmatch( &a->a_nvals[0], &slap_true_bv ) ) 1666 { 1667 /* 1668 * need to inject client controls here to give 1669 * more information. For the moment, we ensure 1670 * that we are disallowed from doing anything 1671 * other than change password. 1672 */ 1673 if ( ppb->set_restrict ) { 1674 ber_dupbv( &pwcons[op->o_conn->c_conn_idx].dn, 1675 &op->o_conn->c_ndn ); 1676 } 1677 1678 ppb->pErr = PP_changeAfterReset; 1679 1680 } else { 1681 /* 1682 * the password does not need to be changed, so 1683 * we now check whether the password has expired. 1684 * 1685 * We can skip this bit if passwords don't age in 1686 * the policy. Also, if there was no pwdChangedTime 1687 * attribute in the entry, the password never expires. 1688 */ 1689 if (ppb->pp.pwdMaxAge == 0) goto grace; 1690 1691 if (pwtime != (time_t)-1) { 1692 /* 1693 * Check: was the last change time of 1694 * the password older than the maximum age 1695 * allowed. (Ignore case 2 from I-D, it's just silly.) 1696 */ 1697 if (now - pwtime > ppb->pp.pwdMaxAge ) pwExpired = 1; 1698 } 1699 } 1700 1701 grace: 1702 if (!pwExpired) goto check_expiring_password; 1703 1704 if ( ppb->pp.pwdGraceExpiry && 1705 now - pwtime > ppb->pp.pwdMaxAge + ppb->pp.pwdGraceExpiry ) { 1706 /* Grace logins have expired now */ 1707 ngut = 0; 1708 } else if ((a = attr_find( e->e_attrs, ad_pwdGraceUseTime )) == NULL) { 1709 ngut = ppb->pp.pwdGraceAuthNLimit; 1710 } else { 1711 for(ngut=0; a->a_nvals[ngut].bv_val; ngut++); 1712 ngut = ppb->pp.pwdGraceAuthNLimit - ngut; 1713 } 1714 1715 /* 1716 * ngut is the number of remaining grace logins 1717 */ 1718 Debug( LDAP_DEBUG_ANY, 1719 "ppolicy_bind: Entry %s has an expired password: %d grace logins\n", 1720 e->e_name.bv_val, ngut ); 1721 1722 ngut--; 1723 1724 if (ngut < 0) { 1725 ppb->pErr = PP_passwordExpired; 1726 rs->sr_err = LDAP_INVALID_CREDENTIALS; 1727 goto done; 1728 } 1729 1730 /* 1731 * Add a grace user time to the entry 1732 */ 1733 m = ch_calloc( sizeof(Modifications), 1 ); 1734 m->sml_op = LDAP_MOD_ADD; 1735 m->sml_flags = 0; 1736 m->sml_type = ad_pwdGraceUseTime->ad_cname; 1737 m->sml_desc = ad_pwdGraceUseTime; 1738 m->sml_numvals = 1; 1739 m->sml_values = ch_calloc( sizeof(struct berval), 2 ); 1740 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 ); 1741 ber_dupbv( &m->sml_values[0], ×tamp_usec ); 1742 ber_dupbv( &m->sml_nvalues[0], ×tamp_usec ); 1743 m->sml_next = mod; 1744 mod = m; 1745 1746 check_expiring_password: 1747 /* 1748 * Now we need to check to see 1749 * if it is about to expire, and if so, should the user 1750 * be warned about it in the password policy control. 1751 * 1752 * If the password has expired, and we're in the grace period, then 1753 * we don't need to do this bit. Similarly, if we don't have password 1754 * aging, then there's no need to do this bit either. 1755 */ 1756 if ((ppb->pp.pwdMaxAge < 1) || (pwExpired) || (ppb->pp.pwdExpireWarning < 1)) 1757 goto done; 1758 1759 age = (int)(now - pwtime); 1760 1761 /* 1762 * We know that there is a password Change Time attribute - if 1763 * there wasn't, then the pwdExpired value would be true, unless 1764 * there is no password aging - and if there is no password aging, 1765 * then this section isn't called anyway - you can't have an 1766 * expiring password if there's no limit to expire. 1767 */ 1768 if (ppb->pp.pwdMaxAge - age < ppb->pp.pwdExpireWarning ) { 1769 /* 1770 * Set the warning value. 1771 */ 1772 warn = ppb->pp.pwdMaxAge - age; /* seconds left until expiry */ 1773 if (warn < 0) warn = 0; /* something weird here - why is pwExpired not set? */ 1774 1775 Debug( LDAP_DEBUG_ANY, 1776 "ppolicy_bind: Setting warning for password expiry for %s = %d seconds\n", 1777 op->o_req_dn.bv_val, warn ); 1778 } 1779 } 1780 1781 done: 1782 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1783 be_entry_release_r( op, e ); 1784 1785 locked: 1786 if ( mod && !pi->disable_write ) { 1787 Operation op2 = *op; 1788 SlapReply r2 = { REP_RESULT }; 1789 slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; 1790 LDAPControl c, *ca[2]; 1791 1792 op2.o_tag = LDAP_REQ_MODIFY; 1793 op2.o_callback = &cb; 1794 op2.orm_modlist = mod; 1795 op2.orm_no_opattrs = 0; 1796 op2.o_dn = op->o_bd->be_rootdn; 1797 op2.o_ndn = op->o_bd->be_rootndn; 1798 1799 /* If this server is a shadow and forward_updates is true, 1800 * use the frontend to perform this modify. That will trigger 1801 * the update referral, which can then be forwarded by the 1802 * chain overlay. Obviously the updateref and chain overlay 1803 * must be configured appropriately for this to be useful. 1804 */ 1805 if ( SLAP_SHADOW( op->o_bd ) && pi->forward_updates ) { 1806 op2.o_bd = frontendDB; 1807 1808 /* Must use Relax control since these are no-user-mod */ 1809 op2.o_relax = SLAP_CONTROL_CRITICAL; 1810 op2.o_ctrls = ca; 1811 ca[0] = &c; 1812 ca[1] = NULL; 1813 BER_BVZERO( &c.ldctl_value ); 1814 c.ldctl_iscritical = 1; 1815 c.ldctl_oid = LDAP_CONTROL_RELAX; 1816 } else { 1817 /* If not forwarding, don't update opattrs and don't replicate */ 1818 if ( SLAP_SINGLE_SHADOW( op->o_bd )) { 1819 op2.orm_no_opattrs = 1; 1820 op2.o_dont_replicate = 1; 1821 } 1822 op2.o_bd->bd_info = (BackendInfo *)on->on_info; 1823 } 1824 rc = op2.o_bd->be_modify( &op2, &r2 ); 1825 if ( rc != LDAP_SUCCESS ) { 1826 Debug( LDAP_DEBUG_ANY, "%s ppolicy_bind_response: " 1827 "ppolicy state change failed with rc=%d text=%s\n", 1828 op->o_log_prefix, rc, r2.sr_text ); 1829 } 1830 } 1831 if ( mod ) { 1832 slap_mods_free( mod, 1 ); 1833 } 1834 1835 if ( ppb->send_ctrl ) { 1836 1837 /* Do we really want to tell that the account is locked? */ 1838 if ( ppb->pErr == PP_accountLocked && !pi->use_lockout ) { 1839 ppb->pErr = PP_noError; 1840 } 1841 ctrl = create_passcontrol( op, warn, ngut, ppb->pErr ); 1842 } else if ( pi->send_netscape_controls ) { 1843 if ( ppb->pErr != PP_noError || pwExpired ) { 1844 ctrl = create_passexpiry( op, 1, 0 ); 1845 } else if ( warn > 0 ) { 1846 ctrl = create_passexpiry( op, 0, warn ); 1847 } 1848 } 1849 if ( ctrl ) { 1850 ppb->oldctrls = add_passcontrol( op, rs, ctrl ); 1851 op->o_callback->sc_cleanup = ppolicy_ctrls_cleanup; 1852 } 1853 op->o_bd->bd_info = bi; 1854 ldap_pvt_thread_mutex_unlock( &pi->pwdFailureTime_mutex ); 1855 return SLAP_CB_CONTINUE; 1856 } 1857 1858 static int 1859 ppolicy_bind( Operation *op, SlapReply *rs ) 1860 { 1861 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1862 1863 /* Reset lockout status on all Bind requests */ 1864 if ( !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { 1865 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 1866 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 1867 } 1868 1869 /* Root bypasses policy */ 1870 if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn )) { 1871 Entry *e; 1872 int rc; 1873 ppbind *ppb; 1874 slap_callback *cb; 1875 1876 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1877 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 1878 1879 if ( rc != LDAP_SUCCESS ) { 1880 return SLAP_CB_CONTINUE; 1881 } 1882 1883 cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback), 1884 1, op->o_tmpmemctx ); 1885 ppb = (ppbind *)(cb+1); 1886 ppb->on = on; 1887 ppb->pErr = PP_noError; 1888 ppb->set_restrict = 1; 1889 1890 /* Setup a callback so we can munge the result */ 1891 1892 cb->sc_response = ppolicy_bind_response; 1893 cb->sc_private = ppb; 1894 overlay_callback_after_backover( op, cb, 1 ); 1895 1896 /* Did we receive a password policy request control? */ 1897 if ( op->o_ctrlflag[ppolicy_cid] ) { 1898 ppb->send_ctrl = 1; 1899 } 1900 1901 op->o_bd->bd_info = (BackendInfo *)on; 1902 1903 if ( ppolicy_get( op, e, &ppb->pp ) == LDAP_SUCCESS ) { 1904 rc = account_locked( op, e, &ppb->pp, &ppb->mod ); 1905 } 1906 1907 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1908 be_entry_release_r( op, e ); 1909 1910 if ( rc ) { 1911 ppb->pErr = PP_accountLocked; 1912 send_ldap_error( op, rs, LDAP_INVALID_CREDENTIALS, NULL ); 1913 return rs->sr_err; 1914 } 1915 1916 } 1917 1918 return SLAP_CB_CONTINUE; 1919 } 1920 1921 /* Reset the restricted info for the next session on this connection */ 1922 static int 1923 ppolicy_connection_destroy( BackendDB *bd, Connection *conn ) 1924 { 1925 if ( pwcons && !BER_BVISEMPTY( &pwcons[conn->c_conn_idx].dn )) { 1926 ch_free( pwcons[conn->c_conn_idx].dn.bv_val ); 1927 BER_BVZERO( &pwcons[conn->c_conn_idx].dn ); 1928 } 1929 return SLAP_CB_CONTINUE; 1930 } 1931 1932 /* Check if this connection is restricted */ 1933 static int 1934 ppolicy_restrict( 1935 Operation *op, 1936 SlapReply *rs ) 1937 { 1938 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1939 int send_ctrl = 0; 1940 1941 /* Did we receive a password policy request control? */ 1942 if ( op->o_ctrlflag[ppolicy_cid] ) { 1943 send_ctrl = 1; 1944 } 1945 1946 if ( op->o_conn && !BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { 1947 LDAPControl **oldctrls; 1948 /* if the current authcDN doesn't match the one we recorded, 1949 * then an intervening Bind has succeeded and the restriction 1950 * no longer applies. (ITS#4516) 1951 */ 1952 if ( !dn_match( &op->o_conn->c_ndn, 1953 &pwcons[op->o_conn->c_conn_idx].dn )) { 1954 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 1955 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 1956 return SLAP_CB_CONTINUE; 1957 } 1958 1959 Debug( LDAP_DEBUG_TRACE, 1960 "connection restricted to password changing only\n" ); 1961 if ( send_ctrl ) { 1962 LDAPControl *ctrl = NULL; 1963 ctrl = create_passcontrol( op, -1, -1, PP_changeAfterReset ); 1964 oldctrls = add_passcontrol( op, rs, ctrl ); 1965 } 1966 op->o_bd->bd_info = (BackendInfo *)on->on_info; 1967 send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS, 1968 "Operations are restricted to bind/unbind/abandon/StartTLS/modify password" ); 1969 if ( send_ctrl ) { 1970 ctrls_cleanup( op, rs, oldctrls ); 1971 } 1972 return rs->sr_err; 1973 } 1974 1975 return SLAP_CB_CONTINUE; 1976 } 1977 1978 static int 1979 ppolicy_account_usability_entry_cb( Operation *op, SlapReply *rs ) 1980 { 1981 slap_overinst *on = op->o_callback->sc_private; 1982 BackendInfo *bi = op->o_bd->bd_info; 1983 LDAPControl *ctrl = NULL; 1984 PassPolicy pp; 1985 Attribute *a; 1986 Entry *e = NULL; 1987 time_t pwtime = 0, seconds_until_expiry = -1, now = op->o_time; 1988 int isExpired = 0, grace = -1; 1989 1990 if ( rs->sr_type != REP_SEARCH ) { 1991 return SLAP_CB_CONTINUE; 1992 } 1993 1994 if ( be_entry_get_rw( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &e ) != LDAP_SUCCESS ) { 1995 goto done; 1996 } 1997 1998 op->o_bd->bd_info = (BackendInfo *)on; 1999 2000 if ( ppolicy_get( op, e, &pp ) != LDAP_SUCCESS ) { 2001 /* TODO: If there is no policy, should we check if */ 2002 goto done; 2003 } 2004 2005 if ( !access_allowed( op, e, pp.ad, NULL, ACL_COMPARE, NULL ) ) { 2006 goto done; 2007 } 2008 2009 if ( attr_find( e->e_attrs, pp.ad ) == NULL ) { 2010 goto done; 2011 } 2012 2013 if ((a = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL) { 2014 pwtime = parse_time( a->a_nvals[0].bv_val ); 2015 } 2016 2017 if ( pp.pwdMaxAge && pwtime ) { 2018 seconds_until_expiry = pwtime + pp.pwdMaxAge - now; 2019 if ( seconds_until_expiry <= 0 ) isExpired = 1; 2020 if ( pp.pwdGraceAuthNLimit ) { 2021 if ( !pp.pwdGraceExpiry || seconds_until_expiry + pp.pwdGraceExpiry > 0 ) { 2022 grace = pp.pwdGraceAuthNLimit; 2023 if ( attr_find( e->e_attrs, ad_pwdGraceUseTime ) ) { 2024 grace -= a->a_numvals; 2025 } 2026 } 2027 } 2028 } 2029 if ( !isExpired && pp.pwdMaxIdle && (a = attr_find( e->e_attrs, ad_pwdLastSuccess )) ) { 2030 time_t lastbindtime = pwtime; 2031 2032 if ( (a = attr_find( e->e_attrs, ad_pwdLastSuccess )) != NULL ) { 2033 lastbindtime = parse_time( a->a_nvals[0].bv_val ); 2034 } 2035 2036 if ( lastbindtime ) { 2037 int remaining_idle = lastbindtime + pp.pwdMaxIdle - now; 2038 if ( remaining_idle <= 0 ) { 2039 isExpired = 1; 2040 } else if ( seconds_until_expiry == -1 || remaining_idle < seconds_until_expiry ) { 2041 seconds_until_expiry = remaining_idle; 2042 } 2043 } 2044 } 2045 2046 if ( isExpired || account_locked( op, e, &pp, NULL ) ) { 2047 LDAPAccountUsabilityMoreInfo more_info = { 0, 0, 0, -1, -1 }; 2048 time_t then, lockoutEnd = 0; 2049 2050 if ( isExpired ) more_info.remaining_grace = grace; 2051 2052 if ( (a = attr_find( e->e_attrs, ad_pwdAccountLockedTime )) != NULL ) { 2053 then = parse_time( a->a_vals[0].bv_val ); 2054 if ( then == 0 ) 2055 lockoutEnd = -1; 2056 2057 /* Still in the future? not yet in effect */ 2058 if ( now < then ) 2059 then = 0; 2060 2061 if ( !pp.pwdLockoutDuration ) 2062 lockoutEnd = -1; 2063 2064 if ( now < then + pp.pwdLockoutDuration ) 2065 lockoutEnd = then + pp.pwdLockoutDuration; 2066 } 2067 2068 if ( (a = attr_find( e->e_attrs, ad_pwdAccountTmpLockoutEnd )) != NULL ) { 2069 then = parse_time( a->a_vals[0].bv_val ); 2070 if ( lockoutEnd != -1 && then > lockoutEnd ) 2071 lockoutEnd = then; 2072 } 2073 2074 if ( lockoutEnd > now ) { 2075 more_info.inactive = 1; 2076 more_info.seconds_before_unlock = lockoutEnd - now; 2077 } 2078 2079 if ( pp.pwdMustChange && 2080 (a = attr_find( e->e_attrs, ad_pwdReset )) && 2081 bvmatch( &a->a_nvals[0], &slap_true_bv ) ) 2082 { 2083 more_info.reset = 1; 2084 } 2085 2086 add_account_control( op, rs, 0, -1, &more_info ); 2087 } else { 2088 add_account_control( op, rs, 1, seconds_until_expiry, NULL ); 2089 } 2090 2091 done: 2092 op->o_bd->bd_info = bi; 2093 if ( e ) { 2094 be_entry_release_r( op, e ); 2095 } 2096 return SLAP_CB_CONTINUE; 2097 } 2098 2099 static int 2100 ppolicy_search( 2101 Operation *op, 2102 SlapReply *rs ) 2103 { 2104 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2105 int rc = ppolicy_restrict( op, rs ); 2106 2107 if ( rc != SLAP_CB_CONTINUE ) { 2108 return rc; 2109 } 2110 2111 if ( op->o_ctrlflag[account_usability_cid] ) { 2112 slap_callback *cb; 2113 2114 cb = op->o_tmpcalloc( sizeof(slap_callback), 1, op->o_tmpmemctx ); 2115 2116 cb->sc_response = ppolicy_account_usability_entry_cb; 2117 cb->sc_private = on; 2118 overlay_callback_after_backover( op, cb, 1 ); 2119 } 2120 2121 return SLAP_CB_CONTINUE; 2122 } 2123 2124 static int 2125 ppolicy_compare_response( 2126 Operation *op, 2127 SlapReply *rs ) 2128 { 2129 /* map compare responses to bind responses */ 2130 if ( rs->sr_err == LDAP_COMPARE_TRUE ) 2131 rs->sr_err = LDAP_SUCCESS; 2132 else if ( rs->sr_err == LDAP_COMPARE_FALSE ) 2133 rs->sr_err = LDAP_INVALID_CREDENTIALS; 2134 2135 ppolicy_bind_response( op, rs ); 2136 2137 /* map back to compare */ 2138 if ( rs->sr_err == LDAP_SUCCESS ) 2139 rs->sr_err = LDAP_COMPARE_TRUE; 2140 else if ( rs->sr_err == LDAP_INVALID_CREDENTIALS ) 2141 rs->sr_err = LDAP_COMPARE_FALSE; 2142 2143 return SLAP_CB_CONTINUE; 2144 } 2145 2146 static int 2147 ppolicy_compare( 2148 Operation *op, 2149 SlapReply *rs ) 2150 { 2151 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2152 2153 if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE ) 2154 return rs->sr_err; 2155 2156 /* Did we receive a password policy request control? 2157 * Are we testing the userPassword? 2158 */ 2159 if ( op->o_ctrlflag[ppolicy_cid] && 2160 op->orc_ava->aa_desc == slap_schema.si_ad_userPassword ) { 2161 Entry *e; 2162 int rc; 2163 ppbind *ppb; 2164 slap_callback *cb; 2165 2166 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2167 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 2168 2169 if ( rc != LDAP_SUCCESS ) { 2170 return SLAP_CB_CONTINUE; 2171 } 2172 2173 cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback), 2174 1, op->o_tmpmemctx ); 2175 ppb = (ppbind *)(cb+1); 2176 ppb->on = on; 2177 ppb->pErr = PP_noError; 2178 ppb->send_ctrl = 1; 2179 /* failures here don't lockout the connection */ 2180 ppb->set_restrict = 0; 2181 2182 /* Setup a callback so we can munge the result */ 2183 2184 cb->sc_response = ppolicy_compare_response; 2185 cb->sc_private = ppb; 2186 overlay_callback_after_backover( op, cb, 1 ); 2187 2188 op->o_bd->bd_info = (BackendInfo *)on; 2189 2190 if ( ppolicy_get( op, e, &ppb->pp ) == LDAP_SUCCESS ) { 2191 rc = account_locked( op, e, &ppb->pp, &ppb->mod ); 2192 } 2193 2194 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2195 be_entry_release_r( op, e ); 2196 2197 if ( rc ) { 2198 ppb->pErr = PP_accountLocked; 2199 send_ldap_error( op, rs, LDAP_COMPARE_FALSE, NULL ); 2200 return rs->sr_err; 2201 } 2202 } 2203 return SLAP_CB_CONTINUE; 2204 } 2205 2206 static int 2207 ppolicy_add( 2208 Operation *op, 2209 SlapReply *rs ) 2210 { 2211 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2212 pp_info *pi = on->on_bi.bi_private; 2213 PassPolicy pp; 2214 Attribute *pa; 2215 const char *txt; 2216 2217 if ( ppolicy_restrict( op, rs ) != SLAP_CB_CONTINUE ) 2218 return rs->sr_err; 2219 2220 /* If this is a replica, assume the provider checked everything */ 2221 if ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) ) 2222 return SLAP_CB_CONTINUE; 2223 2224 /* Check for password in entry */ 2225 if ((pa = attr_find( op->oq_add.rs_e->e_attrs, 2226 slap_schema.si_ad_userPassword ))) 2227 { 2228 assert( pa->a_vals != NULL ); 2229 assert( !BER_BVISNULL( &pa->a_vals[ 0 ] ) ); 2230 2231 if ( !BER_BVISNULL( &pa->a_vals[ 1 ] ) ) { 2232 send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, "Password policy only allows one password value" ); 2233 return rs->sr_err; 2234 } 2235 2236 ppolicy_get( op, op->ora_e, &pp ); 2237 2238 /* 2239 * new entry contains a password - if we're not the root user 2240 * then we need to check that the password fits in with the 2241 * security policy for the new entry. 2242 */ 2243 2244 if (pp.pwdCheckQuality > 0 && !be_isroot( op )) { 2245 struct berval *bv = &(pa->a_vals[0]); 2246 int rc, send_ctrl = 0; 2247 LDAPPasswordPolicyError pErr = PP_noError; 2248 char *txt; 2249 2250 /* Did we receive a password policy request control? */ 2251 if ( op->o_ctrlflag[ppolicy_cid] ) { 2252 send_ctrl = 1; 2253 } 2254 rc = check_password_quality( bv, &pp, &pErr, op->ora_e, &txt ); 2255 if (rc != LDAP_SUCCESS) { 2256 LDAPControl **oldctrls = NULL; 2257 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2258 if ( send_ctrl ) { 2259 LDAPControl *ctrl = NULL; 2260 ctrl = create_passcontrol( op, -1, -1, pErr ); 2261 oldctrls = add_passcontrol( op, rs, ctrl ); 2262 } 2263 send_ldap_error( op, rs, rc, txt ? txt : "Password fails quality checking policy" ); 2264 if ( txt ) { 2265 free( txt ); 2266 } 2267 if ( send_ctrl ) { 2268 ctrls_cleanup( op, rs, oldctrls ); 2269 } 2270 return rs->sr_err; 2271 } 2272 } 2273 /* 2274 * A controversial bit. We hash cleartext 2275 * passwords provided via add and modify operations 2276 * You're not really supposed to do this, since 2277 * the X.500 model says "store attributes" as they 2278 * get provided. By default, this is what we do 2279 * 2280 * But if the hash_passwords flag is set, we hash 2281 * any cleartext password attribute values via the 2282 * default password hashing scheme. 2283 */ 2284 if ((pi->hash_passwords) && 2285 (password_scheme( &(pa->a_vals[0]), NULL ) != LDAP_SUCCESS)) { 2286 struct berval hpw; 2287 2288 slap_passwd_hash( &(pa->a_vals[0]), &hpw, &txt ); 2289 if (hpw.bv_val == NULL) { 2290 /* 2291 * hashing didn't work. Emit an error. 2292 */ 2293 rs->sr_err = LDAP_OTHER; 2294 rs->sr_text = txt; 2295 send_ldap_error( op, rs, LDAP_OTHER, "Password hashing failed" ); 2296 return rs->sr_err; 2297 } 2298 2299 memset( pa->a_vals[0].bv_val, 0, pa->a_vals[0].bv_len); 2300 ber_memfree( pa->a_vals[0].bv_val ); 2301 pa->a_vals[0].bv_val = hpw.bv_val; 2302 pa->a_vals[0].bv_len = hpw.bv_len; 2303 } 2304 2305 /* If password aging is in effect, set the pwdChangedTime */ 2306 if ( pp.pwdMaxAge || pp.pwdMinAge ) { 2307 struct berval timestamp; 2308 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 2309 time_t now = slap_get_time(); 2310 2311 timestamp.bv_val = timebuf; 2312 timestamp.bv_len = sizeof(timebuf); 2313 slap_timestamp( &now, ×tamp ); 2314 2315 attr_merge_one( op->ora_e, ad_pwdChangedTime, ×tamp, ×tamp ); 2316 } 2317 } 2318 return SLAP_CB_CONTINUE; 2319 } 2320 2321 static int 2322 ppolicy_mod_cb( Operation *op, SlapReply *rs ) 2323 { 2324 slap_callback *sc = op->o_callback; 2325 op->o_callback = sc->sc_next; 2326 if ( rs->sr_err == LDAP_SUCCESS ) { 2327 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 2328 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 2329 } 2330 op->o_tmpfree( sc, op->o_tmpmemctx ); 2331 return SLAP_CB_CONTINUE; 2332 } 2333 2334 static int 2335 ppolicy_text_cleanup( Operation *op, SlapReply *rs ) 2336 { 2337 slap_callback *sc = op->o_callback; 2338 2339 if ( rs->sr_text == sc->sc_private ) { 2340 rs->sr_text = NULL; 2341 } 2342 free( sc->sc_private ); 2343 2344 op->o_callback = sc->sc_next; 2345 op->o_tmpfree( sc, op->o_tmpmemctx ); 2346 return SLAP_CB_CONTINUE; 2347 } 2348 2349 static int 2350 ppolicy_modify( Operation *op, SlapReply *rs ) 2351 { 2352 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2353 pp_info *pi = on->on_bi.bi_private; 2354 int i, rc, mod_pw_only, pwmod = 0, pwmop = -1, deladd, 2355 hsize = 0, hskip; 2356 PassPolicy pp; 2357 Modifications *mods = NULL, *modtail = NULL, 2358 *ml, *delmod, *addmod; 2359 Attribute *pa, *ha, at; 2360 const char *txt; 2361 pw_hist *tl = NULL, *p; 2362 int zapReset, send_ctrl = 0, free_txt = 0; 2363 Entry *e; 2364 struct berval newpw = BER_BVNULL, oldpw = BER_BVNULL, 2365 *bv, cr[2]; 2366 LDAPPasswordPolicyError pErr = PP_noError; 2367 LDAPControl *ctrl = NULL; 2368 LDAPControl **oldctrls = NULL; 2369 int is_pwdexop = 0, is_pwdadmin = 0; 2370 int got_del_grace = 0, got_del_lock = 0, got_pw = 0, got_del_fail = 0, 2371 got_del_success = 0; 2372 int got_changed = 0, got_history = 0; 2373 int have_policy = 0; 2374 2375 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2376 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e ); 2377 op->o_bd->bd_info = (BackendInfo *)on; 2378 2379 if ( rc != LDAP_SUCCESS ) return SLAP_CB_CONTINUE; 2380 if ( pi->disable_write ) return SLAP_CB_CONTINUE; 2381 2382 /* If this is a replica, we may need to tweak some of the 2383 * provider's modifications. Otherwise, just pass it through. 2384 */ 2385 if ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) ) { 2386 Modifications **prev; 2387 Attribute *a_grace, *a_lock, *a_fail, *a_success; 2388 2389 a_grace = attr_find( e->e_attrs, ad_pwdGraceUseTime ); 2390 a_lock = attr_find( e->e_attrs, ad_pwdAccountLockedTime ); 2391 a_fail = attr_find( e->e_attrs, ad_pwdFailureTime ); 2392 a_success = attr_find( e->e_attrs, ad_pwdLastSuccess ); 2393 2394 for( prev = &op->orm_modlist, ml = *prev; ml; ml = *prev ) { 2395 2396 if ( ml->sml_desc == slap_schema.si_ad_userPassword ) 2397 got_pw = 1; 2398 2399 /* If we're deleting an attr that didn't exist, 2400 * drop this delete op 2401 */ 2402 if ( ml->sml_op == LDAP_MOD_DELETE || 2403 ml->sml_op == SLAP_MOD_SOFTDEL ) { 2404 int drop = 0; 2405 2406 if ( ml->sml_desc == ad_pwdGraceUseTime ) { 2407 if ( !a_grace || got_del_grace ) { 2408 drop = ml->sml_op == LDAP_MOD_DELETE; 2409 } else { 2410 got_del_grace = 1; 2411 } 2412 } else 2413 if ( ml->sml_desc == ad_pwdAccountLockedTime ) { 2414 if ( !a_lock || got_del_lock ) { 2415 drop = ml->sml_op == LDAP_MOD_DELETE; 2416 } else { 2417 got_del_lock = 1; 2418 } 2419 } else 2420 if ( ml->sml_desc == ad_pwdFailureTime ) { 2421 if ( !a_fail || got_del_fail ) { 2422 drop = ml->sml_op == LDAP_MOD_DELETE; 2423 } else { 2424 got_del_fail = 1; 2425 } 2426 } 2427 if ( ml->sml_desc == ad_pwdLastSuccess ) { 2428 if ( !a_success || got_del_success ) { 2429 drop = ml->sml_op == LDAP_MOD_DELETE; 2430 } else { 2431 got_del_success = 1; 2432 } 2433 } 2434 if ( drop ) { 2435 *prev = ml->sml_next; 2436 ml->sml_next = NULL; 2437 slap_mods_free( ml, 1 ); 2438 continue; 2439 } 2440 } 2441 prev = &ml->sml_next; 2442 } 2443 2444 /* If we're resetting the password, make sure grace, accountlock, 2445 * success, and failure also get removed. 2446 */ 2447 if ( got_pw ) { 2448 if ( a_grace && !got_del_grace ) { 2449 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 2450 ml->sml_op = LDAP_MOD_DELETE; 2451 ml->sml_flags = SLAP_MOD_INTERNAL; 2452 ml->sml_type.bv_val = NULL; 2453 ml->sml_desc = ad_pwdGraceUseTime; 2454 ml->sml_numvals = 0; 2455 ml->sml_values = NULL; 2456 ml->sml_nvalues = NULL; 2457 ml->sml_next = NULL; 2458 *prev = ml; 2459 prev = &ml->sml_next; 2460 } 2461 if ( a_lock && !got_del_lock ) { 2462 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 2463 ml->sml_op = LDAP_MOD_DELETE; 2464 ml->sml_flags = SLAP_MOD_INTERNAL; 2465 ml->sml_type.bv_val = NULL; 2466 ml->sml_desc = ad_pwdAccountLockedTime; 2467 ml->sml_numvals = 0; 2468 ml->sml_values = NULL; 2469 ml->sml_nvalues = NULL; 2470 ml->sml_next = NULL; 2471 *prev = ml; 2472 } 2473 if ( a_fail && !got_del_fail ) { 2474 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 2475 ml->sml_op = LDAP_MOD_DELETE; 2476 ml->sml_flags = SLAP_MOD_INTERNAL; 2477 ml->sml_type.bv_val = NULL; 2478 ml->sml_desc = ad_pwdFailureTime; 2479 ml->sml_numvals = 0; 2480 ml->sml_values = NULL; 2481 ml->sml_nvalues = NULL; 2482 ml->sml_next = NULL; 2483 *prev = ml; 2484 } 2485 if ( a_success && !got_del_success ) { 2486 ml = (Modifications *) ch_malloc( sizeof( Modifications ) ); 2487 ml->sml_op = LDAP_MOD_DELETE; 2488 ml->sml_flags = SLAP_MOD_INTERNAL; 2489 ml->sml_type.bv_val = NULL; 2490 ml->sml_desc = ad_pwdLastSuccess; 2491 ml->sml_numvals = 0; 2492 ml->sml_values = NULL; 2493 ml->sml_nvalues = NULL; 2494 ml->sml_next = NULL; 2495 *prev = ml; 2496 } 2497 } 2498 op->o_bd->bd_info = (BackendInfo *)on->on_info; 2499 be_entry_release_r( op, e ); 2500 return SLAP_CB_CONTINUE; 2501 } 2502 2503 /* Did we receive a password policy request control? */ 2504 if ( op->o_ctrlflag[ppolicy_cid] ) { 2505 send_ctrl = 1; 2506 } 2507 2508 /* See if this is a pwdModify exop. If so, we can 2509 * access the plaintext passwords from that request. 2510 */ 2511 { 2512 slap_callback *sc; 2513 2514 for ( sc = op->o_callback; sc; sc=sc->sc_next ) { 2515 if ( sc->sc_response == slap_null_cb && 2516 sc->sc_private ) { 2517 req_pwdexop_s *qpw = sc->sc_private; 2518 newpw = qpw->rs_new; 2519 oldpw = qpw->rs_old; 2520 is_pwdexop = 1; 2521 break; 2522 } 2523 } 2524 } 2525 2526 /* ppolicy_hash_cleartext depends on pwmod being determined first */ 2527 if ( ppolicy_get( op, e, &pp ) == LDAP_SUCCESS ) { 2528 have_policy = 1; 2529 } 2530 2531 if ( access_allowed( op, e, pp.ad, NULL, ACL_MANAGE, NULL ) ) { 2532 is_pwdadmin = 1; 2533 } 2534 2535 for ( ml = op->orm_modlist, 2536 pwmod = 0, mod_pw_only = 1, 2537 deladd = 0, delmod = NULL, 2538 addmod = NULL, 2539 zapReset = 1; 2540 ml != NULL; modtail = ml, ml = ml->sml_next ) 2541 { 2542 if ( ml->sml_desc == pp.ad ) { 2543 pwmod = 1; 2544 pwmop = ml->sml_op; 2545 if ((deladd == 0) && (ml->sml_op == LDAP_MOD_DELETE) && 2546 (ml->sml_values) && !BER_BVISNULL( &ml->sml_values[0] )) 2547 { 2548 deladd = 1; 2549 delmod = ml; 2550 } 2551 2552 if ((ml->sml_op == LDAP_MOD_ADD) || 2553 (ml->sml_op == LDAP_MOD_REPLACE)) 2554 { 2555 if ( ml->sml_values && !BER_BVISNULL( &ml->sml_values[0] )) { 2556 if ( deladd == 1 ) 2557 deladd = 2; 2558 2559 /* FIXME: there's no easy way to ensure 2560 * that add does not cause multiple 2561 * userPassword values; one way (that 2562 * would be consistent with the single 2563 * password constraint) would be to turn 2564 * add into replace); another would be 2565 * to disallow add. 2566 * 2567 * Let's check at least that a single value 2568 * is being added 2569 */ 2570 if ( addmod || !BER_BVISNULL( &ml->sml_values[ 1 ] ) ) { 2571 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 2572 rs->sr_text = "Password policy only allows one password value"; 2573 goto return_results; 2574 } 2575 2576 addmod = ml; 2577 } else { 2578 /* replace can have no values, add cannot */ 2579 assert( ml->sml_op == LDAP_MOD_REPLACE ); 2580 } 2581 } 2582 2583 } else if ( !(ml->sml_flags & SLAP_MOD_INTERNAL) && !is_at_operational( ml->sml_desc->ad_type ) ) { 2584 mod_pw_only = 0; 2585 /* modifying something other than password */ 2586 } 2587 2588 /* 2589 * If there is a request to explicitly add a pwdReset 2590 * attribute, then we suppress the normal behaviour on 2591 * password change, which is to remove the pwdReset 2592 * attribute. 2593 * 2594 * This enables an administrator to assign a new password 2595 * and place a "must reset" flag on the entry, which will 2596 * stay until the user explicitly changes his/her password. 2597 */ 2598 if (ml->sml_desc == ad_pwdReset ) { 2599 if ((ml->sml_op == LDAP_MOD_ADD) || 2600 (ml->sml_op == LDAP_MOD_REPLACE)) 2601 zapReset = 0; 2602 } 2603 if ( ml->sml_op == LDAP_MOD_DELETE ) { 2604 if ( ml->sml_desc == ad_pwdGraceUseTime ) { 2605 got_del_grace = 1; 2606 } else if ( ml->sml_desc == ad_pwdAccountLockedTime ) { 2607 got_del_lock = 1; 2608 } else if ( ml->sml_desc == ad_pwdFailureTime ) { 2609 got_del_fail = 1; 2610 } else if ( ml->sml_desc == ad_pwdLastSuccess ) { 2611 got_del_success = 1; 2612 } 2613 } 2614 if ( ml->sml_desc == ad_pwdChangedTime ) { 2615 got_changed = 1; 2616 } else if (ml->sml_desc == ad_pwdHistory ) { 2617 got_history = 1; 2618 } 2619 } 2620 2621 if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn ) && !mod_pw_only ) { 2622 if ( dn_match( &op->o_conn->c_ndn, 2623 &pwcons[op->o_conn->c_conn_idx].dn )) { 2624 Debug( LDAP_DEBUG_TRACE, 2625 "connection restricted to password changing only\n" ); 2626 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 2627 rs->sr_text = "Operations are restricted to bind/unbind/abandon/StartTLS/modify password"; 2628 pErr = PP_changeAfterReset; 2629 goto return_results; 2630 } else { 2631 ch_free( pwcons[op->o_conn->c_conn_idx].dn.bv_val ); 2632 BER_BVZERO( &pwcons[op->o_conn->c_conn_idx].dn ); 2633 } 2634 } 2635 2636 /* 2637 * if we have a "safe password modify policy", then we need to check if we're doing 2638 * a delete (with the old password), followed by an add (with the new password). 2639 * 2640 * If we got just a delete with nothing else, just let it go. We also skip all the checks if 2641 * the root user is bound. Root can do anything, including avoid the policies. 2642 */ 2643 2644 if (!have_policy || !pwmod) goto do_modify; 2645 2646 /* 2647 * Build the password history list in ascending time order 2648 * We need this, even if the user is root, in order to maintain 2649 * the pwdHistory operational attributes properly. 2650 */ 2651 if (addmod && pp.pwdInHistory > 0 && (ha = attr_find( e->e_attrs, ad_pwdHistory ))) { 2652 struct berval oldpw; 2653 time_t oldtime; 2654 2655 for(i=0; ha->a_nvals[i].bv_val; i++) { 2656 rc = parse_pwdhistory( &(ha->a_nvals[i]), NULL, 2657 &oldtime, &oldpw ); 2658 2659 if (rc != LDAP_SUCCESS) continue; /* invalid history entry */ 2660 2661 if (oldpw.bv_val) { 2662 add_to_pwd_history( &tl, oldtime, &oldpw, 2663 &(ha->a_nvals[i]) ); 2664 oldpw.bv_val = NULL; 2665 oldpw.bv_len = 0; 2666 } 2667 } 2668 for(p=tl; p; p=p->next, hsize++); /* count history size */ 2669 } 2670 2671 if (is_pwdadmin) goto do_modify; 2672 2673 /* NOTE: according to draft-behera-ldap-password-policy 2674 * pwdAllowUserChange == FALSE must only prevent pwd changes 2675 * by the user the pwd belongs to (ITS#7021) */ 2676 if (!pp.pwdAllowUserChange && dn_match(&op->o_req_ndn, &op->o_ndn)) { 2677 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 2678 rs->sr_text = "User alteration of password is not allowed"; 2679 pErr = PP_passwordModNotAllowed; 2680 goto return_results; 2681 } 2682 2683 /* Just deleting? */ 2684 if (!addmod) { 2685 /* skip everything else */ 2686 pwmod = 0; 2687 goto do_modify; 2688 } 2689 2690 /* This is a pwdModify exop that provided the old pw. 2691 * We need to create a Delete mod for this old pw and 2692 * let the matching value get found later 2693 */ 2694 if (pp.pwdSafeModify && oldpw.bv_val ) { 2695 ml = (Modifications *)ch_calloc( sizeof( Modifications ), 1 ); 2696 ml->sml_op = LDAP_MOD_DELETE; 2697 ml->sml_flags = SLAP_MOD_INTERNAL; 2698 ml->sml_desc = pp.ad; 2699 ml->sml_type = pp.ad->ad_cname; 2700 ml->sml_numvals = 1; 2701 ml->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); 2702 ber_dupbv( &ml->sml_values[0], &oldpw ); 2703 BER_BVZERO( &ml->sml_values[1] ); 2704 ml->sml_next = op->orm_modlist; 2705 op->orm_modlist = ml; 2706 delmod = ml; 2707 deladd = 2; 2708 } 2709 2710 if (pp.pwdSafeModify && deladd != 2) { 2711 Debug( LDAP_DEBUG_TRACE, 2712 "change password must use DELETE followed by ADD/REPLACE\n" ); 2713 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 2714 rs->sr_text = "Must supply old password to be changed as well as new one"; 2715 pErr = PP_mustSupplyOldPassword; 2716 goto return_results; 2717 } 2718 2719 /* Check age, but only if pwdReset is not TRUE */ 2720 pa = attr_find( e->e_attrs, ad_pwdReset ); 2721 if ((!pa || !bvmatch( &pa->a_nvals[0], &slap_true_bv )) && 2722 pp.pwdMinAge > 0) { 2723 time_t pwtime = (time_t)-1, now; 2724 int age; 2725 2726 if ((pa = attr_find( e->e_attrs, ad_pwdChangedTime )) != NULL) 2727 pwtime = parse_time( pa->a_nvals[0].bv_val ); 2728 now = slap_get_time(); 2729 age = (int)(now - pwtime); 2730 if ((pwtime != (time_t)-1) && (age < pp.pwdMinAge)) { 2731 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 2732 rs->sr_text = "Password is too young to change"; 2733 pErr = PP_passwordTooYoung; 2734 goto return_results; 2735 } 2736 } 2737 2738 /* pa is used in password history check below, be sure it's set */ 2739 if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL && delmod) { 2740 /* 2741 * we have a password to check 2742 */ 2743 bv = oldpw.bv_val ? &oldpw : delmod->sml_values; 2744 /* FIXME: no access checking? */ 2745 rc = slap_passwd_check( op, NULL, pa, bv, &txt ); 2746 if (rc != LDAP_SUCCESS) { 2747 Debug( LDAP_DEBUG_TRACE, 2748 "old password check failed: %s\n", txt ); 2749 2750 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 2751 rs->sr_text = "Must supply correct old password to change to new one"; 2752 pErr = PP_mustSupplyOldPassword; 2753 goto return_results; 2754 2755 } else { 2756 int i; 2757 2758 /* 2759 * replace the delete value with the (possibly hashed) 2760 * value which is currently in the password. 2761 */ 2762 for ( i = 0; !BER_BVISNULL( &delmod->sml_values[i] ); i++ ) { 2763 free( delmod->sml_values[i].bv_val ); 2764 BER_BVZERO( &delmod->sml_values[i] ); 2765 } 2766 free( delmod->sml_values ); 2767 delmod->sml_values = ch_calloc( sizeof(struct berval), 2 ); 2768 BER_BVZERO( &delmod->sml_values[1] ); 2769 ber_dupbv( &(delmod->sml_values[0]), &(pa->a_nvals[0]) ); 2770 } 2771 } 2772 2773 bv = newpw.bv_val ? &newpw : &addmod->sml_values[0]; 2774 if (pp.pwdCheckQuality > 0) { 2775 2776 rc = check_password_quality( bv, &pp, &pErr, e, (char **)&txt ); 2777 if (rc != LDAP_SUCCESS) { 2778 rs->sr_err = rc; 2779 if ( txt ) { 2780 rs->sr_text = txt; 2781 free_txt = 1; 2782 } else { 2783 rs->sr_text = "Password fails quality checking policy"; 2784 } 2785 goto return_results; 2786 } 2787 } 2788 2789 /* If pwdInHistory is zero, passwords may be reused */ 2790 if (pa && pp.pwdInHistory > 0) { 2791 /* 2792 * Last check - the password history. 2793 */ 2794 /* FIXME: no access checking? */ 2795 if (slap_passwd_check( op, NULL, pa, bv, &txt ) == LDAP_SUCCESS) { 2796 /* 2797 * This is bad - it means that the user is attempting 2798 * to set the password to the same as the old one. 2799 */ 2800 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 2801 rs->sr_text = "Password is not being changed from existing value"; 2802 pErr = PP_passwordInHistory; 2803 goto return_results; 2804 } 2805 2806 /* We need this when reduce pwdInHistory */ 2807 hskip = hsize - pp.pwdInHistory; 2808 2809 /* 2810 * Iterate through the password history, and fail on any 2811 * password matches. 2812 */ 2813 at = *pa; 2814 at.a_vals = cr; 2815 cr[1].bv_val = NULL; 2816 for(p=tl; p; p=p->next) { 2817 if(hskip > 0){ 2818 hskip--; 2819 continue; 2820 } 2821 cr[0] = p->pw; 2822 /* FIXME: no access checking? */ 2823 rc = slap_passwd_check( op, NULL, &at, bv, &txt ); 2824 2825 if (rc != LDAP_SUCCESS) continue; 2826 2827 rs->sr_err = LDAP_CONSTRAINT_VIOLATION; 2828 rs->sr_text = "Password is in history of old passwords"; 2829 pErr = PP_passwordInHistory; 2830 goto return_results; 2831 } 2832 } 2833 2834 do_modify: 2835 if (pwmod) { 2836 struct berval timestamp; 2837 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 2838 time_t now = slap_get_time(); 2839 2840 /* If the conn is restricted, set a callback to clear it 2841 * if the pwmod succeeds 2842 */ 2843 if (!BER_BVISEMPTY( &pwcons[op->o_conn->c_conn_idx].dn )) { 2844 slap_callback *sc = op->o_tmpcalloc( 1, sizeof( slap_callback ), 2845 op->o_tmpmemctx ); 2846 sc->sc_next = op->o_callback; 2847 /* Must use sc_response to insure we reset on success, before 2848 * the client sees the response. Must use sc_cleanup to insure 2849 * that it gets cleaned up if sc_response is not called. 2850 */ 2851 sc->sc_response = ppolicy_mod_cb; 2852 sc->sc_cleanup = ppolicy_mod_cb; 2853 op->o_callback = sc; 2854 } 2855 2856 /* 2857 * keep the necessary pwd.. operational attributes 2858 * up to date. 2859 */ 2860 2861 if (!got_changed) { 2862 timestamp.bv_val = timebuf; 2863 timestamp.bv_len = sizeof(timebuf); 2864 slap_timestamp( &now, ×tamp ); 2865 2866 mods = NULL; 2867 if (pwmop != LDAP_MOD_DELETE) { 2868 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2869 mods->sml_op = LDAP_MOD_REPLACE; 2870 mods->sml_numvals = 1; 2871 mods->sml_values = (BerVarray) ch_calloc( sizeof( struct berval ), 2 ); 2872 mods->sml_nvalues = (BerVarray) ch_calloc( sizeof( struct berval ), 2 ); 2873 2874 ber_dupbv( &mods->sml_values[0], ×tamp ); 2875 ber_dupbv( &mods->sml_nvalues[0], ×tamp ); 2876 } else if (attr_find(e->e_attrs, ad_pwdChangedTime )) { 2877 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2878 mods->sml_op = LDAP_MOD_DELETE; 2879 } 2880 if (mods) { 2881 mods->sml_desc = ad_pwdChangedTime; 2882 mods->sml_flags = SLAP_MOD_INTERNAL; 2883 mods->sml_next = NULL; 2884 modtail->sml_next = mods; 2885 modtail = mods; 2886 } 2887 } 2888 2889 if (!got_del_grace && attr_find(e->e_attrs, ad_pwdGraceUseTime )) { 2890 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2891 mods->sml_op = LDAP_MOD_DELETE; 2892 mods->sml_desc = ad_pwdGraceUseTime; 2893 mods->sml_flags = SLAP_MOD_INTERNAL; 2894 mods->sml_next = NULL; 2895 modtail->sml_next = mods; 2896 modtail = mods; 2897 } 2898 2899 if (!got_del_lock && attr_find(e->e_attrs, ad_pwdAccountLockedTime )) { 2900 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2901 mods->sml_op = LDAP_MOD_DELETE; 2902 mods->sml_desc = ad_pwdAccountLockedTime; 2903 mods->sml_flags = SLAP_MOD_INTERNAL; 2904 mods->sml_next = NULL; 2905 modtail->sml_next = mods; 2906 modtail = mods; 2907 } 2908 2909 if (!got_del_fail && attr_find(e->e_attrs, ad_pwdFailureTime )) { 2910 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2911 mods->sml_op = LDAP_MOD_DELETE; 2912 mods->sml_desc = ad_pwdFailureTime; 2913 mods->sml_flags = SLAP_MOD_INTERNAL; 2914 mods->sml_next = NULL; 2915 modtail->sml_next = mods; 2916 modtail = mods; 2917 } 2918 2919 if ( zapReset ) { 2920 /* 2921 * ITS#7084 Is this a modification by the password 2922 * administrator? Then force a reset if configured. 2923 * Otherwise clear it. 2924 */ 2925 if ( pp.pwdMustChange && is_pwdadmin ) { 2926 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2927 mods->sml_op = LDAP_MOD_REPLACE; 2928 mods->sml_desc = ad_pwdReset; 2929 mods->sml_flags = SLAP_MOD_INTERNAL; 2930 mods->sml_numvals = 1; 2931 mods->sml_values = (BerVarray) ch_calloc( sizeof( struct berval ), 2 ); 2932 mods->sml_nvalues = (BerVarray) ch_calloc( sizeof( struct berval ), 2 ); 2933 2934 ber_dupbv( &mods->sml_values[0], (struct berval *)&slap_true_bv ); 2935 ber_dupbv( &mods->sml_nvalues[0], (struct berval *)&slap_true_bv ); 2936 2937 mods->sml_next = NULL; 2938 modtail->sml_next = mods; 2939 modtail = mods; 2940 } else if ( attr_find( e->e_attrs, ad_pwdReset ) ) { 2941 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2942 mods->sml_op = LDAP_MOD_DELETE; 2943 mods->sml_desc = ad_pwdReset; 2944 mods->sml_flags = SLAP_MOD_INTERNAL; 2945 mods->sml_next = NULL; 2946 modtail->sml_next = mods; 2947 modtail = mods; 2948 } 2949 } 2950 2951 /* TODO: do we remove pwdLastSuccess or set it to 'now'? */ 2952 if (!got_del_success && attr_find(e->e_attrs, ad_pwdLastSuccess )){ 2953 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2954 mods->sml_op = LDAP_MOD_DELETE; 2955 mods->sml_flags = SLAP_MOD_INTERNAL; 2956 mods->sml_desc = ad_pwdLastSuccess; 2957 mods->sml_next = NULL; 2958 modtail->sml_next = mods; 2959 modtail = mods; 2960 } 2961 2962 /* Delete all pwdInHistory attribute */ 2963 if (!got_history && pp.pwdInHistory == 0 && 2964 attr_find(e->e_attrs, ad_pwdHistory )){ 2965 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2966 mods->sml_op = LDAP_MOD_DELETE; 2967 mods->sml_flags = SLAP_MOD_INTERNAL; 2968 mods->sml_desc = ad_pwdHistory; 2969 mods->sml_next = NULL; 2970 modtail->sml_next = mods; 2971 modtail = mods; 2972 } 2973 2974 if (!got_history && pp.pwdInHistory > 0){ 2975 if (hsize >= pp.pwdInHistory) { 2976 /* 2977 * We use the >= operator, since we are going to add 2978 * the existing password attribute value into the 2979 * history - thus the cardinality of history values is 2980 * about to rise by one. 2981 * 2982 * If this would push it over the limit of history 2983 * values (remembering - the password policy could have 2984 * changed since the password was last altered), we must 2985 * delete at least 1 value from the pwdHistory list. 2986 * 2987 * In fact, we delete '(#pwdHistory attrs - max pwd 2988 * history length) + 1' values, starting with the oldest. 2989 * This is easily evaluated, since the linked list is 2990 * created in ascending time order. 2991 */ 2992 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 2993 mods->sml_op = LDAP_MOD_DELETE; 2994 mods->sml_flags = SLAP_MOD_INTERNAL; 2995 mods->sml_desc = ad_pwdHistory; 2996 mods->sml_numvals = hsize - pp.pwdInHistory + 1; 2997 mods->sml_values = ch_calloc( sizeof( struct berval ), 2998 hsize - pp.pwdInHistory + 2 ); 2999 BER_BVZERO( &mods->sml_values[ hsize - pp.pwdInHistory + 1 ] ); 3000 for(i=0,p=tl; i < (hsize - pp.pwdInHistory + 1); i++, p=p->next) { 3001 BER_BVZERO( &mods->sml_values[i] ); 3002 ber_dupbv( &(mods->sml_values[i]), &p->bv ); 3003 } 3004 mods->sml_next = NULL; 3005 modtail->sml_next = mods; 3006 modtail = mods; 3007 } 3008 free_pwd_history_list( &tl ); 3009 3010 /* 3011 * Now add the existing password into the history list. 3012 * This will be executed even if the operation is to delete 3013 * the password entirely. 3014 * 3015 * This isn't in the spec explicitly, but it seems to make 3016 * sense that the password history list is the list of all 3017 * previous passwords - even if they were deleted. Thus, if 3018 * someone tries to add a historical password at some future 3019 * point, it will fail. 3020 */ 3021 if ((pa = attr_find( e->e_attrs, pp.ad )) != NULL) { 3022 mods = (Modifications *) ch_malloc( sizeof( Modifications ) ); 3023 mods->sml_op = LDAP_MOD_ADD; 3024 mods->sml_flags = SLAP_MOD_INTERNAL; 3025 mods->sml_type.bv_val = NULL; 3026 mods->sml_desc = ad_pwdHistory; 3027 mods->sml_nvalues = NULL; 3028 mods->sml_numvals = 1; 3029 mods->sml_values = ch_calloc( sizeof( struct berval ), 2 ); 3030 mods->sml_values[ 1 ].bv_val = NULL; 3031 mods->sml_values[ 1 ].bv_len = 0; 3032 make_pwd_history_value( timebuf, &mods->sml_values[0], pa ); 3033 mods->sml_next = NULL; 3034 modtail->sml_next = mods; 3035 modtail = mods; 3036 3037 } else { 3038 Debug( LDAP_DEBUG_TRACE, 3039 "ppolicy_modify: password attr lookup failed\n" ); 3040 } 3041 } 3042 3043 /* 3044 * Controversial bit here. If the new password isn't hashed 3045 * (ie, is cleartext), we probably should hash it according 3046 * to the default hash. The reason for this is that we want 3047 * to use the policy if possible, but if we hash the password 3048 * before, then we're going to run into trouble when it 3049 * comes time to check the password. 3050 * 3051 * Now, the right thing to do is to use the extended password 3052 * modify operation, but not all software can do this, 3053 * therefore it makes sense to hash the new password, now 3054 * we know it passes the policy requirements. 3055 * 3056 * Of course, if the password is already hashed, then we 3057 * leave it alone. 3058 */ 3059 3060 if ((pi->hash_passwords) && (addmod) && !newpw.bv_val && 3061 (password_scheme( &(addmod->sml_values[0]), NULL ) != LDAP_SUCCESS)) 3062 { 3063 struct berval hpw, bv; 3064 3065 slap_passwd_hash( &(addmod->sml_values[0]), &hpw, &txt ); 3066 if (hpw.bv_val == NULL) { 3067 /* 3068 * hashing didn't work. Emit an error. 3069 */ 3070 rs->sr_err = LDAP_OTHER; 3071 rs->sr_text = txt; 3072 goto return_results; 3073 } 3074 bv = addmod->sml_values[0]; 3075 /* clear and discard the clear password */ 3076 memset(bv.bv_val, 0, bv.bv_len); 3077 ber_memfree(bv.bv_val); 3078 addmod->sml_values[0] = hpw; 3079 } 3080 } else { 3081 /* ITS#8762 Make sure we drop pwdFailureTime if unlocking */ 3082 if (got_del_lock && !got_del_fail && attr_find(e->e_attrs, ad_pwdFailureTime )) { 3083 mods = (Modifications *) ch_calloc( sizeof( Modifications ), 1 ); 3084 mods->sml_op = LDAP_MOD_DELETE; 3085 mods->sml_desc = ad_pwdFailureTime; 3086 mods->sml_flags = SLAP_MOD_INTERNAL; 3087 mods->sml_next = NULL; 3088 modtail->sml_next = mods; 3089 modtail = mods; 3090 } 3091 } 3092 op->o_bd->bd_info = (BackendInfo *)on->on_info; 3093 be_entry_release_r( op, e ); 3094 return SLAP_CB_CONTINUE; 3095 3096 return_results: 3097 free_pwd_history_list( &tl ); 3098 op->o_bd->bd_info = (BackendInfo *)on->on_info; 3099 be_entry_release_r( op, e ); 3100 if ( send_ctrl ) { 3101 ctrl = create_passcontrol( op, -1, -1, pErr ); 3102 oldctrls = add_passcontrol( op, rs, ctrl ); 3103 } 3104 send_ldap_result( op, rs ); 3105 if ( free_txt ) { 3106 if ( is_pwdexop ) { 3107 slap_callback *cb; 3108 cb = op->o_tmpcalloc( sizeof(ppbind)+sizeof(slap_callback), 3109 1, op->o_tmpmemctx ); 3110 3111 /* Setup a callback so we can free the text when sent */ 3112 cb->sc_cleanup = ppolicy_text_cleanup; 3113 cb->sc_private = (void *)txt; 3114 overlay_callback_after_backover( op, cb, 1 ); 3115 } else { 3116 if ( rs->sr_text == txt ) { 3117 rs->sr_text = NULL; 3118 } 3119 free( (char *)txt ); 3120 } 3121 } 3122 if ( send_ctrl ) { 3123 if ( is_pwdexop ) { 3124 if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) { 3125 op->o_tmpfree( oldctrls, op->o_tmpmemctx ); 3126 } 3127 oldctrls = NULL; 3128 rs->sr_flags |= REP_CTRLS_MUSTBEFREED; 3129 3130 } else { 3131 ctrls_cleanup( op, rs, oldctrls ); 3132 } 3133 } 3134 return rs->sr_err; 3135 } 3136 3137 static int 3138 ppolicy_parseCtrl( 3139 Operation *op, 3140 SlapReply *rs, 3141 LDAPControl *ctrl ) 3142 { 3143 if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) { 3144 rs->sr_text = "passwordPolicyRequest control value not absent"; 3145 return LDAP_PROTOCOL_ERROR; 3146 } 3147 op->o_ctrlflag[ppolicy_cid] = ctrl->ldctl_iscritical 3148 ? SLAP_CONTROL_CRITICAL 3149 : SLAP_CONTROL_NONCRITICAL; 3150 3151 return LDAP_SUCCESS; 3152 } 3153 3154 static int 3155 ppolicy_au_parseCtrl( 3156 Operation *op, 3157 SlapReply *rs, 3158 LDAPControl *ctrl ) 3159 { 3160 if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) { 3161 rs->sr_text = "account usability control value not absent"; 3162 return LDAP_PROTOCOL_ERROR; 3163 } 3164 op->o_ctrlflag[account_usability_cid] = ctrl->ldctl_iscritical 3165 ? SLAP_CONTROL_CRITICAL 3166 : SLAP_CONTROL_NONCRITICAL; 3167 3168 return LDAP_SUCCESS; 3169 } 3170 3171 static int 3172 attrPretty( 3173 Syntax *syntax, 3174 struct berval *val, 3175 struct berval *out, 3176 void *ctx ) 3177 { 3178 AttributeDescription *ad = NULL; 3179 const char *err; 3180 int code; 3181 3182 code = slap_bv2ad( val, &ad, &err ); 3183 if ( !code ) { 3184 ber_dupbv_x( out, &ad->ad_type->sat_cname, ctx ); 3185 } 3186 return code; 3187 } 3188 3189 static int 3190 attrNormalize( 3191 slap_mask_t use, 3192 Syntax *syntax, 3193 MatchingRule *mr, 3194 struct berval *val, 3195 struct berval *out, 3196 void *ctx ) 3197 { 3198 AttributeDescription *ad = NULL; 3199 const char *err; 3200 int code; 3201 3202 code = slap_bv2ad( val, &ad, &err ); 3203 if ( !code ) { 3204 ber_str2bv_x( ad->ad_type->sat_oid, 0, 1, out, ctx ); 3205 } 3206 return code; 3207 } 3208 3209 static int 3210 ppolicy_db_init( 3211 BackendDB *be, 3212 ConfigReply *cr 3213 ) 3214 { 3215 slap_overinst *on = (slap_overinst *) be->bd_info; 3216 pp_info *pi; 3217 3218 if ( SLAP_ISGLOBALOVERLAY( be ) ) { 3219 /* do not allow slapo-ppolicy to be global by now (ITS#5858) */ 3220 if ( cr ){ 3221 snprintf( cr->msg, sizeof(cr->msg), 3222 "slapo-ppolicy cannot be global" ); 3223 Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg ); 3224 } 3225 return 1; 3226 } 3227 3228 pi = on->on_bi.bi_private = ch_calloc( sizeof(pp_info), 1 ); 3229 3230 if ( !pwcons ) { 3231 /* accommodate for c_conn_idx == -1 */ 3232 pwcons = ch_calloc( sizeof(pw_conn), dtblsize + 1 ); 3233 pwcons++; 3234 } 3235 3236 ov_count++; 3237 3238 ldap_pvt_thread_mutex_init( &pi->pwdFailureTime_mutex ); 3239 3240 return 0; 3241 } 3242 3243 static int 3244 ppolicy_db_open( 3245 BackendDB *be, 3246 ConfigReply *cr 3247 ) 3248 { 3249 int rc; 3250 3251 if ( (rc = overlay_register_control( be, LDAP_CONTROL_X_ACCOUNT_USABILITY )) != LDAP_SUCCESS ) { 3252 return rc; 3253 } 3254 return overlay_register_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST ); 3255 } 3256 3257 static int 3258 ppolicy_db_close( 3259 BackendDB *be, 3260 ConfigReply *cr 3261 ) 3262 { 3263 #ifdef SLAP_CONFIG_DELETE 3264 overlay_unregister_control( be, LDAP_CONTROL_PASSWORDPOLICYREQUEST ); 3265 overlay_unregister_control( be, LDAP_CONTROL_X_ACCOUNT_USABILITY ); 3266 #endif /* SLAP_CONFIG_DELETE */ 3267 3268 return 0; 3269 } 3270 3271 static int 3272 ppolicy_db_destroy( 3273 BackendDB *be, 3274 ConfigReply *cr 3275 ) 3276 { 3277 slap_overinst *on = (slap_overinst *) be->bd_info; 3278 pp_info *pi = on->on_bi.bi_private; 3279 3280 on->on_bi.bi_private = NULL; 3281 ldap_pvt_thread_mutex_destroy( &pi->pwdFailureTime_mutex ); 3282 free( pi->def_policy.bv_val ); 3283 free( pi ); 3284 3285 ov_count--; 3286 if ( ov_count <=0 && pwcons ) { 3287 pw_conn *pwc = pwcons; 3288 pwcons = NULL; 3289 pwc--; 3290 ch_free( pwc ); 3291 } 3292 return 0; 3293 } 3294 3295 static char *extops[] = { 3296 LDAP_EXOP_MODIFY_PASSWD, 3297 NULL 3298 }; 3299 3300 static slap_overinst ppolicy; 3301 3302 int ppolicy_initialize() 3303 { 3304 int i, code; 3305 3306 for (i=0; pwd_OpSchema[i].def; i++) { 3307 code = register_at( pwd_OpSchema[i].def, pwd_OpSchema[i].ad, 0 ); 3308 if ( code ) { 3309 Debug( LDAP_DEBUG_ANY, 3310 "ppolicy_initialize: register_at failed\n" ); 3311 return code; 3312 } 3313 /* Allow Manager to set these as needed */ 3314 if ( is_at_no_user_mod( (*pwd_OpSchema[i].ad)->ad_type )) { 3315 (*pwd_OpSchema[i].ad)->ad_type->sat_flags |= 3316 SLAP_AT_MANAGEABLE; 3317 } 3318 } 3319 ad_pwdLastSuccess = slap_schema.si_ad_pwdLastSuccess; 3320 { 3321 Syntax *syn; 3322 MatchingRule *mr; 3323 3324 syn = ch_malloc( sizeof( Syntax )); 3325 *syn = *ad_pwdAttribute->ad_type->sat_syntax; 3326 syn->ssyn_pretty = attrPretty; 3327 ad_pwdAttribute->ad_type->sat_syntax = syn; 3328 3329 mr = ch_malloc( sizeof( MatchingRule )); 3330 *mr = *ad_pwdAttribute->ad_type->sat_equality; 3331 mr->smr_normalize = attrNormalize; 3332 ad_pwdAttribute->ad_type->sat_equality = mr; 3333 } 3334 3335 for (i=0; pwd_ocs[i]; i++) { 3336 code = register_oc( pwd_ocs[i], NULL, 0 ); 3337 if ( code ) { 3338 Debug( LDAP_DEBUG_ANY, "ppolicy_initialize: " 3339 "register_oc failed\n" ); 3340 return code; 3341 } 3342 } 3343 3344 code = register_supported_control( LDAP_CONTROL_PASSWORDPOLICYREQUEST, 3345 SLAP_CTRL_ADD|SLAP_CTRL_BIND|SLAP_CTRL_MODIFY, extops, 3346 ppolicy_parseCtrl, &ppolicy_cid ); 3347 if ( code != LDAP_SUCCESS ) { 3348 Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code ); 3349 return code; 3350 } 3351 3352 code = register_supported_control( LDAP_CONTROL_X_ACCOUNT_USABILITY, 3353 SLAP_CTRL_SEARCH, NULL, 3354 ppolicy_au_parseCtrl, &account_usability_cid ); 3355 if ( code != LDAP_SUCCESS ) { 3356 Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code ); 3357 return code; 3358 } 3359 3360 /* We don't expect to receive these controls, only send them */ 3361 code = register_supported_control( LDAP_CONTROL_X_PASSWORD_EXPIRED, 3362 0, NULL, NULL, NULL ); 3363 if ( code != LDAP_SUCCESS ) { 3364 Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code ); 3365 return code; 3366 } 3367 3368 code = register_supported_control( LDAP_CONTROL_X_PASSWORD_EXPIRING, 3369 0, NULL, NULL, NULL ); 3370 if ( code != LDAP_SUCCESS ) { 3371 Debug( LDAP_DEBUG_ANY, "Failed to register control %d\n", code ); 3372 return code; 3373 } 3374 3375 ldap_pvt_thread_mutex_init( &chk_syntax_mutex ); 3376 3377 ppolicy.on_bi.bi_type = "ppolicy"; 3378 ppolicy.on_bi.bi_flags = SLAPO_BFLAG_SINGLE; 3379 ppolicy.on_bi.bi_db_init = ppolicy_db_init; 3380 ppolicy.on_bi.bi_db_open = ppolicy_db_open; 3381 ppolicy.on_bi.bi_db_close = ppolicy_db_close; 3382 ppolicy.on_bi.bi_db_destroy = ppolicy_db_destroy; 3383 3384 ppolicy.on_bi.bi_op_add = ppolicy_add; 3385 ppolicy.on_bi.bi_op_bind = ppolicy_bind; 3386 ppolicy.on_bi.bi_op_compare = ppolicy_compare; 3387 ppolicy.on_bi.bi_op_delete = ppolicy_restrict; 3388 ppolicy.on_bi.bi_op_modify = ppolicy_modify; 3389 ppolicy.on_bi.bi_op_search = ppolicy_search; 3390 ppolicy.on_bi.bi_connection_destroy = ppolicy_connection_destroy; 3391 3392 ppolicy.on_bi.bi_cf_ocs = ppolicyocs; 3393 code = config_register_schema( ppolicycfg, ppolicyocs ); 3394 if ( code ) return code; 3395 3396 return overlay_register( &ppolicy ); 3397 } 3398 3399 #if SLAPD_OVER_PPOLICY == SLAPD_MOD_DYNAMIC 3400 int init_module(int argc, char *argv[]) { 3401 return ppolicy_initialize(); 3402 } 3403 #endif 3404 3405 #endif /* defined(SLAPD_OVER_PPOLICY) */ 3406