From dde5b629534c87b4e49f39df32190c05ba941a87 Mon Sep 17 00:00:00 2001 From: Thierry Bordaz Date: Mar 08 2016 10:06:47 +0000 Subject: Ticket 48746: Crash when indexing an attribute with a matching rule Bug Description: When creating a mr_indexer, we first look at the registered MR (global_mr_oids). If the indexer is not registered or have no indexer create function, we try - to find a plugin (possibly a custom one) that could provide such indexer create. - use a default indexer The problem is that going through the matching rule plugins, we pick the first one with an indexer even if it applies to a different syntax. For example, searching for an caseExactIA5Match MR plugin we select caseIgnoreIA5Match because it appears first in the plugins list. The consequence is that we may index with the wrong index function (and trigger https://fedorahosted.org/389/ticket/48745) and picking a wrong indexer_create (or filter_create) function the MR private in the pblock (SLAPI_PLUGIN_OBJECT) can be NULL (https://fedorahosted.org/389/ticket/48746). Also we can imagine an incorrect custom MR plugin that forgets to set this MR private object and could trigger a crash. So use of MR private object should check if it was set. Fix Description: The fix is: slapi_mr_indexer_create: plugin_mr_filter_create: If there is no register MR for a specific oid, we search a plugin that can handle that oid (plugin_mr_find). mr_wrap_mr_index_sv_fn: mr_wrap_mr_index_fn: default_mr_filter_match: default_mr_filter_index: hardening if a custom plugin index_create function did not set SLAPI_PLUGIN_OBJECT https://fedorahosted.org/389/ticket/48746 Reviewed by: Rich Megginson (thanks Rich for all help/feedback and the review) Platforms tested: F17 Flag Day: no Doc impact: no --- diff --git a/dirsrvtests/tests/tickets/ticket48745_test.py b/dirsrvtests/tests/tickets/ticket48745_test.py new file mode 100644 index 0000000..bfbaf03 --- /dev/null +++ b/dirsrvtests/tests/tickets/ticket48745_test.py @@ -0,0 +1,185 @@ +import os +import sys +import time +import ldap +import logging +#import pytest +from lib389 import DirSrv, Entry, tools, tasks +from lib389.tools import DirSrvTools +from lib389._constants import * +from lib389.properties import * +from lib389.tasks import * +from lib389.utils import * + +logging.getLogger(__name__).setLevel(logging.DEBUG) +log = logging.getLogger(__name__) + +installation1_prefix = None + +NEW_ACCOUNT = "new_account" +MAX_ACCOUNTS = 20 + +MIXED_VALUE="/home/mYhOmEdIrEcToRy" +LOWER_VALUE="/home/myhomedirectory" +HOMEDIRECTORY_INDEX = 'cn=homeDirectory,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config' +HOMEDIRECTORY_CN="homedirectory" +MATCHINGRULE = 'nsMatchingRule' +UIDNUMBER_INDEX = 'cn=uidnumber,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config' +UIDNUMBER_CN="uidnumber" + + +class TopologyStandalone(object): + def __init__(self, standalone): + standalone.open() + self.standalone = standalone + + +@pytest.fixture(scope="module") +def topology(request): + global installation1_prefix + if installation1_prefix: + args_instance[SER_DEPLOYED_DIR] = installation1_prefix + + # Creating standalone instance ... + standalone = DirSrv(verbose=False) + if installation1_prefix: + args_instance[SER_DEPLOYED_DIR] = installation1_prefix + args_instance[SER_HOST] = HOST_STANDALONE + args_instance[SER_PORT] = PORT_STANDALONE + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX + args_standalone = args_instance.copy() + standalone.allocate(args_standalone) + instance_standalone = standalone.exists() + if instance_standalone: + standalone.delete() + standalone.create() + standalone.open() + + # Delete each instance in the end + def fin(): + standalone.delete() + #request.addfinalizer(fin) + + # Clear out the tmp dir + standalone.clearTmpDir(__file__) + + return TopologyStandalone(standalone) + +def test_ticket48745_init(topology): + log.info("Initialization: add dummy entries for the tests") + for cpt in range(MAX_ACCOUNTS): + name = "%s%d" % (NEW_ACCOUNT, cpt) + topology.standalone.add_s(Entry(("uid=%s,%s" % (name, SUFFIX), { + 'objectclass': "top posixAccount".split(), + 'uid': name, + 'cn': name, + 'uidnumber': str(111), + 'gidnumber': str(222), + 'homedirectory': "/home/tbordaz_%d" % cpt}))) + +def test_ticket48745_homeDirectory_indexed_cis(topology): + log.info("\n\nindex homeDirectory in caseIgnoreIA5Match and caseExactIA5Match") + try: + ent = topology.standalone.getEntry(HOMEDIRECTORY_INDEX, ldap.SCOPE_BASE) + except ldap.NO_SUCH_OBJECT: + topology.standalone.add_s(Entry((HOMEDIRECTORY_INDEX, { + 'objectclass': "top nsIndex".split(), + 'cn': HOMEDIRECTORY_CN, + 'nsSystemIndex': 'false', + 'nsIndexType': 'eq'}))) + #log.info("attach debugger") + #time.sleep(60) + + IGNORE_MR_NAME='caseIgnoreIA5Match' + EXACT_MR_NAME='caseExactIA5Match' + mod = [(ldap.MOD_REPLACE, MATCHINGRULE, (IGNORE_MR_NAME, EXACT_MR_NAME))] + topology.standalone.modify_s(HOMEDIRECTORY_INDEX, mod) + + #topology.standalone.stop(timeout=10) + log.info("successfully checked that filter with exact mr , a filter with lowercase eq is failing") + #assert topology.standalone.db2index(bename=DEFAULT_BENAME, suffixes=None, attrs=['homeDirectory']) + #topology.standalone.start(timeout=10) + args = {TASK_WAIT: True} + topology.standalone.tasks.reindex(suffix=SUFFIX, attrname='homeDirectory', args=args) + + log.info("Check indexing succeeded with a specified matching rule") + file_path = os.path.join(topology.standalone.prefix, "var/log/dirsrv/slapd-%s/errors" % topology.standalone.serverid) + file_obj = open(file_path, "r") + + # Check if the MR configuration failure occurs + regex = re.compile("unknown or invalid matching rule") + while True: + line = file_obj.readline() + found = regex.search(line) + if ((line == '') or (found)): + break + + if (found): + log.info("The configuration of a specific MR fails") + log.info(line) + assert 0 + +def test_ticket48745_homeDirectory_mixed_value(topology): + # Set a homedirectory value with mixed case + name = "uid=%s1,%s" % (NEW_ACCOUNT, SUFFIX) + mod = [(ldap.MOD_REPLACE, 'homeDirectory', MIXED_VALUE)] + topology.standalone.modify_s(name, mod) + +def test_ticket48745_extensible_search_after_index(topology): + name = "uid=%s1,%s" % (NEW_ACCOUNT, SUFFIX) + + # check with the exact stored value + log.info("Default: can retrieve an entry filter syntax with exact stored value") + ent = topology.standalone.getEntry(SUFFIX, ldap.SCOPE_SUBTREE, "(homeDirectory=%s)" % MIXED_VALUE) +# log.info("attach debugger") +# time.sleep(60) + + # This search will fail because a + # subtree search with caseExactIA5Match will find a key + # where the value has been lowercase + log.info("Default: can retrieve an entry filter caseExactIA5Match with exact stored value") + ent = topology.standalone.getEntry(SUFFIX, ldap.SCOPE_SUBTREE, "(homeDirectory:caseExactIA5Match:=%s)" % MIXED_VALUE) + assert ent + + # But do additional searches.. just for more tests + # check with a lower case value that is different from the stored value + log.info("Default: can not retrieve an entry filter syntax match with lowered stored value") + try: + ent = topology.standalone.getEntry(SUFFIX, ldap.SCOPE_SUBTREE, "(homeDirectory=%s)" % LOWER_VALUE) + assert ent is None + except ldap.NO_SUCH_OBJECT: + pass + log.info("Default: can not retrieve an entry filter caseExactIA5Match with lowered stored value") + try: + ent = topology.standalone.getEntry(SUFFIX, ldap.SCOPE_SUBTREE, "(homeDirectory:caseExactIA5Match:=%s)" % LOWER_VALUE) + assert ent is None + except ldap.NO_SUCH_OBJECT: + pass + log.info("Default: can retrieve an entry filter caseIgnoreIA5Match with lowered stored value") + ent = topology.standalone.getEntry(SUFFIX, ldap.SCOPE_SUBTREE, "(homeDirectory:caseIgnoreIA5Match:=%s)" % LOWER_VALUE) + +def test_ticket48745(topology): + """Write your testcase here... + + Also, if you need any testcase initialization, + please, write additional fixture for that(include finalizer). + """ + + log.info('Test complete') + + +if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode +# global installation1_prefix +# installation1_prefix = None +# topo = topology(True) +# test_ticket48745_init(topo) +# +# test_ticket48745_homeDirectory_indexed_cis(topo) +# test_ticket48745_homeDirectory_mixed_value(topo) +# test_ticket48745_extensible_search_after_index(topo) + + CURRENT_FILE = os.path.realpath(__file__) + pytest.main("-s %s" % CURRENT_FILE) diff --git a/dirsrvtests/tests/tickets/ticket48746_test.py b/dirsrvtests/tests/tickets/ticket48746_test.py new file mode 100644 index 0000000..5ee0b9e --- /dev/null +++ b/dirsrvtests/tests/tickets/ticket48746_test.py @@ -0,0 +1,213 @@ +import os +import sys +import time +import ldap +import logging +#import pytest +from lib389 import DirSrv, Entry, tools, tasks +from lib389.tools import DirSrvTools +from lib389._constants import * +from lib389.properties import * +from lib389.tasks import * +from lib389.utils import * + +logging.getLogger(__name__).setLevel(logging.DEBUG) +log = logging.getLogger(__name__) + +installation1_prefix = None + +NEW_ACCOUNT = "new_account" +MAX_ACCOUNTS = 20 + +MIXED_VALUE="/home/mYhOmEdIrEcToRy" +LOWER_VALUE="/home/myhomedirectory" +HOMEDIRECTORY_INDEX = 'cn=homeDirectory,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config' +HOMEDIRECTORY_CN="homedirectory" +MATCHINGRULE = 'nsMatchingRule' +UIDNUMBER_INDEX = 'cn=uidnumber,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config' +UIDNUMBER_CN="uidnumber" + + +class TopologyStandalone(object): + def __init__(self, standalone): + standalone.open() + self.standalone = standalone + + +@pytest.fixture(scope="module") +def topology(request): + global installation1_prefix + if installation1_prefix: + args_instance[SER_DEPLOYED_DIR] = installation1_prefix + + # Creating standalone instance ... + standalone = DirSrv(verbose=False) + if installation1_prefix: + args_instance[SER_DEPLOYED_DIR] = installation1_prefix + args_instance[SER_HOST] = HOST_STANDALONE + args_instance[SER_PORT] = PORT_STANDALONE + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX + args_standalone = args_instance.copy() + standalone.allocate(args_standalone) + instance_standalone = standalone.exists() + if instance_standalone: + standalone.delete() + standalone.create() + standalone.open() + + # Delete each instance in the end + def fin(): + standalone.delete() + #request.addfinalizer(fin) + + # Clear out the tmp dir + standalone.clearTmpDir(__file__) + + return TopologyStandalone(standalone) + +def test_ticket48746_init(topology): + log.info("Initialization: add dummy entries for the tests") + for cpt in range(MAX_ACCOUNTS): + name = "%s%d" % (NEW_ACCOUNT, cpt) + topology.standalone.add_s(Entry(("uid=%s,%s" % (name, SUFFIX), { + 'objectclass': "top posixAccount".split(), + 'uid': name, + 'cn': name, + 'uidnumber': str(111), + 'gidnumber': str(222), + 'homedirectory': "/home/tbordaz_%d" % cpt}))) + +def test_ticket48746_homeDirectory_indexed_cis(topology): + log.info("\n\nindex homeDirectory in caseIgnoreIA5Match and caseExactIA5Match") + try: + ent = topology.standalone.getEntry(HOMEDIRECTORY_INDEX, ldap.SCOPE_BASE) + except ldap.NO_SUCH_OBJECT: + topology.standalone.add_s(Entry((HOMEDIRECTORY_INDEX, { + 'objectclass': "top nsIndex".split(), + 'cn': HOMEDIRECTORY_CN, + 'nsSystemIndex': 'false', + 'nsIndexType': 'eq'}))) + #log.info("attach debugger") + #time.sleep(60) + + IGNORE_MR_NAME='caseIgnoreIA5Match' + EXACT_MR_NAME='caseExactIA5Match' + mod = [(ldap.MOD_REPLACE, MATCHINGRULE, (IGNORE_MR_NAME, EXACT_MR_NAME))] + topology.standalone.modify_s(HOMEDIRECTORY_INDEX, mod) + + #topology.standalone.stop(timeout=10) + log.info("successfully checked that filter with exact mr , a filter with lowercase eq is failing") + #assert topology.standalone.db2index(bename=DEFAULT_BENAME, suffixes=None, attrs=['homeDirectory']) + #topology.standalone.start(timeout=10) + args = {TASK_WAIT: True} + topology.standalone.tasks.reindex(suffix=SUFFIX, attrname='homeDirectory', args=args) + + log.info("Check indexing succeeded with a specified matching rule") + file_path = os.path.join(topology.standalone.prefix, "var/log/dirsrv/slapd-%s/errors" % topology.standalone.serverid) + file_obj = open(file_path, "r") + + # Check if the MR configuration failure occurs + regex = re.compile("unknown or invalid matching rule") + while True: + line = file_obj.readline() + found = regex.search(line) + if ((line == '') or (found)): + break + + if (found): + log.info("The configuration of a specific MR fails") + log.info(line) + assert not found + +def test_ticket48746_homeDirectory_mixed_value(topology): + # Set a homedirectory value with mixed case + name = "uid=%s1,%s" % (NEW_ACCOUNT, SUFFIX) + mod = [(ldap.MOD_REPLACE, 'homeDirectory', MIXED_VALUE)] + topology.standalone.modify_s(name, mod) + +def test_ticket48746_extensible_search_after_index(topology): + name = "uid=%s1,%s" % (NEW_ACCOUNT, SUFFIX) + + # check with the exact stored value +# log.info("Default: can retrieve an entry filter syntax with exact stored value") +# ent = topology.standalone.getEntry(name, ldap.SCOPE_BASE, "(homeDirectory=%s)" % MIXED_VALUE) +# log.info("attach debugger") +# time.sleep(60) + + # This search is enought to trigger the crash + # because it loads a registered filter MR plugin that has no indexer create function + # following index will trigger the crash + log.info("Default: can retrieve an entry filter caseExactIA5Match with exact stored value") + ent = topology.standalone.getEntry(name, ldap.SCOPE_BASE, "(homeDirectory:caseExactIA5Match:=%s)" % MIXED_VALUE) + + + +def test_ticket48746_homeDirectory_indexed_ces(topology): + log.info("\n\nindex homeDirectory in caseExactIA5Match, this would trigger the crash") + try: + ent = topology.standalone.getEntry(HOMEDIRECTORY_INDEX, ldap.SCOPE_BASE) + except ldap.NO_SUCH_OBJECT: + topology.standalone.add_s(Entry((HOMEDIRECTORY_INDEX, { + 'objectclass': "top nsIndex".split(), + 'cn': HOMEDIRECTORY_CN, + 'nsSystemIndex': 'false', + 'nsIndexType': 'eq'}))) +# log.info("attach debugger") +# time.sleep(60) + + EXACT_MR_NAME='caseExactIA5Match' + mod = [(ldap.MOD_REPLACE, MATCHINGRULE, (EXACT_MR_NAME))] + topology.standalone.modify_s(HOMEDIRECTORY_INDEX, mod) + + #topology.standalone.stop(timeout=10) + log.info("successfully checked that filter with exact mr , a filter with lowercase eq is failing") + #assert topology.standalone.db2index(bename=DEFAULT_BENAME, suffixes=None, attrs=['homeDirectory']) + #topology.standalone.start(timeout=10) + args = {TASK_WAIT: True} + topology.standalone.tasks.reindex(suffix=SUFFIX, attrname='homeDirectory', args=args) + + log.info("Check indexing succeeded with a specified matching rule") + file_path = os.path.join(topology.standalone.prefix, "var/log/dirsrv/slapd-%s/errors" % topology.standalone.serverid) + file_obj = open(file_path, "r") + + # Check if the MR configuration failure occurs + regex = re.compile("unknown or invalid matching rule") + while True: + line = file_obj.readline() + found = regex.search(line) + if ((line == '') or (found)): + break + + if (found): + log.info("The configuration of a specific MR fails") + log.info(line) + assert not found + +def test_ticket48746(topology): + """Write your testcase here... + + Also, if you need any testcase initialization, + please, write additional fixture for that(include finalizer). + """ + + log.info('Test complete') + + +if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode +# global installation1_prefix +# installation1_prefix = None +# topo = topology(True) +# test_ticket48746_init(topo) +# +# +# test_ticket48746_homeDirectory_indexed_cis(topo) +# test_ticket48746_homeDirectory_mixed_value(topo) +# test_ticket48746_extensible_search_after_index(topo) +# # crash should occur here +# test_ticket48746_homeDirectory_indexed_ces(topo) + + CURRENT_FILE = os.path.realpath(__file__) + pytest.main("-s %s" % CURRENT_FILE) diff --git a/ldap/servers/slapd/plugin_mr.c b/ldap/servers/slapd/plugin_mr.c index 2ff63a6..0ff4b78 100644 --- a/ldap/servers/slapd/plugin_mr.c +++ b/ldap/servers/slapd/plugin_mr.c @@ -165,44 +165,43 @@ slapi_mr_indexer_create (Slapi_PBlock* opb) } else { - /* call each plugin, until one is able to handle this request. */ - rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; - for (mrp = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); mrp != NULL; mrp = mrp->plg_next) - { + /* look for a new syntax-style mr plugin */ + struct slapdplugin* pi = plugin_mr_find(oid); + rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + + /* register that plugin at the condition it has a createFn/index/indexSvFn */ + if (pi) { IFP indexFn = NULL; IFP indexSvFn = NULL; Slapi_PBlock pb; - memcpy (&pb, opb, sizeof(Slapi_PBlock)); - slapi_pblock_set(&pb, SLAPI_PLUGIN, mrp); - if (slapi_pblock_get(&pb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, &createFn)) { - /* plugin not a matchingrule type */ - continue; - } + memcpy(&pb, opb, sizeof (Slapi_PBlock)); + slapi_pblock_set(&pb, SLAPI_PLUGIN, pi); + slapi_pblock_get(&pb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, &createFn); if (createFn && !createFn(&pb)) { + /* we need to call the createFn before testing the indexFn/indexSvFn + * because it sets the index callbacks + */ slapi_pblock_get(&pb, SLAPI_PLUGIN_MR_INDEX_FN, &indexFn); slapi_pblock_get(&pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, &indexSvFn); if (indexFn || indexSvFn) { - /* Success: this plugin can handle it. */ + /* Use the defined indexer_create function if it exists */ memcpy(opb, &pb, sizeof (Slapi_PBlock)); - plugin_mr_bind(oid, mrp); /* for future reference */ + plugin_mr_bind(oid, pi); /* for future reference */ rc = 0; /* success */ - break; } - } - } - if (rc != 0) { - /* look for a new syntax-style mr plugin */ - struct slapdplugin *pi = plugin_mr_find(oid); - if (pi) { - Slapi_PBlock pb; - memcpy (&pb, opb, sizeof(Slapi_PBlock)); - slapi_pblock_set(&pb, SLAPI_PLUGIN, pi); - rc = default_mr_indexer_create(&pb); - if (!rc) { - memcpy (opb, &pb, sizeof(Slapi_PBlock)); - plugin_mr_bind (oid, pi); /* for future reference */ - } + } + if (pi && (rc != 0)) { + /* No defined indexer_create or it fails + * Let's use the default one + */ + Slapi_PBlock pb; + memcpy(&pb, opb, sizeof (Slapi_PBlock)); + slapi_pblock_set(&pb, SLAPI_PLUGIN, pi); + rc = default_mr_indexer_create(&pb); + if (!rc) { + memcpy(opb, &pb, sizeof (Slapi_PBlock)); + plugin_mr_bind(oid, pi); /* for future reference */ } } } @@ -292,8 +291,14 @@ mr_wrap_mr_index_sv_fn(Slapi_PBlock* pb) slapi_pblock_set(pb, SLAPI_PLUGIN_MR_KEYS, out_vals); /* we have to save out_vals to free next time or during destroy */ slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv); - mr_private_indexer_done(mrpriv); /* free old vals, if any */ - mrpriv->sva = out_vals; /* save pointer for later */ + + /* In case SLAPI_PLUGIN_OBJECT is not set + * (e.g. custom index/filter create function did not initialize it + */ + if (mrpriv) { + mr_private_indexer_done(mrpriv); /* free old vals, if any */ + mrpriv->sva = out_vals; /* save pointer for later */ + } rc = 0; } return rc; @@ -329,8 +334,14 @@ mr_wrap_mr_index_fn(Slapi_PBlock* pb) get freed by mr_private_indexer_done() */ /* we have to save out_vals to free next time or during destroy */ slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv); - mr_private_indexer_done(mrpriv); /* free old vals, if any */ - mrpriv->bva = out_vals; /* save pointer for later */ + + /* In case SLAPI_PLUGIN_OBJECT is not set + * (e.g. custom index/filter create function did not initialize it + */ + if (mrpriv) { + mr_private_indexer_done(mrpriv); /* free old vals, if any */ + mrpriv->bva = out_vals; /* save pointer for later */ + } /* set return value berval array for caller */ slapi_pblock_set(pb, SLAPI_PLUGIN_MR_KEYS, out_vals); @@ -359,6 +370,11 @@ default_mr_filter_match(void *obj, Slapi_Entry *e, Slapi_Attr *attr) */ int rc = -1; struct mr_private* mrpriv = (struct mr_private*)obj; + + /* In case SLAPI_PLUGIN_OBJECT is not set, mrpriv may be NULL */ + if (mrpriv == NULL) + return rc; + for (; (rc == -1) && (attr != NULL); slapi_entry_next_attr(e, attr, &attr)) { char* type = NULL; if (!slapi_attr_get_type (attr, &type) && type != NULL && @@ -385,6 +401,22 @@ default_mr_filter_index(Slapi_PBlock *pb) struct mr_private* mrpriv = NULL; slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv); + + /* In case SLAPI_PLUGIN_OBJECT is not set + * (e.g. custom index/filter create function did not initialize it + */ + if (mrpriv == NULL) { + char* mrOID = NULL; + char* mrTYPE = NULL; + slapi_pblock_get(pb, SLAPI_PLUGIN_MR_OID, &mrOID); + slapi_pblock_get(pb, SLAPI_PLUGIN_MR_TYPE, &mrTYPE); + + slapi_log_error(SLAPI_LOG_FATAL, "default_mr_filter_index", + "Failure because mrpriv is NULL : %s %s\n", + mrOID ? "" : " oid", + mrTYPE ? "" : " attribute type"); + return -1; + } slapi_pblock_set(pb, SLAPI_PLUGIN, (void *)mrpriv->pi); slapi_pblock_set(pb, SLAPI_PLUGIN_MR_TYPE, (void *)mrpriv->type); @@ -547,19 +579,7 @@ plugin_mr_filter_create (mr_filter_t* f) { rc = attempt_mr_filter_create (f, mrp, &pb); } - else - { - /* call each plugin, until one is able to handle this request. */ - for (mrp = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); mrp != NULL; mrp = mrp->plg_next) - { - if (!(rc = attempt_mr_filter_create (f, mrp, &pb))) - { - plugin_mr_bind (f->mrf_oid, mrp); /* for future reference */ - break; - } - } - } - if (rc) + if (!mrp || rc) { /* look for a new syntax-style mr plugin */ mrp = plugin_mr_find(f->mrf_oid);