]> git.sur5r.net Git - openldap/blobdiff - doc/guide/admin/access-control.sdf
Happy New Year!
[openldap] / doc / guide / admin / access-control.sdf
index a1b312586f58ce24e37c3c111c58300ede2029b0..e661aa1e0962ae528676b291aa94ae3be1a7243c 100644 (file)
@@ -1,42 +1,63 @@
 # $OpenLDAP$
-# Copyright 1999-2008 The OpenLDAP Foundation, All Rights Reserved.
+# Copyright 1999-2012 The OpenLDAP Foundation, All Rights Reserved.
 # COPYING RESTRICTIONS APPLY, see COPYRIGHT.
 
 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 greater depth and 
+follow with some examples and recommendations. See {{slapd.access}}(5) for
+complete details.
+
 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
@@ -55,9 +76,9 @@ and attributes to which the access control applies.  Entries are
 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
@@ -76,12 +97,12 @@ under the DN (but not the entry named by the DN).
 
 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;
@@ -92,32 +113,34 @@ For example, if the directory contained entries named:
 
 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
 subject must have {{EX:read}} access to the target's {{entry}}
-attribute.  To add or delete an entry, the subject must have
+attribute.  To perform a search, the subject must have
+{{EX:search}} access to the search base's {{entry}} attribute.
+To add or delete an entry, the subject must have
 {{EX:write}} access to the entry's {{EX:entry}} attribute AND must
 have {{EX:write}} access to the entry's parent's {{EX:children}}
 attribute.  To rename an entry, the subject must have {{EX:write}}
@@ -138,7 +161,7 @@ access. Note that access is granted to "entities" not "entries."
 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
@@ -154,7 +177,7 @@ Other control factors are also supported.  For example, a {{EX:<who>}}
 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
@@ -171,16 +194,16 @@ H3: The access to grant
 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,
@@ -196,8 +219,15 @@ When evaluating whether some requester should be given access to
 an entry and/or attribute, slapd compares the entry and/or attribute
 to the {{EX:<what>}} selectors given in the configuration file.
 For each entry, access controls provided in the database which holds
-the entry (or the first database if not held in any database) apply
-first, followed by the global access directives.  Within this
+the entry (or the global access directives if not held in any database) apply
+first, followed by the global access directives. However, when dealing with 
+an access list, because the global access list is effectively appended 
+to each per-database list, if the resulting list is non-empty then the 
+access list will end with an implicit {{EX:access to * by * none}} directive. 
+If there are no access directives applicable to a backend, then a default 
+read is used.
+
+Within this
 priority, access directives are examined in the order in which they
 appear in the config file.  Slapd stops with the first {{EX:<what>}}
 selector that matches the entry and/or attribute. The corresponding
@@ -231,14 +261,14 @@ section shows some examples of its use for descriptive purposes.
 
 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
@@ -251,10 +281,10 @@ It is often desirable to restrict operations based upon the level
 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,
@@ -267,10 +297,10 @@ The following example shows the use of a style specifiers to select
 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,
@@ -282,23 +312,26 @@ are also under {{EX:dc=com}} entries.
 
 Also note that if no {{EX:access to}} directive matches or no {{EX:by
 <who>}} clause, {{B:access is denied}}.  That is, every {{EX:access
-to}} directive ends with an implicit {{EX:by * none}} clause and
-every access list ends with an implicit {{EX:access to * by * none}}
-directive.
+to}} directive ends with an implicit {{EX:by * none}} clause. When dealing
+with an access list, because the global access list is effectively appended 
+to each per-database list, if the resulting list is non-empty then the access 
+list will end with an implicit {{EX:access to * by * none}} directive. If
+there are no access directives applicable to a backend, then a default read is
+used.
 
 The next example again shows the importance of ordering, both of
 the access directives and the {{EX:by <who>}} clauses.  It also
 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
@@ -317,8 +350,8 @@ create a group and allow people to add and remove only
 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
@@ -333,125 +366,36 @@ consult the {{Advanced Access Control}} chapter.
 !endif
 
 
-H3: Configuration File Example
-
-The following is an example configuration file, interspersed
-with explanatory text. It defines two databases to handle
-different parts of the {{TERM:X.500}} tree; both are {{TERM:BDB}}
-database instances. The line numbers shown are provided for
-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
-Line 1 is a comment. Line 2 includes another config file
-which contains {{core}} schema definitions.
-The {{EX:referral}} directive on line 3
-means that queries not local to one of the databases defined
-below will be referred to the LDAP server running on the
-standard port (389) at the host {{EX:root.openldap.org}}.
-
-Line 4 is a global access control.  It applies to all
-entries (after any applicable database-specific access
-controls).
-
-The next section of the configuration file defines a BDB
-backend that will handle queries for things in the
-"dc=example,dc=com" portion of the tree. The
-database is to be replicated to two slave slapds, one on
-truelies, the other on judgmentday. Indices are to be
-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
-
-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
-for queries to pass to this database. Line 8 specifies the directory
-in which the database files will live.
-
-Lines 9 and 10 identify the database {{super-user}} entry and associated
-password. This entry is not subject to access control or size or
-time limit restrictions.
-
-Lines 12 through 14 indicate the indices to maintain for various
-attributes.
-
-Lines 16 through 24 specify access control for entries in this
-database.  As this is the first database, the controls also apply
-to entries not held in any database (such as the Root DSE).  For
-all applicable entries, the {{EX:userPassword}} attribute is writable
-by the entry itself and by the "admin" entry.  It may be used for
-authentication/authorization purposes, but is otherwise not readable.
-All other attributes are writable by the entry and the "admin"
-entry, but may be read by all users (authenticated or not).
-
-The next section of the example configuration file defines another
-BDB database. This one handles queries involving the
-{{EX:dc=example,dc=net}} subtree but is managed by the same entity
-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
-
 H2: Access Control via Dynamic Configuration
 
 Access to slapd entries and attributes is controlled by the
 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
@@ -470,9 +414,9 @@ and attributes to which the access control applies.  Entries are
 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
@@ -491,12 +435,12 @@ under the DN (but not the entry named by the DN).
 
 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;
@@ -507,32 +451,34 @@ For example, if the directory contained entries named:
 
 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
 subject must have {{EX:read}} access to the target's {{entry}}
-attribute.  To add or delete an entry, the subject must have
+attribute.  To perform a search, the subject must have
+{{EX:search}} access to the search base's {{entry}} attribute.
+To add or delete an entry, the subject must have
 {{EX:write}} access to the entry's {{EX:entry}} attribute AND must
 have {{EX:write}} access to the entry's parent's {{EX:children}}
 attribute.  To rename an entry, the subject must have {{EX:write}}
@@ -553,7 +499,7 @@ access. Note that access is granted to "entities" not "entries."
 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
@@ -569,7 +515,7 @@ Other control factors are also supported.  For example, a {{EX:<who>}}
 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
@@ -586,16 +532,16 @@ H3: The access to grant
 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,
@@ -611,9 +557,16 @@ When evaluating whether some requester should be given access to
 an entry and/or attribute, slapd compares the entry and/or attribute
 to the {{EX:<what>}} selectors given in the configuration.  For
 each entry, access controls provided in the database which holds
-the entry (or the first database if not held in any database) apply
+the entry (or the global access directives if not held in any database) apply
 first, followed by the global access directives (which are held in
-the {{EX:frontend}} database definition).  Within this priority,
+the {{EX:frontend}} database definition). However, when dealing with 
+an access list, because the global access list is effectively appended 
+to each per-database list, if the resulting list is non-empty then the 
+access list will end with an implicit {{EX:access to * by * none}} directive. 
+If there are no access directives applicable to a backend, then a default 
+read is used.
+
+Within this priority,
 access directives are examined in the order in which they appear
 in the configuration attribute.  Slapd stops with the first
 {{EX:<what>}} selector that matches the entry and/or attribute. The
@@ -648,14 +601,14 @@ section shows some examples of its use for descriptive purposes.
 
 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
@@ -668,10 +621,10 @@ It is often desirable to restrict operations based upon the level
 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,
@@ -684,10 +637,10 @@ The following example shows the use of style specifiers to select
 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,
@@ -698,24 +651,25 @@ would never be reached, since all entries under {{EX:dc=example,dc=com}}
 are also under {{EX:dc=com}} entries.
 
 Also note that if no {{EX:olcAccess: to}} directive matches or no {{EX:by
-<who>}} clause, {{B:access is denied}}.  That is, every {{EX:olcAccess:
-to}} directive ends with an implicit {{EX:by * none}} clause and
-every access list ends with an implicit {{EX:olcAccess: to * by * none}}
-directive.
+<who>}} clause, {{B:access is denied}}.  When dealing with an access list, 
+because the global access list is effectively appended to each per-database 
+list, if the resulting list is non-empty then the access list will end with 
+an implicit {{EX:access to * by * none}} directive. If there are no access 
+directives applicable to a backend, then a default read is used.
 
 The next example again shows the importance of ordering, both of
 the access directives and the {{EX:by <who>}} clauses.  It also
 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
@@ -734,8 +688,8 @@ create a group and allow people to add and remove only
 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
@@ -758,21 +712,21 @@ tags are maintained automatically by slapd and do not need to be specified
 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
@@ -782,36 +736,36 @@ numeric index is very helpful when multiple access rules are being managed.
 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.
 
@@ -821,136 +775,387 @@ consult the {{Advanced Access Control}} chapter.
 !endif
 
 
-H3: Configuration Example
-
-The following is an example configuration, interspersed
-with explanatory text. It defines two databases to handle
-different parts of the {{TERM:X.500}} tree; both are {{TERM:BDB}}
-database instances. The line numbers shown are provided for
-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. 
-
-Line 1 is a comment. Lines 2-4 identify this as the global
-configuration entry.
-The {{EX:olcReferral:}} directive on line 5
-means that queries not local to one of the databases defined
-below will be referred to the LDAP server running on the
-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. 
-
-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. 
-
-Line 12 is a comment. Line 13 is an LDIF include directive which
-accesses the {{core}} schema definitions in LDIF format. Line 14
-is a blank line.
-
-Next comes the database definitions. The first database is the
-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. 
-
-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
-entries (after any applicable database-specific access controls).
-
-The next entry defines a BDB backend that will handle queries for things
-in the "dc=example,dc=com" portion of the tree. Indices are to be maintained
-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. 
-
-Line 21 is a comment. Lines 22-25 identify this entry as a BDB database
-configuration entry.  Line 26 specifies the DN suffix
-for queries to pass to this database. Line 27 specifies the directory
-in which the database files will live.
-
-Lines 28 and 29 identify the database {{super-user}} entry and associated
-password. This entry is not subject to access control or size or
-time limit restrictions.
-
-Lines 30 through 32 indicate the indices to maintain for various
-attributes.
-
-Lines 33 through 41 specify access control for entries in this
-database.  As this is the first database, the controls also apply
-to entries not held in any database (such as the Root DSE).  For
-all applicable entries, the {{EX:userPassword}} attribute is writable
-by the entry itself and by the "admin" entry.  It may be used for
-authentication/authorization purposes, but is otherwise not readable.
-All other attributes are writable by the entry and the "admin"
-entry, but may be read by all users (authenticated or not).
-
-Line 42 is a blank line, indicating the end of this entry.
-
-The next section of the example configuration file defines another
-BDB database. This one handles queries involving the
-{{EX:dc=example,dc=net}} subtree but is managed by the same entity
-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
-
-
-H3: Converting from slapd.conf(8) 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}}(5), loglevel 128 and {{slapacl}}(8) for debugging
+information.
 
 
 H2: Sets - Granting rights based on relationships
@@ -1118,7 +1323,7 @@ The end result is that when Jane accesses John's entry, she will be granted
 write access to the specified attributes. Better yet, this will happen to any
 entry she accesses which has Mary as the manager.
 
-This is all cool and nice, but perhaps gives to much power to secretaries. Maybe we need to further
+This is all cool and nice, but perhaps gives too much power to secretaries. Maybe we need to further
 restrict it. For example, let's only allow executive secretaries to have this power:
 
 > access to dn.exact="uid=john,ou=people,dc=example,dc=com"