[SSSD] [PATCHES] Wildcard lookups for InfoPipe
Jakub Hrozek
jhrozek at redhat.com
Mon Jul 13 16:25:13 UTC 2015
On Fri, Jul 10, 2015 at 01:30:07PM +0200, Pavel Březina wrote:
> On 07/09/2015 12:17 PM, Jakub Hrozek wrote:
> >>It may be also better
> >>to move them into the sysdb module?
> >
> >I would do that if we anticipate more listing intefaces using this
> >kind of filter.
>
> I disagree since in my opinion it belongs into sysdb, but I will not insist.
>
> >>If I read the code correctly, you always return only records that were
> >>updated. It this sufficient? I think we need to return all records that
> >>match the provided filter.
> >
> >Please check my logic here, but I think the way it's coded now is
> >safer. On the back end side, we can't reasonably detect if an entry has
> >been removed if we only use the wildcard lookup. So the back end can't
> >reasonably decide which entries have been removed from the server.
> >
> >The reason is the limit. There might be more entries on the server side
> >that those that match the filter, so what the back end sees is just a
> >subset. And the entries outside the limit can be cached by direct
> >lookups, so we simply shouldn't touch them..
> >
> >What the code does now is only returns entries updated by the wildcard
> >lookup. The entries that were not updated are not returned to the
> >fronted -- they just sit in the cache until some application requests
> >them with a direct lookup. The direct lookup can detect removal of the
> >object on the server side and also remove the cached object.
> >
> >Does that make sense?
>
> Yes, thank you for explanation. I think the logic is sound.
>
> >>> if (state->result == NULL || state->result->count == 0 ||
> >>> state->input->type == CACHE_REQ_USER_BY_FILTER ||
> >>> state->input->type == CACHE_REQ_GROUP_BY_FILTER) {
> >>> ret = ENOENT;
> >>> } else {
> >>
> >>I would like to avoid this type of code whenever possible. Can we replace it
> >>with a macro e.g. always_check_cache(state->input) or function?
> >
> >OK, done. Please feel free to suggest a better function name.
> >
> >>
> >>Is it a valid operation to use a filter that needs to be parse into name and
> >>domain (user*@domain)?
> >
> >I don't think so, we have a specialized function for that.
ListByDomainAndName
>
> What function?
>
> *Patch #01 tests: Move N_ELEMENTS definition to tests/common.h*
> ACK
>
> *Patch #02 SYSDB: Add functions to look up multiple entries including name
> and custom filter*
>
> >+static char *enum_filter(TALLOC_CTX *mem_ctx,
> >+ const char *base_filter,
> >+ const char *name_filter,
> >+ const char *addtl_filter)
>
> You are leaking memory here if any of the allocation fails. I know it will
> be freed in the caller but it is not a good practice.
As discussed on IRC, I added a context.
>
> *Patch #03 DP: Add DP_WILDCARD and
> SSS_DP_WILDCARD_USER/SSS_DP_WILDCARD_GROUP*
>
> >+ } else if (info->type == SSS_DP_WILDCARD_USER ||
> >+ info->type == SSS_DP_WILDCARD_GROUP) {
> >+ if (info->extra) {
> >+ filter = talloc_asprintf(info, "%s=%s:%s", DP_WILDCARD,
> >+ info->opt_name, info->extra);
> >+ } else {
> >+ filter = talloc_asprintf(info, "%s=%s", DP_WILDCARD,
> >+ info->opt_name);
> >+ }
>
> Do you think it is safe to use the same prefix for both users and groups
> look up?
yes, because the target is defined with be_type.
>
> *Patch #04 cache_req: Extend cache_req with wildcard lookups*
>
> > case CACHE_REQ_USER_BY_FILTER:
> > case CACHE_REQ_GROUP_BY_FILTER:
> > /* Nothing to do, adding a wildcard request to ncache doesn't
> > * make sense */
>
> >/* Return true if the request can be cached or false if the cache_req
> > * code needs to contact the DP every time
> > */
>
> Can you finish the sentence with dot so it is consistent with the rest of
> the code?
Done.
>
> >static bool cache_req_cachable(struct cache_req_input *input)
>
> How about cache_req_avoid_cache?
OK, renamed.
>
> *Patch #05 UTIL: Add sss_filter_sanitize_ex*
>
> >+ const char has_all_allow_asterisk_expected[] = "\\5c\\28user\\29*name";
>
> Can you add comment with unescaped characters so it is human-readable?
Done.
>
> *Patch #06 LDAP: Fetch users and groups using wildcards*
>
> >@@ -953,6 +991,14 @@ static void groups_get_done(struct tevent_req *subreq)
> > * group we have nothing to do here. */
> > break;
> >
> >+ case BE_FILTER_WILDCARD:
> >+ /* We can't know if all users are up-to-date, especially in a large
> >+ * environment. Do not delete any records, let the responder fetch
> >+ * the entries they are requested in
> >+ */
> >+ break;
>
> Copy and paste error... you meant groups here.
Yes, thanks. Fixed.
>
> *Patch #07 LDAP: Add sdap_get_and_parse_generic_send*
> ACK
>
> *Patch #08 LDAP: Use sdap_get_and_parse_generic_/_recv*
> ACK
>
> *Patch #09 LDAP: Add sdap_lookup_type enum*
> ACK
>
> *Patch #10 LDAP: Add the wildcard_limit option*
>
> >+ldap_pwdlockout_dn = str, None, false
>
> This probably belongs to separate patch...
Yeah, this was wrong.
>
> *Patch #11 IFP: Add wildcard requests*
>
> >size_t ifp_list_ctx_cap(struct ifp_list_ctx *list_ctx, size_t entries)
>
> ifp_list_ctx_remaining_capacity? I had no idea what the function does before
> I read its code.
OK, renamed.
Thanks for the review, new patches are attached.
-------------- next part --------------
>From 0758b5f22664ec45557cdcf62bd87a8ba2cb5e1c Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 25 Mar 2015 10:03:43 +0100
Subject: [PATCH 01/11] tests: Move N_ELEMENTS definition to tests/common.h
Avoids code duplication
---
src/tests/cmocka/test_nested_groups.c | 3 ---
src/tests/cmocka/test_nss_srv.c | 3 ---
src/tests/common.h | 2 ++
src/tests/sbus_codegen_tests.c | 3 ---
4 files changed, 2 insertions(+), 9 deletions(-)
diff --git a/src/tests/cmocka/test_nested_groups.c b/src/tests/cmocka/test_nested_groups.c
index eef9df2dc25c231cb81243f48b759e2fced1a85d..8081ff26102e53b2e453838c3a18e4560ac5317e 100644
--- a/src/tests/cmocka/test_nested_groups.c
+++ b/src/tests/cmocka/test_nested_groups.c
@@ -48,9 +48,6 @@
#define GROUP_BASE_DN "cn=groups," OBJECT_BASE_DN
#define USER_BASE_DN "cn=users," OBJECT_BASE_DN
-#define N_ELEMENTS(arr) \
- (sizeof(arr) / sizeof(arr[0]))
-
struct nested_groups_test_ctx {
struct sss_test_ctx *tctx;
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
index d1a4c16851427a36b123f04cecee5fe5ae2d333d..3ab8d39c44a8bb8cacae20f534dcbeb6ca7dec08 100644
--- a/src/tests/cmocka/test_nss_srv.c
+++ b/src/tests/cmocka/test_nss_srv.c
@@ -41,9 +41,6 @@
#define TEST_ID_PROVIDER "ldap"
#define TEST_DOM_SID "S-1-5-21-444379608-1639770488-2995963434"
-#define N_ELEMENTS(arr) \
- (sizeof(arr) / sizeof(arr[0]))
-
struct nss_test_ctx {
struct sss_test_ctx *tctx;
struct sss_domain_info *subdom;
diff --git a/src/tests/common.h b/src/tests/common.h
index 0b351f5d647a8f72bdbc399c6fe02579d4b4e1be..1c6de2c3d6eb924ba7306bd350f8546d61f30751 100644
--- a/src/tests/common.h
+++ b/src/tests/common.h
@@ -30,6 +30,8 @@
#include "providers/data_provider.h"
#include "providers/ldap/sdap.h"
+#define N_ELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
+
extern TALLOC_CTX *global_talloc_context;
#define check_leaks(ctx, bytes) _check_leaks((ctx), (bytes), __location__)
diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
index 9e9be52e84672eb3ee3afa4e13d5f60047150e98..4637b92b84459041806bb5950e969e988716bec8 100644
--- a/src/tests/sbus_codegen_tests.c
+++ b/src/tests/sbus_codegen_tests.c
@@ -33,9 +33,6 @@
#include "tests/sbus_codegen_tests_generated.h"
#include "util/util_errors.h"
-#define N_ELEMENTS(arr) \
- (sizeof(arr) / sizeof(arr[0]))
-
/* The following 2 macros were taken from check's project source files (0.9.10)
* http://check.sourceforge.net/
*/
--
2.4.3
-------------- next part --------------
>From bef6bbd84eeb8ea27477987325be01a0c6fee19a Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 24 Mar 2015 23:24:22 +0100
Subject: [PATCH 02/11] SYSDB: Add functions to look up multiple entries
including name and custom filter
Related:
https://fedorahosted.org/sssd/ticket/2553
Adds new sysdb function:
- sysdb_enumpwent_filter
- sysdb_enumpwent_filter_with_views
- sysdb_enumgrent_filter
- sysdb_enumgrent_filter_with_views
These are similar to enumeration functions, but optionally allow to
specify a filter to be applied on user/group names. Also an additional
custom filter can be applied.
---
src/db/sysdb.h | 24 ++
src/db/sysdb_search.c | 252 ++++++++++++------
src/tests/cmocka/test_sysdb_views.c | 494 ++++++++++++++++++++++++++++++++++++
3 files changed, 691 insertions(+), 79 deletions(-)
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 48dd26dd294333b265b69b28cd3b5d37f1293b43..0f745ccb1a646d77ba4ad3d714d5f4dce0a51211 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -601,10 +601,22 @@ int sysdb_enumpwent(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
struct ldb_result **res);
+int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name_filter,
+ const char *addtl_filter,
+ struct ldb_result **res);
+
int sysdb_enumpwent_with_views(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
struct ldb_result **res);
+int sysdb_enumpwent_filter_with_views(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name_filter,
+ const char *addtl_filter,
+ struct ldb_result **res);
+
int sysdb_getgrnam(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
const char *name,
@@ -619,10 +631,22 @@ int sysdb_enumgrent(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
struct ldb_result **res);
+int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name_filter,
+ const char *addtl_filter,
+ struct ldb_result **res);
+
int sysdb_enumgrent_with_views(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
struct ldb_result **res);
+int sysdb_enumgrent_filter_with_views(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name_filter,
+ const char *addtl_filter,
+ struct ldb_result **res);
+
struct sysdb_netgroup_ctx {
enum {SYSDB_NETGROUP_TRIPLE_VAL, SYSDB_NETGROUP_GROUP_VAL} type;
union {
diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
index a8dcc9f8d6617be8e8fb82a1c6360c6df9726a37..dd9c8ff13e7ee3ca2e134094ae7ff242ad74f4ba 100644
--- a/src/db/sysdb_search.c
+++ b/src/db/sysdb_search.c
@@ -255,44 +255,104 @@ done:
return ret;
}
+static char *enum_filter(TALLOC_CTX *mem_ctx,
+ const char *base_filter,
+ const char *name_filter,
+ const char *addtl_filter)
+{
+ char *filter;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ if (name_filter == NULL && addtl_filter == NULL) {
+ filter = talloc_strdup(mem_ctx, base_filter);
+ } else {
+ filter = talloc_asprintf(mem_ctx, "(&%s", base_filter);
+
+ if (filter != NULL && name_filter != NULL) {
+ filter = talloc_asprintf_append(filter, "(%s=%s)",
+ SYSDB_NAME, name_filter);
+ }
+
+ if (filter != NULL && addtl_filter != NULL) {
+ filter = talloc_asprintf_append(filter, "%s", addtl_filter);
+ }
+
+ if (filter != NULL) {
+ filter = talloc_asprintf_append(filter, ")");
+ }
+ }
+
+ if (filter) {
+ talloc_steal(mem_ctx, filter);
+ }
+
+ talloc_free(tmp_ctx);
+ return filter;
+}
+
+int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name_filter,
+ const char *addtl_filter,
+ struct ldb_result **_res)
+{
+ TALLOC_CTX *tmp_ctx;
+ static const char *attrs[] = SYSDB_PW_ATTRS;
+ char *filter = NULL;
+ struct ldb_dn *base_dn;
+ struct ldb_result *res;
+ int ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ base_dn = sysdb_user_base_dn(tmp_ctx, domain);
+ if (!base_dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ filter = enum_filter(tmp_ctx, SYSDB_PWENT_FILTER,
+ name_filter, addtl_filter);
+ if (filter == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ DEBUG(SSSDBG_TRACE_LIBS, "Searching cache with [%s]\n", filter);
+
+ ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
+ LDB_SCOPE_SUBTREE, attrs, "%s", filter);
+ if (ret) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ *_res = talloc_steal(mem_ctx, res);
+
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
int sysdb_enumpwent(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
struct ldb_result **_res)
{
- TALLOC_CTX *tmp_ctx;
- static const char *attrs[] = SYSDB_PW_ATTRS;
- struct ldb_dn *base_dn;
- struct ldb_result *res;
- int ret;
-
- tmp_ctx = talloc_new(NULL);
- if (!tmp_ctx) {
- return ENOMEM;
- }
-
- base_dn = sysdb_user_base_dn(tmp_ctx, domain);
- if (!base_dn) {
- ret = ENOMEM;
- goto done;
- }
-
- ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
- LDB_SCOPE_SUBTREE, attrs, SYSDB_PWENT_FILTER);
- if (ret) {
- ret = sysdb_error_to_errno(ret);
- goto done;
- }
-
- *_res = talloc_steal(mem_ctx, res);
-
-done:
- talloc_zfree(tmp_ctx);
- return ret;
+ return sysdb_enumpwent_filter(mem_ctx, domain, NULL, 0, _res);
}
-int sysdb_enumpwent_with_views(TALLOC_CTX *mem_ctx,
- struct sss_domain_info *domain,
- struct ldb_result **_res)
+int sysdb_enumpwent_filter_with_views(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name_filter,
+ const char *addtl_filter,
+ struct ldb_result **_res)
{
TALLOC_CTX *tmp_ctx;
struct ldb_result *res;
@@ -305,7 +365,7 @@ int sysdb_enumpwent_with_views(TALLOC_CTX *mem_ctx,
return ENOMEM;
}
- ret = sysdb_enumpwent(tmp_ctx, domain, &res);
+ ret = sysdb_enumpwent_filter(tmp_ctx, domain, name_filter, addtl_filter, &res);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_enumpwent failed.\n");
goto done;
@@ -331,6 +391,13 @@ done:
return ret;
}
+int sysdb_enumpwent_with_views(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ struct ldb_result **_res)
+{
+ return sysdb_enumpwent_filter_with_views(mem_ctx, domain, NULL, NULL, _res);
+}
+
/* groups */
static int mpg_convert(struct ldb_message *msg)
@@ -662,57 +729,77 @@ done:
return ret;
}
+int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name_filter,
+ const char *addtl_filter,
+ struct ldb_result **_res)
+{
+ TALLOC_CTX *tmp_ctx;
+ static const char *attrs[] = SYSDB_GRSRC_ATTRS;
+ const char *filter = NULL;
+ const char *base_filter;
+ struct ldb_dn *base_dn;
+ struct ldb_result *res;
+ int ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ if (domain->mpg) {
+ base_filter = SYSDB_GRENT_MPG_FILTER;
+ base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
+ SYSDB_DOM_BASE, domain->name);
+ } else {
+ base_filter = SYSDB_GRENT_FILTER;
+ base_dn = sysdb_group_base_dn(tmp_ctx, domain);
+ }
+ if (!base_dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ filter = enum_filter(tmp_ctx, base_filter,
+ name_filter, addtl_filter);
+ if (filter == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ DEBUG(SSSDBG_TRACE_LIBS, "Searching cache with [%s]\n", filter);
+
+ ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
+ LDB_SCOPE_SUBTREE, attrs, "%s", filter);
+ if (ret) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ ret = mpg_res_convert(res);
+ if (ret) {
+ goto done;
+ }
+
+ *_res = talloc_steal(mem_ctx, res);
+
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
int sysdb_enumgrent(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
struct ldb_result **_res)
{
- TALLOC_CTX *tmp_ctx;
- static const char *attrs[] = SYSDB_GRSRC_ATTRS;
- const char *fmt_filter;
- struct ldb_dn *base_dn;
- struct ldb_result *res;
- int ret;
-
- tmp_ctx = talloc_new(NULL);
- if (!tmp_ctx) {
- return ENOMEM;
- }
-
- if (domain->mpg) {
- fmt_filter = SYSDB_GRENT_MPG_FILTER;
- base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
- SYSDB_DOM_BASE, domain->name);
- } else {
- fmt_filter = SYSDB_GRENT_FILTER;
- base_dn = sysdb_group_base_dn(tmp_ctx, domain);
- }
- if (!base_dn) {
- ret = ENOMEM;
- goto done;
- }
-
- ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
- LDB_SCOPE_SUBTREE, attrs, "%s", fmt_filter);
- if (ret) {
- ret = sysdb_error_to_errno(ret);
- goto done;
- }
-
- ret = mpg_res_convert(res);
- if (ret) {
- goto done;
- }
-
- *_res = talloc_steal(mem_ctx, res);
-
-done:
- talloc_zfree(tmp_ctx);
- return ret;
+ return sysdb_enumgrent_filter(mem_ctx, domain, NULL, 0, _res);
}
-int sysdb_enumgrent_with_views(TALLOC_CTX *mem_ctx,
- struct sss_domain_info *domain,
- struct ldb_result **_res)
+int sysdb_enumgrent_filter_with_views(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name_filter,
+ const char *addtl_filter,
+ struct ldb_result **_res)
{
TALLOC_CTX *tmp_ctx;
struct ldb_result *res;
@@ -725,7 +812,7 @@ int sysdb_enumgrent_with_views(TALLOC_CTX *mem_ctx,
return ENOMEM;
}
- ret = sysdb_enumgrent(tmp_ctx, domain,&res);
+ ret = sysdb_enumgrent_filter(tmp_ctx, domain, name_filter, addtl_filter, &res);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_enumgrent failed.\n");
goto done;
@@ -759,6 +846,13 @@ done:
return ret;
}
+int sysdb_enumgrent_with_views(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ struct ldb_result **_res)
+{
+ return sysdb_enumgrent_filter_with_views(mem_ctx, domain, NULL, NULL, _res);
+}
+
int sysdb_initgroups(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
const char *name,
diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
index 69118cd87a172696f8220e1446df7a856e368cb6..1fb598219e9ee581e465ddbb32ba9f2544600c26 100644
--- a/src/tests/cmocka/test_sysdb_views.c
+++ b/src/tests/cmocka/test_sysdb_views.c
@@ -45,6 +45,7 @@
#define TEST_USER_HOMEDIR "/home/home"
#define TEST_USER_SHELL "/bin/shell"
#define TEST_USER_SID "S-1-2-3-4"
+#define TEST_GID_OVERRIDE_BASE 100
struct sysdb_test_ctx {
struct sysdb_ctx *sysdb;
@@ -108,6 +109,7 @@ static int _setup_sysdb_tests(struct sysdb_test_ctx **ctx, bool enumerate)
TESTS_PATH, &test_ctx->domain);
assert_int_equal(ret, EOK);
+ test_ctx->domain->has_views = true;
test_ctx->sysdb = test_ctx->domain->sysdb;
*ctx = test_ctx;
@@ -115,6 +117,7 @@ static int _setup_sysdb_tests(struct sysdb_test_ctx **ctx, bool enumerate)
}
#define setup_sysdb_tests(ctx) _setup_sysdb_tests((ctx), false)
+#define setup_sysdb_enum_tests(ctx) _setup_sysdb_tests((ctx), true)
static int test_sysdb_setup(void **state)
{
@@ -426,6 +429,473 @@ void test_sysdb_invalidate_overrides(void **state)
assert_int_equal(ldb_msg_find_attr_as_uint64(msg, SYSDB_CACHE_EXPIRE, 0),
1);
assert_null(ldb_msg_find_attr_as_string(msg, SYSDB_OVERRIDE_DN, NULL));
+
+ ret = sysdb_delete_user(test_ctx->domain, TEST_USER_NAME, 0);
+ assert_int_equal(ret, EOK);
+}
+
+static const char *users[] = { "alice", "bob", "barney", NULL };
+
+static void enum_test_user_override(struct sysdb_test_ctx *test_ctx,
+ const char *name)
+{
+ int ret;
+ struct sysdb_attrs *attrs;
+ struct ldb_dn *dn;
+ TALLOC_CTX *tmp_ctx;
+ const char *anchor;
+ const char *override_gecos;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ attrs = sysdb_new_attrs(tmp_ctx);
+ assert_non_null(attrs);
+
+ dn = sysdb_user_dn(tmp_ctx, test_ctx->domain, name);
+ assert_non_null(dn);
+
+ anchor = talloc_asprintf(tmp_ctx, "%s%s", TEST_ANCHOR_PREFIX, name);
+ ret = sysdb_attrs_add_string(attrs, SYSDB_OVERRIDE_ANCHOR_UUID, anchor);
+ assert_int_equal(ret, EOK);
+
+ override_gecos = talloc_asprintf(attrs, "%s_GECOS_OVERRIDE", name);
+ ret = sysdb_attrs_add_string(attrs, SYSDB_GECOS, override_gecos);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_store_override(test_ctx->domain, TEST_VIEW_NAME,
+ SYSDB_MEMBER_USER, attrs, dn);
+ assert_int_equal(ret, EOK);
+
+ talloc_free(tmp_ctx);
+}
+
+static void enum_test_add_users(struct sysdb_test_ctx *test_ctx,
+ const char *usernames[])
+{
+ int i;
+ int ret;
+ struct sysdb_attrs *attrs;
+
+ for (i = 0; usernames[i] != NULL; i++) {
+ attrs = talloc(test_ctx, struct sysdb_attrs);
+ assert_non_null(attrs);
+
+ ret = sysdb_store_user(test_ctx->domain, usernames[i],
+ NULL, 0, 0, usernames[i], "/", "/bin/sh",
+ NULL, NULL, NULL, 1, 1234 + i);
+ assert_int_equal(ret, EOK);
+
+ enum_test_user_override(test_ctx, usernames[i]);
+
+ talloc_free(attrs);
+ }
+}
+
+static void enum_test_del_users(struct sss_domain_info *dom,
+ const char *usernames[])
+{
+ int i;
+ int ret;
+
+ for (i = 0; usernames[i] != NULL; i++) {
+ ret = sysdb_delete_user(dom, usernames[i], 0);
+ if (ret != EOK && ret != ENOENT) {
+ fail();
+ }
+ }
+}
+
+static int test_enum_users_setup(void **state)
+{
+ int ret;
+ struct sysdb_test_ctx *test_ctx;
+
+ assert_true(leak_check_setup());
+
+ ret = setup_sysdb_enum_tests(&test_ctx);
+ assert_int_equal(ret, EOK);
+
+ enum_test_add_users(test_ctx, users);
+
+ *state = (void *) test_ctx;
+ return 0;
+}
+
+static void assert_user_attrs(struct ldb_message *msg,
+ const char *name,
+ bool has_views)
+{
+ const char *str;
+
+ str = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+ assert_string_equal(str, name);
+ str = ldb_msg_find_attr_as_string(msg, SYSDB_GECOS, NULL);
+ assert_string_equal(str, name);
+
+ str = ldb_msg_find_attr_as_string(msg, OVERRIDE_PREFIX SYSDB_GECOS, NULL);
+ if (has_views) {
+ char *override;
+
+ assert_non_null(str);
+ override = talloc_asprintf(msg, "%s_GECOS_OVERRIDE", name);
+ assert_non_null(override);
+
+ assert_string_equal(str, override);
+ talloc_free(override);
+ } else {
+ assert_null(str);
+ }
+}
+
+static int test_enum_users_teardown(void **state)
+{
+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct sysdb_test_ctx);
+
+ enum_test_del_users(test_ctx->domain, users);
+ return test_sysdb_teardown(state);
+}
+
+static void check_enumpwent(int ret, struct ldb_result *res, bool views)
+{
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, N_ELEMENTS(users)-1);
+ assert_user_attrs(res->msgs[0], "barney", views);
+ assert_user_attrs(res->msgs[1], "alice", views);
+ assert_user_attrs(res->msgs[2], "bob", views);
+}
+
+static void test_sysdb_enumpwent(void **state)
+{
+ int ret;
+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct sysdb_test_ctx);
+ struct ldb_result *res;
+
+ ret = sysdb_enumpwent(test_ctx, test_ctx->domain, &res);
+ check_enumpwent(ret, res, false);
+}
+
+static void test_sysdb_enumpwent_views(void **state)
+{
+ int ret;
+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct sysdb_test_ctx);
+ struct ldb_result *res;
+
+ ret = sysdb_enumpwent_with_views(test_ctx, test_ctx->domain, &res);
+ check_enumpwent(ret, res, true);
+}
+
+static void test_sysdb_enumpwent_filter(void **state)
+{
+ int ret;
+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct sysdb_test_ctx);
+ struct ldb_result *res;
+ char *addtl_filter;
+
+ ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "a*", 0, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 1);
+ assert_user_attrs(res->msgs[0], "alice", false);
+
+ ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "b*", 0, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 2);
+ assert_user_attrs(res->msgs[0], "barney", false);
+ assert_user_attrs(res->msgs[1], "bob", false);
+
+ ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "c*", 0, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 0);
+
+ ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "*", 0, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, N_ELEMENTS(users)-1);
+
+ /* Test searching based on time as well */
+ addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
+ SYSDB_LAST_UPDATE, 1233);
+ ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "a*", addtl_filter, &res);
+ talloc_free(addtl_filter);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 0);
+
+ addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
+ SYSDB_LAST_UPDATE, 1234);
+ ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "a*", addtl_filter, &res);
+ talloc_free(addtl_filter);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 1);
+ assert_user_attrs(res->msgs[0], "alice", false);
+}
+
+static void test_sysdb_enumpwent_filter_views(void **state)
+{
+ int ret;
+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct sysdb_test_ctx);
+ struct ldb_result *res;
+ char *addtl_filter;
+
+ ret = sysdb_enumpwent_filter_with_views(test_ctx, test_ctx->domain,
+ "a*", NULL, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 1);
+ assert_user_attrs(res->msgs[0], "alice", true);
+
+ ret = sysdb_enumpwent_filter_with_views(test_ctx, test_ctx->domain,
+ "b*", NULL, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 2);
+ assert_user_attrs(res->msgs[0], "barney", true);
+ assert_user_attrs(res->msgs[1], "bob", true);
+
+ addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
+ SYSDB_LAST_UPDATE, 1235);
+ ret = sysdb_enumpwent_filter_with_views(test_ctx, test_ctx->domain,
+ "b*", addtl_filter, &res);
+ talloc_free(addtl_filter);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 1);
+ assert_user_attrs(res->msgs[0], "bob", true);
+
+ ret = sysdb_enumpwent_filter_with_views(test_ctx,
+ test_ctx->domain, "c*", NULL, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 0);
+
+ ret = sysdb_enumpwent_filter_with_views(test_ctx,
+ test_ctx->domain, "*", NULL, &res);
+ check_enumpwent(ret, res, true);
+}
+
+static const char *groups[] = { "one", "two", "three", NULL };
+
+static void enum_test_group_override(struct sysdb_test_ctx *test_ctx,
+ const char *name,
+ unsigned override_gid)
+{
+ int ret;
+ struct sysdb_attrs *attrs;
+ struct ldb_dn *dn;
+ TALLOC_CTX *tmp_ctx;
+ const char *anchor;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ attrs = sysdb_new_attrs(tmp_ctx);
+ assert_non_null(attrs);
+
+ dn = sysdb_group_dn(tmp_ctx, test_ctx->domain, name);
+ assert_non_null(dn);
+
+ anchor = talloc_asprintf(tmp_ctx, "%s%s", TEST_ANCHOR_PREFIX, name);
+ ret = sysdb_attrs_add_string(attrs, SYSDB_OVERRIDE_ANCHOR_UUID, anchor);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, override_gid);
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_store_override(test_ctx->domain, TEST_VIEW_NAME,
+ SYSDB_MEMBER_GROUP, attrs, dn);
+ assert_int_equal(ret, EOK);
+
+ talloc_free(tmp_ctx);
+}
+
+static void enum_test_add_groups(struct sysdb_test_ctx *test_ctx,
+ const char *groupnames[])
+{
+ int i;
+ int ret;
+ struct sysdb_attrs *attrs;
+
+ for (i = 0; groupnames[i] != NULL; i++) {
+ attrs = talloc(test_ctx, struct sysdb_attrs);
+ assert_non_null(attrs);
+
+ ret = sysdb_store_group(test_ctx->domain, groupnames[i],
+ 0, NULL, 1, 1234 + i);
+ assert_int_equal(ret, EOK);
+
+ enum_test_group_override(test_ctx, groupnames[i],
+ TEST_GID_OVERRIDE_BASE + i);
+ talloc_free(attrs);
+ }
+}
+
+static void enum_test_del_groups(struct sss_domain_info *dom,
+ const char *groupnames[])
+{
+ int i;
+ int ret;
+
+ for (i = 0; groupnames[i] != NULL; i++) {
+ ret = sysdb_delete_group(dom, groupnames[i], 0);
+ if (ret != EOK && ret != ENOENT) {
+ fail();
+ }
+ }
+}
+
+static int test_enum_groups_setup(void **state)
+{
+ int ret;
+ struct sysdb_test_ctx *test_ctx;
+
+ assert_true(leak_check_setup());
+
+ ret = setup_sysdb_enum_tests(&test_ctx);
+ assert_int_equal(ret, EOK);
+
+ enum_test_add_groups(test_ctx, groups);
+
+ *state = (void *) test_ctx;
+ return 0;
+}
+
+static int test_enum_groups_teardown(void **state)
+{
+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct sysdb_test_ctx);
+
+ enum_test_del_groups(test_ctx->domain, groups);
+ return test_sysdb_teardown(state);
+}
+
+static void assert_group_attrs(struct ldb_message *msg,
+ const char *name,
+ unsigned expected_override_gid)
+{
+ const char *str;
+ unsigned gid;
+
+ str = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+ assert_string_equal(str, name);
+
+ if (expected_override_gid) {
+ gid = ldb_msg_find_attr_as_uint64(msg,
+ OVERRIDE_PREFIX SYSDB_GIDNUM, 0);
+ assert_int_equal(gid, expected_override_gid);
+ }
+}
+
+static void check_enumgrent(int ret, struct ldb_result *res, bool views)
+{
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, N_ELEMENTS(groups)-1);
+ assert_group_attrs(res->msgs[0], "three", views ? TEST_GID_OVERRIDE_BASE + 2 : 0);
+ assert_group_attrs(res->msgs[1], "one", views ? TEST_GID_OVERRIDE_BASE : 0);
+ assert_group_attrs(res->msgs[2], "two", views ? TEST_GID_OVERRIDE_BASE + 1 : 0);
+}
+
+static void test_sysdb_enumgrent(void **state)
+{
+ int ret;
+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct sysdb_test_ctx);
+ struct ldb_result *res;
+
+ ret = sysdb_enumgrent(test_ctx, test_ctx->domain, &res);
+ check_enumgrent(ret, res, false);
+}
+
+static void test_sysdb_enumgrent_views(void **state)
+{
+ int ret;
+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct sysdb_test_ctx);
+ struct ldb_result *res;
+
+ ret = sysdb_enumgrent_with_views(test_ctx, test_ctx->domain, &res);
+ check_enumgrent(ret, res, true);
+}
+
+static void test_sysdb_enumgrent_filter(void **state)
+{
+ int ret;
+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct sysdb_test_ctx);
+ struct ldb_result *res;
+ char *addtl_filter;
+
+ ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "o*", 0, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 1);
+ assert_group_attrs(res->msgs[0], "one", 0);
+
+ ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "t*", 0, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 2);
+ assert_group_attrs(res->msgs[0], "three", 0);
+ assert_group_attrs(res->msgs[1], "two", 0);
+
+ ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "x*", 0, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 0);
+
+ ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "*", 0, &res);
+ check_enumgrent(ret, res, false);
+
+ addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
+ SYSDB_LAST_UPDATE, 1233);
+ ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "o*", addtl_filter, &res);
+ talloc_free(addtl_filter);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 0);
+
+ addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
+ SYSDB_LAST_UPDATE, 1234);
+ ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "o*", addtl_filter, &res);
+ talloc_free(addtl_filter);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 1);
+ assert_group_attrs(res->msgs[0], "one", 0);
+
+}
+
+static void test_sysdb_enumgrent_filter_views(void **state)
+{
+ int ret;
+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct sysdb_test_ctx);
+ struct ldb_result *res;
+ char *addtl_filter;
+
+ ret = sysdb_enumgrent_filter_with_views(test_ctx, test_ctx->domain,
+ "o*", NULL, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 1);
+ assert_group_attrs(res->msgs[0], "one", TEST_GID_OVERRIDE_BASE);
+
+ ret = sysdb_enumgrent_filter_with_views(test_ctx, test_ctx->domain,
+ "t*", NULL, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 2);
+ assert_group_attrs(res->msgs[0], "three", TEST_GID_OVERRIDE_BASE + 2);
+ assert_group_attrs(res->msgs[1], "two", TEST_GID_OVERRIDE_BASE + 1);
+
+ addtl_filter = talloc_asprintf(test_ctx, "(%s<=%d)",
+ SYSDB_LAST_UPDATE, 1235);
+ ret = sysdb_enumgrent_filter_with_views(test_ctx, test_ctx->domain,
+ "t*", addtl_filter, &res);
+ talloc_free(addtl_filter);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 1);
+ assert_group_attrs(res->msgs[0], "two", TEST_GID_OVERRIDE_BASE + 1);
+
+ ret = sysdb_enumgrent_filter_with_views(test_ctx, test_ctx->domain,
+ "x*", NULL, &res);
+ assert_int_equal(ret, EOK);
+ assert_int_equal(res->count, 0);
+
+ ret = sysdb_enumgrent_filter_with_views(test_ctx, test_ctx->domain,
+ "*", NULL, &res);
+ check_enumgrent(ret, res, true);
}
int main(int argc, const char *argv[])
@@ -453,6 +923,30 @@ int main(int argc, const char *argv[])
test_sysdb_setup, test_sysdb_teardown),
cmocka_unit_test_setup_teardown(test_sysdb_invalidate_overrides,
test_sysdb_setup, test_sysdb_teardown),
+ cmocka_unit_test_setup_teardown(test_sysdb_enumpwent,
+ test_enum_users_setup,
+ test_enum_users_teardown),
+ cmocka_unit_test_setup_teardown(test_sysdb_enumpwent_views,
+ test_enum_users_setup,
+ test_enum_users_teardown),
+ cmocka_unit_test_setup_teardown(test_sysdb_enumpwent_filter,
+ test_enum_users_setup,
+ test_enum_users_teardown),
+ cmocka_unit_test_setup_teardown(test_sysdb_enumpwent_filter_views,
+ test_enum_users_setup,
+ test_enum_users_teardown),
+ cmocka_unit_test_setup_teardown(test_sysdb_enumgrent,
+ test_enum_groups_setup,
+ test_enum_groups_teardown),
+ cmocka_unit_test_setup_teardown(test_sysdb_enumgrent_views,
+ test_enum_groups_setup,
+ test_enum_groups_teardown),
+ cmocka_unit_test_setup_teardown(test_sysdb_enumgrent_filter,
+ test_enum_groups_setup,
+ test_enum_groups_teardown),
+ cmocka_unit_test_setup_teardown(test_sysdb_enumgrent_filter_views,
+ test_enum_groups_setup,
+ test_enum_groups_teardown),
};
/* Set debug level to invalid value so we can deside if -d 0 was used. */
--
2.4.3
-------------- next part --------------
>From 4143f5a8d6c9b26834d99eb3a7b7aea5543e6d05 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 4 May 2015 12:34:32 +0200
Subject: [PATCH 03/11] DP: Add DP_WILDCARD and
SSS_DP_WILDCARD_USER/SSS_DP_WILDCARD_GROUP
Related:
https://fedorahosted.org/sssd/ticket/2553
Extends the Data Provider interface and the responder<->Data provider
interface with wildcard lookups.
The patch uses a new "wildcard" prefix rather than reusing the existing
user/group prefixes.
---
src/providers/data_provider.h | 4 ++++
src/providers/data_provider_be.c | 5 +++++
src/responder/common/responder.h | 4 +++-
src/responder/common/responder_dp.c | 11 +++++++++++
4 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
index 13a700308e9c9d1a80c0310dbb1c17de33607498..510c63ce41c99314ec8fcf11fffb2e66082e8951 100644
--- a/src/providers/data_provider.h
+++ b/src/providers/data_provider.h
@@ -129,6 +129,7 @@
#define BE_FILTER_SECID 4
#define BE_FILTER_UUID 5
#define BE_FILTER_CERT 6
+#define BE_FILTER_WILDCARD 7
#define BE_REQ_USER 0x0001
#define BE_REQ_GROUP 0x0002
@@ -153,6 +154,9 @@
#define DP_SEC_ID_LEN (sizeof(DP_SEC_ID) - 1)
#define DP_CERT_LEN (sizeof(DP_CERT) - 1)
+#define DP_WILDCARD "wildcard"
+#define DP_WILDCARD_LEN (sizeof(DP_WILDCARD) - 1)
+
#define EXTRA_NAME_IS_UPN "U"
#define EXTRA_INPUT_MAYBE_WITH_VIEW "V"
diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
index f5bdfb676011975defa4c5a734d420c8694f3bdd..d147630248f0a24f5a632760b55b9284a6928e40 100644
--- a/src/providers/data_provider_be.c
+++ b/src/providers/data_provider_be.c
@@ -1204,6 +1204,11 @@ static int be_get_account_info(struct sbus_request *dbus_req, void *user_data)
ret = split_name_extended(req, &filter[DP_CERT_LEN + 1],
&req->filter_value,
&req->extra_value);
+ } else if (strncmp(filter, DP_WILDCARD"=", DP_WILDCARD_LEN + 1) == 0) {
+ req->filter_type = BE_FILTER_WILDCARD;
+ ret = split_name_extended(req, &filter[DP_WILDCARD_LEN + 1],
+ &req->filter_value,
+ &req->extra_value);
} else if (strcmp(filter, ENUM_INDICATOR) == 0) {
req->filter_type = BE_FILTER_ENUM;
req->filter_value = NULL;
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index bd0250d52aae1efdac3bc0847f692542c6cfb6d2..4d927cfe321bf3ad240b7c175568081ea73ab652 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -282,7 +282,9 @@ enum sss_dp_acct_type {
SSS_DP_SERVICES,
SSS_DP_SECID,
SSS_DP_USER_AND_GROUP,
- SSS_DP_CERT
+ SSS_DP_CERT,
+ SSS_DP_WILDCARD_USER,
+ SSS_DP_WILDCARD_GROUP,
};
struct tevent_req *
diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c
index f752c94c37fd0efa0d072ef8c567bd875a08e6f7..f7f8df04e80439d2d02df3e4d2aa4f3576997f36 100644
--- a/src/responder/common/responder_dp.c
+++ b/src/responder/common/responder_dp.c
@@ -528,9 +528,11 @@ sss_dp_get_account_msg(void *pvt)
switch (info->type) {
case SSS_DP_USER:
+ case SSS_DP_WILDCARD_USER:
be_type = BE_REQ_USER;
break;
case SSS_DP_GROUP:
+ case SSS_DP_WILDCARD_GROUP:
be_type = BE_REQ_GROUP;
break;
case SSS_DP_INITGROUPS:
@@ -574,6 +576,15 @@ sss_dp_get_account_msg(void *pvt)
filter = talloc_asprintf(info, "%s=%s", DP_CERT,
info->opt_name);
}
+ } else if (info->type == SSS_DP_WILDCARD_USER ||
+ info->type == SSS_DP_WILDCARD_GROUP) {
+ if (info->extra) {
+ filter = talloc_asprintf(info, "%s=%s:%s", DP_WILDCARD,
+ info->opt_name, info->extra);
+ } else {
+ filter = talloc_asprintf(info, "%s=%s", DP_WILDCARD,
+ info->opt_name);
+ }
} else {
if (info->extra) {
filter = talloc_asprintf(info, "name=%s:%s",
--
2.4.3
-------------- next part --------------
>From f0c86a2e5ba10486def8e73f19bda4dca78fe407 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Tue, 24 Mar 2015 23:24:50 +0100
Subject: [PATCH 04/11] cache_req: Extend cache_req with wildcard lookups
Related:
https://fedorahosted.org/sssd/ticket/2553
Adds two new functions to the cache_req API:
- cache_req_user_by_filter_send
- cache_req_group_by_filter_send
These functions can be used to retrieve users or groups that match a
specified filter.
Also renames a variable to avoid constant confusion -- the variable is
only used for debug output.
---
src/responder/common/responder_cache_req.c | 156 ++++++++++-
src/responder/common/responder_cache_req.h | 24 +-
src/tests/cmocka/test_responder_cache_req.c | 414 +++++++++++++++++++++++++++-
3 files changed, 579 insertions(+), 15 deletions(-)
diff --git a/src/responder/common/responder_cache_req.c b/src/responder/common/responder_cache_req.c
index dd81abadf71c5e10e7bc2ea2490429a49bdc0270..e7099f171d7ef39af7b146a524dadc38a9165e22 100644
--- a/src/responder/common/responder_cache_req.c
+++ b/src/responder/common/responder_cache_req.c
@@ -28,6 +28,44 @@
#include "responder/common/responder_cache_req.h"
#include "providers/data_provider.h"
+static errno_t updated_users_by_filter(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name_filter,
+ time_t since,
+ struct ldb_result **_res)
+{
+ int ret;
+ char *recent_filter;
+
+ recent_filter = talloc_asprintf(mem_ctx, "(%s>=%lu)",
+ SYSDB_LAST_UPDATE, since);
+ ret = sysdb_enumpwent_filter_with_views(mem_ctx, domain,
+ name_filter, recent_filter,
+ _res);
+ talloc_free(recent_filter);
+
+ return ret;
+}
+
+static errno_t updated_groups_by_filter(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name_filter,
+ time_t since,
+ struct ldb_result **_res)
+{
+ int ret;
+ char *recent_filter;
+
+ recent_filter = talloc_asprintf(mem_ctx, "(%s>=%lu)",
+ SYSDB_LAST_UPDATE, since);
+ ret = sysdb_enumgrent_filter_with_views(mem_ctx, domain,
+ name_filter, recent_filter,
+ _res);
+ talloc_free(recent_filter);
+
+ return ret;
+}
+
struct cache_req_input {
enum cache_req_type type;
@@ -51,6 +89,8 @@ struct cache_req_input {
/* Fully qualified object name used in debug messages. */
const char *debug_fqn;
+ /* Time when the request started. Useful for by-filter lookups */
+ time_t req_start;
};
struct cache_req_input *
@@ -68,11 +108,14 @@ cache_req_input_create(TALLOC_CTX *mem_ctx,
}
input->type = type;
+ input->req_start = time(NULL);
/* Check that input parameters match selected type. */
switch (input->type) {
case CACHE_REQ_USER_BY_NAME:
case CACHE_REQ_GROUP_BY_NAME:
+ case CACHE_REQ_USER_BY_FILTER:
+ case CACHE_REQ_GROUP_BY_FILTER:
case CACHE_REQ_INITGROUPS:
if (name == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
@@ -121,9 +164,18 @@ cache_req_input_create(TALLOC_CTX *mem_ctx,
case CACHE_REQ_INITGROUPS:
input->dp_type = SSS_DP_INITGROUPS;
break;
+
case CACHE_REQ_USER_BY_CERT:
input->dp_type = SSS_DP_CERT;
break;
+
+ case CACHE_REQ_USER_BY_FILTER:
+ input->dp_type = SSS_DP_WILDCARD_USER;
+ break;
+
+ case CACHE_REQ_GROUP_BY_FILTER:
+ input->dp_type = SSS_DP_WILDCARD_GROUP;
+ break;
}
return input;
@@ -157,7 +209,7 @@ cache_req_input_set_domain(struct cache_req_input *input,
{
TALLOC_CTX *tmp_ctx = NULL;
const char *name = NULL;
- const char *fqn = NULL;
+ const char *debug_fqn = NULL;
errno_t ret;
tmp_ctx = talloc_new(NULL);
@@ -171,6 +223,8 @@ cache_req_input_set_domain(struct cache_req_input *input,
switch (input->type) {
case CACHE_REQ_USER_BY_NAME:
case CACHE_REQ_GROUP_BY_NAME:
+ case CACHE_REQ_USER_BY_FILTER:
+ case CACHE_REQ_GROUP_BY_FILTER:
case CACHE_REQ_INITGROUPS:
name = sss_get_cased_name(tmp_ctx, input->orig_name,
domain->case_sensitive);
@@ -185,8 +239,8 @@ cache_req_input_set_domain(struct cache_req_input *input,
goto done;
}
- fqn = talloc_asprintf(tmp_ctx, "%s@%s", name, domain->name);
- if (fqn == NULL) {
+ debug_fqn = talloc_asprintf(tmp_ctx, "%s@%s", name, domain->name);
+ if (debug_fqn == NULL) {
ret = ENOMEM;
goto done;
}
@@ -194,16 +248,16 @@ cache_req_input_set_domain(struct cache_req_input *input,
break;
case CACHE_REQ_USER_BY_ID:
- fqn = talloc_asprintf(tmp_ctx, "UID:%d@%s", input->id, domain->name);
- if (fqn == NULL) {
+ debug_fqn = talloc_asprintf(tmp_ctx, "UID:%d@%s", input->id, domain->name);
+ if (debug_fqn == NULL) {
ret = ENOMEM;
goto done;
}
break;
case CACHE_REQ_GROUP_BY_ID:
- fqn = talloc_asprintf(tmp_ctx, "GID:%d@%s", input->id, domain->name);
- if (fqn == NULL) {
+ debug_fqn = talloc_asprintf(tmp_ctx, "GID:%d@%s", input->id, domain->name);
+ if (debug_fqn == NULL) {
ret = ENOMEM;
goto done;
}
@@ -211,10 +265,10 @@ cache_req_input_set_domain(struct cache_req_input *input,
case CACHE_REQ_USER_BY_CERT:
/* certificates might be quite long, only use the last 10 charcters
* for logging */
- fqn = talloc_asprintf(tmp_ctx, "CERT:%s@%s",
- get_last_x_chars(input->cert, 10),
- domain->name);
- if (fqn == NULL) {
+ debug_fqn = talloc_asprintf(tmp_ctx, "CERT:%s@%s",
+ get_last_x_chars(input->cert, 10),
+ domain->name);
+ if (debug_fqn == NULL) {
ret = ENOMEM;
goto done;
}
@@ -223,7 +277,7 @@ cache_req_input_set_domain(struct cache_req_input *input,
input->domain = domain;
input->dom_objname = talloc_steal(input, name);
- input->debug_fqn = talloc_steal(input, fqn);
+ input->debug_fqn = talloc_steal(input, debug_fqn);
ret = EOK;
@@ -257,6 +311,10 @@ static errno_t cache_req_check_ncache(struct cache_req_input *input,
case CACHE_REQ_USER_BY_CERT:
ret = sss_ncache_check_cert(ncache, neg_timeout, input->cert);
break;
+ case CACHE_REQ_USER_BY_FILTER:
+ case CACHE_REQ_GROUP_BY_FILTER:
+ ret = EOK;
+ break;
}
if (ret == EEXIST) {
@@ -282,6 +340,10 @@ static void cache_req_add_to_ncache(struct cache_req_input *input,
ret = sss_ncache_set_group(ncache, false, input->domain,
input->dom_objname);
break;
+ case CACHE_REQ_USER_BY_FILTER:
+ case CACHE_REQ_GROUP_BY_FILTER:
+ /* Nothing to do, adding a wildcard request to ncache doesn't
+ * make sense */
case CACHE_REQ_USER_BY_ID:
case CACHE_REQ_GROUP_BY_ID:
case CACHE_REQ_USER_BY_CERT:
@@ -308,6 +370,10 @@ static void cache_req_add_to_ncache_global(struct cache_req_input *input,
errno_t ret = ERR_INTERNAL;
switch (input->type) {
+ case CACHE_REQ_USER_BY_FILTER:
+ case CACHE_REQ_GROUP_BY_FILTER:
+ /* Nothing to do, adding a wildcard request to ncache doesn't
+ * make sense */
case CACHE_REQ_USER_BY_NAME:
case CACHE_REQ_GROUP_BY_NAME:
case CACHE_REQ_INITGROUPS:
@@ -377,6 +443,18 @@ static errno_t cache_req_get_object(TALLOC_CTX *mem_ctx,
ret = sysdb_search_user_by_cert(mem_ctx, input->domain,
input->cert, &result);
break;
+ case CACHE_REQ_USER_BY_FILTER:
+ one_item_only = false;
+ ret = updated_users_by_filter(mem_ctx, input->domain,
+ input->dom_objname, input->req_start,
+ &result);
+ break;
+ case CACHE_REQ_GROUP_BY_FILTER:
+ one_item_only = false;
+ ret = updated_groups_by_filter(mem_ctx, input->domain,
+ input->dom_objname, input->req_start,
+ &result);
+ break;
}
if (ret != EOK) {
@@ -397,6 +475,19 @@ done:
return ret;
}
+/* Return true if the request bypasses cache or false if the cache_req
+ * code can leverage sysdb for this request.
+ */
+static bool cache_req_bypass_cache(struct cache_req_input *input)
+{
+ if (input->type == CACHE_REQ_USER_BY_FILTER ||
+ input->type == CACHE_REQ_GROUP_BY_FILTER) {
+ return true;
+ }
+
+ return false;
+}
+
struct cache_req_cache_state {
/* input data */
struct tevent_context *ev;
@@ -504,7 +595,8 @@ static errno_t cache_req_cache_check(struct tevent_req *req)
state = tevent_req_data(req, struct cache_req_cache_state);
- if (state->result == NULL || state->result->count == 0) {
+ if (state->result == NULL || state->result->count == 0 ||
+ cache_req_bypass_cache(state->input) == true) {
ret = ENOENT;
} else {
if (state->input->type == CACHE_REQ_INITGROUPS) {
@@ -1059,3 +1151,41 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
neg_timeout, cache_refresh_percent,
domain, input);
}
+
+struct tevent_req *
+cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ const char *domain,
+ const char *filter)
+{
+ struct cache_req_input *input;
+
+ input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_FILTER,
+ filter, 0, NULL);
+ if (input == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_input_and_send(mem_ctx, ev, rctx, NULL,
+ 0, 0, domain, input);
+}
+
+struct tevent_req *
+cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ const char *domain,
+ const char *filter)
+{
+ struct cache_req_input *input;
+
+ input = cache_req_input_create(mem_ctx, CACHE_REQ_GROUP_BY_FILTER,
+ filter, 0, NULL);
+ if (input == NULL) {
+ return NULL;
+ }
+
+ return cache_req_steal_input_and_send(mem_ctx, ev, rctx, NULL,
+ 0, 0, domain, input);
+}
diff --git a/src/responder/common/responder_cache_req.h b/src/responder/common/responder_cache_req.h
index 84a9dde7d9df066e44b1352e0a4557f02d08cc15..9e3f88a1427f3dcbde9f81df2ec647821b7aa931 100644
--- a/src/responder/common/responder_cache_req.h
+++ b/src/responder/common/responder_cache_req.h
@@ -33,7 +33,9 @@ enum cache_req_type {
CACHE_REQ_GROUP_BY_NAME,
CACHE_REQ_GROUP_BY_ID,
CACHE_REQ_INITGROUPS,
- CACHE_REQ_USER_BY_CERT
+ CACHE_REQ_USER_BY_CERT,
+ CACHE_REQ_USER_BY_FILTER,
+ CACHE_REQ_GROUP_BY_FILTER,
};
struct cache_req_input;
@@ -143,4 +145,24 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
#define cache_req_initgr_by_name_recv(mem_ctx, req, _result, _domain, _name) \
cache_req_recv(mem_ctx, req, _result, _domain, _name)
+struct tevent_req *
+cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ const char *domain,
+ const char *filter);
+
+#define cache_req_user_by_filter_recv(mem_ctx, req, _result, _domain) \
+ cache_req_recv(mem_ctx, req, _result, _domain, NULL)
+
+struct tevent_req *
+cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ const char *domain,
+ const char *filter);
+
+#define cache_req_group_by_filter_recv(mem_ctx, req, _result, _domain) \
+ cache_req_recv(mem_ctx, req, _result, _domain, NULL)
+
#endif /* RESPONDER_CACHE_H_ */
diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c
index e30deed1c6bc4023a4f2154db21fe1339e9bb3c5..31b6694668607815652f45bc93210554fd2ac918 100644
--- a/src/tests/cmocka/test_responder_cache_req.c
+++ b/src/tests/cmocka/test_responder_cache_req.c
@@ -38,6 +38,9 @@
#define TEST_GROUP_NAME "test-group"
#define TEST_GROUP_ID 1000
+#define TEST_USER_NAME2 "test-user2"
+#define TEST_GROUP_NAME2 "test-group2"
+
#define new_single_domain_test(test) \
cmocka_unit_test_setup_teardown(test_ ## test, \
test_single_domain_setup, \
@@ -1694,6 +1697,405 @@ void test_group_by_id_missing_notfound(void **state)
assert_true(test_ctx->dp_called);
}
+static void cache_req_user_by_filter_test_done(struct tevent_req *req)
+{
+ struct cache_req_test_ctx *ctx = NULL;
+
+ ctx = tevent_req_callback_data(req, struct cache_req_test_ctx);
+
+ ctx->tctx->error = cache_req_user_by_filter_recv(ctx, req,
+ &ctx->result,
+ &ctx->domain);
+ talloc_zfree(req);
+ ctx->tctx->done = true;
+}
+
+void test_users_by_filter_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ TALLOC_CTX *req_mem_ctx = NULL;
+ struct tevent_req *req = NULL;
+ const char *ldbname = NULL;
+ errno_t ret;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+ test_ctx->create_user = true;
+
+ ret = sysdb_store_user(test_ctx->tctx->dom, TEST_USER_NAME2, "pwd", 1001, 1001,
+ NULL, NULL, NULL, "cn="TEST_USER_NAME2",dc=test", NULL,
+ NULL, 1000, time(NULL));
+ assert_int_equal(ret, EOK);
+
+ req_mem_ctx = talloc_new(global_talloc_context);
+ check_leaks_push(req_mem_ctx);
+
+ /* Filters always go to DP */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ mock_account_recv_simple();
+
+ req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
+ test_ctx->rctx,
+ test_ctx->tctx->dom->name,
+ "test*");
+ assert_non_null(req);
+ tevent_req_set_callback(req, cache_req_user_by_filter_test_done, test_ctx);
+
+ ret = test_ev_loop(test_ctx->tctx);
+ assert_int_equal(ret, ERR_OK);
+ assert_true(check_leaks_pop(req_mem_ctx));
+
+ assert_non_null(test_ctx->result);
+ assert_int_equal(test_ctx->result->count, 2);
+
+ ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
+ SYSDB_NAME, NULL);
+ assert_non_null(ldbname);
+ assert_string_equal(ldbname, TEST_USER_NAME2);
+
+ ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[1],
+ SYSDB_NAME, NULL);
+ assert_non_null(ldbname);
+ assert_string_equal(ldbname, TEST_USER_NAME);
+}
+
+void test_users_by_filter_filter_old(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ TALLOC_CTX *req_mem_ctx = NULL;
+ struct tevent_req *req = NULL;
+ const char *ldbname = NULL;
+ errno_t ret;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+ test_ctx->create_user = true;
+
+ /* This user was updated in distant past, so it wont't be reported by
+ * the filter search */
+ ret = sysdb_store_user(test_ctx->tctx->dom, TEST_USER_NAME2, "pwd", 1001, 1001,
+ NULL, NULL, NULL, "cn="TEST_USER_NAME2",dc=test", NULL,
+ NULL, 1000, 1);
+ assert_int_equal(ret, EOK);
+
+ req_mem_ctx = talloc_new(global_talloc_context);
+ check_leaks_push(req_mem_ctx);
+
+ /* Filters always go to DP */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ mock_account_recv_simple();
+
+ req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
+ test_ctx->rctx,
+ test_ctx->tctx->dom->name,
+ "test*");
+ assert_non_null(req);
+ tevent_req_set_callback(req, cache_req_user_by_filter_test_done, test_ctx);
+
+ ret = test_ev_loop(test_ctx->tctx);
+ assert_int_equal(ret, ERR_OK);
+ assert_true(check_leaks_pop(req_mem_ctx));
+
+ assert_non_null(test_ctx->result);
+ assert_int_equal(test_ctx->result->count, 1);
+
+ ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
+ SYSDB_NAME, NULL);
+ assert_non_null(ldbname);
+ assert_string_equal(ldbname, TEST_USER_NAME);
+}
+
+void test_users_by_filter_notfound(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ TALLOC_CTX *req_mem_ctx = NULL;
+ struct tevent_req *req = NULL;
+ errno_t ret;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ req_mem_ctx = talloc_new(global_talloc_context);
+ check_leaks_push(req_mem_ctx);
+
+ /* Filters always go to DP */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ mock_account_recv_simple();
+
+ req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
+ test_ctx->rctx,
+ test_ctx->tctx->dom->name,
+ "nosuchuser*");
+ assert_non_null(req);
+ tevent_req_set_callback(req, cache_req_user_by_filter_test_done, test_ctx);
+
+ ret = test_ev_loop(test_ctx->tctx);
+ assert_int_equal(ret, ENOENT);
+ assert_true(check_leaks_pop(req_mem_ctx));
+}
+
+static void test_users_by_filter_multiple_domains_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ TALLOC_CTX *req_mem_ctx = NULL;
+ struct tevent_req *req = NULL;
+ const char *ldbname = NULL;
+ errno_t ret;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+
+ ret = sysdb_store_user(domain, TEST_USER_NAME, "pwd", 1000, 1000,
+ NULL, NULL, NULL, "cn="TEST_USER_NAME",dc=test", NULL,
+ NULL, 1000, time(NULL));
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_store_user(domain, TEST_USER_NAME2, "pwd", 1001, 1001,
+ NULL, NULL, NULL, "cn="TEST_USER_NAME2",dc=test", NULL,
+ NULL, 1000, time(NULL));
+ assert_int_equal(ret, EOK);
+
+ req_mem_ctx = talloc_new(global_talloc_context);
+ check_leaks_push(req_mem_ctx);
+
+ /* Filters always go to DP */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ mock_account_recv_simple();
+
+ req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
+ test_ctx->rctx,
+ domain->name,
+ "test*");
+ assert_non_null(req);
+ tevent_req_set_callback(req, cache_req_user_by_filter_test_done, test_ctx);
+
+ ret = test_ev_loop(test_ctx->tctx);
+ assert_int_equal(ret, ERR_OK);
+ assert_true(check_leaks_pop(req_mem_ctx));
+
+ assert_non_null(test_ctx->result);
+ assert_int_equal(test_ctx->result->count, 2);
+
+ ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
+ SYSDB_NAME, NULL);
+ assert_non_null(ldbname);
+ assert_string_equal(ldbname, TEST_USER_NAME2);
+
+ ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[1],
+ SYSDB_NAME, NULL);
+ assert_non_null(ldbname);
+ assert_string_equal(ldbname, TEST_USER_NAME);
+}
+
+static void test_users_by_filter_multiple_domains_notfound(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ TALLOC_CTX *req_mem_ctx = NULL;
+ struct tevent_req *req = NULL;
+ errno_t ret;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+
+ req_mem_ctx = talloc_new(global_talloc_context);
+ check_leaks_push(req_mem_ctx);
+
+ /* Filters always go to DP */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ mock_account_recv_simple();
+
+ req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
+ test_ctx->rctx,
+ domain->name,
+ "nosuchuser*");
+ assert_non_null(req);
+ tevent_req_set_callback(req, cache_req_user_by_filter_test_done, test_ctx);
+
+ ret = test_ev_loop(test_ctx->tctx);
+ assert_int_equal(ret, ENOENT);
+ assert_true(check_leaks_pop(req_mem_ctx));
+}
+
+static void cache_req_group_by_filter_test_done(struct tevent_req *req)
+{
+ struct cache_req_test_ctx *ctx = NULL;
+
+ ctx = tevent_req_callback_data(req, struct cache_req_test_ctx);
+
+ ctx->tctx->error = cache_req_group_by_filter_recv(ctx, req,
+ &ctx->result,
+ &ctx->domain);
+ talloc_zfree(req);
+ ctx->tctx->done = true;
+}
+
+void test_groups_by_filter_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ TALLOC_CTX *req_mem_ctx = NULL;
+ struct tevent_req *req = NULL;
+ const char *ldbname = NULL;
+ errno_t ret;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+ test_ctx->create_group = true;
+
+ ret = sysdb_store_group(test_ctx->tctx->dom, TEST_GROUP_NAME2,
+ 1001, NULL, 1001, time(NULL));
+ assert_int_equal(ret, EOK);
+
+ req_mem_ctx = talloc_new(global_talloc_context);
+ check_leaks_push(req_mem_ctx);
+
+ /* Filters always go to DP */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ mock_account_recv_simple();
+
+ req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
+ test_ctx->rctx,
+ test_ctx->tctx->dom->name,
+ "test*");
+ assert_non_null(req);
+ tevent_req_set_callback(req, cache_req_group_by_filter_test_done, test_ctx);
+
+ ret = test_ev_loop(test_ctx->tctx);
+ assert_int_equal(ret, ERR_OK);
+ assert_true(check_leaks_pop(req_mem_ctx));
+
+ assert_non_null(test_ctx->result);
+ assert_int_equal(test_ctx->result->count, 2);
+
+ ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
+ SYSDB_NAME, NULL);
+ assert_non_null(ldbname);
+ assert_string_equal(ldbname, TEST_GROUP_NAME2);
+
+ ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[1],
+ SYSDB_NAME, NULL);
+ assert_non_null(ldbname);
+ assert_string_equal(ldbname, TEST_GROUP_NAME);
+}
+
+void test_groups_by_filter_notfound(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ TALLOC_CTX *req_mem_ctx = NULL;
+ struct tevent_req *req = NULL;
+ errno_t ret;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ req_mem_ctx = talloc_new(global_talloc_context);
+ check_leaks_push(req_mem_ctx);
+
+ /* Filters always go to DP */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ mock_account_recv_simple();
+
+ req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
+ test_ctx->rctx,
+ test_ctx->tctx->dom->name,
+ "nosuchgroup*");
+ assert_non_null(req);
+ tevent_req_set_callback(req, cache_req_group_by_filter_test_done, test_ctx);
+
+ ret = test_ev_loop(test_ctx->tctx);
+ assert_int_equal(ret, ENOENT);
+ assert_true(check_leaks_pop(req_mem_ctx));
+}
+
+void test_groups_by_filter_multiple_domains_valid(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ TALLOC_CTX *req_mem_ctx = NULL;
+ struct tevent_req *req = NULL;
+ const char *ldbname = NULL;
+ errno_t ret;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+
+ ret = sysdb_store_group(domain, TEST_GROUP_NAME,
+ 1000, NULL, 1000, time(NULL));
+ assert_int_equal(ret, EOK);
+
+ ret = sysdb_store_group(domain, TEST_GROUP_NAME2,
+ 1001, NULL, 1001, time(NULL));
+ assert_int_equal(ret, EOK);
+
+ req_mem_ctx = talloc_new(global_talloc_context);
+ check_leaks_push(req_mem_ctx);
+
+ /* Filters always go to DP */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ mock_account_recv_simple();
+
+ req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
+ test_ctx->rctx,
+ domain->name,
+ "test*");
+ assert_non_null(req);
+ tevent_req_set_callback(req, cache_req_group_by_filter_test_done, test_ctx);
+
+ ret = test_ev_loop(test_ctx->tctx);
+ assert_int_equal(ret, ERR_OK);
+ assert_true(check_leaks_pop(req_mem_ctx));
+
+ assert_non_null(test_ctx->result);
+ assert_int_equal(test_ctx->result->count, 2);
+
+ ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[0],
+ SYSDB_NAME, NULL);
+ assert_non_null(ldbname);
+ assert_string_equal(ldbname, TEST_GROUP_NAME2);
+
+ ldbname = ldb_msg_find_attr_as_string(test_ctx->result->msgs[1],
+ SYSDB_NAME, NULL);
+ assert_non_null(ldbname);
+ assert_string_equal(ldbname, TEST_GROUP_NAME);
+}
+
+void test_groups_by_filter_multiple_domains_notfound(void **state)
+{
+ struct cache_req_test_ctx *test_ctx = NULL;
+ struct sss_domain_info *domain = NULL;
+ TALLOC_CTX *req_mem_ctx = NULL;
+ struct tevent_req *req = NULL;
+ errno_t ret;
+
+ test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+ domain = find_domain_by_name(test_ctx->tctx->dom,
+ "responder_cache_req_test_d", true);
+ assert_non_null(domain);
+
+ req_mem_ctx = talloc_new(global_talloc_context);
+ check_leaks_push(req_mem_ctx);
+
+ /* Filters always go to DP */
+ will_return(__wrap_sss_dp_get_account_send, test_ctx);
+ mock_account_recv_simple();
+
+ req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev,
+ test_ctx->rctx,
+ domain->name,
+ "nosuchgroup*");
+ assert_non_null(req);
+ tevent_req_set_callback(req, cache_req_group_by_filter_test_done, test_ctx);
+
+ ret = test_ev_loop(test_ctx->tctx);
+ assert_int_equal(ret, ENOENT);
+ assert_true(check_leaks_pop(req_mem_ctx));
+}
+
int main(int argc, const char *argv[])
{
poptContext pc;
@@ -1741,7 +2143,17 @@ int main(int argc, const char *argv[])
new_single_domain_test(group_by_id_missing_found),
new_single_domain_test(group_by_id_missing_notfound),
new_multi_domain_test(group_by_id_multiple_domains_found),
- new_multi_domain_test(group_by_id_multiple_domains_notfound)
+ new_multi_domain_test(group_by_id_multiple_domains_notfound),
+
+ new_single_domain_test(users_by_filter_valid),
+ new_single_domain_test(users_by_filter_filter_old),
+ new_single_domain_test(users_by_filter_notfound),
+ new_multi_domain_test(users_by_filter_multiple_domains_valid),
+ new_multi_domain_test(users_by_filter_multiple_domains_notfound),
+ new_single_domain_test(groups_by_filter_valid),
+ new_single_domain_test(groups_by_filter_notfound),
+ new_multi_domain_test(groups_by_filter_multiple_domains_valid),
+ new_multi_domain_test(groups_by_filter_multiple_domains_notfound),
};
/* Set debug level to invalid value so we can deside if -d 0 was used. */
--
2.4.3
-------------- next part --------------
>From d063d07e70b352c133d09b35993e6fad93da587e Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 4 May 2015 13:10:01 +0200
Subject: [PATCH 05/11] UTIL: Add sss_filter_sanitize_ex
Related:
https://fedorahosted.org/sssd/ticket/2553
In order to support wildcard request, we need to introduce an optionally
relaxed version of sss_filter_sanitize that allows to select which
characters are exempt from sanitizing.
---
src/tests/util-tests.c | 9 +++++++++
src/util/util.c | 28 +++++++++++++++++++++++++---
src/util/util.h | 5 +++++
3 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/src/tests/util-tests.c b/src/tests/util-tests.c
index 3d42f0193a677200d5cb4a46805892bed978305c..bfdf078027250b8ff0ce0da2d37fbb20f391d06b 100644
--- a/src/tests/util-tests.c
+++ b/src/tests/util-tests.c
@@ -406,6 +406,15 @@ START_TEST(test_sss_filter_sanitize)
"Expected [%s], got [%s]",
has_all_expected, sanitized);
+ /* Input is reused from previous test - "\\(user)*name" */
+ const char has_all_allow_asterisk_expected[] = "\\5c\\28user\\29*name";
+ ret = sss_filter_sanitize_ex(test_ctx, has_all, &sanitized, "*");
+ fail_unless(ret == EOK, "has_all error [%d][%s]",
+ ret, strerror(ret));
+ fail_unless(strcmp(has_all_allow_asterisk_expected, sanitized)==0,
+ "Expected [%s], got [%s]",
+ has_all_expected, sanitized);
+
talloc_free(test_ctx);
}
END_TEST
diff --git a/src/util/util.c b/src/util/util.c
index cfd26a58b31048996e9669163b821282b219b2de..782cd026b7928e607a8980fb5f333c794feb5b1a 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -525,13 +525,15 @@ errno_t sss_hash_create(TALLOC_CTX *mem_ctx, unsigned long count,
return sss_hash_create_ex(mem_ctx, count, tbl, 0, 0, 0, 0, NULL, NULL);
}
-errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
- const char *input,
- char **sanitized)
+errno_t sss_filter_sanitize_ex(TALLOC_CTX *mem_ctx,
+ const char *input,
+ char **sanitized,
+ const char *ignore)
{
char *output;
size_t i = 0;
size_t j = 0;
+ char *allowed;
/* Assume the worst-case. We'll resize it later, once */
output = talloc_array(mem_ctx, char, strlen(input) * 3 + 1);
@@ -540,6 +542,19 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
}
while (input[i]) {
+ /* Even though this character might have a special meaning, if it's
+ * expliticly allowed, just copy it and move on
+ */
+ if (ignore == NULL) {
+ allowed = NULL;
+ } else {
+ allowed = strchr(ignore, input[i]);
+ }
+ if (allowed) {
+ output[j++] = input[i++];
+ continue;
+ }
+
switch(input[i]) {
case '\t':
output[j++] = '\\';
@@ -587,6 +602,13 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
return EOK;
}
+errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
+ const char *input,
+ char **sanitized)
+{
+ return sss_filter_sanitize_ex(mem_ctx, input, sanitized, NULL);
+}
+
char *
sss_escape_ip_address(TALLOC_CTX *mem_ctx, int family, const char *addr)
{
diff --git a/src/util/util.h b/src/util/util.h
index 3d90cf0d1024b93016987a4d3e8a515359fd974d..94a3ddea839f0998cb7796f1d2fe13f743de3aaf 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -485,6 +485,11 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx,
const char *input,
char **sanitized);
+errno_t sss_filter_sanitize_ex(TALLOC_CTX *mem_ctx,
+ const char *input,
+ char **sanitized,
+ const char *ignore);
+
errno_t sss_filter_sanitize_for_dom(TALLOC_CTX *mem_ctx,
const char *input,
struct sss_domain_info *dom,
--
2.4.3
-------------- next part --------------
>From 7e58e6b481b07fad6a98a4a6c5084ddcac361fea Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 4 May 2015 15:16:44 +0200
Subject: [PATCH 06/11] LDAP: Fetch users and groups using wildcards
Related:
https://fedorahosted.org/sssd/ticket/2553
Adds handler for the BE_FILTER_WILDCARD in the LDAP provider. So far
it's the same code as if enumeration was used, so there are no limits.
---
src/providers/ldap/ldap_common.h | 3 +++
src/providers/ldap/ldap_id.c | 50 ++++++++++++++++++++++++++++++++++++++--
2 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index 424eacb1da0a6934b132ccb2a5bb175233fa1a80..8294d1db23bdca8d94a098533d93405c4d55226b 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -39,6 +39,9 @@
#define LDAP_SSL_URI "ldaps://"
#define LDAP_LDAPI_URI "ldapi://"
+/* Only the asterisk is allowed in wildcard requests */
+#define LDAP_ALLOWED_WILDCARDS "*"
+
/* a fd the child process would log into */
extern int ldap_child_debug_fd;
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index 3245e1b12a69483f961f01210d13654b1c7c5345..61f09fc41d3210af5044f5338dd90db67e0123a7 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -114,6 +114,14 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
sdom->dom->name,
sdom->dom->domain_id);
switch (filter_type) {
+ case BE_FILTER_WILDCARD:
+ attr_name = ctx->opts->user_map[SDAP_AT_USER_NAME].name;
+ ret = sss_filter_sanitize_ex(state, name, &clean_name,
+ LDAP_ALLOWED_WILDCARDS);
+ if (ret != EOK) {
+ goto done;
+ }
+ break;
case BE_FILTER_NAME:
if (extra_value && strcmp(extra_value, EXTRA_NAME_IS_UPN) == 0) {
attr_name = ctx->opts->user_map[SDAP_AT_USER_PRINC].name;
@@ -388,6 +396,13 @@ static void users_get_search(struct tevent_req *req)
struct users_get_state *state = tevent_req_data(req,
struct users_get_state);
struct tevent_req *subreq;
+ bool multiple_results;
+
+ if (state->filter_type == BE_FILTER_WILDCARD) {
+ multiple_results = true;
+ } else {
+ multiple_results = false;
+ }
subreq = sdap_get_users_send(state, state->ev,
state->domain, state->sysdb,
@@ -397,7 +412,7 @@ static void users_get_search(struct tevent_req *req)
state->attrs, state->filter,
dp_opt_get_int(state->ctx->opts->basic,
SDAP_SEARCH_TIMEOUT),
- false);
+ multiple_results);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
@@ -508,6 +523,13 @@ static void users_get_done(struct tevent_req *subreq)
* group we have nothing to do here. */
break;
+ case BE_FILTER_WILDCARD:
+ /* We can't know if all users are up-to-date, especially in a large
+ * environment. Do not delete any records, let the responder fetch
+ * the entries they are requested in
+ */
+ break;
+
default:
tevent_req_error(req, EINVAL);
return;
@@ -619,6 +641,14 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
sdom->dom->domain_id);
switch(filter_type) {
+ case BE_FILTER_WILDCARD:
+ attr_name = ctx->opts->group_map[SDAP_AT_GROUP_NAME].name;
+ ret = sss_filter_sanitize_ex(state, name, &clean_name,
+ LDAP_ALLOWED_WILDCARDS);
+ if (ret != EOK) {
+ goto done;
+ }
+ break;
case BE_FILTER_NAME:
attr_name = ctx->opts->group_map[SDAP_AT_GROUP_NAME].name;
@@ -871,6 +901,13 @@ static void groups_get_search(struct tevent_req *req)
struct groups_get_state *state = tevent_req_data(req,
struct groups_get_state);
struct tevent_req *subreq;
+ bool multiple_results;
+
+ if (state->filter_type == BE_FILTER_WILDCARD) {
+ multiple_results = true;
+ } else {
+ multiple_results = false;
+ }
subreq = sdap_get_groups_send(state, state->ev,
state->sdom,
@@ -879,7 +916,8 @@ static void groups_get_search(struct tevent_req *req)
state->attrs, state->filter,
dp_opt_get_int(state->ctx->opts->basic,
SDAP_SEARCH_TIMEOUT),
- false, state->no_members);
+ multiple_results,
+ state->no_members);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
@@ -953,6 +991,14 @@ static void groups_get_done(struct tevent_req *subreq)
* group we have nothing to do here. */
break;
+ case BE_FILTER_WILDCARD:
+ /* We can't know if all groups are up-to-date, especially in
+ * a large environment. Do not delete any records, let the
+ * responder fetch the entries they are requested in.
+ */
+ break;
+
+
default:
tevent_req_error(req, EINVAL);
return;
--
2.4.3
-------------- next part --------------
>From 6d2143196b6709f3a0f6858392a0b9af4b4058fb Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 4 May 2015 16:27:06 +0200
Subject: [PATCH 07/11] LDAP: Add sdap_get_and_parse_generic_send
Related:
https://fedorahosted.org/sssd/ticket/2553
So far we had a simple sdap_get_generic_send() request that uses the
right defaults around the low-level sdap_get_generic_ext_send() request
and calls the parser.
This patch adds also sdap_get_and_parse_generic_send() that exposes all
options that sdap_get_generic_ext_send() offers but also calls the
parser.
In this patch the function is not used at all.
---
src/providers/ldap/sdap_async.c | 185 ++++++++++++++++++++++++++++------------
src/providers/ldap/sdap_async.h | 22 +++++
2 files changed, 154 insertions(+), 53 deletions(-)
diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index 5263c250b8a15a98e685ca81e636def27ea05894..c5be8561a197c96f62bb2582a4d30c28de71f580 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -1656,9 +1656,8 @@ static void generic_ext_search_handler(struct tevent_req *subreq,
tevent_req_done(req);
}
-
-/* ==Generic Search============================================ */
-struct sdap_get_generic_state {
+/* ==Generic Search exposing all options======================= */
+struct sdap_get_and_parse_generic_state {
struct sdap_attr_map *map;
int map_num_attrs;
@@ -1666,10 +1665,119 @@ struct sdap_get_generic_state {
struct sdap_options *opts;
};
+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);
+
+struct tevent_req *sdap_get_and_parse_generic_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sdap_handle *sh,
+ const char *search_base,
+ int scope,
+ const char *filter,
+ const char **attrs,
+ struct sdap_attr_map *map,
+ int map_num_attrs,
+ int attrsonly,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ int sizelimit,
+ int timeout,
+ bool allow_paging)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct sdap_get_and_parse_generic_state *state = NULL;
+
+ req = tevent_req_create(memctx, &state,
+ struct sdap_get_and_parse_generic_state);
+ if (!req) return NULL;
+
+ state->map = map;
+ state->map_num_attrs = map_num_attrs;
+ state->opts = opts;
+
+ subreq = sdap_get_generic_ext_send(state, ev, opts, sh, search_base,
+ scope, filter, attrs, false, NULL,
+ NULL, sizelimit, timeout, allow_paging,
+ sdap_get_and_parse_generic_parse_entry, state);
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, sdap_get_and_parse_generic_done, req);
+
+ return req;
+}
+
+static errno_t sdap_get_and_parse_generic_parse_entry(struct sdap_handle *sh,
+ struct sdap_msg *msg,
+ void *pvt)
+{
+ errno_t ret;
+ struct sysdb_attrs *attrs;
+ struct sdap_get_and_parse_generic_state *state =
+ talloc_get_type(pvt, struct sdap_get_and_parse_generic_state);
+
+ bool disable_range_rtrvl = dp_opt_get_bool(state->opts->basic,
+ SDAP_DISABLE_RANGE_RETRIEVAL);
+
+ ret = sdap_parse_entry(state, sh, msg,
+ state->map, state->map_num_attrs,
+ &attrs, disable_range_rtrvl);
+ 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);
+ if (ret != EOK) {
+ talloc_free(attrs);
+ DEBUG(SSSDBG_CRIT_FAILURE, "add_to_reply failed.\n");
+ return ret;
+ }
+
+ /* add_to_reply steals attrs, no need to free them here */
+ return EOK;
+}
+
+static void sdap_get_and_parse_generic_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ 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);
+}
+
+int sdap_get_and_parse_generic_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *reply_count,
+ struct sysdb_attrs ***reply)
+{
+ struct sdap_get_and_parse_generic_state *state = tevent_req_data(req,
+ struct sdap_get_and_parse_generic_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *reply_count = state->sreply.reply_count;
+ *reply = talloc_steal(mem_ctx, state->sreply.reply);
+
+ return EOK;
+}
+
+
+/* ==Simple generic search============================================== */
+struct sdap_get_generic_state {
+ size_t reply_count;
+ struct sysdb_attrs **reply;
+};
+
static void sdap_get_generic_done(struct tevent_req *subreq);
-static errno_t sdap_get_generic_parse_entry(struct sdap_handle *sh,
- struct sdap_msg *msg,
- void *pvt);
struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
@@ -1691,16 +1799,12 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
req = tevent_req_create(memctx, &state, struct sdap_get_generic_state);
if (!req) return NULL;
- state->map = map;
- state->map_num_attrs = map_num_attrs;
- state->opts = opts;
-
- subreq = sdap_get_generic_ext_send(state, ev, opts, sh, search_base,
- scope, filter, attrs, false, NULL,
- NULL, 0, timeout, allow_paging,
- sdap_get_generic_parse_entry, state);
- if (!subreq) {
- talloc_zfree(req);
+ subreq = sdap_get_and_parse_generic_send(memctx, ev, opts, sh, search_base,
+ scope, filter, attrs,
+ map, map_num_attrs,
+ false, NULL, NULL, 0, timeout,
+ allow_paging);
+ if (subreq == NULL) {
return NULL;
}
tevent_req_set_callback(subreq, sdap_get_generic_done, req);
@@ -1708,46 +1812,21 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
return req;
}
-static errno_t sdap_get_generic_parse_entry(struct sdap_handle *sh,
- struct sdap_msg *msg,
- void *pvt)
-{
- errno_t ret;
- struct sysdb_attrs *attrs;
- struct sdap_get_generic_state *state =
- talloc_get_type(pvt, struct sdap_get_generic_state);
-
- bool disable_range_rtrvl = dp_opt_get_bool(state->opts->basic,
- SDAP_DISABLE_RANGE_RETRIEVAL);
-
- ret = sdap_parse_entry(state, sh, msg,
- state->map, state->map_num_attrs,
- &attrs, disable_range_rtrvl);
- 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);
- if (ret != EOK) {
- talloc_free(attrs);
- DEBUG(SSSDBG_CRIT_FAILURE, "add_to_reply failed.\n");
- return ret;
- }
-
- /* add_to_reply steals attrs, no need to free them here */
- return EOK;
-}
-
static void sdap_get_generic_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct sdap_get_generic_state *state =
tevent_req_data(req, struct sdap_get_generic_state);
+ errno_t ret;
- return generic_ext_search_handler(subreq, state->opts);
+ ret = sdap_get_and_parse_generic_recv(subreq, state,
+ &state->reply_count, &state->reply);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+ tevent_req_done(req);
}
int sdap_get_generic_recv(struct tevent_req *req,
@@ -1755,13 +1834,13 @@ int sdap_get_generic_recv(struct tevent_req *req,
size_t *reply_count,
struct sysdb_attrs ***reply)
{
- struct sdap_get_generic_state *state = tevent_req_data(req,
- struct sdap_get_generic_state);
+ struct sdap_get_generic_state *state =
+ tevent_req_data(req, struct sdap_get_generic_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
- *reply_count = state->sreply.reply_count;
- *reply = talloc_steal(mem_ctx, state->sreply.reply);
+ *reply_count = state->reply_count;
+ *reply = talloc_steal(mem_ctx, state->reply);
return EOK;
}
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index b5db64d7fa3c852fba60e07db19e823e818d29f3..b23dfc313905d01caedd1eace6bcb525481b9ebe 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -181,6 +181,28 @@ int sdap_cli_connect_recv(struct tevent_req *req,
struct sdap_handle **gsh,
struct sdap_server_opts **srv_opts);
+/* Exposes all options of generic send while allowing to parse by map */
+struct tevent_req *sdap_get_and_parse_generic_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sdap_handle *sh,
+ const char *search_base,
+ int scope,
+ const char *filter,
+ const char **attrs,
+ struct sdap_attr_map *map,
+ int map_num_attrs,
+ int attrsonly,
+ LDAPControl **serverctrls,
+ LDAPControl **clientctrls,
+ int sizelimit,
+ int timeout,
+ bool allow_paging);
+int sdap_get_and_parse_generic_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *reply_count,
+ struct sysdb_attrs ***reply);
+
struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
struct sdap_options *opts,
--
2.4.3
-------------- next part --------------
>From aa44adf105da54ae6ed7a209fd503242d83a3479 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 4 May 2015 16:33:37 +0200
Subject: [PATCH 08/11] LDAP: Use sdap_get_and_parse_generic_/_recv
Related:
https://fedorahosted.org/sssd/ticket/2553
Using the new request sdap_get_and_parse_generic_send is a separate
commit so that we can audit where the function is used during a code
review.
---
src/providers/ldap/sdap_async_groups.c | 8 ++++----
src/providers/ldap/sdap_async_users.c | 8 ++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
index 73caa9b5bd662477cd29b5220f6b437991831578..e785307e60d0df5be96a5b2de2c07baabaf1e371 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -1870,14 +1870,14 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
"Searching for groups with base [%s]\n",
state->search_bases[state->base_iter]->basedn);
- subreq = sdap_get_generic_send(
+ subreq = sdap_get_and_parse_generic_send(
state, state->ev, state->opts,
state->ldap_sh != NULL ? state->ldap_sh : state->sh,
state->search_bases[state->base_iter]->basedn,
state->search_bases[state->base_iter]->scope,
state->filter, state->attrs,
state->opts->group_map, SDAP_OPTS_GROUP,
- state->timeout,
+ 0, NULL, NULL, 0, state->timeout,
state->enumeration); /* If we're enumerating, we need paging */
if (!subreq) {
return ENOMEM;
@@ -1903,8 +1903,8 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
struct sysdb_attrs **groups;
char **groupnamelist;
- ret = sdap_get_generic_recv(subreq, state,
- &count, &groups);
+ ret = sdap_get_and_parse_generic_recv(subreq, state,
+ &count, &groups);
talloc_zfree(subreq);
if (ret) {
tevent_req_error(req, ret);
diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
index 416bedda8491fae5385e6b6a074b4cf05ae86b65..216b49477bf21481265444c5c03df0aac7ee84e4 100644
--- a/src/providers/ldap/sdap_async_users.c
+++ b/src/providers/ldap/sdap_async_users.c
@@ -688,13 +688,13 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
"Searching for users with base [%s]\n",
state->search_bases[state->base_iter]->basedn);
- subreq = sdap_get_generic_send(
+ subreq = sdap_get_and_parse_generic_send(
state, state->ev, state->opts, state->sh,
state->search_bases[state->base_iter]->basedn,
state->search_bases[state->base_iter]->scope,
state->filter, state->attrs,
state->opts->user_map, state->opts->user_map_cnt,
- state->timeout,
+ 0, NULL, NULL, 0, state->timeout,
state->enumeration); /* If we're enumerating, we need paging */
if (subreq == NULL) {
return ENOMEM;
@@ -715,8 +715,8 @@ static void sdap_search_user_process(struct tevent_req *subreq)
struct sysdb_attrs **users;
bool next_base = false;
- ret = sdap_get_generic_recv(subreq, state,
- &count, &users);
+ ret = sdap_get_and_parse_generic_recv(subreq, state,
+ &count, &users);
talloc_zfree(subreq);
if (ret) {
tevent_req_error(req, ret);
--
2.4.3
-------------- next part --------------
>From 15eeb29f4811ccbc06c23f5c5a84d4f566e998ef Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Fri, 8 May 2015 14:49:09 +0200
Subject: [PATCH 09/11] LDAP: Add sdap_lookup_type enum
Related:
https://fedorahosted.org/sssd/ticket/2553
Change the boolan parameter of sdap_get_users_send and sdap_get_groups_send
to a tri-state that controls whether we expect only a single entry
(ie don't use the paging control), multiple entries with a search limit
(wildcard request) or multiple entries with no limit (enumeration).
---
src/providers/ldap/ldap_auth.c | 2 +-
src/providers/ldap/ldap_id.c | 16 +++++++-------
src/providers/ldap/sdap_async.h | 12 +++++++---
src/providers/ldap/sdap_async_enum.c | 4 ++--
src/providers/ldap/sdap_async_groups.c | 40 ++++++++++++++++++++++++----------
src/providers/ldap/sdap_async_users.c | 32 ++++++++++++++++++++-------
6 files changed, 73 insertions(+), 33 deletions(-)
diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
index 81717942613b4a91ebab668ba2ecfe13caab38be..217e80fd07abc41f2594d19397783683d44600cd 100644
--- a/src/providers/ldap/ldap_auth.c
+++ b/src/providers/ldap/ldap_auth.c
@@ -418,7 +418,7 @@ static struct tevent_req *get_user_dn_send(TALLOC_CTX *memctx,
sh, attrs, filter,
dp_opt_get_int(opts->basic,
SDAP_SEARCH_TIMEOUT),
- false);
+ SDAP_LOOKUP_SINGLE);
if (!subreq) {
ret = ENOMEM;
goto done;
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index 61f09fc41d3210af5044f5338dd90db67e0123a7..73840d2885ed15a7a9dae2e9175d8361c8fdfe7d 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -396,12 +396,12 @@ static void users_get_search(struct tevent_req *req)
struct users_get_state *state = tevent_req_data(req,
struct users_get_state);
struct tevent_req *subreq;
- bool multiple_results;
+ enum sdap_entry_lookup_type lookup_type;
if (state->filter_type == BE_FILTER_WILDCARD) {
- multiple_results = true;
+ lookup_type = SDAP_LOOKUP_WILDCARD;
} else {
- multiple_results = false;
+ lookup_type = SDAP_LOOKUP_SINGLE;
}
subreq = sdap_get_users_send(state, state->ev,
@@ -412,7 +412,7 @@ static void users_get_search(struct tevent_req *req)
state->attrs, state->filter,
dp_opt_get_int(state->ctx->opts->basic,
SDAP_SEARCH_TIMEOUT),
- multiple_results);
+ lookup_type);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
@@ -901,12 +901,12 @@ static void groups_get_search(struct tevent_req *req)
struct groups_get_state *state = tevent_req_data(req,
struct groups_get_state);
struct tevent_req *subreq;
- bool multiple_results;
+ enum sdap_entry_lookup_type lookup_type;
if (state->filter_type == BE_FILTER_WILDCARD) {
- multiple_results = true;
+ lookup_type = SDAP_LOOKUP_WILDCARD;
} else {
- multiple_results = false;
+ lookup_type = SDAP_LOOKUP_SINGLE;
}
subreq = sdap_get_groups_send(state, state->ev,
@@ -916,7 +916,7 @@ static void groups_get_search(struct tevent_req *req)
state->attrs, state->filter,
dp_opt_get_int(state->ctx->opts->basic,
SDAP_SEARCH_TIMEOUT),
- multiple_results,
+ lookup_type,
state->no_members);
if (!subreq) {
tevent_req_error(req, ENOMEM);
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index b23dfc313905d01caedd1eace6bcb525481b9ebe..09bc0d65407253f93514b30877850cc38009c625 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -59,6 +59,12 @@ errno_t sdap_connect_host_recv(TALLOC_CTX *mem_ctx,
struct sdap_handle **_sh);
/* Search users in LDAP, return them as attrs */
+enum sdap_entry_lookup_type {
+ SDAP_LOOKUP_SINGLE, /* Direct single-user/group lookup */
+ SDAP_LOOKUP_WILDCARD, /* Multiple entries with a limit */
+ SDAP_LOOKUP_ENUMERATE, /* Fetch all entries from the server */
+};
+
struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
struct sss_domain_info *dom,
@@ -68,7 +74,7 @@ struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx,
const char **attrs,
const char *filter,
int timeout,
- bool enumeration);
+ enum sdap_entry_lookup_type lookup_type);
int sdap_search_user_recv(TALLOC_CTX *memctx, struct tevent_req *req,
char **higher_usn, struct sysdb_attrs ***users,
size_t *count);
@@ -84,7 +90,7 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
const char **attrs,
const char *filter,
int timeout,
- bool enumeration);
+ enum sdap_entry_lookup_type lookup_type);
int sdap_get_users_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx, char **timestamp);
@@ -96,7 +102,7 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
const char **attrs,
const char *filter,
int timeout,
- bool enumeration,
+ enum sdap_entry_lookup_type lookup_type,
bool no_members);
int sdap_get_groups_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx, char **timestamp);
diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index 35afc55f809669a44aa2beda7d87dfe62d6ec10b..f22276c3ce6f839b765bbc1602fafb010cc37d89 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -635,7 +635,7 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
state->attrs, state->filter,
dp_opt_get_int(state->ctx->opts->basic,
SDAP_ENUM_SEARCH_TIMEOUT),
- true);
+ SDAP_LOOKUP_ENUMERATE);
if (!subreq) {
ret = ENOMEM;
goto fail;
@@ -811,7 +811,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
state->attrs, state->filter,
dp_opt_get_int(state->ctx->opts->basic,
SDAP_ENUM_SEARCH_TIMEOUT),
- true, false);
+ SDAP_LOOKUP_ENUMERATE, false);
if (!subreq) {
ret = ENOMEM;
goto fail;
diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
index e785307e60d0df5be96a5b2de2c07baabaf1e371..ad0354df1fce9011c68cabb6049e7feee92a44c0 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -1721,7 +1721,7 @@ struct sdap_get_groups_state {
const char *base_filter;
char *filter;
int timeout;
- bool enumeration;
+ enum sdap_entry_lookup_type lookup_type;
bool no_members;
char *higher_usn;
@@ -1752,7 +1752,7 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
const char **attrs,
const char *filter,
int timeout,
- bool enumeration,
+ enum sdap_entry_lookup_type lookup_type,
bool no_members)
{
errno_t ret;
@@ -1775,7 +1775,7 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
state->groups = NULL;
state->count = 0;
state->timeout = timeout;
- state->enumeration = enumeration;
+ state->lookup_type = lookup_type;
state->no_members = no_members;
state->base_filter = filter;
state->base_iter = 0;
@@ -1855,6 +1855,7 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
{
struct tevent_req *subreq;
struct sdap_get_groups_state *state;
+ bool need_paging = false;
state = tevent_req_data(req, struct sdap_get_groups_state);
@@ -1870,6 +1871,19 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
"Searching for groups with base [%s]\n",
state->search_bases[state->base_iter]->basedn);
+ switch (state->lookup_type) {
+ case SDAP_LOOKUP_SINGLE:
+ need_paging = false;
+ break;
+ /* Only requests that can return multiple entries should require
+ * the paging control
+ */
+ case SDAP_LOOKUP_WILDCARD:
+ case SDAP_LOOKUP_ENUMERATE:
+ need_paging = true;
+ break;
+ }
+
subreq = sdap_get_and_parse_generic_send(
state, state->ev, state->opts,
state->ldap_sh != NULL ? state->ldap_sh : state->sh,
@@ -1878,7 +1892,7 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
state->filter, state->attrs,
state->opts->group_map, SDAP_OPTS_GROUP,
0, NULL, NULL, 0, state->timeout,
- state->enumeration); /* If we're enumerating, we need paging */
+ need_paging);
if (!subreq) {
return ENOMEM;
}
@@ -1914,14 +1928,17 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
DEBUG(SSSDBG_TRACE_FUNC,
"Search for groups, returned %zu results.\n", count);
- if (!state->enumeration && count > 1) {
+ if (state->lookup_type == SDAP_LOOKUP_SINGLE && count > 1) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Individual group search returned multiple results\n");
tevent_req_error(req, EINVAL);
return;
}
- if (state->enumeration || count == 0) {
+ if (state->lookup_type == SDAP_LOOKUP_WILDCARD || \
+ state->lookup_type == SDAP_LOOKUP_ENUMERATE || \
+ count == 0) {
+ /* No users found in this search or looking up multiple entries */
next_base = true;
}
@@ -2003,7 +2020,7 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
* LDAP_MATCHING_RULE_IN_CHAIN available in
* AD 2008 and later
*/
- if (!state->enumeration) {
+ if (state->lookup_type == SDAP_LOOKUP_SINGLE) {
if ((state->opts->schema_type != SDAP_SCHEMA_RFC2307)
&& (dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0)
&& !dp_opt_get_bool(state->opts->basic, SDAP_AD_MATCHING_RULE_GROUPS)) {
@@ -2026,7 +2043,7 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
/* If we're using LDAP_MATCHING_RULE_IN_CHAIN, start a subreq to
* retrieve the members so we can save them in a single step.
*/
- if (!state->enumeration
+ if (state->lookup_type == SDAP_LOOKUP_SINGLE
&& (state->opts->schema_type != SDAP_SCHEMA_RFC2307)
&& state->opts->support_matching_rule
&& dp_opt_get_bool(state->opts->basic, SDAP_AD_MATCHING_RULE_GROUPS)) {
@@ -2050,7 +2067,8 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
return;
}
- if (state->enumeration
+ if ((state->lookup_type == SDAP_LOOKUP_ENUMERATE
+ || state->lookup_type == SDAP_LOOKUP_WILDCARD)
&& state->opts->schema_type != SDAP_SCHEMA_RFC2307
&& dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0) {
DEBUG(SSSDBG_TRACE_ALL, "Saving groups without members first "
@@ -2069,7 +2087,7 @@ static void sdap_get_groups_process(struct tevent_req *subreq)
subreq = sdap_process_group_send(state, state->ev, state->dom,
state->sysdb, state->opts,
state->sh, state->groups[i],
- state->enumeration);
+ state->lookup_type == SDAP_LOOKUP_ENUMERATE);
if (!subreq) {
tevent_req_error(req, ENOMEM);
@@ -2116,7 +2134,7 @@ static void sdap_get_groups_done(struct tevent_req *subreq)
ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
state->groups, state->count,
!state->dom->ignore_group_members, NULL,
- !state->enumeration,
+ state->lookup_type == SDAP_LOOKUP_SINGLE,
&state->higher_usn);
if (ret) {
DEBUG(SSSDBG_OP_FAILURE, "Failed to store groups.\n");
diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
index 216b49477bf21481265444c5c03df0aac7ee84e4..f66ae2604c867d4a5e8d223081ece9f1e474cf73 100644
--- a/src/providers/ldap/sdap_async_users.c
+++ b/src/providers/ldap/sdap_async_users.c
@@ -606,7 +606,7 @@ struct sdap_search_user_state {
const char *base_filter;
const char *filter;
int timeout;
- bool enumeration;
+ enum sdap_entry_lookup_type lookup_type;
char *higher_usn;
struct sysdb_attrs **users;
@@ -628,7 +628,7 @@ struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx,
const char **attrs,
const char *filter,
int timeout,
- bool enumeration)
+ enum sdap_entry_lookup_type lookup_type)
{
errno_t ret;
struct tevent_req *req;
@@ -649,7 +649,7 @@ struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx,
state->base_filter = filter;
state->base_iter = 0;
state->search_bases = search_bases;
- state->enumeration = enumeration;
+ state->lookup_type = lookup_type;
if (!state->search_bases) {
DEBUG(SSSDBG_CRIT_FAILURE,
@@ -673,6 +673,7 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
{
struct tevent_req *subreq;
struct sdap_search_user_state *state;
+ bool need_paging = false;
state = tevent_req_data(req, struct sdap_search_user_state);
@@ -688,6 +689,19 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
"Searching for users with base [%s]\n",
state->search_bases[state->base_iter]->basedn);
+ switch (state->lookup_type) {
+ case SDAP_LOOKUP_SINGLE:
+ need_paging = false;
+ break;
+ /* Only requests that can return multiple entries should require
+ * the paging control
+ */
+ case SDAP_LOOKUP_WILDCARD:
+ case SDAP_LOOKUP_ENUMERATE:
+ need_paging = true;
+ break;
+ }
+
subreq = sdap_get_and_parse_generic_send(
state, state->ev, state->opts, state->sh,
state->search_bases[state->base_iter]->basedn,
@@ -695,7 +709,7 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
state->filter, state->attrs,
state->opts->user_map, state->opts->user_map_cnt,
0, NULL, NULL, 0, state->timeout,
- state->enumeration); /* If we're enumerating, we need paging */
+ need_paging);
if (subreq == NULL) {
return ENOMEM;
}
@@ -726,8 +740,10 @@ static void sdap_search_user_process(struct tevent_req *subreq)
DEBUG(SSSDBG_TRACE_FUNC,
"Search for users, returned %zu results.\n", count);
- if (state->enumeration || count == 0) {
- /* No users found in this search or enumerating */
+ if (state->lookup_type == SDAP_LOOKUP_WILDCARD || \
+ state->lookup_type == SDAP_LOOKUP_ENUMERATE || \
+ count == 0) {
+ /* No users found in this search or looking up multiple entries */
next_base = true;
}
@@ -827,7 +843,7 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
const char **attrs,
const char *filter,
int timeout,
- bool enumeration)
+ enum sdap_entry_lookup_type lookup_type)
{
errno_t ret;
struct tevent_req *req;
@@ -842,7 +858,7 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
state->dom = dom;
subreq = sdap_search_user_send(state, ev, dom, opts, search_bases,
- sh, attrs, filter, timeout, enumeration);
+ sh, attrs, filter, timeout, lookup_type);
if (subreq == NULL) {
ret = ENOMEM;
goto done;
--
2.4.3
-------------- next part --------------
>From 3396f4a50cfc34ea6c3fb61147dfbadef566487e Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 17 Jun 2015 16:13:51 +0200
Subject: [PATCH 10/11] LDAP: Add the wildcard_limit option
Related:
https://fedorahosted.org/sssd/ticket/2553
Adds a new wildcard_limit option that is set by default to 1000 (one
page). This option limits the number of entries that can by default be
returned by a wildcard search.
---
src/config/SSSDConfig/__init__.py.in | 1 +
src/config/etc/sssd.api.d/sssd-ad.conf | 1 +
src/config/etc/sssd.api.d/sssd-ipa.conf | 1 +
src/config/etc/sssd.api.d/sssd-ldap.conf | 1 +
src/man/sssd-ldap.5.xml | 17 +++++++++++++++++
src/providers/ad/ad_opts.h | 1 +
src/providers/ipa/ipa_opts.h | 1 +
src/providers/ldap/ldap_opts.h | 1 +
src/providers/ldap/sdap.h | 1 +
src/providers/ldap/sdap_async_groups.c | 8 +++++++-
src/providers/ldap/sdap_async_users.c | 8 +++++++-
11 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 4d45e42af4fa32717caa69cc621834cdffc27431..4b519eddd04cde83c209f5a1940832cc7f41c736 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -355,6 +355,7 @@ option_strings = {
'ldap_min_id' : _('Set lower boundary for allowed IDs from the LDAP server'),
'ldap_max_id' : _('Set upper boundary for allowed IDs from the LDAP server'),
'ldap_pwdlockout_dn' : _('DN for ppolicy queries'),
+ 'wildcard_limit' : _('How many maximum entries to fetch during a wildcard request'),
# [provider/ldap/auth]
'ldap_pwd_policy' : _('Policy to evaluate the password expiration'),
diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
index faab3a51e54d6d498392021a8945501120870f70..b636d93108ef0a3831970d7827895c14b0f3571c 100644
--- a/src/config/etc/sssd.api.d/sssd-ad.conf
+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
@@ -56,6 +56,7 @@ ldap_deref_threshold = int, None, false
ldap_connection_expire_timeout = int, None, false
ldap_disable_paging = bool, None, false
krb5_confd_path = str, None, false
+wildcard_limit = int, None, false
[provider/ad/id]
ldap_search_timeout = int, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
index cfcc00f6f7ca768df861e8cf7face065f90e9e83..ab712fe55cdac6d247a085aeca5cc82d65966623 100644
--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
@@ -52,6 +52,7 @@ ldap_deref_threshold = int, None, false
ldap_connection_expire_timeout = int, None, false
ldap_disable_paging = bool, None, false
krb5_confd_path = str, None, false
+wildcard_limit = int, None, false
[provider/ipa/id]
ldap_search_timeout = int, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
index c10290217b1b133792b893d9b80e2599969838a6..8fd45fd4093714f458161eb352157c845d926f06 100644
--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
@@ -37,6 +37,7 @@ ldap_sasl_minssf = int, None, false
ldap_connection_expire_timeout = int, None, false
ldap_disable_paging = bool, None, false
ldap_disable_range_retrieval = bool, None, false
+wildcard_limit = int, None, false
[provider/ldap/id]
ldap_search_timeout = int, None, false
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index f14090843fd32141ad4f491b69868aa7b2412301..9ac175f8d4a8aa01ca2434b800ebae1be88575f5 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -2135,6 +2135,23 @@ ldap_access_filter = (employeeType=admin)
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>wildcart_limit (integer)</term>
+ <listitem>
+ <para>
+ Specifies an upper limit on the number of entries
+ that are downloaded during a wildcard lookup.
+ </para>
+ <para>
+ At the moment, only the InfoPipe responder supports
+ wildcard lookups.
+ </para>
+ <para>
+ Default: 1000 (often the size of one page)
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</para>
</refsect1>
diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
index cb4c05d846d9abe5eedb28013ad13fff6476d431..d685edcb44c771b0afc7a232a82c21fc9d1c89f9 100644
--- a/src/providers/ad/ad_opts.h
+++ b/src/providers/ad/ad_opts.h
@@ -146,6 +146,7 @@ struct dp_option ad_def_ldap_opts[] = {
{ "ldap_min_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
{ "ldap_max_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
{ "ldap_pwdlockout_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "wildcard_limit", DP_OPT_NUMBER, { .number = 1000 }, NULL_NUMBER},
DP_OPTION_TERMINATOR
};
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index 253c0715355536cc181c57beed5326a77e87e464..9576228d1bf3424c8867bda058b59c3ca6b2216b 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -157,6 +157,7 @@ struct dp_option ipa_def_ldap_opts[] = {
{ "ldap_min_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
{ "ldap_max_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
{ "ldap_pwdlockout_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "wildcard_limit", DP_OPT_NUMBER, { .number = 1000 }, NULL_NUMBER},
DP_OPTION_TERMINATOR
};
diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
index c1b9bf688ef0a92046195c13a11d2c17b2419d67..9f58db5bd9eef1391e97c1890cbff94c2a5406d6 100644
--- a/src/providers/ldap/ldap_opts.h
+++ b/src/providers/ldap/ldap_opts.h
@@ -122,6 +122,7 @@ struct dp_option default_basic_opts[] = {
{ "ldap_min_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
{ "ldap_max_id", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER},
{ "ldap_pwdlockout_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "wildcard_limit", DP_OPT_NUMBER, { .number = 1000 }, NULL_NUMBER},
DP_OPTION_TERMINATOR
};
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index d9b2d18637bdb3e7823af9d1de2c042c8134780f..444502bf7159edcf4cebe530cce8b216c737ec30 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -231,6 +231,7 @@ enum sdap_basic_opt {
SDAP_MIN_ID,
SDAP_MAX_ID,
SDAP_PWDLOCKOUT_DN,
+ SDAP_WILDCARD_LIMIT,
SDAP_OPTS_BASIC /* opts counter */
};
diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
index ad0354df1fce9011c68cabb6049e7feee92a44c0..525c6fa09553d8c0232ce2317751184f83632d86 100644
--- a/src/providers/ldap/sdap_async_groups.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -1856,6 +1856,7 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
struct tevent_req *subreq;
struct sdap_get_groups_state *state;
bool need_paging = false;
+ int sizelimit = 0;
state = tevent_req_data(req, struct sdap_get_groups_state);
@@ -1873,13 +1874,18 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
switch (state->lookup_type) {
case SDAP_LOOKUP_SINGLE:
+ sizelimit = 1;
need_paging = false;
break;
/* Only requests that can return multiple entries should require
* the paging control
*/
case SDAP_LOOKUP_WILDCARD:
+ sizelimit = dp_opt_get_int(state->opts->basic, SDAP_WILDCARD_LIMIT);
+ need_paging = true;
+ break;
case SDAP_LOOKUP_ENUMERATE:
+ sizelimit = 0; /* unlimited */
need_paging = true;
break;
}
@@ -1891,7 +1897,7 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req)
state->search_bases[state->base_iter]->scope,
state->filter, state->attrs,
state->opts->group_map, SDAP_OPTS_GROUP,
- 0, NULL, NULL, 0, state->timeout,
+ 0, NULL, NULL, sizelimit, state->timeout,
need_paging);
if (!subreq) {
return ENOMEM;
diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
index f66ae2604c867d4a5e8d223081ece9f1e474cf73..a864a8b2187de7972aa963b355856e97f7c692a9 100644
--- a/src/providers/ldap/sdap_async_users.c
+++ b/src/providers/ldap/sdap_async_users.c
@@ -674,6 +674,7 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
struct tevent_req *subreq;
struct sdap_search_user_state *state;
bool need_paging = false;
+ int sizelimit = 0;
state = tevent_req_data(req, struct sdap_search_user_state);
@@ -691,13 +692,18 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
switch (state->lookup_type) {
case SDAP_LOOKUP_SINGLE:
+ sizelimit = 1;
need_paging = false;
break;
/* Only requests that can return multiple entries should require
* the paging control
*/
case SDAP_LOOKUP_WILDCARD:
+ sizelimit = dp_opt_get_int(state->opts->basic, SDAP_WILDCARD_LIMIT);
+ need_paging = true;
+ break;
case SDAP_LOOKUP_ENUMERATE:
+ sizelimit = 0; /* unlimited */
need_paging = true;
break;
}
@@ -708,7 +714,7 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req)
state->search_bases[state->base_iter]->scope,
state->filter, state->attrs,
state->opts->user_map, state->opts->user_map_cnt,
- 0, NULL, NULL, 0, state->timeout,
+ 0, NULL, NULL, sizelimit, state->timeout,
need_paging);
if (subreq == NULL) {
return ENOMEM;
--
2.4.3
-------------- next part --------------
>From da0aba106262f067be848d614f9871c2595468bf Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 17 Jun 2015 13:39:43 +0200
Subject: [PATCH 11/11] IFP: Add wildcard requests
Resolves:
https://fedorahosted.org/sssd/ticket/2553
Can be used as:
dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
/org/freedesktop/sssd/infopipe/Users \
org.freedesktop.sssd.infopipe.Users.ListByName \
string:r\* uint32:10
dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
/org/freedesktop/sssd/infopipe/Groups \
org.freedesktop.sssd.infopipe.Groups.ListByName \
string:r\* uint32:10
dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
/org/freedesktop/sssd/infopipe/Users \
org.freedesktop.sssd.infopipe.Users.ListByDomainAndName \
string:ipaldap string:r\* uint32:10
dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
/org/freedesktop/sssd/infopipe/Groups \
org.freedesktop.sssd.infopipe.Groups.ListByDomainAndName \
string:ipaldap string:r\* uint32:10
By default the wildcard_limit is unset, that is, the request will return
all cached entries that match.
---
src/confdb/confdb.h | 1 +
src/man/sssd-ifp.5.xml | 15 ++++
src/responder/ifp/ifp_groups.c | 175 ++++++++++++++++++++++++++++++++++++++
src/responder/ifp/ifp_private.h | 22 +++++
src/responder/ifp/ifp_users.c | 184 ++++++++++++++++++++++++++++++++++++++++
src/responder/ifp/ifpsrv.c | 23 +++++
src/responder/ifp/ifpsrv_util.c | 52 ++++++++++++
7 files changed, 472 insertions(+)
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index b2ec2e0b98a9be2d50009df524a1072e9b1c15c7..36df6aea268cc5c82696f20b1a65963350d5e100 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -140,6 +140,7 @@
/* InfoPipe */
#define CONFDB_IFP_CONF_ENTRY "config/ifp"
#define CONFDB_IFP_USER_ATTR_LIST "user_attributes"
+#define CONFDB_IFP_WILDCARD_LIMIT "wildcard_limit"
/* Domains */
#define CONFDB_DOMAIN_PATH_TMPL "config/domain/%s"
diff --git a/src/man/sssd-ifp.5.xml b/src/man/sssd-ifp.5.xml
index 867c117edccc3c000f7d9e8456298b72ebcdf693..da247f89dd2d9d08e0b1591d4c89f52197b278df 100644
--- a/src/man/sssd-ifp.5.xml
+++ b/src/man/sssd-ifp.5.xml
@@ -131,6 +131,21 @@ user_attributes = +telephoneNumber, -loginShell
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>wildcart_limit (integer)</term>
+ <listitem>
+ <para>
+ Specifies an upper limit on the number of entries
+ that are downloaded during a wildcard lookup that
+ overrides caller-supplied limit.
+ </para>
+ <para>
+ Default: 0 (let the caller set an upper limit)
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c
index 1b581b568f14362a47b4a80eb55d2de8eb936ae3..3060035924026641cc245f2a1970db9e2646e11c 100644
--- a/src/responder/ifp/ifp_groups.c
+++ b/src/responder/ifp/ifp_groups.c
@@ -81,6 +81,27 @@ done:
return ret;
}
+static int ifp_groups_list_copy(struct ifp_list_ctx *list_ctx,
+ struct ldb_result *result)
+{
+ size_t copy_count, i;
+
+ copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count);
+
+ for (i = 0; i < copy_count; i++) {
+ list_ctx->paths[list_ctx->path_count + i] = \
+ ifp_groups_build_path_from_msg(list_ctx->paths,
+ list_ctx->dom,
+ result->msgs[i]);
+ if (list_ctx->paths[list_ctx->path_count + i] == NULL) {
+ return ENOMEM;
+ }
+ }
+
+ list_ctx->path_count += copy_count;
+ return EOK;
+}
+
static void ifp_groups_find_by_name_done(struct tevent_req *req);
int ifp_groups_find_by_name(struct sbus_request *sbus_req,
@@ -221,23 +242,177 @@ done:
return;
}
+static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx);
+static void ifp_groups_list_by_name_done(struct tevent_req *req);
+static void ifp_groups_list_by_name_reply(struct ifp_list_ctx *list_ctx);
+
int ifp_groups_list_by_name(struct sbus_request *sbus_req,
void *data,
const char *filter,
uint32_t limit)
{
+ struct ifp_ctx *ctx;
+ struct ifp_list_ctx *list_ctx;
+
+ ctx = talloc_get_type(data, struct ifp_ctx);
+ if (ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
+ return ERR_INTERNAL;
+ }
+
+ list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
+ if (list_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ return ifp_groups_list_by_name_step(list_ctx);
+}
+
+static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx)
+{
+ struct tevent_req *req;
+
+ req = cache_req_group_by_filter_send(list_ctx,
+ list_ctx->ctx->rctx->ev,
+ list_ctx->ctx->rctx,
+ list_ctx->dom->name,
+ list_ctx->filter);
+ if (req == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(req,
+ ifp_groups_list_by_name_done, list_ctx);
+
return EOK;
}
+static void ifp_groups_list_by_name_done(struct tevent_req *req)
+{
+ DBusError *error;
+ struct ifp_list_ctx *list_ctx;
+ struct sbus_request *sbus_req;
+ struct ldb_result *result;
+ struct sss_domain_info *domain;
+ errno_t ret;
+
+ list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
+ sbus_req = list_ctx->sbus_req;
+
+ ret = cache_req_group_by_name_recv(sbus_req, req, &result, &domain, NULL);
+ talloc_zfree(req);
+ if (ret != EOK && ret != ENOENT) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
+ "groups by filter [%d]: %s\n", ret, sss_strerror(ret));
+ sbus_request_fail_and_finish(sbus_req, error);
+ return;
+ }
+
+ ret = ifp_groups_list_copy(list_ctx, result);
+ if (ret != EOK) {
+ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
+ "Failed to copy domain result");
+ sbus_request_fail_and_finish(sbus_req, error);
+ return;
+ }
+
+ list_ctx->dom = get_next_domain(list_ctx->dom, true);
+ if (list_ctx->dom == NULL) {
+ return ifp_groups_list_by_name_reply(list_ctx);
+ }
+
+ ret = ifp_groups_list_by_name_step(list_ctx);
+ if (ret != EOK) {
+ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
+ "Failed to start next-domain search");
+ sbus_request_fail_and_finish(sbus_req, error);
+ return;
+ }
+}
+
+static void ifp_groups_list_by_name_reply(struct ifp_list_ctx *list_ctx)
+{
+ iface_ifp_groups_ListByDomainAndName_finish(list_ctx->sbus_req,
+ list_ctx->paths,
+ list_ctx->path_count);
+}
+
+static void ifp_groups_list_by_domain_and_name_done(struct tevent_req *req);
+
int ifp_groups_list_by_domain_and_name(struct sbus_request *sbus_req,
void *data,
const char *domain,
const char *filter,
uint32_t limit)
{
+ struct tevent_req *req;
+ struct ifp_ctx *ctx;
+ struct ifp_list_ctx *list_ctx;
+
+ ctx = talloc_get_type(data, struct ifp_ctx);
+ if (ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
+ return ERR_INTERNAL;
+ }
+
+ list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
+ if (list_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ req = cache_req_group_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx,
+ domain, filter);
+ if (req == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(req,
+ ifp_groups_list_by_domain_and_name_done, list_ctx);
+
return EOK;
}
+static void ifp_groups_list_by_domain_and_name_done(struct tevent_req *req)
+{
+ DBusError *error;
+ struct ifp_list_ctx *list_ctx;
+ struct sbus_request *sbus_req;
+ struct ldb_result *result;
+ struct sss_domain_info *domain;
+ errno_t ret;
+
+ list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
+ sbus_req = list_ctx->sbus_req;
+
+ ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
+ talloc_zfree(req);
+ if (ret == ENOENT) {
+ error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
+ "User not found by filter");
+ goto done;
+ } else if (ret != EOK) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
+ "groups by filter [%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = ifp_groups_list_copy(list_ctx, result);
+ if (ret != EOK) {
+ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
+ "Failed to copy domain result");
+ goto done;
+ }
+
+done:
+ if (ret != EOK) {
+ sbus_request_fail_and_finish(sbus_req, error);
+ return;
+ }
+
+ iface_ifp_groups_ListByDomainAndName_finish(sbus_req,
+ list_ctx->paths,
+ list_ctx->path_count);
+ return;
+}
+
static errno_t
ifp_groups_group_get(struct sbus_request *sbus_req,
void *data,
diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h
index 304e4dc535aac4215cf318a0bea845c161c5f079..43519de6fef3033f1e47cecb787d6b02dc9c6e56 100644
--- a/src/responder/ifp/ifp_private.h
+++ b/src/responder/ifp/ifp_private.h
@@ -44,6 +44,7 @@ struct ifp_ctx {
struct sysbus_ctx *sysbus;
const char **user_whitelist;
+ uint32_t wildcard_limit;
};
errno_t ifp_register_sbus_interface(struct sbus_connection *conn,
@@ -84,4 +85,25 @@ ifp_get_user_extra_attributes(TALLOC_CTX *mem_ctx, struct ifp_ctx *ifp_ctx);
bool ifp_attr_allowed(const char *whitelist[], const char *attr);
bool ifp_is_user_attr_allowed(struct ifp_ctx *ifp_ctx, const char *attr);
+/* Used for list calls */
+struct ifp_list_ctx {
+ struct sbus_request *sbus_req;
+ const char *filter;
+ uint32_t limit;
+
+ struct sss_domain_info *dom;
+ struct ifp_ctx *ctx;
+
+ const char **paths;
+ size_t path_count;
+};
+
+struct ifp_list_ctx *ifp_list_ctx_new(struct sbus_request *sbus_req,
+ struct ifp_ctx *ctx,
+ const char *filter,
+ uint32_t limit);
+
+size_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx,
+ size_t entries);
+
#endif /* _IFPSRV_PRIVATE_H_ */
diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
index 2ec74c30b348ac5f2b84cdc8e2dd406fd44a7da3..effefdc0435d794206dbe7358c61d2ea47760361 100644
--- a/src/responder/ifp/ifp_users.c
+++ b/src/responder/ifp/ifp_users.c
@@ -309,23 +309,207 @@ done:
return;
}
+static int ifp_users_list_copy(struct ifp_list_ctx *list_ctx,
+ struct ldb_result *result)
+{
+ size_t copy_count, i;
+
+ copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count);
+
+ for (i = 0; i < copy_count; i++) {
+ list_ctx->paths[list_ctx->path_count + i] = \
+ ifp_users_build_path_from_msg(list_ctx->paths,
+ list_ctx->dom,
+ result->msgs[i]);
+ if (list_ctx->paths[list_ctx->path_count + i] == NULL) {
+ return ENOMEM;
+ }
+ }
+
+ list_ctx->path_count += copy_count;
+ return EOK;
+}
+
+static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx);
+static void ifp_users_list_by_name_done(struct tevent_req *req);
+static void ifp_users_list_by_name_reply(struct ifp_list_ctx *list_ctx);
+
int ifp_users_list_by_name(struct sbus_request *sbus_req,
void *data,
const char *filter,
uint32_t limit)
{
+ struct ifp_ctx *ctx;
+ struct ifp_list_ctx *list_ctx;
+
+ ctx = talloc_get_type(data, struct ifp_ctx);
+ if (ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
+ return ERR_INTERNAL;
+ }
+
+ list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
+ if (list_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ return ifp_users_list_by_name_step(list_ctx);
+}
+
+static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx)
+{
+ struct tevent_req *req;
+
+ req = cache_req_user_by_filter_send(list_ctx,
+ list_ctx->ctx->rctx->ev,
+ list_ctx->ctx->rctx,
+ list_ctx->dom->name,
+ list_ctx->filter);
+ if (req == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(req,
+ ifp_users_list_by_name_done, list_ctx);
+
return EOK;
}
+static void ifp_users_list_by_name_done(struct tevent_req *req)
+{
+ DBusError *error;
+ struct ifp_list_ctx *list_ctx;
+ struct sbus_request *sbus_req;
+ struct ldb_result *result;
+ struct sss_domain_info *domain;
+ errno_t ret;
+
+ list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
+ sbus_req = list_ctx->sbus_req;
+
+ ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
+ talloc_zfree(req);
+ if (ret != EOK && ret != ENOENT) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
+ "users by filter [%d]: %s\n", ret, sss_strerror(ret));
+ sbus_request_fail_and_finish(sbus_req, error);
+ return;
+ }
+
+ ret = ifp_users_list_copy(list_ctx, result);
+ if (ret != EOK) {
+ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
+ "Failed to copy domain result");
+ sbus_request_fail_and_finish(sbus_req, error);
+ return;
+ }
+
+ list_ctx->dom = get_next_domain(list_ctx->dom, true);
+ if (list_ctx->dom == NULL) {
+ return ifp_users_list_by_name_reply(list_ctx);
+ }
+
+ ret = ifp_users_list_by_name_step(list_ctx);
+ if (ret != EOK) {
+ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
+ "Failed to start next-domain search");
+ sbus_request_fail_and_finish(sbus_req, error);
+ return;
+ }
+}
+
+static void ifp_users_list_by_name_reply(struct ifp_list_ctx *list_ctx)
+{
+ iface_ifp_users_ListByName_finish(list_ctx->sbus_req,
+ list_ctx->paths,
+ list_ctx->path_count);
+}
+
+static void ifp_users_list_by_domain_and_name_done(struct tevent_req *req);
+
int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req,
void *data,
const char *domain,
const char *filter,
uint32_t limit)
{
+ struct tevent_req *req;
+ struct ifp_ctx *ctx;
+ struct ifp_list_ctx *list_ctx;
+
+ ctx = talloc_get_type(data, struct ifp_ctx);
+ if (ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
+ return ERR_INTERNAL;
+ }
+
+ list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
+ if (list_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ req = cache_req_user_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx,
+ domain, filter);
+ if (req == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(req,
+ ifp_users_list_by_domain_and_name_done, list_ctx);
+
return EOK;
}
+static void ifp_users_list_by_domain_and_name_done(struct tevent_req *req)
+{
+ DBusError *error;
+ struct ifp_list_ctx *list_ctx;
+ struct sbus_request *sbus_req;
+ struct ldb_result *result;
+ struct sss_domain_info *domain;
+ errno_t ret;
+ size_t copy_count, i;
+
+ list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
+ sbus_req = list_ctx->sbus_req;
+
+ ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
+ talloc_zfree(req);
+ if (ret == ENOENT) {
+ error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
+ "User not found by filter");
+ goto done;
+ } else if (ret != EOK) {
+ error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
+ "users by filter [%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+
+ copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count);
+
+ for (i = 0; i < copy_count; i++) {
+ list_ctx->paths[i] = ifp_users_build_path_from_msg(list_ctx->paths,
+ list_ctx->dom,
+ result->msgs[i]);
+ if (list_ctx->paths[i] == NULL) {
+ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
+ "Failed to compose object path");
+ goto done;
+ }
+ }
+
+ list_ctx->path_count += copy_count;
+
+done:
+ if (ret != EOK) {
+ sbus_request_fail_and_finish(sbus_req, error);
+ return;
+ }
+
+ iface_ifp_users_ListByDomainAndName_finish(sbus_req,
+ list_ctx->paths,
+ list_ctx->path_count);
+ return;
+}
+
static errno_t
ifp_users_user_get(struct sbus_request *sbus_req,
struct ifp_ctx *ifp_ctx,
diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
index 631bcd266d7e06154dbf1f37f9f439119b2b8944..cdc411faa330dc2c063e52abe63cd68dbe16a5d9 100644
--- a/src/responder/ifp/ifpsrv.c
+++ b/src/responder/ifp/ifpsrv.c
@@ -34,6 +34,7 @@
#include <dbus/dbus.h>
#include "util/util.h"
+#include "util/strtonum.h"
#include "sbus/sssd_dbus.h"
#include "monitor/monitor_interfaces.h"
#include "confdb/confdb.h"
@@ -228,6 +229,7 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
int max_retries;
char *uid_str;
char *attr_list_str;
+ char *wildcard_limit_str;
ifp_cmds = get_ifp_cmds();
ret = sss_process_init(mem_ctx, ev, cdb,
@@ -321,6 +323,27 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
goto fail;
}
+ /* A bit convoluted way until we have a confdb_get_uint32 */
+ ret = confdb_get_string(ifp_ctx->rctx->cdb,
+ ifp_ctx->rctx,
+ CONFDB_IFP_CONF_ENTRY,
+ CONFDB_IFP_WILDCARD_LIMIT,
+ NULL, /* no limit by default */
+ &wildcard_limit_str);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to retrieve limit for a wildcard search\n");
+ goto fail;
+ }
+
+ if (wildcard_limit_str) {
+ ifp_ctx->wildcard_limit = strtouint32(wildcard_limit_str, NULL, 10);
+ if (errno != 0) {
+ ret = errno;
+ goto fail;
+ }
+ }
+
for (iter = ifp_ctx->rctx->be_conns; iter; iter = iter->next) {
sbus_reconnect_init(iter->conn, max_retries,
ifp_dp_reconnect_init, iter);
diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c
index 674165ee4901115c9e17458a75fdb3536b6468c2..3b02fd06f5227e4ffc3d40ffb20fed981c5028a7 100644
--- a/src/responder/ifp/ifpsrv_util.c
+++ b/src/responder/ifp/ifpsrv_util.c
@@ -21,6 +21,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <sys/param.h>
+
#include "db/sysdb.h"
#include "responder/ifp/ifp_private.h"
@@ -269,3 +271,53 @@ ifp_is_user_attr_allowed(struct ifp_ctx *ifp_ctx, const char *attr)
{
return ifp_attr_allowed(ifp_ctx->user_whitelist, attr);
}
+
+static uint32_t ifp_list_limit(struct ifp_ctx *ctx, uint32_t limit)
+{
+ if (ctx->wildcard_limit) {
+ return MIN(ctx->wildcard_limit, limit);
+ } else {
+ return limit;
+ }
+}
+
+struct ifp_list_ctx *ifp_list_ctx_new(struct sbus_request *sbus_req,
+ struct ifp_ctx *ctx,
+ const char *filter,
+ uint32_t limit)
+{
+ struct ifp_list_ctx *list_ctx;
+
+ list_ctx = talloc_zero(sbus_req, struct ifp_list_ctx);
+ if (list_ctx == NULL) {
+ return NULL;
+ }
+
+ list_ctx->sbus_req = sbus_req;
+ list_ctx->limit = ifp_list_limit(ctx, limit);
+ list_ctx->ctx = ctx;
+ list_ctx->dom = ctx->rctx->domains;
+ list_ctx->filter = filter;
+ list_ctx->paths = talloc_zero_array(list_ctx, const char *, limit);
+ if (list_ctx->paths == NULL) {
+ talloc_free(list_ctx);
+ return NULL;
+ }
+
+ return list_ctx;
+}
+
+size_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx,
+ size_t entries)
+{
+ size_t capacity = list_ctx->limit - list_ctx->path_count;
+
+ if (capacity < entries) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "IFP list request has limit of %"PRIu32" entries but back end "
+ "returned %zu entries\n", list_ctx->limit, entries);
+ return capacity;
+ } else {
+ return entries;
+ }
+}
--
2.4.3
More information about the sssd-devel
mailing list