summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2015-11-06 13:00:47 +0100
committerLukas Slebodnik <lslebodn@redhat.com>2015-12-15 16:25:57 +0100
commita13cf3d295a4a6654dfa7e4193c0a2bc8bb78e92 (patch)
treed3cd4769dd68a4adb976ab9744f4f83b5f7b0e1d
parente131fef2d3f40bce5af85613690df8aa15f90fde (diff)
downloadsssd-a13cf3d295a4a6654dfa7e4193c0a2bc8bb78e92.tar.gz
sssd-a13cf3d295a4a6654dfa7e4193c0a2bc8bb78e92.tar.xz
sssd-a13cf3d295a4a6654dfa7e4193c0a2bc8bb78e92.zip
SUDO: convert periodical refreshes to be_ptask
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 <jhrozek@redhat.com> Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-rw-r--r--Makefile.am2
-rw-r--r--src/providers/ldap/sdap_async_sudo_timer.c178
-rw-r--r--src/providers/ldap/sdap_sudo.c470
-rw-r--r--src/providers/ldap/sdap_sudo.h37
-rw-r--r--src/providers/ldap/sdap_sudo_refresh.c157
5 files changed, 186 insertions, 658 deletions
diff --git a/Makefile.am b/Makefile.am
index 9f76dd60b..a9d3f25d3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2856,8 +2856,8 @@ if BUILD_SUDO
libsss_ldap_common_la_SOURCES += \
src/providers/ldap/sdap_sudo_cache.c \
src/providers/ldap/sdap_async_sudo.c \
- src/providers/ldap/sdap_async_sudo_timer.c \
src/providers/ldap/sdap_async_sudo_hostinfo.c \
+ src/providers/ldap/sdap_sudo_refresh.c \
src/providers/ldap/sdap_sudo.c
endif
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 <pbrezina@redhat.com>
-
- 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 <http://www.gnu.org/licenses/>.
-*/
-
-#include <errno.h>
-#include <tevent.h>
-#include <talloc.h>
-
-#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 <pbrezina@redhat.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <errno.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#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;
+}