Samba_4_SID_Allocation_using_DNA_Plugin#

Overview#

A security identifier (SID) is a unique value of variable length that is used to identify a security principal or security group in Active Directory/Samba. Each domain has an SID which is generated during setup. Each user/group has an SID which is generated when the user/group is created. The user/group SID is created by concatenating the domain SID with a relative identifier (RID).

A domain may contain multiple domain controllers (DC). To guarantee uniqueness across the entire domain, the RID must be obtained from an integer pool which is maintained by the DC where the user/group is being created.

Active Directory uses an RID Manager which resides on the master DC. The RID Manager is responsible for distributing non-overlapping RID pools to the DC’s. When a DC is running out of entries in its pool, it will request for a new pool from the RID Manager.

Currently Samba doesn’t have such RID Manager. Basically each Samba instances has a large pool but the range overlaps with other pools in other instances, meaning that SID conflicts can occur.

One solution is to implement an RID Manager similar to Active Directory, but this could take some time.

A faster solution is using the DNA plugin in Fedora DS to generate unique SID’s across DS instances. Unlike RID Manager, the DNA plugin doesn’t rely on a single master server.

SID Formats#

SID has both binary and string (human readable) formats. SID is stored in the directory in its binary format (i.e. objectSid attribute) but should be displayed in UI in its string format.

SID binary format:

<revision> <sub-authority count> <identifier authority> <sub-authority>*
  • revision: 1 byte

  • sub-authority count: 1 byte

  • identifier authority: 6 bytes (big-endian)

  • sub-authority: 4 bytes (little-endian)

SID string format:

S - <revision> - <identifier authority> [ - <sub-authority> ]*
  • revision: decimal

  • identifier authority: decimal

  • sub-authority: decimal

Consider the following domain SID in binaries:

01 04 00 00 00 00 00 05 15 00 00 00 01 d2 f9 89 aa 27 ba fc d8 a2 6c ff
Revision: 01 = 1
Sub-authority count: 04 = 4
Identifier authority: 00 00 00 00 00 05 = 000000000005 = 5
1st sub-authority: 15 00 00 00 = 00000015 = 21
2nd sub-authority: 01 d2 f9 89 = 89f9d201 = 2314850817
3rd sub-authority: aa 27 ba fc = fcba27aa = 4240058282
4th sub-authority: d8 a2 6c ff = ff6ca2d8 = 4285309656
The string representation of the domain SID is:
S-1-5-21-2314850817-4240058282-4285309656

The following user SID is generated by adding an RID (e.g. 1158) to the above domain SID:

01 05 00 00 00 00 00 05 15 00 00 00 01 d2 f9 89 aa 27 ba fc d8 a2 6c ff 86 04 00 00
Notice that the sub-authority count is now 5.
5th sub-authority: 86 04 00 00 = 00000486 = 1158
The string representation of the user SID is:
S-1-5-21-2314850817-4240058282-4285309656-1158

DNA Plugin#

DNA plugin provides a way to generate integer values that are unique across DS instances. These values are called managed values. A prefix can be specified so that it will be prepended to all managed values.

The DNA plugin can be used to generate SID values by splitting the SID in two parts:

  • prefix: domain SID (e.g. S-1-5-21-2314850817-4240058282-4285309656)

  • managed value: RID (e.g. 1158)

When a new user is added into the DS, the plugin will automatically assign a full SID value which consists of the domain SID and the RID.

Current Code#

SAM LDB Module#

Currently the SAM LDB module generates SID values for new users. The code is located in source4/dsdb/samdb/ldb_modules/samldb.c:

static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
{
    // check entry SID
    ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");

    if ( ! ac->sid) { // no entry SID specified

        // generate entry SID from domain SID and (next RID + 1)
        samldb_add_step(ac, samldb_new_sid);

    } else { // new entry contains SID

        // find domain object and next RID based on entry SID
        samldb_add_step(ac, samldb_get_sid_domain);
    }

    // increment next RID in the domain object
    samldb_add_step(ac, samldb_notice_sid);
}

Proposed Changes#

Samba Configuration#

A new parameter should be added into smb.conf to control how the SID will be generated:

[globals]
    sid generator = backend

Valid values:

  • internal: Samba will generate the SID and add it to the backend

  • backend: Backend will generate the SID

If the paramater is not specified, the default value should be “internal”.

The parameter should be defined in source4/param/loadparm.c:

enum sid_generator {
    SID_GENERATOR_INTERNAL=0,
    SID_GENERATOR_BACKEND=1
};

struct loadparm_global
{
    enum sid_generator sid_generator;
}

static const struct enum_list enum_sid_generator[] = {
    {SID_GENERATOR_INTERNAL, "internal"},
    {SID_GENERATOR_BACKEND, "backend"},
    {-1, NULL}
};

static struct parm_struct parm_table[] = {
    {"sid generator", P_ENUM, P_GLOBAL, GLOBAL_VAR(sid_generator), NULL, enum_sid_generator},

_PUBLIC_ FN_GLOBAL_INTEGER(lp_sid_generator, sid_generator)

SAM LDB Module#

The module should generate the SID values only when the “sid generator” parameter is set to “internal”:

static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
{
    sid_generator = lp_sid_generator(lp_ctx);
    if (sid_generator == SID_GENERATOR_INTERNAL) {

        // check entry SID
        ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");

        if ( ! ac->sid) { // no entry SID specified

            // generate entry SID from domain SID and (next RID + 1)
            samldb_add_step(ac, samldb_new_sid);

        } else { // new entry contains SID

            // find domain object and next RID based on entry SID
            samldb_add_step(ac, samldb_get_sid_domain);
        }

        // increment next RID in the domain object
        samldb_add_step(ac, samldb_notice_sid);
    }
}

Provisioning Tool#

The provisioning tool should generate the following configuration:

dn: cn=Samba SIDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
objectClass: top
objectClass: extensibleObject
cn: Samba SIDs
dnaType: sambaSID
dnaMaxValue: 10000
dnaMagicRegen: 0
dnaFilter: (|(objectClass=user)(objectClass=group))
dnaScope: ${DOMAINDN}
dnaNextValue: 1000
dnaSharedCfgDn: cn=Samba SIDs,ou=Ranges,${SAMBADN}
dnaPrefix: ${DOMAINSID}-

The plugin should be enabled:

dn: cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
changetype: modify
replace: nsslapd-pluginEnabled
nsslapd-pluginEnabled: on

The provisioning tool should also add a container entry for sharing SID ranges among multiple DS instances.

dn: ou=Ranges,${SAMBADN}
objectClass: top
objectClass: organizationalUnit
ou: Ranges

dn: ou=Ranges,${SAMBADN}
dn: cn=Samba SIDs,ou=Ranges,${SAMBADN}
objectClass: top
objectClass: nsContainer
cn: Object SIDs

Issues#

Samba currently stores the SID in DS in its binary format. However, the DNA plugin currently only supports generating integer and string attributes. The options are:

Patches#

The following patch has been applied to the source repository:

References#

Category:Obsolete