Blame SOURCES/0096-sssctl-print-active-server-and-server-list.patch

b2d430
From 7f4199c2d4dc9147be436005d75e03fc468f5349 Mon Sep 17 00:00:00 2001
b2d430
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
b2d430
Date: Mon, 27 Jun 2016 13:56:13 +0200
b2d430
Subject: [PATCH 096/102] sssctl: print active server and server list
b2d430
MIME-Version: 1.0
b2d430
Content-Type: text/plain; charset=UTF-8
b2d430
Content-Transfer-Encoding: 8bit
b2d430
b2d430
Resolves:
b2d430
https://fedorahosted.org/sssd/ticket/3069
b2d430
b2d430
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
b2d430
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
b2d430
(cherry picked from commit bd4c2ed5aec7f57ea04500f0e43f151eedfdde45)
b2d430
---
b2d430
 src/providers/data_provider/dp_iface.c           |   6 +-
b2d430
 src/providers/data_provider/dp_iface.h           |   8 +
b2d430
 src/providers/data_provider/dp_iface.xml         |   8 +
b2d430
 src/providers/data_provider/dp_iface_failover.c  | 297 ++++++++++++++++++++++-
b2d430
 src/providers/data_provider/dp_iface_generated.c |  52 ++++
b2d430
 src/providers/data_provider/dp_iface_generated.h |  10 +
b2d430
 src/providers/fail_over.c                        |  42 ++++
b2d430
 src/providers/fail_over.h                        |   4 +
b2d430
 src/responder/ifp/ifp_domains.c                  |  48 ++++
b2d430
 src/responder/ifp/ifp_domains.h                  |   8 +
b2d430
 src/responder/ifp/ifp_iface.c                    |   4 +-
b2d430
 src/responder/ifp/ifp_iface.xml                  |  10 +
b2d430
 src/responder/ifp/ifp_iface_generated.c          |  52 ++++
b2d430
 src/responder/ifp/ifp_iface_generated.h          |  10 +
b2d430
 src/tools/sssctl/sssctl_domains.c                | 182 +++++++++++++-
b2d430
 15 files changed, 722 insertions(+), 19 deletions(-)
b2d430
b2d430
diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c
b2d430
index 8ed7274f0dd7b59598e2cf21e0dd59d16666df0b..4b2b0ddca68be8899f7285b4d881a91444b99362 100644
b2d430
--- a/src/providers/data_provider/dp_iface.c
b2d430
+++ b/src/providers/data_provider/dp_iface.c
b2d430
@@ -42,8 +42,10 @@ struct iface_dp_backend iface_dp_backend = {
b2d430
 };
b2d430
 
b2d430
 struct iface_dp_failover iface_dp_failover = {
b2d430
-    {&iface_dp_failover_meta, 0},
b2d430
-    .ListServices = dp_failover_list_services
b2d430
+    { &iface_dp_failover_meta, 0 },
b2d430
+    .ListServices = dp_failover_list_services,
b2d430
+    .ActiveServer = dp_failover_active_server,
b2d430
+    .ListServers = dp_failover_list_servers
b2d430
 };
b2d430
 
b2d430
 static struct sbus_iface_map dp_map[] = {
b2d430
diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h
b2d430
index 76e623d21c413fd68f8f3c9a91ea32fd707dc54d..5c6f0eb2f5dd68b63bda389e6fdd2446ca9efb21 100644
b2d430
--- a/src/providers/data_provider/dp_iface.h
b2d430
+++ b/src/providers/data_provider/dp_iface.h
b2d430
@@ -69,4 +69,12 @@ errno_t dp_failover_list_services(struct sbus_request *sbus_req,
b2d430
                                   void *dp_cli,
b2d430
                                   const char *domname);
b2d430
 
b2d430
+errno_t dp_failover_active_server(struct sbus_request *sbus_req,
b2d430
+                                  void *dp_cli,
b2d430
+                                  const char *service_name);
b2d430
+
b2d430
+errno_t dp_failover_list_servers(struct sbus_request *sbus_req,
b2d430
+                                 void *dp_cli,
b2d430
+                                 const char *service_name);
b2d430
+
b2d430
 #endif /* DP_IFACE_H_ */
b2d430
diff --git a/src/providers/data_provider/dp_iface.xml b/src/providers/data_provider/dp_iface.xml
b2d430
index eab7fc0f1500bf8890030352421da62c134115b9..992848a048ef9fe813d6ae05bbcabd0913ecb277 100644
b2d430
--- a/src/providers/data_provider/dp_iface.xml
b2d430
+++ b/src/providers/data_provider/dp_iface.xml
b2d430
@@ -22,6 +22,14 @@
b2d430
             <arg name="domain_name" type="s" direction="in" />
b2d430
             <arg name="services" type="as" direction="out" />
b2d430
         </method>
b2d430
+        <method name="ActiveServer">
b2d430
+            <arg name="service_name" type="s" direction="in" />
b2d430
+            <arg name="server" type="s" direction="out" />
b2d430
+        </method>
b2d430
+        <method name="ListServers">
b2d430
+            <arg name="service_name" type="s" direction="in" />
b2d430
+            <arg name="servers" type="as" direction="out" />
b2d430
+        </method>
b2d430
     </interface>
b2d430
 
b2d430
     <interface name="org.freedesktop.sssd.dataprovider">
b2d430
diff --git a/src/providers/data_provider/dp_iface_failover.c b/src/providers/data_provider/dp_iface_failover.c
b2d430
index 038791088eeab7e9c5923996db77d2a107ff067d..7d95ffdd627604eb8c7e1b2882bf1665f792b660 100644
b2d430
--- a/src/providers/data_provider/dp_iface_failover.c
b2d430
+++ b/src/providers/data_provider/dp_iface_failover.c
b2d430
@@ -28,20 +28,208 @@
b2d430
 #include "providers/backend.h"
b2d430
 #include "util/util.h"
b2d430
 
b2d430
+static errno_t
b2d430
+dp_failover_list_services_ldap(struct be_ctx *be_ctx,
b2d430
+                               const char **services,
b2d430
+                               int *_count)
b2d430
+{
b2d430
+    struct be_svc_data *svc;
b2d430
+    int count;
b2d430
+
b2d430
+    count = 0;
b2d430
+    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
b2d430
+        services[count] = talloc_strdup(services, svc->name);
b2d430
+        if (services[count] == NULL) {
b2d430
+            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
b2d430
+            return ENOMEM;
b2d430
+        }
b2d430
+        count++;
b2d430
+    }
b2d430
+
b2d430
+    *_count = count;
b2d430
+
b2d430
+    return EOK;
b2d430
+}
b2d430
+
b2d430
+static errno_t
b2d430
+dp_failover_list_services_ad(struct be_ctx *be_ctx,
b2d430
+                             struct sss_domain_info *domain,
b2d430
+                             const char **services,
b2d430
+                             int *_count)
b2d430
+{
b2d430
+    char *fo_svc_name = NULL;
b2d430
+    struct be_svc_data *svc;
b2d430
+    errno_t ret;
b2d430
+    int count;
b2d430
+
b2d430
+    fo_svc_name = talloc_asprintf(services, "sd_%s", domain->name);
b2d430
+    if (fo_svc_name == NULL) {
b2d430
+        ret = ENOMEM;
b2d430
+        goto done;
b2d430
+    }
b2d430
+
b2d430
+    count = 0;
b2d430
+    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
b2d430
+        /* Drop each sd_gc_* since this service is not used with AD at all,
b2d430
+         * we only connect to AD_GC for global catalog. */
b2d430
+        if (strncasecmp(svc->name, "sd_gc_", strlen("sd_gc_")) == 0) {
b2d430
+            continue;
b2d430
+        }
b2d430
+
b2d430
+        /* Drop all subdomain services for different domain. */
b2d430
+        if (strncasecmp(svc->name, "sd_", strlen("sd_")) == 0) {
b2d430
+            if (!IS_SUBDOMAIN(domain)) {
b2d430
+                continue;
b2d430
+            }
b2d430
+
b2d430
+            if (strcasecmp(svc->name, fo_svc_name) != 0) {
b2d430
+                continue;
b2d430
+            }
b2d430
+        }
b2d430
+
b2d430
+        if (IS_SUBDOMAIN(domain)) {
b2d430
+            /* Drop AD since we connect to subdomain.com for LDAP. */
b2d430
+            if (strcasecmp(svc->name, "AD") == 0) {
b2d430
+                continue;
b2d430
+            }
b2d430
+        }
b2d430
+
b2d430
+        services[count] = talloc_strdup(services, svc->name);
b2d430
+        if (services[count] == NULL) {
b2d430
+            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
b2d430
+            ret = ENOMEM;
b2d430
+            goto done;
b2d430
+        }
b2d430
+        count++;
b2d430
+    }
b2d430
+
b2d430
+    *_count = count;
b2d430
+
b2d430
+    ret = EOK;
b2d430
+
b2d430
+done:
b2d430
+    talloc_free(fo_svc_name);
b2d430
+    return ret;
b2d430
+}
b2d430
+
b2d430
+static errno_t
b2d430
+dp_failover_list_services_ipa(struct be_ctx *be_ctx,
b2d430
+                              struct sss_domain_info *domain,
b2d430
+                              const char **services,
b2d430
+                              int *_count)
b2d430
+{
b2d430
+    struct be_svc_data *svc;
b2d430
+    char *fo_svc_name = NULL;
b2d430
+    char *fo_gc_name = NULL;
b2d430
+    errno_t ret;
b2d430
+    int count;
b2d430
+
b2d430
+    fo_svc_name = talloc_asprintf(services, "sd_%s", domain->name);
b2d430
+    if (fo_svc_name == NULL) {
b2d430
+        ret = ENOMEM;
b2d430
+        goto done;
b2d430
+    }
b2d430
+
b2d430
+    fo_gc_name = talloc_asprintf(services, "sd_gc_%s", domain->name);
b2d430
+    if (fo_gc_name == NULL) {
b2d430
+        ret = ENOMEM;
b2d430
+        goto done;
b2d430
+    }
b2d430
+
b2d430
+    count = 0;
b2d430
+    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
b2d430
+        /* Drop all subdomain services for different domain. */
b2d430
+        if (strncasecmp(svc->name, "sd_", strlen("sd_")) == 0) {
b2d430
+            if (!IS_SUBDOMAIN(domain)) {
b2d430
+                continue;
b2d430
+            }
b2d430
+
b2d430
+            if (strcasecmp(svc->name, fo_svc_name) != 0
b2d430
+                    && strcasecmp(svc->name, fo_gc_name) != 0) {
b2d430
+                continue;
b2d430
+            }
b2d430
+        }
b2d430
+
b2d430
+        services[count] = talloc_strdup(services, svc->name);
b2d430
+        if (services[count] == NULL) {
b2d430
+            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
b2d430
+            return ENOMEM;
b2d430
+        }
b2d430
+        count++;
b2d430
+    }
b2d430
+
b2d430
+    *_count = count;
b2d430
+
b2d430
+    ret = EOK;
b2d430
+
b2d430
+done:
b2d430
+    talloc_free(fo_svc_name);
b2d430
+    talloc_free(fo_gc_name);
b2d430
+
b2d430
+    return ret;
b2d430
+}
b2d430
+
b2d430
+enum dp_fo_svc_type {
b2d430
+    DP_FO_SVC_LDAP = 0,
b2d430
+    DP_FO_SVC_AD = 1,
b2d430
+    DP_FO_SVC_IPA = 1 << 1,
b2d430
+    DP_FO_SVC_MIXED = DP_FO_SVC_AD | DP_FO_SVC_IPA
b2d430
+};
b2d430
+
b2d430
 errno_t dp_failover_list_services(struct sbus_request *sbus_req,
b2d430
                                   void *dp_cli,
b2d430
                                   const char *domname)
b2d430
 {
b2d430
+    enum dp_fo_svc_type svc_type = DP_FO_SVC_LDAP;
b2d430
+    struct sss_domain_info *domain;
b2d430
     struct be_ctx *be_ctx;
b2d430
     struct be_svc_data *svc;
b2d430
     const char **services;
b2d430
     int num_services;
b2d430
+    errno_t ret;
b2d430
 
b2d430
     be_ctx = dp_client_be(dp_cli);
b2d430
 
b2d430
+    if (SBUS_IS_STRING_EMPTY(domname)) {
b2d430
+        domain = be_ctx->domain;
b2d430
+    } else {
b2d430
+        domain = find_domain_by_name(be_ctx->domain, domname, false);
b2d430
+        if (domain == NULL) {
b2d430
+            sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
b2d430
+                                     "Unknown domain %s", domname);
b2d430
+            return EOK;
b2d430
+        }
b2d430
+    }
b2d430
+
b2d430
+    /**
b2d430
+     * Returning list of failover services is currently rather difficult
b2d430
+     * since there is only one failover context for the whole backend.
b2d430
+     *
b2d430
+     * The list of services for the given domain depends on whether it is
b2d430
+     * a master domain or a subdomain and whether we are using IPA, AD or
b2d430
+     * LDAP backend.
b2d430
+     *
b2d430
+     * For LDAP we just return everything we have.
b2d430
+     * For AD master domain we return AD, AD_GC.
b2d430
+     * For AD subdomain we return subdomain.com, AD_GC.
b2d430
+     * For IPA in client mode we return IPA.
b2d430
+     * For IPA in server mode we return IPA for master domain and
b2d430
+     * subdomain.com, gc_subdomain.com for subdomain.
b2d430
+     *
b2d430
+     * We also return everything else for all cases if any other service
b2d430
+     * such as kerberos is configured separately.
b2d430
+     */
b2d430
+
b2d430
+    /* Allocate enough space. */
b2d430
     num_services = 0;
b2d430
     DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
b2d430
         num_services++;
b2d430
+
b2d430
+        if (strcasecmp(svc->name, "AD") == 0) {
b2d430
+            svc_type |= DP_FO_SVC_AD;
b2d430
+        } else if (strcasecmp(svc->name, "IPA") == 0) {
b2d430
+            svc_type |= DP_FO_SVC_IPA;
b2d430
+        }
b2d430
     }
b2d430
 
b2d430
     services = talloc_zero_array(sbus_req, const char *, num_services);
b2d430
@@ -50,17 +238,108 @@ errno_t dp_failover_list_services(struct sbus_request *sbus_req,
b2d430
         return ENOMEM;
b2d430
     }
b2d430
 
b2d430
-    num_services = 0;
b2d430
-    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
b2d430
-        services[num_services] = talloc_strdup(services, svc->name);
b2d430
-        if (services[num_services] == NULL) {
b2d430
-            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
b2d430
-            talloc_free(services);
b2d430
-            return ENOMEM;
b2d430
-        }
b2d430
-        num_services++;
b2d430
+    /* Fill the list. */
b2d430
+    switch (svc_type) {
b2d430
+    case DP_FO_SVC_LDAP:
b2d430
+    case DP_FO_SVC_MIXED:
b2d430
+        ret = dp_failover_list_services_ldap(be_ctx, services, &num_services);
b2d430
+        break;
b2d430
+    case DP_FO_SVC_AD:
b2d430
+        ret = dp_failover_list_services_ad(be_ctx, domain,
b2d430
+                                           services, &num_services);
b2d430
+        break;
b2d430
+    case DP_FO_SVC_IPA:
b2d430
+        ret = dp_failover_list_services_ipa(be_ctx, domain,
b2d430
+                                            services, &num_services);
b2d430
+        break;
b2d430
+    default:
b2d430
+        ret = ERR_INTERNAL;
b2d430
+        break;
b2d430
+    }
b2d430
+
b2d430
+    if (ret != EOK) {
b2d430
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create service list [%d]: %s\n",
b2d430
+              ret, sss_strerror(ret));
b2d430
+        talloc_free(services);
b2d430
+        return ret;
b2d430
     }
b2d430
 
b2d430
     iface_dp_failover_ListServices_finish(sbus_req, services, num_services);
b2d430
     return EOK;
b2d430
 }
b2d430
+
b2d430
+errno_t dp_failover_active_server(struct sbus_request *sbus_req,
b2d430
+                                  void *dp_cli,
b2d430
+                                  const char *service_name)
b2d430
+{
b2d430
+    struct be_ctx *be_ctx;
b2d430
+    struct be_svc_data *svc;
b2d430
+    const char *server;
b2d430
+    bool found = false;
b2d430
+
b2d430
+    be_ctx = dp_client_be(dp_cli);
b2d430
+
b2d430
+    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
b2d430
+        if (strcmp(svc->name, service_name) == 0) {
b2d430
+            found = true;
b2d430
+            break;
b2d430
+        }
b2d430
+    }
b2d430
+
b2d430
+    if (!found) {
b2d430
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get server name\n");
b2d430
+        sbus_request_reply_error(sbus_req, SBUS_ERROR_NOT_FOUND,
b2d430
+                                 "Unknown service name");
b2d430
+        return EOK;
b2d430
+    }
b2d430
+
b2d430
+    if (svc->last_good_srv == NULL) {
b2d430
+        server = "";
b2d430
+    } else {
b2d430
+        server = fo_get_server_name(svc->last_good_srv);
b2d430
+        if (server == NULL) {
b2d430
+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get server name\n");
b2d430
+            sbus_request_reply_error(sbus_req, SBUS_ERROR_INTERNAL,
b2d430
+                                     "Unable to get server name");
b2d430
+            return EOK;
b2d430
+        }
b2d430
+    }
b2d430
+
b2d430
+    iface_dp_failover_ActiveServer_finish(sbus_req, server);
b2d430
+    return EOK;
b2d430
+}
b2d430
+
b2d430
+errno_t dp_failover_list_servers(struct sbus_request *sbus_req,
b2d430
+                                 void *dp_cli,
b2d430
+                                 const char *service_name)
b2d430
+{
b2d430
+    struct be_ctx *be_ctx;
b2d430
+    struct be_svc_data *svc;
b2d430
+    const char **servers;
b2d430
+    bool found = false;
b2d430
+    size_t count;
b2d430
+
b2d430
+    be_ctx = dp_client_be(dp_cli);
b2d430
+
b2d430
+    DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) {
b2d430
+        if (strcmp(svc->name, service_name) == 0) {
b2d430
+            found = true;
b2d430
+            break;
b2d430
+        }
b2d430
+    }
b2d430
+
b2d430
+    if (!found) {
b2d430
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get server list\n");
b2d430
+        sbus_request_reply_error(sbus_req, SBUS_ERROR_NOT_FOUND,
b2d430
+                                 "Unknown service name");
b2d430
+        return EOK;
b2d430
+    }
b2d430
+
b2d430
+    servers = fo_svc_server_list(sbus_req, svc->fo_service, &count);
b2d430
+    if (servers == NULL) {
b2d430
+        return ENOMEM;
b2d430
+    }
b2d430
+
b2d430
+    iface_dp_failover_ListServers_finish(sbus_req, servers, (int)count);
b2d430
+    return EOK;
b2d430
+}
b2d430
diff --git a/src/providers/data_provider/dp_iface_generated.c b/src/providers/data_provider/dp_iface_generated.c
b2d430
index 7b36fd8aaeebb976a511c5592b1dd0ae28e9bb8a..fd2acb4f4bd8cf1dcbe8842cccc6dc2077fc83a2 100644
b2d430
--- a/src/providers/data_provider/dp_iface_generated.c
b2d430
+++ b/src/providers/data_provider/dp_iface_generated.c
b2d430
@@ -111,6 +111,44 @@ int iface_dp_failover_ListServices_finish(struct sbus_request *req, const char *
b2d430
                                          DBUS_TYPE_INVALID);
b2d430
 }
b2d430
 
b2d430
+/* arguments for org.freedesktop.sssd.DataProvider.Failover.ActiveServer */
b2d430
+const struct sbus_arg_meta iface_dp_failover_ActiveServer__in[] = {
b2d430
+    { "service_name", "s" },
b2d430
+    { NULL, }
b2d430
+};
b2d430
+
b2d430
+/* arguments for org.freedesktop.sssd.DataProvider.Failover.ActiveServer */
b2d430
+const struct sbus_arg_meta iface_dp_failover_ActiveServer__out[] = {
b2d430
+    { "server", "s" },
b2d430
+    { NULL, }
b2d430
+};
b2d430
+
b2d430
+int iface_dp_failover_ActiveServer_finish(struct sbus_request *req, const char *arg_server)
b2d430
+{
b2d430
+   return sbus_request_return_and_finish(req,
b2d430
+                                         DBUS_TYPE_STRING, &arg_server,
b2d430
+                                         DBUS_TYPE_INVALID);
b2d430
+}
b2d430
+
b2d430
+/* arguments for org.freedesktop.sssd.DataProvider.Failover.ListServers */
b2d430
+const struct sbus_arg_meta iface_dp_failover_ListServers__in[] = {
b2d430
+    { "service_name", "s" },
b2d430
+    { NULL, }
b2d430
+};
b2d430
+
b2d430
+/* arguments for org.freedesktop.sssd.DataProvider.Failover.ListServers */
b2d430
+const struct sbus_arg_meta iface_dp_failover_ListServers__out[] = {
b2d430
+    { "servers", "as" },
b2d430
+    { NULL, }
b2d430
+};
b2d430
+
b2d430
+int iface_dp_failover_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers)
b2d430
+{
b2d430
+   return sbus_request_return_and_finish(req,
b2d430
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &arg_servers, len_servers,
b2d430
+                                         DBUS_TYPE_INVALID);
b2d430
+}
b2d430
+
b2d430
 /* methods for org.freedesktop.sssd.DataProvider.Failover */
b2d430
 const struct sbus_method_meta iface_dp_failover__methods[] = {
b2d430
     {
b2d430
@@ -120,6 +158,20 @@ const struct sbus_method_meta iface_dp_failover__methods[] = {
b2d430
         offsetof(struct iface_dp_failover, ListServices),
b2d430
         invoke_s_method,
b2d430
     },
b2d430
+    {
b2d430
+        "ActiveServer", /* name */
b2d430
+        iface_dp_failover_ActiveServer__in,
b2d430
+        iface_dp_failover_ActiveServer__out,
b2d430
+        offsetof(struct iface_dp_failover, ActiveServer),
b2d430
+        invoke_s_method,
b2d430
+    },
b2d430
+    {
b2d430
+        "ListServers", /* name */
b2d430
+        iface_dp_failover_ListServers__in,
b2d430
+        iface_dp_failover_ListServers__out,
b2d430
+        offsetof(struct iface_dp_failover, ListServers),
b2d430
+        invoke_s_method,
b2d430
+    },
b2d430
     { NULL, }
b2d430
 };
b2d430
 
b2d430
diff --git a/src/providers/data_provider/dp_iface_generated.h b/src/providers/data_provider/dp_iface_generated.h
b2d430
index 977ab3bae803ca002162b02d0c3d9677779983f4..7c2216aa27022769c707d80b59e9b436e72d1739 100644
b2d430
--- a/src/providers/data_provider/dp_iface_generated.h
b2d430
+++ b/src/providers/data_provider/dp_iface_generated.h
b2d430
@@ -22,6 +22,8 @@
b2d430
 /* constants for org.freedesktop.sssd.DataProvider.Failover */
b2d430
 #define IFACE_DP_FAILOVER "org.freedesktop.sssd.DataProvider.Failover"
b2d430
 #define IFACE_DP_FAILOVER_LISTSERVICES "ListServices"
b2d430
+#define IFACE_DP_FAILOVER_ACTIVESERVER "ActiveServer"
b2d430
+#define IFACE_DP_FAILOVER_LISTSERVERS "ListServers"
b2d430
 
b2d430
 /* constants for org.freedesktop.sssd.dataprovider */
b2d430
 #define IFACE_DP "org.freedesktop.sssd.dataprovider"
b2d430
@@ -72,11 +74,19 @@ int iface_dp_backend_IsOnline_finish(struct sbus_request *req, bool arg_status);
b2d430
 struct iface_dp_failover {
b2d430
     struct sbus_vtable vtable; /* derive from sbus_vtable */
b2d430
     int (*ListServices)(struct sbus_request *req, void *data, const char *arg_domain_name);
b2d430
+    int (*ActiveServer)(struct sbus_request *req, void *data, const char *arg_service_name);
b2d430
+    int (*ListServers)(struct sbus_request *req, void *data, const char *arg_service_name);
b2d430
 };
b2d430
 
b2d430
 /* finish function for ListServices */
b2d430
 int iface_dp_failover_ListServices_finish(struct sbus_request *req, const char *arg_services[], int len_services);
b2d430
 
b2d430
+/* finish function for ActiveServer */
b2d430
+int iface_dp_failover_ActiveServer_finish(struct sbus_request *req, const char *arg_server);
b2d430
+
b2d430
+/* finish function for ListServers */
b2d430
+int iface_dp_failover_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers);
b2d430
+
b2d430
 /* vtable for org.freedesktop.sssd.dataprovider */
b2d430
 struct iface_dp {
b2d430
     struct sbus_vtable vtable; /* derive from sbus_vtable */
b2d430
diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
b2d430
index 1d88d2aa54bfdebd4b648e2b13fa8d03e2be3973..8ab39f27f77e19e601855632196006a8dbbdf136 100644
b2d430
--- a/src/providers/fail_over.c
b2d430
+++ b/src/providers/fail_over.c
b2d430
@@ -1660,6 +1660,48 @@ bool fo_svc_has_server(struct fo_service *service, struct fo_server *server)
b2d430
     return false;
b2d430
 }
b2d430
 
b2d430
+const char **fo_svc_server_list(TALLOC_CTX *mem_ctx,
b2d430
+                                struct fo_service *service,
b2d430
+                                size_t *_count)
b2d430
+{
b2d430
+    const char **list;
b2d430
+    const char *server;
b2d430
+    struct fo_server *srv;
b2d430
+    size_t count;
b2d430
+
b2d430
+    count = 0;
b2d430
+    DLIST_FOR_EACH(srv, service->server_list) {
b2d430
+        count++;
b2d430
+    }
b2d430
+
b2d430
+    list = talloc_zero_array(mem_ctx, const char *, count + 1);
b2d430
+    if (list == NULL) {
b2d430
+        return NULL;
b2d430
+    }
b2d430
+
b2d430
+    count = 0;
b2d430
+    DLIST_FOR_EACH(srv, service->server_list) {
b2d430
+        server = fo_get_server_name(srv);
b2d430
+        if (server == NULL) {
b2d430
+            /* _srv_ */
b2d430
+            continue;
b2d430
+        }
b2d430
+
b2d430
+        list[count] = talloc_strdup(list, server);
b2d430
+        if (list[count] == NULL) {
b2d430
+            talloc_free(list);
b2d430
+            return NULL;
b2d430
+        }
b2d430
+        count++;
b2d430
+    }
b2d430
+
b2d430
+    if (_count != NULL) {
b2d430
+        *_count = count;
b2d430
+    }
b2d430
+
b2d430
+    return list;
b2d430
+}
b2d430
+
b2d430
 bool fo_set_srv_lookup_plugin(struct fo_ctx *ctx,
b2d430
                               fo_srv_lookup_plugin_send_t send_fn,
b2d430
                               fo_srv_lookup_plugin_recv_t recv_fn,
b2d430
diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h
b2d430
index f24b5715f13931965400c20562a1578aaf756908..d70212fb7ea569b9c47bba36704aa8ae18754cbb 100644
b2d430
--- a/src/providers/fail_over.h
b2d430
+++ b/src/providers/fail_over.h
b2d430
@@ -212,6 +212,10 @@ struct fo_server *fo_get_active_server(struct fo_service *service);
b2d430
 
b2d430
 bool fo_svc_has_server(struct fo_service *service, struct fo_server *server);
b2d430
 
b2d430
+const char **fo_svc_server_list(TALLOC_CTX *mem_ctx,
b2d430
+                                struct fo_service *service,
b2d430
+                                size_t *_count);
b2d430
+
b2d430
 /*
b2d430
  * pvt will be talloc_stealed to ctx
b2d430
  */
b2d430
diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c
b2d430
index ff690ed6a7d5519979d242a4d5dadd08aff50347..977bbfcbe818f08873ce072d34fdcf900cabf52f 100644
b2d430
--- a/src/responder/ifp/ifp_domains.c
b2d430
+++ b/src/responder/ifp/ifp_domains.c
b2d430
@@ -582,3 +582,51 @@ int ifp_domains_domain_list_services(struct sbus_request *sbus_req,
b2d430
 
b2d430
     return EOK;
b2d430
 }
b2d430
+
b2d430
+int ifp_domains_domain_active_server(struct sbus_request *sbus_req,
b2d430
+                                     void *data,
b2d430
+                                     const char *service)
b2d430
+{
b2d430
+    struct ifp_ctx *ifp_ctx;
b2d430
+    struct sss_domain_info *dom;
b2d430
+
b2d430
+    ifp_ctx = talloc_get_type(data, struct ifp_ctx);
b2d430
+
b2d430
+    dom = get_domain_info_from_req(sbus_req, data);
b2d430
+    if (dom == NULL) {
b2d430
+        sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
b2d430
+                                 "Unknown domain");
b2d430
+        return EOK;
b2d430
+    }
b2d430
+
b2d430
+    rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH,
b2d430
+                               IFACE_DP_FAILOVER,
b2d430
+                               IFACE_DP_FAILOVER_ACTIVESERVER,
b2d430
+                               DBUS_TYPE_STRING, &service);
b2d430
+
b2d430
+    return EOK;
b2d430
+}
b2d430
+
b2d430
+int ifp_domains_domain_list_servers(struct sbus_request *sbus_req,
b2d430
+                                    void *data,
b2d430
+                                    const char *service)
b2d430
+{
b2d430
+    struct ifp_ctx *ifp_ctx;
b2d430
+    struct sss_domain_info *dom;
b2d430
+
b2d430
+    ifp_ctx = talloc_get_type(data, struct ifp_ctx);
b2d430
+
b2d430
+    dom = get_domain_info_from_req(sbus_req, data);
b2d430
+    if (dom == NULL) {
b2d430
+        sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
b2d430
+                                 "Unknown domain");
b2d430
+        return EOK;
b2d430
+    }
b2d430
+
b2d430
+    rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH,
b2d430
+                               IFACE_DP_FAILOVER,
b2d430
+                               IFACE_DP_FAILOVER_LISTSERVERS,
b2d430
+                               DBUS_TYPE_STRING, &service);
b2d430
+
b2d430
+    return EOK;
b2d430
+}
b2d430
diff --git a/src/responder/ifp/ifp_domains.h b/src/responder/ifp/ifp_domains.h
b2d430
index 91645e60701f8f75e89a42e93e2c066def67b018..621ba6158e285911cb8298cef212219dfd3afec8 100644
b2d430
--- a/src/responder/ifp/ifp_domains.h
b2d430
+++ b/src/responder/ifp/ifp_domains.h
b2d430
@@ -100,4 +100,12 @@ int ifp_domains_domain_is_online(struct sbus_request *sbus_req,
b2d430
 int ifp_domains_domain_list_services(struct sbus_request *sbus_req,
b2d430
                                      void *data);
b2d430
 
b2d430
+int ifp_domains_domain_active_server(struct sbus_request *sbus_req,
b2d430
+                                     void *data,
b2d430
+                                     const char *service);
b2d430
+
b2d430
+int ifp_domains_domain_list_servers(struct sbus_request *sbus_req,
b2d430
+                                    void *data,
b2d430
+                                    const char *service);
b2d430
+
b2d430
 #endif /* IFP_DOMAINS_H_ */
b2d430
diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c
b2d430
index 90bb52b2ccf5207034abbe12bddbfa1eeaf875f7..e6ddc687ba9db878ee39fee5868d1f924d58482d 100644
b2d430
--- a/src/responder/ifp/ifp_iface.c
b2d430
+++ b/src/responder/ifp/ifp_iface.c
b2d430
@@ -81,7 +81,9 @@ struct iface_ifp_domains iface_ifp_domains = {
b2d430
 struct iface_ifp_domains_domain iface_ifp_domains_domain = {
b2d430
     { &iface_ifp_domains_domain_meta, 0 },
b2d430
     .IsOnline = ifp_domains_domain_is_online,
b2d430
-    .ListServices = ifp_domains_domain_list_services
b2d430
+    .ListServices = ifp_domains_domain_list_services,
b2d430
+    .ActiveServer = ifp_domains_domain_active_server,
b2d430
+    .ListServers = ifp_domains_domain_list_servers
b2d430
 };
b2d430
 
b2d430
 struct iface_ifp_users iface_ifp_users = {
b2d430
diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml
b2d430
index 7f6f47299deeba4b1baa23d1e63ee7bb17304a59..25b104ad70c0fd84b6c0fe9dbb0dc6e6439c1376 100644
b2d430
--- a/src/responder/ifp/ifp_iface.xml
b2d430
+++ b/src/responder/ifp/ifp_iface.xml
b2d430
@@ -112,6 +112,16 @@
b2d430
         <method name="ListServices">
b2d430
             <arg name="services" type="as" direction="out" />
b2d430
         </method>
b2d430
+
b2d430
+        <method name="ActiveServer">
b2d430
+            <arg name="service" type="s" direction="in" />
b2d430
+            <arg name="server" type="s" direction="out" />
b2d430
+        </method>
b2d430
+
b2d430
+        <method name="ListServers">
b2d430
+            <arg name="service_name" type="s" direction="in" />
b2d430
+            <arg name="servers" type="as" direction="out" />
b2d430
+        </method>
b2d430
     </interface>
b2d430
 
b2d430
     <interface name="org.freedesktop.sssd.infopipe.Cache">
b2d430
diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c
b2d430
index 4d3bb5727b03ae64adad14fcdbb3eb5366edb406..6156ca2947434f301d206232f83cfc0647007707 100644
b2d430
--- a/src/responder/ifp/ifp_iface_generated.c
b2d430
+++ b/src/responder/ifp/ifp_iface_generated.c
b2d430
@@ -558,6 +558,44 @@ int iface_ifp_domains_domain_ListServices_finish(struct sbus_request *req, const
b2d430
                                          DBUS_TYPE_INVALID);
b2d430
 }
b2d430
 
b2d430
+/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ActiveServer */
b2d430
+const struct sbus_arg_meta iface_ifp_domains_domain_ActiveServer__in[] = {
b2d430
+    { "service", "s" },
b2d430
+    { NULL, }
b2d430
+};
b2d430
+
b2d430
+/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ActiveServer */
b2d430
+const struct sbus_arg_meta iface_ifp_domains_domain_ActiveServer__out[] = {
b2d430
+    { "server", "s" },
b2d430
+    { NULL, }
b2d430
+};
b2d430
+
b2d430
+int iface_ifp_domains_domain_ActiveServer_finish(struct sbus_request *req, const char *arg_server)
b2d430
+{
b2d430
+   return sbus_request_return_and_finish(req,
b2d430
+                                         DBUS_TYPE_STRING, &arg_server,
b2d430
+                                         DBUS_TYPE_INVALID);
b2d430
+}
b2d430
+
b2d430
+/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ListServers */
b2d430
+const struct sbus_arg_meta iface_ifp_domains_domain_ListServers__in[] = {
b2d430
+    { "service_name", "s" },
b2d430
+    { NULL, }
b2d430
+};
b2d430
+
b2d430
+/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ListServers */
b2d430
+const struct sbus_arg_meta iface_ifp_domains_domain_ListServers__out[] = {
b2d430
+    { "servers", "as" },
b2d430
+    { NULL, }
b2d430
+};
b2d430
+
b2d430
+int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers)
b2d430
+{
b2d430
+   return sbus_request_return_and_finish(req,
b2d430
+                                         DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &arg_servers, len_servers,
b2d430
+                                         DBUS_TYPE_INVALID);
b2d430
+}
b2d430
+
b2d430
 /* methods for org.freedesktop.sssd.infopipe.Domains.Domain */
b2d430
 const struct sbus_method_meta iface_ifp_domains_domain__methods[] = {
b2d430
     {
b2d430
@@ -574,6 +612,20 @@ const struct sbus_method_meta iface_ifp_domains_domain__methods[] = {
b2d430
         offsetof(struct iface_ifp_domains_domain, ListServices),
b2d430
         NULL, /* no invoker */
b2d430
     },
b2d430
+    {
b2d430
+        "ActiveServer", /* name */
b2d430
+        iface_ifp_domains_domain_ActiveServer__in,
b2d430
+        iface_ifp_domains_domain_ActiveServer__out,
b2d430
+        offsetof(struct iface_ifp_domains_domain, ActiveServer),
b2d430
+        invoke_s_method,
b2d430
+    },
b2d430
+    {
b2d430
+        "ListServers", /* name */
b2d430
+        iface_ifp_domains_domain_ListServers__in,
b2d430
+        iface_ifp_domains_domain_ListServers__out,
b2d430
+        offsetof(struct iface_ifp_domains_domain, ListServers),
b2d430
+        invoke_s_method,
b2d430
+    },
b2d430
     { NULL, }
b2d430
 };
b2d430
 
b2d430
diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h
b2d430
index 2eff57410e5292a05818050b96eb85aa3a4f2e16..141348249d2da5447fa04495564a8c6a55d67a1b 100644
b2d430
--- a/src/responder/ifp/ifp_iface_generated.h
b2d430
+++ b/src/responder/ifp/ifp_iface_generated.h
b2d430
@@ -58,6 +58,8 @@
b2d430
 #define IFACE_IFP_DOMAINS_DOMAIN "org.freedesktop.sssd.infopipe.Domains.Domain"
b2d430
 #define IFACE_IFP_DOMAINS_DOMAIN_ISONLINE "IsOnline"
b2d430
 #define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES "ListServices"
b2d430
+#define IFACE_IFP_DOMAINS_DOMAIN_ACTIVESERVER "ActiveServer"
b2d430
+#define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVERS "ListServers"
b2d430
 
b2d430
 /* constants for org.freedesktop.sssd.infopipe.Cache */
b2d430
 #define IFACE_IFP_CACHE "org.freedesktop.sssd.infopipe.Cache"
b2d430
@@ -215,6 +217,8 @@ struct iface_ifp_domains_domain {
b2d430
     struct sbus_vtable vtable; /* derive from sbus_vtable */
b2d430
     int (*IsOnline)(struct sbus_request *req, void *data);
b2d430
     int (*ListServices)(struct sbus_request *req, void *data);
b2d430
+    int (*ActiveServer)(struct sbus_request *req, void *data, const char *arg_service);
b2d430
+    int (*ListServers)(struct sbus_request *req, void *data, const char *arg_service_name);
b2d430
 };
b2d430
 
b2d430
 /* finish function for IsOnline */
b2d430
@@ -223,6 +227,12 @@ int iface_ifp_domains_domain_IsOnline_finish(struct sbus_request *req, bool arg_
b2d430
 /* finish function for ListServices */
b2d430
 int iface_ifp_domains_domain_ListServices_finish(struct sbus_request *req, const char *arg_services[], int len_services);
b2d430
 
b2d430
+/* finish function for ActiveServer */
b2d430
+int iface_ifp_domains_domain_ActiveServer_finish(struct sbus_request *req, const char *arg_server);
b2d430
+
b2d430
+/* finish function for ListServers */
b2d430
+int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers);
b2d430
+
b2d430
 /* vtable for org.freedesktop.sssd.infopipe.Cache */
b2d430
 struct iface_ifp_cache {
b2d430
     struct sbus_vtable vtable; /* derive from sbus_vtable */
b2d430
diff --git a/src/tools/sssctl/sssctl_domains.c b/src/tools/sssctl/sssctl_domains.c
b2d430
index 40962792b84eabeb2c142f158184b17180a01669..545ed95f4415da597b191146409ea6ba028f36f8 100644
b2d430
--- a/src/tools/sssctl/sssctl_domains.c
b2d430
+++ b/src/tools/sssctl/sssctl_domains.c
b2d430
@@ -112,6 +112,155 @@ done:
b2d430
     return ret;
b2d430
 }
b2d430
 
b2d430
+static const char *proper_service_name(const char *service)
b2d430
+{
b2d430
+    if (strcasecmp(service, "AD_GC") == 0) {
b2d430
+        return "AD Global Catalog";
b2d430
+    } else if (strcasecmp(service, "AD") == 0) {
b2d430
+        return "AD Domain Controller";
b2d430
+    } else if (strncasecmp(service, "sd_gc_", strlen("sd_gc_")) == 0) {
b2d430
+        return "AD Global Catalog";
b2d430
+    } else if (strncasecmp(service, "sd_", strlen("sd_")) == 0) {
b2d430
+        return "AD Domain Controller";
b2d430
+    }
b2d430
+
b2d430
+    return service;
b2d430
+}
b2d430
+
b2d430
+static errno_t sssctl_domain_status_active_server(struct sss_tool_ctx *tool_ctx,
b2d430
+                                                  sss_sifp_ctx *sifp,
b2d430
+                                                  const char *domain_path)
b2d430
+{
b2d430
+    TALLOC_CTX *tmp_ctx;
b2d430
+    sss_sifp_error error;
b2d430
+    DBusMessage *reply;
b2d430
+    const char *server;
b2d430
+    const char **services;
b2d430
+    int num_services;
b2d430
+    errno_t ret;
b2d430
+    int i;
b2d430
+
b2d430
+    tmp_ctx = talloc_new(NULL);
b2d430
+    if (tmp_ctx == NULL) {
b2d430
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
b2d430
+        return ENOMEM;
b2d430
+    }
b2d430
+
b2d430
+    error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path,
b2d430
+                             IFACE_IFP_DOMAINS_DOMAIN,
b2d430
+                             IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES);
b2d430
+    if (error != SSS_SIFP_OK) {
b2d430
+        sssctl_sifp_error(sifp, error, "Unable to list services");
b2d430
+        ret = EIO;
b2d430
+        goto done;
b2d430
+    }
b2d430
+
b2d430
+    ret = sbus_parse_reply(reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
b2d430
+                           &services, &num_services);
b2d430
+    if (ret != EOK) {
b2d430
+        goto done;
b2d430
+    }
b2d430
+
b2d430
+    printf(_("Active servers:\n"));
b2d430
+    for (i = 0; i < num_services; i++) {
b2d430
+        error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path,
b2d430
+                                 IFACE_IFP_DOMAINS_DOMAIN,
b2d430
+                                 IFACE_IFP_DOMAINS_DOMAIN_ACTIVESERVER,
b2d430
+                                 DBUS_TYPE_STRING, &services[i]);
b2d430
+        if (error != SSS_SIFP_OK) {
b2d430
+            sssctl_sifp_error(sifp, error, "Unable to get active server");
b2d430
+            ret = EIO;
b2d430
+            goto done;
b2d430
+        }
b2d430
+
b2d430
+        ret = sbus_parse_reply(reply, DBUS_TYPE_STRING, &server);
b2d430
+        if (ret != EOK) {
b2d430
+            goto done;
b2d430
+        }
b2d430
+
b2d430
+        server = SBUS_IS_STRING_EMPTY(server) ? _("not connected") : server;
b2d430
+        printf("%s: %s\n", proper_service_name(services[i]), server);
b2d430
+    }
b2d430
+
b2d430
+    ret = EOK;
b2d430
+
b2d430
+done:
b2d430
+    talloc_free(tmp_ctx);
b2d430
+    return ret;
b2d430
+}
b2d430
+
b2d430
+static errno_t sssctl_domain_status_server_list(struct sss_tool_ctx *tool_ctx,
b2d430
+                                                sss_sifp_ctx *sifp,
b2d430
+                                                const char *domain_path)
b2d430
+{
b2d430
+    TALLOC_CTX *tmp_ctx;
b2d430
+    sss_sifp_error error;
b2d430
+    DBusMessage *reply;
b2d430
+    const char **servers;
b2d430
+    int num_servers;
b2d430
+    const char **services;
b2d430
+    int num_services;
b2d430
+    errno_t ret;
b2d430
+    int i, j;
b2d430
+
b2d430
+    tmp_ctx = talloc_new(NULL);
b2d430
+    if (tmp_ctx == NULL) {
b2d430
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
b2d430
+        return ENOMEM;
b2d430
+    }
b2d430
+
b2d430
+    error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path,
b2d430
+                             IFACE_IFP_DOMAINS_DOMAIN,
b2d430
+                             IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES);
b2d430
+    if (error != SSS_SIFP_OK) {
b2d430
+        sssctl_sifp_error(sifp, error, "Unable to list services");
b2d430
+        ret = EIO;
b2d430
+        goto done;
b2d430
+    }
b2d430
+
b2d430
+    ret = sbus_parse_reply(reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
b2d430
+                           &services, &num_services);
b2d430
+    if (ret != EOK) {
b2d430
+        goto done;
b2d430
+    }
b2d430
+
b2d430
+    for (i = 0; i < num_services; i++) {
b2d430
+        printf(_("Discovered %s servers:\n"), proper_service_name(services[i]));
b2d430
+        error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path,
b2d430
+                                 IFACE_IFP_DOMAINS_DOMAIN,
b2d430
+                                 IFACE_IFP_DOMAINS_DOMAIN_LISTSERVERS,
b2d430
+                                 DBUS_TYPE_STRING, &services[i]);
b2d430
+        if (error != SSS_SIFP_OK) {
b2d430
+            sssctl_sifp_error(sifp, error, "Unable to get active server");
b2d430
+            ret = EIO;
b2d430
+            goto done;
b2d430
+        }
b2d430
+
b2d430
+        ret = sbus_parse_reply(reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
b2d430
+                               &servers, &num_servers);
b2d430
+        if (ret != EOK) {
b2d430
+            goto done;
b2d430
+        }
b2d430
+
b2d430
+        if (num_servers == 0) {
b2d430
+            puts(_("None so far.\n"));
b2d430
+            continue;
b2d430
+        }
b2d430
+
b2d430
+        for (j = 0; j < num_servers; j++) {
b2d430
+            printf("- %s\n", servers[j]);
b2d430
+        }
b2d430
+
b2d430
+        printf("\n");
b2d430
+    }
b2d430
+
b2d430
+    ret = EOK;
b2d430
+
b2d430
+done:
b2d430
+    talloc_free(tmp_ctx);
b2d430
+    return ret;
b2d430
+}
b2d430
+
b2d430
 struct sssctl_domain_status_opts {
b2d430
     const char *domain;
b2d430
     int online;
b2d430
@@ -135,11 +284,8 @@ errno_t sssctl_domain_status(struct sss_cmdline *cmdline,
b2d430
     /* Parse command line. */
b2d430
     struct poptOption options[] = {
b2d430
         {"online", 'o', POPT_ARG_NONE , &opts.online, 0, _("Show online status"), NULL },
b2d430
-        /*
b2d430
-        {"last-requests", 'l', POPT_ARG_NONE, &opts.last, 0, _("Show last requests that went to data provider"), NULL },
b2d430
         {"active-server", 'a', POPT_ARG_NONE, &opts.active, 0, _("Show information about active server"), NULL },
b2d430
         {"servers", 'r', POPT_ARG_NONE, &opts.servers, 0, _("Show list of discovered servers"), NULL },
b2d430
-        */
b2d430
         {"start", 's', POPT_ARG_NONE, &opts.force_start, 0, _("Start SSSD if it is not running"), NULL },
b2d430
         POPT_TABLEEND
b2d430
     };
b2d430
@@ -175,10 +321,32 @@ errno_t sssctl_domain_status(struct sss_cmdline *cmdline,
b2d430
         return EFAULT;
b2d430
     }
b2d430
 
b2d430
-    ret = sssctl_domain_status_online(tool_ctx, sifp, path);
b2d430
-    if (ret != EOK) {
b2d430
-        fprintf(stderr, _("Unable to get online status\n"));
b2d430
-        return ret;
b2d430
+    if (opts.online) {
b2d430
+        ret = sssctl_domain_status_online(tool_ctx, sifp, path);
b2d430
+        if (ret != EOK) {
b2d430
+            fprintf(stderr, _("Unable to get online status\n"));
b2d430
+            return ret;
b2d430
+        }
b2d430
+
b2d430
+        printf("\n");
b2d430
+    }
b2d430
+
b2d430
+    if (opts.active) {
b2d430
+        ret = sssctl_domain_status_active_server(tool_ctx, sifp, path);
b2d430
+        if (ret != EOK) {
b2d430
+            fprintf(stderr, _("Unable to get online status\n"));
b2d430
+            return ret;
b2d430
+        }
b2d430
+
b2d430
+        printf("\n");
b2d430
+    }
b2d430
+
b2d430
+    if (opts.servers) {
b2d430
+        ret = sssctl_domain_status_server_list(tool_ctx, sifp, path);
b2d430
+        if (ret != EOK) {
b2d430
+            fprintf(stderr, _("Unable to get server list\n"));
b2d430
+            return ret;
b2d430
+        }
b2d430
     }
b2d430
 
b2d430
     return EOK;
b2d430
-- 
b2d430
2.4.11
b2d430