From a13cf3d295a4a6654dfa7e4193c0a2bc8bb78e92 Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Fri, 6 Nov 2015 13:00:47 +0100 Subject: SUDO: convert periodical refreshes to be_ptask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes old sudo timer and simplyfies code a lot. It also allows to manage offline/online state. - Full and smart refresh are disabled when offline. - Full refresh is run immediately when sssd is back online. - Smart refresh is scheduled normally when sssd is back online. Resolves: https://fedorahosted.org/sssd/ticket/1943 Reviewed-by: Jakub Hrozek Reviewed-by: Lukáš Slebodník --- src/providers/ldap/sdap_async_sudo_timer.c | 178 ----------- src/providers/ldap/sdap_sudo.c | 470 +---------------------------- src/providers/ldap/sdap_sudo.h | 37 +-- src/providers/ldap/sdap_sudo_refresh.c | 157 ++++++++++ 4 files changed, 185 insertions(+), 657 deletions(-) delete mode 100644 src/providers/ldap/sdap_async_sudo_timer.c create mode 100644 src/providers/ldap/sdap_sudo_refresh.c (limited to 'src/providers') diff --git a/src/providers/ldap/sdap_async_sudo_timer.c b/src/providers/ldap/sdap_async_sudo_timer.c deleted file mode 100644 index 035341909..000000000 --- a/src/providers/ldap/sdap_async_sudo_timer.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - Authors: - Pavel Březina - - Copyright (C) 2011 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include -#include -#include - -#include "util/util.h" -#include "providers/ldap/sdap.h" -#include "providers/ldap/sdap_id_op.h" -#include "providers/ldap/sdap_sudo.h" - -struct sdap_sudo_timer_state { - struct tevent_context *ev; - struct sdap_sudo_ctx *sudo_ctx; - time_t timeout; /* relative time how many seconds wait before - canceling fn request */ - sdap_sudo_timer_fn_t fn; /* request executed on 'when' */ - - struct tevent_req *subreq; - struct tevent_timer *timer_timeout; -}; - -static void sdap_sudo_timer(struct tevent_context *ev, - struct tevent_timer *tt, - struct timeval tv, void *pvt); - -static void sdap_sudo_timer_done(struct tevent_req *subreq); - -static void sdap_sudo_timer_timeout(struct tevent_context *ev, - struct tevent_timer *tt, - struct timeval tv, void *pvt); - -struct tevent_req * sdap_sudo_timer_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sdap_sudo_ctx *sudo_ctx, - struct timeval when, - time_t timeout, - sdap_sudo_timer_fn_t fn) -{ - struct tevent_req *req = NULL; - struct tevent_timer *timer = NULL; - struct sdap_sudo_timer_state *state = NULL; - int ret; - - /* create request */ - req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_timer_state); - if (req == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, "tevent_req_create() failed\n"); - return NULL; - } - - state->ev = ev; - state->sudo_ctx = sudo_ctx; - state->timeout = timeout; - state->fn = fn; - - /* set timer */ - timer = tevent_add_timer(ev, req, when, sdap_sudo_timer, req); - if (timer == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, "tevent_add_timer() failed\n"); - ret = ENOMEM; - goto immediately; - } - - return req; - -immediately: - if (ret == EOK) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); - } - tevent_req_post(req, ev); - - return req; -} - -int sdap_sudo_timer_recv(TALLOC_CTX *mem_ctx, - struct tevent_req *req, - struct tevent_req **_subreq) -{ - struct sdap_sudo_timer_state *state = NULL; - - state = tevent_req_data(req, struct sdap_sudo_timer_state); - TEVENT_REQ_RETURN_ON_ERROR(req); - - *_subreq = talloc_steal(mem_ctx, state->subreq); - - return EOK; -} - -static void sdap_sudo_timer(struct tevent_context *ev, - struct tevent_timer *tt, - struct timeval tv, void *pvt) -{ - struct tevent_req *req = NULL; - struct sdap_sudo_timer_state *state = NULL; - - req = talloc_get_type(pvt, struct tevent_req); - state = tevent_req_data(req, struct sdap_sudo_timer_state); - - /* issue request */ - state->subreq = state->fn(state, state->sudo_ctx); - if (state->subreq == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to issue timed request!\n"); - tevent_req_error(req, ENOMEM); - return; - } - - tevent_req_set_callback(state->subreq, sdap_sudo_timer_done, req); - - /* schedule timeout */ - tv = tevent_timeval_current_ofs(state->timeout, 0); - state->timer_timeout = tevent_add_timer(state->ev, state->subreq, tv, - sdap_sudo_timer_timeout, req); - if (state->timer_timeout == NULL) { - /* If we can't guarantee a timeout, we - * need to cancel the request, to avoid - * the possibility of starting another - * concurrently - */ - DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set timeout, " - "canceling request!\n"); - talloc_zfree(state->subreq); - tevent_req_error(req, ENOMEM); - } -} - -static void sdap_sudo_timer_done(struct tevent_req *subreq) -{ - struct tevent_req *req = NULL; - struct sdap_sudo_timer_state *state = NULL; - - req = tevent_req_callback_data(subreq, struct tevent_req); - /* do not free subreq, it is returned in recv */ - - /* cancel timeout */ - state = tevent_req_data(req, struct sdap_sudo_timer_state); - talloc_zfree(state->timer_timeout); - - tevent_req_done(req); -} - -static void sdap_sudo_timer_timeout(struct tevent_context *ev, - struct tevent_timer *tt, - struct timeval tv, void *pvt) -{ - struct tevent_req *req = NULL; - struct sdap_sudo_timer_state *state = NULL; - - req = talloc_get_type(pvt, struct tevent_req); - state = tevent_req_data(req, struct sdap_sudo_timer_state); - - DEBUG(SSSDBG_CRIT_FAILURE, "Request timed out. Is timeout too small?" - " (%lds)!\n", state->timeout); - - talloc_zfree(state->subreq); - - tevent_req_error(req, EAGAIN); -} diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c index ccc775fb0..4885564ec 100644 --- a/src/providers/ldap/sdap_sudo.c +++ b/src/providers/ldap/sdap_sudo.c @@ -30,8 +30,6 @@ #include "providers/ldap/sdap_sudo_cache.h" #include "db/sysdb_sudo.h" -#define SUDO_MAX_FIRST_REFRESH_DELAY 16 - struct sdap_sudo_full_refresh_state { struct sdap_sudo_ctx *sudo_ctx; struct sdap_id_ctx *id_ctx; @@ -41,15 +39,8 @@ struct sdap_sudo_full_refresh_state { int error; }; -static struct tevent_req *sdap_sudo_full_refresh_send(TALLOC_CTX *mem_ctx, - struct sdap_sudo_ctx *sudo_ctx); - static void sdap_sudo_full_refresh_done(struct tevent_req *subreq); -static int sdap_sudo_full_refresh_recv(struct tevent_req *req, - int *dp_error, - int *error); - struct sdap_sudo_rules_refresh_state { struct sdap_id_ctx *id_ctx; size_t num_rules; @@ -76,35 +67,8 @@ struct sdap_sudo_smart_refresh_state { struct sysdb_ctx *sysdb; }; -static struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, - struct sdap_sudo_ctx *sudo_ctx); - static void sdap_sudo_smart_refresh_done(struct tevent_req *subreq); -static int sdap_sudo_smart_refresh_recv(struct tevent_req *req, - int *dp_error, - int *error); - -static void sdap_sudo_periodical_first_refresh_done(struct tevent_req *req); - -static void sdap_sudo_periodical_full_refresh_done(struct tevent_req *req); - -static void sdap_sudo_periodical_smart_refresh_done(struct tevent_req *req); - -static int sdap_sudo_schedule_refresh(TALLOC_CTX *mem_ctx, - struct sdap_sudo_ctx *sudo_ctx, - enum sdap_sudo_refresh_type refresh, - tevent_req_fn callback, - time_t delay, - time_t timeout, - struct tevent_req **_req); - -static int sdap_sudo_schedule_full_refresh(struct sdap_sudo_ctx *sudo_ctx, - time_t delay); - -static int sdap_sudo_schedule_smart_refresh(struct sdap_sudo_ctx *sudo_ctx, - time_t delay); - static void sdap_sudo_shutdown(struct be_req *req) { @@ -117,7 +81,6 @@ struct bet_ops sdap_sudo_ops = { }; static void sdap_sudo_get_hostinfo_done(struct tevent_req *req); -static int sdap_sudo_setup_periodical_refresh(struct sdap_sudo_ctx *sudo_ctx); int sdap_sudo_init(struct be_ctx *be_ctx, struct sdap_id_ctx *id_ctx, @@ -162,7 +125,7 @@ int sdap_sudo_init(struct be_ctx *be_ctx, sudo_ctx->use_host_filter = false; - ret = sdap_sudo_setup_periodical_refresh(sudo_ctx); + ret = sdap_sudo_ptask_setup(sudo_ctx->id_ctx->be, sudo_ctx); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Unable to setup periodical refresh" @@ -200,94 +163,13 @@ static void sdap_sudo_get_hostinfo_done(struct tevent_req *req) sudo_ctx->hostnames = talloc_move(sudo_ctx, &hostnames); sudo_ctx->ip_addr = talloc_move(sudo_ctx, &ip_addr); - ret = sdap_sudo_setup_periodical_refresh(sudo_ctx); + 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 int sdap_sudo_setup_periodical_refresh(struct sdap_sudo_ctx *sudo_ctx) -{ - struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx; - time_t smart_default; - time_t smart_interval; - time_t full_interval; - time_t last_full; - time_t delay; - int ret; - - smart_interval = dp_opt_get_int(id_ctx->opts->basic, - SDAP_SUDO_SMART_REFRESH_INTERVAL); - - full_interval = dp_opt_get_int(id_ctx->opts->basic, - SDAP_SUDO_FULL_REFRESH_INTERVAL); - - if (smart_interval == 0 && full_interval == 0) { - smart_default = id_ctx->opts->basic[SDAP_SUDO_SMART_REFRESH_INTERVAL].def_val.number; - - DEBUG(SSSDBG_MINOR_FAILURE, "At least one periodical update has to be " - "enabled. Setting smart refresh interval to default value (%ld).\n", - smart_default); - - ret = dp_opt_set_int(id_ctx->opts->basic, - SDAP_SUDO_SMART_REFRESH_INTERVAL, - smart_default); - if (ret != EOK) { - return ret; - } - } - - if (full_interval <= smart_interval) { - DEBUG(SSSDBG_MINOR_FAILURE, "Full refresh interval has to be greater" - "than smart refresh interval. Periodical full refresh will be " - "disabled.\n"); - ret = dp_opt_set_int(id_ctx->opts->basic, - SDAP_SUDO_FULL_REFRESH_INTERVAL, - 0); - if (ret != EOK) { - return ret; - } - } - - ret = sysdb_sudo_get_last_full_refresh(id_ctx->be->domain, - &last_full); - if (ret != EOK) { - return ret; - } - - if (last_full == 0) { - /* If this is the first startup, we need to kick off - * an refresh immediately, to close a window where - * clients requesting sudo information won't get an - * immediate reply with no entries - */ - delay = 0; - } else { - /* At least one update has previously run, - * so clients will get cached data. - * We will delay the refresh so we don't slow - * down the startup process if this is happening - * during system boot. - */ - - /* delay at least by 10s */ - delay = 10; - } - - ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, - SDAP_SUDO_REFRESH_FULL, - sdap_sudo_periodical_first_refresh_done, - delay, full_interval, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to schedule full refresh of sudo " - "rules! Periodical updates will not work!\n"); - return ret; - } - - return EOK; -} - static void sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, char *usn) { unsigned int usn_number; @@ -532,8 +414,8 @@ fail: } /* issue full refresh of sudo rules */ -static struct tevent_req *sdap_sudo_full_refresh_send(TALLOC_CTX *mem_ctx, - struct sdap_sudo_ctx *sudo_ctx) +struct tevent_req *sdap_sudo_full_refresh_send(TALLOC_CTX *mem_ctx, + struct sdap_sudo_ctx *sudo_ctx) { struct tevent_req *req = NULL; struct tevent_req *subreq = NULL; @@ -657,9 +539,9 @@ done: tevent_req_done(req); } -static int sdap_sudo_full_refresh_recv(struct tevent_req *req, - int *dp_error, - int *error) +int sdap_sudo_full_refresh_recv(struct tevent_req *req, + int *dp_error, + int *error) { struct sdap_sudo_full_refresh_state *state = NULL; state = tevent_req_data(req, struct sdap_sudo_full_refresh_state); @@ -835,8 +717,8 @@ static int sdap_sudo_rules_refresh_recv(struct tevent_req *req, } /* issue smart refresh of sudo rules */ -static struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, - struct sdap_sudo_ctx *sudo_ctx) +struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + struct sdap_sudo_ctx *sudo_ctx) { struct tevent_req *req = NULL; struct tevent_req *subreq = NULL; @@ -959,9 +841,9 @@ done: tevent_req_done(req); } -static int sdap_sudo_smart_refresh_recv(struct tevent_req *req, - int *dp_error, - int *error) +int sdap_sudo_smart_refresh_recv(struct tevent_req *req, + int *dp_error, + int *error) { struct sdap_sudo_smart_refresh_state *state = NULL; state = tevent_req_data(req, struct sdap_sudo_smart_refresh_state); @@ -971,331 +853,3 @@ static int sdap_sudo_smart_refresh_recv(struct tevent_req *req, return sdap_sudo_refresh_recv(state, state->subreq, dp_error, error, NULL, NULL); } - -static void sdap_sudo_full_refresh_online_cb(void *pvt) -{ - struct sdap_sudo_ctx *sudo_ctx = NULL; - time_t timeout; - int ret; - - sudo_ctx = talloc_get_type(pvt, struct sdap_sudo_ctx); - - /* remove online callback */ - talloc_zfree(sudo_ctx->first_refresh_online_cb); - - /* schedule new first refresh only if this callback wasn't triggered - * by ongoing full refresh */ - if (sudo_ctx->full_refresh_in_progress) { - return; - } - - /* otherwise cancel the concurrent timer for full refresh */ - talloc_zfree(sudo_ctx->first_refresh_timer); - - /* and fire full refresh immediately */ - timeout = dp_opt_get_int(sudo_ctx->id_ctx->opts->basic, - SDAP_SUDO_FULL_REFRESH_INTERVAL); - if (timeout == 0) { - /* runtime configuration change? */ - DEBUG(SSSDBG_TRACE_FUNC, "Periodical full refresh of sudo rules " - "is disabled\n"); - return; - } - - ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, - SDAP_SUDO_REFRESH_FULL, - sdap_sudo_periodical_first_refresh_done, - 0, timeout, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to schedule full refresh of sudo " - "rules! Periodical updates will not work!\n"); - } -} - -static void sdap_sudo_periodical_first_refresh_done(struct tevent_req *req) -{ - struct tevent_req *subreq = NULL; /* req from sdap_sudo_full_refresh_send() */ - struct sdap_sudo_ctx *sudo_ctx = NULL; - time_t delay; - time_t timeout; - int dp_error = DP_ERR_OK; - int error = EOK; - int ret; - - ret = sdap_sudo_timer_recv(req, req, &subreq); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "Sudo timer failed [%d]: %s\n", ret, strerror(ret)); - goto schedule; - } - - ret = sdap_sudo_full_refresh_recv(subreq, &dp_error, &error); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Periodical full refresh of sudo rules " - "failed [%d]: %s)\n", ret, strerror(ret)); - goto schedule; - } - - if (dp_error != DP_ERR_OK || error != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Periodical full refresh of sudo rules " - "failed [dp_error: %d] ([%d]: %s)\n", - dp_error, error, strerror(error)); - goto schedule; - } - -schedule: - sudo_ctx = tevent_req_callback_data(req, struct sdap_sudo_ctx); - if (sudo_ctx->first_refresh_timer == req) { - sudo_ctx->first_refresh_timer = NULL; - } - talloc_zfree(req); - - /* full refresh */ - delay = dp_opt_get_int(sudo_ctx->id_ctx->opts->basic, - SDAP_SUDO_FULL_REFRESH_INTERVAL); - if (delay == 0) { - /* runtime configuration change? */ - DEBUG(SSSDBG_TRACE_FUNC, "Periodical full refresh of sudo rules " - "is disabled\n"); - return; - } - - /* if we are offline, we will try to perform another full refresh */ - if (dp_error == DP_ERR_OFFLINE) { - sudo_ctx->full_refresh_attempts++; - timeout = delay; - delay = sudo_ctx->full_refresh_attempts << 1; - if (delay > SUDO_MAX_FIRST_REFRESH_DELAY) { - delay = SUDO_MAX_FIRST_REFRESH_DELAY; - } - - DEBUG(SSSDBG_TRACE_FUNC, "Data provider is offline. " - "Scheduling another full refresh in %ld minutes.\n", delay); - - ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, - SDAP_SUDO_REFRESH_FULL, - sdap_sudo_periodical_first_refresh_done, - delay * 60, timeout, - &sudo_ctx->first_refresh_timer); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to schedule full refresh of sudo " - "rules! Periodical updates will not work!\n"); - } - - /* also setup online callback to make sure the refresh is fired as soon - * as possible */ - ret = be_add_online_cb(sudo_ctx->id_ctx->be, sudo_ctx->id_ctx->be, - sdap_sudo_full_refresh_online_cb, - sudo_ctx, &sudo_ctx->first_refresh_online_cb); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Could not set up online callback\n"); - } - - return; - } - - ret = sdap_sudo_schedule_full_refresh(sudo_ctx, delay); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Full periodical refresh will not work.\n"); - } - - /* smart refresh */ - delay = dp_opt_get_int(sudo_ctx->id_ctx->opts->basic, - SDAP_SUDO_SMART_REFRESH_INTERVAL); - if (delay == 0) { - /* runtime configuration change? */ - DEBUG(SSSDBG_TRACE_FUNC, "Periodical smart refresh of sudo rules " - "is disabled\n"); - return; - } - - ret = sdap_sudo_schedule_smart_refresh(sudo_ctx, delay); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Smart periodical refresh will not work.\n"); - } -} - -static void sdap_sudo_periodical_full_refresh_done(struct tevent_req *req) -{ - struct tevent_req *subreq = NULL; /* req from sdap_sudo_full_refresh_send() */ - struct sdap_sudo_ctx *sudo_ctx = NULL; - time_t delay; - int dp_error = DP_ERR_FATAL; - int error = EFAULT; - int ret; - - ret = sdap_sudo_timer_recv(req, req, &subreq); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "Sudo timer failed [%d]: %s\n", ret, strerror(ret)); - goto schedule; - } - - ret = sdap_sudo_full_refresh_recv(subreq, &dp_error, &error); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Periodical full refresh of sudo rules " - "failed [%d]: %s)\n", ret, strerror(ret)); - goto schedule; - } - - if (dp_error != DP_ERR_OK || error != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Periodical full refresh of sudo rules " - "failed [dp_error: %d] ([%d]: %s)\n", - dp_error, error, strerror(error)); - goto schedule; - } - -schedule: - sudo_ctx = tevent_req_callback_data(req, struct sdap_sudo_ctx); - talloc_zfree(req); - - delay = dp_opt_get_int(sudo_ctx->id_ctx->opts->basic, - SDAP_SUDO_FULL_REFRESH_INTERVAL); - if (delay == 0) { - /* runtime configuration change? */ - DEBUG(SSSDBG_TRACE_FUNC, "Periodical full refresh of sudo rules " - "is disabled\n"); - return; - } - - ret = sdap_sudo_schedule_full_refresh(sudo_ctx, delay); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Full periodical refresh will not work.\n"); - } -} - -static void sdap_sudo_periodical_smart_refresh_done(struct tevent_req *req) -{ - struct tevent_req *subreq = NULL; /* req from sdap_sudo_smart_refresh_send() */ - struct sdap_sudo_ctx *sudo_ctx = NULL; - time_t delay; - int dp_error; - int error; - int ret; - - ret = sdap_sudo_timer_recv(req, req, &subreq); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "Sudo timer failed [%d]: %s\n", ret, strerror(ret)); - goto schedule; - } - - ret = sdap_sudo_smart_refresh_recv(subreq, &dp_error, &error); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Periodical smart refresh of sudo rules " - "failed [%d]: %s\n", ret, strerror(ret)); - } - - if (dp_error != DP_ERR_OK || error != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Periodical smart refresh of sudo rules " - "failed [dp_error: %d] ([%d]: %s)\n", - dp_error, error, strerror(error)); - goto schedule; - } - -schedule: - sudo_ctx = tevent_req_callback_data(req, struct sdap_sudo_ctx); - talloc_zfree(req); - - delay = dp_opt_get_int(sudo_ctx->id_ctx->opts->basic, - SDAP_SUDO_SMART_REFRESH_INTERVAL); - if (delay == 0) { - /* runtime configuration change? */ - DEBUG(SSSDBG_TRACE_FUNC, "Periodical smart refresh of sudo rules " - "is disabled\n"); - return; - } - - ret = sdap_sudo_schedule_smart_refresh(sudo_ctx, delay); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Smart periodical refresh will not work.\n"); - } -} - -static int sdap_sudo_schedule_refresh(TALLOC_CTX *mem_ctx, - struct sdap_sudo_ctx *sudo_ctx, - enum sdap_sudo_refresh_type refresh, - tevent_req_fn callback, - time_t delay, - time_t timeout, - struct tevent_req **_req) -{ - struct tevent_req *req = NULL; - sdap_sudo_timer_fn_t send_fn = NULL; - const char *name = NULL; - struct timeval when; - - when = tevent_timeval_current_ofs(delay, 0); - - switch (refresh) { - case SDAP_SUDO_REFRESH_FULL: - send_fn = sdap_sudo_full_refresh_send; - name = "Full refresh"; - break; - case SDAP_SUDO_REFRESH_SMART: - send_fn = sdap_sudo_smart_refresh_send; - name = "Smart refresh"; - break; - case SDAP_SUDO_REFRESH_RULES: - DEBUG(SSSDBG_OP_FAILURE, "Rules refresh can't be scheduled!\n"); - return EINVAL; - default: - DEBUG(SSSDBG_CRIT_FAILURE, "Unknown refresh type [%d].\n", refresh); - return EINVAL; - } - - - - req = sdap_sudo_timer_send(mem_ctx, sudo_ctx->id_ctx->be->ev, sudo_ctx, - when, timeout, send_fn); - if (req == NULL) { - return ENOMEM; - } - - tevent_req_set_callback(req, callback, sudo_ctx); - - DEBUG(SSSDBG_TRACE_FUNC, "%s scheduled at: %lld\n", - name, (long long)when.tv_sec); - - if (_req != NULL) { - *_req = req; - } - - return EOK; -} - -static int sdap_sudo_schedule_full_refresh(struct sdap_sudo_ctx *sudo_ctx, - time_t delay) -{ - int ret; - - ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, - SDAP_SUDO_REFRESH_FULL, - sdap_sudo_periodical_full_refresh_done, - delay, delay, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to schedule full refresh of sudo " - "rules!\n"); - return ret; - } - - return EOK; -} - -static int sdap_sudo_schedule_smart_refresh(struct sdap_sudo_ctx *sudo_ctx, - time_t delay) -{ - int ret; - - ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, - SDAP_SUDO_REFRESH_SMART, - sdap_sudo_periodical_smart_refresh_done, - delay, delay, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to schedule smart refresh of sudo " - "rules!\n"); - return ret; - } - - return EOK; -} diff --git a/src/providers/ldap/sdap_sudo.h b/src/providers/ldap/sdap_sudo.h index e2764b90c..51e99f561 100644 --- a/src/providers/ldap/sdap_sudo.h +++ b/src/providers/ldap/sdap_sudo.h @@ -21,6 +21,9 @@ #ifndef _SDAP_SUDO_H_ #define _SDAP_SUDO_H_ +#include "providers/dp_backend.h" +#include "providers/ldap/ldap_common.h" + struct sdap_sudo_ctx { struct sdap_id_ctx *id_ctx; @@ -32,15 +35,6 @@ struct sdap_sudo_ctx { bool full_refresh_done; bool full_refresh_in_progress; - int full_refresh_attempts; - struct be_cb *first_refresh_online_cb; - struct tevent_req *first_refresh_timer; -}; - -enum sdap_sudo_refresh_type { - SDAP_SUDO_REFRESH_FULL, - SDAP_SUDO_REFRESH_SMART, - SDAP_SUDO_REFRESH_RULES }; /* Common functions from ldap_sudo.c */ @@ -65,21 +59,22 @@ int sdap_sudo_refresh_recv(TALLOC_CTX *mem_ctx, char **usn, size_t *num_rules); -/* timer */ +struct tevent_req *sdap_sudo_full_refresh_send(TALLOC_CTX *mem_ctx, + struct sdap_sudo_ctx *sudo_ctx); + +int sdap_sudo_full_refresh_recv(struct tevent_req *req, + int *dp_error, + int *error); -typedef struct tevent_req * (*sdap_sudo_timer_fn_t)(TALLOC_CTX *mem_ctx, - struct sdap_sudo_ctx *sudo_ctx); +struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + struct sdap_sudo_ctx *sudo_ctx); -struct tevent_req * sdap_sudo_timer_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sdap_sudo_ctx *sudo_ctx, - struct timeval when, - time_t timeout, - sdap_sudo_timer_fn_t fn); +int sdap_sudo_smart_refresh_recv(struct tevent_req *req, + int *dp_error, + int *error); -int sdap_sudo_timer_recv(TALLOC_CTX *mem_ctx, - struct tevent_req *req, - struct tevent_req **_subreq); +errno_t +sdap_sudo_ptask_setup(struct be_ctx *be_ctx, struct sdap_sudo_ctx *sudo_ctx); /* host info */ struct tevent_req * sdap_sudo_get_hostinfo_send(TALLOC_CTX *mem_ctx, diff --git a/src/providers/ldap/sdap_sudo_refresh.c b/src/providers/ldap/sdap_sudo_refresh.c new file mode 100644 index 000000000..39821840a --- /dev/null +++ b/src/providers/ldap/sdap_sudo_refresh.c @@ -0,0 +1,157 @@ +/* + Authors: + Pavel Březina + + Copyright (C) 2015 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include + +#include "util/util.h" +#include "providers/dp_ptask.h" +#include "providers/ldap/sdap_sudo.h" +#include "db/sysdb_sudo.h" + +static struct tevent_req * +sdap_sudo_ptask_full_refresh_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + struct be_ptask *be_ptask, + void *pvt) +{ + struct sdap_sudo_ctx *sudo_ctx; + sudo_ctx = talloc_get_type(pvt, struct sdap_sudo_ctx); + + return sdap_sudo_full_refresh_send(mem_ctx, sudo_ctx); +} + +static errno_t +sdap_sudo_ptask_full_refresh_recv(struct tevent_req *req) +{ + int dp_error; + int error; + + return sdap_sudo_full_refresh_recv(req, &dp_error, &error); +} + +static struct tevent_req * +sdap_sudo_ptask_smart_refresh_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + struct be_ptask *be_ptask, + void *pvt) +{ + struct sdap_sudo_ctx *sudo_ctx; + sudo_ctx = talloc_get_type(pvt, struct sdap_sudo_ctx); + + return sdap_sudo_smart_refresh_send(mem_ctx, sudo_ctx); +} + +static errno_t +sdap_sudo_ptask_smart_refresh_recv(struct tevent_req *req) +{ + int dp_error; + int error; + + return sdap_sudo_smart_refresh_recv(req, &dp_error, &error); +} + +errno_t +sdap_sudo_ptask_setup(struct be_ctx *be_ctx, struct sdap_sudo_ctx *sudo_ctx) +{ + struct dp_option *opts = sudo_ctx->id_ctx->opts->basic; + time_t smart; + time_t full; + time_t delay; + time_t last_refresh; + errno_t ret; + + smart = dp_opt_get_int(opts, SDAP_SUDO_SMART_REFRESH_INTERVAL); + full = dp_opt_get_int(opts, SDAP_SUDO_FULL_REFRESH_INTERVAL); + + if (smart == 0 && full == 0) { + /* We don't allow both types to be disabled. At least smart refresh + * needs to be enabled. In this case smart refresh will catch up new + * and modified rules and deleted rules are caught when expired. */ + smart = opts[SDAP_SUDO_SMART_REFRESH_INTERVAL].def_val.number; + + DEBUG(SSSDBG_CONF_SETTINGS, "At least smart refresh needs to be " + "enabled. Setting smart refresh interval to default value " + "(%ld) seconds.\n", smart); + } else if (full <= smart) { + /* In this case it does not make any sense to run smart refresh. */ + smart = 0; + + DEBUG(SSSDBG_CONF_SETTINGS, "Smart refresh interval has to be lower " + "than full refresh interval. Periodical smart refresh will be " + "disabled.\n"); + } + + ret = sysdb_sudo_get_last_full_refresh(be_ctx->domain, &last_refresh); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "Unable to obtain time of last full " + "refresh. Assuming none was performed so far.\n"); + last_refresh = 0; + } + + if (last_refresh == 0) { + /* If this is the first startup, we need to kick off an refresh + * immediately, to close a window where clients requesting sudo + * information won't get an immediate reply with no entries */ + delay = 0; + } else { + /* At least one update has previously run, so clients will get cached + * data. We will delay the refresh so we don't slow down the startup + * process if this is happening during system boot. */ + delay = 10; + } + + /* Full refresh. + * + * Disable when offline and run immediately when SSSD goes back online. + * Since we have periodical online check we don't have to run this task + * when offline. */ + ret = be_ptask_create(be_ctx, be_ctx, full, delay, 0, 0, full, + BE_PTASK_OFFLINE_DISABLE, 0, + sdap_sudo_ptask_full_refresh_send, + sdap_sudo_ptask_full_refresh_recv, + sudo_ctx, "SUDO Full Refresh", NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup full refresh ptask " + "[%d]: %s\n", ret, sss_strerror(ret)); + return ret; + } + + /* Smart refresh. + * + * Disable when offline and reschedule normally when SSSD goes back online. + * Since we have periodical online check we don't have to run this task + * when offline. */ + ret = be_ptask_create(be_ctx, be_ctx, smart, delay + smart, smart, 0, smart, + BE_PTASK_OFFLINE_DISABLE, 0, + sdap_sudo_ptask_smart_refresh_send, + sdap_sudo_ptask_smart_refresh_recv, + sudo_ctx, "SUDO Smart Refresh", NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup smart refresh ptask " + "[%d]: %s\n", ret, sss_strerror(ret)); + return ret; + } + + return EOK; +} -- cgit