diff options
author | Simo Sorce <simo@redhat.com> | 2012-12-05 17:40:45 +0000 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2012-12-05 23:01:37 +0100 |
commit | 2fdd57d428e0c38e3ce1f9286337f750727f0e2e (patch) | |
tree | 1146da1f53def3c186839aab20855d4eda053316 | |
parent | 408914f68673f2caa1c82a1a21336fcb7ddd52ef (diff) | |
download | sssd-2fdd57d428e0c38e3ce1f9286337f750727f0e2e.tar.gz sssd-2fdd57d428e0c38e3ce1f9286337f750727f0e2e.tar.bz2 sssd-2fdd57d428e0c38e3ce1f9286337f750727f0e2e.zip |
Add backchannel NSS provider query on initgr calls
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.
-rw-r--r-- | src/providers/data_provider_be.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c index f4ad8536..da319ffa 100644 --- a/src/providers/data_provider_be.c +++ b/src/providers/data_provider_be.c @@ -560,6 +560,160 @@ 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 the user is completely missing or has no group memberships + * at all there is no need to contact NSS, it would be a noop */ + if (ret == ENOENT || res->count == 0 || res->count == 1) { + /* 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 +891,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, |