[Pkg-freeipa-devel] slapi-nis: Changes to 'upstream'
Timo Aaltonen
tjaalton at moszumanska.debian.org
Mon Feb 22 05:45:48 UTC 2016
configure.ac | 2
doc/ipa/sch-ipa.txt | 15 ++
doc/nis-configuration.txt | 4
doc/sch-configuration.txt | 11 +
slapi-nis.spec | 7
src/back-sch-idview.c | 6
src/back-sch-nss.c | 29 +++
src/back-sch.c | 336 ++++++++++++++++++++++++++++++++++++++++++----
src/back-sch.h | 20 ++
src/back-shr.c | 155 ++++++++++++++++++---
src/defs-nis.c | 10 -
src/plug-sch.c | 38 ++++-
src/plugin.h | 4
13 files changed, 573 insertions(+), 64 deletions(-)
New commits:
commit dc18db811d26a9e376788688d4e68937b078ac58
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date: Tue Jan 26 13:42:54 2016 +0200
Release 0.55
diff --git a/configure.ac b/configure.ac
index ae626de..5b10376 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(slapi-nis,0.54.2)
+AC_INIT(slapi-nis,0.55)
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE(foreign)
LT_INIT([disable-static])
diff --git a/slapi-nis.spec b/slapi-nis.spec
index f0c2647..2546509 100644
--- a/slapi-nis.spec
+++ b/slapi-nis.spec
@@ -10,7 +10,7 @@
%endif
Name: slapi-nis
-Version: 0.54.2
+Version: 0.55
Release: 1%{?dist}
Summary: NIS Server and Schema Compatibility plugins for Directory Server
Group: System Environment/Daemons
@@ -85,6 +85,11 @@ rm -rf $RPM_BUILD_ROOT
%{_sbindir}/nisserver-plugin-defs
%changelog
+* Tue Jan 26 2016 Alexander Bokovoy <abokovoy at redhat.com> - 0.55-1
+- Support external members of IPA groups in schema compat
+- Support bind over ID overrides when uid is not overridden
+- Populate schema compat trees in parallel to LDAP server startup
+
* Thu Mar 26 2015 Alexander Bokovoy <abokovoy at redhat.com> - 0.54.2-1
- CVE-2015-0283 slapi-nis: infinite loop in getgrnam_r() and getgrgid_r()
- Make sure nss_sss.so.2 module is used directly
commit 00468e8eebd455ab4e41d4d86772fb5f8a745d0a
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date: Thu Jan 21 19:16:30 2016 +0200
idviews: bind with original DN if ID view does not override uid attribute
With ID Views in FreeIPA one can override different kinds of attributes,
including the uid. When uid attribute is overriden, LDAP BINDs with
DNs using new (overridden) uid are properly modified to reference the
original (non-overridden) object.
However, when uid attribute is not overridden, slapi-nis did mistakenly
avoided to build a reference to the original object without ID view.
This resulted in inability to do LDAP BIND as overriden DN with original
uid attribute.
Fix the issue by always processing a DN after removing ID view reference
from it, whether RDN value (uid) was replaced or not.
Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1301300
diff --git a/src/back-sch-idview.c b/src/back-sch-idview.c
index 8ffab91..8842906 100644
--- a/src/back-sch-idview.c
+++ b/src/back-sch-idview.c
@@ -311,7 +311,7 @@ idview_replace_bval_by_override(const char *bval_usage, const char *attr_name,
}
attr_val = slapi_value_new_berval(bval);
- slapi_log_error(SLAPI_LOG_FATAL, cbdata->state->plugin_desc->spd_id,
+ slapi_log_error(SLAPI_LOG_PLUGIN, 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);
@@ -347,7 +347,7 @@ idview_replace_bval_by_override(const char *bval_usage, const char *attr_name,
slapi_ber_bvdone(bval);
slapi_ber_bvcpy(bval, slapi_value_get_berval(anchor_val));
anchor_override_found = TRUE;
- slapi_log_error(SLAPI_LOG_FATAL, cbdata->state->plugin_desc->spd_id,
+ slapi_log_error(SLAPI_LOG_PLUGIN, 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,
diff --git a/src/back-sch.c b/src/back-sch.c
index 871734c..9a0e96b 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -465,13 +465,13 @@ backend_set_process_external_members(Slapi_PBlock *pb,
* 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.",
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+ "group \"%s\" does not exist because SSSD is offline.\n",
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...");
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+ "waiting for SSSD to become online...\n");
DS_Sleep(PR_SecondsToInterval(35));
} else {
break;
@@ -1609,15 +1609,15 @@ backend_search_cb(Slapi_PBlock *pb)
{
struct backend_search_cbdata cbdata;
struct backend_staged_search *staged, *next;
- int i, isroot;
+ int i, isroot, ret;
if (wrap_get_call_level() > 0) {
return 0;
}
memset(&cbdata, 0, sizeof(cbdata));
cbdata.pb = pb;
- slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
- if (cbdata.state->plugin_base == NULL) {
+ ret = slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
+ if ((ret == -1) || (cbdata.state->plugin_base == NULL)) {
/* The plugin was not actually started. */
return 0;
}
@@ -1626,9 +1626,9 @@ backend_search_cb(Slapi_PBlock *pb)
return 0;
}
- slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
+ ret = slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
- if (slapi_op_internal(pb) || (slapi_is_ldapi_conn(pb) && isroot)) {
+ if ((ret == -1) || (slapi_op_internal(pb) || (slapi_is_ldapi_conn(pb) && isroot))) {
/* The plugin should not engage in internal searches of other
* plugins or ldapi+cn=DM */
return 0;
@@ -1959,10 +1959,10 @@ backend_locate(Slapi_PBlock *pb, struct backend_entry_data **data, const char **
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_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);
commit 5eaad9c4c218d9a59f6930a29f5bee54235c4fab
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date: Tue Jan 19 07:37:46 2016 +0200
nis: lock out accounts if nsAccountLock is TRUE
Add a rule that adds two bang characters in front of the password.
When the password algorithm is defined as CRYPT and NIS is used to
authenticate users on other systems, there is no way to disable or lock
accounts. Traditional convention has been to put two bang (exclamation)
characters in front of the password, creating an impossible password
hash. This effectively locks the user account, preventing
authentication.
All UNIX systems agree that for encrypted passwords presence of a
character which cannot be part of CRYPT password scheme renders
impossible to login to system with such password. However, not all
systems have meaning of locked accounts and even how these locked
accounts express themselves.
There is certain controversy in what could be used to indicate locked
accounts:
- GNU/Linux systems expect '!' as first character of the password field
- FreeBSD expects '*LOCKED*' string at start of the password field
- Various Solaris versions expect '*LOCK*' string at start of the
password field
- NetBSD has no meaning of locked passwords via content of password field
Given that it is impossible to serve NIS maps with encrypted passwords
in a different way to different clients, standardize on '!!' scheme as
traditional among UNIX administrators.
Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1298478
diff --git a/src/defs-nis.c b/src/defs-nis.c
index 3d2b9e9..ad0e7dc 100644
--- a/src/defs-nis.c
+++ b/src/defs-nis.c
@@ -52,17 +52,17 @@ static struct configuration {
{"passwd.byname", config_exact, FALSE, NULL,
"(objectClass=posixAccount)",
"%{uid}", NULL,
- "%{uid}:%ifeq(\"objectClass\",\"shadowAccount\",\"x\",\"%regsubi(\\\"%{userPassword}\\\",\\\"^\\\\\\\\{CRYPT\\\\\\\\}(..*)\\\",\\\"%1\\\",\\\"*\\\")\"):%regmatch(\"%{uidNumber}\",\"[0-9]+\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%{gecos:-%{cn:-}}:%{homeDirectory:-/}:%{loginShell:-" _PATH_BSHELL "}", NULL,
+ "%{uid}:%ifeq(\"nsAccountLock\",\"TRUE\",\"!!\",\"\")%ifeq(\"objectClass\",\"shadowAccount\",\"x\",\"%regsubi(\\\"%{userPassword}\\\",\\\"^\\\\\\\\{CRYPT\\\\\\\\}(..*)\\\",\\\"%1\\\",\\\"*\\\")\"):%regmatch(\"%{uidNumber}\",\"[0-9]+\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%{gecos:-%{cn:-}}:%{homeDirectory:-/}:%{loginShell:-" _PATH_BSHELL "}", NULL,
":\r\n"},
{"passwd.byuid", config_exact, FALSE, NULL,
"(objectClass=posixAccount)",
"%{uidNumber}", NULL,
- "%{uid}:%ifeq(\"objectClass\",\"shadowAccount\",\"x\",\"%regsubi(\\\"%{userPassword}\\\",\\\"^\\\\\\\\{CRYPT\\\\\\\\}(..*)\\\",\\\"%1\\\",\\\"*\\\")\"):%regmatch(\"%{uidNumber}\",\"[0-9]+\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%{gecos:-%{cn:-}}:%{homeDirectory:-/}:%{loginShell:-" _PATH_BSHELL "}", NULL,
+ "%{uid}:%ifeq(\"nsAccountLock\",\"TRUE\",\"!!\",\"\")%ifeq(\"objectClass\",\"shadowAccount\",\"x\",\"%regsubi(\\\"%{userPassword}\\\",\\\"^\\\\\\\\{CRYPT\\\\\\\\}(..*)\\\",\\\"%1\\\",\\\"*\\\")\"):%regmatch(\"%{uidNumber}\",\"[0-9]+\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%{gecos:-%{cn:-}}:%{homeDirectory:-/}:%{loginShell:-" _PATH_BSHELL "}", NULL,
":\r\n"},
{"shadow.byname", config_exact, TRUE, NULL,
"(objectClass=shadowAccount)",
"%{uid}", NULL,
- "%{uid}:%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%{shadowLastChange:-}:%{shadowMin:-}:%{shadowMax:-}:%{shadowWarning:-}:%{shadowInactive:-}:%{shadowExpire:-}:%{shadowFlag:-}", NULL,
+ "%{uid}:%ifeq(\"nsAccountLock\",\"TRUE\",\"!!\",\"\")%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%{shadowLastChange:-}:%{shadowMin:-}:%{shadowMax:-}:%{shadowWarning:-}:%{shadowInactive:-}:%{shadowExpire:-}:%{shadowFlag:-}", NULL,
":\r\n"},
{"passwd.adjunct.byname", config_exact, TRUE, NULL,
"(objectClass=shadowAccount)",
@@ -72,12 +72,12 @@ static struct configuration {
{"group.byname", config_exact, FALSE, NULL,
"(objectClass=posixGroup)",
"%{cn}", NULL,
- "%{cn}:%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%merge(\",\",\"%{memberUid}\",\"%deref_r(\\\"member\\\",\\\"uid\\\")\",\"%deref_r(\\\"uniqueMember\\\",\\\"uid\\\")\")", NULL,
+ "%{cn}:%ifeq(\"nsAccountLock\",\"TRUE\",\"!!\",\"\")%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%merge(\",\",\"%{memberUid}\",\"%deref_r(\\\"member\\\",\\\"uid\\\")\",\"%deref_r(\\\"uniqueMember\\\",\\\"uid\\\")\")", NULL,
":,\r\n"},
{"group.bygid", config_exact, FALSE, NULL,
"(objectClass=posixGroup)",
"%{gidNumber}", NULL,
- "%{cn}:%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%{gidNumber}:%merge(\",\",\"%{memberUid}\",\"%deref_r(\\\"member\\\",\\\"uid\\\")\",\"%deref_r(\\\"uniqueMember\\\",\\\"uid\\\")\")", NULL,
+ "%{cn}:%ifeq(\"nsAccountLock\",\"TRUE\",\"!!\",\"\")%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%{gidNumber}:%merge(\",\",\"%{memberUid}\",\"%deref_r(\\\"member\\\",\\\"uid\\\")\",\"%deref_r(\\\"uniqueMember\\\",\\\"uid\\\")\")", NULL,
":,\r\n"},
{"netgroup", config_exact, FALSE, NULL,
"(objectClass=nisNetgroup)",
commit 3aaf4941fc17df388c43776eda6d41f62017a143
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date: Fri Jan 15 17:17:23 2016 +0200
slapi-nis: serialize map cache initialization
Serialize process of initiliazing map cache to avoid locking the
directory server backends.
diff --git a/src/back-shr.c b/src/back-shr.c
index 131365d..0157582 100644
--- a/src/back-shr.c
+++ b/src/back-shr.c
@@ -678,49 +678,68 @@ backend_shr_data_initialize_thread_cb(void *arg)
struct backend_shr_data_init_cbdata *cbdata = (struct backend_shr_data_init_cbdata *)arg;
Slapi_PBlock *pb = NULL;
struct backend_set_config_entry_add_cbdata set_cbdata;
- int result = 0;
+ int result = 0, i = 0;
+ Slapi_Entry **entries = NULL;
+ struct plugin_state *state = NULL;
+
if (cbdata == NULL) {
return;
}
+ state = cbdata->state;
+
/* Scan may require consulting SSSD for external identities
* therefore, we need to make sure the scan starts after ns-slapd
* started to serve LDAP clients. There is no a signal for this,
* so we just wait some time. */
DS_Sleep(PR_SecondsToInterval(PLUGIN_SCAN_DELAY));
- backend_update_params(cbdata->parent_pb, cbdata->state);
+ backend_update_params(cbdata->parent_pb, state);
slapi_log_error(SLAPI_LOG_PLUGIN,
- cbdata->state->plugin_desc->spd_id,
+ state->plugin_desc->spd_id,
"searching under \"%s\" for configuration\n",
- cbdata->state->plugin_base);
+ state->plugin_base);
pb = wrap_pblock_new(cbdata->parent_pb);
slapi_search_internal_set_pb(pb,
- cbdata->state->plugin_base,
+ state->plugin_base,
LDAP_SCOPE_ONELEVEL,
cbdata->filter,
NULL, FALSE,
NULL,
NULL,
- cbdata->state->plugin_identity,
+ state->plugin_identity,
0);
- if (map_wrlock() != 0) {
- slapi_log_error(SLAPI_LOG_PLUGIN,
- cbdata->state->plugin_desc->spd_id,
+ wrap_inc_call_level();
+ set_cbdata.state = state;
+ set_cbdata.pb = pb;
+
+ /* Do a search and collect found entries to avoid locking the backends */
+ if (slapi_search_internal_pb(pb) == 0) {
+ if (map_wrlock() != 0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ state->plugin_desc->spd_id,
"failed to search under \"%s\" for "
"configuration: failed to acquire a lock\n",
- cbdata->state->plugin_base);
- goto done_with_lock;
+ state->plugin_base);
+ goto done_with_lock;
+ }
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
+ if (result == 0) {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ for (i = 0; entries[i] != NULL; i++) {
+ backend_set_config_entry_add_cb(entries[i], &set_cbdata);
+ }
+ }
+ map_unlock();
+ slapi_free_search_results_internal(pb);
}
- set_cbdata.state = cbdata->state;
- set_cbdata.pb = pb;
- slapi_search_internal_callback_pb(pb, &set_cbdata,
- NULL,
- backend_set_config_entry_add_cb,
- NULL);
- map_unlock();
+ slapi_log_error(SLAPI_LOG_FATAL,
+ state->plugin_desc->spd_id,
+ "Finished plugin initialization.\n");
+
done_with_lock:
+ wrap_dec_call_level();
slapi_pblock_destroy(pb);
if (cbdata) {
slapi_ch_free((void**)&cbdata);
commit 594fcb2320033d01cfe2b8121793d431d1017987
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date: Fri Jan 15 16:39:12 2016 +0200
slapi-nis: process requests only when initialization completed
Initializing map cache may take time. Skip slapi-nis lookups untli
the map cache is ready.
diff --git a/src/back-sch.c b/src/back-sch.c
index 04fe667..871734c 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1609,7 +1609,7 @@ backend_search_cb(Slapi_PBlock *pb)
{
struct backend_search_cbdata cbdata;
struct backend_staged_search *staged, *next;
- int i;
+ int i, isroot;
if (wrap_get_call_level() > 0) {
return 0;
@@ -1621,6 +1621,19 @@ backend_search_cb(Slapi_PBlock *pb)
/* The plugin was not actually started. */
return 0;
}
+ if (cbdata.state->ready_to_serve == 0) {
+ /* No data to serve yet */
+ return 0;
+ }
+
+ slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
+
+ if (slapi_op_internal(pb) || (slapi_is_ldapi_conn(pb) && isroot)) {
+ /* The plugin should not engage in internal searches of other
+ * plugins or ldapi+cn=DM */
+ return 0;
+ }
+
slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &cbdata.target);
slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &cbdata.scope);
slapi_pblock_get(pb, SLAPI_SEARCH_SIZELIMIT, &cbdata.sizelimit);
@@ -2018,6 +2031,10 @@ backend_write_cb(Slapi_PBlock *pb, struct plugin_state *state)
if (wrap_get_call_level() > 0) {
return 0;
}
+ if (state->ready_to_serve == 0) {
+ /* No data to serve yet */
+ return 0;
+ }
wrap_inc_call_level();
if (map_rdlock() == 0) {
@@ -2125,6 +2142,10 @@ backend_bind_cb(Slapi_PBlock *pb)
}
slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
+ if (state->ready_to_serve == 0) {
+ /* No data to serve yet */
+ return 0;
+ }
/* The code below handles three separate facts:
* 1. For NSSWITCH-discovered users PAM is responsible for authentication.
* We want to run PAM auth without any slapi-nis lock taken to avoid
diff --git a/src/back-shr.c b/src/back-shr.c
index 36ecc0b..131365d 100644
--- a/src/back-shr.c
+++ b/src/back-shr.c
@@ -725,6 +725,8 @@ done_with_lock:
if (cbdata) {
slapi_ch_free((void**)&cbdata);
}
+
+ PR_AtomicSet(&state->ready_to_serve, 1);
}
static void
@@ -769,6 +771,7 @@ backend_shr_startup(struct plugin_state *state,
return;
}
+ PR_AtomicSet(&state->ready_to_serve, 0);
cbdata->state = state;
cbdata->parent_pb = parent_pb;
cbdata->filter = filter;
@@ -1798,6 +1801,11 @@ backend_shr_add_cb(Slapi_PBlock *pb)
/* The plugin was not actually started. */
return 0;
}
+ if (cbdata.state->ready_to_serve == 0) {
+ /* No data yet, ignore */
+ return 0;
+ }
+
slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &cbdata.e);
slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn);
slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc);
@@ -2208,6 +2216,10 @@ backend_shr_modify_cb(Slapi_PBlock *pb)
/* The plugin was not actually started. */
return 0;
}
+ if (cbdata.state->ready_to_serve == 0) {
+ /* No data yet, ignore */
+ return 0;
+ }
slapi_pblock_get(pb, SLAPI_MODIFY_TARGET, &dn);
slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &cbdata.mods);
slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &cbdata.e_pre);
@@ -2410,6 +2422,10 @@ backend_shr_modrdn_cb(Slapi_PBlock *pb)
/* The plugin was not actually started. */
return 0;
}
+ if (cbdata.state->ready_to_serve == 0) {
+ /* No data yet, ignore */
+ return 0;
+ }
slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &cbdata.e_pre);
slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &cbdata.e_post);
@@ -2549,6 +2565,10 @@ backend_shr_delete_cb(Slapi_PBlock *pb)
/* The plugin was not actually started. */
return 0;
}
+ if (cbdata.state->ready_to_serve == 0) {
+ /* No data yet, ignore */
+ return 0;
+ }
slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &cbdata.e);
slapi_pblock_get(pb, SLAPI_DELETE_TARGET, &dn);
slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc);
diff --git a/src/plugin.h b/src/plugin.h
index 429e291..7a89ac7 100644
--- a/src/plugin.h
+++ b/src/plugin.h
@@ -33,6 +33,7 @@ struct plugin_state {
Slapi_ComponentId *plugin_identity;
Slapi_PluginDesc *plugin_desc;
unsigned int use_be_txns: 1;
+ PRInt32 ready_to_serve;
/* NIS-specific data. */
struct wrapped_thread *tid;
commit d1b87904462e890a855ac9d3b68ed02e089450d8
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date: Wed Dec 23 15:04:40 2015 +0200
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.
diff --git a/doc/ipa/sch-ipa.txt b/doc/ipa/sch-ipa.txt
index 106e6cc..eb6238a 100644
--- a/doc/ipa/sch-ipa.txt
+++ b/doc/ipa/sch-ipa.txt
@@ -81,6 +81,21 @@ and groups from trusted domains. No additional configuration is needed.
ipa-adtrust-install, however, will not set the minimal numeric id for user or
group.
+Additionally, group area configuration should include following two attributes to
+allow resolving external members of IPA groups:
+
+schema-compat-entry-attribute: ipaexternalmember=%deref_r("member","ipaexternalmember")
+schema-compat-entry-attribute: objectclass=ipaexternalgroup
+
+When 'ipaExternalMember' attribute is present in the group entry generated by
+Schema Compatibility plugin, the plugin will attempt to retrieve the group
+members from SSSD daemon. If group has non-empty list of members, these new
+members will replace the original ones as they will include both IPA and external
+group members.
+
+SSSD greater than 1.13.3 is required to produce correct behavior due to bug
+https://fedorahosted.org/sssd/ticket/2522
+
== Authentication of the trusted domains' users ==
When the Schema Compatibility Plugin is configured to expose users from trusted
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);
commit 52beb5e79905712a8aaabf19e52e654fc4648a94
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date: Fri Jan 15 16:16:00 2016 +0200
nss: force lower case for memberUid attribute as per RFC2307
When memberUid attribute is generated, it has to be normalized or
otherwise searches for members against groups in compat tree will fail.
slapi-nis already normalizes elements of a search filter that mention
memberUid attribute values but the original memberUid value should be
normalized as well.
diff --git a/src/back-sch-nss.c b/src/back-sch-nss.c
index 16d4164..702590c 100644
--- a/src/back-sch-nss.c
+++ b/src/back-sch-nss.c
@@ -246,8 +246,8 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
return NULL;
}
- dn = backend_build_dn("uid", pwd->pw_name, container_sdn);
- if (dn == NULL) {
+ name = (char *) slapi_utf8StrToLower((unsigned char *) pwd->pw_name);
+ if (name == NULL) {
slapi_log_error(SLAPI_LOG_FATAL,
cbdata->state->plugin_desc->spd_id,
"error building DN for uid=%s,%s skipping\n",
@@ -256,12 +256,22 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
return NULL;
}
+ dn = backend_build_dn("uid", name, container_sdn);
+ if (dn == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL,
+ cbdata->state->plugin_desc->spd_id,
+ "error building DN for uid=%s,%s skipping\n",
+ name, container_sdn);
+ slapi_entry_free(entry);
+ return NULL;
+ }
+
slapi_entry_add_string(entry,
"objectClass", "top");
slapi_entry_add_string(entry,
"objectClass", "posixAccount");
slapi_entry_add_string(entry,
- "uid", pwd->pw_name);
+ "uid", name);
slapi_entry_attr_set_uint(entry,
"uidNumber", pwd->pw_uid);
slapi_entry_attr_set_uint(entry,
@@ -286,6 +296,7 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
}
slapi_entry_set_dn(entry, dn);
+ slapi_ch_free_string(&name);
#ifdef HAVE_SSS_NSS_IDMAP
rc = sss_nss_getsidbyid(pwd->pw_uid, &sid_str, &id_type);
@@ -520,6 +531,7 @@ backend_make_group_entry_from_nsswitch_group(struct group *grp,
Slapi_Entry *entry;
int rc, i;
char *dn = NULL;
+ char *name = NULL;
#ifdef HAVE_SSS_NSS_IDMAP
enum sss_id_type id_type;
char *sid_str;
@@ -551,7 +563,9 @@ backend_make_group_entry_from_nsswitch_group(struct group *grp,
if (grp->gr_mem) {
for (i=0; grp->gr_mem[i]; i++) {
- slapi_entry_add_string(entry, "memberUid", grp->gr_mem[i]);
+ name = (char *) slapi_utf8StrToLower((unsigned char*) grp->gr_mem[i]);
+ slapi_entry_add_string(entry, "memberUid", name);
+ slapi_ch_free_string(&name);
}
}
commit 2df48b57adb666112cab22e62750dd984fc7450a
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date: Wed Dec 23 14:57:03 2015 +0200
slapi-nis: populate data trees asynchronously after LDAP server startup
Currently slapi-nis design assumes the map cache is populated by
scanning the original trees on plugin start up. This has few
consequences:
- LDAP server cannot serve LDAP clients until all plugins are
initialized
- slapi-nis cannot ask SSSD to resolve external identities at
this point as SSSD will need to talk to the LDAP server which
is at this point not listening for connections. SSSD will put
whole IPA domain into offline and always will respond
with negative result
To solve these issues, schedule tree scan after LDAP server startup.
The problem here is that it is not possible to reliably detect when
389-ds starts to listen to the incoming connections. However, it is
possible to schedule an event into 389-ds event queue that will run
shortly after start of the event loop. Given that the call back function
which is registered to be called is called within the event loop thread,
one can fire off another thread and wait in the thread function some
time until the LDAP server is ready for connections.
The time interval is something that would depend on a specific
deployment profile but experiments show that having 5 seconds delay
should be enough as event queue is created just before starting the
listeners.
diff --git a/src/back-shr.c b/src/back-shr.c
index c68640a..36ecc0b 100644
--- a/src/back-shr.c
+++ b/src/back-shr.c
@@ -664,40 +664,56 @@ backend_shr_get_vattr_sdnlist(struct plugin_state *state,
return ret;
}
-/* Scan for the list of configured groups and sets. */
-void
-backend_shr_startup(struct plugin_state *state,
- Slapi_PBlock *parent_pb,
- const char *filter)
+struct backend_shr_data_init_cbdata {
+ Slapi_PBlock *parent_pb;
+ struct plugin_state *state;
+ const char *filter;
+};
+
+#define PLUGIN_SCAN_DELAY 5
+
+static void
+backend_shr_data_initialize_thread_cb(void *arg)
{
- Slapi_PBlock *pb;
+ struct backend_shr_data_init_cbdata *cbdata = (struct backend_shr_data_init_cbdata *)arg;
+ Slapi_PBlock *pb = NULL;
struct backend_set_config_entry_add_cbdata set_cbdata;
+ int result = 0;
+ if (cbdata == NULL) {
+ return;
+ }
+
+ /* Scan may require consulting SSSD for external identities
+ * therefore, we need to make sure the scan starts after ns-slapd
+ * started to serve LDAP clients. There is no a signal for this,
+ * so we just wait some time. */
+ DS_Sleep(PR_SecondsToInterval(PLUGIN_SCAN_DELAY));
- backend_update_params(parent_pb, state);
+ backend_update_params(cbdata->parent_pb, cbdata->state);
slapi_log_error(SLAPI_LOG_PLUGIN,
- state->plugin_desc->spd_id,
+ cbdata->state->plugin_desc->spd_id,
"searching under \"%s\" for configuration\n",
- state->plugin_base);
- pb = wrap_pblock_new(parent_pb);
+ cbdata->state->plugin_base);
+ pb = wrap_pblock_new(cbdata->parent_pb);
slapi_search_internal_set_pb(pb,
- state->plugin_base,
+ cbdata->state->plugin_base,
LDAP_SCOPE_ONELEVEL,
- filter,
+ cbdata->filter,
NULL, FALSE,
NULL,
NULL,
- state->plugin_identity,
+ cbdata->state->plugin_identity,
0);
if (map_wrlock() != 0) {
slapi_log_error(SLAPI_LOG_PLUGIN,
- state->plugin_desc->spd_id,
+ cbdata->state->plugin_desc->spd_id,
"failed to search under \"%s\" for "
"configuration: failed to acquire a lock\n",
- state->plugin_base);
+ cbdata->state->plugin_base);
goto done_with_lock;
}
- set_cbdata.state = state;
+ set_cbdata.state = cbdata->state;
set_cbdata.pb = pb;
slapi_search_internal_callback_pb(pb, &set_cbdata,
NULL,
@@ -706,6 +722,68 @@ backend_shr_startup(struct plugin_state *state,
map_unlock();
done_with_lock:
slapi_pblock_destroy(pb);
+ if (cbdata) {
+ slapi_ch_free((void**)&cbdata);
+ }
+}
+
+static void
+backend_shr_data_initialize_thread(time_t when, void *arg)
+{
+ struct backend_shr_data_init_cbdata *cbdata = (struct backend_shr_data_init_cbdata *)arg;
+ PRThread *thread = NULL;
+
+ /* start data import as a separate thread */
+ thread = PR_CreateThread(PR_USER_THREAD, backend_shr_data_initialize_thread_cb,
+ (void *)arg, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if (thread == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL,
+ cbdata->state->plugin_desc->spd_id,
+ "unable to create compatibility tree scan thread!\n");
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL,
+ cbdata->state->plugin_desc->spd_id,
+ "%s tree scan will start in about %d seconds!\n",
+ cbdata->state->plugin_desc->spd_id, PLUGIN_SCAN_DELAY);
+ }
+
+}
+
+/* Scan for the list of configured groups and sets. */
+void
+backend_shr_startup(struct plugin_state *state,
+ Slapi_PBlock *parent_pb,
+ const char *filter)
+{
+ struct backend_shr_data_init_cbdata *cbdata = NULL;
+
+ cbdata = (struct backend_shr_data_init_cbdata *)
+ slapi_ch_malloc(sizeof(struct backend_shr_data_init_cbdata));
+
+ if (cbdata == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL,
+ state->plugin_desc->spd_id,
+ "failed to create a task for populating "
+ "compatibility tree\n");
+ return;
+ }
+
+ cbdata->state = state;
+ cbdata->parent_pb = parent_pb;
+ cbdata->filter = filter;
+
+ /* Schedule running a callback that will create a thread */
+ slapi_eq_once(backend_shr_data_initialize_thread,
+ cbdata, PR_SecondsToInterval(PLUGIN_SCAN_DELAY));
+
+ slapi_log_error(SLAPI_LOG_FATAL,
+ cbdata->state->plugin_desc->spd_id,
+ "scheduled %s tree scan in about %d seconds after the server startup!\n",
+ state->plugin_desc->spd_id, PLUGIN_SCAN_DELAY);
+
+ return;
+
}
/* Process a set configuration directory entry. Pull out the group and set
diff --git a/src/plug-sch.c b/src/plug-sch.c
index f132e6d..95a4fd8 100644
--- a/src/plug-sch.c
+++ b/src/plug-sch.c
@@ -109,8 +109,6 @@ plugin_startup(Slapi_PBlock *pb)
state->plugin_base ? "\"" : "",
state->plugin_base ? state->plugin_base : "NULL",
state->plugin_base ? "\"" : "");
- /* Populate the tree of fake entries. */
- backend_startup(pb, state);
state->pam_lock = wrap_new_rwlock();
backend_nss_init_context((struct nss_ops_ctx**) &state->nss_context);
if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
@@ -123,6 +121,8 @@ plugin_startup(Slapi_PBlock *pb)
wrap_rwlock_wrlock(state->cached_entries_lock);
state->cached_entries = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareValues, 0, 0);
wrap_rwlock_unlock(state->cached_entries_lock);
+ /* Populate the tree of fake entries. */
+ backend_startup(pb, state);
/* Note that the plugin is ready to go. */
slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
"plugin startup completed\n");
commit da26d9595e6449009575e8d2a4c888176829a97f
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date: Tue Nov 3 14:42:05 2015 +0200
slapi-nis: fix processing of ID views
- ID View processing should only happen if ID view is defined
- When finding attribute with slapi_entry_attr_find() use correct return
code (slapi_entry_attr_exists() returns 1, _find() returns 0)
- cn=<view>,cn=views,cn=compat,$SUFFIX lookup is fixed
Resolves: rhbz#1277576, rhbz#1265465
https://bugzilla.redhat.com/show_bug.cgi?id=1277576
https://bugzilla.redhat.com/show_bug.cgi?id=1265465
diff --git a/src/back-sch-idview.c b/src/back-sch-idview.c
index 93fbab5..8ffab91 100644
--- a/src/back-sch-idview.c
+++ b/src/back-sch-idview.c
@@ -175,7 +175,7 @@ idview_process_overrides(struct backend_search_cbdata *cbdata,
/* Replace the attribute's value with the override or
* add an override value if the attribute didn't exist */
result = slapi_entry_attr_find(entry, override_type, &sattr);
- if (result == 1) {
+ if (result == 0) {
result = slapi_entry_attr_delete(entry, override_type);
}
result = slapi_attr_get_valueset(override_attr, &override_valueset);
diff --git a/src/back-sch.c b/src/back-sch.c
index b2362d0..98542c5 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1043,17 +1043,21 @@ backend_search_entry_cb(const char *domain, const char *map, bool_t secure,
slapi_sdn_get_ndn(sdn));
entry = entry_data->e;
#ifdef USE_IPA_IDVIEWS
- entry = slapi_entry_dup(entry_data->e);
if (cbdata->idview != NULL) {
- idview_process_overrides(cbdata, key, map, domain, entry);
- }
+ entry = slapi_entry_dup(entry_data->e);
More information about the Pkg-freeipa-devel
mailing list