SLAPO_PPOLICY(5)
π SLAPO_PPOLICY(5) π
so the manual name is SLAPO_PPOLICY(5) (File Formats Manual, bestie, we are in the file formats section) and the whole thing is about slapo-ppolicy β the Password Policy overlay for slapd. it's giving security queen π
π SYNOPSIS
/etc/openldap/slapd.conf
β¨ DESCRIPTION β¨
okay so first things first: the ppolicy overlay is an implementation of the most recent IETF Password Policy proposal for LDAP. the second you instantiate it, it intercepts, decodes and applies specific password policy controls to your overall use of a backend database, to changes to user password fields, etc. it's literally always watching π«Ά
and the overlay serves up a whole buffet of password control mechanisms, no cap:
- password aging β both minimum and maximum ages
- password reuse and duplication control
- account time-outs
- mandatory password resets
- acceptable password content
- and even grace logins πΈ
different groups of users may be associated with different password policies, and there is no limit to the number of password policies that may be created. infinite policies, infinite vibes.
heads up bestie: some of the policies do not take effect when the operation is performed with the rootdn identity. all the operations, when performed with any other identity, may be subjected to constraints, like access control. also β this overlay requires a rootdn to be configured on the database. so set that up or it's not gonna fly π
during a password update, an identity with manage access to the userPassword attribute is considered a password administrator where relevant to the IETF Password Policy proposal.
another note, and this one's important: the IETF Password Policy proposal for LDAP makes sense when you're thinking about a single-valued password attribute, while the userPassword attribute allows multiple values. this implementation enforces a single value for the userPassword attribute, despite its specification. yes, it overrides the spec. she does what she wants π
in addition to supporting the IETF Password Policy, this module supports the SunDS Account Usability control (1.3.6.1.4.1.42.2.27.9.5.8) on search requests, and it can send the Netscape Password validity controls when configured to do so. iconic behavior, honestly.
π οΈ CONFIGURATION π οΈ
these slapd.conf configuration options apply to the ppolicy overlay. they should appear after the overlay directive β order matters, bestie, don't be messy.
ppolicy_forward_updatesβ say that policy state changes that result from Bind operations (like recording failures, lockout, etc.) on a consumer should be forwarded to a provider instead of being written directly into the consumer's local database. this setting is only useful on a replication consumer, and it also requires theupdaterefsetting and thechainoverlay to be appropriately configured. lowkey a whole ensemble cast for this one.ppolicy_hash_cleartextβ say that cleartext passwords present in Add and Modify requests should be hashed before being stored in the database. this violates the X.500/LDAP information model, but may be needed to compensate for LDAP clients that don't use the Password Modify extended operation to manage passwords. it is recommended that when this option is used, thatcompare,search, andreadaccess be denied to all directory users. fr fr, deny the access, protect the people.ppolicy_use_lockoutβ a client will always receive an LDAPInvalidCredentialsresponse when Binding to a locked account. by default, when a Password Policy control was provided on the Bind request, a Password Policy response will be included with no special error code set. this option changes the Password Policy response to include theAccountLockederror code.
β οΈ but bestie, note that sending the AccountLocked error code provides useful information to an attacker. sites that are sensitive to security issues should not enable this option. please think before you toggle. π
ppolicy_send_netscape_controlsβ if set,ppolicywill send the password policy expired (2.16.840.1.113730.3.4.4) and password policy expiring (2.16.840.1.113730.3.4.5) controls when appropriate. the controls are not sent for bind requests where the Password policy control has already been requested. default is not to send the controls.ppolicy_check_module <path>β specify the path of a loadable module containing acheck_password()function for additional password quality checks. the use of this module is described further below in the description of thepwdPolicyCheckerobjectclass.
π Note: the user-defined loadable module must be inslapd's standard executable searchPATH, or an absolute path must be provided.
π Note: use of a ppolicy_check_module is a non-standard extension to the LDAP password policy proposal. she's custom, she's extra, we love her.
ppolicy_rules [dn[.<dnstyle>]=<DN/regex>] [require_password=yes|no] [filter=<filter str>] [group[.expand][/<objectclass>[/<attribute>]]=<DN/pattern>] no_policy|policy_dn=<policyDN>|policy_dn.expand=<pattern> [stop|continue]β specify whichpwdPolicyobject to use when no specific policy is set on a given user's entry. the rules are checked in order and the first one to match will apply (but see thecontinueaction). if a rule that specifiesno_policyis selected, or the selectedpolicyDNis an entry with objectclasspwdPolicybut its contents are not valid, then no policies will be enforced. shrug emoji.
when checking whether a rule applies, ppolicy checks:
- the entry's DN against the
dn[.<dnstyle>] - if
require_passwordisyes(the default), presence of thepasswordattribute (currently onlyuserPassword) - the entry's contents against the
filter - whether it is considered a member of the
groupspecified ingroup[.expand]
all of which are optional. matching and meaning of <dnstyle> and expand loosely follow that described in slapd.access(5), except that the expansions in the pattern space are slightly more limited β only the $<digit> form is supported at the moment, and only if dnstyle is regex. it then tries to retrieve policyDN and check that its objectclass is pwdPolicy.
if all of the rule checks pass, behaviour depends on the action keyword (stop|continue). if action is stop (the default), processing ends here with the policy that was just chosen (or the no_policy decision). if action is continue, the decision is remembered, processing continues, and it can be overridden by later rules. keep the receipts π
the way to configure this in cn=config is through child entries under the overlay entry with objectclass olcPPolicyRegexRule for regex-based DN matching and olcPPolicyScopedRule for any other <dnstyle>.
ppolicy_default <policyDN>β specify the DN of thepwdPolicyobject to use when no specific policy is set on a given user's entry and none of theppolicy_rulesmatched. if there is no specific policy for an entry and no default is given, then no policies will be enforced.
π¨ this option is deprecated in favour ofppolicy_rulesand support for it will be removed in a future release. it behaves as if the following rule was the first rule inppolicy_rules:
ppolicy_rules policyDN=<policyDN> continue
π OBJECT CLASSES π
the ppolicy overlay depends on the pwdPolicy object class. the definition of that class is as follows:
( 1.3.6.1.4.1.42.2.27.8.2.1
NAME 'pwdPolicy'
AUXILIARY
SUP top
MUST ( pwdAttribute )
MAY (
pwdMinAge $ pwdMaxAge $ pwdInHistory $
pwdCheckQuality $ pwdMinLength $ pwdMaxLength $
pwdExpireWarning $ pwdGraceAuthnLimit $
pwdGraceExpiry $ pwdLockout $ pwdLockoutDuration $
pwdMaxFailure $ pwdFailureCountInterval $
pwdMustChange $ pwdAllowUserChange $
pwdSafeModify $ pwdMaxRecordedFailure $
pwdMinDelay $ pwdMaxDelay $ pwdMaxIdle ) )
the pwdPolicy class is not structural, so entries using it require another, structural, object class. the namedPolicy object class is a good choice π β namedPolicy requires a cn attribute, suitable as the policy entry's rDN.
this implementation also provides two additional objectclasses:
pwdPolicyChecker objectclass β used for password quality checking π΅οΈβοΈ
( 1.3.6.1.4.1.4754.2.99.1
NAME 'pwdPolicyChecker'
AUXILIARY
SUP top
MAY ( pwdCheckModule $ pwdCheckModuleArg $ pwdUseCheckModule ) )
and pwdHashingPolicy objectclass β for more fine-grained control over password hashing π
( 1.3.6.1.4.1.4754.2.99.2
NAME 'pwdHashingPolicy'
SUP pwdPolicy
AUXILIARY
MAY ( pwdDefaultHash $ pwdRehashOnBind ) )
see specific attributes below for usage β¨
every account that should be subject to password policy control should have a pwdPolicySubentry attribute containing the DN of a valid pwdPolicy entry β or they can simply use the configured default. this way different users may be managed according to different policies. custom policies per user? main character energy fr π
𧬠OBJECT CLASS ATTRIBUTES π§¬
each one of the sections below details the meaning and use of a particular attribute of this pwdPolicy object class. buckle up bestie, it's a long list and we're doing all of it.
pwdAttribute
this attribute contains the name of the attribute to which the password policy is applied. for example, the password policy may be applied to the userPassword attribute.
π Note: in this implementation, the only value accepted forpwdAttributeisuserPassword. just the one. periodt.
( 1.3.6.1.4.1.42.2.27.8.1.1
NAME 'pwdAttribute'
EQUALITY objectIdentifierMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
pwdMinAge
this attribute contains the number of seconds that must elapse between modifications allowed to the password. if this attribute is not present, zero seconds is assumed (i.e. the password may be modified whenever and however often is desired). go off, i guess.
( 1.3.6.1.4.1.42.2.27.8.1.2
NAME 'pwdMinAge'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdMaxAge
this attribute contains the number of seconds after which a modified password will expire. if this attribute is not present, or if its value is zero (0), then passwords will not expire. immortal password era πΈ
( 1.3.6.1.4.1.42.2.27.8.1.3
NAME 'pwdMaxAge'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdInHistory
this attribute is used to specify the maximum number of used passwords that will be stored in the pwdHistory attribute. if the pwdInHistory attribute is not present, or if its value is zero (0), used passwords will not be stored in pwdHistory and thus any previously-used password may be reused. no history checking occurs if the password is being modified by the rootdn, although the password is saved in the history. so rootdn gets a free pass but the history still keeps the receipt π
( 1.3.6.1.4.1.42.2.27.8.1.4
NAME 'pwdInHistory'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdCheckQuality πΈ
okay so this one is literally the vibe check for your password's whole syntax situation. It says if and how password syntax gets checked while a password is being modified or added.
- Not there at all, or set to zero (0)? Then no syntax checking happens, periodt. Do whatever bestie, nobody's looking.
- Set to one (1)? The server will check the syntax, but if it genuinely can't β say, a client-side hashed password, or some other reason β it'll just accept it anyway. Forgiving queen.
- Set to two (2)? Server checks the syntax, and if it can't check it, it returns an error and refuses the password. Strict! No notes! π
( 1.3.6.1.4.1.42.2.27.8.1.5
NAME 'pwdCheckQuality'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdMinLength π
When syntax checking is on (peep the pwdCheckQuality attribute, they're besties), this holds the minimum length in bytes that'll be accepted in a password. No attribute? Then min length is not enforced, live your life.
If the server can't check the length of the password β client-side hashed password, other chaos, whatever β then it depends on pwdCheckQuality: it either accepts the password without checking it (when pwdCheckQuality is zero (0) or one (1)) or refuses it (when pwdCheckQuality is two (2)).
And hmm, if you want the number of characters enforced with regards to a particular encoding, you need an appropriate ppolicy_check_module. That's the move. β¨
( 1.3.6.1.4.1.42.2.27.8.1.6
NAME 'pwdMinLength'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdMaxLength π¦
Same energy, opposite direction: when syntax checking is enabled (yes, pwdCheckQuality again), this one holds the maximum length in bytes accepted in a password. If it's not present, the max isn't enforced, no cap bestie.
And fr fr, if the server can't check the password's length β client-side hashed, some other reason, the usual β then depending on pwdCheckQuality it either accepts without checking (pwdCheckQuality equals zero (0) or one (1)) or refuses it (pwdCheckQuality equals two (2)).
Want the character count enforced according to a specific encoding? Then you need an appropriate ppolicy_check_module, iykyk. π
( 1.3.6.1.4.1.42.2.27.8.1.31
NAME 'pwdMaxLength'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdExpireWarning β°
This is the maximum number of seconds before a password is due to expire that the server still slides those expiration warning messages into the face of a user who's authenticating to the directory. If the attribute isn't present, or the value is zero (0), no warnings get sent. Silent treatment, lowkey rude but okay.
( 1.3.6.1.4.1.42.2.27.8.1.7
NAME 'pwdExpireWarning'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdGraceAuthnLimit π°οΈ
The number of times an expired password can still be used to authenticate a user to the directory. Basically the grace-period pass. If this attribute isn't present, or its value is zero (0), then nope β users with expired passwords won't be allowed to authenticate to the directory at all. πͺ
( 1.3.6.1.4.1.42.2.27.8.1.8
NAME 'pwdGraceAuthnLimit'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdGraceExpiry π
how long those grace authentications are actually valid: this attribute specifies the number of seconds they stay good for. Not present, or value of zero (0)? Then there's no time limit on the grace authentications at all. Go off, no rush.
( 1.3.6.1.4.1.42.2.27.8.1.30
NAME 'pwdGraceExpiry'
EQUALITY integerMatch
ORDERING integerOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdLockout π
This one decides what the directory does when someone's been out here failing to authenticate over and over. If pwdLockout is set (value "TRUE"), then once there've been a specified number of consecutive failed bind attempts, the user won't be allowed to even attempt authenticating to the directory. That max number is what pwdMaxFailure says. If pwdLockout isn't present, or its value is "FALSE", then the password can be used to authenticate no matter how many consecutive failed binds have stacked up. Infinite attempts, chaotic but free. π
( 1.3.6.1.4.1.42.2.27.8.1.9
NAME 'pwdLockout'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE )
pwdLockoutDuration β
The number of seconds during which the password cannot be used to authenticate that user to the directory, because of too many consecutive failed bind attempts. (Go read pwdLockout and pwdMaxFailure too, they're all one storyline.)
If pwdLockoutDuration isn't present, or its value is zero (0), then the password can't be used to authenticate that user again until an administrator resets it. Not a timeout, a whole situation. π
( 1.3.6.1.4.1.42.2.27.8.1.10
NAME 'pwdLockoutDuration'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdMaxFailure π’
The number of consecutive failed bind attempts after which the password may no longer be used to authenticate a user to the directory. If pwdMaxFailure isn't present, or its value is zero (0), then the user gets to keep trying forever, no matter how many consecutive failed bind attempts have happened with that user's DN. (See also pwdLockout and pwdLockoutDuration β the whole trio eats together.) π
( 1.3.6.1.4.1.42.2.27.8.1.11
NAME 'pwdMaxFailure'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdMaxRecordedFailure π
The maximum number of failed bind attempts to actually store in a user's entry. If pwdMaxRecordedFailure isn't present, or its value is zero (0), then it just defaults to whatever pwdMaxFailure is. And if that value is also 0, the default becomes 5. Ripple-effect defaults, iconic honestly.
( 1.3.6.1.4.1.42.2.27.8.1.32
NAME 'pwdMaxRecordedFailure'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdFailureCountInterval π§Ή
The number of seconds after which old consecutive failed bind attempts get purged from the failure counter β even though nobody successfully authenticated. Just a lil cleanup. If pwdFailureCountInterval isn't present, or its value is zero (0), then that failure counter only ever gets reset by a successful authentication. Nothing else saves you bestie. π«Ά
( 1.3.6.1.4.1.42.2.27.8.1.12
NAME 'pwdFailureCountInterval'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdMustChange π
Whether users have to change their passwords when they first bind to the directory after an administrator sets or resets it. If pwdMustChange is "TRUE", yeah β users must change their password on that first bind after the admin set or reset it. If pwdMustChange isn't present, or its value is "FALSE", then no, users aren't required to change anything when they bind after the admin sets or resets the password. Old password stays, main character energy. π
( 1.3.6.1.4.1.42.2.27.8.1.13
NAME 'pwdMustChange'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE )
pwdAllowUserChange π
Whether users are allowed to change their own passwords. If pwdAllowUserChange is set to "TRUE" β or if the attribute isn't even present β then yes, users can change their own passwords. If its value is "FALSE", then users cannot change their own passwords.
Note: this implies that when pwdAllowUserChange is "TRUE", users will still be able to change the password of another user, subject to access control. This restriction only applies to modifications of one's own password.
Also worth clocking: pwdAllowUserChange was defined in the spec to provide rough access control to the password attribute, in implementations that don't do fine-grain access control. Since OpenLDAP does provide fine-grain access control, using this attribute is discouraged β use ACLs instead, bestie. Peep slapd.access(5) for the details. β¨
( 1.3.6.1.4.1.42.2.27.8.1.14
NAME 'pwdAllowUserChange'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE )
pwdSafeModify π‘οΈ
Denotes whether the user's existing password has to be sent along with their new password when they change it. If pwdSafeModify is set to "TRUE", then yes β old password must come along with the new one. If the attribute isn't present, or its value is "FALSE", then nah, the existing password doesn't need to be sent with the new one.
( 1.3.6.1.4.1.42.2.27.8.1.15
NAME 'pwdSafeModify'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE )
pwdMinDelay π’
The number of seconds to delay responding to the first failed authentication attempt. If this attribute isn't set, or is zero (0), then no delays get used at all. And heads up: pwdMaxDelay must also be specified if pwdMinDelay is set. They're a package deal. π
Note: this implementation uses a variable lockout instead of delaying the bind response. So don't expect the literal delay, okay?
( 1.3.6.1.4.1.42.2.27.8.1.24
NAME 'pwdMinDelay'
EQUALITY integerMatch
ORDERING integerOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
pwdMaxDelay π
The maximum number of seconds to delay when responding to a failed authentication attempt. Here's the tea: the time in pwdMinDelay is the starting point, and then it doubles on every failure until the delay time is greater than or equal to pwdMaxDelay β or until a successful authentication happens, which resets that failure counter. And pwdMinDelay must also be specified if pwdMaxDelay is set, no solo acts here.
Note: this implementation uses a variable lockout instead of delaying the bind response. Same as before, don't come looking for the literal delay. π
πΈ pwdMaxDelay (schema, continued)
( 1.3.6.1.4.1.42.2.27.8.1.25
NAME 'pwdMaxDelay'
EQUALITY integerMatch
ORDERING integerOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
π pwdMaxIdle
okay so this one is the clock-watcher of the policy π
β it says how many seconds an account can just sit there, untouched and unused, before it gets locked. Not set? Or set to zero (0)? Then no check happens at all, it just vibes forever.
β οΈ But bestie, listen β for this to actually be enforced, thelastbindfunctionality has to be turned on for the database. That meansolcLastBindis set toTRUE. Nolastbind, no enforcement, periodt.
And here's its whole lil schema glow-up β¨:
( 1.3.6.1.4.1.42.2.27.8.1.26
NAME 'pwdMaxIdle'
EQUALITY integerMatch
ORDERING integerOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
SINGLE-VALUE )
π§ pwdUseCheckModule / pwdCheckModuleArg
omg this one is giving plug-in era main character energy π₯. The pwdUseCheckModule attribute turns on a loadable module that you already set up earlier with ppolicy_check_module β but only for this policy, iykyk.
That module must instantiate the check_password() function. So when does it get called? Only when pwdCheckQuality is set to one (1) or two (2), and only after every single built-in password compliance check has already passed. So it's the final boss check, not the first one π.
It gets called according to this function prototype, literally character for character:
int check_password (char *pPasswd, struct berval *pErrmsg, Entry *pEntry, struct berval *pArg);
Breakdown, bestie:
pPasswdβ the clear-text user password, right there in the flesh.pErrmsgβ points to astruct bervalwith space to hand back human-readable details about any error it runs into. Thebv_lenfield must contain the size of the space thatbv_valgives you. (No lying about your buffer size, that's so not it.)pEntryβ optional. If it's non-NULL, it carries a pointer to the entry whose password is being checked.pArgβ optional. Points to astruct bervalholding the value ofpwdCheckModuleArgin the effective password policy, if that's set. Otherwise it'sNULL.
β οΈ IfpErrmsgisNULL, thenfuncNamemust NOT attempt to use it. Like, at all. Zero. Don't do it.
Return value rules: LDAP_SUCCESS from the called function = the password is ok β
. Any other value = the password is unacceptable β. If it's unacceptable, the server returns an error to the client, and pErrmsg may be used to return a human-readable textual explanation of the error.
And if the space the caller passed in is too small? The function may replace it with a dynamically allocated buffer β which slapd will free() for you. So cute of it π«Ά.
π Heads up: the pwdCheckModule attribute is now obsolete and is ignored. RIP to a real one.
All three schemas, coming right up β¨:
( 1.3.6.1.4.1.4754.1.99.1
NAME 'pwdCheckModule'
EQUALITY caseExactIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
OBSOLETE
SINGLE-VALUE )
( 1.3.6.1.4.1.4754.1.99.2
NAME 'pwdCheckModuleArg'
EQUALITY octetStringMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
DESC 'Argument to pass to check_password() function'
SINGLE-VALUE )
( 1.3.6.1.4.1.4754.1.99.3
NAME 'pwdUseCheckModule'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE )
π pwdDefaultHash
If you set this, it overrides the configured default password hash β but only for the objects governed by this policy. So it's per-policy, very exclusive, very "this is my table" π .
( 1.3.6.1.4.1.4754.1.99.4
NAME 'pwdDefaultHash'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
DESC 'Per policy default hash setting'
SINGLE-VALUE )
π¦ pwdRehashOnBind
This one says whether the user's existing password should get rehashed. Here's the tea: if pwdRehashOnBind is set to "TRUE", pwdDefaultHash is set to a known password hash, and a Simple Bind succeeds β then the entry's userPassword gets replaced with a version using that hash. Glow-up on login, obsessed β¨.
( 1.3.6.1.4.1.4754.1.99.5
NAME 'pwdRehashOnBind'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
DESC 'On successful Simple Bind, rehash password
with default hash if different'
SINGLE-VALUE )
β¨ OPERATIONAL ATTRIBUTES β¨
okay so these operational attributes live inside the user's entry, bestie. most of them are not for users to poke at directly β they're there to track what the user's been doing. they're documented here so admins AND users can both actually understand how the ppolicy module is doing its thing π
real talk though: the current IETF Password Policy proposal does not define how these operational attributes are supposed to behave in a replication setup. so in general, authentication attempts on a replica only touch the copy of the operational attributes on that replica, and won't affect any of the attributes on the provider's copy of the user's entry. meanwhile, operational attribute changes that come from authentication attempts on a provider will usually replicate out to the replicas (and will also overwrite any changes that started on the replica). these behaviors are not guaranteed and are subject to change once a formal spec shows up. π
userPassword
this one isn't strictly part of the ppolicy module, ngl β but it is the attribute that the module tracks and controls. its definition lives in the standard OpenLDAP schema, so go look there. π«Ά
pwdPolicySubentry
this attribute points directly at the pwdPolicy subentry that's meant to be used for this particular directory user. every account that should be subject to password policy control will have a pwdPolicySubentry attribute holding the DN of a pwdPolicy entry. the module uses the one stored in the DB if it exists, otherwise it'll try to derive the right policy to apply based on the rules it's been configured with β see the ppolicy_rules / olcPPolicyScopedRule / olcPPolicyRegexRule configuration options. that's how different users can be managed under different configurable policies, iconic behavior honestly. the value of the effective policy DN gets returned if you ask for it in a search request, but heads up: this is a virtual attribute and it is not usable in a filter. Modifying/adding this attribute directly is deprecated, and the ability to do it will be removed in a future release. π
( 1.3.6.1.4.1.42.2.27.8.1.23
NAME 'pwdPolicySubentry'
DESC 'The pwdPolicy subentry in effect for
this object'
EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
SINGLE-VALUE
USAGE directoryOperation)
pwdChangedTime
this one is the timestamp of the last time the entry's password got changed. the password expiration policy reads this value to figure out whether the password is too old to still be allowed for user authentication. and here's the tea: if pwdChangedTime doesn't exist, the user's password will not expire. π
( 1.3.6.1.4.1.42.2.27.8.1.16
NAME 'pwdChangedTime'
DESC 'The time the password was last changed'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SINGLE-VALUE
NO-USER-MODIFICATION
USAGE directoryOperation)
pwdAccountLockedTime
this attribute holds the time the user's account got locked. once the account is locked, that password can no longer be used to authenticate the user to the directory. and if pwdAccountLockedTime is set to 000001010000Z, the account is permanently locked and only an administrator can unlock it π. quick note: account locking only kicks in when the pwdLockout password policy attribute is set to "TRUE".
( 1.3.6.1.4.1.42.2.27.8.1.17
NAME 'pwdAccountLockedTime'
DESC 'The time an user account was locked'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SINGLE-VALUE
USAGE directoryOperation)
pwdFailureTime
this one holds the timestamps of every one of the consecutive authentication failures made on attempted authentication to this DN (i.e. this account). if too many timestamps pile up in here (peep the pwdMaxFailure password policy attribute for the details) and the pwdLockout password policy attribute is set to "TRUE", the account may get locked. (go look at the pwdLockout password policy attribute too, bestie.) excess timestamps beyond what pwdMaxFailure or pwdMaxRecordedFailure allows may also get purged. and if a successful authentication happens on this DN (i.e. this user account), then pwdFailureTime gets cleansed of entries. glow-up β¨
( 1.3.6.1.4.1.42.2.27.8.1.19
NAME 'pwdFailureTime'
DESC 'The timestamps of the last consecutive
authentication failures'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
NO-USER-MODIFICATION
USAGE directoryOperation )
pwdHistory
this attribute is the history of previously used passwords for this DN (i.e. this user account). the values get stored in string format, like this:
pwdHistory=
time "#" syntaxOID "#" length "#" data
time=
GeneralizedTime as specified in section 3.3.13 of [RFC4517]
syntaxOID = numericoid
This is the string representation of the dotted-decimal OID that
defines the syntax used to store the password. numericoid is
described in section 1.4 of [RFC4512].
length = NumericString
The number of octets in the data. NumericString is described in
section 3.3.23 of [RFC4517].
data =
Octets representing the password in the format specified by
syntaxOID.
this format lets the server store and transmit a history of passwords that have been used. and for equality matching on the values in this attribute to actually work properly, the time field has to be in GMT format. no cap.
( 1.3.6.1.4.1.42.2.27.8.1.20
NAME 'pwdHistory'
DESC 'The history of user passwords'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
EQUALITY octetStringMatch
NO-USER-MODIFICATION
USAGE directoryOperation)
pwdGraceUseTime
this attribute holds the list of timestamps of logins made after the user password in the DN has already expired. these post-expiration logins are known as "grace logins". if too many grace logins get used (peep the pwdGraceAuthnLimit password policy attribute), then the DN can no longer be used to authenticate the user to the directory until the administrator changes the DN's userPassword attribute. π
( 1.3.6.1.4.1.42.2.27.8.1.21
NAME 'pwdGraceUseTime'
DESC 'The timestamps of the grace login once the password has
expired'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
EQUALITY generalizedTimeMatch
NO-USER-MODIFICATION
USAGE directoryOperation)
pwdReset
this attribute tells you whether the user's password got reset by the administrator and therefore must be changed on the first use of this DN to authenticate to the directory. if pwdReset is set to "TRUE", then yeah β the password was reset and the user must change it on first authentication. if the attribute doesn't exist, or it's set to "FALSE", then the user does not need to change their password due to an administrative reset. easy. π
( 1.3.6.1.4.1.42.2.27.8.1.22
NAME 'pwdReset'
DESC 'The indication that the password has
been reset'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE
USAGE directoryOperation)
pwdStartTime
this attribute says when the entry's password becomes valid for authentication. any authentication attempt made before this time will fail. and if this attribute doesn't exist, then no restriction applies at all. β
( 1.3.6.1.4.1.42.2.27.8.1.27
NAME 'pwdStartTime'
DESC 'The time the password becomes enabled'
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE
USAGE directoryOperation )
pwdEndTime
this attribute says when the entry's password becomes invalid for authentication. any authentication attempt made after this time will fail, no matter what the expiration or grace settings say. and if this attribute doesn't exist, then this restriction doesn't apply. π¦
( 1.3.6.1.4.1.42.2.27.8.1.28
NAME 'pwdEndTime'
DESC 'The time the password becomes disabled'
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE
USAGE directoryOperation )
lowkey important note: pwdStartTime may be set to a time that's greater than or equal to pwdEndTime β and what that does is simply disable the account. π
pwdAccountTmpLockoutEnd
this attribute is that the user's password has been locked out temporarily according to the pwdMinDelay policy option, and when the lockout ends.
( 1.3.6.1.4.1.42.2.27.8.1.33
NAME 'pwdAccountTmpLockoutEnd'
DESC 'Temporary lockout end'
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE
NO-USER-MODIFICATION
USAGE directoryOperation )
π SUNDS ACCOUNT USABILITY CONTROL π
so if the SunDS Account Usability control is used with a search request, the overlay will attach validity information to each entry β but only if all of these things are true, bestie:
- there is a password policy that applies to the entry
- the user has compare access to the entry's password attribute.
- the configured password attribute is present in the entry
πΈ EXAMPLES πΈ
okay here's what it actually looks like in a config, slay:
database mdb
suffix dc=example,dc=com
...
overlay ppolicy
ppolicy_default "cn=Standard,ou=Policies,dc=example,dc=com"
π₯ SEE ALSO π₯
ldap(3),slapd.conf(5),slapd-config(5),slapo-chain(5).- "OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/)
- IETF LDAP password policy proposal by P. Behera, L. Poitou and J. Sermersheim: documented in IETF document "draft-behera-ldap-password-policy-10.txt".
π BUGS π
the LDAP Password Policy specification is not yet an approved standard, and it is still evolving. this code will continue to be in flux until the specification is finalized. so yeahβ¦ it's giving "we're so back / it's so over" at the same time, fr fr. π
β¨ ACKNOWLEDGEMENTS β¨
okay so acknowledgements time, bestie, because we gotta give credit where credit is due π
This module was written in 2004 by Howard Chu of Symas Corporation, with significant input from Neil Dunbar and Kartik Subbarao of Hewlett-Packard. iconic behavior, no cap π
This manual page borrows heavily and shamelessly from the specification upon which the password policy module it describes is based. the audacity? love that for us π
This source is the IETF LDAP password policy proposal by P. Behera, L. Poitou and J. Sermersheim. The proposal is fully documented in the IETF document named draft-behera-ldap-password-policy-10.txt, written in August of 2009 πβ¨
OpenLDAP Software is developed and maintained by The OpenLDAP Project (<http://www.openldap.org/>) π«Ά OpenLDAP Software is derived from the University of Michigan LDAP 3.3 Release. periodt π
okay bestie, that's the whole entire man page, and we ATE π no crumbs. This was OpenLDAP 2.7.2, dated 2026/10/21, and you've been reading SLAPO_PPOLICY(5) πβ¨π¦
π¦ where this page comes from
- arch rolling: openldap 2.7.2-2 Β· OLDAP-2.8
- Copyright 2004-2026 The OpenLDAP Foundation All Rights Reserved
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms