summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2017-02-02 11:24:02 +0100
committerSumit Bose <sbose@redhat.com>2017-02-13 17:31:47 +0100
commit0fe77bbfa9d4e6099c29c7fdcb10971c3ee768b9 (patch)
tree5005340c8bad32cf4926adc1cff40de5b74ac7f4
parenta900fb16256367af2daceec381e1908ecf17c15e (diff)
downloadsssd-0fe77bbfa9d4e6099c29c7fdcb10971c3ee768b9.tar.gz
sssd-0fe77bbfa9d4e6099c29c7fdcb10971c3ee768b9.tar.xz
sssd-0fe77bbfa9d4e6099c29c7fdcb10971c3ee768b9.zip
certmap: add new library libsss_certmap
-rw-r--r--Makefile.am54
-rw-r--r--configure.ac1
-rw-r--r--contrib/sssd.spec.in31
-rw-r--r--src/lib/certmap/sss_cert_content_nss.c346
-rw-r--r--src/lib/certmap/sss_certmap.c1398
-rw-r--r--src/lib/certmap/sss_certmap.doxy.in3
-rw-r--r--src/lib/certmap/sss_certmap.exports13
-rw-r--r--src/lib/certmap/sss_certmap.h69
-rw-r--r--src/lib/certmap/sss_certmap.pc.in11
-rw-r--r--src/lib/certmap/sss_certmap_int.h140
-rw-r--r--src/tests/cmocka/test_certmap.c853
-rw-r--r--src/tests/dlopen-tests.c1
12 files changed, 2919 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index a3965ec00..95cf55e18 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -274,6 +274,7 @@ if HAVE_CMOCKA
test_ipa_dn \
simple-access-tests \
krb5_common_test \
+ sss_certmap_test \
$(NULL)
if HAVE_LIBRESOLV
@@ -335,7 +336,8 @@ sssdlib_LTLIBRARIES = \
libsss_ldap.la \
libsss_krb5.la \
libsss_proxy.la \
- libsss_simple.la
+ libsss_simple.la \
+ $(NULL)
if BUILD_SAMBA
sssdlib_LTLIBRARIES += \
@@ -1044,6 +1046,7 @@ SSSD_INTERNAL_LTLIBS = \
lib_LTLIBRARIES = libipa_hbac.la \
libsss_idmap.la \
libsss_nss_idmap.la \
+ libsss_certmap.la \
$(NULL)
pkgconfig_DATA += src/lib/ipa_hbac/ipa_hbac.pc
@@ -1098,6 +1101,7 @@ include_HEADERS = \
src/lib/ipa_hbac/ipa_hbac.h \
src/lib/idmap/sss_idmap.h \
src/sss_client/idmap/sss_nss_idmap.h \
+ src/lib/certmap/sss_certmap.h \
$(NULL)
if BUILD_LIBWBCLIENT
@@ -1662,6 +1666,35 @@ sss_ssh_knownhostsproxy_LDADD = \
$(CLIENT_LIBS) $(TALLOC_LIBS) $(POPT_LIBS)
endif
+if HAVE_NSS
+pkgconfig_DATA += src/lib/certmap/sss_certmap.pc
+libsss_certmap_la_DEPENDENCIES = src/lib/certmap/sss_certmap.exports
+libsss_certmap_la_SOURCES = \
+ src/lib/certmap/sss_certmap.c \
+ src/lib/certmap/sss_cert_content_nss.c \
+ src/util/util_ext.c \
+ src/util/cert/cert_common.c \
+ src/util/crypto/nss/nss_base64.c \
+ src/util/cert/nss/cert.c \
+ src/util/crypto/nss/nss_util.c \
+ $(NULL)
+libsss_certmap_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(TALLOC_CFLAGS) \
+ $(NSS_CFLAGS) \
+ $(NULL)
+libsss_certmap_la_LIBADD = \
+ $(TALLOC_LIBS) \
+ $(NSS_LIBS) \
+ $(NULL)
+libsss_certmap_la_LDFLAGS = \
+ -Wl,--version-script,$(srcdir)/src/lib/certmap/sss_certmap.exports \
+ -version-info 0:0:0
+
+dist_noinst_DATA += src/lib/certmap/sss_certmap.exports
+dist_noinst_HEADERS += src/lib/certmap/sss_certmap_int.h
+endif
+
#################
# Feature Tests #
#################
@@ -3157,6 +3190,24 @@ krb5_common_test_LDADD = \
libdlopen_test_providers.la \
$(NULL)
+if HAVE_NSS
+sss_certmap_test_SOURCES = \
+ src/tests/cmocka/test_certmap.c \
+ $(NULL)
+sss_certmap_test_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(NSS_CFLAGS) \
+ $(NULL)
+sss_certmap_test_LDADD = \
+ $(CMOCKA_LIBS) \
+ $(POPT_LIBS) \
+ $(TALLOC_LIBS) \
+ $(NSS_LIBS) \
+ $(SSSD_INTERNAL_LTLIBS) \
+ libsss_test_common.la \
+ libsss_certmap.la \
+ $(NULL)
+endif
endif # HAVE_CMOCKA
noinst_PROGRAMS = pam_test_client
@@ -4275,6 +4326,7 @@ docs:
$(DOXYGEN) src/lib/ipa_hbac/ipa_hbac.doxy
$(DOXYGEN) src/lib/idmap/sss_idmap.doxy
$(DOXYGEN) src/sss_client/idmap/sss_nss_idmap.doxy
+ $(DOXYGEN) src/lib/certmap/sss_certmap.doxy
if BUILD_IFP
$(DOXYGEN) src/lib/sifp/sss_simpleifp.doxy
endif
diff --git a/configure.ac b/configure.ac
index d264abf3e..e82c010b2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -482,6 +482,7 @@ AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config
src/tests/intg/Makefile
src/lib/ipa_hbac/ipa_hbac.pc src/lib/ipa_hbac/ipa_hbac.doxy
src/lib/idmap/sss_idmap.pc src/lib/idmap/sss_idmap.doxy
+ src/lib/certmap/sss_certmap.pc src/lib/certmap/sss_certmap.doxy
src/sss_client/idmap/sss_nss_idmap.pc
src/sss_client/idmap/sss_nss_idmap.doxy
src/sss_client/libwbclient/wbclient_sssd.pc
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index c0c9e364b..bbb5eb5d6 100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -658,6 +658,25 @@ The libnfsidmap sssd module provides a way for rpc.idmapd to call SSSD to map
UIDs/GIDs to names and vice versa. It can be also used for mapping principal
(user) name to IDs(UID or GID) or to obtain groups which user are member of.
+%package -n libsss_certmap
+Summary: SSSD Certficate Mapping Library
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_certmap
+Library to map certificates to users based on rules
+
+%package -n libsss_certmap-devel
+Summary: SSSD Certficate Mapping Library
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libsss_certmap = %{version}-%{release}
+
+%description -n libsss_certmap-devel
+Library to map certificates to users based on rules
+
%prep
%setup -q -n %{name}-%{version}
@@ -1139,6 +1158,18 @@ done
%files nfs-idmap
%{_libdir}/libnfsidmap/sss.so
+%files -n libsss_certmap
+%defattr(-,root,root,-)
+%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libsss_certmap.so.*
+
+%files -n libsss_certmap-devel
+%defattr(-,root,root,-)
+%doc certmap_doc/html
+%{_includedir}/sss_certmap.h
+%{_libdir}/libsss_certmap.so
+%{_libdir}/pkgconfig/sss_certmap.pc
+
%pre common
getent group sssd >/dev/null || groupadd -r sssd
getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
diff --git a/src/lib/certmap/sss_cert_content_nss.c b/src/lib/certmap/sss_cert_content_nss.c
new file mode 100644
index 000000000..c166877e8
--- /dev/null
+++ b/src/lib/certmap/sss_cert_content_nss.c
@@ -0,0 +1,346 @@
+/*
+ SSSD - certificate handling utils - NSS version
+ The calls defined here should be useable outside of SSSD as well, e.g. in
+ libsss_certmap.
+
+ Copyright (C) Sumit Bose <sbose@redhat.com> 2017
+
+ 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 "config.h"
+
+#include <nss.h>
+#include <cert.h>
+#include <base64.h>
+#include <prerror.h>
+#include <secport.h>
+#include <nspr4/prprf.h>
+#include <talloc.h>
+
+#include "util/crypto/sss_crypto.h"
+#include "util/crypto/nss/nss_util.h"
+#include "util/cert.h"
+#include "lib/certmap/sss_certmap.h"
+#include "lib/certmap/sss_certmap_int.h"
+
+
+/* The following two functions are copied from NSS's lib/certdb/secname.c
+ * becasue CERT_AddAVA is not exported. I just renamed it and made it static
+ * to avoid issues if the call gets exported some time in future. */
+
+static void **
+AddToArray(PLArenaPool *arena, void **array, void *element)
+{
+ unsigned count;
+ void **ap;
+
+ /* Count up number of slots already in use in the array */
+ count = 0;
+ ap = array;
+ if (ap) {
+ while (*ap++) {
+ count++;
+ }
+ }
+
+ if (array) {
+ array = (void**) PORT_ArenaGrow(arena, array,
+ (count + 1) * sizeof(void *),
+ (count + 2) * sizeof(void *));
+ } else {
+ array = (void**) PORT_ArenaAlloc(arena, (count + 2) * sizeof(void *));
+ }
+ if (array) {
+ array[count] = element;
+ array[count+1] = 0;
+ }
+ return array;
+}
+
+
+static SECStatus
+sss_CERT_AddAVA(PLArenaPool *arena, CERTRDN *rdn, CERTAVA *ava)
+{
+ rdn->avas = (CERTAVA**) AddToArray(arena, (void**) rdn->avas, ava);
+ return rdn->avas ? SECSuccess : SECFailure;
+}
+
+static SECItem *
+cert_get_ext_by_tag(CERTCertificate *cert, SECOidTag tag)
+{
+ SECOidData *oid;
+ int i;
+
+ oid = SECOID_FindOIDByTag(tag);
+ for (i = 0;
+ (cert->extensions != NULL) && (cert->extensions[i] != NULL);
+ i++)
+ if (SECITEM_ItemsAreEqual(&cert->extensions[i]->id, &oid->oid))
+ return &cert->extensions[i]->value;
+ return NULL;
+}
+
+static int get_extended_key_usage_oids(TALLOC_CTX *mem_ctx,
+ CERTCertificate *cert,
+ const char ***_oids)
+{
+ PLArenaPool *pool;
+ SECItem *ext;
+ SECItem **oids = NULL;
+ const char **oids_list = NULL;
+ size_t c;
+ SECStatus rv;
+ char *tmp_str;
+ int ret;
+
+ pool = PORT_NewArena(sizeof(double));
+ ext = cert_get_ext_by_tag(cert, SEC_OID_X509_EXT_KEY_USAGE);
+ if (ext != NULL) {
+ rv = SEC_ASN1DecodeItem(pool, &oids,
+ SEC_ASN1_GET(SEC_SequenceOfObjectIDTemplate),
+ ext);
+ if (rv != SECSuccess) {
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ for (c = 0; (oids != NULL && oids[c] != NULL); c++);
+ oids_list = talloc_zero_array(mem_ctx, const char *, c + 1);
+ if (oids_list == NULL) {
+ return ENOMEM;
+ }
+
+ for (c = 0; (oids != NULL && oids[c] != NULL); c++) {
+ tmp_str = CERT_GetOidString(oids[c]);
+ /* is it expexted that NSS OID strings start with "OID." but we
+ * prefer the plain dotted-decimal version so the prefix is skipped */
+ if (tmp_str == NULL || strncmp(tmp_str, "OID.", 4) != 0) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ oids_list[c] = talloc_strdup(oids_list, tmp_str + 4);
+ PR_smprintf_free(tmp_str);
+ if(oids_list[c] == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ ret = 0;
+
+done:
+ PORT_FreeArena(pool, PR_TRUE);
+ if (ret == 0) {
+ *_oids = oids_list;
+ } else {
+ talloc_free(oids_list);
+ }
+
+ return ret;
+
+}
+
+static int get_rdn_str(TALLOC_CTX *mem_ctx, CERTAVA **avas,
+ const char **rdn_str)
+{
+ size_t c;
+ char *tmp_name = NULL;
+ const char *tmp_str = NULL;
+ int ret;
+ SECStatus rv;
+ CERTRDN rdn = { 0 };
+ CERTName *name = NULL;
+ PLArenaPool *arena = NULL;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+
+ /* Multiple AVAs should be avoided becasue there is no general ordering
+ * rule and the RDN strings are not reproducible */
+ for (c = 0; avas[c] != NULL; c++) {
+ rv = sss_CERT_AddAVA(arena, &rdn, avas[c]);
+ if (rv != SECSuccess) {
+ ret = EIO;
+ goto done;
+ }
+ }
+
+ name = CERT_CreateName(&rdn, NULL);
+ if (name == NULL) {
+ ret = EIO;
+ goto done;
+ }
+
+ tmp_name = CERT_NameToAscii(name);
+ CERT_DestroyName(name);
+ if (tmp_name == NULL) {
+ ret = EIO;
+ goto done;
+ }
+
+ tmp_str = talloc_strdup(mem_ctx, tmp_name);
+ PORT_Free(tmp_name);
+ if (tmp_str == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *rdn_str = tmp_str;
+ } else {
+ talloc_free(discard_const(tmp_str));
+ }
+ PORT_FreeArena(arena, PR_FALSE);
+
+ return ret;
+}
+
+static int get_rdn_list(TALLOC_CTX *mem_ctx, CERTRDN **rdns,
+ const char ***rdn_list)
+{
+ int ret;
+ size_t c;
+ const char **list = NULL;
+
+ for (c = 0; rdns[c] != NULL; c++);
+ list = talloc_zero_array(mem_ctx, const char *, c + 1);
+ if (list == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ for (c = 0; rdns[c] != NULL; c++) {
+ ret = get_rdn_str(list, rdns[c]->avas,
+ &(list[c]));
+ if (ret != 0) {
+ goto done;
+ }
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *rdn_list = list;
+ } else {
+ talloc_free(list);
+ }
+
+ return ret;
+}
+
+int sss_cert_get_content(TALLOC_CTX *mem_ctx,
+ const uint8_t *der_blob, size_t der_size,
+ struct sss_cert_content **content)
+{
+ int ret;
+ struct sss_cert_content *cont = NULL;
+ CERTCertDBHandle *handle;
+ CERTCertificate *cert = NULL;
+ SECItem der_item;
+ NSSInitContext *nss_ctx;
+ NSSInitParameters parameters = { 0 };
+ parameters.length = sizeof (parameters);
+
+ if (der_blob == NULL || der_size == 0) {
+ return EINVAL;
+ }
+
+ nss_ctx = NSS_InitContext("", "", "", "", NULL, NSS_INIT_READONLY
+ | NSS_INIT_NOCERTDB
+ | NSS_INIT_NOMODDB
+ | NSS_INIT_FORCEOPEN
+ | NSS_INIT_NOROOTINIT
+ | NSS_INIT_OPTIMIZESPACE);
+ if (nss_ctx == NULL) {
+ return EIO;
+ }
+
+ cont = talloc_zero(mem_ctx, struct sss_cert_content);
+ if (cont == NULL) {
+ return ENOMEM;
+ }
+
+ handle = CERT_GetDefaultCertDB();
+ der_item.len = der_size;
+ der_item.data = discard_const(der_blob);
+
+ cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE);
+ if (cert == NULL) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ cont->issuer_str = talloc_strdup(cont, cert->issuerName);
+ if (cont->issuer_str == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = get_rdn_list(cont, cert->issuer.rdns, &cont->issuer_rdn_list);
+ if (ret != 0) {
+ goto done;
+ }
+
+ cont->subject_str = talloc_strdup(cont, cert->subjectName);
+ if (cont->subject_str == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = get_rdn_list(cont, cert->subject.rdns, &cont->subject_rdn_list);
+ if (ret != 0) {
+ goto done;
+ }
+
+
+ cont->key_usage = cert->keyUsage;
+
+ ret = get_extended_key_usage_oids(cont, cert,
+ &(cont->extended_key_usage_oids));
+ if (ret != 0) {
+ goto done;
+ }
+
+ cont->cert_der = talloc_memdup(cont, der_blob, der_size);
+ if (cont->cert_der == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ cont->cert_der_size = der_size;
+ ret = EOK;
+
+done:
+
+ CERT_DestroyCertificate(cert);
+ NSS_ShutdownContext(nss_ctx);
+
+ if (ret == EOK) {
+ *content = cont;
+ } else {
+ talloc_free(cont);
+ }
+
+ return ret;
+}
diff --git a/src/lib/certmap/sss_certmap.c b/src/lib/certmap/sss_certmap.c
new file mode 100644
index 000000000..0028a120c
--- /dev/null
+++ b/src/lib/certmap/sss_certmap.c
@@ -0,0 +1,1398 @@
+/*
+ SSSD
+
+ Library for rule based certificate to user mapping
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2017 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 "util/util.h"
+#include "util/cert.h"
+#include "util/crypto/sss_crypto.h"
+#include "lib/certmap/sss_certmap.h"
+#include "lib/certmap/sss_certmap_int.h"
+
+#include "util/crypto/nss/nss_util.h"
+
+int debug_level;
+void sss_debug_fn(const char *file,
+ long line,
+ const char *function,
+ int level,
+ const char *format, ...)
+{
+ return;
+}
+
+//#define ERRMSG(text) text "("__FILE__":"__LINE__" "__FUNCTION__")"
+#define ERRMSG(text) text
+
+int sss_certmap_init(TALLOC_CTX *mem_ctx,
+ sss_certmap_ext_debug *debug, void *debug_priv,
+ struct sss_certmap_ctx **ctx)
+{
+ if (ctx == NULL) {
+ return EINVAL;
+ }
+
+ *ctx = talloc_zero(mem_ctx, struct sss_certmap_ctx);
+ if (*ctx == NULL) {
+ return ENOMEM;
+ }
+
+ (*ctx)->debug = debug;
+ (*ctx)->debug_priv = debug_priv;
+
+ CM_DEBUG((*ctx), "sss_certmap initialized.\n");
+ return EOK;
+}
+
+void sss_certmap_free_ctx(struct sss_certmap_ctx *ctx)
+{
+ talloc_free(ctx);
+}
+
+void sss_certmap_free_filter_and_domains(char *filter, char **domains)
+{
+ talloc_free(filter);
+ talloc_free(domains);
+}
+
+const char *sss_certmap_err_msg(struct sss_certmap_ctx *ctx)
+{
+ if (ctx->err_msg != NULL) {
+ return ctx->err_msg;
+ }
+
+ return "(no error messages available)";
+}
+
+static int get_type_prefix(TALLOC_CTX *mem_ctx, const char *match_rule,
+ char **type, const char **rule_start)
+{
+ const char *c;
+ char *delim;
+
+ *type = NULL;
+ *rule_start = match_rule;
+
+ delim = strchr(match_rule, ':');
+ if (delim == NULL) {
+ /* no type prefix found */
+ return 0;
+ }
+
+ /* rule starts with ':', empty type */
+ if (delim == match_rule) {
+ *rule_start = delim + 1;
+ return EOK;
+ }
+
+ for (c = match_rule; c < delim; c++) {
+ /* type prefix may only contain digits and upper-case ASCII characters */
+ if (!(isascii(*c) && (isdigit(*c) || isupper(*c)))) {
+ /* no type prefix found */
+ return 0;
+ }
+ }
+
+ *rule_start = delim + 1;
+ *type = talloc_strndup(mem_ctx, match_rule, (delim - match_rule));
+ if (*type == NULL) {
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+static int component_list_destructor(void *data)
+{
+ struct component_list *comp = talloc_get_type(data, struct component_list);
+
+ if (comp != NULL) {
+ regfree(&(comp->regexp));
+ }
+
+ return 0;
+}
+
+/*
+ * The syntax of the MIT Kerberos style matching rules is:
+ * [KRB5:][relation-operator]component-rule ...
+ *
+ * where:
+ *
+ * relation-operator
+ * can be either &&, meaning all component rules must match, or ||,
+ * meaning only one component rule must match. The default is &&.
+ *
+ * component-rule
+ * can be one of the following. Note that there is no punctuation or whitespace between component rules.
+ * <SUBJECT>regular-expression
+ * <ISSUER>regular-expression
+ * <SAN>regular-expression
+ * <EKU>extended-key-usage
+ * <KU>key-usage
+ *
+ * TODO:
+ * generic extension handling for e.g. MSFT 1.3.6.1.4.1.311.20.2
+ */
+
+static int get_comp_value(TALLOC_CTX *mem_ctx,
+ struct sss_certmap_ctx *ctx,
+ const char **cur,
+ struct component_list **_comp)
+
+{
+ struct component_list *comp = NULL;
+ const char *end;
+ int ret;
+
+ comp = talloc_zero(mem_ctx, struct component_list);
+ if (comp == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_set_destructor((TALLOC_CTX *) comp, component_list_destructor);
+
+ end = strchr(*cur, '<');
+
+ if (end == NULL) {
+ comp->val = talloc_strdup(comp, *cur);
+ } else {
+ comp->val = talloc_strndup(comp, *cur, end - *cur);
+ }
+ if (comp->val == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ if (*(comp->val) == '\0') {
+ ctx->err_msg = ERRMSG("Missing component value.");
+ ret = EINVAL;
+ goto done;
+ }
+
+ *cur += strlen(comp->val);
+ *_comp = comp;
+ ret = 0;
+
+done:
+ if (ret != 0) {
+ talloc_free(comp);
+ }
+
+ return ret;
+}
+
+static int parse_krb5_get_eku_value(TALLOC_CTX *mem_ctx,
+ struct sss_certmap_ctx *ctx,
+ const char **cur,
+ struct component_list **_comp)
+{
+ struct component_list *comp = NULL;
+ int ret;
+ char **eku_list;
+ size_t c;
+ size_t k;
+ const char *o;
+ size_t e = 0;
+ int eku_list_size;
+
+ struct ext_key_usage {
+ const char *name;
+ const char *oid;
+ } ext_key_usage[] = {
+ /* RFC 3280 section 4.2.1.13 */
+ {"serverAuth", "1.3.6.1.5.5.7.3.1"},
+ {"clientAuth", "1.3.6.1.5.5.7.3.2"},
+ {"codeSigning", "1.3.6.1.5.5.7.3.3"},
+ {"emailProtection", "1.3.6.1.5.5.7.3.4"},
+ {"timeStamping", "1.3.6.1.5.5.7.3.8"},
+ {"OCSPSigning", "1.3.6.1.5.5.7.3.9"},
+
+ /* RFC 4556 section 3.2.2 */
+ {"KPClientAuth", "1.3.6.1.5.2.3.4"},
+ {"pkinit", "1.3.6.1.5.2.3.4"},
+
+ /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography*/
+ {"msScLogin", "1.3.6.1.4.1.311.20.2.2"},
+
+ {NULL ,0}
+ };
+
+ ret = get_comp_value(mem_ctx, ctx, cur, &comp);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to parse regexp.");
+ goto done;
+ }
+
+ ret = split_on_separator(mem_ctx, comp->val, ',', true, true,
+ &eku_list, &eku_list_size);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to split list.");
+ CM_DEBUG(ctx, "Failed to split list.");
+ goto done;
+ }
+
+ for (c = 0; eku_list[c] != NULL; c++) {
+ for (k = 0; ext_key_usage[k].name != NULL; k++) {
+CM_DEBUG(ctx, "[%s][%s].", eku_list[c], ext_key_usage[k].name);
+ if (strcasecmp(eku_list[c], ext_key_usage[k].name) == 0) {
+ if (comp->eku_oid_list == NULL) {
+ comp->eku_oid_list = talloc_zero_array(comp, const char *,
+ eku_list_size + 1);
+ if (comp->eku_oid_list == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list,
+ ext_key_usage[k].oid);
+ if (comp->eku_oid_list[e] == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ e++;
+ break;
+ }
+ }
+
+ if (ext_key_usage[k].name == NULL) {
+ /* check for an dotted-decimal OID */
+ if (*(eku_list[c]) != '.') {
+ o = eku_list[c];
+ while (*o != '\0') {
+ if (*o != '.' && !isdigit(*o)) {
+ break;
+ }
+ o++;
+ }
+ if (*o == '\0' && *(o - 1) != '.') {
+ /* looks like a OID, only '.' and digits */
+ comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list,
+ eku_list[c]);
+ if (comp->eku_oid_list[e] == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ e++;
+ continue;
+ }
+ }
+ CM_DEBUG(ctx, "No matching extended key usage found.");
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *_comp = comp;
+ } else {
+ talloc_free(comp);
+ }
+
+ return ret;
+}
+
+static int parse_krb5_get_ku_value(TALLOC_CTX *mem_ctx,
+ struct sss_certmap_ctx *ctx,
+ const char **cur,
+ struct component_list **_comp)
+{
+ struct component_list *comp = NULL;
+ int ret;
+ char **ku_list;
+ size_t c;
+ size_t k;
+
+ struct key_usage {
+ const char *name;
+ uint32_t flag;
+ } key_usage[] = {
+ {"digitalSignature" , SSS_KU_DIGITAL_SIGNATURE},
+ {"nonRepudiation" , SSS_KU_NON_REPUDIATION},
+ {"keyEncipherment" , SSS_KU_KEY_ENCIPHERMENT},
+ {"dataEncipherment" , SSS_KU_DATA_ENCIPHERMENT},
+ {"keyAgreement" , SSS_KU_KEY_AGREEMENT},
+ {"keyCertSign" , SSS_KU_KEY_CERT_SIGN},
+ {"cRLSign" , SSS_KU_CRL_SIGN},
+ {"encipherOnly" , SSS_KU_ENCIPHER_ONLY},
+ {"decipherOnly" , SSS_KU_DECIPHER_ONLY},
+ {NULL ,0}
+ };
+
+
+ ret = get_comp_value(mem_ctx, ctx, cur, &comp);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to get value.");
+ CM_DEBUG(ctx, "Failed to get value.");
+ goto done;
+ }
+
+ ret = split_on_separator(mem_ctx, comp->val, ',', true, true,
+ &ku_list, NULL);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to split list.");
+ CM_DEBUG(ctx, "Failed to split list.");
+ goto done;
+ }
+
+ for (c = 0; ku_list[c] != NULL; c++) {
+ for (k = 0; key_usage[k].name != NULL; k++) {
+ if (strcasecmp(ku_list[c], key_usage[k].name) == 0) {
+ comp->ku |= key_usage[k].flag;
+ break;
+ }
+ }
+
+ if (key_usage[k].name == NULL) {
+ /* FIXME: add check for numerical ku */
+ CM_DEBUG(ctx, "No matching key usage found.");
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *_comp = comp;
+ } else {
+ talloc_free(comp);
+ }
+
+ return ret;
+}
+
+static int parse_krb5_get_component_value(TALLOC_CTX *mem_ctx,
+ struct sss_certmap_ctx *ctx,
+ const char **cur,
+ struct component_list **_comp)
+{
+ struct component_list *comp = NULL;
+ int ret;
+
+ ret = get_comp_value(mem_ctx, ctx, cur, &comp);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to parse regexp.");
+ goto done;
+ }
+
+ ret = regcomp(&(comp->regexp), comp->val, REG_EXTENDED);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to parse regexp.");
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *_comp = comp;
+ } else {
+ talloc_free(comp);
+ }
+
+ return ret;
+}
+
+static int parse_krb5_match_rule(struct sss_certmap_ctx *ctx,
+ const char *rule_start,
+ struct krb5_match_rule **match_rule)
+{
+ const char *cur;
+ struct krb5_match_rule *rule;
+ struct component_list *comp;
+ int ret;
+
+ rule = talloc_zero(ctx, struct krb5_match_rule);
+ if (rule == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ cur = rule_start;
+ /* check relation */
+ if (strncmp(cur, "&&", 2) == 0) {
+ rule->r = relation_and;
+ cur += 2;
+ } else if (strncmp(cur, "||", 2) == 0) {
+ rule->r = relation_or;
+ cur += 2;
+ } else {
+ rule->r = relation_and;
+ }
+
+ while (*cur != '\0') {
+ /* new component must start with '<' */
+ if (*cur != '<') {
+ ctx->err_msg = ERRMSG("Invalid KRB5 matching rule.");
+ ret = EINVAL;
+ goto done;
+ }
+ cur++;
+
+ if (strncmp(cur, "ISSUER>", 7) == 0) {
+ cur += 7;
+ ret = parse_krb5_get_component_value(rule, ctx, &cur, &comp);
+ if (ret != 0) {
+ goto done;
+ }
+ DLIST_ADD(rule->issuer, comp);
+ } else if (strncmp(cur, "SUBJECT>", 8) == 0) {
+ cur += 8;
+ ret = parse_krb5_get_component_value(rule, ctx, &cur, &comp);
+ if (ret != 0) {
+ goto done;
+ }
+ DLIST_ADD(rule->subject, comp);
+ } else if (strncmp(cur, "KU>", 3) == 0) {
+ cur += 3;
+ ret = parse_krb5_get_ku_value(rule, ctx, &cur, &comp);
+ if (ret != 0) {
+ goto done;
+ }
+ DLIST_ADD(rule->ku, comp);
+ } else if (strncmp(cur, "EKU>", 4) == 0) {
+ cur += 4;
+ ret = parse_krb5_get_eku_value(rule, ctx, &cur, &comp);
+ if (ret != 0) {
+ goto done;
+ }
+ DLIST_ADD(rule->eku, comp);
+ } else {
+ ctx->err_msg = ERRMSG("Invalid KRB5 matching rule.");
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *match_rule = rule;
+ } else {
+ talloc_free(rule);
+ }
+
+ return ret;
+}
+
+static int parse_match_rule(struct sss_certmap_ctx *ctx, const char *match_rule,
+ struct krb5_match_rule **parsed_match_rule)
+{
+ int ret;
+ char *type;
+ const char *rule_start;
+
+ ret = get_type_prefix(ctx, match_rule, &type, &rule_start);
+ if (ret != EOK) {
+ ctx->err_msg = ERRMSG("Failed to read rule type.");
+ goto done;
+ }
+
+ if (type == NULL || strcmp(type, "KRB5") == 0) {
+ ret = parse_krb5_match_rule(ctx, rule_start, parsed_match_rule);
+ if (ret != EOK) {
+ ctx->err_msg = ERRMSG("Failed to parse KRB5 matching rule.\n");
+ goto done;
+ }
+ } else {
+ ctx->err_msg = ERRMSG("Unsupported matching rule type.\n");
+ ret = ESRCH;
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(type);
+
+ return ret;
+}
+
+struct template_table {
+ const char *name;
+ const char **attr_name;
+ const char **conversion;
+};
+
+const char *empty[] = {NULL};
+const char *name_attr[] = {"name", NULL};
+const char *x500_conv[] = {"x500", "x500ad", NULL};
+const char *bin_conv[] = {"bin", "base64", NULL};
+
+struct template_table template_table[] = {
+ {"issuer_dn", empty, x500_conv},
+ {"subject_dn", empty, x500_conv},
+ {"subject_nt_principal", name_attr, empty},
+ {"cert", empty, bin_conv},
+ {NULL, NULL, NULL}};
+
+static int check_parsed_template(struct sss_certmap_ctx *ctx,
+ struct parsed_template *parsed)
+{
+ size_t n;
+ size_t a;
+ size_t c;
+ bool attr_name_valid = false;
+ bool conversion_valid = false;
+
+ for (n = 0; template_table[n].name != NULL; n++) {
+ if (strcmp(template_table[n].name, parsed->name) != 0) {
+ continue;
+ }
+
+ if (parsed->attr_name != NULL) {
+ for (a = 0; template_table[n].attr_name[a] != NULL; a++) {
+ if (strcmp(template_table[n].attr_name[a],
+ parsed->attr_name) == 0) {
+ attr_name_valid = true;
+ break;
+ }
+ }
+ } else {
+ attr_name_valid = true;
+ }
+
+ if (parsed->conversion != NULL) {
+ for (c = 0; template_table[n].conversion[c] != NULL; c++) {
+ if (strcmp(template_table[n].conversion[c],
+ parsed->conversion) == 0) {
+ conversion_valid = true;
+ break;
+ }
+ }
+ } else {
+ conversion_valid = true;
+ }
+
+ if (attr_name_valid && conversion_valid) {
+ return 0;
+ }
+ }
+
+ return EINVAL;
+}
+
+static int parse_template(TALLOC_CTX *mem_ctx, struct sss_certmap_ctx *ctx,
+ const char *template,
+ struct parsed_template **parsed_template)
+{
+ int ret;
+ struct parsed_template *parsed = NULL;
+ const char *dot;
+ const char *excl;
+ const char *p;
+
+ parsed = talloc_zero(mem_ctx, struct parsed_template);
+ if (parsed == NULL) {
+ //ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ dot = strchr(template, '.');
+ if (dot != NULL) {
+ p = strchr(dot + 1, '.');
+ if (p != NULL) {
+ //ctx->err_msg = ERRMSG("Only one '.' allowed in template.");
+ CM_DEBUG(ctx, "Only one '.' allowed in template.");
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (dot == template) {
+ //ctx->err_msg = ERRMSG("Missing name in template.");
+ CM_DEBUG(ctx, "Missing name in template.");
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ excl = strchr(template, '!');
+ if (excl != NULL) {
+ p = strchr(excl + 1, '!');
+ if (p != NULL) {
+ //ctx->err_msg = ERRMSG("Only one '!' allowed in template.");
+ CM_DEBUG(ctx, "Only one '!' allowed in template.");
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (excl == template) {
+ //ctx->err_msg = ERRMSG("Missing name in template.");
+ CM_DEBUG(ctx, "Missing name in template.");
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ if (excl != NULL && excl[1] != '\0') {
+ parsed->conversion = talloc_strdup(parsed, excl + 1);
+ if (parsed->conversion == NULL) {
+ //ctx->err_msg = ERRMSG("Memory allocation failed.");
+ CM_DEBUG(ctx, "Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ if (dot != NULL && dot[1] != '\0' && dot[1] != '!') {
+ if (excl == NULL) {
+ parsed->attr_name = talloc_strdup(parsed, dot + 1);
+ } else {
+ parsed->attr_name = talloc_strndup(parsed, dot + 1,
+ (excl - dot - 1));
+ }
+ if (parsed->attr_name == NULL) {
+ CM_DEBUG(ctx, "Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ if (dot != NULL) {
+ parsed->name = talloc_strndup(parsed, template, (dot - template));
+ } else if (excl != NULL) {
+ parsed->name = talloc_strndup(parsed, template, (excl - template));
+ } else {
+ parsed->name = talloc_strdup(parsed, template);
+ }
+ if (parsed->name == NULL) {
+ //ctx->err_msg = ERRMSG("Memory allocation failed.");
+ CM_DEBUG(ctx, "Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = check_parsed_template(ctx, parsed);
+ if (ret != 0) {
+ CM_DEBUG(ctx, "Parse template invalid.");
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *parsed_template = parsed;
+ } else {
+ talloc_free(parsed);
+ }
+
+ return ret;
+}
+
+static int add_comp(struct sss_certmap_ctx *ctx, struct ldap_mapping_rule *rule,
+ const char *string, enum comp_type type)
+{
+ int ret;
+ struct ldap_mapping_rule_comp *comp;
+
+ comp = talloc_zero(rule, struct ldap_mapping_rule_comp);
+ if (comp == NULL) {
+ return ENOMEM;
+ }
+
+ comp->type = type;
+ comp->val = talloc_strdup(comp, string);
+ if (comp->val == NULL) {
+ talloc_free(comp);
+ return ENOMEM;
+ }
+
+ if (type == comp_template) {
+ ret = parse_template(comp, ctx, string, &comp->parsed_template);
+ if (ret != 0) {
+ talloc_free(comp);
+ return ret;
+ }
+ }
+
+ DLIST_ADD_END(rule->list, comp, struct ldap_mapping_rule_comp *);
+
+ return 0;
+}
+
+static int add_string(struct sss_certmap_ctx *ctx,
+ struct ldap_mapping_rule *rule, const char *string)
+{
+ return add_comp(ctx, rule, string, comp_string);
+}
+
+static int add_template(struct sss_certmap_ctx *ctx,
+ struct ldap_mapping_rule *rule, const char *string)
+{
+ return add_comp(ctx, rule, string, comp_template);
+}
+
+static int parse_ldap_mapping_rule(struct sss_certmap_ctx *ctx,
+ const char *rule_start,
+ struct ldap_mapping_rule **mapping_rule)
+{
+ size_t c;
+ const char *cur;
+ char *tmp_string = NULL;
+ size_t tmp_string_size;
+ struct ldap_mapping_rule *rule = NULL;
+ int ret;
+ bool in_template = false;
+
+ rule = talloc_zero(ctx, struct ldap_mapping_rule);
+ if (rule == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tmp_string_size = strlen(rule_start) + 1;
+ tmp_string = talloc_zero_size(ctx, tmp_string_size);
+ if (tmp_string == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ cur = rule_start;
+ c = 0;
+
+ while (*cur != '\0') {
+ if (c > tmp_string_size) {
+ ctx->err_msg = ERRMSG("Cannot parse mapping rule.");
+ ret = EIO;
+ goto done;
+ }
+ switch (*cur) {
+ case '{':
+ if (in_template) {
+ ctx->err_msg = ERRMSG("'{' not allowed in templates.");
+ ret = EINVAL;
+ goto done;
+ }
+ if (cur[1] == '{') {
+ /* Add only a single '{' to the output */
+ tmp_string[c] = '{';
+ c++;
+ cur += 2;
+ } else {
+ if (c != 0) {
+ ret = add_string(ctx, rule, tmp_string);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to add string.");
+ ret = EINVAL;
+ goto done;
+ }
+ memset(tmp_string, 0, tmp_string_size);
+ c = 0;
+ }
+ cur++;
+ in_template = true;
+ }
+ break;
+ case '}':
+ if (cur[1] == '}') {
+ if (in_template) {
+ ctx->err_msg = ERRMSG("'}}' not allowed in templates.");
+ ret = EINVAL;
+ goto done;
+ } else {
+ /* Add only a single '}' to the output */
+ tmp_string[c] = '}';
+ c++;
+ cur += 2;
+ }
+ } else {
+ ret = add_template(ctx, rule, tmp_string);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to add template.");
+ ret = EINVAL;
+ goto done;
+ }
+ memset(tmp_string, 0, tmp_string_size);
+ c = 0;
+ cur++;
+ in_template = false;
+ }
+ break;
+ default:
+ tmp_string[c] = *cur;
+ c++;
+ cur++;
+ }
+ }
+ if (in_template) {
+ ctx->err_msg = ERRMSG("Rule ended inside template.");
+ ret = EINVAL;
+ goto done;
+ }
+ if (c != 0) {
+ ret = add_string(ctx, rule, tmp_string);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to add string.");
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *mapping_rule = rule;
+ } else {
+ talloc_free(rule);
+ }
+
+ talloc_free(tmp_string);
+
+ return ret;
+}
+
+static int parse_mapping_rule(struct sss_certmap_ctx *ctx,
+ const char *mapping_rule,
+ struct ldap_mapping_rule **parsed_mapping_rule)
+{
+ int ret;
+ char *type;
+ const char *rule_start;
+
+ ret = get_type_prefix(ctx, mapping_rule, &type, &rule_start);
+ if (ret != EOK) {
+ ctx->err_msg = ERRMSG("Failed to read rule type.");
+ goto done;
+ }
+
+ if (type == NULL || strcmp(type, "LDAP") == 0) {
+ ret = parse_ldap_mapping_rule(ctx, rule_start, parsed_mapping_rule);
+ if (ret != EOK) {
+ ctx->err_msg = ERRMSG("Failed to parse LDAP mapping rule.\n");
+ goto done;
+ }
+ } else {
+ ctx->err_msg = ERRMSG("Unsupported mapping rule type.\n");
+ ret = ESRCH;
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(type);
+
+ return ret;
+}
+
+int sss_certmap_add_rule(struct sss_certmap_ctx *ctx,
+ unsigned int priority, const char *match_rule,
+ const char *map_rule, const char **domains)
+{
+ size_t c;
+ int ret;
+ struct match_map_rule *rule;
+ struct TALLOC_CTX *tmp_ctx;
+ struct priority_list *p;
+ struct priority_list *p_new;
+ struct krb5_match_rule *parsed_match_rule;
+ struct ldap_mapping_rule *parsed_mapping_rule;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ return ENOMEM;
+ }
+
+ rule = talloc_zero(tmp_ctx, struct match_map_rule);
+ if (rule == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ rule->priority = priority;
+
+ if (match_rule == NULL) {
+ match_rule = DEFAULT_MATCH_RULE;
+ }
+ ret = parse_match_rule(ctx, match_rule, &parsed_match_rule);
+ if (ret == 0) {
+ rule->parsed_match_rule = talloc_steal(rule, parsed_match_rule);
+ rule->match_rule = talloc_strdup(rule, match_rule);
+ if (rule->match_rule == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ } else if (ret == ESRCH) {
+ /* report unsupported rules */
+ goto done;
+ } else {
+ goto done;
+ }
+
+ if (map_rule == NULL) {
+ map_rule = DEFAULT_MAP_RULE;
+ }
+ ret = parse_mapping_rule(ctx, map_rule, &parsed_mapping_rule);
+ if (ret == 0) {
+ rule->parsed_mapping_rule = talloc_steal(rule, parsed_mapping_rule);
+ rule->map_rule = talloc_strdup(rule, map_rule);
+ if (rule->map_rule == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ } else if (ret == ESRCH) {
+ /* report unsupported rules */
+ goto done;
+ } else {
+ goto done;
+ }
+
+ if (domains != NULL && *domains != NULL) {
+ for (c = 0; domains[c] != NULL; c++);
+ rule->domains = talloc_zero_array(rule, char *, c + 1);
+ if (rule->domains == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ for (c = 0; domains[c] != NULL; c++) {
+ rule->domains[c] = talloc_strdup(rule->domains, domains[c]);
+ if (rule->domains[c] == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ }
+
+ if (ctx->prio_list == NULL) {
+ ctx->prio_list = talloc_zero(ctx, struct priority_list);
+ if (ctx->prio_list == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ctx->prio_list->priority = rule->priority;
+ ctx->prio_list->rule_list = rule;
+ } else {
+ for (p = ctx->prio_list; p != NULL && p->priority < rule->priority;
+ p = p->next);
+ if (p != NULL && p->priority == priority) {
+ DLIST_ADD(p->rule_list, rule);
+ } else {
+ p_new = talloc_zero(ctx, struct priority_list);
+ if (p_new == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ p_new->priority = rule->priority;
+ p_new->rule_list = rule;
+
+ if (p == NULL) {
+ DLIST_ADD_END(ctx->prio_list, p_new, struct priority_list *);
+ } else if (p->prev == NULL) {
+ DLIST_ADD(ctx->prio_list, p_new);
+ } else {
+ DLIST_ADD_AFTER(ctx->prio_list, p_new, p->prev);
+ }
+ }
+ }
+
+ talloc_steal(ctx, rule);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static int expand_cert(struct sss_certmap_ctx *ctx,
+ struct parsed_template *parsed_template,
+ struct sss_cert_content *cert_content,
+ char **expanded)
+{
+ int ret;
+ char *tmp_str = NULL;
+
+ if (parsed_template->conversion == NULL
+ || strcmp(parsed_template->conversion, "bin") == 0) {
+ ret = bin_to_ldap_filter_value(ctx, cert_content->cert_der,
+ cert_content->cert_der_size, &tmp_str);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("bin conversion failed.");
+ CM_DEBUG(ctx, "bin conversion failed.");
+ goto done;
+ }
+ } else if (strcmp(parsed_template->conversion, "base64") == 0) {
+ tmp_str = sss_base64_encode(ctx, cert_content->cert_der,
+ cert_content->cert_der_size);
+ if (tmp_str == NULL) {
+ ctx->err_msg = ERRMSG("base64 conversion failed.");
+ CM_DEBUG(ctx, "base64 conversion failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ } else {
+ ctx->err_msg = ERRMSG("Unsupported conversion.");
+ CM_DEBUG(ctx, "Unsupported conversion.");
+ ret = EINVAL;
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *expanded = tmp_str;
+ } else {
+ talloc_free(tmp_str);
+ }
+
+ return ret;
+}
+
+static int get_dn_str(struct sss_certmap_ctx *ctx, const char *conversion,
+ const char **rdn_list, char **result)
+{
+ char *str = NULL;
+ size_t c;
+ int ret;
+
+ str = talloc_strdup(ctx, "");
+ if (str == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ if (conversion == NULL || strcmp(conversion, "ldap") == 0) {
+ for (c = 0; rdn_list[c] != NULL; c++);
+ while (c != 0) {
+ c--;
+ str = talloc_asprintf_append(str, "%s%s",
+ (rdn_list[c + 1] == NULL) ? "" : ",",
+ rdn_list[c]);
+ if (str == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ };
+ } else if (strcmp(conversion, "x500") == 0) {
+ for (c = 0; rdn_list[c] != NULL; c++) {
+ str = talloc_asprintf_append(str, "%s%s", (c == 0) ? "" : ",",
+ rdn_list[c]);
+ if (str == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ } else {
+ ret = EINVAL;
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *result = str;
+ } else {
+ talloc_free(str);
+ }
+
+ return ret;
+}
+
+static int expand_template(struct sss_certmap_ctx *ctx,
+ struct parsed_template *parsed_template,
+ struct sss_cert_content *cert_content,
+ char **expanded)
+{
+ int ret;
+ char *exp;
+
+ if (strcmp("issuer_dn", parsed_template->name) == 0) {
+ //exp = talloc_strdup(ctx, cert_content->issuer_str);
+ ret = get_dn_str(ctx, parsed_template->conversion,
+ cert_content->issuer_rdn_list, &exp);
+ } else if (strcmp("subject_dn", parsed_template->name) == 0) {
+ //exp = talloc_strdup(ctx, cert_content->subject_str);
+ ret = get_dn_str(ctx, parsed_template->conversion,
+ cert_content->subject_rdn_list, &exp);
+ } else if (strcmp("cert", parsed_template->name) == 0) {
+ ret = expand_cert(ctx, parsed_template, cert_content, &exp);
+ } else {
+ ctx->err_msg = ERRMSG("Unsupported template name.");
+ CM_DEBUG(ctx, "Unsupported template name.");
+ ret = EINVAL;
+ goto done;
+ }
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to expand template.");
+ CM_DEBUG(ctx, "Failed to expand [%s] template.", parsed_template->name);
+ goto done;
+ }
+
+ if (exp == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *expanded = exp;
+ } else {
+ talloc_free(exp);
+ }
+
+ return ret;
+}
+
+static int get_filter(struct sss_certmap_ctx *ctx,
+ struct ldap_mapping_rule *parsed_mapping_rule,
+ struct sss_cert_content *cert_content,
+ char **filter)
+{
+ struct ldap_mapping_rule_comp *comp;
+ char *result = NULL;
+ char *expanded = NULL;
+ int ret;
+
+ result = talloc_strdup(ctx, "");
+ if (result == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ return ENOMEM;
+ }
+
+ for (comp = parsed_mapping_rule->list; comp != NULL; comp = comp->next) {
+ if (comp->type == comp_string) {
+ result = talloc_strdup_append(result, comp->val);
+ } else if (comp->type == comp_template) {
+ ret = expand_template(ctx, comp->parsed_template, cert_content,
+ &expanded);
+ if (ret != 0) {
+ CM_DEBUG(ctx, "Failed to expanded template.");
+ ctx->err_msg = ERRMSG("Failed to expand template.");
+ goto done;
+ }
+
+ result = talloc_strdup_append(result, expanded);
+ talloc_free(expanded);
+ expanded = NULL;
+ if (result == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation failed.");
+ ret = ENOMEM;
+ goto done;
+ }
+ } else {
+ ret = EINVAL;
+ CM_DEBUG(ctx, "Unsupported component type.");
+ ctx->err_msg = ERRMSG("Unsupported component type.");
+ goto done;
+ }
+ }
+
+ ret = 0;
+done:
+ talloc_free(expanded);
+ if (ret == 0) {
+ *filter = result;
+ } else {
+ talloc_free(result);
+ }
+
+ return ret;
+}
+
+static int do_match(struct krb5_match_rule *parsed_match_rule,
+ struct sss_cert_content *cert_content)
+{
+ struct component_list *comp;
+ bool match = false;
+
+ if (parsed_match_rule == NULL || cert_content == NULL) {
+ return EINVAL;
+ }
+
+ /* Issuer */
+ if (cert_content->issuer_str != NULL) {
+ for (comp = parsed_match_rule->issuer; comp != NULL; comp = comp->next) {
+ match = (regexec(&(comp->regexp), cert_content->issuer_str,
+ 0, NULL, 0) == 0);
+ if (match && parsed_match_rule->r == relation_or) {
+ /* match */
+ return 0;
+ } else if (!match && parsed_match_rule->r == relation_and) {
+ /* no match */
+ return ENOENT;
+ }
+
+ }
+ }
+
+ if (cert_content->subject_str != NULL) {
+ for (comp = parsed_match_rule->subject; comp != NULL; comp = comp->next) {
+ if (match && parsed_match_rule->r == relation_or) {
+ match = (regexec(&(comp->regexp), cert_content->issuer_str,
+ 0, NULL, 0) == 0);
+ /* match */
+ return 0;
+ } else if (!match && parsed_match_rule->r == relation_and) {
+ /* no match */
+ return ENOENT;
+ }
+
+ }
+ }
+
+ if (match) {
+ /* match */
+ return 0;
+ }
+
+ /* no match */
+ return ENOENT;
+}
+
+int sss_certmap_match_cert(struct sss_certmap_ctx *ctx,
+ uint8_t *der_cert, size_t der_size)
+{
+ int ret;
+ struct match_map_rule *r;
+ struct priority_list *p;
+ struct sss_cert_content *cert_content = NULL;
+
+ ret = sss_cert_get_content(ctx, der_cert, der_size, &cert_content);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to get certificate content.");
+ return ret;
+ }
+
+ for (p = ctx->prio_list; p != NULL; p = p->next) {
+ for (r = p->rule_list; r != NULL; r = r->next) {
+ ret = do_match(r->parsed_match_rule, cert_content);
+ if (ret == 0) {
+ /* match */
+ goto done;
+ }
+ }
+ }
+
+ ret = ENOENT;
+done:
+ talloc_free(cert_content);
+
+ return ret;
+}
+
+int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx,
+ uint8_t *der_cert, size_t der_size,
+ char **_filter, char ***_domains)
+{
+ int ret;
+ struct match_map_rule *r;
+ struct priority_list *p;
+ struct sss_cert_content *cert_content = NULL;
+ char *filter = NULL;
+ char **domains = NULL;
+ size_t c;
+
+ if (_filter == NULL || _domains == NULL) {
+ return EINVAL;
+ }
+
+ ret = sss_cert_get_content(ctx, der_cert, der_size, &cert_content);
+ if (ret != 0) {
+ ctx->err_msg = ERRMSG("Failed to get certificate content.");
+ return ret;
+ }
+
+ for (p = ctx->prio_list; p != NULL; p = p->next) {
+ for (r = p->rule_list; r != NULL; r = r->next) {
+ ret = do_match(r->parsed_match_rule, cert_content);
+ if (ret == 0) {
+ /* match */
+ ret = get_filter(ctx, r->parsed_mapping_rule, cert_content,
+ &filter);
+ if (ret != 0) {
+ CM_DEBUG(ctx, "Failed to get filter");
+ ctx->err_msg = ERRMSG("Failed to get filter.");
+ goto done;
+ }
+
+ if (r->domains != NULL) {
+ for (c = 0; r->domains[c] != NULL; c++);
+ domains = talloc_zero_array(ctx, char *, c + 1);
+ if (domains == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation false.");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (c = 0; r->domains[c] != NULL; c++) {
+ domains[c] = talloc_strdup(domains, r->domains[c]);
+ if (domains[c] == NULL) {
+ ctx->err_msg = ERRMSG("Memory allocation false.");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+ }
+
+ ret = 0;
+ goto done;
+ }
+ }
+ }
+
+ ret = ENOENT;
+
+done:
+ talloc_free(cert_content);
+ if (ret == 0) {
+ *_filter = filter;
+ *_domains = domains;
+ } else {
+ talloc_free(filter);
+ talloc_free(domains);
+ }
+
+ return ret;
+}
diff --git a/src/lib/certmap/sss_certmap.doxy.in b/src/lib/certmap/sss_certmap.doxy.in
new file mode 100644
index 000000000..e8959e209
--- /dev/null
+++ b/src/lib/certmap/sss_certmap.doxy.in
@@ -0,0 +1,3 @@
+PROJECT_NAME = sss_certmap
+OUTPUT_DIRECTORY = certmap_doc
+INPUT = @abs_top_srcdir@/src/lib/certmap/sss_certmap.h
diff --git a/src/lib/certmap/sss_certmap.exports b/src/lib/certmap/sss_certmap.exports
new file mode 100644
index 000000000..8b5d53666
--- /dev/null
+++ b/src/lib/certmap/sss_certmap.exports
@@ -0,0 +1,13 @@
+SSS_CERTMAP_0.0 {
+ global:
+ sss_certmap_init;
+ sss_certmap_free_ctx;
+ sss_certmap_err_msg;
+ sss_certmap_add_rule;
+ sss_certmap_match_cert;
+ sss_certmap_get_search_filter;
+ sss_cert_get_content;
+ sss_certmap_free_filter_and_domains;
+ local:
+ *;
+};
diff --git a/src/lib/certmap/sss_certmap.h b/src/lib/certmap/sss_certmap.h
new file mode 100644
index 000000000..2e3f7f76e
--- /dev/null
+++ b/src/lib/certmap/sss_certmap.h
@@ -0,0 +1,69 @@
+/*
+ SSSD
+
+ Library for rule based certificate to user mapping
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2017 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/>.
+*/
+
+#ifndef _SSS_CERTMAP_H_
+#define _SSS_CERTMAP_H_
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include <talloc.h>
+
+/**
+ * Opaque type for the idmap context
+ */
+struct sss_certmap_ctx;
+
+#define SSS_CERTMAP_MIN_PRIO UINT32_MAX
+
+typedef void (sss_certmap_ext_debug)(void *private,
+ const char *file, long line,
+ const char *function,
+ const char *format, ...);
+/**
+ * @brief
+ */
+int sss_certmap_init(TALLOC_CTX *mem_ctx,
+ sss_certmap_ext_debug *debug, void *debug_priv,
+ struct sss_certmap_ctx **ctx);
+
+void sss_certmap_free_ctx(struct sss_certmap_ctx *ctx);
+
+const char *sss_certmap_err_msg(struct sss_certmap_ctx *ctx);
+
+int sss_certmap_add_rule(struct sss_certmap_ctx *ctx,
+ unsigned int priority, const char *match_rule,
+ const char *map_rule, const char **domains);
+
+int sss_certmap_match_cert(struct sss_certmap_ctx *ctx,
+ uint8_t *der_cert, size_t der_size);
+
+int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx,
+ uint8_t *der_cert, size_t der_size,
+ char **filter, char ***domains);
+
+void sss_certmap_free_filter_and_domains(char *filter, char **domains);
+#endif /* _SSS_CERTMAP_H_ */
diff --git a/src/lib/certmap/sss_certmap.pc.in b/src/lib/certmap/sss_certmap.pc.in
new file mode 100644
index 000000000..e60b476ef
--- /dev/null
+++ b/src/lib/certmap/sss_certmap.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: sss_certmap
+Description: SSS certificate mapping library
+Version: @VERSION@
+Libs: -L${libdir} -lsss_certmap
+Cflags:
+URL: http://fedorahosted.org/sssd/
diff --git a/src/lib/certmap/sss_certmap_int.h b/src/lib/certmap/sss_certmap_int.h
new file mode 100644
index 000000000..12954a326
--- /dev/null
+++ b/src/lib/certmap/sss_certmap_int.h
@@ -0,0 +1,140 @@
+/*
+ SSSD
+
+ Library for rule based certificate to user mapping
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2017 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 <sys/types.h>
+#include <regex.h>
+
+#ifndef __SSS_CERTMAP_INT_H__
+#define __SSS_CERTMAP_INT_H__
+
+#define CM_DEBUG(cm_ctx, format, ...) do { \
+ if (cm_ctx != NULL && cm_ctx->debug != NULL) { \
+ cm_ctx->debug(cm_ctx->debug_priv, __FILE__, __LINE__, __FUNCTION__, \
+ format, ##__VA_ARGS__); \
+ } \
+} while (0)
+
+#define DEFAULT_MATCH_RULE "<KU>digitalSignature<EKU>clientAuth"
+#define DEFAULT_MAP_RULE "LDAP:userCertificate;binary={cert!bin}"
+
+/* KRB5 matching rule */
+enum relation_type {
+ relation_none = 0,
+ relation_and,
+ relation_or
+};
+
+struct component_list {
+ char *val;
+ regex_t regexp;
+ uint32_t ku;
+ const char **eku_oid_list;
+ struct component_list *prev;
+ struct component_list *next;
+};
+
+struct krb5_match_rule {
+ enum relation_type r;
+ struct component_list *issuer;
+ struct component_list *subject;
+ struct component_list *ku;
+ struct component_list *eku;
+};
+
+enum comp_type {
+ comp_none = 0,
+ comp_string,
+ comp_template
+};
+
+struct parsed_template {
+ char *name;
+ char *attr_name;
+ char *conversion;
+};
+
+struct ldap_mapping_rule_comp {
+ enum comp_type type;
+ char *val;
+ struct parsed_template *parsed_template;
+ struct ldap_mapping_rule_comp *prev;
+ struct ldap_mapping_rule_comp *next;
+};
+
+struct ldap_mapping_rule {
+ struct ldap_mapping_rule_comp *list;
+};
+
+struct match_map_rule {
+ unsigned int priority;
+ char *match_rule;
+ struct krb5_match_rule *parsed_match_rule;
+ char *map_rule;
+ struct ldap_mapping_rule *parsed_mapping_rule;
+ char **domains;
+ struct match_map_rule *prev;
+ struct match_map_rule *next;
+};
+
+struct priority_list {
+ unsigned int priority;
+ struct match_map_rule *rule_list;
+ struct priority_list *prev;
+ struct priority_list *next;
+};
+
+struct sss_certmap_ctx {
+ struct priority_list *prio_list;
+ const char *err_msg;
+ sss_certmap_ext_debug *debug;
+ void *debug_priv;
+};
+
+/* key usage flags, see RFC 3280 section 4.2.1.3 */
+#define SSS_KU_DIGITAL_SIGNATURE 0x0080
+#define SSS_KU_NON_REPUDIATION 0x0040
+#define SSS_KU_KEY_ENCIPHERMENT 0x0020
+#define SSS_KU_DATA_ENCIPHERMENT 0x0010
+#define SSS_KU_KEY_AGREEMENT 0x0008
+#define SSS_KU_KEY_CERT_SIGN 0x0004
+#define SSS_KU_CRL_SIGN 0x0002
+#define SSS_KU_ENCIPHER_ONLY 0x0001
+#define SSS_KU_DECIPHER_ONLY 0x8000
+
+struct sss_cert_content {
+ const char *issuer_str;
+ const char **issuer_rdn_list;
+ const char *subject_str;
+ const char **subject_rdn_list;
+ uint32_t key_usage;
+ const char **extended_key_usage_oids;
+
+ uint8_t *cert_der;
+ size_t cert_der_size;
+};
+
+int sss_cert_get_content(TALLOC_CTX *mem_ctx,
+ const uint8_t *der_blob, size_t der_size,
+ struct sss_cert_content **content);
+#endif /* __SSS_CERTMAP_INT_H__ */
diff --git a/src/tests/cmocka/test_certmap.c b/src/tests/cmocka/test_certmap.c
new file mode 100644
index 000000000..ab89db6ff
--- /dev/null
+++ b/src/tests/cmocka/test_certmap.c
@@ -0,0 +1,853 @@
+/*
+ SSSD
+
+ certmap - Tests for SSSD's certificate mapping library
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2017 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 <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <popt.h>
+
+#include "lib/certmap/sss_certmap.h"
+#include "lib/certmap/sss_certmap_int.h"
+
+#include "util/crypto/sss_crypto.h"
+
+#include "tests/cmocka/common_mock.h"
+#include "tests/common.h"
+
+struct priv_sss_debug {
+ int level;
+};
+
+void ext_debug(void *private, const char *file, long line, const char *function,
+ const char *format, ...)
+{
+ va_list ap;
+ struct priv_sss_debug *data = private;
+ int level = SSSDBG_OP_FAILURE;
+
+ if (data != NULL) {
+ level = data->level;
+ }
+
+ if (DEBUG_IS_SET(level)) {
+ va_start(ap, format);
+ sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
+ format, ap);
+ va_end(ap);
+ }
+}
+
+static void test_sss_certmap_init(void **state)
+{
+ int ret;
+ struct sss_certmap_ctx *ctx;
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+
+ sss_certmap_free_ctx(ctx);
+}
+
+static struct sss_certmap_ctx *setup_prio(const int *l)
+{
+ int ret;
+ size_t c;
+ struct sss_certmap_ctx *ctx;
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+
+ for (c = 0; c < 10; c++) {
+ ret = sss_certmap_add_rule(ctx, l[c], NULL, NULL, NULL);
+ assert_int_equal(ret, EOK);
+ }
+
+ return ctx;
+}
+
+static void test_sss_certmap_add_rule(void **state)
+{
+ struct sss_certmap_ctx *ctx;
+ int i;
+ struct priority_list *p;
+ struct priority_list *last;
+ size_t c;
+
+ const int tests_a[][10] = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
+ {9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
+ {1, 3, 5 ,7, 9, 0, 2, 4, 6, 8},
+ {0, 2, 4, 6, 8, 1, 3, 5, 7, 9},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+ const int tests_b[][10] = {{0, 0, 0, 0, 1, 1, 1, 2, 2, 2},
+ {2, 2, 2, 1, 1, 1, 0, 0, 0, 0},
+ {0, 1, 2, 0, 1, 2, 0, 1, 2, 0},
+ {0, 2, 1, 0, 2, 1, 0, 2, 1, 0},
+ {0, 1, 2, 0, 2, 1, 0, 0, 1, 2},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+ for (c = 0; tests_a[c][0] != 0 || tests_a[c][9] != 0; c++) {
+ ctx = setup_prio(tests_a[0]);
+ assert_non_null(ctx);
+ i = 0;
+ for (p = ctx->prio_list; p != NULL; p = p->next) {
+ assert_int_equal(i, p->priority);
+ assert_non_null(p->rule_list);
+ assert_int_equal(i, p->rule_list->priority);
+ assert_null(p->rule_list->prev);
+ assert_null(p->rule_list->next);
+ i++;
+ }
+
+ i = 9;
+ for (last = ctx->prio_list; last->next != NULL; last = last->next);
+ for (p = last; p != NULL; p = p->prev) {
+ assert_int_equal(i, p->priority);
+ assert_int_equal(i, p->rule_list->priority);
+ i--;
+ }
+
+ sss_certmap_free_ctx(ctx);
+ }
+ for (c = 0; tests_b[c][0] != 0 || tests_b[c][9] != 0; c++) {
+ ctx = setup_prio(tests_b[0]);
+ assert_non_null(ctx);
+ i = 0;
+ for (p = ctx->prio_list; p != NULL; p = p->next) {
+ assert_int_equal(i, p->priority);
+ assert_non_null(p->rule_list);
+ assert_int_equal(i, p->rule_list->priority);
+ assert_null(p->rule_list->prev);
+ assert_non_null(p->rule_list->next);
+ assert_ptr_equal(p->rule_list, p->rule_list->next->prev);
+ assert_non_null(p->rule_list->next->next);
+ assert_ptr_equal(p->rule_list->next,
+ p->rule_list->next->next->prev);
+ if (i == 0) {
+ assert_non_null(p->rule_list->next->next->next);
+ assert_ptr_equal(p->rule_list->next->next,
+ p->rule_list->next->next->next->prev);
+ assert_null(p->rule_list->next->next->next->next);
+ } else {
+ assert_null(p->rule_list->next->next->next);
+ }
+ i++;
+ }
+ sss_certmap_free_ctx(ctx);
+ }
+}
+
+static void test_sss_certmap_add_matching_rule(void **state)
+{
+ struct sss_certmap_ctx *ctx;
+ int ret;
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "fsdf", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "FDSF:fsdf", NULL, NULL);
+ assert_int_equal(ret, ESRCH);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<rgerge>", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:<rgerge>", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<ISSUER>", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<SUBJECT>", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<KU>", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<KU>ddqwdq", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<KU>digitalSignature,dddq", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>dwqwqw", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>.", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>.1.2.3", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>1.2.3.", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>1.a.3", NULL, NULL);
+ assert_int_equal(ret, EINVAL);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "<ISSUER>a", NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
+ relation_and);
+ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
+ assert_string_equal("a",
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
+ talloc_free(ctx);
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+ assert_null(ctx->prio_list);
+ ret = sss_certmap_add_rule(ctx, 1, "&&<ISSUER>a", NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
+ relation_and);
+ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
+ assert_string_equal("a",
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
+ talloc_free(ctx);
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+ assert_null(ctx->prio_list);
+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:||<ISSUER>a", NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
+ relation_or);
+ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
+ assert_string_equal("a",
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
+ talloc_free(ctx);
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+ assert_null(ctx->prio_list);
+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:<ISSUER>a<SUBJECT>b", NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
+ relation_and);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
+ assert_string_equal("b",
+ ctx->prio_list->rule_list->parsed_match_rule->subject->val);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
+ assert_string_equal("a",
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
+ talloc_free(ctx);
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+ assert_null(ctx->prio_list);
+ ret = sss_certmap_add_rule(ctx, 1000,
+ "KRB5:<ISSUER>a<SUBJECT>b<ISSUER>c<SUBJECT>d",
+ NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
+ relation_and);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
+ assert_string_equal("d",
+ ctx->prio_list->rule_list->parsed_match_rule->subject->val);
+ assert_string_equal("b",
+ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
+ assert_string_equal("c",
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
+ assert_string_equal("a",
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val);
+
+ ret = sss_certmap_add_rule(ctx, 99,
+ "KRB5:<ISSUER>a<SUBJECT>b"
+ "<KU>dataEncipherment,cRLSign<ISSUER>c"
+ "<SUBJECT>d",
+ NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
+ relation_and);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
+ assert_string_equal("d",
+ ctx->prio_list->rule_list->parsed_match_rule->subject->val);
+ assert_string_equal("b",
+ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
+ assert_string_equal("c",
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
+ assert_string_equal("a",
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->ku);
+ assert_int_equal(SSS_KU_CRL_SIGN|SSS_KU_DATA_ENCIPHERMENT,
+ ctx->prio_list->rule_list->parsed_match_rule->ku->ku);
+
+ ret = sss_certmap_add_rule(ctx, 98,
+ "KRB5:<ISSUER>a<SUBJECT>b"
+ "<KU>dataEncipherment,cRLSign<ISSUER>c"
+ "<EKU>clientAuth,emailProtection"
+ "<SUBJECT>d",
+ NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
+ relation_and);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
+ assert_string_equal("d",
+ ctx->prio_list->rule_list->parsed_match_rule->subject->val);
+ assert_string_equal("b",
+ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
+ assert_string_equal("c",
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
+ assert_string_equal("a",
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->ku);
+ assert_int_equal(SSS_KU_CRL_SIGN|SSS_KU_DATA_ENCIPHERMENT,
+ ctx->prio_list->rule_list->parsed_match_rule->ku->ku);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->eku);
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.2",
+ discard_const(
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list),
+ true));
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.4",
+ discard_const(
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list),
+ true));
+ assert_null(
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list[2]);
+
+ ret = sss_certmap_add_rule(ctx, 97,
+ "KRB5:<EKU>clientAuth,1.2.3,emailProtection",
+ NULL, NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
+ relation_and);
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->eku);
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.2",
+ discard_const(
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list),
+ true));
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.4",
+ discard_const(
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list),
+ true));
+ assert_true(string_in_list("1.2.3",
+ discard_const(
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list),
+ true));
+ assert_null(
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list[3]);
+
+ talloc_free(ctx);
+}
+
+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};
+
+void test_sss_cert_get_content(void **state)
+{
+ int ret;
+ struct sss_cert_content *content;
+
+ ret = sss_cert_get_content(NULL, test_cert_der, sizeof(test_cert_der),
+ &content);
+ assert_int_equal(ret , 0);
+ assert_non_null(content);
+ assert_non_null(content->issuer_str);
+ assert_string_equal(content->issuer_str, "CN=Certificate Authority,O=IPA.DEVEL");
+ assert_non_null(content->subject_str);
+ assert_string_equal(content->subject_str, "CN=ipa-devel.ipa.devel,O=IPA.DEVEL");
+ assert_int_equal(content->key_usage, SSS_KU_DIGITAL_SIGNATURE
+ |SSS_KU_NON_REPUDIATION
+ |SSS_KU_KEY_ENCIPHERMENT
+ |SSS_KU_DATA_ENCIPHERMENT);
+ assert_non_null(content->extended_key_usage_oids);
+ assert_non_null(content->extended_key_usage_oids[0]);
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.1",
+ discard_const(content->extended_key_usage_oids), true));
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.2",
+ discard_const(content->extended_key_usage_oids), true));
+ assert_null(content->extended_key_usage_oids[2]);
+ assert_int_equal(content->cert_der_size, sizeof(test_cert_der));
+ assert_memory_equal(content->cert_der, test_cert_der, sizeof(test_cert_der));
+
+ assert_non_null(content->issuer_rdn_list);
+ assert_string_equal(content->issuer_rdn_list[0], "O=IPA.DEVEL");
+ assert_string_equal(content->issuer_rdn_list[1], "CN=Certificate Authority");
+ assert_null(content->issuer_rdn_list[2]);
+
+ assert_non_null(content->subject_rdn_list);
+ assert_string_equal(content->subject_rdn_list[0], "O=IPA.DEVEL");
+ assert_string_equal(content->subject_rdn_list[1], "CN=ipa-devel.ipa.devel");
+ assert_null(content->subject_rdn_list[2]);
+
+
+ talloc_free(content);
+}
+
+static void test_sss_certmap_match_cert(void **state)
+{
+ struct sss_certmap_ctx *ctx;
+ int ret;
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:<ISSUER>xyz<SUBJECT>xyz",
+ NULL, NULL);
+ assert_int_equal(ret, EOK);
+
+ ret = sss_certmap_match_cert(ctx, discard_const(test_cert_der),
+ sizeof(test_cert_der));
+ assert_int_equal(ret, ENOENT);
+
+ ret = sss_certmap_add_rule(ctx, 1,
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
+ NULL, NULL);
+ assert_int_equal(ret, EOK);
+
+ ret = sss_certmap_match_cert(ctx, discard_const(test_cert_der),
+ sizeof(test_cert_der));
+ assert_int_equal(ret, 0);
+
+ sss_certmap_free_ctx(ctx);
+}
+
+static void test_sss_certmap_add_mapping_rule(void **state)
+{
+ struct sss_certmap_ctx *ctx;
+ int ret;
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 1, NULL, "FWEAWEF:fwefwe", NULL);
+ assert_int_equal(ret, ESRCH);
+
+ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:abc", NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule);
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list);
+ assert_int_equal(comp_string,
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type);
+ assert_string_equal("abc",
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val);
+ talloc_free(ctx);
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+ assert_null(ctx->prio_list);
+ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:abc{issuer_dn}", NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule);
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list);
+ assert_int_equal(comp_string,
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type);
+ assert_string_equal("abc",
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val);
+ assert_int_equal(comp_template,
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type);
+ assert_string_equal("issuer_dn",
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val);
+ talloc_free(ctx);
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+ assert_null(ctx->prio_list);
+ ret = sss_certmap_add_rule(ctx, 1, NULL, "{issuer_dn}a:b{{c}}", NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule);
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list);
+ assert_int_equal(comp_template,
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type);
+ assert_string_equal("issuer_dn",
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val);
+ assert_int_equal(comp_string,
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type);
+ assert_string_equal("a:b{c}",
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val);
+ talloc_free(ctx);
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+ assert_null(ctx->prio_list);
+ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:{issuer_dn}{subject_dn}",
+ NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(ctx->prio_list);
+ assert_non_null(ctx->prio_list->rule_list);
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule);
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list);
+ assert_int_equal(comp_template,
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type);
+ assert_string_equal("issuer_dn",
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val);
+ assert_int_equal(comp_template,
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type);
+ assert_string_equal("subject_dn",
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val);
+ talloc_free(ctx);
+}
+
+#define TEST_CERT_BIN \
+ "\\30\\82\\04\\09\\30\\82\\02\\f1\\a0\\03\\02\\01\\02\\02\\01\\09" \
+ "\\30\\0d\\06\\09\\2a\\86\\48\\86\\f7\\0d\\01\\01\\0b\\05\\00\\30" \
+ "\\34\\31\\12\\30\\10\\06\\03\\55\\04\\0a\\0c\\09\\49\\50\\41\\2e" \
+ "\\44\\45\\56\\45\\4c\\31\\1e\\30\\1c\\06\\03\\55\\04\\03\\0c\\15" \
+ "\\43\\65\\72\\74\\69\\66\\69\\63\\61\\74\\65\\20\\41\\75\\74\\68" \
+ "\\6f\\72\\69\\74\\79\\30\\1e\\17\\0d\\31\\35\\30\\34\\32\\38\\31" \
+ "\\30\\32\\31\\31\\31\\5a\\17\\0d\\31\\37\\30\\34\\32\\38\\31\\30" \
+ "\\32\\31\\31\\31\\5a\\30\\32\\31\\12\\30\\10\\06\\03\\55\\04\\0a" \
+ "\\0c\\09\\49\\50\\41\\2e\\44\\45\\56\\45\\4c\\31\\1c\\30\\1a\\06" \
+ "\\03\\55\\04\\03\\0c\\13\\69\\70\\61\\2d\\64\\65\\76\\65\\6c\\2e" \
+ "\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\30\\82\\01\\22\\30\\0d\\06" \
+ "\\09\\2a\\86\\48\\86\\f7\\0d\\01\\01\\01\\05\\00\\03\\82\\01\\0f" \
+ "\\00\\30\\82\\01\\0a\\02\\82\\01\\01\\00\\b2\\32\\92\\ab\\47\\b8" \
+ "\\0c\\13\\54\\4a\\1f\\1e\\29\\06\\ff\\d0\\50\\cb\\f7\\5f\\79\\91" \
+ "\\65\\b1\\39\\01\\83\\6a\\ad\\9e\\77\\3b\\f3\\0d\\d7\\b9\\f6\\dc" \
+ "\\9e\\4a\\49\\a7\\d0\\66\\72\\cc\\bf\\77\\d6\\de\\a9\\fe\\67\\96" \
+ "\\cc\\49\\f1\\37\\23\\2e\\c4\\50\\f4\\eb\\ba\\62\\d4\\23\\4d\\f3" \
+ "\\37\\38\\82\\ee\\3b\\3f\\2c\\d0\\80\\9b\\17\\aa\\9b\\eb\\a6\\dd" \
+ "\\f6\\15\\ff\\06\\b2\\ce\\ff\\df\\8a\\9e\\95\\85\\49\\1f\\84\\fd" \
+ "\\81\\26\\ce\\06\\32\\0d\\36\\ca\\7c\\15\\81\\68\\6b\\8f\\3e\\b3" \
+ "\\a2\\fc\\ae\\af\\c2\\44\\58\\15\\95\\40\\fc\\56\\19\\91\\80\\ed" \
+ "\\42\\11\\66\\04\\ef\\3c\\e0\\76\\33\\4b\\83\\fa\\7e\\b4\\47\\dc" \
+ "\\fb\\ed\\46\\a5\\8d\\0a\\66\\87\\a5\\ef\\7b\\74\\62\\ac\\be\\73" \
+ "\\36\\c9\\b4\\fe\\20\\c4\\81\\f3\\fe\\78\\19\\a8\\d0\\af\\7f\\81" \
+ "\\72\\24\\61\\d9\\76\\93\\e3\\0b\\d2\\4f\\19\\17\\33\\57\\d4\\82" \
+ "\\b0\\f1\\a8\\03\\f6\\01\\99\\a9\\b8\\8c\\83\\c9\\ba\\19\\87\\ea" \
+ "\\d6\\3b\\06\\eb\\4c\\f7\\f1\\e5\\28\\a9\\10\\b6\\46\\de\\e1\\e1" \
+ "\\3f\\c1\\cc\\72\\be\\2a\\43\\c6\\f6\\d0\\b5\\a0\\c4\\24\\6e\\4f" \
+ "\\bd\\ec\\22\\8a\\07\\11\\3d\\f9\\d3\\15\\02\\03\\01\\00\\01\\a3" \
+ "\\82\\01\\26\\30\\82\\01\\22\\30\\1f\\06\\03\\55\\1d\\23\\04\\18" \
+ "\\30\\16\\80\\14\\f2\\9d\\42\\4e\\0f\\c4\\48\\25\\58\\2f\\1c\\ce" \
+ "\\0f\\a1\\3f\\22\\c8\\55\\c8\\91\\30\\3b\\06\\08\\2b\\06\\01\\05" \
+ "\\05\\07\\01\\01\\04\\2f\\30\\2d\\30\\2b\\06\\08\\2b\\06\\01\\05" \
+ "\\05\\07\\30\\01\\86\\1f\\68\\74\\74\\70\\3a\\2f\\2f\\69\\70\\61" \
+ "\\2d\\63\\61\\2e\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\2f\\63\\61" \
+ "\\2f\\6f\\63\\73\\70\\30\\0e\\06\\03\\55\\1d\\0f\\01\\01\\ff\\04" \
+ "\\04\\03\\02\\04\\f0\\30\\1d\\06\\03\\55\\1d\\25\\04\\16\\30\\14" \
+ "\\06\\08\\2b\\06\\01\\05\\05\\07\\03\\01\\06\\08\\2b\\06\\01\\05" \
+ "\\05\\07\\03\\02\\30\\74\\06\\03\\55\\1d\\1f\\04\\6d\\30\\6b\\30" \
+ "\\69\\a0\\31\\a0\\2f\\86\\2d\\68\\74\\74\\70\\3a\\2f\\2f\\69\\70" \
+ "\\61\\2d\\63\\61\\2e\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\2f\\69" \
+ "\\70\\61\\2f\\63\\72\\6c\\2f\\4d\\61\\73\\74\\65\\72\\43\\52\\4c" \
+ "\\2e\\62\\69\\6e\\a2\\34\\a4\\32\\30\\30\\31\\0e\\30\\0c\\06\\03" \
+ "\\55\\04\\0a\\0c\\05\\69\\70\\61\\63\\61\\31\\1e\\30\\1c\\06\\03" \
+ "\\55\\04\\03\\0c\\15\\43\\65\\72\\74\\69\\66\\69\\63\\61\\74\\65" \
+ "\\20\\41\\75\\74\\68\\6f\\72\\69\\74\\79\\30\\1d\\06\\03\\55\\1d" \
+ "\\0e\\04\\16\\04\\14\\2d\\2b\\3f\\cb\\f5\\b2\\ff\\32\\2c\\a8\\c2" \
+ "\\1c\\dd\\bd\\8c\\80\\1e\\dd\\31\\82\\30\\0d\\06\\09\\2a\\86\\48" \
+ "\\86\\f7\\0d\\01\\01\\0b\\05\\00\\03\\82\\01\\01\\00\\9a\\47\\2e" \
+ "\\50\\a7\\4d\\1d\\53\\0f\\c9\\71\\42\\0c\\e5\\da\\7d\\49\\64\\e7" \
+ "\\ab\\c8\\df\\df\\02\\c1\\87\\d1\\5b\\de\\da\\6f\\2b\\e4\\f0\\be" \
+ "\\ba\\09\\df\\02\\85\\0b\\8a\\e6\\9b\\06\\7d\\69\\38\\6c\\72\\ff" \
+ "\\4c\\7b\\2a\\0d\\3f\\23\\2f\\16\\46\\ff\\05\\93\\b0\\ea\\24\\28" \
+ "\\d7\\12\\a1\\57\\b8\\59\\19\\25\\f3\\43\\0a\\d3\\fd\\0f\\37\\8d" \
+ "\\b8\\ca\\15\\e7\\48\\8a\\a0\\c7\\c7\\4b\\7f\\01\\3c\\58\\d7\\37" \
+ "\\e5\\ff\\7d\\2b\\01\\ac\\0d\\9f\\51\\6a\\e5\\40\\24\\e6\\5e\\55" \
+ "\\0d\\f7\\b8\\2f\\42\\ac\\6d\\e5\\29\\6b\\c6\\0b\\a4\\bf\\19\\bd" \
+ "\\39\\27\\ee\\fe\\c5\\b3\\db\\62\\d4\\be\\d2\\47\\ba\\96\\30\\5a" \
+ "\\fd\\62\\00\\b8\\27\\5d\\2f\\3a\\94\\0b\\95\\35\\85\\40\\2c\\bc" \
+ "\\67\\df\\8a\\f9\\f1\\7b\\19\\96\\3e\\42\\48\\13\\23\\04\\95\\a9" \
+ "\\6b\\11\\33\\81\\47\\5a\\83\\72\\f6\\20\\fa\\8e\\41\\7b\\8f\\77" \
+ "\\47\\7c\\c7\\5d\\46\\f4\\4f\\fd\\81\\0a\\ae\\39\\27\\b6\\6a\\26" \
+ "\\63\\b1\\d3\\bf\\55\\83\\82\\9b\\36\\6c\\33\\64\\0f\\50\\c0\\55" \
+ "\\94\\13\\c3\\85\\f4\\d5\\71\\65\\d0\\c0\\dd\\fc\\e6\\ec\\9c\\5b" \
+ "\\f0\\11\\b5\\2c\\f3\\48\\c1\\36\\8c\\a2\\96\\48\\84"
+static void test_sss_certmap_get_search_filter(void **state)
+{
+ int ret;
+ struct sss_certmap_ctx *ctx;
+ char *filter;
+ char **domains;
+ const char *dom_list[] = {"test.dom", NULL};
+
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
+ assert_int_equal(ret, EOK);
+ assert_non_null(ctx);
+ assert_null(ctx->prio_list);
+
+ ret = sss_certmap_add_rule(ctx, 100,
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
+ "LDAP:<I>{issuer_dn}<S>{subject_dn}", NULL);
+ assert_int_equal(ret, 0);
+
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
+ sizeof(test_cert_der),
+ &filter, &domains);
+ assert_int_equal(ret, 0);
+ assert_non_null(filter);
+ assert_string_equal(filter, "<I>CN=Certificate Authority,O=IPA.DEVEL"
+ "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL");
+ assert_null(domains);
+
+ ret = sss_certmap_add_rule(ctx, 99,
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
+ "LDAP:<I>{issuer_dn}<S>{subject_dn}", dom_list);
+ assert_int_equal(ret, 0);
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
+ sizeof(test_cert_der),
+ &filter, &domains);
+ assert_int_equal(ret, 0);
+ assert_non_null(filter);
+ assert_string_equal(filter, "<I>CN=Certificate Authority,O=IPA.DEVEL"
+ "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL");
+ assert_non_null(domains);
+ assert_string_equal(domains[0], "test.dom");
+ assert_null(domains[1]);
+
+ ret = sss_certmap_add_rule(ctx, 98,
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
+ "LDAP:userCertificate;binary={cert!bin}", dom_list);
+ assert_int_equal(ret, 0);
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
+ sizeof(test_cert_der),
+ &filter, &domains);
+ assert_int_equal(ret, 0);
+ assert_non_null(filter);
+ assert_string_equal(filter, "userCertificate;binary=" TEST_CERT_BIN);
+ assert_non_null(domains);
+ assert_string_equal(domains[0], "test.dom");
+ assert_null(domains[1]);
+
+ ret = sss_certmap_add_rule(ctx, 97,
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
+ "LDAP:<I>{issuer_dn!x500}<S>{subject_dn}",
+ dom_list);
+ assert_int_equal(ret, 0);
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
+ sizeof(test_cert_der),
+ &filter, &domains);
+ assert_int_equal(ret, 0);
+ assert_non_null(filter);
+ assert_string_equal(filter, "<I>O=IPA.DEVEL,CN=Certificate Authority"
+ "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL");
+ assert_non_null(domains);
+ assert_string_equal(domains[0], "test.dom");
+ assert_null(domains[1]);
+
+ ret = sss_certmap_add_rule(ctx, 96,
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
+ "LDAP:<I>{issuer_dn!x500}<S>{subject_dn!x500}",
+ dom_list);
+ assert_int_equal(ret, 0);
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
+ sizeof(test_cert_der),
+ &filter, &domains);
+ assert_int_equal(ret, 0);
+ assert_non_null(filter);
+ assert_string_equal(filter, "<I>O=IPA.DEVEL,CN=Certificate Authority"
+ "<S>O=IPA.DEVEL,CN=ipa-devel.ipa.devel");
+ assert_non_null(domains);
+ assert_string_equal(domains[0], "test.dom");
+ assert_null(domains[1]);
+
+ ret = sss_certmap_add_rule(ctx, 95,
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
+ NULL, NULL);
+ assert_int_equal(ret, 0);
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
+ sizeof(test_cert_der),
+ &filter, &domains);
+ assert_int_equal(ret, 0);
+ assert_non_null(filter);
+ assert_string_equal(filter, "userCertificate;binary=" TEST_CERT_BIN);
+ assert_null(domains);
+
+ sss_certmap_free_ctx(ctx);
+}
+
+int main(int argc, const char *argv[])
+{
+ int rv;
+ poptContext pc;
+ int opt;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ SSSD_DEBUG_OPTS
+ POPT_TABLEEND
+ };
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_sss_certmap_init),
+ cmocka_unit_test(test_sss_certmap_add_rule),
+ cmocka_unit_test(test_sss_certmap_add_matching_rule),
+ cmocka_unit_test(test_sss_cert_get_content),
+ cmocka_unit_test(test_sss_certmap_match_cert),
+ cmocka_unit_test(test_sss_certmap_add_mapping_rule),
+ cmocka_unit_test(test_sss_certmap_get_search_filter),
+ };
+
+ /* 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);
+
+ tests_set_cwd();
+ rv = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rv;
+}
diff --git a/src/tests/dlopen-tests.c b/src/tests/dlopen-tests.c
index d11ae9651..89b4dae22 100644
--- a/src/tests/dlopen-tests.c
+++ b/src/tests/dlopen-tests.c
@@ -45,6 +45,7 @@ struct so {
{ "libsss_idmap.so", { LIBPFX"libsss_idmap.so", NULL } },
{ "libsss_nss_idmap.so", { LIBPFX"libsss_nss_idmap.so", NULL } },
{ "libnss_sss.so", { LIBPFX"libnss_sss.so", NULL } },
+ { "libsss_certmap.so", { LIBPFX"libsss_certmap.so", NULL } },
{ "pam_sss.so", { LIBPFX"pam_sss.so", NULL } },
#ifdef BUILD_LIBWBCLIENT
{ "libwbclient.so", { LIBPFX"libwbclient.so", NULL } },