On Tue, Jun 07, 2016 at 01:56:10PM +0200, Jakub Hrozek wrote:
> On Tue, Jun 07, 2016 at 12:28:22PM +0200, Sumit Bose wrote:
> > sure, here you are.
> > 
> > bye,
> > Sumit
> 
> Hmm, are these the correct patches?
> 
> /home/remote/jhrozek/devel/sssd/src/db/sysdb_views.c: In function 
> 'sysdb_search_override_by_cert':
> /home/remote/jhrozek/devel/sssd/src/db/sysdb_views.c:880:11: error: too many 
> arguments to function 'sss_cert_derb64_to_ldap_filter'
>      ret = sss_cert_derb64_to_ldap_filter(tmp_ctx, cert, SYSDB_USER_CERT, 
> NULL,
>            ^
> In file included from 
> /home/remote/jhrozek/devel/sssd/src/db/sysdb_views.c:23:0:
> /home/remote/jhrozek/devel/sssd/src/util/cert.h:40:9: note: declared here
>  errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char 
> *derb64,
>          ^

ah, sorry, I picked the patches from a wrong branch.

Please try the new version.

bye,
Sumit

> 
> I applied:
> $ git rev-list origin/master..HEAD
> 91fe4dec3d70759a84ff48c4cc7502327f717894
> 8df9665f49a4b669299504cdaa5e745f12336de6
> 5ac83ad804b06fb6678f46cd289269a1bccfe4ad
> 2976137caa3d57e6b87b736ab1040c778af4d44b
> e57eea3aaad72138596343c540f84e705f4f0e17
> 61a5346d0efaabe7b3bbacc5c202dc797c2684a7
> d0911e8fb6c5748cac8267d978971022cbc0c859
> 330f21d2f0df5b9b6c9c54e685774c722a629efd
> eecf83cb6a79dcea1f99e4363e76c1758dcd69fb
> 98c2123924dc6e1e9d695fa7b45292b1c635dee3
> 7faa5fb5c0006a6d77a0b5b735846c61b533e7ff
> f506e3a307e5899d35b3ad8ff55d9a02d5a71ade
> _______________________________________________
> sssd-devel mailing list
> sssd-devel@lists.fedorahosted.org
> https://lists.fedorahosted.org/admin/lists/sssd-devel@lists.fedorahosted.org
From 309a477d08314f849609bd61b5b18a738a1724c6 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Mon, 30 Nov 2015 12:14:16 +0100
Subject: [PATCH 01/12] sysdb: add sysdb_attrs_add_base64_blob()

---
 src/db/sysdb.c                      | 22 ++++++++++++++++++++++
 src/db/sysdb.h                      |  2 ++
 src/tests/cmocka/test_sysdb_utils.c | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 61 insertions(+)

diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index 
3c888a42ca6f3b3e37b9f63e35c31bb7d5ffc367..d7540f0ccbe7de38f840f84dbe8f51f4793821bc
 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -23,6 +23,7 @@
 #include "util/util.h"
 #include "util/strtonum.h"
 #include "util/sss_utf8.h"
+#include "util/crypto/sss_crypto.h"
 #include "db/sysdb_private.h"
 #include "confdb/confdb.h"
 #include <time.h>
@@ -634,6 +635,27 @@ int sysdb_attrs_add_mem(struct sysdb_attrs *attrs, const 
char *name,
        return sysdb_attrs_add_val(attrs, name, &v);
 }
 
+int sysdb_attrs_add_base64_blob(struct sysdb_attrs *attrs, const char *name,
+                                const char *base64_str)
+{
+    struct ldb_val v;
+    int ret;
+
+    if (base64_str == NULL) {
+        return EINVAL;
+    }
+
+    v.data = sss_base64_decode(attrs, base64_str, &v.length);
+    if (v.data == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
+        return ENOMEM;
+    }
+
+    ret = sysdb_attrs_add_val(attrs, name, &v);
+    talloc_free(v.data);
+    return ret;
+}
+
 int sysdb_attrs_add_bool(struct sysdb_attrs *attrs,
                          const char *name, bool value)
 {
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 
11b680f3f67319abd8856ea42045f6b8f0cef4ba..ec398496d67f0d32351a1fa974b2ab17dc9af88c
 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -322,6 +322,8 @@ int sysdb_attrs_add_lower_case_string(struct sysdb_attrs 
*attrs, bool safe,
                                       const char *name, const char *str);
 int sysdb_attrs_add_mem(struct sysdb_attrs *attrs, const char *name,
                         const void *mem, size_t size);
+int sysdb_attrs_add_base64_blob(struct sysdb_attrs *attrs, const char *name,
+                                const char *base64_str);
 int sysdb_attrs_add_bool(struct sysdb_attrs *attrs,
                          const char *name, bool value);
 int sysdb_attrs_add_long(struct sysdb_attrs *attrs,
diff --git a/src/tests/cmocka/test_sysdb_utils.c 
b/src/tests/cmocka/test_sysdb_utils.c
index 
b791f14b7fdfdd4e55343fc1c03a7fd55d8ed101..42abed3c52463893525c35e563044d430e9a6a8b
 100644
--- a/src/tests/cmocka/test_sysdb_utils.c
+++ b/src/tests/cmocka/test_sysdb_utils.c
@@ -103,6 +103,42 @@ static void test_sysdb_handle_original_uuid(void **state)
     talloc_free(dest_attrs);
 }
 
+#define TEST_BASE64_ABC "YWJj"
+#define TEST_BASE64_123 "AQID"
+static void test_sysdb_attrs_add_base64_blob(void **state)
+{
+    struct sysdb_attrs *attrs;
+    struct ldb_message_element *el;
+    char zero[] = {'\1', '\2', '\3'};
+    int ret;
+
+    attrs = sysdb_new_attrs(NULL);
+    assert_non_null(attrs);
+
+    ret = sysdb_attrs_add_base64_blob(attrs, "testAttrABC", TEST_BASE64_ABC);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_attrs_add_base64_blob(attrs, "testAttr000", TEST_BASE64_123);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_attrs_get_el(attrs, "testAttrABC", &el);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(el->num_values, 1);
+    assert_non_null(el->values);
+    assert_non_null(el->values[0].data);
+    assert_int_equal(el->values[0].length, 3);
+    assert_memory_equal(el->values[0].data, "abc", 3);
+
+    ret = sysdb_attrs_get_el(attrs, "testAttr000", &el);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(el->num_values, 1);
+    assert_non_null(el->values);
+    assert_non_null(el->values[0].data);
+    assert_int_equal(el->values[0].length, 3);
+    assert_memory_equal(el->values[0].data, zero, 3);
+}
+
+
 int main(int argc, const char *argv[])
 {
     int rv;
@@ -116,6 +152,7 @@ int main(int argc, const char *argv[])
 
     const struct CMUnitTest tests[] = {
         cmocka_unit_test(test_sysdb_handle_original_uuid),
+        cmocka_unit_test(test_sysdb_attrs_add_base64_blob),
     };
 
     /* Set debug level to invalid value so we can deside if -d 0 was used. */
-- 
2.1.0

From 8d03267f1ceaf1a6afd72b9d163b0e06c8dadc90 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Wed, 6 Apr 2016 11:12:30 +0200
Subject: [PATCH 02/12] sysdb: add searches by certificate with overrides

---
 src/db/sysdb.h        |  12 ++++++
 src/db/sysdb_search.c |  68 +++++++++++++++++++++++++++++++++
 src/db/sysdb_views.c  | 103 +++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 182 insertions(+), 1 deletion(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 
ec398496d67f0d32351a1fa974b2ab17dc9af88c..d694508166d78a909316b66d672e3f16067c43ae
 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -545,6 +545,13 @@ errno_t sysdb_search_group_override_by_gid(TALLOC_CTX 
*mem_ctx,
                                             struct ldb_result **override_obj,
                                             struct ldb_result **orig_obj);
 
+errno_t sysdb_search_override_by_cert(TALLOC_CTX *mem_ctx,
+                                      struct sss_domain_info *domain,
+                                      const char *cert,
+                                      const char **attrs,
+                                      struct ldb_result **override_obj,
+                                      struct ldb_result **orig_obj);
+
 errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain,
                                       struct ldb_message *obj,
                                       struct ldb_message *override_obj,
@@ -722,6 +729,11 @@ int sysdb_get_user_attr_with_views(TALLOC_CTX *mem_ctx,
                                    const char **attributes,
                                    struct ldb_result **res);
 
+int sysdb_search_user_by_cert_with_views(TALLOC_CTX *mem_ctx,
+                                          struct sss_domain_info *domain,
+                                          const char *cert,
+                                          struct ldb_result **res);
+
 int sysdb_get_netgroup_attr(TALLOC_CTX *mem_ctx,
                             struct sss_domain_info *domain,
                             const char *netgrname,
diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
index 
1e403119131a7704a1f36ca2fd597d9ee64b9319..fd55544309693d9909077c634145663cb5189388
 100644
--- a/src/db/sysdb_search.c
+++ b/src/db/sysdb_search.c
@@ -1842,3 +1842,71 @@ done:
     talloc_free(tmp_ctx);
     return ret;
 }
+
+int sysdb_search_user_by_cert_with_views(TALLOC_CTX *mem_ctx,
+                                          struct sss_domain_info *domain,
+                                          const char *cert,
+                                          struct ldb_result **res)
+{
+    TALLOC_CTX *tmp_ctx;
+    int ret;
+    struct ldb_result *orig_obj = NULL;
+    struct ldb_result *override_obj = NULL;
+    const char *attrs[] = SYSDB_PW_ATTRS;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    /* If there are views we first have to search the overrides for matches */
+    if (DOM_HAS_VIEWS(domain)) {
+        ret = sysdb_search_override_by_cert(tmp_ctx, domain, cert, attrs,
+                                            &override_obj, &orig_obj);
+        if (ret != EOK && ret != ENOENT) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "sysdb_search_override_by_cert failed.\n");
+            goto done;
+        }
+    }
+
+    /* If there are no views or nothing was found in the overrides the
+     * original objects are searched. */
+    if (orig_obj == NULL) {
+        ret = sysdb_search_user_by_cert(tmp_ctx, domain, cert, &orig_obj);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_cert failed.\n");
+            goto done;
+        }
+    }
+
+    /* If there are views we have to check if override values must be added to
+     * the original object. */
+    if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) {
+        ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0],
+                          override_obj == NULL ? NULL : override_obj->msgs[0],
+                          NULL);
+        if (ret == ENOENT) {
+            *res = talloc_zero(mem_ctx, struct ldb_result);
+            if (*res == NULL) {
+                DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
+                ret = ENOMEM;
+            } else {
+                ret = EOK;
+            }
+            goto done;
+        } else if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object 
failed.\n");
+            goto done;
+        }
+
+    }
+
+    *res = talloc_steal(mem_ctx, orig_obj);
+    ret = EOK;
+
+done:
+
+    talloc_free(tmp_ctx);
+    return ret;
+}
diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
index 
f0459fc174b94d7a735b7c416555eb5aaac42b7c..c7b907df8393d38043cf448de6a703af42009e5f
 100644
--- a/src/db/sysdb_views.c
+++ b/src/db/sysdb_views.c
@@ -20,6 +20,7 @@
 */
 
 #include "util/util.h"
+#include "util/cert.h"
 #include "db/sysdb_private.h"
 
 /* In general is should not be possible that there is a view container without
@@ -736,6 +737,7 @@ errno_t sysdb_apply_default_override(struct sss_domain_info 
*domain,
                                     SYSDB_SHELL,
                                     SYSDB_NAME,
                                     SYSDB_SSH_PUBKEY,
+                                    SYSDB_USER_CERT,
                                     NULL };
     bool override_attrs_found = false;
 
@@ -781,8 +783,10 @@ errno_t sysdb_apply_default_override(struct 
sss_domain_info *domain,
                 }
             } else {
                 num_values = el->num_values;
-                /* Only SYSDB_SSH_PUBKEY is allowed to have multiple values. */
+                /* Only SYSDB_SSH_PUBKEY and SYSDB_USER_CERT are allowed to
+                 * have multiple values. */
                 if (strcmp(allowed_attrs[c], SYSDB_SSH_PUBKEY) != 0
+                        && strcmp(allowed_attrs[c], SYSDB_USER_CERT) != 0
                         && num_values != 1) {
                     DEBUG(SSSDBG_MINOR_FAILURE,
                           "Override attribute for [%s] has more [%zd] " \
@@ -835,6 +839,7 @@ done:
 
 #define SYSDB_USER_NAME_OVERRIDE_FILTER 
"(&(objectClass="SYSDB_OVERRIDE_USER_CLASS")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
 #define SYSDB_USER_UID_OVERRIDE_FILTER 
"(&(objectClass="SYSDB_OVERRIDE_USER_CLASS")("SYSDB_UIDNUM"=%lu))"
+#define SYSDB_USER_CERT_OVERIDE_FILTER 
"(&(objectClass="SYSDB_OVERRIDE_USER_CLASS")%s)"
 #define SYSDB_GROUP_NAME_OVERRIDE_FILTER 
"(&(objectClass="SYSDB_OVERRIDE_GROUP_CLASS")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
 #define SYSDB_GROUP_GID_OVERRIDE_FILTER 
"(&(objectClass="SYSDB_OVERRIDE_GROUP_CLASS")("SYSDB_GIDNUM"=%lu))"
 
@@ -844,6 +849,101 @@ enum override_object_type {
     OO_TYPE_GROUP
 };
 
+errno_t sysdb_search_override_by_cert(TALLOC_CTX *mem_ctx,
+                                      struct sss_domain_info *domain,
+                                      const char *cert,
+                                      const char **attrs,
+                                      struct ldb_result **override_obj,
+                                      struct ldb_result **orig_obj)
+{
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_dn *base_dn;
+    struct ldb_result *override_res;
+    struct ldb_result *orig_res;
+    char *cert_filter;
+    int ret;
+    const char *orig_obj_dn;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
+                             SYSDB_TMPL_VIEW_SEARCH_BASE, domain->view_name);
+    if (base_dn == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sss_cert_derb64_to_ldap_filter(tmp_ctx, cert, SYSDB_USER_CERT,
+                                         &cert_filter);
+
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n");
+        goto done;
+    }
+
+    ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &override_res, base_dn,
+                     LDB_SCOPE_SUBTREE, attrs, SYSDB_USER_CERT_OVERIDE_FILTER,
+                     cert_filter);
+    if (ret != LDB_SUCCESS) {
+        ret = sysdb_error_to_errno(ret);
+        goto done;
+    }
+
+    if (override_res->count == 0) {
+        DEBUG(SSSDBG_TRACE_FUNC, "No user override found for cert [%s].\n",
+                                 cert);
+        ret = ENOENT;
+        goto done;
+    } else if (override_res->count > 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Found more than one override for cert [%s].\n", cert);
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (orig_obj != NULL) {
+        orig_obj_dn = ldb_msg_find_attr_as_string(override_res->msgs[0],
+                                                  SYSDB_OVERRIDE_OBJECT_DN,
+                                                  NULL);
+        if (orig_obj_dn == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Missing link to original object in override [%s].\n",
+                  ldb_dn_get_linearized(override_res->msgs[0]->dn));
+            ret = EINVAL;
+            goto done;
+        }
+
+        base_dn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, orig_obj_dn);
+        if (base_dn == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &orig_res, base_dn,
+                         LDB_SCOPE_BASE, attrs, NULL);
+        if (ret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(ret);
+            goto done;
+        }
+
+        *orig_obj = talloc_steal(mem_ctx, orig_res);
+    }
+
+
+    *override_obj = talloc_steal(mem_ctx, override_res);
+
+    ret = EOK;
+
+done:
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
 static errno_t sysdb_search_override_by_name(TALLOC_CTX *mem_ctx,
                                              struct sss_domain_info *domain,
                                              const char *name,
@@ -1170,6 +1270,7 @@ errno_t sysdb_add_overrides_to_object(struct 
sss_domain_info *domain,
         {SYSDB_SHELL, OVERRIDE_PREFIX SYSDB_SHELL},
         {SYSDB_NAME, OVERRIDE_PREFIX SYSDB_NAME},
         {SYSDB_SSH_PUBKEY, OVERRIDE_PREFIX SYSDB_SSH_PUBKEY},
+        {SYSDB_USER_CERT, OVERRIDE_PREFIX SYSDB_USER_CERT},
         {NULL, NULL}
     };
     size_t c;
-- 
2.1.0

From b40106541e0e58b9995a8d93e171c04d499a3cf0 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Wed, 6 Apr 2016 11:13:22 +0200
Subject: [PATCH 03/12] cache_req: use overide aware call for lookup by
 certificate

---
 src/responder/common/responder_cache_req.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/responder/common/responder_cache_req.c 
b/src/responder/common/responder_cache_req.c
index 
a3253a5efcfea014a01dc38e42ae2a4466dff1a2..96cb65077931e0393383a86e4561e8af0f717d74
 100644
--- a/src/responder/common/responder_cache_req.c
+++ b/src/responder/common/responder_cache_req.c
@@ -714,8 +714,8 @@ static errno_t cache_req_get_object(TALLOC_CTX *mem_ctx,
         break;
     case CACHE_REQ_USER_BY_CERT:
         one_item_only = true;
-        ret = sysdb_search_user_by_cert(mem_ctx, cr->domain,
-                                        cr->data->cert, &result);
+        ret = sysdb_search_user_by_cert_with_views(mem_ctx, cr->domain,
+                                                   cr->data->cert, &result);
         break;
     case CACHE_REQ_USER_BY_FILTER:
         one_item_only = false;
-- 
2.1.0

From baa02a26721dc38edd241729074dfc5dd201b5a1 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Wed, 6 Apr 2016 11:15:32 +0200
Subject: [PATCH 04/12] ipa: add support for certificate overrides

---
 src/providers/ipa/ipa_common.h        |  1 +
 src/providers/ipa/ipa_opts.c          |  1 +
 src/providers/ipa/ipa_subdomains_id.c |  6 ++++++
 src/providers/ipa/ipa_views.c         | 25 +++++++++++++++++++++++++
 4 files changed, 33 insertions(+)

diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 
d1688bb6a226cd45318dd22380d0ff73d9b2ec47..51de819c8471d2575495bd5349d19eb46d41d54b
 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -129,6 +129,7 @@ enum ipa_override_attrs {
     IPA_AT_OVERRIDE_GROUP_NAME,
     IPA_AT_OVERRIDE_GROUP_GID_NUMBER,
     IPA_AT_OVERRIDE_USER_SSH_PUBLIC_KEY,
+    IPA_AT_OVERRIDE_USER_CERT,
 
     IPA_OPTS_OVERRIDE
 };
diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
index 
5b0b44e2493ebba0f0cfdb63894a7c75533fc959..a0c318a511693d884f03f0372c592d633ebdcbae
 100644
--- a/src/providers/ipa/ipa_opts.c
+++ b/src/providers/ipa/ipa_opts.c
@@ -289,6 +289,7 @@ struct sdap_attr_map ipa_override_map[] = {
     { "ldap_group_name", "cn", SYSDB_NAME, NULL },
     { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL },
     { "ldap_user_ssh_public_key", "ipaSshPubKey", SYSDB_SSH_PUBKEY, NULL },
+    { "ldap_user_certificate", "userCertificate;binary", SYSDB_USER_CERT, NULL 
},
     SDAP_ATTR_MAP_TERMINATOR
 };
 
diff --git a/src/providers/ipa/ipa_subdomains_id.c 
b/src/providers/ipa/ipa_subdomains_id.c
index 
f98f8bf8e28cc643b46e7ccfd6f559b3e85a7661..e8dd82446f58afc5dfd439ce88cb2b5741c9f100
 100644
--- a/src/providers/ipa/ipa_subdomains_id.c
+++ b/src/providers/ipa/ipa_subdomains_id.c
@@ -402,6 +402,7 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX 
*memctx,
         case BE_REQ_USER:
         case BE_REQ_GROUP:
         case BE_REQ_BY_SECID:
+        case BE_REQ_BY_CERT:
         case BE_REQ_USER_AND_GROUP:
             ret = EOK;
             break;
@@ -526,6 +527,11 @@ static void ipa_get_subdom_acct_connected(struct 
tevent_req *subreq)
                 return;
             }
             break;
+        case BE_FILTER_CERT:
+            DEBUG(SSSDBG_OP_FAILURE, "Lookup by certificate not supported 
yet.\n");
+            state->dp_error = dp_error;
+            tevent_req_error(req, EINVAL);
+            return;
         default:
             DEBUG(SSSDBG_OP_FAILURE, "Invalid sub-domain filter type.\n");
             state->dp_error = dp_error;
diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c
index 
00dcbeb751a4ed63bedd8642bbc87a5226d28d34..76528a60c1e2ce666710e2d7653531d6d075cdc1
 100644
--- a/src/providers/ipa/ipa_views.c
+++ b/src/providers/ipa/ipa_views.c
@@ -24,6 +24,7 @@
 
 #include "util/util.h"
 #include "util/strtonum.h"
+#include "util/cert.h"
 #include "providers/ldap/sdap_async.h"
 #include "providers/ipa/ipa_id.h"
 
@@ -35,6 +36,8 @@ static errno_t be_acct_req_to_override_filter(TALLOC_CTX 
*mem_ctx,
     char *filter;
     uint32_t id;
     char *endptr;
+    char *cert_filter;
+    int ret;
 
     switch (ar->filter_type) {
     case BE_FILTER_NAME:
@@ -140,6 +143,28 @@ static errno_t be_acct_req_to_override_filter(TALLOC_CTX 
*mem_ctx,
         }
         break;
 
+    case BE_FILTER_CERT:
+        if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_BY_CERT) {
+            ret = sss_cert_derb64_to_ldap_filter(mem_ctx, ar->filter_value,
+                         
ipa_opts->override_map[IPA_AT_OVERRIDE_USER_CERT].name,
+                         &cert_filter);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "sss_cert_derb64_to_ldap_filter failed.\n");
+                return ret;
+            }
+            filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)%s)",
+                        ipa_opts->override_map[IPA_OC_OVERRIDE_USER].name,
+                        cert_filter);
+            talloc_free(cert_filter);
+        } else {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Unexpected entry type [%d] for certificate filter.\n",
+                  ar->entry_type);
+            return EINVAL;
+        }
+        break;
+
     default:
         DEBUG(SSSDBG_OP_FAILURE, "Invalid sub-domain filter type.\n");
         return EINVAL;
-- 
2.1.0

From a0ec9ba7a45f1f67d3f5f8feed977ca37fc029a5 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Wed, 6 Apr 2016 11:18:38 +0200
Subject: [PATCH 05/12] nss: include certificates in full result list

---
 src/responder/nss/nsssrv_cmd.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 
0c7bf8adad8695082e7dfb376836c2398f6b46b4..ab6700a182850b0158bd5d2e0cd1fc023211aa71
 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -4480,6 +4480,7 @@ static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx 
*dctx)
                                    SYSDB_AD_ACCOUNT_EXPIRES,
                                    SYSDB_AD_USER_ACCOUNT_CONTROL,
                                    SYSDB_SSH_PUBKEY,
+                                   SYSDB_USER_CERT,
                                    SYSDB_ORIG_DN,
                                    SYSDB_ORIG_MEMBEROF,
                                    SYSDB_DEFAULT_ATTRS, NULL};
@@ -5045,6 +5046,7 @@ static errno_t fill_orig(struct sss_packet *packet,
                                     SYSDB_AD_ACCOUNT_EXPIRES,
                                     SYSDB_AD_USER_ACCOUNT_CONTROL,
                                     SYSDB_SSH_PUBKEY,
+                                    SYSDB_USER_CERT,
                                     SYSDB_ORIG_DN,
                                     SYSDB_ORIG_MEMBEROF,
                                     NULL};
-- 
2.1.0

From 702e83f19bb77dfe0f0a35a8901f3f686f003d9a Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Wed, 6 Apr 2016 18:07:37 +0200
Subject: [PATCH 06/12] ipa: save cert as blob in the cache

The IPA extdom plugin returns the user certificate base64 encoded.
Before the IPA client can store it in the cache it must be decoded so
that it is stored as a binary as the certificate from other sources.
---
 src/providers/ipa/ipa_s2n_exop.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 
c1bc42ff14e7217eba258bbfa1a170dfee2ac972..b6136befaa78ac30e7bf2ca52ef1875e16a74304
 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -22,6 +22,7 @@
 #include "util/util.h"
 #include "util/sss_nss.h"
 #include "util/strtonum.h"
+#include "util/crypto/sss_crypto.h"
 #include "providers/ldap/sdap_async_private.h"
 #include "providers/ldap/sdap_async_ad.h"
 #include "providers/ldap/ldap_common.h"
@@ -497,8 +498,22 @@ static errno_t get_extra_attrs(BerElement *ber, struct 
resp_attrs *resp_attrs)
 
         for (c = 0; values[c] != NULL; c++) {
 
-            v.data = (uint8_t *) values[c]->bv_val;
-            v.length = values[c]->bv_len;
+            if (strcmp(name, SYSDB_USER_CERT) == 0) {
+                if (values[c]->bv_val[values[c]->bv_len] != '\0') {
+                    DEBUG(SSSDBG_OP_FAILURE,
+                          "base64 encoded certificate not 0-terminated.\n");
+                    return EINVAL;
+                }
+
+                v.data = sss_base64_decode(NULL,values[c]->bv_val, &v.length);
+                if (v.data == NULL) {
+                    DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
+                    return EINVAL;
+                }
+            } else {
+                v.data = (uint8_t *) values[c]->bv_val;
+                v.length = values[c]->bv_len;
+            }
 
             ret = sysdb_attrs_add_val(resp_attrs->sysdb_attrs, name, &v);
             if (ret != EOK) {
-- 
2.1.0

From 98e4ac87ab6f892ba7e524c89875fd4ca307dcf8 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Wed, 6 Apr 2016 18:10:48 +0200
Subject: [PATCH 07/12] AD: read user certificate if available

---
 src/providers/ad/ad_opts.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
index 
15024adb7959de9e16cdc92ca30daa74bb5f648d..57dfcca6b998083c7cf9ac0bcb142ff7736cc8b9
 100644
--- a/src/providers/ad/ad_opts.c
+++ b/src/providers/ad/ad_opts.c
@@ -217,7 +217,7 @@ struct sdap_attr_map ad_2008r2_user_map[] = {
     { "ldap_user_nds_login_allowed_time_map", NULL, 
SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
     { "ldap_user_ssh_public_key", NULL, SYSDB_SSH_PUBKEY, NULL },
     { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
-    { "ldap_user_certificate", NULL, SYSDB_USER_CERT, NULL },
+    { "ldap_user_certificate", "userCertificate;binary", SYSDB_USER_CERT, NULL 
},
     SDAP_ATTR_MAP_TERMINATOR
 };
 
-- 
2.1.0

From c5399cc96ee8bac64f634bbdb0fff94bd08d1a26 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Wed, 6 Apr 2016 18:12:31 +0200
Subject: [PATCH 08/12] nss: return user certificate base64 encoded

---
 src/responder/nss/nsssrv_cmd.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 
ab6700a182850b0158bd5d2e0cd1fc023211aa71..f44ae6f26a7ad82b9f19d487ef08f3c055fd3f3d
 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -22,6 +22,7 @@
 #include "util/util.h"
 #include "util/sss_nss.h"
 #include "util/sss_cli_cmd.h"
+#include "util/crypto/sss_crypto.h"
 #include "responder/nss/nsssrv.h"
 #include "responder/nss/nsssrv_private.h"
 #include "responder/nss/nsssrv_netgroup.h"
@@ -4973,8 +4974,9 @@ static errno_t process_attr_list(TALLOC_CTX *mem_ctx, 
struct ldb_message *msg,
     size_t d;
     struct sized_string *keys;
     struct sized_string *vals;
-    struct ldb_val *val;
+    struct ldb_val val;
     struct ldb_message_element *el;
+    bool use_base64;
 
     keys = *_keys;
     vals = *_vals;
@@ -4993,18 +4995,31 @@ static errno_t process_attr_list(TALLOC_CTX *mem_ctx, 
struct ldb_message *msg,
                     return ENOMEM;
                 }
             }
+
+            use_base64 = false;
+            if (strcmp(attr_list[c], SYSDB_USER_CERT) == 0) {
+                use_base64 = true;
+            }
             for (d = 0; d < el->num_values; d++) {
                 to_sized_string(&keys[*found], attr_list[c]);
                 *sum += keys[*found].len;
-                val = &(el->values[d]);
-                if (val == NULL || val->data == NULL
-                        || val->data[val->length] != '\0') {
+                if (use_base64) {
+                    val.data = (uint8_t *) sss_base64_encode(vals,
+                                                          el->values[d].data,
+                                                          
el->values[d].length);
+                    if (val.data != NULL) {
+                        val.length = strlen((char *) val.data);
+                    }
+                } else {
+                    val = el->values[d];
+                }
+                if (val.data == NULL || val.data[val.length] != '\0') {
                     DEBUG(SSSDBG_CRIT_FAILURE,
                           "Unexpected attribute value found for [%s].\n",
                           attr_list[c]);
                     return EINVAL;
                 }
-                to_sized_string(&vals[*found], (const char *)val->data);
+                to_sized_string(&vals[*found], (const char *)val.data);
                 *sum += vals[*found].len;
 
                 (*found)++;
-- 
2.1.0

From fea2e21063c7dc249d1dade780217215884551e8 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Fri, 8 Apr 2016 13:22:24 +0200
Subject: [PATCH 09/12] sss_override: add certificate support

---
 src/db/sysdb.h                             |  1 +
 src/man/sss_override.8.xml                 |  6 +++--
 src/tests/intg/ldap_local_override_test.py |  8 +++----
 src/tools/sss_override.c                   | 38 ++++++++++++++++++++++++++----
 4 files changed, 42 insertions(+), 11 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 
d694508166d78a909316b66d672e3f16067c43ae..25c8763f76fcebc84fc32458edf18bcaec86658d
 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -215,6 +215,7 @@
                         SYSDB_PRIMARY_GROUP_GIDNUM, \
                         SYSDB_SID_STR, \
                         SYSDB_UPN, \
+                        SYSDB_USER_CERT, \
                         SYSDB_OVERRIDE_DN, \
                         SYSDB_OVERRIDE_OBJECT_DN, \
                         SYSDB_DEFAULT_OVERRIDE_NAME, \
diff --git a/src/man/sss_override.8.xml b/src/man/sss_override.8.xml
index 
ef73aee981a34f9679907bb793126c0c19a50cef..349bba27cdced4379bffab72f816bca271eeb2dc
 100644
--- a/src/man/sss_override.8.xml
+++ b/src/man/sss_override.8.xml
@@ -64,6 +64,8 @@
                     <optional><option>-h,--home</option> HOME</optional>
                     <optional><option>-s,--shell</option> SHELL</optional>
                     <optional><option>-c,--gecos</option> GECOS</optional>
+                    <optional><option>-x,--certificate</option>
+                                     BASE64 ENCODED CERTIFICATE</optional>
                 </term>
                 <listitem>
                     <para>
@@ -123,7 +125,7 @@
                         The format is:
                     </para>
                     <para>
-                        original_name:name:uid:gid:gecos:home:shell
+                        
original_name:name:uid:gid:gecos:home:shell:base64_encoded_certificate
                     </para>
                     <para>
                         where original_name is original name of the user whose
@@ -138,7 +140,7 @@
                         ckent:superman::::::
                     </para>
                     <para>
-                        
ck...@krypton.com::501:501:Superman:/home/earth:/bin/bash
+                        
ck...@krypton.com::501:501:Superman:/home/earth:/bin/bash:
                     </para>
                 </listitem>
             </varlistentry>
diff --git a/src/tests/intg/ldap_local_override_test.py 
b/src/tests/intg/ldap_local_override_test.py
index 
542527180cf2c7ec5a2984f6b42655fb0c75f5d1..046535c7727d0f2271f4b974f68ba0722222982b
 100644
--- a/src/tests/intg/ldap_local_override_test.py
+++ b/src/tests/intg/ldap_local_override_test.py
@@ -529,11 +529,11 @@ def test_show_user_override(ldap_conn, 
env_show_user_override):
 
     out = check_output(['sss_override', 'user-show', 'user1'])
     assert out == "user1@LDAP:ov_user1:10010:20010:Overriden User 1:"\
-                  "/home/ov/user1:/bin/ov_user1_shell\n"
+                  "/home/ov/user1:/bin/ov_user1_shell:\n"
 
     out = check_output(['sss_override', 'user-show', 'user2@LDAP'])
     assert out == "user2@LDAP:ov_user2:10020:20020:Overriden User 2:"\
-                  "/home/ov/user2:/bin/ov_user2_shell\n"
+                  "/home/ov/user2:/bin/ov_user2_shell:\n"
 
     # Return error on non-existing user
     ret = subprocess.call(['sss_override', 'user-show', 'nonexisting_user'])
@@ -557,9 +557,9 @@ def test_find_user_override(ldap_conn, 
env_find_user_override):
 
     # Expected override of users
     exp_usr_ovrd = ['user1@LDAP:ov_user1:10010:20010:Overriden User 1:'
-                    '/home/ov/user1:/bin/ov_user1_shell',
+                    '/home/ov/user1:/bin/ov_user1_shell:',
                     'user2@LDAP:ov_user2:10020:20020:Overriden User 2:'
-                    '/home/ov/user2:/bin/ov_user2_shell']
+                    '/home/ov/user2:/bin/ov_user2_shell:']
 
     assert set(out.splitlines()) == set(exp_usr_ovrd)
 
diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c
index 
7e63bdf6ecb3bb968f631e79f691942237f61793..f911ce8806228d3b1b9fb113cc5b451a04a44140
 100644
--- a/src/tools/sss_override.c
+++ b/src/tools/sss_override.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 
 #include "util/util.h"
+#include "util/crypto/sss_crypto.h"
 #include "db/sysdb.h"
 #include "tools/common/sss_tools.h"
 #include "tools/common/sss_colondb.h"
@@ -39,6 +40,7 @@ struct override_user {
     const char *home;
     const char *shell;
     const char *gecos;
+    const char *cert;
 };
 
 struct override_group {
@@ -97,6 +99,7 @@ static int parse_cmdline_user_add(struct sss_cmdline *cmdline,
         {"home", 'h', POPT_ARG_STRING, &user->home, 0, _("Override home 
directory"), NULL },
         {"shell", 's', POPT_ARG_STRING, &user->shell, 0, _("Override shell"), 
NULL },
         {"gecos", 'c', POPT_ARG_STRING, &user->gecos, 0, _("Override gecos"), 
NULL },
+        {"certificate", 'x', POPT_ARG_STRING, &user->cert, 0, _("Override 
certificate"), NULL },
         POPT_TABLEEND
     };
 
@@ -296,7 +299,8 @@ static struct sysdb_attrs *build_attrs(TALLOC_CTX *mem_ctx,
                                        gid_t gid,
                                        const char *home,
                                        const char *shell,
-                                       const char *gecos)
+                                       const char *gecos,
+                                       const char *cert)
 {
     struct sysdb_attrs *attrs;
     errno_t ret;
@@ -348,6 +352,13 @@ static struct sysdb_attrs *build_attrs(TALLOC_CTX *mem_ctx,
         }
     }
 
+    if (cert != NULL) {
+        ret = sysdb_attrs_add_base64_blob(attrs, SYSDB_USER_CERT, cert);
+        if (ret != EOK) {
+            goto done;
+        }
+    }
+
     ret = EOK;
 
 done:
@@ -363,13 +374,13 @@ static struct sysdb_attrs *build_user_attrs(TALLOC_CTX 
*mem_ctx,
                                             struct override_user *user)
 {
     return build_attrs(mem_ctx, user->name, user->uid, user->gid, user->home,
-                       user->shell, user->gecos);
+                       user->shell, user->gecos, user->cert);
 }
 
 static struct sysdb_attrs *build_group_attrs(TALLOC_CTX *mem_ctx,
                                              struct override_group *group)
 {
-    return build_attrs(mem_ctx, group->name, 0, group->gid, 0, NULL, NULL);
+    return build_attrs(mem_ctx, group->name, 0, group->gid, 0, NULL, NULL, 
NULL);
 }
 
 static char *get_fqname(TALLOC_CTX *mem_ctx,
@@ -1101,6 +1112,7 @@ list_user_overrides(TALLOC_CTX *mem_ctx,
     size_t i;
     errno_t ret;
     const char *attrs[] = SYSDB_PW_ATTRS;
+    struct ldb_message_element *el;
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
@@ -1136,6 +1148,20 @@ list_user_overrides(TALLOC_CTX *mem_ctx,
         objs[i].shell = ldb_msg_find_attr_as_string(msgs[i], SYSDB_SHELL, 
NULL);
         objs[i].gecos = ldb_msg_find_attr_as_string(msgs[i], SYSDB_GECOS, 
NULL);
 
+        el = ldb_msg_find_element(msgs[i], SYSDB_USER_CERT);
+        if (el != NULL && el->num_values > 0) {
+            /* Currently we support only 1 certificate override */
+            objs[i].cert = sss_base64_encode(objs, el->values[0].data,
+                                             el->values[0].length);
+            if (objs[i].cert == NULL) {
+                DEBUG(SSSDBG_CRIT_FAILURE, "sss_base64_encode failed.\n");
+                ret = ERR_INTERNAL;
+                goto done;
+            }
+        } else {
+            objs[i].cert = NULL;
+        }
+
         talloc_steal(objs, objs[i].orig_name);
         talloc_steal(objs, objs[i].name);
         talloc_steal(objs, objs[i].home);
@@ -1249,7 +1275,7 @@ static errno_t user_export(const char *filename,
 
         for (i = 0; objs[i].orig_name != NULL; i++) {
             /**
-             * Format: orig_name:name:uid:gid:gecos:home:shell
+             * Format: orig_name:name:uid:gid:gecos:home:shell:certificate
              */
             struct sss_colondb_write_field table[] = {
                 {SSS_COLONDB_STRING, {.str = objs[i].orig_name}},
@@ -1259,6 +1285,7 @@ static errno_t user_export(const char *filename,
                 {SSS_COLONDB_STRING, {.str = objs[i].gecos}},
                 {SSS_COLONDB_STRING, {.str = objs[i].home}},
                 {SSS_COLONDB_STRING, {.str = objs[i].shell}},
+                {SSS_COLONDB_STRING, {.str = objs[i].cert}},
                 {SSS_COLONDB_SENTINEL, {0}}
             };
 
@@ -1523,7 +1550,7 @@ static int override_user_import(struct sss_cmdline 
*cmdline,
     }
 
     /**
-     * Format: orig_name:name:uid:gid:gecos:home:shell
+     * Format: orig_name:name:uid:gid:gecos:home:shell:certificate
      */
     struct sss_colondb_read_field table[] = {
         {SSS_COLONDB_STRING, {.str = &obj.input_name}},
@@ -1533,6 +1560,7 @@ static int override_user_import(struct sss_cmdline 
*cmdline,
         {SSS_COLONDB_STRING, {.str = &obj.gecos}},
         {SSS_COLONDB_STRING, {.str = &obj.home}},
         {SSS_COLONDB_STRING, {.str = &obj.shell}},
+        {SSS_COLONDB_STRING, {.str = &obj.cert}},
         {SSS_COLONDB_SENTINEL, {0}}
     };
 
-- 
2.1.0

From 9745955dc16be996de938667d6ece16b3d48f113 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Fri, 22 Apr 2016 17:56:05 +0200
Subject: [PATCH 10/12] IPA: allow lookups by cert in sub-domains on the client

---
 src/providers/ipa/ipa_s2n_exop.c      | 18 +++++++++++++++++-
 src/providers/ipa/ipa_subdomains.h    |  4 +++-
 src/providers/ipa/ipa_subdomains_id.c | 21 +++++++++++++++++----
 3 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 
b6136befaa78ac30e7bf2ca52ef1875e16a74304..bdbe8ea9ff851a83d6b76fd3cd745218cc270820
 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -36,7 +36,8 @@ enum input_types {
     INP_SID = 1,
     INP_NAME,
     INP_POSIX_UID,
-    INP_POSIX_GID
+    INP_POSIX_GID,
+    INP_CERT
 };
 
 enum request_types {
@@ -363,6 +364,17 @@ static errno_t s2n_encode_request(TALLOC_CTX *mem_ctx,
                 goto done;
             }
             break;
+        case BE_REQ_BY_CERT:
+            if (req_input->type == REQ_INP_CERT) {
+            ret = ber_printf(ber, "{ees}", INP_CERT, request_type,
+                                           req_input->inp.cert);
+            } else {
+                DEBUG(SSSDBG_OP_FAILURE, "Unexpected input type [%d].\n",
+                                          req_input->type);
+                ret = EINVAL;
+                goto done;
+            }
+            break;
         default:
             ret = EINVAL;
             goto done;
@@ -1535,6 +1547,10 @@ static void ipa_s2n_get_user_done(struct tevent_req 
*subreq)
     talloc_zfree(subreq);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "s2n exop request failed.\n");
+        if (state->req_input->type == REQ_INP_CERT) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                "Maybe the server does not support lookups by 
certificates.\n");
+        }
         goto done;
     }
 
diff --git a/src/providers/ipa/ipa_subdomains.h 
b/src/providers/ipa/ipa_subdomains.h
index 
23c3b7e3cd3ee1e0ac1dbcf98dc71a6c2337b835..9eb841b027041feb70149ad76a3992a28da7bc36
 100644
--- a/src/providers/ipa/ipa_subdomains.h
+++ b/src/providers/ipa/ipa_subdomains.h
@@ -116,7 +116,8 @@ int ipa_ad_subdom_init(struct be_ctx *be_ctx,
 enum req_input_type {
     REQ_INP_NAME,
     REQ_INP_ID,
-    REQ_INP_SECID
+    REQ_INP_SECID,
+    REQ_INP_CERT
 };
 
 struct req_input {
@@ -125,6 +126,7 @@ struct req_input {
         const char *name;
         uint32_t id;
         const char *secid;
+        const char *cert;
     } inp;
 };
 
diff --git a/src/providers/ipa/ipa_subdomains_id.c 
b/src/providers/ipa/ipa_subdomains_id.c
index 
e8dd82446f58afc5dfd439ce88cb2b5741c9f100..665ff635b878370d92590c99a132b0ab14fbada6
 100644
--- a/src/providers/ipa/ipa_subdomains_id.c
+++ b/src/providers/ipa/ipa_subdomains_id.c
@@ -528,10 +528,23 @@ static void ipa_get_subdom_acct_connected(struct 
tevent_req *subreq)
             }
             break;
         case BE_FILTER_CERT:
-            DEBUG(SSSDBG_OP_FAILURE, "Lookup by certificate not supported 
yet.\n");
-            state->dp_error = dp_error;
-            tevent_req_error(req, EINVAL);
-            return;
+            if (sdap_is_extension_supported(sdap_id_op_handle(state->op),
+                                            EXOP_SID2NAME_V1_OID)) {
+                req_input->type = REQ_INP_CERT;
+                req_input->inp.cert = talloc_strdup(req_input, state->filter);
+                if (req_input->inp.cert == NULL) {
+                    DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
+                    tevent_req_error(req, ENOMEM);
+                    return;
+                }
+            } else {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "Lookup by certificate not supported by the server.\n");
+                state->dp_error = DP_ERR_OK;
+                tevent_req_error(req, EINVAL);
+                return;
+            }
+            break;
         default:
             DEBUG(SSSDBG_OP_FAILURE, "Invalid sub-domain filter type.\n");
             state->dp_error = dp_error;
-- 
2.1.0

From 065150bfcbb833ad16ccea24caa9e4d60f06e861 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Mon, 25 Apr 2016 16:09:48 +0200
Subject: [PATCH 11/12] NSS: add SSS_NSS_GETNAMEBYCERT request

---
 Makefile.am                     |   1 +
 src/responder/nss/nsssrv_cmd.c  | 117 ++++++++++++++++++++++++++++++++
 src/sss_client/sss_cli.h        |   5 ++
 src/tests/cmocka/test_nss_srv.c | 145 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 268 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 
390e58938b123a4043edec3bc4dea0230c0fd298..d20a10fa61f8a2fc296f839318503960382a9879
 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1928,6 +1928,7 @@ nss_srv_tests_LDFLAGS = \
     -Wl,-wrap,sss_ncache_check_user \
     -Wl,-wrap,sss_ncache_check_uid \
     -Wl,-wrap,sss_ncache_check_sid \
+    -Wl,-wrap,sss_ncache_check_cert \
     -Wl,-wrap,sss_packet_get_body \
     -Wl,-wrap,sss_packet_get_cmd \
     -Wl,-wrap,sss_cmd_send_empty \
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 
f44ae6f26a7ad82b9f19d487ef08f3c055fd3f3d..762c26b74581acb5568b602caaef2586521f6903
 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -23,12 +23,14 @@
 #include "util/sss_nss.h"
 #include "util/sss_cli_cmd.h"
 #include "util/crypto/sss_crypto.h"
+#include "util/cert.h"
 #include "responder/nss/nsssrv.h"
 #include "responder/nss/nsssrv_private.h"
 #include "responder/nss/nsssrv_netgroup.h"
 #include "responder/nss/nsssrv_services.h"
 #include "responder/nss/nsssrv_mmap_cache.h"
 #include "responder/common/negcache.h"
+#include "responder/common/responder_cache_req.h"
 #include "providers/data_provider.h"
 #include "confdb/confdb.h"
 #include "db/sysdb.h"
@@ -5492,6 +5494,115 @@ done:
     return nss_cmd_done(cmdctx, ret);
 }
 
+static void users_find_by_cert_done(struct tevent_req *req);
+
+static int nss_cmd_getbycert(enum sss_cli_command cmd, struct cli_ctx *cctx)
+{
+
+    struct tevent_req *req;
+    uint8_t *body;
+    size_t blen;
+    int ret;
+    const char *derb64;
+    char *pem_cert = NULL;
+    size_t pem_size;
+    struct nss_ctx *nctx;
+
+    nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx);
+
+    if (cmd != SSS_NSS_GETNAMEBYCERT) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid command type [%d][%s].\n",
+              cmd, sss_cmd2str(cmd));
+        return EINVAL;
+    }
+
+    /* get certificate to query */
+    sss_packet_get_body(cctx->creq->in, &body, &blen);
+
+    /* if not terminated fail */
+    if (body[blen -1] != '\0') {
+        return EINVAL;
+    }
+
+    derb64 = (const char *) body;
+
+    /* check input */
+    ret = sss_cert_derb64_to_pem(cctx, derb64, &pem_cert, &pem_size);
+    talloc_free(pem_cert);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_cert_pem_to_derb64 failed.\n");
+        return ret;
+    }
+
+    req = cache_req_user_by_cert_send(cctx, cctx->rctx->ev, cctx->rctx,
+                                      nctx->rctx->ncache, 0, NULL, derb64);
+    if (req == NULL) {
+        return ENOMEM;
+    }
+
+    tevent_req_set_callback(req, users_find_by_cert_done, cctx);
+
+    return EOK;
+}
+
+static void users_find_by_cert_done(struct tevent_req *req)
+{
+    struct cli_ctx *cctx;
+    struct sss_domain_info *domain;
+    struct ldb_result *result;
+    errno_t ret;
+
+    cctx = tevent_req_callback_data(req, struct cli_ctx);
+
+    ret = cache_req_user_by_cert_recv(cctx, req, &result, &domain, NULL);
+    talloc_zfree(req);
+    if (ret == ENOENT || result->count == 0) {
+        ret = ENOENT;
+        goto done;
+    } else if (ret != EOK) {
+        goto done;
+    }
+
+    if (result->count > 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Found more than 1 result with certficate search.\n");
+
+        ret = EINVAL;
+        goto done;
+    }
+
+
+    ret = sss_packet_new(cctx->creq, 0,
+                         sss_packet_get_cmd(cctx->creq->in),
+                         &cctx->creq->out);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_packet_new failed.\n");
+        ret = EFAULT;
+        goto done;
+    }
+
+    ret = fill_name(cctx->creq->out, domain, SSS_ID_TYPE_UID, true,
+                    result->msgs[0]);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "fill_name failed.\n");
+        goto done;
+    }
+
+    ret = EOK;
+
+done:
+    if (ret == EOK) {
+        sss_packet_set_error(cctx->creq->out, EOK);
+        sss_cmd_done(cctx, NULL);
+    } else if (ret == ENOENT) {
+        sss_cmd_send_empty(cctx, NULL);
+    } else {
+        sss_cmd_send_error(cctx, ret);
+    }
+
+    return;
+}
+
 static int nss_cmd_getsidbyname(struct cli_ctx *cctx)
 {
     return nss_cmd_getbynam(SSS_NSS_GETSIDBYNAME, cctx);
@@ -5517,6 +5628,11 @@ static int nss_cmd_getorigbyname(struct cli_ctx *cctx)
     return nss_cmd_getbynam(SSS_NSS_GETORIGBYNAME, cctx);
 }
 
+static int nss_cmd_getnamebycert(struct cli_ctx *cctx)
+{
+    return nss_cmd_getbycert(SSS_NSS_GETNAMEBYCERT, cctx);
+}
+
 struct cli_protocol_version *register_cli_protocol_version(void)
 {
     static struct cli_protocol_version nss_cli_protocol_version[] = {
@@ -5553,6 +5669,7 @@ static struct sss_cmd_table nss_cmds[] = {
     {SSS_NSS_GETNAMEBYSID, nss_cmd_getnamebysid},
     {SSS_NSS_GETIDBYSID, nss_cmd_getidbysid},
     {SSS_NSS_GETORIGBYNAME, nss_cmd_getorigbyname},
+    {SSS_NSS_GETNAMEBYCERT, nss_cmd_getnamebycert},
     {SSS_CLI_NULL, NULL}
 };
 
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index 
f39ceba5e401b742b27a012ea0ef3059cb19aecc..17d8e4503e6cb57fa9c801c54ef71dfbd18d35af
 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -255,6 +255,11 @@ SSS_NSS_GETORIGBYNAME = 0x0115, /**< Takes a zero 
terminated fully qualified
                                      second the value. Hence the list should
                                      have an even number of strings, if not
                                      the whole list is invalid. */
+SSS_NSS_GETNAMEBYCERT = 0x0116, /**< Takes the zero terminated string
+                                     of the base64 encoded DER representation
+                                     of a X509 certificate and returns the zero
+                                     terminated fully qualified name of the
+                                     related object. */
 };
 
 /**
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
index 
3064a96ea30633b5d65a874b16f7a17d9b87101e..44d9c54001393d2fef695589238545d75dd1c904
 100644
--- a/src/tests/cmocka/test_nss_srv.c
+++ b/src/tests/cmocka/test_nss_srv.c
@@ -32,6 +32,8 @@
 #include "responder/nss/nsssrv_private.h"
 #include "sss_client/idmap/sss_nss_idmap.h"
 #include "util/util_sss_idmap.h"
+#include "util/crypto/sss_crypto.h"
+#include "util/crypto/nss/nss_util.h"
 #include "db/sysdb_private.h"   /* new_subdomain() */
 
 #define TESTS_PATH "tp_" BASE_FILE_STEM
@@ -190,6 +192,21 @@ int __wrap_sss_ncache_check_sid(struct sss_nc_ctx *ctx,
     return ret;
 }
 
+int __real_sss_ncache_check_cert(struct sss_nc_ctx *ctx,
+                                 int ttl, const char *cert);
+
+int __wrap_sss_ncache_check_cert(struct sss_nc_ctx *ctx,
+                                 int ttl, const char *cert)
+{
+    int ret;
+
+    ret = __real_sss_ncache_check_cert(ctx, ttl, cert);
+    if (ret == EEXIST) {
+        nss_test_ctx->ncache_hits++;
+    }
+    return ret;
+}
+
 /* Mock input from the client library */
 static void mock_input_user_or_group(const char *username)
 {
@@ -2896,6 +2913,124 @@ void test_nss_getnamebysid_update(void **state)
     assert_string_equal(shell, "/bin/ksh");
 }
 
+#define TEST_TOKEN_CERT \
+"MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
+"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA2MjMx" \
+"NjMyMDdaFw0xNzA2MjMxNjMyMDdaMDIxEjAQBgNVBAoMCUlQQS5ERVZFTDEcMBoG" \
+"A1UEAwwTaXBhLWRldmVsLmlwYS5kZXZlbDCCASIwDQYJKoZIhvcNAQEBBQADggEP" \
+"ADCCAQoCggEBALXUq56VlY+Z0aWLLpFAjFfbElPBXGQsbZb85J3cGyPjaMHC9wS+" \
+"wjB6Ve4HmQyPLx8hbINdDmbawMHYQvTScLYfsqLtj0Lqw20sUUmedk+Es5Oh9VHo" \
+"nd8MavYx25Du2u+T0iSgNIDikXguiwCmtAj8VC49ebbgITcjJGzMmiiuJkV3o93Y" \
+"vvYF0VjLGDQbQWOy7IxzYJeNVJnZWKo67CHdok6qOrm9rxQt81rzwV/mGLbCMUbr" \
+"+N4M8URtd7EmzaYZQmNm//s2owFrCYMxpLiURPj+URZVuB72504/Ix7X0HCbA/AV" \
+"26J27fPY5nc8DMwfhUDCbTqPH/JEjd3mvY8CAwEAAaOCASYwggEiMB8GA1UdIwQY" \
+"MBaAFJOq+KAQmPEnNp8Wok23eGTdE7aDMDsGCCsGAQUFBwEBBC8wLTArBggrBgEF" \
+"BQcwAYYfaHR0cDovL2lwYS1jYS5pcGEuZGV2ZWwvY2Evb2NzcDAOBgNVHQ8BAf8E" \
+"BAMCBPAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHQGA1UdHwRtMGsw" \
+"aaAxoC+GLWh0dHA6Ly9pcGEtY2EuaXBhLmRldmVsL2lwYS9jcmwvTWFzdGVyQ1JM" \
+"LmJpbqI0pDIwMDEOMAwGA1UECgwFaXBhY2ExHjAcBgNVBAMMFUNlcnRpZmljYXRl" \
+"IEF1dGhvcml0eTAdBgNVHQ4EFgQUFaDNd5a53QGpaw5m63hnwXicMQ8wDQYJKoZI" \
+"hvcNAQELBQADggEBADH7Nj00qqGhGJeXJQAsepqSskz/wooqXh8vgVyb8SS4N0/c" \
+"0aQtVmY81xamlXE12ZFpwDX43d+EufBkwCUKFX/+8JFDd2doAyeJxv1xM22kKRpc" \
+"AqITPgMsa9ToGMWxjbVpc/X/5YfZixWPF0/eZUTotBj9oaR039UrhGfyN7OguF/G" \
+"rzmxtB5y4ZrMpcD/Oe90mkd9HY7sA/fB8OWOUgeRfQoh97HNS0UiDWsPtfxmjQG5" \
+"zotpoBIZmdH+ipYsu58HohHVlM9Wi5H4QmiiXl+Soldkq7eXYlafcmT7wv8+cKwz" \
+"Nz0Tm3+eYpFqRo3skr6QzXi525Jkg3r6r+kkhxU="
+
+static int test_nss_getnamebycert_check(uint32_t status, uint8_t *body, size_t 
blen)
+{
+    size_t rp = 2 * sizeof(uint32_t); /* num_results and reserved */
+    uint32_t id_type;
+    const char *name;
+
+    assert_int_equal(status, EOK);
+
+    SAFEALIGN_COPY_UINT32(&id_type, body+rp, &rp);
+    assert_int_equal(id_type, SSS_ID_TYPE_UID);
+
+    name = (const char *) body + rp;
+    assert_string_equal(name, "testcertuser");
+
+    return EOK;
+}
+
+static void test_nss_getnamebycert(void **state)
+{
+    errno_t ret;
+    struct sysdb_attrs *attrs;
+    unsigned char *der = NULL;
+    size_t der_size;
+
+    attrs = sysdb_new_attrs(nss_test_ctx);
+    assert_non_null(attrs);
+
+    der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size);
+    assert_non_null(der);
+
+    ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
+    talloc_free(der);
+    assert_int_equal(ret, EOK);
+
+    /* Prime the cache with a valid user */
+    ret = sysdb_add_user(nss_test_ctx->tctx->dom,
+                         "testcertuser", 23456, 6890, "test cert user",
+                         "/home/testcertuser", "/bin/sh", NULL,
+                         attrs, 300, 0);
+    assert_int_equal(ret, EOK);
+    talloc_free(attrs);
+
+    mock_input_user_or_group(TEST_TOKEN_CERT);
+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETNAMEBYCERT);
+    mock_fill_bysid();
+
+    /* Query for that user, call a callback when command finishes */
+    /* Should go straight to back end, without contacting DP */
+    set_cmd_cb(test_nss_getnamebycert_check);
+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYCERT,
+                          nss_test_ctx->nss_cmds);
+    assert_int_equal(ret, EOK);
+
+    /* Wait until the test finishes with EOK */
+    ret = test_ev_loop(nss_test_ctx->tctx);
+    assert_int_equal(ret, EOK);
+}
+
+void test_nss_getnamebycert_neg(void **state)
+{
+    errno_t ret;
+
+    mock_input_user_or_group(TEST_TOKEN_CERT);
+    mock_account_recv_simple();
+
+    assert_int_equal(nss_test_ctx->ncache_hits, 0);
+
+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYCERT,
+                          nss_test_ctx->nss_cmds);
+    assert_int_equal(ret, EOK);
+
+    /* Wait until the test finishes with ENOENT */
+    ret = test_ev_loop(nss_test_ctx->tctx);
+    assert_int_equal(ret, ENOENT);
+    assert_int_equal(nss_test_ctx->ncache_hits, 0);
+
+    /* Test that subsequent search for a nonexistent user yields
+     * ENOENT and Account callback is not called, on the other hand
+     * the ncache functions will be called
+     */
+    nss_test_ctx->tctx->done = false;
+
+    mock_input_user_or_group(TEST_TOKEN_CERT);
+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETNAMEBYCERT,
+                          nss_test_ctx->nss_cmds);
+    assert_int_equal(ret, EOK);
+
+    /* Wait until the test finishes with ENOENT */
+    ret = test_ev_loop(nss_test_ctx->tctx);
+    assert_int_equal(ret, ENOENT);
+    /* Negative cache was hit this time */
+    assert_int_equal(nss_test_ctx->ncache_hits, 1);
+}
+
 int main(int argc, const char *argv[])
 {
     int rv;
@@ -3009,6 +3144,10 @@ int main(int argc, const char *argv[])
                                         nss_test_setup, nss_test_teardown),
         cmocka_unit_test_setup_teardown(test_nss_getnamebysid_update,
                                         nss_test_setup, nss_test_teardown),
+        cmocka_unit_test_setup_teardown(test_nss_getnamebycert_neg,
+                                        nss_test_setup, nss_test_teardown),
+        cmocka_unit_test_setup_teardown(test_nss_getnamebycert,
+                                        nss_test_setup, nss_test_teardown),
     };
 
     /* Set debug level to invalid value so we can deside if -d 0 was used. */
@@ -3038,5 +3177,11 @@ int main(int argc, const char *argv[])
     if (rv == 0 && !no_cleanup) {
         test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
     }
+
+#ifdef HAVE_NSS
+    /* Cleanup NSS and NSPR to make valgrund happy. */
+    nspr_nss_cleanup();
+#endif
+
     return rv;
 }
-- 
2.1.0

From 3255dd44a69198b6216ec9e13cd2957fb3ee4c81 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Tue, 26 Apr 2016 13:13:43 +0200
Subject: [PATCH 12/12] nss-idmap: add sss_nss_getnamebycert()

---
 Makefile.am                                |  2 +-
 src/python/pysss_nss_idmap.c               | 47 ++++++++++++++++++++++++++++--
 src/responder/nss/nsssrv_cmd.c             |  1 +
 src/sss_client/idmap/sss_nss_idmap.c       | 26 ++++++++++++++++-
 src/sss_client/idmap/sss_nss_idmap.exports |  6 ++++
 src/sss_client/idmap/sss_nss_idmap.h       | 15 ++++++++++
 6 files changed, 93 insertions(+), 4 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 
d20a10fa61f8a2fc296f839318503960382a9879..58255b0dc766e3755d70c12ee312a9aa52d6a724
 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -989,7 +989,7 @@ libsss_nss_idmap_la_LIBADD = \
     $(CLIENT_LIBS)
 libsss_nss_idmap_la_LDFLAGS = \
     -Wl,--version-script,$(srcdir)/src/sss_client/idmap/sss_nss_idmap.exports \
-    -version-info 1:0:1
+    -version-info 2:0:2
 
 dist_noinst_DATA += src/sss_client/idmap/sss_nss_idmap.exports
 
diff --git a/src/python/pysss_nss_idmap.c b/src/python/pysss_nss_idmap.c
index 
36d66f405442d63e430f92862990f1656486112d..a88ef77a3c8056e4962c35811de3dbbb18f4c9a4
 100644
--- a/src/python/pysss_nss_idmap.c
+++ b/src/python/pysss_nss_idmap.c
@@ -33,7 +33,8 @@ enum lookup_type {
     SIDBYNAME,
     SIDBYID,
     NAMEBYSID,
-    IDBYSID
+    IDBYSID,
+    NAMEBYCERT
 };
 
 static int add_dict(PyObject *py_result, PyObject *key, PyObject *res_type,
@@ -166,6 +167,28 @@ static int do_getsidbyid(PyObject *py_result, PyObject 
*py_id)
     return ret;
 }
 
+static int do_getnamebycert(PyObject *py_result, PyObject *py_cert)
+{
+    int ret;
+    const char *cert;
+    char *name = NULL;
+    enum sss_id_type id_type;
+
+    cert = py_string_or_unicode_as_string(py_cert);
+    if (cert == NULL) {
+        return EINVAL;
+    }
+
+    ret = sss_nss_getnamebycert(cert, &name, &id_type);
+    if (ret == 0) {
+        ret = add_dict(py_result, py_cert, PyBytes_FromString(SSS_NAME_KEY),
+                       PyUnicode_FromString(name), PYNUMBER_FROMLONG(id_type));
+    }
+    free(name);
+
+    return ret;
+}
+
 static int do_getidbysid(PyObject *py_result, PyObject *py_sid)
 {
     const char *sid;
@@ -203,6 +226,9 @@ static int do_lookup(enum lookup_type type, PyObject 
*py_result,
     case IDBYSID:
         return do_getidbysid(py_result, py_inp);
         break;
+    case NAMEBYCERT:
+        return do_getnamebycert(py_result, py_inp);
+        break;
     default:
         return ENOSYS;
     }
@@ -260,7 +286,7 @@ static PyObject *check_args(enum lookup_type type, PyObject 
*args)
         case ENOENT: /* nothing found, return empty dict */
             break;
         case EINVAL:
-            PyErr_Format(PyExc_ValueError, "Unable to retrieve argument\n");
+            PyErr_Format(PyExc_ValueError, "Unable to retrieve result\n");
             Py_XDECREF(py_result);
             return NULL;
             break;
@@ -339,6 +365,21 @@ static PyObject * py_getidbysid(PyObject *module, PyObject 
*args)
     return check_args(IDBYSID, args);
 }
 
+PyDoc_STRVAR(getnamebycert_doc,
+"getnamebycert(sid or list/tuple of certificates) -> dict(sid => 
dict(results))\n\
+\n\
+Returns a dictionary with a dictonary of results for each given 
certificates.\n\
+The result dictonary contain the name and the type of the object which can 
be\n\
+accessed with the key constants NAME_KEY and TYPE_KEY, respectively.\n\
+\n\
+NOTE: getnamebycert currently works only with id_provider set as \"ad\" or 
\"ipa\""
+);
+
+static PyObject * py_getnamebycert(PyObject *module, PyObject *args)
+{
+    return check_args(NAMEBYCERT, args);
+}
+
 static PyMethodDef methods[] = {
     { sss_py_const_p(char, "getsidbyname"), (PyCFunction) py_getsidbyname,
       METH_VARARGS, getsidbyname_doc },
@@ -348,6 +389,8 @@ static PyMethodDef methods[] = {
       METH_VARARGS, getnamebysid_doc },
     { sss_py_const_p(char, "getidbysid"), (PyCFunction) py_getidbysid,
       METH_VARARGS, getidbysid_doc },
+    { sss_py_const_p(char, "getnamebycert"), (PyCFunction) py_getnamebycert,
+      METH_VARARGS, getnamebycert_doc },
     { NULL,NULL, 0, NULL }
 };
 
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 
762c26b74581acb5568b602caaef2586521f6903..64e2945a99a6f3262517aa7c817475904418a1ed
 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -5525,6 +5525,7 @@ static int nss_cmd_getbycert(enum sss_cli_command cmd, 
struct cli_ctx *cctx)
     }
 
     derb64 = (const char *) body;
+    DEBUG(SSSDBG_TRACE_ALL, "cert [%s]\n", derb64);
 
     /* check input */
     ret = sss_cert_derb64_to_pem(cctx, derb64, &pem_cert, &pem_size);
diff --git a/src/sss_client/idmap/sss_nss_idmap.c 
b/src/sss_client/idmap/sss_nss_idmap.c
index 
55d8043bd992bebf82a46206a9f3aecbe1e88238..fa5a499e3606f7e45a406de4d63002ba35365cb1
 100644
--- a/src/sss_client/idmap/sss_nss_idmap.c
+++ b/src/sss_client/idmap/sss_nss_idmap.c
@@ -159,7 +159,8 @@ static int sss_nss_getyyybyxxx(union input inp, enum 
sss_cli_command cmd ,
     case SSS_NSS_GETNAMEBYSID:
     case SSS_NSS_GETIDBYSID:
     case SSS_NSS_GETORIGBYNAME:
-        ret = sss_strnlen(inp.str, SSS_NAME_MAX, &inp_len);
+    case SSS_NSS_GETNAMEBYCERT:
+        ret = sss_strnlen(inp.str, 2048, &inp_len);
         if (ret != EOK) {
             return EINVAL;
         }
@@ -209,6 +210,7 @@ static int sss_nss_getyyybyxxx(union input inp, enum 
sss_cli_command cmd ,
     case SSS_NSS_GETSIDBYID:
     case SSS_NSS_GETSIDBYNAME:
     case SSS_NSS_GETNAMEBYSID:
+    case SSS_NSS_GETNAMEBYCERT:
         if (data_len <= 1 || repbuf[replen - 1] != '\0') {
             ret = EBADMSG;
             goto done;
@@ -368,3 +370,25 @@ int sss_nss_getorigbyname(const char *fq_name, struct 
sss_nss_kv **kv_list,
 
     return ret;
 }
+
+int sss_nss_getnamebycert(const char *cert, char **fq_name,
+                          enum sss_id_type *type)
+{
+    int ret;
+    union input inp;
+    struct output out;
+
+    if (fq_name == NULL || cert == NULL || *cert == '\0') {
+        return EINVAL;
+    }
+
+    inp.str = cert;
+
+    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYCERT, &out);
+    if (ret == EOK) {
+        *fq_name = out.d.str;
+        *type = out.type;
+    }
+
+    return ret;
+}
diff --git a/src/sss_client/idmap/sss_nss_idmap.exports 
b/src/sss_client/idmap/sss_nss_idmap.exports
index 
8aa4702416534c49176d29cee381e1c9292c4847..bd5d80212017d38334c3cdeefa47d6029f42aebb
 100644
--- a/src/sss_client/idmap/sss_nss_idmap.exports
+++ b/src/sss_client/idmap/sss_nss_idmap.exports
@@ -19,3 +19,9 @@ SSS_NSS_IDMAP_0.1.0 {
         sss_nss_getorigbyname;
         sss_nss_free_kv;
 } SSS_NSS_IDMAP_0.0.1;
+
+SSS_NSS_IDMAP_0.2.0 {
+    # public functions
+    global:
+        sss_nss_getnamebycert;
+} SSS_NSS_IDMAP_0.1.0;
diff --git a/src/sss_client/idmap/sss_nss_idmap.h 
b/src/sss_client/idmap/sss_nss_idmap.h
index 
78a8a11c1d597e7d19bb692dcaeb566b770b900e..8a6299194e7b91e084b26c0c96e2f93875a832e7
 100644
--- a/src/sss_client/idmap/sss_nss_idmap.h
+++ b/src/sss_client/idmap/sss_nss_idmap.h
@@ -124,6 +124,21 @@ int sss_nss_getorigbyname(const char *fq_name, struct 
sss_nss_kv **kv_list,
                           enum sss_id_type *type);
 
 /**
+ * @brief Return the fully qualified name for the given base64 encoded
+ * X.509 certificate in DER format
+ *
+ * @param[in] cert     base64 encoded certificate
+ * @param[out] fq_name Fully qualified name of a user or a group,
+ *                     must be freed by the caller
+ * @param[out] type    Type of the object related to the SID
+ *
+ * @return
+ *  - see #sss_nss_getsidbyname
+ */
+int sss_nss_getnamebycert(const char *cert, char **fq_name,
+                          enum sss_id_type *type);
+
+/**
  * @brief Free key-value list returned by sss_nss_getorigbyname()
  *
  * @param[in] kv_list Key-value list returned by sss_nss_getorigbyname().
-- 
2.1.0

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/admin/lists/sssd-devel@lists.fedorahosted.org

Reply via email to