summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/back-sch-pam.c44
-rw-r--r--src/back-sch-sssd.c273
-rw-r--r--src/back-sch.c341
-rw-r--r--src/back-sch.h25
-rw-r--r--src/format.c12
-rw-r--r--src/format.h2
-rw-r--r--src/plug-sch.c3
-rw-r--r--src/plugin.h2
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