diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/config/SSSDConfig.py | 2 | ||||
-rw-r--r-- | src/config/etc/sssd.api.d/sssd-ldap.conf | 2 | ||||
-rw-r--r-- | src/providers/ipa/ipa_common.c | 2 | ||||
-rw-r--r-- | src/providers/ipa/ipa_common.h | 2 | ||||
-rw-r--r-- | src/providers/ldap/ldap_common.c | 60 | ||||
-rw-r--r-- | src/providers/ldap/ldap_common.h | 1 | ||||
-rw-r--r-- | src/providers/ldap/ldap_init.c | 5 | ||||
-rw-r--r-- | src/providers/ldap/sdap.h | 2 | ||||
-rw-r--r-- | src/providers/ldap/sdap_sudo_timer.c | 236 | ||||
-rw-r--r-- | src/providers/ldap/sdap_sudo_timer.h | 41 |
10 files changed, 352 insertions, 1 deletions
diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py index 0a73893b..c5c73b14 100644 --- a/src/config/SSSDConfig.py +++ b/src/config/SSSDConfig.py @@ -240,6 +240,8 @@ option_strings = { # [provider/ldap/sudo] 'ldap_sudo_search_base' : _('Base DN for sudo rules lookups'), + 'ldap_sudo_refresh_enabled' : _('Enable periodical update of all sudo rules'), + 'ldap_sudo_refresh_timeout' : _('Length of time between rules updates'), 'ldap_sudorule_object_class' : _('Object class for sudo rules'), 'ldap_sudorule_name' : _('Sudo rule name'), 'ldap_sudorule_command' : _('Sudo rule command attribute'), diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf index b155c2bc..fb48dcd3 100644 --- a/src/config/etc/sssd.api.d/sssd-ldap.conf +++ b/src/config/etc/sssd.api.d/sssd-ldap.conf @@ -109,6 +109,8 @@ ldap_chpass_dns_service_name = str, None, false [provider/ldap/sudo] ldap_sudo_search_base = str, None, false +ldap_sudo_refresh_enabled = bool, None, false +ldap_sudo_refresh_timeout = int, None, false ldap_sudorule_object_class = str, None, false ldap_sudorule_name = str, None, false ldap_sudorule_command = str, None, false diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c index c3ea8c37..12c69dd1 100644 --- a/src/providers/ipa/ipa_common.c +++ b/src/providers/ipa/ipa_common.c @@ -61,6 +61,8 @@ struct dp_option ipa_def_ldap_opts[] = { { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_sudo_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_sudo_refresh_enabled", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ldap_sudo_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER }, { "ldap_schema", DP_OPT_STRING, { "ipa_v1" }, NULL_STRING }, { "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, { "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h index 577e3e19..f29a238a 100644 --- a/src/providers/ipa/ipa_common.h +++ b/src/providers/ipa/ipa_common.h @@ -35,7 +35,7 @@ struct ipa_service { /* the following defines are used to keep track of the options in the ldap * module, so that if they change and ipa is not updated correspondingly * this will trigger a runtime abort error */ -#define IPA_OPTS_BASIC_TEST 56 +#define IPA_OPTS_BASIC_TEST 58 /* the following define is used to keep track of the options in the krb5 * module, so that if they change and ipa is not updated correspondingly diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c index 6ca6f346..18df5ba8 100644 --- a/src/providers/ldap/ldap_common.c +++ b/src/providers/ldap/ldap_common.c @@ -26,6 +26,7 @@ #include "providers/fail_over.h" #include "providers/ldap/sdap_async_private.h" #include "providers/krb5/krb5_common.h" +#include "providers/ldap/sdap_sudo_timer.h" #include "db/sysdb_sudo.h" #include "util/sss_krb5.h" @@ -51,6 +52,8 @@ struct dp_option default_basic_opts[] = { { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "ldap_sudo_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ldap_sudo_refresh_enabled", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ldap_sudo_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER }, { "ldap_schema", DP_OPT_STRING, { "rfc2307" }, NULL_STRING }, { "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, { "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, @@ -564,6 +567,63 @@ int ldap_get_sudo_options(TALLOC_CTX *memctx, return EOK; } +int sdap_sudo_setup_tasks(struct sdap_id_ctx *id_ctx) +{ + struct sdap_sudo_refresh_ctx *refresh_ctx = NULL; + struct timeval tv; + int ret = EOK; + bool refreshed = false; + bool refresh_enabled = dp_opt_get_bool(id_ctx->opts->basic, + SDAP_SUDO_REFRESH_ENABLED); + + /* set up periodical update of sudo rules */ + if (refresh_enabled) { + refresh_ctx = sdap_sudo_refresh_ctx_init(id_ctx, id_ctx->be, id_ctx, + id_ctx->opts, + tevent_timeval_zero()); + if (refresh_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("sdap_sudo_refresh_ctx_init() failed!\n")); + return ENOMEM; + } + + /* 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 + */ + ret = sysdb_sudo_get_refreshed(id_ctx->be->sysdb, &refreshed); + if (ret != EOK) { + return ret; + } + if (refreshed) { + /* At least one update has previously run, + * so clients will get cached data. We will delay + * starting to enumerate by 10s so we don't slow + * down the startup process if this is happening + * during system boot. + */ + tv = tevent_timeval_current_ofs(10, 0); + DEBUG(SSSDBG_FUNC_DATA, ("Delaying first refresh of SUDO rules " + "for 10 seconds\n")); + } else { + /* This is our first startup. Schedule the + * update to start immediately once we + * enter the mainloop. + */ + tv = tevent_timeval_current(); + } + + ret = sdap_sudo_refresh_set_timer(refresh_ctx, tv); + if (ret != EOK) { + talloc_free(refresh_ctx); + return ret; + } + } + + return EOK; +} + errno_t sdap_parse_search_base(TALLOC_CTX *mem_ctx, struct dp_option *opts, int class, struct sdap_search_base ***_search_bases) diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h index e6bb8b6a..0ab0a5e1 100644 --- a/src/providers/ldap/ldap_common.h +++ b/src/providers/ldap/ldap_common.h @@ -88,6 +88,7 @@ void sdap_pam_access_handler(struct be_req *breq); #ifdef BUILD_SUDO /* sudo */ void sdap_sudo_handler(struct be_req *breq); +int sdap_sudo_setup_tasks(struct sdap_id_ctx *ctx); #endif diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c index 8c4d3e68..2721b000 100644 --- a/src/providers/ldap/ldap_init.c +++ b/src/providers/ldap/ldap_init.c @@ -419,6 +419,11 @@ int sssm_ldap_sudo_init(struct be_ctx *be_ctx, return ret; } + ret = sdap_sudo_setup_tasks(id_ctx); + if (ret != EOK) { + return ret; + } + return ret; #else return EOK; diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h index da328d27..5d6bfb82 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -165,6 +165,8 @@ enum sdap_basic_opt { SDAP_GROUP_SEARCH_SCOPE, SDAP_GROUP_SEARCH_FILTER, SDAP_SUDO_SEARCH_BASE, + SDAP_SUDO_REFRESH_ENABLED, + SDAP_SUDO_REFRESH_TIMEOUT, SDAP_SCHEMA, SDAP_OFFLINE_TIMEOUT, SDAP_FORCE_UPPER_CASE_REALM, diff --git a/src/providers/ldap/sdap_sudo_timer.c b/src/providers/ldap/sdap_sudo_timer.c new file mode 100644 index 00000000..cc664abf --- /dev/null +++ b/src/providers/ldap/sdap_sudo_timer.c @@ -0,0 +1,236 @@ +/* + 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 "util/util.h" +#include "providers/ldap/ldap_common.h" +#include "providers/ldap/sdap_sudo_timer.h" +#include "providers/ldap/sdap_sudo.h" +#include "db/sysdb_sudo.h" + +struct sdap_sudo_refresh_ctx { + struct be_ctx *be_ctx; + struct sdap_id_ctx *id_ctx; + struct sdap_options *opts; + + struct timeval last_refresh; +}; + +static void sdap_sudo_refresh_timer(struct tevent_context *ev, + struct tevent_timer *tt, + struct timeval tv, void *pvt); + +static void sdap_sudo_refresh_reschedule(struct tevent_req *req); + +static void sdap_sudo_refresh_timeout(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval tv, void *pvt); + +struct sdap_sudo_refresh_ctx * +sdap_sudo_refresh_ctx_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct sdap_id_ctx *id_ctx, + struct sdap_options *opts, + struct timeval last_refresh) +{ + struct sdap_sudo_refresh_ctx *refresh_ctx = NULL; + + refresh_ctx = talloc_zero(mem_ctx, struct sdap_sudo_refresh_ctx); + if (refresh_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_zero() failed!\n")); + return NULL; + } + + refresh_ctx->be_ctx = be_ctx; + refresh_ctx->id_ctx = id_ctx; + refresh_ctx->opts = opts; + refresh_ctx->last_refresh = last_refresh; + + return refresh_ctx; +} + +int sdap_sudo_refresh_set_timer(struct sdap_sudo_refresh_ctx *ctx, + struct timeval tv) +{ + struct tevent_timer *enum_task; + + DEBUG(SSSDBG_TRACE_FUNC, ("Scheduling next refresh of SUDO rules at " + "%ld.%ld\n", (long)tv.tv_sec, (long)tv.tv_usec)); + + enum_task = tevent_add_timer(ctx->be_ctx->ev, ctx, + tv, sdap_sudo_refresh_timer, ctx); + if (!enum_task) { + DEBUG(SSSDBG_FATAL_FAILURE, + ("FATAL: failed to setup SUDO rules refresh task!\n")); + return EFAULT; + } + + return EOK; +} + +static void sdap_sudo_refresh_timer(struct tevent_context *ev, + struct tevent_timer *tt, + struct timeval tv, void *pvt) +{ + struct sdap_sudo_refresh_ctx *refresh_ctx = NULL; + struct sdap_sudo_ctx *sudo_ctx = NULL; + struct tevent_timer *timeout = NULL; + struct tevent_req *req = NULL; + int delay = 0; + int ret; + + refresh_ctx = talloc_get_type(pvt, struct sdap_sudo_refresh_ctx); + + delay = dp_opt_get_int(refresh_ctx->opts->basic, SDAP_SUDO_REFRESH_TIMEOUT); + + if (be_is_offline(refresh_ctx->be_ctx)) { + DEBUG(SSSDBG_TRACE_FUNC, ("Backend is marked offline, retry later!\n")); + tv = tevent_timeval_current_ofs(delay, 0); + ret = sdap_sudo_refresh_set_timer(refresh_ctx, tv); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Error setting up SUDO refresh timer\n")); + } + return; + } + + /* create sudo context */ + sudo_ctx = talloc_zero(refresh_ctx, struct sdap_sudo_ctx); + if (sudo_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_zero() failed!\n")); + tv = tevent_timeval_current_ofs(delay, 0); + ret = sdap_sudo_refresh_set_timer(refresh_ctx, tv); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Error setting up SUDO refresh timer\n")); + } + + return; + } + + sudo_ctx->be_ctx = refresh_ctx->be_ctx; + sudo_ctx->be_req = NULL; + sudo_ctx->sdap_ctx = refresh_ctx->id_ctx; + sudo_ctx->sdap_op = NULL; + sudo_ctx->sdap_conn_cache = refresh_ctx->id_ctx->conn_cache; + sudo_ctx->username = NULL; /* download all rules */ + sudo_ctx->uid = 0; + sudo_ctx->groups = NULL; + + /* send request */ + req = sdap_sudo_refresh_send(sudo_ctx, sudo_ctx); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to schedule refresh of SUDO rules, " + "retrying later!\n")); + tv = tevent_timeval_current_ofs(delay, 0); + ret = sdap_sudo_refresh_set_timer(refresh_ctx, tv); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Error setting up SUDO refresh timer\n")); + } + + return; + } + refresh_ctx->last_refresh = tevent_timeval_current(); + + tevent_req_set_callback(req, sdap_sudo_refresh_reschedule, refresh_ctx); + + /* schedule timeout */ + tv = tevent_timeval_current_ofs(delay, 0); + timeout = tevent_add_timer(refresh_ctx->be_ctx->ev, req, tv, + sdap_sudo_refresh_timeout, req); + if (timeout == NULL) { + /* If we can't guarantee a timeout, we + * need to cancel the request, to avoid + * the possibility of starting another + * concurrently + */ + talloc_zfree(req); + + DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to schedule refresh of SUDO rules, " + "retrying later!\n")); + tv = tevent_timeval_current_ofs(delay, 0); + ret = sdap_sudo_refresh_set_timer(refresh_ctx, tv); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Error setting up SUDO refresh timer\n")); + } + } + + return; +} + +static void sdap_sudo_refresh_reschedule(struct tevent_req *req) +{ + struct sdap_sudo_refresh_ctx *refresh_ctx = NULL; + struct sdap_sudo_ctx *sudo_ctx = NULL; + struct timeval tv; + int delay; + int dp_error; + int error; + int ret; + + refresh_ctx = tevent_req_callback_data(req, struct sdap_sudo_refresh_ctx); + ret = sdap_sudo_refresh_recv(req, &sudo_ctx, &dp_error, &error); + talloc_zfree(req); + talloc_zfree(sudo_ctx); + if (ret != EOK) { + tv = tevent_timeval_current(); + } else { + tv = refresh_ctx->last_refresh; + + /* Ok, we've completed a refresh. Save this to the + * sysdb so we can postpone starting up the refresh + * process on the next SSSD service restart (to avoid + * slowing down system boot-up + */ + ret = sysdb_sudo_set_refreshed(refresh_ctx->be_ctx->sysdb, true); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Could not mark domain as having refreshed.\n")); + /* This error is non-fatal, so continue */ + } + } + + delay = dp_opt_get_int(refresh_ctx->opts->basic, SDAP_SUDO_REFRESH_TIMEOUT); + tv = tevent_timeval_add(&tv, delay, 0); + ret = sdap_sudo_refresh_set_timer(refresh_ctx, tv); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Error setting up SUDO refresh timer\n")); + } +} + +static void sdap_sudo_refresh_timeout(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval tv, void *pvt) +{ + struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); + struct sdap_sudo_refresh_ctx *refresh_ctx = NULL; + int delay; + + refresh_ctx = tevent_req_callback_data(req, struct sdap_sudo_refresh_ctx); + + delay = dp_opt_get_int(refresh_ctx->opts->basic, SDAP_SUDO_REFRESH_TIMEOUT); + DEBUG(SSSDBG_CRIT_FAILURE, ("Refreshing SUDO rules timed out!" + " Timeout too small? (%ds)!\n", delay)); + + tv = tevent_timeval_current_ofs(delay, 0); + sdap_sudo_refresh_set_timer(refresh_ctx, tv); + + talloc_zfree(req); +} diff --git a/src/providers/ldap/sdap_sudo_timer.h b/src/providers/ldap/sdap_sudo_timer.h new file mode 100644 index 00000000..ad7dcad8 --- /dev/null +++ b/src/providers/ldap/sdap_sudo_timer.h @@ -0,0 +1,41 @@ +/* + 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/>. +*/ + +#ifndef _SDAP_SUDO_TIMER_H_ +#define _SDAP_SUDO_TIMER_H_ + +#include <time.h> + +#include "providers/dp_backend.h" +#include "providers/ldap/ldap_common.h" + +struct sdap_sudo_refresh_ctx; + +int sdap_sudo_refresh_set_timer(struct sdap_sudo_refresh_ctx *ctx, + struct timeval tv); + +struct sdap_sudo_refresh_ctx * +sdap_sudo_refresh_ctx_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct sdap_id_ctx *id_ctx, + struct sdap_options *opts, + struct timeval last_refresh); + +#endif /* _SDAP_SUDO_TIMER_H_ */ |