From 674f16d154ca4a07ea317f06c9cc2694cf5154b8 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 16 Dec 2011 12:19:59 +0100
Subject: [PATCH 09/21] data provider: added subdomains

---
 src/confdb/confdb.h              |    1 +
 src/config/SSSDConfigTest.py     |    6 +-
 src/config/etc/sssd.api.conf     |    1 +
 src/man/sssd.conf.5.xml          |   24 ++++++
 src/providers/data_provider.h    |    2 -
 src/providers/data_provider_be.c |  160 ++++++++++++++++++++++++++++++++++++++
 src/providers/dp_backend.h       |    7 ++
 7 files changed, 197 insertions(+), 4 deletions(-)

diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 18f6c1fd7807f3b327a25648325fc95e9fa816d6..44b334e20593be1728842a9ec76ff64430099de5 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -124,6 +124,7 @@
 #define CONFDB_DOMAIN_AUTOFS_PROVIDER "autofs_provider"
 #define CONFDB_DOMAIN_SESSION_PROVIDER "session_provider"
 #define CONFDB_DOMAIN_HOSTID_PROVIDER "hostid_provider"
+#define CONFDB_DOMAIN_SUBDOMAINS_PROVIDER "subdomains_provider"
 #define CONFDB_DOMAIN_COMMAND "command"
 #define CONFDB_DOMAIN_TIMEOUT "timeout"
 #define CONFDB_DOMAIN_ATTR "cn"
diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
index 2d3cd8587034096704af95f15b5f33849357963e..06371da328751b62eb3d626cc9dbd279ca5a99f0 100755
--- a/src/config/SSSDConfigTest.py
+++ b/src/config/SSSDConfigTest.py
@@ -500,7 +500,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
             'sudo_provider',
             'autofs_provider',
             'session_provider',
-            'hostid_provider']
+            'hostid_provider',
+            'subdomains_provider']
 
         self.assertTrue(type(options) == dict,
                         "Options should be a dictionary")
@@ -827,7 +828,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
             'sudo_provider',
             'autofs_provider',
             'session_provider',
-            'hostid_provider']
+            'hostid_provider',
+            'subdomains_provider']
 
         self.assertTrue(type(options) == dict,
                         "Options should be a dictionary")
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index 65c0fcef878b37b98e2536f36280905ef91c60e8..17750ef9f7ea2d8015d5bb75c05dc0bd87ccb9a7 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -69,6 +69,7 @@ sudo_provider = str, None, false
 autofs_provider = str, None, false
 session_provider = str, None, false
 hostid_provider = str, None, false
+subdomains_provider = str, None, false
 
 [domain]
 # Options available to all domains
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 32966e8bc8648f2e694cc323d0efb9fe2e427877..f14d9a6f37d7d8d70fcc033ab1912094ab3b4cbb 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -1093,6 +1093,30 @@
                         </para>
                     </listitem>
                 </varlistentry>
+                <varlistentry>
+                    <term>subdomains_provider (string)</term>
+                    <listitem>
+                        <para>
+                            The provider which should handle fetching of subdomains.
+                            This value should be always the same as id_provider.
+                            Supported subdomain providers are:
+                        </para>
+                        <para>
+                            <quote>ipa</quote> to load a list of subdomains
+                            from an IPA server. See
+                            <citerefentry>
+                                <refentrytitle>sssd-ipa</refentrytitle>
+                                <manvolnum>5</manvolnum>
+                            </citerefentry> for more information on configuring IPA.
+                        </para>
+                        <para>
+                            <quote>none</quote> disallows fetching subdomains explicitly.
+                        </para>
+                        <para>
+                            Default: none
+                        </para>
+                    </listitem>
+                </varlistentry>
 
                 <varlistentry condition="with_autofs">
                     <term>autofs_provider (string)</term>
diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
index fb3ad041bbf8bf8f92cfd93719b8e927ec518bbb..b3e6bce7d2c28c231cacb251d6afc32781777141 100644
--- a/src/providers/data_provider.h
+++ b/src/providers/data_provider.h
@@ -120,8 +120,6 @@
  * @}
  */ /* end of group pamHandler */
 
-
-
 #define DP_ERR_OK 0
 #define DP_ERR_OFFLINE 1
 #define DP_ERR_TIMEOUT 2
diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
index 969c041185e72a00a2903b13921eb5f025a5a865..a3607236ca0b04ac44ee383d8faf3940e3c23bc4 100644
--- a/src/providers/data_provider_be.c
+++ b/src/providers/data_provider_be.c
@@ -84,6 +84,7 @@ static int be_pam_handler(DBusMessage *message, struct sbus_connection *conn);
 static int be_sudo_handler(DBusMessage *message, struct sbus_connection *conn);
 static int be_autofs_handler(DBusMessage *message, struct sbus_connection *conn);
 static int be_host_handler(DBusMessage *message, struct sbus_connection *conn);
+static int be_get_subdomains(DBusMessage *message, struct sbus_connection *conn);
 
 struct sbus_method be_methods[] = {
     { DP_METHOD_REGISTER, client_registration },
@@ -92,6 +93,7 @@ struct sbus_method be_methods[] = {
     { DP_METHOD_SUDOHANDLER, be_sudo_handler },
     { DP_METHOD_AUTOFSHANDLER, be_autofs_handler },
     { DP_METHOD_HOSTHANDLER, be_host_handler },
+    { DP_METHOD_GETDOMAINS, be_get_subdomains },
     { NULL, NULL }
 };
 
@@ -113,6 +115,7 @@ static struct bet_data bet_data[] = {
     {BET_AUTOFS, CONFDB_DOMAIN_AUTOFS_PROVIDER, "sssm_%s_autofs_init"},
     {BET_SESSION, CONFDB_DOMAIN_SESSION_PROVIDER, "sssm_%s_session_init"},
     {BET_HOSTID, CONFDB_DOMAIN_HOSTID_PROVIDER, "sssm_%s_hostid_init"},
+    {BET_SUBDOMAINS, CONFDB_DOMAIN_SUBDOMAINS_PROVIDER, "sssm_%s_subdomains_init"},
     {BET_MAX, NULL, NULL}
 };
 
@@ -305,6 +308,153 @@ static char *dp_pam_err_to_string(TALLOC_CTX *memctx, int dp_err_type, int errnu
     return NULL;
 }
 
+static void get_subdomains_callback(struct be_req *req,
+                                    int dp_err_type,
+                                    int errnum,
+                                    const char *errstr)
+{
+    DBusMessage *reply;
+    DBusConnection *dbus_conn;
+    dbus_bool_t dbret;
+
+    DEBUG(SSSDBG_TRACE_FUNC, ("Backend returned: (%d, %d, %s) [%s]\n",
+              dp_err_type, errnum, errstr?errstr:"<NULL>",
+              dp_pam_err_to_string(req, dp_err_type, errnum)));
+
+    reply = (DBusMessage *)req->pvt;
+    dbret = dbus_message_append_args(reply,
+                                     DBUS_TYPE_UINT32, &errnum,
+                                     DBUS_TYPE_INVALID);
+    if (!dbret) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to generate dbus reply\n"));
+        dbus_message_unref(reply);
+        return;
+    }
+
+    dbus_conn = sbus_get_connection(req->becli->conn);
+    if (dbus_conn == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("D-BUS not connected\n"));
+        return;
+    }
+    dbus_connection_send(dbus_conn, reply, NULL);
+    dbus_message_unref(reply);
+
+    talloc_free(req);
+}
+
+static int be_get_subdomains(DBusMessage *message, struct sbus_connection *conn)
+{
+    struct be_get_subdomains_req *req;
+    struct be_req *be_req = NULL;
+    struct be_client *becli;
+    DBusMessage *reply;
+    DBusError dbus_error;
+    dbus_bool_t dbret;
+    void *user_data;
+    bool force;
+    char *domain_hint;
+    dbus_uint32_t status;
+    int ret;
+
+    user_data = sbus_conn_get_private_data(conn);
+    if (!user_data) return EINVAL;
+    becli = talloc_get_type(user_data, struct be_client);
+    if (!becli) return EINVAL;
+
+    dbus_error_init(&dbus_error);
+
+    ret = dbus_message_get_args(message, &dbus_error,
+                                DBUS_TYPE_BOOLEAN, &force,
+                                DBUS_TYPE_STRING, &domain_hint,
+                                DBUS_TYPE_INVALID);
+    if (!ret) {
+        DEBUG(SSSDBG_CRIT_FAILURE,("Failed, to parse message!\n"));
+        if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
+        return EIO;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, ("Got get subdomains [%sforced][%s]\n", force ? "" : "not ",
+              domain_hint == NULL ? "no hint": domain_hint ));
+
+    reply = dbus_message_new_method_return(message);
+    if (!reply) return ENOMEM;
+
+    /* If we are offline return immediately
+     */
+    if (becli->bectx->offstat.offline) {
+        DEBUG(SSSDBG_TRACE_FUNC, ("Cannot proceed, provider is offline.\n"));
+        status = EAGAIN;
+        goto done;
+    }
+
+    /* process request */
+    be_req = talloc_zero(becli, struct be_req);
+    if (!be_req) {
+        status = ENOMEM;
+        goto done;
+    }
+    be_req->becli = becli;
+    be_req->be_ctx = becli->bectx;
+    be_req->fn = get_subdomains_callback;
+    be_req->pvt = reply;
+
+    req = talloc(be_req, struct be_get_subdomains_req);
+    if (!req) {
+        status = ENOMEM;
+        goto done;
+    }
+    req->force = force;
+    req->domain_hint = talloc_strdup(req, domain_hint);
+    req->domain_list = NULL;
+    if (!req->domain_hint) {
+        status = ENOMEM;
+        goto done;
+    }
+
+    be_req->req_data = req;
+
+    /* return an error if corresponding backend target is not configured */
+    if (becli->bectx->bet_info[BET_SUBDOMAINS].bet_ops == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Undefined backend target.\n"));
+        ret = ENODEV;
+        goto done;
+    }
+
+
+    ret = be_file_request(becli->bectx,
+                          be_req,
+                          becli->bectx->bet_info[BET_SUBDOMAINS].bet_ops->handler);
+    if (ret != EOK) {
+        status = ret;
+        goto done;
+    }
+
+    return EOK;
+
+done:
+    if (be_req) {
+        talloc_free(be_req);
+    }
+
+    if (reply) {
+        dbret = dbus_message_append_args(reply,
+                                         DBUS_TYPE_UINT32, &status,
+                                         DBUS_TYPE_INVALID);
+        if (!dbret) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to generate dbus reply\n"));
+            dbus_message_unref(reply);
+            return EIO;
+        }
+
+        DEBUG(SSSDBG_TRACE_FUNC, ("Request processed. Returned [%d]\n", status));
+
+        /* send reply back */
+        sbus_conn_send_reply(conn, reply);
+        dbus_message_unref(reply);
+    }
+
+    return EOK;
+}
 
 static void acctinfo_callback(struct be_req *req,
                               int dp_err_type,
@@ -2000,6 +2150,16 @@ int be_process_init(TALLOC_CTX *mem_ctx,
                ctx->bet_info[BET_HOSTID].mod_name));
     }
 
+    ret = load_backend_module(ctx, BET_SUBDOMAINS,
+                              &ctx->bet_info[BET_SUBDOMAINS], NULL);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Subdomains are not supported for [%s] !!\n", be_domain));
+    } else {
+        DEBUG(SSSDBG_TRACE_ALL, ("Get-Subdomains backend target successfully loaded "
+                  "from provider [%s].\n",
+                  ctx->bet_info[BET_SUBDOMAINS].mod_name));
+    }
+
     /* Handle SIGUSR1 to force offline behavior */
     BlockSignals(false, SIGUSR1);
     tes = tevent_add_signal(ctx->ev, ctx, SIGUSR1, 0,
diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
index 6e98e7ef3c9370f0cbf93a8f344641b2642bd9a8..76b0e43dce0ed6c0490d6e1ff5cbaf92e8d62be4 100644
--- a/src/providers/dp_backend.h
+++ b/src/providers/dp_backend.h
@@ -53,6 +53,7 @@ enum bet_type {
     BET_AUTOFS,
     BET_SESSION,
     BET_HOSTID,
+    BET_SUBDOMAINS,
     BET_MAX
 };
 
@@ -162,6 +163,12 @@ struct be_autofs_req {
     char *mapname;
 };
 
+struct be_get_subdomains_req {
+    bool force;
+    char *domain_hint;
+    struct subdomain_info **domain_list;
+};
+
 bool be_is_offline(struct be_ctx *ctx);
 void be_mark_offline(struct be_ctx *ctx);
 
-- 
1.7.10

