#51067 Ticket 51037 - RFE AD filter rewriter for ObjectSID
Closed 3 years ago by spichugi. Opened 4 years ago by tbordaz.
tbordaz/389-ds-base ticket_51037  into  master

@@ -1,33 +1,35 @@ 

  import pytest

  import glob

+ import base64

+ import re

  from lib389.tasks import *

+ from lib389.rewriters import *

+ from lib389.idm.user import UserAccounts

  from lib389.utils import *

  from lib389.topologies import topology_st

  

  from lib389._constants import DEFAULT_SUFFIX, HOST_STANDALONE, PORT_STANDALONE

  

+ samba_missing = False

+ try:

+     from samba.dcerpc import security

+     from samba.ndr import ndr_pack, ndr_unpack

+ except:

+     samba_missing = True

+     pass

+ 

  log = logging.getLogger(__name__)

  # Skip on versions 1.4.2 and before. Rewriters are expected in 1.4.3

  pytestmark = [pytest.mark.tier2,

                pytest.mark.skipif(ds_is_older('1.4.3'), reason="Not implemented")]

  

  PW = 'password'

- configuration_container = 'cn=Configuration,%s' % DEFAULT_SUFFIX

- schema_container = "cn=Schema,%s" % configuration_container

- 

- def _create_ad_objects_container(inst):

-     inst.add_s(Entry((

-         configuration_container, {

-             'objectClass': 'top nsContainer'.split(),

-             'cn': 'Configuration'

-         })))

-     inst.add_s(Entry((

-         schema_container, {

-             'objectClass': 'top nsContainer'.split(),

-             'cn': 'Schema'

-         })))

  

- def _create_user(inst, name, salt):

+ #

+ # Necessary because objectcategory relies on cn=xxx RDN

+ # while userAccount creates uid=xxx RDN

+ #

+ def _create_user(inst, schema_container, name, salt):

      dn = 'cn=%s,%s' % (name, schema_container)

      inst.add_s(Entry((

          dn, {
@@ -40,7 +42,6 @@ 

          })))

  

  

- 

  def test_adfilter_objectCategory(topology_st):

      """

      Test adfilter objectCategory rewriter function
@@ -48,15 +49,12 @@ 

  

      librewriters = os.path.join( topology_st.standalone.ds_paths.lib_dir, 'dirsrv/librewriters.so')

      assert librewriters

-     # register objectCategory rewriter

-     topology_st.standalone.add_s(Entry((

-         "cn=adfilter,cn=rewriters,cn=config", {

-             "objectClass": "top rewriterEntry".split(),

-             "cn": "adfilter",

-             "nsslapd-libpath": librewriters,

-             "nsslapd-filterrewriter": "adfilter_rewrite_objectCategory",

-         }

-     )))

+ 

+     rewriters = AdRewriters(topology_st.standalone)

+     ad_rewriter = rewriters.ensure_state(properties={"cn": "adfilter", "nsslapd-libpath": librewriters})

+     ad_rewriter.add('nsslapd-filterrewriter', "adfilter_rewrite_objectCategory")

+     ad_rewriter.create_containers(DEFAULT_SUFFIX)

+     schema_container = ad_rewriter.get_schema_dn()

  

      objectcategory_attr = '( NAME \'objectCategory\' DESC \'test of objectCategory\' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )'

      topology_st.standalone.schema.add_schema('attributetypes', [ensure_bytes(objectcategory_attr)])
@@ -64,9 +62,8 @@ 

      topology_st.standalone.restart(60)

  

      # Add a user

-     _create_ad_objects_container(topology_st.standalone)

      for i in range(0, 20):

-         _create_user(topology_st.standalone, "user_%d" % i, str(i))

+         _create_user(topology_st.standalone, schema_container, "user_%d" % i, str(i))

  

      # Check EQUALITY filter rewrite => it should match only one entry

      for i in range(0, 20):
@@ -83,3 +80,98 @@ 

  

      log.info('Test PASSED')

  

+ def sid_to_objectsid(sid):

+     return base64.b64encode(ndr_pack(security.dom_sid(sid))).decode('utf-8')

+ 

+ def objectsid_to_sid(objectsid):

+     sid = ndr_unpack(security.dom_sid, base64.b64decode(objectsid))

+     return str(sid)

+ 

+ @pytest.mark.skipif(samba_missing, reason="It is missing samba python bindings")

+ def test_adfilter_objectSid(topology_st):

+     """

+     Test adfilter objectCategory rewriter function

+ 

+     :id: fc5880ff-4305-47ba-84fb-38429e264e9e

+ 

+     :setup: Standalone instance

+ 

+     :steps:

+          1. add a objectsid rewriter (from librewriters.so)

+          2. add a dummy schema definition of objectsid to prevent nsslapd-verify-filter-schema

+          3. restart the server (to load the rewriter)

+          4. Add "samba" container/users

+          5. Searches using objectsid in string format

+ 

+     :expectedresults:

+          1. Add operation should PASS.

+          2. Add operations should PASS.

+          3. restart should PASS

+          4. Add "samba" users should PASS

+          5. Search returns only one entry

+     """

+     librewriters = os.path.join( topology_st.standalone.ds_paths.lib_dir, 'dirsrv/librewriters.so')

+     assert librewriters

+ 

+     rewriters = AdRewriters(topology_st.standalone)

+     ad_rewriter = rewriters.ensure_state(properties={"cn": "adfilter", "nsslapd-libpath": librewriters})

+     ad_rewriter.add('nsslapd-filterrewriter', "adfilter_rewrite_objectsid")

+     ad_rewriter.create_containers(DEFAULT_SUFFIX)

+     schema_container = ad_rewriter.get_schema_dn()

+ 

+     # to prevent nsslapd-verify-filter-schema to reject searches with objectsid

+     objectcategory_attr = '( NAME \'objectsid\' DESC \'test of objectsid\' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )'

+     topology_st.standalone.schema.add_schema('attributetypes', [ensure_bytes(objectcategory_attr)])

+ 

+     topology_st.standalone.restart()

+ 

+     # Contains a list of b64encoded SID from https://github.com/SSSD/sssd/blob/master/src/tests/intg/data/ad_data.ldif

+     SIDs = ["AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EUAQAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8E9gEAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EAwIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EBAIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EBgIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EBwIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EBQIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EAAIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EAQIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EAgIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ECAIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EKQIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EOwIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EPAIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ECQIAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8E8gEAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ETQQAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ETgQAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EeUMBAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EekMBAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8Ee0MBAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EfEMBAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ETwQAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EUQQAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ESUMBAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ESkMBAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ES0MBAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ETEMBAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8E9AEAAA==",

+             "AQUAAAAAAAUVAAAADcfLTVzC66zo0l8E9QEAAA=="]

+ 

+     # Add a container and "samba" like users containing objectsid

+     users = UserAccounts(topology_st.standalone, schema_container, rdn=None)

+     i = 0

+     for sid in SIDs:

+         decoded = base64.b64decode(sid)

+         user = users.create_test_user(uid=i)

+         user.add('objectclass', 'extensibleobject')

+         user.replace('objectsid', decoded)

+         user.replace('objectSidString', objectsid_to_sid(sid))

+         i = i + 1

+ 

+     # Check that objectsid rewrite can retrieve the "samba" user

+     # using either a string objectsid (i.e. S-1-5...) or a blob objectsid

+     for sid_blob in SIDs:

+         sid_string = objectsid_to_sid(sid_blob)

+         ents_sid_string = topology_st.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, '(objectsid=%s)' % sid_string)

+         assert len(ents_sid_string) == 1

+ 

file modified
+2 -2
@@ -315,8 +315,8 @@ 

  attributeTypes: ( 2.16.840.1.113730.3.1.2364 NAME 'nsds5replicaLastInitStatusJSON' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.2365 NAME 'nsds5replicaLastUpdateStatusJSON' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.2367 NAME 'nsslapd-libPath' DESC 'Rewriter shared library path' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

- attributeTypes: ( 2.16.840.1.113730.3.1.2368 NAME 'nsslapd-filterrewriter' DESC 'Filter rewriter function name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

- attributeTypes: ( 2.16.840.1.113730.3.1.2369 NAME 'nsslapd-returnedAttrRewriter' DESC 'Returned attribute rewriter function name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

+ attributeTypes: ( 2.16.840.1.113730.3.1.2368 NAME 'nsslapd-filterrewriter' DESC 'Filter rewriter function name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN '389 Directory Server' )

+ attributeTypes: ( 2.16.840.1.113730.3.1.2369 NAME 'nsslapd-returnedAttrRewriter' DESC 'Returned attribute rewriter function name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN '389 Directory Server' )

  attributeTypes: ( 2.16.840.1.113730.3.1.2370 NAME 'nsslapd-enable-upgrade-hash' DESC 'Upgrade password hash on bind' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )

  #

  # objectclasses

@@ -0,0 +1,92 @@ 

+ # --- BEGIN COPYRIGHT BLOCK ---

+ # Copyright (C) 2020 Red Hat, Inc.

+ # All rights reserved.

+ #

+ # License: GPL (version 3 or any later version).

+ # See LICENSE for details.

+ # --- END COPYRIGHT BLOCK ---

+ 

+ import collections

+ import ldap

+ import copy

+ import os.path

+ from lib389.utils import *

+ from lib389._entry import Entry

+ from lib389.idm.nscontainer import nsContainers

+ from lib389._mapped_object import DSLdapObjects, DSLdapObject

+ from lib389._constants import DEFAULT_SUFFIX

+ 

+ class Rewriter(DSLdapObject):

+     """A single instance of a rewriter entry

+ 

+     :param instance: An instance

+     :type instance: lib389.DirSrv

+     :param dn: Entry DN

+     :type dn: str

+     """

+ 

+     def __init__(self, instance, dn=None):

+         super(Rewriter, self).__init__(instance, dn)

+         self._rdn_attribute = 'cn'

+         self._must_attributes = ['nsslapd-libpath']

+         self._create_objectclasses = ['top', 'rewriterEntry']

+ 

+ 

+ class Rewriters(DSLdapObjects):

+     """A DSLdapObjects entity which represents rewriter entry

+ 

+     :param instance: An instance

+     :type instance: lib389.DirSrv

+     :param basedn: Base DN for all account entries below

+     :type basedn: str

+     """

+ 

+     def __init__(self, instance, basedn=None):

+         super(Rewriters, self).__init__(instance=instance)

+         self._objectclasses = ['top', 'rewriterEntry']

+         self._filterattrs = ['cn', 'nsslapd-libpath']

+         self._childobject = Rewriter

+         self._basedn = 'cn=rewriters,cn=config'

+         self._list_attrlist = ['dn', 'nsslapd-libpath']

+ 

+ 

+ class AdRewriter(Rewriter):

+     """An instance of AD rewriter entry

+ 

+     :param instance: An instance

+     :type instance: lib389.DirSrv

+     :param dn: Entry DN

+     :type dn: str

+     """

+ 

+     def __init__(self, instance, dn="cn=adrewriter,cn=rewriter,cn=config"):

+         super(AdRewriter, self).__init__(instance, dn)

+         self._configuration_dn = None

+         self._schema_dn = None

+ 

+     def create_containers(self, suffix):

+         conf_conts = nsContainers(self._instance, suffix)

+         conf_cont = conf_conts.ensure_state(properties={'cn': 'Configuration'})

+         schema_conts = nsContainers(self._instance, conf_cont.dn)

+         schema_cont = schema_conts.ensure_state(properties={'cn': 'Schema'})

+         self._configuration_dn = conf_cont.dn

+         self._schema_dn = schema_cont.dn

+ 

+     def get_schema_dn(self):

+         return self._schema_dn

+ 

+ 

+ class AdRewriters(Rewriters):

+     """A DSLdapObjects entity which represents AD rewriter entry

+ 

+     :param instance: An instance

+     :type instance: lib389.DirSrv

+     :param basedn: Base DN for all account entries below

+     :type basedn: str

+     """

+ 

+     def __init__(self, instance, basedn=None):

+         super(AdRewriters, self).__init__(instance=instance)

+         self._childobject = AdRewriter

+ 

+ 

file modified
+308 -2
@@ -21,9 +21,315 @@ 

  static char *rewriter_name = "filter rewriter adfilter";

  

  #define OBJECTCATEGORY "objectCategory"

+ #define OBJECTSID "objectSid"

  

  

- /* Rewrite ObjectCategory as described in [1]

+ /**********************************************************

+  * Rewrite ObjectSID

+  */

+ 

+ #define SID_ID_AUTHS 6

+ #define SID_SUB_AUTHS 15

+ typedef struct dom_sid {

+         uint8_t sid_rev_num;

+         int8_t num_auths;                  /* [range(0,15)] */

+         uint8_t id_auth[SID_ID_AUTHS];     /* highest order byte has index 0 */

+         uint32_t sub_auths[SID_SUB_AUTHS]; /* host byte-order */

+ } dom_sid_t;

+ 

+ typedef struct bin_sid {

+     uint8_t *sid;

+     size_t length;

+ } bin_sid_t;

+ 

+ /*

+  * Borrowed from SSSD

+  * src/lib/idmap/sss_idmap_conv.c:sss_idmap_dom_sid_to_bin_sid

+  * returns:

+  *   -1: if this is not a SID in dom_sid format

+  *    0: success

+  *    1: internal error

+  */

+ static int32_t

+ dom_sid_to_bin_sid(dom_sid_t *dom_sid, bin_sid_t *res)

+ {

+     bin_sid_t bin_sid = {0};

+     size_t p = 0;

+     uint32_t val;

+ 

+     if (res == NULL) {

+         return 1;

+     }

+     if (dom_sid->num_auths > SID_SUB_AUTHS) {

+         return -1;

+     }

+     bin_sid.length = 2 + SID_ID_AUTHS + dom_sid->num_auths * sizeof(uint32_t);

+ 

+     bin_sid.sid = (uint8_t *) slapi_ch_calloc(1, bin_sid.length);

+     if (bin_sid.sid == NULL) {

+         return 1;

+     }

+ 

+     bin_sid.sid[p] = dom_sid->sid_rev_num;

+     p++;

+ 

+     bin_sid.sid[p] = dom_sid->num_auths;

+     p++;

+ 

+     for (size_t i = 0; i < SID_ID_AUTHS; i++) {

+         bin_sid.sid[p] = dom_sid->id_auth[i];

+         p++;

+     }

+ 

+     for (size_t i = 0; i < dom_sid->num_auths; i++) {

+         if ((p + sizeof(uint32_t)) > bin_sid.length) {

+             return -1;

+         }

+         val = htole32(dom_sid->sub_auths[i]);

+         memcpy(&bin_sid.sid[p], &val, sizeof(val));

+         p += sizeof(val);

+     }

+     res->sid = bin_sid.sid;

+     res->length = bin_sid.length;

+ 

+     return 0;

+ }

+ /*

+  * Borrowed from SSSD

+  * src/lib/idmap/sss_idmap_conv.c:sss_idmap_sid_to_dom_sid

+  * returns:

+  *   -1: if this is not a SID in string format

+  *    0: success

+  *    1: internal error

+  */

+ static int32_t

+ str_sid_to_dom_sid(char *sid_string, dom_sid_t *res)

+ {

+     dom_sid_t sid = {0};

+     uint64_t ul;

+     char *r, *end;

+ 

+     if (res == NULL) {

+         return 1;

+     }

+ 

+     if ((sid_string == NULL) || strncasecmp(sid_string, "S-", 2)) {

+         return -1;

+     }

+ 

+     /* Here we have a string SID i.e.: S-1-2-4..

+      * S-X-2-3-4..  X is sid_rev_num 8bits

+      */

+     if (!isdigit(sid_string[2])) {

+         return -1;

+     }

+     ul =  (uint64_t) strtoul(sid_string + 2, &r, 10);

+     if (r == NULL || *r != '-' || ul > UINT8_MAX) {

+         return -1;

+     }

+     sid.sid_rev_num = (uint8_t) ul;

+     r++;

+ 

+     /* r points to 2-3-4..

+      * '2' is used for the id_auth

+      */

+     ul = strtoul(r, &r, 10);

+     if (r == NULL || ul > UINT32_MAX) {

+         return -1;

+     }

+ 

+     /* id_auth in the string should always be <2^32 in decimal */

+     /* store values in the same order as the binary representation */

+     sid.id_auth[0] = 0;

+     sid.id_auth[1] = 0;

+     sid.id_auth[2] = (ul & 0xff000000) >> 24;

+     sid.id_auth[3] = (ul & 0x00ff0000) >> 16;

+     sid.id_auth[4] = (ul & 0x0000ff00) >> 8;

+     sid.id_auth[5] = (ul & 0x000000ff);

+ 

+     /* Now r point the the sub_auth

+      * There are maximum of 15 sub_auth (SID_SUB_AUTHS): -3-4-5...*/

+     if (*r == '\0') {

+         /* no sub auths given */

+         return 0;

+     }

+     if (*r != '-') {

+         return -1;

+     }

+     do {

+         if (sid.num_auths >= SID_SUB_AUTHS) {

+             return -1;

+         }

+ 

+         r++;

+         if (!isdigit(*r)) {

+             return -1;

+         }

+ 

+         ul = strtoul(r, &end, 10);

+         if (ul > UINT32_MAX || end == NULL || (*end != '\0' && *end != '-')) {

+             return -1;

+         }

+ 

+         sid.sub_auths[sid.num_auths++] = ul;

+ 

+         r = end;

+     } while (*r != '\0');

+ 

+     memcpy(res, &sid, sizeof(sid));

+     return 0;

+ }

+ 

+ /*

+  * Callback to rewrite string objectSid

+  * Borrowed from SSSD sss_idmap_sid_to_bin_sid

+  */

+ static int

+ substitute_string_objectsid(Slapi_Filter *f, void *arg)

+ {

+     char *filter_type;

+     struct berval *bval;

+     char *newval;

+     char logbuf[1024] = {0};

+     int32_t rc;

+     char *objectsid_string_header="S-";

+     dom_sid_t dom_sid = {0};

+     bin_sid_t bin_sid = {0};

+     int32_t loglevel;

+ 

+     /* If (objectSid=S-1-2-3-4..) --> (objectSid=<binary representation of S-1-2-3-4..> */

+     if ((slapi_filter_get_ava(f, &filter_type, &bval) == 0) &&

+         (slapi_filter_get_choice(f) == LDAP_FILTER_EQUALITY) &&

+         (bval->bv_val) &&

+         (strcasecmp(filter_type, OBJECTSID) == 0) &&

+         (strncasecmp(bval->bv_val, objectsid_string_header, strlen(objectsid_string_header)) == 0)) {

+         /* This filter component is "(objectsid=S-..) let's try to convert it */

+ 

+         rc = str_sid_to_dom_sid(bval->bv_val, &dom_sid);

+         switch (rc) {

+         case -1:

+             /* This is not a valid string objectSid */

+             slapi_log_err(SLAPI_LOG_ERR, rewriter_name, "substitute_string_objectsid component %s : is not a valid string sid\n",

+                           slapi_filter_to_string(f, logbuf, sizeof (logbuf)));

+ 

+             /* do not rewrite this component but continue with the others */

+             return SLAPI_FILTER_SCAN_CONTINUE;

+         case 1:

+             /* internal error while converting string objectSid */

+             slapi_log_err(SLAPI_LOG_ERR, rewriter_name, "substitute_string_objectsid component %s : fail to convert into dom_sid a string sid\n",

+                           slapi_filter_to_string(f, logbuf, sizeof (logbuf)));

+ 

+             /* do not rewrite this component but continue with the others */

+             return SLAPI_FILTER_SCAN_CONTINUE;

+         default:

+                 /* go through */

+             break;

+         }

+         rc = dom_sid_to_bin_sid(&dom_sid, &bin_sid);

+         switch (rc) {

+         case -1:

+             /* This is not a valid dom objectSid */

+             slapi_log_err(SLAPI_LOG_ERR, rewriter_name, "substitute_string_objectsid component %s : is not a valid dom sid\n",

+                           slapi_filter_to_string(f, logbuf, sizeof (logbuf)));

+ 

+             /* do not rewrite this component but continue with the others */

+             return SLAPI_FILTER_SCAN_CONTINUE;

+         case 1:

+             /* internal error while converting dom objectSid */

+             slapi_log_err(SLAPI_LOG_ERR, rewriter_name, "substitute_string_objectsid component %s : fail to convert into binary sid a dom sid\n",

+                           slapi_filter_to_string(f, logbuf, sizeof (logbuf)));

+ 

+             /* do not rewrite this component but continue with the others */

+             return SLAPI_FILTER_SCAN_CONTINUE;

+         default:

+                 /* go through */

+             break;

+         }

+         loglevel = LDAP_DEBUG_ANY;

+         if (loglevel_is_set(loglevel)) {

+             char logbuf[100] = {0};

+             char filterbuf[1024] = {0};

+             char *valueb64, *valueb64_sav;

+             size_t lenb64;

+             size_t maxcopy;

+ 

+             if (sizeof(logbuf) <= ((bin_sid.length * 2) + 1)) {

+                 maxcopy = (sizeof(logbuf)/2) - 1;

+             } else {

+                 maxcopy = bin_sid.length;

+             }

+ 

+             for (size_t i = 0, j = 0; i < maxcopy; i++) {

+                 PR_snprintf(logbuf + j, 3, "%02x", bin_sid.sid[i]);

+                 j += 2;

+             }

+             lenb64 = LDIF_SIZE_NEEDED(strlen("encodedb64"), bin_sid.length);

+             valueb64 = valueb64_sav = (char *) slapi_ch_calloc(1, lenb64 + 1);

+             slapi_ldif_put_type_and_value_with_options(&valueb64, "encodedb64", (const char *)bin_sid.sid, bin_sid.length, LDIF_OPT_NOWRAP);

+ 

+             slapi_log_err(SLAPI_LOG_INFO, rewriter_name, "substitute_string_objectsid component %s : 0x%s (%s)\n",

+                           slapi_filter_to_string(f, filterbuf, sizeof (filterbuf)),

+                           logbuf,

+                           valueb64_sav);

+             slapi_ch_free_string(&valueb64_sav);

+         }

+         slapi_ch_free_string(&bval->bv_val);

+         /* It consums the value returned by dom_sid_to_bin_sid

+          * setting it into the bval it will be later freed

+          * when the filter will be freed

+          */

+         bval->bv_val = bin_sid.sid;

+         bval->bv_len = bin_sid.length;

+     }

+ 

+     /* Return continue because we should

+      * substitute 'from' in all filter components

+      */

+     return SLAPI_FILTER_SCAN_CONTINUE;

+ }

+ 

+ /*

+  * This is a filter rewriter function for 'ObjectSid' attribute

+  *

+  * Its rewriter config entry looks like

+  * dn: cn=adfilter,cn=rewriters,cn=config

+  * objectClass: top

+  * objectClass: extensibleObject

+  * cn: adfilter

+  * nsslapd-libpath: /lib/dirsrv/librewriters

+  * nsslapd-filterrewriter: adfilter_rewrite_objectsid

+  */

+ int32_t

+ adfilter_rewrite_objectsid(Slapi_PBlock *pb)

+ {

+     Slapi_Filter *clientFilter = NULL;

+     Slapi_DN *sdn = NULL;

+     int error_code = 0;

+     int rc;

+     char *strFilter;

+ 

+     slapi_pblock_get(pb, SLAPI_SEARCH_FILTER, &clientFilter);

+     slapi_pblock_get(pb, SLAPI_SEARCH_STRFILTER, &strFilter);

+     slapi_pblock_get(pb, SLAPI_SEARCH_TARGET_SDN, &sdn);

+ 

+     if (strFilter && (strcasestr(strFilter, OBJECTSID) == NULL)) {

+         /* accelerator: returns if filter string does not contain objectSID */

+         return SEARCH_REWRITE_CALLBACK_CONTINUE;

+     }

+     /* Now apply substitute_string_objectsid on each filter component */

+     rc = slapi_filter_apply(clientFilter, substitute_string_objectsid, NULL /* no arg */, &error_code);

+     if (rc == SLAPI_FILTER_SCAN_NOMORE) {

+         return SEARCH_REWRITE_CALLBACK_CONTINUE; /* Let's others rewriter play */

+     } else {

+         slapi_log_err(SLAPI_LOG_ERR,

+                       "adfilter_rewrite_objectSid", "Could not update the search filter - error %d (%d)\n",

+                       rc, error_code);

+         return SEARCH_REWRITE_CALLBACK_ERROR; /* operation error */

+     }

+ }

+ 

+ /*********************************************************

+  * Rewrite OBJECTCATEGORY as described in [1]

   * [1] https://social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx#Filter_on_objectCategory_and_objectClass

   * static char *objectcategory_shortcuts[] = {"person", "computer", "user", "contact", "group", "organizationalPerson", NULL};

   */
@@ -77,7 +383,7 @@ 

   * objectClass: top

   * objectClass: extensibleObject

   * cn: adfilter

-  * nsslapd-libpath: librewriters

+  * nsslapd-libpath: /lib/dirsrv/librewriters

   * nsslapd-filterrewriter: adfilter_rewrite_objectCategory

   */

  int32_t

Bug Description:
AD provides flexibility, to AD clients, to use string representation of objectSID
(for example S-1-5-21-1305200397-1234-1234-1234)
To support AD client using 'ObjectSid' shortcut, we need a 389-ds filter rewriters that
translate the filter '(objectSid=S-1-5-21-1305200397-1234-1234-1234)' into '(objectSid=<objectsid blob>)'
before processing the filter
see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-ada3/afac8414-c614-4c6a-b316-41f5978308bd

Fix Description:
This patch uses the new ability to registers rewriters (https://pagure.io/389-ds-base/issue/50980)
It implements a new callback filter rewriter adfilter_rewrite_objectsid in librewriters.so

https://pagure.io/389-ds-base/issue/51037

Reviewed by: ?

Platforms tested: F30

Flag Day: no

Doc impact: no

Since we are trying to use the correct int types, then shouldn't this be uint64_t?

rebased onto 484d8fe3f185ddb48b5d0c96ee172930d308ff20

4 years ago

Shouldn't we add the proper lib389 types here for filter rewriters as part of config, so that we can later expose them via the cli?

nitpick, you don't need to define a restart timeout anymore

You can define this in the for loop with for (size_t i ...) to prevent scope issues.

I'd like to see some other tests here, like invalid format sids, really long ones, too short, etc. We want to make sure that we test these edge cases :)

Otherwise it's looking good, thanks @tbordaz

The restart is to take into consideration the new rewriter (rewriters_init called by main). I think it would be possible to make it dynamic but I prefer to do it on a separate ticket if there is a need.

Anticipating this point ;). I had a doubt because 'i' is used in two loops. I can imagine the compiler will optimize this but I was not sure.
To make the code easier to read I will do that change, just stop me if it exists a concern to declare 'i' in two loops.

This is because 'rc' is the returned code of slapi-filter_apply that is a 'int'.

Where specifically would you implement rewriters in lib389 ?

That's not what I meant @tbordaz, you don't need the 60 in the restart, the timeout has a default value.

Also, you should never re-use an 'i' between loops incase you DONT reset it between them, so it's always better to have them seperate and per-loop.

We should comment about that int then I think ....

Where specifically would you implement rewriters in lib389 ?

Make a new rewriters.py similar to plugins I think?

I see that you allocate a memory here but I am not sure where you free it... Have you checked with ASAN?

Both test cases add cn=adfilter,cn=rewriters,cn=config and do some other stuff (like this line).
I checked and the second test case fails if we run the whole test suite as py.test dirsrvtests/tests/suites/rewriters/adfilter_test.py.

rebased onto a12aacc1aff50b4cf14dd59a3e62427ef0987254

3 years ago

@spichugi you were right.. there was a leak ! Thanks for catching that. @firstyear I created a new lib389 rewriters library. Regarding running all the tests, the creation AD container/config entry is now in the lib389 rewriter and protected with try/except ALREADY_EXIST.

This doesn't seem right. Have a look at: https://pagure.io/389-ds-base/blob/master/f/src/lib389/lib389/idm/group.py#_26 for more. You should not need to call .add_s or Entry at all in a subclass of DSLdapObject. You should specify a "template" of what it looks like, and then calls to ".create" should work.

Similar here, you shouldn't need modify_s, you should be able to call self.replace I think.

rebased onto 9fe862ff72d8b0aabe3eadb2df0b30d66d0d9fea

3 years ago

Thank you sooo much @spichugi for your help !
Patch updated

Is this supposed to be commented out? If so, can it just be removed?

rebased onto f49568794b1d1971e82be8748e30492f199c30cb

3 years ago

Oppsss I missed this one. Done

I think this is no longer needed as you can get the DN with get_schema_dn function (I think you need to fix def _create_user(inst, name, salt): dn = 'cn=%s,%s' % (name, schema_container) in the tests so schema_container is acquired using get_schema_dn.

The rest looks good to me! Thanks!

rebased onto 3516495

3 years ago

Great! You have my ack, at least:)

Pull-Request has been merged by tbordaz

3 years ago

389-ds-base is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in 389-ds-base's github repository.

This pull request has been cloned to Github as issue and is available here:
- https://github.com/389ds/389-ds-base/issues/4120

If you want to continue to work on the PR, please navigate to the github issue,
download the patch from the attachments and file a new pull request.

Thank you for understanding. We apologize for all inconvenience.

Pull-Request has been closed by spichugi

3 years ago