[SSSD] [PATCHES] IFP: add FindByCertificate method for User objects

Sumit Bose sbose at redhat.com
Thu Jun 4 09:06:48 UTC 2015


Hi,

this patch-set aims to solve https://fedorahosted.org/sssd/ticket/2596.
The first patch is unrelated but needed to make the changes in the
second patch properly aligned.

Patches 3,4 and 6 add some certificate related utilities while patch 5
adds the backend changes and patch 7 the changes for InfoPipe.

bye,
Sumit
-------------- next part --------------
From 8ac976d5e5476c7dcf7fac2217f0b6c9bb1daab4 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 7 May 2015 10:58:33 +0200
Subject: [PATCH 1/7] adding ldap_user_auth_type where missing

---
 src/config/SSSDConfig/__init__.py.in     | 2 ++
 src/config/etc/sssd.api.d/sssd-ad.conf   | 1 +
 src/config/etc/sssd.api.d/sssd-ipa.conf  | 1 +
 src/config/etc/sssd.api.d/sssd-ldap.conf | 1 +
 4 files changed, 5 insertions(+)

diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index f58c52faf7dd3f9199bd0af4286546d4fe804a88..4851f20810b8bc793916db04c8709b6189271452 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -306,6 +306,8 @@ option_strings = {
     'ldap_user_nds_login_expiration_time' : _('loginExpirationTime attribute of NDS'),
     'ldap_user_nds_login_allowed_time_map' : _('loginAllowedTimeMap attribute of NDS'),
     'ldap_user_ssh_public_key' : _('SSH public key attribute'),
+    'ldap_user_auth_type' : _('attribute listing allowed authentication types for a user'),
+
     'ldap_user_extra_attrs' : _('A list of extra attributes to download along with the user entry'),
 
     'ldap_group_search_base' : _('Base DN for group lookups'),
diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
index c46f3a7cb50db519d113e15f425c7f746d34ad81..23194d38a35fcc9ae2134c3dbbc7cef1aefcf079 100644
--- a/src/config/etc/sssd.api.d/sssd-ad.conf
+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
@@ -93,6 +93,7 @@ ldap_user_krb_last_pwd_change = str, None, false
 ldap_user_krb_password_expiration = str, None, false
 ldap_pwd_attribute = str, None, false
 ldap_user_ssh_public_key = str, None, false
+ldap_user_auth_type = str, None, false
 ldap_group_search_base = str, None, false
 ldap_group_search_scope = str, None, false
 ldap_group_search_filter = str, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
index 6bae609fa9ff57e70c195b858eeea4eca680f62f..075a74e3aabe4ff664814b8a1aef8117496e9273 100644
--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
@@ -89,6 +89,7 @@ ldap_user_krb_last_pwd_change = str, None, false
 ldap_user_krb_password_expiration = str, None, false
 ldap_pwd_attribute = str, None, false
 ldap_user_ssh_public_key = str, None, false
+ldap_user_auth_type = str, None, false
 ldap_group_search_base = str, None, false
 ldap_group_search_scope = str, None, false
 ldap_group_search_filter = str, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
index ba5f56f1942da552fc6ab8f82851714756683a8f..e27d570b8cdf8ad765d16b8f8befe5c25fbebc28 100644
--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
@@ -83,6 +83,7 @@ ldap_user_nds_login_disabled = str, None, false
 ldap_user_nds_login_expiration_time = str, None, false
 ldap_user_nds_login_allowed_time_map = str, None, false
 ldap_user_ssh_public_key = str, None, false
+ldap_user_auth_type = str, None, false
 ldap_group_search_base = str, None, false
 ldap_group_search_scope = str, None, false
 ldap_group_search_filter = str, None, false
-- 
2.1.0

-------------- next part --------------
From 7eaaeb2561fdbaef1c562be9a5457aa77bba6e85 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Thu, 7 May 2015 10:59:10 +0200
Subject: [PATCH 2/7] LDAP: add ldap_user_certificate option

Related to https://fedorahosted.org/sssd/ticket/2596
---
 src/config/SSSDConfig/__init__.py.in     |  1 +
 src/config/etc/sssd.api.d/sssd-ad.conf   |  1 +
 src/config/etc/sssd.api.d/sssd-ipa.conf  |  1 +
 src/config/etc/sssd.api.d/sssd-ldap.conf |  1 +
 src/db/sysdb.h                           |  1 +
 src/man/sssd-ldap.5.xml                  | 14 ++++++++++++++
 src/providers/ad/ad_opts.h               |  1 +
 src/providers/ipa/ipa_opts.h             |  1 +
 src/providers/ldap/ldap_opts.h           |  3 +++
 src/providers/ldap/sdap.h                |  1 +
 10 files changed, 25 insertions(+)

diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 4851f20810b8bc793916db04c8709b6189271452..2d488d878450623ff4cc92bf3423acab4f38059e 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -307,6 +307,7 @@ option_strings = {
     'ldap_user_nds_login_allowed_time_map' : _('loginAllowedTimeMap attribute of NDS'),
     'ldap_user_ssh_public_key' : _('SSH public key attribute'),
     'ldap_user_auth_type' : _('attribute listing allowed authentication types for a user'),
+    'ldap_user_certificate' : _('attribute containing the X509 certificate of the user'),
 
     'ldap_user_extra_attrs' : _('A list of extra attributes to download along with the user entry'),
 
diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
index 23194d38a35fcc9ae2134c3dbbc7cef1aefcf079..faab3a51e54d6d498392021a8945501120870f70 100644
--- a/src/config/etc/sssd.api.d/sssd-ad.conf
+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
@@ -94,6 +94,7 @@ ldap_user_krb_password_expiration = str, None, false
 ldap_pwd_attribute = str, None, false
 ldap_user_ssh_public_key = str, None, false
 ldap_user_auth_type = str, None, false
+ldap_user_certificate = str, None, false
 ldap_group_search_base = str, None, false
 ldap_group_search_scope = str, None, false
 ldap_group_search_filter = str, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
index 075a74e3aabe4ff664814b8a1aef8117496e9273..cfcc00f6f7ca768df861e8cf7face065f90e9e83 100644
--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
@@ -90,6 +90,7 @@ ldap_user_krb_password_expiration = str, None, false
 ldap_pwd_attribute = str, None, false
 ldap_user_ssh_public_key = str, None, false
 ldap_user_auth_type = str, None, false
+ldap_user_certificate = str, None, false
 ldap_group_search_base = str, None, false
 ldap_group_search_scope = str, None, false
 ldap_group_search_filter = str, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
index e27d570b8cdf8ad765d16b8f8befe5c25fbebc28..c10290217b1b133792b893d9b80e2599969838a6 100644
--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
@@ -84,6 +84,7 @@ ldap_user_nds_login_expiration_time = str, None, false
 ldap_user_nds_login_allowed_time_map = str, None, false
 ldap_user_ssh_public_key = str, None, false
 ldap_user_auth_type = str, None, false
+ldap_user_certificate = str, None, false
 ldap_group_search_base = str, None, false
 ldap_group_search_scope = str, None, false
 ldap_group_search_filter = str, None, false
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 4035a39d3cd37390259cda79e6fcafe688bfd360..361d26d37481c521e93584b23af48a0861296e1f 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -132,6 +132,7 @@
 #define SYSDB_SSH_PUBKEY "sshPublicKey"
 
 #define SYSDB_AUTH_TYPE "authType"
+#define SYSDB_USER_CERT "userCertificate"
 
 #define SYSDB_SUBDOMAIN_REALM "realmName"
 #define SYSDB_SUBDOMAIN_FLAT "flatName"
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index 1b7a2609ac4ebd0bccfd15a04d041e283bcf9cab..f14090843fd32141ad4f491b69868aa7b2412301 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -814,6 +814,20 @@
                 </varlistentry>
 
                 <varlistentry>
+                    <term>ldap_user_certificate (string)</term>
+                    <listitem>
+                        <para>
+                            Name of the LDAP attribute containing the X509
+                            certificate of the user.
+                        </para>
+                        <para>
+                            Default: no set in the general case, userCertificate
+                            for IPA
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
                     <term>ldap_group_object_class (string)</term>
                     <listitem>
                         <para>
diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
index 0f03d33839affe1381fd5eb72bfeba6e5b1dcc68..cb4c05d846d9abe5eedb28013ad13fff6476d431 100644
--- a/src/providers/ad/ad_opts.h
+++ b/src/providers/ad/ad_opts.h
@@ -216,6 +216,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 },
     SDAP_ATTR_MAP_TERMINATOR
 };
 
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index 34e9e167eb46f290d017b5af817571122b359b4f..253c0715355536cc181c57beed5326a77e87e464 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -203,6 +203,7 @@ struct sdap_attr_map ipa_user_map[] = {
     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
     { "ldap_user_ssh_public_key", "ipaSshPubKey", SYSDB_SSH_PUBKEY, NULL },
     { "ldap_user_auth_type", "ipaUserAuthType", SYSDB_AUTH_TYPE, NULL },
+    { "ldap_user_certificate", "userCertificate", SYSDB_USER_CERT, NULL },
     SDAP_ATTR_MAP_TERMINATOR
 };
 
diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
index f449ec7c309a5f664941cdefbb3c45a2fab10c99..c1b9bf688ef0a92046195c13a11d2c17b2419d67 100644
--- a/src/providers/ldap/ldap_opts.h
+++ b/src/providers/ldap/ldap_opts.h
@@ -180,6 +180,7 @@ struct sdap_attr_map rfc2307_user_map[] = {
     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
     { "ldap_user_ssh_public_key", "sshPublicKey", SYSDB_SSH_PUBKEY, NULL },
     { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
+    { "ldap_user_certificate", NULL, SYSDB_USER_CERT, NULL },
     SDAP_ATTR_MAP_TERMINATOR
 };
 
@@ -235,6 +236,7 @@ struct sdap_attr_map rfc2307bis_user_map[] = {
     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
     { "ldap_user_ssh_public_key", "sshPublicKey", SYSDB_SSH_PUBKEY, NULL },
     { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL },
+    { "ldap_user_certificate", NULL, SYSDB_USER_CERT, NULL },
     SDAP_ATTR_MAP_TERMINATOR
 };
 
@@ -290,6 +292,7 @@ struct sdap_attr_map gen_ad2008r2_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 },
     SDAP_ATTR_MAP_TERMINATOR
 };
 
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index d7f6c646e59a8af8347e39afb644d8ea40b9a4c3..582ac8d4d51e63d3fff42417d63ea3d8959f502a 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -281,6 +281,7 @@ enum sdap_user_attrs {
     SDAP_AT_NDS_LOGIN_ALLOWED_TIME_MAP,
     SDAP_AT_USER_SSH_PUBLIC_KEY,
     SDAP_AT_USER_AUTH_TYPE,
+    SDAP_AT_USER_CERT,
 
     SDAP_OPTS_USER /* attrs counter */
 };
-- 
2.1.0

-------------- next part --------------
From d36e68e147a3f5614af2cdfcb9f4cbb26a3df5e5 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 8 May 2015 09:02:26 +0200
Subject: [PATCH 3/7] certs: add PEM/DER conversion utilities

Related to https://fedorahosted.org/sssd/ticket/2596
---
 Makefile.am                        |  33 ++++
 configure.ac                       |   5 +-
 src/tests/cmocka/test_cert_utils.c | 361 +++++++++++++++++++++++++++++++++++++
 src/util/cert.h                    |  47 +++++
 src/util/cert/cert_common.c        | 154 ++++++++++++++++
 src/util/cert/libcrypto/cert.c     | 168 +++++++++++++++++
 6 files changed, 765 insertions(+), 3 deletions(-)
 create mode 100644 src/tests/cmocka/test_cert_utils.c
 create mode 100644 src/util/cert.h
 create mode 100644 src/util/cert/cert_common.c
 create mode 100644 src/util/cert/libcrypto/cert.c

diff --git a/Makefile.am b/Makefile.am
index 34c18ebbf8f75abee0200892c395c9601b570472..303dd44e1e0e3e66c8d2739051a9d5d63bf8e075 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -225,6 +225,7 @@ if HAVE_CMOCKA
         test_sbus_opath \
         test_fo_srv \
         pam-srv-tests \
+        test_cert_utils \
         $(NULL)
 
 if HAVE_LIBRESOLV
@@ -495,6 +496,7 @@ endif
 dist_noinst_HEADERS = \
     src/monitor/monitor.h \
     src/util/crypto/sss_crypto.h \
+    src/util/cert.h \
     src/util/dlinklist.h \
     src/util/util.h \
     src/util/io.h \
@@ -716,6 +718,23 @@ libsss_crypt_la_LIBADD = \
 libsss_crypt_la_LDFLAGS = \
     -avoid-version
 
+pkglib_LTLIBRARIES += libsss_cert.la
+
+libsss_cert_la_SOURCES = \
+    src/util/cert/cert_common.c \
+    src/util/cert/libcrypto/cert.c \
+    $(NULL)
+libsss_cert_la_CFLAGS = \
+    $(CRYPTO_CFLAGS) \
+    $(NULL)
+libsss_cert_la_LIBADD = \
+    $(CRYPTO_LIBS) \
+    libsss_crypt.la \
+    $(NULL)
+libsss_cert_la_LDFLAGS = \
+    -avoid-version \
+    $(NULL)
+
 pkglib_LTLIBRARIES += libsss_util.la
 libsss_util_la_SOURCES = \
     src/confdb/confdb.c \
@@ -2405,6 +2424,20 @@ test_fo_srv_LDADD = \
     libsss_test_common.la \
     $(NULL)
 
+test_cert_utils_SOURCES = \
+    src/tests/cmocka/test_cert_utils.c \
+    $(NULL)
+test_cert_utils_CFLAGS = \
+    $(AM_CFLAGS) \
+    $(NULL)
+test_cert_utils_LDADD = \
+    $(CMOCKA_LIBS) \
+    $(POPT_LIBS) \
+    $(TALLOC_LIBS) \
+    libsss_debug.la \
+    libsss_test_common.la \
+    libsss_cert.la \
+    $(NULL)
 endif # HAVE_CMOCKA
 
 noinst_PROGRAMS = pam_test_client
diff --git a/configure.ac b/configure.ac
index a127d0bd57ee4149f664e193a65271d50d95f83b..d1c6ba35f6deed327ca8305cc567b77b9a9be5d6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -339,9 +339,8 @@ fi
 if test x$cryptolib = xnss; then
     AM_CHECK_NSS
 fi
-if test x$cryptolib = xlibcrypto; then
-    AM_CHECK_LIBCRYPTO
-fi
+
+AM_CHECK_LIBCRYPTO
 
 AM_CHECK_INOTIFY
 
diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c
new file mode 100644
index 0000000000000000000000000000000000000000..5bcbafb27dbdff596c07b8aad10ca15a35ff4ef5
--- /dev/null
+++ b/src/tests/cmocka/test_cert_utils.c
@@ -0,0 +1,361 @@
+/*
+    SSSD
+
+    Certificates - Utilities tests
+
+    Authors:
+        Sumit Bose <sbose at redhat.com>
+
+    Copyright (C) 2015 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <popt.h>
+#include <openssl/objects.h>
+
+#include "util/cert.h"
+#include "tests/cmocka/common_mock.h"
+#include "util/crypto/nss/nss_util.h"
+
+
+/* TODO: create a certificate for this test */
+const uint8_t test_cert_der[] = {
+0x30, 0x82, 0x04, 0x09, 0x30, 0x82, 0x02, 0xf1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x09,
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+0x34, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x49, 0x50, 0x41, 0x2e,
+0x44, 0x45, 0x56, 0x45, 0x4c, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15,
+0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
+0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x34, 0x32, 0x38, 0x31,
+0x30, 0x32, 0x31, 0x31, 0x31, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x34, 0x32, 0x38, 0x31, 0x30,
+0x32, 0x31, 0x31, 0x31, 0x5a, 0x30, 0x32, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a,
+0x0c, 0x09, 0x49, 0x50, 0x41, 0x2e, 0x44, 0x45, 0x56, 0x45, 0x4c, 0x31, 0x1c, 0x30, 0x1a, 0x06,
+0x03, 0x55, 0x04, 0x03, 0x0c, 0x13, 0x69, 0x70, 0x61, 0x2d, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2e,
+0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06,
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb2, 0x32, 0x92, 0xab, 0x47, 0xb8,
+0x0c, 0x13, 0x54, 0x4a, 0x1f, 0x1e, 0x29, 0x06, 0xff, 0xd0, 0x50, 0xcb, 0xf7, 0x5f, 0x79, 0x91,
+0x65, 0xb1, 0x39, 0x01, 0x83, 0x6a, 0xad, 0x9e, 0x77, 0x3b, 0xf3, 0x0d, 0xd7, 0xb9, 0xf6, 0xdc,
+0x9e, 0x4a, 0x49, 0xa7, 0xd0, 0x66, 0x72, 0xcc, 0xbf, 0x77, 0xd6, 0xde, 0xa9, 0xfe, 0x67, 0x96,
+0xcc, 0x49, 0xf1, 0x37, 0x23, 0x2e, 0xc4, 0x50, 0xf4, 0xeb, 0xba, 0x62, 0xd4, 0x23, 0x4d, 0xf3,
+0x37, 0x38, 0x82, 0xee, 0x3b, 0x3f, 0x2c, 0xd0, 0x80, 0x9b, 0x17, 0xaa, 0x9b, 0xeb, 0xa6, 0xdd,
+0xf6, 0x15, 0xff, 0x06, 0xb2, 0xce, 0xff, 0xdf, 0x8a, 0x9e, 0x95, 0x85, 0x49, 0x1f, 0x84, 0xfd,
+0x81, 0x26, 0xce, 0x06, 0x32, 0x0d, 0x36, 0xca, 0x7c, 0x15, 0x81, 0x68, 0x6b, 0x8f, 0x3e, 0xb3,
+0xa2, 0xfc, 0xae, 0xaf, 0xc2, 0x44, 0x58, 0x15, 0x95, 0x40, 0xfc, 0x56, 0x19, 0x91, 0x80, 0xed,
+0x42, 0x11, 0x66, 0x04, 0xef, 0x3c, 0xe0, 0x76, 0x33, 0x4b, 0x83, 0xfa, 0x7e, 0xb4, 0x47, 0xdc,
+0xfb, 0xed, 0x46, 0xa5, 0x8d, 0x0a, 0x66, 0x87, 0xa5, 0xef, 0x7b, 0x74, 0x62, 0xac, 0xbe, 0x73,
+0x36, 0xc9, 0xb4, 0xfe, 0x20, 0xc4, 0x81, 0xf3, 0xfe, 0x78, 0x19, 0xa8, 0xd0, 0xaf, 0x7f, 0x81,
+0x72, 0x24, 0x61, 0xd9, 0x76, 0x93, 0xe3, 0x0b, 0xd2, 0x4f, 0x19, 0x17, 0x33, 0x57, 0xd4, 0x82,
+0xb0, 0xf1, 0xa8, 0x03, 0xf6, 0x01, 0x99, 0xa9, 0xb8, 0x8c, 0x83, 0xc9, 0xba, 0x19, 0x87, 0xea,
+0xd6, 0x3b, 0x06, 0xeb, 0x4c, 0xf7, 0xf1, 0xe5, 0x28, 0xa9, 0x10, 0xb6, 0x46, 0xde, 0xe1, 0xe1,
+0x3f, 0xc1, 0xcc, 0x72, 0xbe, 0x2a, 0x43, 0xc6, 0xf6, 0xd0, 0xb5, 0xa0, 0xc4, 0x24, 0x6e, 0x4f,
+0xbd, 0xec, 0x22, 0x8a, 0x07, 0x11, 0x3d, 0xf9, 0xd3, 0x15, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
+0x82, 0x01, 0x26, 0x30, 0x82, 0x01, 0x22, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
+0x30, 0x16, 0x80, 0x14, 0xf2, 0x9d, 0x42, 0x4e, 0x0f, 0xc4, 0x48, 0x25, 0x58, 0x2f, 0x1c, 0xce,
+0x0f, 0xa1, 0x3f, 0x22, 0xc8, 0x55, 0xc8, 0x91, 0x30, 0x3b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+0x05, 0x07, 0x01, 0x01, 0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+0x05, 0x07, 0x30, 0x01, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x69, 0x70, 0x61,
+0x2d, 0x63, 0x61, 0x2e, 0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2f, 0x63, 0x61,
+0x2f, 0x6f, 0x63, 0x73, 0x70, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+0x04, 0x03, 0x02, 0x04, 0xf0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14,
+0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+0x05, 0x07, 0x03, 0x02, 0x30, 0x74, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x6d, 0x30, 0x6b, 0x30,
+0x69, 0xa0, 0x31, 0xa0, 0x2f, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x69, 0x70,
+0x61, 0x2d, 0x63, 0x61, 0x2e, 0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2f, 0x69,
+0x70, 0x61, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x43, 0x52, 0x4c,
+0x2e, 0x62, 0x69, 0x6e, 0xa2, 0x34, 0xa4, 0x32, 0x30, 0x30, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03,
+0x55, 0x04, 0x0a, 0x0c, 0x05, 0x69, 0x70, 0x61, 0x63, 0x61, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03,
+0x55, 0x04, 0x03, 0x0c, 0x15, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
+0x0e, 0x04, 0x16, 0x04, 0x14, 0x2d, 0x2b, 0x3f, 0xcb, 0xf5, 0xb2, 0xff, 0x32, 0x2c, 0xa8, 0xc2,
+0x1c, 0xdd, 0xbd, 0x8c, 0x80, 0x1e, 0xdd, 0x31, 0x82, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x9a, 0x47, 0x2e,
+0x50, 0xa7, 0x4d, 0x1d, 0x53, 0x0f, 0xc9, 0x71, 0x42, 0x0c, 0xe5, 0xda, 0x7d, 0x49, 0x64, 0xe7,
+0xab, 0xc8, 0xdf, 0xdf, 0x02, 0xc1, 0x87, 0xd1, 0x5b, 0xde, 0xda, 0x6f, 0x2b, 0xe4, 0xf0, 0xbe,
+0xba, 0x09, 0xdf, 0x02, 0x85, 0x0b, 0x8a, 0xe6, 0x9b, 0x06, 0x7d, 0x69, 0x38, 0x6c, 0x72, 0xff,
+0x4c, 0x7b, 0x2a, 0x0d, 0x3f, 0x23, 0x2f, 0x16, 0x46, 0xff, 0x05, 0x93, 0xb0, 0xea, 0x24, 0x28,
+0xd7, 0x12, 0xa1, 0x57, 0xb8, 0x59, 0x19, 0x25, 0xf3, 0x43, 0x0a, 0xd3, 0xfd, 0x0f, 0x37, 0x8d,
+0xb8, 0xca, 0x15, 0xe7, 0x48, 0x8a, 0xa0, 0xc7, 0xc7, 0x4b, 0x7f, 0x01, 0x3c, 0x58, 0xd7, 0x37,
+0xe5, 0xff, 0x7d, 0x2b, 0x01, 0xac, 0x0d, 0x9f, 0x51, 0x6a, 0xe5, 0x40, 0x24, 0xe6, 0x5e, 0x55,
+0x0d, 0xf7, 0xb8, 0x2f, 0x42, 0xac, 0x6d, 0xe5, 0x29, 0x6b, 0xc6, 0x0b, 0xa4, 0xbf, 0x19, 0xbd,
+0x39, 0x27, 0xee, 0xfe, 0xc5, 0xb3, 0xdb, 0x62, 0xd4, 0xbe, 0xd2, 0x47, 0xba, 0x96, 0x30, 0x5a,
+0xfd, 0x62, 0x00, 0xb8, 0x27, 0x5d, 0x2f, 0x3a, 0x94, 0x0b, 0x95, 0x35, 0x85, 0x40, 0x2c, 0xbc,
+0x67, 0xdf, 0x8a, 0xf9, 0xf1, 0x7b, 0x19, 0x96, 0x3e, 0x42, 0x48, 0x13, 0x23, 0x04, 0x95, 0xa9,
+0x6b, 0x11, 0x33, 0x81, 0x47, 0x5a, 0x83, 0x72, 0xf6, 0x20, 0xfa, 0x8e, 0x41, 0x7b, 0x8f, 0x77,
+0x47, 0x7c, 0xc7, 0x5d, 0x46, 0xf4, 0x4f, 0xfd, 0x81, 0x0a, 0xae, 0x39, 0x27, 0xb6, 0x6a, 0x26,
+0x63, 0xb1, 0xd3, 0xbf, 0x55, 0x83, 0x82, 0x9b, 0x36, 0x6c, 0x33, 0x64, 0x0f, 0x50, 0xc0, 0x55,
+0x94, 0x13, 0xc3, 0x85, 0xf4, 0xd5, 0x71, 0x65, 0xd0, 0xc0, 0xdd, 0xfc, 0xe6, 0xec, 0x9c, 0x5b,
+0xf0, 0x11, 0xb5, 0x2c, 0xf3, 0x48, 0xc1, 0x36, 0x8c, 0xa2, 0x96, 0x48, 0x84};
+
+#define TEST_CERT_PEM "-----BEGIN CERTIFICATE-----\n" \
+"MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu\n" \
+"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA0Mjgx\n" \
+"MDIxMTFaFw0xNzA0MjgxMDIxMTFaMDIxEjAQBgNVBAoMCUlQQS5ERVZFTDEcMBoG\n" \
+"A1UEAwwTaXBhLWRldmVsLmlwYS5kZXZlbDCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" \
+"ADCCAQoCggEBALIykqtHuAwTVEofHikG/9BQy/dfeZFlsTkBg2qtnnc78w3Xufbc\n" \
+"nkpJp9Bmcsy/d9beqf5nlsxJ8TcjLsRQ9Ou6YtQjTfM3OILuOz8s0ICbF6qb66bd\n" \
+"9hX/BrLO/9+KnpWFSR+E/YEmzgYyDTbKfBWBaGuPPrOi/K6vwkRYFZVA/FYZkYDt\n" \
+"QhFmBO884HYzS4P6frRH3PvtRqWNCmaHpe97dGKsvnM2ybT+IMSB8/54GajQr3+B\n" \
+"ciRh2XaT4wvSTxkXM1fUgrDxqAP2AZmpuIyDyboZh+rWOwbrTPfx5SipELZG3uHh\n" \
+"P8HMcr4qQ8b20LWgxCRuT73sIooHET350xUCAwEAAaOCASYwggEiMB8GA1UdIwQY\n" \
+"MBaAFPKdQk4PxEglWC8czg+hPyLIVciRMDsGCCsGAQUFBwEBBC8wLTArBggrBgEF\n" \
+"BQcwAYYfaHR0cDovL2lwYS1jYS5pcGEuZGV2ZWwvY2Evb2NzcDAOBgNVHQ8BAf8E\n" \
+"BAMCBPAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHQGA1UdHwRtMGsw\n" \
+"aaAxoC+GLWh0dHA6Ly9pcGEtY2EuaXBhLmRldmVsL2lwYS9jcmwvTWFzdGVyQ1JM\n" \
+"LmJpbqI0pDIwMDEOMAwGA1UECgwFaXBhY2ExHjAcBgNVBAMMFUNlcnRpZmljYXRl\n" \
+"IEF1dGhvcml0eTAdBgNVHQ4EFgQULSs/y/Wy/zIsqMIc3b2MgB7dMYIwDQYJKoZI\n" \
+"hvcNAQELBQADggEBAJpHLlCnTR1TD8lxQgzl2n1JZOeryN/fAsGH0Vve2m8r5PC+\n" \
+"ugnfAoULiuabBn1pOGxy/0x7Kg0/Iy8WRv8Fk7DqJCjXEqFXuFkZJfNDCtP9DzeN\n" \
+"uMoV50iKoMfHS38BPFjXN+X/fSsBrA2fUWrlQCTmXlUN97gvQqxt5Slrxgukvxm9\n" \
+"OSfu/sWz22LUvtJHupYwWv1iALgnXS86lAuVNYVALLxn34r58XsZlj5CSBMjBJWp\n" \
+"axEzgUdag3L2IPqOQXuPd0d8x11G9E/9gQquOSe2aiZjsdO/VYOCmzZsM2QPUMBV\n" \
+"lBPDhfTVcWXQwN385uycW/ARtSzzSME2jKKWSIQ=\n" \
+"-----END CERTIFICATE-----\n"
+
+#define TEST_CERT_DERB64 \
+"MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
+"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA0Mjgx" \
+"MDIxMTFaFw0xNzA0MjgxMDIxMTFaMDIxEjAQBgNVBAoMCUlQQS5ERVZFTDEcMBoG" \
+"A1UEAwwTaXBhLWRldmVsLmlwYS5kZXZlbDCCASIwDQYJKoZIhvcNAQEBBQADggEP" \
+"ADCCAQoCggEBALIykqtHuAwTVEofHikG/9BQy/dfeZFlsTkBg2qtnnc78w3Xufbc" \
+"nkpJp9Bmcsy/d9beqf5nlsxJ8TcjLsRQ9Ou6YtQjTfM3OILuOz8s0ICbF6qb66bd" \
+"9hX/BrLO/9+KnpWFSR+E/YEmzgYyDTbKfBWBaGuPPrOi/K6vwkRYFZVA/FYZkYDt" \
+"QhFmBO884HYzS4P6frRH3PvtRqWNCmaHpe97dGKsvnM2ybT+IMSB8/54GajQr3+B" \
+"ciRh2XaT4wvSTxkXM1fUgrDxqAP2AZmpuIyDyboZh+rWOwbrTPfx5SipELZG3uHh" \
+"P8HMcr4qQ8b20LWgxCRuT73sIooHET350xUCAwEAAaOCASYwggEiMB8GA1UdIwQY" \
+"MBaAFPKdQk4PxEglWC8czg+hPyLIVciRMDsGCCsGAQUFBwEBBC8wLTArBggrBgEF" \
+"BQcwAYYfaHR0cDovL2lwYS1jYS5pcGEuZGV2ZWwvY2Evb2NzcDAOBgNVHQ8BAf8E" \
+"BAMCBPAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHQGA1UdHwRtMGsw" \
+"aaAxoC+GLWh0dHA6Ly9pcGEtY2EuaXBhLmRldmVsL2lwYS9jcmwvTWFzdGVyQ1JM" \
+"LmJpbqI0pDIwMDEOMAwGA1UECgwFaXBhY2ExHjAcBgNVBAMMFUNlcnRpZmljYXRl" \
+"IEF1dGhvcml0eTAdBgNVHQ4EFgQULSs/y/Wy/zIsqMIc3b2MgB7dMYIwDQYJKoZI" \
+"hvcNAQELBQADggEBAJpHLlCnTR1TD8lxQgzl2n1JZOeryN/fAsGH0Vve2m8r5PC+" \
+"ugnfAoULiuabBn1pOGxy/0x7Kg0/Iy8WRv8Fk7DqJCjXEqFXuFkZJfNDCtP9DzeN" \
+"uMoV50iKoMfHS38BPFjXN+X/fSsBrA2fUWrlQCTmXlUN97gvQqxt5Slrxgukvxm9" \
+"OSfu/sWz22LUvtJHupYwWv1iALgnXS86lAuVNYVALLxn34r58XsZlj5CSBMjBJWp" \
+"axEzgUdag3L2IPqOQXuPd0d8x11G9E/9gQquOSe2aiZjsdO/VYOCmzZsM2QPUMBV" \
+"lBPDhfTVcWXQwN385uycW/ARtSzzSME2jKKWSIQ="
+
+struct test_state {
+    void *dummy;
+};
+
+static int setup(void **state)
+{
+    struct test_state *ts = NULL;
+
+    assert_true(leak_check_setup());
+
+    ts = talloc(global_talloc_context, struct test_state);
+    assert_non_null(ts);
+
+    check_leaks_push(ts);
+    *state = (void *)ts;
+    return 0;
+}
+
+static int teardown(void **state)
+{
+    struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
+
+    assert_non_null(ts);
+
+    assert_true(check_leaks_pop(ts));
+    talloc_free(ts);
+    assert_true(leak_check_teardown());
+    return 0;
+}
+
+void test_sss_cert_der_to_pem(void **state)
+{
+    int ret;
+    char *pem_str;
+    size_t pem_size;
+    struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
+    assert_non_null(ts);
+
+    ret = sss_cert_der_to_pem(NULL, NULL, 0, NULL, NULL);
+    assert_int_equal(ret, EINVAL);
+
+    ret = sss_cert_der_to_pem(ts, test_cert_der, sizeof(test_cert_der),
+                              &pem_str, &pem_size);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(sizeof(TEST_CERT_PEM) - 1, pem_size);
+    assert_string_equal(pem_str, TEST_CERT_PEM);
+
+    talloc_free(pem_str);
+}
+
+void test_sss_cert_pem_to_der(void **state)
+{
+    int ret;
+    uint8_t *der;
+    size_t der_size;
+    struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
+    assert_non_null(ts);
+
+    ret = sss_cert_pem_to_der(NULL, NULL, NULL, NULL);
+    assert_int_equal(ret, EINVAL);
+
+    ret = sss_cert_pem_to_der(ts, TEST_CERT_PEM, &der, &der_size);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(sizeof(test_cert_der), der_size);
+    assert_memory_equal(der, test_cert_der, der_size);
+
+    talloc_free(der);
+}
+
+void test_sss_cert_derb64_to_pem(void **state)
+{
+    int ret;
+    char *pem_str;
+    size_t pem_size;
+    struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
+    assert_non_null(ts);
+
+    ret = sss_cert_derb64_to_pem(NULL, NULL, NULL, NULL);
+    assert_int_equal(ret, EINVAL);
+
+    ret = sss_cert_derb64_to_pem(ts, TEST_CERT_DERB64, &pem_str, &pem_size);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(sizeof(TEST_CERT_PEM) - 1, pem_size);
+    assert_string_equal(pem_str, TEST_CERT_PEM);
+
+    talloc_free(pem_str);
+}
+
+void test_sss_cert_pem_to_derb64(void **state)
+{
+    int ret;
+    char *derb64;
+    struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
+    assert_non_null(ts);
+
+    ret = sss_cert_pem_to_derb64(NULL, NULL, NULL);
+    assert_int_equal(ret, EINVAL);
+
+    ret = sss_cert_pem_to_derb64(ts, TEST_CERT_PEM, &derb64);
+    assert_int_equal(ret, EOK);
+    assert_string_equal(derb64, TEST_CERT_DERB64);
+
+    talloc_free(derb64);
+}
+
+void test_bin_to_ldap_filter_value(void **state)
+{
+    int ret;
+    size_t c;
+    char *str;
+    struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
+    assert_non_null(ts);
+
+    struct test_data {
+        uint8_t blob[5];
+        const char *str;
+    }  test_data[] = {
+        {{0x01, 0x02, 0x03, 0x04, 0x05}, "\\01\\02\\03\\04\\05"},
+        {{0x00, 0x00, 0x00, 0x00, 0x00}, "\\00\\00\\00\\00\\00"},
+        {{0xff, 0xff, 0xff, 0xff, 0xff}, "\\ff\\ff\\ff\\ff\\ff"},
+        {{0xca, 0xfe, 0xc0, 0xff, 0xee}, "\\ca\\fe\\c0\\ff\\ee"},
+        {{0}, NULL}
+    };
+
+    ret = bin_to_ldap_filter_value(ts, NULL, 0, NULL);
+    assert_int_equal(ret, EINVAL);
+
+    for (c = 0; test_data[c].str != NULL; c++) {
+        ret = bin_to_ldap_filter_value(ts, test_data[c].blob, 5, &str);
+        assert_int_equal(ret, EOK);
+        assert_string_equal(str, test_data[c].str);
+
+        talloc_free(str);
+    }
+
+}
+
+void test_sss_cert_derb64_to_ldap_filter(void **state)
+{
+    int ret;
+    char *filter;
+
+    struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
+    assert_non_null(ts);
+
+    ret = sss_cert_derb64_to_ldap_filter(ts, NULL, NULL, NULL);
+    assert_int_equal(ret, EINVAL);
+
+    ret = sss_cert_derb64_to_ldap_filter(ts, "AAECAwQFBgcICQ==", "attrName",
+                                         &filter);
+    assert_int_equal(ret, EOK);
+    assert_string_equal(filter,
+                        "(attrName=\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09)");
+
+    talloc_free(filter);
+}
+
+int main(int argc, const char *argv[])
+{
+    poptContext pc;
+    int opt;
+    int ret;
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        SSSD_DEBUG_OPTS
+        POPT_TABLEEND
+    };
+
+    const struct CMUnitTest tests[] = {
+        cmocka_unit_test_setup_teardown(test_sss_cert_der_to_pem,
+                                        setup, teardown),
+        cmocka_unit_test_setup_teardown(test_sss_cert_pem_to_der,
+                                        setup, teardown),
+        cmocka_unit_test_setup_teardown(test_sss_cert_derb64_to_pem,
+                                        setup, teardown),
+        cmocka_unit_test_setup_teardown(test_sss_cert_pem_to_derb64,
+                                        setup, teardown),
+        cmocka_unit_test_setup_teardown(test_bin_to_ldap_filter_value,
+                                        setup, teardown),
+        cmocka_unit_test_setup_teardown(test_sss_cert_derb64_to_ldap_filter,
+                                        setup, teardown),
+    };
+
+    /* Set debug level to invalid value so we can deside if -d 0 was used. */
+    debug_level = SSSDBG_INVALID;
+
+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+    while((opt = poptGetNextOpt(pc)) != -1) {
+        switch(opt) {
+        default:
+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                    poptBadOption(pc, 0), poptStrerror(opt));
+            poptPrintUsage(pc, stderr, 0);
+            return 1;
+        }
+    }
+    poptFreeContext(pc);
+
+    DEBUG_CLI_INIT(debug_level);
+
+    ret = cmocka_run_group_tests(tests, NULL, NULL);
+
+    CRYPTO_cleanup_all_ex_data(); /* to make valgrind happy */
+
+#ifdef HAVE_NSS
+    /* Cleanup NSS and NSPR to make valgrind happy. */
+    nspr_nss_cleanup();
+#endif
+
+
+    return ret;
+}
diff --git a/src/util/cert.h b/src/util/cert.h
new file mode 100644
index 0000000000000000000000000000000000000000..79ea1a4ab58149a312bece265798ab3a3f459114
--- /dev/null
+++ b/src/util/cert.h
@@ -0,0 +1,47 @@
+/*
+   SSSD - certificate handling utils - openssl version
+
+   Copyright (C) Sumit Bose <sbose at redhat.com> 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdint.h>
+#include <talloc.h>
+
+#include "util/util.h"
+
+#ifndef __CERT_H__
+#define __CERT_H__
+
+errno_t sss_cert_der_to_pem(TALLOC_CTX *mem_ctx, const uint8_t *der_blob,
+                            size_t der_size, char **pem, size_t *pem_size);
+
+errno_t sss_cert_pem_to_der(TALLOC_CTX *mem_ctx, const char *pem,
+                            uint8_t **der_blob, size_t *der_size);
+
+errno_t sss_cert_derb64_to_pem(TALLOC_CTX *mem_ctx, const char *derb64,
+                               char **pem, size_t *pem_size);
+
+errno_t sss_cert_pem_to_derb64(TALLOC_CTX *mem_ctx, const char *pem,
+                               char **derb64);
+
+errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64,
+                                       const char *attr_name,
+                                       char **ldap_filter);
+
+errno_t bin_to_ldap_filter_value(TALLOC_CTX *mem_ctx,
+                                 const uint8_t *blob, size_t blob_size,
+                                 char **_str);
+#endif /* __CERT_H__ */
diff --git a/src/util/cert/cert_common.c b/src/util/cert/cert_common.c
new file mode 100644
index 0000000000000000000000000000000000000000..a29696ed3cd9f2168f47323fac97d44e9b49f921
--- /dev/null
+++ b/src/util/cert/cert_common.c
@@ -0,0 +1,154 @@
+/*
+   SSSD - certificate handling utils
+
+   Copyright (C) Sumit Bose <sbose at redhat.com> 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include "util/cert.h"
+#include "util/crypto/sss_crypto.h"
+
+errno_t sss_cert_derb64_to_pem(TALLOC_CTX *mem_ctx, const char *derb64,
+                               char **pem, size_t *pem_size)
+{
+    int ret;
+    unsigned char *der;
+    size_t der_size;
+
+    if (derb64 == NULL) {
+        return EINVAL;
+    }
+
+    der = sss_base64_decode(mem_ctx, derb64, &der_size);
+    if (der == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
+        return EINVAL;
+    }
+
+    ret = sss_cert_der_to_pem(mem_ctx, der, der_size, pem, pem_size);
+    talloc_free(der);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_cert_der_to_pem failed.\n");
+    }
+
+    return ret;
+}
+
+errno_t sss_cert_pem_to_derb64(TALLOC_CTX *mem_ctx, const char *pem,
+                               char **derb64)
+{
+    int ret;
+    uint8_t *der;
+    size_t der_size;
+
+    ret = sss_cert_pem_to_der(mem_ctx, pem, &der, &der_size);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_cert_pem_to_der failed.\n");
+        return ret;
+    }
+
+    *derb64 = sss_base64_encode(mem_ctx, der, der_size);
+    talloc_free(der);
+    if (*derb64 == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_base64_encode failed.\n");
+        return EINVAL;
+    }
+
+    return EOK;
+}
+
+errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64,
+                                       const char *attr_name,
+                                       char **ldap_filter)
+{
+    int ret;
+    unsigned char *der;
+    size_t der_size;
+    char *val;
+
+    if (derb64 == NULL || attr_name == NULL) {
+        return EINVAL;
+    }
+
+    der = sss_base64_decode(mem_ctx, derb64, &der_size);
+    if (der == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
+        return EINVAL;
+    }
+
+    ret = bin_to_ldap_filter_value(mem_ctx, der, der_size, &val);
+    talloc_free(der);
+    if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "bin_to_ldap_filter_value failed.\n");
+            return ret;
+    }
+
+    *ldap_filter = talloc_asprintf(mem_ctx, "(%s=%s)", attr_name, val);
+    talloc_free(val);
+    if (*ldap_filter == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+            return ENOMEM;
+    }
+
+    return EOK;
+}
+
+errno_t bin_to_ldap_filter_value(TALLOC_CTX *mem_ctx,
+                                 const uint8_t *blob, size_t blob_size,
+                                 char **_str)
+{
+    int ret;
+    size_t c;
+    size_t len;
+    char *str = NULL;
+    char *p;
+
+    if (blob == NULL || blob_size == 0 || _str == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "Missing input parameter.\n");
+        return EINVAL;
+    }
+
+    len = (blob_size * 3) + 1;
+    str = talloc_size(mem_ctx, len);
+    if (str == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
+        return ENOMEM;
+    }
+    str[len - 1] = '\0';
+
+    p = str;
+    for (c = 0; c < blob_size; c++) {
+        ret = snprintf(p, 4, "\\%02x", blob[c]);
+        if (ret != 3) {
+            DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n");
+            ret = EIO;
+            goto done;
+        }
+
+        p += 3;
+    }
+
+    ret = EOK;
+
+done:
+    if (ret == EOK) {
+        *_str = str;
+    } else {
+        talloc_free(str);
+    }
+
+    return ret;
+}
diff --git a/src/util/cert/libcrypto/cert.c b/src/util/cert/libcrypto/cert.c
new file mode 100644
index 0000000000000000000000000000000000000000..1a250f60d1a7dfd5c883ec7e9b1f9491fb74c9b0
--- /dev/null
+++ b/src/util/cert/libcrypto/cert.c
@@ -0,0 +1,168 @@
+/*
+   SSSD - certificate handling utils - openssl version
+
+   Copyright (C) Sumit Bose <sbose at redhat.com> 2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <openssl/x509.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+
+#include "util/util.h"
+
+errno_t sss_cert_der_to_pem(TALLOC_CTX *mem_ctx, const uint8_t *der_blob,
+                            size_t der_size, char **pem, size_t *pem_size)
+{
+    X509 *x509 = NULL;
+    BIO *bio_mem = NULL;
+    const unsigned char *d;
+    int ret;
+    long p_size;
+    char *p;
+
+    if (der_blob == NULL || der_size == 0) {
+        return EINVAL;
+    }
+
+    d = (const unsigned char *) der_blob;
+
+    x509 = d2i_X509(NULL, &d, (int) der_size);
+    if (x509 == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "d2i_X509 failed.\n");
+        return EINVAL;
+    }
+
+    bio_mem = BIO_new(BIO_s_mem());
+    if (bio_mem == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "BIO_new failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = PEM_write_bio_X509(bio_mem, x509);
+    if (ret != 1) {
+        DEBUG(SSSDBG_OP_FAILURE, "PEM_write_bio_X509 failed.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    p_size = BIO_get_mem_data(bio_mem, &p);
+    if (p_size == 0) {
+        DEBUG(SSSDBG_OP_FAILURE, "Unexpected PEM size [%ld].\n", p_size);
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (pem != NULL) {
+        *pem = talloc_strndup(mem_ctx, p, p_size);
+        if (*pem == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_memdup failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
+    if (pem_size != NULL) {
+        *pem_size = p_size;
+    }
+
+    ret = EOK;
+
+done:
+    X509_free(x509);
+    BIO_free_all(bio_mem);
+
+    return ret;
+}
+
+errno_t sss_cert_pem_to_der(TALLOC_CTX *mem_ctx, const char *pem,
+                            uint8_t **_der_blob, size_t *_der_size)
+{
+    X509 *x509 = NULL;
+    BIO *bio_mem = NULL;
+    int ret;
+    unsigned char *buf;
+    int buf_size;
+    uint8_t *der_blob;
+    size_t der_size;
+
+    if (pem == NULL) {
+        return EINVAL;
+    }
+
+    bio_mem = BIO_new(BIO_s_mem());
+    if (bio_mem == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "BIO_new failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = BIO_puts(bio_mem, pem);
+    if (ret <= 0) {
+        DEBUG(SSSDBG_OP_FAILURE, "BIO_puts failed.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    x509 = PEM_read_bio_X509(bio_mem, NULL, NULL, NULL);
+    if (x509 == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "PEM_read_bio_X509 failed.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    buf_size = i2d_X509(x509, NULL);
+    if (buf_size <= 0) {
+        DEBUG(SSSDBG_OP_FAILURE, "i2d_X509 failed.\n");
+        ret = EIO;
+        goto done;
+    }
+
+    if (_der_blob != NULL) {
+        buf = talloc_size(mem_ctx, buf_size);
+        if (buf == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        der_blob = buf;
+
+        der_size = i2d_X509(x509, &buf);
+        if (der_size != buf_size) {
+            talloc_free(der_blob);
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "i2d_X509 size mismatch between two calls.\n");
+            ret = EIO;
+            goto done;
+        }
+
+        *_der_blob = der_blob;
+    }
+
+    if (_der_size != NULL) {
+        *_der_size = buf_size;
+    }
+
+    ret = EOK;
+
+done:
+    X509_free(x509);
+    BIO_free_all(bio_mem);
+
+    return ret;
+
+}
-- 
2.1.0

-------------- next part --------------
From 46e477e2821ed9f824b715acdf8b504b1153379a Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 27 May 2015 11:22:20 +0200
Subject: [PATCH 4/7] sysdb: add sysdb_search_user_by_cert() and
 sysdb_search_object_by_cert()

Related to https://fedorahosted.org/sssd/ticket/2596
---
 Makefile.am                 |  1 +
 src/db/sysdb.h              | 14 ++++++++++++
 src/db/sysdb_ops.c          | 35 ++++++++++++++++++++++++++++++
 src/tests/cwrap/Makefile.am |  2 ++
 src/tests/sysdb-tests.c     | 53 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 105 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 303dd44e1e0e3e66c8d2739051a9d5d63bf8e075..9e68c37826776b52c4b18bd75108f56638158ef4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -804,6 +804,7 @@ libsss_util_la_LIBADD = \
     libsss_debug.la \
     libsss_child.la \
     libsss_crypt.la \
+    libsss_cert.la \
     $(NULL)
 if BUILD_SUDO
     libsss_util_la_SOURCES += src/db/sysdb_sudo.c
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 361d26d37481c521e93584b23af48a0861296e1f..9759642c4953bfc2e67599193f7846189fbdfa59 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -193,6 +193,7 @@
 
 #define SYSDB_SID_FILTER "(&(|("SYSDB_UC")("SYSDB_GC"))("SYSDB_SID_STR"=%s))"
 #define SYSDB_UUID_FILTER "(&(|("SYSDB_UC")("SYSDB_GC"))("SYSDB_UUID"=%s))"
+#define SYSDB_USER_CERT_FILTER "(&("SYSDB_UC")%s)"
 
 #define SYSDB_HAS_ENUMERATED "has_enumerated"
 
@@ -1060,6 +1061,19 @@ errno_t sysdb_search_object_by_uuid(TALLOC_CTX *mem_ctx,
                                     const char **attrs,
                                     struct ldb_result **res);
 
+errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx,
+                                    struct sss_domain_info *domain,
+                                    const char *cert,
+                                    const char **attrs,
+                                    struct ldb_result **res);
+
+errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx,
+                                  struct sss_domain_info *domain,
+                                  const char *cert,
+                                  struct ldb_result **res);
+
+
+
 /* === 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 d132af3813351aff69b3afac41a0735e30531ba2..5f09acb517e243fd5040be9380e1bca4ade66132 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -24,6 +24,7 @@
 #include "db/sysdb_services.h"
 #include "db/sysdb_autofs.h"
 #include "util/crypto/sss_crypto.h"
+#include "util/cert.h"
 #include <time.h>
 
 int add_string(struct ldb_message *msg, int flags,
@@ -3713,6 +3714,40 @@ errno_t sysdb_search_object_by_uuid(TALLOC_CTX *mem_ctx,
                                            uuid_str, attrs, res);
 }
 
+errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx,
+                                    struct sss_domain_info *domain,
+                                    const char *cert,
+                                    const char **attrs,
+                                    struct ldb_result **res)
+{
+    int ret;
+    char *user_filter;
+
+    ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_CERT,
+                                         &user_filter);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n");
+        return ret;
+    }
+
+    ret =  sysdb_search_object_by_str_attr(mem_ctx, domain,
+                                           SYSDB_USER_CERT_FILTER,
+                                           user_filter, attrs, res);
+    talloc_free(user_filter);
+
+    return ret;
+}
+
+errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx,
+                                  struct sss_domain_info *domain,
+                                  const char *cert,
+                                  struct ldb_result **res)
+{
+    const char *user_attrs[] = SYSDB_PW_ATTRS;
+
+    return  sysdb_search_object_by_cert(mem_ctx, domain, cert, user_attrs, res);
+}
+
 errno_t sysdb_get_sids_of_members(TALLOC_CTX *mem_ctx,
                                   struct sss_domain_info *dom,
                                   const char *group_name,
diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
index b805e834977f60d6ba2efdf0f700061bb5e0e264..dc92192928a55abb247096ef310251098d16038f 100644
--- a/src/tests/cwrap/Makefile.am
+++ b/src/tests/cwrap/Makefile.am
@@ -109,6 +109,7 @@ server_tests_LDADD = \
     $(abs_top_builddir)/libsss_debug.la \
     $(abs_top_builddir)/libsss_crypt.la \
     $(abs_top_builddir)/libsss_test_common.la \
+    $(abs_top_builddir)/libsss_cert.la \
     $(NULL)
 
 usertools_tests_SOURCES = \
@@ -143,6 +144,7 @@ usertools_tests_LDADD = \
     $(abs_top_builddir)/libsss_debug.la \
     $(abs_top_builddir)/libsss_crypt.la \
     $(abs_top_builddir)/libsss_test_common.la \
+    $(abs_top_builddir)/libsss_cert.la \
     $(NULL)
 
 responder_common_tests_SOURCES =\
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 6a77c6eebc4d8e29c09d67f9b1de17939591410a..b892f5ad9ab39567ccf379e27ead3ce9a42a5ddd 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -5201,6 +5201,56 @@ START_TEST(test_sysdb_search_object_by_uuid)
 }
 END_TEST
 
+/* For simple searches the content of the certificate does not matter */
+#define TEST_USER_CERT_DERB64 "gJznJT7L0aETU5CMk+n+1Q=="
+START_TEST(test_sysdb_search_user_by_cert)
+{
+    errno_t ret;
+    struct sysdb_test_ctx *test_ctx;
+    struct ldb_result *res;
+    struct sysdb_attrs *attrs = NULL;
+    struct ldb_val val;
+
+    /* Setup */
+    ret = setup_sysdb_tests(&test_ctx);
+    fail_if(ret != EOK, "Could not set up the test");
+
+    val.data = sss_base64_decode(test_ctx, TEST_USER_CERT_DERB64, &val.length);
+    fail_unless(val.data != NULL, "sss_base64_decode failed.");
+
+    attrs = sysdb_new_attrs(test_ctx);
+    fail_unless(attrs != NULL, "sysdb_new_attrs failed");
+
+    ret = sysdb_attrs_add_val(attrs, SYSDB_USER_CERT, &val);
+    fail_unless(ret == EOK, "sysdb_attrs_add_val failed with [%d][%s].",
+                ret, strerror(ret));
+
+    ret = sysdb_add_user(test_ctx->domain, "certuser",
+                         234567, 0, "cert user", "/home/certuser", "/bin/bash",
+                         NULL, attrs, 0, 0);
+    fail_unless(ret == EOK, "sysdb_add_user failed with [%d][%s].",
+                ret, strerror(ret));
+
+    ret = sysdb_search_user_by_cert(test_ctx, test_ctx->domain, "ABC", &res);
+    fail_unless(ret == ENOENT,
+                "Unexpected return code from sysdb_search_user_by_cert for "
+                "missing object, expected [%d], got [%d].", ENOENT, ret);
+
+    ret = sysdb_search_user_by_cert(test_ctx, test_ctx->domain,
+                                    TEST_USER_CERT_DERB64, &res);
+    fail_unless(ret == EOK, "sysdb_search_user_by_cert failed with [%d][%s].",
+                ret, strerror(ret));
+    fail_unless(res->count == 1, "Unexpected number of results, " \
+                                 "expected [%u], get [%u].", 1, res->count);
+    fail_unless(strcmp(ldb_msg_find_attr_as_string(res->msgs[0],
+                                                   SYSDB_NAME, ""),
+                      "certuser") == 0, "Unexpected object found, " \
+                      "expected [%s], got [%s].", "certuser",
+                      ldb_msg_find_attr_as_string(res->msgs[0],SYSDB_NAME, ""));
+    talloc_free(test_ctx);
+}
+END_TEST
+
 START_TEST(test_sysdb_delete_by_sid)
 {
     errno_t ret;
@@ -6370,6 +6420,9 @@ Suite *create_sysdb_suite(void)
     /* Test UUID string searches */
     tcase_add_test(tc_sysdb, test_sysdb_search_object_by_uuid);
 
+    /* Test user by certificate searches */
+    tcase_add_test(tc_sysdb, test_sysdb_search_user_by_cert);
+
     /* Test canonicalizing names */
     tcase_add_test(tc_sysdb, test_sysdb_get_real_name);
 
-- 
2.1.0

-------------- next part --------------
From 49a9cfe5d90e246738eddea3afcb1ef72dddf2b9 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 27 May 2015 18:23:49 +0200
Subject: [PATCH 5/7] LDAP/IPA: add user lookup by certificate

Related to https://fedorahosted.org/sssd/ticket/2596
---
 src/providers/data_provider.h         |  6 +++-
 src/providers/data_provider_be.c      |  5 ++++
 src/providers/ipa/ipa_subdomains_id.c | 14 +++++++++
 src/providers/ldap/ldap_id.c          | 55 +++++++++++++++++++++++++++++++----
 4 files changed, 73 insertions(+), 7 deletions(-)

diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h
index 5df493e9d1ae21ada6f5fd6198a6d9c36680d044..cea478fe4d6f7202f9d599b566c7b503a9728734 100644
--- a/src/providers/data_provider.h
+++ b/src/providers/data_provider.h
@@ -128,6 +128,7 @@
 #define BE_FILTER_ENUM 3
 #define BE_FILTER_SECID 4
 #define BE_FILTER_UUID 5
+#define BE_FILTER_CERT 6
 
 #define BE_REQ_USER          0x0001
 #define BE_REQ_GROUP         0x0002
@@ -140,14 +141,17 @@
 #define BE_REQ_HOST          0x0010
 #define BE_REQ_BY_SECID      0x0011
 #define BE_REQ_USER_AND_GROUP 0x0012
-#define BE_REQ_BY_UUID      0x0013
+#define BE_REQ_BY_UUID       0x0013
+#define BE_REQ_BY_CERT       0x0014
 #define BE_REQ_TYPE_MASK     0x00FF
 #define BE_REQ_FAST          0x1000
 
 #define DP_SEC_ID "secid"
+#define DP_CERT "cert"
 /* sizeof() counts the trailing \0 so we must substract 1 for the string
  * length */
 #define DP_SEC_ID_LEN (sizeof(DP_SEC_ID) - 1)
+#define DP_CERT_LEN (sizeof(DP_CERT) - 1)
 
 #define EXTRA_NAME_IS_UPN "U"
 #define EXTRA_INPUT_MAYBE_WITH_VIEW "V"
diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
index 34c7b2c766ee4072ee980ad43f1e1d33ee7c8a5a..f5bdfb676011975defa4c5a734d420c8694f3bdd 100644
--- a/src/providers/data_provider_be.c
+++ b/src/providers/data_provider_be.c
@@ -1199,6 +1199,11 @@ static int be_get_account_info(struct sbus_request *dbus_req, void *user_data)
             ret = split_name_extended(req, &filter[DP_SEC_ID_LEN + 1],
                                       &req->filter_value,
                                       &req->extra_value);
+        } else if (strncmp(filter, DP_CERT"=", DP_CERT_LEN + 1) == 0) {
+            req->filter_type = BE_FILTER_CERT;
+            ret = split_name_extended(req, &filter[DP_CERT_LEN + 1],
+                                      &req->filter_value,
+                                      &req->extra_value);
         } else if (strcmp(filter, ENUM_INDICATOR) == 0) {
             req->filter_type = BE_FILTER_ENUM;
             req->filter_value = NULL;
diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
index 617c091d3abc4808da4a279213ffc3e1119001bf..74773def113553ccf011d2c99a6ef3fd2b3150a9 100644
--- a/src/providers/ipa/ipa_subdomains_id.c
+++ b/src/providers/ipa/ipa_subdomains_id.c
@@ -918,6 +918,20 @@ errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
 
         ret = EOK;
         goto done;
+    } else if (ar->filter_type == BE_FILTER_CERT) {
+        ret = sysdb_search_object_by_cert(mem_ctx, dom, ar->filter_value, attrs,
+                                          &res);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "Failed to make request to our cache: [%d]: [%s]\n",
+                   ret, sss_strerror(ret));
+            goto done;
+        }
+
+        *_msg = res->msgs[0];
+
+        ret = EOK;
+        goto done;
     } else if (ar->filter_type == BE_FILTER_IDNUM) {
         errno = 0;
         id = strtouint32(ar->filter_value, NULL, 10);
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index d4f46f1dcd69898e5883d21be07f895fd198cf50..952ca20ef486f57de9e5415945b8369c6df8d39c 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -28,6 +28,7 @@
 
 #include "util/util.h"
 #include "util/strtonum.h"
+#include "util/cert.h"
 #include "db/sysdb.h"
 #include "providers/ldap/ldap_common.h"
 #include "providers/ldap/sdap_async.h"
@@ -78,12 +79,13 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
     struct tevent_req *req;
     struct users_get_state *state;
     const char *attr_name = NULL;
-    char *clean_name;
+    char *clean_name = NULL;
     char *endptr;
     int ret;
     uid_t uid;
     enum idmap_error_code err;
     char *sid;
+    char *user_filter = NULL;
 
     req = tevent_req_create(memctx, &state, struct users_get_state);
     if (!req) return NULL;
@@ -194,6 +196,23 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
             goto done;
         }
         break;
+    case BE_FILTER_CERT:
+        attr_name = ctx->opts->user_map[SDAP_AT_USER_CERT].name;
+        if (attr_name == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Certificate search not configured for this backend.\n");
+            ret = EINVAL;
+            goto done;
+        }
+
+        ret = sss_cert_derb64_to_ldap_filter(state, attr_name, name,
+                                             &user_filter);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "sss_cert_derb64_to_ldap_filter failed.\n");
+            goto done;
+        }
+        break;
     default:
         ret = EINVAL;
         goto done;
@@ -205,29 +224,39 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
         goto done;
     }
 
+    if (user_filter == NULL) {
+        user_filter = talloc_asprintf(state, "(%s=%s)", attr_name, clean_name);
+        talloc_free(clean_name);
+        if (user_filter == NULL) {
+            DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
     if (state->use_id_mapping || filter_type == BE_FILTER_SECID) {
         /* When mapping IDs or looking for SIDs, we don't want to limit
          * ourselves to users with a UID value. But there must be a SID to map
          * from.
          */
         state->filter = talloc_asprintf(state,
-                                        "(&(%s=%s)(objectclass=%s)(%s=*)(%s=*))",
-                                        attr_name, clean_name,
+                                        "(&%s(objectclass=%s)(%s=*)(%s=*))",
+                                        user_filter,
                                         ctx->opts->user_map[SDAP_OC_USER].name,
                                         ctx->opts->user_map[SDAP_AT_USER_NAME].name,
                                         ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name);
     } else {
         /* When not ID-mapping, make sure there is a non-NULL UID */
         state->filter = talloc_asprintf(state,
-                                        "(&(%s=%s)(objectclass=%s)(%s=*)(&(%s=*)(!(%s=0))))",
-                                        attr_name, clean_name,
+                                        "(&%s(objectclass=%s)(%s=*)(&(%s=*)(!(%s=0))))",
+                                        user_filter,
                                         ctx->opts->user_map[SDAP_OC_USER].name,
                                         ctx->opts->user_map[SDAP_AT_USER_NAME].name,
                                         ctx->opts->user_map[SDAP_AT_USER_UID].name,
                                         ctx->opts->user_map[SDAP_AT_USER_UID].name);
     }
 
-    talloc_zfree(clean_name);
+    talloc_zfree(user_filter);
     if (!state->filter) {
         DEBUG(SSSDBG_OP_FAILURE, "Failed to build the base filter\n");
         ret = ENOMEM;
@@ -1537,6 +1566,16 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx,
                                          noexist_delete);
         break;
 
+    case BE_REQ_BY_CERT:
+        subreq = users_get_send(state, be_ctx->ev, id_ctx,
+                                sdom, conn,
+                                ar->filter_value,
+                                ar->filter_type,
+                                ar->extra_value,
+                                ar->attr_type,
+                                noexist_delete);
+        break;
+
     default: /*fail*/
         ret = EINVAL;
         state->err = "Invalid request type";
@@ -1602,6 +1641,10 @@ sdap_handle_acct_req_done(struct tevent_req *subreq)
         ret = sdap_get_user_and_group_recv(subreq, &state->dp_error,
                                            &state->sdap_ret);
         break;
+    case BE_REQ_BY_CERT:
+        err = "User lookup by certificate failed";
+        ret = users_get_recv(subreq, &state->dp_error, &state->sdap_ret);
+        break;
     default: /*fail*/
         ret = EINVAL;
         break;
-- 
2.1.0

-------------- next part --------------
From ca7d49f5d256a39a144e063b98372c0b4d123d4a Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Wed, 3 Jun 2015 16:18:05 +0200
Subject: [PATCH 6/7] ncache: add calls for certificate based searches

Related to https://fedorahosted.org/sssd/ticket/2596
---
 src/responder/common/negcache.c  | 31 +++++++++++++++++++++++++++++
 src/responder/common/negcache.h  |  3 +++
 src/tests/cmocka/test_negcache.c | 42 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 76 insertions(+)

diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
index cf70dc52fe122328810064ebd112aec501f892a4..64270f4672f81fcd71f60acb83728d82dd4a1965 100644
--- a/src/responder/common/negcache.c
+++ b/src/responder/common/negcache.c
@@ -35,6 +35,7 @@
 #define NC_UID_PREFIX NC_ENTRY_PREFIX"UID"
 #define NC_GID_PREFIX NC_ENTRY_PREFIX"GID"
 #define NC_SID_PREFIX NC_ENTRY_PREFIX"SID"
+#define NC_CERT_PREFIX NC_ENTRY_PREFIX"CERT"
 
 struct sss_nc_ctx {
     struct tdb_context *tdb;
@@ -417,6 +418,21 @@ int sss_ncache_check_sid(struct sss_nc_ctx *ctx, int ttl, const char *sid)
     return ret;
 }
 
+int sss_ncache_check_cert(struct sss_nc_ctx *ctx, int ttl, const char *cert)
+{
+    char *str;
+    int ret;
+
+    str = talloc_asprintf(ctx, "%s/%s", NC_CERT_PREFIX, cert);
+    if (!str) return ENOMEM;
+
+    ret = sss_ncache_check_str(ctx, str, ttl);
+
+    talloc_free(str);
+    return ret;
+}
+
+
 static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent,
                                    const char *domain, const char *name)
 {
@@ -548,6 +564,21 @@ int sss_ncache_set_sid(struct sss_nc_ctx *ctx, bool permanent, const char *sid)
     return ret;
 }
 
+int sss_ncache_set_cert(struct sss_nc_ctx *ctx, bool permanent,
+                        const char *cert)
+{
+    char *str;
+    int ret;
+
+    str = talloc_asprintf(ctx, "%s/%s", NC_CERT_PREFIX, cert);
+    if (!str) return ENOMEM;
+
+    ret = sss_ncache_set_str(ctx, str, permanent);
+
+    talloc_free(str);
+    return ret;
+}
+
 static int delete_permanent(struct tdb_context *tdb,
                             TDB_DATA key, TDB_DATA data, void *state)
 {
diff --git a/src/responder/common/negcache.h b/src/responder/common/negcache.h
index b96fbfda5a63ce32c42b31bcfe517d2369f06138..e7cbfe11451399a639d8e77b3479e74968e72921 100644
--- a/src/responder/common/negcache.h
+++ b/src/responder/common/negcache.h
@@ -37,6 +37,7 @@ int sss_ncache_check_netgr(struct sss_nc_ctx *ctx, int ttl,
 int sss_ncache_check_uid(struct sss_nc_ctx *ctx, int ttl, uid_t uid);
 int sss_ncache_check_gid(struct sss_nc_ctx *ctx, int ttl, gid_t gid);
 int sss_ncache_check_sid(struct sss_nc_ctx *ctx, int ttl, const char *sid);
+int sss_ncache_check_cert(struct sss_nc_ctx *ctx, int ttl, const char *cert);
 
 int sss_ncache_check_service(struct sss_nc_ctx *ctx, int ttl,
                              struct sss_domain_info *dom,
@@ -60,6 +61,8 @@ int sss_ncache_set_netgr(struct sss_nc_ctx *ctx, bool permanent,
 int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent, uid_t uid);
 int sss_ncache_set_gid(struct sss_nc_ctx *ctx, bool permanent, gid_t gid);
 int sss_ncache_set_sid(struct sss_nc_ctx *ctx, bool permanent, const char *sid);
+int sss_ncache_set_cert(struct sss_nc_ctx *ctx, bool permanent,
+                        const char *cert);
 int sss_ncache_set_service_name(struct sss_nc_ctx *ctx, bool permanent,
                                 struct sss_domain_info *dom,
                                 const char *name, const char *proto);
diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c
index 6f9802a38c44adfc41688ce1a9297a8636c5d616..fa07ea2481e2040e3e83eecfb5c69dbec17e26fa 100644
--- a/src/tests/cmocka/test_negcache.c
+++ b/src/tests/cmocka/test_negcache.c
@@ -45,6 +45,7 @@
 
 #define PORT 21
 #define SID "S-1-2-3-4-5"
+#define CERT "MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEuREVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA0MjgxMDIxMTFaFw0xNzA0MjgxMDIxMTFaMDIxEjAQBgNVBAoMCUlQQS5ERVZFTDEcMBoGA1UEAwwTaXBhLWRldmVsLmlwYS5kZXZlbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALIykqtHuAwTVEofHikG/9BQy/dfeZFlsTkBg2qtnnc78w3XufbcnkpJp9Bmcsy/d9beqf5nlsxJ8TcjLsRQ9Ou6YtQjTfM3OILuOz8s0ICbF6qb66bd9hX/BrLO/9+KnpWFSR+E/YEmzgYyDTbKfBWBaGuPPrOi/K6vwkRYFZVA/FYZkYDtQhFmBO884HYzS4P6frRH3PvtRqWNCmaHpe97dGKsvnM2ybT+IMSB8/54GajQr3+BciRh2XaT4wvSTxkXM1fUgrDxqAP2AZmpuIyDyboZh+rWOwbrTPfx5SipELZG3uHhP8HMcr4qQ8b20LWgxCRuT73sIooHET350xUCAwEAAaOCASYwggEiMB8GA1UdIwQYMBaAFPKdQk4PxEglWC8czg+hPyLIVciRMDsGCCsGAQUFBwEBBC8wLTArBggrBgEFBQcwAYYfaHR0cDovL2lwYS1jYS5pcGEuZGV2ZWwvY2Evb2NzcDAOBgNVHQ8BAf8EBAMCBPAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHQGA1UdHwRtMGswaaAxoC+GLWh0dHA6Ly9pcGEtY2EuaXBhLmRldmVsL2lwYS9jcmwvTWFzdGVyQ1JMLmJpbqI0pDIwMDEOMAwGA1UECgwFaXBhY2ExHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAdBgNVHQ4EFgQULSs/y/Wy/zIsqMIc3b2MgB7dMYIwDQYJKoZIhvcNAQELBQADggEBAJpHLlCnTR1TD8lxQgzl2n1JZOeryN/fAsGH0Vve2m8r5PC+ugnfAoULiuabBn1pOGxy/0x7Kg0/Iy8WRv8Fk7DqJCjXEqFXuFkZJfNDCtP9DzeNuMoV50iKoMfHS38BPFjXN+X/fSsBrA2fUWrlQCTmXlUN97gvQqxt5Slrxgukvxm9OSfu/sWz22LUvtJHupYwWv1iALgnXS86lAuVNYVALLxn34r58XsZlj5CSBMjBJWpaxEzgUdag3L2IPqOQXuPd0d8x11G9E/9gQquOSe2aiZjsdO/VYOCmzZsM2QPUMBVlBPDhfTVcWXQwN385uycW/ARtSzzSME2jKKWSIQ="
 #define PROTO "TCP"
 #define LIFETIME 200
 #define SHORTSPAN 1
@@ -317,6 +318,46 @@ static void test_sss_ncache_sid(void **state)
     assert_int_equal(ret, EEXIST);
 }
 
+/* @test_sss_ncache_cert : test following functions
+ * sss_ncache_set_cert
+ * sss_ncache_check_cert_
+ */
+static void test_sss_ncache_cert(void **state)
+{
+    int ret, ttl;
+    bool permanent;
+    const char *cert = NULL;
+    struct test_state *ts;
+
+    ttl = LIFETIME;
+    cert = CERT;
+    ts = talloc_get_type_abort(*state, struct test_state);
+
+    /*test when cert in not present in database */
+    ret = sss_ncache_check_cert(ts->ctx, ttl, cert);
+    assert_int_equal(ret, ENOENT);
+
+    /* test when cert is present in database */
+    permanent = true;
+    ret = sss_ncache_set_cert(ts->ctx, permanent, cert);
+    assert_int_equal(ret, EOK);
+
+    ret = sss_ncache_check_cert(ts->ctx, ttl, cert);
+    assert_int_equal(ret, EEXIST);
+
+    permanent = false;
+    ret = sss_ncache_set_cert(ts->ctx, permanent, cert);
+    assert_int_equal(ret, EOK);
+
+    ret = sss_ncache_check_cert(ts->ctx, ttl, cert);
+    assert_int_equal(ret, EEXIST);
+
+    /* test when ttl is -1 with cert present in database*/
+    ttl = -1;
+    ret = sss_ncache_check_cert(ts->ctx, ttl, cert);
+    assert_int_equal(ret, EEXIST);
+}
+
 /* @test_sss_ncache_user : test following functions
  * sss_ncache_check_user
  * sss_ncache_set_user
@@ -809,6 +850,7 @@ int main(void)
         cmocka_unit_test_setup_teardown(test_sss_ncache_uid, setup, teardown),
         cmocka_unit_test_setup_teardown(test_sss_ncache_gid, setup, teardown),
         cmocka_unit_test_setup_teardown(test_sss_ncache_sid, setup, teardown),
+        cmocka_unit_test_setup_teardown(test_sss_ncache_cert, setup, teardown),
         cmocka_unit_test_setup_teardown(test_sss_ncache_user, setup, teardown),
         cmocka_unit_test_setup_teardown(test_sss_ncache_group, setup, teardown),
         cmocka_unit_test_setup_teardown(test_sss_ncache_netgr, setup, teardown),
-- 
2.1.0

-------------- next part --------------
From 2736c0c926d0f01b281243d15fcd664191a54886 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Tue, 26 May 2015 14:29:17 +0200
Subject: [PATCH 7/7] IFP: add FindByCertificate method for User objects

Related to https://fedorahosted.org/sssd/ticket/2596
---
 Makefile.am                                |  4 +-
 src/responder/common/responder.h           |  3 +-
 src/responder/common/responder_cache_req.c | 59 ++++++++++++++++++--
 src/responder/common/responder_cache_req.h | 16 +++++-
 src/responder/common/responder_dp.c        | 11 ++++
 src/responder/ifp/ifp_iface.c              |  1 +
 src/responder/ifp/ifp_iface.xml            |  4 ++
 src/responder/ifp/ifp_iface_generated.c    | 26 +++++++++
 src/responder/ifp/ifp_iface_generated.h    |  5 ++
 src/responder/ifp/ifp_users.c              | 87 ++++++++++++++++++++++++++++++
 src/responder/ifp/ifp_users.h              |  4 ++
 src/sbus/sssd_dbus_errors.h                |  1 +
 12 files changed, 215 insertions(+), 6 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 9e68c37826776b52c4b18bd75108f56638158ef4..b1a41eb8ac230f30fa2925fe766fdb45a51d8494 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1127,7 +1127,9 @@ sssd_ifp_CFLAGS = \
     $(AM_CFLAGS)
 sssd_ifp_LDADD = \
     $(SSSD_LIBS) \
-    $(SSSD_INTERNAL_LTLIBS)
+    $(SSSD_INTERNAL_LTLIBS) \
+    libsss_cert.la \
+    $(NULL)
 dist_dbuspolicy_DATA = \
     src/responder/ifp/org.freedesktop.sssd.infopipe.conf
 dist_dbusservice_DATA = \
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 9c7a73809a3de8859aa546c2a7d31620fea39ac9..bd0250d52aae1efdac3bc0847f692542c6cfb6d2 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -281,7 +281,8 @@ enum sss_dp_acct_type {
     SSS_DP_NETGR,
     SSS_DP_SERVICES,
     SSS_DP_SECID,
-    SSS_DP_USER_AND_GROUP
+    SSS_DP_USER_AND_GROUP,
+    SSS_DP_CERT
 };
 
 struct tevent_req *
diff --git a/src/responder/common/responder_cache_req.c b/src/responder/common/responder_cache_req.c
index 7ba257276b064d923b6144f45ade59cac48849d5..2afc01b0f9a14a97007df21d2ad59a8d96ad482f 100644
--- a/src/responder/common/responder_cache_req.c
+++ b/src/responder/common/responder_cache_req.c
@@ -70,6 +70,7 @@ cache_req_input_create(TALLOC_CTX *mem_ctx,
     /* Check that input parameters match selected type. */
     switch (input->type) {
     case CACHE_REQ_USER_BY_NAME:
+    case CACHE_REQ_USER_BY_CERT:
     case CACHE_REQ_GROUP_BY_NAME:
     case CACHE_REQ_INITGROUPS:
         if (name == NULL) {
@@ -108,6 +109,9 @@ cache_req_input_create(TALLOC_CTX *mem_ctx,
     case CACHE_REQ_INITGROUPS:
         input->dp_type = SSS_DP_INITGROUPS;
         break;
+    case CACHE_REQ_USER_BY_CERT:
+        input->dp_type = SSS_DP_CERT;
+        break;
     }
 
     return input;
@@ -192,6 +196,14 @@ cache_req_input_set_domain(struct cache_req_input *input,
             goto done;
         }
         break;
+    case CACHE_REQ_USER_BY_CERT:
+        fqn = talloc_asprintf(tmp_ctx, "CERT:%s@%s", input->orig_name,
+                                                     domain->name);
+        if (fqn == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+        break;
     }
 
     input->domain = domain;
@@ -227,6 +239,9 @@ static errno_t cache_req_check_ncache(struct cache_req_input *input,
     case CACHE_REQ_GROUP_BY_ID:
         ret = sss_ncache_check_gid(ncache, neg_timeout, input->id);
         break;
+    case CACHE_REQ_USER_BY_CERT:
+        ret = sss_ncache_check_cert(ncache, neg_timeout, input->orig_name);
+        break;
     }
 
     if (ret == EEXIST) {
@@ -254,6 +269,7 @@ static void cache_req_add_to_ncache(struct cache_req_input *input,
         break;
     case CACHE_REQ_USER_BY_ID:
     case CACHE_REQ_GROUP_BY_ID:
+    case CACHE_REQ_USER_BY_CERT:
         /* Nothing to do. Those types must be unique among all domains so
          * the don't contain domain part. Therefore they must be set only
          * if all domains are search and the entry is not found. */
@@ -290,6 +306,9 @@ static void cache_req_add_to_ncache_global(struct cache_req_input *input,
     case CACHE_REQ_GROUP_BY_ID:
         ret = sss_ncache_set_gid(ncache, false, input->id);
         break;
+    case CACHE_REQ_USER_BY_CERT:
+        ret = sss_ncache_set_cert(ncache, false, input->orig_name);
+        break;
     }
 
     if (ret != EOK) {
@@ -338,6 +357,11 @@ static errno_t cache_req_get_object(TALLOC_CTX *mem_ctx,
         ret = sysdb_initgroups_with_views(mem_ctx, input->domain,
                                           input->dom_objname, &result);
         break;
+    case CACHE_REQ_USER_BY_CERT:
+        one_item_only = true;
+        ret = sysdb_search_user_by_cert(mem_ctx, input->domain,
+                                        input->orig_name, &result);
+        break;
     }
 
     if (ret != EOK) {
@@ -461,6 +485,7 @@ static errno_t cache_req_cache_check(struct tevent_req *req)
     const char *extra_flag = NULL;
     uint64_t cache_expire = 0;
     errno_t ret;
+    const char *search_str;
 
     state = tevent_req_data(req, struct cache_req_cache_state);
 
@@ -479,6 +504,8 @@ static errno_t cache_req_cache_check(struct tevent_req *req)
                                   state->cache_refresh_percent, cache_expire);
     }
 
+    search_str = state->input->type == CACHE_REQ_USER_BY_CERT ?
+                            state->input->orig_name : state->input->dom_objname;
     switch (ret) {
     case EOK:
         DEBUG(SSSDBG_TRACE_FUNC, "Cached entry is valid, returning...\n");
@@ -492,7 +519,7 @@ static errno_t cache_req_cache_check(struct tevent_req *req)
         subreq = sss_dp_get_account_send(state, state->rctx,
                                          state->input->domain, true,
                                          state->input->dp_type,
-                                         state->input->dom_objname,
+                                         search_str,
                                          state->input->id, NULL);
         if (subreq == NULL) {
             DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory sending out-of-band "
@@ -514,7 +541,7 @@ static errno_t cache_req_cache_check(struct tevent_req *req)
         subreq = sss_dp_get_account_send(state, state->rctx,
                                          state->input->domain, true,
                                          state->input->dp_type,
-                                         state->input->dom_objname,
+                                         search_str,
                                          state->input->id, extra_flag);
         if (subreq == NULL) {
             DEBUG(SSSDBG_CRIT_FAILURE,
@@ -648,7 +675,10 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
     state->cache_refresh_percent = cache_refresh_percent;
     state->input = input;
 
-    if (state->input->orig_name != NULL && domain == NULL) {
+    if (state->input->orig_name != NULL && domain == NULL
+            && (input->type == CACHE_REQ_USER_BY_NAME
+                || input->type == CACHE_REQ_GROUP_BY_NAME
+                || input->type == CACHE_REQ_INITGROUPS)) {
         /* Parse input name first, since it may contain domain name. */
         subreq = sss_parse_inp_send(state, rctx, input->orig_name);
         if (subreq == NULL) {
@@ -923,6 +953,29 @@ cache_req_user_by_id_send(TALLOC_CTX *mem_ctx,
 }
 
 struct tevent_req *
+cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx,
+                            struct tevent_context *ev,
+                            struct resp_ctx *rctx,
+                            struct sss_nc_ctx *ncache,
+                            int neg_timeout,
+                            int cache_refresh_percent,
+                            const char *domain,
+                            const char *pem_cert)
+{
+    struct cache_req_input *input;
+
+    input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_CERT,
+                                   pem_cert, 0);
+    if (input == NULL) {
+        return NULL;
+    }
+
+    return cache_req_steal_input_and_send(mem_ctx, ev, rctx, ncache,
+                                          neg_timeout, cache_refresh_percent,
+                                          domain, input);
+}
+
+struct tevent_req *
 cache_req_group_by_name_send(TALLOC_CTX *mem_ctx,
                              struct tevent_context *ev,
                              struct resp_ctx *rctx,
diff --git a/src/responder/common/responder_cache_req.h b/src/responder/common/responder_cache_req.h
index 088e8efe0ceefe49510bc5eab37e7825b667e5f3..9b862a8b7751bfd938205184b4d6452a75f2684e 100644
--- a/src/responder/common/responder_cache_req.h
+++ b/src/responder/common/responder_cache_req.h
@@ -32,7 +32,8 @@ enum cache_req_type {
     CACHE_REQ_USER_BY_ID,
     CACHE_REQ_GROUP_BY_NAME,
     CACHE_REQ_GROUP_BY_ID,
-    CACHE_REQ_INITGROUPS
+    CACHE_REQ_INITGROUPS,
+    CACHE_REQ_USER_BY_CERT
 };
 
 struct cache_req_input;
@@ -90,6 +91,19 @@ cache_req_user_by_id_send(TALLOC_CTX *mem_ctx,
     cache_req_recv(mem_ctx, req, _result, _domain, NULL)
 
 struct tevent_req *
+cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx,
+                          struct tevent_context *ev,
+                          struct resp_ctx *rctx,
+                          struct sss_nc_ctx *ncache,
+                          int neg_timeout,
+                          int cache_refresh_percent,
+                          const char *domain,
+                          const char *pem_cert);
+
+#define cache_req_user_by_cert_recv(mem_ctx, req, _result, _domain, _name) \
+    cache_req_recv(mem_ctx, req, _result, _domain, _name)
+
+struct tevent_req *
 cache_req_group_by_name_send(TALLOC_CTX *mem_ctx,
                              struct tevent_context *ev,
                              struct resp_ctx *rctx,
diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c
index 853b3eae3877a8b6b2ffb310a0fb9ccf017498ae..f752c94c37fd0efa0d072ef8c567bd875a08e6f7 100644
--- a/src/responder/common/responder_dp.c
+++ b/src/responder/common/responder_dp.c
@@ -548,6 +548,9 @@ sss_dp_get_account_msg(void *pvt)
         case SSS_DP_USER_AND_GROUP:
             be_type = BE_REQ_USER_AND_GROUP;
             break;
+        case SSS_DP_CERT:
+            be_type = BE_REQ_BY_CERT;
+            break;
     }
 
     if (info->fast_reply) {
@@ -563,6 +566,14 @@ sss_dp_get_account_msg(void *pvt)
                 filter = talloc_asprintf(info, "%s=%s", DP_SEC_ID,
                                                info->opt_name);
             }
+        } else if (info->type == SSS_DP_CERT) {
+            if (info->extra) {
+                filter = talloc_asprintf(info, "%s=%s:%s", DP_CERT,
+                                               info->opt_name, info->extra);
+            } else {
+                filter = talloc_asprintf(info, "%s=%s", DP_CERT,
+                                               info->opt_name);
+            }
         } else {
             if (info->extra) {
                 filter = talloc_asprintf(info, "name=%s:%s",
diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c
index 015c66dc5323e237dd21575162e434b11acd8ed7..86d8d338c3d18c22a8dc449b6520f65f8968e26b 100644
--- a/src/responder/ifp/ifp_iface.c
+++ b/src/responder/ifp/ifp_iface.c
@@ -82,6 +82,7 @@ struct iface_ifp_users iface_ifp_users = {
     { &iface_ifp_users_meta, 0 },
     .FindByName = ifp_users_find_by_name,
     .FindByID = ifp_users_find_by_id,
+    .FindByCertificate = ifp_users_find_by_cert,
     .ListByName = ifp_users_list_by_name,
     .ListByDomainAndName = ifp_users_list_by_domain_and_name
 };
diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml
index 340eb6d23ebfebb508e12118b9ac6c9a71fed099..612a5b5a2817231d5793346778b49cc5a132fc73 100644
--- a/src/responder/ifp/ifp_iface.xml
+++ b/src/responder/ifp/ifp_iface.xml
@@ -136,6 +136,10 @@
             <arg name="id" type="u" direction="in" />
             <arg name="result" type="o" direction="out" />
         </method>
+        <method name="FindByCertificate">
+            <arg name="pem_cert" type="s" direction="in" />
+            <arg name="result" type="o" direction="out" />
+        </method>
         <method name="ListByName">
             <arg name="name_filter" type="s" direction="in" />
             <arg name="limit" type="u" direction="in" />
diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c
index 8255cbea729d9b2c0696cbfdef5c0daf9d958631..a4fdd5d12cd5c82e7832de9d07f55ea6eb621fba 100644
--- a/src/responder/ifp/ifp_iface_generated.c
+++ b/src/responder/ifp/ifp_iface_generated.c
@@ -685,6 +685,25 @@ int iface_ifp_users_FindByID_finish(struct sbus_request *req, const char *arg_re
                                          DBUS_TYPE_INVALID);
 }
 
+/* arguments for org.freedesktop.sssd.infopipe.Users.FindByCertificate */
+const struct sbus_arg_meta iface_ifp_users_FindByCertificate__in[] = {
+    { "pem_cert", "s" },
+    { NULL, }
+};
+
+/* arguments for org.freedesktop.sssd.infopipe.Users.FindByCertificate */
+const struct sbus_arg_meta iface_ifp_users_FindByCertificate__out[] = {
+    { "result", "o" },
+    { NULL, }
+};
+
+int iface_ifp_users_FindByCertificate_finish(struct sbus_request *req, const char *arg_result)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_OBJECT_PATH, &arg_result,
+                                         DBUS_TYPE_INVALID);
+}
+
 /* arguments for org.freedesktop.sssd.infopipe.Users.ListByName */
 const struct sbus_arg_meta iface_ifp_users_ListByName__in[] = {
     { "name_filter", "s" },
@@ -743,6 +762,13 @@ const struct sbus_method_meta iface_ifp_users__methods[] = {
         invoke_u_method,
     },
     {
+        "FindByCertificate", /* name */
+        iface_ifp_users_FindByCertificate__in,
+        iface_ifp_users_FindByCertificate__out,
+        offsetof(struct iface_ifp_users, FindByCertificate),
+        invoke_s_method,
+    },
+    {
         "ListByName", /* name */
         iface_ifp_users_ListByName__in,
         iface_ifp_users_ListByName__out,
diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h
index d2e5cdd3a689d42509e63adde70237cbde627ee2..4dfe61ddff3763b1d3ee165b9098efd667037663 100644
--- a/src/responder/ifp/ifp_iface_generated.h
+++ b/src/responder/ifp/ifp_iface_generated.h
@@ -68,6 +68,7 @@
 #define IFACE_IFP_USERS "org.freedesktop.sssd.infopipe.Users"
 #define IFACE_IFP_USERS_FINDBYNAME "FindByName"
 #define IFACE_IFP_USERS_FINDBYID "FindByID"
+#define IFACE_IFP_USERS_FINDBYCERTIFICATE "FindByCertificate"
 #define IFACE_IFP_USERS_LISTBYNAME "ListByName"
 #define IFACE_IFP_USERS_LISTBYDOMAINANDNAME "ListByDomainAndName"
 
@@ -235,6 +236,7 @@ struct iface_ifp_users {
     struct sbus_vtable vtable; /* derive from sbus_vtable */
     int (*FindByName)(struct sbus_request *req, void *data, const char *arg_name);
     int (*FindByID)(struct sbus_request *req, void *data, uint32_t arg_id);
+    int (*FindByCertificate)(struct sbus_request *req, void *data, const char *arg_pem_cert);
     int (*ListByName)(struct sbus_request *req, void *data, const char *arg_name_filter, uint32_t arg_limit);
     int (*ListByDomainAndName)(struct sbus_request *req, void *data, const char *arg_domain_name, const char *arg_name_filter, uint32_t arg_limit);
 };
@@ -245,6 +247,9 @@ int iface_ifp_users_FindByName_finish(struct sbus_request *req, const char *arg_
 /* finish function for FindByID */
 int iface_ifp_users_FindByID_finish(struct sbus_request *req, const char *arg_result);
 
+/* finish function for FindByCertificate */
+int iface_ifp_users_FindByCertificate_finish(struct sbus_request *req, const char *arg_result);
+
 /* finish function for ListByName */
 int iface_ifp_users_ListByName_finish(struct sbus_request *req, const char *arg_result[], int len_result);
 
diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
index fa6f47f0d2f7ce52c3f0069b8ebf0bf1c98dbf22..e661b8b1b886fed922df7ea286b8756c5ad429de 100644
--- a/src/responder/ifp/ifp_users.c
+++ b/src/responder/ifp/ifp_users.c
@@ -25,6 +25,7 @@
 #include "db/sysdb.h"
 #include "util/util.h"
 #include "util/strtonum.h"
+#include "util/cert.h"
 #include "sbus/sssd_dbus_errors.h"
 #include "responder/common/responder.h"
 #include "responder/common/responder_cache_req.h"
@@ -222,6 +223,92 @@ done:
     return;
 }
 
+static void ifp_users_find_by_cert_done(struct tevent_req *req);
+
+int ifp_users_find_by_cert(struct sbus_request *sbus_req, void *data,
+                           const char *pem_cert)
+{
+    struct ifp_ctx *ctx;
+    struct tevent_req *req;
+    int ret;
+    char *derb64;
+    DBusError *error;
+
+    ctx = talloc_get_type(data, struct ifp_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
+        return ERR_INTERNAL;
+    }
+
+    ret = sss_cert_pem_to_derb64(sbus_req, pem_cert, &derb64);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "sss_cert_pem_to_derb64 failed.\n");
+
+        if (ret == ENOMEM) {
+            return ret;
+        }
+
+        error = sbus_error_new(sbus_req, SBUS_ERROR_EINVAL,
+                               "Invalid certificate format");
+        sbus_request_fail_and_finish(sbus_req, error);
+        /* the connection is already terminated with an error message, hence
+         * we have to return EOK to not terminate the connection twice. */
+        return EOK;
+    }
+
+    req = cache_req_user_by_cert_send(sbus_req, ctx->rctx->ev, ctx->rctx,
+                                      ctx->ncache, ctx->neg_timeout, 0,
+                                      NULL, derb64);
+    if (req == NULL) {
+        return ENOMEM;
+    }
+
+    tevent_req_set_callback(req, ifp_users_find_by_cert_done, sbus_req);
+
+    return EOK;
+}
+
+static void ifp_users_find_by_cert_done(struct tevent_req *req)
+{
+    DBusError *error;
+    struct sbus_request *sbus_req;
+    struct sss_domain_info *domain;
+    struct ldb_result *result;
+    char *object_path;
+    errno_t ret;
+
+    sbus_req = tevent_req_callback_data(req, struct sbus_request);
+
+    ret = cache_req_user_by_cert_recv(sbus_req, req, &result, &domain, NULL);
+    talloc_zfree(req);
+    if (ret == ENOENT) {
+        error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
+                               "User not found");
+        goto done;
+    } else if (ret != EOK) {
+        error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
+                               "user [%d]: %s\n", ret, sss_strerror(ret));
+        goto done;
+    }
+
+    object_path = ifp_users_build_path_from_msg(sbus_req, domain,
+                                                result->msgs[0]);
+    if (object_path == NULL) {
+        error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
+                               "Failed to compose object path");
+        goto done;
+    }
+
+done:
+    if (ret != EOK) {
+        sbus_request_fail_and_finish(sbus_req, error);
+        return;
+    }
+
+    iface_ifp_users_FindByCertificate_finish(sbus_req, object_path);
+    return;
+}
+
 int ifp_users_list_by_name(struct sbus_request *sbus_req,
                            void *data,
                            const char *filter,
diff --git a/src/responder/ifp/ifp_users.h b/src/responder/ifp/ifp_users.h
index 4da0a734752a2a1bd11b0e21c532a1302c9126f1..471c3fb019c7cd0858b2928969b045091f370446 100644
--- a/src/responder/ifp/ifp_users.h
+++ b/src/responder/ifp/ifp_users.h
@@ -43,6 +43,10 @@ int ifp_users_find_by_id(struct sbus_request *sbus_req,
                          void *data,
                          uint32_t id);
 
+int ifp_users_find_by_cert(struct sbus_request *sbus_req,
+                           void *data,
+                           const char *pem_cert);
+
 int ifp_users_list_by_name(struct sbus_request *sbus_req,
                            void *data,
                            const char *filter,
diff --git a/src/sbus/sssd_dbus_errors.h b/src/sbus/sssd_dbus_errors.h
index b2b2b233be4d2839d59cb32389505de2b393ba57..7f1656a274f3d2fd52ccd4cb1575ace78bc6d0d1 100644
--- a/src/sbus/sssd_dbus_errors.h
+++ b/src/sbus/sssd_dbus_errors.h
@@ -25,5 +25,6 @@
 
 #define SBUS_ERROR_INTERNAL "org.freedesktop.sssd.Error.Internal"
 #define SBUS_ERROR_NOT_FOUND "org.freedesktop.sssd.Error.NotFound"
+#define SBUS_ERROR_EINVAL "org.freedesktop.sssd.Error.InvalidArgument"
 
 #endif /* SSSD_DBUS_ERRORS_H_ */
-- 
2.1.0



More information about the sssd-devel mailing list