[Freeipa-devel] [PATCH, slapi-nis] ID view-related patches to slapi-nis

Alexander Bokovoy abokovoy at redhat.com
Tue Oct 28 21:11:36 UTC 2014


Hi,

two patches to slapi-nis are attached:

- make sure only DNs from the schema-compat trees are targeted for ID
  view replacement. This solves issue of https://bugzilla.redhat.com/show_bug.cgi?id=1157989
  found by Sumit.

- support ID overrides in the BIND callback. So far the only thing we
  need is overriding uid.

They need to be applied in this order, on top of 0.54 release version of
slapi-nis.

-- 
/ Alexander Bokovoy
-------------- next part --------------
From 4645af44d48c81d8332020eb390db877ab179b3b Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy at redhat.com>
Date: Tue, 28 Oct 2014 10:09:47 +0200
Subject: [PATCH 1/2] ID views: ignore searches for views outside the subtrees
 of schema-compat sets

schema-compat plugin may provide multiple disjoint subtrees which
can be used to request overridden entries by prefixing the subtree
suffix with a

  cn=<name of view>,cn=views,<subtree suffix>

As subtrees may be disjoint, we cannot rely on the common suffix. Thus,
any attempt to replace target DN and update filter terms must only be
done once we are sure the search will be done in the subtree.

This optimization prevents mistakenly changing the search filter when
FreeIPA and SSSD search for the ID overrides themselves, as the same
structure of the target DN is used for  cn=views,cn=accounts,$SUFFIX
subtree in FreeIPA. This subtree is never handled by slapi-nis and
should be ignored.

https://bugzilla.redhat.com/show_bug.cgi?id=1157989
---
 src/back-sch-idview.c | 11 +++++--
 src/back-sch.c        | 83 +++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 83 insertions(+), 11 deletions(-)

diff --git a/src/back-sch-idview.c b/src/back-sch-idview.c
index 5a2b450..a56a9e9 100644
--- a/src/back-sch-idview.c
+++ b/src/back-sch-idview.c
@@ -334,6 +334,10 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
 						slapi_ber_bvdone(bval);
 						slapi_ber_bvcpy(bval, slapi_value_get_berval(anchor_val));
 						config->override_found = TRUE;
+						slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id,
+								"Overriding the filter %s with %s=%*s from the override %s\n.",
+								filter_type, filter_type, bval->bv_len, bval->bv_val,
+								slapi_entry_get_dn_const(cbdata->overrides[i]));
 						break;
 					}
 				}
@@ -346,6 +350,11 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
 					slapi_ber_bvdone(bval);
 					slapi_ber_bvcpy(bval, slapi_value_get_berval(anchor_val));
 					config->override_found = TRUE;
+					slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id,
+							"Overriding the filter %s with %s=%*s from the override %s\n.",
+							filter_type, IPA_IDVIEWS_ATTR_ANCHORUUID,
+							bval->bv_len, bval->bv_val,
+							slapi_entry_get_dn_const(cbdata->overrides[i]));
 					break;
 				}
 
@@ -366,8 +375,6 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
  *
  * Note that in reality we don't use original value of the uid/cn attribue. Instead, we use ipaAnchorUUID
  * to refer to the original entry. */
-extern char *
-slapi_filter_to_string( const struct slapi_filter *f, char *buf, size_t bufsize );
 void
 idview_replace_filter(struct backend_search_cbdata *cbdata)
 {
diff --git a/src/back-sch.c b/src/back-sch.c
index 27d5101..902adb2 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1166,6 +1166,44 @@ backend_search_set_cb(const char *group, const char *set, bool_t flag,
 	return TRUE;
 }
 
+/* Routines to search if a target DN is within any of the sets we handle */
+static bool_t
+backend_search_find_set_dn_in_group_cb(const char *group, const char *set, bool_t flag,
+					 void *backend_data, void *cb_data)
+{
+	struct backend_search_cbdata *cbdata;
+	struct backend_set_data *set_data;
+
+	cbdata = cb_data;
+	set_data = backend_data;
+
+	if (slapi_sdn_scope_test(cbdata->target_dn,
+				 set_data->container_sdn,
+				 cbdata->scope) == 1) {
+		cbdata->answer = TRUE;
+	}
+
+	if (slapi_sdn_compare(set_data->container_sdn,
+			      cbdata->target_dn) == 0) {
+		cbdata->answer = TRUE;
+	}
+
+	return TRUE;
+
+}
+
+static bool_t
+backend_search_find_set_dn_cb(const char *group, void *cb_data)
+{
+	struct backend_search_cbdata *cbdata;
+
+	cbdata = cb_data;
+	map_data_foreach_map(cbdata->state, group,
+			     backend_search_find_set_dn_in_group_cb, cb_data);
+	return TRUE;
+}
+
+/* Routines to find out the set that has the same group as requested */
 static bool_t
 backend_search_find_set_data_in_group_cb(const char *group, const char *set, bool_t flag,
 					 void *backend_data, void *cb_data)
@@ -1340,9 +1378,6 @@ backend_search_cb(Slapi_PBlock *pb)
 			"searching from \"%s\" for \"%s\" with scope %d%s\n",
 			cbdata.target, cbdata.strfilter, cbdata.scope,
 			backend_sch_scope_as_string(cbdata.scope));
-#ifdef USE_IPA_IDVIEWS
-	idview_replace_target_dn(&cbdata.target, &cbdata.idview);
-#endif
 	cbdata.target_dn = slapi_sdn_new_dn_byval(cbdata.target);
 	/* Check if there's a backend handling this search. */
 	if (!slapi_be_exist(cbdata.target_dn)) {
@@ -1351,19 +1386,49 @@ backend_search_cb(Slapi_PBlock *pb)
 				"slapi_be_exists(\"%s\") = 0, "
 				"ignoring search\n", cbdata.target);
 		slapi_sdn_free(&cbdata.target_dn);
+		return 0;
+	}
+
+#ifdef USE_IPA_IDVIEWS
+	/* We may have multiple disjoint trees in the sets, search if the target matches any of them
+	 * as in general there don't have to be a single subtree (cn=compat,$SUFFIX) for all trees to easily
+	 * detect the ID view use. Unless the ID view is within the set we control, don't consider the override */
+	map_data_foreach_domain(cbdata.state, backend_search_find_set_dn_cb, &cbdata);
+	if (cbdata.answer == FALSE) {
+		idview_replace_target_dn(&cbdata.target, &cbdata.idview);
 		if (cbdata.idview != NULL) {
-			slapi_ch_free_string(&cbdata.target);
+			slapi_sdn_free(&cbdata.target_dn);
+			/* Perform another check, now for rewritten DN */
+			cbdata.target_dn = slapi_sdn_new_dn_byval(cbdata.target);
+			map_data_foreach_domain(cbdata.state, backend_search_find_set_dn_cb, &cbdata);
+			/* Rewritten DN might still be outside of our trees */
+			if (cbdata.answer == TRUE) {
+				slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id,
+						"Use of ID view '%s' is detected, searching from \"%s\" "
+						"for \"%s\" with scope %d%s. Filter may get overridden later.\n",
+						cbdata.idview, cbdata.target, cbdata.strfilter, cbdata.scope,
+						backend_sch_scope_as_string(cbdata.scope));
+				cbdata.answer = FALSE;
+			} else {
+				slapi_sdn_free(&cbdata.target_dn);
+				slapi_ch_free_string(&cbdata.target);
+				slapi_ch_free_string(&cbdata.idview);
+				slapi_log_error(SLAPI_LOG_PLUGIN,
+						cbdata.state->plugin_desc->spd_id,
+						"The search base didn't match any of the containers, "
+						"ignoring search\n");
+				return 0;
+			}
 		}
-		slapi_ch_free_string(&cbdata.idview);
-#ifdef USE_IPA_IDVIEWS
-		idview_free_overrides(&cbdata);
-#endif
-		return 0;
+	} else {
+		cbdata.answer = FALSE;
 	}
+#endif
 
 	/* Walk the list of groups. */
 	wrap_inc_call_level();
 #ifdef USE_IPA_IDVIEWS
+	/* Filter replacement requires increased call level as we may fetch overrides and thus come back here */
 	idview_replace_filter(&cbdata);
 #endif
 	if (map_rdlock() == 0) {
-- 
2.1.0

-------------- next part --------------
From ec01afd2bd2543dbd2a79a3f78b4c6b6aa085c6c Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy at redhat.com>
Date: Tue, 28 Oct 2014 11:16:50 +0200
Subject: [PATCH 2/2] schema-compat: support ID overrides in bind callback

If RDN of the bind DN is overridden within the ID view, rewrite the
target to use original value of the uid attribute.

If original uid attribute is not available, fail the search and thus
the whole bind request by claiming that bind DN does not exist.
---
 src/back-sch-idview.c | 86 ++++++++++++++++++++++++++++++++++-----------------
 src/back-sch.c        | 52 ++++++++++++++++++++++++++-----
 src/back-sch.h        |  4 +++
 3 files changed, 107 insertions(+), 35 deletions(-)

diff --git a/src/back-sch-idview.c b/src/back-sch-idview.c
index a56a9e9..f1150cd 100644
--- a/src/back-sch-idview.c
+++ b/src/back-sch-idview.c
@@ -290,21 +290,15 @@ idview_replace_target_dn(char **target, char **idview)
 	}
 }
 
-static int
-idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct berval *bval, struct backend_search_filter_config *config)
+int
+idview_replace_bval_by_override(const char *bval_usage, const char *attr_name,
+				struct berval *bval, struct backend_search_cbdata *cbdata)
 {
 	int res, i;
-	Slapi_Value *filter_val, *value, *anchor_val;
+	Slapi_Value *attr_val, *value, *anchor_val;
 	Slapi_Attr *anchor, *attr = NULL;
-	struct backend_search_cbdata *cbdata = (struct backend_search_cbdata *) config->callback_data;
-
-	if (cbdata == NULL || cbdata->idview == NULL) {
-		return SLAPI_FILTER_SCAN_CONTINUE;
-	}
-
-	if (filter_type == NULL || config->name == NULL) {
-		return SLAPI_FILTER_SCAN_CONTINUE;
-	}
+	bool_t uid_override_found = FALSE;
+	bool_t anchor_override_found = FALSE;
 
 	if (cbdata->overrides == NULL) {
 		/* Only retrieve overrides for the view first time when neccessary */
@@ -312,31 +306,34 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
 	}
 
 	if (cbdata->overrides == NULL) {
-		return SLAPI_FILTER_SCAN_CONTINUE;
+		return 0;
 	}
 
-	filter_val = slapi_value_new_berval(bval);
+	attr_val = slapi_value_new_berval(bval);
+	slapi_log_error(SLAPI_LOG_FATAL, cbdata->state->plugin_desc->spd_id,
+			"Searching for an override of the %s %s with %s=%*s from the overrides\n.",
+			bval_usage, attr_name, attr_name, (int) bval->bv_len, bval->bv_val);
 
 	/* If filter contains an attribute name which is overridden in the view and filter value
 	 * corresponds to the override, replace the filter by (ipaAnchorUUID=...) from the override
 	 * to point to the original because otherwise an entry will not be found in the slapi-nis map */
 	for(i=0; cbdata->overrides[i] != NULL; i++) {
-		res = slapi_entry_attr_find(cbdata->overrides[i], filter_type, &attr);
+		res = slapi_entry_attr_find(cbdata->overrides[i], attr_name, &attr);
 		if ((res == 0) && (attr != NULL)) {
 			res = slapi_attr_first_value(attr, &value);
-			res = slapi_value_compare(attr, value, filter_val);
+			res = slapi_value_compare(attr, value, attr_val);
 			if (res == 0) {
 				/* For uid overrides we should have ipaOriginalUID in the override */
-				if (strcasecmp(filter_type, "uid") == 0) {
+				if (strcasecmp(attr_name, "uid") == 0) {
 					res = slapi_entry_attr_find(cbdata->overrides[i], IPA_IDVIEWS_ATTR_ORIGINALUID, &anchor);
 					if (res == 0) {
 						res = slapi_attr_first_value(anchor, &anchor_val);
 						slapi_ber_bvdone(bval);
 						slapi_ber_bvcpy(bval, slapi_value_get_berval(anchor_val));
-						config->override_found = TRUE;
-						slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id,
-								"Overriding the filter %s with %s=%*s from the override %s\n.",
-								filter_type, filter_type, bval->bv_len, bval->bv_val,
+						uid_override_found = TRUE;
+						slapi_log_error(SLAPI_LOG_FATAL, cbdata->state->plugin_desc->spd_id,
+								"Overriding the %s %s with %s=%*s from the override %s\n.",
+								bval_usage, attr_name, attr_name, (int) bval->bv_len, bval->bv_val,
 								slapi_entry_get_dn_const(cbdata->overrides[i]));
 						break;
 					}
@@ -346,14 +343,13 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
 				res = slapi_entry_attr_find(cbdata->overrides[i], IPA_IDVIEWS_ATTR_ANCHORUUID, &anchor);
 				if (res == 0) {
 					res = slapi_attr_first_value(anchor, &anchor_val);
-					slapi_filter_changetype(filter, IPA_IDVIEWS_ATTR_ANCHORUUID);
 					slapi_ber_bvdone(bval);
 					slapi_ber_bvcpy(bval, slapi_value_get_berval(anchor_val));
-					config->override_found = TRUE;
-					slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id,
-							"Overriding the filter %s with %s=%*s from the override %s\n.",
-							filter_type, IPA_IDVIEWS_ATTR_ANCHORUUID,
-							bval->bv_len, bval->bv_val,
+					anchor_override_found = TRUE;
+					slapi_log_error(SLAPI_LOG_FATAL, cbdata->state->plugin_desc->spd_id,
+							"Overriding the %s %s with %s=%*s from the override %s\n.",
+							bval_usage, attr_name, IPA_IDVIEWS_ATTR_ANCHORUUID,
+							(int) bval->bv_len, bval->bv_val,
 							slapi_entry_get_dn_const(cbdata->overrides[i]));
 					break;
 				}
@@ -362,7 +358,41 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
 		}
 	}
 
-	slapi_value_free(&filter_val);
+	slapi_value_free(&attr_val);
+
+	if (uid_override_found) {
+		return 1;
+	}
+
+	if (anchor_override_found) {
+		return 2;
+	}
+
+	return 0;
+}
+
+static int
+idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type,
+			 struct berval *bval, struct backend_search_filter_config *config)
+{
+	int res;
+	struct backend_search_cbdata *cbdata = (struct backend_search_cbdata *) config->callback_data;
+
+	if (cbdata == NULL || cbdata->idview == NULL) {
+		return SLAPI_FILTER_SCAN_CONTINUE;
+	}
+
+	if (filter_type == NULL || config->name == NULL) {
+		return SLAPI_FILTER_SCAN_CONTINUE;
+	}
+
+	res = idview_replace_bval_by_override("filter", filter_type, bval, cbdata);
+
+	if (res == 2) {
+		slapi_filter_changetype(filter, IPA_IDVIEWS_ATTR_ANCHORUUID);
+	}
+
+	config->override_found = (res != 0);
 
 	return SLAPI_FILTER_SCAN_CONTINUE;
 
diff --git a/src/back-sch.c b/src/back-sch.c
index 902adb2..8bcf655 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1634,6 +1634,7 @@ backend_locate(Slapi_PBlock *pb, struct backend_entry_data **data, const char **
 {
 	struct backend_locate_cbdata cbdata;
 	char *idview = NULL;
+	char *target = NULL;
 
 	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
 	if (cbdata.state->plugin_base == NULL) {
@@ -1642,22 +1643,59 @@ backend_locate(Slapi_PBlock *pb, struct backend_entry_data **data, const char **
 		return;
 	}
 	slapi_pblock_get(pb, SLAPI_TARGET_DN, &cbdata.target);
-#ifdef USE_IPA_IDVIEWS
-	idview_replace_target_dn(&cbdata.target, &idview);
-#endif
+
 	cbdata.target_dn = slapi_sdn_new_dn_byval(cbdata.target);
 	cbdata.entry_data = NULL;
 	cbdata.entry_group = NULL;
 	cbdata.entry_set = NULL;
 	map_data_foreach_map(cbdata.state, NULL, backend_locate_cb, &cbdata);
+#ifdef USE_IPA_IDVIEWS
+	/* In case nothing was found but we are operating on the ID override,
+	 * rebuild the target's RDN to use original attribute's value */
+	if (cbdata.entry_data == NULL) {
+		target = slapi_ch_strdup(cbdata.target);
+		idview_replace_target_dn(&target, &idview);
+		if (idview != NULL) {
+			char *rdnstr;
+			char *val;
+			struct berval bval;
+			int res;
+			struct backend_search_cbdata scbdata;
+			Slapi_RDN *rdn = slapi_rdn_new_all_dn(target);
+			if (rdn != NULL) {
+				res = slapi_rdn_get_first(rdn, &rdnstr, &val);
+				if (res == 1) {
+					bval.bv_len = strlen(val) + 1;
+					bval.bv_val = slapi_ch_strdup(val);
+					memset(&scbdata, 0, sizeof(scbdata));
+					scbdata.idview = idview;
+					scbdata.target = target;
+					scbdata.pb = pb;
+					scbdata.state = cbdata.state;
+					scbdata.target_dn = slapi_sdn_new_dn_byval(target);
+					res = idview_replace_bval_by_override("rdn", rdnstr, &bval, &scbdata);
+					/* only accept uid overrides */
+					if (res == 1) {
+						slapi_rdn_remove_index(rdn, 1);
+						slapi_rdn_add(rdn, "uid", bval.bv_val);
+						slapi_sdn_free(&cbdata.target_dn);
+						cbdata.target_dn = slapi_sdn_set_rdn(scbdata.target_dn, rdn);
+						map_data_foreach_map(cbdata.state, NULL, backend_locate_cb, &cbdata);
+					}
+					slapi_ber_bvdone(&bval);
+					slapi_rdn_free(&rdn);
+					idview_free_overrides(&scbdata);
+				}
+			}
+		}
+		slapi_ch_free_string(&target);
+		slapi_ch_free_string(&idview);
+	}
+#endif
 	*data = cbdata.entry_data;
 	*group = cbdata.entry_group;
 	*set = cbdata.entry_set;
 	slapi_sdn_free(&cbdata.target_dn);
-	if (idview != NULL) {
-		slapi_ch_free_string(&cbdata.target);
-	}
-	slapi_ch_free_string(&idview);
 }
 
 /* Check if the target DN is part of this group's tree.  If it is, return an
diff --git a/src/back-sch.h b/src/back-sch.h
index 9f0b201..26e12d1 100644
--- a/src/back-sch.h
+++ b/src/back-sch.h
@@ -131,6 +131,10 @@ void idview_process_overrides(struct backend_search_cbdata *cbdata,
 			      Slapi_Entry *entry);
 void idview_replace_target_dn(char **target, char **idview);
 void idview_replace_filter(struct backend_search_cbdata *cbdata);
+/* Takes struct berval value of an attribute attr_name and replaces it with an override
+ * Returns 0 if no override was found, 1 for 'uid' replacement, 2 for ipaAnchorUUID replacement */
+int  idview_replace_bval_by_override(const char *bval_usage, const char *attr_name,
+				     struct berval *bval, struct backend_search_cbdata *cbdata);
 #endif
 
 #endif
-- 
2.1.0



More information about the Freeipa-devel mailing list