From cb235ec146f1ba81c211f8506736edea436be28a Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Tue, 10 Nov 2015 12:32:16 +0100 Subject: SUDO: obtain host information when going online MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves: https://fedorahosted.org/sssd/ticket/2672 Reviewed-by: Jakub Hrozek Reviewed-by: Lukáš Slebodník --- src/providers/ldap/sdap_async_sudo.c | 75 ++++++++++++++++++++++++++++++---- src/providers/ldap/sdap_sudo.c | 79 +++++++++++++++--------------------- src/providers/ldap/sdap_sudo.h | 2 + 3 files changed, 101 insertions(+), 55 deletions(-) diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c index b8310275b..c2ac6988d 100644 --- a/src/providers/ldap/sdap_async_sudo.c +++ b/src/providers/ldap/sdap_async_sudo.c @@ -497,6 +497,8 @@ struct sdap_sudo_refresh_state { static errno_t sdap_sudo_refresh_retry(struct tevent_req *req); static void sdap_sudo_refresh_connect_done(struct tevent_req *subreq); +static void sdap_sudo_refresh_hostinfo_done(struct tevent_req *subreq); +static errno_t sdap_sudo_refresh_sudoers(struct tevent_req *req); static void sdap_sudo_refresh_done(struct tevent_req *subreq); struct tevent_req *sdap_sudo_refresh_send(TALLOC_CTX *mem_ctx, @@ -588,7 +590,6 @@ static void sdap_sudo_refresh_connect_done(struct tevent_req *subreq) { struct tevent_req *req; struct sdap_sudo_refresh_state *state; - char *filter; int dp_error; int ret; @@ -608,15 +609,74 @@ static void sdap_sudo_refresh_connect_done(struct tevent_req *subreq) DEBUG(SSSDBG_TRACE_FUNC, "SUDO LDAP connection successful\n"); + /* Renew host information if needed. */ + if (state->sudo_ctx->run_hostinfo) { + subreq = sdap_sudo_get_hostinfo_send(state, state->opts, + state->sudo_ctx->id_ctx->be); + if (subreq == NULL) { + state->dp_error = DP_ERR_FATAL; + tevent_req_error(req, ENOMEM); + return; + } + + tevent_req_set_callback(subreq, sdap_sudo_refresh_hostinfo_done, req); + state->sudo_ctx->run_hostinfo = false; + return; + } + + ret = sdap_sudo_refresh_sudoers(req); + if (ret != EAGAIN) { + state->dp_error = DP_ERR_FATAL; + tevent_req_error(req, ret); + } +} + +static void sdap_sudo_refresh_hostinfo_done(struct tevent_req *subreq) +{ + struct sdap_sudo_ctx *sudo_ctx; + struct sdap_sudo_refresh_state *state; + struct tevent_req *req; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_sudo_refresh_state); + + sudo_ctx = state->sudo_ctx; + + ret = sdap_sudo_get_hostinfo_recv(sudo_ctx, subreq, &sudo_ctx->hostnames, + &sudo_ctx->ip_addr); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve host information, " + "host filter will be disabled [%d]: %s\n", + ret, sss_strerror(ret)); + sudo_ctx->use_host_filter = false; + } else { + sudo_ctx->use_host_filter = true; + } + + ret = sdap_sudo_refresh_sudoers(req); + if (ret != EAGAIN) { + state->dp_error = DP_ERR_FATAL; + tevent_req_error(req, ret); + } +} + +static errno_t sdap_sudo_refresh_sudoers(struct tevent_req *req) +{ + struct sdap_sudo_refresh_state *state; + struct tevent_req *subreq; + char *filter; + + state = tevent_req_data(req, struct sdap_sudo_refresh_state); + /* We are connected. Host information may have changed during transition * from offline to online state. At this point we can combine search * and host filter. */ filter = sdap_sudo_get_filter(state, state->opts->sudorule_map, state->sudo_ctx, state->search_filter); if (filter == NULL) { - state->dp_error = DP_ERR_FATAL; - tevent_req_error(req, ENOMEM); - return; + return ENOMEM; } subreq = sdap_sudo_load_sudoers_send(state, state->ev, @@ -624,14 +684,13 @@ static void sdap_sudo_refresh_connect_done(struct tevent_req *subreq) sdap_id_op_handle(state->sdap_op), filter); if (subreq == NULL) { - state->dp_error = DP_ERR_FATAL; - tevent_req_error(req, ENOMEM); - return; + talloc_free(filter); + return ENOMEM; } tevent_req_set_callback(subreq, sdap_sudo_refresh_done, req); - return; + return EAGAIN; } static void sdap_sudo_refresh_done(struct tevent_req *subreq) diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c index ed4ecc674..76cc41050 100644 --- a/src/providers/ldap/sdap_sudo.c +++ b/src/providers/ldap/sdap_sudo.c @@ -41,7 +41,20 @@ struct bet_ops sdap_sudo_ops = { .finalize = sdap_sudo_shutdown }; -static void sdap_sudo_get_hostinfo_done(struct tevent_req *req); +static void sdap_sudo_online_cb(void *pvt) +{ + struct sdap_sudo_ctx *sudo_ctx; + + sudo_ctx = talloc_get_type(pvt, struct sdap_sudo_ctx); + if (sudo_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "BUG: sudo_ctx is NULL\n"); + return; + } + + DEBUG(SSSDBG_TRACE_FUNC, "We are back online. SUDO host information will " + "be renewed on next refresh.\n"); + sudo_ctx->run_hostinfo = true; +} int sdap_sudo_init(struct be_ctx *be_ctx, struct sdap_id_ctx *id_ctx, @@ -49,7 +62,6 @@ int sdap_sudo_init(struct be_ctx *be_ctx, void **pvt_data) { struct sdap_sudo_ctx *sudo_ctx = NULL; - struct tevent_req *req = NULL; int ret; DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing sudo LDAP back end\n"); @@ -79,23 +91,26 @@ int sdap_sudo_init(struct be_ctx *be_ctx, goto done; } - req = sdap_sudo_get_hostinfo_send(sudo_ctx, id_ctx->opts, be_ctx); - if (req == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to retrieve host information - " - "(host filter will be disabled)\n"); - - sudo_ctx->use_host_filter = false; - - ret = sdap_sudo_ptask_setup(sudo_ctx->id_ctx->be, sudo_ctx); + if (sudo_ctx->use_host_filter) { + ret = be_add_online_cb(sudo_ctx, sudo_ctx->id_ctx->be, + sdap_sudo_online_cb, sudo_ctx, NULL); if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "Unable to setup periodical refresh" - "of sudo rules [%d]: %s\n", ret, strerror(ret)); - /* periodical updates will not work, but specific-rule update - * is no affected by this, therefore we don't have to fail here */ + DEBUG(SSSDBG_OP_FAILURE, "Unable to install online callback " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; } - } else { - tevent_req_set_callback(req, sdap_sudo_get_hostinfo_done, sudo_ctx); + + /* Obtain hostinfo with the first refresh. */ + sudo_ctx->run_hostinfo = true; + } + + ret = sdap_sudo_ptask_setup(sudo_ctx->id_ctx->be, sudo_ctx); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Unable to setup periodical refresh of sudo rules [%d]: %s\n", + ret, strerror(ret)); + /* periodical updates will not work, but specific-rule update + * is no affected by this, therefore we don't have to fail here */ } ret = EOK; @@ -108,36 +123,6 @@ done: return ret; } -static void sdap_sudo_get_hostinfo_done(struct tevent_req *req) -{ - struct sdap_sudo_ctx *sudo_ctx = NULL; - char **hostnames = NULL; - char **ip_addr = NULL; - int ret; - - sudo_ctx = tevent_req_callback_data(req, struct sdap_sudo_ctx); - - ret = sdap_sudo_get_hostinfo_recv(sudo_ctx, req, &hostnames, &ip_addr); - talloc_zfree(req); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to retrieve host information - " - "(host filter will be disabled) [%d]: %s\n", ret, strerror(ret)); - sudo_ctx->use_host_filter = false; - } - - talloc_zfree(sudo_ctx->hostnames); - talloc_zfree(sudo_ctx->ip_addr); - - sudo_ctx->hostnames = talloc_move(sudo_ctx, &hostnames); - sudo_ctx->ip_addr = talloc_move(sudo_ctx, &ip_addr); - - ret = sdap_sudo_ptask_setup(sudo_ctx->id_ctx->be, sudo_ctx); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to setup periodical refresh" - "of sudo rules [%d]: %s\n", ret, strerror(ret)); - } -} - static void sdap_sudo_reply(struct tevent_req *req) { struct be_req *be_req = NULL; diff --git a/src/providers/ldap/sdap_sudo.h b/src/providers/ldap/sdap_sudo.h index c3222b211..6b4d249a8 100644 --- a/src/providers/ldap/sdap_sudo.h +++ b/src/providers/ldap/sdap_sudo.h @@ -35,6 +35,8 @@ struct sdap_sudo_ctx { bool full_refresh_done; bool full_refresh_in_progress; + + bool run_hostinfo; }; /* Common functions from ldap_sudo.c */ -- cgit