diff options
author | Alexander Bokovoy <abokovoy@redhat.com> | 2013-07-23 21:08:56 +0300 |
---|---|---|
committer | Alexander Bokovoy <abokovoy@redhat.com> | 2013-07-26 16:10:05 +0300 |
commit | d862fc6fc65f1fb5ff0582e3561a7ab988af9432 (patch) | |
tree | a175494a22ae321ea89c410afb53d79d14d9f375 /src/back-sch-sssd.c | |
parent | 633c4c92b73efeb3d660b70480108b0db41fa3bd (diff) | |
download | slapi-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-sssd.c')
-rw-r--r-- | src/back-sch-sssd.c | 273 |
1 files changed, 199 insertions, 74 deletions
diff --git a/src/back-sch-sssd.c b/src/back-sch-sssd.c index 8168675..2a02f90 100644 --- a/src/back-sch-sssd.c +++ b/src/back-sch-sssd.c @@ -47,18 +47,21 @@ #include "plugin.h" #include "map.h" #include "back-sch.h" +#include "format.h" struct backend_search_filter_config { bool_t search_user; bool_t search_group; bool_t search_uid; bool_t search_gid; + bool_t search_members; bool_t name_set; + bool_t wrong_search; char *name; }; /* Check simple filter to see if it has - * (cn|uid|uidNumber|gidNumber=<value>) or (objectClass=posixGroup) + * (cn|uid|uidNumber|gidNumber|memberUid=<value>) or (objectClass=posixGroup|shadowAccount) * Called by slapi_filter_apply(). */ static int backend_search_filter_has_cn_uid(Slapi_Filter *filter, void *arg) @@ -82,13 +85,19 @@ backend_search_filter_has_cn_uid(Slapi_Filter *filter, void *arg) config->name_set = TRUE; } else if (0 == strcasecmp(filter_type, "cn")) { config->name_set = TRUE; + } else if (0 == strcasecmp(filter_type, "memberUid")) { + config->name_set = TRUE; + config->search_members = TRUE; } else if ((0 == strcasecmp(filter_type, "objectClass")) && (0 == strcasecmp(bval->bv_val, "posixGroup"))) { config->search_group = TRUE; + } else if ((0 == strcasecmp(filter_type, "objectClass")) && + (0 == strcasecmp(bval->bv_val, "shadowAccount"))) { + config->wrong_search = TRUE; } if ((NULL == config->name) && config->name_set) { - config->name = bval->bv_val; + config->name = format_strdupbv(bval); } } @@ -103,27 +112,27 @@ backend_search_filter_has_cn_uid(Slapi_Filter *filter, void *arg) static Slapi_Entry * backend_retrieve_user_entry_from_sssd(char *user_name, bool_t is_uid, - struct backend_set_data *set_data, - struct backend_search_cbdata *cbdata) + char *container_sdn, + struct backend_search_cbdata *cbdata) { struct passwd pwd, *result; Slapi_Entry *entry; int rc; enum sss_id_type id_type; - char *sid_str; + char *sid_str, *dn; - if (set_data->sssd_buffer == NULL) { + if (cbdata->sssd_buffer == NULL) { return NULL; } if (is_uid) { rc = getpwuid_r(atoi(user_name), &pwd, - set_data->sssd_buffer, - set_data->sssd_buffer_len, &result); + cbdata->sssd_buffer, + cbdata->sssd_buffer_len, &result); } else { rc = getpwnam_r(user_name, &pwd, - set_data->sssd_buffer, - set_data->sssd_buffer_len, &result); + cbdata->sssd_buffer, + cbdata->sssd_buffer_len, &result); } if ((result == NULL) || (rc != 0)) { return NULL; @@ -138,6 +147,14 @@ backend_retrieve_user_entry_from_sssd(char *user_name, bool_t is_uid, return NULL; } + dn = slapi_ch_smprintf("uid=%s,%s", + slapi_escape_filter_value(pwd.pw_name, -1), + container_sdn); + if (dn == NULL) { + slapi_entry_free(entry); + return NULL; + } + slapi_entry_add_string(entry, "objectClass", "top"); slapi_entry_add_string(entry, @@ -145,7 +162,7 @@ backend_retrieve_user_entry_from_sssd(char *user_name, bool_t is_uid, slapi_entry_add_string(entry, "objectClass", "extensibleObject"); slapi_entry_add_string(entry, - "uid", user_name); + "uid", pwd.pw_name); slapi_entry_attr_set_int(entry, "uidNumber", pwd.pw_uid); slapi_entry_attr_set_int(entry, @@ -157,16 +174,15 @@ backend_retrieve_user_entry_from_sssd(char *user_name, bool_t is_uid, "cn", pwd.pw_gecos); } else { slapi_entry_add_string(entry, - "cn", user_name); + "cn", pwd.pw_name); } slapi_entry_add_string(entry, "homeDirectory", pwd.pw_dir); slapi_entry_add_string(entry, "loginShell", pwd.pw_shell); - slapi_entry_set_sdn(entry, set_data->container_sdn); - slapi_entry_set_dn(entry, slapi_ch_smprintf("uid=%s,%s", - user_name, slapi_sdn_get_dn(set_data->container_sdn))); + + slapi_entry_set_dn(entry, dn); rc = sss_nss_getsidbyid(pwd.pw_uid, &sid_str, &id_type); if ((rc == 0) && (sid_str != NULL)) { @@ -175,35 +191,33 @@ backend_retrieve_user_entry_from_sssd(char *user_name, bool_t is_uid, free(sid_str); } - return entry; } static Slapi_Entry * backend_retrieve_group_entry_from_sssd(char *group_name, bool_t is_gid, - struct backend_set_data *set_data, - struct backend_search_cbdata *cbdata) + char *container_sdn, + struct backend_search_cbdata *cbdata) { struct group grp, *result; - const char *sdn; Slapi_Entry *entry; int rc, i; enum sss_id_type id_type; - char *sid_str; + char *sid_str, *dn; - if (set_data->sssd_buffer == NULL) { + if (cbdata->sssd_buffer == NULL) { return NULL; } if (is_gid) { rc = getgrgid_r(atoi(group_name), &grp, - set_data->sssd_buffer, - set_data->sssd_buffer_len, &result); + cbdata->sssd_buffer, + cbdata->sssd_buffer_len, &result); } else { rc = getgrnam_r(group_name, &grp, - set_data->sssd_buffer, - set_data->sssd_buffer_len, &result); + cbdata->sssd_buffer, + cbdata->sssd_buffer_len, &result); } if ((result == NULL) || (rc != 0)) { return NULL; @@ -218,6 +232,14 @@ backend_retrieve_group_entry_from_sssd(char *group_name, bool_t is_gid, return NULL; } + dn = slapi_ch_smprintf("cn=%s,%s", + slapi_escape_filter_value(grp.gr_name, -1), + container_sdn); + if (dn == NULL) { + slapi_entry_free(entry); + return NULL; + } + slapi_entry_add_string(entry, "objectClass", "top"); slapi_entry_add_string(entry, @@ -225,27 +247,18 @@ backend_retrieve_group_entry_from_sssd(char *group_name, bool_t is_gid, slapi_entry_add_string(entry, "objectClass", "extensibleObject"); slapi_entry_add_string(entry, - "cn", group_name); + "cn", grp.gr_name); slapi_entry_attr_set_int(entry, "gidNumber", grp.gr_gid); - slapi_entry_set_sdn(entry, set_data->container_sdn); - slapi_entry_set_dn(entry, - slapi_ch_smprintf("cn=%s,%s", group_name, - slapi_sdn_get_dn(set_data->container_sdn))); - if (grp.gr_mem) { - if (set_data->sssd_relevant_set != NULL) { - sdn = slapi_sdn_get_dn(set_data->sssd_relevant_set->container_sdn); - } else { - sdn = slapi_sdn_get_dn(set_data->container_sdn); - } for (i=0; grp.gr_mem[i]; i++) { - slapi_entry_add_string(entry, "memberUid", - slapi_ch_smprintf("uid=%s,%s", grp.gr_mem[i], sdn)); + slapi_entry_add_string(entry, "memberUid", grp.gr_mem[i]); } } + slapi_entry_set_dn(entry, dn); + rc = sss_nss_getsidbyid(grp.gr_gid, &sid_str, &id_type); if ((rc == 0) && (sid_str != NULL)) { slapi_entry_add_string(entry, "objectClass", "ipaNTGroupAttrs"); @@ -256,42 +269,89 @@ backend_retrieve_group_entry_from_sssd(char *group_name, bool_t is_gid, return entry; } -static void -backend_search_sssd_send_entry(struct backend_set_data *set_data, - struct backend_search_cbdata *cbdata, - Slapi_Entry *entry) +static Slapi_Entry ** +backend_retrieve_group_list_from_sssd(char *user_name, char *container_sdn, + struct backend_search_cbdata *cbdata, + int *count) { - char *ndn; - if (entry) { - slapi_entry_add_string(entry, - "schema-compat-origin", "sssd"); - cbdata->matched = TRUE; - ndn = slapi_entry_get_ndn(entry); - backend_set_entry(cbdata->pb, entry, set_data); - slapi_send_ldap_search_entry(cbdata->pb, entry, - NULL, cbdata->attrs, - cbdata->attrsonly); - cbdata->n_entries++; - if (cbdata->closest_match) { - free(cbdata->closest_match); + struct passwd pwd, *pwd_result; + gid_t *grouplist; + Slapi_Entry **entries, *entry; + int rc, ngroups, i, idx; + /* gid_t is unsigned int */ +#define GROUP_LEN_MAX (sizeof("4294967295") + 1) + char group[GROUP_LEN_MAX]; + + if (cbdata->sssd_buffer == NULL) { + return NULL; + } + + rc = getpwnam_r(user_name, &pwd, + cbdata->sssd_buffer, + cbdata->sssd_buffer_len, &pwd_result); + + if ((pwd_result == NULL) || (rc != 0)) { + return NULL; + } + + if (pwd.pw_uid < cbdata->sssd_min_id) { + return NULL; + } + + ngroups = 32; + grouplist = malloc(sizeof(gid_t) * ngroups); + if (grouplist == NULL) { + return NULL; + } + + do { + rc = getgrouplist(user_name, pwd.pw_gid, grouplist, &ngroups); + if (rc < ngroups) { + grouplist = realloc(grouplist, ngroups * sizeof(gid_t)); } - cbdata->closest_match = strdup(ndn); - /* Entry is created, cache it via map. - * Next request will be served from the cache */ - //backend_set_entry(cbdata->pb, entry, set_data); - slapi_entry_free(entry); + } while (rc != ngroups); + + entries = malloc(sizeof(Slapi_Entry *) * ngroups); + if (entries == NULL) { + free(grouplist); + return NULL; + } + + idx = 0; + /* At this point we are not interested in the buffer used in pwd anymore + * so the next function can take it over for getgrid_r() */ + for (i = 0; i < ngroups; i++) { + rc = snprintf(group, GROUP_LEN_MAX, "%u", grouplist[i]); + if ((rc > 0) && (rc <= GROUP_LEN_MAX)) { + entry = backend_retrieve_group_entry_from_sssd(group, TRUE, container_sdn, cbdata); + if (entry) { + entries[idx] = entry; + idx++; + } + } + } + + if (idx != ngroups) { + entries = realloc(entries, idx * sizeof(Slapi_Entry *)); } + + *count = idx; + + free(grouplist); + + return entries; + } /* Check filter for a component like (uid=<value>) and if found, - * perform look up against SSSD and create entry based on that */ + * stage SSSD lookup. Lookup will be performed later, with call to backend_retrieve_from_sssd */ void backend_search_sssd(struct backend_set_data *set_data, struct backend_search_cbdata *cbdata) { int result, rc; - Slapi_Entry *entry; - struct backend_search_filter_config config = {FALSE, FALSE, FALSE, FALSE, FALSE, NULL}; + struct backend_search_filter_config config = {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL}; + struct backend_staged_data *staged = NULL; /* There was no match but we asked to check SSSD */ /* First, we search the filter to see if it includes cn|uid=<value> check */ @@ -302,6 +362,10 @@ backend_search_sssd(struct backend_set_data *set_data, return; } + if (config.wrong_search) { + return; + } + /* Drop irrelevant requests. Each set only works with a single type */ if ((cbdata->check_sssd == SCH_SSSD_GROUP) && (config.search_uid || config.search_user)) { @@ -314,22 +378,83 @@ backend_search_sssd(struct backend_set_data *set_data, } if ((config.search_gid || config.search_uid) && - (atol(config.name) < set_data->sssd_min_id)) { + (atol(config.name) < cbdata->sssd_min_id)) { return; } - if ((config.search_group || config.search_gid) && - (NULL != config.name)) { - entry = backend_retrieve_group_entry_from_sssd(config.name, - config.search_gid, set_data, cbdata); - backend_search_sssd_send_entry(set_data, cbdata, entry); + + staged = malloc(sizeof(struct backend_staged_data)); + if (staged == NULL) { + free(config.name); return; } - if ((config.search_user || config.search_uid) && - (NULL != config.name)) { - entry = backend_retrieve_user_entry_from_sssd(config.name, - config.search_uid, set_data, cbdata); - backend_search_sssd_send_entry(set_data, cbdata, entry); + staged->map_group = slapi_ch_strdup(set_data->common.group); + staged->map_set = slapi_ch_strdup(set_data->common.set); + staged->set_data_fixup = NULL; + staged->count = 0; + staged->entries = NULL; + + staged->container_sdn = slapi_ch_strdup(slapi_sdn_get_dn(set_data->container_sdn)); + + staged->type = cbdata->check_sssd; + staged->name = config.name; + staged->is_id = config.search_gid || config.search_uid; + staged->search_members = config.search_members; + + staged->next = cbdata->staged; + cbdata->staged = staged; +} + + /* perform look up against SSSD and create entry based on that */ +bool_t +backend_retrieve_from_sssd(struct backend_staged_data *staged, + struct backend_search_cbdata *cbdata) +{ + Slapi_Entry *entry, **entries; + int i; + + if (((staged->type == SCH_SSSD_GROUP) && staged->search_members) && + (NULL != staged->name)) { + entries = backend_retrieve_group_list_from_sssd(staged->name, staged->container_sdn, + cbdata, &staged->count); + if (entries != NULL) { + staged->entries = entries; + for (i = 0; i < staged->count; i++) { + slapi_entry_add_string(entries[i], "schema-compat-origin", "sssd"); + } + return TRUE; + } + return FALSE; } + + if ((staged->type == SCH_SSSD_GROUP) && (NULL != staged->name)) { + entry = backend_retrieve_group_entry_from_sssd(staged->name, staged->is_id, + staged->container_sdn, + cbdata); + if (entry) { + slapi_entry_add_string(entry, "schema-compat-origin", "sssd"); + staged->count = 1; + staged->entries = malloc(sizeof(Slapi_Entry *)); + staged->entries[0] = entry; + return TRUE; + } + return FALSE; + } + + if ((staged->type == SCH_SSSD_USER) && (NULL != staged->name)) { + entry = backend_retrieve_user_entry_from_sssd(staged->name, staged->is_id, + staged->container_sdn, + cbdata); + if (entry) { + slapi_entry_add_string(entry, "schema-compat-origin", "sssd"); + staged->count = 1; + staged->entries = malloc(sizeof(Slapi_Entry *)); + staged->entries[0] = entry; + return TRUE; + } + return FALSE; + } + + return FALSE; } |