From f713ff87552c1a135ba62085de3bf133f81fa599 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 7 May 2012 17:08:20 +0200
Subject: [PATCH 22/29] sudo ldap provider: find highest USN

---
 src/providers/ldap/sdap_async_sudo.c |   34 +++++++++----
 src/providers/ldap/sdap_sudo.c       |   12 ++--
 src/providers/ldap/sdap_sudo.h       |    6 ++-
 src/providers/ldap/sdap_sudo_cache.c |   87 +++++++++++++++++++++++++++++++--
 src/providers/ldap/sdap_sudo_cache.h |    6 ++-
 5 files changed, 119 insertions(+), 26 deletions(-)

diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c
index 2ca3ff0b233cfbaaf2dca6bb2f779ce32e6b8fb0..ca4addb0cf328409c73d5ea6fe88bf5db29a2f44 100644
--- a/src/providers/ldap/sdap_async_sudo.c
+++ b/src/providers/ldap/sdap_async_sudo.c
@@ -47,6 +47,7 @@ struct sdap_sudo_refresh_state {
 
     int dp_error;
     int error;
+    char *highest_usn;
 };
 
 struct sdap_sudo_load_sudoers_state {
@@ -84,12 +85,14 @@ static int sdap_sudo_load_sudoers_recv(struct tevent_req *req,
 
 static void sdap_sudo_load_sudoers_done(struct tevent_req *subreq);
 
-static int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx,
+static int sdap_sudo_store_sudoers(TALLOC_CTX *mem_ctx,
+                                   struct sysdb_ctx *sysdb_ctx,
                                    struct sdap_options *opts,
                                    size_t rules_count,
                                    struct sysdb_attrs **rules,
                                    int cache_timeout,
-                                   time_t now);
+                                   time_t now,
+                                   char **_usn);
 
 struct tevent_req *sdap_sudo_refresh_send(TALLOC_CTX *mem_ctx,
                                           struct be_ctx *be_ctx,
@@ -117,6 +120,7 @@ struct tevent_req *sdap_sudo_refresh_send(TALLOC_CTX *mem_ctx,
     state->sysdb_filter = sysdb_filter;
     state->dp_error = DP_ERR_OK;
     state->error = EOK;
+    state->highest_usn = NULL;
 
     if (state->ldap_filter == NULL) {
         ret = EINVAL;
@@ -140,9 +144,11 @@ immediately:
     return req;
 }
 
-int sdap_sudo_refresh_recv(struct tevent_req *req,
+int sdap_sudo_refresh_recv(TALLOC_CTX *mem_ctx,
+                           struct tevent_req *req,
                            int *dp_error,
-                           int *error)
+                           int *error,
+                           char **usn)
 {
     struct sdap_sudo_refresh_state *state = NULL;
 
@@ -153,6 +159,10 @@ int sdap_sudo_refresh_recv(struct tevent_req *req,
     *dp_error = state->dp_error;
     *error = state->error;
 
+    if (usn != NULL && state->highest_usn != NULL) {
+        *usn = talloc_steal(mem_ctx, state->highest_usn);
+    }
+
     return EOK;
 }
 
@@ -461,8 +471,9 @@ static void sdap_sudo_load_sudoers_done(struct tevent_req *subreq)
 
     /* store rules */
     now = time(NULL);
-    ret = sdap_sudo_store_sudoers(state->sysdb, state->opts, rules_count, rules,
-                                  state->domain->sudo_timeout, now);
+    ret = sdap_sudo_store_sudoers(state, state->sysdb, state->opts, rules_count,
+                                  rules, state->domain->sudo_timeout, now,
+                                  &state->highest_usn);
     if (ret != EOK) {
         goto done;
     }
@@ -495,12 +506,14 @@ done:
     }
 }
 
-static int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx,
+static int sdap_sudo_store_sudoers(TALLOC_CTX *mem_ctx,
+                                   struct sysdb_ctx *sysdb_ctx,
                                    struct sdap_options *opts,
                                    size_t rules_count,
                                    struct sysdb_attrs **rules,
                                    int cache_timeout,
-                                   time_t now)
+                                   time_t now,
+                                   char **_usn)
 {
     errno_t ret;
 
@@ -509,8 +522,9 @@ static int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx,
         return EOK;
     }
 
-    ret = sdap_save_native_sudorule_list(sysdb_ctx, opts->sudorule_map,
-                                         rules, rules_count, cache_timeout, now);
+    ret = sdap_save_native_sudorule_list(mem_ctx, sysdb_ctx, opts->sudorule_map,
+                                         rules, rules_count, cache_timeout, now,
+                                         _usn);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, ("failed to save sudo rules [%d]: %s\n",
               ret, strerror(ret)));
diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c
index fc651bf286fb0e2a826f9cc974ad6b7de0beb3f9..4fa191569695f6c82a316f55e5c3f4ed3fe29dd2 100644
--- a/src/providers/ldap/sdap_sudo.c
+++ b/src/providers/ldap/sdap_sudo.c
@@ -300,7 +300,7 @@ static int sdap_sudo_full_refresh_recv(struct tevent_req *req,
 
     TEVENT_REQ_RETURN_ON_ERROR(req);
 
-    return sdap_sudo_refresh_recv(state->subreq, dp_error, error);
+    return sdap_sudo_refresh_recv(state, state->subreq, dp_error, error, NULL);
 }
 
 static void sdap_sudo_full_refresh_done(struct tevent_req *subreq)
@@ -311,15 +311,15 @@ static void sdap_sudo_full_refresh_done(struct tevent_req *subreq)
     int error;
     int ret;
 
-    ret = sdap_sudo_refresh_recv(subreq, &dp_error, &error);
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_sudo_full_refresh_state);
+
+    ret = sdap_sudo_refresh_recv(state, subreq, &dp_error, &error, NULL);
     if (ret != EOK || dp_error != DP_ERR_OK || error != EOK) {
         tevent_req_error(req, ret);
         return;
     }
 
-    req = tevent_req_callback_data(subreq, struct tevent_req);
-    state = tevent_req_data(req, struct sdap_sudo_full_refresh_state);
-
     /* save the time in the sysdb */
     ret = sysdb_sudo_set_last_full_refresh(state->sysdb, time(NULL));
     if (ret != EOK) {
@@ -406,7 +406,7 @@ static int sdap_sudo_rules_refresh_recv(struct tevent_req *req,
                                         int *dp_error,
                                         int *error)
 {
-    return sdap_sudo_refresh_recv(req, dp_error, error);
+    return sdap_sudo_refresh_recv(req, req, dp_error, error, NULL);
 }
 
 static void sdap_sudo_periodical_full_refresh_done(struct tevent_req *req)
diff --git a/src/providers/ldap/sdap_sudo.h b/src/providers/ldap/sdap_sudo.h
index 26a0139c9b858cef9b2514ec333e6202d54d0139..c407015c1e61a2e0f4916812941c224758dbcb2c 100644
--- a/src/providers/ldap/sdap_sudo.h
+++ b/src/providers/ldap/sdap_sudo.h
@@ -36,9 +36,11 @@ struct tevent_req *sdap_sudo_refresh_send(TALLOC_CTX *mem_ctx,
                                           const char *ldap_filter,
                                           const char *sysdb_filter);
 
-int sdap_sudo_refresh_recv(struct tevent_req *req,
+int sdap_sudo_refresh_recv(TALLOC_CTX *mem_ctx,
+                           struct tevent_req *req,
                            int *dp_error,
-                           int *error);
+                           int *error,
+                           char **usn);
 
 /* timer */
 
diff --git a/src/providers/ldap/sdap_sudo_cache.c b/src/providers/ldap/sdap_sudo_cache.c
index 39b028d66c222fedec82ddecb72a7f8bcbff6e21..f6462fa910879eeea7fdf65b28f864b68c2135c0 100644
--- a/src/providers/ldap/sdap_sudo_cache.c
+++ b/src/providers/ldap/sdap_sudo_cache.c
@@ -18,17 +18,53 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <talloc.h>
+
 #include "db/sysdb.h"
 #include "db/sysdb_sudo.h"
 #include "providers/ldap/sdap_sudo_cache.h"
 
 /* ==========  Functions specific for the native sudo LDAP schema ========== */
+static errno_t sdap_sudo_get_usn(TALLOC_CTX *mem_ctx,
+                                 struct sysdb_attrs *attrs,
+                                 struct sdap_attr_map *map,
+                                 const char *name,
+                                 char **_usn)
+{
+    struct ldb_message_element *el = NULL;
+    const char *usn;
+    errno_t ret;
+
+    ret = sysdb_attrs_get_string(attrs, map[SDAP_AT_SUDO_USN].sys_name, &usn);
+    if (ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("Failed to retrieve USN value: [%s]\n", strerror(ret)));
+
+        return ret;
+    }
+
+    if (ret == ENOENT || el->num_values == 0) {
+        DEBUG(SSSDBG_TRACE_LIBS,
+              ("Original USN value is not available for [%s].\n", name));
+        return ret;
+    } else {
+        *_usn = talloc_strdup(mem_ctx, usn);
+        if (*_usn == NULL) {
+            return ENOMEM;
+        }
+    }
+
+    return EOK;
+}
+
 static errno_t
-sdap_save_native_sudorule(struct sysdb_ctx *sysdb_ctx,
+sdap_save_native_sudorule(TALLOC_CTX *mem_ctx,
+                          struct sysdb_ctx *sysdb_ctx,
                           struct sdap_attr_map *map,
                           struct sysdb_attrs *attrs,
                           int cache_timeout,
-                          time_t now)
+                          time_t now,
+                          char **_usn)
 {
     errno_t ret;
     const char *rule_name;
@@ -49,6 +85,12 @@ sdap_save_native_sudorule(struct sysdb_ctx *sysdb_ctx,
         return ret;
     }
 
+    ret = sdap_sudo_get_usn(mem_ctx, attrs, map, rule_name, _usn);
+    if (ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Could not read USN from %s\n", rule_name));
+        return ret;
+    }
+
     ret = sysdb_save_sudorule(sysdb_ctx, rule_name, attrs);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, ("Could not save sudorule %s\n", rule_name));
@@ -59,17 +101,28 @@ sdap_save_native_sudorule(struct sysdb_ctx *sysdb_ctx,
 }
 
 errno_t
-sdap_save_native_sudorule_list(struct sysdb_ctx *sysdb_ctx,
+sdap_save_native_sudorule_list(TALLOC_CTX *mem_ctx,
+                               struct sysdb_ctx *sysdb_ctx,
                                struct sdap_attr_map *map,
                                struct sysdb_attrs **replies,
                                size_t replies_count,
                                int cache_timeout,
-                               time_t now)
+                               time_t now,
+                               char **_usn)
 {
+    TALLOC_CTX *tmp_ctx = NULL;
+    char *higher_usn = NULL;
+    char *usn_value = NULL;
     errno_t ret, tret;
     bool in_transaction = false;
     size_t i;
 
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL)  {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("talloc_new() failed\n"));
+        return ENOMEM;
+    }
+
     ret = sysdb_transaction_start(sysdb_ctx);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("Could not start transaction\n"));
@@ -78,11 +131,27 @@ sdap_save_native_sudorule_list(struct sysdb_ctx *sysdb_ctx,
     in_transaction = true;
 
     for (i=0; i<replies_count; i++) {
-        ret = sdap_save_native_sudorule(sysdb_ctx, map, replies[i],
-                                        cache_timeout, now);
+        usn_value = NULL;
+        ret = sdap_save_native_sudorule(tmp_ctx, sysdb_ctx, map, replies[i],
+                                        cache_timeout, now, &usn_value);
         if (ret != EOK) {
             goto fail;
         }
+
+        /* find highest usn */
+        if (usn_value) {
+            if (higher_usn) {
+                if ((strlen(usn_value) > strlen(higher_usn)) ||
+                    (strcmp(usn_value, higher_usn) > 0)) {
+                    talloc_zfree(higher_usn);
+                    higher_usn = usn_value;
+                } else {
+                    talloc_zfree(usn_value);
+                }
+            } else {
+                higher_usn = usn_value;
+            }
+        }
     }
 
     ret = sysdb_transaction_commit(sysdb_ctx);
@@ -92,6 +161,10 @@ sdap_save_native_sudorule_list(struct sysdb_ctx *sysdb_ctx,
     }
     in_transaction = false;
 
+    if (higher_usn != NULL) {
+        *_usn = talloc_steal(mem_ctx, higher_usn);
+    }
+
     ret = EOK;
 fail:
     if (in_transaction) {
@@ -101,5 +174,7 @@ fail:
         }
     }
 
+    talloc_free(tmp_ctx);
+
     return ret;
 }
diff --git a/src/providers/ldap/sdap_sudo_cache.h b/src/providers/ldap/sdap_sudo_cache.h
index 146d38f2acbe1eba6198d442322430a521817e8d..6413d2361decf37f723e4d57b4677bbf7d46614e 100644
--- a/src/providers/ldap/sdap_sudo_cache.h
+++ b/src/providers/ldap/sdap_sudo_cache.h
@@ -25,11 +25,13 @@
 
 /* Cache functions specific for the native sudo LDAP schema */
 errno_t
-sdap_save_native_sudorule_list(struct sysdb_ctx *sysdb_ctx,
+sdap_save_native_sudorule_list(TALLOC_CTX *mem_ctx,
+                               struct sysdb_ctx *sysdb_ctx,
                                struct sdap_attr_map *map,
                                struct sysdb_attrs **replies,
                                size_t replies_count,
                                int cache_timeout,
-                               time_t now);
+                               time_t now,
+                               char **_usn);
 
 #endif /* _SDAP_SUDO_CACHE_H_ */
-- 
1.7.6.5

