summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Bokovoy <abokovoy@redhat.com>2015-12-23 15:04:40 +0200
committerAlexander Bokovoy <abokovoy@redhat.com>2016-01-18 18:30:58 +0200
commitcd642e58ec86ee170ea98648f617f18883d8b4a9 (patch)
treee31b18f99d849656aa48b65f75295cb93e4b2c08
parentf54d461a8678a490a0fd757f242d4aa756516e61 (diff)
downloadslapi-nis-cd642e58ec86ee170ea98648f617f18883d8b4a9.tar.gz
slapi-nis-cd642e58ec86ee170ea98648f617f18883d8b4a9.tar.xz
slapi-nis-cd642e58ec86ee170ea98648f617f18883d8b4a9.zip
slapi-nis: add support to resolve external members of IPA groups
FreeIPA allows to include external (non-LDAP) members into POSIX groups. To define external members, an attribute ipaExternalMember is set to the list of references to external members. Currently both FreeIPA and SSSD support only references done with SIDs (Security Identifiers) from the forests trusted by FreeIPA. Resolving external members of FreeIPA groups requires resolving SIDs to user and group names. However, since this resolution is already implemented by SSSD for the group in question, slapi-nis can use the fact that there is non-empty ipaExternalMember attribute's value to trigger lookup of the FreeIPA group via SSSD and then copy over memberUid attribute value set. This logic requires that ipaExternalMember attribute value is present in the entry to be put into the map cache. Thus, an additional configuration is needed for the groups container: schema-compat-entry-attribute: ipaexternalmember=%deref_r("member","ipaexternalmember") Note that resolving external members of IPA groups requires to use version of slapi-nis that populates the map cache after LDAP server startup, as SSSD needs to talk back to the LDAP server in the process of resolving external group members and that is not possible at the time when slapi-nis plugin starts up as the LDAP server is not yet listenting for incoming connections at that point.
-rw-r--r--src/back-sch.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/back-sch.c b/src/back-sch.c
index 98542c5..04fe667 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -419,6 +419,115 @@ backend_set_operational_attributes(Slapi_Entry *e,
}
}
+#ifdef USE_NSSWITCH
+#define IPA_ATTR_EXTERNAL_MEMBER "ipaExternalMember"
+#define IPA_ATTR_MEMBERUID "memberUid"
+static void
+backend_set_process_external_members(Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ struct plugin_state *state,
+ struct backend_set_data *data)
+{
+ Slapi_Attr *attr = NULL;
+ Slapi_ValueSet *valueset = NULL;
+ bool_t is_attr_exists, is_group_exists;
+ struct backend_staged_search staged = {0, };
+ struct backend_search_cbdata cbdata = {0, };
+ char *plugin_id = state->plugin_desc->spd_id;
+
+ is_attr_exists = slapi_entry_attr_find(e, IPA_ATTR_EXTERNAL_MEMBER, &attr) == 0;
+
+ if (!is_attr_exists || attr == NULL) {
+ return;
+ }
+
+ /* There are external members in this entry, do group lookup via SSSD
+ * and update entry's memberUid attribute */
+
+ staged.name = slapi_entry_attr_get_charptr(e, "cn");
+ staged.type = SCH_NSSWITCH_GROUP;
+ staged.search_members = FALSE;
+ staged.is_id = FALSE;
+ staged.is_sid = FALSE;
+ staged.container_sdn = (char*) slapi_sdn_get_dn(data->container_sdn);
+ staged.entries = NULL;
+ staged.count = 0;
+ cbdata.nsswitch_buffer_len = MAX(16384, MAX(sysconf(_SC_GETPW_R_SIZE_MAX), sysconf(_SC_GETGR_R_SIZE_MAX)));
+ cbdata.nsswitch_buffer = malloc(cbdata.nsswitch_buffer_len);
+ cbdata.state = state;
+ cbdata.staged = &staged;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
+ "refreshing group membership for group \"%s\"\n", staged.name);
+
+ do {
+ /* This group must exist because it exists in the original tree
+ * but as dirsrv was restarted, SSSD might still consider its domain offline. */
+ is_group_exists = backend_retrieve_from_nsswitch(&staged, &cbdata);
+ if (!is_group_exists) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
+ "group \"%s\" does not exist because SSSD is offline.",
+ staged.name);
+ if (state->ready_to_serve == 0) {
+ /* Only wait for SSSD when we populate the original set */
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
+ "waiting for SSSD to become online...");
+ DS_Sleep(PR_SecondsToInterval(35));
+ } else {
+ break;
+ }
+ }
+ } while (!is_group_exists);
+
+ if (staged.entries != NULL && staged.entries[0] != NULL) {
+ attr = NULL;
+ if (slapi_entry_attr_find(staged.entries[0], IPA_ATTR_MEMBERUID, &attr) == 0) {
+#if 0
+ /* Debug output of original and updated memberUid values */
+ char **ary1, **ary2;
+ ary1 = slapi_entry_attr_get_charray(e, "memberUid");
+ ary2 = slapi_entry_attr_get_charray(staged.entries[0], "memberUid");
+
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+ "original group \"%s\":\n", staged.name);
+ for (int i = 0; ary1 && ary1[i] != NULL; ++i) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+ "\t> %s\n", ary1[i]);
+ }
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+ "new group \"%s\":\n", staged.name);
+ for (int i = 0; ary2 && ary2[i] != NULL; ++i) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+ "\t> %s\n", ary2[i]);
+ }
+ slapi_ch_array_free(ary2);
+ slapi_ch_array_free(ary1);
+#endif
+
+ (void)slapi_attr_get_valueset(attr, &valueset);
+
+ if (slapi_entry_attr_find(e, IPA_ATTR_MEMBERUID, &attr) == 0) {
+ (void) slapi_entry_attr_delete(e, IPA_ATTR_MEMBERUID);
+ }
+ (void) slapi_entry_add_valueset(e, IPA_ATTR_MEMBERUID, valueset);
+ slapi_valueset_free(valueset);
+ } else {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
+ "group \"%s\" doesn't have memberUid attribute\n", staged.name);
+ }
+ slapi_entry_free(staged.entries[0]);
+ }
+
+ if (staged.entries != NULL) {
+ free(staged.entries);
+ }
+
+ (void)slapi_entry_attr_delete(e, IPA_ATTR_EXTERNAL_MEMBER);
+ free(cbdata.nsswitch_buffer);
+ slapi_ch_free_string(&staged.name);
+}
+#endif
+
/* Given a map-entry directory entry, determine a key, a value, and extra data
* to be stored in the map cache, and add them to the map cache. */
static void
@@ -613,6 +722,9 @@ backend_set_entry_from(Slapi_PBlock *pb, enum backend_entry_source source,
slapi_entry_add_string(entry,
"objectClass", "extensibleObject");
}
+#ifdef USE_NSSWITCH
+ backend_set_process_external_members(pb, entry, data->common.state, data);
+#endif
/* Clean up the entry by doing a round trip through the LDIF parser. */
ldif = slapi_entry2str(entry, &len);
slapi_entry_free(entry);