From fe9a0097970d12ff261b7417f9e57db95957ab24 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 17 Jun 2015 13:39:43 +0200 Subject: [PATCH 12/13] IFP: Add wildcard requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Reviewed-by: Pavel Březina --- 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 + + + wildcart_limit (integer) + + + Specifies an upper limit on the number of entries + that are downloaded during a wildcard lookup that + overrides caller-supplied limit. + + + Default: 0 (let the caller set an upper limit) + + + + 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 #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 . */ +#include + #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