Blame SOURCES/0012-IFP-Add-wildcard-requests.patch

6cf099
From fe9a0097970d12ff261b7417f9e57db95957ab24 Mon Sep 17 00:00:00 2001
6cf099
From: Jakub Hrozek <jhrozek@redhat.com>
6cf099
Date: Wed, 17 Jun 2015 13:39:43 +0200
6cf099
Subject: [PATCH 12/13] IFP: Add wildcard requests
6cf099
MIME-Version: 1.0
6cf099
Content-Type: text/plain; charset=UTF-8
6cf099
Content-Transfer-Encoding: 8bit
6cf099
6cf099
Resolves:
6cf099
    https://fedorahosted.org/sssd/ticket/2553
6cf099
6cf099
Can be used as:
6cf099
6cf099
dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
6cf099
        /org/freedesktop/sssd/infopipe/Users \
6cf099
        org.freedesktop.sssd.infopipe.Users.ListByName \
6cf099
        string:r\* uint32:10
6cf099
6cf099
dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
6cf099
        /org/freedesktop/sssd/infopipe/Groups \
6cf099
        org.freedesktop.sssd.infopipe.Groups.ListByName \
6cf099
        string:r\* uint32:10
6cf099
6cf099
dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
6cf099
        /org/freedesktop/sssd/infopipe/Users \
6cf099
        org.freedesktop.sssd.infopipe.Users.ListByDomainAndName \
6cf099
        string:ipaldap string:r\* uint32:10
6cf099
6cf099
dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe \
6cf099
        /org/freedesktop/sssd/infopipe/Groups \
6cf099
        org.freedesktop.sssd.infopipe.Groups.ListByDomainAndName \
6cf099
        string:ipaldap string:r\* uint32:10
6cf099
6cf099
By default the wildcard_limit is unset, that is, the request will return
6cf099
all cached entries that match.
6cf099
6cf099
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
6cf099
---
6cf099
 src/confdb/confdb.h             |   1 +
6cf099
 src/man/sssd-ifp.5.xml          |  15 ++++
6cf099
 src/responder/ifp/ifp_groups.c  | 175 ++++++++++++++++++++++++++++++++++++++
6cf099
 src/responder/ifp/ifp_private.h |  22 +++++
6cf099
 src/responder/ifp/ifp_users.c   | 184 ++++++++++++++++++++++++++++++++++++++++
6cf099
 src/responder/ifp/ifpsrv.c      |  23 +++++
6cf099
 src/responder/ifp/ifpsrv_util.c |  52 ++++++++++++
6cf099
 7 files changed, 472 insertions(+)
6cf099
6cf099
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
6cf099
index b2ec2e0b98a9be2d50009df524a1072e9b1c15c7..36df6aea268cc5c82696f20b1a65963350d5e100 100644
6cf099
--- a/src/confdb/confdb.h
6cf099
+++ b/src/confdb/confdb.h
6cf099
@@ -140,6 +140,7 @@
6cf099
 /* InfoPipe */
6cf099
 #define CONFDB_IFP_CONF_ENTRY "config/ifp"
6cf099
 #define CONFDB_IFP_USER_ATTR_LIST "user_attributes"
6cf099
+#define CONFDB_IFP_WILDCARD_LIMIT "wildcard_limit"
6cf099
 
6cf099
 /* Domains */
6cf099
 #define CONFDB_DOMAIN_PATH_TMPL "config/domain/%s"
6cf099
diff --git a/src/man/sssd-ifp.5.xml b/src/man/sssd-ifp.5.xml
6cf099
index 867c117edccc3c000f7d9e8456298b72ebcdf693..da247f89dd2d9d08e0b1591d4c89f52197b278df 100644
6cf099
--- a/src/man/sssd-ifp.5.xml
6cf099
+++ b/src/man/sssd-ifp.5.xml
6cf099
@@ -131,6 +131,21 @@ user_attributes = +telephoneNumber, -loginShell
6cf099
                         </para>
6cf099
                     </listitem>
6cf099
                 </varlistentry>
6cf099
+
6cf099
+                <varlistentry>
6cf099
+                    <term>wildcart_limit (integer)</term>
6cf099
+                    <listitem>
6cf099
+                        <para>
6cf099
+                            Specifies an upper limit on the number of entries
6cf099
+                            that are downloaded during a wildcard lookup that
6cf099
+                            overrides caller-supplied limit.
6cf099
+                        </para>
6cf099
+                        <para>
6cf099
+                            Default: 0 (let the caller set an upper limit)
6cf099
+                        </para>
6cf099
+                    </listitem>
6cf099
+                </varlistentry>
6cf099
+
6cf099
             </variablelist>
6cf099
     </refsect1>
6cf099
 
6cf099
diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c
6cf099
index 1b581b568f14362a47b4a80eb55d2de8eb936ae3..3060035924026641cc245f2a1970db9e2646e11c 100644
6cf099
--- a/src/responder/ifp/ifp_groups.c
6cf099
+++ b/src/responder/ifp/ifp_groups.c
6cf099
@@ -81,6 +81,27 @@ done:
6cf099
     return ret;
6cf099
 }
6cf099
 
6cf099
+static int ifp_groups_list_copy(struct ifp_list_ctx *list_ctx,
6cf099
+                                struct ldb_result *result)
6cf099
+{
6cf099
+    size_t copy_count, i;
6cf099
+
6cf099
+    copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count);
6cf099
+
6cf099
+    for (i = 0; i < copy_count; i++) {
6cf099
+        list_ctx->paths[list_ctx->path_count + i] = \
6cf099
+            ifp_groups_build_path_from_msg(list_ctx->paths,
6cf099
+                                           list_ctx->dom,
6cf099
+                                           result->msgs[i]);
6cf099
+        if (list_ctx->paths[list_ctx->path_count + i] == NULL) {
6cf099
+            return ENOMEM;
6cf099
+        }
6cf099
+    }
6cf099
+
6cf099
+    list_ctx->path_count += copy_count;
6cf099
+    return EOK;
6cf099
+}
6cf099
+
6cf099
 static void ifp_groups_find_by_name_done(struct tevent_req *req);
6cf099
 
6cf099
 int ifp_groups_find_by_name(struct sbus_request *sbus_req,
6cf099
@@ -221,23 +242,177 @@ done:
6cf099
     return;
6cf099
 }
6cf099
 
6cf099
+static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx);
6cf099
+static void ifp_groups_list_by_name_done(struct tevent_req *req);
6cf099
+static void ifp_groups_list_by_name_reply(struct ifp_list_ctx *list_ctx);
6cf099
+
6cf099
 int ifp_groups_list_by_name(struct sbus_request *sbus_req,
6cf099
                             void *data,
6cf099
                             const char *filter,
6cf099
                             uint32_t limit)
6cf099
 {
6cf099
+    struct ifp_ctx *ctx;
6cf099
+    struct ifp_list_ctx *list_ctx;
6cf099
+
6cf099
+    ctx = talloc_get_type(data, struct ifp_ctx);
6cf099
+    if (ctx == NULL) {
6cf099
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
6cf099
+        return ERR_INTERNAL;
6cf099
+    }
6cf099
+
6cf099
+    list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
6cf099
+    if (list_ctx == NULL) {
6cf099
+        return ENOMEM;
6cf099
+    }
6cf099
+
6cf099
+    return ifp_groups_list_by_name_step(list_ctx);
6cf099
+}
6cf099
+
6cf099
+static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx)
6cf099
+{
6cf099
+    struct tevent_req *req;
6cf099
+
6cf099
+    req = cache_req_group_by_filter_send(list_ctx,
6cf099
+                                        list_ctx->ctx->rctx->ev,
6cf099
+                                        list_ctx->ctx->rctx,
6cf099
+                                        list_ctx->dom->name,
6cf099
+                                        list_ctx->filter);
6cf099
+    if (req == NULL) {
6cf099
+        return ENOMEM;
6cf099
+    }
6cf099
+    tevent_req_set_callback(req,
6cf099
+                            ifp_groups_list_by_name_done, list_ctx);
6cf099
+
6cf099
     return EOK;
6cf099
 }
6cf099
 
6cf099
+static void ifp_groups_list_by_name_done(struct tevent_req *req)
6cf099
+{
6cf099
+    DBusError *error;
6cf099
+    struct ifp_list_ctx *list_ctx;
6cf099
+    struct sbus_request *sbus_req;
6cf099
+    struct ldb_result *result;
6cf099
+    struct sss_domain_info *domain;
6cf099
+    errno_t ret;
6cf099
+
6cf099
+    list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
6cf099
+    sbus_req = list_ctx->sbus_req;
6cf099
+
6cf099
+    ret = cache_req_group_by_name_recv(sbus_req, req, &result, &domain, NULL);
6cf099
+    talloc_zfree(req);
6cf099
+    if (ret != EOK && ret != ENOENT) {
6cf099
+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
6cf099
+                               "groups by filter [%d]: %s\n", ret, sss_strerror(ret));
6cf099
+        sbus_request_fail_and_finish(sbus_req, error);
6cf099
+        return;
6cf099
+    }
6cf099
+
6cf099
+    ret = ifp_groups_list_copy(list_ctx, result);
6cf099
+    if (ret != EOK) {
6cf099
+        error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
6cf099
+                               "Failed to copy domain result");
6cf099
+        sbus_request_fail_and_finish(sbus_req, error);
6cf099
+        return;
6cf099
+    }
6cf099
+
6cf099
+    list_ctx->dom = get_next_domain(list_ctx->dom, true);
6cf099
+    if (list_ctx->dom == NULL) {
6cf099
+        return ifp_groups_list_by_name_reply(list_ctx);
6cf099
+    }
6cf099
+
6cf099
+    ret = ifp_groups_list_by_name_step(list_ctx);
6cf099
+    if (ret != EOK) {
6cf099
+        error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
6cf099
+                               "Failed to start next-domain search");
6cf099
+        sbus_request_fail_and_finish(sbus_req, error);
6cf099
+        return;
6cf099
+    }
6cf099
+}
6cf099
+
6cf099
+static void ifp_groups_list_by_name_reply(struct ifp_list_ctx *list_ctx)
6cf099
+{
6cf099
+    iface_ifp_groups_ListByDomainAndName_finish(list_ctx->sbus_req,
6cf099
+                                               list_ctx->paths,
6cf099
+                                               list_ctx->path_count);
6cf099
+}
6cf099
+
6cf099
+static void ifp_groups_list_by_domain_and_name_done(struct tevent_req *req);
6cf099
+
6cf099
 int ifp_groups_list_by_domain_and_name(struct sbus_request *sbus_req,
6cf099
                                        void *data,
6cf099
                                        const char *domain,
6cf099
                                        const char *filter,
6cf099
                                        uint32_t limit)
6cf099
 {
6cf099
+    struct tevent_req *req;
6cf099
+    struct ifp_ctx *ctx;
6cf099
+    struct ifp_list_ctx *list_ctx;
6cf099
+
6cf099
+    ctx = talloc_get_type(data, struct ifp_ctx);
6cf099
+    if (ctx == NULL) {
6cf099
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
6cf099
+        return ERR_INTERNAL;
6cf099
+    }
6cf099
+
6cf099
+    list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
6cf099
+    if (list_ctx == NULL) {
6cf099
+        return ENOMEM;
6cf099
+    }
6cf099
+
6cf099
+    req = cache_req_group_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx,
6cf099
+                                        domain, filter);
6cf099
+    if (req == NULL) {
6cf099
+        return ENOMEM;
6cf099
+    }
6cf099
+    tevent_req_set_callback(req,
6cf099
+                            ifp_groups_list_by_domain_and_name_done, list_ctx);
6cf099
+
6cf099
     return EOK;
6cf099
 }
6cf099
 
6cf099
+static void ifp_groups_list_by_domain_and_name_done(struct tevent_req *req)
6cf099
+{
6cf099
+    DBusError *error;
6cf099
+    struct ifp_list_ctx *list_ctx;
6cf099
+    struct sbus_request *sbus_req;
6cf099
+    struct ldb_result *result;
6cf099
+    struct sss_domain_info *domain;
6cf099
+    errno_t ret;
6cf099
+
6cf099
+    list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
6cf099
+    sbus_req = list_ctx->sbus_req;
6cf099
+
6cf099
+    ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
6cf099
+    talloc_zfree(req);
6cf099
+    if (ret == ENOENT) {
6cf099
+        error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
6cf099
+                               "User not found by filter");
6cf099
+        goto done;
6cf099
+    } else if (ret != EOK) {
6cf099
+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
6cf099
+                               "groups by filter [%d]: %s\n", ret, sss_strerror(ret));
6cf099
+        goto done;
6cf099
+    }
6cf099
+
6cf099
+    ret = ifp_groups_list_copy(list_ctx, result);
6cf099
+    if (ret != EOK) {
6cf099
+        error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
6cf099
+                               "Failed to copy domain result");
6cf099
+        goto done;
6cf099
+    }
6cf099
+
6cf099
+done:
6cf099
+    if (ret != EOK) {
6cf099
+        sbus_request_fail_and_finish(sbus_req, error);
6cf099
+        return;
6cf099
+    }
6cf099
+
6cf099
+    iface_ifp_groups_ListByDomainAndName_finish(sbus_req,
6cf099
+                                                list_ctx->paths,
6cf099
+                                                list_ctx->path_count);
6cf099
+    return;
6cf099
+}
6cf099
+
6cf099
 static errno_t
6cf099
 ifp_groups_group_get(struct sbus_request *sbus_req,
6cf099
                      void *data,
6cf099
diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h
6cf099
index 304e4dc535aac4215cf318a0bea845c161c5f079..43519de6fef3033f1e47cecb787d6b02dc9c6e56 100644
6cf099
--- a/src/responder/ifp/ifp_private.h
6cf099
+++ b/src/responder/ifp/ifp_private.h
6cf099
@@ -44,6 +44,7 @@ struct ifp_ctx {
6cf099
 
6cf099
     struct sysbus_ctx *sysbus;
6cf099
     const char **user_whitelist;
6cf099
+    uint32_t wildcard_limit;
6cf099
 };
6cf099
 
6cf099
 errno_t ifp_register_sbus_interface(struct sbus_connection *conn,
6cf099
@@ -84,4 +85,25 @@ ifp_get_user_extra_attributes(TALLOC_CTX *mem_ctx, struct ifp_ctx *ifp_ctx);
6cf099
 bool ifp_attr_allowed(const char *whitelist[], const char *attr);
6cf099
 bool ifp_is_user_attr_allowed(struct ifp_ctx *ifp_ctx, const char *attr);
6cf099
 
6cf099
+/* Used for list calls */
6cf099
+struct ifp_list_ctx {
6cf099
+    struct sbus_request *sbus_req;
6cf099
+    const char *filter;
6cf099
+    uint32_t limit;
6cf099
+
6cf099
+    struct sss_domain_info *dom;
6cf099
+    struct ifp_ctx *ctx;
6cf099
+
6cf099
+    const char **paths;
6cf099
+    size_t path_count;
6cf099
+};
6cf099
+
6cf099
+struct ifp_list_ctx *ifp_list_ctx_new(struct sbus_request *sbus_req,
6cf099
+                                      struct ifp_ctx *ctx,
6cf099
+                                      const char *filter,
6cf099
+                                      uint32_t limit);
6cf099
+
6cf099
+size_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx,
6cf099
+                                       size_t entries);
6cf099
+
6cf099
 #endif /* _IFPSRV_PRIVATE_H_ */
6cf099
diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
6cf099
index 2ec74c30b348ac5f2b84cdc8e2dd406fd44a7da3..effefdc0435d794206dbe7358c61d2ea47760361 100644
6cf099
--- a/src/responder/ifp/ifp_users.c
6cf099
+++ b/src/responder/ifp/ifp_users.c
6cf099
@@ -309,23 +309,207 @@ done:
6cf099
     return;
6cf099
 }
6cf099
 
6cf099
+static int ifp_users_list_copy(struct ifp_list_ctx *list_ctx,
6cf099
+                               struct ldb_result *result)
6cf099
+{
6cf099
+    size_t copy_count, i;
6cf099
+
6cf099
+    copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count);
6cf099
+
6cf099
+    for (i = 0; i < copy_count; i++) {
6cf099
+        list_ctx->paths[list_ctx->path_count + i] = \
6cf099
+                             ifp_users_build_path_from_msg(list_ctx->paths,
6cf099
+                                                           list_ctx->dom,
6cf099
+                                                           result->msgs[i]);
6cf099
+        if (list_ctx->paths[list_ctx->path_count + i] == NULL) {
6cf099
+            return ENOMEM;
6cf099
+        }
6cf099
+    }
6cf099
+
6cf099
+    list_ctx->path_count += copy_count;
6cf099
+    return EOK;
6cf099
+}
6cf099
+
6cf099
+static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx);
6cf099
+static void ifp_users_list_by_name_done(struct tevent_req *req);
6cf099
+static void ifp_users_list_by_name_reply(struct ifp_list_ctx *list_ctx);
6cf099
+
6cf099
 int ifp_users_list_by_name(struct sbus_request *sbus_req,
6cf099
                            void *data,
6cf099
                            const char *filter,
6cf099
                            uint32_t limit)
6cf099
 {
6cf099
+    struct ifp_ctx *ctx;
6cf099
+    struct ifp_list_ctx *list_ctx;
6cf099
+
6cf099
+    ctx = talloc_get_type(data, struct ifp_ctx);
6cf099
+    if (ctx == NULL) {
6cf099
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
6cf099
+        return ERR_INTERNAL;
6cf099
+    }
6cf099
+
6cf099
+    list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
6cf099
+    if (list_ctx == NULL) {
6cf099
+        return ENOMEM;
6cf099
+    }
6cf099
+
6cf099
+    return ifp_users_list_by_name_step(list_ctx);
6cf099
+}
6cf099
+
6cf099
+static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx)
6cf099
+{
6cf099
+    struct tevent_req *req;
6cf099
+
6cf099
+    req = cache_req_user_by_filter_send(list_ctx,
6cf099
+                                        list_ctx->ctx->rctx->ev,
6cf099
+                                        list_ctx->ctx->rctx,
6cf099
+                                        list_ctx->dom->name,
6cf099
+                                        list_ctx->filter);
6cf099
+    if (req == NULL) {
6cf099
+        return ENOMEM;
6cf099
+    }
6cf099
+    tevent_req_set_callback(req,
6cf099
+                            ifp_users_list_by_name_done, list_ctx);
6cf099
+
6cf099
     return EOK;
6cf099
 }
6cf099
 
6cf099
+static void ifp_users_list_by_name_done(struct tevent_req *req)
6cf099
+{
6cf099
+    DBusError *error;
6cf099
+    struct ifp_list_ctx *list_ctx;
6cf099
+    struct sbus_request *sbus_req;
6cf099
+    struct ldb_result *result;
6cf099
+    struct sss_domain_info *domain;
6cf099
+    errno_t ret;
6cf099
+
6cf099
+    list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
6cf099
+    sbus_req = list_ctx->sbus_req;
6cf099
+
6cf099
+    ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
6cf099
+    talloc_zfree(req);
6cf099
+    if (ret != EOK && ret != ENOENT) {
6cf099
+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
6cf099
+                               "users by filter [%d]: %s\n", ret, sss_strerror(ret));
6cf099
+        sbus_request_fail_and_finish(sbus_req, error);
6cf099
+        return;
6cf099
+    }
6cf099
+
6cf099
+    ret = ifp_users_list_copy(list_ctx, result);
6cf099
+    if (ret != EOK) {
6cf099
+        error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
6cf099
+                               "Failed to copy domain result");
6cf099
+        sbus_request_fail_and_finish(sbus_req, error);
6cf099
+        return;
6cf099
+    }
6cf099
+
6cf099
+    list_ctx->dom = get_next_domain(list_ctx->dom, true);
6cf099
+    if (list_ctx->dom == NULL) {
6cf099
+        return ifp_users_list_by_name_reply(list_ctx);
6cf099
+    }
6cf099
+
6cf099
+    ret = ifp_users_list_by_name_step(list_ctx);
6cf099
+    if (ret != EOK) {
6cf099
+        error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
6cf099
+                               "Failed to start next-domain search");
6cf099
+        sbus_request_fail_and_finish(sbus_req, error);
6cf099
+        return;
6cf099
+    }
6cf099
+}
6cf099
+
6cf099
+static void ifp_users_list_by_name_reply(struct ifp_list_ctx *list_ctx)
6cf099
+{
6cf099
+    iface_ifp_users_ListByName_finish(list_ctx->sbus_req,
6cf099
+                                      list_ctx->paths,
6cf099
+                                      list_ctx->path_count);
6cf099
+}
6cf099
+
6cf099
+static void ifp_users_list_by_domain_and_name_done(struct tevent_req *req);
6cf099
+
6cf099
 int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req,
6cf099
                                       void *data,
6cf099
                                       const char *domain,
6cf099
                                       const char *filter,
6cf099
                                       uint32_t limit)
6cf099
 {
6cf099
+    struct tevent_req *req;
6cf099
+    struct ifp_ctx *ctx;
6cf099
+    struct ifp_list_ctx *list_ctx;
6cf099
+
6cf099
+    ctx = talloc_get_type(data, struct ifp_ctx);
6cf099
+    if (ctx == NULL) {
6cf099
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
6cf099
+        return ERR_INTERNAL;
6cf099
+    }
6cf099
+
6cf099
+    list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
6cf099
+    if (list_ctx == NULL) {
6cf099
+        return ENOMEM;
6cf099
+    }
6cf099
+
6cf099
+    req = cache_req_user_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx,
6cf099
+                                        domain, filter);
6cf099
+    if (req == NULL) {
6cf099
+        return ENOMEM;
6cf099
+    }
6cf099
+    tevent_req_set_callback(req,
6cf099
+                            ifp_users_list_by_domain_and_name_done, list_ctx);
6cf099
+
6cf099
     return EOK;
6cf099
 }
6cf099
 
6cf099
+static void ifp_users_list_by_domain_and_name_done(struct tevent_req *req)
6cf099
+{
6cf099
+    DBusError *error;
6cf099
+    struct ifp_list_ctx *list_ctx;
6cf099
+    struct sbus_request *sbus_req;
6cf099
+    struct ldb_result *result;
6cf099
+    struct sss_domain_info *domain;
6cf099
+    errno_t ret;
6cf099
+    size_t copy_count, i;
6cf099
+
6cf099
+    list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
6cf099
+    sbus_req = list_ctx->sbus_req;
6cf099
+
6cf099
+    ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
6cf099
+    talloc_zfree(req);
6cf099
+    if (ret == ENOENT) {
6cf099
+        error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
6cf099
+                               "User not found by filter");
6cf099
+        goto done;
6cf099
+    } else if (ret != EOK) {
6cf099
+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
6cf099
+                               "users by filter [%d]: %s\n", ret, sss_strerror(ret));
6cf099
+        goto done;
6cf099
+    }
6cf099
+
6cf099
+    copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count);
6cf099
+
6cf099
+    for (i = 0; i < copy_count; i++) {
6cf099
+        list_ctx->paths[i] = ifp_users_build_path_from_msg(list_ctx->paths,
6cf099
+                                                           list_ctx->dom,
6cf099
+                                                           result->msgs[i]);
6cf099
+        if (list_ctx->paths[i] == NULL) {
6cf099
+            error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
6cf099
+                                   "Failed to compose object path");
6cf099
+            goto done;
6cf099
+        }
6cf099
+    }
6cf099
+
6cf099
+    list_ctx->path_count += copy_count;
6cf099
+
6cf099
+done:
6cf099
+    if (ret != EOK) {
6cf099
+        sbus_request_fail_and_finish(sbus_req, error);
6cf099
+        return;
6cf099
+    }
6cf099
+
6cf099
+    iface_ifp_users_ListByDomainAndName_finish(sbus_req,
6cf099
+                                               list_ctx->paths,
6cf099
+                                               list_ctx->path_count);
6cf099
+    return;
6cf099
+}
6cf099
+
6cf099
 static errno_t
6cf099
 ifp_users_user_get(struct sbus_request *sbus_req,
6cf099
                    struct ifp_ctx *ifp_ctx,
6cf099
diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
6cf099
index 631bcd266d7e06154dbf1f37f9f439119b2b8944..cdc411faa330dc2c063e52abe63cd68dbe16a5d9 100644
6cf099
--- a/src/responder/ifp/ifpsrv.c
6cf099
+++ b/src/responder/ifp/ifpsrv.c
6cf099
@@ -34,6 +34,7 @@
6cf099
 #include <dbus/dbus.h>
6cf099
 
6cf099
 #include "util/util.h"
6cf099
+#include "util/strtonum.h"
6cf099
 #include "sbus/sssd_dbus.h"
6cf099
 #include "monitor/monitor_interfaces.h"
6cf099
 #include "confdb/confdb.h"
6cf099
@@ -228,6 +229,7 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
6cf099
     int max_retries;
6cf099
     char *uid_str;
6cf099
     char *attr_list_str;
6cf099
+    char *wildcard_limit_str;
6cf099
 
6cf099
     ifp_cmds = get_ifp_cmds();
6cf099
     ret = sss_process_init(mem_ctx, ev, cdb,
6cf099
@@ -321,6 +323,27 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
6cf099
         goto fail;
6cf099
     }
6cf099
 
6cf099
+    /* A bit convoluted way until we have a confdb_get_uint32 */
6cf099
+    ret = confdb_get_string(ifp_ctx->rctx->cdb,
6cf099
+                            ifp_ctx->rctx,
6cf099
+                            CONFDB_IFP_CONF_ENTRY,
6cf099
+                            CONFDB_IFP_WILDCARD_LIMIT,
6cf099
+                            NULL, /* no limit by default */
6cf099
+                            &wildcard_limit_str);
6cf099
+    if (ret != EOK) {
6cf099
+        DEBUG(SSSDBG_FATAL_FAILURE,
6cf099
+              "Failed to retrieve limit for a wildcard search\n");
6cf099
+        goto fail;
6cf099
+    }
6cf099
+
6cf099
+    if (wildcard_limit_str) {
6cf099
+        ifp_ctx->wildcard_limit = strtouint32(wildcard_limit_str, NULL, 10);
6cf099
+        if (errno != 0) {
6cf099
+            ret = errno;
6cf099
+            goto fail;
6cf099
+        }
6cf099
+    }
6cf099
+
6cf099
     for (iter = ifp_ctx->rctx->be_conns; iter; iter = iter->next) {
6cf099
         sbus_reconnect_init(iter->conn, max_retries,
6cf099
                             ifp_dp_reconnect_init, iter);
6cf099
diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c
6cf099
index 674165ee4901115c9e17458a75fdb3536b6468c2..3b02fd06f5227e4ffc3d40ffb20fed981c5028a7 100644
6cf099
--- a/src/responder/ifp/ifpsrv_util.c
6cf099
+++ b/src/responder/ifp/ifpsrv_util.c
6cf099
@@ -21,6 +21,8 @@
6cf099
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
6cf099
 */
6cf099
 
6cf099
+#include <sys/param.h>
6cf099
+
6cf099
 #include "db/sysdb.h"
6cf099
 #include "responder/ifp/ifp_private.h"
6cf099
 
6cf099
@@ -269,3 +271,53 @@ ifp_is_user_attr_allowed(struct ifp_ctx *ifp_ctx, const char *attr)
6cf099
 {
6cf099
     return ifp_attr_allowed(ifp_ctx->user_whitelist, attr);
6cf099
 }
6cf099
+
6cf099
+static uint32_t ifp_list_limit(struct ifp_ctx *ctx, uint32_t limit)
6cf099
+{
6cf099
+    if (ctx->wildcard_limit) {
6cf099
+        return MIN(ctx->wildcard_limit, limit);
6cf099
+    } else {
6cf099
+        return limit;
6cf099
+    }
6cf099
+}
6cf099
+
6cf099
+struct ifp_list_ctx *ifp_list_ctx_new(struct sbus_request *sbus_req,
6cf099
+                                      struct ifp_ctx *ctx,
6cf099
+                                      const char *filter,
6cf099
+                                      uint32_t limit)
6cf099
+{
6cf099
+    struct ifp_list_ctx *list_ctx;
6cf099
+
6cf099
+    list_ctx = talloc_zero(sbus_req, struct ifp_list_ctx);
6cf099
+    if (list_ctx == NULL) {
6cf099
+        return NULL;
6cf099
+    }
6cf099
+
6cf099
+    list_ctx->sbus_req = sbus_req;
6cf099
+    list_ctx->limit = ifp_list_limit(ctx, limit);
6cf099
+    list_ctx->ctx = ctx;
6cf099
+    list_ctx->dom = ctx->rctx->domains;
6cf099
+    list_ctx->filter = filter;
6cf099
+    list_ctx->paths = talloc_zero_array(list_ctx, const char *, limit);
6cf099
+    if (list_ctx->paths == NULL) {
6cf099
+        talloc_free(list_ctx);
6cf099
+        return NULL;
6cf099
+    }
6cf099
+
6cf099
+    return list_ctx;
6cf099
+}
6cf099
+
6cf099
+size_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx,
6cf099
+                                       size_t entries)
6cf099
+{
6cf099
+    size_t capacity = list_ctx->limit - list_ctx->path_count;
6cf099
+
6cf099
+    if (capacity < entries) {
6cf099
+        DEBUG(SSSDBG_MINOR_FAILURE,
6cf099
+              "IFP list request has limit of %"PRIu32" entries but back end "
6cf099
+              "returned %zu entries\n", list_ctx->limit, entries);
6cf099
+        return capacity;
6cf099
+    } else {
6cf099
+        return entries;
6cf099
+    }
6cf099
+}
6cf099
-- 
6cf099
2.4.3
6cf099