Blame SOURCES/slapi-0013-track-changes-to-ID-overrides-and-evict-map-cache-en.patch

9c73bd
From bcdcb8e762c6a8824ff1dd67f7e068ef519b3952 Mon Sep 17 00:00:00 2001
9c73bd
From: Alexander Bokovoy <abokovoy@redhat.com>
9c73bd
Date: Mon, 11 Sep 2017 15:33:24 +0300
9c73bd
Subject: [PATCH 13/17] track changes to ID overrides and evict map cache
9c73bd
 entries
9c73bd
9c73bd
Plug into a processing of LDAP add/delete/modify to see if an ID override entry
9c73bd
was added/deleted/updated. ID overrides aren't directly used to produce
9c73bd
map cache entries but when AD user or group is resolved, SSSD on IPA
9c73bd
master amends that information with ID Override from a Default Trust
9c73bd
View. Since nothing else would remove AD user or group entry from the map cache
9c73bd
on ID override change, handle their removal here.
9c73bd
9c73bd
Check if we have any nssswitch-generated entry in a map cache that
9c73bd
corresponds to this entry. Such entries would be evicted from the map
9c73bd
cache to allow their refresh.
9c73bd
9c73bd
Allow backends to inspect entries related to a map set
9c73bd
9c73bd
Entries may be related to a map set content but not used directly to
9c73bd
generate it. An example would be ID overrides in FreeIPA. An addition,
9c73bd
removal or change of an ID override in the Default Trust View should be
9c73bd
reflected by evicting an entry from the corresponding seti.
9c73bd
9c73bd
Let backends to handle exact logic. NIS backend does not support
9c73bd
exposing AD users so it provides set of dummy callbacks that always
9c73bd
return FALSE (entry is not related). Schema Compat backend, on other
9c73bd
hand, does track ID overrides in a Default Trust View in FreeIPA.
9c73bd
---
9c73bd
 src/back-sch.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9c73bd
 src/back-shr.c |  55 ++++++++++++++----
9c73bd
 src/backend.h  |  20 +++++++
9c73bd
 3 files changed, 239 insertions(+), 12 deletions(-)
9c73bd
9c73bd
diff --git a/src/back-sch.c b/src/back-sch.c
9c73bd
index e15988f..f98b0b4 100644
9c73bd
--- a/src/back-sch.c
9c73bd
+++ b/src/back-sch.c
9c73bd
@@ -33,6 +33,7 @@
9c73bd
 #ifdef HAVE_DIRSRV_SLAPI_PLUGIN_H
9c73bd
 #include <nspr.h>
9c73bd
 #include <plhash.h>
9c73bd
+#include <plstr.h>
9c73bd
 #include <nss.h>
9c73bd
 #include <dirsrv/slapi-plugin.h>
9c73bd
 #else
9c73bd
@@ -2099,6 +2100,181 @@ backend_write_cb(Slapi_PBlock *pb, struct plugin_state *state)
9c73bd
 	return ret;
9c73bd
 }
9c73bd
 
9c73bd
+#ifdef USE_IPA_IDVIEWS
9c73bd
+/* Check if ID override applies to an entry in our map cache
9c73bd
+ * and remove the entry in case it does. */
9c73bd
+
9c73bd
+static bool_t
9c73bd
+backend__get_original_uid_and_ndn(Slapi_Entry *e,
9c73bd
+				  char **original_uid,
9c73bd
+				  const char **original_anchor)
9c73bd
+{
9c73bd
+	char **elem = NULL;
9c73bd
+	char *v = NULL;
9c73bd
+	char *ndn = NULL;
9c73bd
+	char *view = NULL;
9c73bd
+	int n_elem = 0;
9c73bd
+	int i = 0;
9c73bd
+
9c73bd
+	if (e == NULL) {
9c73bd
+		return FALSE;
9c73bd
+	}
9c73bd
+
9c73bd
+	elem = slapi_entry_attr_get_charray_ext(e, "objectClass", &n_elem);
9c73bd
+	if (elem == NULL) {
9c73bd
+		/* weird, objectClass should be existing */
9c73bd
+		return FALSE;
9c73bd
+	}
9c73bd
+
9c73bd
+	for (i=0; i < n_elem; i++) {
9c73bd
+		if (strncasecmp(elem[i], "ipaOverrideAnchor", 17) == 0) {
9c73bd
+			break;
9c73bd
+		}
9c73bd
+	}
9c73bd
+
9c73bd
+	slapi_ch_array_free(elem);
9c73bd
+	if (i == n_elem) {
9c73bd
+		/* This is not an override, bail out */
9c73bd
+		return FALSE;
9c73bd
+	}
9c73bd
+
9c73bd
+	ndn = slapi_entry_get_ndn(e);
9c73bd
+	if (ndn == NULL) {
9c73bd
+		return FALSE;
9c73bd
+	}
9c73bd
+
9c73bd
+	view = PL_strcasestr(ndn, "cn=Default Trust View,");
9c73bd
+	if (view == NULL || view == ndn) {
9c73bd
+		return FALSE;
9c73bd
+	}
9c73bd
+
9c73bd
+	/* This is an ID override, we need to search for a referenced ipaOriginalUid or cn in our maps */
9c73bd
+	v = slapi_entry_attr_get_charptr(e, "ipaOriginalUid");
9c73bd
+	if (v == NULL) {
9c73bd
+		v = slapi_entry_attr_get_charptr(e, "cn");
9c73bd
+		if (v == NULL) {
9c73bd
+			return FALSE;
9c73bd
+		}
9c73bd
+	}
9c73bd
+
9c73bd
+	*original_uid = v;
9c73bd
+	*original_anchor = ndn;
9c73bd
+	return TRUE;
9c73bd
+}
9c73bd
+
9c73bd
+bool_t
9c73bd
+backend_entry_evict_if_related(const char *group, const char *set, bool_t flag,
9c73bd
+			       void *shared_set_data,
9c73bd
+			       Slapi_PBlock *pb,
9c73bd
+			       Slapi_Entry *e)
9c73bd
+{
9c73bd
+	struct backend_set_data *set_data;
9c73bd
+	struct plugin_state *state = NULL;
9c73bd
+	char *id = NULL;
9c73bd
+	char *original_uid = NULL;
9c73bd
+	const char *original_anchor = NULL;
9c73bd
+	const char *rdn_attribute[] = {NULL, "uid=%s,%s,%s", "cn=%s,%s,%s"};
9c73bd
+	bool_t result = FALSE;
9c73bd
+
9c73bd
+	set_data = shared_set_data;
9c73bd
+
9c73bd
+	/* We only interested in NSSWITCH-capable maps */
9c73bd
+	if (set_data->check_nsswitch == SCH_NSSWITCH_NONE) {
9c73bd
+		return FALSE;
9c73bd
+	}
9c73bd
+
9c73bd
+	/* See if the entry pre modification had original UID */
9c73bd
+	if (!backend__get_original_uid_and_ndn(e,
9c73bd
+					       &original_uid,
9c73bd
+					       &original_anchor)) {
9c73bd
+		return FALSE;
9c73bd
+	}
9c73bd
+
9c73bd
+	id = slapi_ch_smprintf(rdn_attribute[set_data->check_nsswitch],
9c73bd
+			       original_uid, set, group);
9c73bd
+
9c73bd
+	if (id == NULL) {
9c73bd
+		slapi_ch_free_string(&original_uid);
9c73bd
+		return FALSE;
9c73bd
+	}
9c73bd
+
9c73bd
+	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
9c73bd
+	result = map_data_check_entry(state, group, set, id);
9c73bd
+	if (result) {
9c73bd
+		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
9c73bd
+				"evicted entry %s due to changed content of ID override %s\n",
9c73bd
+				id, original_anchor);
9c73bd
+
9c73bd
+		/* An entry corresponding to our target is found, evict it */
9c73bd
+		map_data_unset_entry(state, group, set, id);
9c73bd
+	}
9c73bd
+
9c73bd
+	slapi_ch_free_string(&id;;
9c73bd
+	slapi_ch_free_string(&original_uid);
9c73bd
+	return result;
9c73bd
+}
9c73bd
+
9c73bd
+bool_t
9c73bd
+backend_entry_is_add_related(const char *group, const char *set, bool_t flag,
9c73bd
+			     void *shared_set_data,
9c73bd
+			     Slapi_PBlock *pb,
9c73bd
+			     Slapi_Entry *e)
9c73bd
+{
9c73bd
+	return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e);
9c73bd
+}
9c73bd
+
9c73bd
+
9c73bd
+bool_t
9c73bd
+backend_entry_is_modify_related(const char *group, const char *set, bool_t flag,
9c73bd
+				void *shared_set_data,
9c73bd
+				Slapi_PBlock *pb,
9c73bd
+				Slapi_Entry *e_pre,
9c73bd
+				Slapi_Entry *e_post)
9c73bd
+{
9c73bd
+	return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e_pre);
9c73bd
+}
9c73bd
+
9c73bd
+bool_t
9c73bd
+backend_entry_is_delete_related(const char *group, const char *set, bool_t flag,
9c73bd
+				void *shared_set_data,
9c73bd
+				Slapi_PBlock *pb,
9c73bd
+				Slapi_Entry *e)
9c73bd
+{
9c73bd
+	return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e);
9c73bd
+}
9c73bd
+
9c73bd
+#else
9c73bd
+
9c73bd
+bool_t
9c73bd
+backend_entry_is_add_related(const char *group, const char *set, bool_t flag,
9c73bd
+			     void *shared_set_data,
9c73bd
+			     Slapi_PBlock *pb,
9c73bd
+			     Slapi_Entry *e)
9c73bd
+{
9c73bd
+	return FALSE;
9c73bd
+}
9c73bd
+
9c73bd
+bool_t
9c73bd
+backend_entry_is_modify_related(const char *group, const char *set, bool_t flag,
9c73bd
+				void *shared_set_data,
9c73bd
+				Slapi_PBlock *pb,
9c73bd
+				Slapi_Entry *e_pre,
9c73bd
+				Slapi_Entry *e_post)
9c73bd
+{
9c73bd
+	return FALSE;
9c73bd
+}
9c73bd
+
9c73bd
+bool_t
9c73bd
+backend_entry_is_delete_related(const char *group, const char *set, bool_t flag,
9c73bd
+				void *shared_set_data,
9c73bd
+				Slapi_PBlock *pb,
9c73bd
+				Slapi_Entry *e)
9c73bd
+{
9c73bd
+	return FALSE;
9c73bd
+}
9c73bd
+
9c73bd
+#endif
9c73bd
+
9c73bd
 static int
9c73bd
 backend_pre_write_cb(Slapi_PBlock *pb)
9c73bd
 {
9c73bd
diff --git a/src/back-shr.c b/src/back-shr.c
9c73bd
index 7842e05..a7ea92f 100644
9c73bd
--- a/src/back-shr.c
9c73bd
+++ b/src/back-shr.c
9c73bd
@@ -1856,11 +1856,21 @@ backend_shr_add_entry_cb(const char *group, const char *set, bool_t secure,
9c73bd
 
9c73bd
 	/* If the entry doesn't match the set, skip it. */
9c73bd
 	if (!backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e)) {
9c73bd
-		slapi_log_error(SLAPI_LOG_PLUGIN,
9c73bd
-				cbdata->state->plugin_desc->spd_id,
9c73bd
-				"entry \"%s\" does not belong in "
9c73bd
-				"\"%s\"/\"%s\"\n",
9c73bd
-				cbdata->ndn, group, set);
9c73bd
+		/* Give backend a chance to perform other operations on the add op.
9c73bd
+		 * For example, ID override addition in FreeIPA need to be noted to
9c73bd
+		 * evict AD user/group entries from a map cache while ID overrides
9c73bd
+		 * themselves aren't present in any map.
9c73bd
+		 * Note that we could do this as a part of backend_shr_entry_matches_set()
9c73bd
+		 * but it is better to isolate this operation in a separate call. */
9c73bd
+		if (!backend_entry_is_add_related(group, set, secure,
9c73bd
+						  set_data, cbdata->pb,
9c73bd
+						  cbdata->e)) {
9c73bd
+			slapi_log_error(SLAPI_LOG_PLUGIN,
9c73bd
+					cbdata->state->plugin_desc->spd_id,
9c73bd
+					"entry \"%s\" does not belong in "
9c73bd
+					"\"%s\"/\"%s\"\n",
9c73bd
+					cbdata->ndn, group, set);
9c73bd
+		}
9c73bd
 		return TRUE;
9c73bd
 	}
9c73bd
 
9c73bd
@@ -2010,13 +2020,24 @@ backend_shr_modify_entry_cb(const char *group, const char *set, bool_t flag,
9c73bd
 					   cbdata->e_post) &&
9c73bd
 	    !backend_shr_entry_matches_set(set_data, cbdata->pb,
9c73bd
 					   cbdata->e_pre)) {
9c73bd
-		slapi_log_error(SLAPI_LOG_PLUGIN,
9c73bd
-				cbdata->state->plugin_desc->spd_id,
9c73bd
-				"\"%s\" not in \"%s\"/\"%s\", "
9c73bd
-				"before or after modify\n",
9c73bd
-				cbdata->ndn,
9c73bd
-				set_data->group,
9c73bd
-				set_data->set);
9c73bd
+		/* Give backend a chance to perform other operations on the modify op.
9c73bd
+		 * For example, ID override updates in FreeIPA need to be noted to
9c73bd
+		 * evict AD user/group entries from a map cache while ID overrides
9c73bd
+		 * themselves aren't present in any map.
9c73bd
+		 * Note that we could do this as a part of backend_shr_entry_matches_set()
9c73bd
+		 * but it is better to isolate this operation in a separate call. */
9c73bd
+		if (!backend_entry_is_modify_related(group, set, flag,
9c73bd
+						     set_data, cbdata->pb,
9c73bd
+						     cbdata->e_pre,
9c73bd
+						     cbdata->e_post)) {
9c73bd
+			slapi_log_error(SLAPI_LOG_PLUGIN,
9c73bd
+					cbdata->state->plugin_desc->spd_id,
9c73bd
+					"\"%s\" not in \"%s\"/\"%s\", "
9c73bd
+					"before or after modify\n",
9c73bd
+					cbdata->ndn,
9c73bd
+					set_data->group,
9c73bd
+					set_data->set);
9c73bd
+		}
9c73bd
 		return TRUE;
9c73bd
 	}
9c73bd
 	if (set_data->skip_uninteresting_updates &&
9c73bd
@@ -2631,6 +2652,16 @@ backend_shr_delete_entry_cb(const char *group, const char *set, bool_t flag,
9c73bd
 				group, set, set_data->group, set_data->set,
9c73bd
 				cbdata->ndn);
9c73bd
 		map_data_unset_entry(cbdata->state, group, set, cbdata->ndn);
9c73bd
+	} else {
9c73bd
+		/* Give backend a chance to perform other operations on the delete op.
9c73bd
+		 * For example, ID override removal in FreeIPA need to be noted to
9c73bd
+		 * evict AD user/group entries from a map cache while ID overrides
9c73bd
+		 * themselves aren't present in any map.
9c73bd
+		 * Note that we could do this as a part of backend_shr_entry_matches_set()
9c73bd
+		 * but it is better to isolate this operation in a separate call. */
9c73bd
+		(void) backend_entry_is_delete_related(group, set, flag,
9c73bd
+						       set_data, cbdata->pb,
9c73bd
+						       cbdata->e);
9c73bd
 	}
9c73bd
 	return TRUE;
9c73bd
 }
9c73bd
diff --git a/src/backend.h b/src/backend.h
9c73bd
index 4608d2d..f0a5bbb 100644
9c73bd
--- a/src/backend.h
9c73bd
+++ b/src/backend.h
9c73bd
@@ -115,4 +115,24 @@ void backend_update_params(Slapi_PBlock *pb, struct plugin_state *state);
9c73bd
 bool_t backend_shr_is_caller(struct plugin_state *state,
9c73bd
 			     struct slapi_pblock *pb);
9c73bd
 
9c73bd
+/* Check if an operation is performed on an entry that is related to
9c73bd
+ * any entry in the set. This allows to catch changes of the entries that
9c73bd
+ * aren't directly included in the map set but should affect the set. */
9c73bd
+bool_t
9c73bd
+backend_entry_is_modify_related(const char *group, const char *set, bool_t flag,
9c73bd
+				void *shared_set_data,
9c73bd
+				Slapi_PBlock *pb,
9c73bd
+				Slapi_Entry *e_pre,
9c73bd
+				Slapi_Entry *e_post);
9c73bd
+bool_t
9c73bd
+backend_entry_is_add_related(const char *group, const char *set, bool_t flag,
9c73bd
+			     void *shared_set_data,
9c73bd
+			     Slapi_PBlock *pb,
9c73bd
+			     Slapi_Entry *e);
9c73bd
+bool_t
9c73bd
+backend_entry_is_delete_related(const char *group, const char *set, bool_t flag,
9c73bd
+				void *shared_set_data,
9c73bd
+				Slapi_PBlock *pb,
9c73bd
+				Slapi_Entry *e);
9c73bd
+
9c73bd
 #endif
9c73bd
-- 
9c73bd
2.13.6
9c73bd