summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2012-12-05 17:40:44 +0000
committerJakub Hrozek <jhrozek@redhat.com>2012-12-05 23:10:05 +0100
commitd2282b42c9e2381fa0652479ca00621dc59e1771 (patch)
tree2ea63b2bdae7e7f62c941ed99e54d2e85fa159a2
parent535e5ce8fc6594207aa72da245524c1cfcb1280e (diff)
downloadsssd-d2282b42c9e2381fa0652479ca00621dc59e1771.tar.gz
sssd-d2282b42c9e2381fa0652479ca00621dc59e1771.tar.xz
sssd-d2282b42c9e2381fa0652479ca00621dc59e1771.zip
Hook for mmap cache update on initgroup calls
This set of functions enumerate the user's groups and invalidate them all if the list does not matches what we get from the caller.
-rw-r--r--src/providers/data_provider.h1
-rw-r--r--src/responder/nss/nsssrv.c53
-rw-r--r--src/responder/nss/nsssrv_cmd.c91
-rw-r--r--src/responder/nss/nsssrv_private.h3
4 files changed, 148 insertions, 0 deletions
diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
index d82b4c94a..415e97717 100644
--- a/src/providers/data_provider.h
+++ b/src/providers/data_provider.h
@@ -59,6 +59,7 @@
* the nss responder to tell it to update the mmap
* cache */
#define DP_REV_METHOD_UPDATE_CACHE "updateCache"
+#define DP_REV_METHOD_INITGR_CHECK "initgrCheck"
/**
* @defgroup pamHandler PAM DBUS request
diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
index 94aada5ec..71f9a0bce 100644
--- a/src/responder/nss/nsssrv.c
+++ b/src/responder/nss/nsssrv.c
@@ -294,8 +294,61 @@ static int nss_update_memcache(DBusMessage *message,
return EOK;
}
+static int nss_memcache_initgr_check(DBusMessage *message,
+ struct sbus_connection *conn)
+{
+ struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(conn),
+ struct resp_ctx);
+ struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
+ DBusError dbus_error;
+ dbus_bool_t dbret;
+ DBusMessage *reply;
+ char *user;
+ char *domain;
+ uint32_t *groups;
+ int gnum;
+
+ dbus_error_init(&dbus_error);
+
+ dbret = dbus_message_get_args(message, &dbus_error,
+ DBUS_TYPE_STRING, &user,
+ DBUS_TYPE_STRING, &domain,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ &groups, &gnum,
+ DBUS_TYPE_INVALID);
+
+ if (!dbret) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed, to parse message!\n"));
+ if (dbus_error_is_set(&dbus_error)) {
+ dbus_error_free(&dbus_error);
+ }
+ return EIO;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS,
+ ("Got request for [%s@%s]\n", user, domain));
+
+ nss_update_initgr_memcache(nctx, user, domain, gnum, groups);
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply) return ENOMEM;
+
+ dbret = dbus_message_append_args(reply, DBUS_TYPE_INVALID);
+ if (!dbret) {
+ dbus_message_unref(reply);
+ return EIO;
+ }
+
+ /* send reply back */
+ sbus_conn_send_reply(conn, reply);
+ dbus_message_unref(reply);
+
+ return EOK;
+}
+
static struct sbus_method nss_dp_methods[] = {
{ DP_REV_METHOD_UPDATE_CACHE, nss_update_memcache },
+ { DP_REV_METHOD_INITGR_CHECK, nss_memcache_initgr_check },
{ NULL, NULL }
};
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 29d2ee700..a8985b592 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -3343,6 +3343,97 @@ done:
return EOK;
}
+void nss_update_initgr_memcache(struct nss_ctx *nctx,
+ const char *name, const char *domain,
+ int gnum, uint32_t *groups)
+{
+ struct sss_domain_info *dom;
+ struct ldb_result *res;
+ bool changed = false;
+ uint32_t id;
+ uint32_t gids[gnum];
+ int ret;
+ int i, j;
+
+ if (gnum == 0) {
+ /* there are no groups to invalidate in any case, just return */
+ return;
+ }
+
+ for (dom = nctx->rctx->domains; dom != NULL; dom = dom->next) {
+ if (strcasecmp(dom->name, domain) == 0) {
+ break;
+ }
+ }
+
+ if (dom == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Unknown domain (%s) requested by provider\n", domain));
+ return;
+ }
+
+ ret = sysdb_initgroups(NULL, dom->sysdb, name, &res);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Failed to make request to our cache! [%d][%s]\n",
+ ret, strerror(ret)));
+ return;
+ }
+
+ /* copy, we need the original intact in case we need to invalidate
+ * all the original groups */
+ memcpy(gids, groups, gnum * sizeof(uint32_t));
+
+ if (ret == ENOENT || res->count == 0) {
+ changed = true;
+ } else {
+ /* we skip the first entry, it's the user itself */
+ for (i = 1; i < res->count; i++) {
+ id = ldb_msg_find_attr_as_uint(res->msgs[i], SYSDB_GIDNUM, 0);
+ if (id == 0) {
+ /* probably non-posix group, skip */
+ continue;
+ }
+ for (j = 0; j < gnum; j++) {
+ if (gids[j] == id) {
+ gids[j] = 0;
+ break;
+ }
+ }
+ if (j >= gnum) {
+ /* we couldn't find a match, this means the groups have
+ * changed after the refresh */
+ changed = true;
+ break;
+ }
+ }
+
+ if (!changed) {
+ for (j = 0; j < gnum; j++) {
+ if (gids[j] != 0) {
+ /* we found an un-cleared groups, this means the groups
+ * have changed after the refresh (some got deleted) */
+ changed = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ for (i = 0; i < gnum; i++) {
+ id = groups[i];
+
+ ret = sss_mmap_cache_gr_invalidate_gid(nctx->grp_mc_ctx, id);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Internal failure in memory cache code: %d [%s]\n",
+ ret, strerror(ret)));
+ }
+ }
+ }
+}
+
/* FIXME: what about mpg, should we return the user's GID ? */
/* FIXME: should we filter out GIDs ? */
static int fill_initgr(struct sss_packet *packet, struct ldb_result *res)
diff --git a/src/responder/nss/nsssrv_private.h b/src/responder/nss/nsssrv_private.h
index c58893110..5e614d201 100644
--- a/src/responder/nss/nsssrv_private.h
+++ b/src/responder/nss/nsssrv_private.h
@@ -125,5 +125,8 @@ errno_t check_cache(struct nss_dom_ctx *dctx,
void nss_update_pw_memcache(struct nss_ctx *nctx);
void nss_update_gr_memcache(struct nss_ctx *nctx);
+void nss_update_initgr_memcache(struct nss_ctx *nctx,
+ const char *name, const char *domain,
+ int gnum, uint32_t *groups);
#endif /* NSSSRV_PRIVATE_H_ */