/* * 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 #include #include #include #ifdef HAVE_DIRSRV_SLAPI_PLUGIN_H #include #include #include #else #include #endif #include #include #ifdef HAVE_TCPD_H #include #endif #include "backend.h" #include "defaults.h" #include "dispatch.h" #include "format.h" #include "plugin.h" #include "map.h" #define MAP_CONFIGURATION_FILTER "(objectClass=*)(" MAP_CONFIGURATION_BASE_ATTR "=*)(" MAP_CONFIGURATION_DOMAIN_ATTR "=*)(" MAP_CONFIGURATION_MAP_ATTR "=*)" /* The data we ask the map cache to keep, for us, for each map. */ struct backend_map_data { struct plugin_state *state; char *domain, *map, **bases, *entry_filter, **key_formats; char *value_format; int n_key_formats; char *disallowed_chars; char **ref_attrs; struct format_inref_attr **inref_attrs; }; /* Read the name of the NIS master. */ void backend_free_master_name(struct plugin_state *state, char *master) { free(master); } int backend_read_master_name(struct plugin_state *state, char **master) { Slapi_DN *config_dn; Slapi_Entry *config; Slapi_ValueSet *values; Slapi_Value *value; char *attrs[] = {"nsslapd-localhost", NULL}, *actual_attr; const char *cvalue; int disposition, buffer_flags; *master = NULL; /* Try to read our name from the top-level configuration node. */ config_dn = slapi_sdn_new_dn_byval("cn=config"); if (config_dn == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "backend_master_name: " "error parsing \"cn=config\"\n"); return -1; } config = NULL; slapi_search_internal_get_entry(config_dn, attrs, &config, state->plugin_identity); if (config == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "backend_master_name: failure reading entry " "\"cn=config\"\n"); slapi_sdn_free(&config_dn); return -1; } slapi_sdn_free(&config_dn); /* Pull out the attribute. */ if (slapi_vattr_values_get(config, attrs[0], &values, &disposition, &actual_attr, 0, &buffer_flags) == 0) { if (slapi_valueset_first_value(values, &value) == 0) { cvalue = slapi_value_get_string(value); if (cvalue != NULL) { *master = strdup(cvalue); } } else { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "backend_master_name: no \"%s\" value " "for \"cn=config\"", attrs[0]); } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } slapi_entry_free(config); return (*master != NULL) ? 0 : -1; } static void backend_free_strlist(char **strlist) { int i; if (strlist) { free(strlist); } } static char ** backend_dup_strlist(char **strlist) { int i, l; char **ret, *s; /* Handle the NULL case. */ if (strlist == NULL) { return NULL; } /* Count the amount of space needed for the strings. */ for (i = 0, l = 0; (strlist[i] != NULL); i++) { l += (strlen(strlist[i]) + 1); } /* No strings = no list. */ if (i == 0) { return NULL; } /* Allocate space for the array of pointers (with NULL terminator) and * then the string data. */ ret = malloc(((i + 1) * sizeof(char *)) + l); if (ret != NULL) { /* Figure out where the string data will start. */ s = (char *) &ret[i + 1]; for (i = 0; (strlist[i] != NULL); 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(s) + 1); } /* NULL-terminate the array. */ ret[i] = NULL; } return ret; } static void backend_free_map_data_contents(void *data) { struct backend_map_data *map_data = data; if (map_data != NULL) { free(map_data->domain); free(map_data->map); free(map_data->bases); free(map_data->disallowed_chars); format_free_attr_list(map_data->ref_attrs); format_free_inref_attrs(map_data->inref_attrs); free(map_data->entry_filter); backend_free_strlist(map_data->key_formats); free(map_data->value_format); } } static void backend_free_map_data(void *data) { backend_free_map_data_contents(data); free(data); } static struct backend_map_data * backend_copy_cb_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->domain = strdup(data->domain); ret->map = strdup(data->map); ret->bases = backend_dup_strlist(data->bases); ret->disallowed_chars = data->disallowed_chars ? strdup(data->disallowed_chars) : NULL; 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->key_formats = backend_dup_strlist(data->key_formats); ret->n_key_formats = data->n_key_formats; ret->value_format = strdup(data->value_format); if ((ret->domain == NULL) || (ret->map == NULL) || (ret->bases == NULL) || (ret->disallowed_chars == NULL) || (ret->entry_filter == NULL) || (ret->key_formats == NULL) || (ret->value_format == NULL)) { backend_free_map_data(ret); return NULL; } return ret; } /* Given a map-entry directory entry, determine which keys it should have, * determine which value should be associated with those keys, 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 **keys, *value, *ndn; int i, j; data = callback_data; /* Pull out the keys and value for the entry. */ keys = malloc((data->n_key_formats + 1) * sizeof(char *)); if (keys != NULL) { for (i = 0; i < data->n_key_formats; i++) { keys[i] = format_get_data(data->state, NULL, e, data->domain, data->map, data->key_formats[i], data->disallowed_chars, &data->ref_attrs, &data->inref_attrs); } keys[i] = NULL; } else { return 0; } value = format_get_data(data->state, NULL, e, data->domain, data->map, data->value_format, data->disallowed_chars, &data->ref_attrs, &data->inref_attrs); /* Pull out the NDN of this entry. */ ndn = slapi_entry_get_ndn(e); /* If we actually generated a value, then set it, otherwise clear it in * case there was one set before. */ if ((keys != NULL) && (value != NULL)) { for (i = 0; i < data->n_key_formats; i++) { slapi_log_error(SLAPI_LOG_PLUGIN, data->state->plugin_desc->spd_id, "setting domain/map/key/value " "\"%s\"/\"%s\"/\"%s\"(\"%s\")=\"%s\"\n", data->domain, data->map, keys[i], ndn, value); } map_data_set_entry(data->state, data->domain, data->map, ndn, data->n_key_formats, NULL, keys, -1, value); } else { slapi_log_error(SLAPI_LOG_PLUGIN, data->state->plugin_desc->spd_id, "no value for %s, unsetting domain/map/id" "\"%s\"/\"%s\"/(\"%s\")\n", ndn, data->domain, data->map, ndn); map_data_unset_entry_id(data->state, data->domain, data->map, ndn); } format_free_data(value); for (i = 0; i < data->n_key_formats; i++) { format_free_data(keys[i]); } free(keys); 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); } } /* * Generate a copy of the filter string, with specific sequences replaced: * %d -> name of the domain * %m -> name of the map * %% -> literal '%' */ static char * backend_map_config_filter(const char *format, const char *domain, const char *map) { char *ret; int i, j, l; l = 0; for (i = 0; format[i] != '\0'; i++) { if (format[i] == '%') { switch (format[i + 1]) { case 'd': l += strlen(domain); i++; break; case 'm': l += strlen(map); i++; break; case '%': l++; i++; break; default: l++; break; } } else { l++; } } ret = malloc(l + 1); for (i = j = 0; format[i] != '\0'; i++) { if (format[i] == '%') { switch (format[i + 1]) { case 'd': strcpy(ret + j, domain); i++; j += strlen(domain); break; case 'm': strcpy(ret + j, map); i++; j += strlen(map); break; case '%': i++; ret[j++] = format[i]; break; default: ret[j++] = format[i]; break; } } else { ret[j++] = format[i]; } } ret[j] = '\0'; return ret; } /* Given an entry, read the map configuration for the given domain and map * name. */ static void backend_map_config_read_config(struct plugin_state *state, Slapi_Entry *e, const char *domain, const char *map, bool_t *secure, struct backend_map_data *ret) { const char *default_filter, **default_key_formats; const char *default_value_format, *default_disallowed_chars; char **bases, *entry_filter, **key_formats, *value_format, *actual_attr; char **ref_attrs, *disallowed_chars; struct format_inref_attr **inref_attrs; char **use_bases, *use_entry_filter, **use_key_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 hard-coded defaults for a map with this name. */ defaults_get_map_config(map, secure, &default_filter, &default_key_formats, &default_value_format, &default_disallowed_chars); /* Read the values from the configuration entry. */ bases = NULL; if (slapi_vattr_values_get(e, MAP_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, MAP_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); entry_filter = strdup(cvalue); } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } key_formats = NULL; if (slapi_vattr_values_get(e, MAP_CONFIGURATION_KEY_ATTR, &values, &disposition, &actual_attr, 0, &buffer_flags) == 0) { key_formats = malloc((slapi_valueset_count(values) + 1) * (sizeof (char *))); if (key_formats != 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); key_formats[i++] = strdup(cvalue); } key_formats[i] = NULL; slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } } value_format = NULL; if (slapi_vattr_values_get(e, MAP_CONFIGURATION_VALUE_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); value_format = strdup(cvalue); } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } disallowed_chars = NULL; if (slapi_vattr_values_get(e, MAP_CONFIGURATION_DISALLOWED_CHARS_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); disallowed_chars = strdup(cvalue); } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } *secure = FALSE; if (slapi_vattr_values_get(e, MAP_CONFIGURATION_SECURE_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); /* FIXME: use nl_langinfo(YESEXPR) here? */ if ((strcasecmp(cvalue, "yes") == 0) || (strcasecmp(cvalue, "on") == 0) || (strcasecmp(cvalue, "1") == 0)) { *secure = TRUE; } else { *secure = FALSE; } } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } /* Build a filter, using either the configured value or the default as * a template, we need to do this because RFC2307bis sometimes stores * the map name in each entry, so it's useful to be able to filter on * it. */ use_entry_filter = backend_map_config_filter(entry_filter ? entry_filter : default_filter, domain, map); use_key_formats = key_formats ? backend_dup_strlist(key_formats) : backend_dup_strlist((char **) default_key_formats); use_value_format = value_format ? strdup(value_format) : strdup(default_value_format); use_bases = backend_dup_strlist(bases); use_disallowed_chars = disallowed_chars ? disallowed_chars : (default_disallowed_chars ? strdup(default_disallowed_chars) : NULL); /* Free the values we read from the entry. */ free(value_format); backend_free_strlist(key_formats); free(entry_filter); backend_free_strlist(bases); /* Populate the returned structure. */ ret->state = state; ret->domain = strdup(domain); ret->map = strdup(map); ret->bases = use_bases; ret->disallowed_chars = use_disallowed_chars; ret->entry_filter = use_entry_filter; ret->key_formats = use_key_formats; ret->value_format = use_value_format; ret->ref_attrs = NULL; ret->inref_attrs = NULL; ret->n_key_formats = 0; for (i = 0; (use_key_formats != NULL) && (use_key_formats[i] != NULL); i++) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "initializing map %s in %s (3): " "filter \"%s\", " "key \"%s\", " "value \"%s\"\n", map, domain, use_entry_filter, use_key_formats[i], use_value_format); ret->n_key_formats++; } } /* Given a directory server entry which represents a map's configuration, set * up and populate the map. */ static int backend_map_config_entry_add_one(struct plugin_state *state, Slapi_Entry *e, const char *domain, const char *map) { Slapi_PBlock *pb; int i; bool_t secure; struct backend_map_data cb_data, *map_cb_data; pb = slapi_pblock_new(); secure = FALSE; backend_map_config_read_config(state, e, domain, map, &secure, &cb_data); map_cb_data = backend_copy_cb_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 map definition %s in %s (2)\n", map, domain); slapi_pblock_destroy(pb); return 0; } slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "initializing map %s in %s, secure=%s (2)\n", map, domain, secure ? "yes" : "no"); map_data_set_map(state, domain, map, map_cb_data->n_key_formats, secure, map_cb_data, &backend_free_map_data); map_data_clear_map(state, domain, map); /* Search under each base in turn, adding the matching directory * entries to the NIS maps. */ 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 domain and map * names which are valid for this configuration and configure such a map for * each in turn. */ static int backend_map_config_entry_add_cb(Slapi_Entry *e, void *callback_data) { char **domains, **maps, *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; domains = NULL; if (slapi_vattr_values_get(e, MAP_CONFIGURATION_DOMAIN_ATTR, &values, &disposition, &actual_attr, 0, &buffer_flags) == 0) { count = slapi_valueset_count(values); domains = malloc(sizeof(char *) * (count + 1)); if (domains != 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); domains[i] = strdup(cvalue); } domains[count] = NULL; } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } maps = NULL; if (slapi_vattr_values_get(e, MAP_CONFIGURATION_MAP_ATTR, &values, &disposition, &actual_attr, 0, &buffer_flags) == 0) { count = slapi_valueset_count(values); maps = malloc(sizeof(char *) * (count + 1)); if (maps != 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); maps[i] = strdup(cvalue); } maps[count] = NULL; } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } for (i = 0; (domains != NULL) && (domains[i] != NULL); i++) { for (j = 0; (maps != NULL) && (maps[j] != NULL); j++) { ret = backend_map_config_entry_add_one(state, e, domains[i], maps[j]); } } if (domains != NULL) { for (i = 0; (domains != NULL) && (domains[i] != NULL); i++) { free(domains[i]); } free(domains); } if (maps != NULL) { for (i = 0; (maps != NULL) && (maps[i] != NULL); i++) { free(maps[i]); } free(maps); } return 0; } /* Update/initialize parameters stored in the plugin's configuration entry. */ static void backend_read_params(struct plugin_state *state) { Slapi_DN *our_dn; Slapi_Entry *our_entry; Slapi_ValueSet *values; Slapi_Value *value; char *actual_attr; const char *cvalue; int disposition, buffer_flags, ivalue, i, j; unsigned int uvalue; char *attrs[] = { PLUGIN_CONFIGURATION_MAXVALUE_ATTR, PLUGIN_CONFIGURATION_MAXDGRAM_ATTR, PLUGIN_CONFIGURATION_PORT_ATTR, PLUGIN_CONFIGURATION_SECURENET_ATTR, PLUGIN_CONFIGURATION_TCPWRAPNAME_ATTR, NULL, }; our_dn = slapi_sdn_new_dn_byval(state->plugin_base); if (our_dn == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "backend_read_params: " "error parsing %s%s%s\n", state->plugin_base ? "\"" : "", state->plugin_base ? state->plugin_base : "NULL", state->plugin_base ? "\"" : ""); return; } slapi_search_internal_get_entry(our_dn, attrs, &our_entry, state->plugin_identity); slapi_sdn_free(&our_dn); our_dn = NULL; if (our_entry == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "backend_read_params: failure reading entry " "\"%s\"\n", state->plugin_base); return; } /* Pull out the attribute values. */ for (i = 0; attrs[i] != NULL; i++) { if (slapi_vattr_values_get(our_entry, attrs[i], &values, &disposition, &actual_attr, 0, &buffer_flags) == 0) { value = NULL; j = slapi_valueset_first_value(values, &value); if (j != -1) { switch (i) { case 0: /* max value size */ uvalue = slapi_value_get_uint(value); if (uvalue != 0) { state->max_value_size = uvalue; } else { state->max_value_size = DEFAULT_MAX_VALUE_SIZE; } slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "backend_read_params: " "setting max value " "size %u\n", state->max_value_size); break; case 1: /* max dgram size */ uvalue = slapi_value_get_uint(value); if (uvalue != 0) { state->max_dgram_size = uvalue; } else { state->max_dgram_size = DEFAULT_MAX_DGRAM_SIZE; } slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "backend_read_params: " "setting max dgram " "size %u\n", state->max_dgram_size); break; case 3: /* securenet entry */ dispatch_securenets_clear(state); while (j != -1) { cvalue = slapi_value_get_string(value); dispatch_securenets_add(state, cvalue); j = slapi_valueset_next_value(values, j, &value); } break; case 4: /* tcp-wrappers name */ #ifdef HAVE_TCPD_H cvalue = slapi_value_get_string(value); request_set(state->request_info, RQ_DAEMON, cvalue); #endif break; default: break; } } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } else { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "backend_read_params: no \"%s\" value " "for \"%s\", using default\n", attrs[i], state->plugin_base); } } slapi_entry_free(our_entry); } /* Scan for the list of configured domains and maps. */ void backend_startup(struct plugin_state *state) { Slapi_PBlock *pb; char *attrs = NULL; backend_read_params(state); pb = slapi_pblock_new(); slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "searching \"%s\" for maps\n", state->plugin_base); slapi_search_internal_set_pb(pb, state->plugin_base, LDAP_SCOPE_ONE, MAP_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 **domains, **maps; int i, j, ret; struct plugin_state *state; state = callback_data; domains = slapi_entry_attr_get_charray(e, "domain"); maps = slapi_entry_attr_get_charray(e, "map"); for (i = 0; (domains != NULL) && (domains[i] != NULL); i++) { for (j = 0; (maps != NULL) && (maps[j] != NULL); j++) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "removing map %s in %s\n", maps[j], domains[i]); map_data_unset_map(state, domains[i], maps[j]); } } slapi_ch_array_free(maps); slapi_ch_array_free(domains); return 0; } 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) { int i; 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, **ret; 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 map configuration from \"%s\"\n", slapi_entry_get_ndn(e)); values = NULL; value = NULL; if (slapi_vattr_values_get(e, MAP_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, MAP_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 *domain, const char *map, bool_t *secure, char ***bases, char **entry_filter) { Slapi_PBlock *pb; char *filter; char *attrs[] = {"filter", "base", NULL}; const char *default_filter; bool_t map_secure; struct backend_get_map_config_cb cbdata; /* Build the search filter. */ filter = malloc(strlen("(&(" MAP_CONFIGURATION_DOMAIN_ATTR "=)(" MAP_CONFIGURATION_MAP_ATTR "=)(" MAP_CONFIGURATION_BASE_ATTR "=*))") + strlen(domain) + strlen(map) + strlen(MAP_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", domain, map); return; } sprintf(filter, "(&(" MAP_CONFIGURATION_DOMAIN_ATTR "=%s)(" MAP_CONFIGURATION_MAP_ATTR "=%s)(" MAP_CONFIGURATION_BASE_ATTR "=*)%s)", domain, map, MAP_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; map_secure = FALSE; defaults_get_map_config(map, &map_secure, &default_filter, NULL, NULL, NULL); cbdata.entry_filter = strdup(default_filter); slapi_search_internal_callback_pb(pb, &cbdata, NULL, backend_get_map_config_entry_cb, NULL); /* Return the results. */ if (secure) { *secure = map_secure; } *bases = cbdata.bases; *entry_filter = backend_map_config_filter(cbdata.entry_filter, domain, map); free(cbdata.entry_filter); /* Clean up. */ slapi_pblock_destroy(pb); free(filter); } /* Our postoperation callbacks. */ /* Given a map configuration, return true if the entry is supposed to be in the * map. */ 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 NIS map. */ 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 map_configuration_filter[] = MAP_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(map_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 map configuration " "(didn't match filter " "\"%s\")\n", slapi_sdn_get_ndn(entry_sdn), MAP_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 **referred_to_dn, **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) { Slapi_DN *base_sdn, *entry_sdn; Slapi_Filter *filter; 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) { Slapi_DN *base_sdn, *entry_sdn; Slapi_Filter *filter; 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 domain/map/id " "\"%s\"/\"%s\"/(\"%s\")\n", map_data->domain, map_data->map, cbdata->ndn); map_data_unset_entry_id(cbdata->state, map_data->domain, map_data->map, 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); } /* Lastly, if the entry is our own entry, re-read parameters. */ sdn = slapi_sdn_new_dn_byref(cbdata.state->plugin_base); if (sdn != NULL) { if ((strcmp(slapi_entry_get_ndn(cbdata.e_pre), slapi_sdn_get_ndn(sdn)) == 0) || (strcmp(slapi_entry_get_ndn(cbdata.e_post), slapi_sdn_get_ndn(sdn)) == 0)) { backend_read_params(cbdata.state); } slapi_sdn_free(&sdn); } 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 domain/map/id " "\"%s\"/\"%s\"/(\"%s\")\n", map_data->domain, map_data->map, cbdata->ndn_pre); map_data_unset_entry_id(cbdata->state, map_data->domain, map_data->map, 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 *domain, const char *map, 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 domain/map/id" "\"%s\"/\"%s\"=\"%s\"/\"%s\"/(\"%s\")\n", domain, map, map_data->domain, map_data->map, cbdata->ndn); map_data_unset_entry_id(cbdata->state, domain, map, 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"); } }