>From bef7f2d0bb5a9705b36769ebcff6bc0778c98967 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Fri, 2 May 2014 19:17:38 +0200 Subject: [PATCH 2/2] IFP: Add a GetGroupsList method This patch adds a new method on the bus with the following synopsis: Its purpose is to return names of groups the user is a member of as a list of strings. --- Makefile.am | 1 + src/responder/ifp/ifp_iface.xml | 5 + src/responder/ifp/ifp_iface_generated.c | 45 ++++++++ src/responder/ifp/ifp_iface_generated.h | 5 + src/responder/ifp/ifp_private.h | 3 + src/responder/ifp/ifpsrv.c | 1 + src/responder/ifp/ifpsrv_cmd.c | 180 +++++++++++++++++++++++++++++--- 7 files changed, 226 insertions(+), 14 deletions(-) diff --git a/Makefile.am b/Makefile.am index a94baf82f45a3a6c6b99475ab9811f163e891d43..c46bba5da0dbd6f14459f0dd5d9c964ab19b263c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1753,6 +1753,7 @@ ifp_tests_SOURCES = \ $(TEST_MOCK_RESP_OBJ) \ src/tests/cmocka/test_ifp.c \ src/responder/ifp/ifpsrv_cmd.c \ + src/responder/ifp/ifp_iface_generated.c \ src/responder/ifp/ifpsrv_util.c ifp_tests_CFLAGS = \ $(AM_CFLAGS) diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml index de6acce2f55afcda8f4028e3ba18825a28537e52..4893e2df5bd23ff8c3a445e7a665b374586eb90f 100644 --- a/src/responder/ifp/ifp_iface.xml +++ b/src/responder/ifp/ifp_iface.xml @@ -16,5 +16,10 @@ + + + + + diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c index ed8d651872af892f0d5996e335410096696a8ec4..d3cb4990cf13fd51621b7606371cdf3175bc789a 100644 --- a/src/responder/ifp/ifp_iface_generated.c +++ b/src/responder/ifp/ifp_iface_generated.c @@ -5,6 +5,9 @@ #include "sbus/sssd_dbus_meta.h" #include "ifp_iface_generated.h" +/* invokes a handler with a 's' DBus signature */ +static int invoke_s_method(struct sbus_request *dbus_req, void *function_ptr); + /* arguments for org.freedesktop.sssd.infopipe.GetUserAttr */ const struct sbus_arg_meta infopipe_iface_GetUserAttr__in[] = { { "user", "s" }, @@ -18,6 +21,25 @@ const struct sbus_arg_meta infopipe_iface_GetUserAttr__out[] = { { NULL, } }; +/* arguments for org.freedesktop.sssd.infopipe.GetUserGroups */ +const struct sbus_arg_meta infopipe_iface_GetUserGroups__in[] = { + { "user", "s" }, + { NULL, } +}; + +/* arguments for org.freedesktop.sssd.infopipe.GetUserGroups */ +const struct sbus_arg_meta infopipe_iface_GetUserGroups__out[] = { + { "values", "as" }, + { NULL, } +}; + +int infopipe_iface_GetUserGroups_finish(struct sbus_request *req, const char *arg_values[], int len_values) +{ + return sbus_request_return_and_finish(req, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &arg_values, len_values, + DBUS_TYPE_INVALID); +} + /* methods for org.freedesktop.sssd.infopipe */ const struct sbus_method_meta infopipe_iface__methods[] = { { @@ -34,6 +56,13 @@ const struct sbus_method_meta infopipe_iface__methods[] = { offsetof(struct infopipe_iface, GetUserAttr), NULL, /* no invoker */ }, + { + "GetUserGroups", /* name */ + infopipe_iface_GetUserGroups__in, + infopipe_iface_GetUserGroups__out, + offsetof(struct infopipe_iface, GetUserGroups), + invoke_s_method, + }, { NULL, } }; @@ -44,3 +73,19 @@ const struct sbus_interface_meta infopipe_iface_meta = { NULL, /* no signals */ NULL, /* no propetries */ }; + +/* invokes a handler with a 's' DBus signature */ +static int invoke_s_method(struct sbus_request *dbus_req, void *function_ptr) +{ + const char * arg_0; + int (*handler)(struct sbus_request *, void *, const char *) = function_ptr; + + if (!sbus_request_parse_or_finish(dbus_req, + DBUS_TYPE_STRING, &arg_0, + DBUS_TYPE_INVALID)) { + return EOK; /* request handled */ + } + + return (handler)(dbus_req, dbus_req->intf->instance_data, + arg_0); +} diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h index c52e87f06fea797bd73f451b9057b406397219a9..9b92b9b071a85bc073f13114923c4cf4903d9bdf 100644 --- a/src/responder/ifp/ifp_iface_generated.h +++ b/src/responder/ifp/ifp_iface_generated.h @@ -15,6 +15,7 @@ #define INFOPIPE_IFACE "org.freedesktop.sssd.infopipe" #define INFOPIPE_IFACE_PING "Ping" #define INFOPIPE_IFACE_GETUSERATTR "GetUserAttr" +#define INFOPIPE_IFACE_GETUSERGROUPS "GetUserGroups" /* ------------------------------------------------------------------------ * DBus handlers @@ -39,8 +40,12 @@ struct infopipe_iface { struct sbus_vtable vtable; /* derive from sbus_vtable */ sbus_msg_handler_fn Ping; sbus_msg_handler_fn GetUserAttr; + int (*GetUserGroups)(struct sbus_request *req, void *data, const char *arg_user); }; +/* finish function for GetUserGroups */ +int infopipe_iface_GetUserGroups_finish(struct sbus_request *req, const char *arg_values[], int len_values); + /* ------------------------------------------------------------------------ * DBus Interface Metadata * diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h index c03cf6ccc8767de4ffeb469bfea84f06a4da3441..e7fcaa4c32063a2a387e9b51ca2872431c5246f0 100644 --- a/src/responder/ifp/ifp_private.h +++ b/src/responder/ifp/ifp_private.h @@ -52,6 +52,9 @@ int ifp_ping(struct sbus_request *dbus_req, void *data); int ifp_user_get_attr(struct sbus_request *dbus_req, void *data); +int ifp_user_get_groups(struct sbus_request *req, + void *data, const char *arg_user); + /* == Utility functions == */ struct ifp_req { struct sbus_request *dbus_req; diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c index e02b5f08a1c9ef5ecec518020c015df7005d4612..b221ced7047115fcf4439f85cc02793a3d01f274 100644 --- a/src/responder/ifp/ifpsrv.c +++ b/src/responder/ifp/ifpsrv.c @@ -67,6 +67,7 @@ struct infopipe_iface ifp_iface = { { &infopipe_iface_meta, 0 }, .Ping = ifp_ping, .GetUserAttr = ifp_user_get_attr, + .GetUserGroups = ifp_user_get_groups, }; struct sss_cmd_table *get_ifp_cmds(void) diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c index cd9ab44412164ee8d7e763177810feb87287779b..5a7190b094f46ba37a9cab831dff733276adace3 100644 --- a/src/responder/ifp/ifpsrv_cmd.c +++ b/src/responder/ifp/ifpsrv_cmd.c @@ -35,6 +35,7 @@ struct ifp_attr_req { static struct tevent_req * ifp_user_get_attr_send(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx, struct sss_nc_ctx *ncache, int neg_timeout, + enum sss_dp_acct_type search_type, const char *inp, const char **attrs); static errno_t ifp_user_get_attr_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, @@ -84,6 +85,7 @@ int ifp_user_get_attr(struct sbus_request *dbus_req, void *data) req = ifp_user_get_attr_send(ireq, ifp_ctx->rctx, ifp_ctx->ncache, ifp_ctx->neg_timeout, + SSS_DP_USER, attr_req->name, attr_req->attrs); if (req == NULL) { return sbus_request_finish(dbus_req, NULL); @@ -163,15 +165,17 @@ static void ifp_user_get_attr_process(struct tevent_req *req) ret = ifp_user_get_attr_handle_reply(attr_req->ireq, attr_req->name, attr_req->attrs, res); if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Could not handle reply!\n"); - /* Nothing to do, let the client time out */ + sbus_request_fail_and_finish(attr_req->ireq->dbus_req, + sbus_error_new(attr_req->ireq->dbus_req, + DBUS_ERROR_FAILED, + "Failed to build a reply\n")); return; } } static errno_t ifp_user_get_attr_handle_reply(struct ifp_req *ireq, const char *user, - const char **attrs, struct ldb_result *res) + const char **attrs, struct ldb_result *res) { errno_t ret; dbus_bool_t dbret; @@ -228,11 +232,134 @@ ifp_user_get_attr_handle_reply(struct ifp_req *ireq, const char *user, return sbus_request_finish(ireq->dbus_req, reply); } +static void ifp_user_get_groups_process(struct tevent_req *req); +static errno_t ifp_user_get_groups_reply(struct ifp_req *ireq, + const char *user, + struct ldb_result *res); + +int ifp_user_get_groups(struct sbus_request *dbus_req, + void *data, const char *arg_user) +{ + struct ifp_req *ireq; + struct ifp_ctx *ifp_ctx; + struct ifp_attr_req *group_req; + struct tevent_req *req; + errno_t ret; + + ifp_ctx = talloc_get_type(data, struct ifp_ctx); + if (ifp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n"); + return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID); + } + + ret = ifp_req_create(dbus_req, ifp_ctx, &ireq); + if (ret != EOK) { + return ifp_req_create_handle_failure(dbus_req, ret); + } + + group_req = talloc_zero(ireq, struct ifp_attr_req); + if (group_req == NULL) { + return sbus_request_finish(dbus_req, NULL); + } + group_req->ireq = ireq; + group_req->name = arg_user; + + group_req->attrs = talloc_zero_array(group_req, const char *, 2); + if (group_req->attrs == NULL) { + return sbus_request_finish(dbus_req, NULL); + } + + group_req->attrs[0] = talloc_strdup(group_req->attrs, SYSDB_MEMBEROF); + if (group_req->attrs[0] == NULL) { + return sbus_request_finish(dbus_req, NULL); + } + + DEBUG(SSSDBG_FUNC_DATA, + "Looking up groups of user [%s] on behalf of %"PRIi64"\n", + group_req->name, group_req->ireq->dbus_req->client); + + req = ifp_user_get_attr_send(ireq, ifp_ctx->rctx, + ifp_ctx->ncache, ifp_ctx->neg_timeout, + SSS_DP_INITGROUPS, + group_req->name, group_req->attrs); + if (req == NULL) { + return sbus_request_finish(dbus_req, NULL); + } + tevent_req_set_callback(req, ifp_user_get_groups_process, group_req); + return EOK; +} + +static void ifp_user_get_groups_process(struct tevent_req *req) +{ + struct ifp_attr_req *group_req; + errno_t ret; + struct ldb_result *res; + + group_req = tevent_req_callback_data(req, struct ifp_attr_req); + + ret = ifp_user_get_attr_recv(group_req, req, &res); + talloc_zfree(req); + if (ret == ENOENT) { + sbus_request_fail_and_finish(group_req->ireq->dbus_req, + sbus_error_new(group_req->ireq->dbus_req, + DBUS_ERROR_FAILED, + "No such user\n")); + return; + } else if (ret != EOK) { + sbus_request_fail_and_finish(group_req->ireq->dbus_req, + sbus_error_new(group_req->ireq->dbus_req, + DBUS_ERROR_FAILED, + "Failed to read attribute\n")); + return; + } + + ret = ifp_user_get_groups_reply(group_req->ireq, group_req->name, res); + if (ret != EOK) { + sbus_request_fail_and_finish(group_req->ireq->dbus_req, + sbus_error_new(group_req->ireq->dbus_req, + DBUS_ERROR_FAILED, + "Failed to build a reply\n")); + return; + } +} + +static errno_t +ifp_user_get_groups_reply(struct ifp_req *ireq, const char *user, + struct ldb_result *res) +{ + int i, num; + const char *name; + const char **groupnames; + + /* one less, the first one is the user entry */ + num = res->count - 1; + groupnames = talloc_zero_array(ireq, const char *, num); + if (groupnames == NULL) { + return sbus_request_finish(ireq->dbus_req, NULL); + } + + for (i = 0; i < num; i++) { + name = ldb_msg_find_attr_as_string(res->msgs[i + 1], SYSDB_NAME, NULL); + if (name == NULL) { + DEBUG(SSSDBG_MINOR_FAILURE, "Skipping a group with no name\n"); + continue; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Adding group %s\n", name); + groupnames[i] = name; + } + + return infopipe_iface_GetUserGroups_finish(ireq->dbus_req, + groupnames, num); +} + struct ifp_user_get_attr_state { const char *inp; const char **attrs; struct ldb_result *res; + enum sss_dp_acct_type search_type; + char *name; char *domname; @@ -248,6 +375,7 @@ struct ifp_user_get_attr_state { static void ifp_user_get_attr_dom(struct tevent_req *subreq); static errno_t ifp_user_get_attr_search(struct tevent_req *req); int ifp_cache_check(struct ifp_user_get_attr_state *state, + enum sss_dp_acct_type search_type, sss_dp_callback_t callback, unsigned int cache_refresh_percent, void *pvt); @@ -256,6 +384,7 @@ void ifp_user_get_attr_done(struct tevent_req *req); static struct tevent_req * ifp_user_get_attr_send(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx, struct sss_nc_ctx *ncache, int neg_timeout, + enum sss_dp_acct_type search_type, const char *inp, const char **attrs) { errno_t ret; @@ -272,6 +401,7 @@ ifp_user_get_attr_send(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx, state->rctx = rctx; state->ncache = ncache; state->neg_timeout = neg_timeout; + state->search_type = search_type; subreq = sss_parse_inp_send(req, rctx, inp); if (subreq == NULL) { @@ -392,17 +522,32 @@ static errno_t ifp_user_get_attr_search(struct tevent_req *req) DEBUG(SSSDBG_FUNC_DATA, "Requesting info for [%s@%s]\n", name, dom->name); - ret = sysdb_get_user_attr(state, dom, name, state->attrs, &state->res); + switch (state->search_type) { + case SSS_DP_USER: + ret = sysdb_get_user_attr(state, dom, name, + state->attrs, &state->res); + break; + case SSS_DP_INITGROUPS: + ret = sysdb_initgroups(state, dom, name, + &state->res); + break; + default: + DEBUG(SSSDBG_OP_FAILURE, "Unsupported operation\n"); + return EIO; + } + if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to make request to our cache!\n"); return EIO; } - if (state->res->count > 1) { - DEBUG(SSSDBG_CRIT_FAILURE, - "getpwnam call returned more than one result !?!\n"); - return ENOENT; + if (state->search_type == SSS_DP_USER) { + if (state->res->count > 1) { + DEBUG(SSSDBG_CRIT_FAILURE, + "getpwnam call returned more than one result !?!\n"); + return ENOENT; + } } if (state->res->count == 0 && state->check_provider == false) { @@ -427,7 +572,8 @@ static errno_t ifp_user_get_attr_search(struct tevent_req *req) /* if this is a caching provider (or if we haven't checked the cache * yet) then verify that the cache is uptodate */ if (state->check_provider) { - ret = ifp_cache_check(state, ifp_dp_callback, 0, req); + ret = ifp_cache_check(state, state->search_type, + ifp_dp_callback, 0, req); if (ret != EOK) { /* Anything but EOK means we should reenter the mainloop * because we may be refreshing the cache @@ -448,6 +594,7 @@ static errno_t ifp_user_get_attr_search(struct tevent_req *req) } int ifp_cache_check(struct ifp_user_get_attr_state *state, + enum sss_dp_acct_type search_type, sss_dp_callback_t callback, unsigned int cache_refresh_percent, void *pvt) @@ -457,7 +604,7 @@ int ifp_cache_check(struct ifp_user_get_attr_state *state, struct tevent_req *req; struct dp_callback_ctx *cb_ctx = NULL; - if (state->res->count > 1) { + if (search_type == SSS_DP_USER && state->res->count > 1) { DEBUG(SSSDBG_OP_FAILURE, "cache search call returned more than one result! " "DB Corrupted?\n"); @@ -465,8 +612,13 @@ int ifp_cache_check(struct ifp_user_get_attr_state *state, } if (state->res->count > 0) { - cache_expire = ldb_msg_find_attr_as_uint64(state->res->msgs[0], - SYSDB_CACHE_EXPIRE, 0); + if (search_type == SSS_DP_USER) { + cache_expire = ldb_msg_find_attr_as_uint64(state->res->msgs[0], + SYSDB_CACHE_EXPIRE, 0); + } else { + cache_expire = ldb_msg_find_attr_as_uint64(state->res->msgs[0], + SYSDB_INITGR_EXPIRE, 0); + } /* if we have any reply let's check cache validity */ ret = sss_cmd_check_cache(state->res->msgs[0], cache_refresh_percent, @@ -493,7 +645,7 @@ int ifp_cache_check(struct ifp_user_get_attr_state *state, DEBUG(SSSDBG_TRACE_FUNC, "Performing midpoint cache update\n"); req = sss_dp_get_account_send(state, state->rctx, state->dom, true, - SSS_DP_USER, state->inp, 0, + search_type, state->inp, 0, NULL); if (req == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, @@ -517,7 +669,7 @@ int ifp_cache_check(struct ifp_user_get_attr_state *state, state->check_provider = false; req = sss_dp_get_account_send(state, state->rctx, state->dom, true, - SSS_DP_USER, state->inp, 0, NULL); + search_type, state->inp, 0, NULL); if (req == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory sending data provider request\n"); -- 1.9.0