summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2015-06-17 13:39:43 +0200
committerJakub Hrozek <jhrozek@redhat.com>2015-07-15 17:32:49 +0200
commitbdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6 (patch)
tree69f3d6854385099e016e4e96aaf25f5530f6c583
parentb9e74a747b8f1012bba3575f3e4289ef4877d64a (diff)
downloadsssd-bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6.tar.gz
sssd-bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6.tar.xz
sssd-bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6.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>
-rw-r--r--src/confdb/confdb.h1
-rw-r--r--src/man/sssd-ifp.5.xml15
-rw-r--r--src/responder/ifp/ifp_groups.c175
-rw-r--r--src/responder/ifp/ifp_private.h22
-rw-r--r--src/responder/ifp/ifp_users.c184
-rw-r--r--src/responder/ifp/ifpsrv.c23
-rw-r--r--src/responder/ifp/ifpsrv_util.c52
7 files changed, 472 insertions, 0 deletions
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index b2ec2e0b9..36df6aea2 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 867c117ed..da247f89d 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 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;
+ }
+}