H1: Access Control
+H2: Introduction
+
+As the directory gets populated with more and more data of varying sensitivity,
+controlling the kinds of access granted to the directory becomes more and more
+critical. For instance, the directory may contain data of a confidential nature
+that you may need to protect by contract or by law. Or, if using the directory
+to control access to other services, inappropriate access to the directory may
+create avenues of attack to your sites security that result in devastating
+damage to your assets.
+
Access to your directory can be configured via two methods, the first using
{{SECT:The slapd Configuration File}} and the second using the {{slapd-config}}(5)
format ({{SECT:Configuring slapd}}).
+The default access control policy is allow read by all clients. Regardless of
+what access control policy is defined, the {{rootdn}} is always allowed full
+rights (i.e. auth, search, compare, read and write) on everything and anything.
+
+As a consequence, it's useless (and results in a performance penalty) to explicitly
+list the {{rootdn}} among the {{<by>}} clauses.
+
+The following sections will describe Access Control Lists in more details and
+follow with some examples and recommendations.
+
H2: Access Control via Static Configuration
Access to entries and attributes is controlled by the
access configuration file directive. The general form of an
access line is:
-> <access directive> ::= access to <what>
-> [by <who> [<access>] [<control>] ]+
-> <what> ::= * |
-> [dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
-> [filter=<ldapfilter>] [attrs=<attrlist>]
-> <basic-style> ::= regex | exact
-> <scope-style> ::= base | one | subtree | children
-> <attrlist> ::= <attr> [val[.<basic-style>]=<regex>] | <attr> , <attrlist>
-> <attr> ::= <attrname> | entry | children
-> <who> ::= * | [anonymous | users | self
-> | dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
-> [dnattr=<attrname>]
-> [group[/<objectclass>[/<attrname>][.<basic-style>]]=<regex>]
-> [peername[.<basic-style>]=<regex>]
-> [sockname[.<basic-style>]=<regex>]
-> [domain[.<basic-style>]=<regex>]
-> [sockurl[.<basic-style>]=<regex>]
-> [set=<setspec>]
-> [aci=<attrname>]
-> <access> ::= [self]{<level>|<priv>}
-> <level> ::= none | disclose | auth | compare | search | read | write | manage
-> <priv> ::= {=|+|-}{m|w|r|s|c|x|d|0}+
-> <control> ::= [stop | continue | break]
+> <access directive> ::= access to <what>
+> [by <who> [<access>] [<control>] ]+
+> <what> ::= * |
+> [dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
+> [filter=<ldapfilter>] [attrs=<attrlist>]
+> <basic-style> ::= regex | exact
+> <scope-style> ::= base | one | subtree | children
+> <attrlist> ::= <attr> [val[.<basic-style>]=<regex>] | <attr> , <attrlist>
+> <attr> ::= <attrname> | entry | children
+> <who> ::= * | [anonymous | users | self
+> | dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
+> [dnattr=<attrname>]
+> [group[/<objectclass>[/<attrname>][.<basic-style>]]=<regex>]
+> [peername[.<basic-style>]=<regex>]
+> [sockname[.<basic-style>]=<regex>]
+> [domain[.<basic-style>]=<regex>]
+> [sockurl[.<basic-style>]=<regex>]
+> [set=<setspec>]
+> [aci=<attrname>]
+> <access> ::= [self]{<level>|<priv>}
+> <level> ::= none | disclose | auth | compare | search | read | write | manage
+> <priv> ::= {=|+|-}{m|w|r|s|c|x|d|0}+
+> <control> ::= [stop | continue | break]
where the <what> part selects the entries and/or attributes to which
the access applies, the {{EX:<who>}} part specifies which entities
commonly selected in two ways: by DN and by filter. The following
qualifiers select entries by DN:
-> to *
-> to dn[.<basic-style>]=<regex>
-> to dn.<scope-style>=<DN>
+> to *
+> to dn[.<basic-style>]=<regex>
+> to dn.<scope-style>=<DN>
The first form is used to select all entries. The second form may
be used to select entries by matching a regular expression against
For example, if the directory contained entries named:
-> 0: o=suffix
-> 1: cn=Manager,o=suffix
-> 2: ou=people,o=suffix
-> 3: uid=kdz,ou=people,o=suffix
-> 4: cn=addresses,uid=kdz,ou=people,o=suffix
-> 5: uid=hyc,ou=people,o=suffix
+> 0: o=suffix
+> 1: cn=Manager,o=suffix
+> 2: ou=people,o=suffix
+> 3: uid=kdz,ou=people,o=suffix
+> 4: cn=addresses,uid=kdz,ou=people,o=suffix
+> 5: uid=hyc,ou=people,o=suffix
\Then:
. {{EX:dn.base="ou=people,o=suffix"}} match 2;
Entries may also be selected using a filter:
-> to filter=<ldap filter>
+> to filter=<ldap filter>
where <ldap filter> is a string representation of an LDAP
search filter, as described in {{REF:RFC4515}}. For example:
-> to filter=(objectClass=person)
+> to filter=(objectClass=person)
Note that entries may be selected by both DN and filter by
including both qualifiers in the <what> clause.
-> to dn.one="ou=people,o=suffix" filter=(objectClass=person)
+> to dn.one="ou=people,o=suffix" filter=(objectClass=person)
Attributes within an entry are selected by including a comma-separated
list of attribute names in the <what> selector:
-> attrs=<attribute list>
+> attrs=<attribute list>
A specific value of an attribute is selected by using a single
attribute name and also using a value selector:
-> attrs=<attribute> val[.<style>]=<regex>
+> attrs=<attribute> val[.<style>]=<regex>
There are two special {{pseudo}} attributes {{EX:entry}} and
{{EX:children}}. To read (and hence return) a target entry, the
The following table summarizes entity specifiers:
!block table; align=Center; coltags="EX,N"; \
- title="Table 6.3: Access Entity Specifiers"
+ title="Table 6.3: Access Entity Specifiers"
Specifier|Entities
*|All, including anonymous and authenticated users
anonymous|Anonymous (non-authenticated) users
can be restricted by an entry listed in a DN-valued attribute in
the entry to which the access applies:
-> dnattr=<dn-valued attribute name>
+> dnattr=<dn-valued attribute name>
The dnattr specification is used to give access to an entry
whose DN is listed in an attribute of the entry (e.g., give
The kind of <access> granted can be one of the following:
!block table; colaligns="LRL"; coltags="EX,EX,N"; align=Center; \
- title="Table 6.4: Access Levels"
-Level Privileges Description
-none =0 no access
-disclose =d needed for information disclosure on error
-auth =dx needed to authenticate (bind)
-compare =cdx needed to compare
-search =scdx needed to apply search filters
-read =rscdx needed to read search results
-write =wrscdx needed to modify/rename
-manage =mwrscdx needed to manage
+ title="Table 6.4: Access Levels"
+Level Privileges Description
+none =0 no access
+disclose =d needed for information disclosure on error
+auth =dx needed to authenticate (bind)
+compare =cdx needed to compare
+search =scdx needed to apply search filters
+read =rscdx needed to read search results
+write =wrscdx needed to modify/rename
+manage =mwrscdx needed to manage
!endblock
Each level implies all lower levels of access. So, for example,
A simple example:
-> access to * by * read
+> access to * by * read
This access directive grants read access to everyone.
-> access to *
-> by self write
-> by anonymous auth
-> by * read
+> access to *
+> by self write
+> by anonymous auth
+> by * read
This directive allows the user to modify their entry, allows anonymous
to authentication against these entries, and allows all others to
of protection in place. The following shows how security strength
factors (SSF) can be used.
-> access to *
-> by ssf=128 self write
-> by ssf=64 anonymous auth
-> by ssf=64 users read
+> access to *
+> by ssf=128 self write
+> by ssf=64 anonymous auth
+> by ssf=64 users read
This directive allows users to modify their own entries if security
protections have of strength 128 or better have been established,
the entries by DN in two access directives where ordering is
significant.
-> access to dn.children="dc=example,dc=com"
-> by * search
-> access to dn.children="dc=com"
-> by * read
+> access to dn.children="dc=example,dc=com"
+> by * search
+> access to dn.children="dc=com"
+> by * read
Read access is granted to entries under the {{EX:dc=com}} subtree,
except for those entries under the {{EX:dc=example,dc=com}} subtree,
shows the use of an attribute selector to grant access to a specific
attribute and various {{EX:<who>}} selectors.
-> access to dn.subtree="dc=example,dc=com" attrs=homePhone
-> by self write
-> by dn.children="dc=example,dc=com" search
-> by peername.regex=IP:10\..+ read
-> access to dn.subtree="dc=example,dc=com"
-> by self write
-> by dn.children="dc=example,dc=com" search
-> by anonymous auth
+> access to dn.subtree="dc=example,dc=com" attrs=homePhone
+> by self write
+> by dn.children="dc=example,dc=com" search
+> by peername.regex=IP:10\..+ read
+> access to dn.subtree="dc=example,dc=com"
+> by self write
+> by dn.children="dc=example,dc=com" search
+> by anonymous auth
This example applies to entries in the "{{EX:dc=example,dc=com}}"
subtree. To all attributes except {{EX:homePhone}}, an entry can
their own DN from the member attribute, you could accomplish
it with an access directive like this:
-> access to attrs=member,entry
-> by dnattr=member selfwrite
+> access to attrs=member,entry
+> by dnattr=member selfwrite
The dnattr {{EX:<who>}} selector says that the access applies to
entries listed in the {{EX:member}} attribute. The {{EX:selfwrite}} access
reference only and are not included in the actual file. First, the
global configuration section:
-E: 1. # example config file - global configuration section
-E: 2. include /usr/local/etc/schema/core.schema
-E: 3. referral ldap://root.openldap.org
-E: 4. access to * by * read
+E: 1. # example config file - global configuration section
+E: 2. include /usr/local/etc/schema/core.schema
+E: 3. referral ldap://root.openldap.org
+E: 4. access to * by * read
Line 1 is a comment. Line 2 includes another config file
which contains {{core}} schema definitions.
maintained for several attributes, and the {{EX:userPassword}}
attribute is to be protected from unauthorized access.
-E: 5. # BDB definition for the example.com
-E: 6. database bdb
-E: 7. suffix "dc=example,dc=com"
-E: 8. directory /usr/local/var/openldap-data
-E: 9. rootdn "cn=Manager,dc=example,dc=com"
-E: 10. rootpw secret
-E: 11. # indexed attribute definitions
-E: 12. index uid pres,eq
-E: 13. index cn,sn,uid pres,eq,approx,sub
-E: 14. index objectClass eq
-E: 15. # database access control definitions
-E: 16. access to attrs=userPassword
-E: 17. by self write
-E: 18. by anonymous auth
-E: 19. by dn.base="cn=Admin,dc=example,dc=com" write
-E: 20. by * none
-E: 21. access to *
-E: 22. by self write
-E: 23. by dn.base="cn=Admin,dc=example,dc=com" write
-E: 24. by * read
+E: 5. # BDB definition for the example.com
+E: 6. database bdb
+E: 7. suffix "dc=example,dc=com"
+E: 8. directory /usr/local/var/openldap-data
+E: 9. rootdn "cn=Manager,dc=example,dc=com"
+E: 10. rootpw secret
+E: 11. # indexed attribute definitions
+E: 12. index uid pres,eq
+E: 13. index cn,sn,uid pres,eq,approx,sub
+E: 14. index objectClass eq
+E: 15. # database access control definitions
+E: 16. access to attrs=userPassword
+E: 17. by self write
+E: 18. by anonymous auth
+E: 19. by dn.base="cn=Admin,dc=example,dc=com" write
+E: 20. by * none
+E: 21. access to *
+E: 22. by self write
+E: 23. by dn.base="cn=Admin,dc=example,dc=com" write
+E: 24. by * read
Line 5 is a comment. The start of the database definition is marked
by the database keyword on line 6. Line 7 specifies the DN suffix
as the first database. Note that without line 39, the read access
would be allowed due to the global access rule at line 4.
-E: 33. # BDB definition for example.net
-E: 34. database bdb
-E: 35. suffix "dc=example,dc=net"
-E: 36. directory /usr/local/var/openldap-data-net
-E: 37. rootdn "cn=Manager,dc=example,dc=com"
-E: 38. index objectClass eq
-E: 39. access to * by users read
+E: 33. # BDB definition for example.net
+E: 34. database bdb
+E: 35. suffix "dc=example,dc=net"
+E: 36. directory /usr/local/var/openldap-data-net
+E: 37. rootdn "cn=Manager,dc=example,dc=com"
+E: 38. index objectClass eq
+E: 39. access to * by users read
H2: Access Control via Dynamic Configuration
olcAccess attribute, whose values are a sequence of access directives.
The general form of the olcAccess configuration is:
-> olcAccess: <access directive>
-> <access directive> ::= to <what>
-> [by <who> [<access>] [<control>] ]+
-> <what> ::= * |
-> [dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
-> [filter=<ldapfilter>] [attrs=<attrlist>]
-> <basic-style> ::= regex | exact
-> <scope-style> ::= base | one | subtree | children
-> <attrlist> ::= <attr> [val[.<basic-style>]=<regex>] | <attr> , <attrlist>
-> <attr> ::= <attrname> | entry | children
-> <who> ::= * | [anonymous | users | self
-> | dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
-> [dnattr=<attrname>]
-> [group[/<objectclass>[/<attrname>][.<basic-style>]]=<regex>]
-> [peername[.<basic-style>]=<regex>]
-> [sockname[.<basic-style>]=<regex>]
-> [domain[.<basic-style>]=<regex>]
-> [sockurl[.<basic-style>]=<regex>]
-> [set=<setspec>]
-> [aci=<attrname>]
-> <access> ::= [self]{<level>|<priv>}
-> <level> ::= none | disclose | auth | compare | search | read | write | manage
-> <priv> ::= {=|+|-}{m|w|r|s|c|x|d|0}+
-> <control> ::= [stop | continue | break]
+> olcAccess: <access directive>
+> <access directive> ::= to <what>
+> [by <who> [<access>] [<control>] ]+
+> <what> ::= * |
+> [dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
+> [filter=<ldapfilter>] [attrs=<attrlist>]
+> <basic-style> ::= regex | exact
+> <scope-style> ::= base | one | subtree | children
+> <attrlist> ::= <attr> [val[.<basic-style>]=<regex>] | <attr> , <attrlist>
+> <attr> ::= <attrname> | entry | children
+> <who> ::= * | [anonymous | users | self
+> | dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
+> [dnattr=<attrname>]
+> [group[/<objectclass>[/<attrname>][.<basic-style>]]=<regex>]
+> [peername[.<basic-style>]=<regex>]
+> [sockname[.<basic-style>]=<regex>]
+> [domain[.<basic-style>]=<regex>]
+> [sockurl[.<basic-style>]=<regex>]
+> [set=<setspec>]
+> [aci=<attrname>]
+> <access> ::= [self]{<level>|<priv>}
+> <level> ::= none | disclose | auth | compare | search | read | write | manage
+> <priv> ::= {=|+|-}{m|w|r|s|c|x|d|0}+
+> <control> ::= [stop | continue | break]
where the <what> part selects the entries and/or attributes to which
the access applies, the {{EX:<who>}} part specifies which entities
commonly selected in two ways: by DN and by filter. The following
qualifiers select entries by DN:
-> to *
-> to dn[.<basic-style>]=<regex>
-> to dn.<scope-style>=<DN>
+> to *
+> to dn[.<basic-style>]=<regex>
+> to dn.<scope-style>=<DN>
The first form is used to select all entries. The second form may
be used to select entries by matching a regular expression against
For example, if the directory contained entries named:
-> 0: o=suffix
-> 1: cn=Manager,o=suffix
-> 2: ou=people,o=suffix
-> 3: uid=kdz,ou=people,o=suffix
-> 4: cn=addresses,uid=kdz,ou=people,o=suffix
-> 5: uid=hyc,ou=people,o=suffix
+> 0: o=suffix
+> 1: cn=Manager,o=suffix
+> 2: ou=people,o=suffix
+> 3: uid=kdz,ou=people,o=suffix
+> 4: cn=addresses,uid=kdz,ou=people,o=suffix
+> 5: uid=hyc,ou=people,o=suffix
\Then:
. {{EX:dn.base="ou=people,o=suffix"}} match 2;
Entries may also be selected using a filter:
-> to filter=<ldap filter>
+> to filter=<ldap filter>
where <ldap filter> is a string representation of an LDAP
search filter, as described in {{REF:RFC4515}}. For example:
-> to filter=(objectClass=person)
+> to filter=(objectClass=person)
Note that entries may be selected by both DN and filter by
including both qualifiers in the <what> clause.
-> to dn.one="ou=people,o=suffix" filter=(objectClass=person)
+> to dn.one="ou=people,o=suffix" filter=(objectClass=person)
Attributes within an entry are selected by including a comma-separated
list of attribute names in the <what> selector:
-> attrs=<attribute list>
+> attrs=<attribute list>
A specific value of an attribute is selected by using a single
attribute name and also using a value selector:
-> attrs=<attribute> val[.<style>]=<regex>
+> attrs=<attribute> val[.<style>]=<regex>
There are two special {{pseudo}} attributes {{EX:entry}} and
{{EX:children}}. To read (and hence return) a target entry, the
The following table summarizes entity specifiers:
!block table; align=Center; coltags="EX,N"; \
- title="Table 5.3: Access Entity Specifiers"
+ title="Table 5.3: Access Entity Specifiers"
Specifier|Entities
*|All, including anonymous and authenticated users
anonymous|Anonymous (non-authenticated) users
can be restricted by an entry listed in a DN-valued attribute in
the entry to which the access applies:
-> dnattr=<dn-valued attribute name>
+> dnattr=<dn-valued attribute name>
The dnattr specification is used to give access to an entry
whose DN is listed in an attribute of the entry (e.g., give
The kind of <access> granted can be one of the following:
!block table; colaligns="LRL"; coltags="EX,EX,N"; align=Center; \
- title="Table 5.4: Access Levels"
-Level Privileges Description
-none =0 no access
-disclose =d needed for information disclosure on error
-auth =dx needed to authenticate (bind)
-compare =cdx needed to compare
-search =scdx needed to apply search filters
-read =rscdx needed to read search results
-write =wrscdx needed to modify/rename
-manage =mwrscdx needed to manage
+ title="Table 5.4: Access Levels"
+Level Privileges Description
+none =0 no access
+disclose =d needed for information disclosure on error
+auth =dx needed to authenticate (bind)
+compare =cdx needed to compare
+search =scdx needed to apply search filters
+read =rscdx needed to read search results
+write =wrscdx needed to modify/rename
+manage =mwrscdx needed to manage
!endblock
Each level implies all lower levels of access. So, for example,
A simple example:
-> olcAccess: to * by * read
+> olcAccess: to * by * read
This access directive grants read access to everyone.
-> olcAccess: to *
-> by self write
-> by anonymous auth
-> by * read
+> olcAccess: to *
+> by self write
+> by anonymous auth
+> by * read
This directive allows the user to modify their entry, allows anonymous
to authenticate against these entries, and allows all others to
of protection in place. The following shows how security strength
factors (SSF) can be used.
-> olcAccess: to *
-> by ssf=128 self write
-> by ssf=64 anonymous auth
-> by ssf=64 users read
+> olcAccess: to *
+> by ssf=128 self write
+> by ssf=64 anonymous auth
+> by ssf=64 users read
This directive allows users to modify their own entries if security
protections of strength 128 or better have been established,
the entries by DN in two access directives where ordering is
significant.
-> olcAccess: to dn.children="dc=example,dc=com"
-> by * search
-> olcAccess: to dn.children="dc=com"
-> by * read
+> olcAccess: to dn.children="dc=example,dc=com"
+> by * search
+> olcAccess: to dn.children="dc=com"
+> by * read
Read access is granted to entries under the {{EX:dc=com}} subtree,
except for those entries under the {{EX:dc=example,dc=com}} subtree,
shows the use of an attribute selector to grant access to a specific
attribute and various {{EX:<who>}} selectors.
-> olcAccess: to dn.subtree="dc=example,dc=com" attrs=homePhone
-> by self write
-> by dn.children=dc=example,dc=com" search
-> by peername.regex=IP:10\..+ read
-> olcAccess: to dn.subtree="dc=example,dc=com"
-> by self write
-> by dn.children="dc=example,dc=com" search
-> by anonymous auth
+> olcAccess: to dn.subtree="dc=example,dc=com" attrs=homePhone
+> by self write
+> by dn.children=dc=example,dc=com" search
+> by peername.regex=IP:10\..+ read
+> olcAccess: to dn.subtree="dc=example,dc=com"
+> by self write
+> by dn.children="dc=example,dc=com" search
+> by anonymous auth
This example applies to entries in the "{{EX:dc=example,dc=com}}"
subtree. To all attributes except {{EX:homePhone}}, an entry can
their own DN from the member attribute, you could accomplish
it with an access directive like this:
-> olcAccess: to attrs=member,entry
-> by dnattr=member selfwrite
+> olcAccess: to attrs=member,entry
+> by dnattr=member selfwrite
The dnattr {{EX:<who>}} selector says that the access applies to
entries listed in the {{EX:member}} attribute. The {{EX:selfwrite}} access
when originally defining the values. For example, when you create the
settings
-> olcAccess: to attrs=member,entry
-> by dnattr=member selfwrite
-> olcAccess: to dn.children="dc=example,dc=com"
-> by * search
-> olcAccess: to dn.children="dc=com"
-> by * read
+> olcAccess: to attrs=member,entry
+> by dnattr=member selfwrite
+> olcAccess: to dn.children="dc=example,dc=com"
+> by * search
+> olcAccess: to dn.children="dc=com"
+> by * read
when you read them back using slapcat or ldapsearch they will contain
-> olcAccess: {0}to attrs=member,entry
-> by dnattr=member selfwrite
-> olcAccess: {1}to dn.children="dc=example,dc=com"
-> by * search
-> olcAccess: {2}to dn.children="dc=com"
-> by * read
+> olcAccess: {0}to attrs=member,entry
+> by dnattr=member selfwrite
+> olcAccess: {1}to dn.children="dc=example,dc=com"
+> by * search
+> olcAccess: {2}to dn.children="dc=com"
+> by * read
The numeric index may be used to specify a particular value to change
when using ldapmodify to edit the access rules. This index can be used
For example, if we needed to change the second rule above to grant
write access instead of search, we could try this LDIF:
-> changetype: modify
-> delete: olcAccess
-> olcAccess: to dn.children="dc=example,dc=com" by * search
-> -
-> add: olcAccess
-> olcAccess: to dn.children="dc=example,dc=com" by * write
-> -
+> changetype: modify
+> delete: olcAccess
+> olcAccess: to dn.children="dc=example,dc=com" by * search
+> -
+> add: olcAccess
+> olcAccess: to dn.children="dc=example,dc=com" by * write
+> -
But this example {{B:will not}} guarantee that the existing values remain in
their original order, so it will most likely yield a broken security
configuration. Instead, the numeric index should be used:
-> changetype: modify
-> delete: olcAccess
-> olcAccess: {1}
-> -
-> add: olcAccess
-> olcAccess: {1}to dn.children="dc=example,dc=com" by * write
-> -
+> changetype: modify
+> delete: olcAccess
+> olcAccess: {1}
+> -
+> add: olcAccess
+> olcAccess: {1}to dn.children="dc=example,dc=com" by * write
+> -
This example deletes whatever rule is in value #1 of the {{EX:olcAccess}}
attribute (regardless of its value) and adds a new value that is
explicitly inserted as value #1. The result will be
-> olcAccess: {0}to attrs=member,entry
-> by dnattr=member selfwrite
-> olcAccess: {1}to dn.children="dc=example,dc=com"
-> by * write
-> olcAccess: {2}to dn.children="dc=com"
-> by * read
+> olcAccess: {0}to attrs=member,entry
+> by dnattr=member selfwrite
+> olcAccess: {1}to dn.children="dc=example,dc=com"
+> by * write
+> olcAccess: {2}to dn.children="dc=com"
+> by * read
which is exactly what was intended.
reference only and are not included in the actual file. First, the
global configuration section:
-E: 1. # example config file - global configuration entry
-E: 2. dn: cn=config
-E: 3. objectClass: olcGlobal
-E: 4. cn: config
-E: 5. olcReferral: ldap://root.openldap.org
-E: 6.
+E: 1. # example config file - global configuration entry
+E: 2. dn: cn=config
+E: 3. objectClass: olcGlobal
+E: 4. cn: config
+E: 5. olcReferral: ldap://root.openldap.org
+E: 6.
Line 1 is a comment. Lines 2-4 identify this as the global
configuration entry.
standard port (389) at the host {{EX:root.openldap.org}}.
Line 6 is a blank line, indicating the end of this entry.
-E: 7. # internal schema
-E: 8. dn: cn=schema,cn=config
-E: 9. objectClass: olcSchemaConfig
-E: 10. cn: schema
-E: 11.
+E: 7. # internal schema
+E: 8. dn: cn=schema,cn=config
+E: 9. objectClass: olcSchemaConfig
+E: 10. cn: schema
+E: 11.
Line 7 is a comment. Lines 8-10 identify this as the root of
the schema subtree. The actual schema definitions in this entry
are hardcoded into slapd so no additional attributes are specified here.
Line 11 is a blank line, indicating the end of this entry.
-E: 12. # include the core schema
-E: 13. include: file:///usr/local/etc/openldap/schema/core.ldif
-E: 14.
+E: 12. # include the core schema
+E: 13. include: file:///usr/local/etc/openldap/schema/core.ldif
+E: 14.
Line 12 is a comment. Line 13 is an LDIF include directive which
accesses the {{core}} schema definitions in LDIF format. Line 14
special {{EX:frontend}} database whose settings are applied globally
to all the other databases.
-E: 15. # global database parameters
-E: 16. dn: olcDatabase=frontend,cn=config
-E: 17. objectClass: olcDatabaseConfig
-E: 18. olcDatabase: frontend
-E: 19. olcAccess: to * by * read
-E: 20.
+E: 15. # global database parameters
+E: 16. dn: olcDatabase=frontend,cn=config
+E: 17. objectClass: olcDatabaseConfig
+E: 18. olcDatabase: frontend
+E: 19. olcAccess: to * by * read
+E: 20.
Line 15 is a comment. Lines 16-18 identify this entry as the global
database entry. Line 19 is a global access control. It applies to all
for several attributes, and the {{EX:userPassword}} attribute is to be
protected from unauthorized access.
-E: 21. # BDB definition for example.com
-E: 22. dn: olcDatabase=bdb,cn=config
-E: 23. objectClass: olcDatabaseConfig
-E: 24. objectClass: olcBdbConfig
-E: 25. olcDatabase: bdb
-E: 26. olcSuffix: "dc=example,dc=com"
-E: 27. olcDbDirectory: /usr/local/var/openldap-data
-E: 28. olcRootDN: "cn=Manager,dc=example,dc=com"
-E: 29. olcRootPW: secret
-E: 30. olcDbIndex: uid pres,eq
-E: 31. olcDbIndex: cn,sn,uid pres,eq,approx,sub
-E: 32. olcDbIndex: objectClass eq
-E: 33. olcAccess: to attrs=userPassword
-E: 34. by self write
-E: 35. by anonymous auth
-E: 36. by dn.base="cn=Admin,dc=example,dc=com" write
-E: 37. by * none
-E: 38. olcAccess: to *
-E: 39. by self write
-E: 40. by dn.base="cn=Admin,dc=example,dc=com" write
-E: 41. by * read
-E: 42.
+E: 21. # BDB definition for example.com
+E: 22. dn: olcDatabase=bdb,cn=config
+E: 23. objectClass: olcDatabaseConfig
+E: 24. objectClass: olcBdbConfig
+E: 25. olcDatabase: bdb
+E: 26. olcSuffix: "dc=example,dc=com"
+E: 27. olcDbDirectory: /usr/local/var/openldap-data
+E: 28. olcRootDN: "cn=Manager,dc=example,dc=com"
+E: 29. olcRootPW: secret
+E: 30. olcDbIndex: uid pres,eq
+E: 31. olcDbIndex: cn,sn,uid pres,eq,approx,sub
+E: 32. olcDbIndex: objectClass eq
+E: 33. olcAccess: to attrs=userPassword
+E: 34. by self write
+E: 35. by anonymous auth
+E: 36. by dn.base="cn=Admin,dc=example,dc=com" write
+E: 37. by * none
+E: 38. olcAccess: to *
+E: 39. by self write
+E: 40. by dn.base="cn=Admin,dc=example,dc=com" write
+E: 41. by * read
+E: 42.
Line 21 is a comment. Lines 22-25 identify this entry as a BDB database
configuration entry. Line 26 specifies the DN suffix
as the first database. Note that without line 52, the read access
would be allowed due to the global access rule at line 19.
-E: 43. # BDB definition for example.net
-E: 44. dn: olcDatabase=bdb,cn=config
-E: 45. objectClass: olcDatabaseConfig
-E: 46. objectClass: olcBdbConfig
-E: 47. olcDatabase: bdb
-E: 48. olcSuffix: "dc=example,dc=net"
-E: 49. olcDbDirectory: /usr/local/var/openldap-data-net
-E: 50. olcRootDN: "cn=Manager,dc=example,dc=com"
-E: 51. olcDbIndex: objectClass eq
-E: 52. olcAccess: to * by users read
+E: 43. # BDB definition for example.net
+E: 44. dn: olcDatabase=bdb,cn=config
+E: 45. objectClass: olcDatabaseConfig
+E: 46. objectClass: olcBdbConfig
+E: 47. olcDatabase: bdb
+E: 48. olcSuffix: "dc=example,dc=net"
+E: 49. olcDbDirectory: /usr/local/var/openldap-data-net
+E: 50. olcRootDN: "cn=Manager,dc=example,dc=com"
+E: 51. olcDbIndex: objectClass eq
+E: 52. olcAccess: to * by users read
-H3: Converting from slapd.conf(8) to a {{B:cn=config}} directory format
+H3: Converting from {{slapd.conf}}(5) to a {{B:cn=config}} directory format
Discuss slap* -f slapd.conf -F slapd.d/ (man slapd-config)
+H2: Access Control Common Examples
+
+H3: Basic ACLs
+
+Generally one should start with some basic ACLs such as:
+
+> access to attr=userPassword
+> by self =xw
+> by anonymous auth
+> by * none
+>
+>
+> access to *
+> by self write
+> by users read
+> by * none
+
+The first ACL allows users to update (but not read) their passwords, anonymous
+users to authenticate against this attribute, and (implicitly) denying all
+access to others.
+
+The second ACL allows users full access to their entry, authenticated users read
+access to anything, and (implicitly) denying all access to others (in this case,
+anonymous users).
+
+
+H3: Matching Anonymous and Authenticated users
+
+An anonymous user has a empty DN. While the {{dn.exact=""}} or {{dn.regex="^$"}}
+ could be used, {{slapd}}(8)) offers an anonymous shorthand which should be
+used instead.
+
+> access to *
+> by anonymous none
+> by * read
+
+denies all access to anonymous users while granting others read.
+
+Authenticated users have a subject DN. While {{dn.regex=".+"}} will match any
+authenticated user, OpenLDAP provides the users short hand which should be used
+instead.
+
+> access to *
+> by users read
+> by * none
+
+This ACL grants read permissions to authenticated users while denying others
+(i.e.: anonymous users).
+
+
+H3: Controlling rootdn access
+
+You could specify the {{rootdn}} in {{slapd.conf}}(5) or {[slapd.d}} without
+specifying a {{rootpw}}. Then you have to add an actual directory entry with
+the same dn, e.g.:
+
+> dn: cn=Manager,o=MyOrganization
+> cn: Manager
+> sn: Manager
+> objectClass: person
+> objectClass: top
+> userPassword: {SSHA}someSSHAdata
+
+Then binding as the {{rootdn}} will require a regular bind to that DN, which
+in turn requires auth access to that entry's DN and {{userPassword}}, and this
+can be restricted via ACLs. E.g.:
+
+> access to dn.base="cn=Manager,o=MyOrganization"
+> by peername.regex=127\.0\.0\.1 auth
+> by peername.regex=192\.168\.0\..* auth
+> by users none
+> by * none
+
+The ACLs above will only allow binding using rootdn from localhost and
+192.168.0.0/24.
+
+
+H3: Managing access with Groups
+
+There are a few ways to do this. One approach is illustrated here. Consider the
+following DIT layout:
+
+> +-dc=example,dc=com
+> +---cn=administrators,dc=example,dc=com
+> +---cn=fred blogs,dc=example,dc=com
+
+and the following group object (in LDIF format):
+
+> dn: cn=administrators,dc=example,dc=com
+> cn: administrators of this region
+> objectclass: groupOfNames (important for the group acl feature)
+> member: cn=fred blogs,dc=example,dc=com
+> member: cn=somebody else,dc=example,dc=com
+
+One can then grant access to the members of this this group by adding appropriate
+{{by group}} clause to an access directive in {{slapd.conf}}(5). For instance,
+
+> access to dn.children="dc=example,dc=com"
+> by self write
+> by group.exact="cn=Administrators,dc=example,dc=com" write
+> by * auth
+
+Like by {[dn}} clauses, one can also use {{expand}} to expand the group name
+based upon the regular expression matching of the target, that is, the to {{dn.regex}}).
+For instance,
+
+> access to dn.regex="(.+,)?ou=People,(dc=[^,]+,dc=[^,]+)$"
+> attrs=children,entry,uid
+> by group.expand="cn=Managers,$2" write
+> by users read
+> by * auth
+
+
+The above illustration assumed that the group members are to be found in the
+{{member}} attribute type of the {{groupOfNames}} object class. If you need to
+use a different group object and/or a different attribute type then use the
+following {{slapd.conf}}(5) (abbreviated) syntax:
+
+> access to <what>
+> by group/<objectclass>/<attributename>=<DN> <access>
+
+For example:
+
+> access to *
+> by group/organizationalRole/roleOccupant="cn=Administrator,dc=example,dc=com" write
+
+In this case, we have an ObjectClass {{organizationalRole}} which contains the
+administrator DN's in the {{roleOccupant}} attribute. For instance:
+
+> dn: cn=Administrator,dc=example,dc=com
+> cn: Administrator
+> objectclass: organizationalRole
+> roleOccupant: cn=Jane Doe,dc=example,dc=com
+
+Note: the specified member attribute type MUST be of DN or {{NameAndOptionalUID}} syntax,
+and the specified object class SHOULD allow the attribute type.
+
+Dynamic Groups are also supported in Access Control. Please see {{slapo-dynlist}}(5)
+and the {{SECT:Dynamic Lists}} overlay section.
+
+
+H3: Granting access to a subset of attributes
+
+You can grant access to a set of attributes by specifying a list of attribute names
+in the ACL {{to}} clause. To be useful, you also need to grant access to the
+{{entry}} itself. Also note how {{children}} controls the ability to add, delete,
+and rename entries.
+
+> # mail: self may write, authenticated users may read
+> access to attrs=mail
+> by self write
+> by users read
+> by * none
+>
+> # cn, sn: self my write, all may read
+> access to attrs=cn,sn
+> by self write
+> by * read
+>
+> # immediate children: only self can add/delete entries under this entry
+> access to attrs=children
+> by self write
+>
+> # entry itself: self may write, all may read
+> access to attrs=entry
+> by self write
+> by * read
+>
+> # other attributes: self may write, others have no access
+> access to *
+> by self write
+> by * none
+
+ObjectClass names may also be specified in this list, which will affect
+all the attributes that are required and/or allowed by that {{objectClass}}.
+Actually, names in {{attrlist}} that are prefixed by {{@}} are directly treated
+as objectClass names. A name prefixed by {{!}} is also treated as an objectClass,
+but in this case the access rule affects the attributes that are not required
+nor allowed by that {{objectClass}}.
+
+
+H3: Allowing a user write to all entries below theirs
+
+For a setup where a user can write to its own record and to all of its children:
+
+> access to dn.regex="(.+,)?(uid=[^,]+,o=Company)$"
+> by dn.exact,expand="$2" write
+> by anonymous auth
+
+(Add more examples for above)
+
+
+H3: Allowing entry creation
+
+Let's say, you have it like this:
+
+> o=<basedn>
+> ou=domains
+> associatedDomain=<somedomain>
+> ou=users
+> uid=<someuserid>
+> uid=<someotheruserid>
+> ou=addressbooks
+> uid=<someuserid>
+> cn=<someone>
+> cn=<someoneelse>
+
+and, for another domain <someotherdomain>:
+
+> o=<basedn>
+> ou=domains
+> associatedDomain=<someotherdomain>
+> ou=users
+> uid=<someuserid>
+> uid=<someotheruserid>
+> ou=addressbooks
+> uid=<someotheruserid>
+> cn=<someone>
+> cn=<someoneelse>
+
+then, if you wanted user {{uid=<someuserid>}} to {{B:ONLY}} create an entry
+for its own thing, you could write an ACL like this:
+
+> # this rule lets users of "associatedDomain=<matcheddomain>"
+> # write under "ou=addressbook,associatedDomain=<matcheddomain>,ou=domains,o=<basedn>",
+> # i.e. a user can write ANY entry below its domain's address book;
+> # this permission is necessary, but not sufficient, the next
+> # will restrict this permission further
+>
+>
+> access to dn.regex="^ou=addressbook,associatedDomain=([^,]+),ou=domains,o=<basedn>$" attrs=children
+> by dn.regex="^uid=([^,]+),ou=users,associatedDomain=$1,ou=domains,o=<basedn>$$" write
+> by * none
+>
+>
+> # Note that above the "by" clause needs a "regex" style to make sure
+> # it expands to a DN that starts with a "uid=<someuserid>" pattern
+> # while substituting the associatedDomain submatch from the "what" clause.
+>
+>
+> # This rule lets a user with "uid=<matcheduid>" of "<associatedDomain=matcheddomain>"
+> # write (i.e. add, modify, delete) the entry whose DN is exactly
+> # "uid=<matcheduid>,ou=addressbook,associatedDomain=<matcheddomain>,ou=domains,o=<basedn>"
+> # and ANY entry as subtree of it
+>
+>
+> access to dn.regex="^(.+,)?uid=([^,]+),ou=addressbook,associatedDomain=([^,]+),ou=domains,o=<basedn>$"
+> by dn.exact,expand="uid=$2,ou=users,associatedDomain=$3,ou=domains,o=<basedn>" write
+> by * none
+>
+>
+> # Note that above the "by" clause uses the "exact" style with the "expand"
+> # modifier because now the whole pattern can be rebuilt by means of the
+> # submatches from the "what" clause, so a "regex" compilation and evaluation
+> # is no longer required.
+
+
+H3: Tips for using regular expressions in Access Control
+
+Always use {{dn.regex=<pattern>}} when you intend to use regular expression
+matching. {{dn=<pattern>}} alone defaults to {{dn.exact<pattern>}}.
+
+Use {{(.+)}} instead of {{(.*)}} when you want at least one char to be matched.
+{{(.*)}} matches the empty string as well.
+
+Don't use regular expressions for matches that can be done otherwise in a safer
+and cheaper manner. Examples:
+
+> dn.regex=".*dc=example,dc=com"
+
+is unsafe and expensive:
+
+ * unsafe because any string containing {{dc=example,dc=com }}will match,
+not only those that end with the desired pattern; use {{.*dc=example,dc=com$}} instead.
+ * unsafe also because it would allow any {{attributeType}} ending with {{dc}}
+ as naming attribute for the first RDN in the string, e.g. a custom attributeType
+{{mydc}} would match as well. If you really need a regular expression that allows
+just {{dc=example,dc=com}} or any of its subtrees, use {{^(.+,)?dc=example,dc=com$}},
+which means: anything to the left of dc=..., if any (the question mark after the
+pattern within brackets), must end with a comma;
+ * expensive because if you don't need submatches, you could use scoping styles, e.g.
+
+> dn.subtree="dc=example,dc=com"
+
+to include {{dc=example,dc=com}} in the matching patterns,
+
+> dn.children="dc=example,dc=com"
+
+to exclude {{dc=example,dc=com}} from the matching patterns, or
+
+> dn.onelevel="dc=example,dc=com"
+
+to allow exactly one sublevel matches only.
+
+Always use {{^}} and {{$}} in regexes, whenever appropriate, because
+{{ou=(.+),ou=(.+),ou=addressbooks,o=basedn}} will match
+{{something=bla,ou=xxx,ou=yyy,ou=addressbooks,o=basedn,ou=addressbooks,o=basedn,dc=some,dc=org}}
+
+Always use {{([^,]+)}} to indicate exactly one RDN, because {{(.+)}} can
+include any number of RDNs; e.g. {{ou=(.+),dc=example,dc=com}} will match
+{{ou=My,o=Org,dc=example,dc=com}}, which might not be what you want.
+
+Never add the rootdn to the by clauses. ACLs are not even processed for operations
+performed with rootdn identity (otherwise there would be no reason to define a
+rootdn at all).
+
+Use shorthands. The user directive matches authenticated users and the anonymous
+directive matches anonymous users.
+
+Don't use the {{dn.regex}} form for <by> clauses if all you need is scoping
+and/or substring replacement; use scoping styles (e.g. {{exact}}, {{onelevel}},
+{{children}} or {{subtree}}) and the style modifier expand to cause substring expansion.
+
+For instance,
+
+> access to dn.regex=".+,dc=([^,]+),dc=([^,]+)$"
+> by dn.regex="^[^,],ou=Admin,dc=$1,dc=$2$$" write
+
+although correct, can be safely and efficiently replaced by
+
+> access to dn.regex=".+,(dc=[^,]+,dc=[^,]+)$"
+> by dn.onelevel,expand="ou=Admin,$1" write
+
+where the regex in the {{<what>}} clause is more compact, and the one in the {{<by>}}
+clause is replaced by a much more efficient scoping style of onelevel with substring expansion.
+
+
+H3: Granting and Denying access based on security strength factors (ssf)
+
+You can restrict access based on the security strength factor (SSF)
+
+> access to dn="cn=example,cn=edu"
+> by * ssf=256 read
+
+0 (zero) implies no protection,
+1 implies integrity protection only,
+56 DES or other weak ciphers,
+112 triple DES and other strong ciphers,
+128 RC4, Blowfish and other modern strong ciphers.
+
+Other possibilities:
+
+> transport_ssf=<n>
+> tls_ssf=<n>
+> sasl_ssf=<n>
+
+256 is recommended.
+
+See {{slapd.conf}}(5) for information on {{ssf}}.
+
+
+H3: When things aren't working as expected
+
+Consider this example:
+
+> access to *
+> by anonymous auth
+>
+> access to *
+> by self write
+>
+> access to *
+> by users read
+
+You may think this will allow any user to login, to read everything and change
+his own data if he is logged in. But in this example only the login works and
+an ldapsearch returns no data. The Problem is that SLAPD goes through its access
+config line by line and stops as soon as it finds a match in the part of the
+access rule.(here: {{to *}})
+
+To get what we wanted the file has to read:
+
+> access to *
+> by anonymous auth
+> by self write
+> by users read
+
+The general rule is: "special access rules first, generic access rules last"
+
+See also {{slapd.access}}(8), loglevel 128 and {{slapacl}}(8) for debugging
+information.
+
+
H2: Sets - Granting rights based on relationships
Sets are best illustrated via examples. The following sections will present