summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNalin Dahyabhai <nalin@dahyabhai.net>2013-09-19 11:51:41 -0400
committerNalin Dahyabhai <nalin@dahyabhai.net>2013-09-19 11:51:41 -0400
commit0e560c77761e581c7bcfeb728f28ba1045ff1597 (patch)
tree54447145e520b483f261d22712f0f03ece6af100
parentabed694a1856101a80eee1575eb5c8b96e7c8fca (diff)
downloadslapi-nis-0e560c77761e581c7bcfeb728f28ba1045ff1597.tar.gz
slapi-nis-0e560c77761e581c7bcfeb728f28ba1045ff1597.tar.xz
slapi-nis-0e560c77761e581c7bcfeb728f28ba1045ff1597.zip
Add ignore-subtree and restrict-subtree settings
Add {nis,schema-compat}-ignore-subtree (subtrees under which we ignore contents and updates )and {nis,schema-compat}-restrict-subtree (subtrees out of which we ignore contents and updates, if set) settings, and default the former to "cn=tasks,cn=config". This should avoid cases where we're looking through the ldbm backend for entries which have a dangling reference to a newly-added task (which, because it's in the DSE, means we acquire an ldbm lock after acquiring our internal lock) while also updating a compat entry after its source entry is modified (for example, by the memberOf plugin, which results in us attempting to acquire our lock while the ldbm lock is already held).
-rw-r--r--configure.ac13
-rw-r--r--doc/nis-configuration.txt29
-rw-r--r--doc/sch-configuration.txt21
-rw-r--r--src/back-nis.c27
-rw-r--r--src/back-sch.c21
-rw-r--r--src/back-shr.c113
-rw-r--r--src/back-shr.h1
-rw-r--r--src/backend.h10
-rw-r--r--src/format.c231
-rw-r--r--src/format.h4
-rwxr-xr-xtests/test37-schema-ignore/after.sh5
-rw-r--r--tests/test37-schema-ignore/after.txt20
-rwxr-xr-xtests/test37-schema-ignore/before.sh2
-rw-r--r--tests/test37-schema-ignore/before.txt7
-rwxr-xr-xtests/test37-schema-ignore/change.sh15
-rw-r--r--tests/test37-schema-ignore/change.txt4
-rw-r--r--tests/test37-schema-ignore/description.txt1
-rw-r--r--tests/test37-schema-ignore/dse.ldif37
-rw-r--r--tests/test37-schema-ignore/plugin-process-all.txt1
-rw-r--r--tests/test37-schema-ignore/userRoot.ldif87
-rwxr-xr-xtests/test38-schema-restrict/after.sh5
-rw-r--r--tests/test38-schema-restrict/after.txt20
-rwxr-xr-xtests/test38-schema-restrict/before.sh2
-rw-r--r--tests/test38-schema-restrict/before.txt7
-rwxr-xr-xtests/test38-schema-restrict/change.sh15
-rw-r--r--tests/test38-schema-restrict/change.txt4
-rw-r--r--tests/test38-schema-restrict/description.txt1
-rw-r--r--tests/test38-schema-restrict/dse.ldif37
-rw-r--r--tests/test38-schema-restrict/plugin-process-all.txt1
-rw-r--r--tests/test38-schema-restrict/userRoot.ldif87
-rwxr-xr-xtests/test39-schema-restrictignore/after.sh5
-rw-r--r--tests/test39-schema-restrictignore/after.txt20
-rwxr-xr-xtests/test39-schema-restrictignore/before.sh2
-rw-r--r--tests/test39-schema-restrictignore/before.txt7
-rwxr-xr-xtests/test39-schema-restrictignore/change.sh15
-rw-r--r--tests/test39-schema-restrictignore/change.txt4
-rw-r--r--tests/test39-schema-restrictignore/description.txt1
-rw-r--r--tests/test39-schema-restrictignore/dse.ldif38
-rw-r--r--tests/test39-schema-restrictignore/plugin-process-all.txt1
-rw-r--r--tests/test39-schema-restrictignore/userRoot.ldif87
-rwxr-xr-xtests/test40-schema-ignoredefault/after.sh3
-rw-r--r--tests/test40-schema-ignoredefault/after.txt8
-rwxr-xr-xtests/test40-schema-ignoredefault/before.sh2
-rw-r--r--tests/test40-schema-ignoredefault/before.txt7
-rwxr-xr-xtests/test40-schema-ignoredefault/change.sh18
-rw-r--r--tests/test40-schema-ignoredefault/change.txt2
-rw-r--r--tests/test40-schema-ignoredefault/description.txt1
-rw-r--r--tests/test40-schema-ignoredefault/dse.ldif16
-rw-r--r--tests/test40-schema-ignoredefault/plugin-process-all.txt1
-rw-r--r--tests/test40-schema-ignoredefault/userRoot.ldif86
50 files changed, 1056 insertions, 96 deletions
diff --git a/configure.ac b/configure.ac
index 28d5ca4..e24405c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -420,14 +420,15 @@ AC_SUBST(groups)
AC_DEFINE(DEFAULT_MAX_DGRAM_SIZE,YPMAXRECORD,[Define to the default maximum datagram reply size.])
AC_DEFINE(DEFAULT_MAX_VALUE_SIZE,(256 * 1024),[Define to the default maximum map entry key and value size.])
AC_DEFINE(DEFAULT_TARGET_REPLY_SIZE,(4 * 1024),[Define to the default target size for a connected reply fragment.])
+AC_DEFINE_UNQUOTED(DEFAULT_IGNORE_SUBTREE,["cn=tasks,cn=config"],[Define to the default subtree to ignore if no value is explicitly configured for the map.])
AM_CONDITIONAL(NIS,true)
nisbaseattr=nis-base
AC_DEFINE_UNQUOTED(NIS_MAP_CONFIGURATION_BASE_ATTR,"$nisbaseattr",
[Define to name of the attribute which lists the containers for entries for a given map.])
-nisrelevantsubtreeattr=nis-relevant-subtree
-AC_DEFINE_UNQUOTED(NIS_MAP_CONFIGURATION_RELEVANT_SUBTREES_ATTR,"$nisrelevantsubtreeattr",
- [Define to name of the attribute which lists the only subtrees which are relevant when locating entries and reading data to be used for constructing entries for a given container.])
+nisrestrictsubtreeattr=nis-restrict-subtree
+AC_DEFINE_UNQUOTED(NIS_MAP_CONFIGURATION_RESTRICT_SUBTREES_ATTR,"$nisrestrictsubtreeattr",
+ [Define to name of the attribute which lists the only subtrees which we care about when locating entries and reading data to be used for constructing entries for a given container.])
nisignoresubtreeattr=nis-ignore-subtree
AC_DEFINE_UNQUOTED(NIS_MAP_CONFIGURATION_IGNORE_SUBTREES_ATTR,"$nisignoresubtreeattr",
[Define to name of the attribute which lists the subtrees to ignore when locating entries and reading data to be used for constructing entries for a given container.])
@@ -472,9 +473,9 @@ AC_DEFINE_UNQUOTED(SCH_CONTAINER_CONFIGURATION_ACCESS_ATTR,"$checkaciattr",
schbaseattr=schema-compat-search-base
AC_DEFINE_UNQUOTED(SCH_CONTAINER_CONFIGURATION_BASE_ATTR,"$schbaseattr",
[Define to name of the attribute which lists the containers to search when locating entries to be used for constructing entries for a given container.])
-schrelevantsubtreeattr=schema-compat-relevant-subtree
-AC_DEFINE_UNQUOTED(SCH_CONTAINER_CONFIGURATION_RELEVANT_SUBTREES_ATTR,"$schrelevantsubtreeattr",
- [Define to name of the attribute which lists the only subtrees which are relevant when locating entries and reading data to be used for constructing entries for a given container.])
+schrestrictsubtreeattr=schema-compat-restrict-subtree
+AC_DEFINE_UNQUOTED(SCH_CONTAINER_CONFIGURATION_RESTRICT_SUBTREES_ATTR,"$schrestrictsubtreeattr",
+ [Define to name of the attribute which lists the only subtrees which we care about when locating entries and reading data to be used for constructing entries for a given container.])
schignoresubtreeattr=schema-compat-ignore-subtree
AC_DEFINE_UNQUOTED(SCH_CONTAINER_CONFIGURATION_IGNORE_SUBTREES_ATTR,"$schignoresubtreeattr",
[Define to name of the attribute which lists the subtrees to ignore when locating entries and reading data to be used for constructing entries for a given container.])
diff --git a/doc/nis-configuration.txt b/doc/nis-configuration.txt
index 577a051..8f8df9f 100644
--- a/doc/nis-configuration.txt
+++ b/doc/nis-configuration.txt
@@ -58,37 +58,37 @@ look like this:
Configuration for individual maps should be stored in entries directly
beneath the plugin's entry. These attributes are recognized:
- * nis-domain
+ * nis-domain (required, multivalued)
The NIS domain in which this map appears. The server will claim to
support any domain for which it has at least one map configured.
There is no default value, and a single map will appear in multiple
domains if this attribute has multiple values.
- * nis-map
+ * nis-map (required, multivalued)
The name of this map in the domain. There is no default value, and a
single map will appear with multiple names if this attribute has
multiple values.
- * nis-base
+ * nis-base (required, multivalued)
The entry under which directory server entries which should be
converted into NIS map entries can be found. There is no default
setting. If this attribute has more than one value, the resulting
NIS map will include every entry which can be found by searching
under all of the specified entries.
- * nis-secure
+ * nis-secure (optional)
Indicates that the contents of this map should only be visible to
clients whose queries originated from port numbers below 1024. The
default setting for all maps is "no".
- * nis-filter
+ * nis-filter (optional)
The filter which is used to select entries for conversion, given as
an LDAP search filter. A default value, which varies based on the
name of the map, is used if none is specified.
- * nis-key-format
+ * nis-key-format (required if nis-keys-format is not set)
A format specifier which the plugin will use to convert the contents
of the directory server entry into a key for the NIS map. If the
expression fails to evaluate, or evaluates to more than one value,
the entry will be ignored. This can be used to ensure a 1-to-1
mapping between entries in the directory server and a NIS map. The
syntax of format specifiers is described in "format-specifiers.txt".
- * nis-keys-format
+ * nis-keys-format (required if nis-key-format is not set, multivalued)
A format specifier which the plugin will use to convert the contents
of the directory server entry into a set of keys for the NIS map.
The resulting NIS map will include a key for each value to which the
@@ -96,12 +96,12 @@ beneath the plugin's entry. These attributes are recognized:
number of NIS map entries to be created for a given directory server
entry. The syntax of format specifiers is described in
"format-specifiers.txt".
- * nis-value-format
+ * nis-value-format (required if nis-values-format is not set)
A format specifier which the plugin will use to convert the contents
of the directory server entry into a NIS map entry's value. If the
entry will have multiple keys, each key will use the same value. The
syntax of format specifiers is described in "format-specifiers.txt".
- * nis-values-format
+ * nis-values-format (required if nis-value-format is not set)
A format specifier which the plugin will use to convert the contents
of the directory server entry into values for NIS map entries.
Typically this will be used in combination with a "nis-keys-format"
@@ -109,10 +109,19 @@ beneath the plugin's entry. These attributes are recognized:
server entry. If there are fewer values than keys, the values will
be reused. The syntax of format specifiers is described in
"format-specifiers.txt".
- * nis-disallowed-chars
+ * nis-disallowed-chars (optional)
A list of characters which, if found in an attribute value, will
cause that attribute value to be ignored when evaluating keys and
values.
+ * nis-ignore-subtree (optional, multivalued)
+ An optional set of subtrees under which the plugin will ignore all
+ content and updates. By default, this is set to "cn=tasks,cn=config".
+ * nis-restrict-subtree (optional, multivalued)
+ An optional set of subtrees from under which the plugin will only
+ consider content and updates. If you have a large DIT and many
+ maps, using this setting may reduce the amount of work the plugin
+ has to do, by short-circuiting possibly-expensive checks to see if
+ an entry being modified affects the contents of various maps.
The nis-filter, nis-key-format, nis-keys-format, nis-value-format, and
nis-values-format settings all have defaults which vary based on the
diff --git a/doc/sch-configuration.txt b/doc/sch-configuration.txt
index 93e5298..e07a4af 100644
--- a/doc/sch-configuration.txt
+++ b/doc/sch-configuration.txt
@@ -20,24 +20,33 @@ look like this:
Configuration for individual sets should be stored in entries directly
beneath the plugin's entry. These attributes are recognized:
- * schema-compat-container-group
+ * schema-compat-container-group (required)
The top-level container DN under which this container's entry
appears. This level of grouping is primarily useful when using the
''referred'' function.
- * schema-compat-container-rdn
+ * schema-compat-container-rdn (optional)
The RDN of this particular container. If it's omitted, generated
entries will show up directly in the container group.
- * schema-compat-search-base
+ * schema-compat-search-base (required, multivalued)
One or more locations in the directory where candidate entries can be
found.
- * schema-compat-search-filter
+ * schema-compat-search-filter (required)
A filter used to select which candidate entries should have new
entries created for them in this container.
- * schema-compat-entry-rdn
+ * schema-compat-entry-rdn (required)
The RDN to give to generated entries, which will be stored as
children of this container.
- * schema-compat-entry-attribute
+ * schema-compat-entry-attribute (optional, multivalued)
Additional attributes to add to each entry in this container.
+ * schema-compat-ignore-subtree (optional, multivalued)
+ An optional set of subtrees under which the plugin will ignore all
+ content and updates. By default, this is set to "cn=tasks,cn=config".
+ * schema-compat-restrict-subtree (optional, multivalued)
+ An optional set of subtrees from under which the plugin will only
+ consider content and updates. If you have a large DIT and many
+ maps, using this setting may reduce the amount of work the plugin
+ has to do, by short-circuiting possibly-expensive checks to see if
+ an entry being modified affects the contents of various maps.
An pair of example definitions might look like this:
diff --git a/src/back-nis.c b/src/back-nis.c
index 8a8f89c..be6bb6a 100644
--- a/src/back-nis.c
+++ b/src/back-nis.c
@@ -87,7 +87,7 @@ backend_free_set_data_contents(void *data)
free(set_data->common.group);
free(set_data->common.set);
backend_shr_free_strlist(set_data->common.bases);
- backend_shr_free_sdnlist(set_data->common.relevant_subtrees);
+ backend_shr_free_sdnlist(set_data->common.restrict_subtrees);
backend_shr_free_sdnlist(set_data->common.ignore_subtrees);
format_free_attr_list(set_data->common.rel_attrs);
free(set_data->common.rel_attr_list);
@@ -123,7 +123,7 @@ backend_copy_set_data(const struct backend_set_data *data)
ret->common.set = strdup(data->common.set);
ret->common.bases = backend_shr_dup_strlist(data->common.bases);
ret->common.entry_filter = strdup(data->common.entry_filter);
- ret->common.relevant_subtrees = backend_shr_dup_sdnlist(data->common.relevant_subtrees);
+ ret->common.restrict_subtrees = backend_shr_dup_sdnlist(data->common.restrict_subtrees);
ret->common.ignore_subtrees = backend_shr_dup_sdnlist(data->common.ignore_subtrees);
ret->common.rel_attrs = data->common.rel_attrs ?
format_dup_attr_list(data->common.rel_attrs) :
@@ -199,6 +199,8 @@ backend_gather_data(struct plugin_state *state,
const char *domain, const char *map,
char **single_formats, char **group_formats,
const char *disallowed_chars,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char ***rel_attrs,
char ***ref_attrs,
struct format_inref_attr ***inref_attrs,
@@ -259,6 +261,8 @@ backend_gather_data(struct plugin_state *state,
singles[i] = format_get_data(state, pb, e, domain, map,
single_formats[i],
disallowed_chars,
+ restrict_subtrees,
+ ignore_subtrees,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
&single_lengths[i]);
@@ -287,6 +291,8 @@ backend_gather_data(struct plugin_state *state,
groups[j] = format_get_data_set(state, pb, e, domain, map,
group_formats[i],
disallowed_chars,
+ restrict_subtrees,
+ ignore_subtrees,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
&group_lengths[j]);
@@ -365,6 +371,8 @@ backend_set_entry(Slapi_PBlock *pb, Slapi_Entry *e,
data->key_formats,
data->keys_formats,
data->disallowed_chars,
+ data->common.restrict_subtrees,
+ data->common.ignore_subtrees,
&data->common.rel_attrs,
&data->common.ref_attrs,
&data->common.inref_attrs,
@@ -382,6 +390,8 @@ backend_set_entry(Slapi_PBlock *pb, Slapi_Entry *e,
data->value_formats,
data->values_formats,
data->disallowed_chars,
+ data->common.restrict_subtrees,
+ data->common.ignore_subtrees,
&data->common.rel_attrs,
&data->common.ref_attrs,
&data->common.inref_attrs,
@@ -517,7 +527,7 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e,
char **use_bases, *use_entry_filter;
char **use_key_formats, **use_keys_formats;
char **use_value_formats, **use_values_formats, *use_disallowed_chars;
- const Slapi_DN **relevant_subtrees, **ignore_subtrees;
+ const Slapi_DN **restrict_subtrees, **ignore_subtrees;
int i, j;
/* Read the hard-coded defaults for a map with this name. */
@@ -528,10 +538,13 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e,
/* Read the values from the configuration entry. */
bases = backend_shr_get_vattr_strlist(state, e,
NIS_MAP_CONFIGURATION_BASE_ATTR);
- relevant_subtrees = backend_shr_get_vattr_sdnlist(state, e,
- NIS_MAP_CONFIGURATION_RELEVANT_SUBTREES_ATTR);
+ restrict_subtrees = backend_shr_get_vattr_sdnlist(state, e,
+ NIS_MAP_CONFIGURATION_RESTRICT_SUBTREES_ATTR);
ignore_subtrees = backend_shr_get_vattr_sdnlist(state, e,
NIS_MAP_CONFIGURATION_IGNORE_SUBTREES_ATTR);
+ if (ignore_subtrees == NULL) {
+ backend_shr_add_sdnlist(&ignore_subtrees, DEFAULT_IGNORE_SUBTREE);
+ }
entry_filter = backend_shr_get_vattr_filter(state, e,
NIS_MAP_CONFIGURATION_FILTER_ATTR);
key_formats = backend_shr_get_vattr_strlist(state, e,
@@ -613,7 +626,7 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e,
ret.common.group = strdup(domain);
ret.common.set = strdup(map);
ret.common.bases = use_bases;
- ret.common.relevant_subtrees = relevant_subtrees;
+ ret.common.restrict_subtrees = restrict_subtrees;
ret.common.ignore_subtrees = ignore_subtrees;
ret.common.entry_filter = use_entry_filter;
ret.common.rel_attrs = NULL;
@@ -716,7 +729,7 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e,
free(ret.common.group);
free(ret.common.set);
backend_shr_free_strlist(ret.common.bases);
- backend_shr_free_sdnlist(ret.common.relevant_subtrees);
+ backend_shr_free_sdnlist(ret.common.restrict_subtrees);
free(ret.disallowed_chars);
free(ret.common.entry_filter);
backend_shr_free_strlist(ret.key_formats);
diff --git a/src/back-sch.c b/src/back-sch.c
index 3130fbc..e5a6937 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -79,7 +79,7 @@ backend_set_config_free_config_contents(void *data)
free(set_data->common.group);
free(set_data->common.set);
free(set_data->common.bases);
- backend_shr_free_sdnlist(set_data->common.relevant_subtrees);
+ backend_shr_free_sdnlist(set_data->common.restrict_subtrees);
backend_shr_free_sdnlist(set_data->common.ignore_subtrees);
format_free_attr_list(set_data->common.rel_attrs);
free(set_data->common.rel_attr_list);
@@ -112,7 +112,7 @@ backend_copy_set_config(const struct backend_set_data *data)
ret->common.group = strdup(data->common.group);
ret->common.set = strdup(data->common.set);
ret->common.bases = backend_shr_dup_strlist(data->common.bases);
- ret->common.relevant_subtrees = backend_shr_dup_sdnlist(data->common.relevant_subtrees);
+ ret->common.restrict_subtrees = backend_shr_dup_sdnlist(data->common.restrict_subtrees);
ret->common.ignore_subtrees = backend_shr_dup_sdnlist(data->common.ignore_subtrees);
ret->common.rel_attrs = data->common.rel_attrs ?
format_dup_attr_list(data->common.rel_attrs) :
@@ -164,15 +164,18 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e,
bool_t check_access;
struct backend_set_data ret;
Slapi_DN *tmp_sdn;
- const Slapi_DN **relevant_subtrees, **ignore_subtrees;
+ const Slapi_DN **restrict_subtrees, **ignore_subtrees;
/* Read the values from the configuration entry. */
bases = backend_shr_get_vattr_strlist(state, e,
SCH_CONTAINER_CONFIGURATION_BASE_ATTR);
- relevant_subtrees = backend_shr_get_vattr_sdnlist(state, e,
- SCH_CONTAINER_CONFIGURATION_RELEVANT_SUBTREES_ATTR);
+ restrict_subtrees = backend_shr_get_vattr_sdnlist(state, e,
+ SCH_CONTAINER_CONFIGURATION_RESTRICT_SUBTREES_ATTR);
ignore_subtrees = backend_shr_get_vattr_sdnlist(state, e,
SCH_CONTAINER_CONFIGURATION_IGNORE_SUBTREES_ATTR);
+ if (ignore_subtrees == NULL) {
+ backend_shr_add_sdnlist(&ignore_subtrees, DEFAULT_IGNORE_SUBTREE);
+ }
entry_filter = backend_shr_get_vattr_filter(state, e,
SCH_CONTAINER_CONFIGURATION_FILTER_ATTR);
rdn_format = backend_shr_get_vattr_str(state, e,
@@ -193,7 +196,7 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e,
slapi_sdn_free(&tmp_sdn);
ret.common.set = strdup(container);
ret.common.bases = bases;
- ret.common.relevant_subtrees = relevant_subtrees;
+ ret.common.restrict_subtrees = restrict_subtrees;
ret.common.ignore_subtrees = ignore_subtrees;
ret.common.entry_filter = entry_filter;
ret.common.rel_attrs = NULL;
@@ -259,7 +262,7 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e,
free(ret.common.group);
free(ret.common.set);
backend_shr_free_strlist(ret.common.bases);
- backend_shr_free_sdnlist(ret.common.relevant_subtrees);
+ backend_shr_free_sdnlist(ret.common.restrict_subtrees);
backend_shr_free_sdnlist(ret.common.ignore_subtrees);
free(ret.common.entry_filter);
slapi_sdn_free(&ret.container_sdn);
@@ -429,6 +432,8 @@ backend_set_entry_from(Slapi_PBlock *pb, enum backend_entry_source source,
rdn = format_get_data(data->common.state, pb, e,
data->common.group, data->common.set,
data->rdn_format, NULL,
+ data->common.restrict_subtrees,
+ data->common.ignore_subtrees,
&data->common.rel_attrs,
&data->common.ref_attrs,
&data->common.inref_attrs,
@@ -512,6 +517,8 @@ backend_set_entry_from(Slapi_PBlock *pb, enum backend_entry_source source,
data->common.set,
data->attribute_format[i],
NULL,
+ data->common.restrict_subtrees,
+ data->common.ignore_subtrees,
&data->common.rel_attrs,
&data->common.ref_attrs,
&data->common.inref_attrs,
diff --git a/src/back-shr.c b/src/back-shr.c
index 00ca097..63ed700 100644
--- a/src/back-shr.c
+++ b/src/back-shr.c
@@ -284,6 +284,30 @@ backend_shr_set_entry_cb(Slapi_Entry *e, void *callback_data)
backend_shr_set_entry(cbdata->pb, e, cbdata->set_data);
return 0;
}
+void
+backend_shr_add_sdnlist(const Slapi_DN ***sdnlist, const char *dn)
+{
+ const Slapi_DN **ret;
+ int i = 0;
+ if (dn == NULL) {
+ return NULL;
+ }
+ if ((sdnlist != NULL) && (*sdnlist != NULL)) {
+ for (i = 0; (*sdnlist)[i] != NULL; i++) {
+ continue;
+ }
+ }
+ ret = calloc(i + 2, sizeof(ret[0]));
+ if (ret != NULL) {
+ if ((sdnlist != NULL) && (*sdnlist != NULL)) {
+ memcpy(ret, *sdnlist, (i + 1) * sizeof(ret[0]));
+ free(*sdnlist);
+ }
+ ret[i] = slapi_sdn_new_dn_byval(dn);
+ ret[i + 1] = NULL;
+ *sdnlist = ret;
+ }
+}
static const Slapi_DN **
backend_shr_dup_sdnlist_n(const Slapi_DN **sdnlist, int n)
{
@@ -791,48 +815,54 @@ static bool_t
backend_shr_entry_matches_set(struct backend_shr_set_data *set_data,
Slapi_PBlock *pb, Slapi_Entry *e)
{
- const Slapi_DN **relevant_subtrees, **ignore_subtrees;
+ const Slapi_DN **restrict_subtrees, **ignore_subtrees;
char **set_bases;
char *set_filter;
int i;
- relevant_subtrees = set_data->relevant_subtrees;
+ restrict_subtrees = set_data->restrict_subtrees;
ignore_subtrees = set_data->ignore_subtrees;
set_bases = set_data->bases;
set_filter = set_data->entry_filter;
- if (ignore_subtrees != NULL) {
- for (i = 0; ignore_subtrees[i] != NULL; i++) {
- if (slapi_sdn_scope_test(slapi_entry_get_sdn_const(e),
- ignore_subtrees[i],
- LDAP_SCOPE_SUBTREE) != 0) {
- return FALSE;
- }
- }
- }
- if (relevant_subtrees != NULL) {
- for (i = 0; relevant_subtrees[i] != NULL; i++) {
- if (slapi_sdn_scope_test(slapi_entry_get_sdn_const(e),
- relevant_subtrees[i],
- LDAP_SCOPE_SUBTREE) != 0) {
- break;
- }
- }
- if (relevant_subtrees[i] == NULL) {
- /* Non-empty list, but no match. */
- return FALSE;
- }
- }
-
if (set_bases != NULL) {
+ /* Check if it's in the map's configured area(s). */
for (i = 0; set_bases[i] != NULL; i++) {
if (backend_shr_entry_matches(pb, e,
set_bases[i],
LDAP_SCOPE_SUBTREE,
set_filter)) {
- return TRUE;
+ break;
}
}
+ if (set_bases[i] != NULL) {
+ /* If it is, then check that it's in the subtrees we're
+ * restricting updates to... */
+ if (restrict_subtrees != NULL) {
+ for (i = 0; restrict_subtrees[i] != NULL; i++) {
+ if (slapi_sdn_scope_test(slapi_entry_get_sdn_const(e),
+ restrict_subtrees[i],
+ LDAP_SCOPE_SUBTREE) != 0) {
+ break;
+ }
+ }
+ if (restrict_subtrees[i] == NULL) {
+ /* Non-empty list, but no match. */
+ return FALSE;
+ }
+ }
+ /* ... and not in one that we intend to ignore. */
+ if (ignore_subtrees != NULL) {
+ for (i = 0; ignore_subtrees[i] != NULL; i++) {
+ if (slapi_sdn_scope_test(slapi_entry_get_sdn_const(e),
+ ignore_subtrees[i],
+ LDAP_SCOPE_SUBTREE) != 0) {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+ }
}
return FALSE;
@@ -1015,30 +1045,31 @@ backend_shr_update_references_cb(const char *group, const char *set,
cbdata = cbdata_ptr;
state = set_data->state;
- /* Check if this entry is in one of the areas we've been specifically
- * told to ignore. */
- if (set_data->ignore_subtrees != NULL) {
- for (i = 0; set_data->ignore_subtrees[i] != NULL; i++) {
+ /* If it is, then check that it's in one of the subtrees we're
+ * restricting updates to... */
+ if (set_data->restrict_subtrees != NULL) {
+ for (i = 0; set_data->restrict_subtrees[i] != NULL; i++) {
if (slapi_sdn_scope_test(slapi_entry_get_sdn_const(cbdata->e),
- set_data->ignore_subtrees[i],
+ set_data->restrict_subtrees[i],
LDAP_SCOPE_SUBTREE) != 0) {
- /* Yeah, we're done here. */
- return TRUE;
+ break;
}
}
+ if (set_data->restrict_subtrees[i] == NULL) {
+ /* Non-empty list, but no match. */
+ return TRUE;
+ }
}
- if (set_data->relevant_subtrees != NULL) {
- for (i = 0; set_data->relevant_subtrees[i] != NULL; i++) {
+ /* ... and not in one that we intend to ignore. */
+ if (set_data->ignore_subtrees != NULL) {
+ for (i = 0; set_data->ignore_subtrees[i] != NULL; i++) {
if (slapi_sdn_scope_test(slapi_entry_get_sdn_const(cbdata->e),
- set_data->relevant_subtrees[i],
+ set_data->ignore_subtrees[i],
LDAP_SCOPE_SUBTREE) != 0) {
- break;
+ /* Yeah, we're done here. */
+ return TRUE;
}
}
- if (set_data->relevant_subtrees[i] == NULL) {
- /* Non-empty list, but no match. */
- return TRUE;
- }
}
/* If the entry didn't change any attributes which are at all relevant
diff --git a/src/back-shr.h b/src/back-shr.h
index 83c049d..44c25fe 100644
--- a/src/back-shr.h
+++ b/src/back-shr.h
@@ -33,6 +33,7 @@ char **backend_shr_dup_strlist_n(char **strlist, int n);
char **backend_shr_dup_strlist(char **strlist);
char **backend_shr_dup_strlist_unless_empty(char **strlist);
void backend_shr_add_strlist(char ***strlist, const char *item);
+void backend_shr_add_sdnlist(const Slapi_DN ***sdnlist, const char *dn);
const Slapi_DN **backend_shr_dup_sdnlist(const Slapi_DN **sdnlist);
void backend_shr_free_sdnlist(const Slapi_DN **sdnlist);
diff --git a/src/backend.h b/src/backend.h
index 8c00dd4..7974aae 100644
--- a/src/backend.h
+++ b/src/backend.h
@@ -46,10 +46,12 @@ struct backend_shr_set_data {
/* Configuration flag indicating whether or not we try to skip
* recomputing data in this map. */
unsigned int skip_uninteresting_updates:1;
- /* Subtrees under which all of the contents that we care about will be
- * stored. Other locaoins will be silently ignored. */
- const struct slapi_dn **relevant_subtrees;
- /* Subtrees under which we ignore contents. */
+ /* Subtrees under which all of the contents that we care about, and
+ * anything that refers to content that we care about, will be stored.
+ * Other locations will be silently ignored if this list contains any
+ * values. */
+ const struct slapi_dn **restrict_subtrees;
+ /* Subtrees under which we ignore contents and updates. */
const struct slapi_dn **ignore_subtrees;
struct backend_set_data *self;
};
diff --git a/src/format.c b/src/format.c
index cfec33e..d5dc7ff 100644
--- a/src/format.c
+++ b/src/format.c
@@ -60,6 +60,8 @@ static int format_expand(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *fmt, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -286,8 +288,8 @@ format_add_sdn_list(struct slapi_dn ***list, struct slapi_dn ***list2,
}
static int
-format_check_entry(Slapi_PBlock *pb, const char *dn, char *filter,
- void *identity)
+format_check_entry_exists(Slapi_PBlock *pb, const char *dn, char *filter,
+ void *identity)
{
Slapi_DN *sdn;
Slapi_Entry *entry;
@@ -303,12 +305,62 @@ format_check_entry(Slapi_PBlock *pb, const char *dn, char *filter,
}
}
+static int
+format_check_sdn_location(const Slapi_DN *sdn,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees)
+{
+ int i;
+
+ if (restrict_subtrees != NULL) {
+ for (i = 0; restrict_subtrees[i] != NULL; i++) {
+ if (slapi_sdn_scope_test(sdn,
+ restrict_subtrees[i],
+ LDAP_SCOPE_SUBTREE) != 0) {
+ break;
+ }
+ }
+ if (restrict_subtrees[i] == NULL) {
+ /* Non-empty list, but no match. */
+ return ENOENT;
+ }
+ }
+ if (ignore_subtrees != NULL) {
+ for (i = 0; ignore_subtrees[i] != NULL; i++) {
+ if (slapi_sdn_scope_test(sdn,
+ ignore_subtrees[i],
+ LDAP_SCOPE_SUBTREE) != 0) {
+ return ENOENT;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+format_check_dn_location(const char *dn,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees)
+{
+ int ret = ENOENT;
+ Slapi_DN *sdn;
+
+ sdn = slapi_sdn_new_dn_byref(dn);
+ if (sdn != NULL) {
+ ret = format_check_sdn_location(sdn,
+ restrict_subtrees,
+ ignore_subtrees);
+ slapi_sdn_free(&sdn);
+ }
+ return ret;
+}
+
static void
-format_add_filtered_sdn_list(Slapi_PBlock *pb,
- struct slapi_dn ***list, struct slapi_dn ***list2,
- const char *dn, char *filter, void *identity)
+format_maybe_add_sdn_list(Slapi_PBlock *pb,
+ struct slapi_dn ***list, struct slapi_dn ***list2,
+ const char *dn, char *filter, void *identity)
{
- if (format_check_entry(pb, dn, filter, identity) == 0) {
+ if (format_check_entry_exists(pb, dn, filter, identity) == 0) {
format_add_sdn_list(list, list2, dn);
}
}
@@ -918,6 +970,8 @@ static int
format_first(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -951,6 +1005,7 @@ format_first(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
ret = -ENOENT;
values = format_get_data_set(state, pb, e, group, set,
value_format, disallowed,
+ restrict_subtrees, ignore_subtrees,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
&lengths);
@@ -966,6 +1021,8 @@ format_first(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
i = format_expand(state, pb, e,
group, set,
default_value, NULL,
+ restrict_subtrees,
+ ignore_subtrees,
outbuf, outbuf_len,
outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
@@ -1006,6 +1063,8 @@ format_deref_x(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *fname, const char *group, const char *set,
char *ref_attr, char *target_attr,
char *filter, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -1059,6 +1118,16 @@ format_deref_x(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
"\"%s\"\n", fname, cref);
continue;
}
+ if (format_check_sdn_location(refdn,
+ restrict_subtrees,
+ ignore_subtrees) != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "%s: entry \"%s\" is in a location "
+ "where we don't look\n", fname, cref);
+ slapi_sdn_free(&refdn);
+ continue;
+ }
wrap_search_internal_get_entry(pb, refdn, filter, attrs, &ref,
state->plugin_identity);
if (ref == NULL) {
@@ -1115,6 +1184,8 @@ static int
format_deref(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -1147,6 +1218,7 @@ format_deref(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
target_attr = argv[1];
ret = format_deref_x(state, pb, e, "deref", group, set,
ref_attr, target_attr, NULL, disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list);
@@ -1158,6 +1230,8 @@ static int
format_deref_f(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -1191,6 +1265,7 @@ format_deref_f(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
target_attr = argv[2];
ret = format_deref_x(state, pb, e, "deref_f", group, set,
ref_attr, target_attr, filter, disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list);
@@ -1207,6 +1282,8 @@ format_deref_rx(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *fname, const char *group, const char *set,
const char **attributes, const char **filters,
const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -1272,6 +1349,18 @@ format_deref_rx(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
format_add_sdn_list(&list->links[i].base_sdn_list,
&list->links[i].base_sdn_list2,
slapi_sdn_get_ndn(parent));
+ /* Check if the referred-to entry is in a location that
+ * we care about. */
+ if (format_check_sdn_location(these[j],
+ restrict_subtrees,
+ ignore_subtrees) != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "%s: entry \"%s\" is in a location "
+ "where we don't look\n", fname,
+ slapi_sdn_get_ndn(these[j]));
+ continue;
+ }
/* Pull up the named entry. */
wrap_search_internal_get_entry(pb, these[j],
NULL,
@@ -1315,18 +1404,25 @@ format_deref_rx(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
if (cvalue == NULL) {
continue;
}
+ /* If it's in an area that we're
+ * ignoring, then ignore it already. */
+ if (format_check_dn_location(cvalue,
+ restrict_subtrees,
+ ignore_subtrees) != 0) {
+ continue;
+ }
/* Let's visit the named entry this
* time, in case we're nesting. */
- format_add_filtered_sdn_list(pb, &these, &these2,
- cvalue,
- list->links[i + 1].filter_str,
- state->plugin_identity);
+ format_maybe_add_sdn_list(pb, &these, &these2,
+ cvalue,
+ list->links[i + 1].filter_str,
+ state->plugin_identity);
/* We need to visit the named entry
* next time. */
- format_add_filtered_sdn_list(pb, &next, &next2,
- cvalue,
- list->links[i + 1].filter_str,
- state->plugin_identity);
+ format_maybe_add_sdn_list(pb, &next, &next2,
+ cvalue,
+ list->links[i + 1].filter_str,
+ state->plugin_identity);
} else {
/* Get the value. */
bval = slapi_value_get_berval(value);
@@ -1373,6 +1469,8 @@ static int
format_deref_r(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -1405,6 +1503,7 @@ format_deref_r(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
group, set,
(const char **) argv, NULL,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len,
outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
@@ -1417,6 +1516,8 @@ static int
format_deref_rf(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -1475,6 +1576,7 @@ format_deref_rf(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
group, set,
(const char **) attrs, (const char **) filters,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len,
outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
@@ -1543,6 +1645,8 @@ static int
format_referred(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -1748,6 +1852,8 @@ static int
format_referred_r(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -1989,6 +2095,8 @@ static int
format_merge(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2021,6 +2129,7 @@ format_merge(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
"merge: expanding ->%s<-\n", argv[i]);
values = format_get_data_set(state, pb, e, group, set,
argv[i], disallowed,
+ restrict_subtrees, ignore_subtrees,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
&lengths);
@@ -2074,6 +2183,8 @@ format_match_generic(struct plugin_state *state,
const char *group, const char *set,
const char *args, int min_args, int default_arg,
const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -2109,6 +2220,7 @@ format_match_generic(struct plugin_state *state,
lengths = NULL;
values = format_get_data_set(state, pb, e, group, set,
argv[0], disallowed,
+ restrict_subtrees, ignore_subtrees,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
&lengths);
@@ -2164,6 +2276,8 @@ format_match_generic(struct plugin_state *state,
group, set,
argv[default_arg],
disallowed,
+ restrict_subtrees,
+ ignore_subtrees,
rel_attrs,
ref_attrs,
inref_attrs,
@@ -2273,6 +2387,8 @@ format_match(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2282,6 +2398,7 @@ format_match(struct plugin_state *state,
{
return format_match_generic(state, pb, e, group, set, args, 2, 2,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
@@ -2292,6 +2409,8 @@ format_mmatch(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2301,6 +2420,7 @@ format_mmatch(struct plugin_state *state,
{
return format_match_generic(state, pb, e, group, set, args, 2, -1,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
@@ -2333,6 +2453,8 @@ format_regmatch(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2342,6 +2464,7 @@ format_regmatch(struct plugin_state *state,
{
return format_match_generic(state, pb, e, group, set, args, 2, 2,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
@@ -2352,6 +2475,8 @@ format_mregmatch(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2361,6 +2486,7 @@ format_mregmatch(struct plugin_state *state,
{
return format_match_generic(state, pb, e, group, set, args, 2, -1,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
@@ -2376,6 +2502,8 @@ format_regmatchi(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2385,6 +2513,7 @@ format_regmatchi(struct plugin_state *state,
{
return format_match_generic(state, pb, e, group, set, args, 2, 2,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
@@ -2395,6 +2524,8 @@ format_mregmatchi(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2404,6 +2535,7 @@ format_mregmatchi(struct plugin_state *state,
{
return format_match_generic(state, pb, e, group, set, args, 2, -1,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
@@ -2529,6 +2661,8 @@ format_regsub(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2538,6 +2672,7 @@ format_regsub(struct plugin_state *state,
{
return format_match_generic(state, pb, e, group, set, args, 3, 3,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
@@ -2548,6 +2683,8 @@ format_mregsub(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2557,6 +2694,7 @@ format_mregsub(struct plugin_state *state,
{
return format_match_generic(state, pb, e, group, set, args, 3, -1,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
@@ -2572,6 +2710,8 @@ format_regsubi(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2581,6 +2721,7 @@ format_regsubi(struct plugin_state *state,
{
return format_match_generic(state, pb, e, group, set, args, 3, 3,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
@@ -2591,6 +2732,8 @@ format_mregsubi(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2600,6 +2743,7 @@ format_mregsubi(struct plugin_state *state,
{
return format_match_generic(state, pb, e, group, set, args, 3, -1,
disallowed,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
@@ -2615,6 +2759,8 @@ static int
format_ifeq(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2657,6 +2803,7 @@ format_ifeq(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
/* Evaluate the value expression to get a list of candidate values. */
values = format_get_data_set(state, pb, e, group, set,
argv[1], disallowed,
+ restrict_subtrees, ignore_subtrees,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
&lengths);
@@ -2695,6 +2842,8 @@ format_ifeq(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
* return its values. */
ret = format_expand(state, pb, e, group, set,
argv[matched ? 2 : 3], disallowed,
+ restrict_subtrees,
+ ignore_subtrees,
outbuf, outbuf_len,
outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
@@ -2709,6 +2858,8 @@ static int
format_default(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2737,6 +2888,8 @@ format_default(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
for (i = 0; i < argc; i++) {
ret = format_expand(state, pb, e, group, set,
argv[i], disallowed,
+ restrict_subtrees,
+ ignore_subtrees,
outbuf, outbuf_len,
outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
@@ -2779,6 +2932,8 @@ static int
format_sort(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2821,6 +2976,7 @@ format_sort(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
choices = NULL;
values = format_get_data_set(state, pb, e, group, set,
argv[0], disallowed,
+ restrict_subtrees, ignore_subtrees,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
&lengths);
@@ -2884,6 +3040,8 @@ static int
format_collect(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -2922,6 +3080,7 @@ format_collect(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
/* Evaluate this argument. */
values = format_get_data_set(state, pb, e, group, set,
argv[i], disallowed,
+ restrict_subtrees, ignore_subtrees,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
&lengths);
@@ -2985,6 +3144,8 @@ static int
format_link(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -3046,6 +3207,8 @@ format_link(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
j = (i / 3) * 2;
values[j] = format_get_data_set(state, pb, e, group, set,
argv[i], disallowed,
+ restrict_subtrees,
+ ignore_subtrees,
rel_attrs,
ref_attrs, inref_attrs,
ref_attr_list,
@@ -3059,6 +3222,8 @@ format_link(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
"link: evaluating \"%s\"\n", argv[i + 1]);
values[j] = format_get_data_set(state, pb, e, group, set,
argv[i + 1], disallowed,
+ restrict_subtrees,
+ ignore_subtrees,
rel_attrs,
ref_attrs, inref_attrs,
ref_attr_list,
@@ -3219,6 +3384,8 @@ static int
format_unique(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -3261,6 +3428,7 @@ format_unique(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
ret = -ENOENT;
values = format_get_data_set(state, pb, e, group, set,
value_format, disallowed,
+ restrict_subtrees, ignore_subtrees,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
&lengths);
@@ -3276,6 +3444,8 @@ format_unique(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
i = format_expand(state, pb, e,
group, set,
default_value, NULL,
+ restrict_subtrees,
+ ignore_subtrees,
outbuf, outbuf_len,
outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
@@ -3333,6 +3503,8 @@ format_internal_sequence_number(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -3378,6 +3550,8 @@ format_dribble_merge(struct plugin_state *state, Slapi_PBlock *pb,
Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -3429,6 +3603,7 @@ format_dribble_merge(struct plugin_state *state, Slapi_PBlock *pb,
"dribble_merge: expanding ->%s<-\n", argv[i]);
values = format_get_data_set(state, pb, e, group, set,
argv[i], disallowed,
+ restrict_subtrees, ignore_subtrees,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
&lengths);
@@ -3538,6 +3713,8 @@ format_lookup_fn(const char *fnname)
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -3883,6 +4060,8 @@ format_expand_simple(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *fmt, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -3993,6 +4172,8 @@ format_expand_simple(struct plugin_state *state,
i = format_expand(state, pb, e,
group, set,
default_value, NULL,
+ restrict_subtrees,
+ ignore_subtrees,
outbuf, outbuf_len,
outbuf_choices,
rel_attrs,
@@ -4012,6 +4193,8 @@ format_expand_simple(struct plugin_state *state,
i = format_expand(state, pb, e,
group, set,
alternate_value, NULL,
+ restrict_subtrees,
+ ignore_subtrees,
outbuf, outbuf_len,
outbuf_choices,
rel_attrs,
@@ -4041,6 +4224,7 @@ format_expand_simple(struct plugin_state *state,
/* Supply the alternate value. */
i = format_expand(state, pb, e,
group, set, alternate_value, NULL,
+ restrict_subtrees, ignore_subtrees,
outbuf, outbuf_len, outbuf_choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list);
@@ -4079,6 +4263,8 @@ static int
format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *fmt, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs, char ***ref_attrs,
@@ -4094,6 +4280,8 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *args, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char *outbuf, int outbuf_len,
struct format_choice **outbuf_choices,
char ***rel_attrs,
@@ -4154,6 +4342,8 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
set,
subexp,
disallowed,
+ restrict_subtrees,
+ ignore_subtrees,
outbuf + j,
outbuf_len - j,
outbuf_choices,
@@ -4260,6 +4450,8 @@ format_expand(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e,
used = (*formatfn)(state, pb, e,
group, set,
params, disallowed,
+ restrict_subtrees,
+ ignore_subtrees,
outbuf + j, outbuf_len - j,
outbuf_choices,
rel_attrs,
@@ -4321,6 +4513,8 @@ format_format(struct plugin_state *state,
const char *group, const char *set,
const char *fmt, const char *disallowed,
struct format_choice **choices,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char ***rel_attrs, char ***ref_attrs,
struct format_inref_attr ***inref_attrs,
struct format_ref_attr_list ***ref_attr_list,
@@ -4348,6 +4542,8 @@ format_format(struct plugin_state *state,
pb = wrap_pblock_new(parent_pb);
i = format_expand(state, pb, e, group, set,
fmt, disallowed,
+ restrict_subtrees,
+ ignore_subtrees,
buf, buflen, choices,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list);
@@ -4410,6 +4606,8 @@ format_get_data(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *fmt, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char ***rel_attrs,
char ***ref_attrs,
struct format_inref_attr ***inref_attrs,
@@ -4420,6 +4618,7 @@ format_get_data(struct plugin_state *state,
unsigned int ignored;
return format_format(state, pb, e, group, set, fmt,
disallowed, NULL,
+ restrict_subtrees, ignore_subtrees,
rel_attrs,
ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
@@ -4443,6 +4642,8 @@ format_get_data_set(struct plugin_state *state,
Slapi_PBlock *pb, Slapi_Entry *e,
const char *group, const char *set,
const char *fmt, const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char ***rel_attrs,
char ***ref_attrs,
struct format_inref_attr ***inref_attrs,
@@ -4457,7 +4658,7 @@ format_get_data_set(struct plugin_state *state,
unsigned int template_len;
choices = NULL;
template = format_format(state, pb, e, group, set, fmt, disallowed,
- &choices,
+ &choices, restrict_subtrees, ignore_subtrees,
rel_attrs, ref_attrs, inref_attrs,
ref_attr_list, inref_attr_list,
&template_len);
diff --git a/src/format.h b/src/format.h
index 0aa7d20..4cde2dc 100644
--- a/src/format.h
+++ b/src/format.h
@@ -59,6 +59,8 @@ char *format_get_data(struct plugin_state *state,
const char *domain, const char *map,
const char *fmt,
const char *disallowed_chars,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char ***rel_attrs,
char ***ref_attrs,
struct format_inref_attr ***inref_attrs,
@@ -71,6 +73,8 @@ char **format_get_data_set(struct plugin_state *state,
const char *domain, const char *map,
const char *fmt,
const char *disallowed,
+ const struct slapi_dn **restrict_subtrees,
+ const struct slapi_dn **ignore_subtrees,
char ***rel_attrs,
char ***ref_attrs,
struct format_inref_attr ***inref_attrs,
diff --git a/tests/test37-schema-ignore/after.sh b/tests/test37-schema-ignore/after.sh
new file mode 100755
index 0000000..0579ab2
--- /dev/null
+++ b/tests/test37-schema-ignore/after.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+echo '[updated]'
+search -b "cn=NIS Server,cn=plugins,cn=config" dn nis-domain nis-map | $LDIFSORT
+echo '[result]'
+search -b cn=compat,cn=accounts,dc=example,dc=com dn gidNumber memberCN | $LDIFSORT
diff --git a/tests/test37-schema-ignore/after.txt b/tests/test37-schema-ignore/after.txt
new file mode 100644
index 0000000..cbbef96
--- /dev/null
+++ b/tests/test37-schema-ignore/after.txt
@@ -0,0 +1,20 @@
+[updated]
+dn: cn=NIS Server,cn=plugins,cn=config
+
+dn: nis-domain=example.com+nis-map=mac2name,cn=NIS Server,cn=plugins,cn=config
+nis-domain: example.com
+nis-map: mac2name
+
+dn: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+nis-domain: example.com
+nis-map: name2mac
+nis-map: name2mac2
+
+[result]
+dn: cn=compat,cn=accounts,dc=example,dc=com
+
+dn: cn=g2,ou=group,cn=compat,cn=accounts,dc=example,dc=com
+gidNumber: 2002
+
+dn: ou=group,cn=compat,cn=accounts,dc=example,dc=com
+
diff --git a/tests/test37-schema-ignore/before.sh b/tests/test37-schema-ignore/before.sh
new file mode 100755
index 0000000..b85c1ab
--- /dev/null
+++ b/tests/test37-schema-ignore/before.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+search -b cn=compat,cn=accounts,dc=example,dc=com dn gidNumber memberCN | $LDIFSORT
diff --git a/tests/test37-schema-ignore/before.txt b/tests/test37-schema-ignore/before.txt
new file mode 100644
index 0000000..9c92512
--- /dev/null
+++ b/tests/test37-schema-ignore/before.txt
@@ -0,0 +1,7 @@
+dn: cn=compat,cn=accounts,dc=example,dc=com
+
+dn: cn=g2,ou=group,cn=compat,cn=accounts,dc=example,dc=com
+gidNumber: 2002
+
+dn: ou=group,cn=compat,cn=accounts,dc=example,dc=com
+
diff --git a/tests/test37-schema-ignore/change.sh b/tests/test37-schema-ignore/change.sh
new file mode 100755
index 0000000..0db2c95
--- /dev/null
+++ b/tests/test37-schema-ignore/change.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+modify << EOF
+dn: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+changetype: modify
+add: nis-map
+nis-map: name2mac2
+-
+
+dn: cn=g2,cn=groups,cn=accounts,dc=example,dc=com
+changetype: modify
+add: member
+member: nis-domain=example.com+nis-map=mac2name,cn=NIS Server,cn=plugins,cn=config
+-
+
+EOF
diff --git a/tests/test37-schema-ignore/change.txt b/tests/test37-schema-ignore/change.txt
new file mode 100644
index 0000000..50b0ac7
--- /dev/null
+++ b/tests/test37-schema-ignore/change.txt
@@ -0,0 +1,4 @@
+modifying entry "nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config"
+
+modifying entry "cn=g2,cn=groups,cn=accounts,dc=example,dc=com"
+
diff --git a/tests/test37-schema-ignore/description.txt b/tests/test37-schema-ignore/description.txt
new file mode 100644
index 0000000..9248be6
--- /dev/null
+++ b/tests/test37-schema-ignore/description.txt
@@ -0,0 +1 @@
+ignore selected subtrees
diff --git a/tests/test37-schema-ignore/dse.ldif b/tests/test37-schema-ignore/dse.ldif
new file mode 100644
index 0000000..79e5e3a
--- /dev/null
+++ b/tests/test37-schema-ignore/dse.ldif
@@ -0,0 +1,37 @@
+dn: cn=compat-group,cn=Schema Compatibility,cn=plugins,cn=config
+objectClass: top
+objectClass: extensibleObject
+cn: compat-group
+schema-compat-container-group: cn=compat,cn=accounts,dc=example,dc=com
+schema-compat-container-rdn: ou=group
+schema-compat-check-access: yes
+schema-compat-search-base: cn=groups,cn=Accounts,dc=example,dc=com
+schema-compat-search-base: cn=managed-groups,cn=Accounts,dc=example,dc=com
+schema-compat-search-filter: (&(objectClass=posixGroup)(gidNumber>=1500))
+schema-compat-entry-rdn: cn=%{cn}
+schema-compat-entry-attribute: objectclass=extensibleObject
+schema-compat-entry-attribute: memberUid=%deref_r("member","uid")
+schema-compat-entry-attribute: memberCN=%deref_r("member","nis-map")
+schema-compat-entry-attribute: gidNumber=%{gidNumber}
+schema-compat-ignore-subtree: cn=NIS Server,cn=plugins,cn=config
+
+dn: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+objectClass: top
+objectClass: extensibleObject
+nis-domain: example.com
+nis-map: name2mac
+nis-base: cn=computers, cn=Accounts, dc=example, dc=com
+nis-filter: objectclass=ieee802device
+nis-keys-format: %mregsub("%{macaddress} %{cn}","(..:..:..:..:..:..) (.*)","%2")
+nis-values-format: %{macaddress} %{cn}
+
+dn: nis-domain=example.com+nis-map=mac2name,cn=NIS Server,cn=plugins,cn=config
+objectClass: top
+objectClass: extensibleObject
+nis-domain: example.com
+nis-map: mac2name
+nis-base: cn=computers, cn=Accounts, dc=example, dc=com
+nis-filter: objectclass=ieee802device
+nis-keys-format: %mregsub("%{macaddress} %{cn}","(..:..:..:..:..:..) (.*)","%1")
+nis-values-format: %{macaddress} %{cn}
+
diff --git a/tests/test37-schema-ignore/plugin-process-all.txt b/tests/test37-schema-ignore/plugin-process-all.txt
new file mode 100644
index 0000000..fc7b80d
--- /dev/null
+++ b/tests/test37-schema-ignore/plugin-process-all.txt
@@ -0,0 +1 @@
+verifying that we get called
diff --git a/tests/test37-schema-ignore/userRoot.ldif b/tests/test37-schema-ignore/userRoot.ldif
new file mode 100644
index 0000000..f450895
--- /dev/null
+++ b/tests/test37-schema-ignore/userRoot.ldif
@@ -0,0 +1,87 @@
+# users, accounts, example.com
+dn: cn=users,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: users
+
+# groups, accounts, example.com
+dn: cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: groups
+
+# managed-groups, accounts, example.com
+dn: cn=managed-groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: groups
+
+# tuser1, users, accounts, example.com
+dn: uid=tuser1,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser1
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1003
+gecos: tuser1
+sn: User
+homeDirectory: /home/tuser1
+cn: Tim User
+uidNumber: 1101
+
+# tuser2, users, accounts, example.com
+dn: uid=tuser2,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser2
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1004
+gecos: tuser2
+sn: User
+homeDirectory: /home/tuser2
+cn: Timmy User
+uidNumber: 1102
+
+# tuser3, users, accounts, example.com
+dn: uid=tuser3,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser3
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1004
+gecos: tuser3
+sn: User
+homeDirectory: /home/tuser3
+cn: Timothy User
+uidNumber: 1103
+
+# g1, groups, accounts, example.com
+dn: cn=g1,cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: groupofnames
+objectClass: posixGroup
+objectClass: inetUser
+gidNumber: 1001
+cn: g1
+description: g1
+member: uid=tuser1,cn=users,cn=accounts,dc=example,dc=com
+member: cn=compat-group,cn=Schema Compatibility,cn=plugins,cn=config
+
+# g2, groups, accounts, example.com
+dn: cn=g2,cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: groupofnames
+objectClass: posixGroup
+objectClass: inetUser
+gidNumber: 2002
+cn: g2
+description: g2
+member: cn=g1,cn=groups,cn=accounts,dc=example,dc=com
+member: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+
diff --git a/tests/test38-schema-restrict/after.sh b/tests/test38-schema-restrict/after.sh
new file mode 100755
index 0000000..0579ab2
--- /dev/null
+++ b/tests/test38-schema-restrict/after.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+echo '[updated]'
+search -b "cn=NIS Server,cn=plugins,cn=config" dn nis-domain nis-map | $LDIFSORT
+echo '[result]'
+search -b cn=compat,cn=accounts,dc=example,dc=com dn gidNumber memberCN | $LDIFSORT
diff --git a/tests/test38-schema-restrict/after.txt b/tests/test38-schema-restrict/after.txt
new file mode 100644
index 0000000..cbbef96
--- /dev/null
+++ b/tests/test38-schema-restrict/after.txt
@@ -0,0 +1,20 @@
+[updated]
+dn: cn=NIS Server,cn=plugins,cn=config
+
+dn: nis-domain=example.com+nis-map=mac2name,cn=NIS Server,cn=plugins,cn=config
+nis-domain: example.com
+nis-map: mac2name
+
+dn: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+nis-domain: example.com
+nis-map: name2mac
+nis-map: name2mac2
+
+[result]
+dn: cn=compat,cn=accounts,dc=example,dc=com
+
+dn: cn=g2,ou=group,cn=compat,cn=accounts,dc=example,dc=com
+gidNumber: 2002
+
+dn: ou=group,cn=compat,cn=accounts,dc=example,dc=com
+
diff --git a/tests/test38-schema-restrict/before.sh b/tests/test38-schema-restrict/before.sh
new file mode 100755
index 0000000..b85c1ab
--- /dev/null
+++ b/tests/test38-schema-restrict/before.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+search -b cn=compat,cn=accounts,dc=example,dc=com dn gidNumber memberCN | $LDIFSORT
diff --git a/tests/test38-schema-restrict/before.txt b/tests/test38-schema-restrict/before.txt
new file mode 100644
index 0000000..9c92512
--- /dev/null
+++ b/tests/test38-schema-restrict/before.txt
@@ -0,0 +1,7 @@
+dn: cn=compat,cn=accounts,dc=example,dc=com
+
+dn: cn=g2,ou=group,cn=compat,cn=accounts,dc=example,dc=com
+gidNumber: 2002
+
+dn: ou=group,cn=compat,cn=accounts,dc=example,dc=com
+
diff --git a/tests/test38-schema-restrict/change.sh b/tests/test38-schema-restrict/change.sh
new file mode 100755
index 0000000..0db2c95
--- /dev/null
+++ b/tests/test38-schema-restrict/change.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+modify << EOF
+dn: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+changetype: modify
+add: nis-map
+nis-map: name2mac2
+-
+
+dn: cn=g2,cn=groups,cn=accounts,dc=example,dc=com
+changetype: modify
+add: member
+member: nis-domain=example.com+nis-map=mac2name,cn=NIS Server,cn=plugins,cn=config
+-
+
+EOF
diff --git a/tests/test38-schema-restrict/change.txt b/tests/test38-schema-restrict/change.txt
new file mode 100644
index 0000000..50b0ac7
--- /dev/null
+++ b/tests/test38-schema-restrict/change.txt
@@ -0,0 +1,4 @@
+modifying entry "nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config"
+
+modifying entry "cn=g2,cn=groups,cn=accounts,dc=example,dc=com"
+
diff --git a/tests/test38-schema-restrict/description.txt b/tests/test38-schema-restrict/description.txt
new file mode 100644
index 0000000..78e51e5
--- /dev/null
+++ b/tests/test38-schema-restrict/description.txt
@@ -0,0 +1 @@
+restrict updates to selected subtrees
diff --git a/tests/test38-schema-restrict/dse.ldif b/tests/test38-schema-restrict/dse.ldif
new file mode 100644
index 0000000..402bbf2
--- /dev/null
+++ b/tests/test38-schema-restrict/dse.ldif
@@ -0,0 +1,37 @@
+dn: cn=compat-group,cn=Schema Compatibility,cn=plugins,cn=config
+objectClass: top
+objectClass: extensibleObject
+cn: compat-group
+schema-compat-container-group: cn=compat,cn=accounts,dc=example,dc=com
+schema-compat-container-rdn: ou=group
+schema-compat-check-access: yes
+schema-compat-search-base: cn=groups,cn=Accounts,dc=example,dc=com
+schema-compat-search-base: cn=managed-groups,cn=Accounts,dc=example,dc=com
+schema-compat-search-filter: (&(objectClass=posixGroup)(gidNumber>=1500))
+schema-compat-entry-rdn: cn=%{cn}
+schema-compat-entry-attribute: objectclass=extensibleObject
+schema-compat-entry-attribute: memberUid=%deref_r("member","uid")
+schema-compat-entry-attribute: memberCN=%deref_r("member","nis-map")
+schema-compat-entry-attribute: gidNumber=%{gidNumber}
+schema-compat-restrict-subtree: cn=accounts,dc=example,dc=com
+
+dn: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+objectClass: top
+objectClass: extensibleObject
+nis-domain: example.com
+nis-map: name2mac
+nis-base: cn=computers, cn=Accounts, dc=example, dc=com
+nis-filter: objectclass=ieee802device
+nis-keys-format: %mregsub("%{macaddress} %{cn}","(..:..:..:..:..:..) (.*)","%2")
+nis-values-format: %{macaddress} %{cn}
+
+dn: nis-domain=example.com+nis-map=mac2name,cn=NIS Server,cn=plugins,cn=config
+objectClass: top
+objectClass: extensibleObject
+nis-domain: example.com
+nis-map: mac2name
+nis-base: cn=computers, cn=Accounts, dc=example, dc=com
+nis-filter: objectclass=ieee802device
+nis-keys-format: %mregsub("%{macaddress} %{cn}","(..:..:..:..:..:..) (.*)","%1")
+nis-values-format: %{macaddress} %{cn}
+
diff --git a/tests/test38-schema-restrict/plugin-process-all.txt b/tests/test38-schema-restrict/plugin-process-all.txt
new file mode 100644
index 0000000..fc7b80d
--- /dev/null
+++ b/tests/test38-schema-restrict/plugin-process-all.txt
@@ -0,0 +1 @@
+verifying that we get called
diff --git a/tests/test38-schema-restrict/userRoot.ldif b/tests/test38-schema-restrict/userRoot.ldif
new file mode 100644
index 0000000..f450895
--- /dev/null
+++ b/tests/test38-schema-restrict/userRoot.ldif
@@ -0,0 +1,87 @@
+# users, accounts, example.com
+dn: cn=users,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: users
+
+# groups, accounts, example.com
+dn: cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: groups
+
+# managed-groups, accounts, example.com
+dn: cn=managed-groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: groups
+
+# tuser1, users, accounts, example.com
+dn: uid=tuser1,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser1
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1003
+gecos: tuser1
+sn: User
+homeDirectory: /home/tuser1
+cn: Tim User
+uidNumber: 1101
+
+# tuser2, users, accounts, example.com
+dn: uid=tuser2,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser2
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1004
+gecos: tuser2
+sn: User
+homeDirectory: /home/tuser2
+cn: Timmy User
+uidNumber: 1102
+
+# tuser3, users, accounts, example.com
+dn: uid=tuser3,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser3
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1004
+gecos: tuser3
+sn: User
+homeDirectory: /home/tuser3
+cn: Timothy User
+uidNumber: 1103
+
+# g1, groups, accounts, example.com
+dn: cn=g1,cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: groupofnames
+objectClass: posixGroup
+objectClass: inetUser
+gidNumber: 1001
+cn: g1
+description: g1
+member: uid=tuser1,cn=users,cn=accounts,dc=example,dc=com
+member: cn=compat-group,cn=Schema Compatibility,cn=plugins,cn=config
+
+# g2, groups, accounts, example.com
+dn: cn=g2,cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: groupofnames
+objectClass: posixGroup
+objectClass: inetUser
+gidNumber: 2002
+cn: g2
+description: g2
+member: cn=g1,cn=groups,cn=accounts,dc=example,dc=com
+member: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+
diff --git a/tests/test39-schema-restrictignore/after.sh b/tests/test39-schema-restrictignore/after.sh
new file mode 100755
index 0000000..0579ab2
--- /dev/null
+++ b/tests/test39-schema-restrictignore/after.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+echo '[updated]'
+search -b "cn=NIS Server,cn=plugins,cn=config" dn nis-domain nis-map | $LDIFSORT
+echo '[result]'
+search -b cn=compat,cn=accounts,dc=example,dc=com dn gidNumber memberCN | $LDIFSORT
diff --git a/tests/test39-schema-restrictignore/after.txt b/tests/test39-schema-restrictignore/after.txt
new file mode 100644
index 0000000..cbbef96
--- /dev/null
+++ b/tests/test39-schema-restrictignore/after.txt
@@ -0,0 +1,20 @@
+[updated]
+dn: cn=NIS Server,cn=plugins,cn=config
+
+dn: nis-domain=example.com+nis-map=mac2name,cn=NIS Server,cn=plugins,cn=config
+nis-domain: example.com
+nis-map: mac2name
+
+dn: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+nis-domain: example.com
+nis-map: name2mac
+nis-map: name2mac2
+
+[result]
+dn: cn=compat,cn=accounts,dc=example,dc=com
+
+dn: cn=g2,ou=group,cn=compat,cn=accounts,dc=example,dc=com
+gidNumber: 2002
+
+dn: ou=group,cn=compat,cn=accounts,dc=example,dc=com
+
diff --git a/tests/test39-schema-restrictignore/before.sh b/tests/test39-schema-restrictignore/before.sh
new file mode 100755
index 0000000..b85c1ab
--- /dev/null
+++ b/tests/test39-schema-restrictignore/before.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+search -b cn=compat,cn=accounts,dc=example,dc=com dn gidNumber memberCN | $LDIFSORT
diff --git a/tests/test39-schema-restrictignore/before.txt b/tests/test39-schema-restrictignore/before.txt
new file mode 100644
index 0000000..9c92512
--- /dev/null
+++ b/tests/test39-schema-restrictignore/before.txt
@@ -0,0 +1,7 @@
+dn: cn=compat,cn=accounts,dc=example,dc=com
+
+dn: cn=g2,ou=group,cn=compat,cn=accounts,dc=example,dc=com
+gidNumber: 2002
+
+dn: ou=group,cn=compat,cn=accounts,dc=example,dc=com
+
diff --git a/tests/test39-schema-restrictignore/change.sh b/tests/test39-schema-restrictignore/change.sh
new file mode 100755
index 0000000..0db2c95
--- /dev/null
+++ b/tests/test39-schema-restrictignore/change.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+modify << EOF
+dn: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+changetype: modify
+add: nis-map
+nis-map: name2mac2
+-
+
+dn: cn=g2,cn=groups,cn=accounts,dc=example,dc=com
+changetype: modify
+add: member
+member: nis-domain=example.com+nis-map=mac2name,cn=NIS Server,cn=plugins,cn=config
+-
+
+EOF
diff --git a/tests/test39-schema-restrictignore/change.txt b/tests/test39-schema-restrictignore/change.txt
new file mode 100644
index 0000000..50b0ac7
--- /dev/null
+++ b/tests/test39-schema-restrictignore/change.txt
@@ -0,0 +1,4 @@
+modifying entry "nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config"
+
+modifying entry "cn=g2,cn=groups,cn=accounts,dc=example,dc=com"
+
diff --git a/tests/test39-schema-restrictignore/description.txt b/tests/test39-schema-restrictignore/description.txt
new file mode 100644
index 0000000..2699c9a
--- /dev/null
+++ b/tests/test39-schema-restrictignore/description.txt
@@ -0,0 +1 @@
+restrict and ignore, working together
diff --git a/tests/test39-schema-restrictignore/dse.ldif b/tests/test39-schema-restrictignore/dse.ldif
new file mode 100644
index 0000000..1fbf5f9
--- /dev/null
+++ b/tests/test39-schema-restrictignore/dse.ldif
@@ -0,0 +1,38 @@
+dn: cn=compat-group,cn=Schema Compatibility,cn=plugins,cn=config
+objectClass: top
+objectClass: extensibleObject
+cn: compat-group
+schema-compat-container-group: cn=compat,cn=accounts,dc=example,dc=com
+schema-compat-container-rdn: ou=group
+schema-compat-check-access: yes
+schema-compat-search-base: cn=groups,cn=Accounts,dc=example,dc=com
+schema-compat-search-base: cn=managed-groups,cn=Accounts,dc=example,dc=com
+schema-compat-search-filter: (&(objectClass=posixGroup)(gidNumber>=1500))
+schema-compat-entry-rdn: cn=%{cn}
+schema-compat-entry-attribute: objectclass=extensibleObject
+schema-compat-entry-attribute: memberUid=%deref_r("member","uid")
+schema-compat-entry-attribute: memberCN=%deref_r("member","nis-map")
+schema-compat-entry-attribute: gidNumber=%{gidNumber}
+schema-compat-ignore-subtree: cn=NIS Server,cn=plugins,cn=config
+schema-compat-restrict-subtree: cn=accounts,dc=example,dc=com
+
+dn: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+objectClass: top
+objectClass: extensibleObject
+nis-domain: example.com
+nis-map: name2mac
+nis-base: cn=computers, cn=Accounts, dc=example, dc=com
+nis-filter: objectclass=ieee802device
+nis-keys-format: %mregsub("%{macaddress} %{cn}","(..:..:..:..:..:..) (.*)","%2")
+nis-values-format: %{macaddress} %{cn}
+
+dn: nis-domain=example.com+nis-map=mac2name,cn=NIS Server,cn=plugins,cn=config
+objectClass: top
+objectClass: extensibleObject
+nis-domain: example.com
+nis-map: mac2name
+nis-base: cn=computers, cn=Accounts, dc=example, dc=com
+nis-filter: objectclass=ieee802device
+nis-keys-format: %mregsub("%{macaddress} %{cn}","(..:..:..:..:..:..) (.*)","%1")
+nis-values-format: %{macaddress} %{cn}
+
diff --git a/tests/test39-schema-restrictignore/plugin-process-all.txt b/tests/test39-schema-restrictignore/plugin-process-all.txt
new file mode 100644
index 0000000..fc7b80d
--- /dev/null
+++ b/tests/test39-schema-restrictignore/plugin-process-all.txt
@@ -0,0 +1 @@
+verifying that we get called
diff --git a/tests/test39-schema-restrictignore/userRoot.ldif b/tests/test39-schema-restrictignore/userRoot.ldif
new file mode 100644
index 0000000..f450895
--- /dev/null
+++ b/tests/test39-schema-restrictignore/userRoot.ldif
@@ -0,0 +1,87 @@
+# users, accounts, example.com
+dn: cn=users,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: users
+
+# groups, accounts, example.com
+dn: cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: groups
+
+# managed-groups, accounts, example.com
+dn: cn=managed-groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: groups
+
+# tuser1, users, accounts, example.com
+dn: uid=tuser1,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser1
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1003
+gecos: tuser1
+sn: User
+homeDirectory: /home/tuser1
+cn: Tim User
+uidNumber: 1101
+
+# tuser2, users, accounts, example.com
+dn: uid=tuser2,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser2
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1004
+gecos: tuser2
+sn: User
+homeDirectory: /home/tuser2
+cn: Timmy User
+uidNumber: 1102
+
+# tuser3, users, accounts, example.com
+dn: uid=tuser3,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser3
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1004
+gecos: tuser3
+sn: User
+homeDirectory: /home/tuser3
+cn: Timothy User
+uidNumber: 1103
+
+# g1, groups, accounts, example.com
+dn: cn=g1,cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: groupofnames
+objectClass: posixGroup
+objectClass: inetUser
+gidNumber: 1001
+cn: g1
+description: g1
+member: uid=tuser1,cn=users,cn=accounts,dc=example,dc=com
+member: cn=compat-group,cn=Schema Compatibility,cn=plugins,cn=config
+
+# g2, groups, accounts, example.com
+dn: cn=g2,cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: groupofnames
+objectClass: posixGroup
+objectClass: inetUser
+gidNumber: 2002
+cn: g2
+description: g2
+member: cn=g1,cn=groups,cn=accounts,dc=example,dc=com
+member: nis-domain=example.com+nis-map=name2mac,cn=NIS Server,cn=plugins,cn=config
+
diff --git a/tests/test40-schema-ignoredefault/after.sh b/tests/test40-schema-ignoredefault/after.sh
new file mode 100755
index 0000000..278fcae
--- /dev/null
+++ b/tests/test40-schema-ignoredefault/after.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+echo '[result]'
+search -b cn=compat,cn=accounts,dc=example,dc=com dn gidNumber memberCN | $LDIFSORT
diff --git a/tests/test40-schema-ignoredefault/after.txt b/tests/test40-schema-ignoredefault/after.txt
new file mode 100644
index 0000000..db120fb
--- /dev/null
+++ b/tests/test40-schema-ignoredefault/after.txt
@@ -0,0 +1,8 @@
+[result]
+dn: cn=compat,cn=accounts,dc=example,dc=com
+
+dn: cn=g2,ou=group,cn=compat,cn=accounts,dc=example,dc=com
+gidNumber: 2002
+
+dn: ou=group,cn=compat,cn=accounts,dc=example,dc=com
+
diff --git a/tests/test40-schema-ignoredefault/before.sh b/tests/test40-schema-ignoredefault/before.sh
new file mode 100755
index 0000000..b85c1ab
--- /dev/null
+++ b/tests/test40-schema-ignoredefault/before.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+search -b cn=compat,cn=accounts,dc=example,dc=com dn gidNumber memberCN | $LDIFSORT
diff --git a/tests/test40-schema-ignoredefault/before.txt b/tests/test40-schema-ignoredefault/before.txt
new file mode 100644
index 0000000..9c92512
--- /dev/null
+++ b/tests/test40-schema-ignoredefault/before.txt
@@ -0,0 +1,7 @@
+dn: cn=compat,cn=accounts,dc=example,dc=com
+
+dn: cn=g2,ou=group,cn=compat,cn=accounts,dc=example,dc=com
+gidNumber: 2002
+
+dn: ou=group,cn=compat,cn=accounts,dc=example,dc=com
+
diff --git a/tests/test40-schema-ignoredefault/change.sh b/tests/test40-schema-ignoredefault/change.sh
new file mode 100755
index 0000000..d1510b9
--- /dev/null
+++ b/tests/test40-schema-ignoredefault/change.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+add << EOF
+dn: cn=reindex now,cn=index,cn=tasks,cn=config
+changetype: add
+objectclass: top
+objectclass: extensibleObject
+cn: reindex now
+nsInstance: userRoot
+nsIndexAttribute: objectclass
+nsIndexAttribute: aci
+nsIndexAttribute: cn
+nsIndexAttribute: mail
+nsIndexAttribute: member
+nsIndexAttribute: memberOf
+nsIndexAttribute: uid
+nis-map: bogus
+
+EOF
diff --git a/tests/test40-schema-ignoredefault/change.txt b/tests/test40-schema-ignoredefault/change.txt
new file mode 100644
index 0000000..7cfd0b0
--- /dev/null
+++ b/tests/test40-schema-ignoredefault/change.txt
@@ -0,0 +1,2 @@
+adding new entry "cn=reindex now,cn=index,cn=tasks,cn=config"
+
diff --git a/tests/test40-schema-ignoredefault/description.txt b/tests/test40-schema-ignoredefault/description.txt
new file mode 100644
index 0000000..d883f1f
--- /dev/null
+++ b/tests/test40-schema-ignoredefault/description.txt
@@ -0,0 +1 @@
+ignore default subtrees
diff --git a/tests/test40-schema-ignoredefault/dse.ldif b/tests/test40-schema-ignoredefault/dse.ldif
new file mode 100644
index 0000000..b134a65
--- /dev/null
+++ b/tests/test40-schema-ignoredefault/dse.ldif
@@ -0,0 +1,16 @@
+dn: cn=compat-group,cn=Schema Compatibility,cn=plugins,cn=config
+objectClass: top
+objectClass: extensibleObject
+cn: compat-group
+schema-compat-container-group: cn=compat,cn=accounts,dc=example,dc=com
+schema-compat-container-rdn: ou=group
+schema-compat-check-access: yes
+schema-compat-search-base: cn=groups,cn=Accounts,dc=example,dc=com
+schema-compat-search-base: cn=managed-groups,cn=Accounts,dc=example,dc=com
+schema-compat-search-filter: (&(objectClass=posixGroup)(gidNumber>=1500))
+schema-compat-entry-rdn: cn=%{cn}
+schema-compat-entry-attribute: objectclass=extensibleObject
+schema-compat-entry-attribute: memberUid=%deref_r("member","uid")
+schema-compat-entry-attribute: memberCN=%deref_r("member","nis-map")
+schema-compat-entry-attribute: gidNumber=%{gidNumber}
+
diff --git a/tests/test40-schema-ignoredefault/plugin-process-all.txt b/tests/test40-schema-ignoredefault/plugin-process-all.txt
new file mode 100644
index 0000000..fc7b80d
--- /dev/null
+++ b/tests/test40-schema-ignoredefault/plugin-process-all.txt
@@ -0,0 +1 @@
+verifying that we get called
diff --git a/tests/test40-schema-ignoredefault/userRoot.ldif b/tests/test40-schema-ignoredefault/userRoot.ldif
new file mode 100644
index 0000000..cc579f8
--- /dev/null
+++ b/tests/test40-schema-ignoredefault/userRoot.ldif
@@ -0,0 +1,86 @@
+# users, accounts, example.com
+dn: cn=users,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: users
+
+# groups, accounts, example.com
+dn: cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: groups
+
+# managed-groups, accounts, example.com
+dn: cn=managed-groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: nsContainer
+cn: groups
+
+# tuser1, users, accounts, example.com
+dn: uid=tuser1,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser1
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1003
+gecos: tuser1
+sn: User
+homeDirectory: /home/tuser1
+cn: Tim User
+uidNumber: 1101
+
+# tuser2, users, accounts, example.com
+dn: uid=tuser2,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser2
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1004
+gecos: tuser2
+sn: User
+homeDirectory: /home/tuser2
+cn: Timmy User
+uidNumber: 1102
+
+# tuser3, users, accounts, example.com
+dn: uid=tuser3,cn=users,cn=accounts,dc=example,dc=com
+uid: tuser3
+objectClass: top
+objectClass: person
+objectClass: posixAccount
+objectClass: inetUser
+loginShell: /bin/sh
+gidNumber: 1004
+gecos: tuser3
+sn: User
+homeDirectory: /home/tuser3
+cn: Timothy User
+uidNumber: 1103
+
+# g1, groups, accounts, example.com
+dn: cn=g1,cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: groupofnames
+objectClass: posixGroup
+objectClass: inetUser
+gidNumber: 1001
+cn: g1
+description: g1
+member: uid=tuser1,cn=users,cn=accounts,dc=example,dc=com
+member: cn=reindex now,cn=index,cn=tasks,cn=config
+
+# g2, groups, accounts, example.com
+dn: cn=g2,cn=groups,cn=accounts,dc=example,dc=com
+objectClass: top
+objectClass: groupofnames
+objectClass: posixGroup
+objectClass: inetUser
+gidNumber: 2002
+cn: g2
+description: g2
+member: cn=g1,cn=groups,cn=accounts,dc=example,dc=com
+