diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/back-sch-pam.c | 44 | ||||
-rw-r--r-- | src/back-sch-sssd.c | 273 | ||||
-rw-r--r-- | src/back-sch.c | 341 | ||||
-rw-r--r-- | src/back-sch.h | 25 | ||||
-rw-r--r-- | src/format.c | 12 | ||||
-rw-r--r-- | src/format.h | 2 | ||||
-rw-r--r-- | src/plug-sch.c | 3 | ||||
-rw-r--r-- | src/plugin.h | 2 |
8 files changed, 441 insertions, 261 deletions
diff --git a/src/back-sch-pam.c b/src/back-sch-pam.c index 3266261..c37758a 100644 --- a/src/back-sch-pam.c +++ b/src/back-sch-pam.c @@ -54,12 +54,7 @@ #include <security/pam_appl.h> - -/* - * PAM is not thread safe. We have to execute any PAM API calls in - * a critical section. This is the lock that protects that code. - */ -static Slapi_Mutex *PAMLock = NULL; +#include "format.h" /* Utility struct to wrap strings to avoid mallocs if possible - use stack allocated string space */ @@ -98,15 +93,6 @@ struct my_pam_conv_str { char *pam_identity; }; -/* returns a berval value as a null terminated string */ -static char *strdupbv(struct berval *bv) -{ - char *str = slapi_ch_malloc(bv->bv_len+1); - memcpy(str, bv->bv_val, bv->bv_len); - str[bv->bv_len] = 0; - return str; -} - static void free_pam_response(int nresp, struct pam_response *resp) { @@ -131,25 +117,24 @@ pam_conv_func(int num_msg, const struct pam_message **msg, struct pam_response * int ii; struct berval *creds; struct my_pam_conv_str *my_data = (struct my_pam_conv_str *)mydata; - struct pam_response *reply; + struct pam_response *reply; int ret = PAM_SUCCESS; - if (num_msg <= 0) { + if (num_msg <= 0) { return PAM_CONV_ERR; } /* empty reply structure */ - reply = (struct pam_response *)slapi_ch_calloc(num_msg, - sizeof(struct pam_response)); + reply = (struct pam_response *)slapi_ch_calloc(num_msg, sizeof(struct pam_response)); slapi_pblock_get( my_data->pb, SLAPI_BIND_CREDENTIALS, &creds ); /* the password */ for (ii = 0; ii < num_msg; ++ii) { /* hard to tell what prompt is for . . . */ /* assume prompts for password are either BINARY or ECHO_OFF */ if (msg[ii]->msg_style == PAM_PROMPT_ECHO_OFF) { - reply[ii].resp = strdupbv(creds); + reply[ii].resp = format_strdupbv(creds); #ifdef LINUX } else if (msg[ii]->msg_style == PAM_BINARY_PROMPT) { - reply[ii].resp = strdupbv(creds); + reply[ii].resp = format_strdupbv(creds); #endif } else if (msg[ii]->msg_style == PAM_PROMPT_ECHO_ON) { /* assume username */ reply[ii].resp = slapi_ch_strdup(my_data->pam_identity); @@ -190,7 +175,7 @@ do_pam_auth( Slapi_PBlock *pb, char *pam_service, /* name of service for pam_start() */ int pw_response_requested, /* do we need to send pwd policy resp control */ - Slapi_Entry *entry + const char *username ) { MyStrBuf pam_id; @@ -212,10 +197,7 @@ do_pam_auth( } binddn = slapi_sdn_get_dn(bindsdn); - char *val = slapi_entry_attr_get_charptr(entry, "uid"); - init_my_str_buf(&pam_id, val); - slapi_ch_free_string(&val); - + init_my_str_buf(&pam_id, username); if (!pam_id.str) { errmsg = PR_smprintf("Bind DN [%s] is invalid or not found", binddn); retcode = LDAP_NO_SUCH_OBJECT; /* user unknown */ @@ -226,7 +208,6 @@ do_pam_auth( my_data.pb = pb; my_data.pam_identity = pam_id.str; my_pam_conv.appdata_ptr = &my_data; - slapi_lock_mutex(PAMLock); /* from this point on we are in the critical section */ rc = pam_start(pam_service, pam_id.str, &my_pam_conv, &pam_handle); @@ -304,7 +285,6 @@ do_pam_auth( } rc = pam_end(pam_handle, rc); - slapi_unlock_mutex(PAMLock); /* not in critical section any more */ done: @@ -334,17 +314,13 @@ done: * depending on what methods are set in the config. */ int -backend_sch_do_pam_auth(Slapi_PBlock *pb, Slapi_Entry *entry) +backend_sch_do_pam_auth(Slapi_PBlock *pb, const char *username) { int rc = LDAP_SUCCESS; MyStrBuf pam_service; /* avoid malloc if possible */ int pw_response_requested; LDAPControl **reqctrls = NULL; - if (!PAMLock && !(PAMLock = slapi_new_mutex())) { - return LDAP_LOCAL_ERROR; - } - init_my_str_buf(&pam_service, "system-auth"); slapi_pblock_get (pb, SLAPI_REQCONTROLS, &reqctrls); @@ -353,7 +329,7 @@ backend_sch_do_pam_auth(Slapi_PBlock *pb, Slapi_Entry *entry) /* figure out which method is the last one - we only return error codes, controls to the client and send a response on the last method */ - rc = do_pam_auth(pb, pam_service.str, pw_response_requested, entry); + rc = do_pam_auth(pb, pam_service.str, pw_response_requested, username); delete_my_str_buf(&pam_service); 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; } 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 diff --git a/src/back-sch.h b/src/back-sch.h index 85ea86f..0741434 100644 --- a/src/back-sch.h +++ b/src/back-sch.h @@ -38,9 +38,6 @@ struct backend_set_data { bool_t check_access; enum sch_search_sssd_t check_sssd; long sssd_min_id; - char *sssd_buffer; - ssize_t sssd_buffer_len; - struct backend_set_data *sssd_relevant_set; }; struct backend_entry_data { @@ -48,6 +45,19 @@ struct backend_entry_data { Slapi_Entry *e; }; +struct backend_staged_data { + struct backend_staged_data *next; + struct backend_set_data *set_data_fixup; + char *map_group, *map_set; + enum sch_search_sssd_t type; + bool_t is_id; + bool_t search_members; + char *name; + char *container_sdn; + int count; + Slapi_Entry **entries; +}; + /* Intercept a search request, and if it belongs to one of our compatibility * trees, answer from our cache before letting the default database have a * crack at it. */ @@ -61,23 +71,30 @@ struct backend_search_cbdata { Slapi_DN *target_dn; Slapi_Filter *filter; long sssd_min_id; + char *sssd_buffer; + ssize_t sssd_buffer_len; bool_t answer; int result; bool_t matched; char *closest_match, *text; int n_entries; + struct backend_staged_data *staged; + struct backend_staged_data *cur_staged; }; void backend_search_sssd(struct backend_set_data *set_data, struct backend_search_cbdata *cbdata); +bool_t backend_retrieve_from_sssd(struct backend_staged_data *staged, + struct backend_search_cbdata *cbdata); + void backend_set_operational_attributes(Slapi_Entry *e, struct plugin_state *state, time_t timestamp, int n_subordinates, const char *usn); -int backend_sch_do_pam_auth(Slapi_PBlock *pb, Slapi_Entry *entry); +int backend_sch_do_pam_auth(Slapi_PBlock *pb, const char *username); #endif diff --git a/src/format.c b/src/format.c index 9ee2444..fbbfb7d 100644 --- a/src/format.c +++ b/src/format.c @@ -103,6 +103,18 @@ xmemdup(char *region, int size) return ret; } +/* returns a berval value as a null terminated string */ +char * +format_strdupbv(struct berval *bv) +{ + char *str = slapi_ch_malloc(bv->bv_len+1); + if (str != NULL) { + memcpy(str, bv->bv_val, bv->bv_len); + str[bv->bv_len] = 0; + } + return str; +} + /* Maintain a DN list, which is list of distinguished names, and a sorted copy * which we can check for inclusion much faster. */ static int diff --git a/src/format.h b/src/format.h index 0aa7d20..84fa837 100644 --- a/src/format.h +++ b/src/format.h @@ -79,4 +79,6 @@ char **format_get_data_set(struct plugin_state *state, unsigned int **data_lengths); char *format_escape_for_filter(const char *unescaped); +/* Copy struct berval * as NULL-terminated string*/ +char *format_strdupbv(struct berval *bv); #endif diff --git a/src/plug-sch.c b/src/plug-sch.c index 5440e00..5d74beb 100644 --- a/src/plug-sch.c +++ b/src/plug-sch.c @@ -108,6 +108,7 @@ plugin_startup(Slapi_PBlock *pb) state->plugin_base ? "\"" : ""); /* Populate the tree of fake entries. */ backend_startup(pb, state); + state->pam_lock = wrap_new_rwlock(); /* Note that the plugin is ready to go. */ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id, "plugin startup completed\n"); @@ -120,6 +121,8 @@ plugin_shutdown(Slapi_PBlock *pb) struct plugin_state *state; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); map_done(state); + wrap_free_rwlock(state->pam_lock); + state->pam_lock = NULL; state->plugin_base = NULL; slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "plugin shutdown completed\n"); diff --git a/src/plugin.h b/src/plugin.h index b54e2ad..3967fb0 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -44,6 +44,8 @@ struct plugin_state { struct { int fd, port, pf, type; } listener[4]; + /* Schema compat-specific data. */ + struct wrapped_rwlock *pam_lock; }; #endif |