diff options
-rw-r--r-- | ldap/servers/slapd/filter.h | 1 | ||||
-rw-r--r-- | ldap/servers/slapd/plugin_mr.c | 426 |
2 files changed, 327 insertions, 100 deletions
diff --git a/ldap/servers/slapd/filter.h b/ldap/servers/slapd/filter.h index ad85b5fd..a2d4117c 100644 --- a/ldap/servers/slapd/filter.h +++ b/ldap/servers/slapd/filter.h @@ -58,7 +58,6 @@ typedef struct mr_filter_t { char* mrf_type; struct berval mrf_value; char mrf_dnAttrs; - struct slapdplugin* mrf_plugin; mrFilterMatchFn mrf_match; mrf_plugin_fn mrf_index; unsigned int mrf_reusable; /* MRF_ANY_xxx */ diff --git a/ldap/servers/slapd/plugin_mr.c b/ldap/servers/slapd/plugin_mr.c index 014082b7..b8b0499c 100644 --- a/ldap/servers/slapd/plugin_mr.c +++ b/ldap/servers/slapd/plugin_mr.c @@ -47,9 +47,28 @@ #include "slap.h" -struct mr_indexer_private { +/* because extensible_candidates can call an indexing + operation in the middle of a filtering operation, + we have to use a structure that can be used by both + since we can only have 1 SLAPI_PLUGIN_OBJECT in + that case */ +struct mr_private { Slapi_Value **sva; /* if using index_sv_fn */ struct berval **bva; /* if using index_fn */ + /* if doing a purely indexing operation, the fields + below are not used */ + const struct slapdplugin *pi; /* our plugin */ + const char *oid; /* orig oid */ + const char *type; /* orig type from filter */ + const struct berval *value; /* orig value from filter */ + int ftype; /* filter type */ + int op; /* query op type */ + IFP match_fn; /* match func to use */ + /* note - substring matching rules not currently supported */ + char *initial; /* these are for substring matches */ + char *any[2]; /* at most one value for extensible filter */ + char *final; /* these are for substring matches */ + const struct berval *values[2]; /* for indexing */ }; static oid_item_t* global_mr_oids = NULL; @@ -86,9 +105,10 @@ plugin_mr_find( const char *nameoroid ) } static int -plugin_mr_get_type(struct slapdplugin *pi) +plugin_mr_get_type(struct slapdplugin *pi, int *ordering) { int rc = LDAP_FILTER_EQUALITY; + *ordering = 0; if (pi) { char **str = pi->plg_mr_names; for (; str && *str; ++str) { @@ -100,6 +120,10 @@ plugin_mr_get_type(struct slapdplugin *pi) rc = LDAP_FILTER_APPROX; break; } + if (PL_strcasestr(*str, "ordering")) { + *ordering = 1; + break; + } } } @@ -203,100 +227,59 @@ slapi_mr_indexer_create (Slapi_PBlock* opb) return rc; } -static int -attempt_mr_filter_create (mr_filter_t* f, struct slapdplugin* mrp, Slapi_PBlock* pb) +static struct mr_private * +mr_private_new(const struct slapdplugin *pi, const char *oid, const char *type, const struct berval *value, int ftype, int op) { - int rc; - IFP mrf_create = NULL; - f->mrf_match = NULL; - pblock_init (pb); - if (!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN, mrp)) && - !(rc = slapi_pblock_get (pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, &mrf_create)) && - mrf_create != NULL && - !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_OID, f->mrf_oid)) && - !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_TYPE, f->mrf_type)) && - !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUE, &(f->mrf_value))) && - !(rc = mrf_create (pb)) && - !(rc = slapi_pblock_get (pb, SLAPI_PLUGIN_MR_FILTER_MATCH_FN, &(f->mrf_match)))) { - if (f->mrf_match == NULL) - { - rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; - } - } - return rc; + struct mr_private *mrpriv; + + mrpriv = (struct mr_private *)slapi_ch_calloc(1, sizeof(struct mr_private)); + mrpriv->pi = pi; + mrpriv->oid = oid; /* should be consistent for lifetime of usage - no copy necessary */ + mrpriv->type = type; /* should be consistent for lifetime of usage - no copy necessary */ + mrpriv->value = value; /* should be consistent for lifetime of usage - no copy necessary */ + mrpriv->ftype = ftype; + mrpriv->op = op; + mrpriv->values[0] = mrpriv->value; /* for filter_index */ + + return mrpriv; } -int /* an LDAP error code, hopefully LDAP_SUCCESS */ -plugin_mr_filter_create (mr_filter_t* f) -{ - int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; - struct slapdplugin* mrp = plugin_mr_find_registered (f->mrf_oid); - Slapi_PBlock pb; - - if (mrp != NULL) - { - 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) - { - /* This plugin has created the desired filter. */ - f->mrf_plugin = mrp; - slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_INDEX_FN, &(f->mrf_index)); - slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_REUSABLE, &(f->mrf_reusable)); - slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_RESET_FN, &(f->mrf_reset)); - slapi_pblock_get (&pb, SLAPI_PLUGIN_OBJECT, &(f->mrf_object)); - slapi_pblock_get (&pb, SLAPI_PLUGIN_DESTROY_FN, &(f->mrf_destroy)); - } - return rc; -} - -int /* an LDAP error code, hopefully LDAP_SUCCESS */ -slapi_mr_filter_index (Slapi_Filter* f, Slapi_PBlock* pb) -{ - int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; - if (f->f_choice == LDAP_FILTER_EXTENDED && f->f_mr.mrf_index != NULL && - !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_OBJECT, f->f_mr.mrf_object))) - { - rc = f->f_mr.mrf_index (pb); - } - return rc; -} - -static struct mr_indexer_private * -mr_indexer_private_new() +static void +mr_private_indexer_done(struct mr_private *mrpriv) { - return (struct mr_indexer_private *)slapi_ch_calloc(1, sizeof(struct mr_indexer_private)); + if (mrpriv && mrpriv->sva) { + valuearray_free(&mrpriv->sva); + } else if (mrpriv && mrpriv->bva) { + ber_bvecfree(mrpriv->bva); + mrpriv->bva = NULL; + } } static void -mr_indexer_private_done(struct mr_indexer_private *mrip) +mr_private_done(struct mr_private *mrpriv) { - if (mrip && mrip->sva) { - valuearray_free(&mrip->sva); - } else if (mrip && mrip->bva) { - ber_bvecfree(mrip->bva); - mrip->bva = NULL; + if (mrpriv) { + mrpriv->pi = NULL; + mrpriv->oid = NULL; + mrpriv->type = NULL; + mrpriv->value = NULL; + mrpriv->ftype = 0; + mrpriv->op = 0; + slapi_ch_free_string(&mrpriv->initial); + slapi_ch_free_string(&mrpriv->any[0]); + slapi_ch_free_string(&mrpriv->final); + mrpriv->match_fn = NULL; + mrpriv->values[0] = NULL; } + mr_private_indexer_done(mrpriv); } static void -mr_indexer_private_free(struct mr_indexer_private **mrip) +mr_private_free(struct mr_private **mrpriv) { - if (mrip) { - mr_indexer_private_done(*mrip); - slapi_ch_free((void **)mrip); + if (mrpriv) { + mr_private_done(*mrpriv); + slapi_ch_free((void **)mrpriv); } } @@ -318,15 +301,16 @@ mr_wrap_mr_index_sv_fn(Slapi_PBlock* pb) } else if (!pi->plg_mr_values2keys) { LDAPDebug0Args(LDAP_DEBUG_ANY, "mr_wrap_mr_index_sv_fn: error - plugin has no plg_mr_values2keys function\n"); } else { - struct mr_indexer_private *mrip = NULL; - int ftype = plugin_mr_get_type(pi); + int ordering = 0; + struct mr_private *mrpriv = NULL; + int ftype = plugin_mr_get_type(pi, &ordering); slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUES, &in_vals); (*pi->plg_mr_values2keys)(pb, in_vals, &out_vals, ftype); 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, &mrip); - mr_indexer_private_done(mrip); /* free old vals, if any */ - mrip->sva = out_vals; /* save pointer for later */ + 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 */ rc = 0; } return rc; @@ -341,7 +325,7 @@ mr_wrap_mr_index_fn(Slapi_PBlock* pb) int rc = -1; struct berval **in_vals = NULL; struct berval **out_vals = NULL; - struct mr_indexer_private *mrip = NULL; + struct mr_private *mrpriv = NULL; Slapi_Value **in_vals_sv = NULL; Slapi_Value **out_vals_sv = NULL; @@ -356,22 +340,267 @@ mr_wrap_mr_index_fn(Slapi_PBlock* pb) valuearray_get_bervalarray(out_vals_sv, &out_vals); valuearray_free(&out_vals_sv); /* don't need svals */ /* we have to save out_vals to free next time or during destroy */ - slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrip); - mr_indexer_private_done(mrip); /* free old vals, if any */ - mrip->bva = out_vals; /* save pointer for later */ + 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 */ + + return rc; +} + +static int +default_mr_filter_destroy(Slapi_PBlock* pb) +{ + struct mr_private *mrpriv = NULL; + + slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv); + mr_private_free(&mrpriv); + mrpriv = NULL; + slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mrpriv); + + return 0; +} + +static int +default_mr_filter_match(void *obj, Slapi_Entry *e, Slapi_Attr *attr) +{ +/* returns: 0 filter matched + * -1 filter did not match + * >0 an LDAP error code + */ + int rc = -1; + struct mr_private* mrpriv = (struct mr_private*)obj; + for (; (rc == -1) && (attr != NULL); slapi_entry_next_attr(e, attr, &attr)) { + char* type = NULL; + if (!slapi_attr_get_type (attr, &type) && type != NULL && + !slapi_attr_type_cmp (mrpriv->type, type, 2/*match subtypes*/)) { + Slapi_Value **vals = attr_get_present_values(attr); +#ifdef SUPPORT_MR_SUBSTRING_MATCHING + if (mrpriv->ftype == LDAP_FILTER_SUBSTRINGS) { + rc = (*mrpriv->match_fn)(pb, mrpriv->initial, mrpriv->any, mrpriv->final, vals); + } +#endif + rc = (*mrpriv->match_fn)(NULL, mrpriv->value, vals, mrpriv->ftype, NULL); + } + } + + return rc; +} + +/* convert the filter value into an array of values for use + in index key generation */ +static int +default_mr_filter_index(Slapi_PBlock *pb) +{ + int rc = 0; + struct mr_private* mrpriv = NULL; + + slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv); + + slapi_pblock_set(pb, SLAPI_PLUGIN, mrpriv->pi); + slapi_pblock_set(pb, SLAPI_PLUGIN_MR_TYPE, mrpriv->type); + /* extensible_candidates uses struct berval ** indexer */ + slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEX_FN, mr_wrap_mr_index_fn); + slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, mrpriv->values); + /* the OID is magic - this is used to calculate the index prefix - it + is the indextype value passed to index_index2prefix - it must be the + same OID as used in the index configuration for the index matching + rule */ + slapi_pblock_set(pb, SLAPI_PLUGIN_MR_OID, mrpriv->oid); + slapi_pblock_set(pb, SLAPI_PLUGIN_MR_QUERY_OPERATOR, &mrpriv->op); return rc; } static int +default_mr_filter_create(Slapi_PBlock *pb) +{ + int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* failed to initialize */ + char* mrOID = NULL; + char* mrTYPE = NULL; + struct berval* mrVALUE = NULL; + struct slapdplugin* pi = NULL; + + LDAPDebug0Args(LDAP_DEBUG_FILTER, "=> default_mr_filter_create\n"); + + if (!slapi_pblock_get(pb, SLAPI_PLUGIN_MR_OID, &mrOID) && mrOID != NULL && + !slapi_pblock_get(pb, SLAPI_PLUGIN_MR_TYPE, &mrTYPE) && mrTYPE != NULL && + !slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUE, &mrVALUE) && mrVALUE != NULL && + !slapi_pblock_get(pb, SLAPI_PLUGIN, &pi) && pi != NULL) { + int op = SLAPI_OP_EQUAL; + int ordering = 0; + struct mr_private *mrpriv = NULL; + + LDAPDebug2Args(LDAP_DEBUG_FILTER, "=> default_mr_filter_create(oid %s; type %s)\n", + mrOID, mrTYPE); + + int ftype = plugin_mr_get_type(pi, &ordering); + /* map the ftype to the op type */ + if (ftype == LDAP_FILTER_EQUALITY) { + if (ordering) { /* not sure what to do here - default to GE */ + op = SLAPI_OP_GREATER_OR_EQUAL; + } +/* + } else if (ftype == LDAP_FILTER_SUBSTRINGS) { + op = SLAPI_OP_SUBSTRING; +*/ + } else { /* unsupported */ + /* NOTE: we cannot currently support substring matching rules - the + reason is that the API provides no way to pass in the search time limit + required by the syntax filter substring match functions + */ + LDAPDebug1Arg(LDAP_DEBUG_FILTER, "<= default_mr_filter_create - unsupported filter type %d\n", + ftype); + goto done; + } + slapi_pblock_set(pb, SLAPI_PLUGIN_MR_QUERY_OPERATOR, &op); + mrpriv = mr_private_new(pi, mrOID, mrTYPE, mrVALUE, ftype, op); +#ifdef SUPPORT_MR_SUBSTRING_MATCHING + if ((ftype == LDAP_FILTER_SUBSTRINGS) && (mrVALUE->bv_len > 0) && (mrVALUE->bv_val)) { + char *first, *last; + int have_initial = 0, have_final = 0; + + if ((mrVALUE->bv_len > 1) && (mrVALUE->bv_val[0] == '*')) { + first = &mrVALUE->bv_val[1]; /* point at first "real" char */ + have_final = 1; /* substring final match */ + } else { + first = mrVALUE->bv_val; /* point at beginning */ + } + if ((mrVALUE->bv_len > 1) && (mrVALUE->bv_val[mrVALUE->bv_len-1] == '*')) { + last = &mrVALUE->bv_val[mrVALUE->bv_len-2]; /* point at last "real" char */ + have_initial = 1; /* substring initial match */ + } else { + last = &mrVALUE->bv_val[mrVALUE->bv_len-1]; /* point at end */ + } + if (have_initial == have_final) { /* both or none specified - assume any */ + mrpriv->any[0] = PL_strndup(first, last-first); + } else if (have_initial) { + mrpriv->initial = PL_strndup(first, last-first); + } else if (have_final) { + mrpriv->final = PL_strndup(first, last-first); + } + } + if (ftype == LDAP_FILTER_SUBSTRINGS) { + mrpriv->match_fn = pi->plg_mr_filter_sub; + } else { + mrpriv->match_fn = pi->plg_mr_filter_ava; + } +#else + mrpriv->match_fn = pi->plg_mr_filter_ava; +#endif + slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mrpriv); + slapi_pblock_set(pb, SLAPI_PLUGIN_MR_FILTER_MATCH_FN, default_mr_filter_match); + slapi_pblock_set(pb, SLAPI_PLUGIN_MR_FILTER_INDEX_FN, default_mr_filter_index); + slapi_pblock_set(pb, SLAPI_PLUGIN_DESTROY_FN, default_mr_filter_destroy); + rc = 0; /* success */ + } else { + LDAPDebug(LDAP_DEBUG_FILTER, + "default_mr_filter_create: missing parameter: %s%s%s\n", + mrOID ? "" : " oid", + mrTYPE ? "" : " attribute type", + mrVALUE ? "" : " filter value"); + } + +done: + LDAPDebug1Arg(LDAP_DEBUG_FILTER, "=> default_mr_filter_create: %d\n", rc); + + return rc; +} + +static int +attempt_mr_filter_create (mr_filter_t* f, struct slapdplugin* mrp, Slapi_PBlock* pb) +{ + int rc; + IFP mrf_create = NULL; + f->mrf_match = NULL; + pblock_init (pb); + if (!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN, mrp)) && + !(rc = slapi_pblock_get (pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, &mrf_create)) && + mrf_create != NULL && + !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_OID, f->mrf_oid)) && + !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_TYPE, f->mrf_type)) && + !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUE, &(f->mrf_value))) && + !(rc = mrf_create (pb)) && + !(rc = slapi_pblock_get (pb, SLAPI_PLUGIN_MR_FILTER_MATCH_FN, &(f->mrf_match)))) { + if (f->mrf_match == NULL) + { + rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + } + } + return rc; +} + +int /* an LDAP error code, hopefully LDAP_SUCCESS */ +plugin_mr_filter_create (mr_filter_t* f) +{ + int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + struct slapdplugin* mrp = plugin_mr_find_registered (f->mrf_oid); + Slapi_PBlock pb; + + if (mrp != NULL) + { + 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) + { + /* look for a new syntax-style mr plugin */ + mrp = plugin_mr_find(f->mrf_oid); + if (mrp) + { + /* set the default index create fn */ + pblock_init(&pb); + slapi_pblock_set(&pb, SLAPI_PLUGIN, mrp); + slapi_pblock_set(&pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, default_mr_filter_create); + if (!(rc = attempt_mr_filter_create (f, mrp, &pb))) + { + plugin_mr_bind (f->mrf_oid, mrp); /* for future reference */ + } + } + } + if (!rc) + { + /* This plugin has created the desired filter. */ + slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_INDEX_FN, &(f->mrf_index)); + slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_REUSABLE, &(f->mrf_reusable)); + slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_RESET_FN, &(f->mrf_reset)); + slapi_pblock_get (&pb, SLAPI_PLUGIN_OBJECT, &(f->mrf_object)); + slapi_pblock_get (&pb, SLAPI_PLUGIN_DESTROY_FN, &(f->mrf_destroy)); + } + return rc; +} + +int /* an LDAP error code, hopefully LDAP_SUCCESS */ +slapi_mr_filter_index (Slapi_Filter* f, Slapi_PBlock* pb) +{ + int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; + if (f->f_choice == LDAP_FILTER_EXTENDED && f->f_mr.mrf_index != NULL && + !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_OBJECT, f->f_mr.mrf_object))) + { + rc = f->f_mr.mrf_index (pb); + } + return rc; +} + +static int default_mr_indexer_destroy(Slapi_PBlock* pb) { - struct mr_indexer_private *mrip = NULL; + struct mr_private *mrpriv = NULL; - slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrip); - mr_indexer_private_free(&mrip); - mrip = NULL; - slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mrip); + slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv); + mr_private_free(&mrpriv); + mrpriv = NULL; + slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mrpriv); return 0; } @@ -396,7 +625,7 @@ default_mr_indexer_create(Slapi_PBlock* pb) goto done; } - slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mr_indexer_private_new()); + slapi_pblock_set(pb, SLAPI_PLUGIN_OBJECT, mr_private_new(pi, NULL, NULL, NULL, 0, 0)); slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEX_FN, mr_wrap_mr_index_fn); slapi_pblock_set(pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, mr_wrap_mr_index_sv_fn); slapi_pblock_set(pb, SLAPI_PLUGIN_DESTROY_FN, default_mr_indexer_destroy); @@ -406,4 +635,3 @@ default_mr_indexer_create(Slapi_PBlock* pb) done: return rc; } - |