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. --- src/providers/data_provider.h | 1 + src/responder/nss/nsssrv.c | 53 ++++++++++++++++++++++ src/responder/nss/nsssrv_cmd.c | 87 ++++++++++++++++++++++++++++++++++++ src/responder/nss/nsssrv_private.h | 3 + 4 files changed, 144 insertions(+), 0 deletions(-)
diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index 9c7340021268925860b48b3e62f0d0b4d4731ebb..f131e2c68c9ab322ccc65025ed4068b5a5ca92be 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 8694edaf614f6a218621518416965ffb2e558873..f5cfc85b4861489cd44a1367dc9b26111ff9841c 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 2397fb38d37e0fc4c00b2f2967e3d12afbffde2e..a8cdfc1ec34bb758ff60b32dbc41242896670bc5 100644 --- a/src/responder/nss/nsssrv_cmd.c +++ b/src/responder/nss/nsssrv_cmd.c @@ -3346,6 +3346,93 @@ 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; + + 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) { + /* we skip the first entry, it's the user itself */ + 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 c58893110ec3617e7950d3bfb7ac1607dde69bb5..5e614d201b8e45e9eb4bb8e8ba3c4d868a845dfa 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_ */