summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2012-12-05 17:40:45 +0000
committerJakub Hrozek <jhrozek@redhat.com>2012-12-06 11:46:13 +0100
commitfa665b2e0d06e8c2dd59641d9d40c15ad0d8110d (patch)
treee8d418cecf7241d51acb218fb1f0828736a9e13c
parentdefa5876ba388ba104baa287796f2f6ef5182800 (diff)
downloadsssd-fa665b2e0d06e8c2dd59641d9d40c15ad0d8110d.tar.gz
sssd-fa665b2e0d06e8c2dd59641d9d40c15ad0d8110d.tar.xz
sssd-fa665b2e0d06e8c2dd59641d9d40c15ad0d8110d.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.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
index 76912a6fe..4749fc28c 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,