Debugging OpenLDAP ACLs

OpenLDAP provides a super powerful ACL syntax which allows you to control access to every nook and cranny of your directory server. When I’m testing advanced ACL configurations I have found it incredibly useful to add the “ACL” log option to the loglevel directive:

loglevel ACL

When this option is set slapd will show you how it applies the ACLs to a given LDAP operation:

Dec  4 09:01:00 rocco slapd[6026]: => acl_mask: access to entry "ou=users,dc=prefetch,dc=net", attr "entry" requested
Dec  4 09:01:00 rocco slapd[6026]: => acl_mask: to all values by "", (=0) 
Dec  4 09:01:00 rocco slapd[6026]: <= check a_dn_pat: users
Dec  4 09:01:00 rocco slapd[6026]: <= check a_peername_path: 1.2.3.4
Dec  4 09:01:00 rocco slapd[6026]: <= acl_mask: [2] applying read(=rscxd) (stop)
Dec  4 09:01:00 rocco slapd[6026]: <= acl_mask: [2] mask: read(=rscxd)
Dec  4 09:01:00 rocco slapd[6026]: => slap_access_allowed: search access granted by read(=rscxd)
Dec  4 09:01:00 rocco slapd[6026]: => access_allowed: search access granted by read(=rscxd)
Dec  4 09:01:00 rocco slapd[6026]: => access_allowed: search access to "cn=matty,ou=users,dc=prefetch,dc=net" "uid" requested

This is super handy and will save you tons of time and heartburn when crafting complex ACLs.

LDAP indexes

LDAP indexes are extremely useful for speeding up directory searches, and come in four flavors (there are actually more than four index types, but the following four are the most common):

1 Approximate indexes

Approximate indexes are useful for speeding up seaches that look for attribute values that sound like a specific value. A good example of this is searching the directory for all first names that sound like “Amy”:

$ ldapsearch -b “dc=prefetch,dc=net” -w -D “cn=Directory Manager” ‘givenName~=Amy’

2. Equality indexes

Equality indexes are useful for speed up searches that perform a direct comparison. The following search would benefit from an equality index:

$ ldapsearch -b “dc=prefetch,dc=net” -w -D “cn=Directory Manager” ‘uid=matty’

3. Presence indexes

Presence indexes are useful for speeding up searches for entries that contain a specific attribute. The following search looks for all entries that contain the cn attribute, and would be a good fit for a presence index:

$ ldapsearch -b “dc=prefetch,dc=net” -w -D “cn=Directory Manager” ‘cn=*’

4. Substring indexes

Substring indexes are the most complex index type to maintain, but are useful for speeding up searches that look for substrings. The following search will return all entries where the uid attribute contains the string “foo”, and would be a good fit for a substring index:

$ ldapsearch -b “dc=prefetch,dc=net” -w -D “cn=Directory Manager” ‘uid=*foo*’

Figuring out which indexes to use is actually pretty easy, since most directory servers will tell you that an unindexed search was performed. If you want to determine indexes manually, your best bet is reviewing the logfiles to see which searches are perfomed, and then creating indexes based on your findings.

Compiling openldap on Solaris hosts

Building OpenLDAP on Solaris hosts that use /opt as their software repository can sometimes be a chore. In case anyone finds this useful, here is the procedure I use:

$ LD_LIBRARY_PATH=/opt/openssl/lib:/opt/BerkeleyDB/lib:/usr/sfw/lib:/usr/lib
$ export LD_LIBRARY_PATH

$ export LDFLAGS=”-L/opt/BerkeleyDB/lib -L/opt/openssl/lib”
$ export LDFLAGS

$ export CPPFLAGS=”-I/opt/BerkeleyDB/include -I/opt/openssl/include”
$ export CPPFLAGS

$ configure –prefix=/opt/openldap-2.3.24 –enable-bdb –with-tls –enable –monitor –disable-ipv6

$ make depend && make

Finding BIND failures in OpenLDAP logfiles

When OpenLDAP is configured to log connection information, a RESULT entry is written with the status (e.g., success or failure) of the last BIND:

$ grep RESULT openldap.log | head -1
Dec 28 21:05:01 winnie slapd[7101]: [ID 217296 local4.debug] conn=25 op=0 RESULT tag=97 err=0 text=

The “err=” string contains zero if the BIND was successful, and an error code if the BIND didn’t complete successfully. The error codes are defined in “LDAPResult.h,” which is included with the OpenLDAP source code. When a BIND fails because the credentials were invalid, the error string will contain the value 49:

$ grep “err=49” openldap.log | head -1

Dec 29 12:22:00 winnie slapd[7101]: [ID 217296 local4.debug] conn=27 op=0 RESULT tag=97 err=49 text=

To get the DN that tried to BIND, you can grep the connection number (the value after conn=) out of the OpenLDAP logfile:

$ grep “conn=27.*BIND” openldap.log
Dec 29 12:22:00 winnie slapd[7101]: [ID 347666 local4.debug] conn=27 op=0 BIND dn=”cn=mail,dc=synackfin,dc=com” method=128

You can get the IP address of the host that initiated the BIND by grepping the connection id, along with the ACCEPT keyword, from the OpenLDAP logfile:

$ grep “conn=27.*ACCEPT” openldap.log
Dec 29 12:22:00 winnie slapd[7101]: [ID 848112 local4.debug] conn=27 fd=11 ACCEPT from IP=192.168.1.2:39749 (IP=192.168.1.2:636)

This is useful for tracking down folks who are poking around your directory server.

Checking for OpenLDAP unindexed searches

I was checking my openldap logfiles today, and noticed that the “cn” attribute wasn’t indexed. I found this by checking for the “index_param” string in my OpenLDAP logfiles:

$ grep “index_param failed” /var/log/openldap

Dec 25 13:37:19 winnie slapd[730]: [ID 635189 local4.debug] < = bdb_substring_candidates: (cn) index_param failed (18) To fix this problem, I added an "index" statement to my slapd.conf: index cn,mail,sn eq,pres,sub Once the index was added, I rebuilt the indexes with the "slapdindex" utility: $ slapindex -f /usr/local/openldap-common/etc/slapd.conf -b “dc=synackfin,dc=com”

The OpenLDAP documentation has more info in case your interested in learning more:

http://www.openldap.org/doc/admin22/