lldap/lldap

[FEATURE REQUEST] Return schema in RootDSE for better compatibility with Apache Directory Studio Browser

Opened this issue · 6 comments

Motivation
I want to be able to use Apache Directory Studio Browser to browse LLDAP server

Describe the solution you'd like
When creating the connection to LLDAP in Apache Directory Studio, you must enter the baseDN manually because LLDAP is "Missing schema location in RootDSE" and the baseDN(s) cannot be fetched.

I can make this work half way by creating two connections and manually identifying one baseDN as ou=people,dc=example,dc=com or ou=groups,dc=example,dc=com. However, they must be separate connections. It would be nice if there was an OU one level up or some other way to identify the baseDN. Even better would be for that baseDN to be fetchable by the Apache Directory Studio.

I don't know that much about rootDSE and how to respond with the schema. In the spirit of my limited time and to avoid reading the RFC, could you provide an example of a rootDSE response you'd like to see?

I am not too sure myself. I actually only extremely recently made myself familiar with LDAP because I wanted to use your tool in my homelab, and I had needs for work.

Some searching came up with what I think might be a good explanation of rootDSE here: link

What I think this means is that there is no schema returned when it (Apache Directory Studio) tries to fetch the root of the directory server.

What this results in is the following error message.
image

Also, if there is no "namespaceless" root, then Apache Directory Studio is restricted to a connection to LLDAP that has a baseDN of ou=people,dc=example,dc=com or ou=groups,dc=example,dc=com, but not both in the same connection. I think it is looking for a level above.

I hope this clarifies. I could also be way off base as I am very very new to this stuff and may not have any idea what I am talking about, but I am trying to learn.

By the way... I really like your LLDAP tool. It is amazing for small homelabs to dip feet into LDAP. My friends and I that are on the homelab journey together are enjoying its use. I appreciate the hard work.

@Firstyear hey, do you know what's needed in the rootDSE for this? I made the minimum effort to be compliant, but this is stretching my knowledge.

I guess I need to declare and implement the DC level above the OUs, and declare a schema?

I'll save you the trouble of reading the (whole) RFC:

https://www.rfc-editor.org/rfc/rfc4512#section-4.4

"""
To discover the DN of the subschema (sub)entry holding the subschema
controlling a particular entry, a client reads that entry's
'subschemaSubentry' operational attribute. To read schema attributes
from the subschema (sub)entry, clients MUST issue a Search operation
[RFC4511] where baseObject is the DN of the subschema (sub)entry,
scope is baseObject, filter is "(objectClass=subschema)" [RFC4515],
and the attributes field lists the names of the desired schema
attributes (as they are operational). Note: the
"(objectClass=subschema)" filter allows LDAP servers that gateway to
X.500 to detect that subentry information is being requested.
"""

So this really glosses over whats going on.

In the rootdse you have:

# ldapsearch -H ldap://172.17.0.2:3389 -x -b '' -s base \* +
...
dn:
objectClass: top
subschemaSubentry: cn=schema
...

subschemaSubentry is operational, so only return it on + or when requested.

The client then searches with that as the base dn, you just respond with a single entry with a ton of attributes representing the schema.

These entries are defined in https://www.rfc-editor.org/rfc/rfc4512#section-4.2 again with the usual level of "specific but not clear" as we would expect from an LDAP rfc.

And easy way to "cheat" and check this would be to look at what something else does. So here's an ldif I prepared for you.

ldapsearch -H ldap://172.17.0.2:3389 -x -b 'cn=schema' -s base '(objectClass=subschema)' \+

# schema
dn: cn=schema
objectClasses: ( 2.5.6.0 NAME 'top' ABSTRACT MUST objectClass X-ORIGIN 'RFC 4512' )
objectClasses: ( 2.5.6.1 NAME 'alias' SUP top STRUCTURAL MUST aliasedObjectName X-ORIGIN 'RFC 4512' )
objectClasses: ( 2.5.20.1 NAME 'subschema' AUXILIARY MAY ( dITStructureRules $ nameForms $ dITContentRules $ objectClasses $ attributeTypes $ matchingRules $ matchingRuleUse ) X-ORIGIN 'RFC 4512' )
objectClasses: ( 1.3.6.1.4.1.1466.101.120.111 NAME 'extensibleObject' SUP top AUXILIARY X-ORIGIN 'RFC 4512' )
...
attributeTypes: ( 2.16.840.1.113730.3.1.2384 NAME 'passwordTPRDelayValidFrom' DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN '389 Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.582 NAME 'nsDS5ReplicaCredentials' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s) who may  run sudo' EQUALITY caseExactMatch SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'SUDO' )
attributeTypes: ( 2.16.840.1.113730.3.1.2274 NAME 'nsslapd-instancedir' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
attributeTypes: ( 2.16.840.1.113719.1.301.4.24.1 NAME 'krbHostServer'  EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributeTypes: ( 1.3.18.0.2.4.1139 NAME 'printer-info' DESC 'Descriptive information about this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'rfc3712' )
....
matchingRules: ( 2.5.13.17 NAME 'octetStringMatch' DESC 'The octetStringMatch rule compares an assertion value of the Octet String syntax to an attribute value of a syntax (e.g., the Octet String or JPEG syntax) whose cor
responding ASN.1 type is the OCTET STRING ASN.1 type.  The rule evaluates to TRUE if and only if the attribute value and the assertion value are the same length and corresponding octets (by position) are the same.' SYNTAX
 1.3.6.1.4.1.1466.115.121.1.40 )
matchingRules: ( 2.5.13.18 NAME 'octetStringOrderingMatch' DESC 'The octetStringOrderingMatch rule compares an assertion value of the Octet String syntax to an attribute value of a syntax (e.g., the Octet String or JPEG s
yntax) whose corresponding ASN.1 type is the OCTET STRING ASN.1 type.  The rule evaluates to TRUE if and only if the attribute value appears earlier in the collation order than the assertion value.  The rule compares octe
t strings from the first octet to the last octet, and from the most significant bit to the least significant bit within the octet.  The first occurrence of a different bit determines the ordering of the strings.  A zero b
it precedes a one bit.  If the strings contain different numbers of octets but the longer string is identical to the shorter string up to the length of the shorter string, then the shorter string precedes the longer strin
g.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
...
ldapSyntaxes: ( 2.16.840.1.113730.3.7.1 DESC 'SpaceInsensitiveString' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'TelephoneNumber' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )
ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )

Oh, geez, it's more complicated than I thought... I was hoping for adding a couple of lines to the hardcoded rootDSE 😅

Thanks a lot!

but for once it's not twice as complicated as it should be.