From 534501fd5bed8a61d5ddd907ec00745b171801e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 2 May 2014 13:08:21 +0200
Subject: [PATCH 5/5] IFP: Implement SSSD components

---
 Makefile.am                                        |   7 +
 src/responder/ifp/ifp_components.c                 | 992 +++++++++++++++++++++
 src/responder/ifp/ifp_components.h                 |  87 ++
 src/responder/ifp/ifp_iface.xml                    |  51 ++
 src/responder/ifp/ifp_iface_generated.c            | 378 +++++++-
 src/responder/ifp/ifp_iface_generated.h            |  71 ++
 src/responder/ifp/ifpsrv.c                         |  26 +
 .../ifp/org.freedesktop.sssd.infopipe.conf         |   4 +
 8 files changed, 1615 insertions(+), 1 deletion(-)
 create mode 100644 src/responder/ifp/ifp_components.c
 create mode 100644 src/responder/ifp/ifp_components.h

diff --git a/Makefile.am b/Makefile.am
index 9588b83e4b2a099e38b39dfd906fc83748332b27..11001cce6dae49b91bdcdf254bd6360e3764ea28 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -486,6 +486,7 @@ dist_noinst_HEADERS = \
     src/responder/ssh/sshsrv_private.h \
     src/responder/ifp/ifp_private.h \
     src/responder/ifp/ifp_domains.h \
+    src/responder/ifp/ifp_components.h \
     src/sbus/sbus_client.h \
     src/sbus/sssd_dbus.h \
     src/sbus/sssd_dbus_meta.h \
@@ -860,6 +861,7 @@ sssd_ifp_SOURCES = \
     src/responder/ifp/ifp_iface_generated.h \
     src/responder/ifp/ifpsrv_util.c \
     src/responder/ifp/ifp_domains.c \
+    src/responder/ifp/ifp_components.c \
     $(SSSD_UTIL_OBJ) \
     $(SSSD_RESPONDER_OBJ)
 sssd_ifp_CFLAGS = \
@@ -869,6 +871,11 @@ sssd_ifp_LDADD = \
     $(SSSD_INTERNAL_LTLIBS)
 dist_dbuspolicy_DATA = \
     src/responder/ifp/org.freedesktop.sssd.infopipe.conf
+    
+if BUILD_CONFIG_LIB
+sssd_ifp_LDADD += libsss_config.la
+endif
+    
 endif
 
 sssd_be_SOURCES = \
diff --git a/src/responder/ifp/ifp_components.c b/src/responder/ifp/ifp_components.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3b88e74a76e5643c77196b982677adf33aa778a
--- /dev/null
+++ b/src/responder/ifp/ifp_components.c
@@ -0,0 +1,992 @@
+/*
+    Authors:
+        Pavel Březina <pbrezina@redhat.com>
+
+    Copyright (C) 2014 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 <string.h>
+#include <talloc.h>
+#include <signal.h>
+
+#include "config.h"
+#include "confdb/confdb.h"
+#include "util/util.h"
+#include "responder/common/responder.h"
+#include "responder/ifp/ifp_components.h"
+
+#ifdef HAVE_CONFIG_LIB
+#include "util/sss_config.h"
+#endif
+
+#define PATH_MONITOR    INFOPIPE_COMPONENT_PATH_PFX "/monitor"
+#define PATH_RESPONDERS INFOPIPE_COMPONENT_PATH_PFX "/Responders"
+#define PATH_BACKENDS   INFOPIPE_COMPONENT_PATH_PFX "/Backends"
+
+enum component_type {
+    COMPONENT_MONITOR,
+    COMPONENT_RESPONDER,
+    COMPONENT_BACKEND
+};
+
+static bool responder_exists(const char *name)
+{
+    const char * const *svc = get_known_services();
+    int i;
+
+    for (i = 0; svc[i] != NULL; i++) {
+        if (strcmp(svc[i], name) == 0) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static bool backend_exists(struct confdb_ctx *confdb, const char *name)
+{
+    char **names = NULL;
+    errno_t ret;
+    int i;
+
+    ret = confdb_list_all_domain_names(NULL, confdb, &names);
+    if (ret != EOK) {
+        return false;
+    }
+
+    for (i = 0; names[i] != NULL; i++) {
+        if (strcmp(names[i], name) == 0) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static errno_t check_and_get_component_from_path(TALLOC_CTX *mem_ctx,
+                                                 struct confdb_ctx *confdb,
+                                                 const char *path,
+                                                 enum component_type *_type,
+                                                 char **_name)
+{
+    enum component_type type;
+    const char *name = NULL;
+    char *safe_name = NULL;
+    errno_t ret;
+
+    if (confdb == NULL || path == NULL) {
+        return EINVAL;
+    }
+
+    if (strcmp(path, PATH_MONITOR) == 0) {
+        type = COMPONENT_MONITOR;
+        name = "monitor";
+    } else {
+        name = ifp_path_strip_prefix(path, PATH_RESPONDERS "/");
+        if (name != NULL) {
+            type = COMPONENT_RESPONDER;
+        } else {
+            name = ifp_path_strip_prefix(path, PATH_BACKENDS "/");
+            if (name != NULL) {
+                type = COMPONENT_BACKEND;
+            } else {
+                ret = EINVAL;
+                goto done;
+            }
+        }
+    }
+
+    if (strchr(name, '/') != NULL) {
+        ret = EINVAL;
+        goto done;
+    }
+
+    safe_name = ifp_bus_path_unescape(mem_ctx, name);
+    if (safe_name == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    switch (type) {
+    case COMPONENT_MONITOR:
+        /* noop */
+        break;
+    case COMPONENT_RESPONDER:
+        if (!responder_exists(safe_name)) {
+            ret = ENOENT;
+            goto done;
+        }
+        break;
+    case COMPONENT_BACKEND:
+        if (!backend_exists(confdb, safe_name)) {
+            ret = ENOENT;
+            goto done;
+        }
+        break;
+    }
+
+    if (_type != NULL) {
+        *_type = type;
+    }
+
+    if (_name != NULL) {
+        *_name = safe_name;
+    }
+
+    ret = EOK;
+
+done:
+    return ret;
+}
+
+static errno_t change_debug_level_tmp(struct confdb_ctx *confdb,
+                                      const char *name,
+                                      enum component_type type,
+                                      uint32_t level)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    const char *confdb_path = NULL;
+    const char **values = NULL;
+    errno_t ret;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    switch (type) {
+    case COMPONENT_MONITOR:
+        confdb_path = CONFDB_MONITOR_CONF_ENTRY;
+        break;
+    case COMPONENT_RESPONDER:
+        confdb_path = talloc_asprintf(tmp_ctx, CONFDB_SERVICE_PATH_TMPL, name);
+        break;
+    case COMPONENT_BACKEND:
+        confdb_path = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL, name);
+        break;
+    }
+
+    if (confdb_path == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    values = talloc_zero_array(tmp_ctx, const char*, 2);
+    if (values == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    values[0] = talloc_asprintf(tmp_ctx, "0x%.4x", level);
+    if (values[0] == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = confdb_add_param(confdb, true, confdb_path,
+                           CONFDB_SERVICE_DEBUG_LEVEL, values);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* reload the configuration */
+    if (kill(getppid(), SIGHUP) != 0) {
+        ret = errno;
+        goto done;
+    }
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+static errno_t list_responders(TALLOC_CTX *mem_ctx,
+                               const char ***_list,
+                               int *_num)
+{
+    const char **list = NULL;
+    const char * const *svc = get_known_services();
+    errno_t ret;
+    int num;
+    int i;
+
+    for (num = 0; svc[num] != NULL; num++);
+
+    list = talloc_array(mem_ctx, const char*, num);
+    if (list == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    for (i = 0; i < num; i++) {
+        list[i] = ifp_reply_objpath(list, PATH_RESPONDERS, svc[i]);
+        if (list[i] == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
+    *_num = num;
+    *_list = list;
+    ret = EOK;
+
+done:
+    if (ret != EOK) {
+        talloc_free(list);
+    }
+
+    return ret;
+}
+
+static errno_t list_backends(TALLOC_CTX *mem_ctx,
+                             struct confdb_ctx *confdb,
+                             const char ***_list,
+                             int *_num)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    const char **list = NULL;
+    char **names = NULL;
+    errno_t ret;
+    int num;
+    int i;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    ret = confdb_list_all_domain_names(tmp_ctx, confdb, &names);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    for (num = 0; names[num] != NULL; num++);
+
+    list = talloc_array(tmp_ctx, const char*, num);
+    if (list == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    for (i = 0; i < num; i++) {
+        list[i] = ifp_reply_objpath(list, PATH_BACKENDS, names[i]);
+        if (list[i] == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
+    *_num = num;
+    *_list = talloc_steal(mem_ctx, list);
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+int ifp_list_components(struct sbus_request *req, void *data)
+{
+    struct ifp_ctx *ctx = NULL;
+    DBusError *error = NULL;
+    const char **responders = NULL;
+    const char **backends = NULL;
+    const char **result = NULL;
+    int num_responders;
+    int num_backends;
+    int num;
+    int i;
+    errno_t ret;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "Invalid ifp context!");
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    ret = list_responders(req, &responders, &num_responders);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    ret = list_backends(req, ctx->rctx->cdb, &backends, &num_backends);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    num = num_responders + num_backends + 1;
+    result = talloc_array(req, const char*, num);
+    if (result == NULL) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ENOMEM));
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    result[0] = PATH_MONITOR;
+
+    for (i = 0; i < num_responders; i++) {
+        result[i + 1] = talloc_steal(result, responders[i]);
+    }
+
+    for (i = 0; i < num_backends; i++) {
+        result[i + num_responders + 1] = talloc_steal(result, backends[i]);
+    }
+
+    return infopipe_iface_ListComponents_finish(req, result, num);
+}
+
+int ifp_list_responders(struct sbus_request *req, void *data)
+{
+    DBusError *error = NULL;
+    const char **result = NULL;
+    int num;
+    errno_t ret;
+
+    ret = list_responders(req, &result, &num);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    return infopipe_iface_ListResponders_finish(req, result, num);
+}
+
+int ifp_list_backends(struct sbus_request *req, void *data)
+{
+    struct ifp_ctx *ctx = NULL;
+    DBusError *error = NULL;
+    const char **result = NULL;
+    int num;
+    errno_t ret;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "Invalid ifp context!");
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    ret = list_backends(req, ctx->rctx->cdb, &result, &num);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    return infopipe_iface_ListBackends_finish(req, result, num);
+}
+
+int ifp_find_monitor(struct sbus_request *req, void *data)
+{
+    return infopipe_iface_FindMonitor_finish(req, PATH_MONITOR);
+}
+
+int ifp_find_responder_by_name(struct sbus_request *req,
+                               void *data,
+                               const char *arg_name)
+{
+    DBusError *error = NULL;
+    const char *result = NULL;
+
+    if (responder_exists(arg_name)) {
+        result = ifp_reply_objpath(req, PATH_RESPONDERS, arg_name);
+        if (result == NULL) {
+            error = sbus_error_new(req, DBUS_ERROR_NO_MEMORY,
+                                   "%s", strerror(ENOMEM));
+            return sbus_request_fail_and_finish(req, error);
+        }
+    } else {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED,
+                               "Responder \"%s\" does not exist", arg_name);
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    return infopipe_iface_FindResponderByName_finish(req, result);
+}
+
+int ifp_find_backend_by_name(struct sbus_request *req,
+                             void *data,
+                             const char *arg_name)
+{
+    struct ifp_ctx *ctx = NULL;
+    DBusError *error = NULL;
+    const char *result = NULL;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "Invalid ifp context!");
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    if (backend_exists(ctx->rctx->cdb, arg_name)) {
+        result = ifp_reply_objpath(req, PATH_BACKENDS, arg_name);
+        if (result == NULL) {
+            error = sbus_error_new(req, DBUS_ERROR_NO_MEMORY,
+                                   "%s", strerror(ENOMEM));
+            return sbus_request_fail_and_finish(req, error);
+        }
+    } else {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED,
+                               "Backend \"%s\" does not exist", arg_name);
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    return infopipe_iface_FindBackendByName_finish(req, result);
+}
+
+#ifndef HAVE_CONFIG_LIB
+int ifp_component_enable(struct sbus_request *req, void *data)
+{
+    return sbus_request_fail_and_finish(req,
+                sbus_error_new(req, DBUS_ERROR_NOT_SUPPORTED, NULL));
+}
+#else
+int ifp_component_enable(struct sbus_request *req, void *data)
+{
+    struct ifp_ctx *ctx = NULL;
+    DBusError *error = NULL;
+    const char *path = dbus_message_get_path(req->message);
+    char *name = NULL;
+    enum component_type type;
+    struct sss_config_ctx *config_ctx = NULL;
+    errno_t ret;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "Invalid ifp context!");
+        goto done;
+    }
+
+    ret = check_and_get_component_from_path(req, ctx->rctx->cdb,
+                                            path, &type, &name);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        goto done;
+    }
+
+    config_ctx = sss_config_open(NULL, NULL, CONFDB_DEFAULT_CONFIG_FILE);
+    if (config_ctx == NULL) {
+        error = sbus_error_new(req, DBUS_ERROR_NO_MEMORY,
+                               "%s", strerror(ENOMEM));
+        goto done;
+    }
+
+    switch (type) {
+    case COMPONENT_MONITOR:
+        error = sbus_error_new(req, DBUS_ERROR_NOT_SUPPORTED, NULL);
+        goto done;
+        break;
+    case COMPONENT_RESPONDER:
+        ret = sss_config_service_enable(config_ctx, name);
+        break;
+    case COMPONENT_BACKEND:
+        ret = sss_config_domain_enable(config_ctx, name);
+        break;
+    }
+
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        goto done;
+    }
+
+    ret = sss_config_save(config_ctx);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        goto done;
+    }
+
+done:
+    sss_config_close(&config_ctx);
+
+    if (error != NULL) {
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    return infopipe_component_Enable_finish(req);
+}
+#endif
+
+#ifndef HAVE_CONFIG_LIB
+int ifp_component_disable(struct sbus_request *req, void *data)
+{
+    return sbus_request_fail_and_finish(req,
+                sbus_error_new(req, DBUS_ERROR_NOT_SUPPORTED, NULL));
+}
+#else
+int ifp_component_disable(struct sbus_request *req, void *data)
+{
+    struct ifp_ctx *ctx = NULL;
+    DBusError *error = NULL;
+    const char *path = dbus_message_get_path(req->message);
+    char *name = NULL;
+    enum component_type type;
+    struct sss_config_ctx *config_ctx = NULL;
+    errno_t ret;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "Invalid ifp context!");
+        goto done;
+    }
+
+    ret = check_and_get_component_from_path(req, ctx->rctx->cdb,
+                                            path, &type, &name);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        goto done;
+    }
+
+    config_ctx = sss_config_open(NULL, NULL, CONFDB_DEFAULT_CONFIG_FILE);
+    if (config_ctx == NULL) {
+        error = sbus_error_new(req, DBUS_ERROR_NO_MEMORY,
+                               "%s", strerror(ENOMEM));
+        goto done;
+    }
+
+    switch (type) {
+    case COMPONENT_MONITOR:
+        error = sbus_error_new(req, DBUS_ERROR_NOT_SUPPORTED, NULL);
+        goto done;
+        break;
+    case COMPONENT_RESPONDER:
+        ret = sss_config_service_disable(config_ctx, name);
+        break;
+    case COMPONENT_BACKEND:
+        ret = sss_config_domain_disable(config_ctx, name);
+        break;
+    }
+
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        goto done;
+    }
+
+    ret = sss_config_save(config_ctx);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        goto done;
+    }
+
+done:
+    sss_config_close(&config_ctx);
+
+    if (error != NULL) {
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    return infopipe_component_Disable_finish(req);
+}
+#endif
+
+#ifndef HAVE_CONFIG_LIB
+int ifp_component_change_debug_level(struct sbus_request *req,
+                                     void *data,
+                                     uint32_t arg_new_level)
+{
+    return sbus_request_fail_and_finish(req,
+                sbus_error_new(req, DBUS_ERROR_NOT_SUPPORTED, NULL));
+}
+#else
+int ifp_component_change_debug_level(struct sbus_request *req,
+                                     void *data,
+                                     uint32_t arg_new_level)
+{
+    struct ifp_ctx *ctx = NULL;
+    DBusError *error = NULL;
+    const char *path = dbus_message_get_path(req->message);
+    char *name = NULL;
+    enum component_type type;
+    struct sss_config_ctx *config_ctx = NULL;
+    const char *section = NULL;
+    errno_t ret;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "Invalid ifp context!");
+        goto done;
+    }
+
+    ret = check_and_get_component_from_path(req, ctx->rctx->cdb,
+                                            path, &type, &name);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        goto done;
+    }
+
+    switch (type) {
+    case COMPONENT_MONITOR:
+        section = "sssd";
+        break;
+    case COMPONENT_RESPONDER:
+        section = name;
+        break;
+    case COMPONENT_BACKEND:
+        section = talloc_asprintf(req, "domain/%s", name);
+        break;
+    }
+
+    if (section == NULL) {
+        error = sbus_error_new(req, DBUS_ERROR_NO_MEMORY,
+                               "%s", strerror(ENOMEM));
+        goto done;
+    }
+
+    config_ctx = sss_config_open(NULL, NULL, CONFDB_DEFAULT_CONFIG_FILE);
+    if (config_ctx == NULL) {
+        error = sbus_error_new(req, DBUS_ERROR_NO_MEMORY,
+                               "%s", strerror(ENOMEM));
+        goto done;
+    }
+
+    ret = sss_config_set_debug_level(config_ctx, section, arg_new_level);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED,
+                               "%s", strerror(ret));
+        goto done;
+    }
+
+    ret = sss_config_save(config_ctx);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        goto done;
+    }
+
+    ret = change_debug_level_tmp(ctx->rctx->cdb, name, type, arg_new_level);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        goto done;
+    }
+
+done:
+    sss_config_close(&config_ctx);
+
+    if (error != NULL) {
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    return infopipe_component_ChangeDebugLevel_finish(req);
+}
+#endif
+
+int ifp_component_change_debug_level_tmp(struct sbus_request *req,
+                                         void *data,
+                                         uint32_t arg_new_level)
+{
+    struct ifp_ctx *ctx = NULL;
+    DBusError *error = NULL;
+    const char *path = dbus_message_get_path(req->message);
+    char *name = NULL;
+    enum component_type type;
+    errno_t ret;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "Invalid ifp context!");
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    ret = check_and_get_component_from_path(req, ctx->rctx->cdb,
+                                            path, &type, &name);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    ret = change_debug_level_tmp(ctx->rctx->cdb, name, type, arg_new_level);
+    if (ret != EOK) {
+        error = sbus_error_new(req, DBUS_ERROR_FAILED, "%s", strerror(ret));
+        return sbus_request_fail_and_finish(req, error);
+    }
+
+    return infopipe_component_ChangeDebugLevelTemporarily_finish(req);
+}
+
+void ifp_component_get_name(struct sbus_request *req,
+                            void *data,
+                            const char **_out)
+{
+    struct ifp_ctx *ctx = NULL;
+    const char *path = dbus_message_get_path(req->message);
+    char *name = NULL;
+    errno_t ret;
+
+    *_out = NULL;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        return;
+    }
+
+    ret = check_and_get_component_from_path(req, ctx->rctx->cdb,
+                                            path, NULL, &name);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "Unknown object [%d]: %s\n",
+                                 ret, strerror(ret));
+        return;
+    }
+
+    *_out = name;
+}
+
+void ifp_component_get_debug_level(struct sbus_request *req,
+                                   void *data,
+                                   uint32_t *_out)
+{
+    struct ifp_ctx *ctx = NULL;
+    const char *path = dbus_message_get_path(req->message);
+    const char *confdb_path = NULL;
+    char *name = NULL;
+    enum component_type type;
+    int level;
+    errno_t ret;
+
+    *_out = 0;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        return;
+    }
+
+    ret = check_and_get_component_from_path(req, ctx->rctx->cdb,
+                                            path, &type, &name);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "Unknown object [%d]: %s\n",
+                                 ret, strerror(ret));
+        return;
+    }
+
+    switch (type) {
+    case COMPONENT_MONITOR:
+        confdb_path = CONFDB_MONITOR_CONF_ENTRY;
+        break;
+    case COMPONENT_RESPONDER:
+        confdb_path = talloc_asprintf(req, CONFDB_SERVICE_PATH_TMPL, name);
+        break;
+    case COMPONENT_BACKEND:
+        confdb_path = talloc_asprintf(req, CONFDB_DOMAIN_PATH_TMPL, name);
+        break;
+    }
+
+    if (confdb_path == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n");
+        return;
+    }
+
+    ret = confdb_get_int(ctx->rctx->cdb, confdb_path,
+                         CONFDB_SERVICE_DEBUG_LEVEL, SSSDBG_DEFAULT, &level);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve configuration option"
+                                 "[%d]: %s\n", ret, strerror(ret));
+        return;
+    }
+
+    *_out = level;
+}
+
+void ifp_component_get_enabled(struct sbus_request *req,
+                               void *data,
+                               bool *_out)
+{
+    struct ifp_ctx *ctx = NULL;
+    const char *path = dbus_message_get_path(req->message);
+    const char *param = NULL;
+    char **values = NULL;
+    char *name = NULL;
+    enum component_type type;
+    errno_t ret;
+    int i;
+
+    *_out = false;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        return;
+    }
+
+    ret = check_and_get_component_from_path(req, ctx->rctx->cdb,
+                                            path, &type, &name);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "Unknown object [%d]: %s\n",
+                                 ret, strerror(ret));
+        return;
+    }
+
+    switch (type) {
+    case COMPONENT_MONITOR:
+        *_out = true;
+        return;
+    case COMPONENT_RESPONDER:
+        param = CONFDB_MONITOR_ACTIVE_SERVICES;
+        break;
+    case COMPONENT_BACKEND:
+        param = CONFDB_MONITOR_ACTIVE_DOMAINS;
+        break;
+    }
+
+    ret = confdb_get_string_as_list(ctx->rctx->cdb, req,
+                                    CONFDB_MONITOR_CONF_ENTRY, param, &values);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve configuration option"
+                                 "[%d]: %s\n", ret, strerror(ret));
+        return;
+    }
+
+    for (i = 0; values[i] != NULL; i++) {
+        if (strcmp(values[i], name) == 0) {
+            *_out = true;
+            return;
+        }
+    }
+}
+
+void ifp_component_get_type(struct sbus_request *req,
+                            void *data,
+                            const char **_out)
+{
+    struct ifp_ctx *ctx = NULL;
+    const char *path = dbus_message_get_path(req->message);
+    enum component_type type;
+    errno_t ret;
+
+    *_out = NULL;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        return;
+    }
+
+    ret = check_and_get_component_from_path(req, ctx->rctx->cdb,
+                                            path, &type, NULL);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "Unknown object [%d]: %s\n",
+                                 ret, strerror(ret));
+        return;
+    }
+
+    switch (type) {
+    case COMPONENT_MONITOR:
+        *_out = "monitor";
+        break;
+    case COMPONENT_RESPONDER:
+        *_out = "responder";
+        break;
+    case COMPONENT_BACKEND:
+        *_out = "backend";
+        break;
+    }
+}
+
+void ifp_backend_get_providers(struct sbus_request *req,
+                               void *data,
+                               const char ***_out,
+                               int *_out_len)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    struct ifp_ctx *ctx = NULL;
+    const char *path = dbus_message_get_path(req->message);
+    const char *confdb_path = NULL;
+    char *name = NULL;
+    enum component_type type;
+    const char **out = NULL;
+    char *value = NULL;
+    static const char *providers[] = {CONFDB_DOMAIN_ID_PROVIDER,
+                                      CONFDB_DOMAIN_AUTH_PROVIDER,
+                                      CONFDB_DOMAIN_ACCESS_PROVIDER,
+                                      CONFDB_DOMAIN_CHPASS_PROVIDER,
+                                      CONFDB_DOMAIN_SUDO_PROVIDER,
+                                      CONFDB_DOMAIN_AUTOFS_PROVIDER,
+                                      CONFDB_DOMAIN_SELINUX_PROVIDER,
+                                      CONFDB_DOMAIN_HOSTID_PROVIDER,
+                                      CONFDB_DOMAIN_SUBDOMAINS_PROVIDER};
+    int num_providers = sizeof(providers) / sizeof(providers[0]);
+    errno_t ret;
+    int i;
+    int j;
+
+    *_out = NULL;
+    *_out_len = 0;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return;
+    }
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
+        return;
+    }
+
+    ret = check_and_get_component_from_path(tmp_ctx, ctx->rctx->cdb,
+                                            path, &type, &name);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "Unknown object [%d]: %s\n",
+                                 ret, strerror(ret));
+        return;
+    }
+
+    if (type != COMPONENT_BACKEND) {
+        return;
+    }
+
+    confdb_path = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL, name);
+    if (confdb_path == NULL) {
+        return;
+    }
+
+    out = talloc_zero_array(tmp_ctx, const char*, num_providers);
+    if (out == NULL) {
+        return;
+    }
+
+    j = 0;
+    for (i = 0; i < num_providers; i++) {
+        ret = confdb_get_string(ctx->rctx->cdb, tmp_ctx, confdb_path, providers[i],
+                                NULL, &value);
+        if (ret != EOK) {
+            return;
+        }
+
+        if (value == NULL) {
+            continue;
+        }
+
+        out[j] = talloc_asprintf(out, "%s=%s", providers[i], value);
+        if (out[j] == NULL) {
+            return;
+        }
+
+        j++;
+    }
+
+    *_out = talloc_steal(req, out);
+    *_out_len = j;
+
+    talloc_free(tmp_ctx);
+    return;
+}
diff --git a/src/responder/ifp/ifp_components.h b/src/responder/ifp/ifp_components.h
new file mode 100644
index 0000000000000000000000000000000000000000..26cd3f8aaac0089298d9f4ef199e7ae719528af7
--- /dev/null
+++ b/src/responder/ifp/ifp_components.h
@@ -0,0 +1,87 @@
+/*
+    Authors:
+        Pavel Březina <pbrezina@redhat.com>
+
+    Copyright (C) 2014 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_COMPONENTS_H_
+#define _IFP_COMPONENTS_H_
+
+#include "responder/ifp/ifp_iface_generated.h"
+#include "responder/ifp/ifp_private.h"
+
+#define INFOPIPE_COMPONENT_PATH_PFX "/org/freedesktop/sssd/infopipe/Components"
+#define INFOPIPE_COMPONENT_PATH INFOPIPE_COMPONENT_PATH_PFX "*"
+
+#define INFOPIPE_BACKEND_PATH INFOPIPE_COMPONENT_PATH_PFX "/Backends*"
+
+/* org.freedesktop.sssd.infopipe */
+
+int ifp_list_components(struct sbus_request *req, void *data);
+
+int ifp_list_responders(struct sbus_request *req, void *data);
+
+int ifp_list_backends(struct sbus_request *req, void *data);
+
+int ifp_find_monitor(struct sbus_request *req, void *data);
+
+int ifp_find_responder_by_name(struct sbus_request *req,
+                               void *data,
+                               const char *arg_name);
+
+int ifp_find_backend_by_name(struct sbus_request *req,
+                             void *data,
+                             const char *arg_name);
+
+/* org.freedesktop.sssd.infopipe.Components */
+
+int ifp_component_enable(struct sbus_request *req, void *data);
+
+int ifp_component_disable(struct sbus_request *req, void *data);
+
+int ifp_component_change_debug_level(struct sbus_request *req,
+                                     void *data,
+                                     uint32_t arg_new_level);
+
+int ifp_component_change_debug_level_tmp(struct sbus_request *req,
+                                         void *data,
+                                         uint32_t arg_new_level);
+
+void ifp_component_get_name(struct sbus_request *req,
+                            void *data,
+                            const char **_out);
+
+void ifp_component_get_debug_level(struct sbus_request *req,
+                                   void *data,
+                                   uint32_t *_out);
+
+void ifp_component_get_enabled(struct sbus_request *req,
+                               void *data,
+                               bool *_out);
+
+void ifp_component_get_type(struct sbus_request *req,
+                            void *data,
+                            const char **_out);
+
+/* org.freedesktop.sssd.infopipe.Components.Backends */
+
+void ifp_backend_get_providers(struct sbus_request *dbus_req,
+                               void *data,
+                               const char ***_out,
+                               int *_out_len);
+
+#endif /* _IFP_COMPONENTS_H_ */
diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml
index 1b9acd113db3f30904865e944d7214a7b45c2b34..a425754834430a5a5b0bce2430af82f8550d2606 100644
--- a/src/responder/ifp/ifp_iface.xml
+++ b/src/responder/ifp/ifp_iface.xml
@@ -9,6 +9,34 @@
             <annotation name="org.freedesktop.sssd.RawHandler" value="true"/>
         </method>
 
+        <!-- SSSD components -->
+
+        <method name="ListComponents">
+            <arg name="components" type="ao" direction="out"/>
+        </method>
+
+        <method name="ListResponders">
+            <arg name="responders" type="ao" direction="out"/>
+        </method>
+
+        <method name="ListBackends">
+            <arg name="backends" type="ao" direction="out"/>
+        </method>
+
+        <method name="FindMonitor">
+            <arg name="monitor" type="o" direction="out"/>
+        </method>
+
+        <method name="FindResponderByName">
+            <arg name="name" type="s" direction="in" />
+            <arg name="responder" type="o" direction="out"/>
+        </method>
+
+        <method name="FindBackendByName">
+            <arg name="name" type="s" direction="in" />
+            <arg name="backend" type="o" direction="out"/>
+        </method>
+
         <method name="GetUserAttr">
             <arg name="user" type="s" direction="in" />
             <arg name="attr" type="as" direction="in" />
@@ -32,6 +60,29 @@
 
     </interface>
 
+    <interface name="org.freedesktop.sssd.infopipe.Components">
+        <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="infopipe_component"/>
+
+        <method name="Enable" />
+        <method name="Disable" />
+        <method name="ChangeDebugLevel">
+            <arg name="new_level" type="u" direction="in" />
+        </method>
+        
+        <method name="ChangeDebugLevelTemporarily">
+            <arg name="new_level" type="u" direction="in" />
+        </method>
+
+        <property name="name" type="s" access="read" />
+        <property name="debug_level" type="u" access="read" />
+        <property name="enabled" type="b" access="read" />
+        <property name="type" type="s" access="read" />
+        
+        <!-- FIXME: This should be part of Components.Backends interface, onece
+             SSSD supports multiple interfaces per object path. -->
+        <property name="providers" type="as" access="read" />
+    </interface>
+    
     <interface name="org.freedesktop.sssd.infopipe.Domains">
         <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="infopipe_domain"/>
 
diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c
index 2cc87ee5a4793e8da302a998869a38e30bfad181..ecb68bbcb4b6857e1b2709c9e7a866e7ca18cca7 100644
--- a/src/responder/ifp/ifp_iface_generated.c
+++ b/src/responder/ifp/ifp_iface_generated.c
@@ -7,12 +7,105 @@
 
 /* invokes a handler with a 's' DBus signature */
 static int invoke_s_method(struct sbus_request *dbus_req, void *function_ptr);
+
+/* invokes a handler with a 'u' DBus signature */
+static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr);
 static int invoke_get_s(struct sbus_request *dbus_req, void *function_ptr);
-static int invoke_get_as(struct sbus_request *dbus_req, void *function_ptr);
 static int invoke_get_u(struct sbus_request *dbus_req, void *function_ptr);
 static int invoke_get_b(struct sbus_request *dbus_req, void *function_ptr);
+static int invoke_get_as(struct sbus_request *dbus_req, void *function_ptr);
 static int invoke_get_o(struct sbus_request *dbus_req, void *function_ptr);
 
+/* arguments for org.freedesktop.sssd.infopipe.ListComponents */
+const struct sbus_arg_meta infopipe_iface_ListComponents__out[] = {
+    { "components", "ao" },
+    { NULL, }
+};
+
+int infopipe_iface_ListComponents_finish(struct sbus_request *req, const char *arg_components[], int len_components)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &arg_components, len_components,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* arguments for org.freedesktop.sssd.infopipe.ListResponders */
+const struct sbus_arg_meta infopipe_iface_ListResponders__out[] = {
+    { "responders", "ao" },
+    { NULL, }
+};
+
+int infopipe_iface_ListResponders_finish(struct sbus_request *req, const char *arg_responders[], int len_responders)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &arg_responders, len_responders,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* arguments for org.freedesktop.sssd.infopipe.ListBackends */
+const struct sbus_arg_meta infopipe_iface_ListBackends__out[] = {
+    { "backends", "ao" },
+    { NULL, }
+};
+
+int infopipe_iface_ListBackends_finish(struct sbus_request *req, const char *arg_backends[], int len_backends)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &arg_backends, len_backends,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* arguments for org.freedesktop.sssd.infopipe.FindMonitor */
+const struct sbus_arg_meta infopipe_iface_FindMonitor__out[] = {
+    { "monitor", "o" },
+    { NULL, }
+};
+
+int infopipe_iface_FindMonitor_finish(struct sbus_request *req, const char *arg_monitor)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_OBJECT_PATH, &arg_monitor,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* arguments for org.freedesktop.sssd.infopipe.FindResponderByName */
+const struct sbus_arg_meta infopipe_iface_FindResponderByName__in[] = {
+    { "name", "s" },
+    { NULL, }
+};
+
+/* arguments for org.freedesktop.sssd.infopipe.FindResponderByName */
+const struct sbus_arg_meta infopipe_iface_FindResponderByName__out[] = {
+    { "responder", "o" },
+    { NULL, }
+};
+
+int infopipe_iface_FindResponderByName_finish(struct sbus_request *req, const char *arg_responder)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_OBJECT_PATH, &arg_responder,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* arguments for org.freedesktop.sssd.infopipe.FindBackendByName */
+const struct sbus_arg_meta infopipe_iface_FindBackendByName__in[] = {
+    { "name", "s" },
+    { NULL, }
+};
+
+/* arguments for org.freedesktop.sssd.infopipe.FindBackendByName */
+const struct sbus_arg_meta infopipe_iface_FindBackendByName__out[] = {
+    { "backend", "o" },
+    { NULL, }
+};
+
+int infopipe_iface_FindBackendByName_finish(struct sbus_request *req, const char *arg_backend)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_OBJECT_PATH, &arg_backend,
+                                         DBUS_TYPE_INVALID);
+}
+
 /* arguments for org.freedesktop.sssd.infopipe.GetUserAttr */
 const struct sbus_arg_meta infopipe_iface_GetUserAttr__in[] = {
     { "user", "s" },
@@ -87,6 +180,48 @@ const struct sbus_method_meta infopipe_iface__methods[] = {
         NULL, /* no invoker */
     },
     {
+        "ListComponents", /* name */
+        NULL, /* no in_args */
+        infopipe_iface_ListComponents__out,
+        offsetof(struct infopipe_iface, ListComponents),
+        NULL, /* no invoker */
+    },
+    {
+        "ListResponders", /* name */
+        NULL, /* no in_args */
+        infopipe_iface_ListResponders__out,
+        offsetof(struct infopipe_iface, ListResponders),
+        NULL, /* no invoker */
+    },
+    {
+        "ListBackends", /* name */
+        NULL, /* no in_args */
+        infopipe_iface_ListBackends__out,
+        offsetof(struct infopipe_iface, ListBackends),
+        NULL, /* no invoker */
+    },
+    {
+        "FindMonitor", /* name */
+        NULL, /* no in_args */
+        infopipe_iface_FindMonitor__out,
+        offsetof(struct infopipe_iface, FindMonitor),
+        NULL, /* no invoker */
+    },
+    {
+        "FindResponderByName", /* name */
+        infopipe_iface_FindResponderByName__in,
+        infopipe_iface_FindResponderByName__out,
+        offsetof(struct infopipe_iface, FindResponderByName),
+        invoke_s_method,
+    },
+    {
+        "FindBackendByName", /* name */
+        infopipe_iface_FindBackendByName__in,
+        infopipe_iface_FindBackendByName__out,
+        offsetof(struct infopipe_iface, FindBackendByName),
+        invoke_s_method,
+    },
+    {
         "GetUserAttr", /* name */
         infopipe_iface_GetUserAttr__in,
         infopipe_iface_GetUserAttr__out,
@@ -126,6 +261,231 @@ const struct sbus_interface_meta infopipe_iface_meta = {
     NULL, /* no GetAll invoker */
 };
 
+int infopipe_component_Enable_finish(struct sbus_request *req)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_INVALID);
+}
+
+int infopipe_component_Disable_finish(struct sbus_request *req)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* arguments for org.freedesktop.sssd.infopipe.Components.ChangeDebugLevel */
+const struct sbus_arg_meta infopipe_component_ChangeDebugLevel__in[] = {
+    { "new_level", "u" },
+    { NULL, }
+};
+
+int infopipe_component_ChangeDebugLevel_finish(struct sbus_request *req)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* arguments for org.freedesktop.sssd.infopipe.Components.ChangeDebugLevelTemporarily */
+const struct sbus_arg_meta infopipe_component_ChangeDebugLevelTemporarily__in[] = {
+    { "new_level", "u" },
+    { NULL, }
+};
+
+int infopipe_component_ChangeDebugLevelTemporarily_finish(struct sbus_request *req)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* methods for org.freedesktop.sssd.infopipe.Components */
+const struct sbus_method_meta infopipe_component__methods[] = {
+    {
+        "Enable", /* name */
+        NULL, /* no in_args */
+        NULL, /* no out_args */
+        offsetof(struct infopipe_component, Enable),
+        NULL, /* no invoker */
+    },
+    {
+        "Disable", /* name */
+        NULL, /* no in_args */
+        NULL, /* no out_args */
+        offsetof(struct infopipe_component, Disable),
+        NULL, /* no invoker */
+    },
+    {
+        "ChangeDebugLevel", /* name */
+        infopipe_component_ChangeDebugLevel__in,
+        NULL, /* no out_args */
+        offsetof(struct infopipe_component, ChangeDebugLevel),
+        invoke_u_method,
+    },
+    {
+        "ChangeDebugLevelTemporarily", /* name */
+        infopipe_component_ChangeDebugLevelTemporarily__in,
+        NULL, /* no out_args */
+        offsetof(struct infopipe_component, ChangeDebugLevelTemporarily),
+        invoke_u_method,
+    },
+    { NULL, }
+};
+
+/* invokes GetAll for the 'org.freedesktop.sssd.infopipe.Components' interface */
+static int invoke_infopipe_component_get_all(struct sbus_request *dbus_req, void *function_ptr)
+{
+    struct sbus_interface *intf = dbus_req->intf;
+    const struct sbus_property_meta *property;
+    DBusMessage *reply;
+    dbus_bool_t dbret;
+    DBusMessageIter iter;
+    DBusMessageIter iter_dict;
+    int ret;
+    const char * s_prop_val;
+    const char * s_out_val;
+    void (*s_handler)(struct sbus_request *, void *data, const char * *);
+    bool b_prop_val;
+    dbus_bool_t b_out_val;
+    void (*b_handler)(struct sbus_request *, void *data, bool *);
+    uint32_t u_prop_val;
+    uint32_t u_out_val;
+    void (*u_handler)(struct sbus_request *, void *data, uint32_t *);
+    const char * *as_prop_val;
+    int as_prop_len;
+    const char * *as_out_val;
+    void (*as_handler)(struct sbus_request *, void *data, const char * * *, int *);
+
+    reply = dbus_message_new_method_return(dbus_req->message);
+    if (!reply) return ENOMEM;
+    dbus_message_iter_init_append(reply, &iter);
+    dbret = dbus_message_iter_open_container(
+                                     &iter, DBUS_TYPE_ARRAY,
+                                     DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                     DBUS_TYPE_STRING_AS_STRING
+                                     DBUS_TYPE_VARIANT_AS_STRING
+                                     DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                     &iter_dict);
+    if (!dbret) return ENOMEM;
+
+    property = sbus_meta_find_property(intf->vtable->meta, "name");
+    if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) {
+        s_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get);
+        if (s_handler) {
+            (s_handler)(dbus_req, dbus_req->intf->instance_data, &s_prop_val);
+            s_out_val = s_prop_val == NULL ? "" : s_prop_val;
+            ret = sbus_add_variant_to_dict(&iter_dict, "name", DBUS_TYPE_STRING, &s_out_val);
+            if (ret != EOK) return ret;
+        }
+    }
+
+    property = sbus_meta_find_property(intf->vtable->meta, "debug_level");
+    if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) {
+        u_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get);
+        if (u_handler) {
+            (u_handler)(dbus_req, dbus_req->intf->instance_data, &u_prop_val);
+            u_out_val = u_prop_val;
+            ret = sbus_add_variant_to_dict(&iter_dict, "debug_level", DBUS_TYPE_UINT32, &u_out_val);
+            if (ret != EOK) return ret;
+        }
+    }
+
+    property = sbus_meta_find_property(intf->vtable->meta, "enabled");
+    if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) {
+        b_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get);
+        if (b_handler) {
+            (b_handler)(dbus_req, dbus_req->intf->instance_data, &b_prop_val);
+            b_out_val = b_prop_val;
+            ret = sbus_add_variant_to_dict(&iter_dict, "enabled", DBUS_TYPE_BOOLEAN, &b_out_val);
+            if (ret != EOK) return ret;
+        }
+    }
+
+    property = sbus_meta_find_property(intf->vtable->meta, "type");
+    if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) {
+        s_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get);
+        if (s_handler) {
+            (s_handler)(dbus_req, dbus_req->intf->instance_data, &s_prop_val);
+            s_out_val = s_prop_val == NULL ? "" : s_prop_val;
+            ret = sbus_add_variant_to_dict(&iter_dict, "type", DBUS_TYPE_STRING, &s_out_val);
+            if (ret != EOK) return ret;
+        }
+    }
+
+    property = sbus_meta_find_property(intf->vtable->meta, "providers");
+    if (property != NULL && property->flags & SBUS_PROPERTY_READABLE) {
+        as_handler = VTABLE_FUNC(intf->vtable, property->vtable_offset_get);
+        if (as_handler) {
+            (as_handler)(dbus_req, dbus_req->intf->instance_data, &as_prop_val, &as_prop_len);
+            as_out_val = as_prop_val;
+            ret = sbus_add_array_as_variant_to_dict(&iter_dict, "providers", DBUS_TYPE_STRING, (uint8_t*)as_out_val, as_prop_len, sizeof(const char *));
+            if (ret != EOK) return ret;
+        }
+    }
+
+    dbret = dbus_message_iter_close_container(&iter, &iter_dict);
+    if (!dbret) return ENOMEM;
+
+    return sbus_request_finish(dbus_req, reply);
+}
+
+/* property info for org.freedesktop.sssd.infopipe.Components */
+const struct sbus_property_meta infopipe_component__properties[] = {
+    {
+        "name", /* name */
+        "s", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct infopipe_component, infopipe_component_get_name),
+        invoke_get_s,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "debug_level", /* name */
+        "u", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct infopipe_component, infopipe_component_get_debug_level),
+        invoke_get_u,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "enabled", /* name */
+        "b", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct infopipe_component, infopipe_component_get_enabled),
+        invoke_get_b,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "type", /* name */
+        "s", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct infopipe_component, infopipe_component_get_type),
+        invoke_get_s,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    {
+        "providers", /* name */
+        "as", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct infopipe_component, infopipe_component_get_providers),
+        invoke_get_as,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    { NULL, }
+};
+
+/* interface info for org.freedesktop.sssd.infopipe.Components */
+const struct sbus_interface_meta infopipe_component_meta = {
+    "org.freedesktop.sssd.infopipe.Components", /* name */
+    infopipe_component__methods,
+    NULL, /* no signals */
+    infopipe_component__properties,
+    invoke_infopipe_component_get_all, /* GetAll invoker */
+};
+
 /* invokes GetAll for the 'org.freedesktop.sssd.infopipe.Domains' interface */
 static int invoke_infopipe_domain_get_all(struct sbus_request *dbus_req, void *function_ptr)
 {
@@ -481,6 +841,22 @@ static int invoke_s_method(struct sbus_request *dbus_req, void *function_ptr)
                      arg_0);
 }
 
+/* invokes a handler with a 'u' DBus signature */
+static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr)
+{
+    uint32_t arg_0;
+    int (*handler)(struct sbus_request *, void *, uint32_t) = function_ptr;
+
+    if (!sbus_request_parse_or_finish(dbus_req,
+                               DBUS_TYPE_UINT32, &arg_0,
+                               DBUS_TYPE_INVALID)) {
+         return EOK; /* request handled */
+    }
+
+    return (handler)(dbus_req, dbus_req->intf->instance_data,
+                     arg_0);
+}
+
 /* invokes a getter with a 'const char *' DBus type */
 static int invoke_get_s(struct sbus_request *dbus_req, void *function_ptr)
 {
diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h
index 3fe8c41e9165b89565723c0027b2c63d73a7c1c8..3a3e6955e351d76a23cbd6d94104e1198d51c5f3 100644
--- a/src/responder/ifp/ifp_iface_generated.h
+++ b/src/responder/ifp/ifp_iface_generated.h
@@ -14,11 +14,29 @@
 /* constants for org.freedesktop.sssd.infopipe */
 #define INFOPIPE_IFACE "org.freedesktop.sssd.infopipe"
 #define INFOPIPE_IFACE_PING "Ping"
+#define INFOPIPE_IFACE_LISTCOMPONENTS "ListComponents"
+#define INFOPIPE_IFACE_LISTRESPONDERS "ListResponders"
+#define INFOPIPE_IFACE_LISTBACKENDS "ListBackends"
+#define INFOPIPE_IFACE_FINDMONITOR "FindMonitor"
+#define INFOPIPE_IFACE_FINDRESPONDERBYNAME "FindResponderByName"
+#define INFOPIPE_IFACE_FINDBACKENDBYNAME "FindBackendByName"
 #define INFOPIPE_IFACE_GETUSERATTR "GetUserAttr"
 #define INFOPIPE_IFACE_GETUSERGROUPS "GetUserGroups"
 #define INFOPIPE_IFACE_FINDDOMAINBYNAME "FindDomainByName"
 #define INFOPIPE_IFACE_LISTDOMAINS "ListDomains"
 
+/* constants for org.freedesktop.sssd.infopipe.Components */
+#define INFOPIPE_COMPONENT "org.freedesktop.sssd.infopipe.Components"
+#define INFOPIPE_COMPONENT_ENABLE "Enable"
+#define INFOPIPE_COMPONENT_DISABLE "Disable"
+#define INFOPIPE_COMPONENT_CHANGEDEBUGLEVEL "ChangeDebugLevel"
+#define INFOPIPE_COMPONENT_CHANGEDEBUGLEVELTEMPORARILY "ChangeDebugLevelTemporarily"
+#define INFOPIPE_COMPONENT_NAME "name"
+#define INFOPIPE_COMPONENT_DEBUG_LEVEL "debug_level"
+#define INFOPIPE_COMPONENT_ENABLED "enabled"
+#define INFOPIPE_COMPONENT_TYPE "type"
+#define INFOPIPE_COMPONENT_PROVIDERS "providers"
+
 /* constants for org.freedesktop.sssd.infopipe.Domains */
 #define INFOPIPE_DOMAIN "org.freedesktop.sssd.infopipe.Domains"
 #define INFOPIPE_DOMAIN_NAME "name"
@@ -58,12 +76,36 @@
 struct infopipe_iface {
     struct sbus_vtable vtable; /* derive from sbus_vtable */
     sbus_msg_handler_fn Ping;
+    int (*ListComponents)(struct sbus_request *req, void *data);
+    int (*ListResponders)(struct sbus_request *req, void *data);
+    int (*ListBackends)(struct sbus_request *req, void *data);
+    int (*FindMonitor)(struct sbus_request *req, void *data);
+    int (*FindResponderByName)(struct sbus_request *req, void *data, const char *arg_name);
+    int (*FindBackendByName)(struct sbus_request *req, void *data, const char *arg_name);
     sbus_msg_handler_fn GetUserAttr;
     int (*GetUserGroups)(struct sbus_request *req, void *data, const char *arg_user);
     int (*FindDomainByName)(struct sbus_request *req, void *data, const char *arg_name);
     int (*ListDomains)(struct sbus_request *req, void *data);
 };
 
+/* finish function for ListComponents */
+int infopipe_iface_ListComponents_finish(struct sbus_request *req, const char *arg_components[], int len_components);
+
+/* finish function for ListResponders */
+int infopipe_iface_ListResponders_finish(struct sbus_request *req, const char *arg_responders[], int len_responders);
+
+/* finish function for ListBackends */
+int infopipe_iface_ListBackends_finish(struct sbus_request *req, const char *arg_backends[], int len_backends);
+
+/* finish function for FindMonitor */
+int infopipe_iface_FindMonitor_finish(struct sbus_request *req, const char *arg_monitor);
+
+/* finish function for FindResponderByName */
+int infopipe_iface_FindResponderByName_finish(struct sbus_request *req, const char *arg_responder);
+
+/* finish function for FindBackendByName */
+int infopipe_iface_FindBackendByName_finish(struct sbus_request *req, const char *arg_backend);
+
 /* finish function for GetUserGroups */
 int infopipe_iface_GetUserGroups_finish(struct sbus_request *req, const char *arg_values[], int len_values);
 
@@ -73,6 +115,32 @@ int infopipe_iface_FindDomainByName_finish(struct sbus_request *req, const char
 /* finish function for ListDomains */
 int infopipe_iface_ListDomains_finish(struct sbus_request *req, const char *arg_domain[], int len_domain);
 
+/* vtable for org.freedesktop.sssd.infopipe.Components */
+struct infopipe_component {
+    struct sbus_vtable vtable; /* derive from sbus_vtable */
+    int (*Enable)(struct sbus_request *req, void *data);
+    int (*Disable)(struct sbus_request *req, void *data);
+    int (*ChangeDebugLevel)(struct sbus_request *req, void *data, uint32_t arg_new_level);
+    int (*ChangeDebugLevelTemporarily)(struct sbus_request *req, void *data, uint32_t arg_new_level);
+    void (*infopipe_component_get_name)(struct sbus_request *, void *data, const char * *);
+    void (*infopipe_component_get_debug_level)(struct sbus_request *, void *data, uint32_t *);
+    void (*infopipe_component_get_enabled)(struct sbus_request *, void *data, bool *);
+    void (*infopipe_component_get_type)(struct sbus_request *, void *data, const char * *);
+    void (*infopipe_component_get_providers)(struct sbus_request *, void *data, const char * * *, int *);
+};
+
+/* finish function for Enable */
+int infopipe_component_Enable_finish(struct sbus_request *req);
+
+/* finish function for Disable */
+int infopipe_component_Disable_finish(struct sbus_request *req);
+
+/* finish function for ChangeDebugLevel */
+int infopipe_component_ChangeDebugLevel_finish(struct sbus_request *req);
+
+/* finish function for ChangeDebugLevelTemporarily */
+int infopipe_component_ChangeDebugLevelTemporarily_finish(struct sbus_request *req);
+
 /* vtable for org.freedesktop.sssd.infopipe.Domains */
 struct infopipe_domain {
     struct sbus_vtable vtable; /* derive from sbus_vtable */
@@ -105,6 +173,9 @@ struct infopipe_domain {
 /* interface info for org.freedesktop.sssd.infopipe */
 extern const struct sbus_interface_meta infopipe_iface_meta;
 
+/* interface info for org.freedesktop.sssd.infopipe.Components */
+extern const struct sbus_interface_meta infopipe_component_meta;
+
 /* interface info for org.freedesktop.sssd.infopipe.Domains */
 extern const struct sbus_interface_meta infopipe_domain_meta;
 
diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
index 3e7d0dff6a31761af8174ee16765a3f5e4ea3b16..8613504b45168a830b0dcda35c6f457676a961b4 100644
--- a/src/responder/ifp/ifpsrv.c
+++ b/src/responder/ifp/ifpsrv.c
@@ -39,6 +39,7 @@
 #include "confdb/confdb.h"
 #include "responder/ifp/ifp_private.h"
 #include "responder/ifp/ifp_domains.h"
+#include "responder/ifp/ifp_components.h"
 #include "responder/common/responder_sbus.h"
 
 #define DEFAULT_ALLOWED_UIDS "0"
@@ -67,12 +68,36 @@ static struct data_provider_iface ifp_dp_methods = {
 struct infopipe_iface ifp_iface = {
     { &infopipe_iface_meta, 0 },
     .Ping = ifp_ping,
+
+    /* components */
+    .ListComponents = ifp_list_components,
+    .ListResponders = ifp_list_responders,
+    .ListBackends = ifp_list_backends,
+    .FindMonitor = ifp_find_monitor,
+    .FindResponderByName = ifp_find_responder_by_name,
+    .FindBackendByName = ifp_find_backend_by_name,
+
     .GetUserAttr = ifp_user_get_attr,
     .GetUserGroups = ifp_user_get_groups,
     .ListDomains = ifp_list_domains,
     .FindDomainByName = ifp_find_domain_by_name,
 };
 
+struct infopipe_component ifp_component = {
+    { &infopipe_component_meta, 0 },
+    .Enable = ifp_component_enable,
+    .Disable = ifp_component_disable,
+    .ChangeDebugLevel = ifp_component_change_debug_level,
+    .ChangeDebugLevelTemporarily = ifp_component_change_debug_level_tmp,
+    .infopipe_component_get_name = ifp_component_get_name,
+    .infopipe_component_get_debug_level = ifp_component_get_debug_level,
+    .infopipe_component_get_enabled = ifp_component_get_enabled,
+    .infopipe_component_get_type = ifp_component_get_type,
+    /* FIXME: This should be part of Components.Backends interface, onece
+     * SSSD supports multiple interfaces per object path. */
+    .infopipe_component_get_providers = ifp_backend_get_providers
+};
+
 struct infopipe_domain ifp_domain = {
     { &infopipe_domain_meta, 0 },
     .infopipe_domain_get_name = ifp_dom_get_name,
@@ -99,6 +124,7 @@ struct sysbus_iface {
 static struct sysbus_iface ifp_ifaces[] = {
     { INFOPIPE_PATH, &ifp_iface.vtable },
     { INFOPIPE_DOMAIN_PATH, &ifp_domain.vtable },
+    { INFOPIPE_COMPONENT_PATH, &ifp_component.vtable },
     { NULL, NULL },
 };
 
diff --git a/src/responder/ifp/org.freedesktop.sssd.infopipe.conf b/src/responder/ifp/org.freedesktop.sssd.infopipe.conf
index 4f2a906ba812d46b6bca401d3fc14baa5c18de50..8e27ba453c16b6083050213e8ef14f5ca1e773f2 100644
--- a/src/responder/ifp/org.freedesktop.sssd.infopipe.conf
+++ b/src/responder/ifp/org.freedesktop.sssd.infopipe.conf
@@ -31,5 +31,9 @@
 
     <allow send_interface="org.freedesktop.sssd.infopipe"/>
   </policy>
+  
+  <policy user="root">
+    <allow send_interface="org.freedesktop.sssd.infopipe.Components"/>
+  </policy>
 
 </busconfig>
-- 
1.7.11.7

