/* * Copyright 2008,2009,2010,2011,2012 Red Hat, Inc. * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This Program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this Program; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #ifdef HAVE_DIRSRV_SLAPI_PLUGIN_H #include #include #include #else #include #endif #include #include #include "backend.h" #include "back-shr.h" #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|memberUid=) or (objectClass=posixGroup|shadowAccount) * Called by slapi_filter_apply(). */ static int backend_search_filter_has_cn_uid(Slapi_Filter *filter, void *arg) { struct backend_search_filter_config *config = arg; struct berval *bval; char *filter_type; int f_choice, rc; f_choice = slapi_filter_get_choice(filter); rc = slapi_filter_get_ava(filter, &filter_type, &bval); if ((LDAP_FILTER_EQUALITY == f_choice) && (0 == rc)) { if (0 == strcasecmp(filter_type, "uidNumber")) { config->search_uid = TRUE; config->name_set = TRUE; } else if (0 == strcasecmp(filter_type, "gidNumber")) { config->search_gid = TRUE; config->name_set = TRUE; } else if (0 == strcasecmp(filter_type, "uid")) { config->search_user = TRUE; 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 = format_strdupbv(bval); } } if ((config->search_uid || config->search_gid || config->search_user || config->search_group) && (config->name != NULL)) { return SLAPI_FILTER_SCAN_STOP; } return SLAPI_FILTER_SCAN_CONTINUE; } static Slapi_Entry * backend_retrieve_user_entry_from_sssd(char *user_name, bool_t is_uid, 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, *dn; if (cbdata->sssd_buffer == NULL) { return NULL; } if (is_uid) { rc = getpwuid_r(atoi(user_name), &pwd, cbdata->sssd_buffer, cbdata->sssd_buffer_len, &result); } else { rc = getpwnam_r(user_name, &pwd, cbdata->sssd_buffer, cbdata->sssd_buffer_len, &result); } if ((result == NULL) || (rc != 0)) { return NULL; } if (pwd.pw_uid < cbdata->sssd_min_id) { return NULL; } entry = slapi_entry_alloc(); if (entry == NULL) { 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, "objectClass", "posixAccount"); slapi_entry_add_string(entry, "objectClass", "extensibleObject"); slapi_entry_add_string(entry, "uid", pwd.pw_name); slapi_entry_attr_set_int(entry, "uidNumber", pwd.pw_uid); slapi_entry_attr_set_int(entry, "gidNumber", pwd.pw_gid); slapi_entry_add_string(entry, "gecos", pwd.pw_gecos); if (strlen(pwd.pw_gecos) > 0) { slapi_entry_add_string(entry, "cn", pwd.pw_gecos); } else { slapi_entry_add_string(entry, "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_dn(entry, dn); rc = sss_nss_getsidbyid(pwd.pw_uid, &sid_str, &id_type); if ((rc == 0) && (sid_str != NULL)) { slapi_entry_add_string(entry, "objectClass", "ipaNTUserAttrs"); slapi_entry_add_string(entry, "ipaNTSecurityIdentifier", sid_str); free(sid_str); } return entry; } static Slapi_Entry * backend_retrieve_group_entry_from_sssd(char *group_name, bool_t is_gid, char *container_sdn, struct backend_search_cbdata *cbdata) { struct group grp, *result; Slapi_Entry *entry; int rc, i; enum sss_id_type id_type; char *sid_str, *dn; if (cbdata->sssd_buffer == NULL) { return NULL; } if (is_gid) { rc = getgrgid_r(atoi(group_name), &grp, cbdata->sssd_buffer, cbdata->sssd_buffer_len, &result); } else { rc = getgrnam_r(group_name, &grp, cbdata->sssd_buffer, cbdata->sssd_buffer_len, &result); } if ((result == NULL) || (rc != 0)) { return NULL; } if (grp.gr_gid < cbdata->sssd_min_id) { return NULL; } entry = slapi_entry_alloc(); if (entry == NULL) { 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, "objectClass", "posixGroup"); slapi_entry_add_string(entry, "objectClass", "extensibleObject"); slapi_entry_add_string(entry, "cn", grp.gr_name); slapi_entry_attr_set_int(entry, "gidNumber", grp.gr_gid); if (grp.gr_mem) { for (i=0; grp.gr_mem[i]; i++) { 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"); slapi_entry_add_string(entry, "ipaNTSecurityIdentifier", sid_str); free(sid_str); } return entry; } static Slapi_Entry ** backend_retrieve_group_list_from_sssd(char *user_name, char *container_sdn, struct backend_search_cbdata *cbdata, int *count) { 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)); } } 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=) and if found, * 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; 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= check */ result = slapi_filter_apply(cbdata->filter, backend_search_filter_has_cn_uid, &config, &rc); if ((result != SLAPI_FILTER_SCAN_STOP) || (NULL == config.name)) { 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)) { return; } if ((cbdata->check_sssd == SCH_SSSD_USER) && (config.search_gid || config.search_group)) { return; } if ((config.search_gid || config.search_uid) && (atol(config.name) < cbdata->sssd_min_id)) { return; } staged = malloc(sizeof(struct backend_staged_data)); if (staged == NULL) { free(config.name); return; } 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; }