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