summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2014-05-02 19:17:38 +0200
committerJakub Hrozek <jhrozek@redhat.com>2014-06-03 13:37:06 +0200
commit64f5e4b48926c9c14994e73c5a950a5ac876ec8e (patch)
treeb17e73ca49261a0be00b41d5e05d8076413e17d8
parentbd8cf980dc2e7035a8ce893df4a8ccaf9bbf11ad (diff)
downloadsssd-64f5e4b48926c9c14994e73c5a950a5ac876ec8e.tar.gz
sssd-64f5e4b48926c9c14994e73c5a950a5ac876ec8e.tar.xz
sssd-64f5e4b48926c9c14994e73c5a950a5ac876ec8e.zip
IFP: Add a GetGroupsList method
This patch adds a new method on the bus with the following synopsis: <method name="GetUserGroups"> <arg name="user" type="s" direction="in" /> <arg name="values" type="as" direction="out"/> </method> Its purpose is to return names of groups the user is a member of as a list of strings. Reviewed-by: Pavel Březina <pbrezina@redhat.com> (cherry picked from commit 3fe339bcba0e211cc666bb3afe34e5c8fce85f4f)
-rw-r--r--Makefile.am1
-rw-r--r--src/responder/ifp/ifp_iface.xml5
-rw-r--r--src/responder/ifp/ifp_iface_generated.c45
-rw-r--r--src/responder/ifp/ifp_iface_generated.h5
-rw-r--r--src/responder/ifp/ifp_private.h3
-rw-r--r--src/responder/ifp/ifpsrv.c1
-rw-r--r--src/responder/ifp/ifpsrv_cmd.c181
7 files changed, 226 insertions, 15 deletions
diff --git a/Makefile.am b/Makefile.am
index ff95518a5..2ec384a34 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1630,6 +1630,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 de6acce2f..4893e2df5 100644
--- a/src/responder/ifp/ifp_iface.xml
+++ b/src/responder/ifp/ifp_iface.xml
@@ -16,5 +16,10 @@
<annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
</method>
+ <method name="GetUserGroups">
+ <arg name="user" type="s" direction="in" />
+ <arg name="values" type="as" direction="out"/>
+ </method>
+
</interface>
</node>
diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c
index ed8d65187..d3cb4990c 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 c52e87f06..9b92b9b07 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 c03cf6ccc..e7fcaa4c3 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 e02b5f08a..b221ced70 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 7a200aab8..fab87b916 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,18 +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->sysdb, dom, name,
- state->attrs, &state->res);
+ switch (state->search_type) {
+ case SSS_DP_USER:
+ ret = sysdb_get_user_attr(state, dom->sysdb, dom, name,
+ state->attrs, &state->res);
+ break;
+ case SSS_DP_INITGROUPS:
+ ret = sysdb_initgroups(state, dom->sysdb, 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) {
@@ -428,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
@@ -449,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)
@@ -458,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");
@@ -466,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,
@@ -494,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,
@@ -518,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");