From 94ae3c5231dc7f1cd9f9d172d13a11a8afcacd16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 23 Feb 2016 11:02:42 +0100
Subject: [PATCH] remove user certificate if not found on the server

If the user is not found by cert lookup when the user is already
cached, two things may happen:
1) cert was removed from the user object
2) user was removed

Instead of issuing another cert lookup we will just remove cert
attribute from the cache not touching the expiration timestamp so
the user may be updated later when needed.

Resolves:
https://fedorahosted.org/sssd/ticket/2934
---
 src/db/sysdb.h               |  3 ++-
 src/db/sysdb_ops.c           | 47 ++++++++++++++++++++++++++++++++++++++++++++
 src/providers/ldap/ldap_id.c | 10 ++++++++++
 3 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 2e797fd7fa39163c2ab6a10e51228e0f1af3f9e3..d074d4d661554a798151caee831cc672a927712f 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -1154,7 +1154,8 @@ errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx,
                                   const char *cert,
                                   struct ldb_result **res);
 
-
+errno_t sysdb_remove_cert(struct sss_domain_info *domain,
+                          const char *cert);
 
 /* === Functions related to GPOs === */
 
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index ab0d59ca6db620dfbf7e74a93745df242b6fc3a3..aa688f42f9a6f7f0f86e1171df0a5f0346a59ea5 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -3764,6 +3764,53 @@ errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx,
     return sysdb_search_object_by_cert(mem_ctx, domain, cert, user_attrs, res);
 }
 
+static errno_t sysdb_remove_user_cert(struct sss_domain_info *domain,
+                                      const char *name)
+{
+    struct ldb_message_element el = { 0, SYSDB_USER_CERT, 0, NULL };
+    struct sysdb_attrs attrs = { 1, &el };
+
+    DEBUG(SSSDBG_TRACE_FUNC, "Removing certificate from user %s@%s",
+          name, domain->name);
+
+    return sysdb_set_user_attr(domain, name, &attrs, SYSDB_MOD_DEL);
+}
+
+errno_t sysdb_remove_cert(struct sss_domain_info *domain,
+                          const char *cert)
+{
+    struct ldb_result *res = NULL;
+    const char *name;
+    errno_t ret;
+
+    ret = sysdb_search_user_by_cert(NULL, domain, cert, &res);
+    if (ret == ENOENT || res == NULL || res->count == 0) {
+        ret = EOK;
+        goto done;
+    } else if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "Unable to lookup user by cert "
+              "[%d]: %s\n", ret, sss_strerror(ret));
+        goto done;
+    } else if (res->count > 1) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "More then one result found!");
+        ret = ERR_INTERNAL;
+        goto done;
+    }
+
+    name = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
+    if (name == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "User without name!\n");
+        ret = ERR_INTERNAL;
+        goto done;
+    }
+
+    ret = sysdb_remove_user_cert(domain, name);
+
+done:
+    talloc_free(res);
+    return ret;
+}
+
 errno_t sysdb_get_sids_of_members(TALLOC_CTX *mem_ctx,
                                   struct sss_domain_info *dom,
                                   const char *group_name,
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index b7cef4e13d70f738428cdbf70b661de92a87b4a5..8923e7e0c3fdae4614d6bfef2665de7854b62e8e 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -529,6 +529,16 @@ static void users_get_done(struct tevent_req *subreq)
              */
             break;
 
+        case BE_FILTER_CERT:
+            ret = sysdb_remove_cert(state->domain, state->name);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_CRIT_FAILURE, "Unable to remove user certificate"
+                      "[%d]: %s\n", ret, sss_strerror(ret));
+                tevent_req_error(req, ret);
+                return;
+            }
+            break;
+
         default:
             tevent_req_error(req, EINVAL);
             return;
-- 
2.1.0

