User Tools

Site Tools


ldap:compat_win_unix

Info SID RID UID GID, compatibility Windows/UNIX with AD

UNIX and Linux are compliants to RFC 2307 to manage groups and users. Windows natively doesn't use the same.

Windows is using a SID for all components user, groups, computers on local and in the active directory.

Unix / Linux are using UID (User ID) and GID (Group ID), which are not natively available into Windows Active Directory.

https://viralmutant.wordpress.com/2015/10/22/the-automatic-id-mapping-module-with-active-directory-configuration-autorid/

https://man.archlinux.org/man/sssd-ad.5.en

Linux ID-mapping

The automatic ID-mapping module with Active Directory configuration – “autorid”

“ID-mapping” What’s that?

It’s basically the identity mapping, that is mapping an SID from Windows world to a UID/GID from the Unix world when CIFS data is being accessed on Spectrum Scale.

SID, short for Security identifier, is a unique and immutable identifier for a user or group from Windows operating system. It consists of a domain identifier plus an object identifier (RID) which is unique within that domain. Similarly, UID/GID is the short for user/group identifier from Unix operating system. You may read further about SIDs, UIDs and GIDs from other sources all over the net 🙂

And why do we care?

The underlying filesystem for Spectrum Scale is GPFS. It being a UNIX like filesystem identifies and grants access to the resources based upon the UID/GID only. While CIFS access the SIDs for your user/group needs to be associated with a UID/GID on GPFS to allow access. If for some reason, the mapping fails, the user/group is simply denied access.

Note: Henceforth, I’ll just use xID to mean both UID and GID, unless explicitly stated.

This association between SID and xID is what we refer to as an ID-map. The xID assigned to you on Spectrum Scale will decide what data you may access, depending upon the ACLs on the data.

On Spectrum Scale, the CIFS stack is provided by Samba. And the ID-mapping component is the winbind process. This process is responsible to assign xID for each incoming SID.

There are many ID-mapping schemes built into this process but here, in this post we will talk about only one – the ‘autorid’ mapping backend.

When you use the ‘mmuserauth service create –data-access-method file’ to configure Active Directory authentication, the default ID-mapping algorithm is provided by this ‘autorid’ backend.

RTFM Let’s start from the man page

That’s the right place to begin with. Here are few snippets, with my inline blabbering 🙂

“It automatically configures the range to be used for each domain, so there is no need to specify a specific range for each domain in the forest,

the only configuration that is needed is the range of uid/gids that shall be used for user/group mappings and an optional size of the ranges to be used.

Due to the algorithm being used, it is the module that is most easy to use as it only requires a minimal configuration.”

Yeah, for each new domain it encounters, it assigns a range to assign xID for the users/groups of that domain, provided it has those many ranges available.

And “it requires minimal configuration” that is also true. Just provide it a single, huge pool (range) of IDs from which it has to cut and assign slots to each of the new domain it sees. And the way it has been designed, it may even assign more than one slots to the same domain for reasons I’ll explain below. We call that feature, multi-range support for a domain. The original autorid backend did not have this feature. It was added in some later Samba release and I was personally involved in designing the algorithm behind it 😉

Algorithm – What the F#&# ?

I’ll try to explain the algorithm with an example. Let’s look at the default configuration achieved after executing ‘mmuserauth service create’ command which resides in samba registry which can be listed with ‘net conf list’:

$ /usr/lpp/mmfs/bin/net conf list | grep idmap

  idmap config * : backend = autorid
  idmap config * : range = 10000000 – 299999999
  idmap config * : rangesize = 1000000

Dissecting it line by line:

  • : backend = autorid : This defines that all the incoming domains(*) should be mapped by autorid algorithm
  • : range = 10000000 – 299999999 : This is the huge pool which we are talking about. Ranges are cut out of this pool and assigned to the domains
  • : rangesize = 1000000 : This is the size for each range(slot) from the pool. The RID part of the SID should fit within this range. If it doesn’t then we do some maths to fit it within that range

Let’s do some maths 🙂

  Number of ranges which are available out of the huge pool, defined by rangesize is given by formula:
      ( Upper limit – Lower limit + 1 ) / rangesize        # Consider only the quotient part, disregard the remainder

That means we have ( 299999999 – 10000000 + 1 ) / 1000000 = 290 ranges available with the default configuration. Each of the range has a rangesize 1000000

0th range: 10000000 – 10999999

1st range: 11000000 – 11999999

2nd range: 12000000 – 12999999

289th range: 299000000 – 299999999

Careful observers may notice that we have kept the weird value of 2999… just to keep the division clean, without any remainders, which anyways would be disregarded 😉

So we have plenty of ranges available. But how are they allocated ?

The algorithm is whenever you encounter an SID, divide the RID with the rangesize.

Look at the quotient part of the division and check in the database if we already have a range/slot allocated for this domain with this quotient.

If found, then take that range and add the remainder (from the division) to the lower value of the range to get the xID.

If not found, then check if we have a new range/slot available. If yes, then take that range and add the remainder from the division to get the xID. Also record this domain sid with this quotient and the range in the database for future queries

To understand this we will take some random SIDs as examples:

Example 1:

Say we encounter an SID, S-1-5-21-917267712-1342860078-1792151419-500 where the RID is 500 and domain SID is S-1-5-21-917267712-1342860078-1792151419

Playing the algorithm, divide RID with rangesize, 500 with 1000000.

Quotient = 0

Remainder = 500

It looks up the database to see if domain S-1-5-21-917267712-1342860078-1792151419 is already assigned range for quotient 0 and could not find any.

It checks if we have a range available for allocation

It picks up the next available range, 10000000 – 10999999, 0th in this case and assigns that to this combo.

To get the xID, add the remainder(500) to the lower value of range(10000000) = 10000000 + 500 = 10000500

And it saves a record in the db of the type:

Key: <domain-sid>#<quotient>

Value: <range-number>

In this case:

  Key: S-1-5-21-917267712-1342860078-1792151419
  Value: 0

And also records the next available range-number, 1 in the db

Notes:

  If the quotient is 0, there is no #<quotient> part in the key. One might ask why ?

Well, backward compatibility. As I said that earlier there used to be only a single range assigned to each domain SID. So the ‘Key’ did not have any #<num> in the earlier format. And while adding a feature of multi-range support, we had to keep in mind that ID mapping still works for existing xIDs, after upgrades.

  The range could be reverse calculated from the range number:
  Range begins = Lower value of the global pool + <range-number> * rangesize
  Range ends = Range begins + rangesize -1
  Eg. For 0th range-number
  Range begins = 10000000 + 0 * 1000000 = 10000000
  Range ends = 10000000 + 1000000 – 1 = 10999999
  There is also an entry where Key and Value are interchanged which will help us in reverse lookup of finding domain from xID

Example 2:

We encounter another SID from same domain, S-1-5-21-917267712-1342860078-1792151419-1500

RID: 1500

Domain SID: S-1-5-21-917267712-1342860078-1792151419

Playing the algorithm, divide RID with rangesize, 1500 with 1000000

Quotient = 0

Remainder = 1500

It looks up the database to see if domain S-1-5-21-917267712-1342860078-1792151419 is already assigned range for quotient 0 and finds a hit

Reading the range-number, it can calculate the range 10000000 – 10999999

To get the xID, add the remainder(1500) to the lower value of range(10000000) = 10000000 + 1500 = 10001500

Example 3:

We encounter another SID from same domain, S-1-5-21-917267712-1342860078-1792151419-5000934

RID: 5000934

Domain SID: S-1-5-21-917267712-1342860078-1792151419

Playing the algorithm, divide RID with rangesize, 5000934 with 1000000

Quotient = 5

Remainder = 934

It looks up the database to see if domain S-1-5-21-917267712-1342860078-1792151419 is already assigned range for quotient 5 and could not find any

It picks up the next available range, 11000000 – 11999999, 1st in this case and assigns that to this combo.

To get the xID, add the remainder(934) to the lower value of range(11000000) = 11000000 + 934 = 11000934

And it saves a record in the db of the type:

  Key: S-1-5-21-917267712-1342860078-1792151419#5
  Value: 1

And also records the next available range-number, 2nd in the db

And this is what I meant by multi-range support for a domain. Where a domain gets 2 ranges assigned. Earlier this was not the case and such SIDs would be denied access

Example 4:

We encounter an SID from another domain, S-1-5-21-007967712-9342860078-1003151419-2999999

RID: 2999999

Domain SID: S-1-5-21-007967712-9342860078-1003151419

Playing the algorithm, divide RID with rangesize, 2999999 with 1000000

Quotient = 2

Remainder = 999999

It looks up the database to see if domain S-1-5-21-007967712-9342860078-1003151419 is already assigned range for quotient 2 and could not find any

It picks up the next available range, 12000000 – 12999999, 2nd in this case and assigns that to this combo.

To get the xID, add the remainder(999999) to the lower value of range(12000000) = 12000000 + 999999 = 12999999

And it saves a record in the db of the type:

  Key: S-1-5-21-007967712-9342860078-1003151419#2
  Value: 2

And also records the next available range-number, 3rd in the db

That’s it, it’s that simple 😉

And all these values can be seen in the autorid.tdb on the Spectrum Scale cluster, using ‘/usr/lpp/mmfs/bin/ctdb catdb autorid.tdb’ command

And the same algorithm can be worked backwards to find the domain SID for an incoming xID when winbind needs to lookup User/Group names from xIDs.

Example 1:

Let’s take the same xID we calculated, 11000934, to get back the domain SID

To get the range number from this xID, first subtract the global pool lower value = 11000934 – 10000000 = 1000934

Then divide this by the rangesize = 1000934 / 1000000

Quotient = 1

Remainder = 934

Then lookup the autorid db with Key: 1, where it finds:

Key: 1

Value: S-1-5-21-917267712-1342860078-1792151419#5

Domain SID: S-1-5-21-917267712-1342860078-1792151419

To get the RID, consider the #<quotient> part:

  5 * rangesize + remainder = 5 * 1000000 + 934 = 5000934

Complete SID: S-1-5-21-917267712-1342860078-1792151419-5000934

Example 2:

Let’s take the same xID we calculated, 10000500, to get back the domain SID

To get the range number from this xID, first subtract the global pool lower value = 10000500– 10000000 = 500

Then divide this by the rangesize = 500 / 1000000

Quotient = 0

Remainder = 500

Then lookup the autorid db with Key: 0, where it finds:

Key: 0

Value: S-1-5-21-917267712-1342860078-1792151419

Domain SID: S-1-5-21-917267712-1342860078-1792151419

To get the RID, consider the #<quotient> part:

  0 * rangesize + remainder = 0 * 1000000 + 500 = 500

Complete SID: S-1-5-21-917267712-1342860078-1792151419-500

Now that the secret is out, it’s pure maths and some db records manipulations

A short note on ‘mmuserauth service create’:

I took the example of 0th, 1st, 2nd range just for explanation. In production, these couple of ranges are reserved by winbind process for internal use.

The default value works fine in most cases. Rarely would you come across cases where you need to modify these values using –idmap-range and –idmap-range-size parameter.

There are some limitations on what can be modified by this command. The things which are absolutely fixed, once defined, are ‘rangesize’ and ‘lower value of global pool’.

Since these form the basis of all calculations, once the system is configured with some value for these attributes, trying to modify those will result in unable to regenerate the same xID.

Which eventually means loss of access to existing data.

We don’t allow decreasing the ‘upper value of global pool’ because that means in reducing the number of available slots and we don’t know if that is already assigned to some domain.

So by rerunning this command, you can only increase the upper value of global pool to make more slots available, in-case you run short.

Next blog entry would be on the ‘RFC 2307’ idmapping module, which we developed to query xIDs from LDAP server. It was specifically requested to support Centrify with winbind. But we developed it to work with any LDAP server which is RFC 2307 compliant. An irony, Centrify itself deviates from RFC 2307 schema standards for couple of things and we had to bend to support our customer. Anything for business 😉 Aye !! Who doesn’t love dollars

ldap/compat_win_unix.txt · Last modified: 2022/03/14 18:31 by manu