summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Bokovoy <abokovoy@redhat.com>2013-07-31 14:38:37 +0300
committerAlexander Bokovoy <abokovoy@redhat.com>2013-08-06 14:24:42 +0300
commitb4baf59e2d9c4775485c483d3b7b779d4e426ec8 (patch)
treef08090393f1061b79ad1bca4710f9616b488293c
parent101b120efa6cd82be7ed0b4e65c7c428c958bad0 (diff)
downloadslapi-nis-b4baf59e2d9c4775485c483d3b7b779d4e426ec8.tar.gz
slapi-nis-b4baf59e2d9c4775485c483d3b7b779d4e426ec8.tar.xz
slapi-nis-b4baf59e2d9c4775485c483d3b7b779d4e426ec8.zip
back-sch.c: search users and groups through NSSWITCH
Schema-compat plugin can be configured to serve users and groups through the plugin configuration entry in directory server: schema-compat-lookup-nsswitch: <user|group> schema-compat-nsswitch-min-id: <value> Separate trees should be configured to look up users and groups. If minimal id value is missing, it will default to 1000.
-rw-r--r--src/back-sch.c130
1 files changed, 124 insertions, 6 deletions
diff --git a/src/back-sch.c b/src/back-sch.c
index 8911568..2bdf631 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1004,11 +1004,17 @@ backend_search_set_cb(const char *group, const char *set, bool_t flag,
struct backend_set_data *set_data;
Slapi_Entry *set_entry;
int result, n_entries;
+ int n_entries_nsswitch;
const char *ndn;
cbdata = cb_data;
set_data = backend_data;
cbdata->check_access = set_data->check_access;
+ cbdata->check_nsswitch = set_data->check_nsswitch;
+ cbdata->nsswitch_min_id = set_data->nsswitch_min_id;
+ /* If any entries were actually returned by the descending callback,
+ * avoid to look up in nsswitch even if this set is marked to look up */
+ n_entries_nsswitch = cbdata->n_entries;
/* Check the set itself, unless it's also the group, in which case we
* already evaluated it for this search. */
@@ -1063,6 +1069,19 @@ backend_search_set_cb(const char *group, const char *set, bool_t flag,
cbdata->scope)) {
map_data_foreach_entry_id(cbdata->state, group, set, NULL,
backend_search_entry_cb, cbdata);
+#ifdef USE_NSSWITCH
+ /* If we didn't find an exact match for the entry but asked to look up NSSWITCH,
+ * then try to search NSSWITCH. If search filters would match, the search will be
+ * staged for retrieval. The retrieval process is run after lookup is completed
+ * for all maps as we need to ensure there is no contention for the global
+ * map cache lock. The contention might occur if NSSWITCH would need to re-kinit
+ * its kerberos credentials -- this would cause changes in the original LDAP tree
+ * which, in turn, will trigger modification of the map cache entries. */
+ if ((n_entries_nsswitch == cbdata->n_entries) &&
+ (cbdata->check_nsswitch != SCH_NSSWITCH_NONE)) {
+ backend_search_nsswitch(set_data, cbdata);
+ }
+#endif
}
/* If we didn't find an exact match for the entry, then store this
@@ -1078,6 +1097,36 @@ backend_search_set_cb(const char *group, const char *set, bool_t flag,
}
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)
+{
+ struct backend_search_cbdata *cbdata;
+ struct backend_set_data *set_data;
+
+ cbdata = cb_data;
+ set_data = backend_data;
+
+ if ((0 == strcmp(group, cbdata->cur_staged->map_group)) &&
+ (0 == strcmp(set, cbdata->cur_staged->map_set))) {
+ cbdata->cur_staged->set_data_fixup = set_data;
+ }
+
+ return TRUE;
+
+}
+
+static bool_t
+backend_search_find_set_data_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_data_in_group_cb, cbdata);
+ return TRUE;
+}
+
+static bool_t
backend_search_group_cb(const char *group, void *cb_data)
{
struct backend_search_cbdata *cbdata;
@@ -1180,6 +1229,9 @@ static int
backend_search_cb(Slapi_PBlock *pb)
{
struct backend_search_cbdata cbdata;
+ struct backend_staged_data *staged, *next;
+ int i;
+
if (wrap_get_call_level() > 0) {
return 0;
}
@@ -1204,6 +1256,8 @@ backend_search_cb(Slapi_PBlock *pb)
cbdata.closest_match = NULL;
cbdata.text = NULL;
cbdata.n_entries = 0;
+ cbdata.staged = NULL;
+ cbdata.cur_staged = NULL;
/* Okay, we can search. */
slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id,
"searching from \"%s\" for \"%s\" with scope %d%s\n",
@@ -1225,14 +1279,72 @@ backend_search_cb(Slapi_PBlock *pb)
map_data_foreach_domain(cbdata.state, backend_search_group_cb, &cbdata);
map_unlock();
wrap_dec_call_level();
+#ifdef USE_NSSWITCH
+ /* If during search of some sets we staged additional lookups, perform them. */
+ if (cbdata.staged != NULL) {
+ /* Allocate buffer to be used for getpwnam_r/getgrnam_r requests */
+ cbdata.nsswitch_buffer_len = MAX(sysconf(_SC_GETPW_R_SIZE_MAX), sysconf(_SC_GETGR_R_SIZE_MAX));
+ if (cbdata.nsswitch_buffer_len == -1)
+ cbdata.nsswitch_buffer_len = 16384;
+ cbdata.nsswitch_buffer = malloc(cbdata.nsswitch_buffer_len);
+ /* Go over the list of staged requests and retrieve entries.
+ * It is important to perform the retrieval *without* holding any locks to the map cache */
+ staged = cbdata.staged;
+ while (staged) {
+ if (staged->entries == NULL) {
+ backend_retrieve_from_nsswitch(staged, &cbdata);
+ }
+ next = staged->next;
+ staged = next;
+ }
+ staged = cbdata.staged;
+ /* Add the entries to the map cache */
+ wrap_inc_call_level();
+ map_wrlock();
+ while (staged) {
+ if (staged->entries) {
+ cbdata.cur_staged = staged;
+ /* We actually need to find the original set first */
+ map_data_foreach_domain(cbdata.state, backend_search_find_set_data_cb, &cbdata);
+ if (cbdata.cur_staged->set_data_fixup != NULL) {
+ for (i = 0; i < staged->count ; i++) {
+ if (staged->entries[i] != NULL) {
+ if (!map_data_check_entry(cbdata.state,
+ staged->map_group, staged->map_set,
+ slapi_sdn_get_ndn(staged->entries[i]))) {
+ backend_set_entry(cbdata.pb, staged->entries[i], staged->set_data_fixup);
+ }
+ slapi_entry_free(staged->entries[i]);
+ staged->entries[i] = NULL;
+ }
+ }
+ }
+ free(staged->entries);
+ staged->count = 0;
+ staged->entries = NULL;
+ }
+ slapi_ch_free_string(&staged->map_group);
+ slapi_ch_free_string(&staged->map_set);
+ slapi_ch_free_string(&staged->name);
+ slapi_ch_free_string(&staged->container_sdn);
+ next = staged->next;
+ free(staged);
+ staged = next;
+ }
+ cbdata.staged = NULL;
+ map_unlock();
+ cbdata.nsswitch_buffer_len = 0;
+ free(cbdata.nsswitch_buffer);
+ /* Perform search again, this time to collect the data added by the NSSWITCH search */
+ map_rdlock();
+ map_data_foreach_domain(cbdata.state, backend_search_group_cb, &cbdata);
+ map_unlock();
+ wrap_dec_call_level();
+ }
+#endif
/* If we "own" the search target DN, then we need to send a response. */
if (cbdata.answer) {
- if (cbdata.matched || (cbdata.n_entries > 0)) {
- /* Just in case, free the closest-match that we've
- * recorded. */
- free(cbdata.closest_match);
- cbdata.closest_match = NULL;
- } else {
+ if (!(cbdata.matched || (cbdata.n_entries > 0))) {
/* Return a no-such-object error because the target DN
* was not found. */
cbdata.result = LDAP_NO_SUCH_OBJECT;
@@ -1245,6 +1357,12 @@ backend_search_cb(Slapi_PBlock *pb)
cbdata.closest_match ?
cbdata.closest_match : "(null)",
cbdata.closest_match ? "\"" : "");
+ if (cbdata.matched || (cbdata.n_entries > 0)) {
+ /* Just in case, free the closest-match that we've
+ * recorded. */
+ free(cbdata.closest_match);
+ cbdata.closest_match = NULL;
+ }
slapi_pblock_set(cbdata.pb, SLAPI_PLUGIN_OPRETURN,
&cbdata.result);
/* XXX - THIS IS NOT A PUBLIC FUNCTION, but