Full_Name: Andrew Findlay
Version: HEAD 12 Jan 2009
OS: Linux
URL:
Submission from: (NULL) (88.97.25.132)
Using ACLs to make a non-leaf object non-disclosable does not protect
the subtree beneath that object.
This is not what most people would expect (if I cannot see a given object
then I would not expect to see things underneath it). It also provides
a handy attack on supposedly non-detectable entries.
For example, if I have a DIT like this:
dc=example,dc=org--+
+--dc=a--+
| +--dc=people--+
| +--cn=a1
|
+--dc=b--+
+--dc=people--+
+--cn=b1
and I give read access on dc=example,dc=org (base)
and on dc=a,dc=example,dc=org (subtree)
and dc=people,dc=b,dc=example,dc=org (subtree)
but no access at all on dc=b,dc=example,dc=org
then I would not expect to be able to read the cn=b1 entry, as doing so would
expose the existence of dc=b.
What actually happens is that any attempt to read dc=b itself returns
correctly as if the entry does not exist, but a simple subtree search
happily returns cn=b1.
The workaround is to make every entry in the dc=b subtree non-disclosable,
but this can be awkward in some ACL schemes.
I have tested this with both BDB and HDB and got identical results.
(I also tried to do it with IBM's ITDS and Sun's DSEE but they don't even
support the non-disclose concept...)
There is no RFC for LDAP ACLs so the 'correct' behaviour is debatable...
Here are the files:
--------------------------------- slapd.conf ---------------------------------
# Logging - this goes to syslog as 'local4'
#
# 512+256 to enable stats logging
#
loglevel 768
# Schema definitions
#
include ../../etc/schema/core.schema
include ../../etc/schema/cosine.schema
include ../../etc/schema/inetorgperson.schema
include ../../etc/schema/nis.schema
# These should have absolute pathnames on production systems
pidfile ./slapd.pid
argsfile ./slapd.args
########################################################################
# Default ACL
# (This is overridden by the per-database ACLs)
########################################################################
access to * by * read
########################################################################
#######################################################################
# The main database
#######################################################################
########################################################################
database hdb
suffix "dc=example,dc=org"
rootdn "cn=root,dc=example,dc=org"
password-hash {SSHA}
# Cleartext passwords, especially for the rootdn, should
# be avoided. See slappasswd(8) and slapd.conf(5) for details.
#
# The following two lines describe the same password:
# rootpw secret
# rootpw {SSHA}fFCeSYwjK/wERk1h4ceqYohqrGT/8VxJ
#
rootpw password
# The database directory MUST exist prior to running slapd AND
# should only be accessable by the slapd/tools. Mode 700 recommended.
# This should be an absolute pathname on production servers.
#
directory ./openldap-db
# Entry cache size
#
cachesize 4000
# How often we force a checkpoint on the underlying database
# kilobytes and seconds
#
checkpoint 128 300
########################################################################
# Indices to maintain
########################################################################
index objectClass eq
########################################################################
# ACLs for this database
########################################################################
include ./slapd.conf.acls
----------------------------- slapd.conf.acls ------------------------------
# Allow unconditional access to the base object
#
access to dn.exact="dc=example,dc=org"
by * read
# Allow read access to the whole of the A subtree
#
access to dn.subtree="dc=a,dc=example,dc=org"
by * read
# Allow read access to B's people, but not to B
#
access to dn.subtree="dc=people,dc=b,dc=example,dc=org"
by * read
access to * by * none
----------------------------- data LDIF -----------------------------------
########################################################################
# Create the base object
########################################################################
#
dn: dc=example,dc=org
objectclass: organization
objectclass: dcObject
o: The Example Org
dc: example
description: See-under test
########################################################################
# Create departments
########################################################################
# A
dn: dc=a,dc=example,dc=org
objectclass: organizationalUnit
objectclass: dcObject
ou: Department A
dc: a
dn: dc=people,dc=a,dc=example,dc=org
objectclass: organizationalUnit
objectclass: dcObject
ou: People
dc: people
# B
dn: dc=b,dc=example,dc=org
objectclass: organizationalUnit
objectclass: dcObject
ou: Department B
dc: b
dn: dc=people,dc=b,dc=example,dc=org
objectclass: organizationalUnit
objectclass: dcObject
ou: People
dc: people
########################################################################
# Create accounts
########################################################################
#
dn: cn=a1,dc=people,dc=a,dc=example,dc=org
objectclass: inetOrgPerson
cn: a1
sn: One
dn: cn=b1,dc=people,dc=b,dc=example,dc=org
objectclass: inetOrgPerson
cn: b1
sn: One
----------------------------- tests -----------------------------------------
# Search for dept A: this should work
ldapsearch -x -H ldap://:1389/ -b dc=example,dc=org dc=a
# Search for dept B: this should return zero results as B is protected by ACLs
ldapsearch -x -H ldap://:1389/ -b dc=example,dc=org dc=b
# Try starting at dept B: this should return 'no such object' as B is protected
by ACLs
ldapsearch -x -H ldap://:1389/ -b dc=b,dc=example,dc=org dc=b
# Search for a user in dept A: this should work
ldapsearch -x -H ldap://:1389/ -b dc=example,dc=org cn=a1
# Search for a user in dept B.
# This exposes the supposedly non-detectable department B...
ldapsearch -x -H ldap://:1389/ -b dc=example,dc=org cn=b1