diff options
author | Jakub Hrozek <jhrozek@redhat.com> | 2015-06-17 13:39:43 +0200 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2015-07-16 11:12:51 +0200 |
commit | fe9a0097970d12ff261b7417f9e57db95957ab24 (patch) | |
tree | 3d3114d3806fcf35a9281be7a5e9fee428bb053f /src/responder/ifp | |
parent | 4e795d8ff3a1d1f5cd5a7dddaf364909c60d9191 (diff) | |
download | sssd-fe9a0097970d12ff261b7417f9e57db95957ab24.tar.gz sssd-fe9a0097970d12ff261b7417f9e57db95957ab24.tar.xz sssd-fe9a0097970d12ff261b7417f9e57db95957ab24.zip |
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.
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
Diffstat (limited to 'src/responder/ifp')
-rw-r--r-- | src/responder/ifp/ifp_groups.c | 175 | ||||
-rw-r--r-- | src/responder/ifp/ifp_private.h | 22 | ||||
-rw-r--r-- | src/responder/ifp/ifp_users.c | 184 | ||||
-rw-r--r-- | src/responder/ifp/ifpsrv.c | 23 | ||||
-rw-r--r-- | src/responder/ifp/ifpsrv_util.c | 52 |
5 files changed, 456 insertions, 0 deletions
diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c index 1b581b568..306003592 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 304e4dc53..43519de6f 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 2ec74c30b..effefdc04 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 631bcd266..cdc411faa 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 674165ee4..3b02fd06f 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; + } +} |