The attached patch implements a fast in-memory cache for serving sudo
requests.

Most of the code was written by Pavel, so I retained the attribution
even though I made a couple of fixes and wrote the man page section.

https://fedorahosted.org/sssd/ticket/1111
From 815a7cefd15b2928f3a97c7be9eef2ebee688351 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <[email protected]>
Date: Tue, 24 Jan 2012 13:42:59 +0100
Subject: [PATCH] SUDO Integration - in-memory cache in responder

New sudo responder option: cache_timeout

https://fedorahosted.org/sssd/ticket/1111
---
 Makefile.am                                |    1 +
 src/confdb/confdb.h                        |    2 +
 src/man/sssd.conf.5.xml                    |   38 ++++
 src/responder/sudo/sudosrv.c               |   21 ++
 src/responder/sudo/sudosrv_cache.c         |  284 ++++++++++++++++++++++++++++
 src/responder/sudo/sudosrv_cmd.c           |   46 ++++-
 src/responder/sudo/sudosrv_get_sudorules.c |   25 ++-
 src/responder/sudo/sudosrv_private.h       |   33 ++++
 8 files changed, 441 insertions(+), 9 deletions(-)
 create mode 100644 src/responder/sudo/sudosrv_cache.c

diff --git a/Makefile.am b/Makefile.am
index 
710f33c67c28ee06896dd9edbb71aa8cc8672c4b..409dc84d7fc100039804b1272e3a777d607f7b03
 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -469,6 +469,7 @@ sssd_sudo_SOURCES = \
     src/responder/sudo/sudosrv_get_sudorules.c \
     src/responder/sudo/sudosrv_query.c \
     src/responder/sudo/sudosrv_dp.c \
+    src/responder/sudo/sudosrv_cache.c \
     $(SSSD_RESPONDER_OBJ)
 sssd_sudo_LDADD = \
     $(SSSD_LIBS) \
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 
7cfc73d2b8a9dd61c796fcc14d69c778dc2a0227..83da4474402568ae7f5f9eab61fd3d5dcfc0e773
 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -93,6 +93,8 @@
 
 /* SUDO */
 #define CONFDB_SUDO_CONF_ENTRY "config/sudo"
+#define CONFDB_SUDO_CACHE_TIMEOUT "sudo_cache_timeout"
+#define CONFDB_DEFAULT_SUDO_CACHE_TIMEOUT 180
 
 /* Data Provider */
 #define CONFDB_DP_CONF_ENTRY "config/dp"
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 
fee40a6a14ae6a9ea7282a1f80b1e83c13370d02..b12534b3c12020bc96f4175237ee7e9e486828ae
 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -594,6 +594,44 @@
                 </varlistentry>
             </variablelist>
         </refsect2>
+
+        <refsect2 id='SUDO' condition="with_sudo">
+            <title>SUDO configuration options</title>
+            <para>
+                These options can be used to configure the sudo service.
+            </para>
+            <para>
+                <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; 
href="include/experimental.xml" />
+            </para>
+            <variablelist>
+                <varlistentry>
+                    <term>sudo_cache_timeout (integer)</term>
+                    <listitem>
+                        <para>
+                            For any sudo request that comes while SSSD is
+                            online, the SSSD will attempt to update the cached
+                            rules in order to ensure that sudo has the latest
+                            ruleset.
+                        </para>
+                        <para>
+                            The user may, however, run a couple of sudo 
commands
+                            successively, which would trigger multiple LDAP 
requests.
+                            In order to speed up this use-case, the sudo 
service
+                            maintains an in-memory cache that would be used for
+                            performing fast replies.
+                        </para>
+                        <para>
+                            This option controls how long (in seconds) can the 
sudo
+                            service cache rules for a user.
+                        </para>
+                        <para>
+                            Default: 180
+                        </para>
+                    </listitem>
+                </varlistentry>
+            </variablelist>
+        </refsect2>
+
     </refsect1>
 
     <refsect1 id='domain-sections'>
diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
index 
841be43ef757facab894db9ac0b1dc71838bf993..6b7eae07b51a064eeccb2190f45fa9c063a17adf
 100644
--- a/src/responder/sudo/sudosrv.c
+++ b/src/responder/sudo/sudosrv.c
@@ -129,6 +129,27 @@ int sudo_process_init(TALLOC_CTX *mem_ctx,
                             sudo_dp_reconnect_init, iter);
     }
 
+    /* Get responder options */
+
+    /* Get cache_timeout option */
+    ret = confdb_get_int(sudo_ctx->rctx->cdb, sudo_ctx,
+                         CONFDB_SUDO_CONF_ENTRY, CONFDB_SUDO_CACHE_TIMEOUT,
+                         CONFDB_DEFAULT_SUDO_CACHE_TIMEOUT,
+                         &sudo_ctx->cache_timeout);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("Error reading from confdb (%d) [%s]\n",
+              ret, strerror(ret)));
+        return ret;
+    }
+
+    /* Initialize in-memory cache */
+    ret = sudosrv_cache_init(sudo_ctx, 10, &sudo_ctx->cache);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+              ("Could not create hash table: [%s]", strerror(ret)));
+        return ret;
+    }
+
     DEBUG(SSSDBG_TRACE_FUNC, ("SUDO Initialization complete\n"));
 
     return EOK;
diff --git a/src/responder/sudo/sudosrv_cache.c 
b/src/responder/sudo/sudosrv_cache.c
new file mode 100644
index 
0000000000000000000000000000000000000000..5b91e3b358d9eae97d4fc3151442a17c8d9a54ec
--- /dev/null
+++ b/src/responder/sudo/sudosrv_cache.c
@@ -0,0 +1,284 @@
+/*
+    Authors:
+        Pavel Březina <[email protected]>
+
+    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 <talloc.h>
+#include <dhash.h>
+#include <time.h>
+
+#include "util/util.h"
+#include "confdb/confdb.h"
+#include "db/sysdb.h"
+#include "responder/sudo/sudosrv_private.h"
+
+static void sudosrv_cache_remove(struct tevent_context *ev,
+                                 struct tevent_timer *te,
+                                 struct timeval tv,
+                                 void *pvt);
+
+struct sudo_cache_entry {
+    hash_table_t *table;
+    hash_key_t *key;
+    size_t num_rules;
+    struct sysdb_attrs **rules;
+
+    struct sudo_ctx *sudo_ctx;
+};
+
+errno_t sudosrv_cache_init(TALLOC_CTX *mem_ctx,
+                           unsigned long count,
+                           hash_table_t **table)
+{
+    return sss_hash_create(mem_ctx, count, table);
+}
+
+static errno_t
+sudosrv_cache_reinit(struct sudo_ctx *sudo_ctx)
+{
+    errno_t ret;
+
+    talloc_free(sudo_ctx->cache);
+
+    ret = sudosrv_cache_init(sudo_ctx, 10, &sudo_ctx->cache);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Could not re-initialize hash table: [%s]", strerror(ret)));
+    }
+    return ret;
+}
+
+static hash_key_t *sudosrv_cache_create_key(TALLOC_CTX *mem_ctx,
+                                            struct sss_domain_info *domain,
+                                            const char *username)
+{
+    hash_key_t *key = talloc_zero(NULL, hash_key_t);
+    if (key == NULL) {
+        return NULL;
+    }
+
+    key->type = HASH_KEY_STRING;
+    if (username == NULL) {
+        key->str = talloc_strdup(key, domain->name);
+    } else {
+        key->str = talloc_asprintf(key, "%s:%s", domain->name, username);
+    }
+
+    if (key->str == NULL) {
+        talloc_free(key);
+        return NULL;
+    }
+
+    return talloc_steal(mem_ctx, key);
+}
+
+errno_t sudosrv_cache_set_entry(struct tevent_context *ev,
+                                struct sudo_ctx *sudo_ctx,
+                                hash_table_t *table,
+                                struct sss_domain_info *domain,
+                                const char *username,
+                                size_t num_rules,
+                                struct sysdb_attrs **rules,
+                                time_t timeout)
+{
+    struct sudo_cache_entry *cache_entry = NULL;
+    hash_key_t *key = NULL;
+    hash_value_t value;
+    TALLOC_CTX *tmp_ctx = NULL;
+    struct tevent_timer *timer = NULL;
+    struct timeval tv;
+    errno_t ret;
+    int hret;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        goto done;
+    }
+
+    /* create key */
+    key = sudosrv_cache_create_key(tmp_ctx, domain, username);
+    if (key == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create hash key.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* create value */
+    cache_entry = talloc_zero(tmp_ctx, struct sudo_cache_entry);
+    if (cache_entry == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create hash value.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+    cache_entry->table = table;
+    cache_entry->key = key;
+    cache_entry->num_rules = num_rules;
+    cache_entry->rules = rules;
+    cache_entry->sudo_ctx = sudo_ctx;
+
+    value.type = HASH_VALUE_PTR;
+    value.ptr = cache_entry;
+
+    /* insert value */
+    hret = hash_enter(table, key, &value);
+    if (hret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("Unable to add [%s] to SUDO cache", key->str));
+        DEBUG(SSSDBG_TRACE_LIBS,
+              ("Hash error [%d][%s]", hret, hash_error_string(hret)));
+        ret = EIO;
+        goto done;
+    }
+
+    /* Create a timer event to remove the entry from the cache */
+    tv = tevent_timeval_current_ofs(timeout, 0);
+    timer = tevent_add_timer(ev, cache_entry, tv,
+                             sudosrv_cache_remove,
+                             cache_entry);
+    if (timer == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* everythig is ok, steal the pointers */
+    talloc_steal(cache_entry, key);
+    talloc_steal(cache_entry, rules);
+    talloc_steal(table, cache_entry);
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+static void sudosrv_cache_remove(struct tevent_context *ev,
+                                 struct tevent_timer *te,
+                                 struct timeval tv,
+                                 void *pvt)
+{
+    int hret;
+    hash_key_t *key = NULL;
+    struct sudo_cache_entry *cache_entry = NULL;
+
+    cache_entry = talloc_get_type(pvt, struct sudo_cache_entry);
+    key = cache_entry->key;
+
+    hret = hash_delete(cache_entry->table, key);
+    if (hret != HASH_SUCCESS && hret != HASH_ERROR_KEY_NOT_FOUND
+        && hret != HASH_ERROR_BAD_KEY_TYPE) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("Could not clear [%s] from SUDO cache.\n", key->str));
+        DEBUG(SSSDBG_TRACE_LIBS,
+               ("Hash error [%d][%s]", hret, hash_error_string(hret)));
+
+        /* corrupted memory, re-initialize table */
+        sudosrv_cache_reinit(cache_entry->sudo_ctx);
+    } else {
+        DEBUG(SSSDBG_TRACE_INTERNAL,
+              ("[%s] removed from SUDO cache\n", key->str));
+
+        talloc_free(cache_entry);
+    }
+}
+
+static errno_t sudosrv_cache_lookup_internal(hash_table_t *table,
+                                             struct sss_domain_info *domain,
+                                             const char *username,
+                                             size_t *num_rules,
+                                             struct sysdb_attrs ***rules)
+{
+    struct sudo_cache_entry *cache_entry = NULL;
+    hash_key_t *key = NULL;
+    hash_value_t value;
+    TALLOC_CTX *tmp_ctx = NULL;
+    errno_t ret;
+    int hret;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        goto done;
+    }
+
+    /* create key */
+    key = sudosrv_cache_create_key(tmp_ctx, domain, username);
+    if (key == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create hash key.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    hret = hash_lookup(table, key, &value);
+    if (hret == HASH_SUCCESS) {
+        /* cache hit */
+        cache_entry = value.ptr;
+        *num_rules = cache_entry->num_rules;
+        *rules = cache_entry->rules;
+        ret = EOK;
+    } else if (hret == HASH_ERROR_KEY_NOT_FOUND) {
+        /* cache miss */
+        ret = ENOENT;
+    } else {
+        /* error */
+        ret = EIO;
+    }
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+errno_t sudosrv_cache_lookup(hash_table_t *table,
+                             struct sudo_dom_ctx *dctx,
+                             bool check_next,
+                             const char *username,
+                             size_t *num_rules,
+                             struct sysdb_attrs ***rules)
+{
+    struct sss_domain_info *domain = dctx->domain;
+    errno_t ret;
+
+    if (!check_next) {
+        return sudosrv_cache_lookup_internal(table, dctx->domain, username,
+                                             num_rules, rules);
+    }
+
+    while (domain != NULL) {
+        if (domain->fqnames) {
+            domain = domain->next;
+            continue;
+        }
+
+        ret = sudosrv_cache_lookup_internal(table, domain, username,
+                                            num_rules, rules);
+        if (ret == EOK) {
+            /* user is in this domain */
+            dctx->domain = domain;
+            return ret;
+        } else if (ret != ENOENT) {
+            /* error */
+            return ret;
+        }
+
+        /* user is not in this domain cache, check next */
+        domain = domain->next;
+    }
+
+    /* user is not in cache */
+    return ENOENT;
+}
diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c
index 
3550e8bafaa4a7871b8f61c3c54dd08bddd6e870..cef245fec22072ac3ab0e415af2fb5646e29b5e9
 100644
--- a/src/responder/sudo/sudosrv_cmd.c
+++ b/src/responder/sudo/sudosrv_cmd.c
@@ -151,6 +151,15 @@ static int sudosrv_cmd_get_sudorules(struct cli_ctx 
*cli_ctx)
     cmd_ctx->cli_ctx = cli_ctx;
     cmd_ctx->type = SSS_DP_SUDO_USER;
 
+    /* get responder ctx */
+    cmd_ctx->sudo_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct 
sudo_ctx);
+    if (!cmd_ctx->sudo_ctx) {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("sudo_ctx not set\n"));
+        ret = EFAULT;
+        goto done;
+    }
+
+    /* create domain ctx */
     dctx = talloc_zero(cmd_ctx, struct sudo_dom_ctx);
     if (!dctx) {
         ret = ENOMEM;
@@ -201,8 +210,18 @@ static int sudosrv_cmd_get_sudorules(struct cli_ctx 
*cli_ctx)
         cmd_ctx->check_next = true;
     }
 
-    /* ok, find it ! */
-    ret = sudosrv_get_sudorules(dctx);
+    /* try to find rules in in-memory cache */
+    ret = sudosrv_cache_lookup(cmd_ctx->sudo_ctx->cache, dctx,
+                               cmd_ctx->check_next, cmd_ctx->username,
+                               &dctx->res_count, &dctx->res);
+    if (ret == EOK) {
+        /* cache hit */
+        DEBUG(SSSDBG_FUNC_DATA, ("Returning rules for [%s@%s] "
+              "from in-memory cache\n", cmd_ctx->username, 
dctx->domain->name));
+    } else if (ret == ENOENT) {
+        /* cache expired or missed */
+        ret = sudosrv_get_sudorules(dctx);
+    } /* else error */
 
 done:
     return sudosrv_cmd_done(dctx, ret);
@@ -224,6 +243,15 @@ static int sudosrv_cmd_get_defaults(struct cli_ctx 
*cli_ctx)
     cmd_ctx->username = NULL;
     cmd_ctx->check_next = false;
 
+    /* get responder ctx */
+    cmd_ctx->sudo_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct 
sudo_ctx);
+    if (!cmd_ctx->sudo_ctx) {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("sudo_ctx not set\n"));
+        ret = EFAULT;
+        goto done;
+    }
+
+    /* create domain ctx */
     dctx = talloc_zero(cmd_ctx, struct sudo_dom_ctx);
     if (!dctx) {
         ret = ENOMEM;
@@ -246,8 +274,18 @@ static int sudosrv_cmd_get_defaults(struct cli_ctx 
*cli_ctx)
         goto done;
     }
 
-    /* ok, find it ! */
-    ret = sudosrv_get_rules(dctx);
+    /* try to find rules in in-memory cache */
+    ret = sudosrv_cache_lookup(cmd_ctx->sudo_ctx->cache, dctx,
+                               cmd_ctx->check_next, cmd_ctx->username,
+                               &dctx->res_count, &dctx->res);
+    if (ret == EOK) {
+        /* cache hit */
+        DEBUG(SSSDBG_FUNC_DATA, ("Returning defaults settings for [%s] "
+                                 "from in-memory cache\n", 
dctx->domain->name));
+    } else if (ret == ENOENT) {
+        /* cache expired or missed */
+        ret = sudosrv_get_rules(dctx);
+    } /* else error */
 
 done:
     return sudosrv_cmd_done(dctx, ret);
diff --git a/src/responder/sudo/sudosrv_get_sudorules.c 
b/src/responder/sudo/sudosrv_get_sudorules.c
index 
8cb10e9aa336ce0c29aa3bef9efd90f695209bb9..c53638a359b22d2479bcf06fbe1cef86a6ae5bc2
 100644
--- a/src/responder/sudo/sudosrv_get_sudorules.c
+++ b/src/responder/sudo/sudosrv_get_sudorules.c
@@ -210,7 +210,6 @@ static void sudosrv_check_user_dp_callback(uint16_t 
err_maj, uint32_t err_min,
           ("Data Provider returned, check the cache again\n"));
     dctx->check_provider = false;
     ret = sudosrv_get_user(dctx);
-    /* FIXME - set entry into cache so that we don't perform initgroups too 
often */
     if (ret == EAGAIN) {
         goto done;
     } else if (ret != EOK) {
@@ -250,8 +249,9 @@ errno_t sudosrv_get_rules(struct sudo_dom_ctx *dctx)
     struct sudo_cmd_ctx *cmd_ctx = dctx->cmd_ctx;
     struct dp_callback_ctx *cb_ctx = NULL;
 
-    /* FIXME - cache logic will be here. For now, just refresh
-     * the cache unconditionally */
+    DEBUG(SSSDBG_TRACE_FUNC, ("getting rules for %s\n",
+          cmd_ctx->username ? cmd_ctx->username : "default options"));
+
     dpreq = sss_dp_get_sudoers_send(cmd_ctx->cli_ctx,
                                     cmd_ctx->cli_ctx->rctx,
                                     dctx->domain, false,
@@ -319,7 +319,6 @@ sudosrv_get_sudorules_dp_callback(uint16_t err_maj, 
uint32_t err_min,
                "Will try to return what we have in cache\n",
                (unsigned int)err_maj, (unsigned int)err_min, err_msg));
 
-        /* FIXME - cache or next domain? */
         /* Loop to the next domain if possible */
         if (dctx->domain->next && dctx->cmd_ctx->check_next) {
             dctx->domain = dctx->domain->next;
@@ -355,8 +354,11 @@ static errno_t sudosrv_get_sudorules_from_cache(struct 
sudo_dom_ctx *dctx)
     errno_t ret;
     struct sysdb_ctx *sysdb;
     struct cli_ctx *cli_ctx = dctx->cmd_ctx->cli_ctx;
+    struct sudo_ctx *sudo_ctx = dctx->cmd_ctx->sudo_ctx;
     uid_t uid;
     char **groupnames;
+    const char *safe_name = dctx->cmd_ctx->username ?
+                            dctx->cmd_ctx->username : "default rules";
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) return ENOMEM;
@@ -393,8 +395,21 @@ static errno_t sudosrv_get_sudorules_from_cache(struct 
sudo_dom_ctx *dctx)
         goto done;
     }
 
+    /* Store result in in-memory cache */
+    ret = sudosrv_cache_set_entry(sudo_ctx->rctx->ev, sudo_ctx,
+                                  sudo_ctx->cache, dctx->domain,
+                                  dctx->cmd_ctx->username, dctx->res_count,
+                                  dctx->res, sudo_ctx->cache_timeout);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("Unable to store rules in cache for "
+              "[%s@%s]\n", safe_name, dctx->domain->name));
+    } else {
+        DEBUG(SSSDBG_FUNC_DATA, ("Rules for [%s@%s] stored in in-memory 
cache\n",
+                                 safe_name, dctx->domain->name));
+    }
+
     DEBUG(SSSDBG_TRACE_FUNC, ("Returning rules for [%s@%s]\n",
-          dctx->cmd_ctx->username, dctx->domain->name));
+          safe_name, dctx->domain->name));
 
     ret = EOK;
 done:
diff --git a/src/responder/sudo/sudosrv_private.h 
b/src/responder/sudo/sudosrv_private.h
index 
b59aca4a3b152211724cb405b892ae098a3ba139..c3feb19bf797a706176f4b41b51c2edcade1cfed
 100644
--- a/src/responder/sudo/sudosrv_private.h
+++ b/src/responder/sudo/sudosrv_private.h
@@ -38,10 +38,23 @@ enum sss_dp_sudo_type {
 
 struct sudo_ctx {
     struct resp_ctx *rctx;
+
+    /*
+     * options
+     */
+    int cache_timeout;
+
+    /*
+     * Key: domain          for SSS_DP_SUDO_DEFAULTS
+     *      domain:username for SSS_DP_SUDO_USER
+     * Val: struct sudo_cache_entry *
+     */
+    hash_table_t *cache;
 };
 
 struct sudo_cmd_ctx {
     struct cli_ctx *cli_ctx;
+    struct sudo_ctx *sudo_ctx;
     enum sss_dp_sudo_type type;
     char *username;
     bool check_next;
@@ -121,4 +134,24 @@ sss_dp_get_sudoers_recv(TALLOC_CTX *mem_ctx,
                         dbus_uint32_t *err_min,
                         char **err_msg);
 
+errno_t sudosrv_cache_init(TALLOC_CTX *mem_ctx,
+                           unsigned long count,
+                           hash_table_t **table);
+
+errno_t sudosrv_cache_lookup(hash_table_t *table,
+                             struct sudo_dom_ctx *dctx,
+                             bool check_next,
+                             const char *username,
+                             size_t *res_count,
+                             struct sysdb_attrs ***res);
+
+errno_t sudosrv_cache_set_entry(struct tevent_context *ev,
+                                struct sudo_ctx *sudo_ctx,
+                                hash_table_t *table,
+                                struct sss_domain_info *domain,
+                                const char *username,
+                                size_t res_count,
+                                struct sysdb_attrs **res,
+                                time_t timeout);
+
 #endif /* _SUDOSRV_PRIVATE_H_ */
-- 
1.7.7.6

_______________________________________________
sssd-devel mailing list
[email protected]
https://fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to