From 7b203cca7b7b9827075d0eac5235c684218e9897 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 2 Jun 2015 11:12:15 +0200
Subject: [PATCH 1/5] IFP: Implement
 org.freedesktop.sssd.infopipe.Cache[.Object]

Resolves:
https://fedorahosted.org/sssd/ticket/2338
---
 Makefile.am                                        |   2 +
 src/db/sysdb.h                                     |   1 +
 src/responder/ifp/ifp_cache.c                      | 306 +++++++++++++++++++++
 src/responder/ifp/ifp_cache.h                      |  53 ++++
 src/responder/ifp/ifp_groups.c                     |  52 ++++
 src/responder/ifp/ifp_groups.h                     |  17 ++
 src/responder/ifp/ifp_iface.c                      |  28 ++
 src/responder/ifp/ifp_iface.xml                    |  23 ++
 src/responder/ifp/ifp_iface_generated.c            | 116 ++++++++
 src/responder/ifp/ifp_iface_generated.h            |  42 +++
 src/responder/ifp/ifp_users.c                      |  52 ++++
 src/responder/ifp/ifp_users.h                      |  17 ++
 .../ifp/org.freedesktop.sssd.infopipe.conf         |   2 +
 13 files changed, 711 insertions(+)
 create mode 100644 src/responder/ifp/ifp_cache.c
 create mode 100644 src/responder/ifp/ifp_cache.h

diff --git a/Makefile.am b/Makefile.am
index c21c1f3e93d0d25b47ea9cb3ed2e8919c641dd32..bad92e060375a4ef3bf1a930811ba00a422a6f39 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -552,6 +552,7 @@ dist_noinst_HEADERS = \
     src/responder/ifp/ifp_components.h \
     src/responder/ifp/ifp_users.h \
     src/responder/ifp/ifp_groups.h \
+    src/responder/ifp/ifp_cache.h \
     src/sbus/sbus_client.h \
     src/sbus/sssd_dbus.h \
     src/sbus/sssd_dbus_meta.h \
@@ -1106,6 +1107,7 @@ sssd_ifp_SOURCES = \
     src/responder/ifp/ifp_components.c \
     src/responder/ifp/ifp_users.c \
     src/responder/ifp/ifp_groups.c \
+    src/responder/ifp/ifp_cache.c \
     $(SSSD_UTIL_OBJ) \
     $(SSSD_RESPONDER_OBJ)
 sssd_ifp_CFLAGS = \
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index f667977edbaeb7cf74e20a6a7256594dfa9ff731..63cfa5f7dacc0102cb7753ed7d01d5551ce62349 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -91,6 +91,7 @@
 #define SYSDB_LAST_UPDATE "lastUpdate"
 #define SYSDB_CACHE_EXPIRE "dataExpireTimestamp"
 #define SYSDB_INITGR_EXPIRE "initgrExpireTimestamp"
+#define SYSDB_IFP_CACHED "ifpCached"
 
 #define SYSDB_AUTHORIZED_SERVICE "authorizedService"
 #define SYSDB_AUTHORIZED_HOST "authorizedHost"
diff --git a/src/responder/ifp/ifp_cache.c b/src/responder/ifp/ifp_cache.c
new file mode 100644
index 0000000000000000000000000000000000000000..35d51ab2c249925afd0dfc5c5efb3c244ac889b6
--- /dev/null
+++ b/src/responder/ifp/ifp_cache.c
@@ -0,0 +1,306 @@
+/*
+    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 <talloc.h>
+#include <tevent.h>
+
+#include "db/sysdb.h"
+#include "util/util.h"
+#include "responder/common/responder.h"
+#include "responder/ifp/ifp_cache.h"
+#include "responder/ifp/ifp_users.h"
+#include "responder/ifp/ifp_groups.h"
+#include "responder/ifp/ifp_iface_generated.h"
+
+static struct ldb_dn *
+ifp_cache_build_base_dn(TALLOC_CTX *mem_ctx,
+                        enum ifp_cache_type type,
+                        struct sss_domain_info *domain)
+{
+    struct ldb_dn *base_dn;
+
+    switch (type) {
+    case IFP_CACHE_USER:
+        base_dn = sysdb_user_base_dn(mem_ctx, domain);
+        break;
+    case IFP_CACHE_GROUP:
+        base_dn = sysdb_group_base_dn(mem_ctx, domain);
+        break;
+    }
+
+    return base_dn;
+}
+
+static char *
+ifp_cache_build_path(TALLOC_CTX *mem_ctx,
+                     enum ifp_cache_type type,
+                     struct sss_domain_info *domain,
+                     struct ldb_message *msg)
+{
+    char *path;
+
+    switch (type) {
+    case IFP_CACHE_USER:
+        path = ifp_users_build_path_from_msg(mem_ctx, domain, msg);
+        break;
+    case IFP_CACHE_GROUP:
+        path = ifp_groups_build_path_from_msg(mem_ctx, domain, msg);
+        break;
+    }
+
+    return path;
+}
+
+static const char *
+ifp_cache_object_class(enum ifp_cache_type type)
+{
+    const char *class = NULL;
+
+    switch (type) {
+    case IFP_CACHE_USER:
+        class = SYSDB_USER_CLASS;
+        break;
+    case IFP_CACHE_GROUP:
+        class = SYSDB_GROUP_CLASS;
+        break;
+    }
+
+    return class;
+}
+
+static errno_t
+ifp_cache_get_cached_objects(TALLOC_CTX *mem_ctx,
+                             enum ifp_cache_type type,
+                             struct sss_domain_info *domain,
+                             const char ***_paths,
+                             int *_num_paths)
+{
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_dn *base_dn;
+    struct ldb_result *result;
+    const char *class = ifp_cache_object_class(type);
+    const char **paths;
+    errno_t ret;
+    int ldb_ret;
+    int i;
+    const char *attrs[] = {SYSDB_OBJECTCLASS, SYSDB_UIDNUM,
+                           SYSDB_GIDNUM, NULL};
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    base_dn = ifp_cache_build_base_dn(tmp_ctx, type, domain);
+    if (base_dn == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create base dn\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ldb_ret = ldb_search(sysdb_ctx_get_ldb(domain->sysdb), tmp_ctx, &result,
+                         base_dn, LDB_SCOPE_SUBTREE, attrs,
+                         "(&(objectClass=%s)(%s=TRUE))", class,
+                         SYSDB_IFP_CACHED);
+    if (ldb_ret != LDB_SUCCESS) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to search the cache\n");
+        ret = sysdb_error_to_errno(ldb_ret);
+        goto done;
+    }
+
+    paths = talloc_zero_array(tmp_ctx, const char *, result->count + 1);
+    if (paths == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    for (i = 0; i < result->count; i++) {
+        paths[i] = ifp_cache_build_path(paths, type, domain, result->msgs[i]);
+        if (paths[i] == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
+    *_paths = talloc_steal(mem_ctx, paths);
+    *_num_paths = result->count;
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+int ifp_cache_list(struct sbus_request *sbus_req,
+                   void *data,
+                   enum ifp_cache_type type)
+{
+    DBusError *error;
+    struct sss_domain_info *domain;
+    struct ifp_ctx *ifp_ctx;
+    const char **tmp_paths;
+    int num_tmp_paths;
+    const char **paths;
+    int num_paths;
+    errno_t ret;
+
+    ifp_ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ifp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
+        return ERR_INTERNAL;
+    }
+
+    domain = ifp_ctx->rctx->domains;
+    num_paths = 0;
+    paths = NULL;
+    while (domain != NULL) {
+        ret = ifp_cache_get_cached_objects(sbus_req, type, domain,
+                                           &tmp_paths, &num_tmp_paths);
+        if (ret != EOK) {
+            error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED,
+                                   "Unable to build object list [%d]: %s\n",
+                                   ret, sss_strerror(ret));
+            return sbus_request_fail_and_finish(sbus_req, error);
+        }
+
+        ret = add_strings_lists(sbus_req, paths, tmp_paths, false,
+                                discard_const(&paths));
+        if (ret != EOK) {
+            error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED,
+                                   "Unable to build object list [%d]: %s\n",
+                                   ret, sss_strerror(ret));
+            return sbus_request_fail_and_finish(sbus_req, error);
+        }
+
+        num_paths += num_tmp_paths;
+
+        domain = get_next_domain(domain, true);
+    }
+
+    iface_ifp_cache_List_finish(sbus_req, paths, num_paths);
+
+    return EOK;
+}
+
+int ifp_cache_list_by_domain(struct sbus_request *sbus_req,
+                             void *data,
+                             const char *domainname,
+                             enum ifp_cache_type type)
+{
+    DBusError *error;
+    struct sss_domain_info *domain;
+    struct ifp_ctx *ifp_ctx;
+    const char **paths;
+    int num_paths;
+    errno_t ret;
+
+    ifp_ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ifp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
+        return ERR_INTERNAL;
+    }
+
+    domain = find_domain_by_name(ifp_ctx->rctx->domains, domainname, true);
+    if (domain == NULL) {
+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Unknown domain");
+        return sbus_request_fail_and_finish(sbus_req, error);
+    }
+
+    ret = ifp_cache_get_cached_objects(sbus_req, type, domain,
+                                       &paths, &num_paths);
+    if (ret != EOK) {
+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Unable to build "
+                           "object list [%d]: %s\n", ret, sss_strerror(ret));
+        return sbus_request_fail_and_finish(sbus_req, error);
+    }
+
+    iface_ifp_cache_ListByDomain_finish(sbus_req, paths, num_paths);
+
+    return EOK;
+}
+
+static errno_t ifp_cache_object_set(struct sss_domain_info *domain,
+                                    struct ldb_dn *dn,
+                                    bool value)
+{
+    struct sysdb_attrs *attrs;
+    errno_t ret;
+
+    attrs = sysdb_new_attrs(NULL);
+    if (attrs == NULL) {
+        return ENOMEM;
+    }
+
+    ret = sysdb_attrs_add_bool(attrs, SYSDB_IFP_CACHED, value);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add attribute [%d]: %s\n",
+              ret, sss_strerror(ret));
+        goto done;
+    }
+
+    ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, SYSDB_MOD_REP);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to modify entry [%d]: %s\n",
+              ret, sss_strerror(ret));
+        goto done;
+    }
+
+    ret = EOK;
+
+done:
+    talloc_free(attrs);
+
+    return ret;
+}
+
+int ifp_cache_object_store(struct sbus_request *sbus_req,
+                           struct sss_domain_info *domain,
+                           struct ldb_dn *dn)
+{
+    errno_t ret;
+
+    ret = ifp_cache_object_set(domain, dn, true);
+
+    if (ret == EOK) {
+        iface_ifp_cache_object_Store_finish(sbus_req, true);
+    } else {
+        iface_ifp_cache_object_Store_finish(sbus_req, false);
+    }
+
+    return EOK;
+}
+
+int ifp_cache_object_remove(struct sbus_request *sbus_req,
+                            struct sss_domain_info *domain,
+                            struct ldb_dn *dn)
+{
+    errno_t ret;
+
+    ret = ifp_cache_object_set(domain, dn, false);
+
+    if (ret == EOK) {
+        iface_ifp_cache_object_Remove_finish(sbus_req, true);
+    } else {
+        iface_ifp_cache_object_Remove_finish(sbus_req, false);
+    }
+
+    return EOK;
+}
diff --git a/src/responder/ifp/ifp_cache.h b/src/responder/ifp/ifp_cache.h
new file mode 100644
index 0000000000000000000000000000000000000000..56e90bb9c791d5f63d98e8e94b83f3695d88c742
--- /dev/null
+++ b/src/responder/ifp/ifp_cache.h
@@ -0,0 +1,53 @@
+/*
+    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/>.
+*/
+
+#ifndef IFP_CACHE_H_
+#define IFP_CACHE_H_
+
+#include "responder/common/responder.h"
+#include "responder/ifp/ifp_iface_generated.h"
+
+/* org.freedesktop-sssd-infopipe.Cache */
+
+enum ifp_cache_type {
+    IFP_CACHE_USER,
+    IFP_CACHE_GROUP
+};
+
+int ifp_cache_list(struct sbus_request *sbus_req,
+                   void *data,
+                   enum ifp_cache_type type);
+
+int ifp_cache_list_by_domain(struct sbus_request *sbus_req,
+                             void *data,
+                             const char *domain,
+                             enum ifp_cache_type type);
+
+/* org.freedesktop-sssd-infopipe.Cache.Object */
+
+int ifp_cache_object_store(struct sbus_request *sbus_req,
+                           struct sss_domain_info *domain,
+                           struct ldb_dn *dn);
+
+int ifp_cache_object_remove(struct sbus_request *sbus_req,
+                            struct sss_domain_info *domain,
+                            struct ldb_dn *dn);
+
+#endif /* IFP_CACHE_H_ */
diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c
index f1f86ce1ae29aaa906c2ebd56b81476ce18dfa1a..1b581b568f14362a47b4a80eb55d2de8eb936ae3 100644
--- a/src/responder/ifp/ifp_groups.c
+++ b/src/responder/ifp/ifp_groups.c
@@ -29,6 +29,7 @@
 #include "responder/common/responder_cache_req.h"
 #include "responder/ifp/ifp_groups.h"
 #include "responder/ifp/ifp_users.h"
+#include "responder/ifp/ifp_cache.h"
 
 char * ifp_groups_build_path_from_msg(TALLOC_CTX *mem_ctx,
                                       struct sss_domain_info *domain,
@@ -720,3 +721,54 @@ void ifp_groups_group_get_groups(struct sbus_request *sbus_req,
         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to acquire groups members\n");
     }
 }
+
+int ifp_cache_list_group(struct sbus_request *sbus_req,
+                         void *data)
+{
+    return ifp_cache_list(sbus_req, data, IFP_CACHE_GROUP);
+}
+
+int ifp_cache_list_by_domain_group(struct sbus_request *sbus_req,
+                                   void *data,
+                                   const char *domain)
+{
+    return ifp_cache_list_by_domain(sbus_req, data, domain, IFP_CACHE_GROUP);
+}
+
+int ifp_cache_object_store_group(struct sbus_request *sbus_req,
+                                 void *data)
+{
+    DBusError *error;
+    struct sss_domain_info *domain;
+    struct ldb_message *group;
+    errno_t ret;
+
+    ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group);
+    if (ret != EOK) {
+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
+                               "group [%d]: %s\n", ret, sss_strerror(ret));
+        return sbus_request_fail_and_finish(sbus_req, error);
+    }
+
+    /* The request is finished inside. */
+    return ifp_cache_object_store(sbus_req, domain, group->dn);
+}
+
+int ifp_cache_object_remove_group(struct sbus_request *sbus_req,
+                                  void *data)
+{
+    DBusError *error;
+    struct sss_domain_info *domain;
+    struct ldb_message *group;
+    errno_t ret;
+
+    ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group);
+    if (ret != EOK) {
+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
+                               "group [%d]: %s\n", ret, sss_strerror(ret));
+        return sbus_request_fail_and_finish(sbus_req, error);
+    }
+
+    /* The request is finished inside. */
+    return ifp_cache_object_remove(sbus_req, domain, group->dn);
+}
diff --git a/src/responder/ifp/ifp_groups.h b/src/responder/ifp/ifp_groups.h
index 0474ca44f19cb847ed803d0681f5aac19e55be4a..09c5a1c88d7f8df3c6917e62ba3e7224b990edfc 100644
--- a/src/responder/ifp/ifp_groups.h
+++ b/src/responder/ifp/ifp_groups.h
@@ -77,4 +77,21 @@ void ifp_groups_group_get_groups(struct sbus_request *sbus_req,
                                 const char ***_out,
                                 int *_size);
 
+/* org.freedesktop.sssd.infopipe.Cache */
+
+int ifp_cache_list_group(struct sbus_request *sbus_req,
+                         void *data);
+
+int ifp_cache_list_by_domain_group(struct sbus_request *sbus_req,
+                                   void *data,
+                                   const char *domain);
+
+/* org.freedesktop.sssd.infopipe.Cache.Object */
+
+int ifp_cache_object_store_group(struct sbus_request *sbus_req,
+                                 void *data);
+
+int ifp_cache_object_remove_group(struct sbus_request *sbus_req,
+                                  void *data);
+
 #endif /* IFP_GROUPS_H_ */
diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c
index ce987b6075ee886e7608455600e0a788c30c9741..015c66dc5323e237dd21575162e434b11acd8ed7 100644
--- a/src/responder/ifp/ifp_iface.c
+++ b/src/responder/ifp/ifp_iface.c
@@ -116,6 +116,30 @@ struct iface_ifp_groups_group iface_ifp_groups_group = {
     .get_groups = ifp_groups_group_get_groups
 };
 
+struct iface_ifp_cache iface_ifp_cache_user = {
+    { &iface_ifp_cache_meta, 0 },
+    .List = ifp_cache_list_user,
+    .ListByDomain = ifp_cache_list_by_domain_user
+};
+
+struct iface_ifp_cache_object iface_ifp_cache_object_user = {
+    { &iface_ifp_cache_object_meta, 0 },
+    .Store = ifp_cache_object_store_user,
+    .Remove = ifp_cache_object_remove_user
+};
+
+struct iface_ifp_cache iface_ifp_cache_group = {
+    { &iface_ifp_cache_meta, 0 },
+    .List = ifp_cache_list_group,
+    .ListByDomain = ifp_cache_list_by_domain_group
+};
+
+struct iface_ifp_cache_object iface_ifp_cache_object_group = {
+    { &iface_ifp_cache_object_meta, 0 },
+    .Store = ifp_cache_object_store_group,
+    .Remove = ifp_cache_object_remove_group
+};
+
 struct iface_map {
     const char *path;
     struct sbus_vtable *vtable;
@@ -126,9 +150,13 @@ static struct iface_map iface_map[] = {
     { IFP_PATH_DOMAINS_TREE, &iface_ifp_domains.vtable },
     { IFP_PATH_COMPONENTS_TREE, &iface_ifp_components.vtable },
     { IFP_PATH_USERS, &iface_ifp_users.vtable },
+    { IFP_PATH_USERS, &iface_ifp_cache_user.vtable },
     { IFP_PATH_USERS_TREE, &iface_ifp_users_user.vtable },
+    { IFP_PATH_USERS_TREE, &iface_ifp_cache_object_user.vtable },
     { IFP_PATH_GROUPS, &iface_ifp_groups.vtable },
+    { IFP_PATH_GROUPS, &iface_ifp_cache_group.vtable },
     { IFP_PATH_GROUPS_TREE, &iface_ifp_groups_group.vtable },
+    { IFP_PATH_GROUPS_TREE, &iface_ifp_cache_object_group.vtable },
     { NULL, NULL },
 };
 
diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml
index fbd3d3f5ac812a21c8768e28188217edbc83300b..340eb6d23ebfebb508e12118b9ac6c9a71fed099 100644
--- a/src/responder/ifp/ifp_iface.xml
+++ b/src/responder/ifp/ifp_iface.xml
@@ -101,6 +101,29 @@
         <property name="subdomain" type="b" access="read"/>
         <property name="parent_domain" type="o" access="read"/>
     </interface>
+    
+    <interface name="org.freedesktop.sssd.infopipe.Cache">
+        <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="iface_ifp_cache"/>
+
+        <method name="List">
+            <arg name="result" type="ao" direction="out" />
+        </method>
+        <method name="ListByDomain">
+            <arg name="domain_name" type="s" direction="in" />
+            <arg name="result" type="ao" direction="out"/>
+        </method>
+    </interface>
+    
+    <interface name="org.freedesktop.sssd.infopipe.Cache.Object">
+        <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="iface_ifp_cache_object"/>
+
+        <method name="Store">
+            <arg name="result" type="b" direction="out" />
+        </method>
+        <method name="Remove">
+            <arg name="result" type="b" direction="out" />
+        </method>
+    </interface>
 
     <interface name="org.freedesktop.sssd.infopipe.Users">
         <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="iface_ifp_users"/>
diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c
index ff00be8eaaedc28e37d39cdc85262c8041dafa0b..8255cbea729d9b2c0696cbfdef5c0daf9d958631 100644
--- a/src/responder/ifp/ifp_iface_generated.c
+++ b/src/responder/ifp/ifp_iface_generated.c
@@ -531,6 +531,122 @@ const struct sbus_interface_meta iface_ifp_domains_meta = {
     sbus_invoke_get_all, /* GetAll invoker */
 };
 
+/* arguments for org.freedesktop.sssd.infopipe.Cache.List */
+const struct sbus_arg_meta iface_ifp_cache_List__out[] = {
+    { "result", "ao" },
+    { NULL, }
+};
+
+int iface_ifp_cache_List_finish(struct sbus_request *req, const char *arg_result[], int len_result)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &arg_result, len_result,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* arguments for org.freedesktop.sssd.infopipe.Cache.ListByDomain */
+const struct sbus_arg_meta iface_ifp_cache_ListByDomain__in[] = {
+    { "domain_name", "s" },
+    { NULL, }
+};
+
+/* arguments for org.freedesktop.sssd.infopipe.Cache.ListByDomain */
+const struct sbus_arg_meta iface_ifp_cache_ListByDomain__out[] = {
+    { "result", "ao" },
+    { NULL, }
+};
+
+int iface_ifp_cache_ListByDomain_finish(struct sbus_request *req, const char *arg_result[], int len_result)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &arg_result, len_result,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* methods for org.freedesktop.sssd.infopipe.Cache */
+const struct sbus_method_meta iface_ifp_cache__methods[] = {
+    {
+        "List", /* name */
+        NULL, /* no in_args */
+        iface_ifp_cache_List__out,
+        offsetof(struct iface_ifp_cache, List),
+        NULL, /* no invoker */
+    },
+    {
+        "ListByDomain", /* name */
+        iface_ifp_cache_ListByDomain__in,
+        iface_ifp_cache_ListByDomain__out,
+        offsetof(struct iface_ifp_cache, ListByDomain),
+        invoke_s_method,
+    },
+    { NULL, }
+};
+
+/* interface info for org.freedesktop.sssd.infopipe.Cache */
+const struct sbus_interface_meta iface_ifp_cache_meta = {
+    "org.freedesktop.sssd.infopipe.Cache", /* name */
+    iface_ifp_cache__methods,
+    NULL, /* no signals */
+    NULL, /* no properties */
+    sbus_invoke_get_all, /* GetAll invoker */
+};
+
+/* arguments for org.freedesktop.sssd.infopipe.Cache.Object.Store */
+const struct sbus_arg_meta iface_ifp_cache_object_Store__out[] = {
+    { "result", "b" },
+    { NULL, }
+};
+
+int iface_ifp_cache_object_Store_finish(struct sbus_request *req, bool arg_result)
+{
+    dbus_bool_t cast_result = arg_result;
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_BOOLEAN, &cast_result,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* arguments for org.freedesktop.sssd.infopipe.Cache.Object.Remove */
+const struct sbus_arg_meta iface_ifp_cache_object_Remove__out[] = {
+    { "result", "b" },
+    { NULL, }
+};
+
+int iface_ifp_cache_object_Remove_finish(struct sbus_request *req, bool arg_result)
+{
+    dbus_bool_t cast_result = arg_result;
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_BOOLEAN, &cast_result,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* methods for org.freedesktop.sssd.infopipe.Cache.Object */
+const struct sbus_method_meta iface_ifp_cache_object__methods[] = {
+    {
+        "Store", /* name */
+        NULL, /* no in_args */
+        iface_ifp_cache_object_Store__out,
+        offsetof(struct iface_ifp_cache_object, Store),
+        NULL, /* no invoker */
+    },
+    {
+        "Remove", /* name */
+        NULL, /* no in_args */
+        iface_ifp_cache_object_Remove__out,
+        offsetof(struct iface_ifp_cache_object, Remove),
+        NULL, /* no invoker */
+    },
+    { NULL, }
+};
+
+/* interface info for org.freedesktop.sssd.infopipe.Cache.Object */
+const struct sbus_interface_meta iface_ifp_cache_object_meta = {
+    "org.freedesktop.sssd.infopipe.Cache.Object", /* name */
+    iface_ifp_cache_object__methods,
+    NULL, /* no signals */
+    NULL, /* no properties */
+    sbus_invoke_get_all, /* GetAll invoker */
+};
+
 /* arguments for org.freedesktop.sssd.infopipe.Users.FindByName */
 const struct sbus_arg_meta iface_ifp_users_FindByName__in[] = {
     { "name", "s" },
diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h
index 1bd2a448f3ee9af73091bd991a27f6b60f07a579..d2e5cdd3a689d42509e63adde70237cbde627ee2 100644
--- a/src/responder/ifp/ifp_iface_generated.h
+++ b/src/responder/ifp/ifp_iface_generated.h
@@ -54,6 +54,16 @@
 #define IFACE_IFP_DOMAINS_SUBDOMAIN "subdomain"
 #define IFACE_IFP_DOMAINS_PARENT_DOMAIN "parent_domain"
 
+/* constants for org.freedesktop.sssd.infopipe.Cache */
+#define IFACE_IFP_CACHE "org.freedesktop.sssd.infopipe.Cache"
+#define IFACE_IFP_CACHE_LIST "List"
+#define IFACE_IFP_CACHE_LISTBYDOMAIN "ListByDomain"
+
+/* constants for org.freedesktop.sssd.infopipe.Cache.Object */
+#define IFACE_IFP_CACHE_OBJECT "org.freedesktop.sssd.infopipe.Cache.Object"
+#define IFACE_IFP_CACHE_OBJECT_STORE "Store"
+#define IFACE_IFP_CACHE_OBJECT_REMOVE "Remove"
+
 /* constants for org.freedesktop.sssd.infopipe.Users */
 #define IFACE_IFP_USERS "org.freedesktop.sssd.infopipe.Users"
 #define IFACE_IFP_USERS_FINDBYNAME "FindByName"
@@ -194,6 +204,32 @@ struct iface_ifp_domains {
     void (*get_parent_domain)(struct sbus_request *, void *data, const char **);
 };
 
+/* vtable for org.freedesktop.sssd.infopipe.Cache */
+struct iface_ifp_cache {
+    struct sbus_vtable vtable; /* derive from sbus_vtable */
+    int (*List)(struct sbus_request *req, void *data);
+    int (*ListByDomain)(struct sbus_request *req, void *data, const char *arg_domain_name);
+};
+
+/* finish function for List */
+int iface_ifp_cache_List_finish(struct sbus_request *req, const char *arg_result[], int len_result);
+
+/* finish function for ListByDomain */
+int iface_ifp_cache_ListByDomain_finish(struct sbus_request *req, const char *arg_result[], int len_result);
+
+/* vtable for org.freedesktop.sssd.infopipe.Cache.Object */
+struct iface_ifp_cache_object {
+    struct sbus_vtable vtable; /* derive from sbus_vtable */
+    int (*Store)(struct sbus_request *req, void *data);
+    int (*Remove)(struct sbus_request *req, void *data);
+};
+
+/* finish function for Store */
+int iface_ifp_cache_object_Store_finish(struct sbus_request *req, bool arg_result);
+
+/* finish function for Remove */
+int iface_ifp_cache_object_Remove_finish(struct sbus_request *req, bool arg_result);
+
 /* vtable for org.freedesktop.sssd.infopipe.Users */
 struct iface_ifp_users {
     struct sbus_vtable vtable; /* derive from sbus_vtable */
@@ -285,6 +321,12 @@ extern const struct sbus_interface_meta iface_ifp_components_meta;
 /* interface info for org.freedesktop.sssd.infopipe.Domains */
 extern const struct sbus_interface_meta iface_ifp_domains_meta;
 
+/* interface info for org.freedesktop.sssd.infopipe.Cache */
+extern const struct sbus_interface_meta iface_ifp_cache_meta;
+
+/* interface info for org.freedesktop.sssd.infopipe.Cache.Object */
+extern const struct sbus_interface_meta iface_ifp_cache_object_meta;
+
 /* interface info for org.freedesktop.sssd.infopipe.Users */
 extern const struct sbus_interface_meta iface_ifp_users_meta;
 
diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
index 26c1aa696e5fbc3856ff45b0eb2c88d6bfbd2340..fa6f47f0d2f7ce52c3f0069b8ebf0bf1c98dbf22 100644
--- a/src/responder/ifp/ifp_users.c
+++ b/src/responder/ifp/ifp_users.c
@@ -30,6 +30,7 @@
 #include "responder/common/responder_cache_req.h"
 #include "responder/ifp/ifp_users.h"
 #include "responder/ifp/ifp_groups.h"
+#include "responder/ifp/ifp_cache.h"
 
 char * ifp_users_build_path_from_msg(TALLOC_CTX *mem_ctx,
                                      struct sss_domain_info *domain,
@@ -659,3 +660,54 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req,
 
     *_out = table;
 }
+
+int ifp_cache_list_user(struct sbus_request *sbus_req,
+                        void *data)
+{
+    return ifp_cache_list(sbus_req, data, IFP_CACHE_USER);
+}
+
+int ifp_cache_list_by_domain_user(struct sbus_request *sbus_req,
+                                  void *data,
+                                  const char *domain)
+{
+    return ifp_cache_list_by_domain(sbus_req, data, domain, IFP_CACHE_USER);
+}
+
+int ifp_cache_object_store_user(struct sbus_request *sbus_req,
+                                void *data)
+{
+    DBusError *error;
+    struct sss_domain_info *domain;
+    struct ldb_message *user;
+    errno_t ret;
+
+    ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user);
+    if (ret != EOK) {
+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
+                               "user [%d]: %s\n", ret, sss_strerror(ret));
+        return sbus_request_fail_and_finish(sbus_req, error);
+    }
+
+    /* The request is finished inside. */
+    return ifp_cache_object_store(sbus_req, domain, user->dn);
+}
+
+int ifp_cache_object_remove_user(struct sbus_request *sbus_req,
+                                 void *data)
+{
+    DBusError *error;
+    struct sss_domain_info *domain;
+    struct ldb_message *user;
+    errno_t ret;
+
+    ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user);
+    if (ret != EOK) {
+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
+                               "user [%d]: %s\n", ret, sss_strerror(ret));
+        return sbus_request_fail_and_finish(sbus_req, error);
+    }
+
+    /* The request is finished inside. */
+    return ifp_cache_object_remove(sbus_req, domain, user->dn);
+}
diff --git a/src/responder/ifp/ifp_users.h b/src/responder/ifp/ifp_users.h
index 7027ef14e51e3ca2bd92368fdfc10315edbf2fa8..4da0a734752a2a1bd11b0e21c532a1302c9126f1 100644
--- a/src/responder/ifp/ifp_users.h
+++ b/src/responder/ifp/ifp_users.h
@@ -92,4 +92,21 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req,
                                          void *data,
                                          hash_table_t **_out);
 
+/* org.freedesktop.sssd.infopipe.Cache */
+
+int ifp_cache_list_user(struct sbus_request *sbus_req,
+                        void *data);
+
+int ifp_cache_list_by_domain_user(struct sbus_request *sbus_req,
+                                  void *data,
+                                  const char *domain);
+
+/* org.freedesktop.sssd.infopipe.Cache.Object */
+
+int ifp_cache_object_store_user(struct sbus_request *sbus_req,
+                                void *data);
+
+int ifp_cache_object_remove_user(struct sbus_request *sbus_req,
+                                 void *data);
+
 #endif /* IFP_USERS_H_ */
diff --git a/src/responder/ifp/org.freedesktop.sssd.infopipe.conf b/src/responder/ifp/org.freedesktop.sssd.infopipe.conf
index b8df49350ecdd119fdde196a21771cae41dc52ef..398f303f75df49d159d8527c46459203b2210028 100644
--- a/src/responder/ifp/org.freedesktop.sssd.infopipe.conf
+++ b/src/responder/ifp/org.freedesktop.sssd.infopipe.conf
@@ -34,6 +34,8 @@
     <allow send_interface="org.freedesktop.sssd.infopipe.Users.User"/>
     <allow send_interface="org.freedesktop.sssd.infopipe.Groups"/>
     <allow send_interface="org.freedesktop.sssd.infopipe.Groups.Group"/>
+    <allow send_interface="org.freedesktop.sssd.infopipe.Cache"/>
+    <allow send_interface="org.freedesktop.sssd.infopipe.Cache.Object"/>
   </policy>
 
   <policy user="root">
-- 
2.1.0

