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!"