From 3516495c77c89594c7f6b817fa1db7ac72a2c516 Mon Sep 17 00:00:00 2001 From: Thierry Bordaz Date: May 18 2020 15:36:37 +0000 Subject: Ticket 51037 - RFE AD filter rewriter for ObjectSID 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=)' 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: Mark Reynolds, Alexander Bokovoy, Simon Pichugin, William Brown (Thanks !) Platforms tested: F30 Flag Day: no Doc impact: no --- diff --git a/dirsrvtests/tests/suites/rewriters/adfilter_test.py b/dirsrvtests/tests/suites/rewriters/adfilter_test.py index d2256d6..3f86314 100644 --- a/dirsrvtests/tests/suites/rewriters/adfilter_test.py +++ b/dirsrvtests/tests/suites/rewriters/adfilter_test.py @@ -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 _create_user(inst, name, salt): }))) - def test_adfilter_objectCategory(topology_st): """ Test adfilter objectCategory rewriter function @@ -48,15 +49,12 @@ def test_adfilter_objectCategory(topology_st): 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 @@ def test_adfilter_objectCategory(topology_st): 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 @@ def test_adfilter_objectCategory(topology_st): 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 + diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif index b5478cb..d1063a4 100644 --- a/ldap/schema/01core389.ldif +++ b/ldap/schema/01core389.ldif @@ -315,8 +315,8 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2084 NAME 'nsSymmetricKey' DESC 'A symme 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 diff --git a/src/lib389/lib389/rewriters.py b/src/lib389/lib389/rewriters.py new file mode 100644 index 0000000..885725c --- /dev/null +++ b/src/lib389/lib389/rewriters.py @@ -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 + + diff --git a/src/rewriters/adfilter.c b/src/rewriters/adfilter.c index 35125fc..f3cec16 100644 --- a/src/rewriters/adfilter.c +++ b/src/rewriters/adfilter.c @@ -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= */ + 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 @@ substitute_shortcut(Slapi_Filter *f, void *arg) * objectClass: top * objectClass: extensibleObject * cn: adfilter - * nsslapd-libpath: librewriters + * nsslapd-libpath: /lib/dirsrv/librewriters * nsslapd-filterrewriter: adfilter_rewrite_objectCategory */ int32_t