summaryrefslogtreecommitdiffstats
path: root/src/back-sch.c
diff options
context:
space:
mode:
authorNalin Dahyabhai <nalin.dahyabhai@pobox.com>2008-06-30 16:14:28 -0400
committerNalin Dahyabhai <nalin.dahyabhai@pobox.com>2008-06-30 16:14:28 -0400
commit89516c787c3fcd041a0867472382c37529339f71 (patch)
treed29d052791e7f8d5c4fca21568afad3238840613 /src/back-sch.c
parenta7c6155406df7b44e0e557305460d053af76cada (diff)
downloadslapi-nis-89516c787c3fcd041a0867472382c37529339f71.tar.gz
slapi-nis-89516c787c3fcd041a0867472382c37529339f71.tar.xz
slapi-nis-89516c787c3fcd041a0867472382c37529339f71.zip
- start adding an sch backend
- start factoring out the backend logic where the sch and nis backends overlap
Diffstat (limited to 'src/back-sch.c')
-rw-r--r--src/back-sch.c1356
1 files changed, 1356 insertions, 0 deletions
diff --git a/src/back-sch.c b/src/back-sch.c
new file mode 100644
index 0000000..704e653
--- /dev/null
+++ b/src/back-sch.c
@@ -0,0 +1,1356 @@
+/*
+ * Copyright 2008 Red Hat, Inc.
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; if not, write to the
+ *
+ * Free Software Foundation, Inc.
+ * 59 Temple Place, Suite 330
+ * Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef HAVE_DIRSRV_SLAPI_PLUGIN_H
+#include <nspr.h>
+#include <nss.h>
+#include <dirsrv/slapi-plugin.h>
+#else
+#include <slapi-plugin.h>
+#endif
+
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+
+#ifdef HAVE_TCPD_H
+#include <tcpd.h>
+#endif
+
+#include "backend.h"
+#include "back-sch.h"
+#include "format.h"
+#include "plugin.h"
+#include "map.h"
+
+#define SCH_CONTAINER_CONFIGURATION_FILTER "(&(objectClass=*)(" SCH_CONTAINER_CONFIGURATION_BASE_ATTR "=*)(" SCH_CONTAINER_CONFIGURATION_GROUP_ATTR "=*)(" SCH_CONTAINER_CONFIGURATION_FILTER_ATTR "=*)(" SCH_CONTAINER_CONFIGURATION_ENTRY_FORMAT_ATTR "=*))"
+
+/* The data we ask the map cache to keep, for us, for each map. */
+struct backend_map_data {
+ struct plugin_state *state;
+ char *group, *container, **bases, *entry_filter, *entry_format;
+ char **ref_attrs;
+ struct format_inref_attr **inref_attrs;
+};
+
+/* Read the name of the NIS master. A dummy function for the schema
+ * compatibility plugin. */
+void
+backend_free_master_name(struct plugin_state *state, char *master)
+{
+}
+
+int
+backend_read_master_name(struct plugin_state *state, char **master)
+{
+ *master = "localhost";
+ return -1;
+}
+
+/* Manipulate string lists. */
+static void
+backend_free_strlist(char **strlist)
+{
+ if (strlist) {
+ free(strlist);
+ }
+}
+static char **
+backend_dup_strlist_n(char **strlist, int n)
+{
+ int i, l;
+ char **ret, *s;
+ /* Handle the NULL case. */
+ if (strlist == NULL) {
+ return NULL;
+ }
+ /* No strings = no list. */
+ if (n == 0) {
+ return NULL;
+ }
+ /* Count the amount of space needed for the strings. */
+ for (i = 0, l = 0; i < n; i++) {
+ l += (strlen(strlist[i]) + 1);
+ }
+ /* Allocate space for the array of pointers (with NULL terminator) and
+ * then the string data. */
+ ret = malloc(((n + 1) * sizeof(char *)) + l);
+ if (ret != NULL) {
+ /* Figure out where the string data will start. */
+ s = (char *) ret;
+ s += ((n + 1) * sizeof(char *));
+ for (i = 0; i < n; i++) {
+ /* Set the address of this string, copy the data
+ * around, and then prepare the address of the next
+ * string. */
+ ret[i] = s;
+ strcpy(s, strlist[i]);
+ s += (strlen(strlist[i]) + 1);
+ }
+ /* NULL-terminate the array. */
+ ret[i] = NULL;
+ }
+ return ret;
+}
+static char **
+backend_dup_strlist(char **strlist)
+{
+ int i;
+ for (i = 0; (strlist != NULL) && (strlist[i] != NULL); i++) {
+ continue;
+ }
+ return backend_dup_strlist_n(strlist, i);
+}
+
+/* Manipulate a backend map configuration. */
+static void
+backend_free_map_data_contents(void *data)
+{
+ struct backend_map_data *map_data = data;
+ if (map_data != NULL) {
+ free(map_data->group);
+ free(map_data->container);
+ free(map_data->bases);
+ format_free_attr_list(map_data->ref_attrs);
+ format_free_inref_attrs(map_data->inref_attrs);
+ free(map_data->entry_filter);
+ free(map_data->entry_format);
+ }
+}
+static void
+backend_free_map_data(void *data)
+{
+ backend_free_map_data_contents(data);
+ free(data);
+}
+static struct backend_map_data *
+backend_copy_map_data(const struct backend_map_data *data)
+{
+ struct backend_map_data *ret;
+ ret = malloc(sizeof(*ret));
+ if (ret == NULL) {
+ return NULL;
+ }
+ ret->state = data->state;
+ ret->group = strdup(data->group);
+ ret->container = strdup(data->container);
+ ret->bases = backend_dup_strlist(data->bases);
+ ret->ref_attrs = data->ref_attrs ?
+ format_dup_attr_list(data->ref_attrs) :
+ NULL;
+ ret->inref_attrs = data->inref_attrs ?
+ format_dup_inref_attrs(data->inref_attrs) :
+ NULL;
+ ret->entry_filter = strdup(data->entry_filter);
+ ret->entry_format = strdup(data->entry_format);
+ if ((ret->group == NULL) ||
+ (ret->container == NULL) ||
+ (ret->bases == NULL) ||
+ (ret->entry_filter == NULL) ||
+ (ret->entry_format == NULL)) {
+ backend_free_map_data(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+/* Given a map-entry directory entry, determine a key, a value, and extra data
+ * to be stored in the map cache, and add them to the map cache. */
+static int
+backend_map_config_entry_add_one_cb(Slapi_Entry *e, void *callback_data)
+{
+ struct backend_map_data *data;
+ char *ldif, *ndn, *plugin_id, *ndns[2];
+ int i, j, k, n_key_sets;
+ data = callback_data;
+ plugin_id = data->state->plugin_desc->spd_id;
+ /* Pull out the NDN of this entry. */
+ ndn = slapi_entry_get_ndn(e);
+ ndns[0] = ndn;
+ ndns[1] = NULL;
+ /* Pull out the keys and value for the entry. */
+ ldif = format_get_data(data->state, e, data->group, data->container,
+ data->entry_format, NULL,
+ &data->ref_attrs, &data->inref_attrs);
+ /* If we actually generated a new entry for this entry, then set it,
+ * otherwise clear it in case there was one set before. */
+ if (ldif == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
+ "setting group/container/key/value "
+ "\"%s\"/\"%s\"/\"%s\"(\"%s\")=\"%s\"\n",
+ data->group, data->container, ndn, ndn, ldif);
+ map_data_set_entry(data->state, data->group, data->container,
+ ndn, NULL, ndns, -1, ldif, NULL, NULL);
+ } else {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
+ "no value for %s, unsetting domain/map/id"
+ "\"%s\"/\"%s\"/(\"%s\")\n",
+ ndn, data->group, data->container, ndn);
+ map_data_unset_entry_id(data->state,
+ data->group, data->container,
+ ndn);
+ }
+ format_free_data(ldif);
+ return 0;
+}
+
+static int
+backend_map_config_entry_set_one_cb(Slapi_Entry *e, void *cbdata)
+{
+ backend_map_config_entry_add_one_cb(e, cbdata);
+ return 0;
+}
+
+static void
+backend_map_config_entry_set_one(Slapi_Entry *e,
+ struct backend_map_data *map_data)
+{
+ backend_map_config_entry_set_one_cb(e, map_data);
+}
+
+static void
+backend_map_config_entry_set_one_dn(struct plugin_state *state, const char *dn,
+ struct backend_map_data *map_data)
+{
+ Slapi_DN *sdn;
+ Slapi_Entry *entry;
+ sdn = slapi_sdn_new_dn_byval(dn);
+ if (sdn == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "error parsing DN \"%s\"\n", dn);
+ return;
+ } else {
+ entry = NULL;
+ slapi_search_internal_get_entry(sdn, NULL, &entry,
+ state->plugin_identity);
+ if (entry == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "failure reading entry \"%s\"\n", dn);
+ } else {
+ backend_map_config_entry_set_one(entry, map_data);
+ slapi_entry_free(entry);
+ }
+ slapi_sdn_free(&sdn);
+ }
+}
+
+/* Given an entry, read the map configuration for the given group and container
+ * name. */
+static void
+backend_map_config_read_config(struct plugin_state *state, Slapi_Entry *e,
+ const char *group, const char *container,
+ struct backend_map_data *ret)
+{
+ char **bases, *entry_filter, *entry_format;
+ char **entrykey_formats, **keys_formats, *value_format, *actual_attr;
+ char *disallowed_chars;
+ char **use_bases, *use_entry_filter;
+ char **use_key_formats, **use_keys_formats;
+ char *use_value_format, *use_disallowed_chars;
+ const char *cvalue;
+ int i, j, disposition, buffer_flags, count;
+ Slapi_ValueSet *values;
+ Slapi_Value *value;
+ /* Read the values from the configuration entry. */
+ bases = NULL;
+ if (slapi_vattr_values_get(e, SCH_CONTAINER_CONFIGURATION_BASE_ATTR,
+ &values,
+ &disposition, &actual_attr,
+ 0, &buffer_flags) == 0) {
+ count = slapi_valueset_count(values);
+ bases = malloc(sizeof(char *) * (count + 1));
+ if (bases != NULL) {
+ i = 0;
+ for (j = slapi_valueset_first_value(values, &value);
+ j != -1;
+ j = slapi_valueset_next_value(values, j, &value)) {
+ cvalue = slapi_value_get_string(value);
+ bases[i++] = strdup(cvalue);
+ }
+ bases[i] = NULL;
+ }
+ slapi_vattr_values_free(&values, &actual_attr, buffer_flags);
+ }
+ entry_filter = NULL;
+ if (slapi_vattr_values_get(e, SCH_CONTAINER_CONFIGURATION_FILTER_ATTR,
+ &values,
+ &disposition, &actual_attr,
+ 0, &buffer_flags) == 0) {
+ i = slapi_valueset_first_value(values, &value);
+ if (i != -1) {
+ cvalue = slapi_value_get_string(value);
+ if (strlen(cvalue) > 1) {
+ if ((cvalue[0] != '(') ||
+ (cvalue[strlen(cvalue) - 1] != ')')) {
+ entry_filter = malloc(strlen(cvalue) +
+ 3);
+ if (entry_filter != NULL) {
+ sprintf(entry_filter, "(%s)",
+ cvalue);
+ }
+ }
+ }
+ if (entry_filter == NULL) {
+ entry_filter = strdup(cvalue);
+ }
+ }
+ slapi_vattr_values_free(&values, &actual_attr, buffer_flags);
+ }
+ entry_format = NULL;
+ if (slapi_vattr_values_get(e, SCH_CONTAINER_CONFIGURATION_ENTRY_FORMAT_ATTR,
+ &values,
+ &disposition, &actual_attr,
+ 0, &buffer_flags) == 0) {
+ i = slapi_valueset_first_value(values, &value);
+ if (i != -1) {
+ cvalue = slapi_value_get_string(value);
+ entry_format = strdup(cvalue);
+ }
+ slapi_vattr_values_free(&values, &actual_attr, buffer_flags);
+ }
+ /* Populate the returned structure. */
+ ret->state = state;
+ ret->group = strdup(group);
+ ret->container = strdup(container);
+ ret->bases = backend_dup_strlist(bases);
+ if (bases != NULL) {
+ for (i = 0; bases[i] != NULL; i++) {
+ free(bases[i]);
+ }
+ free(bases);
+ }
+ ret->entry_filter = entry_filter;
+ ret->entry_format = entry_format;
+ ret->ref_attrs = NULL;
+ ret->inref_attrs = NULL;
+}
+
+/* Given a directory server entry which represents a container's configuration,
+ * set up and populate the container. */
+static int
+backend_map_config_entry_add_one(struct plugin_state *state, Slapi_Entry *e,
+ const char *group, const char *container)
+{
+ Slapi_PBlock *pb;
+ int i;
+ struct backend_map_data cb_data, *map_cb_data;
+
+ pb = slapi_pblock_new();
+ backend_map_config_read_config(state, e, group, container, &cb_data);
+ map_cb_data = backend_copy_map_data(&cb_data);
+ backend_free_map_data_contents(&cb_data);
+ if (map_cb_data == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "incomplete container definition %s in %s "
+ "(2)\n", container, group);
+ slapi_pblock_destroy(pb);
+ return 0;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "initializing container %s in %s (2)\n",
+ group, container);
+ map_data_set_map(state, group, container, FALSE,
+ map_cb_data, &backend_free_map_data);
+ map_data_clear_map(state, group, container);
+ /* Search under each base in turn, adding the matching directory
+ * entries to the containers. */
+ for (i = 0;
+ (map_cb_data->bases != NULL) && (map_cb_data->bases[i] != NULL);
+ i++) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "searching '%s' for '%s'\n",
+ map_cb_data->bases[i],
+ map_cb_data->entry_filter);
+ slapi_search_internal_set_pb(pb,
+ map_cb_data->bases[i],
+ LDAP_SCOPE_SUB,
+ map_cb_data->entry_filter,
+ NULL, FALSE,
+ NULL,
+ NULL,
+ state->plugin_identity,
+ 0);
+ slapi_search_internal_callback_pb(pb, map_cb_data,
+ NULL,
+ backend_map_config_entry_add_one_cb,
+ NULL);
+ slapi_free_search_results_internal(pb);
+ }
+ /* Clean up. */
+ slapi_pblock_destroy(pb);
+ return 0;
+}
+
+/* Process a map configuration directory entry. Pull out the group and
+ * container names which are valid for this configuration and configure such a
+ * container for each in turn. */
+static int
+backend_map_config_entry_add_cb(Slapi_Entry *e, void *callback_data)
+{
+ char **groups, **containers, *actual_attr;
+ const char *cvalue;
+ Slapi_ValueSet *values;
+ Slapi_Value *value;
+ int i, j, ret, disposition, buffer_flags, count;
+ struct plugin_state *state;
+
+ state = callback_data;
+ groups = NULL;
+ if (slapi_vattr_values_get(e, SCH_CONTAINER_CONFIGURATION_GROUP_ATTR,
+ &values,
+ &disposition, &actual_attr,
+ 0, &buffer_flags) == 0) {
+ count = slapi_valueset_count(values);
+ groups = malloc(sizeof(char *) * (count + 1));
+ if (groups != NULL) {
+ for (i = slapi_valueset_first_value(values, &value);
+ i != -1;
+ i = slapi_valueset_next_value(values, i, &value)) {
+ cvalue = slapi_value_get_string(value);
+ groups[i] = strdup(cvalue);
+ }
+ groups[count] = NULL;
+ }
+ slapi_vattr_values_free(&values, &actual_attr, buffer_flags);
+ }
+ containers = NULL;
+ if (slapi_vattr_values_get(e, SCH_CONTAINER_CONFIGURATION_CONTAINER_ATTR,
+ &values,
+ &disposition, &actual_attr,
+ 0, &buffer_flags) == 0) {
+ count = slapi_valueset_count(values);
+ containers = malloc(sizeof(char *) * (count + 1));
+ if (containers != NULL) {
+ for (i = slapi_valueset_first_value(values, &value);
+ i != -1;
+ i = slapi_valueset_next_value(values, i, &value)) {
+ cvalue = slapi_value_get_string(value);
+ containers[i] = strdup(cvalue);
+ }
+ containers[count] = NULL;
+ }
+ slapi_vattr_values_free(&values, &actual_attr, buffer_flags);
+ }
+ for (i = 0; (groups != NULL) && (groups[i] != NULL); i++) {
+ for (j = 0;
+ (containers != NULL) && (containers[j] != NULL);
+ j++) {
+ ret = backend_map_config_entry_add_one(state, e,
+ groups[i],
+ containers[j]);
+ }
+ }
+ if (groups != NULL) {
+ for (i = 0; (groups != NULL) && (groups[i] != NULL); i++) {
+ free(groups[i]);
+ }
+ free(groups);
+ }
+ if (containers != NULL) {
+ for (i = 0;
+ (containers != NULL) && (containers[i] != NULL);
+ i++) {
+ free(containers[i]);
+ }
+ free(containers);
+ }
+ return 0;
+}
+
+/* Scan for the list of configured groups and containers. */
+void
+backend_startup(struct plugin_state *state)
+{
+ Slapi_PBlock *pb;
+
+ pb = slapi_pblock_new();
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "searching \"%s\" for containers\n",
+ state->plugin_base);
+ slapi_search_internal_set_pb(pb,
+ state->plugin_base,
+ LDAP_SCOPE_ONE,
+ SCH_CONTAINER_CONFIGURATION_FILTER,
+ NULL, FALSE,
+ NULL,
+ NULL,
+ state->plugin_identity,
+ 0);
+ map_wrlock();
+ slapi_search_internal_callback_pb(pb, state,
+ NULL,
+ backend_map_config_entry_add_cb,
+ NULL);
+ map_unlock();
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+}
+
+/* Process a map configuration directory entry. Pull out the domain and map
+ * names which are specified in the entry and delete each in turn. */
+static int
+backend_map_config_entry_delete_cb(Slapi_Entry *e, void *callback_data)
+{
+ char **groups, **containers;
+ int i, j;
+ struct plugin_state *state;
+
+ state = callback_data;
+ groups = slapi_entry_attr_get_charray(e,
+ SCH_CONTAINER_CONFIGURATION_GROUP_ATTR);
+ containers = slapi_entry_attr_get_charray(e,
+ SCH_CONTAINER_CONFIGURATION_CONTAINER_ATTR);
+ for (i = 0; (groups != NULL) && (groups[i] != NULL); i++) {
+ for (j = 0;
+ (containers != NULL) && (containers[j] != NULL);
+ j++) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "removing container %s in %s\n",
+ containers[j], groups[i]);
+ map_data_unset_map(state, groups[i], containers[j]);
+ }
+ }
+ slapi_ch_array_free(containers);
+ slapi_ch_array_free(groups);
+ return 0;
+}
+
+/* Functions for passing information about a container's configuration to a
+ * caller. */
+struct backend_get_map_config_cb {
+ struct plugin_state *state;
+ char **bases;
+ char *entry_filter;
+};
+
+void
+backend_free_map_config(char **bases, char *entry_filter)
+{
+ backend_free_strlist(bases);
+ free(entry_filter);
+}
+
+static bool_t
+backend_get_map_config_entry_cb(Slapi_Entry *e, void *callback_data)
+{
+ Slapi_ValueSet *values;
+ Slapi_Value *value;
+ struct backend_get_map_config_cb *cbdata;
+ char *actual_attr;
+ const char *cvalue;
+ int disposition, buffer_flags, i, count;
+
+ cbdata = callback_data;
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata->state->plugin_desc->spd_id,
+ "reading container configuration from \"%s\"\n",
+ slapi_entry_get_ndn(e));
+
+ values = NULL;
+ value = NULL;
+ if (slapi_vattr_values_get(e, SCH_CONTAINER_CONFIGURATION_BASE_ATTR,
+ &values,
+ &disposition, &actual_attr,
+ 0, &buffer_flags) == 0) {
+ count = slapi_valueset_count(values);
+ cbdata->bases = malloc(sizeof(char *) * (count + 1));
+ if (cbdata->bases != NULL) {
+ for (i = slapi_valueset_first_value(values, &value);
+ i != -1;
+ i = slapi_valueset_next_value(values, i, &value)) {
+ cvalue = slapi_value_get_string(value);
+ cbdata->bases[i] = strdup(cvalue);
+ }
+ cbdata->bases[count] = NULL;
+ }
+ slapi_vattr_values_free(&values, &actual_attr, buffer_flags);
+ }
+ if (slapi_vattr_values_get(e, SCH_CONTAINER_CONFIGURATION_FILTER_ATTR,
+ &values,
+ &disposition, &actual_attr,
+ 0, &buffer_flags) == 0) {
+ if (slapi_valueset_first_value(values, &value) != -1) {
+ cvalue = slapi_value_get_string(value);
+ if (cvalue != NULL) {
+ free(cbdata->entry_filter);
+ cbdata->entry_filter = strdup(cvalue);
+ }
+ }
+ slapi_vattr_values_free(&values, &actual_attr, buffer_flags);
+ }
+
+ return TRUE;
+}
+
+void
+backend_get_map_config(struct plugin_state *state,
+ const char *group, const char *container,
+ char ***bases, char **entry_filter)
+{
+ Slapi_PBlock *pb;
+ char *filter;
+ char *attrs[] = {SCH_CONTAINER_CONFIGURATION_FILTER_ATTR,
+ SCH_CONTAINER_CONFIGURATION_BASE_ATTR,
+ NULL};
+ const char *default_filter;
+ struct backend_get_map_config_cb cbdata;
+
+ /* Build the search filter. */
+ filter = malloc(strlen("(&("
+ SCH_CONTAINER_CONFIGURATION_GROUP_ATTR "=)("
+ SCH_CONTAINER_CONFIGURATION_CONTAINER_ATTR "=)"
+ "()") +
+ strlen(group) + strlen(container) +
+ strlen(SCH_CONTAINER_CONFIGURATION_FILTER) + 1);
+ if (filter == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "out of memory reading configuration for "
+ "\"%s\"/\"%s\"!\n", group, container);
+ return;
+ }
+ sprintf(filter, "(&("
+ SCH_CONTAINER_CONFIGURATION_GROUP_ATTR "=%s)("
+ SCH_CONTAINER_CONFIGURATION_CONTAINER_ATTR "=%s)(%s)",
+ group, container, SCH_CONTAINER_CONFIGURATION_FILTER);
+
+ /* Perform the search. */
+ pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(pb,
+ state->plugin_base,
+ LDAP_SCOPE_SUB,
+ filter,
+ attrs, FALSE,
+ NULL,
+ NULL,
+ state->plugin_identity,
+ 0);
+ cbdata.bases = NULL;
+ cbdata.state = state;
+ cbdata.entry_filter = NULL;
+ slapi_search_internal_callback_pb(pb, &cbdata,
+ NULL,
+ backend_get_map_config_entry_cb,
+ NULL);
+
+ /* Return the results. */
+ *bases = cbdata.bases;
+ *entry_filter = cbdata.entry_filter;
+
+ /* Clean up. */
+ slapi_pblock_destroy(pb);
+}
+
+/* Our postoperation callbacks. */
+
+/* Given a map configuration, return true if an entry corresponding to the
+ * entry is supposed to be in the container. */
+static bool_t
+backend_entry_matches_map(struct backend_map_data *map_data,
+ Slapi_PBlock *pb, Slapi_Entry *e)
+{
+ Slapi_DN *base_sdn;
+ const Slapi_DN *entry_sdn;
+ Slapi_Filter *filter;
+ int i;
+ /* Decide if the directory server entry belongs in this map. That
+ * means that it must be contained by one of the bases of the map. */
+ entry_sdn = slapi_sdn_new_ndn_byref(slapi_entry_get_ndn(e));
+ if (entry_sdn == NULL) {
+ return FALSE;
+ } else {
+ /* Check each base in turn. */
+ for (i = 0;
+ (map_data->bases != NULL) && (map_data->bases[i] != NULL);
+ i++) {
+ base_sdn = slapi_sdn_new_dn_byval(map_data->bases[i]);
+ if (base_sdn == NULL) {
+ return FALSE;
+ } else {
+ if (slapi_sdn_scope_test(entry_sdn,
+ base_sdn,
+ LDAP_SCOPE_SUB) == 0) {
+ /* The entry is not contained by the
+ * base -- go on to try the next one. */
+ slapi_sdn_free(&base_sdn);
+ continue;
+ }
+ /* The entry is contained by the base. */
+ slapi_sdn_free(&base_sdn);
+ break;
+ }
+ }
+ /* If we ran out of bases to check, it doesn't match. */
+ if ((map_data->bases == NULL) || (map_data->bases[i] == NULL)) {
+ return FALSE;
+ }
+ }
+ /* If it's contained by a search base, compare it to the filter. */
+ filter = slapi_str2filter(map_data->entry_filter);
+ if (filter == NULL) {
+ return FALSE;
+ } else {
+ if (slapi_vattr_filter_test(pb, e, filter, 0) != 0) {
+ /* Didn't match -- return. */
+ slapi_filter_free(filter, 1);
+ return FALSE;
+ }
+ slapi_filter_free(filter, 1);
+ }
+ return TRUE;
+}
+
+/* Given an entry, return true if it describes a compatibility container. */
+static bool_t
+backend_entry_is_a_map(struct plugin_state *state,
+ Slapi_PBlock *pb, Slapi_Entry *e)
+{
+ Slapi_DN *entry_sdn, *plugin_sdn;
+ Slapi_Filter *filter;
+ bool_t ret;
+ char configuration_filter[] = SCH_CONTAINER_CONFIGURATION_FILTER;
+
+ /* First, just do the scope test. */
+ entry_sdn = slapi_sdn_new_ndn_byref(slapi_entry_get_ndn(e));
+ if (entry_sdn == NULL) {
+ return FALSE;
+ } else {
+ plugin_sdn = slapi_sdn_new_dn_byval(state->plugin_base);
+ if (plugin_sdn == NULL) {
+ slapi_sdn_free(&entry_sdn);
+ return FALSE;
+ }
+ }
+ if (slapi_sdn_scope_test(entry_sdn,
+ plugin_sdn,
+ LDAP_SCOPE_ONE) == 0) {
+ /* Didn't match. */
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "entry \"%s\" is not a child of \"%s\"\n",
+ slapi_sdn_get_ndn(entry_sdn),
+ slapi_sdn_get_ndn(plugin_sdn));
+ ret = FALSE;
+ } else {
+ ret = TRUE;
+ }
+ slapi_sdn_free(&plugin_sdn);
+ slapi_sdn_free(&entry_sdn);
+ /* If it's actually part of our configuration tree, check if it's a
+ * valid entry. */
+ if (ret) {
+ filter = slapi_str2filter(configuration_filter);
+ if (filter != NULL) {
+ if (slapi_vattr_filter_test(pb, e, filter, 0) != 0) {
+ /* Didn't match. */
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "entry \"%s\" doesn't look "
+ "like a container "
+ "configuration "
+ "(didn't match filter "
+ "\"%s\")\n",
+ slapi_sdn_get_ndn(entry_sdn),
+ configuration_filter);
+ ret = FALSE;
+ }
+ slapi_filter_free(filter, 1);
+ }
+ }
+ return ret;
+}
+
+/* Update any entries to which the passed-in entry in the passed-in map refers
+ * to, if the referred-to entry is in this map. Everybody got that? */
+struct backend_update_references_cbdata {
+ Slapi_PBlock *pb;
+ Slapi_Entry *e;
+};
+
+static bool_t
+backend_update_references_cb(const char *domain, const char *map, bool_t secure,
+ void *backend_data, void *cbdata_ptr)
+{
+ struct plugin_state *state;
+ struct backend_map_data *map_data;
+ struct backend_update_references_cbdata *cbdata;
+ Slapi_DN *referred_to_sdn;
+ Slapi_ValueSet *values;
+ Slapi_Value *value;
+ char **ref_attrs, *actual_attr, *filter, *tndn;
+ struct format_inref_attr **inref_attrs;
+ const char *ndn, *dn;
+ int i, j, disposition, buffer_flags, filter_size, n_ref_attrs;
+
+ map_data = backend_data;
+ cbdata = cbdata_ptr;
+ state = map_data->state;
+
+ /* For every entry in this map which refers to this entry using
+ * a DN stored in an attribute, update that entry. */
+
+ /* Build a filter with all of these attributes and this entry's DN. */
+ ref_attrs = map_data->ref_attrs;
+ for (i = 0; (ref_attrs != NULL) && (ref_attrs[i] != NULL); i++) {
+ continue;
+ }
+ n_ref_attrs = i;
+ if (n_ref_attrs > 0) {
+ filter_size = strlen("(&(|))") +
+ strlen(map_data->entry_filter) +
+ 1;
+ ndn = slapi_entry_get_ndn(cbdata->e);
+ tndn = format_escape_for_filter(ndn);
+ if (tndn == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "error building filter for "
+ "updating entries\n");
+ return TRUE;
+ }
+ for (i = 0;
+ (ref_attrs != NULL) && (ref_attrs[i] != NULL);
+ i++) {
+ filter_size += (strlen("(=)") +
+ strlen(ref_attrs[i]) +
+ strlen(ndn));
+ }
+ filter = malloc(filter_size);
+ if (filter == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "error building filter for "
+ "updating entries\n");
+ free(tndn);
+ return TRUE;
+ }
+ sprintf(filter, "(&%s(|", map_data->entry_filter);
+ for (i = 0;
+ (ref_attrs != NULL) && (ref_attrs[i] != NULL);
+ i++) {
+ sprintf(filter + strlen(filter),
+ "(%s=%s)", ref_attrs[i], tndn);
+ }
+ strcat(filter, "))");
+ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+ "searching for referrers using filter \"%s\"\n",
+ filter);
+ free(tndn);
+ /* Update any matching entry. */
+ for (i = 0;
+ (map_data->bases != NULL) && (map_data->bases[i] != NULL);
+ i++) {
+ slapi_search_internal_set_pb(cbdata->pb,
+ map_data->bases[i],
+ LDAP_SCOPE_SUB,
+ filter,
+ NULL, FALSE,
+ NULL,
+ NULL,
+ state->plugin_identity,
+ 0);
+ slapi_search_internal_callback_pb(cbdata->pb, map_data,
+ NULL,
+ backend_map_config_entry_set_one_cb,
+ NULL);
+ }
+ free(filter);
+ }
+
+ /* Allocate the DN we'll use to hold values for comparison. */
+ referred_to_sdn = slapi_sdn_new();
+ if (referred_to_sdn == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "error updating entries referred to by %s\n",
+ slapi_entry_get_ndn(cbdata->e));
+ return TRUE;
+ }
+
+ /* For every directory entry to which this directory entry refers and
+ * which also has a corresponding entry in this map, update it. */
+ inref_attrs = map_data->inref_attrs;
+ for (i = 0; (inref_attrs != NULL) && (inref_attrs[i] != NULL); i++) {
+ /* We're only processing inref attributes for this map. */
+ if ((strcmp(inref_attrs[i]->domain, domain) != 0) ||
+ (strcmp(inref_attrs[i]->map, map) != 0)) {
+ continue;
+ }
+ /* Extract the named attribute from the entry. */
+ values = NULL;
+ if (slapi_vattr_values_get(cbdata->e,
+ inref_attrs[i]->attribute,
+ &values, &disposition, &actual_attr,
+ 0, &buffer_flags) != 0) {
+ continue;
+ }
+ /* For each value of this attributes.. */
+ for (j = slapi_valueset_first_value(values, &value);
+ j != -1;
+ j = slapi_valueset_next_value(values, j, &value)) {
+ /* Pull out the value, which is a referred-to entry's
+ * DN. */
+ dn = slapi_value_get_string(value);
+ if (dn == NULL) {
+ continue;
+ }
+ /* Normalize the DN. */
+ slapi_sdn_set_dn_byref(referred_to_sdn, dn);
+ ndn = slapi_sdn_get_ndn(referred_to_sdn);
+ /* If the named entry corresponds to an entry that's
+ * already in this map. */
+ if (map_data_check_entry(state, domain, map, ndn)) {
+ /* ...update it. */
+ backend_map_config_entry_set_one_dn(state, ndn,
+ map_data);
+ }
+ }
+ slapi_vattr_values_free(&values, &actual_attr,
+ buffer_flags);
+ }
+ slapi_sdn_free(&referred_to_sdn);
+ return TRUE;
+}
+
+static void
+backend_update_references(struct plugin_state *state, Slapi_Entry *e)
+{
+ struct backend_update_references_cbdata cbdata;
+ cbdata.e = e;
+ cbdata.pb = slapi_pblock_new();
+ if (!map_data_foreach_map(state, NULL,
+ backend_update_references_cb, &cbdata)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
+ "error updating references for \"%s\"\n",
+ slapi_entry_get_ndn(cbdata.e));
+ }
+ slapi_pblock_destroy(cbdata.pb);
+}
+
+/* Add any map entries which correspond to a directory server entry in this
+ * map. */
+
+struct backend_add_entry_cbdata {
+ struct plugin_state *state;
+ Slapi_PBlock *pb;
+ Slapi_Entry *e;
+ char *ndn;
+};
+
+static bool_t
+backend_add_entry_cb(const char *domain, const char *map, bool_t secure,
+ void *backend_data, void *cbdata_ptr)
+{
+ struct backend_map_data *map_data;
+ struct backend_add_entry_cbdata *cbdata;
+
+ map_data = backend_data;
+ cbdata = cbdata_ptr;
+
+ /* If the entry doesn't match the map, skip it. */
+ if (!backend_entry_matches_map(map_data, cbdata->pb, cbdata->e)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata->state->plugin_desc->spd_id,
+ "entry \"%s\" does not belong in "
+ "\"%s\"/\"%s\"\n",
+ cbdata->ndn, domain, map);
+ return TRUE;
+ }
+
+ /* Set the entry in the map which corresponds to this entry, or clear
+ * any that might if this entry doesn't have a key and value. */
+ backend_map_config_entry_set_one(cbdata->e, map_data);
+
+ return TRUE;
+}
+
+static int
+backend_add_cb(Slapi_PBlock *pb)
+{
+ struct backend_add_entry_cbdata cbdata;
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
+ slapi_pblock_get(pb, SLAPI_ADD_TARGET, &cbdata.ndn);
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &cbdata.e);
+ cbdata.pb = pb;
+ slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id,
+ "added \"%s\"\n", cbdata.ndn);
+
+ /* Check for NULL entries, indicative of a failure elsewhere (?). */
+ if (cbdata.e == NULL) {
+ slapi_pblock_get(pb, SLAPI_ADD_EXISTING_DN_ENTRY, &cbdata.e);
+ if (cbdata.e == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "added entry is NULL\n");
+ return 0;
+ }
+ }
+
+ /* Add map entries which corresponded to this directory server
+ * entry. */
+ map_wrlock();
+ if (!map_data_foreach_map(cbdata.state, NULL,
+ backend_add_entry_cb, &cbdata)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "error adding map entries corresponding to "
+ "\"%s\"\n", cbdata.ndn);
+ }
+
+ /* If it's a map configuration entry, add and populate the maps it
+ * describes. */
+ if (backend_entry_is_a_map(cbdata.state, pb, cbdata.e)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "new entry \"%s\" is a map\n", cbdata.ndn);
+ backend_map_config_entry_add_cb(cbdata.e, cbdata.state);
+ }
+
+ /* Update entries which need to be updated in case this new entry
+ * refers to them. */
+ backend_update_references(cbdata.state, cbdata.e);
+
+ map_unlock();
+ return 0;
+}
+
+struct backend_modify_entry_cbdata {
+ struct plugin_state *state;
+ Slapi_PBlock *pb;
+ LDAPMod **mods;
+ Slapi_Entry *e_pre, *e_post;
+ char *ndn;
+};
+
+static bool_t
+backend_modify_entry_cb(const char *domain, const char *map, bool_t secure,
+ void *backend_data, void *cbdata_ptr)
+{
+ struct backend_map_data *map_data;
+ struct backend_modify_entry_cbdata *cbdata;
+
+ map_data = backend_data;
+ cbdata = cbdata_ptr;
+
+ /* If the entry used to match the map, remove it. */
+ if (backend_entry_matches_map(map_data, cbdata->pb, cbdata->e_pre)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata->state->plugin_desc->spd_id,
+ "clearing group/container/id "
+ "\"%s\"/\"%s\"/(\"%s\")\n",
+ map_data->group, map_data->container,
+ cbdata->ndn);
+ map_data_unset_entry_id(cbdata->state,
+ map_data->group, map_data->container,
+ cbdata->ndn);
+ }
+ /* If the entry now matches the map, add it (or re-add it). */
+ if (backend_entry_matches_map(map_data, cbdata->pb, cbdata->e_post)) {
+ /* Set the entry in the map which corresponds to this entry, or
+ * clear any that might if this entry doesn't have a key and
+ * value. */
+ backend_map_config_entry_set_one(cbdata->e_post, map_data);
+ }
+ return TRUE;
+}
+
+static int
+backend_modify_cb(Slapi_PBlock *pb)
+{
+ Slapi_DN *sdn;
+ struct backend_modify_entry_cbdata cbdata;
+ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
+ slapi_pblock_get(pb, SLAPI_MODIFY_TARGET, &cbdata.ndn);
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &cbdata.mods);
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &cbdata.e_pre);
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &cbdata.e_post);
+ cbdata.pb = pb;
+ slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id,
+ "modified \"%s\"\n", cbdata.ndn);
+ /* Check for NULL entries, indicative of a failure elsewhere (?). */
+ if (cbdata.e_pre == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "pre-modify entry is NULL\n");
+ return 0;
+ }
+ if (cbdata.e_post == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "post-modify entry is NULL\n");
+ return 0;
+ }
+ /* Modify map entries which corresponded to this directory server
+ * entry. */
+ map_wrlock();
+ if (!map_data_foreach_map(cbdata.state, NULL,
+ backend_modify_entry_cb, &cbdata)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "error modifying map entries corresponding to "
+ "\"%s\"\n", cbdata.ndn);
+ }
+ /* Update entries which need to be updated in case this entry
+ * no longer refers to them. */
+ backend_update_references(cbdata.state, cbdata.e_pre);
+ /* Update entries which need to be updated in case this entry
+ * now refers to them. */
+ backend_update_references(cbdata.state, cbdata.e_post);
+ /* If it's a map configuration entry, reconfigure, clear, and
+ * repopulate the map. */
+ if (backend_entry_is_a_map(cbdata.state, pb, cbdata.e_pre)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "modified entry \"%s\" was a map\n",
+ cbdata.ndn);
+ backend_map_config_entry_delete_cb(cbdata.e_pre, cbdata.state);
+ }
+ if (backend_entry_is_a_map(cbdata.state, pb, cbdata.e_post)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "modified entry \"%s\" is now a map\n",
+ cbdata.ndn);
+ backend_map_config_entry_add_cb(cbdata.e_post, cbdata.state);
+ }
+ map_unlock();
+ return 0;
+}
+
+struct backend_modrdn_entry_cbdata {
+ struct plugin_state *state;
+ Slapi_PBlock *pb;
+ Slapi_Entry *e_pre, *e_post;
+ char *ndn_pre, *ndn_post;
+};
+
+static bool_t
+backend_modrdn_entry_cb(const char *domain, const char *map, bool_t secure,
+ void *backend_data, void *cbdata_ptr)
+{
+ struct backend_map_data *map_data;
+ struct backend_modrdn_entry_cbdata *cbdata;
+ bool_t matched_pre, matched_post;
+
+ map_data = backend_data;
+ cbdata = cbdata_ptr;
+
+ matched_pre = backend_entry_matches_map(map_data,
+ cbdata->pb, cbdata->e_pre);
+ matched_post = backend_entry_matches_map(map_data,
+ cbdata->pb, cbdata->e_post);
+
+ /* Now decide what to set, or unset, in this map. */
+ if (matched_pre) {
+ /* If it was a match for the map, clear the entry. */
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata->state->plugin_desc->spd_id,
+ "clearing group/container/id "
+ "\"%s\"/\"%s\"/(\"%s\")\n",
+ map_data->group, map_data->container,
+ cbdata->ndn_pre);
+ map_data_unset_entry_id(cbdata->state,
+ map_data->group, map_data->container,
+ cbdata->ndn_pre);
+ }
+ /* Set the entry in the map which corresponds to this entry, or clear
+ * any that might if this entry doesn't have a key and value. */
+ if (matched_post) {
+ backend_map_config_entry_set_one(cbdata->e_post, map_data);
+ }
+ return TRUE;
+}
+
+static int
+backend_modrdn_cb(Slapi_PBlock *pb)
+{
+ struct backend_modrdn_entry_cbdata cbdata;
+ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &cbdata.e_pre);
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &cbdata.e_post);
+ cbdata.ndn_pre = slapi_entry_get_ndn(cbdata.e_pre);
+ cbdata.ndn_post = slapi_entry_get_ndn(cbdata.e_post);
+ cbdata.pb = pb;
+ slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id,
+ "renamed \"%s\" to \"%s\"\n",
+ cbdata.ndn_pre, cbdata.ndn_post);
+ /* Check for NULL entries, indicative of a failure elsewhere (?). */
+ if (cbdata.e_pre == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "pre-modrdn entry is NULL\n");
+ return 0;
+ }
+ if (cbdata.e_post == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "post-modrdn entry is NULL\n");
+ return 0;
+ }
+ /* Modify map entries which corresponded to this directory server
+ * entry. */
+ map_wrlock();
+ if (!map_data_foreach_map(cbdata.state, NULL,
+ backend_modrdn_entry_cb, &cbdata)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "error renaming map entries corresponding to "
+ "\"%s\"\n", cbdata.ndn_post);
+ }
+ /* If it's a map configuration entry, reconfigure, clear, and
+ * repopulate the map. */
+ if (backend_entry_is_a_map(cbdata.state, pb, cbdata.e_pre)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "renamed entry \"%s\" was a map\n",
+ cbdata.e_pre);
+ backend_map_config_entry_delete_cb(cbdata.e_pre, cbdata.state);
+ }
+ if (backend_entry_is_a_map(cbdata.state, pb, cbdata.e_post)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "renamed entry \"%s\" is now a map\n",
+ cbdata.e_post);
+ backend_map_config_entry_add_cb(cbdata.e_post, cbdata.state);
+ }
+ map_unlock();
+ return 0;
+}
+
+/* Delete any map entries which correspond to a directory server entry in this
+ * map. */
+
+struct backend_delete_entry_cbdata {
+ struct plugin_state *state;
+ Slapi_PBlock *pb;
+ Slapi_Entry *e;
+ char *ndn;
+};
+
+static bool_t
+backend_delete_entry_cb(const char *group, const char *container, bool_t secure,
+ void *backend_data, void *cbdata_ptr)
+{
+ struct backend_map_data *map_data;
+ struct backend_delete_entry_cbdata *cbdata;
+ map_data = backend_data;
+ cbdata = cbdata_ptr;
+ /* If it was in the map, remove it. */
+ if (backend_entry_matches_map(map_data, cbdata->pb, cbdata->e)) {
+ /* Remove this entry from the map. */
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata->state->plugin_desc->spd_id,
+ "unsetting group/container/id"
+ "\"%s\"/\"%s\"=\"%s\"/\"%s\"/(\"%s\")\n",
+ group, container,
+ map_data->group, map_data->container,
+ cbdata->ndn);
+ map_data_unset_entry_id(cbdata->state, group, container,
+ cbdata->ndn);
+ }
+ return TRUE;
+}
+
+/* Called by the server when a directory server entry is deleted. */
+static int
+backend_delete_cb(Slapi_PBlock *pb)
+{
+ struct backend_delete_entry_cbdata cbdata;
+ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
+ slapi_pblock_get(pb, SLAPI_DELETE_TARGET, &cbdata.ndn);
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &cbdata.e);
+ cbdata.pb = pb;
+ slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id,
+ "deleted \"%s\"\n", cbdata.ndn);
+ /* Check for NULL entries, indicative of a failure elsewhere (?). */
+ if (cbdata.e == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "deleted entry is NULL\n");
+ return 0;
+ }
+ /* Remove map entries which corresponded to this directory server
+ * entry. */
+ map_wrlock();
+ if (!map_data_foreach_map(cbdata.state, NULL,
+ backend_delete_entry_cb, &cbdata)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "error removing map entries corresponding to "
+ "\"%s\"\n", cbdata.ndn);
+ }
+ /* If it's a map configuration entry, remove the map. */
+ if (backend_entry_is_a_map(cbdata.state, pb, cbdata.e)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata.state->plugin_desc->spd_id,
+ "deleted entry \"%s\" is a map\n", cbdata.ndn);
+ backend_map_config_entry_delete_cb(cbdata.e, cbdata.state);
+ }
+ /* Update entries which need to be updated in case this entry no longer
+ * refers to them. */
+ backend_update_references(cbdata.state, cbdata.e);
+ map_unlock();
+ return 0;
+}
+
+/* Set our post-op callbacks. */
+void
+backend_init(Slapi_PBlock *pb, struct plugin_state *state)
+{
+ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+ "hooking up postoperation callbacks\n");
+ if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN,
+ backend_add_cb) != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+ "error hooking up add callback\n");
+ }
+ if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN,
+ backend_modify_cb) != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+ "error hooking up modify callback\n");
+ }
+ if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN,
+ backend_modrdn_cb) != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+ "error hooking up modrdn callback\n");
+ }
+ if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN,
+ backend_delete_cb) != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+ "error hooking up delete callback\n");
+ }
+}