At login time we force a remote initgroups call to make sure the user's group memberships are fully up to date. However we were not updating the mmap cache data so some groups may persist there with invalid data if they changed and were not yet expired in the cache.
This patch set implements a callbacj mechanism so that when a provider receives a initgr call request it records the list of groups (by gid) available before the online refresh then before returning it sends the data to the NSS provider so it can verify if anything changed.
If something changed the NSS provider will invalidate all groups in the mmap cache and will let the normal getpw/getgr calls re-populate the cache later.
Note that any other changes in the cache happen only if the mmap cache is already expired, so there is no need to invalidate the mmap cache in any other situation at the moment.
Addresses: https://fedorahosted.org/sssd/ticket/1671
Simo Sorce (5): mmap cache: public functions to invalidate records Hook to perform a mmap cache update from sssd_nss Hook for mmap cache update on initgroup calls Add backchannel NSS provider query on initgr calls Always append rctx as private data
src/providers/data_provider.h | 7 + src/providers/data_provider_be.c | 163 +++++++++++++++++++++++++++ src/responder/common/responder_common.c | 2 +- src/responder/nss/nsssrv.c | 68 +++++++++++ src/responder/nss/nsssrv_cmd.c | 187 +++++++++++++++++++++++++++++++ src/responder/nss/nsssrv_mmap_cache.c | 125 +++++++++++++++++++++ src/responder/nss/nsssrv_mmap_cache.h | 10 ++ src/responder/nss/nsssrv_private.h | 6 + 8 files changed, 567 insertions(+), 1 deletions(-)
These functions can be called from the nss responder to invalidate records that have ceased to exist or that need to be refreshed the first time an application needs them. --- src/responder/nss/nsssrv_mmap_cache.c | 125 +++++++++++++++++++++++++++++++++ src/responder/nss/nsssrv_mmap_cache.h | 10 +++ 2 files changed, 135 insertions(+), 0 deletions(-)
diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c index 1aeac02276e1ce8c5ea78513cdb6ec2f7062d2b4..c6c5a5558400938f7afa701a642070821542b160 100644 --- a/src/responder/nss/nsssrv_mmap_cache.c +++ b/src/responder/nss/nsssrv_mmap_cache.c @@ -368,6 +368,26 @@ static inline void sss_mmap_chain_in_rec(struct sss_mc_ctx *mcc, }
/*************************************************************************** + * generic invalidation + ***************************************************************************/ + +static errno_t sss_mmap_cache_invalidate(struct sss_mc_ctx *mcc, + struct sized_string *key) +{ + struct sss_mc_rec *rec; + + rec = sss_mc_find_record(mcc, key); + if (rec == NULL) { + /* nothing to invalidate */ + return ENOENT; + } + + sss_mc_invalidate_rec(mcc, rec); + + return EOK; +} + +/*************************************************************************** * passwd map ***************************************************************************/
@@ -437,6 +457,58 @@ errno_t sss_mmap_cache_pw_store(struct sss_mc_ctx *mcc, return EOK; }
+errno_t sss_mmap_cache_pw_invalidate(struct sss_mc_ctx *mcc, + struct sized_string *name) +{ + return sss_mmap_cache_invalidate(mcc, name); +} + +errno_t sss_mmap_cache_pw_invalidate_uid(struct sss_mc_ctx *mcc, uid_t uid) +{ + struct sss_mc_rec *rec; + struct sss_mc_pwd_data *data; + uint32_t hash; + uint32_t slot; + char *uidstr; + errno_t ret; + + uidstr = talloc_asprintf(NULL, "%ld", (long)uid); + if (!uidstr) { + return ENOMEM; + } + + hash = sss_mc_hash(mcc, uidstr, strlen(uidstr) + 1); + + slot = mcc->hash_table[hash]; + if (slot > MC_SIZE_TO_SLOTS(mcc->dt_size)) { + ret = ENOENT; + goto done; + } + + while (slot != MC_INVALID_VAL) { + rec = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec); + data = (struct sss_mc_pwd_data *)(&rec->data); + + if (uid == data->uid) { + break; + } + + slot = rec->next; + } + + if (slot == MC_INVALID_VAL) { + ret = ENOENT; + goto done; + } + + sss_mc_invalidate_rec(mcc, rec); + + ret = EOK; + +done: + talloc_zfree(uidstr); + return ret; +}
/*************************************************************************** * group map @@ -502,6 +574,59 @@ int sss_mmap_cache_gr_store(struct sss_mc_ctx *mcc, return EOK; }
+errno_t sss_mmap_cache_gr_invalidate(struct sss_mc_ctx *mcc, + struct sized_string *name) +{ + return sss_mmap_cache_invalidate(mcc, name); +} + +errno_t sss_mmap_cache_gr_invalidate_gid(struct sss_mc_ctx *mcc, gid_t gid) +{ + struct sss_mc_rec *rec; + struct sss_mc_grp_data *data; + uint32_t hash; + uint32_t slot; + char *gidstr; + errno_t ret; + + gidstr = talloc_asprintf(NULL, "%ld", (long)gid); + if (!gidstr) { + return ENOMEM; + } + + hash = sss_mc_hash(mcc, gidstr, strlen(gidstr) + 1); + + slot = mcc->hash_table[hash]; + if (slot > MC_SIZE_TO_SLOTS(mcc->dt_size)) { + ret = ENOENT; + goto done; + } + + while (slot != MC_INVALID_VAL) { + rec = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec); + data = (struct sss_mc_grp_data *)(&rec->data); + + if (gid == data->gid) { + break; + } + + slot = rec->next; + } + + if (slot == MC_INVALID_VAL) { + ret = ENOENT; + goto done; + } + + sss_mc_invalidate_rec(mcc, rec); + + ret = EOK; + +done: + talloc_zfree(gidstr); + return ret; +} +
/*************************************************************************** * initialization diff --git a/src/responder/nss/nsssrv_mmap_cache.h b/src/responder/nss/nsssrv_mmap_cache.h index 2a0712c88b0ce74cf2a9b1ed57ca34c4b3b50b24..0da637970de91b0dec7496523f1511cee4fdbaab 100644 --- a/src/responder/nss/nsssrv_mmap_cache.h +++ b/src/responder/nss/nsssrv_mmap_cache.h @@ -50,6 +50,16 @@ errno_t sss_mmap_cache_gr_store(struct sss_mc_ctx *mcc, gid_t gid, size_t memnum, char *membuf, size_t memsize);
+errno_t sss_mmap_cache_pw_invalidate(struct sss_mc_ctx *mcc, + struct sized_string *name); + +errno_t sss_mmap_cache_pw_invalidate_uid(struct sss_mc_ctx *mcc, uid_t uid); + +errno_t sss_mmap_cache_gr_invalidate(struct sss_mc_ctx *mcc, + struct sized_string *name); + +errno_t sss_mmap_cache_gr_invalidate_gid(struct sss_mc_ctx *mcc, gid_t gid); + errno_t sss_mmap_cache_reinit(TALLOC_CTX *mem_ctx, size_t n_elem, time_t timeout, struct sss_mc_ctx **mc_ctx);
This set of functions enumerate each user/group from all domains and invalidate any mmap cache record that matches. --- src/providers/data_provider.h | 6 ++ src/responder/nss/nsssrv.c | 15 +++++ src/responder/nss/nsssrv_cmd.c | 100 ++++++++++++++++++++++++++++++++++++ src/responder/nss/nsssrv_private.h | 3 + 4 files changed, 124 insertions(+), 0 deletions(-)
diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index bb944509da9f1dc89216266cf62c57fb4127fd57..9c7340021268925860b48b3e62f0d0b4d4731ebb 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -54,6 +54,12 @@ #define DP_METHOD_AUTOFSHANDLER "autofsHandler" #define DP_METHOD_HOSTHANDLER "hostHandler" #define DP_METHOD_GETDOMAINS "getDomains" + +/* this is a reverse method sent from providers to + * the nss responder to tell it to update the mmap + * cache */ +#define DP_REV_METHOD_UPDATE_CACHE "updateCache" + /** * @defgroup pamHandler PAM DBUS request * @ingroup sss_pam diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c index e01bd1a4d49d80e0c43fa1bbe4521636c87015e6..8694edaf614f6a218621518416965ffb2e558873 100644 --- a/src/responder/nss/nsssrv.c +++ b/src/responder/nss/nsssrv.c @@ -33,6 +33,7 @@ #include "popt.h" #include "util/util.h" #include "responder/nss/nsssrv.h" +#include "responder/nss/nsssrv_private.h" #include "responder/nss/nsssrv_mmap_cache.h" #include "responder/common/negcache.h" #include "db/sysdb.h" @@ -280,7 +281,21 @@ done: return ret; }
+static int nss_update_memcache(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); + + nss_update_pw_memcache(nctx); + nss_update_gr_memcache(nctx); + + return EOK; +} + static struct sbus_method nss_dp_methods[] = { + { DP_REV_METHOD_UPDATE_CACHE, nss_update_memcache }, { NULL, NULL } };
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c index db1efdd21f8b0f277c2465bfecdf51bba6395408..2397fb38d37e0fc4c00b2f2967e3d12afbffde2e 100644 --- a/src/responder/nss/nsssrv_cmd.c +++ b/src/responder/nss/nsssrv_cmd.c @@ -107,6 +107,56 @@ struct setent_ctx { * PASSWD db related functions ***************************************************************************/
+void nss_update_pw_memcache(struct nss_ctx *nctx) +{ + struct sss_domain_info *dom; + struct ldb_result *res; + uint64_t exp; + struct sized_string key; + const char *id; + time_t now; + int ret; + int i; + + now = time(NULL); + + for (dom = nctx->rctx->domains; dom != NULL; dom = dom->next) { + ret = sysdb_enumpwent(nctx, dom->sysdb, &res); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Failed to enumerate users for domain [%s]\n", dom->name)); + continue; + } + + for (i = 0; i < res->count; i++) { + exp = ldb_msg_find_attr_as_uint64(res->msgs[i], + SYSDB_CACHE_EXPIRE, 0); + if (exp >= now) { + continue; + } + + /* names require more manipulation (build up fqname conditionally), + * but uidNumber is unique and always resolvable too, so we use + * that to update the cache, as it points to the same entry */ + id = ldb_msg_find_attr_as_string(res->msgs[i], SYSDB_UIDNUM, NULL); + if (!id) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Failed to find uidNumber in %s.\n", + ldb_dn_get_linearized(res->msgs[i]->dn))); + continue; + } + to_sized_string(&key, id); + + ret = sss_mmap_cache_pw_invalidate(nctx->pwd_mc_ctx, &key); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Internal failure in memory cache code: %d [%s]\n", + ret, strerror(ret))); + } + } + } +} + static gid_t get_gid_override(struct ldb_message *msg, struct sss_domain_info *dom) { @@ -1746,6 +1796,56 @@ done: * GROUP db related functions ***************************************************************************/
+void nss_update_gr_memcache(struct nss_ctx *nctx) +{ + struct sss_domain_info *dom; + struct ldb_result *res; + uint64_t exp; + struct sized_string key; + const char *id; + time_t now; + int ret; + int i; + + now = time(NULL); + + for (dom = nctx->rctx->domains; dom != NULL; dom = dom->next) { + ret = sysdb_enumgrent(nctx, dom->sysdb, &res); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Failed to enumerate users for domain [%s]\n", dom->name)); + continue; + } + + for (i = 0; i < res->count; i++) { + exp = ldb_msg_find_attr_as_uint64(res->msgs[i], + SYSDB_CACHE_EXPIRE, 0); + if (exp >= now) { + continue; + } + + /* names require more manipulation (build up fqname conditionally), + * but uidNumber is unique and always resolvable too, so we use + * that to update the cache, as it points to the same entry */ + id = ldb_msg_find_attr_as_string(res->msgs[i], SYSDB_GIDNUM, NULL); + if (!id) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Failed to find gidNumber in %s.\n", + ldb_dn_get_linearized(res->msgs[i]->dn))); + continue; + } + to_sized_string(&key, id); + + ret = sss_mmap_cache_gr_invalidate(nctx->grp_mc_ctx, &key); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Internal failure in memory cache code: %d [%s]\n", + ret, strerror(ret))); + } + } + } +} + #define GID_ROFFSET 0 #define MNUM_ROFFSET sizeof(uint32_t) #define STRS_ROFFSET 2*sizeof(uint32_t) diff --git a/src/responder/nss/nsssrv_private.h b/src/responder/nss/nsssrv_private.h index f1d47c3bc4a62fb816b7b262083e36c05383673d..c58893110ec3617e7950d3bfb7ac1607dde69bb5 100644 --- a/src/responder/nss/nsssrv_private.h +++ b/src/responder/nss/nsssrv_private.h @@ -123,4 +123,7 @@ errno_t check_cache(struct nss_dom_ctx *dctx, sss_dp_callback_t callback, void *pvt);
+void nss_update_pw_memcache(struct nss_ctx *nctx); +void nss_update_gr_memcache(struct nss_ctx *nctx); + #endif /* NSSSRV_PRIVATE_H_ */
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_ */
This is needed in order to assure the memcache is properly and promptly cleaned up if a user memberships change on login.
The list of the current groups for the user is sourced before it is updated and sent to the NSS provider to verify if it has changed after the update call has been made. --- src/providers/data_provider_be.c | 163 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 163 insertions(+), 0 deletions(-)
diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c index f4ad85365409fa64411ed5945d4ce22ee0221310..753746d63fe8fecccdacaf138ddb69997edc21fc 100644 --- a/src/providers/data_provider_be.c +++ b/src/providers/data_provider_be.c @@ -560,6 +560,158 @@ static void acctinfo_callback(struct be_req *req, talloc_free(req); }
+struct be_initgr_prereq { + char *user; + char *domain; + uint32_t gnum; + uint32_t *groups; + + void *orig_pvt_data; + int orig_dp_err_type; + int orig_errnum; + const char *orig_errstr; +}; + +static void acctinfo_callback_initgr_wrap(struct be_req *be_req) +{ + struct be_initgr_prereq *pr = talloc_get_type(be_req->pvt, + struct be_initgr_prereq); + + be_req->pvt = pr->orig_pvt_data; + acctinfo_callback(be_req, pr->orig_dp_err_type, + pr->orig_errnum, pr->orig_errstr); +} + +static void acctinfo_callback_initgr_sbus(DBusPendingCall *pending, void *ptr) +{ + struct be_req *be_req = talloc_get_type(ptr, struct be_req); + + dbus_pending_call_unref(pending); + + acctinfo_callback_initgr_wrap(be_req); +} + +static void acctinfo_initgroups_callback(struct be_req *be_req, + int dp_err_type, + int errnum, + const char *errstr) +{ + struct be_initgr_prereq *pr = talloc_get_type(be_req->pvt, + struct be_initgr_prereq); + DBusMessage *msg = NULL; + dbus_bool_t dbret; + int ret; + + pr->orig_dp_err_type = dp_err_type; + pr->orig_errnum = errnum; + pr->orig_errstr = errstr; + + if (!be_req->be_ctx->nss_cli || !be_req->be_ctx->nss_cli->conn) { + DEBUG(SSSDBG_MINOR_FAILURE, ("NSS Service not conected\n")); + ret = EACCES; + goto done; + } + + /* Set up null request */ + msg = dbus_message_new_method_call(NULL, + DP_PATH, + DP_INTERFACE, + DP_REV_METHOD_INITGR_CHECK); + if (!msg) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory?!\n")); + ret = ENOMEM; + goto done; + } + + dbret = dbus_message_append_args(msg, + DBUS_TYPE_STRING, &pr->user, + DBUS_TYPE_STRING, &pr->domain, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, + &pr->groups, pr->gnum, + DBUS_TYPE_INVALID); + if (!dbret) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory?!\n")); + ret = ENOMEM; + goto done; + } + + /* ping the NSS service, no reply expected */ + ret = sbus_conn_send(be_req->be_ctx->nss_cli->conn, msg, -1, + acctinfo_callback_initgr_sbus, be_req, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_FUNC, + ("Error contacting NSS responder: %d [%s]\n", + ret, strerror(ret))); + } + +done: + if (msg) { + dbus_message_unref(msg); + } + if (ret != EOK) { + /* return immediately if we cannot contact nss provider */ + acctinfo_callback_initgr_wrap(be_req); + } +} + +static errno_t be_initgroups_prereq(struct be_req *be_req) +{ + struct be_acct_req *ar = talloc_get_type(be_req->req_data, + struct be_acct_req); + struct be_initgr_prereq *pr; + struct ldb_result *res; + errno_t ret; + const char *tmpstr; + int i; + + ret = sysdb_initgroups(be_req, be_req->be_ctx->sysdb, + ar->filter_value, &res); + if (ret && ret != ENOENT) { + return ret; + } + if (ret == ENOENT || res->count == 0) { + /* yet unknown, ignore */ + return EOK; + } + + pr = talloc(be_req, struct be_initgr_prereq); + if (!pr) { + return ENOMEM; + } + pr->groups = talloc_array(pr, gid_t, res->count - 1); + if (!pr->groups) { + return ENOMEM; + } + tmpstr = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL); + if (!tmpstr) { + return EINVAL; + } + pr->user = talloc_strdup(pr, tmpstr); + if (!pr->user) { + return ENOMEM; + } + pr->domain = talloc_strdup(pr, be_req->be_ctx->domain->name); + if (!pr->domain) { + return ENOMEM; + } + for (pr->gnum = 0, i = 1; i < res->count; i++) { + pr->groups[pr->gnum] = ldb_msg_find_attr_as_uint(res->msgs[i], + SYSDB_GIDNUM, 0); + /* if 0 it may be a non-posix group, so we skip it */ + if (pr->groups[pr->gnum] != 0) { + pr->gnum++; + } + } + + talloc_zfree(res); + + pr->orig_pvt_data = be_req->pvt; + be_req->pvt = pr; + be_req->fn = acctinfo_initgroups_callback; + + return EOK; +} + static errno_t split_name_extended(TALLOC_CTX *mem_ctx, const char *filter, @@ -737,6 +889,17 @@ static int be_get_account_info(DBusMessage *message, struct sbus_connection *con goto done; }
+ /* see if we need a pre request call, only done for initgroups for now */ + if ((type & 0xFF) == BE_REQ_INITGROUPS) { + ret = be_initgroups_prereq(be_req); + if (ret) { + err_maj = DP_ERR_FATAL; + err_min = ret; + err_msg = "Prerequest failed"; + goto done; + } + } + /* process request */
ret = be_file_request(becli->bectx->bet_info[BET_ID].pvt_bet_data,
This is used for the new calls back from the data provider. --- src/responder/common/responder_common.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c index 50705a3f227d38f7789d4adc5a69d246f4b1be29..c5d7577b57db2232a9cfbd9ab11ff9387d068732 100644 --- a/src/responder/common/responder_common.c +++ b/src/responder/common/responder_common.c @@ -538,7 +538,7 @@ static int sss_dp_init(struct resp_ctx *rctx, ret = sbus_client_init(rctx, rctx->ev, be_conn->sbus_address, intf, &be_conn->conn, - NULL, NULL); + NULL, rctx); if (ret != EOK) { DEBUG(0, ("Failed to connect to monitor services.\n")); return ret;
On Tue, Dec 04, 2012 at 02:47:08PM -0500, Simo Sorce wrote:
These functions can be called from the nss responder to invalidate records that have ceased to exist or that need to be refreshed the first time an application needs them.
src/responder/nss/nsssrv_mmap_cache.c | 125 +++++++++++++++++++++++++++++++++ src/responder/nss/nsssrv_mmap_cache.h | 10 +++ 2 files changed, 135 insertions(+), 0 deletions(-)
Visual ack. It looks like the new functions are not used anywhere, but they might be handy for Michal later.
On Tue, Dec 04, 2012 at 02:47:09PM -0500, Simo Sorce wrote:
This set of functions enumerate each user/group from all domains and invalidate any mmap cache record that matches.
id = ldb_msg_find_attr_as_string(res->msgs[i], SYSDB_UIDNUM, NULL);
if (!id) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Failed to find uidNumber in %s.\n",
ldb_dn_get_linearized(res->msgs[i]->dn)));
continue;
}
to_sized_string(&key, id);
ret = sss_mmap_cache_pw_invalidate(nctx->pwd_mc_ctx, &key);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Internal failure in memory cache code: %d [%s]\n",
ret, strerror(ret)));
}
}
- }
+}
Is there a reason to not use sss_mmap_cache_pw_invalidate_uid here?
ret = sss_mmap_cache_gr_invalidate(nctx->grp_mc_ctx, &key);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Internal failure in memory cache code: %d [%s]\n",
ret, strerror(ret)));
}
}
- }
+}
Same here with sss_mmap_cache_gr_invalidate_gid
On Tue, Dec 04, 2012 at 02:47:10PM -0500, Simo Sorce wrote:
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.
I'm seeing a segfault with this patch when I start with an empty cache and log in as an IPA user. Here is the backtrace:
(gdb) bt #0 __memcpy_ssse3_back () at ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S:2722 #1 0x000000000041cddb in nss_update_initgr_memcache (nctx=0x13cb170, name=0x13e2a64 "admin", domain=0x13e2a70 "ipaldap", gnum=0, groups=0x0) at src/responder/nss/nsssrv_cmd.c:3383 #2 0x0000000000408583 in nss_memcache_initgr_check (message=0x13d3800, conn=0x13d20b0) at src/responder/nss/nsssrv.c:331 #3 0x000000000046e6af in sbus_message_handler (dbus_conn=0x13d1d30, message=0x13d3800, user_data=0x13d02f0) at src/sbus/sssd_dbus_connection.c:430 #4 0x00000038d261d9c5 in _dbus_object_tree_dispatch_and_unlock (tree=0x13d1a70, message=message@entry=0x13d3800, found_object=found_object@entry=0x7fffd86861a4) at dbus-object-tree.c:862 #5 0x00000038d260fc20 in dbus_connection_dispatch (connection=0x13d1d30) at dbus-connection.c:4672 #6 0x000000000046ce48 in sbus_dispatch (ev=0x13c23b0, te=0x13d6e00, tv=..., data=0x13d20b0) at src/sbus/sssd_dbus_connection.c:104 #7 0x00000038d2207d40 in tevent_common_loop_timer_delay (ev=ev@entry=0x13c23b0) at ../tevent_timed.c:254 #8 0x00000038d22073ec in std_event_loop_once (ev=0x13c23b0, location=<optimized out>) at ../tevent_standard.c:560 #9 0x00000038d2204060 in _tevent_loop_once (ev=ev@entry=0x13c23b0, location=location@entry=0x4a1eff "src/util/server.c:601") at ../tevent.c:507 #10 0x00000038d22041eb in tevent_common_loop_wait (ev=0x13c23b0, location=0x4a1eff "src/util/server.c:601") at ../tevent.c:608 #11 0x00000000004754fb in server_loop (main_ctx=0x13c3530) at src/util/server.c:601 #12 0x000000000040a245 in main (argc=2, argv=0x7fffd86866f8) at src/responder/nss/nsssrv.c:563 (gdb) frame 1 #1 0x000000000041cddb in nss_update_initgr_memcache (nctx=0x13cb170, name=0x13e2a64 "admin", domain=0x13e2a70 "ipaldap", gnum=0, groups=0x0) at src/responder/nss/nsssrv_cmd.c:3383 3383 memcpy(gids, groups, gnum + sizeof(uint32_t)); (gdb) print groups $1 = (uint32_t *) 0x0 (gdb) print gnum $2 = 0
The weird part is that ipa user-show tells me that the user *is* a member of group admins, but here nss doesn't get any groups back.
On Tue, Dec 04, 2012 at 02:47:11PM -0500, Simo Sorce wrote:
This is needed in order to assure the memcache is properly and promptly cleaned up if a user memberships change on login.
The list of the current groups for the user is sourced before it is updated and sent to the NSS provider to verify if it has changed after the update call has been made.
Code looks fine, but I haven't been able to test much due to the segfault described earlier.
On Wed, 2012-12-05 at 18:19 +0100, Jakub Hrozek wrote:
On Tue, Dec 04, 2012 at 02:47:10PM -0500, Simo Sorce wrote:
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.
I'm seeing a segfault with this patch when I start with an empty cache and log in as an IPA user.
Ah, my bad, in the latest iterations I only tested with a fully populated cache, I think I know how to fix this.
Simo.
On Wed, 2012-12-05 at 18:14 +0100, Jakub Hrozek wrote:
On Tue, Dec 04, 2012 at 02:47:09PM -0500, Simo Sorce wrote:
This set of functions enumerate each user/group from all domains and invalidate any mmap cache record that matches.
id = ldb_msg_find_attr_as_string(res->msgs[i], SYSDB_UIDNUM, NULL);
if (!id) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Failed to find uidNumber in %s.\n",
ldb_dn_get_linearized(res->msgs[i]->dn)));
continue;
}
to_sized_string(&key, id);
ret = sss_mmap_cache_pw_invalidate(nctx->pwd_mc_ctx, &key);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Internal failure in memory cache code: %d [%s]\n",
ret, strerror(ret)));
}
}
- }
+}
Is there a reason to not use sss_mmap_cache_pw_invalidate_uid here?
ret = sss_mmap_cache_gr_invalidate(nctx->grp_mc_ctx, &key);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Internal failure in memory cache code: %d [%s]\n",
ret, strerror(ret)));
}
}
- }
+}
Same here with sss_mmap_cache_gr_invalidate_gid
No spcific reason, in this case either works fine, and I built this patch before I created the _Xid() versions I needed later. Because these functions are not really used currently, I just left them as is, they work (were tested in a previous incarnation when they were actually fully wired up).
Simo.
sssd-devel@lists.fedorahosted.org