Blame SOURCES/slapi-nis-extmem-0007-slapi-nis-add-support-to-resolve-external-members-of.patch

6b9042
From d1b87904462e890a855ac9d3b68ed02e089450d8 Mon Sep 17 00:00:00 2001
6b9042
From: Alexander Bokovoy <abokovoy@redhat.com>
6b9042
Date: Wed, 23 Dec 2015 15:04:40 +0200
6b9042
Subject: [PATCH 07/12] slapi-nis: add support to resolve external members of
6b9042
 IPA groups
6b9042
6b9042
FreeIPA allows to include external (non-LDAP) members into POSIX groups.
6b9042
To define external members, an attribute ipaExternalMember is set to
6b9042
the list of references to external members. Currently both FreeIPA and
6b9042
SSSD support only references done with SIDs (Security Identifiers) from
6b9042
the forests trusted by FreeIPA.
6b9042
6b9042
Resolving external members of FreeIPA groups requires resolving SIDs to
6b9042
user and group names. However, since this resolution is already
6b9042
implemented by SSSD for the group in question, slapi-nis can use the
6b9042
fact that there is non-empty ipaExternalMember attribute's value to
6b9042
trigger lookup of the FreeIPA group via SSSD and then copy over
6b9042
memberUid attribute value set.
6b9042
6b9042
This logic requires that ipaExternalMember attribute value is present in
6b9042
the entry to be put into the map cache. Thus, an additional
6b9042
configuration is needed for the groups container:
6b9042
6b9042
schema-compat-entry-attribute: ipaexternalmember=%deref_r("member","ipaexternalmember")
6b9042
6b9042
Note that resolving external members of IPA groups requires to use
6b9042
version of slapi-nis that populates the map cache after LDAP server
6b9042
startup, as SSSD needs to talk back to the LDAP server in the process of
6b9042
resolving external group members and that is not possible at the time
6b9042
when slapi-nis plugin starts up as the LDAP server is not yet listenting
6b9042
for incoming connections at that point.
6b9042
---
6b9042
 doc/ipa/sch-ipa.txt |  15 +++++++
6b9042
 src/back-sch.c      | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++
6b9042
 2 files changed, 127 insertions(+)
6b9042
6b9042
diff --git a/doc/ipa/sch-ipa.txt b/doc/ipa/sch-ipa.txt
6b9042
index 106e6cc..eb6238a 100644
6b9042
--- a/doc/ipa/sch-ipa.txt
6b9042
+++ b/doc/ipa/sch-ipa.txt
6b9042
@@ -81,6 +81,21 @@ and groups from trusted domains. No additional configuration is needed.
6b9042
 ipa-adtrust-install, however, will not set the minimal numeric id for user or
6b9042
 group.
6b9042
 
6b9042
+Additionally, group area configuration should include following two attributes to
6b9042
+allow resolving external members of IPA groups:
6b9042
+
6b9042
+schema-compat-entry-attribute: ipaexternalmember=%deref_r("member","ipaexternalmember")
6b9042
+schema-compat-entry-attribute: objectclass=ipaexternalgroup
6b9042
+
6b9042
+When 'ipaExternalMember' attribute is present in the group entry generated by
6b9042
+Schema Compatibility plugin, the plugin will attempt to retrieve the group
6b9042
+members from SSSD daemon. If group has non-empty list of members, these new
6b9042
+members will replace the original ones as they will include both IPA and external
6b9042
+group members.
6b9042
+
6b9042
+SSSD greater than 1.13.3 is required to produce correct behavior due to bug
6b9042
+https://fedorahosted.org/sssd/ticket/2522
6b9042
+
6b9042
 == Authentication of the trusted domains' users ==
6b9042
 
6b9042
 When the Schema Compatibility Plugin is configured to expose users from trusted
6b9042
diff --git a/src/back-sch.c b/src/back-sch.c
6b9042
index 98542c5..04fe667 100644
6b9042
--- a/src/back-sch.c
6b9042
+++ b/src/back-sch.c
6b9042
@@ -419,6 +419,115 @@ backend_set_operational_attributes(Slapi_Entry *e,
6b9042
 	}
6b9042
 }
6b9042
 
6b9042
+#ifdef USE_NSSWITCH
6b9042
+#define IPA_ATTR_EXTERNAL_MEMBER "ipaExternalMember"
6b9042
+#define IPA_ATTR_MEMBERUID "memberUid"
6b9042
+static void
6b9042
+backend_set_process_external_members(Slapi_PBlock *pb,
6b9042
+				   Slapi_Entry *e,
6b9042
+				   struct plugin_state *state,
6b9042
+				   struct backend_set_data *data)
6b9042
+{
6b9042
+	Slapi_Attr *attr = NULL;
6b9042
+	Slapi_ValueSet *valueset = NULL;
6b9042
+	bool_t is_attr_exists, is_group_exists;
6b9042
+	struct backend_staged_search staged = {0, };
6b9042
+	struct backend_search_cbdata cbdata = {0, };
6b9042
+	char *plugin_id = state->plugin_desc->spd_id;
6b9042
+
6b9042
+	is_attr_exists = slapi_entry_attr_find(e, IPA_ATTR_EXTERNAL_MEMBER, &attr) == 0;
6b9042
+
6b9042
+	if (!is_attr_exists || attr == NULL) {
6b9042
+		return;
6b9042
+	}
6b9042
+
6b9042
+	/* There are external members in this entry, do group lookup via SSSD
6b9042
+	 * and update entry's memberUid attribute */
6b9042
+
6b9042
+	staged.name = slapi_entry_attr_get_charptr(e, "cn");
6b9042
+	staged.type = SCH_NSSWITCH_GROUP;
6b9042
+	staged.search_members = FALSE;
6b9042
+	staged.is_id = FALSE;
6b9042
+	staged.is_sid = FALSE;
6b9042
+	staged.container_sdn = (char*) slapi_sdn_get_dn(data->container_sdn);
6b9042
+	staged.entries = NULL;
6b9042
+	staged.count = 0;
6b9042
+	cbdata.nsswitch_buffer_len = MAX(16384, MAX(sysconf(_SC_GETPW_R_SIZE_MAX), sysconf(_SC_GETGR_R_SIZE_MAX)));
6b9042
+	cbdata.nsswitch_buffer = malloc(cbdata.nsswitch_buffer_len);
6b9042
+	cbdata.state = state;
6b9042
+	cbdata.staged = &staged;
6b9042
+
6b9042
+	slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
6b9042
+			"refreshing group membership for group \"%s\"\n", staged.name);
6b9042
+
6b9042
+	do {
6b9042
+		/* This group must exist because it exists in the original tree
6b9042
+		 * but as dirsrv was restarted, SSSD might still consider its domain offline. */
6b9042
+		is_group_exists = backend_retrieve_from_nsswitch(&staged, &cbdata);
6b9042
+		if (!is_group_exists) {
6b9042
+			slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
6b9042
+					"group \"%s\" does not exist because SSSD is offline.",
6b9042
+					staged.name);
6b9042
+			if (state->ready_to_serve == 0) {
6b9042
+				/* Only wait for SSSD when we populate the original set */
6b9042
+				slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
6b9042
+						"waiting for SSSD to become online...");
6b9042
+				DS_Sleep(PR_SecondsToInterval(35));
6b9042
+			} else {
6b9042
+				break;
6b9042
+			}
6b9042
+		}
6b9042
+	} while (!is_group_exists);
6b9042
+
6b9042
+	if (staged.entries != NULL && staged.entries[0] != NULL) {
6b9042
+			attr = NULL;
6b9042
+			if (slapi_entry_attr_find(staged.entries[0], IPA_ATTR_MEMBERUID, &attr) == 0) {
6b9042
+#if 0
6b9042
+				/* Debug output of original and updated memberUid values */
6b9042
+				char **ary1, **ary2;
6b9042
+				ary1 = slapi_entry_attr_get_charray(e, "memberUid");
6b9042
+				ary2 = slapi_entry_attr_get_charray(staged.entries[0], "memberUid");
6b9042
+
6b9042
+				slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
6b9042
+						"original group \"%s\":\n", staged.name);
6b9042
+				for (int i = 0; ary1 && ary1[i] != NULL; ++i) {
6b9042
+					slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
6b9042
+							"\t> %s\n", ary1[i]);
6b9042
+				}
6b9042
+				slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
6b9042
+						"new group \"%s\":\n", staged.name);
6b9042
+				for (int i = 0; ary2 && ary2[i] != NULL; ++i) {
6b9042
+					slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
6b9042
+							"\t> %s\n", ary2[i]);
6b9042
+				}
6b9042
+				slapi_ch_array_free(ary2);
6b9042
+				slapi_ch_array_free(ary1);
6b9042
+#endif
6b9042
+
6b9042
+				(void)slapi_attr_get_valueset(attr, &valueset);
6b9042
+
6b9042
+				if (slapi_entry_attr_find(e, IPA_ATTR_MEMBERUID, &attr) == 0) {
6b9042
+					(void) slapi_entry_attr_delete(e, IPA_ATTR_MEMBERUID);
6b9042
+				}
6b9042
+				(void) slapi_entry_add_valueset(e, IPA_ATTR_MEMBERUID, valueset);
6b9042
+				slapi_valueset_free(valueset);
6b9042
+			} else {
6b9042
+				slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
6b9042
+						"group \"%s\" doesn't have memberUid attribute\n", staged.name);
6b9042
+			}
6b9042
+			slapi_entry_free(staged.entries[0]);
6b9042
+	}
6b9042
+
6b9042
+	if (staged.entries != NULL) {
6b9042
+		free(staged.entries);
6b9042
+	}
6b9042
+
6b9042
+	(void)slapi_entry_attr_delete(e, IPA_ATTR_EXTERNAL_MEMBER);
6b9042
+	free(cbdata.nsswitch_buffer);
6b9042
+	slapi_ch_free_string(&staged.name);
6b9042
+}
6b9042
+#endif
6b9042
+
6b9042
 /* Given a map-entry directory entry, determine a key, a value, and extra data
6b9042
  * to be stored in the map cache, and add them to the map cache. */
6b9042
 static void
6b9042
@@ -613,6 +722,9 @@ backend_set_entry_from(Slapi_PBlock *pb, enum backend_entry_source source,
6b9042
 		slapi_entry_add_string(entry,
6b9042
 				       "objectClass", "extensibleObject");
6b9042
 	}
6b9042
+#ifdef USE_NSSWITCH
6b9042
+	backend_set_process_external_members(pb, entry, data->common.state, data);
6b9042
+#endif
6b9042
 	/* Clean up the entry by doing a round trip through the LDIF parser. */
6b9042
 	ldif = slapi_entry2str(entry, &len;;
6b9042
 	slapi_entry_free(entry);
6b9042
-- 
6b9042
2.5.0
6b9042