summaryrefslogtreecommitdiffstats
path: root/src/back-sch.c
diff options
context:
space:
mode:
authorAlexander Bokovoy <abokovoy@redhat.com>2013-07-23 21:08:56 +0300
committerAlexander Bokovoy <abokovoy@redhat.com>2013-07-26 16:10:05 +0300
commitd862fc6fc65f1fb5ff0582e3561a7ab988af9432 (patch)
treea175494a22ae321ea89c410afb53d79d14d9f375 /src/back-sch.c
parent633c4c92b73efeb3d660b70480108b0db41fa3bd (diff)
downloadslapi-nis-freeipa-nss-compat.tar.gz
slapi-nis-freeipa-nss-compat.tar.xz
slapi-nis-freeipa-nss-compat.zip
WIP compat plugin: solve deadlock when looking up SSSD usersfreeipa-nss-compat
Diffstat (limited to 'src/back-sch.c')
-rw-r--r--src/back-sch.c341
1 files changed, 192 insertions, 149 deletions
diff --git a/src/back-sch.c b/src/back-sch.c
index a235998..c2b7d41 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -85,18 +85,9 @@ backend_set_config_free_config_contents(void *data)
format_free_ref_attr_list(set_data->common.ref_attr_list);
format_free_ref_attr_list(set_data->common.inref_attr_list);
free(set_data->common.entry_filter);
- if (set_data->check_sssd != SCH_SSSD_NONE) {
- /* Remove association to another set (groups/users) */
- if ((set_data->sssd_relevant_set != NULL) &&
- (set_data->sssd_relevant_set->sssd_relevant_set == set_data)) {
- set_data->sssd_relevant_set->sssd_relevant_set = NULL;
- set_data->sssd_relevant_set = NULL;
- }
- }
slapi_sdn_free(&set_data->container_sdn);
free(set_data->rdn_format);
backend_shr_free_strlist(set_data->attribute_format);
- free(set_data->sssd_buffer);
}
}
void
@@ -144,9 +135,6 @@ backend_copy_set_config(const struct backend_set_data *data)
ret->check_access = data->check_access;
ret->check_sssd = data->check_sssd;
ret->sssd_min_id = data->sssd_min_id;
- ret->sssd_buffer = data->sssd_buffer;
- ret->sssd_buffer_len = data->sssd_buffer_len;
- ret->sssd_relevant_set = data->sssd_relevant_set;
if ((ret->common.group == NULL) ||
(ret->common.set == NULL) ||
@@ -231,7 +219,6 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e,
} else {
ret.check_sssd = SCH_SSSD_NONE;
}
- ret.sssd_buffer = NULL;
/* Make sure we don't return system users/groups
* by limiting lower bound on searches */
@@ -251,19 +238,8 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e,
backend_shr_add_strlist(&ret.attribute_format, "objectClass=extensibleObject");
backend_shr_add_strlist(&ret.attribute_format, "schema-compat-origin=%{schema-compat-origin}");
backend_shr_add_strlist(&ret.attribute_format, "ipaNTSecurityIdentifier=%{ipaNTSecurityIdentifier}");
-
- /* Allocate buffer to be used for getpwnam_r/getgrnam_r requests */
- if (ret.check_sssd == SCH_SSSD_USER) {
- ret.sssd_buffer_len = sysconf(_SC_GETPW_R_SIZE_MAX);
- } else {
- ret.sssd_buffer_len = sysconf(_SC_GETGR_R_SIZE_MAX);
- }
- if ((long) ret.sssd_buffer_len == -1 )
- ret.sssd_buffer_len = 16384;
- ret.sssd_buffer = malloc(ret.sssd_buffer_len);
}
- ret.sssd_relevant_set = NULL;
*pret = backend_copy_set_config(&ret);
free(ret.common.group);
free(ret.common.set);
@@ -1082,6 +1058,10 @@ backend_search_set_cb(const char *group, const char *set, bool_t flag,
if (slapi_sdn_compare(set_data->container_sdn,
cbdata->target_dn) == 0) {
cbdata->matched = TRUE;
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ cbdata->state->plugin_desc->spd_id,
+ "search set actual match: %d, check_sssd=%d\n",
+ cbdata->matched, cbdata->check_sssd);
}
/* Walk the set of entries in this set if they're in scope. */
@@ -1090,16 +1070,15 @@ 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 HAVE_SSS_NSS_IDMAP
- /* If we didn't find an exact match for the entry but asked to look up SSSD,
- * then try to search SSSD and if successful, return that entry */
- if ((n_entries_sssd == cbdata->n_entries) &&
- (cbdata->check_sssd != SCH_SSSD_NONE)) {
- backend_search_sssd(set_data, cbdata);
- }
+ /* If we didn't find an exact match for the entry but asked to look up SSSD,
+ * then try to search SSSD and if successful, return that entry */
+ if ((n_entries_sssd == cbdata->n_entries) &&
+ (cbdata->check_sssd != SCH_SSSD_NONE)) {
+ backend_search_sssd(set_data, cbdata);
+ }
#endif
+ }
/* If we didn't find an exact match for the entry, then store this
* container's DN as the closest match. */
@@ -1114,6 +1093,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;
@@ -1216,6 +1225,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;
}
@@ -1240,6 +1252,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",
@@ -1261,14 +1275,66 @@ backend_search_cb(Slapi_PBlock *pb)
map_data_foreach_domain(cbdata.state, backend_search_group_cb, &cbdata);
map_unlock();
wrap_dec_call_level();
+#ifdef HAVE_SSS_NSS_IDMAP
+ /* Search caused some data to be staged for addition */
+ if (cbdata.staged != NULL) {
+ /* Allocate buffer to be used for getpwnam_r/getgrnam_r requests */
+ cbdata.sssd_buffer_len = MAX(sysconf(_SC_GETPW_R_SIZE_MAX), sysconf(_SC_GETGR_R_SIZE_MAX));
+ if ((long) cbdata.sssd_buffer_len == -1)
+ cbdata.sssd_buffer_len = 16384;
+ cbdata.sssd_buffer = malloc(cbdata.sssd_buffer_len);
+ staged = cbdata.staged;
+ while (staged) {
+ if (staged->entries == NULL) {
+ backend_retrieve_from_sssd(staged, &cbdata);
+ }
+ next = staged->next;
+ staged = next;
+ }
+ staged = cbdata.staged;
+ wrap_inc_call_level();
+ map_wrlock();
+ while (staged) {
+ if (staged->entries) {
+ cbdata.cur_staged = staged;
+ 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) &&
+ !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]);
+ }
+ }
+ }
+ free(staged->entries);
+ staged->count = 0;
+ staged->entries = NULL;
+ }
+ free(staged->map_group);
+ free(staged->map_set);
+ free(staged->name);
+ free(staged->container_sdn);
+ next = staged->next;
+ free(staged);
+ staged = next;
+ }
+ cbdata.staged = NULL;
+ map_unlock();
+ cbdata.sssd_buffer_len = 0;
+ free(cbdata.sssd_buffer);
+ /* Perform search again, this time to send out staged data */
+ 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;
@@ -1294,6 +1360,12 @@ backend_search_cb(Slapi_PBlock *pb)
send_ldap_result(cbdata.pb, cbdata.result,
cbdata.closest_match, cbdata.text,
cbdata.n_entries, NULL);
+ 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_sdn_free(&cbdata.target_dn);
free(cbdata.closest_match);
@@ -1448,6 +1520,61 @@ backend_betxn_pre_write_cb(Slapi_PBlock *pb)
return state->use_be_txns ? backend_write_cb(pb) : 0;
}
+#ifdef HAVE_SSS_NSS_IDMAP
+static int
+backend_bind_cb_pam(Slapi_PBlock *pb, const char *username, char *ndn)
+{
+ int ret = 0;
+ LDAPControl **reqctrls = NULL;
+ struct plugin_state *state;
+ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
+
+ /* PAM API is thread-unsafe, we need to lock exclusively */
+ wrap_rwlock_wrlock(state->pam_lock);
+ ret = backend_sch_do_pam_auth(pb, username);
+ wrap_rwlock_unlock(state->pam_lock);
+
+ if (ret != 0) {
+ slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS,
+ NULL, NULL, 0, NULL);
+ ret = -1;
+ free(ndn);
+ } else {
+ /*
+ * If bind succeeded, change authentication information associated
+ * with this connection.
+ */
+ if (ret == LDAP_SUCCESS) {
+ if ((slapi_pblock_set(pb, SLAPI_CONN_DN, (void*) ndn) != 0) ||
+ (slapi_pblock_set(pb, SLAPI_CONN_AUTHMETHOD, SLAPD_AUTH_SIMPLE) != 0)) {
+ ret = LDAP_OPERATIONS_ERROR;
+ } else {
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &reqctrls);
+ if (slapi_control_present(reqctrls, LDAP_CONTROL_AUTH_REQUEST, NULL, NULL)) {
+ slapi_add_auth_response_control(pb, ndn);
+ }
+ }
+ }
+
+ if (ret == LDAP_SUCCESS) {
+ /* we are handling the result */
+ slapi_send_ldap_result(pb, ret, NULL, NULL, 0, NULL);
+ /* tell bind code we handled the result */
+ ret = 0;
+ }
+ }
+ return ret;
+}
+#else
+static int
+backend_bind_cb_pam(Slapi_PBlock *pb, const char *username, char *ndn)
+{
+ slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL);
+ free(ndn);
+ return -1;
+}
+#endif
+
static int
backend_bind_cb(Slapi_PBlock *pb)
{
@@ -1457,6 +1584,7 @@ backend_bind_cb(Slapi_PBlock *pb)
struct berval *urls[] = {&ref, NULL};
const char *ndn;
char *is_sssd_origin = NULL;
+ char *username = NULL;
if (wrap_get_call_level() > 0) {
return 0;
@@ -1466,61 +1594,41 @@ backend_bind_cb(Slapi_PBlock *pb)
map_rdlock();
backend_locate(pb, &data);
if (data != NULL) {
-#ifdef HAVE_SSS_NSS_IDMAP
is_sssd_origin = slapi_entry_attr_get_charptr(data->e, "schema-compat-origin");
+ ndn = slapi_ch_strdup(slapi_sdn_get_ndn(data->original_entry_dn));
+ username = slapi_entry_attr_get_charptr(data->e, "uid");
+ map_unlock();
+ wrap_dec_call_level();
+
+ /* If user comes from SSSD, it will get authentication handled by PAM. */
if ((is_sssd_origin != NULL) &&
(strcasecmp(is_sssd_origin, "sssd") == 0)) {
- ret = backend_sch_do_pam_auth(pb, data->e);
- if (ret != 0) {
- slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS,
- NULL, NULL, 0, NULL);
- ret = -1;
- } else {
- /*
- * If bind succeeded, change authentication information associated
- * with this connection.
- */
- if (ret == LDAP_SUCCESS) {
- ndn = slapi_ch_strdup(slapi_sdn_get_ndn(data->original_entry_dn));
- if ((slapi_pblock_set(pb, SLAPI_CONN_DN, (void*)ndn) != 0) ||
- (slapi_pblock_set(pb, SLAPI_CONN_AUTHMETHOD, SLAPD_AUTH_SIMPLE) != 0)) {
- ret = LDAP_OPERATIONS_ERROR;
- } else {
- LDAPControl **reqctrls = NULL;
- slapi_pblock_get(pb, SLAPI_REQCONTROLS, &reqctrls);
- if (slapi_control_present(reqctrls, LDAP_CONTROL_AUTH_REQUEST, NULL, NULL)) {
- slapi_add_auth_response_control(pb, ndn);
- }
- }
- }
-
- if (ret == LDAP_SUCCESS) {
- /* we are handling the result */
- slapi_send_ldap_result(pb, ret, NULL, NULL, 0, NULL);
- /* tell bind code we handled the result */
- ret = 0;
- }
- }
+ /* backend_bind_cb_pam() takes over ndn */
+ ret = backend_bind_cb_pam(pb, username, ndn);
} else {
-#endif
- ndn = slapi_sdn_get_ndn(data->original_entry_dn);
- ref.bv_len = strlen("ldap:///") + strlen(ndn);
- ref.bv_val = malloc(ref.bv_len + 1);
- if (ref.bv_val != NULL) {
- sprintf(ref.bv_val, "ldap:///%s", ndn);
- slapi_send_ldap_result(pb, LDAP_REFERRAL,
- NULL, NULL, 0, urls);
- free(ref.bv_val);
+ if (username != NULL) {
+ ret = backend_bind_cb_pam(pb, username, ndn);
} else {
- slapi_send_ldap_result(pb, LDAP_BUSY,
- NULL, NULL, 0, NULL);
+ ref.bv_len = strlen("ldap:///") + strlen(ndn);
+ ref.bv_val = malloc(ref.bv_len + 1);
+ if (ref.bv_val != NULL) {
+ sprintf(ref.bv_val, "ldap:///%s", ndn);
+ slapi_send_ldap_result(pb, LDAP_REFERRAL,
+ NULL, NULL, 0, urls);
+ free(ref.bv_val);
+ } else {
+ slapi_send_ldap_result(pb, LDAP_BUSY,
+ NULL, NULL, 0, NULL);
+ }
+ ret = -1;
+ free(ndn);
}
-#ifdef HAVE_SSS_NSS_IDMAP
}
+ free(username);
free(is_sssd_origin);
-#endif
- ret = -1;
} else {
+ map_unlock();
+ wrap_dec_call_level();
if (backend_check_scope_pb(pb)) {
slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS,
NULL, NULL, 0, NULL);
@@ -1529,8 +1637,6 @@ backend_bind_cb(Slapi_PBlock *pb)
ret = 0;
}
}
- map_unlock();
- wrap_dec_call_level();
return ret;
}
@@ -1577,74 +1683,11 @@ backend_check_empty(struct plugin_state *state,
}
}
-struct backend_start_fixup_cbdata {
- Slapi_PBlock *pb;
- struct plugin_state *state;
- struct backend_set_data *groups;
- struct backend_set_data *users;
-};
-
-static bool_t
-backend_start_fixup_sssd_cb(const char *group, const char *set, bool_t flag,
- void *backend_data, void *cb_data)
-{
- struct backend_start_fixup_cbdata *cbdata;
- struct backend_set_data *set_data;
-
- cbdata = cb_data;
- set_data = backend_data;
-
- switch (set_data->check_sssd) {
- case SCH_SSSD_NONE:
- break;
- case SCH_SSSD_USER:
- cbdata->groups = set_data;
- break;
- case SCH_SSSD_GROUP:
- cbdata->users = set_data;
- break;
- default:
- break;
- }
-
- return TRUE;
-}
-
-static bool_t
-backend_start_fixup_cb(const char *group, void *cb_data)
-{
- struct backend_start_fixup_cbdata *cbdata;
- cbdata = cb_data;
- map_data_foreach_map(cbdata->state, group,
- backend_start_fixup_sssd_cb, cbdata);
- if ((cbdata->groups != NULL) &&
- (cbdata->users != NULL)) {
- cbdata->groups->sssd_relevant_set = cbdata->users;
- cbdata->users->sssd_relevant_set = cbdata->groups;
- }
- return TRUE;
-}
-
/* Populate our data cache. */
void
backend_startup(Slapi_PBlock *pb, struct plugin_state *state)
{
- struct backend_start_fixup_cbdata cbdata;
backend_shr_startup(state, pb, SCH_CONTAINER_CONFIGURATION_FILTER);
- /* Walk the list of groups and perform fixups for the cases where
- * some sets depend on others. Right now following fixups are done:
- * -- SSSD searches for the group tree should know user tree DN to
- * produce proper membership
- */
- cbdata.state = state;
- cbdata.pb = pb;
- cbdata.groups = NULL;
- cbdata.users = NULL;
- wrap_inc_call_level();
- map_rdlock();
- map_data_foreach_domain(state, backend_start_fixup_cb, &cbdata);
- map_unlock();
- wrap_dec_call_level();
}
int