From 2cb3519c7a8ef8f65d8364fd1f4ebea4055c9a05 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Wed, 9 May 2012 15:00:39 +0200
Subject: [PATCH 29/29] sudo ldap provider: support periodical smart refresh

When SSSD is started, then full refresh is scheduled.
The smart refresh is scheduled after this full refresh,
if USN values are available.
---
 src/providers/ldap/sdap_sudo.c |  249 ++++++++++++++++++++++++++-------------
 1 files changed, 166 insertions(+), 83 deletions(-)

diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c
index d7c088a05656f84f840e70cc74517340403e6490..b72bcacd3ee3951de161dee8fe3a48acc11bb7dc 100644
--- a/src/providers/ldap/sdap_sudo.c
+++ b/src/providers/ldap/sdap_sudo.c
@@ -70,10 +70,18 @@ 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_full_refresh(struct sdap_id_ctx *id_ctx,
+                                           time_t delay);
+
+static int sdap_sudo_schedule_smart_refresh(struct sdap_id_ctx *id_ctx,
+                                            time_t delay);
+
 static void
 sdap_sudo_shutdown(struct be_req *req)
 {
@@ -85,7 +93,7 @@ struct bet_ops sdap_sudo_ops = {
     .finalize = sdap_sudo_shutdown
 };
 
-int sdap_sudo_setup_periodical_full_refresh(struct sdap_id_ctx *id_ctx);
+int sdap_sudo_setup_periodical_refresh(struct sdap_id_ctx *id_ctx);
 
 int sdap_sudo_init(struct be_ctx *be_ctx,
                    struct sdap_id_ctx *id_ctx,
@@ -107,76 +115,76 @@ int sdap_sudo_init(struct be_ctx *be_ctx,
         return ret;
     }
 
-    ret = sdap_sudo_setup_periodical_full_refresh(id_ctx);
+    ret = sdap_sudo_setup_periodical_refresh(id_ctx);
     if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, ("Unable to setup periodical full refresh"
+        DEBUG(SSSDBG_OP_FAILURE, ("Unable to setup periodical refresh"
                                   "of sudo rules [%d]: %s\n", ret, strerror(ret)));
     }
 
     return EOK;
 }
 
-int sdap_sudo_setup_periodical_full_refresh(struct sdap_id_ctx *id_ctx)
+int sdap_sudo_setup_periodical_refresh(struct sdap_id_ctx *id_ctx)
 {
     struct tevent_req *req;
+    time_t smart_interval;
     time_t full_interval;
     time_t last_full;
-    time_t now;
     struct timeval tv;
     int ret;
 
-    /* setup periodical full refresh */
+    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 (full_interval != 0) {
-        ret = sysdb_sudo_get_last_full_refresh(id_ctx->be->sysdb, &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
-             */
-            tv = tevent_timeval_current();
-        } 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.
-             */
+    if (smart_interval == 0 && full_interval == 0) {
+        DEBUG(SSSDBG_CONF_SETTINGS, ("Periodical updates of sudo rules "
+                                     "are disabled\n"));
 
-            now = time(NULL);
-            if (last_full + full_interval < now) {
-                /* delay at least by 10s */
-                tv = tevent_timeval_current_ofs(10, 0);
-            } else {
-                tv = tevent_timeval_set(last_full + full_interval, 0);
-            }
-        }
+        return EOK;
+    }
 
-        req = sdap_sudo_timer_send(id_ctx, id_ctx->be->ev, id_ctx,
-                                   tv, full_interval,
-                                   sdap_sudo_full_refresh_send);
-        if (req == NULL) {
-            DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo "
-                  "rules! Full periodical refresh will not work.\n"));
-            return ENOMEM;
-        }
+    ret = sysdb_sudo_get_last_full_refresh(id_ctx->be->sysdb, &last_full);
+    if (ret != EOK) {
+        return ret;
+    }
 
-        tevent_req_set_callback(req, sdap_sudo_periodical_full_refresh_done,
-                                id_ctx);
-
-        DEBUG(SSSDBG_TRACE_FUNC, ("Full refresh scheduled at: %lld\n",
-                                      (long long)tv.tv_sec));
+    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
+         */
+        tv = tevent_timeval_current();
     } else {
-        DEBUG(SSSDBG_CONF_SETTINGS, ("Periodical full refresh of sudo rules "
-                                     "is disabled\n"));
+        /* 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 */
+        tv = tevent_timeval_current_ofs(10, 0);
     }
 
+    req = sdap_sudo_timer_send(id_ctx, id_ctx->be->ev, id_ctx,
+                               tv, full_interval,
+                               sdap_sudo_full_refresh_send);
+    if (req == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo "
+              "rules! Periodical updates will not work!\n"));
+        return ENOMEM;
+    }
+
+    tevent_req_set_callback(req, sdap_sudo_periodical_first_refresh_done,
+                            id_ctx);
+
+    DEBUG(SSSDBG_TRACE_FUNC, ("Full refresh scheduled at: %lld\n",
+                              (long long)tv.tv_sec));
+
     return EOK;
 }
 
@@ -558,12 +566,62 @@ static void sdap_sudo_smart_refresh_done(struct tevent_req *subreq)
     tevent_req_done(req);
 }
 
+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_id_ctx *id_ctx = NULL;
+    time_t delay;
+    int dp_error;
+    int error;
+    int ret;
+
+    ret = sdap_sudo_timer_recv(req, req, &subreq);
+    if (ret != EOK) {
+        goto schedule;
+    }
+
+    ret = sdap_sudo_full_refresh_recv(subreq, &dp_error, &error);
+    if (dp_error != DP_ERR_OK || error != EOK) {
+        goto schedule;
+    }
+
+schedule:
+    id_ctx = tevent_req_callback_data(req, struct sdap_id_ctx);
+    talloc_zfree(req);
+
+    /* full refresh */
+    delay = dp_opt_get_int(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(id_ctx, delay);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Full periodical refresh will not work.\n"));
+    }
+
+    /* smart refresh */
+    delay = dp_opt_get_int(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(id_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 tevent_req *newreq = NULL;
     struct sdap_id_ctx *id_ctx = NULL;
-    struct timeval tv;
     time_t delay;
     int dp_error;
     int error;
@@ -591,29 +649,16 @@ schedule:
         return;
     }
 
-    /* schedule new refresh */
-    tv = tevent_timeval_current_ofs(delay, 0);
-    newreq = sdap_sudo_timer_send(id_ctx, id_ctx->be->ev, id_ctx,
-                                  tv, delay, sdap_sudo_full_refresh_send);
-    if (newreq == NULL) {
-        DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo "
-              "rules! Full periodical refresh will not work.\n"));
-        return;
+    ret = sdap_sudo_schedule_full_refresh(id_ctx, delay);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Full periodical refresh will not work.\n"));
     }
-
-    tevent_req_set_callback(newreq, sdap_sudo_periodical_full_refresh_done,
-                            id_ctx);
-
-    DEBUG(SSSDBG_TRACE_FUNC, ("Full refresh scheduled at: %lld\n",
-                              (long long)tv.tv_sec));
 }
 
 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 tevent_req *newreq = NULL;
     struct sdap_id_ctx *id_ctx = NULL;
-    struct timeval tv;
     time_t delay;
     int dp_error;
     int error;
@@ -633,33 +678,71 @@ schedule:
     id_ctx = tevent_req_callback_data(req, struct sdap_id_ctx);
     talloc_zfree(req);
 
+    delay = dp_opt_get_int(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(id_ctx, delay);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Smart periodical refresh will not work.\n"));
+    }
+}
+
+static int sdap_sudo_schedule_full_refresh(struct sdap_id_ctx *id_ctx,
+                                           time_t delay)
+{
+    struct tevent_req *req = NULL;
+    struct timeval tv;
+
+    /* schedule new refresh */
+    tv = tevent_timeval_current_ofs(delay, 0);
+    req = sdap_sudo_timer_send(id_ctx, id_ctx->be->ev, id_ctx,
+                               tv, delay, sdap_sudo_full_refresh_send);
+    if (req == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo "
+              "rules!\n"));
+        return ENOMEM;
+    }
+
+    tevent_req_set_callback(req, sdap_sudo_periodical_full_refresh_done,
+                            id_ctx);
+
+    DEBUG(SSSDBG_TRACE_FUNC, ("Full refresh scheduled at: %lld\n",
+                              (long long)tv.tv_sec));
+
+    return EOK;
+}
+
+static int sdap_sudo_schedule_smart_refresh(struct sdap_id_ctx *id_ctx,
+                                            time_t delay)
+{
+    struct tevent_req *req = NULL;
+    struct timeval tv;
+
     if (id_ctx->srv_opts == NULL || id_ctx->srv_opts->supports_usn == false) {
-        DEBUG(SSSDBG_TRACE_FUNC, ("USN values are not supported by the server. "
-              "Smart refresh of sudo rules will not work!\n"));
-        return;
-    }
-
-    delay = dp_opt_get_int(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;
+        DEBUG(SSSDBG_TRACE_FUNC, ("USN values are not supported by the server.\n"));
+        return ENOENT;
     }
 
     /* schedule new refresh */
     tv = tevent_timeval_current_ofs(delay, 0);
-    newreq = sdap_sudo_timer_send(id_ctx, id_ctx->be->ev, id_ctx,
-                                  tv, delay, sdap_sudo_smart_refresh_send);
-    if (newreq == NULL) {
+    req = sdap_sudo_timer_send(id_ctx, id_ctx->be->ev, id_ctx,
+                               tv, delay, sdap_sudo_smart_refresh_send);
+    if (req == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule smart refresh of sudo "
-              "rules! Smart periodical refresh will not work.\n"));
-        return;
+              "rules!\n"));
+        return ENOMEM;
     }
 
-    tevent_req_set_callback(newreq, sdap_sudo_periodical_smart_refresh_done,
+    tevent_req_set_callback(req, sdap_sudo_periodical_smart_refresh_done,
                             id_ctx);
 
     DEBUG(SSSDBG_TRACE_FUNC, ("Smart refresh scheduled at: %lld\n",
                               (long long)tv.tv_sec));
+
+    return EOK;
 }
-- 
1.7.6.5

