Detecting POSIX attributes in Global Catalog using the Partial Attribute Set

Problem statement

In some environments with SSSD clients joined directly to an Active Directory realm, replicating POSIX attributes such as uidNumber, gidNumber or unixHomeDirectory to the Global Catalog might provide a substantial performance benefit. As an example, if the numerical IDs are replicated to the Global Catalog, then the SSSD is able to locate the domain the ID resides in without iterating over the other domains.

However, the POSIX attributes are not replicated by default, so the SSSD must check whether the attributes are replicated or not. There was a straightforward check in SSSD which just ran a lookup for any entry with POSIX attributes since several versions ago. In large environments, though, this check was very inefficient and causing a high load on the servers.

This design page describes a different method of detecting the POSIX attributes by inspecting the AD schema instead.

Use cases

An SSSD client joined to an Active Directory domain directly. The AD domain must be using POSIX attributes for user and group IDs, the changes in this design page are irrelevant for domains that use ID mapping.

Overview of the solution

Instead of issuing a wide search for any object that contains the uidNumber or gidNumber attribute, the SSSD will consult the Partial Attribute Set which defines what attributes are replicated to the Global Catalog. Which attributes are members of the Partial Attribute Set is described below.

In general terms, all attributes in the Active Directory schema are represented by objects with the objectclass attributeSchema.

The attributeSchema objects as well as all objectclasses are exposed through a subtree called the Schema Naming Context

The Schema Naming Context is exposed typically at the cn=schema,cn=configuration,$FOREST_BASE_DN subtree, but its location is most portably read from the schemaNamingContext attribute of the rootDSE. One important thing to note about the Schema Naming Context is that its location is the same across all DCs in the forest.

Each attribute is represented as an object under the schema subtree and whether the attribute is replicated into the Global Catalog or not is denoted by the isMemberOfPartialAttributeSet attribute value.

This search in an example domain called might be issues with:

ldapsearch -LLL -Y GSSAPI \
           -H ldap:// \
           -b cn=schema,cn=configuration,dc=win,dc=trust,dc=test \
           '(|(cn=uidNumber)(cn=gidNumber))' \

And the result, this time showing that neither attribute was replicated to the Global Catalog might look like:

dn: CN=GidNumber,CN=Schema,CN=Configuration,DC=win,DC=trust,DC=test
isMemberOfPartialAttributeSet: FALSE

dn: CN=UidNumber,CN=Schema,CN=Configuration,DC=win,DC=trust,DC=test
isMemberOfPartialAttributeSet: FALSE

As said earlier, the Schema Naming Context is the same across all domains in the forest, so the search against a DC in a child domain would work as well even though it’s also based at CN=Configuration,DC=win,DC=trust,DC=test:

ldapsearch -Y GSSAPI \
           -H ldap:// \
           -b CN=Schema,CN=Configuration,DC=win,DC=trust,DC=test
           '(|(cn=uidNumber)(cn=gidNumber))' \

Implementation details

First, the rootDSE parsing code must be extended to read the schemaNamingContext attribute from the rootDSE object and store it in the sdap_options structure.

The search itself will be issued in the subdomains provider. Placing the search in the subdomains provider instead of the handlers or the searches makes it possible to remove much of the previous code as the subdomains provider request is guaranteed to be executed before any user or group request except for cases where the subdomains provider is explicitly disabled with subdomains_provider=none, but in that case it makes little sense to use the Global Catalog in the first place.

Because of the property of the schema partition being replicated to all DCs in the forest, the search can always be run after the SSSD connects to the joined domain which triggers reading the rootDSE.

If neither or only one of the attributes would be found, the Global Catalog support will be disabled. The same would happen in the case that the check fails with an error as the Global Catalog itself is not required for SSSD to function at least in a degraded mode.

The search as described in the previous section would be issued using the LDAP connection, in particular the connection to the joined domain. The LDAP connection must be used because the isMemberOfPartialAttributeSet attribute is typically not replicated to the Global Catalog itself.

The old request (sdap_gc_posix_check_send) can probably just be completely removed.

Configuration changes


How To Test

With an AD client that uses ID mapping, the request should not be ran at all. The same is true if the Global Catalog support is explicitly disabled by setting ad_enable_gc=false.

With an AD client that uses POSIX attributes, the subdomains provider should include a search such as:

[sdap_get_generic_ext_step] (0x0400): calling ldap_search_ext with [(&(objectclass=attributeSchema)(|(cn=uidNumber)(cn=gidNumber)))][cn=schema,cn=configuration,DC=win,DC=trust,DC=test]
[sdap_get_generic_ext_step] (0x1000): Requesting attrs: [cn]
[sdap_get_generic_ext_step] (0x1000): Requesting attrs: [isMemberOfPartialAttributeSet]

If this search does not match the uidNumber and gidNumber schema objects or of the objects are not replicated to the global catalog, the Global Catalog support would be disabled irrespective of the ad_enable_gc configuration option value.

How To Debug

The request is decorated with debug messages as usual. In addition to looking at the usual debug logs, netstat might be a handy tool to check what port is SSSD connecting to.