|
|
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 |
|