Blob Blame History Raw
From 1bed72e4faa2734b0eef6a107b2dc24bf052e576 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Mon, 30 Oct 2017 20:50:41 +0100
Subject: [PATCH 73/83] DP: Create a new handler function getAccountDomain()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Adds a new method getAccountDomain() which is a bit similar to
getAccountInfo, except it doesn't fetch, parse and store the entry, but
just returns the domain or a subdomain the entry was found in.

At the moment, the method only supports requests by ID.

A default handler is provided (and in this patch used by all the
domains) which returns ERR_GET_ACCT_DOM_NOT_SUPPORTED. This return
code should be evaluated by the responder so that this DP method is
not called again, because it's not supported by the back end type.

Reviewed-by: Pavel Březina <pbrezina@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
(cherry picked from commit c0f9f5a0f6d71a1596ee3cef549b4b02295313c3)
---
 src/providers/ad/ad_init.c                       |   4 +
 src/providers/data_provider/dp.h                 |  20 ++++
 src/providers/data_provider/dp_custom_data.h     |   6 ++
 src/providers/data_provider/dp_iface.c           |   3 +-
 src/providers/data_provider/dp_iface.h           |  17 ++++
 src/providers/data_provider/dp_iface.xml         |   7 ++
 src/providers/data_provider/dp_iface_generated.c |  31 +++++++
 src/providers/data_provider/dp_iface_generated.h |   5 +
 src/providers/data_provider/dp_target_id.c       | 113 +++++++++++++++++++++++
 src/providers/files/files_init.c                 |   6 ++
 src/providers/ipa/ipa_init.c                     |   4 +
 src/providers/ldap/ldap_init.c                   |   4 +
 src/providers/proxy/proxy_init.c                 |   4 +
 src/util/util_errors.c                           |   1 +
 src/util/util_errors.h                           |   1 +
 15 files changed, 225 insertions(+), 1 deletion(-)

diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index e62025d4acd24844a5c7082d00c597516f35de16..7efb6aa71cbd2551422c87e0b0c5c1fe91390375 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -510,6 +510,10 @@ errno_t sssm_ad_id_init(TALLOC_CTX *mem_ctx,
                   sdap_online_check_handler_send, sdap_online_check_handler_recv, id_ctx->sdap_id_ctx,
                   struct sdap_id_ctx, void, struct dp_reply_std);
 
+    dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER,
+                  default_account_domain_send, default_account_domain_recv, NULL,
+                  void, struct dp_get_acct_domain_data, struct dp_reply_std);
+
     return EOK;
 }
 
diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h
index aa5b781158c54545b26034602bb25db46b189e87..ceb49da53b88142924e1792c6f64a22ec369677b 100644
--- a/src/providers/data_provider/dp.h
+++ b/src/providers/data_provider/dp.h
@@ -82,6 +82,7 @@ enum dp_methods {
     DPM_HOSTID_HANDLER,
     DPM_DOMAINS_HANDLER,
     DPM_SESSION_HANDLER,
+    DPM_ACCT_DOMAIN_HANDLER,
 
     DPM_REFRESH_ACCESS_RULES,
 
@@ -179,4 +180,23 @@ void dp_sbus_reset_users_memcache(struct data_provider *provider);
 void dp_sbus_reset_groups_memcache(struct data_provider *provider);
 void dp_sbus_reset_initgr_memcache(struct data_provider *provider);
 
+/*
+ * A dummy handler for DPM_ACCT_DOMAIN_HANDLER.
+ *
+ * Its purpose is to always return ERR_GET_ACCT_DOM_NOT_SUPPORTED
+ * which the responder should evaluate as "this back end does not
+ * support locating entries' domain" and never call
+ * DPM_ACCT_DOMAIN_HANDLER again
+ *
+ * This request cannot fail, except for critical errors like OOM.
+ */
+struct tevent_req *
+default_account_domain_send(TALLOC_CTX *mem_ctx,
+                            void *unused_ctx,
+                            struct dp_get_acct_domain_data *data,
+                            struct dp_req_params *params);
+errno_t default_account_domain_recv(TALLOC_CTX *mem_ctx,
+                                    struct tevent_req *req,
+                                    struct dp_reply_std *data);
+
 #endif /* _DP_H_ */
diff --git a/src/providers/data_provider/dp_custom_data.h b/src/providers/data_provider/dp_custom_data.h
index d9de288b62f4f6763ceb205dc596876cfc58bf6c..7c64bde4513961e79200e852c7277f77e064d5a3 100644
--- a/src/providers/data_provider/dp_custom_data.h
+++ b/src/providers/data_provider/dp_custom_data.h
@@ -43,6 +43,12 @@ struct dp_subdomains_data {
     const char *domain_hint;
 };
 
+struct dp_get_acct_domain_data {
+    uint32_t entry_type;
+    uint32_t filter_type;
+    const char *filter_value;
+};
+
 struct dp_id_data {
     uint32_t entry_type;
     uint32_t filter_type;
diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c
index 28d70e686f63a3572ac595f493aa1d59436c563f..124be0048f38a93d06561ff7b0d1916838587103 100644
--- a/src/providers/data_provider/dp_iface.c
+++ b/src/providers/data_provider/dp_iface.c
@@ -33,7 +33,8 @@ struct iface_dp iface_dp = {
     .autofsHandler = dp_autofs_handler,
     .hostHandler = dp_host_handler,
     .getDomains = dp_subdomains_handler,
-    .getAccountInfo = dp_get_account_info_handler
+    .getAccountInfo = dp_get_account_info_handler,
+    .getAccountDomain = dp_get_account_domain_handler,
 };
 
 struct iface_dp_backend iface_dp_backend = {
diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h
index 759b9e6c9eb7f53836ae0b641b34e6c31e65779f..0a2f81eb5c108aa7596c974157b0dfafb041869f 100644
--- a/src/providers/data_provider/dp_iface.h
+++ b/src/providers/data_provider/dp_iface.h
@@ -58,6 +58,23 @@ errno_t dp_subdomains_handler(struct sbus_request *sbus_req,
                               void *dp_cli,
                               const char *domain_hint);
 
+/*
+ * Return a domain the account belongs to.
+ *
+ * The request uses the dp_reply_std structure for reply, with the following
+ * semantics:
+ *  - DP_ERR_OK - it is expected that the string message contains the domain name
+ *                the entry was found in. A 'negative' reply where the
+ *                request returns DP_ERR_OK, but no domain should be treated
+ *                as authoritative, as if the entry does not exist.
+ *  - DP_ERR_*  - the string message contains error string that corresponds
+ *                to the errno field in dp_reply_std().
+ */
+errno_t dp_get_account_domain_handler(struct sbus_request *sbus_req,
+                                      void *dp_cli,
+                                      uint32_t entry_type,
+                                      const char *filter);
+
 /* org.freedesktop.sssd.DataProvider.Backend */
 errno_t dp_backend_is_online(struct sbus_request *sbus_req,
                              void *dp_cli,
diff --git a/src/providers/data_provider/dp_iface.xml b/src/providers/data_provider/dp_iface.xml
index 2bfa9dfa7e9d02d2d12c3358967f6969438a97a2..c2431850bca4baa529fb18e0480e781308b12dd6 100644
--- a/src/providers/data_provider/dp_iface.xml
+++ b/src/providers/data_provider/dp_iface.xml
@@ -79,5 +79,12 @@
             <arg name="error" type="u" direction="out" />
             <arg name="error_message" type="s" direction="out" />
         </method>
+        <method name="getAccountDomain">
+            <arg name="entry_type" type="u" direction="in" />
+            <arg name="filter" type="s" direction="in" />
+            <arg name="dp_error" type="q" direction="out" />
+            <arg name="error" type="u" direction="out" />
+            <arg name="domain_name" type="s" direction="out" />
+        </method>
     </interface>
 </node>
diff --git a/src/providers/data_provider/dp_iface_generated.c b/src/providers/data_provider/dp_iface_generated.c
index 11ee2e24a69cc8d4d19fdbeed613e76081aef15d..4d093444536b15d8a17f7e507b93948e1df6ffee 100644
--- a/src/providers/data_provider/dp_iface_generated.c
+++ b/src/providers/data_provider/dp_iface_generated.c
@@ -313,6 +313,30 @@ int iface_dp_getAccountInfo_finish(struct sbus_request *req, uint16_t arg_dp_err
                                          DBUS_TYPE_INVALID);
 }
 
+/* arguments for org.freedesktop.sssd.dataprovider.getAccountDomain */
+const struct sbus_arg_meta iface_dp_getAccountDomain__in[] = {
+    { "entry_type", "u" },
+    { "filter", "s" },
+    { NULL, }
+};
+
+/* arguments for org.freedesktop.sssd.dataprovider.getAccountDomain */
+const struct sbus_arg_meta iface_dp_getAccountDomain__out[] = {
+    { "dp_error", "q" },
+    { "error", "u" },
+    { "domain_name", "s" },
+    { NULL, }
+};
+
+int iface_dp_getAccountDomain_finish(struct sbus_request *req, uint16_t arg_dp_error, uint32_t arg_error, const char *arg_domain_name)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_UINT16, &arg_dp_error,
+                                         DBUS_TYPE_UINT32, &arg_error,
+                                         DBUS_TYPE_STRING, &arg_domain_name,
+                                         DBUS_TYPE_INVALID);
+}
+
 /* methods for org.freedesktop.sssd.dataprovider */
 const struct sbus_method_meta iface_dp__methods[] = {
     {
@@ -357,6 +381,13 @@ const struct sbus_method_meta iface_dp__methods[] = {
         offsetof(struct iface_dp, getAccountInfo),
         invoke_uusss_method,
     },
+    {
+        "getAccountDomain", /* name */
+        iface_dp_getAccountDomain__in,
+        iface_dp_getAccountDomain__out,
+        offsetof(struct iface_dp, getAccountDomain),
+        invoke_us_method,
+    },
     { NULL, }
 };
 
diff --git a/src/providers/data_provider/dp_iface_generated.h b/src/providers/data_provider/dp_iface_generated.h
index 541a90b0b5a5bc0a346cbd04974d33c8bb0983c5..b629ec77487328a41615f3ca7e812088730f40c4 100644
--- a/src/providers/data_provider/dp_iface_generated.h
+++ b/src/providers/data_provider/dp_iface_generated.h
@@ -38,6 +38,7 @@
 #define IFACE_DP_HOSTHANDLER "hostHandler"
 #define IFACE_DP_GETDOMAINS "getDomains"
 #define IFACE_DP_GETACCOUNTINFO "getAccountInfo"
+#define IFACE_DP_GETACCOUNTDOMAIN "getAccountDomain"
 
 /* ------------------------------------------------------------------------
  * DBus handlers
@@ -110,6 +111,7 @@ struct iface_dp {
     int (*hostHandler)(struct sbus_request *req, void *data, uint32_t arg_dp_flags, const char *arg_name, const char *arg_alias);
     int (*getDomains)(struct sbus_request *req, void *data, const char *arg_domain_hint);
     int (*getAccountInfo)(struct sbus_request *req, void *data, uint32_t arg_dp_flags, uint32_t arg_entry_type, const char *arg_filter, const char *arg_domain, const char *arg_extra);
+    int (*getAccountDomain)(struct sbus_request *req, void *data, uint32_t arg_entry_type, const char *arg_filter);
 };
 
 /* finish function for autofsHandler */
@@ -124,6 +126,9 @@ int iface_dp_getDomains_finish(struct sbus_request *req, uint16_t arg_dp_error,
 /* finish function for getAccountInfo */
 int iface_dp_getAccountInfo_finish(struct sbus_request *req, uint16_t arg_dp_error, uint32_t arg_error, const char *arg_error_message);
 
+/* finish function for getAccountDomain */
+int iface_dp_getAccountDomain_finish(struct sbus_request *req, uint16_t arg_dp_error, uint32_t arg_error, const char *arg_domain_name);
+
 /* ------------------------------------------------------------------------
  * DBus Interface Metadata
  *
diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c
index 820a6574cb3a224cce4b7d8286af306f234454a3..11a36e9ce9b1aefcabb04dfe51395b6f4e4bc899 100644
--- a/src/providers/data_provider/dp_target_id.c
+++ b/src/providers/data_provider/dp_target_id.c
@@ -490,3 +490,116 @@ done:
 
     return ret;
 }
+
+static bool
+check_and_parse_acct_domain_filter(struct dp_get_acct_domain_data *data,
+                                   const char *filter)
+{
+    /* We will use sizeof() to determine the length of a string so we don't
+     * call strlen over and over again with each request. Not a bottleneck,
+     * but unnecessary and simple to avoid. */
+    static struct {
+        const char *name;
+        size_t lenght;
+        uint32_t type;
+    } types[] = {FILTER_TYPE("idnumber", BE_FILTER_IDNUM),
+                 {0, 0, 0}};
+    int i;
+
+    if (SBUS_IS_STRING_EMPTY(filter)) {
+        return false;
+    }
+
+    for (i = 0; types[i].name != NULL; i++) {
+        if (strncmp(filter, types[i].name, types[i].lenght) == 0) {
+            data->filter_type = types[i].type;
+            data->filter_value = SBUS_SET_STRING(&filter[types[i].lenght]);
+            return true;
+        }
+    }
+
+    if (strcmp(filter, ENUM_INDICATOR) == 0) {
+        data->filter_type = BE_FILTER_ENUM;
+        data->filter_value = NULL;
+        return true;
+    }
+
+    return false;
+}
+
+errno_t dp_get_account_domain_handler(struct sbus_request *sbus_req,
+                                      void *dp_cli,
+                                      uint32_t entry_type,
+                                      const char *filter)
+{
+    struct dp_get_acct_domain_data *data;
+    const char *key = NULL;
+    errno_t ret;
+
+    data = talloc_zero(sbus_req, struct dp_get_acct_domain_data);
+    if (data == NULL) {
+        return ENOMEM;
+    }
+    data->entry_type = entry_type;
+
+    if (!check_and_parse_acct_domain_filter(data, filter)) {
+        ret = EINVAL;
+        goto done;
+    }
+
+    dp_req_with_reply(dp_cli, NULL, "AccountDomain", key, sbus_req,
+                      DPT_ID, DPM_ACCT_DOMAIN_HANDLER, 0, data,
+                      dp_req_reply_std, struct dp_reply_std);
+
+    ret = EOK;
+
+done:
+    if (ret != EOK) {
+        talloc_free(data);
+    }
+
+    return ret;
+}
+
+struct default_account_domain_state {
+    struct dp_reply_std reply;
+};
+
+struct tevent_req *
+default_account_domain_send(TALLOC_CTX *mem_ctx,
+                            void *unused_ctx,
+                            struct dp_get_acct_domain_data *data,
+                            struct dp_req_params *params)
+{
+    struct default_account_domain_state *state;
+    struct tevent_req *req;
+
+    req = tevent_req_create(mem_ctx, &state,
+                            struct default_account_domain_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+        return NULL;
+    }
+
+    dp_reply_std_set(&state->reply,
+                     DP_ERR_DECIDE, ERR_GET_ACCT_DOM_NOT_SUPPORTED,
+                     NULL);
+    tevent_req_done(req);
+    tevent_req_post(req, params->ev);
+    return req;
+}
+
+errno_t default_account_domain_recv(TALLOC_CTX *mem_ctx,
+                                    struct tevent_req *req,
+                                    struct dp_reply_std *data)
+{
+    struct default_account_domain_state *state = NULL;
+
+    state = tevent_req_data(req, struct default_account_domain_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *data = state->reply;
+
+    return EOK;
+}
diff --git a/src/providers/files/files_init.c b/src/providers/files/files_init.c
index b91dfbac9bf9d4b678ebdfa6b1cb0971b4477dd9..8e5cd4cf913b79653616120d6ed6540e62ade932 100644
--- a/src/providers/files/files_init.c
+++ b/src/providers/files/files_init.c
@@ -88,5 +88,11 @@ int sssm_files_id_init(TALLOC_CTX *mem_ctx,
                   ctx, struct files_id_ctx,
                   struct dp_id_data, struct dp_reply_std);
 
+    dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER,
+                  default_account_domain_send,
+                  default_account_domain_recv,
+                  NULL, void,
+                  struct dp_get_acct_domain_data, struct dp_reply_std);
+
     return EOK;
 }
diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
index f335d51fd65959d256c54a5d92c594a24e895b7c..754e5315c3a7f84ac2901986ecdda73e4dad26bc 100644
--- a/src/providers/ipa/ipa_init.c
+++ b/src/providers/ipa/ipa_init.c
@@ -754,6 +754,10 @@ errno_t sssm_ipa_id_init(TALLOC_CTX *mem_ctx,
                   sdap_online_check_handler_send, sdap_online_check_handler_recv, id_ctx->sdap_id_ctx,
                   struct sdap_id_ctx, void, struct dp_reply_std);
 
+    dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER,
+                  default_account_domain_send, default_account_domain_recv, NULL,
+                  void, struct dp_get_acct_domain_data, struct dp_reply_std);
+
     return EOK;
 }
 
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
index 43d905893081c31ed659fd1ef8343f965bdc5af0..c0ede8941ee8480c2ec4765f89d12e903edcf012 100644
--- a/src/providers/ldap/ldap_init.c
+++ b/src/providers/ldap/ldap_init.c
@@ -531,6 +531,10 @@ errno_t sssm_ldap_id_init(TALLOC_CTX *mem_ctx,
                   sdap_online_check_handler_send, sdap_online_check_handler_recv, id_ctx,
                   struct sdap_id_ctx, void, struct dp_reply_std);
 
+    dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER,
+                  default_account_domain_send, default_account_domain_recv, NULL,
+                  void, struct dp_get_acct_domain_data, struct dp_reply_std);
+
     return EOK;
 }
 
diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
index 7c9d3dafbdf1f9448cc8f8b473aea15cf4206afc..7d997cb16ee62f10f4b86c9c3ab373a48676fe75 100644
--- a/src/providers/proxy/proxy_init.c
+++ b/src/providers/proxy/proxy_init.c
@@ -351,6 +351,10 @@ errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx,
                   proxy_account_info_handler_send, proxy_account_info_handler_recv, ctx,
                   struct proxy_id_ctx, struct dp_id_data, struct dp_reply_std);
 
+    dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER,
+                  default_account_domain_send, default_account_domain_recv, NULL,
+                  void, struct dp_get_acct_domain_data, struct dp_reply_std);
+
     ret = EOK;
 
 done:
diff --git a/src/util/util_errors.c b/src/util/util_errors.c
index 5a92a2dcf6e65f93bc9732cebf562756357123b6..9a9ba3f3063cab4afb538c3a58527a2d2ed3fffd 100644
--- a/src/util/util_errors.c
+++ b/src/util/util_errors.c
@@ -115,6 +115,7 @@ struct err_string error_to_str[] = {
     { "Unable to initialize SSL" }, /* ERR_SSL_FAILURE */
     { "Unable to verify peer" }, /* ERR_UNABLE_TO_VERIFY_PEER */
     { "Unable to resolve host" }, /* ERR_UNABLE_TO_RESOLVE_HOST */
+    { "GetAccountDomain() not supported" }, /* ERR_GET_ACCT_DOM_NOT_SUPPORTED */
     { "ERR_LAST" } /* ERR_LAST */
 };
 
diff --git a/src/util/util_errors.h b/src/util/util_errors.h
index 509ccb805fb97e59f9da0ea2f991ece2f2030ca4..5ee9862c3f2f60c078693b1b85a40f15436e818c 100644
--- a/src/util/util_errors.h
+++ b/src/util/util_errors.h
@@ -137,6 +137,7 @@ enum sssd_errors {
     ERR_SSL_FAILURE,
     ERR_UNABLE_TO_VERIFY_PEER,
     ERR_UNABLE_TO_RESOLVE_HOST,
+    ERR_GET_ACCT_DOM_NOT_SUPPORTED,
     ERR_LAST            /* ALWAYS LAST */
 };
 
-- 
2.14.3