/* * 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 "back-shr.h" #include "format.h" #include "plugin.h" #include "map.h" /* 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(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; } /* 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); } 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. */ void backend_shr_set_entry(Slapi_Entry *e, struct backend_set_data *set_data) { backend_set_entry(e, set_data); } int backend_shr_set_entry_cb(Slapi_Entry *e, void *set_data) { backend_shr_set_entry(e, set_data); return 0; } /* Set or unset the named entry using information in the callback data. */ void backend_shr_set_config_entry_set_one_dn(struct plugin_state *state, 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 { 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_shr_set_entry(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. */ 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; 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_ndn_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) { filter = slapi_str2filter((char *) check_filter); if (filter != NULL) { if (slapi_vattr_filter_test(pb, e, filter, 0) != 0) { ret = FALSE; } slapi_filter_free(filter, 1); } } 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_Entry *e, const char *group, const char *set) { Slapi_PBlock *pb; int i; bool_t flag; struct backend_shr_set_data *set_data; char **set_bases; char *set_entry_filter; pb = slapi_pblock_new(); flag = FALSE; backend_set_config_read_config(state, e, group, set, &flag, &set_data); set_bases = set_data->bases; set_entry_filter = set_data->entry_filter; 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); slapi_pblock_destroy(pb); return 0; } slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "initializing %s in %s, flag=%s (2)\n", set, group, flag ? "yes" : "no"); map_data_set_map(state, group, set, flag, set_data, &backend_shr_set_config_free_config); map_data_clear_map(state, group, set); /* Search under each base in turn, adding the matching directory * entries to the set. */ 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); slapi_search_internal_set_pb(pb, set_bases[i], LDAP_SCOPE_SUB, set_entry_filter, NULL, FALSE, NULL, NULL, state->plugin_identity, 0); slapi_search_internal_callback_pb(pb, set_data, NULL, backend_shr_set_entry_cb, NULL); slapi_free_search_results_internal(pb); } /* Clean up. */ slapi_pblock_destroy(pb); 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)) { 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; const char *cvalue; 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) { 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, "on") == 0) || (strcasecmp(tmp, "1") == 0)) { ret = TRUE; } else { ret = FALSE; } free(tmp); } return ret; } /* Scan for the list of configured groups and sets. */ void backend_shr_startup(struct plugin_state *state, const char *filter) { Slapi_PBlock *pb; backend_update_params(state); pb = slapi_pblock_new(); slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "searching under \"%s\" for configuration\n", state->plugin_base); slapi_search_internal_set_pb(pb, state->plugin_base, LDAP_SCOPE_ONE, filter, NULL, FALSE, NULL, NULL, state->plugin_identity, 0); map_wrlock(); slapi_search_internal_callback_pb(pb, state, NULL, backend_set_config_entry_add_cb, NULL); map_unlock(); slapi_free_search_results_internal(pb); 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; int i, j; 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++) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "removing set %s in %s\n", sets[j], groups[i]); map_data_unset_map(state, groups[i], sets[j]); } } 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. */ bool_t backend_shr_entry_matches_set(struct backend_shr_set_data *set_data, Slapi_PBlock *pb, Slapi_Entry *e) { char **set_bases; char *set_filter; int i; set_bases = set_data->bases; set_filter = set_data->entry_filter; if (set_bases != NULL) { for (i = 0; set_bases[i] != NULL; i++) { if (backend_shr_entry_matches(pb, e, set_bases[i], LDAP_SCOPE_SUB, set_filter)) { 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_ONE, backend_entry_get_set_config_entry_filter()); } /* 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_shr_update_references_cbdata { Slapi_PBlock *pb; Slapi_Entry *e; }; 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; Slapi_DN *referred_to_sdn; Slapi_ValueSet *values; Slapi_Value *value; char **ref_attrs, *actual_attr, *filter, *tndn, **set_bases; struct format_inref_attr **inref_attrs; const char *ndn, *dn; int i, j, disposition, buffer_flags, filter_size, n_ref_attrs; set_data = backend_data; cbdata = cbdata_ptr; state = set_data->state; /* 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) { filter_size = strlen("(&(|))") + strlen(set_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(|", set_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. */ set_bases = set_data->bases; for (i = 0; (set_bases != NULL) && (set_bases[i] != NULL); i++) { slapi_search_internal_set_pb(cbdata->pb, set_bases[i], LDAP_SCOPE_SUB, filter, NULL, FALSE, NULL, NULL, state->plugin_identity, 0); slapi_search_internal_callback_pb(cbdata->pb, set_data, NULL, backend_shr_set_entry_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 = set_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]->group, group) != 0) || (strcmp(inref_attrs[i]->set, set) != 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, group, set, ndn)) { /* ...update it. */ backend_shr_set_config_entry_set_one_dn(state, ndn, set_data->self); } } slapi_vattr_values_free(&values, &actual_attr, buffer_flags); } slapi_sdn_free(&referred_to_sdn); return TRUE; } void backend_shr_update_references(struct plugin_state *state, Slapi_Entry *e) { struct backend_shr_update_references_cbdata cbdata; cbdata.e = e; cbdata.pb = slapi_pblock_new(); 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)); } 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_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->e, set_data->self); return TRUE; } static int backend_shr_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_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); backend_set_config_entry_add_cb(cbdata.e, cbdata.state); } /* Update entries which need to be updated in case this new entry * refers to them. */ backend_shr_update_references(cbdata.state, cbdata.e); map_unlock(); return 0; } struct backend_shr_modify_entry_cbdata { struct plugin_state *state; Slapi_PBlock *pb; LDAPMod **mods; Slapi_Entry *e_pre, *e_post; char *ndn; }; 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; set_data = backend_data; cbdata = cbdata_ptr; /* 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->e_post, set_data->self); } return TRUE; } static int backend_shr_modify_cb(Slapi_PBlock *pb) { Slapi_DN *sdn; struct backend_shr_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_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 this entry * no longer refers to them. */ backend_shr_update_references(cbdata.state, cbdata.e_pre); /* Update entries which need to be updated in case this entry * now refers to them. */ backend_shr_update_references(cbdata.state, cbdata.e_post); /* 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); backend_set_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_update_params(cbdata.state); } slapi_sdn_free(&sdn); } map_unlock(); return 0; } 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->e_post, set_data->self); } return TRUE; } static int backend_shr_modrdn_cb(Slapi_PBlock *pb) { struct backend_shr_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_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", 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", cbdata.e_post); backend_set_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_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; 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_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 this entry no longer * refers to them. */ backend_shr_update_references(cbdata.state, cbdata.e); map_unlock(); return 0; } /* Set our post-op callbacks. */ void backend_shr_postop_init(Slapi_PBlock *pb, struct plugin_state *state) { if (slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN, backend_shr_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_shr_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_shr_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_shr_delete_cb) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "error hooking up delete callback\n"); } }