diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index 1faa11b16e0..db4b72671a2 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -758,7 +758,11 @@ int sysdb_attrs_copy_values(struct sysdb_attrs *src,
return ret;
}
-errno_t sysdb_attrs_copy(struct sysdb_attrs *src, struct sysdb_attrs *dst)
+static
+errno_t sysdb_attrs_copy_ext(struct sysdb_attrs *src,
+ struct sysdb_attrs *dst,
+ const char **exclude,
+ bool check)
{
int ret;
size_t c;
@@ -769,9 +773,14 @@ errno_t sysdb_attrs_copy(struct sysdb_attrs *src, struct sysdb_attrs *dst)
}
for (c = 0; c < src->num; c++) {
+ if (string_in_list(src->a[c].name, discard_const(exclude), false)) {
+ continue;
+ }
for (d = 0; d < src->a[c].num_values; d++) {
- ret = sysdb_attrs_add_val_safe(dst, src->a[c].name,
- &src->a[c].values[d]);
+ ret = sysdb_attrs_add_val_int(dst,
+ src->a[c].name,
+ check,
+ &src->a[c].values[d]);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n");
return ret;
@@ -782,6 +791,19 @@ errno_t sysdb_attrs_copy(struct sysdb_attrs *src, struct sysdb_attrs *dst)
return EOK;
}
+errno_t sysdb_attrs_copy(struct sysdb_attrs *src,
+ struct sysdb_attrs *dst)
+{
+ return sysdb_attrs_copy_ext(src, dst, NULL, true);
+}
+
+errno_t sysdb_attrs_join(struct sysdb_attrs *src,
+ struct sysdb_attrs *dst,
+ const char **exclude)
+{
+ return sysdb_attrs_copy_ext(src, dst, exclude, false);
+}
+
int sysdb_attrs_users_from_str_list(struct sysdb_attrs *attrs,
const char *attr_name,
const char *domain,
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index d0f10e2ccc6..4f6ea28acc5 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -461,6 +461,9 @@ int sysdb_attrs_copy_values(struct sysdb_attrs *src,
struct sysdb_attrs *dst,
const char *name);
errno_t sysdb_attrs_copy(struct sysdb_attrs *src, struct sysdb_attrs *dst);
+errno_t sysdb_attrs_join(struct sysdb_attrs *src,
+ struct sysdb_attrs *dst,
+ const char **exclude);
int sysdb_attrs_get_el(struct sysdb_attrs *attrs, const char *name,
struct ldb_message_element **el);
int sysdb_attrs_get_el_ext(struct sysdb_attrs *attrs, const char *name,
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index cc26458e758..413ca018d42 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -729,9 +729,10 @@
this option prevents SSSD from parsing the range
extension. As a result large groups will appear as they
have no members.
- This option does not enable SSSD to read subsequent
- ranges. To retrieve all members of a group, you must
- increase the MaxValRange setting in Active Directory.
+
+
+ By default, SSSD performs additional queries to obtain
+ subsequent ranges and to complete information.
Default: False
diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index a64d8c157ee..cc19da7ced2 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -405,7 +405,8 @@ int sdap_parse_entry(TALLOC_CTX *memctx,
struct sdap_handle *sh, struct sdap_msg *sm,
struct sdap_attr_map *map, int attrs_num,
struct sysdb_attrs **_attrs,
- bool disable_range_retrieval)
+ bool disable_range_retrieval,
+ const char ***_next_attrs)
{
struct sysdb_attrs *attrs;
BerElement *ber = NULL;
@@ -420,9 +421,14 @@ int sdap_parse_entry(TALLOC_CTX *memctx,
bool base64;
char *base_attr;
uint32_t range_offset;
+ const char **next_attrs = NULL;
+ size_t next_attrs_count = 0;
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
+ if (_next_attrs != NULL) {
+ *_next_attrs = NULL;
+ }
lerrno = 0;
ret = ldap_set_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno);
if (ret != LDAP_OPT_SUCCESS) {
@@ -452,7 +458,7 @@ int sdap_parse_entry(TALLOC_CTX *memctx,
if (ret) goto done;
if (map) {
- vals = ldap_get_values_len(sh->ldap, sm->msg, "objectClass");
+ vals = ldap_get_values_len(sh->ldap, sm->msg, SYSDB_OBJECTCLASS);
if (!vals) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Unknown entry type, no objectClasses found!\n");
@@ -499,10 +505,32 @@ int sdap_parse_entry(TALLOC_CTX *memctx,
/* This attribute contained range values and needs more to
* be retrieved
*/
- /* TODO: return the set of attributes that need additional retrieval
- * For now, we'll continue below and treat it as regular values.
- */
- /* FALLTHROUGH */
+ next_attrs = talloc_realloc(tmp_ctx, next_attrs, const char *,
+ next_attrs_count + 2
+ + (next_attrs_count > 0 ? 0 : 1));
+ if (next_attrs == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ if (next_attrs_count == 0) {
+ /* we need to ask objectClass to correctly
+ * identify the object later
+ */
+ next_attrs[next_attrs_count++] = SYSDB_OBJECTCLASS;
+ }
+ next_attrs[next_attrs_count] = talloc_asprintf(next_attrs,
+ "%s;range=%d-*",
+ base_attr,
+ range_offset);
+ if (next_attrs[next_attrs_count] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "Attribute [%s] for next range request found\n",
+ next_attrs[next_attrs_count]);
+ next_attrs[++next_attrs_count] = NULL;
+ break;
case ECANCELED:
/* FALLTHROUGH */
case EOK:
@@ -633,6 +661,9 @@ int sdap_parse_entry(TALLOC_CTX *memctx,
PROBE(SDAP_PARSE_ENTRY_DONE);
*_attrs = talloc_steal(memctx, attrs);
+ if (_next_attrs != NULL && disable_range_retrieval == false) {
+ *_next_attrs = talloc_steal(memctx, next_attrs);
+ }
ret = EOK;
done:
@@ -722,7 +753,7 @@ errno_t sdap_parse_deref(TALLOC_CTX *mem_ctx,
ocs = NULL;
for (dval = dref->attrVals; dval != NULL; dval = dval->next) {
- if (strcasecmp("objectClass", dval->type) == 0) {
+ if (strcasecmp(SYSDB_OBJECTCLASS, dval->type) == 0) {
if (dval->vals == NULL) {
DEBUG(SSSDBG_CONF_SETTINGS,
"No value for objectClass, skipping\n");
@@ -1613,7 +1644,7 @@ int build_attrs_from_map(TALLOC_CTX *memctx,
}
/* first attribute is "objectclass" not the specific one */
- attrs[0] = talloc_strdup(memctx, "objectClass");
+ attrs[0] = talloc_strdup(memctx, SYSDB_OBJECTCLASS);
if (!attrs[0]) return ENOMEM;
/* add the others */
@@ -2022,11 +2053,12 @@ errno_t sdap_get_primary_fqdn_list(struct sss_domain_info *domain,
char *sdap_make_oc_list(TALLOC_CTX *mem_ctx, struct sdap_attr_map *map)
{
if (map[SDAP_OC_GROUP_ALT].name == NULL) {
- return talloc_asprintf(mem_ctx, "objectClass=%s",
+ return talloc_asprintf(mem_ctx, SYSDB_OBJECTCLASS"=%s",
map[SDAP_OC_GROUP].name);
} else {
return talloc_asprintf(mem_ctx,
- "|(objectClass=%s)(objectClass=%s)",
+ "|("SYSDB_OBJECTCLASS"=%s)"
+ "("SYSDB_OBJECTCLASS"=%s)",
map[SDAP_OC_GROUP].name,
map[SDAP_OC_GROUP_ALT].name);
}
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index aaed7d0fd74..598a1096d86 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -652,7 +652,8 @@ int sdap_parse_entry(TALLOC_CTX *memctx,
struct sdap_handle *sh, struct sdap_msg *sm,
struct sdap_attr_map *map, int attrs_num,
struct sysdb_attrs **_attrs,
- bool disable_range_retrieval);
+ bool disable_range_retrieval,
+ const char *** _next_attrs);
errno_t sdap_parse_deref(TALLOC_CTX *mem_ctx,
struct sdap_attr_map_info *minfo,
diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index 6d662fbdea8..cdd67b647df 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -1197,7 +1197,7 @@ struct tevent_req *sdap_get_rootdse_send(TALLOC_CTX *memctx,
subreq = sdap_get_generic_send(state, ev, opts, sh,
"", LDAP_SCOPE_BASE,
- "(objectclass=*)", attrs, NULL, 0,
+ "("SYSDB_OBJECTCLASS"=*)", attrs, NULL, 0,
dp_opt_get_int(state->opts->basic,
SDAP_SEARCH_TIMEOUT),
false);
@@ -1277,8 +1277,24 @@ struct sdap_reply {
static errno_t add_to_reply(TALLOC_CTX *mem_ctx,
struct sdap_reply *sreply,
- struct sysdb_attrs *msg)
+ struct sysdb_attrs *msg,
+ bool range_retrieval_update)
{
+ int ret;
+ static const char *exclude[] = {SYSDB_OBJECTCLASS, NULL};
+
+ if (range_retrieval_update) {
+ if (sreply->reply_count == 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Can't update empty array\n");
+ return EINVAL;
+ }
+
+ ret = sysdb_attrs_join(msg, sreply->reply[sreply->reply_count - 1],
+ exclude);
+ talloc_free(msg);
+ return ret;
+ }
+
if (sreply->reply == NULL || sreply->reply_max == sreply->reply_count) {
sreply->reply_max += REPLY_REALLOC_INCREMENT;
sreply->reply = talloc_realloc(mem_ctx, sreply->reply,
@@ -1452,7 +1468,9 @@ static void sdap_print_server(struct sdap_handle *sh)
/* ==Generic Search exposing all options======================= */
typedef errno_t (*sdap_parse_cb)(struct sdap_handle *sh,
struct sdap_msg *msg,
- void *pvt);
+ bool range_retrieval_step,
+ void *pvt,
+ const char ***_next_attrs);
struct sdap_get_generic_ext_state {
struct tevent_context *ev;
@@ -1462,6 +1480,8 @@ struct sdap_get_generic_ext_state {
int scope;
const char *filter;
const char **attrs;
+ const char **next_attrs;
+ bool range_retrieval_step;
int timeout;
int sizelimit;
@@ -1508,6 +1528,7 @@ sdap_get_generic_ext_send(TALLOC_CTX *memctx,
int scope,
const char *filter,
const char **attrs,
+ bool range_retrieval_step,
LDAPControl **serverctrls,
LDAPControl **clientctrls,
int sizelimit,
@@ -1532,6 +1553,8 @@ sdap_get_generic_ext_send(TALLOC_CTX *memctx,
state->scope = scope;
state->filter = filter;
state->attrs = attrs;
+ state->range_retrieval_step = range_retrieval_step;
+ state->next_attrs = NULL;
state->op = NULL;
state->sizelimit = sizelimit;
state->timeout = timeout;
@@ -1757,6 +1780,7 @@ static void sdap_get_generic_op_finished(struct sdap_op *op,
struct sdap_get_generic_ext_state);
char *errmsg = NULL;
char **refs = NULL;
+ const char **next_attrs = NULL;
int result;
int ret;
int lret;
@@ -1799,13 +1823,14 @@ static void sdap_get_generic_op_finished(struct sdap_op *op,
break;
case LDAP_RES_SEARCH_ENTRY:
- ret = state->parse_cb(state->sh, reply, state->cb_data);
+ ret = state->parse_cb(state->sh, reply, state->range_retrieval_step,
+ state->cb_data, &next_attrs);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "reply parsing callback failed.\n");
tevent_req_error(req, ret);
return;
}
-
+ state->next_attrs = talloc_steal(state, next_attrs);
sdap_unlock_next_reply(state->op);
break;
@@ -1930,7 +1955,8 @@ static int
sdap_get_generic_ext_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
size_t *ref_count,
- char ***refs)
+ char ***refs,
+ const char ***next_attrs)
{
struct sdap_get_generic_ext_state *state =
tevent_req_data(req, struct sdap_get_generic_ext_state);
@@ -1948,21 +1974,58 @@ sdap_get_generic_ext_recv(struct tevent_req *req,
*refs = talloc_steal(mem_ctx, state->refs);
}
+ if (next_attrs) {
+ *next_attrs = talloc_steal(mem_ctx, state->next_attrs);
+ }
+
return EOK;
}
+static struct tevent_req *
+sdap_get_generic_ext_send_next(TALLOC_CTX *ctx, struct tevent_req *subreq,
+ const char **attrs, bool range_retrieval_step)
+{
+ struct tevent_req *next_subreq = NULL;
+ struct sdap_get_generic_ext_state *state;
+
+ state = tevent_req_data(subreq, struct sdap_get_generic_ext_state);
+ next_subreq = sdap_get_generic_ext_send(ctx,
+ state->ev,
+ state->opts,
+ state->sh,
+ state->search_base,
+ state->scope,
+ state->filter,
+ attrs,
+ range_retrieval_step,
+ state->serverctrls,
+ state->clientctrls,
+ state->sizelimit,
+ state->timeout,
+ state->parse_cb,
+ state->cb_data,
+ state->flags);
+ if (next_subreq) {
+ talloc_steal(next_subreq, attrs);
+ }
+ return next_subreq;
+}
+
/* This search handler can be used by most calls */
static void generic_ext_search_handler(struct tevent_req *subreq,
- struct sdap_options *opts)
+ struct sdap_options *opts,
+ tevent_req_fn done_callback)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
int ret;
size_t ref_count, i;
- char **refs;
+ char **refs = NULL;
+ const char **next_attrs = NULL;
+ struct tevent_req *next_subreq = NULL;
- ret = sdap_get_generic_ext_recv(subreq, req, &ref_count, &refs);
- talloc_zfree(subreq);
+ ret = sdap_get_generic_ext_recv(subreq, req,
+ &ref_count, &refs, &next_attrs);
if (ret != EOK) {
if (ret == ETIMEDOUT) {
@@ -1975,8 +2038,7 @@ static void generic_ext_search_handler(struct tevent_req *subreq,
"sdap_get_generic_ext_recv request failed: [%d]: %s\n",
ret, sss_strerror(ret));
}
- tevent_req_error(req, ret);
- return;
+ goto done;
}
if (ref_count > 0) {
@@ -1991,8 +2053,32 @@ static void generic_ext_search_handler(struct tevent_req *subreq,
}
}
+ if (next_attrs != NULL) {
+ if (done_callback == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Range retrieval is not implemented "
+ "for this type of request.\n");
+ goto done;
+ }
+ next_subreq = sdap_get_generic_ext_send_next(req, subreq,
+ next_attrs, true);
+ if (next_subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ tevent_req_set_callback(next_subreq, done_callback, req);
+ }
+
+ done:
+ talloc_zfree(subreq);
talloc_free(refs);
- tevent_req_done(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+ if (next_subreq == NULL) {
+ tevent_req_done(req);
+ }
}
/* ==Generic Search exposing all options======================= */
@@ -2007,7 +2093,9 @@ struct sdap_get_and_parse_generic_state {
static void sdap_get_and_parse_generic_done(struct tevent_req *subreq);
static errno_t sdap_get_and_parse_generic_parse_entry(struct sdap_handle *sh,
struct sdap_msg *msg,
- void *pvt);
+ bool range_retrieval_step,
+ void *pvt,
+ const char ***next_attrs);
struct tevent_req *sdap_get_and_parse_generic_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
@@ -2048,7 +2136,7 @@ struct tevent_req *sdap_get_and_parse_generic_send(TALLOC_CTX *memctx,
}
subreq = sdap_get_generic_ext_send(state, ev, opts, sh, search_base,
- scope, filter, attrs, serverctrls,
+ scope, filter, attrs, false, serverctrls,
clientctrls, sizelimit, timeout,
sdap_get_and_parse_generic_parse_entry,
state, flags);
@@ -2063,7 +2151,9 @@ struct tevent_req *sdap_get_and_parse_generic_send(TALLOC_CTX *memctx,
static errno_t sdap_get_and_parse_generic_parse_entry(struct sdap_handle *sh,
struct sdap_msg *msg,
- void *pvt)
+ bool range_retrieval_step,
+ void *pvt,
+ const char ***_next_attrs)
{
errno_t ret;
struct sysdb_attrs *attrs;
@@ -2075,14 +2165,14 @@ static errno_t sdap_get_and_parse_generic_parse_entry(struct sdap_handle *sh,
ret = sdap_parse_entry(state, sh, msg,
state->map, state->map_num_attrs,
- &attrs, disable_range_rtrvl);
+ &attrs, disable_range_rtrvl, _next_attrs);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"sdap_parse_entry failed [%d]: %s\n", ret, strerror(ret));
return ret;
}
- ret = add_to_reply(state, &state->sreply, attrs);
+ ret = add_to_reply(state, &state->sreply, attrs, range_retrieval_step);
if (ret != EOK) {
talloc_free(attrs);
DEBUG(SSSDBG_CRIT_FAILURE, "add_to_reply failed.\n");
@@ -2100,7 +2190,7 @@ static void sdap_get_and_parse_generic_done(struct tevent_req *subreq)
struct sdap_get_and_parse_generic_state *state =
tevent_req_data(req, struct sdap_get_and_parse_generic_state);
- return generic_ext_search_handler(subreq, state->opts);
+ return generic_ext_search_handler(subreq, state->opts, sdap_get_and_parse_generic_done);
}
int sdap_get_and_parse_generic_recv(struct tevent_req *req,
@@ -2206,7 +2296,9 @@ static int sdap_x_deref_search_ctrls_destructor(void *ptr);
static errno_t sdap_x_deref_parse_entry(struct sdap_handle *sh,
struct sdap_msg *msg,
- void *pvt);
+ bool not_used,
+ void *pvt,
+ const char ***_not_used);
struct sdap_x_deref_search_state {
struct sdap_handle *sh;
struct sdap_op *op;
@@ -2264,7 +2356,7 @@ sdap_x_deref_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
subreq = sdap_get_generic_ext_send(state, ev, opts, sh, base_dn,
filter == NULL ? LDAP_SCOPE_BASE
: LDAP_SCOPE_SUBTREE,
- filter, attrs,
+ filter, attrs, false,
state->ctrls, NULL, 0, timeout,
sdap_x_deref_parse_entry,
state, SDAP_SRCH_FLG_PAGING);
@@ -2311,7 +2403,9 @@ static int sdap_x_deref_create_control(struct sdap_handle *sh,
static errno_t sdap_x_deref_parse_entry(struct sdap_handle *sh,
struct sdap_msg *msg,
- void *pvt)
+ bool not_used,
+ void *pvt,
+ const char ***_not_used)
{
errno_t ret;
LDAPControl **ctrls = NULL;
@@ -2410,7 +2504,7 @@ static void sdap_x_deref_search_done(struct tevent_req *subreq)
struct sdap_x_deref_search_state *state =
tevent_req_data(req, struct sdap_x_deref_search_state);
- return generic_ext_search_handler(subreq, state->opts);
+ return generic_ext_search_handler(subreq, state->opts, NULL);
}
static int sdap_x_deref_search_ctrls_destructor(void *ptr)
@@ -2455,12 +2549,14 @@ struct sdap_sd_search_state {
};
static int sdap_sd_search_create_control(struct sdap_handle *sh,
- int val,
- LDAPControl **ctrl);
+ int val,
+ LDAPControl **ctrl);
static int sdap_sd_search_ctrls_destructor(void *ptr);
static errno_t sdap_sd_search_parse_entry(struct sdap_handle *sh,
struct sdap_msg *msg,
- void *pvt);
+ bool not_used,
+ void *pvt,
+ const char ***_not_used);
static void sdap_sd_search_done(struct tevent_req *subreq);
struct tevent_req *
@@ -2495,7 +2591,9 @@ sdap_sd_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
DEBUG(SSSDBG_TRACE_FUNC, "Searching entry [%s] using SD\n", base_dn);
subreq = sdap_get_generic_ext_send(state, ev, opts, sh, base_dn,
- LDAP_SCOPE_BASE, "(objectclass=*)", attrs,
+ LDAP_SCOPE_BASE,
+ "("SYSDB_OBJECTCLASS"=*)",
+ attrs, false,
state->ctrls, NULL, 0, timeout,
sdap_sd_search_parse_entry,
state, SDAP_SRCH_FLG_PAGING);
@@ -2551,7 +2649,9 @@ static int sdap_sd_search_create_control(struct sdap_handle *sh,
static errno_t sdap_sd_search_parse_entry(struct sdap_handle *sh,
struct sdap_msg *msg,
- void *pvt)
+ bool not_used,
+ void *pvt,
+ const char ***_not_used)
{
errno_t ret;
struct sysdb_attrs *attrs;
@@ -2563,14 +2663,14 @@ static errno_t sdap_sd_search_parse_entry(struct sdap_handle *sh,
ret = sdap_parse_entry(state, sh, msg,
NULL, 0,
- &attrs, disable_range_rtrvl);
+ &attrs, disable_range_rtrvl, NULL);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"sdap_parse_entry failed [%d]: %s\n", ret, strerror(ret));
return ret;
}
- ret = add_to_reply(state, &state->sreply, attrs);
+ ret = add_to_reply(state, &state->sreply, attrs, false);
if (ret != EOK) {
talloc_free(attrs);
DEBUG(SSSDBG_CRIT_FAILURE, "add_to_reply failed.\n");
@@ -2592,7 +2692,8 @@ static void sdap_sd_search_done(struct tevent_req *subreq)
ret = sdap_get_generic_ext_recv(subreq, state,
&state->ref_count,
- &state->refs);
+ &state->refs,
+ NULL);
talloc_zfree(subreq);
if (ret != EOK) {
@@ -2665,7 +2766,9 @@ static int sdap_asq_search_create_control(struct sdap_handle *sh,
static int sdap_asq_search_ctrls_destructor(void *ptr);
static errno_t sdap_asq_search_parse_entry(struct sdap_handle *sh,
struct sdap_msg *msg,
- void *pvt);
+ bool not_used,
+ void *pvt,
+ const char ***_not_used);
static void sdap_asq_search_done(struct tevent_req *subreq);
static struct tevent_req *
@@ -2706,7 +2809,8 @@ sdap_asq_search_send(TALLOC_CTX *memctx, struct tevent_context *ev,
DEBUG(SSSDBG_TRACE_FUNC, "Dereferencing entry [%s] using ASQ\n", base_dn);
subreq = sdap_get_generic_ext_send(state, ev, opts, sh, base_dn,
- LDAP_SCOPE_BASE, NULL, attrs,
+ LDAP_SCOPE_BASE, NULL,
+ attrs, false,
state->ctrls, NULL, 0, timeout,
sdap_asq_search_parse_entry,
state, SDAP_SRCH_FLG_PAGING);
@@ -2760,7 +2864,9 @@ static int sdap_asq_search_create_control(struct sdap_handle *sh,
static errno_t sdap_asq_search_parse_entry(struct sdap_handle *sh,
struct sdap_msg *msg,
- void *pvt)
+ bool not_used,
+ void *pvt,
+ const char ***_not_used)
{
errno_t ret;
struct sdap_asq_search_state *state =
@@ -2810,7 +2916,7 @@ static errno_t sdap_asq_search_parse_entry(struct sdap_handle *sh,
}
/* Find all suitable maps in the list */
- vals = ldap_get_values_len(sh->ldap, msg->msg, "objectClass");
+ vals = ldap_get_values_len(sh->ldap, msg->msg, SYSDB_OBJECTCLASS);
if (!vals) {
DEBUG(SSSDBG_OP_FAILURE,
"Unknown entry type, no objectClass found for DN [%s]!\n", dn);
@@ -2844,7 +2950,7 @@ static errno_t sdap_asq_search_parse_entry(struct sdap_handle *sh,
ret = sdap_parse_entry(res[mi], sh, msg,
map, num_attrs,
- &res[mi]->attrs, disable_range_rtrvl);
+ &res[mi]->attrs, disable_range_rtrvl, NULL);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"sdap_parse_entry failed [%d]: %s\n", ret, strerror(ret));
@@ -2880,7 +2986,7 @@ static void sdap_asq_search_done(struct tevent_req *subreq)
struct sdap_asq_search_state *state =
tevent_req_data(req, struct sdap_asq_search_state);
- return generic_ext_search_handler(subreq, state->opts);
+ return generic_ext_search_handler(subreq, state->opts, NULL);
}
static int sdap_asq_search_ctrls_destructor(void *ptr)
diff --git a/src/tests/cmocka/test_sdap.c b/src/tests/cmocka/test_sdap.c
index 047591e9e84..a9149cf5b8d 100644
--- a/src/tests/cmocka/test_sdap.c
+++ b/src/tests/cmocka/test_sdap.c
@@ -307,7 +307,7 @@ void test_parse_with_map(void **state)
ret = sdap_parse_entry(test_ctx, &test_ctx->sh, &test_ctx->sm,
map, SDAP_OPTS_USER,
- &attrs, false);
+ &attrs, false, NULL);
assert_int_equal(ret, ERR_OK);
assert_int_equal(attrs->num, 4);
@@ -368,7 +368,7 @@ void test_parse_no_map(void **state)
set_entry_parse(&test_nomap_entry);
ret = sdap_parse_entry(test_ctx, &test_ctx->sh, &test_ctx->sm,
- NULL, 0, &attrs, false);
+ NULL, 0, &attrs, false, NULL);
assert_int_equal(ret, ERR_OK);
assert_int_equal(attrs->num, 3);
@@ -413,7 +413,7 @@ void test_parse_no_attrs(void **state)
ret = sdap_parse_entry(test_ctx, &test_ctx->sh, &test_ctx->sm,
map, SDAP_OPTS_USER,
- &attrs, false);
+ &attrs, false, NULL);
assert_int_equal(ret, ERR_OK);
assert_int_equal(attrs->num, 1);
@@ -460,7 +460,7 @@ void test_parse_dups(void **state)
ret = sdap_parse_entry(test_ctx, &test_ctx->sh, &test_ctx->sm,
map, SDAP_OPTS_USER,
- &attrs, false);
+ &attrs, false, NULL);
assert_int_equal(ret, ERR_OK);
assert_int_equal(attrs->num, 3);
@@ -613,7 +613,7 @@ void test_parse_secondary_oc(void **state)
ret = sdap_parse_entry(test_ctx, &test_ctx->sh, &test_ctx->sm,
map, SDAP_OPTS_GROUP,
- &attrs, false);
+ &attrs, false, NULL);
assert_int_equal(ret, ERR_OK);
talloc_free(map);
@@ -647,7 +647,7 @@ void test_parse_bad_oc(void **state)
ret = sdap_parse_entry(test_ctx, &test_ctx->sh, &test_ctx->sm,
map, SDAP_OPTS_USER,
- &attrs, false);
+ &attrs, false, NULL);
assert_int_not_equal(ret, ERR_OK);
talloc_free(map);
@@ -680,7 +680,7 @@ void test_parse_no_oc(void **state)
ret = sdap_parse_entry(test_ctx, &test_ctx->sh, &test_ctx->sm,
map, SDAP_OPTS_USER,
- &attrs, false);
+ &attrs, false, NULL);
assert_int_not_equal(ret, ERR_OK);
talloc_free(map);
@@ -715,7 +715,7 @@ void test_parse_no_dn(void **state)
ret = sdap_parse_entry(test_ctx, &test_ctx->sh, &test_ctx->sm,
map, SDAP_OPTS_USER,
- &attrs, false);
+ &attrs, false, NULL);
assert_int_not_equal(ret, ERR_OK);
talloc_free(map);
@@ -1159,7 +1159,7 @@ static void test_sdap_get_primary_name(void **state)
assert_int_equal(ret, ERR_OK);
ret = sdap_parse_entry(test_ctx, &test_ctx->sh, &test_ctx->sm,
- map, SDAP_OPTS_IPHOST, &attrs, false);
+ map, SDAP_OPTS_IPHOST, &attrs, false, NULL);
assert_int_equal(ret, ERR_OK);
assert_int_equal(attrs->num, 3);
diff --git a/src/tests/system/tests/test_ad.py b/src/tests/system/tests/test_ad.py
index 6c30ecbcd2b..ae69e4bdeb3 100644
--- a/src/tests/system/tests/test_ad.py
+++ b/src/tests/system/tests/test_ad.py
@@ -111,3 +111,78 @@ def test_authentication__using_the_users_email_address(client: Client, ad: AD, m
assert client.auth.parametrize(method).password(
"uSEr_3@alias-dOMain.com", "Secret123"
), "User uSEr_3@alias-dOMain.com failed login!"
+
+
+@pytest.mark.topology(KnownTopology.AD)
+@pytest.mark.ticket(jira="RHEL-75484")
+@pytest.mark.importance("high")
+def test_range_retrieval__group_membership(client: Client, ad: AD):
+ """
+ :title: Users with with more groups than MaxValRange can be retrieved
+ :description:
+ Testing the feature to retrieve users with more groups than MaxValRange.
+ :setup:
+ 1. Set MaxValRange in lDAPAdminLimits on AD.
+ 2. Create an ad user with number of groups > MaxValRange
+ 3. Clear caches and restart sssd
+ :steps:
+ 1. Retrieve the user running id -u user and check cached content
+ :expectedresults:
+ 1. No groups are missing from the cache
+ :customerscenario: True
+ """
+ size = 152
+ # The lDAPAdminLimits list contains mutiple items in key=value format.
+ # We retrieve the current lDAPAdminLimits, remove MaxValRange from it.
+ # Then we append new MaxValRange and write it back.
+ ad.host.conn.run(
+ rf"""
+ $basedn = '{ad.naming_context}'
+ $policyDN = "CN=Default Query Policy,CN=Query-Policies,CN=Directory"+
+ " Service,CN=Windows NT,CN=Services,CN=Configuration,$basedn"
+ $currentLimits = (Get-ADObject -Identity $policyDN `
+ -Properties lDAPAdminLimits).lDAPAdminLimits
+ Write-Output "Current limits: $currentLimits"
+ $regexPattern = "MaxValRange=.*"
+ $newLimits = @()
+ $newLimits += $currentLimits -notmatch $regexPattern
+ $newLimits += "MaxValRange={size - 2}"
+ Write-Output "New limits: $newLimits"
+ Set-ADObject -Identity $policyDN -Replace @{{lDAPAdminLimits = $newLimits}}
+ """
+ )
+ client.sssd.domain["ldap_id_mapping"] = "false"
+ client.sssd.domain["use_fully_qualified_names"] = "True"
+ client.sssd.start()
+ # Provisioning groups one by one using the framework functions
+ # each in its own ssh call takes too long.
+ ad.host.conn.run(
+ rf"""
+ Import-Module ActiveDirectory
+ $basedn = '{ad.naming_context}'
+ New-ADUser -Name "big-user" -AccountPassword (ConvertTo-SecureString `
+ "Secret123" -AsPlainText -force) -OtherAttributes @{{"uid"="big-user"`
+ ;"uidNumber"=10001;"gidNumber"=20001;"gecos"="big-user";"loginShell"=`
+ "/bin/bash"}} -Enabled $True -Path "cn=users,$basedn" -EmailAddress `
+ big-user@$basedn -GivenName dummyfirstname -Surname dummylastname `
+ -UserPrincipalName big-user@$basedn
+ $count = 0
+ while ($count -lt {size}) {{
+ $gidNumber = 30000 + $count
+ New-ADGroup -Name "group-$count" -GroupScope 'Global' -GroupCategory `
+ 'Security' -OtherAttributes @{{"gidNumber"="$gidNumber"}} -Path "cn=users,$basedn"
+ Add-ADGroupMember -Identity "cn=group-$count,cn=users,$basedn" `
+ -Members "cn=big-user,cn=users,$basedn"
+ $count++
+ }}
+ """
+ )
+ client.sssctl.cache_expire(everything=True)
+ client.host.conn.run(f"id -u big-user@{client.sssd.default_domain}")
+ grps = client.host.conn.run(
+ f"ldbsearch -H /var/lib/sss/db/cache_{client.sssd.default_domain}.ldb"
+ f" '(name=big-user@{client.sssd.default_domain})' | grep -Pio "
+ f"'originalMemberOf: CN=\\K([a-zA-Z0-9-]+)'"
+ ).stdout.splitlines()
+ assert len(grps) != 0, "User is not a member of any group!"
+ assert len(grps) == size, "User's membership is not complete!"