How SID to uid/gid mapping works in sssd – code analysis?

This is my first article on important topic of Linux OS integration with Active Directory. In fact this can become a really difficult issue even in simple infrastructure, but it becomes very complex in big company environment, with a few domains in the tree and non-uniform AD architecture. I hope that this article is only the first one from the series which in total will provide a comprehensive overview of difficulties one can encounter working on sssd configuration.

Because of the dominant role of Microsoft operating systems on desktops it may be not possible to add unix attributes to Active Directory. Impact analysis of such change on AD in global environment, need to establish procedures on specific unix attributes setup, formal agreements between different IT services suppliers can end up in situation where we have to map Windows SID to unix attributes algorithmically. It’s possible to configure consistent mapping for multiple domains across multi host infrastructure, however, there are some non-obvious requirements successful admin have to be aware of.

How SID to uid/gid mapping in sssd works

Each configured domain is assigned a range of possible uid/gid values called a slice. The algorithm responsible for picking up appropriate slice for mapped unix attributes is implemented in sss_idmp.c[1] in sss_idmap_calculate_range function. The function get’s slice number as a pointer to integer.  If value passed to the function in *slice_number equals to -1 then the function will calculate the “proposition” for slice number, otherwise *slice_number is treated as “proposition”. In second step it verifies if “proposed” slice isn’t in use if it is it tries next slice and repeats this procedure as long as it’s needed to allocate slice for this domain, or fails if no more slices are available. The proposition for slice can be simply 0, which will end up with old samba rid algorithm behavior, or number calculated by passing domain SID to murmur hash algorithm [2] and then subjecting result to modulus operation to pick up uid/gid slice.

Important thing to understand is that there is no guarantee to have consistent uid/gid mapping on multiple hosts. For samba rid it is defined by slice assignment order, for “murmurhash+modulus” there is only a probability of consistent assignment that increase with number of slices.

The only way to be 100% sure which slice will be used is to configure ldap_idmap_default_domain_sid in sssd.conf. This option allows zero slice enforcement. Checking implementation of this mechanism in sdap_idmap.c [3] we will see another fine kettle of fish

/* Set the default domain as slice 0 */
ret = sdap_idmap_add_domain(idmap_ctx, dom_name,sid_str, 0);

last argument of sdap_idmap_add_domain is the slice number that will be used to calculate attributes mapping for this domain. Take note that sss_idmap_calculate_range executed with specified slice number (other than -1) doesn’t check if this is already in use, it just calculates range parameters for this slice. What’s wrong with it? The default domain is configured per domain in sssd.conf, if one set different values of ldap_idmap_default_domain_sid for different domains we may end up with conflicting uid/gid mapping(I’ve addressed this in pull request [4]). Where will the conflict occur? Actual attribute mapping is done in comp_id function by

id = range_params->min_id + (rid - range_params->first_rid);

From what we see above we learn what the actual value of unix id will be. It is beginning of the slice plus rid? No! We see that range parameter first_rid is subtracted from RID. This logic allows sssd to map domain to smaller slice then number of RIDs in domain, but it requires dynamic allocation of uid/gid ranges. However, range parameters assignment happens in previously mentioned sss_idmap_calculate_range function and the “use next if already in use” logic. This means that for ranges smaller than actual RID range mapping depends on calls order and should be avoided to achieve coherent results across multiple servers.

After the detailed discussion of sid to unix mappings one can guess important implication of dynamic allocation of ranges. Mapping from unix attributes to AD objects may fail if we didn’t have opposite direction nsswitch call before. This happens because in sss_idmap_unix_to_sid we iterate over ctx->idmap_domain_info list, so the code will even not try to map unix attribute to SID, because the unix attribute may be from the range that was not yet allocated. In current code state uid/gid to other attributes mapping will work after first “sid2unix” in the range of interest, with the one exception for primary slice of default domain – this rage is initiated on sssd start.

It’s important to know that mapping information is stored in persistent cache by sssd, so it survives reboots. However, due to multiple issues with sssd cache admins used to remove it during the restart with simple rm -rf /var/lib/sss/{mc,db}/*.

You may also be interested in video post on this topic:
[VLOG]How sssd maps sid to uid/gid
[VLOG] How to configure sssd idmap parameters to get minimal collision probability
Next posts about sssd and AD integration:
How sssd updates machine account password?



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s