Blob Blame History Raw
From af96fbe97576133ca6077c47f39b812e7e289040 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Sun, 12 Mar 2017 18:31:03 +0100
Subject: [PATCH 07/15] sdap_get_users_send(): new argument mapped_attrs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

mapped_attrs can be a list of sysdb_attrs which are not available on
the server side but should be store with the cached user entry. This is
needed e.g. when the input to look up the user in LDAP is not an
attribute which is stored in LDAP but some data where LDAP attributes
are extracted from. The current use case is the certificate mapping
library which can create LDAP search filters based on content of the
certificate. To allow upcoming cache lookup to use the input directly it
is stored in the user object in the cache.

Related to https://pagure.io/SSSD/sssd/issue/3050

Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
---
 src/db/sysdb.h                             |  3 ++
 src/db/sysdb_ops.c                         | 61 ++++++++++++++++++++++++++++++
 src/providers/ldap/ldap_id.c               |  4 +-
 src/providers/ldap/sdap_async.h            |  3 +-
 src/providers/ldap/sdap_async_enum.c       |  2 +-
 src/providers/ldap/sdap_async_initgroups.c |  2 +-
 src/providers/ldap/sdap_async_private.h    |  1 +
 src/providers/ldap/sdap_async_users.c      | 41 +++++++++++++++++++-
 src/providers/ldap/sdap_users.h            |  1 +
 9 files changed, 111 insertions(+), 7 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index c677957bb639e40db2f985205160612094302e78..098f47f91187aac75c58c02f0af738c344765762 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -1246,6 +1246,9 @@ errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx,
 errno_t sysdb_remove_cert(struct sss_domain_info *domain,
                           const char *cert);
 
+errno_t sysdb_remove_mapped_data(struct sss_domain_info *domain,
+                                 struct sysdb_attrs *mapped_attr);
+
 /* === Functions related to GPOs === */
 
 #define SYSDB_GPO_CONTAINER "cn=gpos,cn=ad,cn=custom"
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index 242d3ce3bb795691e329790a07c3493672e8f523..6c2254df2b75d3d3419528523103ad9cddb40c9d 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -4685,6 +4685,67 @@ errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx,
     return sysdb_search_object_by_cert(mem_ctx, domain, cert, user_attrs, res);
 }
 
+errno_t sysdb_remove_mapped_data(struct sss_domain_info *domain,
+                                 struct sysdb_attrs *mapped_attr)
+{
+    int ret;
+    char *val;
+    char *filter;
+    const char *attrs[] = {SYSDB_NAME, NULL};
+    struct ldb_result *res = NULL;
+    size_t c;
+    bool all_ok = true;
+
+    if (mapped_attr->num != 1 || mapped_attr->a[0].num_values != 1) {
+        DEBUG(SSSDBG_OP_FAILURE, "Unsupported number of attributes.\n");
+        return EINVAL;
+    }
+
+    ret = bin_to_ldap_filter_value(NULL, mapped_attr->a[0].values[0].data,
+                                   mapped_attr->a[0].values[0].length, &val);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "bin_to_ldap_filter_value failed.\n");
+        return ret;
+    }
+
+    filter = talloc_asprintf(NULL, "(&("SYSDB_UC")(%s=%s))",
+                             mapped_attr->a[0].name, val);
+    talloc_free(val);
+    if (filter == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+        return ENOMEM;
+    }
+
+    ret = sysdb_search_object_attr(NULL, domain, filter, attrs, false, &res);
+    talloc_free(filter);
+    if (ret == ENOENT || res == NULL) {
+        DEBUG(SSSDBG_TRACE_ALL, "Mapped data not found.\n");
+        talloc_free(res);
+        return EOK;
+    } else if (ret != EOK) {
+        talloc_free(res);
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_object_attr failed.\n");
+        return ret;
+    }
+
+    for (c = 0; c < res->count; c++) {
+        DEBUG(SSSDBG_TRACE_ALL, "Removing mapped data from [%s].\n",
+                                ldb_dn_get_linearized(res->msgs[c]->dn));
+        /* The timestamp cache is skipped on purpose here. */
+        ret = sysdb_set_cache_entry_attr(domain->sysdb->ldb, res->msgs[c]->dn,
+                                         mapped_attr, SYSDB_MOD_DEL);
+        if (ret != EOK) {
+            all_ok = false;
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "Failed to remove mapped data from [%s], skipping.\n",
+                  ldb_dn_get_linearized(res->msgs[c]->dn));
+        }
+    }
+    talloc_free(res);
+
+    return (all_ok ? EOK : EIO);
+}
+
 errno_t sysdb_remove_cert(struct sss_domain_info *domain,
                           const char *cert)
 {
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index e9455b538daa2d65d944dbb68022a2773623d7b7..898ddb18689d55fcc3fdf021b38df0e574003eb2 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -442,7 +442,7 @@ static void users_get_search(struct tevent_req *req)
                                  state->attrs, state->filter,
                                  dp_opt_get_int(state->ctx->opts->basic,
                                                 SDAP_SEARCH_TIMEOUT),
-                                 lookup_type);
+                                 lookup_type, NULL);
     if (!subreq) {
         tevent_req_error(req, ENOMEM);
         return;
@@ -507,7 +507,7 @@ static void users_get_done(struct tevent_req *subreq)
             ret = sdap_fallback_local_user(state, state->shortname, uid, &usr_attrs);
             if (ret == EOK) {
                 ret = sdap_save_user(state, state->ctx->opts, state->domain,
-                                     usr_attrs[0], NULL, 0);
+                                     usr_attrs[0], NULL, NULL, 0);
             }
         }
     }
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 2ebde6b83646408e446c91cb324809cb767b2617..6e5800b42ba4a045fa7985b09a80b6b86b8c6055 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -90,7 +90,8 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
                                        const char **attrs,
                                        const char *filter,
                                        int timeout,
-                                       enum sdap_entry_lookup_type lookup_type);
+                                       enum sdap_entry_lookup_type lookup_type,
+                                       struct sysdb_attrs *mapped_attrs);
 int sdap_get_users_recv(struct tevent_req *req,
                         TALLOC_CTX *mem_ctx, char **timestamp);
 
diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index 387e53155b567ce106cc68009c7cb99e27d24a17..3f65059e18d5c8b548da0babec867d27c3a64198 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -635,7 +635,7 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
                                  state->attrs, state->filter,
                                  dp_opt_get_int(state->ctx->opts->basic,
                                                 SDAP_ENUM_SEARCH_TIMEOUT),
-                                 SDAP_LOOKUP_ENUMERATE);
+                                 SDAP_LOOKUP_ENUMERATE, NULL);
     if (!subreq) {
         ret = ENOMEM;
         goto fail;
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
index 8c7a65bf36abf341e077cf9eac18a234d3a07c07..79af7a3eda3fe8533933535c98c2b4b4698dfda2 100644
--- a/src/providers/ldap/sdap_async_initgroups.c
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -2991,7 +2991,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
     DEBUG(SSSDBG_TRACE_ALL, "Storing the user\n");
 
     ret = sdap_save_user(state, state->opts, state->dom, state->orig_user,
-                         NULL, 0);
+                         NULL, NULL, 0);
     if (ret) {
         goto fail;
     }
diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h
index 266bc03115e2bdd6a283f5f7da565fd00d3a77be..72507442a9ffd5c0e24ccbd95d75d3ebf9bf0940 100644
--- a/src/providers/ldap/sdap_async_private.h
+++ b/src/providers/ldap/sdap_async_private.h
@@ -94,6 +94,7 @@ int sdap_save_users(TALLOC_CTX *memctx,
                     struct sdap_options *opts,
                     struct sysdb_attrs **users,
                     int num_users,
+                    struct sysdb_attrs *mapped_attrs,
                     char **_usn_value);
 
 int sdap_initgr_common_store(struct sysdb_ctx *sysdb,
diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
index 87d91d8247c37a4c6a1d83b7189399056528fc90..3d957ab584865f74499bc732395388a78965fe5f 100644
--- a/src/providers/ldap/sdap_async_users.c
+++ b/src/providers/ldap/sdap_async_users.c
@@ -117,6 +117,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
                    struct sdap_options *opts,
                    struct sss_domain_info *dom,
                    struct sysdb_attrs *attrs,
+                   struct sysdb_attrs *mapped_attrs,
                    char **_usn_value,
                    time_t now)
 {
@@ -511,6 +512,11 @@ int sdap_save_user(TALLOC_CTX *memctx,
                            user_attrs, missing, cache_timeout, now);
     if (ret) goto done;
 
+    if (mapped_attrs != NULL) {
+        ret = sysdb_set_user_attr(dom, user_name, mapped_attrs, SYSDB_MOD_ADD);
+        if (ret) return ret;
+    }
+
     if (_usn_value) {
         *_usn_value = talloc_steal(memctx, usn_value);
     }
@@ -537,6 +543,7 @@ int sdap_save_users(TALLOC_CTX *memctx,
                     struct sdap_options *opts,
                     struct sysdb_attrs **users,
                     int num_users,
+                    struct sysdb_attrs *mapped_attrs,
                     char **_usn_value)
 {
     TALLOC_CTX *tmpctx;
@@ -565,11 +572,20 @@ int sdap_save_users(TALLOC_CTX *memctx,
     }
     in_transaction = true;
 
+    if (mapped_attrs != NULL) {
+        ret = sysdb_remove_mapped_data(dom, mapped_attrs);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_remove_mapped_data failed, "
+                  "some cached entries might contain invalid mapping data.\n");
+        }
+    }
+
     now = time(NULL);
     for (i = 0; i < num_users; i++) {
         usn_value = NULL;
 
-        ret = sdap_save_user(tmpctx, opts, dom, users[i], &usn_value, now);
+        ret = sdap_save_user(tmpctx, opts, dom, users[i], mapped_attrs,
+                             &usn_value, now);
 
         /* Do not fail completely on errors.
          * Just report the failure to save and go on */
@@ -868,6 +884,7 @@ struct sdap_get_users_state {
 
     char *higher_usn;
     struct sysdb_attrs **users;
+    struct sysdb_attrs *mapped_attrs;
     size_t count;
 };
 
@@ -883,7 +900,8 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
                                        const char **attrs,
                                        const char *filter,
                                        int timeout,
-                                       enum sdap_entry_lookup_type lookup_type)
+                                       enum sdap_entry_lookup_type lookup_type,
+                                       struct sysdb_attrs *mapped_attrs)
 {
     errno_t ret;
     struct tevent_req *req;
@@ -900,6 +918,23 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
     state->filter = filter;
     PROBE(SDAP_SEARCH_USER_SEND, state->filter);
 
+    if (mapped_attrs == NULL) {
+        state->mapped_attrs = NULL;
+    } else {
+        state->mapped_attrs = sysdb_new_attrs(state);
+        if (state->mapped_attrs == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        ret = sysdb_attrs_copy(mapped_attrs, state->mapped_attrs);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_copy failed.\n");
+            goto done;
+        }
+    }
+
     subreq = sdap_search_user_send(state, ev, dom, opts, search_bases,
                                    sh, attrs, filter, timeout, lookup_type);
     if (subreq == NULL) {
@@ -938,9 +973,11 @@ static void sdap_get_users_done(struct tevent_req *subreq)
     }
 
     PROBE(SDAP_SEARCH_USER_SAVE_BEGIN, state->filter);
+
     ret = sdap_save_users(state, state->sysdb,
                           state->dom, state->opts,
                           state->users, state->count,
+                          state->mapped_attrs,
                           &state->higher_usn);
     PROBE(SDAP_SEARCH_USER_SAVE_END, state->filter);
     if (ret) {
diff --git a/src/providers/ldap/sdap_users.h b/src/providers/ldap/sdap_users.h
index 78dafb31a2a07e7289055daec77c5dc5da1bdeef..a6d088a6d7114db75b0f0ea22ef85c57da6fab0f 100644
--- a/src/providers/ldap/sdap_users.h
+++ b/src/providers/ldap/sdap_users.h
@@ -34,6 +34,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
                    struct sdap_options *opts,
                    struct sss_domain_info *dom,
                    struct sysdb_attrs *attrs,
+                   struct sysdb_attrs *mapped_attrs,
                    char **_usn_value,
                    time_t now);
 
-- 
2.9.3