/* * Copyright 2008,2010,2011,2012,2013 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 "../yp/yp.h" #ifdef HAVE_TCPD_H #include #endif #include "backend.h" #include "back-shr.h" #include "format.h" #include "plugin.h" #include "map.h" /* Check if the caller for the current operation is *us*. */ bool_t backend_shr_is_caller(struct plugin_state *state, Slapi_PBlock *pb) { Slapi_ComponentId *identity; slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &identity); return (identity == state->plugin_identity); } /* Read the name of this server. Used by the map module on behalf of the * NIS service logic. */ void backend_shr_free_server_name(struct plugin_state *state, char *master) { free(master); } int backend_shr_read_server_name(Slapi_PBlock *pb, 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; } wrap_search_internal_get_entry(pb, config_dn, NULL, 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; } /* Cache the list of relevant attributes, updating if needed, and return its * value. Currently only used for logging. */ static const char * backend_shr_get_rel_attr_list(struct backend_shr_set_data *data) { int i, length; if (data->rel_attrs_list == data->rel_attrs) { return data->rel_attr_list; } else { free(data->rel_attr_list); if (data->rel_attrs == NULL) { data->rel_attr_list = NULL; } else { for (i = 0, length = 0; data->rel_attrs[i] != NULL; i++) { length += (strlen(data->rel_attrs[i]) + 1); } if (length > 0) { data->rel_attr_list = malloc(length); for (i = 0, length = 0; (data->rel_attrs[i] != NULL); i++) { if (i > 0) { strcpy(data->rel_attr_list + length++, ","); } strcpy(data->rel_attr_list + length, data->rel_attrs[i]); length += strlen(data->rel_attrs[i]); } } else { data->rel_attr_list = NULL; } } data->rel_attrs_list = data->rel_attrs; } return data->rel_attr_list ? data->rel_attr_list : ""; } /* Manipulate string lists. */ void backend_shr_free_strlist(char **strlist) { if (strlist) { free(strlist); } } char ** backend_shr_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; } char ** backend_shr_dup_strlist(char **strlist) { int i; for (i = 0; (strlist != NULL) && (strlist[i] != NULL); i++) { continue; } return backend_shr_dup_strlist_n(strlist, i); } char ** backend_shr_dup_strlist_unless_empty(char **strlist) { int i; for (i = 0; (strlist != NULL) && (strlist[i] != NULL) && (strlen(strlist[i]) > 0); i++) { continue; } if (i > 0) { return backend_shr_dup_strlist_n(strlist, i); } else { return NULL; } } void backend_shr_add_strlist(char ***strlist, const char *value) { int i, elements, length; char **ret, *p; length = strlen(value) + 1; elements = 0; if (*strlist != NULL) { for (i = 0; (*strlist)[i] != NULL; i++) { if (strcmp(value, (*strlist)[i]) == 0) { return; } length += (strlen((*strlist)[i]) + 1); elements++; } } ret = malloc(((elements + 2) * sizeof(char *)) + length); if (ret != NULL) { p = (char *) ret; p += (elements + 2) * sizeof(char *); for (i = 0; i < elements; i++) { ret[i] = p; strcpy(p, (*strlist)[i]); p += (strlen((*strlist)[i]) + 1); } ret[i++] = p; strcpy(p, value); p += (strlen(value) + 1); ret[i] = NULL; backend_shr_free_strlist(*strlist); } *strlist = ret; } /* Set or unset the entry using information in the callback data. */ static void backend_shr_set_entry(Slapi_PBlock *pb, Slapi_Entry *e, struct backend_set_data *set_data) { backend_set_entry(pb, e, set_data); } struct backend_shr_set_entry_cbdata { Slapi_PBlock *pb; struct backend_set_data *set_data; }; static int backend_shr_set_entry_cb(Slapi_Entry *e, void *callback_data) { struct backend_shr_set_entry_cbdata *cbdata; cbdata = 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; } if (*sdnlist != NULL) { for (i = 0; (*sdnlist)[i] != NULL; i++) { continue; } } ret = calloc(i + 2, sizeof(ret[0])); if (ret != NULL) { if (*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) { const Slapi_DN **ret; int i; /* Handle the NULL case. */ if (sdnlist == NULL) { return NULL; } /* No DNs = no list. */ if (n == 0) { return NULL; } ret = calloc(n + 1, sizeof(ret[0])); for (i = 0; (sdnlist[i] != NULL) && (i < n); i++) { ret[i] = slapi_sdn_dup(sdnlist[i]); } return ret; } const Slapi_DN ** backend_shr_dup_sdnlist(const Slapi_DN **sdnlist) { int i; for (i = 0; (sdnlist != NULL) && (sdnlist[i] != NULL); i++) { continue; } return backend_shr_dup_sdnlist_n(sdnlist, i); } void backend_shr_free_sdnlist(const Slapi_DN **sdnlist) { int i; for (i = 0; (sdnlist != NULL) && (sdnlist[i] != NULL); i++) { slapi_sdn_free((Slapi_DN **) &sdnlist[i]); sdnlist[i] = NULL; } free(sdnlist); } /* Set or unset the named entry using information in the callback data. */ static void backend_shr_set_config_entry_set_one_dn(struct plugin_state *state, Slapi_PBlock *pb, const char *dn, struct backend_set_data *set_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 { wrap_search_internal_get_entry(pb, sdn, NULL, 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_shr_set_entry(pb, entry, set_data); slapi_entry_free(entry); } slapi_sdn_free(&sdn); } } /* Check if the given entry is somewhere beneath the NDN and matches the * filter. */ static bool_t backend_shr_entry_matches(Slapi_PBlock *pb, Slapi_Entry *e, const char *containing_ndn, int scope, const char *check_filter) { Slapi_DN *entry_sdn, *containing_sdn; Slapi_Filter *filter; char *filterstr; bool_t ret; /* First, just do the scope test. The item should be a somewhere * beneath the passed-in entry. */ entry_sdn = slapi_sdn_new_ndn_byref(slapi_entry_get_ndn(e)); if (entry_sdn == NULL) { return FALSE; } else { containing_sdn = slapi_sdn_new_dn_byval(containing_ndn); if (containing_sdn == NULL) { slapi_sdn_free(&entry_sdn); return FALSE; } } if (slapi_sdn_scope_test(entry_sdn, containing_sdn, scope) == 0) { ret = FALSE; } else { ret = TRUE; } slapi_sdn_free(&containing_sdn); slapi_sdn_free(&entry_sdn); /* If it's actually in our configuration tree, check if it's a valid * entry. */ if (ret) { /* N.B.: slapi_str2filter isn't kidding -- it really wants a * writable string. */ filterstr = strdup(check_filter); if (filterstr != NULL) { filter = slapi_str2filter(filterstr); if (filter != NULL) { if (slapi_vattr_filter_test(pb, e, filter, 0) != 0) { ret = FALSE; } slapi_filter_free(filter, 1); } free(filterstr); } } return ret; } /* Given a directory server entry which represents a set's configuration, set * up and populate the set. */ static void backend_shr_set_config_free_config(void *cb_data) { struct backend_shr_set_data *set_data; set_data = cb_data; backend_set_config_free_config(set_data); } int backend_shr_set_config_entry_add(struct plugin_state *state, Slapi_PBlock *parent_pb, Slapi_Entry *e, const char *group, const char *set) { Slapi_PBlock *pb; int i; bool_t flag; struct backend_shr_set_data *set_data; struct backend_shr_set_entry_cbdata cbdata; char **set_bases; char *set_entry_filter; flag = FALSE; backend_set_config_read_config(state, e, group, set, &flag, &set_data); if (set_data == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "incomplete definition for %s in %s (2)\n", set, group); return 0; } slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "initializing \"%s\" in %s, flag=%s (2)\n", set_data->set, set_data->group, flag ? "yes" : "no"); map_data_set_map(state, set_data->group, set_data->set, flag, set_data, &backend_shr_set_config_free_config); map_data_clear_map(state, set_data->group, set_data->set); /* Search under each base in turn, adding the matching directory * entries to the set. */ set_bases = set_data->bases; set_entry_filter = set_data->entry_filter; for (i = 0; (set_bases != NULL) && (set_bases[i] != NULL); i++) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "searching '%s' for '%s'\n", set_bases[i], set_entry_filter); pb = wrap_pblock_new(parent_pb); slapi_search_internal_set_pb(pb, set_bases[i], LDAP_SCOPE_SUBTREE, set_entry_filter, NULL, FALSE, NULL, NULL, state->plugin_identity, 0); cbdata.set_data = set_data->self; cbdata.pb = pb; slapi_search_internal_callback_pb(pb, &cbdata, NULL, backend_shr_set_entry_cb, NULL); slapi_pblock_destroy(pb); } /* Warn if we didn't put anything into the set. */ backend_check_empty(state, set_data->group, set_data->set); /* Clean up. */ return 0; } /* Read a list of string values for the named attribute. */ char ** backend_shr_get_vattr_strlist(struct plugin_state *state, Slapi_Entry *e, const char *attribute) { Slapi_ValueSet *values; Slapi_Value *value; int disposition, buffer_flags; char *actual_attr, **ret; const char **tmp; int i, j; ret = NULL; if (slapi_vattr_values_get(e, (char *) attribute, &values, &disposition, &actual_attr, 0, &buffer_flags) == 0) { tmp = malloc(sizeof(char *) * (slapi_valueset_count(values) + 1)); if (tmp != NULL) { j = 0; for (i = slapi_valueset_first_value(values, &value); i != -1; i = slapi_valueset_next_value(values, i, &value)) { if (slapi_value_get_length(value) > 0) { tmp[j++] = slapi_value_get_string(value); } } tmp[j] = NULL; ret = backend_shr_dup_strlist((char **) tmp); free(tmp); } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } return ret; } char * backend_shr_get_vattr_str(struct plugin_state *state, Slapi_Entry *e, const char *attribute) { Slapi_ValueSet *values; Slapi_Value *value; int disposition, buffer_flags; char *actual_attr, *ret; int i; ret = NULL; if (slapi_vattr_values_get(e, (char *) attribute, &values, &disposition, &actual_attr, 0, &buffer_flags) == 0) { i = slapi_valueset_first_value(values, &value); if (i != -1) { if (slapi_value_get_length(value) > 0) { ret = strdup(slapi_value_get_string(value)); } } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } return ret; } unsigned int backend_shr_get_vattr_uint(struct plugin_state *state, Slapi_Entry *e, const char *attribute, unsigned int default_value) { Slapi_ValueSet *values; Slapi_Value *value; int disposition, buffer_flags, i; char *actual_attr; unsigned int ret; ret = default_value; if (slapi_vattr_values_get(e, (char *) attribute, &values, &disposition, &actual_attr, 0, &buffer_flags) == 0) { i = slapi_valueset_first_value(values, &value); if (i != -1) { ret = slapi_value_get_uint(value); } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } return ret; } char * backend_shr_get_vattr_filter(struct plugin_state *state, Slapi_Entry *e, const char *attribute) { char *tmp, *ret; ret = backend_shr_get_vattr_str(state, e, attribute); if (ret != NULL) { if (strlen(ret) > 0) { if ((ret[0] != '(') || (ret[strlen(ret) - 1] != ')')) { tmp = malloc(strlen(ret) + 3); if (tmp != NULL) { sprintf(tmp, "(%s)", ret); free(ret); ret = tmp; } } } } return ret; } bool_t backend_shr_get_vattr_boolean(struct plugin_state *state, Slapi_Entry *e, const char *attribute, bool_t default_value) { char *tmp; bool_t ret; ret = default_value; tmp = backend_shr_get_vattr_str(state, e, attribute); if (tmp != NULL) { /* FIXME: should we use nl_langinfo(YESEXPR) here? */ if ((strcasecmp(tmp, "yes") == 0) || (strcasecmp(tmp, "true") == 0) || (strcasecmp(tmp, "on") == 0) || (strcasecmp(tmp, "1") == 0)) { ret = TRUE; } else { if ((strcasecmp(tmp, "no") == 0) || (strcasecmp(tmp, "false") == 0) || (strcasecmp(tmp, "off") == 0) || (strcasecmp(tmp, "0") == 0)) { ret = FALSE; } else { ret = default_value; } } free(tmp); } return ret; } const Slapi_DN ** backend_shr_get_vattr_sdnlist(struct plugin_state *state, Slapi_Entry *e, const char *attribute) { Slapi_ValueSet *values; Slapi_Value *value; int disposition, buffer_flags; char *actual_attr; const Slapi_DN **ret; int i, j; ret = NULL; if (slapi_vattr_values_get(e, (char *) attribute, &values, &disposition, &actual_attr, 0, &buffer_flags) == 0) { ret = malloc(sizeof(ret[0]) * (slapi_valueset_count(values) + 1)); if (ret != NULL) { j = 0; for (i = slapi_valueset_first_value(values, &value); i != -1; i = slapi_valueset_next_value(values, i, &value)) { if (slapi_value_get_length(value) > 0) { ret[j++] = slapi_sdn_new_dn_byval(slapi_value_get_string(value)); } } ret[j] = NULL; } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } return ret; } /* Scan for the list of configured groups and sets. */ void backend_shr_startup(struct plugin_state *state, Slapi_PBlock *parent_pb, const char *filter) { Slapi_PBlock *pb; struct backend_set_config_entry_add_cbdata set_cbdata; backend_update_params(parent_pb, state); slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "searching under \"%s\" for configuration\n", state->plugin_base); pb = wrap_pblock_new(parent_pb); slapi_search_internal_set_pb(pb, state->plugin_base, LDAP_SCOPE_ONELEVEL, filter, NULL, FALSE, NULL, NULL, state->plugin_identity, 0); if (map_wrlock() != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "failed to search under \"%s\" for " "configuration: failed to acquire a lock\n", state->plugin_base); goto done_with_lock; } set_cbdata.state = state; set_cbdata.pb = pb; slapi_search_internal_callback_pb(pb, &set_cbdata, NULL, backend_set_config_entry_add_cb, NULL); map_unlock(); done_with_lock: slapi_pblock_destroy(pb); } /* Process a set configuration directory entry. Pull out the group and set * names which are specified in the entry and delete each in turn. */ int backend_shr_set_config_entry_delete(struct plugin_state *state, Slapi_Entry *e, const char *group_attr, const char *set_attr) { char **groups, **sets; struct backend_shr_set_data *set_data; int i, j; bool_t flag; groups = slapi_entry_attr_get_charray(e, group_attr); sets = slapi_entry_attr_get_charray(e, set_attr); for (i = 0; (groups != NULL) && (groups[i] != NULL); i++) { for (j = 0; (sets != NULL) && (sets[j] != NULL); j++) { backend_set_config_read_config(state, e, groups[i], sets[j], &flag, &set_data); slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "removing set %s in %s\n", set_data->set, set_data->group); map_data_unset_map(state, set_data->group, set_data->set); backend_set_config_free_config(set_data); } } slapi_ch_array_free(sets); slapi_ch_array_free(groups); return 0; } struct backend_get_set_config_cb { struct plugin_state *state; char **bases; char *entry_filter; }; /* Used by the format functions to read set configuration. */ void backend_shr_free_set_config(char **bases, char *entry_filter) { backend_shr_free_strlist(bases); free(entry_filter); } static bool_t backend_shr_get_set_config_entry_cb(Slapi_Entry *e, void *callback_data, const char *base_attr, const char *filter_attr) { Slapi_ValueSet *values; Slapi_Value *value; struct backend_get_set_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 set configuration from \"%s\"\n", slapi_entry_get_ndn(e)); values = NULL; value = NULL; if (slapi_vattr_values_get(e, (char *) 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, (char *) 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; } /* Our postoperation callbacks. */ /* Given a map configuration, return true if the entry is supposed to be in the * map. */ static bool_t backend_shr_entry_matches_set(struct backend_shr_set_data *set_data, Slapi_PBlock *pb, Slapi_Entry *e) { const Slapi_DN **restrict_subtrees, **ignore_subtrees; char **set_bases; char *set_filter; int i; restrict_subtrees = set_data->restrict_subtrees; ignore_subtrees = set_data->ignore_subtrees; set_bases = set_data->bases; set_filter = set_data->entry_filter; 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)) { 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; } /* Given an entry, return true if it describes a set. */ static bool_t backend_shr_entry_is_a_set(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e) { return backend_shr_entry_matches(pb, e, state->plugin_base, LDAP_SCOPE_ONELEVEL, backend_entry_get_set_config_entry_filter()); } /* Build a filter which includes the basic_filter, if given, and ANDs that * with an OR of the elements of attrs exactly matching the entry's DN. */ static char * backend_build_filter(struct plugin_state *state, Slapi_DN *entry_dn, const char *basic_filter, char **attrs) { char *filter, *tndn; int filter_size, i, n_attrs; if (basic_filter == NULL) { basic_filter = ""; } filter_size = strlen("(&(|))") + strlen(basic_filter) + 1; tndn = format_escape_for_filter(slapi_sdn_get_ndn(entry_dn)); if (tndn == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error building filter for " "updating entries\n"); return NULL; } for (i = 0; (attrs != NULL) && (attrs[i] != NULL); i++) { filter_size += (strlen("(=)") + strlen(attrs[i]) + strlen(tndn)); } n_attrs = i; 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 NULL; } if (n_attrs > 1) { if (strlen(basic_filter) > 0) { sprintf(filter, "(&%s(|", basic_filter); } else { sprintf(filter, "(|"); } } else { if (strlen(basic_filter) > 0) { sprintf(filter, "(&%s", basic_filter); } else { strcpy(filter, ""); } } for (i = 0; (attrs != NULL) && (attrs[i] != NULL); i++) { sprintf(filter + strlen(filter), "(%s=%s)", attrs[i], tndn); } free(tndn); if (n_attrs > 1) { if (strlen(basic_filter) > 0) { strcat(filter, "))"); } else { strcat(filter, ")"); } } else { if (strlen(basic_filter) > 0) { strcat(filter, ")"); } else { strcat(filter, ""); } } return filter; } /* Add the name of this entry to the DN list in the cbdata. */ struct backend_shr_note_entry_sdn_cbdata { struct plugin_state *state; Slapi_DN ***sdn_list, ***sdn_list2; }; static int backend_shr_note_entry_sdn_cb(Slapi_Entry *e, void *cbdata_ptr) { struct backend_shr_note_entry_sdn_cbdata *cbdata = cbdata_ptr; slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id, "matched entry \"%s\"\n", slapi_entry_get_dn(e)); format_add_sdn_list(cbdata->sdn_list, cbdata->sdn_list2, slapi_entry_get_dn(e)); return 0; } /* Build a string representation of the list of attributes being modified by * this list of mods, typically for logging purposes. */ static char * backend_shr_mods_as_string(LDAPMod **mods) { char *ret; int i, length; ret = NULL; for (i = 0, length = 0; (mods != NULL) && (mods[i] != NULL); i++) { length += (strlen(mods[i]->mod_type) + 1 + 8); } if (length > 0) { ret = malloc(length); for (i = 0, length = 0; (mods != NULL) && (mods[i] != NULL); i++) { if (i > 0) { strcpy(ret + length++, ","); } if (SLAPI_IS_MOD_ADD(mods[i]->mod_op)) { strcpy(ret + length, "add:"); length += 4; } if (SLAPI_IS_MOD_REPLACE(mods[i]->mod_op)) { strcpy(ret + length, "replace:"); length += 8; } if (SLAPI_IS_MOD_DELETE(mods[i]->mod_op)) { strcpy(ret + length, "delete:"); length += 7; } strcpy(ret + length, mods[i]->mod_type); length += strlen(mods[i]->mod_type); } } return ret; } /* Update any entries in the map for which the passed-in entry will affect the * values which are derived. */ struct backend_shr_update_references_cbdata { Slapi_PBlock *pb; Slapi_Entry *e; LDAPMod **mods; char *modlist; }; static bool_t backend_shr_update_references_cb(const char *group, const char *set, bool_t flag, void *backend_data, void *cbdata_ptr) { struct plugin_state *state; struct backend_shr_set_data *set_data; struct backend_shr_update_references_cbdata *cbdata; struct backend_shr_set_entry_cbdata set_cbdata; struct backend_shr_note_entry_sdn_cbdata note_cbdata; Slapi_DN *referred_to_sdn, **these_entries, **prev_entries; Slapi_DN **next_entries, **these_bases, **prev_bases; Slapi_DN **these_entries2, **prev_entries2, **next_entries2; Slapi_Entry *this_entry; Slapi_ValueSet *values; Slapi_Value *value; Slapi_Filter *next_filter; Slapi_PBlock *pb; char **ref_attrs, *actual_attr, *filter, **set_bases; char *these_attrs[2], *prev_attrs[2], *next_attrs[2]; const char *these_filter, *prev_filter, *next_filter_str; struct format_inref_attr **inref_attrs; struct format_ref_attr_list **ref_attr_list, *ref_attr; struct format_ref_attr_list **inref_attr_list, *inref_attr; struct format_ref_attr_list_link *this_attr_link, *prev_attr_link; struct format_ref_attr_list_link *next_attr_link; const char *ndn, *dn, *rel_attr_list; int i, j, k, l, disposition, buffer_flags, n_ref_attrs, scope; set_data = backend_data; cbdata = cbdata_ptr; state = set_data->state; /* 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->restrict_subtrees[i], LDAP_SCOPE_SUBTREE) != 0) { break; } } if (set_data->restrict_subtrees[i] == NULL) { /* Non-empty list, but no match. */ return TRUE; } } /* ... 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->ignore_subtrees[i], LDAP_SCOPE_SUBTREE) != 0) { /* Yeah, we're done here. */ return TRUE; } } } /* If the entry didn't change any attributes which are at all relevant * to this map, then we don't need to recompute anything. */ if (set_data->skip_uninteresting_updates && (cbdata->mods != NULL) && (set_data->rel_attrs != NULL)) { for (i = 0; cbdata->mods[i] != NULL; i++) { for (j = 0; set_data->rel_attrs[j] != NULL; j++) { if (slapi_attr_types_equivalent(cbdata->mods[i]->mod_type, set_data->rel_attrs[j])) { break; } } if (set_data->rel_attrs[j] != NULL) { break; } } rel_attr_list = backend_shr_get_rel_attr_list(set_data); if (cbdata->mods[i] == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "no interesting reference-based " "changes for \"%s\"/\"%s\" " "made in \"%s\" (\"%s\" not in \"%s\")\n", set_data->group, set_data->set, slapi_entry_get_ndn(cbdata->e), cbdata->modlist ? cbdata->modlist : "", rel_attr_list ? rel_attr_list : ""); return TRUE; } else { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "interesting reference-based " "changes for \"%s\"/\"%s\" " "made in \"%s\" (\"%s\" in \"%s\")\n", set_data->group, set_data->set, slapi_entry_get_ndn(cbdata->e), cbdata->modlist ? cbdata->modlist : "", rel_attr_list ? rel_attr_list : ""); } } else { rel_attr_list = backend_shr_get_rel_attr_list(set_data); slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "reference-based changes for " "\"%s\"/\"%s\" made in (\"%s\") " "(\"%s\" in list \"%s\" or list empty)\n", set_data->group, set_data->set, slapi_entry_get_ndn(cbdata->e), cbdata->modlist ? cbdata->modlist : "", rel_attr_list ? rel_attr_list : ""); } /* For every entry in this set 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 = set_data->ref_attrs; for (i = 0; (ref_attrs != NULL) && (ref_attrs[i] != NULL); i++) { continue; } n_ref_attrs = i; if (n_ref_attrs > 0) { /* Build the search filter: entries in this map which refer to * this entry. */ filter = backend_build_filter(state, slapi_entry_get_sdn(cbdata->e), set_data->entry_filter, ref_attrs); /* Update any matching entry. */ set_bases = set_data->bases; for (i = 0; (set_bases != NULL) && (set_bases[i] != NULL); i++) { pb = wrap_pblock_new(cbdata->pb); slapi_search_internal_set_pb(pb, set_bases[i], LDAP_SCOPE_SUBTREE, filter, NULL, FALSE, NULL, NULL, state->plugin_identity, 0); set_cbdata.set_data = set_data->self; set_cbdata.pb = pb; slapi_search_internal_callback_pb(pb, &set_cbdata, NULL, backend_shr_set_entry_cb, NULL); slapi_pblock_destroy(pb); } free(filter); } /* For every directory entry to which this directory entry refers and * which also has a corresponding entry in this map, update it. */ /* 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; } inref_attrs = set_data->inref_attrs; for (i = 0; (inref_attrs != NULL) && (inref_attrs[i] != NULL); i++) { /* 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, group, set, ndn)) { /* ...update it. */ backend_shr_set_config_entry_set_one_dn(state, cbdata->pb, ndn, set_data->self); } } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } slapi_sdn_free(&referred_to_sdn); /* Determine if there are any entries in this map which directly (or * indirectly) pull in data from this entry. If there are, update * them. */ /* Walk the set of reference-attribute chains. */ ref_attr_list = set_data->ref_attr_list; for (i = 0; (ref_attr_list != NULL) && (ref_attr_list[i] != NULL); i++) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "updating deref_r[%d] references for \"%s\"\n", i, slapi_entry_get_ndn(cbdata->e)); ref_attr = ref_attr_list[i]; these_entries = NULL; these_entries2 = NULL; prev_entries = NULL; prev_entries2 = NULL; /* Start with this entry. */ format_add_sdn_list(&these_entries, &these_entries2, slapi_entry_get_dn(cbdata->e)); /* Walk the chain backwards. */ for (j = ref_attr->n_links - 1; (j >= 0) && (these_entries != NULL); j--) { /* We can populate the "previous links" set using the * information in the previous link in the chain. */ if (j > 0) { prev_attr_link = &ref_attr->links[j - 1]; prev_attrs[0] = prev_attr_link->attribute; prev_attrs[1] = NULL; prev_filter = prev_attr_link->filter_str; prev_bases = prev_attr_link->base_sdn_list; } else { prev_attr_link = NULL; prev_attrs[0] = NULL; prev_attrs[1] = NULL; prev_filter = NULL; prev_bases = NULL; } /* We may have entries at this point in the chain * which point to other entries at this point in the * chain -- unless it's the last one, which we know * doesn't contain a DN. */ if (j < ref_attr->n_links - 1) { this_attr_link = &ref_attr->links[j]; these_attrs[0] = this_attr_link->attribute; these_attrs[1] = NULL; these_filter = this_attr_link->filter_str; these_bases = this_attr_link->base_sdn_list; } else { this_attr_link = NULL; these_attrs[0] = NULL; these_attrs[1] = NULL; these_filter = NULL; these_bases = NULL; } /* Search for entries which would be predecessors in * the path to this entry. */ for (k = 0; these_entries[k] != NULL; k++) { scope = LDAP_SCOPE_ONELEVEL; slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "searching for references to " "\"%s\" (link=%d, " "attributes=\"%s\",\"%s\")\n", slapi_sdn_get_ndn(these_entries[k]), j, these_attrs[0] ? these_attrs[0] : "", prev_attrs[0] ? prev_attrs[0] : ""); /* Search for entries at this point in the * chain which point to this entry in the * chain (which we started with the entry * which has just been modified). */ filter = backend_build_filter(state, these_entries[k], these_filter, these_attrs); for (l = 0; (these_bases != NULL) && (these_bases[l] != NULL); l++) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "searching under " "\"%s\" for \"%s\" " "with scope %d\n", slapi_sdn_get_ndn(these_bases[l]), filter, scope); pb = wrap_pblock_new(cbdata->pb); slapi_search_internal_set_pb(pb, slapi_sdn_get_ndn(these_bases[l]), scope, filter, NULL, FALSE, NULL, NULL, state->plugin_identity, 0); note_cbdata.state = state; note_cbdata.sdn_list = &these_entries; note_cbdata.sdn_list2 = &these_entries2; slapi_search_internal_callback_pb(pb, ¬e_cbdata, NULL, backend_shr_note_entry_sdn_cb, NULL); slapi_pblock_destroy(pb); } free(filter); /* Search for entries in the previous link in * the chain which point to this entry in the * chain (which we started with the entry * which has just been modified). */ filter = backend_build_filter(state, these_entries[k], prev_filter, prev_attrs); for (l = 0; (prev_bases != NULL) && (prev_bases[l] != NULL); l++) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "searching from \"%s\"" " for \"%s\" with " "scope %d\n", slapi_sdn_get_ndn(prev_bases[l]), filter, scope); pb = wrap_pblock_new(cbdata->pb); slapi_search_internal_set_pb(pb, slapi_sdn_get_ndn(prev_bases[l]), scope, filter, NULL, FALSE, NULL, NULL, state->plugin_identity, 0); note_cbdata.state = state; note_cbdata.sdn_list = &prev_entries; note_cbdata.sdn_list2 = &prev_entries2; slapi_search_internal_callback_pb(pb, ¬e_cbdata, NULL, backend_shr_note_entry_sdn_cb, NULL); slapi_pblock_destroy(pb); } free(filter); } /* Back up to process the list of predecessors, unless * this was the last link, in which case it's become * our list of candidates. */ if (j > 0) { format_free_sdn_list(these_entries, these_entries2); these_entries = prev_entries; these_entries2 = prev_entries2; prev_entries = NULL; prev_entries2 = NULL; } /* Log a diagnostic if there's no more work to do. */ if (these_entries == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "no more references to " "chase (link=%d, " "attributes=\"%s\",\"%s\")\n", j, these_attrs[0] ? these_attrs[0] : "", prev_attrs[0] ? prev_attrs[0] : ""); } } /* Walk the last list of predecessors and update any related * entries in this map. */ for (j = 0; (these_entries != NULL) && (these_entries[j] != NULL); j++) { ndn = slapi_sdn_get_ndn(these_entries[j]); slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "possible dependent entry: \"%s\"\n", ndn); if (!map_data_check_entry(state, group, set, ndn)) { continue; } slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "dependent entry: \"%s\"\n", ndn); backend_shr_set_config_entry_set_one_dn(state, cbdata->pb, ndn, set_data->self); } format_free_sdn_list(these_entries, these_entries2); } /* Determine if there are any entries in this map which are referred to * (directly or indirectly) by this entry. If there are, update them. */ /* Walk the set of reference-attribute chains. */ inref_attr_list = set_data->inref_attr_list; for (i = 0; (inref_attr_list != NULL) && (inref_attr_list[i] != NULL); i++) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "updating referred_r[%d] references for " "\"%s\"\n", i, slapi_entry_get_ndn(cbdata->e)); inref_attr = inref_attr_list[i]; these_entries = NULL; these_entries2 = NULL; next_entries = NULL; next_entries2 = NULL; /* Start with this entry. */ format_add_sdn_list(&these_entries, &these_entries2, slapi_entry_get_dn(cbdata->e)); /* Walk the chain, backwards. */ for (j = inref_attr->n_links - 2; (j >= 0) && (these_entries != NULL); j--) { /* For each link in the chain (except the last, which * we skip because it's not an attribute which is used * to link to other entries), build the set of entries * which are referred to by the entry. */ this_attr_link = &inref_attr->links[j]; these_attrs[0] = this_attr_link->attribute; these_attrs[1] = NULL; if (j > 0) { next_attr_link = &inref_attr->links[j - 1]; next_attrs[0] = next_attr_link->attribute; next_attrs[1] = NULL; next_filter = next_attr_link->filter; next_filter_str = next_attr_link->filter_str; } else { next_attr_link = NULL; next_attrs[0] = NULL; next_attrs[1] = NULL; next_filter = NULL; next_filter_str = NULL; } /* Read the entries at this stage. */ for (k = 0; (these_entries != NULL) && (these_entries[k] != NULL); k++) { /* Read the linked-to DN from the named * attribute in the entry. */ values = NULL; wrap_search_internal_get_entry(cbdata->pb, these_entries[k], NULL, these_attrs, &this_entry, state->plugin_identity); if (this_entry == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "failure reading entry " "\"%s\"\n", slapi_sdn_get_ndn(these_entries[k])); continue; } pb = wrap_pblock_new(cbdata->pb); if ((next_filter != NULL) && (slapi_filter_test(pb, this_entry, next_filter, 0) != 0)) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "entry \"%s\" did not " "match filter \"%s\"\n", slapi_sdn_get_ndn(these_entries[k]), next_filter_str); slapi_entry_free(this_entry); slapi_pblock_destroy(pb); continue; } slapi_pblock_destroy(pb); if (slapi_vattr_values_get(this_entry, these_attrs[0], &values, &disposition, &actual_attr, 0, &buffer_flags) != 0) { slapi_entry_free(this_entry); continue; } /* For each value of this attribute... */ for (l = slapi_valueset_first_value(values, &value); l != -1; l = slapi_valueset_next_value(values, l, &value)) { /* Pull out the value, which is a * referred-to entry's DN. */ dn = slapi_value_get_string(value); if (dn == NULL) { continue; } /* Add it to the list of entries which * we'll examine this go-round. */ format_add_sdn_list(&these_entries, &these_entries2, dn); } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); slapi_entry_free(this_entry); } /* Read the entries for the next stage. */ for (k = 0; (next_attrs[0] != NULL) && (these_entries != NULL) && (these_entries[k] != NULL); k++) { /* Read the linked-to DN from the named * attribute in the entry. */ values = NULL; wrap_search_internal_get_entry(cbdata->pb, these_entries[k], NULL, next_attrs, &this_entry, state->plugin_identity); if (this_entry == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "failure reading entry " "\"%s\"\n", slapi_sdn_get_ndn(these_entries[k])); continue; } if (slapi_vattr_values_get(this_entry, next_attrs[0], &values, &disposition, &actual_attr, 0, &buffer_flags) != 0) { slapi_entry_free(this_entry); continue; } /* For each value of this attribute... */ for (l = slapi_valueset_first_value(values, &value); l != -1; l = slapi_valueset_next_value(values, l, &value)) { /* Pull out the value, which is a * referred-to entry's DN. */ dn = slapi_value_get_string(value); if (dn == NULL) { continue; } /* Add it to the list of entries which * we'll examine next time. */ format_add_sdn_list(&next_entries, &next_entries2, dn); } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); slapi_entry_free(this_entry); } /* Back up to process the list of predecessors, unless * this was the last link, in which case it's become * our list of candidates. */ if (j > 0) { format_free_sdn_list(these_entries, these_entries2); these_entries = next_entries; these_entries2 = next_entries2; next_entries = NULL; next_entries2 = NULL; } /* Log a diagnostic if there's no more work to do. */ if (these_entries == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "no more referrals to chase " "(attributes=\"%s\",\"%s\")\n", these_attrs[0] ? these_attrs[0] : "", prev_attrs[0] ? prev_attrs[0] : ""); } } /* Walk the last list of entries and update any related * entries in this map. */ for (j = 0; (these_entries != NULL) && (these_entries[j] != NULL); j++) { ndn = slapi_sdn_get_ndn(these_entries[j]); slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "possible dependent entry: \"%s\"\n", ndn); if (!map_data_check_entry(state, group, set, ndn)) { continue; } slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "dependent entry: \"%s\"\n", ndn); backend_shr_set_config_entry_set_one_dn(state, cbdata->pb, ndn, set_data->self); } format_free_sdn_list(these_entries, these_entries2); } return TRUE; } static void backend_shr_update_references(struct plugin_state *state, Slapi_PBlock *pb, Slapi_Entry *e, LDAPMod **mods, char *modlist) { struct backend_shr_update_references_cbdata cbdata; cbdata.pb = pb; cbdata.e = e; cbdata.mods = mods; cbdata.modlist = modlist ? modlist : backend_shr_mods_as_string(mods); if (!map_data_foreach_map(state, NULL, backend_shr_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)); } if (modlist != cbdata.modlist) { free(cbdata.modlist); } } /* 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_shr_add_entry_cb(const char *group, const char *set, bool_t secure, void *backend_data, void *cbdata_ptr) { struct backend_shr_set_data *set_data; struct backend_add_entry_cbdata *cbdata; set_data = backend_data; cbdata = cbdata_ptr; /* If the entry doesn't match the set, skip it. */ if (!backend_shr_entry_matches_set(set_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, group, set); 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_set_entry(cbdata->pb, cbdata->e, set_data->self); return TRUE; } static int backend_shr_add_cb(Slapi_PBlock *pb) { struct backend_add_entry_cbdata cbdata; struct backend_set_config_entry_add_cbdata set_cbdata; char *dn; int rc; /* If we somehow recursed here from ourselves, just bail. */ if (wrap_get_call_level() > 0) { return 0; } /* Read parameters from the pblock. */ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state); if (cbdata.state->plugin_base == NULL) { /* The plugin was not actually started. */ return 0; } slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &cbdata.e); slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn); slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc); if (rc != 0) { /* The requested add operation failed, but after the ACL * check?. */ return 0; } cbdata.pb = pb; slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "added \"%s\"\n", dn); /* 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; } } cbdata.ndn = slapi_entry_get_ndn(cbdata.e); /* Add map entries which corresponded to this directory server * entry. */ wrap_inc_call_level(); if (map_wrlock() != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "error adding set entries corresponding to " "\"%s\": failed to acquire a lock\n", cbdata.ndn); goto done_with_lock; } if (!map_data_foreach_map(cbdata.state, NULL, backend_shr_add_entry_cb, &cbdata)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "error adding set entries corresponding to " "\"%s\"\n", cbdata.ndn); } /* If it's a map configuration entry, add and populate the maps it * describes. */ if (backend_shr_entry_is_a_set(cbdata.state, pb, cbdata.e)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "new entry \"%s\" is a set\n", cbdata.ndn); set_cbdata.state = cbdata.state; set_cbdata.pb = pb; backend_set_config_entry_add_cb(cbdata.e, &set_cbdata); } /* Update entries in maps which are affected by this entry. */ backend_shr_update_references(cbdata.state, pb, cbdata.e, NULL, NULL); map_unlock(); done_with_lock: wrap_dec_call_level(); return 0; } static int backend_shr_betxn_post_add_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? backend_shr_add_cb(pb) : 0; } static int backend_shr_post_add_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? 0 : backend_shr_add_cb(pb); } static int backend_shr_internal_post_add_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? 0 : backend_shr_add_cb(pb); } struct backend_shr_modify_entry_cbdata { struct plugin_state *state; Slapi_PBlock *pb; LDAPMod **mods; Slapi_Mods *real_mods; Slapi_Entry *e_pre, *e_post; char *ndn; char *modlist; }; static bool_t backend_shr_modify_entry_cb(const char *group, const char *set, bool_t flag, void *backend_data, void *cbdata_ptr) { struct backend_shr_set_data *set_data; struct backend_shr_modify_entry_cbdata *cbdata; int i, j; LDAPMod *mod; set_data = backend_data; cbdata = cbdata_ptr; /* If the entry didn't change any attributes which are at all relevant * to the map, and it both was and is still is in the map, then we * don't need to recompute anything. */ if (!backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e_post) && !backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e_pre)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id, "\"%s\" not in \"%s\"/\"%s\", " "before or after modify\n", cbdata->ndn, set_data->group, set_data->set); return TRUE; } if (set_data->skip_uninteresting_updates && (cbdata->mods != NULL) && (set_data->rel_attrs != NULL)) { for (i = 0; (mod = cbdata->mods[i]) != NULL; i++) { for (j = 0; set_data->rel_attrs[j] != NULL; j++) { if (slapi_attr_types_equivalent(mod->mod_type, set_data->rel_attrs[j])) { break; } } if (set_data->rel_attrs[j] != NULL) { break; } } if (mod == NULL) { if (backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e_pre) == backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e_post)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id, "no interesting changes for " "\"%s\"/\"%s\" made in (\"%s\") " "(%s not in %s)\n", set_data->group, set_data->set, cbdata->ndn, cbdata->modlist ? cbdata->modlist : "", backend_shr_get_rel_attr_list(set_data)); return TRUE; } } else { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id, "interesting changes for " "\"%s\"/\"%s\" made in (\"%s\") " "(%s in %s)\n", set_data->group, set_data->set, cbdata->ndn, cbdata->modlist ? cbdata->modlist : "", backend_shr_get_rel_attr_list(set_data)); } } else { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id, "changes for " "\"%s\"/\"%s\" made in (\"%s\") " "(%s in %s or empty)\n", set_data->group, set_data->set, cbdata->ndn, cbdata->modlist ? cbdata->modlist : "", backend_shr_get_rel_attr_list(set_data)); } /* If the entry used to match the map, remove it. */ if (backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e_pre)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id, "clearing group/set/id " "\"%s\"/\"%s\"/(\"%s\")\n", set_data->group, set_data->set, cbdata->ndn); map_data_unset_entry(cbdata->state, set_data->group, set_data->set, cbdata->ndn); } /* If the entry now matches the map, add it (or re-add it). */ if (backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e_post)) { /* Set the entry in the set which corresponds to this entry, or * remove any that might if this entry doesn't produce a useful * value. */ backend_shr_set_entry(cbdata->pb, cbdata->e_post, set_data->self); } return TRUE; } /* Walk the list of mods, picking out those which won't have an effect, and * adding the rest to the "relevant" list. */ static void backend_shr_filter_mods(LDAPMod **mods, Slapi_Entry *pre, Slapi_Entry *post, Slapi_Mods *relevant) { LDAPMod *mod; Slapi_Mod *smod; Slapi_ValueSet *values; Slapi_Value *mval; const struct berval *mbv; struct berval msv; char *actual_attr; int i, j, result, disposition, buffer_flags; if (mods == NULL) { return; } mval = slapi_value_new(); smod = slapi_mod_new(); for (i = 0; mods[i] != NULL; i++) { mod = mods[i]; if (slapi_vattr_values_get(pre, mod->mod_type, &values, &disposition, &actual_attr, 0, &buffer_flags) != 0) { /* error of some kind, punt */ slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); continue; } if (SLAPI_IS_MOD_DELETE(mod->mod_op)) { /* if the target entry has values, and one of the ones * we're removing is in the entry, keep it */ if (slapi_valueset_count(values) != 0) { if (mod->mod_op & LDAP_MOD_BVALUES) { if (mod->mod_vals.modv_bvals == NULL) { /* request is to remove all values */ slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); } else for (j = 0; mod->mod_vals.modv_bvals[j] != NULL; j++) { mbv = mod->mod_vals.modv_bvals[j]; mval = slapi_value_set_berval(mval, mbv); if ((slapi_vattr_value_compare(pre, mod->mod_type, mval, &result, 0) == 0) && (result == 1)) { /* request is to remove a value that is present */ slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); break; } } } else { if (mod->mod_vals.modv_strvals == NULL) { /* request is to remove all values */ slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); } else for (j = 0; mod->mod_vals.modv_strvals[j] != NULL; j++) { msv.bv_val = mod->mod_vals.modv_strvals[j]; msv.bv_len = strlen(msv.bv_val); mval = slapi_value_set_berval(mval, &msv); if ((slapi_vattr_value_compare(pre, mod->mod_type, mval, &result, 0) == 0) && (result == 1)) { /* request is to remove a value that is present */ slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); break; } } } } } else if (SLAPI_IS_MOD_ADD(mod->mod_op)) { /* if all of the provided values are already in the * entry, then skip it */ if (mod->mod_op & LDAP_MOD_BVALUES) { if (mod->mod_vals.modv_bvals != NULL) { for (j = 0; mod->mod_vals.modv_bvals[j] != NULL; j++) { mbv = mod->mod_vals.modv_bvals[j]; mval = slapi_value_set_berval(mval, mbv); if ((slapi_vattr_value_compare(pre, mod->mod_type, mval, &result, 0) != 0) || (result != 1)) { /* request is to add a value that is not present */ slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); break; } } } } else { if (mod->mod_vals.modv_strvals != NULL) { for (j = 0; mod->mod_vals.modv_strvals[j] != NULL; j++) { msv.bv_val = mod->mod_vals.modv_strvals[j]; msv.bv_len = strlen(msv.bv_val); mval = slapi_value_set_berval(mval, &msv); if ((slapi_vattr_value_compare(pre, mod->mod_type, mval, &result, 0) != 0) || (result != 1)) { /* request is to add a value that is not present */ slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); break; } } } } } else if (SLAPI_IS_MOD_REPLACE(mod->mod_op)) { /* if the value set is the same as the list we're * given, then skip it */ j = 0; if (mod->mod_op & LDAP_MOD_BVALUES) { if (mod->mod_vals.modv_bvals != NULL) { for (j = 0; mod->mod_vals.modv_bvals[j] != NULL; j++) { continue; } } if (slapi_valueset_count(values) != j) { /* different number of values */ slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); } else { for (j = 0; (mod->mod_vals.modv_bvals != NULL) && (mod->mod_vals.modv_bvals[j] != NULL); j++) { mbv = mod->mod_vals.modv_bvals[j]; mval = slapi_value_set_berval(mval, mbv); if ((slapi_vattr_value_compare(pre, mod->mod_type, mval, &result, 0) != 0) || (result != 1)) { /* request includes a value that is not present */ slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); break; } } } } else { if (mod->mod_vals.modv_strvals != NULL) { for (j = 0; mod->mod_vals.modv_strvals[j] != NULL; j++) { continue; } } if (slapi_valueset_count(values) != j) { /* different number of values */ slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); } else { for (j = 0; (mod->mod_vals.modv_strvals != NULL) && (mod->mod_vals.modv_strvals[j] != NULL); j++) { msv.bv_val = mod->mod_vals.modv_strvals[j]; msv.bv_len = strlen(msv.bv_val); mval = slapi_value_set_berval(mval, &msv); if ((slapi_vattr_value_compare(pre, mod->mod_type, mval, &result, 0) != 0) || (result != 1)) { /* request includes a value that is not present */ slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); break; } } } } } else { slapi_mod_init_byval(smod, mod); slapi_mods_add_ldapmod(relevant, slapi_mod_get_ldapmod_passout(smod)); } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } slapi_mod_free(&smod); slapi_value_free(&mval); } static int backend_shr_modify_cb(Slapi_PBlock *pb) { Slapi_DN *sdn; char *dn, *log_modlist; struct backend_shr_modify_entry_cbdata cbdata; struct backend_set_config_entry_add_cbdata set_cbdata; int rc; /* If we somehow recursed here from ourselves, just bail. */ if (wrap_get_call_level() > 0) { return 0; } /* Read parameters from the pblock. */ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state); if (cbdata.state->plugin_base == NULL) { /* The plugin was not actually started. */ return 0; } slapi_pblock_get(pb, SLAPI_MODIFY_TARGET, &dn); 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); slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc); if (rc != 0) { /* The requested add operation failed, but after the ACL * check?. */ return 0; } cbdata.pb = pb; cbdata.modlist = NULL; slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "modified \"%s\"\n", dn); /* 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; } /* Don't do a lot of work for other plugins which initiated a no-op * modify. */ cbdata.real_mods = slapi_mods_new(); backend_shr_filter_mods(cbdata.mods, cbdata.e_pre, cbdata.e_post, cbdata.real_mods); cbdata.mods = slapi_mods_get_ldapmods_byref(cbdata.real_mods); cbdata.ndn = slapi_entry_get_ndn(cbdata.e_pre); if (cbdata.mods == NULL) { slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &cbdata.mods); log_modlist = backend_shr_mods_as_string(cbdata.mods); slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "no substantive changes to %s: " "(%s) simplified to ()\n", cbdata.ndn, log_modlist); slapi_mods_free(&cbdata.real_mods); free(log_modlist); return 0; } cbdata.modlist = backend_shr_mods_as_string(cbdata.mods); /* Modify map entries which corresponded to this directory server * entry. */ wrap_inc_call_level(); if (map_wrlock() != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "error modifying set entries corresponding to " "\"%s\": failed to acquire a lock\n", cbdata.ndn); goto done_with_lock; } if (!map_data_foreach_map(cbdata.state, NULL, backend_shr_modify_entry_cb, &cbdata)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "error modifying set entries corresponding to " "\"%s\"\n", cbdata.ndn); } /* Update entries which need to be updated in case they are no longer * affected by this entry. */ backend_shr_update_references(cbdata.state, pb, cbdata.e_pre, cbdata.mods, cbdata.modlist); /* Update entries which need to be updated in case they are now * affected by this entry. */ backend_shr_update_references(cbdata.state, pb, cbdata.e_post, cbdata.mods, cbdata.modlist); /* Done with the "real" mods. Put the fake ones back. */ slapi_mods_free(&cbdata.real_mods); cbdata.real_mods = NULL; slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &cbdata.mods); /* If it's a map configuration entry, reconfigure, clear, and * repopulate the map. */ if (backend_shr_entry_is_a_set(cbdata.state, pb, cbdata.e_pre)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "modified entry \"%s\" was a set\n", cbdata.ndn); backend_set_config_entry_delete_cb(cbdata.e_pre, cbdata.state); } if (backend_shr_entry_is_a_set(cbdata.state, pb, cbdata.e_post)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "modified entry \"%s\" is now a set\n", cbdata.ndn); set_cbdata.state = cbdata.state; set_cbdata.pb = pb; backend_set_config_entry_add_cb(cbdata.e_post, &set_cbdata); } /* 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_update_params(pb, cbdata.state); } slapi_sdn_free(&sdn); } map_unlock(); done_with_lock: wrap_dec_call_level(); free(cbdata.modlist); return 0; } static int backend_shr_betxn_post_modify_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? backend_shr_modify_cb(pb) : 0; } static int backend_shr_post_modify_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? 0 : backend_shr_modify_cb(pb); } static int backend_shr_internal_post_modify_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? 0 : backend_shr_modify_cb(pb); } struct backend_shr_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_shr_modrdn_entry_cb(const char *group, const char *set, bool_t secure, void *backend_data, void *cbdata_ptr) { struct backend_shr_set_data *set_data; struct backend_shr_modrdn_entry_cbdata *cbdata; bool_t matched_pre, matched_post; set_data = backend_data; cbdata = cbdata_ptr; /* Now decide what to set, or unset, in this map. */ matched_pre = backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e_pre); 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/set/id " "\"%s\"/\"%s\"/(\"%s\")\n", set_data->group, set_data->set, cbdata->ndn_pre); map_data_unset_entry(cbdata->state, set_data->group, set_data->set, 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. */ matched_post = backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e_post); if (matched_post) { backend_set_entry(cbdata->pb, cbdata->e_post, set_data->self); } return TRUE; } static int backend_shr_modrdn_cb(Slapi_PBlock *pb) { struct backend_shr_modrdn_entry_cbdata cbdata; struct backend_set_config_entry_add_cbdata set_cbdata; /* If we somehow recursed here from ourselves, just bail. */ if (wrap_get_call_level() > 0) { return 0; } /* Read parameters from the pblock. */ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state); if (cbdata.state->plugin_base == NULL) { /* The plugin was not actually started. */ return 0; } slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &cbdata.e_pre); slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &cbdata.e_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; } /* Finish retrieving in the data we'll need. */ 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); /* Modify map entries which corresponded to this directory server * entry. */ wrap_inc_call_level(); if (map_wrlock() != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "error renaming map entries corresponding to " "\"%s\": failed to acquire a lock\n", cbdata.ndn_post); goto done_with_lock; } if (!map_data_foreach_map(cbdata.state, NULL, backend_shr_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 set configuration entry, reconfigure, clear, and * repopulate the set. */ if (backend_shr_entry_is_a_set(cbdata.state, pb, cbdata.e_pre)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "renamed entry \"%s\" was a set\n", slapi_entry_get_ndn(cbdata.e_pre)); backend_set_config_entry_delete_cb(cbdata.e_pre, cbdata.state); } if (backend_shr_entry_is_a_set(cbdata.state, pb, cbdata.e_post)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "renamed entry \"%s\" is now a set\n", slapi_entry_get_ndn(cbdata.e_post)); set_cbdata.state = cbdata.state; set_cbdata.pb = pb; backend_set_config_entry_add_cb(cbdata.e_post, &set_cbdata); } map_unlock(); done_with_lock: wrap_dec_call_level(); return 0; } static int backend_shr_betxn_post_modrdn_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? backend_shr_modrdn_cb(pb) : 0; } static int backend_shr_post_modrdn_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? 0 : backend_shr_modrdn_cb(pb); } static int backend_shr_internal_post_modrdn_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? 0 : backend_shr_modrdn_cb(pb); } /* Delete any map entries which correspond to a directory server entry in this * map. */ struct backend_shr_delete_entry_cbdata { struct plugin_state *state; Slapi_PBlock *pb; Slapi_Entry *e; char *ndn; }; static bool_t backend_shr_delete_entry_cb(const char *group, const char *set, bool_t flag, void *backend_data, void *cbdata_ptr) { struct backend_shr_set_data *set_data; struct backend_shr_delete_entry_cbdata *cbdata; set_data = backend_data; cbdata = cbdata_ptr; /* If it was in the map, remove it. */ if (backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e)) { /* Remove this entry from the set. */ slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id, "unsetting group/set/id" "\"%s\"/\"%s\"=\"%s\"/\"%s\"/(\"%s\")\n", group, set, set_data->group, set_data->set, cbdata->ndn); map_data_unset_entry(cbdata->state, group, set, cbdata->ndn); } return TRUE; } /* Called by the server when a directory server entry is deleted. */ static int backend_shr_delete_cb(Slapi_PBlock *pb) { struct backend_shr_delete_entry_cbdata cbdata; char *dn; int rc; /* If we somehow recursed here from ourselves, just bail. */ if (wrap_get_call_level() > 0) { return 0; } /* Read parameters from the pblock. */ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state); if (cbdata.state->plugin_base == NULL) { /* The plugin was not actually started. */ return 0; } slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &cbdata.e); slapi_pblock_get(pb, SLAPI_DELETE_TARGET, &dn); slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc); if (rc != 0) { /* The requested modify operation failed, but after the ACL * check?. */ return 0; } cbdata.pb = pb; slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "deleted \"%s\"\n", dn); /* 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; } cbdata.ndn = slapi_entry_get_ndn(cbdata.e); /* Remove map entries which corresponded to this directory server * entry. */ wrap_inc_call_level(); if (map_wrlock() != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "error removing entries corresponding to " "\"%s\": failed to acquire a lock\n", cbdata.ndn); goto done_with_lock; } if (!map_data_foreach_map(cbdata.state, NULL, backend_shr_delete_entry_cb, &cbdata)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "error removing entries corresponding to " "\"%s\"\n", cbdata.ndn); } /* If it's a map configuration entry, remove the map. */ if (backend_shr_entry_is_a_set(cbdata.state, pb, cbdata.e)) { slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id, "deleted entry \"%s\" is a set\n", cbdata.ndn); backend_set_config_entry_delete_cb(cbdata.e, cbdata.state); } /* Update entries which need to be updated in case they are no longer * affected by this entry. */ backend_shr_update_references(cbdata.state, pb, cbdata.e, NULL, NULL); map_unlock(); done_with_lock: wrap_dec_call_level(); return 0; } static int backend_shr_betxn_post_delete_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? backend_shr_delete_cb(pb) : 0; } static int backend_shr_post_delete_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? 0 : backend_shr_delete_cb(pb); } static int backend_shr_internal_post_delete_cb(Slapi_PBlock *pb) { struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); return state->use_be_txns ? 0 : backend_shr_delete_cb(pb); } /* Set up our post-op callbacks. */ #ifdef SLAPI_NIS_SUPPORT_BE_TXNS int backend_shr_betxn_postop_init(Slapi_PBlock *pb, struct plugin_state *state) { if (slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_ADD_FN, backend_shr_betxn_post_add_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up betxn post add callback\n"); return -1; } if (slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN, backend_shr_betxn_post_modify_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up betxn post modify " "callback\n"); return -1; } if (slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN, backend_shr_betxn_post_modrdn_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up betxn post modrdn " "callback\n"); return -1; } if (slapi_pblock_set(pb, SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN, backend_shr_betxn_post_delete_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up betxn post delete " "callback\n"); return -1; } return 0; } #endif int backend_shr_postop_init(Slapi_PBlock *pb, struct plugin_state *state) { if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN, backend_shr_post_add_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up post add callback\n"); return -1; } if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN, backend_shr_post_modify_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up post modify callback\n"); return -1; } if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, backend_shr_post_modrdn_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up post modrdn callback\n"); return -1; } if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, backend_shr_post_delete_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up post delete callback\n"); return -1; } return 0; } int backend_shr_internal_postop_init(Slapi_PBlock *pb, struct plugin_state *state) { if (slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, backend_shr_internal_post_add_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up internal post add " "callback\n"); return -1; } if (slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, backend_shr_internal_post_modify_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up internal post modify " "callback\n"); return -1; } if (slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, backend_shr_internal_post_modrdn_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up internal post modrdn " "callback\n"); return -1; } if (slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, backend_shr_internal_post_delete_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up internal post delete " "callback\n"); return -1; } return 0; }