#49579 Support certmap features and slapi_v4 api
Closed 4 years ago by spichugi. Opened 6 years ago by firstyear.
firstyear/389-ds-base 49218-certmap-plugin-latest  into  master

file modified
+30 -31
@@ -153,7 +153,8 @@ 

  # WARNING: This needs a clean up, because slap.h is a horrible mess and is publically exposed!

  DSPLUGIN_CPPFLAGS = $(DS_DEFINES) $(DS_INCLUDES) $(PATH_DEFINES) $(SYSTEMD_DEFINES) @openldap_inc@ $(NSS_CFLAGS) $(NSPR_INCLUDES) $(SYSTEMD_CFLAGS)

  # This should give access to internal headers only for tests!!!

- DSINTERNAL_CPPFLAGS = -I$(srcdir)/include/ldaputil

+ # DSINTERNAL_CPPFLAGS = -I$(srcdir)/include/ldaputil

+ DSINTERNAL_CPPFLAGS =

  # Flags for Datastructure Library

  SDS_CPPFLAGS = $(SDS_INCLUDES) $(NSPR_INCLUDES)

  
@@ -367,7 +368,7 @@ 

  # based on defines

  # ----------------------------------------------------------------------------------------

  

- server_LTLIBRARIES = libsds.la libslapd.la libldaputil.la libns-dshttpd.la librewriters.la

+ server_LTLIBRARIES = libsds.la libslapd.la libns-dshttpd.la librewriters.la

  

  lib_LTLIBRARIES = libsvrcore.la

  
@@ -402,6 +403,7 @@ 

  

  serverplugin_LTLIBRARIES = libacl-plugin.la \

  	libaddn-plugin.la \

+ 	libcertmap-plugin.la \

  	libattr-unique-plugin.la \

  	libautomember-plugin.la libback-ldbm.la libchainingdb-plugin.la \

  	libcollation-plugin.la libcos-plugin.la libderef-plugin.la \
@@ -438,14 +440,6 @@ 

  	include/base/systems.h \

  	include/base/systhr.h \

  	include/base/util.h \

- 	include/ldaputil/cert.h \

- 	include/ldaputil/certmap.h \

- 	include/ldaputil/dbconf.h \

- 	include/ldaputil/encode.h \

- 	include/ldaputil/errors.h \

- 	include/ldaputil/init.h \

- 	include/ldaputil/ldapauth.h \

- 	include/ldaputil/ldaputil.h \

  	include/libaccess/aclerror.h \

  	include/libaccess/acleval.h \

  	include/libaccess/aclglobal.h \
@@ -554,7 +548,10 @@ 

  	ldap/servers/slapd/slapi_pal.h \

  	ldap/servers/slapd/slapi-plugin-compat4.h \

  	ldap/servers/slapd/slapi-plugin.h \

+ 	ldap/servers/slapd/slapi-plugin-v4.h \

  	ldap/servers/slapd/slapi-private.h \

+ 	ldap/servers/slapd/slapi-private-v4.h \

+ 	ldap/servers/slapd/slapi-internal-v4.h \

  	ldap/servers/slapd/snmp_collator.h \

  	ldap/servers/slapd/sslerrstrs.h \

  	ldap/servers/slapd/statechange.h \
@@ -588,7 +585,6 @@ 

  	ldap/systools/pio.h \

  	lib/base/lexer_pvt.h \

  	lib/base/plist_pvt.h \

- 	lib/ldaputil/ldaputili.h \

  	lib/libaccess/access_plhash.h \

  	lib/libaccess/aclcache.h \

  	lib/libaccess/aclpriv.h \
@@ -960,6 +956,7 @@ 

  serverinc_HEADERS = ldap/servers/plugins/replication/repl-session-plugin.h \

  	ldap/servers/slapd/slapi_pal.h \

  	ldap/servers/slapd/slapi-plugin.h \

+ 	ldap/servers/slapd/slapi-plugin-v4.h \

  	ldap/servers/plugins/replication/winsync-plugin.h \

  	src/libsds/include/sds.h

  
@@ -1142,22 +1139,6 @@ 

  libavl_a_SOURCES = ldap/libraries/libavl/avl.c

  libavl_a_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS)

  

- #------------------------

- # libldaputil

- #------------------------

- libldaputil_la_SOURCES = lib/ldaputil/cert.c \

- 	lib/ldaputil/certmap.c \

- 	lib/ldaputil/dbconf.c \

- 	lib/ldaputil/encode.c \

- 	lib/ldaputil/errors.c \

- 	lib/ldaputil/init.c \

- 	lib/ldaputil/ldapauth.c \

- 	lib/ldaputil/vtable.c

- 

- libldaputil_la_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) $(DSINTERNAL_CPPFLAGS) -I$(srcdir)/lib/ldaputil

- libldaputil_la_LIBADD = libslapd.la $(NSS_LINK) $(NSPR_LINK)

- libldaputil_la_LDFLAGS = $(AM_LDFLAGS)

- 

  #////////////////////////////////////////////////////////////////

  #

  #   Dynamic Server Libraries
@@ -1447,8 +1428,8 @@ 

  	lib/libsi18n/reshash.c \

  	lib/libsi18n/txtfile.c

  

- libns_dshttpd_la_CPPFLAGS = -I$(srcdir)/include/base $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) -I$(srcdir)/lib/ldaputil

- libns_dshttpd_la_LIBADD = libslapd.la libldaputil.la $(LDAPSDK_LINK) $(SASL_LINK) $(NSS_LINK) $(NSPR_LINK)

+ libns_dshttpd_la_CPPFLAGS = -I$(srcdir)/include/base $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS)

+ libns_dshttpd_la_LIBADD = libslapd.la $(LDAPSDK_LINK) $(SASL_LINK) $(NSS_LINK) $(NSPR_LINK)

  # Mark that this is a per version library.

  libns_dshttpd_la_LDFLAGS = -release @PACKAGE_VERSION@

  
@@ -1467,6 +1448,8 @@ 

  	ldap/servers/slapd/backend_manager.c \

  	ldap/servers/slapd/bitset.c \

  	ldap/servers/slapd/bulk_import.c \

+ 	ldap/servers/slapd/bvarray_v4.c \

+ 	ldap/servers/slapd/cert_v4.c \

  	ldap/servers/slapd/charray.c \

  	ldap/servers/slapd/ch_malloc.c \

  	ldap/servers/slapd/computed.c \
@@ -1510,7 +1493,9 @@ 

  	ldap/servers/slapd/opshared.c \

  	ldap/servers/slapd/pagedresults.c \

  	ldap/servers/slapd/pblock.c \

+ 	ldap/servers/slapd/pblock_v4.c \

  	ldap/servers/slapd/plugin.c \

+ 	ldap/servers/slapd/plugin_v4.c \

  	ldap/servers/slapd/plugin_acl.c \

  	ldap/servers/slapd/plugin_mmr.c \

  	ldap/servers/slapd/plugin_internal_op.c \
@@ -1533,6 +1518,8 @@ 

  	ldap/servers/slapd/security_wrappers.c \

  	ldap/servers/slapd/slapd_plhash.c \

  	ldap/servers/slapd/slapi_counter.c \

+ 	ldap/servers/slapd/slapi-plugin-v4.c \

+ 	ldap/servers/slapd/slapi-private-v4.c \

  	ldap/servers/slapd/slapi2nspr.c \

  	ldap/servers/slapd/snmp_collator.c \

  	ldap/servers/slapd/sort.c \
@@ -1547,6 +1534,7 @@ 

  	ldap/servers/slapd/utf8.c \

  	ldap/servers/slapd/utf8compare.c \

  	ldap/servers/slapd/util.c \

+ 	ldap/servers/slapd/upgrade.c \

  	ldap/servers/slapd/uuid.c \

  	ldap/servers/slapd/value.c \

  	ldap/servers/slapd/valueset.c \
@@ -1701,6 +1689,16 @@ 

  libaddn_plugin_la_LDFLAGS = -avoid-version

  

  #------------------------

+ # libcertmap-plugin

+ #------------------------

+ libcertmap_plugin_la_SOURCES = ldap/servers/plugins/certmap/certmap.c

+ 

+ libcertmap_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS)

+ libcertmap_plugin_la_LIBADD = libslapd.la $(NSPR_LINK) $(PCRE_LINK)

+ libcertmap_plugin_la_DEPENDENCIES = libslapd.la

+ libcertmap_plugin_la_LDFLAGS = -avoid-version

+ 

+ #------------------------

  # librootdn-access-plugin

  #------------------------

  #
@@ -2286,13 +2284,14 @@ 

  	$(GETSOCKETPEER)

  

  ns_slapd_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) $(SASL_CFLAGS) $(SVRCORE_INCLUDES)

- ns_slapd_LDADD = libslapd.la libldaputil.la libsvrcore.la $(LDAPSDK_LINK) $(NSS_LINK) $(LIBADD_DL) \

+ ns_slapd_LDADD = libslapd.la libsvrcore.la $(LDAPSDK_LINK) $(NSS_LINK) $(LIBADD_DL) \

  	$(NSPR_LINK) $(SASL_LINK) $(LIBNSL) $(LIBSOCKET) $(THREADLIB) $(SYSTEMD_LIBS) $(EVENT_LINK)

  if RUST_ENABLE

  ns_slapd_LDADD += $(RNSSLAPD_LIB)

  ns_slapd_CPPFLAGS += -lssl -lcrypto

  endif

- ns_slapd_DEPENDENCIES = libslapd.la libldaputil.la

+ ns_slapd_DEPENDENCIES = libslapd.la

+ 

  # We need to link ns-slapd with the C++ compiler on HP-UX since we load

  # some C++ shared libraries (such as icu).

  if HPUX

@@ -339,3 +339,4 @@ 

  objectClasses: ( 2.16.840.1.113730.3.2.328 NAME 'nsSchemaPolicy' DESC 'Netscape defined objectclass' SUP top  MAY ( cn $ schemaUpdateObjectclassAccept $ schemaUpdateObjectclassReject $ schemaUpdateAttributeAccept $ schemaUpdateAttributeReject) X-ORIGIN 'Netscape Directory Server' )

  objectClasses: ( 2.16.840.1.113730.3.2.332 NAME 'nsChangelogConfig' DESC 'Configuration of the changelog5 object' SUP top MUST ( cn $ nsslapd-changelogdir ) MAY ( nsslapd-changelogmaxage $ nsslapd-changelogtrim-interval $ nsslapd-changelogmaxentries $ nsslapd-changelogsuffix $ nsslapd-changelogcompactdb-interval $ nsslapd-encryptionalgorithm $ nsSymmetricKey ) X-ORIGIN '389 Directory Server' )

  objectClasses: ( 2.16.840.1.113730.3.2.337 NAME 'rewriterEntry' DESC '' SUP top MUST ( nsslapd-libPath ) MAY ( cn $ nsslapd-filterrewriter $ nsslapd-returnedAttrRewriter ) X-ORIGIN '389 Directory Server' )

+ objectClasses: ( 2.16.840.1.113730.3.2.330 NAME 'nsDylibPlugin4' DESC 'A version 4 slapi plugin that is loaded from a platform dylib' SUP top MUST ( cn $ nsslapd-pluginpath $ nsslapd-plugininitfunc $ nsslapd-pluginenabled ) X-ORIGIN '389 Directory Server Project' )

@@ -0,0 +1,639 @@ 

+ /* BEGIN COPYRIGHT BLOCK

+  * Copyright (C) 2017 Red Hat, Inc.

+  * All rights reserved.

+  *

+  * License: GPL (version 3 or any later version).

+  * See LICENSE for details.

+  * END COPYRIGHT BLOCK */

+ 

+ #define SLAPI_PLUGIN_V4_PRERELEASE_ACKNOWLEDGE

+ #define SLAPI_PRIVATE_V4_ACKNOWLEDGE

+ 

+ #include <slapi-private-v4.h>

+ 

+ /* Fopen and snprintf */

+ #include <stdio.h>

+ /* To access errors with files */

+ #include <errno.h>

+ /* To convert errno to string errors */

+ #include <string.h>

+ /* To use regex in our config parser */

+ #include <pcre.h>

+ 

+ #define CERT_ATTR_TYPE "userCertificate;binary"

+ #define CERT_FILTER_SIZE 64

+ 

+ typedef struct _certmap_config {

+     /* There are the fields "certmap <issuername> <issuerdn>" */

+     char *issuerdn;

+     char *issuername;

+     /* Issuer name is used to associate the remaining fields */

+     char *basedn;

+     char **dncomps;

+     uint_fast16_t dncomps_set;

+     char **filtercomps;

+     uint_fast16_t verifycert;

+     char *compare_attr;

+ } certmap_config;

+ 

+ typedef struct _certmap_config_list {

+     size_t count;

+     certmap_config **configs;

+ } certmap_config_list;

+ 

+ static certmap_config *

+ certmap_get_config_by_name(certmap_config_list *cm_config_list, char *name) {

+     certmap_config *config = NULL;

+     /* this just does a dumb search */

+     for(size_t i = 0; i < cm_config_list->count; i++) {

+         if (strcmp(name, cm_config_list->configs[i]->issuername) == 0) {

+             config = cm_config_list->configs[i];

+         }

+     }

+     return config;

+ }

+ 

+ static certmap_config *

+ certmap_get_config_by_issuer(certmap_config_list *cm_config_list, char *issuer) {

+     certmap_config *config = NULL;

+     /* this just does a dumb search */

+     for(size_t i = 0; i < cm_config_list->count; i++) {

+         if (strcmp(issuer, cm_config_list->configs[i]->issuerdn) == 0) {

+             config = cm_config_list->configs[i];

+         }

+     }

+     return config;

+ }

+ 

+ static void

+ certmap_add_config(certmap_config_list *cm_config_list, char *name, char *issuer) {

+     cm_config_list->count += 1;

+     cm_config_list->configs = (certmap_config **)spal_realloc(cm_config_list->configs, cm_config_list->count * sizeof(certmap_config *));

+ 

+     certmap_config *config = (certmap_config *)spal_calloc(sizeof(certmap_config));

+ 

+     config->issuername = name;

+     /* YOU NEED TO NORMALISE THIS */

+     config->issuerdn = issuer;

+     /* This does strdup for us */

+     config->basedn = config_get_certmap_basedn();

+     /* This gives us a basedn we can search under if none provided */

+     if (config->basedn == NULL) {

+         config->basedn = strdup("");

+     }

+ 

+     cm_config_list->configs[cm_config_list->count - 1] = config;

+ 

+     return;

+ }

+ 

+ static char **

+ certmap_str2charray_stripped(unsigned char *value, char *token) {

+     if (value == NULL) {

+         return NULL;

+     }

+ 

+     size_t number_tokens = 2;

+     for(unsigned char *s = value; *s != '\0'; s++) {

+         if (strchr(token, *s) != NULL) {

+             number_tokens++;

+         }

+     }

+ 

+     char **result = spal_calloc(sizeof(char *) * number_tokens);

+     char *iter = NULL;

+     unsigned char *s = (unsigned char *)ldap_utf8strtok_r((char *)value, token, &iter);

+     for (size_t i = 0; s != NULL; i++) {

+         /* Strip duplicates the string. */

+         unsigned char *stripped = ldap_utf8strip(s);

+         slapi_log_error(SLAPI_LOG_DEBUG, "certmap_str2charray_stripped", "parsed %s\n", stripped);

+         if (stripped != NULL) {

+             result[i] = (char *)stripped;

+         }

+         s = (unsigned char *)ldap_utf8strtok_r(NULL, token, &iter);

+     }

+ 

+     return result;

+ }

+ 

+ static void

+ certmap_add_option_by_name(certmap_config_list *cm_config_list, char *name, char *option, char *values) {

+     slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_add_option_by_name", "certmap.conf section name %s option %s values %s\n", name, option, values);

+     /* Get the config we are modifying */

+     certmap_config *config = certmap_get_config_by_name(cm_config_list, name);

+     if (config == NULL) {

+         /* Skip the invalid option */

+         slapi_log_error(SLAPI_LOG_WARNING, "certmap_add_option_by_name", "certmap.conf section name %s does not exist\n", name);

+         return;

+     }

+ 

+     char *option_lower = (char *)slapi_utf8StrToLower((unsigned char *)option);

+ 

+     /* Which option is it? */

+     if (strcmp(option_lower, "basedn") == 0) {

+         spal_free(config->basedn);

+         if (values == NULL) {

+             config->basedn = config_get_certmap_basedn();

+         } else {

+             /* Values is already alloc by caller */

+             config->basedn = values;

+         }

+     } else if (strcmp(option_lower, "dncomps") == 0) {

+         slapi_v4_charray_free(config->dncomps);

+         /* Distinguish the commented / uncommented case */

+         config->dncomps_set = 1;

+         if (values == NULL) {

+             config->dncomps = NULL;

+         } else {

+             /* Needs to trim whitespaces. */

+             config->dncomps = certmap_str2charray_stripped((unsigned char *)values, ",");

+         }

+     } else if (strcmp(option_lower, "filtercomps") == 0) {

+         /* Parse these to arrays? */

+         slapi_v4_charray_free(config->filtercomps);

+         if (values == NULL) {

+             config->filtercomps = NULL;

+         } else {

+             /* Needs to trim whitespaces. */

+             config->filtercomps = certmap_str2charray_stripped((unsigned char *)values, ",");

+         }

+     } else if (strcmp(option_lower, "verifycert") == 0) {

+         if (values == NULL) {

+             config->verifycert = 0;

+         } else {

+             if (strcmp(values, "on") == 0) {

+                 config->verifycert = 1;

+             } else {

+                 config->verifycert = 0;

+             }

+             spal_free(values);

+         }

+     } else if (strcmp(option_lower, "cmapldapattr") == 0) {

+         /* It's valid for this to reset to NULL */

+         spal_free(config->compare_attr);

+         config->compare_attr = values;

+     } else {

+         slapi_log_error(SLAPI_LOG_WARNING, "certmap_add_option_by_name", "certmap.conf option %s not recognised\n", option);

+     }

+ 

+     spal_free(option_lower);

+ 

+     return;

+ }

+ 

+ static void

+ certmap_config_free(certmap_config *config) {

+     slapi_v4_charray_free(config->dncomps);

+     slapi_v4_charray_free(config->filtercomps);

+     spal_free(config->issuername);

+     spal_free(config->issuerdn);

+     spal_free(config->basedn);

+     spal_free(config);

+ }

+ 

+ slapi_v4_plugin_result *

+ certmap_start_fn(void **ctx) {

+     /* Get the config dir */

+     char *configdir = config_get_configdir();

+     char *configname = "/certmap.conf";

+ 

+     size_t config_path_size = strlen(configdir) + strlen(configname) + 1;

+     char *config_path = (char *)spal_calloc(config_path_size);

+     snprintf(config_path, config_path_size, "%s%s", configdir, configname);

+ 

+     spal_free(configdir);

+ 

+     /* Open the certmap file */

+     /* Handle all those nasty errors that can happen .... */

+     FILE *f = fopen(config_path, "r");

+     if (f == NULL) {

+         int cerrno = errno;

+         char serror[40] = {0};

+         strerror_r(cerrno, serror, 39);

+         char *msg = (char *)spal_calloc(64 * sizeof(char));

+         /* Failed to open */

+         snprintf(msg, 63, "certmap_start_fn - Failed to open file %s - %s", serror, config_path);

+         spal_free(config_path);

+         return slapi_v4_plugin_result_err(SLAPI_V4_PLUGIN_FAILURE, LDAP_OPERATIONS_ERROR, msg);

+     }

+ 

+     /* Create the config list. We may need to realloc as we go ... */

+     certmap_config_list *cm_config_list = (certmap_config_list *)spal_calloc(sizeof(certmap_config_list));

+ 

+     /* Prepare our regex */

+     char *reerr;

+     int reerroffset = 0;

+ 

+     char *cmap_regex = "^certmap\\s+(?P<name>\\S*?)\\s+(?P<issuer>.*)$";

+     pcre *cmap_regex_re = pcre_compile(cmap_regex, 0, (const char **)&reerr, &reerroffset, NULL);

+     if (cmap_regex_re == NULL) {

+         char *msg = spal_calloc(128 * sizeof(char));

+         snprintf(msg, 127, "certmap_start_fn - Failed to compile %s - %s", reerr, cmap_regex);

+         spal_free(config_path);

+         return slapi_v4_plugin_result_err(SLAPI_V4_PLUGIN_FAILURE, LDAP_OPERATIONS_ERROR, msg);

+     }

+ 

+     char *cmap_attr_regex = "^(?P<name>[^\\s#]*?):(?P<attr>[^\\s#]*?)$";

+     pcre *cmap_attr_regex_re = pcre_compile(cmap_attr_regex, 0, (const char **)&reerr, &reerroffset, NULL);

+     if (cmap_attr_regex_re == NULL) {

+         char *msg = spal_calloc(128 * sizeof(char));

+         snprintf(msg, 127, "certmap_start_fn - Failed to compile %s - %s", reerr, cmap_attr_regex);

+         pcre_free(cmap_regex_re);

+         spal_free(config_path);

+         return slapi_v4_plugin_result_err(SLAPI_V4_PLUGIN_FAILURE, LDAP_OPERATIONS_ERROR, msg);

+     }

+ 

+     char *cmap_option_regex = "^(?P<name>[^\\s#]*?):(?P<attr>[^\\s#]*?)\\s+(?P<values>.*)$";

+     pcre *cmap_option_regex_re = pcre_compile(cmap_option_regex, 0, (const char **)&reerr, &reerroffset, NULL);

+     if (cmap_option_regex_re == NULL) {

+         char *msg = spal_calloc(128 * sizeof(char));

+         snprintf(msg, 127, "certmap_start_fn - Failed to compile %s - %s", reerr, cmap_option_regex);

+         pcre_free(cmap_regex_re);

+         pcre_free(cmap_attr_regex_re);

+         spal_free(config_path);

+         return slapi_v4_plugin_result_err(SLAPI_V4_PLUGIN_FAILURE, LDAP_OPERATIONS_ERROR, msg);

+     }

+ 

+     /* For each line, match it to a config ... */

+     char buffer[256] = {0};

+     while (fgets(buffer, 255, f) != NULL) {

+         /* Setup the call to pcre */

+         /* Trim the \n */

+         size_t line_size = strlen(buffer);

+         if (buffer[line_size - 1] == '\n') {

+             buffer[line_size - 1] = '\0';

+             line_size -= 1;

+         }

+         slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_start_fn", "parsing: %s\n", buffer);

+         /*

+          * Pcre is odd: it only uses the first 2/3rd of this as a multiple of 3

+          * for storing capture groups. So we have 3 groups, thus 6 indexes, so we

+          * need 9 in ovector. But the first 2 are the size of the match, so we need

+          # 12.

+          */

+         int ovector[12] = {0};

+         int rc = pcre_exec(cmap_regex_re, NULL, buffer, line_size, 0, 0, ovector, 12);

+         /* Is the line a new definition? */

+         if (rc >= 0) {

+             char *name = strndup(buffer + ovector[2], ovector[3] - ovector[2]);

+             char *issuer = strndup(buffer + ovector[4], ovector[5] - ovector[4]);

+             certmap_add_config(cm_config_list, name, issuer);

+         }

+ 

+         /* Is the line adding to a definition */

+         rc = pcre_exec(cmap_attr_regex_re, NULL, buffer, line_size, 0, 0, ovector, 12);

+         if (rc >= 0) {

+             char *name = strndup(buffer + ovector[2], ovector[3] - ovector[2]);

+             char *attr = strndup(buffer + ovector[4], ovector[5] - ovector[4]);

+             certmap_add_option_by_name(cm_config_list, name, attr, NULL);

+         }

+ 

+         rc = pcre_exec(cmap_option_regex_re, NULL, buffer, line_size, 0, 0, ovector, 12);

+         if (rc >= 0) {

+             char *name = strndup(buffer + ovector[2], ovector[3] - ovector[2]);

+             char *attr = strndup(buffer + ovector[4], ovector[5] - ovector[4]);

+             char *values = strndup(buffer + ovector[6], ovector[7] - ovector[6]);

+             certmap_add_option_by_name(cm_config_list, name, attr, values);

+         }

+ 

+         /* If it's none of these, we skip it .... */

+     }

+ 

+     /* Close the file */

+     fclose(f);

+ 

+     pcre_free(cmap_regex_re);

+     pcre_free(cmap_attr_regex_re);

+     pcre_free(cmap_option_regex_re);

+ 

+     /* Finally, hand this to our private data holder. */

+     *ctx = (void *)cm_config_list;

+ 

+     spal_free(config_path);

+     return slapi_v4_plugin_result_ok();

+ }

+ 

+ slapi_v4_plugin_result *

+ certmap_close_fn(void **ctx) {

+     /* Destroy the certmap configuration */

+     certmap_config_list *cm_config_list = (certmap_config_list *)*ctx;

+ 

+     if (cm_config_list != NULL) {

+         for (size_t i = 0; i < cm_config_list->count; i++) {

+             certmap_config_free(cm_config_list->configs[i]);

+         }

+ 

+         spal_free(cm_config_list->configs);

+         spal_free(cm_config_list);

+     }

+ 

+     return slapi_v4_plugin_result_ok();

+ }

+ 

+ static void

+ certmap_verifycert_fn(struct berval *bv, void *acc, void *arg) {

+     int64_t *status = (int64_t *)acc;

+     struct berval *bp_cert = (struct berval *)arg;

+ 

+     if (*status != 0) {

+         return;

+     }

+ 

+     /* Are the sizes the same? */

+     if (bv->bv_len != bp_cert->bv_len) {

+         return;

+     }

+ 

+     /* What about the actual data? */

+     if (memcmp(bv->bv_val, bp_cert->bv_val, bp_cert->bv_len) == 0) {

+         /*If all good, set status to 1! */

+         *status = 1;

+     }

+ 

+ }

+ 

+ static slapi_v4_dn *

+ certmap_search_int(certmap_config *config, slapi_v4_cert *cert, char *basedn, char *filter, int scope) {

+     /*

+      * Search for the entry.

+      */

+     slapi_v4_dn *base_sdn = slapi_v4_sdn_new_from_char_dn(basedn);

+     slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_search_int", "Searching basedn: %s\n", basedn);

+ 

+     int32_t attrsonly = 0;

+     /* WE ONLY NEED userCertificate;binary */

+     char **attrs = slapi_v4_charray_append(NULL, strdup(CERT_ATTR_TYPE));

+ 

+     /* execute search */

+     /* If basedn == "", but scope == SUBTREE, we need a diff search handler. */

+     slapi_v4_search_pblock *pb_search_result = NULL;

+     if (strcmp(basedn, "") == 0 && scope == LDAP_SCOPE_SUBTREE) {

+         pb_search_result = slapi_v4_search_internal_all_contexts(scope, filter, attrs, attrsonly, NULL, NULL, 0);

+     } else {

+         pb_search_result = slapi_v4_search_internal(base_sdn, scope, filter, attrs, attrsonly, NULL, NULL, 0);

+     }

+ 

+     /* Search is over, don't need the basedn anymore. */

+     slapi_v4_charray_free(attrs);

+     slapi_v4_sdn_free(base_sdn);

+ 

+     /* get the number of entries */

+     uint64_t num_results = slapi_v4_search_pblock_get_num_results(pb_search_result);

+ 

+     if (num_results == 0) {

+         slapi_log_error(SLAPI_LOG_WARNING, "certmap_search_int", "No entries matched filter: %s basedn: %s\n", filter, basedn);

+         slapi_v4_search_pblock_destroy(pb_search_result);

+         return NULL;

+     } else if (num_results >= 2) {

+         slapi_log_error(SLAPI_LOG_WARNING, "certmap_search_int", "Multiple entries matched filter: %s basedn: %s\n", filter, basedn);

+         slapi_v4_search_pblock_destroy(pb_search_result);

+         return NULL;

+     }

+ 

+     slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_search_int", "Query filter: %s basedn: %s number of entries: %"PRIu64"\n", filter, basedn, num_results);

+ 

+     Slapi_Entry **op_entries = slapi_v4_search_pblock_get_entries(pb_search_result);

+     Slapi_Entry *bind_entry = op_entries[0];

+ 

+     /*

+      * Now verify the cert if requested.

+      * This involves checking the certificate attribute contains the DER of our certificate.

+      * only matters if verifyCert == on

+      */

+ 

+     if (config->verifycert == 1) {

+ 

+         struct berval **barray = slapi_v4_entry_attr_get_bervals(bind_entry, CERT_ATTR_TYPE);

+         /*

+          * Now we have to memcmp the certs. We can do this by turning the cert

+          * into a berval.

+          */

+         struct berval *bp_cert = slapi_v4_cert_get_der_berval(cert);

+         int64_t status = 0;

+ 

+         slapi_v4_bvarray_fold(barray, certmap_verifycert_fn, (void *)&status, (void *)bp_cert);

+ 

+         slapi_v4_bv_free(bp_cert);

+         slapi_v4_bvarray_destroy(barray);

+ 

+         if (status == 0) {

+             slapi_log_error(SLAPI_LOG_WARNING, "certmap_search_int", "Certificate verification failed, no matching %s attribute\n", CERT_ATTR_TYPE);

+             slapi_v4_search_pblock_destroy(pb_search_result);

+             return NULL;

+         }

+         slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_search_int", "Certificate verification was successful\n");

+     }

+ 

+     slapi_v4_dn *entry_dn = slapi_v4_sdn_dup(slapi_v4_entry_get_sdn(bind_entry));

+ 

+     slapi_v4_search_pblock_destroy(pb_search_result);

+     return entry_dn;

+ }

+ 

+ slapi_v4_plugin_result *

+ certmap_certmap_fn(void *ctx, slapi_v4_certmap_pblock *pbc) {

+     /*

+      * At this point pbc contains a populated struct of cert info. We need to extract

+      * this and determine an sdn (or entry?) that we should bind to.

+      */

+     slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "Calling bind_certmap plugin.\n");

+     certmap_config_list *cm_config_list = (certmap_config_list *)ctx;

+     /*

+      * Find the relevant certmap config in the list.

+      */

+     slapi_v4_cert *cert = slapi_v4_certmap_pblock_get_clientcert(pbc);

+ 

+     char *subject_dn = slapi_v4_cert_get_subjectdn(cert);

+     slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "Attempting to bind subjectdn: %s\n", subject_dn);

+     char *issuer_dn = slapi_v4_cert_get_issuerdn(cert);

+     slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "Attempting to bind issuerdn: %s\n", issuer_dn);

+ 

+     /* Check if subject and issuer are valid. */

+ 

+     certmap_config *config = certmap_get_config_by_issuer(cm_config_list, issuer_dn);

+     if (config == NULL) {

+         /* No config found, use default! */

+         config = certmap_get_config_by_name(cm_config_list, "default");

+         if (config == NULL) {

+             slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "No default config nor issuer config could be found.\n");

+             /* Free some stuff and bail here */

+             spal_free(subject_dn);

+             spal_free(issuer_dn);

+             return slapi_v4_plugin_result_err(SLAPI_V4_PLUGIN_FAILURE, LDAP_OPERATIONS_ERROR, strdup("Certificate can not be mapped to an identity."));

+         } else {

+             slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "No issuer config could be found, falling back to default..\n");

+         }

+     } else {

+         slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "Found configuration for %s\n", issuer_dn);

+     }

+ 

+     slapi_v4_dn *mapped_dn = NULL;

+ 

+     if (config->dncomps_set == 0) {

+         if (config->compare_attr == NULL) {

+             /*

+              * If dncomps == NONE, cmapattr == None, bind to subject DN

+              */

+             slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "dncomps == NULL, cmap == NULL,\n");

+             slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "Binding to to subjectdn: %s\n", subject_dn);

+ 

+             /* Do a base search for this object */

+             mapped_dn = certmap_search_int(config, cert, subject_dn, "(objectClass=*)", LDAP_SCOPE_BASE);

+ 

+         } else {

+             /*

+              * If dncomps == NONE, cmapattr == Some(dn), search under basedn for cmapattr = subject_dn

+              */

+             slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "dncomps == NULL, cmap == %s,\n", config->compare_attr);

+ 

+             /* Filter escape the subject_dn */

+             char *subject_dn_escaped = slapi_v4_escape_filter_value(subject_dn, strlen(subject_dn));

+ 

+             /* Turn the cmap attr into a filter. */

+             size_t filterlen = strlen(config->compare_attr) + strlen(subject_dn_escaped) + 4;

+             char *filter = spal_calloc(filterlen);

+             snprintf(filter, filterlen, "(%s=%s)", config->compare_attr, subject_dn_escaped);

+             spal_free(subject_dn_escaped);

+ 

+             /* What abotu NULL basedn? */

+             mapped_dn = certmap_search_int(config, cert, config->basedn, filter, LDAP_SCOPE_SUBTREE);

+             spal_free(filter);

+         }

+     } else {

+         slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "dncomps != NULL\n");

+         if (config->dncomps == NULL) {

+             /*

+              * if dncomps == "", use filter comps to search for an entry below basedn.

+              */

+ 

+             /* We have a filtercomps (I hope) */

+             if (config->filtercomps == NULL) {

+                 slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "dncomps != NULL and filtercomps == NULL, can not map certificate!\n");

+                 /* Error! */

+             } else {

+ 

+                 size_t filter_max_len = CERT_FILTER_SIZE;

+                 size_t filter_len = 2;

+                 char *filter = spal_calloc(sizeof(char) * filter_max_len);

+ 

+                 /* Open the filter */

+                 sprintf(filter, "(&");

+ 

+                 /* Take a pointer into the filter at some point range: */

+ 

+                 for (size_t j = 0; config->filtercomps[j] != NULL; j++) {

+                     char *filtercomp = config->filtercomps[j];

+                     /* For each value, extract the ava from the cert */

+                     /* Construct these to a filter. */

+                     char **avas = slapi_v4_cert_get_subject_ava_val(cert, filtercomp);

+                     if (avas == NULL) {

+                         slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "Failed to parse certificate filtercomp %s\n", filtercomp);

+                         spal_free(subject_dn);

+                         spal_free(issuer_dn);

+                         return slapi_v4_plugin_result_err(SLAPI_V4_PLUGIN_FAILURE, LDAP_OPERATIONS_ERROR, strdup("Certificate can not be mapped to an identity."));

+                     }

+                     for (size_t i = 0; avas[i] != NULL; i++) {

+                         char *ava = avas[i];

+                         slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "%s avas %s\n", filtercomp, ava);

+ 

+                         /* Work out how large our new filter element will be */

+                         /* Remember it is: (%s=%s) so at least 3 extra chars. */

+                         size_t ava_len = 3 + strlen(ava) + strlen(filtercomp);

+                         while ((ava_len + filter_len) >= filter_max_len) {

+                             filter_max_len = filter_max_len + CERT_FILTER_SIZE;

+                             filter = spal_realloc(filter, sizeof(char) * filter_max_len);

+                         }

+                         char *filter_ptr = filter + filter_len;

+ 

+                         sprintf(filter_ptr, "(%s=%s)", filtercomp, ava);

+                         filter_len = filter_len + ava_len;

+ 

+                     }

+ 

+                     slapi_v4_charray_free(avas);

+                 }

+ 

+                 sprintf(filter + filter_len, ")");

+                 slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "filter %s\n", filter);

+ 

+                 /* Submit the search! */

+                 mapped_dn = certmap_search_int(config, cert, config->basedn, filter, LDAP_SCOPE_SUBTREE);

+                 spal_free(filter);

+             }

+         } else {

+             /*

+              * if dncomps == "attr list", construct a DN to bind to.

+              */

+             size_t binddn_max_len = CERT_FILTER_SIZE;

+             size_t binddn_len = 0;

+             char *binddn = spal_calloc(sizeof(char) * binddn_max_len);

+ 

+             for (size_t i = 0; config->dncomps[i] != NULL; i++) {

+                 char *dncomp = config->dncomps[i];

+ 

+                 char **avas = slapi_v4_cert_get_subject_ava_val(cert, dncomp);

+                 if (avas == NULL) {

+                     slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "Failed to parse certificate dncomp %s\n", dncomp);

+                     spal_free(subject_dn);

+                     spal_free(issuer_dn);

+                     return slapi_v4_plugin_result_err(SLAPI_V4_PLUGIN_FAILURE, LDAP_OPERATIONS_ERROR, strdup("Certificate can not be mapped to an identity."));

+                 }

+                 for (size_t j = 0; avas[j] != NULL; j++) {

+                     char *ava = avas[j];

+                     slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "%s avas %s\n", dncomp, ava);

+ 

+                     /* Work out how large our new filter element will be */

+                     /* Remember it is: %s=%s, so at least 2 extra chars. */

+                     size_t ava_len = 2 + strlen(ava) + strlen(dncomp);

+                     while ((ava_len + binddn_len) >= binddn_max_len) {

+                         binddn_max_len = binddn_max_len + CERT_FILTER_SIZE;

+                         binddn = spal_realloc(binddn, sizeof(char) * binddn_max_len);

+                     }

+                     char *binddn_ptr = binddn + binddn_len;

+ 

+                     sprintf(binddn_ptr, "%s=%s,", dncomp, ava);

+                     binddn_len = binddn_len + ava_len;

+                 }

+ 

+                 slapi_v4_charray_free(avas);

+             }

+             /* Replace the final trailing , with a \0 */

+             binddn[binddn_len - 1] = '\0';

+ 

+             slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "binddn %s\n", binddn);

+ 

+             /* Submit the search! */

+             mapped_dn = certmap_search_int(config, cert, binddn, "(objectClass=*)", LDAP_SCOPE_BASE);

+             spal_free(binddn);

+         }

+     }

+ 

+     spal_free(subject_dn);

+     spal_free(issuer_dn);

+ 

+     if (mapped_dn == NULL) {

+         slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "bind_certmap plugin failed to map client certficate.\n");

+         return slapi_v4_plugin_result_err(SLAPI_V4_PLUGIN_FAILURE, LDAP_INVALID_CREDENTIALS, strdup("Failed to map client certificate to LDAP entry."));

+     }

+ 

+     /* If it exists, attach the SDN to the pbc */

+     slapi_v4_certmap_pblock_set_clientdn(pbc, mapped_dn);

+ 

+     slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_certmap_fn", "bind_certmap plugin complete.\n");

+     return slapi_v4_plugin_result_ok();

+ }

+ 

+ slapi_v4_plugin_result *

+ certmap_init_fn(slapi_v4_plugin_registration *p_register) {

+     slapi_log_error(SLAPI_LOG_PLUGIN, "certmap_init_fn", "Initialising certmap plugin.\n");

+ 

+     /* register name will dup this for us. */

+     slapi_v4_plugin_register_name(p_register, "certmap plugin");

+     slapi_v4_plugin_register_precedence(p_register, SV4_PLUGIN_PRECEDENCE_DEFAULT);

+     slapi_v4_plugin_register_start_fn(p_register, certmap_start_fn);

+     slapi_v4_plugin_register_close_fn(p_register, certmap_close_fn);

+     slapi_v4_plugin_register_bind_certmap_fn(p_register, certmap_certmap_fn);

+ 

+     return slapi_v4_plugin_result_ok();

+ }

+ 

@@ -20,6 +20,11 @@ 

  #include "slap.h"

  #include <plbase64.h>

  

+ /* We pull in the internal headers for config */

+ 

+ #define SLAPI_PRIVATE_V4_ACKNOWLEDGE

+ #include <slapi-private-v4.h>

+ 

  #define AES_MECH 1

  #define DES_MECH 2

  #define AES_REVER_SCHEME_NAME "AES"

file modified
+34
@@ -38,6 +38,8 @@ 

  #include "pratom.h"

  #include "csngen.h"

  

+ #include <slapi-internal-v4.h>

+ 

  /* Forward declarations */

  static int add_internal_pb(Slapi_PBlock *pb);

  static void op_shared_add(Slapi_PBlock *pb);
@@ -331,6 +333,38 @@ 

      return add_internal_pb(pb);

  }

  

+ /*

+  * v4 add api. We discard the allow_operation check because plugins just have

+  * total access to the server memory - they can do what they please. Instead

+  * we just wrap the existing add code in a nicer api, and we forced the

+  * modifier name to come from the caller rather than the convoluted plugin_id

+  * mechanism. If a plugin wans to lie, we can't stop it, so just go with simple!

+  */

+ 

+ slapi_v4_search_pblock *

+ slapi_v4_add_internal_entry(Slapi_Entry *entry, const char *modifier_name) {

+     if (modifier_name == NULL) {

+         /* Should we create a pblock and return it with a failure code? */

+         return NULL;

+     }

+     /* Create a new pblock */

+     Slapi_PBlock *int_pbs = slapi_pblock_new();

+     /* Allocate a new operation */

+     /* There are NO cases I can find of these flags being used, so don't bother! */

+     Operation *op = internal_operation_new(SLAPI_OPERATION_ADD, 0);

+     slapi_pblock_set(int_pbs, SLAPI_OPERATION, op);

+     slapi_pblock_set(int_pbs, SLAPI_CONTROLS_ARG, NULL);

+     /* Inject the modifier into the entry */

+     slapi_entry_attr_set_charptr(entry, "internalModifiersname", modifier_name);

+     slapi_pblock_set(int_pbs, SLAPI_ADD_ENTRY, entry);

+     /* Add the entry */

+     add_internal_pb(int_pbs);

+     /* Extract and return the result */

+     slapi_v4_search_pblock *pbs = slapi_v4_search_pblock_extract(int_pbs);

+     slapi_pblock_destroy(int_pbs);

+     return pbs;

+ }

+ 

  int

  slapi_add_internal_set_pb(Slapi_PBlock *pb, const char *dn, LDAPMod **attrs, LDAPControl **controls, Slapi_ComponentId *plugin_identity, int operation_flags)

  {

file modified
+61 -406
@@ -20,334 +20,7 @@ 

  #include <sys/param.h>         /* MAXPATHLEN */

  #include "slap.h"              /* slapi_ch_malloc */

  #include "fe.h"

- 

- char *client_auth_config_file = NULL;

- 

- /* forward declarations */

- 

- static void generate_id(void);

- static Slapi_ComponentId *auth_get_component_id(void);

- 

- #define internal_ld NULL

- 

- static int LDAP_CALL LDAP_CALLBACK

- slapu_msgfree(LDAP *ld, LDAPMessage *msg)

- {

-     Slapi_PBlock *pb = (Slapi_PBlock *)msg;

-     if (ld != internal_ld) {

-         return ldap_msgfree(msg);

-     }

-     if (pb) {

-         slapi_free_search_results_internal(pb);

-         slapi_pblock_destroy(pb);

-     }

-     return LDAP_SUCCESS;

- }

- 

- static int LDAP_CALL LDAP_CALLBACK

- slapu_search_s(LDAP *ld, const char *rawbaseDN, int scope, const char *filter, char **attrs, int attrsonly, LDAPMessage **result)

- {

-     int err = LDAP_NO_SUCH_OBJECT;

-     Slapi_PBlock *pb = NULL;

-     LDAPControl **ctrls;

-     Slapi_DN *sdn = slapi_sdn_new_dn_byval(rawbaseDN);

-     const char *baseDN = slapi_sdn_get_dn(sdn);

- 

-     if (ld != internal_ld) {

-         err = ldap_search_ext_s(ld, baseDN, scope, filter, attrs, attrsonly,

-                                 NULL, NULL, NULL, -1, result);

-         slapi_sdn_free(&sdn);

-         return err;

-     }

-     slapi_log_err(SLAPI_LOG_TRACE, "slapu_search_s", "=> (\"%s\", %i, %s)\n",

-                   baseDN, scope, filter);

-     if (filter == NULL)

-         filter = "objectclass=*";

- 

-     /* use new internal search API */

-     pb = slapi_pblock_new();

-     /* we need to provide managedsait control to avoid returning continuation references */

-     ctrls = (LDAPControl **)slapi_ch_calloc(2, sizeof(LDAPControl *));

-     ctrls[0] = (LDAPControl *)slapi_ch_malloc(sizeof(LDAPControl));

-     ctrls[0]->ldctl_oid = slapi_ch_strdup(LDAP_CONTROL_MANAGEDSAIT);

-     ctrls[0]->ldctl_value.bv_val = NULL;

-     ctrls[0]->ldctl_value.bv_len = 0;

-     ctrls[0]->ldctl_iscritical = '\0';

-     slapi_search_internal_set_pb(pb, baseDN, scope, (char *)filter, attrs,

-                                  attrsonly, ctrls, NULL,

-                                  auth_get_component_id(), 0 /* actions */);

-     slapi_search_internal_pb(pb);

- 

-     if (pb != NULL) {

-         if (slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &err)) {

-             err = LDAP_LOCAL_ERROR;

-         }

-         if (err != LDAP_SUCCESS) {

-             slapu_msgfree(ld, (LDAPMessage *)pb);

-             pb = NULL;

-             if (scope == LDAP_SCOPE_SUBTREE) {

-                 char fbuf[BUFSIZ];

-                 slapi_log_err(SLAPI_LOG_ERR, "slapu_search_s", "(\"%s\", subtree, %s) err %i\n",

-                               baseDN, escape_string((char *)filter, fbuf), err);

-             }

-         }

-     } else {

-         char fbuf[BUFSIZ];

-         slapi_log_err(SLAPI_LOG_ERR, "slapu_search_s", "(\"%s\", %i, %s) NULL\n",

-                       baseDN, scope, escape_string((char *)filter, fbuf));

-     }

-     slapi_sdn_free(&sdn);

-     *result = (LDAPMessage *)pb;

-     slapi_log_err(SLAPI_LOG_TRACE, "<= slapu_search_s", "%i\n", err);

-     return err;

- }

- 

- static int LDAP_CALL LDAP_CALLBACK

- slapu_count_entries(LDAP *ld, LDAPMessage *msg)

- {

-     Slapi_Entry **entry = NULL;

-     int count = 0;

-     if (ld != internal_ld) {

-         return ldap_count_entries(ld, msg);

-     }

-     if (!slapi_pblock_get((Slapi_PBlock *)msg, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry) && entry) {

-         for (; *entry; ++entry)

-             ++count;

-     }

-     return count;

- }

- 

- /* slapu_search_s() returns a Slapi_PBlock*, but slapu_first_entry() and

-  * slapu_next_entry() return a Slapi_Entry** pointing into the same array

-  * as the PBlock.  If one of the iteration (Slapi_Entry**) pointers was

-  * passed to slapu_msgfree(), havoc would ensue.  ldaputil never does this.

-  * But ldap_msgfree() would support it (no?); so a plugin function might.

-  * Yet another way this doesn't support plugin functions.

-  */

- 

- static LDAPMessage *LDAP_CALL LDAP_CALLBACK

- slapu_first_entry(LDAP *ld, LDAPMessage *msg)

- {

-     Slapi_Entry **entry = NULL;

-     if (ld != internal_ld) {

-         return ldap_first_entry(ld, msg);

-     }

-     if (!slapi_pblock_get((Slapi_PBlock *)msg, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry) && entry && *entry) {

-         return (LDAPMessage *)entry;

-     }

-     return NULL;

- }

- 

- static LDAPMessage *LDAP_CALL LDAP_CALLBACK

- slapu_next_entry(LDAP *ld, LDAPMessage *msg)

- {

-     Slapi_Entry **entry = (Slapi_Entry **)msg;

-     if (ld != internal_ld) {

-         if (msg) {

-             return ldap_next_entry(ld, msg);

-         } else {

-             return NULL;

-         }

-     }

-     if (entry && *entry && *++entry) {

-         return (LDAPMessage *)entry;

-     }

-     return NULL;

- }

- 

- static char *LDAP_CALL LDAP_CALLBACK

- slapu_get_dn(LDAP *ld, LDAPMessage *entry)

- {

-     if (ld != internal_ld) {

-         return ldap_get_dn(ld, entry);

-     }

-     return slapi_ch_strdup(slapi_entry_get_dn(*(Slapi_Entry **)entry));

- }

- 

- static void LDAP_CALL LDAP_CALLBACK

- slapu_memfree(LDAP *ld, void *dn)

- {

-     if (ld != internal_ld) {

-         ldap_memfree(dn);

-     } else {

-         free(dn);

-     }

- }

- 

- static char *

- slapu_attr_get_desc(Slapi_Attr *attr)

- {

-     char *desc = NULL;

-     if (slapi_attr_get_type(attr, &desc) == LDAP_SUCCESS && desc) {

-         return slapi_ch_strdup(desc);

-     }

-     return NULL;

- }

- 

- /* slapu_first_attribute and slapu_next_attribute use a Slapi_Attr*

-  * as an iterator.  It is malloc'd by first() and free'd by ber_free().

-  */

- 

- static char *LDAP_CALL LDAP_CALLBACK

- slapu_first_attribute(LDAP *ld, LDAPMessage *entry, BerElement **iter)

- {

-     if (ld != internal_ld) {

-         return ldap_first_attribute(ld, entry, iter);

-     } else {

-         Slapi_Attr **attr = (Slapi_Attr **)slapi_ch_malloc(sizeof(Slapi_Attr *));

-         *iter = (BerElement *)attr;

-         if (attr && slapi_entry_first_attr(*(Slapi_Entry **)entry, attr) == LDAP_SUCCESS) {

-             return slapu_attr_get_desc(*attr);

-         }

-     }

-     return NULL;

- }

- 

- static char *LDAP_CALL LDAP_CALLBACK

- slapu_next_attribute(LDAP *ld, LDAPMessage *entry, BerElement *iter)

- {

-     Slapi_Attr **attr = (Slapi_Attr **)iter;

-     if (ld != internal_ld) {

-         return ldap_next_attribute(ld, entry, iter);

-     }

-     if (attr && slapi_entry_next_attr(*(Slapi_Entry **)entry, *attr, attr) == LDAP_SUCCESS) {

-         return slapu_attr_get_desc(*attr);

-     }

-     return NULL;

- }

- 

- static void LDAP_CALL LDAP_CALLBACK

- slapu_ber_free(LDAP *ld, BerElement *iter, int freebuf)

- {

-     if (ld != internal_ld) {

-         ber_free(iter, freebuf);

-     } else {

-         free((Slapi_Attr **)iter);

-     }

- }

- 

- static struct berval **LDAP_CALL LDAP_CALLBACK

- slapu_get_values_len(LDAP *ld, LDAPMessage *entry, const char *desc)

- {

-     Slapi_Attr *attr = NULL;

-     if (ld != internal_ld) {

-         return ldap_get_values_len(ld, entry, desc);

-     }

-     if (slapi_entry_attr_find(*(Slapi_Entry **)entry, desc, &attr) == LDAP_SUCCESS && attr) {

-         struct berval **values = NULL;

-         if (slapi_attr_get_bervals_copy(attr, &values) == 0) {

-             return (values);

-         }

-     }

-     return NULL;

- }

- 

- static void LDAP_CALL LDAP_CALLBACK

- slapu_value_free_len(LDAP *ld, struct berval **values)

- {

-     if (ld != internal_ld) {

-         ldap_value_free_len(values);

-     } else {

-         ber_bvecfree(values);

-     }

- }

- 

- void

- client_auth_init()

- {

-     int err;

-     if (client_auth_config_file == NULL) {

-         char *confdir = config_get_configdir();

-         if (NULL == confdir) {

-             slapi_log_err(SLAPI_LOG_ERR, "client_auth_init", "Failed to get configdir\n");

-             return;

-         }

-         client_auth_config_file = PR_smprintf("%s/certmap.conf", confdir);

-         if (NULL == client_auth_config_file) {

-             slapi_log_err(SLAPI_LOG_ERR, "client_auth_init", "Failed to duplicate \"%s/certmap\"\n", confdir);

-             slapi_ch_free_string(&confdir);

-             return;

-         }

-         slapi_ch_free_string(&confdir);

-     }

-     err = ldaputil_init(client_auth_config_file, "", NULL, "slapd", NULL);

-     if (err != LDAPU_SUCCESS) {

-         slapi_log_err(SLAPI_LOG_TRACE, "client_auth_init", "ldaputil_init(%s,...) %i\n", client_auth_config_file, err);

-     } else {

-         LDAPUVTable_t vtable = {

-             NULL /* ssl_init */,

-             NULL /* set_option */,

-             NULL /* simple_bind_s */,

-             NULL /* unbind */,

-             slapu_search_s,

-             slapu_count_entries,

-             slapu_first_entry,

-             slapu_next_entry,

-             slapu_msgfree,

-             slapu_get_dn,

-             slapu_memfree,

-             slapu_first_attribute,

-             slapu_next_attribute,

-             slapu_ber_free,

-             NULL /* get_values */,

-             NULL /* value_free */,

-             slapu_get_values_len,

-             slapu_value_free_len};

-         ldapu_VTable_set(&vtable);

-     }

- 

-     /* Generate a component id for cert-based authentication */

-     generate_id();

- }

- 

- #include <ssl.h>

- #include "slapi-plugin.h"  /* SLAPI_BERVAL_EQ */

- #include "slapi-private.h" /* COMPONENT_CERT_AUTH */

- 

- static Slapi_ComponentId *auth_component_id = NULL;

- 

- static void

- generate_id(void)

- {

-     if (auth_component_id == NULL) {

-         auth_component_id = generate_componentid(NULL /* Not a plugin */, COMPONENT_CERT_AUTH);

-     }

- }

- 

- static Slapi_ComponentId *

- auth_get_component_id(void)

- {

-     return auth_component_id;

- }

- 

- 

- static char *

- subject_of(CERTCertificate *cert)

- {

-     char *dn = NULL;

-     if (cert != NULL) {

-         int err = ldapu_get_cert_subject_dn(cert, &dn);

-         if (err != LDAPU_SUCCESS) {

-             slapi_log_err(SLAPI_LOG_ERR, "subject_of", "ldapu_get_cert_subject_dn(%p) %i (%s)\n",

-                           (void *)cert, err, ldapu_err2string(err));

-         }

-     }

-     return dn;

- }

- 

- static char *

- issuer_of(CERTCertificate *cert)

- {

-     char *dn = NULL;

-     if (cert != NULL) {

-         int err = ldapu_get_cert_issuer_dn(cert, &dn);

-         if (err != LDAPU_SUCCESS) {

-             slapi_log_err(SLAPI_LOG_ERR, "issuer_of", "ldapu_get_cert_issuer_dn(%p) %i (%s)\n",

-                           (void *)cert, err, ldapu_err2string(err));

-         }

-     }

-     return dn;

- }

+ #include <slapi-internal-v4.h>

  

  /*

   * Log a certificate that was rejected because the client didn't
@@ -365,19 +38,22 @@ 

      CERTCertificate *clientCert = slapd_ssl_peerCertificate(prfd);

  

      PRErrorCode errorCode = PR_GetError();

-     char *subject = subject_of(clientCert);

-     char *issuer = issuer_of(clientCert);

+     char *subject = slapi_v4_cert_get_subjectdn(clientCert);

+     char *issuer = slapi_v4_cert_get_issuerdn(clientCert);

      slapi_log_access(LDAP_DEBUG_STATS,

                       "conn=%" PRIu64 " " SLAPI_COMPONENT_NAME_NSPR " error %i (%s); unauthenticated client %s; issuer %s\n",

                       conn->c_connid, errorCode, slapd_pr_strerror(errorCode),

                       subject ? escape_string(subject, sbuf) : "NULL",

                       issuer ? escape_string(issuer, ibuf) : "NULL");

-     if (issuer)

+     if (issuer) {

          free(issuer);

-     if (subject)

+     }

+     if (subject) {

          free(subject);

-     if (clientCert)

+     }

+     if (clientCert) {

          CERT_DestroyCertificate(clientCert);

+     }

      return -1; /* non-zero means reject this certificate */

  }

  
@@ -395,7 +71,6 @@ 

      Connection *conn = (Connection *)clientData;

      CERTCertificate *clientCert = slapd_ssl_peerCertificate(prfd);

  

-     char *clientDN = NULL;

      int keySize = 0;

      char *cipher = NULL;

      char *extraErrorMsg = "";
@@ -420,7 +95,7 @@ 

      }

  

      keySize = cipherInfo.effectiveKeyBits;

-     cipher = slapi_ch_strdup(cipherInfo.symCipherName);

+     cipher = strdup(cipherInfo.symCipherName);

  

      /* If inside an Start TLS operation, perform the privacy level discovery

       * and if the security degree achieved after the handshake is not reckoned
@@ -445,86 +120,66 @@ 

                           conn->c_connid,

                           sslversion, keySize, cipher ? cipher : "NULL");

      } else {

-         subject = subject_of(clientCert);

-         if (!subject) {

-             (void)slapi_getSSLVersion_str(channelInfo.protocolVersion,

-                                           sslversion, sizeof(sslversion));

-             slapi_log_access(LDAP_DEBUG_STATS,

-                              "conn=%" PRIu64 " %s %i-bit %s; missing subject\n",

-                              conn->c_connid,

-                              sslversion, keySize, cipher ? cipher : "NULL");

+ 

+         slapi_v4_certmap_pblock *pbc = slapi_v4_certmap_pblock_init();

+         /*

+          * Populate all the parameters to pbc that are needed.

+          *

+          * This is where we actually extract all the certificate details we'll need for

+          * the certmap bind process to operate.

+          *

+          * We need: issuer

+          *        : subject dn

+          *        : raw DER?

+          *        What if we just attach the cert to the pbc, then we can call as needed?

+          */

+         slapi_v4_certmap_pblock_set_clientcert(pbc, clientCert);

+ 

+         plugin_v4_result bind_certmap_result = plugin_v4_call_bind_certmap(pbc);

+         if (bind_certmap_result != PLUGIN_V4_SUCCESS) {

+             slapi_log_err(SLAPI_LOG_ERR, "handle_handshake_done", "Failed to execute bind_certmap plugins\n");

+             slapi_v4_certmap_pblock_destroy(pbc);

              goto done;

          }

-         {

-             char *issuer = issuer_of(clientCert);

-             char sbuf[BUFSIZ], ibuf[BUFSIZ];

-             (void)slapi_getSSLVersion_str(channelInfo.protocolVersion,

-                                           sslversion, sizeof(sslversion));

-             slapi_log_access(LDAP_DEBUG_STATS,

-                              "conn=%" PRIu64 " %s %i-bit %s; client %s; issuer %s\n",

-                              conn->c_connid,

-                              sslversion, keySize,

-                              cipher ? cipher : "NULL",

-                              subject ? escape_string(subject, sbuf) : "NULL",

-                              issuer ? escape_string(issuer, ibuf) : "NULL");

-             if (issuer)

-                 free(issuer);

+ 

+         Slapi_DN *client_dn = slapi_v4_certmap_pblock_get_clientdn(pbc);

+ 

+         if (client_dn == NULL) {

+             /*

+              * Given we got a SUCCESS from the plugin, this shouldn't happen, but

+              * who knows what kind of junk people write.

+              */

+             slapi_v4_certmap_pblock_destroy(pbc);

+             slapi_log_err(SLAPI_LOG_ERR, "handle_handshake_done", "bind_certmap plugins return NULL result, this is a mistake!!!!\n");

+             goto done;

          }

-         slapi_dn_normalize(subject);

-         {

-             LDAPMessage *chain = NULL;

-             char *basedn = config_get_basedn();

-             int err;

+         /* As pointless as this seems, I want to wait to change connection->c_dn to sdn */

+         char *binddn = strdup(slapi_sdn_get_dn(client_dn));

  

-             err = ldapu_cert_to_ldap_entry(clientCert, internal_ld, basedn ? basedn : "" /*baseDN*/, &chain);

-             if (err == LDAPU_SUCCESS && chain) {

-                 LDAPMessage *entry = slapu_first_entry(internal_ld, chain);

-                 if (entry) {

-                     /* clientDN is duplicated in slapu_get_dn */

-                     clientDN = slapu_get_dn(internal_ld, entry);

-                 } else {

+         (void)slapi_getSSLVersion_str(channelInfo.protocolVersion, sslversion, sizeof(sslversion));

  

-                     extraErrorMsg = "no entry";

-                     slapi_log_err(SLAPI_LOG_TRACE, "handle_handshake_done", "<= ldapu_cert_to_ldap_entry() %s\n",

-                                   extraErrorMsg);

-                 }

-             } else {

-                 extraErrorMsg = ldapu_err2string(err);

-                 slapi_log_err(SLAPI_LOG_TRACE, "handle_handshake_done", "<= ldapu_cert_to_ldap_entry() %i (%s)%s\n",

-                               err, extraErrorMsg, chain ? "" : " NULL");

-             }

-             slapi_ch_free_string(&basedn);

-             slapu_msgfree(internal_ld, chain);

+         if (client_dn != NULL) {

+             slapi_log_access(LDAP_DEBUG_STATS,

+                              "conn=%" PRIu64 " %s client bound as %s\n",

+                              conn->c_connid,

+                              sslversion, binddn);

+         } else if (clientCert != NULL) {

+             slapi_log_access(LDAP_DEBUG_STATS,

+                              "conn=%" PRIu64 " %s failed to map client "

+                              "certificate to LDAP DN (%s)\n",

+                              conn->c_connid,

+                              sslversion, extraErrorMsg);

          }

-     }

  

-     if (clientDN != NULL) {

-         Slapi_DN *sdn = NULL;

-         sdn = slapi_sdn_new_dn_passin(clientDN);

-         clientDN = slapi_ch_strdup(slapi_sdn_get_dn(sdn));

-         slapi_sdn_free(&sdn);

-         (void)slapi_getSSLVersion_str(channelInfo.protocolVersion,

-                                       sslversion, sizeof(sslversion));

-         slapi_log_access(LDAP_DEBUG_STATS,

-                          "conn=%" PRIu64 " %s client bound as %s\n",

-                          conn->c_connid,

-                          sslversion, clientDN);

-     } else if (clientCert != NULL) {

-         (void)slapi_getSSLVersion_str(channelInfo.protocolVersion,

-                                       sslversion, sizeof(sslversion));

-         slapi_log_access(LDAP_DEBUG_STATS,

-                          "conn=%" PRIu64 " %s failed to map client "

-                          "certificate to LDAP DN (%s)\n",

-                          conn->c_connid,

-                          sslversion, extraErrorMsg);

+         /*

+          * Associate the new credentials with the connection.  Note that

+          * clientDN and clientCert may be NULL.

+          */

+         bind_credentials_set_nolock(conn, SLAPD_AUTH_SSL, binddn, SLAPD_AUTH_SSL, binddn, clientCert, NULL);

+ 

+         slapi_v4_certmap_pblock_destroy(pbc);

      }

  

-     /*

-      * Associate the new credentials with the connection.  Note that

-      * clientDN and clientCert may be NULL.

-      */

-     bind_credentials_set_nolock(conn, SLAPD_AUTH_SSL, clientDN,

-                                 SLAPD_AUTH_SSL, clientDN, clientCert, NULL);

  done:

      slapi_ch_free_string(&subject);

      slapi_ch_free_string(&cipher);

@@ -0,0 +1,60 @@ 

+ /** BEGIN COPYRIGHT BLOCK

+  * Copyright (C) 2017 Red Hat, Inc.

+  * All rights reserved.

+  *

+  * License: GPL (version 3 or any later version).

+  * See LICENSE for details.

+  * END COPYRIGHT BLOCK **/

+ 

+ #ifdef HAVE_CONFIG_H

+ #include <config.h>

+ #endif

+ 

+ #include <slapi-internal-v4.h>

+ 

+ void

+ slapi_v4_bv_free(struct berval *v) {

+     if (v != NULL) {

+         spal_free(v->bv_val);

+         spal_free(v);

+     }

+ }

+ 

+ /* Create a bvarray */

+ struct berval **

+ slapi_v4_bvarray_create() {

+     /* Allocate a default size. */

+     return (struct berval **)spal_calloc(sizeof(struct berval *));

+ }

+ 

+ /* Destroy it */

+ void

+ slapi_v4_bvarray_destroy(struct berval **array) {

+     for(size_t i = 0; array[i] != NULL; i++) {

+         slapi_ch_bvfree(&(array[i]));

+     }

+     spal_free(array);

+ }

+ 

+ /* Push back */

+ struct berval **

+ slapi_v4_bvarray_append(struct berval **array, struct berval *bv) {

+     size_t i= 0;

+     for(; array[i] != NULL; i++) {

+     }

+ 

+     array = (struct berval **)spal_realloc((char *)array, sizeof(struct berval *) * (i + 2));

+ 

+     array[i] = bv;

+     array[i + 1] = NULL;

+ 

+     return array;

+ }

+ 

+ /* fold */

+ void

+ slapi_v4_bvarray_fold(struct berval **array, void (*fn)(struct berval *bv, void *acc, void *arg), void *acc, void *arg){

+     for(size_t i = 0; array[i] != NULL; i++) {

+         fn(array[i], acc, arg);

+     }

+ }

@@ -0,0 +1,128 @@ 

+ /* BEGIN COPYRIGHT BLOCK

+  * Copyright (C) 2017 Red Hat, Inc.

+  * All rights reserved.

+  *

+  * License: GPL (version 3 or any later version).

+  * See LICENSE for details.

+  * END COPYRIGHT BLOCK */

+ 

+ /* For NSS certificate parsing */

+ #include <cert.h>

+ 

+ /*

+  * To fix a compiler warning here: cert.h pulls

+  * in prcpucfg.h which defines LINUX as empty.

+  * However, config.h defines it to 1, so we need

+  * to undefined it after cert.h to let config.h

+  * do it's job.

+  */

+ 

+ #undef LINUX

+ 

+ #include <slapi-internal-v4.h>

+ 

+ static const int SEC_OID_AVA_UNKNOWN = 0; /* unknown OID */

+ 

+ char *

+ slapi_v4_cert_get_subjectdn(slapi_v4_cert *cert) {

+     return CERT_NameToAscii(&cert->subject);

+ }

+ 

+ char *

+ slapi_v4_cert_get_issuerdn(slapi_v4_cert *cert) {

+     return CERT_NameToAscii(&cert->issuer);

+ }

+ 

+ struct berval *

+ slapi_v4_cert_get_der_berval(slapi_v4_cert *cert) {

+     /* Construct a berval and return it. */

+     struct berval *bp = (struct berval *)spal_calloc(sizeof(struct berval));

+ 

+     SECItem derCert = cert->derCert;

+ 

+     bp->bv_len = derCert.len;

+     bp->bv_val = spal_calloc(derCert.len);

+ 

+     memcpy(bp->bv_val, derCert.data, derCert.len);

+     return bp;

+ }

+ 

+ static int

+ slapi_v4_cert_name_to_secoid(const char *attr) {

+     if (!strcasecmp(attr, "c")) {

+         return SEC_OID_AVA_COUNTRY_NAME;

+     } else if (!strcasecmp(attr, "o")) {

+         return SEC_OID_AVA_ORGANIZATION_NAME;

+     } else if (!strcasecmp(attr, "cn")) {

+         return SEC_OID_AVA_COMMON_NAME;

+     } else if (!strcasecmp(attr, "l")) {

+         return SEC_OID_AVA_LOCALITY;

+     } else if (!strcasecmp(attr, "st")) {

+         return SEC_OID_AVA_STATE_OR_PROVINCE;

+     } else if (!strcasecmp(attr, "ou")) {

+         return SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME;

+     } else if (!strcasecmp(attr, "uid")) {

+         return SEC_OID_RFC1274_UID;

+     } else if (!strcasecmp(attr, "e")) {

+         return SEC_OID_PKCS9_EMAIL_ADDRESS;

+     } else if (!strcasecmp(attr, "mail")) {

+         return SEC_OID_RFC1274_MAIL;

+     } else if (!strcasecmp(attr, "dc")) {

+         return SEC_OID_AVA_DC;

+     }

+ 

+     return SEC_OID_AVA_UNKNOWN;

+ }

+ 

+ static char **

+ slapi_v4_cert_get_ava_val(CERTName *dn, const char *attr) {

+     int attr_tag = slapi_v4_cert_name_to_secoid(attr);

+     char **result = NULL;

+ 

+     if (attr_tag == SEC_OID_AVA_UNKNOWN) {

+         return NULL;

+     }

+ 

+     CERTRDN **rdns = dn->rdns;

+     if (rdns == NULL) {