From 9a852c93e326d770ab5aa8c609634eb9d95d1428 Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 16 2020 02:34:39 +0000 Subject: [PATCH 1/11] Ticket 49218 - Certmap - Header file changes Bug Description: This adds support for pluggable certificate mapping libraries. To achieve this, this replaces the existing baked in certificate mapping code. Fix Description: This adds the header files required for the new v4 api, as well as re-locating some key log function defs for shared access. Important to note is the change of the log typse to an enum from a #define, and is the way we should always provide int defines due to compilers ability to check this for us. https://pagure.io/389-ds-base/issue/49218 https://pagure.io/lib389/issue/95 https://pagure.io/lib389/issue/84 Author: wibrown Review by: ??? --- diff --git a/ldap/servers/plugins/rever/rever.h b/ldap/servers/plugins/rever/rever.h index 5c7484a..09b45f5 100644 --- a/ldap/servers/plugins/rever/rever.h +++ b/ldap/servers/plugins/rever/rever.h @@ -20,6 +20,11 @@ #include "slap.h" #include +/* We pull in the internal headers for config */ + +#define SLAPI_PRIVATE_V4_ACKNOWLEDGE +#include + #define AES_MECH 1 #define DES_MECH 2 #define AES_REVER_SCHEME_NAME "AES" diff --git a/ldap/servers/slapd/pblock_v3.h b/ldap/servers/slapd/pblock_v3.h index 7ec2f37..654f8d3 100644 --- a/ldap/servers/slapd/pblock_v3.h +++ b/ldap/servers/slapd/pblock_v3.h @@ -134,6 +134,7 @@ typedef struct _slapi_pblock_intop /* pointer to array of results returned on search */ Slapi_Entry **pb_plugin_internal_search_op_entries; + uint64_t pb_plugin_internal_search_num_entries; char **pb_plugin_internal_search_op_referrals; LDAPControl **pb_search_ctrls; /* for search operations, allows plugins to provide controls to pass for each entry or referral returned */ diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index 41308f1..35b7129 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -349,7 +349,7 @@ int config_set_maxbersize(const char *attrname, char *value, char *errorbuf, int int config_set_maxsasliosize(const char *attrname, char *value, char *errorbuf, int apply); int config_set_versionstring(const char *attrname, char *versionstring, char *errorbuf, int apply); int config_set_enquote_sup_oc(const char *attrname, char *value, char *errorbuf, int apply); -int config_set_basedn(const char *attrname, char *value, char *errorbuf, int apply); +int config_set_certmap_basedn(const char *attrname, char *value, char *errorbuf, int apply); int config_set_configdir(const char *attrname, char *value, char *errorbuf, int apply); int config_set_instancedir(const char *attrname, char *value, char *errorbuf, int apply); int config_set_schemadir(const char *attrname, char *value, char *errorbuf, int apply); @@ -509,8 +509,7 @@ int32_t config_get_maxsasliosize(void); char *config_get_versionstring(void); char *config_get_buildnum(void); int config_get_enquote_sup_oc(void); -char *config_get_basedn(void); -char *config_get_configdir(void); +char *config_get_certmap_basedn(void); char *config_get_schemadir(void); char *config_get_lockdir(void); char *config_get_tmpdir(void); @@ -621,6 +620,7 @@ int modify_config_dse(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int postop_modify_config_dse(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg); int add_root_dse(Slapi_PBlock *pb); int load_plugin_entry(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg); +int load_plugin_v4_entry(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg); /* diff --git a/ldap/servers/slapd/slapi-internal-v4.h b/ldap/servers/slapd/slapi-internal-v4.h new file mode 100644 index 0000000..df478b7 --- /dev/null +++ b/ldap/servers/slapd/slapi-internal-v4.h @@ -0,0 +1,127 @@ +/* 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 */ + +#pragma once + +#include + +#define SLAPI_PLUGIN_V4_PRERELEASE_ACKNOWLEDGE +#define SLAPI_PRIVATE_V4_ACKNOWLEDGE + +#include + +/** + * Internal implementation details of the slapi-plugin v4 call system + * + * This is how the server INTERNALLY manages plugins. Unless you are working + * inside of ns-slapd, libslapd, you will *never* need to include this file. + */ + +typedef enum _plugin_v4_result { + PLUGIN_V4_SUCCESS, + PLUGIN_V4_INVALID_CONFIG, + PLUGIN_V4_NULL_POINTER, + PLUGIN_V4_DUPLICATE, + PLUGIN_V4_RESOURCE, + PLUGIN_V4_INVALID_PLUGIN, + PLUGIN_V4_UNKNOWN, + PLUGIN_V4_INVALID_STATE, +} plugin_v4_result; + +/* + * I think we need a result -> str table. + */ + +plugin_v4_result plugin_v4_init(); +plugin_v4_result plugin_v4_shutdown(); +void plugin_v4_destroy(); + +plugin_v4_result plugin_v4_validate(struct slapi_entry *plugin_entry); + +/** + * This is called with an entry to setup a plugin + */ +plugin_v4_result plugin_v4_startall(); +plugin_v4_result plugin_v4_stopall(); + +plugin_v4_result plugin_v4_modify(struct slapi_entry *plugin_entry); +plugin_v4_result plugin_v4_add(struct slapi_entry *plugin_entry); +plugin_v4_result plugin_v4_setup(struct slapi_entry *plugin_entry); +plugin_v4_result plugin_v4_delete(struct slapi_entry *plugin_entry); + +typedef struct _slapi_v4_plugin_registration { + /* + * The name of the plugin. We will enforce this matches + * the cn. + */ + char *sv4_name; + /* + * Plugin order of operation precedence. + */ + uint64_t precedence; + /* + * This function is called *before* the plugin starts + * and guarantees no operations will start until + * this function is completed. It's guaranteed that + * close will not run until start is complete. + */ + slapi_v4_plugin_result *(*sv4_start_fn)(void **ctx); + /* + * This function is called *after* the plugin has stopped + * processing any operations. This allows you to free and + * stop and resources from your operation. It's guaranteed + * that no other plugin fn will run at the same time as this. + */ + slapi_v4_plugin_result *(*sv4_close_fn)(void **ctx); + /* + * Map certificate details to an entry for bind. + */ + slapi_v4_plugin_result *(*sv4_bind_certmap_fn)(void *ctx, slapi_v4_certmap_pblock *pbc); + +} slapi_v4_plugin_registration; + +slapi_v4_plugin_registration * slapi_v4_plugin_registration_create(); +void slapi_v4_plugin_registration_destroy(slapi_v4_plugin_registration *pr); + +/* + * Internal result handling from operations. + */ +int64_t slapi_v4_plugin_result_is_ok(slapi_v4_plugin_result *result); + +/* + * PLUGIN CALLBACK HOOKS + * + * These are the functions that we call to trigger plugin operations. + */ +plugin_v4_result plugin_v4_start_operation(); +plugin_v4_result plugin_v4_close_operation(); +plugin_v4_result plugin_v4_call_bind_certmap(); + +/* + * Internal pblock operations + */ + +slapi_v4_search_pblock * slapi_v4_search_pblock_extract(Slapi_PBlock *pb); +slapi_v4_search_pblock * slapi_v4_search_pblock_create(); +/* Merge the results of B into A */ +void slapi_v4_search_pblock_merge(slapi_v4_search_pblock *pbs_a, slapi_v4_search_pblock *pbs_b); + +/* from plugin-internal-op */ +int search_internal_pb(Slapi_PBlock *pb); + + +/* + * SERVER UPGRADE INTERNALS + */ +typedef enum _upgrade_status { + UPGRADE_SUCCESS = 0, + UPGRADE_FAILURE = 1, +} upgrade_status; + +upgrade_status upgrade_server(void); + diff --git a/ldap/servers/slapd/slapi-plugin-v4.h b/ldap/servers/slapd/slapi-plugin-v4.h new file mode 100644 index 0000000..2dd615b --- /dev/null +++ b/ldap/servers/slapd/slapi-plugin-v4.h @@ -0,0 +1,74 @@ +/* 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 */ + +#pragma once + +#ifndef SLAPI_PLUGIN_V4_PRERELEASE_ACKNOWLEDGE +#error slapi plugin v4 is *not* stabilised for release. DO NOT USE IT. +#endif + +#include + +#include +#include + +/* Provides va_list */ +#include + + +/* + * Logging + */ + +/* allowed values for the "severity" parameter */ +/* THESE MUST MATCH SLAPI-PLUGIN.h */ +typedef enum _slapi_log_level { + SLAPI_LOG_FATAL = 0, + SLAPI_LOG_TRACE = 1, + SLAPI_LOG_PACKETS = 2, + SLAPI_LOG_ARGS = 3, + SLAPI_LOG_CONNS = 4, + SLAPI_LOG_BER = 5, + SLAPI_LOG_FILTER = 6, + SLAPI_LOG_CONFIG = 7, + SLAPI_LOG_ACL = 8, + SLAPI_LOG_SHELL = 9, + SLAPI_LOG_PARSE = 10, + SLAPI_LOG_HOUSE = 11, + SLAPI_LOG_REPL = 12, + SLAPI_LOG_CACHE = 13, + SLAPI_LOG_PLUGIN = 14, + SLAPI_LOG_TIMING = 15, + SLAPI_LOG_BACKLDBM = 16, + SLAPI_LOG_ACLSUMMARY = 17, + SLAPI_LOG_NUNCSTANS = 18, + SLAPI_LOG_EMERG = 19, + SLAPI_LOG_ALERT = 20, + SLAPI_LOG_CRIT = 21, + SLAPI_LOG_ERR = 22, + SLAPI_LOG_WARNING = 23, + SLAPI_LOG_NOTICE = 24, + SLAPI_LOG_INFO = 25, + SLAPI_LOG_DEBUG = 26, +} slapi_log_level; + +/* The last level must be set in log.c: SLAPI_LOG_MAX */ + +int32_t slapi_log_error(slapi_log_level loglevel, char *subsystem, char *fmt, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 3, 4))); +#else + ; +#endif + +int32_t slapi_log_error_ext(slapi_log_level loglevel, char *subsystem, char *fmt, va_list varg1, va_list varg2); + + +int32_t slapi_is_loglevel_set(const slapi_log_level loglevel); + + diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index be6c98b..bae0d82 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -27,6 +27,9 @@ extern "C" { #endif +#define SLAPI_PLUGIN_V4_PRERELEASE_ACKNOWLEDGE +#include + /* Provides our int types and platform specific requirements. */ #include "slapi_pal.h" #include "prtypes.h" @@ -6023,51 +6026,6 @@ int slapi_register_plugin(const char *plugintype, int enabled, const char *inits int slapi_register_plugin_ext(const char *plugintype, int enabled, const char *initsymbol, slapi_plugin_init_fnptr initfunc, const char *name, char **argv, void *group_identity, int precedence); /* - * logging - */ -int slapi_log_error(int loglevel, char *subsystem, char *fmt, ...) -#ifdef __GNUC__ - __attribute__((format(printf, 3, 4))); -#else - ; -#endif - -int slapi_log_error_ext(int loglevel, char *subsystem, char *fmt, va_list varg1, va_list varg2); - -/* allowed values for the "severity" parameter */ -#define SLAPI_LOG_FATAL 0 -#define SLAPI_LOG_TRACE 1 -#define SLAPI_LOG_PACKETS 2 -#define SLAPI_LOG_ARGS 3 -#define SLAPI_LOG_CONNS 4 -#define SLAPI_LOG_BER 5 -#define SLAPI_LOG_FILTER 6 -#define SLAPI_LOG_CONFIG 7 -#define SLAPI_LOG_ACL 8 -#define SLAPI_LOG_SHELL 9 -#define SLAPI_LOG_PARSE 10 -#define SLAPI_LOG_HOUSE 11 -#define SLAPI_LOG_REPL 12 -#define SLAPI_LOG_CACHE 13 -#define SLAPI_LOG_PLUGIN 14 -#define SLAPI_LOG_TIMING 15 -#define SLAPI_LOG_BACKLDBM 16 -#define SLAPI_LOG_ACLSUMMARY 17 -#define SLAPI_LOG_NUNCSTANS 18 -/* Severity levels */ -#define SLAPI_LOG_EMERG 19 -#define SLAPI_LOG_ALERT 20 -#define SLAPI_LOG_CRIT 21 -#define SLAPI_LOG_ERR 22 -#define SLAPI_LOG_WARNING 23 -#define SLAPI_LOG_NOTICE 24 -#define SLAPI_LOG_INFO 25 -#define SLAPI_LOG_DEBUG 26 /* The last level must be set in log.c: SLAPI_LOG_MAX */ - -int slapi_is_loglevel_set(const int loglevel); - - -/* * locks and synchronization */ typedef struct slapi_mutex Slapi_Mutex; diff --git a/ldap/servers/slapd/slapi-private-v4.h b/ldap/servers/slapd/slapi-private-v4.h new file mode 100644 index 0000000..d50d81a --- /dev/null +++ b/ldap/servers/slapd/slapi-private-v4.h @@ -0,0 +1,198 @@ +/* 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 */ + +#pragma once + +#ifndef SLAPI_PRIVATE_V4_ACKNOWLEDGE +#error slapi private v4 is *not* a guaranteed api. It may change between minor releases. +#endif + +/* + * If you're using the internal private header, you know + * what you're getting into. + */ +#define SLAPI_PLUGIN_V4_PRERELEASE_ACKNOWLEDGE +#include + +/* Could be SLAPI_V4_PLUGIN_RESULT_CODE? */ +/* We *must* define these values for FFI */ +typedef enum { + SLAPI_V4_PLUGIN_SUCCESS = 0, + SLAPI_V4_PLUGIN_FAILURE = 1 +} SV4_PLUGIN_RESULT_CODE; + +typedef struct _slapi_v4_plugin_result { + SV4_PLUGIN_RESULT_CODE result; + /* Should we have an LDAP response code here? */ + /* Will allow sending back responses easily. */ + int ldap_code; + char *msg; +} slapi_v4_plugin_result; + +/* + * Low level berval manipulation + */ + +void slapi_v4_bv_free(struct berval *v); + +struct berval **slapi_v4_bvarray_create(); +void slapi_v4_bvarray_destroy(struct berval **array); +struct berval **slapi_v4_bvarray_append(struct berval **array, struct berval *bv); +void slapi_v4_bvarray_fold(struct berval **array, void (*fn)(struct berval *bv, void *acc, void *arg), void *acc, void *arg); + +/* + * Slapi_DN types + */ + +/** + * Represents a distinguished name in a directory entry. + * + * #Slapi_DN is the data type for an opaque structure that represents a distinguished + * name in the server plug-in. + */ +typedef struct slapi_dn slapi_v4_dn; +void slapi_v4_sdn_free(slapi_v4_dn *sdn); +slapi_v4_dn * slapi_v4_sdn_new_from_char_dn(const char *dn); +slapi_v4_dn * slapi_v4_sdn_dup(const slapi_v4_dn *sdn); + +/* + * TLS and certificate handling. + */ + +typedef struct CERTCertificateStr slapi_v4_cert; +char * slapi_v4_cert_get_subjectdn(slapi_v4_cert *cert); +char * slapi_v4_cert_get_issuerdn(slapi_v4_cert *cert); +struct berval *slapi_v4_cert_get_der_berval(slapi_v4_cert *cert); +char ** slapi_v4_cert_get_subject_ava_val(slapi_v4_cert *cert, const char *attr); + +/* + * PBLOCKS and related option passing code + */ + +/* We only have empty pblock declarations */ + +typedef struct _slapi_v4_certmap_pblock slapi_v4_certmap_pblock; + +slapi_v4_certmap_pblock * slapi_v4_certmap_pblock_init(void); +void slapi_v4_certmap_pblock_destroy(slapi_v4_certmap_pblock *pbc); + +void slapi_v4_certmap_pblock_set_clientdn(slapi_v4_certmap_pblock *pbc, slapi_v4_dn *sdn); +slapi_v4_dn * slapi_v4_certmap_pblock_get_clientdn(slapi_v4_certmap_pblock *pbc); + +slapi_v4_cert * slapi_v4_certmap_pblock_get_clientcert(slapi_v4_certmap_pblock *pbc); +void slapi_v4_certmap_pblock_set_clientcert(slapi_v4_certmap_pblock *pbc, slapi_v4_cert *clientcert); + +/* + * Entry interaction code. + */ +typedef struct slapi_entry Slapi_Entry; + +const slapi_v4_dn * slapi_v4_entry_get_sdn(Slapi_Entry *e); + +char **slapi_v4_entry_attr_get_charray(const Slapi_Entry *e, const char *type); + +struct berval **slapi_v4_entry_attr_get_bervals(const Slapi_Entry *e, const char *type); + +/* + * Search pblock. This is based on the v3 search pblock. + */ +typedef struct _slapi_pblock_intop slapi_v4_search_pblock; + +void slapi_v4_search_pblock_destroy(slapi_v4_search_pblock *pbs); +/* execute a search, and result the result pb */ +slapi_v4_search_pblock * slapi_v4_search_internal(slapi_v4_dn *basedn, + int scope, + const char *filter, + char **attrs, + int attrsonly, + LDAPControl **controls, + const char *uniqueid, + int operation_flags); + +slapi_v4_search_pblock * slapi_v4_search_internal_all_contexts(int scope, + const char *filter, + char **attrs, + int attrsonly, + LDAPControl **controls, + const char *uniqueid, + int operation_flags); + +slapi_v4_search_pblock * slapi_v4_add_internal_entry(Slapi_Entry *entry, const char *modifier_name); + +slapi_v4_plugin_result * slapi_v4_entry_exists_or_create(slapi_v4_dn *dn, const char *filter, const char *entry, const char *modifier_name); + +uint64_t slapi_v4_search_pblock_get_num_results(slapi_v4_search_pblock *pbs); +Slapi_Entry **slapi_v4_search_pblock_get_entries(slapi_v4_search_pblock *pbs); +char **slapi_v4_search_pblogk_get_referrals(slapi_v4_search_pblock *pbs); + +int slapi_v4_search_pblock_get_ldapresult(slapi_v4_search_pblock *pbs); + + + +/* + * PLUGIN REGISTRATION COMPONENTS + */ + +/* Forward declare this empty type */ +typedef struct _slapi_v4_plugin_registration slapi_v4_plugin_registration; + +#define SV4_PLUGIN_PRECEDENCE_DEFAULT 50 + +void slapi_v4_plugin_register_name(slapi_v4_plugin_registration *pr, char *name); +void slapi_v4_plugin_register_precedence(slapi_v4_plugin_registration *pr, uint64_t order); +void slapi_v4_plugin_register_start_fn(slapi_v4_plugin_registration *pr, slapi_v4_plugin_result *(*sv4_start_fn)(void **ctx)); +void slapi_v4_plugin_register_close_fn(slapi_v4_plugin_registration *pr, slapi_v4_plugin_result *(*sv4_close_fn)(void **ctx)); +void slapi_v4_plugin_register_bind_certmap_fn(slapi_v4_plugin_registration *pr, slapi_v4_plugin_result *(*sv4_bind_certmap_fn)(void *ctx, slapi_v4_certmap_pblock *pbc)); + +/* + * RESULT MANAGEMENT + */ + +slapi_v4_plugin_result *slapi_v4_plugin_result_ok(void); +slapi_v4_plugin_result *slapi_v4_plugin_result_err(SV4_PLUGIN_RESULT_CODE result, int ldap_code, char *msg); +void slapi_v4_plugin_result_destroy(slapi_v4_plugin_result *r); + +/* + * CONFIGURATION + * Access to configurations. These should always stay private as plugins should + * never need to access this content. + */ + +char *config_get_configdir(void); + +char *config_get_certmap_basedn(void); + +/* + * Filter management + */ + +char * slapi_v4_escape_filter_value(char *filter_str, int len); + +/* + * Char arrays and manipulation. + */ + +char ** slapi_v4_charray_from_str(char *str, char *brkstr, int allow_dups); +char ** slapi_v4_charray_append(char **a, char *s); +void slapi_v4_charray_free(char **array); + +/* + * BORROW FROM V3 + * + * YOU MUST NOT CHANGE THESE LINES, AND THEY MAY NOT REMAIN STABLE + */ + +/* + * UTF8 string handling + */ + +unsigned char * slapi_utf8StrToLower(unsigned char *s); +unsigned char * ldap_utf8strip(unsigned char *s); +char * ldap_utf8strtok_r(char *sp, const char *brk, char **next); + + diff --git a/ldap/servers/slapd/slapi_pal.h b/ldap/servers/slapd/slapi_pal.h index 07d47d6..e51fb54 100644 --- a/ldap/servers/slapd/slapi_pal.h +++ b/ldap/servers/slapd/slapi_pal.h @@ -20,6 +20,12 @@ #pragma once #include +/* malloc and size_t */ +#include + +void * spal_calloc(size_t size); +void * spal_realloc(void *ptr, size_t size); +void spal_free(void *ptr); /** * Structure that contains our system memory information in bytes and pages. From 134006e6de53c4b2d8f541b932e7eb8be96cba1c Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 16 2020 02:34:39 +0000 Subject: [PATCH 2/11] Ticket 49218 - Certmap - sds changes for set manipulation Bug Description: This adds support for pluggable certificate mapping libraries. To achieve this, this replaces the existing baked in certificate mapping code. Fix Description: Improve the performance of sds, as well as improving some behaviours of the set functions for the b+tree related to iteration. This is required for the plugin interface for efficent calls of plugins. https://pagure.io/389-ds-base/issue/49218 https://pagure.io/lib389/issue/95 https://pagure.io/lib389/issue/84 Author: wibrown Review by: ??? --- diff --git a/src/libsds/include/sds.h b/src/libsds/include/sds.h index 3f0dd86..b0bdba8 100644 --- a/src/libsds/include/sds.h +++ b/src/libsds/include/sds.h @@ -1079,7 +1079,7 @@ sds_result sds_bptree_verify(sds_bptree_instance *binst); * \param fn The function to be applied to each key-value pair. * \retval Result of the operation as sds_result. */ -sds_result sds_bptree_map(sds_bptree_instance *binst, void (*fn)(void *k, void *v)); +sds_result sds_bptree_map(sds_bptree_instance *binst, void *arg, void (*fn)(void *k, void *v, void *arg)); /** * From instance a, and instance b, create a new insance that contains the * keys and values where keys exist in a or b but not both. @@ -1227,7 +1227,16 @@ sds_result sds_bptree_cow_wrtxn_abort(sds_bptree_transaction **btxn); * \retval Result of the operation as sds_result. */ sds_result sds_bptree_cow_wrtxn_commit(sds_bptree_transaction **btxn); - +/** + * Retrieve the current transaction's id. There is *no guarantee* that this + * id increments sequentially, or avoids any kind of int rollover. It's only + * purpose is to allow generational timestamping of external data to assert + * if a newer transaction has passed since. + * + * \param btxn The transaction from which you wish to retrieve the ID + * \retval The transaction ID. + */ +uint64_t sds_bptree_txn_get_id(sds_bptree_transaction *btxn); /** * Search a tree with a valid transaction reference. This returns KEY_PRESENT * or KEY_NOT_PRESENT if the search suceeds or not. Search may operation on a valid @@ -1288,10 +1297,19 @@ sds_result sds_bptree_cow_insert(sds_bptree_transaction *btxn, void *key, void * * \param value The value to update. May be NULL. * \retval Result of the operation as sds_result. */ - sds_result sds_bptree_cow_update(sds_bptree_transaction *btxn, void *key, void *value); /** + * Map over all key/values in the tree within this txn. If the transaction is readonly + * you should only read these values. If the txn is write, you may modify value. + * + * \param btxn The transaction to map over. + * \param arg A generic argument that will be passed to each invocation of fn. + * \param fn the function to apply to each key/value. + */ +sds_result sds_bptree_cow_map(sds_bptree_transaction *btxn, void *arg, void (*fn)(void *k, void *v, void *arg)); + +/** * Search atomic functions as search, but implies a single short lived read transaction. * * If you have multiple searches to make, it is better to use a read transaction due to diff --git a/src/libsds/sds/bpt/bpt.c b/src/libsds/sds/bpt/bpt.c index 8703e2d..79951e0 100644 --- a/src/libsds/sds/bpt/bpt.c +++ b/src/libsds/sds/bpt/bpt.c @@ -384,6 +384,9 @@ sds_bptree_destroy(sds_bptree_instance *binst) { // Remove all the other elements sds_result result = SDS_SUCCESS; + if (binst == NULL) { + return SDS_NULL_POINTER; + } result = sds_bptree_map_nodes(binst, binst->root, sds_bptree_node_destroy); // Finally remove the binst sds_free(binst); diff --git a/src/libsds/sds/bpt/common.c b/src/libsds/sds/bpt/common.c index edae1e3..275ee10 100644 --- a/src/libsds/sds/bpt/common.c +++ b/src/libsds/sds/bpt/common.c @@ -522,7 +522,7 @@ sds_bptree_leaf_delete(sds_bptree_instance *binst, sds_bptree_node *node, void * /* extract the contents (if any) */ void *value = node->values[index]; - if (value != NULL) { + if (value != NULL && binst->value_free_fn != NULL) { binst->value_free_fn(value); } /* Delete the key + value */ diff --git a/src/libsds/sds/bpt/set.c b/src/libsds/sds/bpt/set.c index 9f00d35..523c56c 100644 --- a/src/libsds/sds/bpt/set.c +++ b/src/libsds/sds/bpt/set.c @@ -66,7 +66,7 @@ sds_bptree_list_advance(sds_bptree_node **item, size_t *index) /* Tree mapping functions */ /* Shouldn't this make a set of results? */ sds_result -sds_bptree_map(sds_bptree_instance *binst, void (*fn)(void *k, void *v)) +sds_bptree_map(sds_bptree_instance *binst, void *arg, void (*fn)(void *k, void *v, void *arg)) { /* If this is the non-cow tree, this is easy. */ /* Find the bottom left node, then iterate to the right! */ @@ -74,7 +74,7 @@ sds_bptree_map(sds_bptree_instance *binst, void (*fn)(void *k, void *v)) while (work_node != NULL) { for (size_t index = 0; index < work_node->item_count; index++) { - fn(work_node->keys[index], work_node->values[index]); + fn(work_node->keys[index], work_node->values[index], arg); } work_node = (sds_bptree_node *)work_node->values[SDS_BPTREE_DEFAULT_CAPACITY]; } diff --git a/src/libsds/sds/bpt_cow/bpt_cow.c b/src/libsds/sds/bpt_cow/bpt_cow.c index c2ab607..b55d55e 100644 --- a/src/libsds/sds/bpt_cow/bpt_cow.c +++ b/src/libsds/sds/bpt_cow/bpt_cow.c @@ -469,6 +469,51 @@ sds_bptree_cow_update(sds_bptree_transaction *btxn, void *key, void *value) return SDS_SUCCESS; } +sds_result +sds_bptree_cow_map(sds_bptree_transaction *btxn, void *arg, void (*fn)(void *k, void *v, void *arg)) { + /* + * For each leaf node, map fn to each value. + * + * This is really similar to map_nodes, but only applies fn at level == 0 + */ + + if (btxn == NULL) { + return SDS_INVALID_TXN; + } + + sds_bptree_node_list *cur = sds_malloc(sizeof(sds_bptree_node_list)); + sds_bptree_node_list *prev = cur; + sds_bptree_node_list *tail = cur; + + cur->node = btxn->root; + cur->next = NULL; + sds_result final_result = SDS_SUCCESS; + + while (cur != NULL) { + if (cur->node->level > 0) { + /* Has to be <= here as this is access values, not keys! */ + for (size_t i = 0; i <= cur->node->item_count; i++) { + /* Alloc a new element, and shuffle along .... */ + if (cur->node->values[i] != NULL) { + tail->next = sds_malloc(sizeof(sds_bptree_node_list)); + tail = tail->next; + tail->node = (sds_bptree_node *)cur->node->values[i]; + tail->next = NULL; + } + } + } else { + /* We have a leaf! map the fn over valid values. */ + for (size_t index = 0; index < cur->node->item_count; index++) { + fn(cur->node->keys[index], cur->node->values[index], arg); + } + } + prev = cur; + cur = cur->next; + free(prev); + } + return final_result; +} + // Does this need to work on a transaction perhaps to verify the tree is "sane"? sds_result sds_bptree_cow_verify(sds_bptree_cow_instance *binst) diff --git a/src/libsds/sds/bpt_cow/txn.c b/src/libsds/sds/bpt_cow/txn.c index 1da0ae4..c6be44e 100644 --- a/src/libsds/sds/bpt_cow/txn.c +++ b/src/libsds/sds/bpt_cow/txn.c @@ -54,7 +54,7 @@ sds_bptree_txn_create(sds_bptree_cow_instance *binst) // The initial ref count is 0, and we only up to 1 when we commit. // Atomically set this to 0. - __atomic_and_fetch(&(btxn->reference_count), 0, __ATOMIC_SEQ_CST); + __atomic_and_fetch(&(btxn->reference_count), 0, __ATOMIC_RELAXED); #ifdef SDS_DEBUG // Update our needed checksums @@ -76,6 +76,23 @@ sds_bptree_txn_create(sds_bptree_cow_instance *binst) * ============================================================== */ +uint64_t +sds_bptree_txn_get_id(sds_bptree_transaction *btxn) { + if (btxn != NULL) { + return btxn->txn_id; + } + return 0; +} + +/* ========================= WARNING ============================ + * UNLESS YOU HAVE READ: + * https://www.kernel.org/doc/Documentation/memory-barriers.txt + * and SERIOUSLY understand it, and how it works you *MUST* not + * edit this file. This section of the code relies on a deep + * understanding of locking and memory barriers. + * ============================================================== + */ + // Should be caled by txn decrement. static void sds_bptree_txn_free(sds_bptree_transaction *btxn) @@ -111,7 +128,7 @@ sds_bptree_txn_free(sds_bptree_transaction *btxn) static void sds_bptree_txn_increment(sds_bptree_transaction *btxn) { - __atomic_add_fetch(&(btxn->reference_count), 1, __ATOMIC_SEQ_CST); + __atomic_add_fetch(&(btxn->reference_count), 1, __ATOMIC_RELAXED); // PR_AtomicIncrement(&(btxn->reference_count)); #ifdef SDS_DEBUG @@ -140,7 +157,7 @@ sds_bptree_txn_decrement(sds_bptree_transaction *btxn) // Atomic dec the counter. // PR_AtomicDecrement returns the set value. - uint32_t result = __atomic_sub_fetch(&(btxn->reference_count), 1, __ATOMIC_SEQ_CST); + uint32_t result = __atomic_sub_fetch(&(btxn->reference_count), 1, __ATOMIC_RELAXED); /* WARNING: After this point, another thread MAY free btxn under us. * You MUST *not* deref btxn after this point. */ @@ -169,7 +186,7 @@ sds_bptree_txn_decrement(sds_bptree_transaction *btxn) // * there are more parents left, so we are > 0 // * there are still active holders left, so we are > 0 if (btxn != NULL) { - result = __atomic_sub_fetch(&(btxn->reference_count), 1, __ATOMIC_SEQ_CST); + result = __atomic_sub_fetch(&(btxn->reference_count), 1, __ATOMIC_RELAXED); } } } @@ -400,7 +417,7 @@ sds_bptree_cow_wrtxn_commit(sds_bptree_transaction **btxn) // Say we are alive and commited - 2 means "our former transaction owns us" // and "we are the active root". uint32_t default_ref_count = 2; - __atomic_store(&((*btxn)->reference_count), &default_ref_count, __ATOMIC_SEQ_CST); + __atomic_store(&((*btxn)->reference_count), &default_ref_count, __ATOMIC_RELAXED); // Set it. (*btxn)->binst->txn = *btxn; // Update our parent to reference us. diff --git a/src/libsds/test/test_sds_cow.c b/src/libsds/test/test_sds_cow.c index 9fd5ab0..0ece309 100644 --- a/src/libsds/test/test_sds_cow.c +++ b/src/libsds/test/test_sds_cow.c @@ -562,6 +562,40 @@ test_cow_update(void **state) assert_int_equal(sds_bptree_cow_rotxn_close(&ro_btxn_b), SDS_SUCCESS); } +static void +test_cow_map_cb(void *key __attribute((unused)), void *value, void *arg __attribute((unused))) { + *(uint64_t *)value = 12345; +} + +static void +test_cow_map(void **state) +{ + sds_bptree_cow_instance *binst = *state; + sds_bptree_transaction *wr_btxn = NULL; + sds_result result = SDS_SUCCESS; + + assert_int_equal(sds_bptree_cow_wrtxn_begin(binst, &wr_btxn), SDS_SUCCESS); + + /* Insert a set of keys with values */ + for (uint64_t i = 10; i < (10 + SDS_BPTREE_DEFAULT_CAPACITY); i++) { + result = sds_bptree_cow_insert(wr_btxn, (void *)&i, sds_uint64_t_dup((void *)&i)); + assert_int_equal(result, SDS_SUCCESS); + } + /* Map and change the values */ + + assert_int_equal(sds_bptree_cow_map(wr_btxn, NULL, test_cow_map_cb), SDS_SUCCESS); + + for (uint64_t i = 10; i < (10 + SDS_BPTREE_DEFAULT_CAPACITY); i++) { + uint64_t *output = NULL; + assert_int_equal(sds_bptree_cow_retrieve(wr_btxn, (void *)&i, (void **)&output), SDS_KEY_PRESENT); + assert_int_equal(result, SDS_SUCCESS); + assert_int_equal(*output, 12345); + } + /* Assert the values have changed. */ + + assert_int_equal(sds_bptree_cow_wrtxn_commit(&wr_btxn), SDS_SUCCESS); +} + int run_cow_tests(void) { @@ -627,6 +661,9 @@ run_cow_tests(void) cmocka_unit_test_setup_teardown(test_cow_update, bptree_test_cow_setup, bptree_test_cow_teardown), + cmocka_unit_test_setup_teardown(test_cow_map, + bptree_test_cow_setup, + bptree_test_cow_teardown), }; return cmocka_run_group_tests_name("bpt_cow", tests, NULL, NULL); } diff --git a/src/libsds/test/test_sds_set.c b/src/libsds/test/test_sds_set.c index e1080dc..3831bba 100644 --- a/src/libsds/test/test_sds_set.c +++ b/src/libsds/test/test_sds_set.c @@ -16,7 +16,7 @@ static int32_t cb_count = 0; static void -test_31_map_cb(void *k __attribute__((unused)), void *v __attribute__((unused))) +test_31_map_cb(void *k __attribute__((unused)), void *v __attribute__((unused)), void *arg __attribute__((unused))) { cb_count++; } @@ -39,7 +39,7 @@ test_31_map(void **state) result = sds_bptree_verify(binst); assert_int_equal(result, SDS_SUCCESS); } - sds_bptree_map(binst, test_31_map_cb); + sds_bptree_map(binst, NULL, test_31_map_cb); assert_int_equal(cb_count, 199); } From bc083075307f37b04345515775ccd1778e722208 Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 16 2020 02:40:08 +0000 Subject: [PATCH 3/11] Ticket 49218 - Certmap - plugin v4 api Bug Description: This adds support for pluggable certificate mapping libraries. To achieve this, this replaces the existing baked in certificate mapping code. Fix Description: Add the suppport for the v4 api. This includes a more efficent search interface, some type wrappers for important escape and filter types, as well as improvements to the memory allocation routines. https://pagure.io/389-ds-base/issue/49218 https://pagure.io/lib389/issue/95 https://pagure.io/lib389/issue/84 Author: wibrown Review by: ??? --- diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c index 52c64fa..ff16a75 100644 --- a/ldap/servers/slapd/add.c +++ b/ldap/servers/slapd/add.c @@ -38,6 +38,8 @@ #include "pratom.h" #include "csngen.h" +#include + /* Forward declarations */ static int add_internal_pb(Slapi_PBlock *pb); static void op_shared_add(Slapi_PBlock *pb); @@ -331,6 +333,38 @@ slapi_add_internal_pb(Slapi_PBlock *pb) 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) { diff --git a/ldap/servers/slapd/bvarray_v4.c b/ldap/servers/slapd/bvarray_v4.c new file mode 100644 index 0000000..f277feb --- /dev/null +++ b/ldap/servers/slapd/bvarray_v4.c @@ -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 +#endif + +#include + +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); + } +} diff --git a/ldap/servers/slapd/cert_v4.c b/ldap/servers/slapd/cert_v4.c new file mode 100644 index 0000000..bfbbdba --- /dev/null +++ b/ldap/servers/slapd/cert_v4.c @@ -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 + +/* + * 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 + +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) { + return NULL; + } + + for (size_t i = 0; rdns[i] != NULL; i++) { + CERTRDN *rdn = rdns[i]; + CERTAVA **avas = rdn->avas; + + for (size_t j = 0; avas[j] != NULL; j++) { + CERTAVA *ava = avas[j]; + if (attr_tag == CERT_GetAVATag(ava)) { + /* + * In the original implementation we need to trim + * the ava value here else it will fail to be parsed. + */ + size_t datalen = ava->value.len + 4; + char *data = spal_calloc(datalen); + + int offset = 2; + if (ava->value.len >= 128) { + offset = 3; + } + + int rv = CERT_RFC1485_EscapeAndQuote(data, datalen, (char *)(ava->value.data + offset), ava->value.len - offset); + if (rv == SECSuccess) { + slapi_ch_array_add(&result, data); + } + break; + } + } + + } + + return result; +} + +char ** +slapi_v4_cert_get_subject_ava_val(slapi_v4_cert *cert, const char *attr) { + CERTName *dn = &(cert->subject); + return slapi_v4_cert_get_ava_val(dn, attr); +} + diff --git a/ldap/servers/slapd/ch_malloc.c b/ldap/servers/slapd/ch_malloc.c index 75e7911..21c5213 100644 --- a/ldap/servers/slapd/ch_malloc.c +++ b/ldap/servers/slapd/ch_malloc.c @@ -158,7 +158,8 @@ slapi_ch_realloc( char * slapi_ch_calloc( unsigned long nelem, - unsigned long size) + unsigned long size +) { char *newmem; diff --git a/ldap/servers/slapd/charray.c b/ldap/servers/slapd/charray.c index c27c5da..bad4c66 100644 --- a/ldap/servers/slapd/charray.c +++ b/ldap/servers/slapd/charray.c @@ -62,6 +62,13 @@ slapi_ch_array_add_ext(char ***a, char *s) return n; } +char ** +slapi_v4_charray_append(char **a, char *s) { + char **ptr = a; + charray_add(&ptr, s); + return ptr; +} + void charray_merge( char ***a, @@ -201,11 +208,13 @@ charray_free(char **array) for (a = array; *a != NULL; a++) { char *tmp = *a; - slapi_ch_free((void **)&tmp); + spal_free(tmp); } - slapi_ch_free((void **)&array); + spal_free(array); } +void slapi_v4_charray_free(char **array) __attribute__((weak, alias("charray_free"))); + /* * charray_free version for plugins: there is a need for plugins to free * the ch_arrays returned by functions like: @@ -322,6 +331,9 @@ slapi_str2charray(char *str, char *brkstr) return (slapi_str2charray_ext(str, brkstr, 1)); } +char ** +slapi_v4_charray_from_str(char *str, char *brkstr) __attribute__((weak, alias("slapi_str2charray"))); + /* * extended version of str2charray lets you disallow * duplicate values into the array. diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c index 2af3f38..95a5ed7 100644 --- a/ldap/servers/slapd/dn.c +++ b/ldap/servers/slapd/dn.c @@ -2010,6 +2010,9 @@ slapi_sdn_new_dn_byval(const char *dn) } Slapi_DN * +slapi_v4_sdn_new_from_char_dn(const char *dn) __attribute__((weak, alias("slapi_sdn_new_dn_byval"))); + +Slapi_DN * slapi_sdn_new_ndn_byval(const char *ndn) { Slapi_DN *sdn = slapi_sdn_new(); @@ -2322,21 +2325,28 @@ slapi_sdn_done(Slapi_DN *sdn) } void -slapi_sdn_free(Slapi_DN **sdn) -{ - if (sdn != NULL && *sdn != NULL) { +slapi_v4_sdn_free(Slapi_DN *sdn) { + if (sdn != NULL) { int is_allocated = 0; - SDN_DUMP(*sdn, "slapi_sdn_free"); - is_allocated = slapi_isbitset_uchar((*sdn)->flag, FLAG_ALLOCATED); - slapi_sdn_done(*sdn); + SDN_DUMP(sdn, "slapi_sdn_free"); + is_allocated = slapi_isbitset_uchar(sdn->flag, FLAG_ALLOCATED); + slapi_sdn_done(sdn); if (is_allocated) { - slapi_ch_free((void **)sdn); + spal_free(sdn); PR_INCREMENT_COUNTER(slapi_sdn_counter_deleted); PR_DECREMENT_COUNTER(slapi_sdn_counter_exist); } } } +void +slapi_sdn_free(Slapi_DN **sdn) +{ + if (sdn != NULL) { + slapi_v4_sdn_free(*sdn); + } +} + const char * slapi_sdn_get_dn(const Slapi_DN *sdn) { @@ -2471,6 +2481,9 @@ slapi_sdn_dup(const Slapi_DN *sdn) return tmp; } +Slapi_DN * +slapi_v4_sdn_dup(const Slapi_DN *sdn) __attribute__((weak, alias("slapi_sdn_dup"))); + void slapi_sdn_copy(const Slapi_DN *from, Slapi_DN *to) { diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c index 1cc30fc..252b79e 100644 --- a/ldap/servers/slapd/entry.c +++ b/ldap/servers/slapd/entry.c @@ -22,6 +22,8 @@ #include #include "slap.h" +#include + #undef ENTRY_DEBUG #define DELETED_ATTR_STRING ";deletedattribute" @@ -2085,6 +2087,9 @@ slapi_entry_get_sdn_const(const Slapi_Entry *e) return &e->e_sdn; } +const Slapi_DN * +slapi_v4_entry_get_sdn(Slapi_Entry *e) __attribute__((weak, alias("slapi_entry_get_sdn_const"))); + Slapi_DN * slapi_entry_get_sdn(Slapi_Entry *e) { @@ -2698,6 +2703,9 @@ slapi_entry_attr_get_charray(const Slapi_Entry *e, const char *type) return slapi_entry_attr_get_charray_ext(e, type, &ignore); } +char ** +slapi_v4_entry_attr_get_charray(const Slapi_Entry *e, const char *type) __attribute__((weak, alias("slapi_entry_attr_get_charray"))); + /* * The extension also gathers the number of values. * The caller must free with slapi_ch_array_free @@ -2755,6 +2763,27 @@ slapi_entry_attr_get_charptr(const Slapi_Entry *e, const char *type) return p; } +struct berval ** +slapi_v4_entry_attr_get_bervals(const Slapi_Entry *e, const char *type) { + + struct berval **bervals = {0}; + Slapi_Attr *attr = NULL; + slapi_entry_attr_find(e, type, &attr); + + if (attr != NULL) { + bervals = slapi_v4_bvarray_create(); + int hint; + Slapi_Value *v = NULL; + + for (hint = slapi_attr_first_value(attr, &v); hint != -1; hint = slapi_attr_next_value(attr, hint, &v)) { + struct berval *bvp = slapi_ch_bvdup(slapi_value_get_berval(v)); + bervals = slapi_v4_bvarray_append(bervals, bvp); + } + } + + return bervals; +} + /* returned value: attribute value as an integer type */ int slapi_entry_attr_get_int(const Slapi_Entry *e, const char *type) diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c index 3500108..e58afbe 100644 --- a/ldap/servers/slapd/log.c +++ b/ldap/servers/slapd/log.c @@ -29,6 +29,10 @@ #include "log.h" #include "fe.h" #include /* getpwnam */ + +/* Access the log levels enum. */ +#include + #define _PSEP '/' #ifdef SYSTEMTAP @@ -2462,17 +2466,9 @@ vslapd_log_error( return (0); } -/* - * Log a message to the errors log - * - * loglevel - The logging level: replication, plugin, etc - * severity - LOG_ERR, LOG_WARNING, LOG_INFO, etc - */ -int -slapi_log_error(int loglevel, char *subsystem, char *fmt, ...) +int32_t +slapi_log_error_ext(slapi_log_level loglevel, char *subsystem, char *fmt, va_list ap_err, va_list ap_file) { - va_list ap_err; - va_list ap_file; int rc = LDAP_SUCCESS; int lbackend = loginfo.log_backend; /* We copy this to make these next checks atomic */ @@ -2485,33 +2481,19 @@ slapi_log_error(int loglevel, char *subsystem, char *fmt, ...) if (slapd_ldap_debug & slapi_log_map[loglevel]) { if (lbackend & LOGGING_BACKEND_INTERNAL) { - va_start(ap_err, fmt); - va_start(ap_file, fmt); rc = slapd_log_error_proc_internal(loglevel, subsystem, fmt, ap_err, ap_file); - va_end(ap_file); - va_end(ap_err); } if (rc != LDAP_SUCCESS) { return (rc); } if (lbackend & LOGGING_BACKEND_SYSLOG) { - va_start(ap_err, fmt); - /* va_start( ap_file, fmt ); */ /* This returns void, so we hope it worked */ vsyslog(get_syslog_loglevel(loglevel), fmt, ap_err); - /* vsyslog(LOG_ERROR, fmt, ap_file); */ - /* va_end(ap_file); */ - va_end(ap_err); } #ifdef HAVE_JOURNALD if (lbackend & LOGGING_BACKEND_JOURNALD) { - va_start(ap_err, fmt); - /* va_start( ap_file, fmt ); */ /* This isn't handling RC nicely ... */ rc = sd_journal_printv(get_syslog_loglevel(loglevel), fmt, ap_err); - /* rc = sd_journal_printv(LOG_ERROR, fmt, ap_file); */ - /* va_end(ap_file); */ - va_end(ap_err); } #endif } else { @@ -2521,28 +2503,27 @@ slapi_log_error(int loglevel, char *subsystem, char *fmt, ...) return (rc); } -int -slapi_log_error_ext(int loglevel, char *subsystem, char *fmt, va_list varg1, va_list varg2) -{ - int rc = 0; - - if (loglevel < SLAPI_LOG_MIN || loglevel > SLAPI_LOG_MAX) { - (void)slapd_log_error_proc(loglevel, subsystem, "slapi_log_error: invalid severity %d (message %s)\n", - loglevel, fmt); - return (-1); - } - - if (slapd_ldap_debug & slapi_log_map[loglevel]) { - rc = slapd_log_error_proc_internal(loglevel, subsystem, fmt, varg1, varg2); - } else { - rc = 0; /* nothing to be logged --> always return success */ - } - - return (rc); +/* + * Log a message to the errors log + * + * loglevel - The logging level: replication, plugin, etc + * severity - LOG_ERR, LOG_WARNING, LOG_INFO, etc + */ +int32_t +slapi_log_error(slapi_log_level loglevel, char *subsystem, char *fmt, ...) { + int32_t rc = 0; + va_list ap_err; + va_list ap_file; + va_start(ap_err, fmt); + va_start(ap_file, fmt); + rc = slapi_log_error_ext(loglevel, subsystem, fmt, ap_err, ap_file); + va_end(ap_file); + va_end(ap_err); + return rc; } -int -slapi_is_loglevel_set(const int loglevel) +int32_t +slapi_is_loglevel_set(const slapi_log_level loglevel) { return (slapd_ldap_debug & slapi_log_map[loglevel] ? 1 : 0); } diff --git a/ldap/servers/slapd/pblock_v4.c b/ldap/servers/slapd/pblock_v4.c new file mode 100644 index 0000000..56eec93 --- /dev/null +++ b/ldap/servers/slapd/pblock_v4.c @@ -0,0 +1,173 @@ +/* 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 */ + +/* + * Replacement of the monolithic pblock into smaller focused + * versions. + * + * Basically the extension of the pblock_v3 breakup and hiding work, but + * without needing a super structure wrapper in front. + */ + +#define SLAPI_PLUGIN_V4_PRERELEASE_ACKNOWLEDGE +#define SLAPI_PRIVATE_V4_ACKNOWLEDGE + +#include "pblock_v3.h" +#include + +/* NSS cert includes for certcertificate */ +#include + +typedef struct _slapi_v4_certmap_pblock { + slapi_v4_dn *sdn; + slapi_v4_cert *clientcert; +} slapi_v4_certmap_pblock; + +slapi_v4_certmap_pblock * +slapi_v4_certmap_pblock_init(void) { + slapi_v4_certmap_pblock *pbc = (slapi_v4_certmap_pblock *)spal_calloc(sizeof(slapi_v4_certmap_pblock)); + return pbc; +} + +slapi_v4_dn * +slapi_v4_certmap_pblock_get_clientdn(slapi_v4_certmap_pblock *pbc) { + return pbc->sdn; +} + +void +slapi_v4_certmap_pblock_set_clientdn(slapi_v4_certmap_pblock *pbc, slapi_v4_dn *sdn) { + pbc->sdn = sdn; +} + +slapi_v4_cert * +slapi_v4_certmap_pblock_get_clientcert(slapi_v4_certmap_pblock *pbc) { + return pbc->clientcert; +} + +void +slapi_v4_certmap_pblock_set_clientcert(slapi_v4_certmap_pblock *pbc, slapi_v4_cert *clientcert) { + pbc->clientcert = clientcert; +} + +void +slapi_v4_certmap_pblock_destroy(slapi_v4_certmap_pblock *pbc) { + slapi_sdn_free(&(pbc->sdn)); + spal_free(pbc); +} + + +/* + * Search pblock functions. + */ + +/* + * To the external world we present a simple api of get/set same as pblock + * + * But when we go to commit a search, we actually alloc a v3 pblock, and push + * this as the intop pblock into it. + * + * This abstraction means that later we can later remove the v3 layer from the middle + * and just go full v4 for search pblock access. + */ + +slapi_v4_search_pblock * +slapi_v4_search_pblock_create(void) { + slapi_v4_search_pblock *pbs = (slapi_v4_search_pblock *)spal_calloc(sizeof(slapi_v4_search_pblock)); + return pbs; +} + +slapi_v4_search_pblock * +slapi_v4_search_pblock_extract(Slapi_PBlock *pb) { + slapi_v4_search_pblock *pbs = pb->pb_intop; + pb->pb_intop = NULL; + return pbs; +} + +void +slapi_v4_search_pblock_destroy(slapi_v4_search_pblock *pbs) { + + Slapi_Entry **op_entries = pbs->pb_plugin_internal_search_op_entries; + + if (op_entries != NULL) { + for (size_t i = 0; op_entries[i] != NULL; i++) { + slapi_entry_free(op_entries[i]); + } + spal_free(op_entries); + } + + char **op_referrals = pbs->pb_plugin_internal_search_op_referrals; + + if (op_referrals != NULL) { + for (size_t i = 0; op_referrals[i] != NULL; i++) { + spal_free(op_referrals[i]); + } + spal_free(op_referrals); + } + + if (pbs != NULL) { + delete_passwdPolicy(&pbs->pwdpolicy); + spal_free(pbs->pb_result_text); + } + spal_free(pbs); +} + +uint64_t +slapi_v4_search_pblock_get_num_results(slapi_v4_search_pblock *pbs) { + return pbs->pb_plugin_internal_search_num_entries; +} + +Slapi_Entry ** +slapi_v4_search_pblock_get_entries(slapi_v4_search_pblock *pbs) { + return pbs->pb_plugin_internal_search_op_entries; +} + +char ** +slapi_v4_search_pblock_get_referrals(slapi_v4_search_pblock *pbs) { + return pbs->pb_plugin_internal_search_op_referrals; +} + +int +slapi_v4_search_pblock_get_ldapresult(slapi_v4_search_pblock *pbs) { + return pbs->pb_internal_op_result; +} + +void +slapi_v4_search_pblock_merge(slapi_v4_search_pblock *pbs_a, slapi_v4_search_pblock *pbs_b) { + /* Check the a and b are valid */ + if (pbs_a == NULL || pbs_b == NULL) { + return; + } + /* Check the search results of b exist. */ + + if (pbs_b->pb_plugin_internal_search_num_entries > 0) { + /* Merge the content of B into A if any */ + uint64_t total_entries = pbs_a->pb_plugin_internal_search_num_entries + pbs_b->pb_plugin_internal_search_num_entries; + /* Realloc the entry array space. */ + pbs_a->pb_plugin_internal_search_op_entries = (Slapi_Entry **)spal_realloc((char *)pbs_a->pb_plugin_internal_search_op_entries, + sizeof(Slapi_Entry *) * (total_entries + 1)); + + for(size_t i = 0; i < pbs_b->pb_plugin_internal_search_num_entries; i++) { + /* + * This works as if pbs_a->num_ent == 0, we get 0 with i== 0. If we have 1 + * we get 1, and the entry is at 0. Etc. + */ + size_t offset_a = pbs_a->pb_plugin_internal_search_num_entries + i; + pbs_a->pb_plugin_internal_search_op_entries[offset_a] = pbs_b->pb_plugin_internal_search_op_entries[i]; + pbs_b->pb_plugin_internal_search_op_entries[i] = NULL; + } + /* Ensure the last slot is null. */ + pbs_a->pb_plugin_internal_search_op_entries[total_entries] = NULL; + + pbs_a->pb_plugin_internal_search_num_entries = total_entries; + } + + /* Finally, destroy b. */ + slapi_v4_search_pblock_destroy(pbs_b); +} + + diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c index e6b48de..a3f3c66 100644 --- a/ldap/servers/slapd/plugin.c +++ b/ldap/servers/slapd/plugin.c @@ -18,6 +18,9 @@ #include #include "slap.h" +#define SLAPI_PRIVATE_V4_ACKNOWLEDGE +#include + /* this defines are used for plugin configuration */ #define LOCAL_DATA "local data" #define REMOTE_DATA "remote data" diff --git a/ldap/servers/slapd/plugin_internal_op.c b/ldap/servers/slapd/plugin_internal_op.c index a140e79..7fddcad 100644 --- a/ldap/servers/slapd/plugin_internal_op.c +++ b/ldap/servers/slapd/plugin_internal_op.c @@ -55,8 +55,8 @@ typedef struct callback_fn_ptrs /* forward declarations */ static int seq_internal_callback_pb(Slapi_PBlock *pb, void *callback_data, plugin_result_callback prc, plugin_search_entry_callback psec, plugin_referral_entry_callback prec); -static int search_internal_pb(Slapi_PBlock *pb); static int search_internal_callback_pb(Slapi_PBlock *pb, void *callback_data, plugin_result_callback prc, plugin_search_entry_callback psec, plugin_referral_entry_callback prec); +int search_internal_pb(Slapi_PBlock *pb); void internal_getresult_callback(struct conn *unused1 __attribute__((unused)), @@ -564,7 +564,7 @@ internal_plugin_result_callback(int rc, void *callback_data) ((plugin_search_internal_data *)callback_data)->rc = rc; } -static int +int search_internal_pb(Slapi_PBlock *pb) { plugin_search_internal_data psid; diff --git a/ldap/servers/slapd/slapi-plugin-v4.c b/ldap/servers/slapd/slapi-plugin-v4.c new file mode 100644 index 0000000..2ace85f --- /dev/null +++ b/ldap/servers/slapd/slapi-plugin-v4.c @@ -0,0 +1,70 @@ +/* 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 +#include + +slapi_v4_plugin_result * +slapi_v4_plugin_result_ok(void) { + /* + * A potential (and premature, and probably silly) + * optimisation here is OK is == NULL, to avoid an alloc / free. + * + * However, this may interfere with FFI which may expect a value. + * provided we *don't* offer an api that allows modification of a + * result post creation, it's a possibility. + */ + slapi_v4_plugin_result *res = (slapi_v4_plugin_result *)spal_calloc(sizeof(slapi_v4_plugin_result)); + res->result = SLAPI_V4_PLUGIN_SUCCESS; + return res; +} + +slapi_v4_plugin_result * +slapi_v4_plugin_result_err(SV4_PLUGIN_RESULT_CODE result, int ldap_code, char *msg) { + slapi_v4_plugin_result *res = (slapi_v4_plugin_result *)spal_calloc(sizeof(slapi_v4_plugin_result)); + res->result = result; + res->ldap_code = ldap_code; + res->msg = msg; + return res; +} + +void +slapi_v4_plugin_result_destroy(slapi_v4_plugin_result *r) { + if (r != NULL) { + spal_free(r->msg); + spal_free(r); + } +} + +void +slapi_v4_plugin_register_name(slapi_v4_plugin_registration *pr, char *name) { + pr->sv4_name = strdup(name); +} + +void +slapi_v4_plugin_register_precedence(slapi_v4_plugin_registration *pr, uint64_t order) { + pr->precedence = order; +} + +void +slapi_v4_plugin_register_start_fn(slapi_v4_plugin_registration *pr, slapi_v4_plugin_result *(*sv4_start_fn)(void **ctx)) { + pr->sv4_start_fn = sv4_start_fn; +} + +void +slapi_v4_plugin_register_close_fn(slapi_v4_plugin_registration *pr, slapi_v4_plugin_result *(*sv4_close_fn)(void **ctx)) { + pr->sv4_close_fn = sv4_close_fn; +} + +void +slapi_v4_plugin_register_bind_certmap_fn(slapi_v4_plugin_registration *pr, slapi_v4_plugin_result *(*sv4_bind_certmap_fn)(void *ctx, slapi_v4_certmap_pblock *pbc)) { + pr->sv4_bind_certmap_fn = sv4_bind_certmap_fn; +} diff --git a/ldap/servers/slapd/slapi-private-v4.c b/ldap/servers/slapd/slapi-private-v4.c new file mode 100644 index 0000000..ac505d1 --- /dev/null +++ b/ldap/servers/slapd/slapi-private-v4.c @@ -0,0 +1,131 @@ +/* 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 */ + +#include + +slapi_v4_plugin_registration * +slapi_v4_plugin_registration_create() { + slapi_v4_plugin_registration *pr = (slapi_v4_plugin_registration *)spal_calloc(sizeof(slapi_v4_plugin_registration)); + return pr; +} + +void +slapi_v4_plugin_registration_destroy(slapi_v4_plugin_registration *pr) { + spal_free(pr->sv4_name); + spal_free(pr); +} + + +/* Internal search helper functions. */ + +slapi_v4_search_pblock * +slapi_v4_search_internal(Slapi_DN *basedn, + int32_t scope, + const char *filter, + char **attrs, + int32_t attrsonly, + LDAPControl **controls, + const char *uniqueid, + int32_t operation_flags) +{ + /* + * This setups the search pblock similar to slapi_search_internal_set_pb_ext + * followed by calling search_internal_pb + */ + + Slapi_PBlock *int_pbs = slapi_pblock_new(); + /* Allocate a new operation */ + Operation *op = internal_operation_new(SLAPI_OPERATION_SEARCH, operation_flags); + slapi_pblock_set(int_pbs, SLAPI_OPERATION, op); + + /* Setup the search pb */ + slapi_pblock_set(int_pbs, SLAPI_ORIGINAL_TARGET_DN, (void *)slapi_sdn_get_udn(basedn)); + slapi_pblock_set(int_pbs, SLAPI_TARGET_SDN, (void *)basedn); + slapi_pblock_set(int_pbs, SLAPI_SEARCH_SCOPE, &scope); + slapi_pblock_set(int_pbs, SLAPI_SEARCH_STRFILTER, (void *)filter); + slapi_pblock_set(int_pbs, SLAPI_CONTROLS_ARG, controls); + /* forbidden attrs could be removed in slapi_pblock_set. */ + char **tmp_attrs = slapi_ch_array_dup(attrs); + slapi_pblock_set(int_pbs, SLAPI_SEARCH_ATTRS, tmp_attrs); + slapi_pblock_set(int_pbs, SLAPI_SEARCH_ATTRSONLY, &attrsonly); + slapi_pblock_set(int_pbs, SLAPI_TARGET_UNIQUEID, (void *)uniqueid); + + /* Do the search */ + search_internal_pb(int_pbs); + /* Check the result. */ + + /* Now undefined the pb_search from pb so we can free pb*/ + slapi_v4_search_pblock *pbs = slapi_v4_search_pblock_extract(int_pbs); + slapi_pblock_destroy(int_pbs); + return pbs; +} + +slapi_v4_search_pblock * +slapi_v4_search_internal_all_contexts(int32_t scope, + const char *filter, + char **attrs, + int32_t attrsonly, + LDAPControl **controls, + const char *uniqueid, + int32_t operation_flags) +{ + /* We can use mapping tree to iterate over the suffixes. */ + void *mt_node = NULL; + /* Create a new result */ + slapi_v4_search_pblock *pbs = slapi_v4_search_pblock_create(); + /* Search each of them, building a result set, */ + + slapi_v4_dn *basedn = slapi_get_first_suffix(&mt_node, 0); + while (basedn != NULL) { + /* Search it! */ + slapi_log_error(SLAPI_LOG_DEBUG, "slapi_v4_search_internal_all_contexts", "Searching %s ...\n", slapi_sdn_get_dn(basedn)); + slapi_v4_search_pblock *pbs_inner = slapi_v4_search_internal(basedn, scope, filter, attrs, attrsonly, controls, uniqueid, operation_flags); + slapi_v4_search_pblock_merge(pbs, pbs_inner); + + basedn = slapi_get_next_suffix(&mt_node, 0); + } + /* Return it! */ + return pbs; +} + +slapi_v4_plugin_result * +slapi_v4_entry_exists_or_create(Slapi_DN *dn, const char *filter, const char *entry, const char *modifier_name) { + + /* Search for the entry */ + int32_t attrsonly = 0; + char **attrs = NULL; + + slapi_v4_search_pblock *pb_search_result = slapi_v4_search_internal(dn, LDAP_SCOPE_BASE, filter, attrs, attrsonly, NULL, NULL, 0); + + uint64_t num_results = slapi_v4_search_pblock_get_num_results(pb_search_result); + slapi_v4_search_pblock_destroy(pb_search_result); + + if (num_results == 0) { + slapi_log_error(SLAPI_LOG_DEBUG, "slapi_v4_entry_exists_or_create", "creating entry:\n%s\n", entry); + /* Create the entry */ + + Slapi_Entry *certmap_entry = slapi_str2entry((char *)entry, 0); + if (certmap_entry == NULL) { + return slapi_v4_plugin_result_err(SLAPI_V4_PLUGIN_FAILURE, LDAP_OPERATIONS_ERROR, strdup("Failed to parse entry")); + } + slapi_v4_search_pblock *pb_add_result = slapi_v4_add_internal_entry(certmap_entry, modifier_name); + + if (pb_add_result == NULL) { + return slapi_v4_plugin_result_err(SLAPI_V4_PLUGIN_FAILURE, LDAP_OPERATIONS_ERROR, strdup("Failed to create entry, missing modifier name?")); + } + + int opresult = slapi_v4_search_pblock_get_ldapresult(pb_add_result); + slapi_v4_search_pblock_destroy(pb_add_result); + + if (opresult != LDAP_SUCCESS) { + return slapi_v4_plugin_result_err(SLAPI_V4_PLUGIN_FAILURE, opresult, strdup("Failed to create entry")); + } + } + return slapi_v4_plugin_result_ok(); +} + diff --git a/ldap/servers/slapd/slapi_pal.c b/ldap/servers/slapd/slapi_pal.c index f658d46..457849f 100644 --- a/ldap/servers/slapd/slapi_pal.c +++ b/ldap/servers/slapd/slapi_pal.c @@ -46,6 +46,84 @@ #define CG2_HEADER_FORMAT "0::" #define CG2_HEADER_LEN strlen(CG2_HEADER_FORMAT) +/* + * Memory allocation wrappers + * + * Why do we use these instead of slapi_ch_* types? + * + * The problems that existed that slapi_ch_* were trying to solve don't + * exist anymore. + * + * First, we don't have our memory allocator - no matter what, we can't write + * something better than jemalloc, so don't. + * + * Second, linux lies. while we tried to check for null on ptr return + * and then handle the situation, the situation handlers were broken and + * didn't work, and the check doesn't matter anyway, because linux *always* + * returns a valid pointer to a zero page and it's only on write do we actually + * discover OOM. OOPs! + * + * Third, we tried to wrap calloc to have a number * size, but this means + * that the compiler can't pre-compute values, so we should just use size. + * + * Fourth, even in an OOM scenario, all past experiences and examples show + * we *never* get to this scenario where we can safely handle this, and infact + * we are OOM killed by the kernel first. + * + * Fifth, the slapi_ch types use ulongs not size_t. + * + * Finally, We spent so much time with free (&type) and then checking nulls + * and setting nulls that doesn't matter. free literally handles ptr == null as + * a no-op, and the setting of a pointer to null *does not* help us beside a tiny + * set of datastructure scenarios that we *don't use*. + * + * Thus, we should stop messing about and make these interfaces much lighter + * and simpler. + */ + +void * +spal_calloc(size_t size) { +#ifdef LINUX + return calloc(1, size); +#else + void *ptr = calloc(1, size); + if (ptr == NULL) { + /* + * Just abort - the core will tell us where and why, and there + * is no safe way to shutdown in OOM anyway. + */ + abort(); + } + return ptr; +#endif +} + +void * +spal_realloc(void *ptr, size_t size) { +#ifdef LINUX + return realloc(ptr, size); +#else + void *ptr = realloc(ptr, size); + if (ptr == NULL) { + /* + * Just abort - the core will tell us where and why, and there + * is no safe way to shutdown in OOM anyway. + */ + abort(); + } + return ptr; +#endif +} + +void +spal_free(void *ptr) { + free(ptr); +} + +/* + * Limit management. + */ + static int_fast32_t _spal_rlimit_get(int resource, uint64_t *soft_limit, uint64_t *hard_limit) { diff --git a/ldap/servers/slapd/utf8.c b/ldap/servers/slapd/utf8.c index 92724e9..1c64658 100644 --- a/ldap/servers/slapd/utf8.c +++ b/ldap/servers/slapd/utf8.c @@ -408,3 +408,30 @@ ldap_utf8isspace(char *s) /* should never reach here */ return 0; } + +unsigned char * +ldap_utf8strip(unsigned char *s) { + /* First find the first non-whitespace char */ + size_t first = 0; + size_t last = strlen((char *)s); + + for(; ldap_utf8isspace((char *)(s + first)); first++) { + } + for(; ldap_utf8isspace((char *)(s + last)); last--) { + } + + /* You are so screwed if this is true. */ + if (last <= first) { + return NULL; + } + size_t size = last - first + 1; + if (size == 0) { + return NULL; + } + + unsigned char *out = spal_calloc(size * sizeof(unsigned char)); + snprintf(out, size, "%s", (char *)(s + first)); + + return out; +} + diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c index 7d0dc07..d150f5d 100644 --- a/ldap/servers/slapd/util.c +++ b/ldap/servers/slapd/util.c @@ -479,6 +479,9 @@ replace_char(char *str, char c, char c2) } } +char * +slapi_v4_escape_filter_value(char *filter_str, int len) __attribute__((weak, alias("slapi_escape_filter_value"))); + /* ** This function takes a quoted attribute value of the form "abc", ** and strips off the enclosing quotes. It also deals with quoted From 6416682631f872efe2eee501a5949d8ad979874a Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 16 2020 02:51:03 +0000 Subject: [PATCH 4/11] Ticket 49218 - Certmap - plugin v4 dylib handlers and routines Bug Description: This adds support for pluggable certificate mapping libraries. To achieve this, this replaces the existing baked in certificate mapping code. Fix Description: Add support for opening and managing dylibs transactionally and safely with cow structures. ADditionally this provides the support for txns in operations related to plugin types that require it. https://pagure.io/389-ds-base/issue/49218 https://pagure.io/lib389/issue/95 https://pagure.io/lib389/issue/84 Author: wibrown Review by: ??? --- diff --git a/ldap/servers/slapd/auth.c b/ldap/servers/slapd/auth.c index a2050b9..12e3b7c 100644 --- a/ldap/servers/slapd/auth.c +++ b/ldap/servers/slapd/auth.c @@ -20,334 +20,7 @@ #include /* 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 -#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 /* * Log a certificate that was rejected because the client didn't @@ -365,19 +38,22 @@ handle_bad_certificate(void *clientData, PRFileDesc *prfd) 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 @@ handle_handshake_done(PRFileDesc *prfd, void *clientData) 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 @@ handle_handshake_done(PRFileDesc *prfd, void *clientData) } 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 @@ handle_handshake_done(PRFileDesc *prfd, void *clientData) 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); diff --git a/ldap/servers/slapd/config.c b/ldap/servers/slapd/config.c index 80e5ec4..a3c65a6 100644 --- a/ldap/servers/slapd/config.c +++ b/ldap/servers/slapd/config.c @@ -27,7 +27,7 @@ #include #include -#define MAXARGS 1000 +#include extern int should_detach; extern Slapi_PBlock *repl_pb; @@ -334,14 +334,10 @@ slapd_bootstrap_config(const char *configdir) } #endif /* see if the entry is a child of the plugin base dn */ - if (slapi_sdn_isparent(&plug_dn, - slapi_entry_get_sdn_const(e))) { - if (entry_has_attr_and_value(e, "objectclass", - "nsSlapdPlugin", 0) && - (entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE, - "syntax", 0) || - entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE, - "matchingrule", 0))) { + if (slapi_sdn_isparent(&plug_dn, slapi_entry_get_sdn_const(e))) { + if (entry_has_attr_and_value(e, "objectclass", "nsSlapdPlugin", 0) && + (entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE, "syntax", 0) || + entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE, "matchingrule", 0))) { /* add the syntax/matching scheme rule plugin */ if (plugin_setup(e, 0, 0, 1, returntext)) { slapi_log_err(SLAPI_LOG_ERR, "slapd_bootstrap_config", @@ -351,6 +347,16 @@ slapd_bootstrap_config(const char *configdir) slapi_sdn_done(&plug_dn); goto bail; } + } else if (entry_has_attr_and_value(e, "objectclass", "nsDylibPlugin4", 0)) { + plugin_v4_result p_result = plugin_v4_setup(e); + if (p_result != PLUGIN_V4_SUCCESS) { + slapi_log_err(SLAPI_LOG_ERR, "slapd_bootstrap_config", + "The plugin entry [%s] in the configfile %s was invalid. %d\n", + slapi_entry_get_dn(e), configfile, p_result); + rc = 0; + slapi_sdn_done(&plug_dn); + goto bail; + } } } diff --git a/ldap/servers/slapd/configdse.c b/ldap/servers/slapd/configdse.c index 8c10ad7..54772e7 100644 --- a/ldap/servers/slapd/configdse.c +++ b/ldap/servers/slapd/configdse.c @@ -22,6 +22,7 @@ #include "log.h" #include "slap.h" #include "pw.h" +#include static int check_all_maxdiskspace_and_mlogsize(Slapi_PBlock *pb, LDAPMod **mod, char *returntext); static int is_delete_a_replace(LDAPMod **mods, int mod_count); @@ -368,6 +369,26 @@ load_plugin_entry(Slapi_PBlock *pb __attribute__((unused)), } int +load_plugin_v4_entry(Slapi_PBlock *pb __attribute__((unused)), + Slapi_Entry* e, + Slapi_Entry* ignored __attribute__((unused)), + int *returncode, + char *returntext __attribute__((unused)), + void *arg __attribute__((unused))) +{ + plugin_v4_result p_result = plugin_v4_setup(e); + if (p_result != PLUGIN_V4_SUCCESS) { + slapi_log_err(SLAPI_LOG_ERR, "load_plugin_v4_entry", + "The plugin entry [%s] is invalid. %d\n", + slapi_entry_get_dn(e), p_result); + exit(1); + } + + *returncode = (int)p_result; + return SLAPI_DSE_CALLBACK_OK; +} + +int modify_config_dse(Slapi_PBlock *pb, Slapi_Entry *entryBefore __attribute__((unused)), Slapi_Entry *e, diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c index 006e22d..13d2317 100644 --- a/ldap/servers/slapd/connection.c +++ b/ldap/servers/slapd/connection.c @@ -27,6 +27,8 @@ #include /* for TCP_CORK */ #endif +#include + typedef Connection work_q_item; static void connection_threadmain(void); static void connection_add_operation(Connection *conn, Operation *op); @@ -1594,7 +1596,14 @@ connection_threadmain() g_decr_active_threadcnt(); return; } + /* Get our plugins ready. */ + if (plugin_v4_start_operation() != PLUGIN_V4_SUCCESS) { + slapi_log_err(SLAPI_LOG_CRIT, "connection_threadmain", "Failed to init plugins for operation\n"); + goto done; + } + maxthreads = conn->c_max_threads_per_conn; + more_data = 0; ret = connection_read_operation(conn, op, &tag, &more_data); if ((ret == CONN_DONE) || (ret == CONN_TIMEDOUT)) { @@ -1753,6 +1762,15 @@ connection_threadmain() connection_dispatch_operation(conn, op, pb); done: + /* + * Operation is complete, yield the plugin list. + * Future william: Should plugin tls be part of operation instead? + */ + if (plugin_v4_close_operation() != PLUGIN_V4_SUCCESS) { + /* This is a recoverable error, but may leak memory. */ + slapi_log_err(SLAPI_LOG_CRIT, "connection_threadmain", "closing plugin after operation failed!\n"); + } + if (doshutdown) { pthread_mutex_lock(&(conn->c_mutex)); connection_remove_operation_ext(pb, conn, op); diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c index 772b496..8e3aae7 100644 --- a/ldap/servers/slapd/daemon.c +++ b/ldap/servers/slapd/daemon.c @@ -56,6 +56,8 @@ #include #include "fe.h" +#include + #if defined(ENABLE_LDAPI) #include "getsocketpeer.h" #endif /* ENABLE_LDAPI */ @@ -1228,6 +1230,13 @@ slapd_daemon(daemon_ports_t *ports) */ connection_table_free(the_connection_table); the_connection_table = NULL; + /* + * Shutdown all plugin_v4 components. + */ + if (plugin_v4_shutdown() != PLUGIN_V4_SUCCESS) { + slapi_log_err(SLAPI_LOG_WARNING, "slapd_daemon", + "Unable to cleanly stop plugin v4 subsystem. Some resources may leak ...\n"); + } if (!in_referral_mode) { /* Close SNMP collator after the plugins closed... diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c index b62c6d3..59fbd12 100644 --- a/ldap/servers/slapd/dse.c +++ b/ldap/servers/slapd/dse.c @@ -44,6 +44,8 @@ #include /* provides fsync/close */ +#include + /* #define SLAPI_DSE_DEBUG */ /* define this to force trace log */ /* messages to always be logged */ @@ -1940,6 +1942,10 @@ dse_modify(Slapi_PBlock *pb) /* JCM There should only be one exit point from thi goto done; } } + } else if (slapi_entry_attr_hasvalue(ecc, SLAPI_ATTR_OBJECTCLASS, "nsDylibPlugin4")) { + /* Let the plugin know it's being modified. */ + /* It will work out what actions need to be taken. */ + plugin_v4_modify(ecc); } } } @@ -2156,14 +2162,15 @@ dse_add_plugin(Slapi_Entry *entry, char *returntext) { int rc = LDAP_SUCCESS; - if (!slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, "nsSlapdPlugin") || - !config_get_dynamic_plugins()) { - /* - * This is not a plugin, or we are not allowing dynamic updates. - */ - return rc; + if (slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, "nsSlapdPlugin") && + config_get_dynamic_plugins()) { + rc = plugin_add(entry, returntext, 0 /* not locked */); + } else if (slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, "nsDylibPlugin4")) { + plugin_v4_result result = plugin_v4_add(entry); + if (result != PLUGIN_V4_SUCCESS) { + rc = LDAP_UNWILLING_TO_PERFORM; + } } - rc = plugin_add(entry, returntext, 0 /* not locked */); return rc; } @@ -2176,16 +2183,16 @@ dse_delete_plugin(Slapi_Entry *entry, char *returntext) { int rc = LDAP_SUCCESS; - if (!slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, "nsSlapdPlugin") || - slapi_entry_attr_hasvalue(entry, "nsslapd-PluginEnabled", "off") || + if (slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, "nsSlapdPlugin") && + slapi_entry_attr_hasvalue(entry, "nsslapd-PluginEnabled", "off") && !config_get_dynamic_plugins()) { - /* - * This is not a plugin, this plugin was not enabled to begin with, or we - * are not allowing dynamic updates . - */ - return rc; + rc = plugin_delete(entry, returntext, 0 /* not locked */); + } else if (slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, "nsDylibPlugin4")) { + plugin_v4_result result = plugin_v4_delete(entry); + if (result != PLUGIN_V4_SUCCESS) { + rc = LDAP_UNWILLING_TO_PERFORM; + } } - rc = plugin_delete(entry, returntext, 0 /* not locked */); return rc; } diff --git a/ldap/servers/slapd/fedse.c b/ldap/servers/slapd/fedse.c index 0ad8e87..8df3c35 100644 --- a/ldap/servers/slapd/fedse.c +++ b/ldap/servers/slapd/fedse.c @@ -42,6 +42,7 @@ #include "slap.h" #include "fe.h" #include +#include extern char **getSupportedCiphers(void); extern char **getEnabledCiphers(void); @@ -2535,6 +2536,7 @@ static const char *easter_egg_photos[NUM_EASTER_EGG_PHOTOS + 1]; static struct dse *pfedse = NULL; static int check_plugin_path(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *e, int *returncode, char *returntext, void *arg); +static int check_plugin_v4(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *e, int *returncode, char *returntext, void *arg); static void internal_add_helper(Slapi_Entry *e, int dont_write_file) @@ -2582,6 +2584,9 @@ init_dse_file(const char *configdir, Slapi_DN *config) dse_register_callback(pfedse, DSE_OPERATION_READ, DSE_FLAG_PREOP, config, LDAP_SCOPE_BASE, "(objectclass=*)", load_config_dse, NULL, NULL); + dse_register_callback(pfedse, DSE_OPERATION_READ, DSE_FLAG_PREOP, config, + LDAP_SCOPE_SUBTREE, "(objectclass=nsDylibPlugin4)", + load_plugin_v4_entry, NULL, NULL); slapi_pblock_set(pb, SLAPI_CONFIG_DIRECTORY, (void *)configdir); /* don't write out the file when reading */ @@ -2865,6 +2870,7 @@ setup_internal_backends(char *configdir) dse_register_callback(pfedse, SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, &root, LDAP_SCOPE_BASE, "(objectclass=*)", modify_root_dse, NULL, NULL); dse_register_callback(pfedse, SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, &saslmapping, LDAP_SCOPE_SUBTREE, "(objectclass=nsSaslMapping)", sasl_map_config_modify, NULL, NULL); dse_register_callback(pfedse, SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, &plugins, LDAP_SCOPE_SUBTREE, "(objectclass=nsSlapdPlugin)", check_plugin_path, NULL, NULL); + dse_register_callback(pfedse, SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, &plugins, LDAP_SCOPE_SUBTREE, "(objectclass=nsDylibPlugin4)", check_plugin_v4, NULL, NULL); /* Delete */ dse_register_callback(pfedse, SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, &config, LDAP_SCOPE_BASE, "(objectclass=*)", dont_allow_that, NULL, NULL); @@ -2881,6 +2887,7 @@ setup_internal_backends(char *configdir) /* Add */ dse_register_callback(pfedse, SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, &saslmapping, LDAP_SCOPE_SUBTREE, "(objectclass=nsSaslMapping)", sasl_map_config_add, NULL, NULL); dse_register_callback(pfedse, SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, &plugins, LDAP_SCOPE_SUBTREE, "(objectclass=nsSlapdPlugin)", check_plugin_path, NULL, NULL); + dse_register_callback(pfedse, SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, &plugins, LDAP_SCOPE_SUBTREE, "(objectclass=nsDylibPlugin4)", check_plugin_v4, NULL, NULL); be = be_new_internal(pfedse, "DSE", DSE_BACKEND, &fedse_plugin); be_addsuffix(be, &root); @@ -3026,3 +3033,32 @@ check_plugin_path(Slapi_PBlock *pb __attribute__((unused)), return rc; } + +static int +check_plugin_v4(Slapi_PBlock *pb __attribute__((unused)), + Slapi_Entry* entryBefore, + Slapi_Entry* e, + int *returncode, + char *returntext, + void *arg __attribute__((unused))) +{ + int rc = SLAPI_DSE_CALLBACK_OK; + + plugin_v4_result result = {0}; + + if (e == NULL) { + /* The add case uses entryBefore */ + result = plugin_v4_validate(entryBefore); + } else { + result = plugin_v4_validate(e); + } + /* Validate logs it's own error message for admin. */ + + if (result != PLUGIN_V4_SUCCESS) { + *returncode = LDAP_UNWILLING_TO_PERFORM; + PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid plugin configuration"); + rc = SLAPI_DSE_CALLBACK_ERROR; + } + return rc; +} + diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c index 97af7bb..9a955d2 100644 --- a/ldap/servers/slapd/libglobs.c +++ b/ldap/servers/slapd/libglobs.c @@ -693,8 +693,8 @@ static struct config_get_and_set {CONFIG_SECUREPORT_ATTRIBUTE, config_set_secureport, NULL, 0, (void **)&global_slapdFrontendConfig.secureport, - CONFIG_INT, NULL, NULL, NULL}, - {CONFIG_BASEDN_ATTRIBUTE, config_set_basedn, + CONFIG_INT, NULL, NULL}, + {CONFIG_BASEDN_ATTRIBUTE, config_set_certmap_basedn, NULL, 0, (void **)&global_slapdFrontendConfig.certmap_basedn, CONFIG_STRING, NULL, NULL, NULL /* deletion is not allowed */}, @@ -6611,7 +6611,7 @@ config_get_return_orig_type_switch() } char * -config_get_basedn(void) +config_get_certmap_basedn(void) { slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); char *retVal; @@ -6624,7 +6624,7 @@ config_get_basedn(void) } int -config_set_basedn(const char *attrname, char *value, char *errorbuf, int apply) +config_set_certmap_basedn(const char *attrname, char *value, char *errorbuf, int apply) { int retVal = LDAP_SUCCESS; slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c index 9e5219c..78273b8 100644 --- a/ldap/servers/slapd/main.c +++ b/ldap/servers/slapd/main.c @@ -54,12 +54,14 @@ union semun #include "slapi-plugin.h" #include "prinit.h" #include "snmp_collator.h" -#include "fe.h" /* client_auth_init() */ +#include "fe.h" #include "protect_db.h" #include "getopt_ext.h" #include "fe.h" #include +#include + #ifdef LINUX /* For mallopt. Should be removed soon. */ #include @@ -686,6 +688,15 @@ main(int argc, char **argv) global_plugin_init(); /* + * Initialise the plugin v4 structures and values. + */ + if (plugin_v4_init() != PLUGIN_V4_SUCCESS) { + slapi_log_err(SLAPI_LOG_EMERG, "main", + "Unable to initialise plugin v4 subsystem\n"); + exit(1); + } + + /* * Process the config files. */ if (0 == slapd_bootstrap_config(slapdFrontendConfig->configdir)) { @@ -1020,6 +1031,21 @@ main(int argc, char **argv) task_cleanup(); /* + * This step checks for any updates and changes on upgrade + * specifically, it manages assumptions about what plugins should exist, and their + * configurations, and potentially even the state of configurations on the server + * and their removal and deprecation. + */ + if (upgrade_server() != UPGRADE_SUCCESS) { + return_value = 1; + goto cleanup; + } + + /* init the thread data indexes */ + slapi_td_dn_init(); + slapi_td_plugin_lock_init(); + + /* * Initialize password storage in entry extension. * Need to be initialized before plugin_startall in case stucked * changes are replicated as soon as the replication plugin is started. @@ -1028,6 +1054,10 @@ main(int argc, char **argv) plugin_print_lists(); plugin_startall(argc, argv, NULL /* specific plugin list */); + if (plugin_v4_startall() != PLUGIN_V4_SUCCESS) { + return_value = 1; + goto cleanup; + } compute_plugins_started(); (void) rewriters_init(); if (housekeeping_start((time_t)0, NULL) == NULL) { @@ -1097,6 +1127,7 @@ main(int argc, char **argv) reslimit_cleanup(); vattr_cleanup(); sasl_map_done(); + plugin_v4_destroy(); cleanup: slapi_ch_free_string(&(mcfg.myname)); compute_terminate(); @@ -2894,10 +2925,6 @@ slapd_do_all_nss_ssl_init(int slapd_exemode, int importexport_encrypt, int s_por } } - if (slapd_exemode == SLAPD_EXEMODE_SLAPD) { - client_auth_init(); - } - if (init_ssl && slapd_ssl_init()) { if (force_to_disable_security("SSL", &init_ssl, ports_info)) { return 1; diff --git a/ldap/servers/slapd/operation.c b/ldap/servers/slapd/operation.c index 4dd3481..352b787 100644 --- a/ldap/servers/slapd/operation.c +++ b/ldap/servers/slapd/operation.c @@ -209,6 +209,7 @@ operation_done(Slapi_Operation **op, Connection *conn) factory_destroy_extension(get_operation_object_type(), *op, conn, &((*op)->o_extension)); slapi_sdn_done(&(*op)->o_sdn); slapi_sdn_free(&(*op)->o_target_spec); + (*op)->o_target_spec = NULL; slapi_ch_free_string(&(*op)->o_authtype); if ((*op)->o_searchattrs != NULL) { charray_free((*op)->o_searchattrs); diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c index 7a9578d..88fa468 100644 --- a/ldap/servers/slapd/pblock.c +++ b/ldap/servers/slapd/pblock.c @@ -3956,6 +3956,9 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) if (pblock->pb_op != NULL) { pblock->pb_op->o_results.r.r_search.nentries = *((int *)value); } + _pblock_assert_pb_intop(pblock); + /* We are given an int, need to extend it */ + pblock->pb_intop->pb_plugin_internal_search_num_entries = (uint64_t)(*((int *)value)); break; /* Referrals encountered while iterating over the result set */ case SLAPI_SEARCH_REFERRALS: diff --git a/ldap/servers/slapd/plugin_v4.c b/ldap/servers/slapd/plugin_v4.c new file mode 100644 index 0000000..eaa9aee --- /dev/null +++ b/ldap/servers/slapd/plugin_v4.c @@ -0,0 +1,1171 @@ +/* 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 */ + +/* See also https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html */ + +/* ========================= WARNING ============================ + * UNLESS YOU HAVE READ: + * https://www.kernel.org/doc/Documentation/memory-barriers.txt + * and SERIOUSLY understand it, and how it works you *MUST* not + * edit this file. This section of the code relies on a deep + * understanding of locking and memory barriers. + * ============================================================== + */ + +/* + * A majority of the safety here is provided by the bptree_cow + * which is already well tested and proven safe. We still need to + * understand it's safety properties, so really, read the above + * before you start making wild changes here. + */ + +#include + +/* + * Provides dlopen and related components. + */ +#include + +/* + * Provides SDS datastructures + */ +#include + +/* For realpath */ +#include +#include + +/** + * Plugin v4 types are *always* dynamic, so there is no need for expensive checks + * in this space. + */ + +typedef enum _plugin_v4_type { + PLUGIN_V4_INTERNAL, + PLUGIN_V4_DYLIB, +} plugin_v4_type; + +typedef enum _plugin_v4_state { + /* Says we are running and enabled. */ + PLUGIN_V4_ENABLED, + /* We are enabled, but not yet running, so wait ... */ + PLUGIN_V4_ENABLED_PRESTART, + /* Not running at all. */ + PLUGIN_V4_DISABLE, +} plugin_v4_state; + +typedef struct _dylib_v4 { + char *path; + void *handle; + uint64_t refcount; +} dylib_v4; + +typedef struct _plugin_v4 { + uint64_t precedence; + char *name; + plugin_v4_state state; + plugin_v4_type type; + dylib_v4 *dl_handle; + void *plugin_private; + uint64_t refcount; + slapi_v4_plugin_result *(*start_fn)(void **ctx); + slapi_v4_plugin_result *(*close_fn)(void **ctx); + slapi_v4_plugin_result *(*bind_certmap_fn)(void *ctx, slapi_v4_certmap_pblock *pbc); +} plugin_v4; + +typedef struct _plugin_key_v4 { + uint64_t precedence; + char *name; +} plugin_key_v4; + +typedef enum _plugin_v4_op_proceed { + OP_PROCEED, + OP_TERMINATE, +} plugin_v4_op_proceed; + +typedef struct _plugin_v4_op_ctx { + plugin_v4_op_proceed proceed; + slapi_v4_plugin_result *res; + void *pb; +} plugin_v4_op_ctx; + +typedef slapi_v4_plugin_result *(*slapi_v4_init_ptr)(slapi_v4_plugin_registration *p_register); + +/* + * We store: + * * tree of dlopened values. These last for the LIFETIME of the server + * because we open them with NODELETE. This means if you delete/add a plugin + * we actually use the same in memory library. This solves *real* consistency + * issues. + * * tree of plugin configs. These are *all* the currently loaded plugin configs + * of the server regardless of enable/disable status. + * * + */ + +static sds_bptree_cow_instance *dylib_tree = NULL; +static sds_bptree_cow_instance *plugin_tree = NULL; + +/* + * plugin thread local storage components + * This is used to keep a thread local map of the active plugins making look up + * and access much faster for a txn. + */ + +typedef enum _plugin_v4_op_state { + PLUGIN_V4_OP_INACTIVE, + PLUGIN_V4_OP_RUNNING, +} plugin_v4_op_state; + +static pthread_key_t plugin_v4_tls_key; + +typedef struct _plugin_v4_tls_map { + plugin_v4_op_state state; + uint64_t txnid; + sds_bptree_transaction *rotxn; + sds_bptree_instance *bind_certmap_map; +} plugin_v4_tls_map; + +/* + * These functions manage the thread local storage. Specifically, the are used + * to destroy the trees and used to + */ + +static void +plugin_v4_tls_destroy(void *tls) { + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_tls_destroy", "cleaning thread local storage\n"); + plugin_v4_tls_map *tls_map = (plugin_v4_tls_map *)tls; + if (tls_map != NULL) { + /* Now destroy all the maps that exist */ + sds_bptree_destroy(tls_map->bind_certmap_map); + /* Finally free the value */ + spal_free(tls_map); + } +} + +/* + * Check registration worked. + */ + +static plugin_v4_result +slapi_v4_plugin_registration_validate(slapi_v4_plugin_registration *pr, plugin_v4 *plugin_inst) { + /* + * For a plugin registration to be valid we require: + * * name + * * precedence + * * start + * * close + * otherwise, we can have as many or few hooks after that. + */ + if (pr->sv4_name == NULL || + pr->precedence == 0 || + pr->sv4_start_fn == NULL || + pr->sv4_close_fn == NULL) { + return PLUGIN_V4_INVALID_PLUGIN; + slapi_log_error(SLAPI_LOG_CRIT, "slapi_v4_plugin_registration_validate", "Plugin returned NULL on a critical pointer type.\n"); + } + /* + * Assert our Cn and name match *exactly* + * + * This is how we force single instance (to a point ...) + */ + if (strcmp(plugin_inst->name, pr->sv4_name) != 0) { + slapi_log_error(SLAPI_LOG_CRIT, "slapi_v4_plugin_registration_validate", "Plugin cn differed from config cn. Plugin 'cn=%s' must be named 'cn=%s'.\n", pr->sv4_name, plugin_inst->name); + return PLUGIN_V4_INVALID_PLUGIN; + } + + return PLUGIN_V4_SUCCESS; +} + +/* Plugin key management. */ + +plugin_key_v4 * +plugin_key_extract(plugin_v4 *p) { + plugin_key_v4 *pk = (plugin_key_v4 *)spal_calloc(sizeof(plugin_key_v4)); + pk->precedence = p->precedence; + pk->name = strdup(p->name); + return pk; +} + +char * +plugin_key_name_extract(plugin_v4 *p) { + return strdup(p->name); +} + +static int64_t +plugin_key_cmp_fn(void *a, void *b) { + /* Convert the types. */ + plugin_key_v4 *pka = (plugin_key_v4 *)a; + plugin_key_v4 *pkb = (plugin_key_v4 *)b; + if (pka->precedence != pkb->precedence) { + if (pka->precedence < pkb->precedence) { + return -1; + } else { + return 1; + } + } + /* Same precedence, strcmp them. */ + return (int64_t)strcmp((const char *)pka->name, (const char *)pkb->name); +} + +void * +plugin_key_dup_fn(void *a) { + plugin_key_v4 *pka = (plugin_key_v4 *)a; + plugin_key_v4 *pkn = (plugin_key_v4 *)spal_calloc(sizeof(plugin_key_v4)); + pkn->precedence = pka->precedence; + pkn->name = strdup(pka->name); + return (void *)pkn; +} + +void +plugin_key_free_fn(void *a) { + plugin_key_v4 *pk = (plugin_key_v4 *)a; + spal_free(pk->name); + spal_free(pk); +} + +/* Plugin instance management */ + +/* ========================= WARNING ============================ + * UNLESS YOU HAVE READ: + * https://www.kernel.org/doc/Documentation/memory-barriers.txt + * and SERIOUSLY understand it, and how it works you *MUST* not + * edit this file. This section of the code relies on a deep + * understanding of locking and memory barriers. + * ============================================================== + */ + +static plugin_v4 * +plugin_create() { + plugin_v4 *p = (plugin_v4 *)spal_calloc(sizeof(plugin_v4)); + __atomic_add_fetch_8(&(p->refcount), 1, __ATOMIC_RELAXED); + return p; +} + +static void * +plugin_dup_fn(void *a) { + /* + * During a dup, we need to rc by 1 + * this is thread safe inside of SDS because in a rotxn /wrtxn + * we already hold at least 1 rc for the node to be alive, so + * this can't fail. + */ + plugin_v4 *p = (plugin_v4 *)a; + __atomic_add_fetch_8(&(p->refcount), 1, __ATOMIC_RELAXED); + return a; +} + +static plugin_v4 * +plugin_clone_fn(plugin_v4 *p1) { + plugin_v4 *p_new = plugin_create(); + p_new->precedence = p1->precedence; + p_new->type = p1->type; + p_new->dl_handle = p1->dl_handle; + p_new->start_fn = p1->start_fn; + p_new->close_fn = p1->close_fn; + p_new->bind_certmap_fn = p1->bind_certmap_fn; + return p_new; +} + +static plugin_v4 * +plugin_from_entry(struct slapi_entry *plugin_entry) { + plugin_v4 *plugin_inst = plugin_create(); + plugin_inst->name = slapi_entry_attr_get_charptr(plugin_entry, "cn"); + + char *state = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginEnabled"); + if (strcmp(state, "on") == 0) { + plugin_inst->state = PLUGIN_V4_ENABLED_PRESTART; + } else { + plugin_inst->state = PLUGIN_V4_DISABLE; + } + spal_free(state); + plugin_inst->type = PLUGIN_V4_DYLIB; + + return plugin_inst; +} + +static plugin_v4 * +plugin_lookup_from_entry(sds_bptree_transaction *plugin_wrtxn, struct slapi_entry *plugin_entry) { + char *plugin_key = slapi_entry_attr_get_charptr(plugin_entry, "cn"); + if (plugin_key == NULL) { + return NULL; + } + plugin_v4 *plugin_inst = NULL; + sds_bptree_cow_retrieve(plugin_wrtxn, plugin_key, (void **)&plugin_inst); + /* + * If this fails, plugin_inst is already NULL so we have a course of action .... + */ + + spal_free(plugin_key); + + /* return the entry or NULL */ + return plugin_inst; +} + +static void +plugin_free_fn(void *a) { + /* + * Dec the ref count. If we get to 0, there can be no situation + * in which another dup of us occurs, so we can free here. + */ + plugin_v4 *p = (plugin_v4 *)a; + /* + * this can be relaxed, because to have this pointer the barrier + * must have already been issued, so we don't need another. + */ + uint64_t rc = __atomic_sub_fetch_8(&(p->refcount), 1, __ATOMIC_RELAXED); + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_free_fn", "%s %p refcount %"PRId64" \n", p->name, (void *)p, rc); + if (rc == 0) { + /* + * Now we can free it. + */ + slapi_v4_plugin_result *close_result = p->close_fn(&p->plugin_private); + if (close_result == NULL || close_result->result != SLAPI_V4_PLUGIN_SUCCESS) { + /* What was the error? better handle it .... */ + slapi_log_error(SLAPI_LOG_WARNING, "plugin_free_fn", "recoverable - plugin close failed: %"PRId32" '%s'\n", close_result->ldap_code, close_result->msg); + } + slapi_v4_plugin_result_destroy(close_result); + /* + * IF the plugin state is enabled, call the close fn. + */ + spal_free(p->name); + spal_free(p); + } +} + +/* dylib key management */ + +char * +dylib_key_extract(dylib_v4 *d) { + return strdup(d->path); +} + +/* Shared string comparisons */ + +static int64_t +string_key_cmp_fn(void *a, void *b) { + return (int64_t)strcmp((const char *)a, (const char *)b); +} + +static void * +string_key_dup_fn(void *a) { + return (void *)strdup((char *)a); +} + +static void +string_key_free_fn(void *a) { + spal_free(a); +} + +/* dylib helpers */ + +/* ========================= WARNING ============================ + * UNLESS YOU HAVE READ: + * https://www.kernel.org/doc/Documentation/memory-barriers.txt + * and SERIOUSLY understand it, and how it works you *MUST* not + * edit this file. This section of the code relies on a deep + * understanding of locking and memory barriers. + * ============================================================== + */ + +dylib_v4 * +dylib_create() { + dylib_v4 *d = (dylib_v4 *)spal_calloc(sizeof(dylib_v4)); + __atomic_add_fetch_8(&(d->refcount), 1, __ATOMIC_RELAXED); + return d; +} + +void * +dylib_dup_fn(void *a) { + dylib_v4 *d = (dylib_v4 *)a; + __atomic_add_fetch_8(&(d->refcount), 1, __ATOMIC_RELAXED); + return a; +} + +void +dylib_free_fn(void *a) { + dylib_v4 *d = (dylib_v4 *)a; + uint64_t rc = __atomic_sub_fetch_8(&(d->refcount), 1, __ATOMIC_RELAXED); + if (rc == 0) { + slapi_log_error(SLAPI_LOG_DEBUG, "dylib_free_fn", "freeing dylib at rc 0 - %s\n", d->path); + /* Close the library. */ + dlclose(d->handle); + /* Remember, path is from real path which uses malloc, not slapi_ch* - not that this matters too much ... */ + free(d->path); + spal_free(d); + } +} + +/* + * We then get the txn id, and compare to thread local storage. If they match, + * use the TLS cache. If not, we map the fn types, and build TLS of the event + * types. + * + * This means very little inter-thread contention on the lists, they are protected + * by the same txn as we hold from the tree, fast access etc. + */ + +plugin_v4_result +plugin_v4_init() { + /* + * This pattern leaks if we fail to alloc dylib tree, but if we can't + * alloc it, you are so screwed anyway. + */ + if (sds_bptree_cow_init(&plugin_tree, 0, string_key_cmp_fn, plugin_free_fn, plugin_dup_fn, string_key_free_fn, string_key_dup_fn) != SDS_SUCCESS) { + return PLUGIN_V4_RESOURCE; + } + if (sds_bptree_cow_init(&dylib_tree, 0, string_key_cmp_fn, dylib_free_fn, dylib_dup_fn, string_key_free_fn, string_key_dup_fn) != SDS_SUCCESS) { + return PLUGIN_V4_RESOURCE; + } + /* Create the TLS key for threads to store caches of plugin maps */ + if (pthread_key_create(&plugin_v4_tls_key, plugin_v4_tls_destroy) != 0) { + return PLUGIN_V4_RESOURCE; + } + + return PLUGIN_V4_SUCCESS; +} + +/* + * Finally we free and destroy the tree. This is done after the thread + * pools have stopped. + */ +void +plugin_v4_destroy() { + sds_bptree_cow_destroy(plugin_tree); + sds_bptree_cow_destroy(dylib_tree); +} + +static char * +_plugin_v4_normalise_libpath(char *path) { + char *abs_path = NULL; + char *real_path = NULL; + + if (path[0] != '/') { + /* It's not an abs path already */ + /* + 2 for \0 and / */ + size_t total_len = strlen(path) + strlen(PLUGINDIR) + 2; + abs_path = spal_calloc(total_len); + snprintf(abs_path, total_len, "%s/%s", PLUGINDIR, path); + } else { + /* Already abs, just copy it. */ + abs_path = strdup(path); + } + + /* Do we end in .so (or other platform lib nams we could add here) */ + char *suffix = "-plugin.so"; + size_t suffix_len = strlen(suffix); + size_t abs_path_len = strlen(abs_path); + if (strncmp(abs_path + (abs_path_len - suffix_len), suffix, suffix_len) != 0) { + /* Need to add .so.*/ + size_t total_len = abs_path_len + suffix_len + 1; + char *tmp_abs_path = spal_calloc(total_len); + snprintf(tmp_abs_path, total_len, "%s%s", abs_path, suffix); + spal_free(abs_path); + abs_path = tmp_abs_path; + } + + real_path = realpath(abs_path, NULL); + spal_free(abs_path); + + return real_path; +} + +static plugin_v4_result +_plugin_v4_validate_dylib(struct slapi_entry *plugin_entry, dylib_v4 **d) { + /* Normalise the dl path */ + char *path = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginpath"); + if (path == NULL) { + return PLUGIN_V4_NULL_POINTER; + } + + char *dylib_path = _plugin_v4_normalise_libpath(path); + + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_validate", "normalised to %s\n", dylib_path); + + spal_free(path); + + /* + * IF dylib_path == NULL, then there is NO REAL item in the fs + * that we can access. + */ + if (dylib_path == NULL) { + slapi_log_error(SLAPI_LOG_FATAL, "plugin_v4_validate", "nsslapd-pluginpath: %s does not exist or in inaccesible\n", path); + return PLUGIN_V4_INVALID_CONFIG; + } + + /* + * Does this dylib exist already in our DB? + * We need to do this in a wrtxn because we don't want someone else to try + * and add it while we are looking. + */ + plugin_v4_result final_result = PLUGIN_V4_SUCCESS; + sds_bptree_transaction *dylib_wrtxn; + dylib_v4 *d_tree = NULL; + sds_bptree_cow_wrtxn_begin(dylib_tree, &dylib_wrtxn); + + if (sds_bptree_cow_retrieve(dylib_wrtxn, dylib_path, (void **)&d_tree) == SDS_KEY_PRESENT) { + /* + * It already exists. We don't need to do anything else, we'll + * reuse the handle when it comes to it. + */ + if (d != NULL) { + /* + * provide the handle to our caller. + * normally it's *unsafe* to move out of the txn scope + * but the design of this module dylib tree is additive only + * and we ditch all our refs as we shutdown the plugin trees + * which means moving this out of scope is safe here. + * + * a potential option is to do a dylib dup / free with the plugin? + */ + *d = d_tree; + } + /* AT this point we have succeeded in the check. */ + free(dylib_path); + sds_bptree_cow_wrtxn_abort(&dylib_wrtxn); + } else { + /* It's not in the tree yet. Can we open it? */ + /* Can we open the dylib? */ + void *handle = dlopen(dylib_path, RTLD_NOW|RTLD_LOCAL); + if (handle == NULL) { + sds_bptree_cow_wrtxn_abort(&dylib_wrtxn); + slapi_log_error(SLAPI_LOG_FATAL, "plugin_v4_validate", "Unable to dlopen(%s)\n", dylib_path); + free(dylib_path); + /* okay, we failed here. */ + final_result = PLUGIN_V4_RESOURCE; + } else { + /* We opened the library. Let's put it in the tree. */ + d_tree = dylib_create(); + d_tree->path = dylib_path; + d_tree->handle = handle; + + sds_bptree_cow_insert(dylib_wrtxn, dylib_path, d_tree); + + if (d != NULL) { + *d = d_tree; + } + + sds_bptree_cow_wrtxn_commit(&dylib_wrtxn); + } + } + + return final_result; +} + +plugin_v4_result +plugin_v4_validate(struct slapi_entry *plugin_entry) { + /* Given a plugin entry, validate the configuration. */ + /* + * v3 only checks the dylib works at this point, not the + * actual config. The config is up to the plugin arguably + */ + return _plugin_v4_validate_dylib(plugin_entry, NULL); +} + +/* + * _plugin_v4_create takes a plugin DN and entry, and processes + * it into our plugin tree. + */ +static plugin_v4_result +_plugin_v4_create(sds_bptree_transaction *plugin_wrtxn, struct slapi_entry *plugin_entry, plugin_v4 **plugin_out) { + /* + * Name comes from from_entry. + * validate already confirmed it matches our expectations. + * plugin_inst->name = strdup(p_register->sv4_name); + */ + plugin_v4 *plugin_inst = plugin_from_entry(plugin_entry); + + slapi_v4_init_ptr init_fn_ptr = NULL; + + if (plugin_inst->type == PLUGIN_V4_DYLIB) { + /* First validate the entry */ + dylib_v4 *dl = NULL; + plugin_v4_result result = _plugin_v4_validate_dylib(plugin_entry, &dl); + if (result != PLUGIN_V4_SUCCESS) { + plugin_free_fn((void *)plugin_inst); + return result; + } + /* + * We have a handle to the dl now. Lets check our init function is + * present. + */ + char *init_fn = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugininitfunc"); + if (init_fn == NULL) { + /* Can't init with no fn! */ + plugin_free_fn((void *)plugin_inst); + return PLUGIN_V4_NULL_POINTER; + } + + init_fn_ptr = (slapi_v4_init_ptr)dlsym(dl->handle, init_fn); + spal_free(init_fn); + /* Now stash the dylib lookup */ + plugin_inst->dl_handle = dl; + + } + + if (init_fn_ptr == NULL) { + plugin_free_fn((void *)plugin_inst); + return PLUGIN_V4_INVALID_CONFIG; + } + + /* + * Call the init fn. This is needed to get the fns and precedence. + * this is SAFE to run mulitple times. The wrtxn prevents it being + * run in parallel though. + */ + slapi_v4_plugin_registration *p_register = slapi_v4_plugin_registration_create(); + + slapi_v4_plugin_result *res = init_fn_ptr(p_register); + + if (res->result != SLAPI_V4_PLUGIN_SUCCESS) { + plugin_free_fn((void *)plugin_inst); + slapi_v4_plugin_registration_destroy(p_register); + slapi_log_error(SLAPI_LOG_ERR, "_plugin_v4_create", "Plugin init function failed - %s\n", res->msg); + slapi_v4_plugin_result_destroy(res); + return PLUGIN_V4_INVALID_CONFIG; + } else { + slapi_v4_plugin_result_destroy(res); + } + + + /* + * Validate our plugin registration has enough information. + */ + plugin_v4_result reg_result = slapi_v4_plugin_registration_validate(p_register, plugin_inst); + if (reg_result != PLUGIN_V4_SUCCESS) { + plugin_free_fn((void *)plugin_inst); + slapi_v4_plugin_registration_destroy(p_register); + slapi_log_error(SLAPI_LOG_CRIT, "_plugin_v4_create", "Plugin is registration is invalid, and will not function\n"); + return reg_result; + } + + /* + * Finally, we have enough information now. Lets create the plugin + * object and commit, because we are ready to *rock*. \m/ + */ + plugin_inst->precedence = p_register->precedence; + /* + * For now we only support dylib. + */ + plugin_inst->start_fn = p_register->sv4_start_fn; + plugin_inst->close_fn = p_register->sv4_close_fn; + plugin_inst->bind_certmap_fn = p_register->sv4_bind_certmap_fn; + + /* + * We are done with registration. + */ + slapi_v4_plugin_registration_destroy(p_register); + + /* + * Does this plugin already exist? + * Generate a plugin key, and check. + */ + void *plugin_key = (void*)plugin_key_name_extract(plugin_inst); + sds_result insert_result = sds_bptree_cow_insert(plugin_wrtxn, plugin_key, plugin_inst); + spal_free(plugin_key); + if (insert_result != SDS_SUCCESS) { + plugin_free_fn((void *)plugin_inst); + if (insert_result == SDS_DUPLICATE_KEY) { + /* + * Plugin with this name exists. Need to bail now. Setup *may* try to call this multiple times + * so we just have to ignore it :( + */ + slapi_log_error(SLAPI_LOG_DEBUG, "_plugin_v4_create", "Plugin cn already exists in tree, ignoring ...\n"); + return PLUGIN_V4_DUPLICATE; + } else { + slapi_log_error(SLAPI_LOG_CRIT, "_plugin_v4_create", "Plugin cn failed to be added for an unknown reason.\n"); + return PLUGIN_V4_UNKNOWN; + } + } + + slapi_log_error(SLAPI_LOG_DEBUG, "_plugin_v4_create", "Plugin %s registered correctly\n", plugin_inst->name ); + *plugin_out = plugin_inst; + + return PLUGIN_V4_SUCCESS; +} + +/* + * INTERNAL start and stop. These actually perform the STATE transitions on plugins to move + * them from the "just added" prestart state to enabled or disabled. + */ + +static plugin_v4_result +_plugin_v4_start_trans(plugin_v4 *plugin_inst) { + + /* + * When we get here we should be in PRESTART. Create builds in PRESTART, and add + * does too. If we build "off" we are DISABLE, so we *don't* want to start no + * matter what. + */ + if (plugin_inst->state == PLUGIN_V4_ENABLED || plugin_inst->state == PLUGIN_V4_DISABLE) { + slapi_log_error(SLAPI_LOG_DEBUG, "_plugin_v4_start_trans", "Plugin already enabled or disabled\n"); + return PLUGIN_V4_SUCCESS; + } + + slapi_v4_plugin_result *start_result = plugin_inst->start_fn(&plugin_inst->plugin_private); + + if (start_result == NULL || start_result->result != SLAPI_V4_PLUGIN_SUCCESS) { + /* What was the error? better handle it .... */ + slapi_log_error(SLAPI_LOG_CRIT, "_plugin_v4_start_trans", "plugin start failed: %"PRId32" '%s'\n", start_result->ldap_code, start_result->msg); + return PLUGIN_V4_DUPLICATE; + } else { + plugin_inst->state = PLUGIN_V4_ENABLED; + slapi_log_error(SLAPI_LOG_DEBUG, "_plugin_v4_start_trans", "started %s state %"PRIu32"\n", plugin_inst->name, plugin_inst->state); + } + + slapi_v4_plugin_result_destroy(start_result); + + return PLUGIN_V4_SUCCESS; +} + +static plugin_v4_result +_plugin_v4_close_trans(sds_bptree_transaction *plugin_wrtxn, plugin_v4 *plugin_inst) { + /* + * How does this blackmagic work! Why are you updating and deleting! + * + * So we know that some set of past operations may still be open in the + * tree consuming plugin_inst - so we can *NOT* change it. We need them + * to finish before we call close too. + * + * We exploit the properties of plugin_free_fn, that it calls close + * when the ref count hits 0. So by calling update, this reduces the in + * wrtxn refcount by 1 - so all other references to plugin inst *must* be + * from past generations now. + * + * So either we are the last ref and update will "close" the plugin, or + * we are waiting on older txns - when they close, because we cowed this node, + * the older tree node will be fred, and that will trigger the refcount to drop to + * to 0 as well, which then causes the plugin inst to fall to 0, and the close + * to run. + * + * Lockless thread safety all up in this code mf!!!!! + */ + + plugin_v4_result op_result = PLUGIN_V4_SUCCESS; + + plugin_v4 *plugin_clone = plugin_clone_fn(plugin_inst); + plugin_clone->state = PLUGIN_V4_DISABLE; + + void *plugin_key = (void*)plugin_key_name_extract(plugin_inst); + sds_result update_result = sds_bptree_cow_update(plugin_wrtxn, plugin_key, plugin_clone); + if (update_result != SDS_SUCCESS) { + op_result = PLUGIN_V4_UNKNOWN; + slapi_log_error(SLAPI_LOG_ERR, "_plugin_v4_close_trans", "Failed to disable %s, reverting to enabled.\n", plugin_clone->name); + plugin_free_fn(plugin_clone); + } + string_key_free_fn(plugin_key); + return op_result; +} + +static plugin_v4_result +_plugin_v4_delete_trans(sds_bptree_transaction *plugin_wrtxn, plugin_v4 *plugin_inst) { + /* + * This works on the same principal as close, but uses delete instead. + */ + void *plugin_key = (void*)plugin_key_name_extract(plugin_inst); + sds_result update_result = sds_bptree_cow_delete(plugin_wrtxn, plugin_key); + string_key_free_fn(plugin_key); + if (update_result != SDS_KEY_PRESENT) { + return PLUGIN_V4_UNKNOWN; + } + return PLUGIN_V4_SUCCESS; +} + +static void +plugin_v4_start_cb(void *plugin_key __attribute__((unused)), void *plugin, void *arg __attribute__((unused))) { + plugin_v4 *plugin_inst = (plugin_v4 *)plugin; + _plugin_v4_start_trans(plugin_inst); +} + +/* + * This is the point where everything that's enabled gets moved into the + * actually event proccessing lists. + */ +plugin_v4_result +plugin_v4_startall() { + /* + * For everything in the tree, move the state to enabled from prestart + */ + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_startall", "starting ....\n"); + sds_bptree_transaction *plugin_wrtxn = NULL; + sds_bptree_cow_wrtxn_begin(plugin_tree, &plugin_wrtxn); + + sds_bptree_cow_map(plugin_wrtxn, NULL, plugin_v4_start_cb); + + sds_bptree_cow_wrtxn_commit(&plugin_wrtxn); + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_startall", "started\n"); + return PLUGIN_V4_SUCCESS; +} + +static void +plugin_v4_stop_cb(void *plugin_key __attribute__((unused)), void *plugin, void *arg) { + plugin_v4 *plugin_inst = (plugin_v4 *)plugin; + sds_bptree_transaction *plugin_wrtxn = (sds_bptree_transaction *)arg; + /* + * We *can not* change value or key here, but we can use them to UPDATE + * in the write txn! + */ + _plugin_v4_close_trans(plugin_wrtxn, plugin_inst); +} +/* + * This has mulitple stages. First, we need to let every current user drain + * (hopefully should already be the case). We then clean all the processing lists + * next we ditch all the open plugins configs + * finally, we close everything in the dlopen tree. + */ +plugin_v4_result +plugin_v4_shutdown() { + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_shutdown", "stopping ....\n"); + sds_bptree_transaction *plugin_wrtxn = NULL; + sds_bptree_transaction *plugin_rotxn = NULL; + sds_bptree_cow_wrtxn_begin(plugin_tree, &plugin_wrtxn); + + /* + * Okay, now that we have the wrtxn, we can GUARANTEE no new + * txns will commit after us. So we open a READ txn for the map. + */ + sds_bptree_cow_rotxn_begin(plugin_tree, &plugin_rotxn); + + /* + * Now, we use the rotxn to map the tree because this WILL NOT change + * but within that we pass the wrtxn to the CB to update each key! + */ + sds_bptree_cow_map(plugin_rotxn, plugin_wrtxn, plugin_v4_stop_cb); + + /* + * Now undo in reverse order. + */ + sds_bptree_cow_rotxn_close(&plugin_rotxn); + sds_bptree_cow_wrtxn_commit(&plugin_wrtxn); + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_shutdown", "stopped\n"); + return PLUGIN_V4_SUCCESS; +} + +/* + * When a change to dse is made via cn=config, this picks it up. We know that + * the entry was *modified* only, so we go from there. + */ +plugin_v4_result +plugin_v4_modify(struct slapi_entry *plugin_entry) { + /* + * Update the plugin value, IE replace it. This will effectively call delete then + * add on the plugin. Why? Because this lets the INIT FUNCTION change. + */ + + sds_bptree_transaction *plugin_wrtxn = NULL; + sds_bptree_cow_wrtxn_begin(plugin_tree, &plugin_wrtxn); + + plugin_v4 *plugin_ref = plugin_lookup_from_entry(plugin_wrtxn, plugin_entry); + /* + * IN THEORY this state is impossible, becuase it means we are modify a plugin + * that *is not in the dse*. This *can not happen* but lets be defensive anyway. + */ + if (plugin_ref == NULL) { + sds_bptree_cow_wrtxn_abort(&plugin_wrtxn); + return PLUGIN_V4_UNKNOWN; + } + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_modify", "modifying %s\n", plugin_ref->name); + + plugin_v4_result delete_result = _plugin_v4_delete_trans(plugin_wrtxn, plugin_ref); + if (delete_result != PLUGIN_V4_SUCCESS) { + slapi_log_error(SLAPI_LOG_CRIT, "plugin_v4_modify", "resetting failed, aborting %s\n", plugin_ref->name); + sds_bptree_cow_wrtxn_abort(&plugin_wrtxn); + return delete_result; + } + /* + * May not access plugin ref from here .... + */ + plugin_v4 *plugin_ref_new = NULL; + + plugin_v4_result create_result = _plugin_v4_create(plugin_wrtxn, plugin_entry, &plugin_ref_new); + if (create_result != PLUGIN_V4_SUCCESS) { + slapi_log_error(SLAPI_LOG_CRIT, "plugin_v4_modify", "cow failed, aborting %s\n", plugin_ref_new->name); + sds_bptree_cow_wrtxn_abort(&plugin_wrtxn); + return create_result; + } + + plugin_v4_result enable_result = _plugin_v4_start_trans(plugin_ref_new); + if (enable_result != PLUGIN_V4_SUCCESS) { + slapi_log_error(SLAPI_LOG_CRIT, "plugin_v4_modify", "start failed, aborting %s\n", plugin_ref_new->name); + sds_bptree_cow_wrtxn_abort(&plugin_wrtxn); + } else { + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_modify", "started, commiting %s state : %"PRIu32"\n", plugin_ref->name, plugin_ref_new->state); + sds_bptree_cow_wrtxn_commit(&plugin_wrtxn); + } + + return enable_result; +} + +/* + * This creates the plugin but *does not* start it. + */ +plugin_v4_result +plugin_v4_setup(struct slapi_entry *plugin_entry) { + /* Pelrhaps do this in a txn? */ + /* + * create the txn + */ + sds_bptree_transaction *plugin_wrtxn = NULL; + sds_bptree_cow_wrtxn_begin(plugin_tree, &plugin_wrtxn); + + plugin_v4 *plugin_ref = NULL; + plugin_v4_result create_result = _plugin_v4_create(plugin_wrtxn, plugin_entry, &plugin_ref); + + /* + * Commit or abort. + */ + if (create_result == PLUGIN_V4_SUCCESS) { + /* + * Finally, commit. My plugin is ready. + */ + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_setup", "create commiting %s state: %"PRIu32" \n", plugin_ref->name, plugin_ref->state); + sds_bptree_cow_wrtxn_commit(&plugin_wrtxn); + } else if (create_result == PLUGIN_V4_DUPLICATE) { + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_setup", "create, already exists\n"); + sds_bptree_cow_wrtxn_abort(&plugin_wrtxn); + create_result = PLUGIN_V4_SUCCESS; + } else { + slapi_log_error(SLAPI_LOG_CRIT, "plugin_v4_setup", "create aborting %s \n", plugin_ref->name); + sds_bptree_cow_wrtxn_abort(&plugin_wrtxn); + } + + return create_result; +} + +/* + * This creates the plugin and *does* start it. + */ +plugin_v4_result +plugin_v4_add(struct slapi_entry *plugin_entry) { + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_add", "begin\n"); + /* + * Create the txn + */ + sds_bptree_transaction *plugin_wrtxn = NULL; + sds_bptree_cow_wrtxn_begin(plugin_tree, &plugin_wrtxn); + + plugin_v4 *plugin_ref = NULL; + + plugin_v4_result create_result = _plugin_v4_create(plugin_wrtxn, plugin_entry, &plugin_ref); + if (create_result != PLUGIN_V4_SUCCESS) { + sds_bptree_cow_wrtxn_abort(&plugin_wrtxn); + return create_result; + } + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_add", "adding %s\n", plugin_ref->name); + + plugin_v4_result enable_result = _plugin_v4_start_trans(plugin_ref); + if (enable_result != PLUGIN_V4_SUCCESS) { + slapi_log_error(SLAPI_LOG_CRIT, "plugin_v4_add", "failed to add, aborting %s\n", plugin_ref->name); + sds_bptree_cow_wrtxn_abort(&plugin_wrtxn); + } else { + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_add", "added, commiting %s\n", plugin_ref->name); + sds_bptree_cow_wrtxn_commit(&plugin_wrtxn); + } + return enable_result; +} + +/* + * A plugin was deleted. This means we need to disable it, and then + * let the COW gc do it's job. + */ +plugin_v4_result +plugin_v4_delete(struct slapi_entry *plugin_entry) { + + sds_bptree_transaction *plugin_wrtxn = NULL; + sds_bptree_cow_wrtxn_begin(plugin_tree, &plugin_wrtxn); + + plugin_v4 *plugin_ref = plugin_lookup_from_entry(plugin_wrtxn, plugin_entry); + /* + * IN THEORY this state is impossible, becuase it means we are deleting a plugin + * that *is not in the dse*. This *can not happen* but lets be defensive anyway. + */ + if (plugin_ref == NULL) { + sds_bptree_cow_wrtxn_abort(&plugin_wrtxn); + return PLUGIN_V4_UNKNOWN; + } + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_delete", "removing %s\n", plugin_ref->name); + + plugin_v4_result delete_result = _plugin_v4_delete_trans(plugin_wrtxn, plugin_ref); + if (delete_result != PLUGIN_V4_SUCCESS) { + slapi_log_error(SLAPI_LOG_CRIT, "plugin_v4_delete", "failed to remove, aborting %s\n", plugin_ref->name); + sds_bptree_cow_wrtxn_abort(&plugin_wrtxn); + } else { + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_delete", "removed, commiting %s\n", plugin_ref->name); + sds_bptree_cow_wrtxn_commit(&plugin_wrtxn); + } + /* + * DANGER from here you MUST NOT touch plugin_inst again as it MAY BE FREED. + */ + return delete_result; +} + + +/* + * ===================================================================== + * PLUGIN CALLS HERE + * ===================================================================== + * + * Below this line is where we actually execute plugin callbacks. + * + * The behaviour is that we have a thread local linked list (created by the b+tree) + * of the plugins that are valid for this transaction. This is because our *main* plugin + * tree stores all plugins regardless of state, but the tls bpt stores many smaller + * lists of plugins sorted by PRECEDENCE and NAME, and only adds them if they + * are enabled *and* relevant to the call type. This is why we have many smaller + * maps of plugins here, and we extract them at the start of the operation. + * + * To provide a performant solution, we check if the transaction id we hold + * is the same as the txn id that created the map - if they are we are still valid. + * because txnid is 64bit int, this is never going to conflict. If this valued changes + * we ditch the lists and we build new ones. + * + * The benefit of this is *zero* locking, cache locality, and memory saftey protected + * by the main plugin tree, and we get ordered lists. This makes operation execution + * very fast. + */ + +/* ========================= WARNING ============================ + * UNLESS YOU HAVE READ: + * https://www.kernel.org/doc/Documentation/memory-barriers.txt + * and SERIOUSLY understand it, and how it works you *MUST* not + * edit this file. This section of the code relies on a deep + * understanding of locking and memory barriers. + * ============================================================== + */ + +static void +plugin_v4_bind_certmap_populate_cb(void *key __attribute__((unused)), void *value, void *arg) { + sds_bptree_instance *map = (sds_bptree_instance *)arg; + plugin_v4 *plugin = (plugin_v4 *)value; + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_bind_certmap_populate_cb", "Checking '%s' for state\n", plugin->name); + /* Test if the plugin matches our criteria */ + if (plugin->bind_certmap_fn != NULL && plugin->state == PLUGIN_V4_ENABLED) { + plugin_key_v4 *pkey = plugin_key_extract(plugin); + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_bind_certmap_populate_cb", "Adding '%s' to active map\n", plugin->name); + sds_bptree_insert(map, pkey, plugin); + /* Now free the pkey, bptree clones this. */ + plugin_key_free_fn(pkey); + } else { + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_bind_certmap_populate_cb", "Skipping '%s', either disabled or does not support operation type\n", plugin->name); + } +} + + +plugin_v4_result +plugin_v4_start_operation() { + /* + * This will check the presence of our tls. If it exists + * and is valid, we return it. If it exists and is invalid, we rebuild it. + * if it doesn't existi, we build it. + */ + /* Begin a read transaction */ + sds_bptree_transaction *plugin_rotxn = NULL; + sds_bptree_cow_rotxn_begin(plugin_tree, &plugin_rotxn); + /* extract the txnid */ + uint64_t txnid = sds_bptree_txn_get_id(plugin_rotxn); + /* Get the key */ + plugin_v4_tls_map *tls_map = (plugin_v4_tls_map *)pthread_getspecific(plugin_v4_tls_key); + /* If doesn't exist, create it */ + if (tls_map == NULL) { + tls_map = (plugin_v4_tls_map *)spal_calloc(sizeof(plugin_v4_tls_map)); + tls_map->state = PLUGIN_V4_OP_INACTIVE; + /* + * This is a trick to trigger our update below - since we don't + * match, we'll recreate these lists. + */ + tls_map->txnid = txnid - 1; + pthread_setspecific(plugin_v4_tls_key, (void *)tls_map); + } + if (tls_map->state != PLUGIN_V4_OP_INACTIVE) { + slapi_log_error(SLAPI_LOG_CRIT, "plugin_v4_start_operation", "Invalid state, plugin operation already running\n"); + sds_bptree_cow_rotxn_close(&plugin_rotxn); + return PLUGIN_V4_INVALID_STATE; + } + /* What txn id is it? did we just create? */ + if (tls_map->txnid != txnid) { + /* We differ, so we need to rebuild the txn maps */ + /* Free the existing maps */ + sds_bptree_destroy(tls_map->bind_certmap_map); + /* Now init a new map, and add our plugins that match. */ + sds_bptree_init(&(tls_map->bind_certmap_map), 1, plugin_key_cmp_fn, NULL, plugin_key_free_fn, plugin_key_dup_fn); + /* Now tell our rotxn to map over the values, inserting them to the new bind_certmap_map */ + sds_bptree_cow_map(plugin_rotxn, (void *)tls_map->bind_certmap_map, plugin_v4_bind_certmap_populate_cb); + + /* Now update our txnid */ + tls_map->txnid = txnid; + } + /* Finally stash the rotxn in the tls map for close. */ + tls_map->rotxn = plugin_rotxn; + /* And mark the state as ready. */ + tls_map->state = PLUGIN_V4_OP_RUNNING; + return PLUGIN_V4_SUCCESS; +} + +plugin_v4_result +plugin_v4_close_operation() { + /* Just move the state to done */ + plugin_v4_tls_map *tls_map = (plugin_v4_tls_map *)pthread_getspecific(plugin_v4_tls_key); + if (tls_map == NULL) { + return PLUGIN_V4_INVALID_STATE; + } + tls_map->state = PLUGIN_V4_OP_INACTIVE; + if (sds_bptree_cow_rotxn_close(&(tls_map->rotxn)) != SDS_SUCCESS) { + return PLUGIN_V4_INVALID_STATE; + } + return PLUGIN_V4_SUCCESS; +} + +static void +plugin_v4_call_bind_certmap_cb(void *key __attribute__((unused)), void *value, void *arg) { + plugin_v4_op_ctx *op_ctx = (plugin_v4_op_ctx *)arg; + if (op_ctx->proceed != OP_PROCEED) { + /* A previous operation failed, bail! */ + return; + } + /* Free the previous iterations result */ + slapi_v4_plugin_result_destroy(op_ctx->res); + + plugin_v4 *plugin = (plugin_v4 *)value; + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_call_bind_certmap_cb", "calling bind_certmap function on plugin %s\n", plugin->name); + op_ctx->res = plugin->bind_certmap_fn(plugin->plugin_private, (slapi_v4_certmap_pblock *)op_ctx->pb); + /* Now act on the result. Probably need to hand it to our operation context */ + if (op_ctx->res->result != SLAPI_V4_PLUGIN_SUCCESS) { + slapi_log_error(SLAPI_LOG_WARNING, "plugin_v4_call_bind_certmap_cb", "Plugin %s operation failed reason %s\n", plugin->name, op_ctx->res->msg); + /* In some cases we could send back an ldap result here. */ + op_ctx->proceed = OP_TERMINATE; + } +} + +plugin_v4_result +plugin_v4_call_bind_certmap(slapi_v4_certmap_pblock *pbc) { + slapi_log_error(SLAPI_LOG_DEBUG, "plugin_v4_call_bind_certmap", "calling bind_certmap functions\n"); + /* + * First check the tls + */ + plugin_v4_tls_map *tls_map = (plugin_v4_tls_map *)pthread_getspecific(plugin_v4_tls_key); + if (pbc == NULL || tls_map == NULL || tls_map->state != PLUGIN_V4_OP_RUNNING) { + return PLUGIN_V4_INVALID_STATE; + } + plugin_v4_op_ctx op_ctx = {0}; + op_ctx.proceed = OP_PROCEED; + op_ctx.pb = (void *)pbc; + /* + * Now that we know the TLS is good, access it, and iterate over the bind_certmap_fn types + * We rely on sds map for this + */ + sds_bptree_map(tls_map->bind_certmap_map, &op_ctx, plugin_v4_call_bind_certmap_cb); + /* op_ctx now has a result here */ + /* How can we get a plugin response back out here? Give a ctx? */ + if (op_ctx.res->result == SLAPI_V4_PLUGIN_SUCCESS) { + slapi_v4_plugin_result_destroy(op_ctx.res); + return PLUGIN_V4_SUCCESS; + } else { + slapi_v4_plugin_result_destroy(op_ctx.res); + return PLUGIN_V4_UNKNOWN; + } +} + From 468efdde17ae25a3d4d4c3ef1cf436e09f82d33b Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 16 2020 02:51:03 +0000 Subject: [PATCH 5/11] Ticket 49218 - Certmap - inplace upgrade mechanism Bug Description: This adds support for pluggable certificate mapping libraries. To achieve this, this replaces the existing baked in certificate mapping code. Fix Description: Add an inplace upgrae mechanism that is docker compatible. This is important as we can not rely on the ability of setup-ds.pl -u or other external tool to have been run, this MUST be internal to the server at start up. https://pagure.io/389-ds-base/issue/49218 https://pagure.io/lib389/issue/95 https://pagure.io/lib389/issue/84 Author: wibrown Review by: ??? --- diff --git a/ldap/servers/slapd/upgrade.c b/ldap/servers/slapd/upgrade.c new file mode 100644 index 0000000..ed80090 --- /dev/null +++ b/ldap/servers/slapd/upgrade.c @@ -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 */ + +#include + +/* + * This is called on server startup *before* plugins start + * but after config dse is read for operations. This allows + * us to make internal assertions about the state of the configuration + * at start up, enable plugins, and more. + */ + +static char *modifier_name = "cn=upgrade internal,cn=config"; + +/* + * Ensure that the certmap plugin object exists. If not, + * create and enable it. If it exists and is disabled, + * ignore it. + */ +static upgrade_status +upgrade_137_certmap_exists(void) { + /* Does it exist? */ + char *certmap = strdup("dn: cn=certmap plugin,cn=plugins,cn=config\n" + "objectClass: top\n" + "objectClass: nsDylibPlugin4\n" + "cn: certmap plugin\n" + "nsslapd-pluginpath: libcertmap\n" + "nsslapd-plugininitfunc: certmap_init_fn\n" + "nsslapd-pluginenabled: on"); + + slapi_v4_dn *base_sdn = slapi_v4_sdn_new_from_char_dn("cn=certmap plugin,cn=plugins,cn=config"); + /* If not, create it. */ + slapi_v4_plugin_result *result = slapi_v4_entry_exists_or_create(base_sdn, "(cn=certmap plugin)", certmap, modifier_name); + upgrade_status uresult = UPGRADE_SUCCESS; + + if (result->result != SLAPI_V4_PLUGIN_SUCCESS) { + slapi_log_error(SLAPI_LOG_FATAL, "upgrade_137_certmap_exists", "Failed to create certmap entry: %"PRId32": %s\n", result->ldap_code, result->msg); + uresult = UPGRADE_FAILURE; + } + spal_free(certmap); + slapi_v4_sdn_free(base_sdn); + slapi_v4_plugin_result_destroy(result); + return uresult; +} + +upgrade_status +upgrade_server(void) { + /* Could this iterate over an array of function pointers? */ + if (upgrade_137_certmap_exists() != UPGRADE_SUCCESS) { + return UPGRADE_FAILURE; + } + return UPGRADE_SUCCESS; +} + + From 4809c516c15bddc3cbee122dae2221872f72ebe9 Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 16 2020 02:51:03 +0000 Subject: [PATCH 6/11] Ticket 49218 - Certmap - certmap plugin Bug Description: This adds support for pluggable certificate mapping libraries. To achieve this, this replaces the existing baked in certificate mapping code. Fix Description: An implementation of the static certmap.conf handler, as a plugin using the new api system. https://pagure.io/389-ds-base/issue/49218 https://pagure.io/lib389/issue/95 https://pagure.io/lib389/issue/84 Author: wibrown Review by: ??? --- diff --git a/ldap/servers/plugins/certmap/certmap.c b/ldap/servers/plugins/certmap/certmap.c new file mode 100644 index 0000000..dc010d4 --- /dev/null +++ b/ldap/servers/plugins/certmap/certmap.c @@ -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 + +/* Fopen and snprintf */ +#include +/* To access errors with files */ +#include +/* To convert errno to string errors */ +#include +/* To use regex in our config parser */ +#include + +#define CERT_ATTR_TYPE "userCertificate;binary" +#define CERT_FILTER_SIZE 64 + +typedef struct _certmap_config { + /* There are the fields "certmap " */ + 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\\S*?)\\s+(?P.*)$"; + 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[^\\s#]*?):(?P[^\\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[^\\s#]*?):(?P[^\\s#]*?)\\s+(?P.*)$"; + 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(); +} + diff --git a/lib/ldaputil/certmap.conf b/lib/ldaputil/certmap.conf index 386e100..bc42903 100644 --- a/lib/ldaputil/certmap.conf +++ b/lib/ldaputil/certmap.conf @@ -41,11 +41,14 @@ # empty - set the filter to "objectclass=*" # attr names - a comma separated list of attributes to form the filter # +# 7. basedn is the basedn to search rather than using dncomps. If dncomps +# is specified, basedn is ignored. If basedn is not specified, we use +# nsslapd-certmap-basedn +# -certmap default default +certmap default default +#default:basedn ou=People,dc=example,dc=com #default:DNComps -#default:FilterComps e, uid -#default:verifycert on -#default:CmapLdapAttr certSubjectDN -#default:library -#default:InitFn +#default:FilterComps e, uid +#default:verifycert on +#default:CmapLdapAttr nsCertSubjectDN From 3481a1022401811503c95bec4ec922a38f24a03c Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 16 2020 02:52:14 +0000 Subject: [PATCH 7/11] Ticket 49218 - Certmap - build and schema Bug Description: This adds support for pluggable certificate mapping libraries. To achieve this, this replaces the existing baked in certificate mapping code. Fix Description: Support building the new types, as well as the schema to make cert types core to the server (rather than requiring admins to manually edit schema). https://pagure.io/389-ds-base/issue/49218 https://pagure.io/lib389/issue/95 https://pagure.io/lib389/issue/84 Author: wibrown Review by: ??? --- diff --git a/Makefile.am b/Makefile.am index 4ea239a..87e0355 100644 --- a/Makefile.am +++ b/Makefile.am @@ -153,7 +153,8 @@ AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(GCCSEC_CFLAGS) $(ASAN_CFLAGS) $(MSAN_CFLAGS) $ # 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) @@ -402,6 +403,7 @@ endif 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 @@ dist_noinst_HEADERS = \ 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 @@ dist_noinst_HEADERS = \ 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 @@ dist_noinst_HEADERS = \ 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 @@ pkgconfig_DATA = src/pkgconfig/dirsrv.pc \ 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,6 +1139,7 @@ endif libavl_a_SOURCES = ldap/libraries/libavl/avl.c libavl_a_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) +<<<<<<< HEAD #------------------------ # libldaputil #------------------------ @@ -1158,6 +1156,8 @@ libldaputil_la_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) $(DSINTERNAL_CPPFL libldaputil_la_LIBADD = libslapd.la $(NSS_LINK) $(NSPR_LINK) libldaputil_la_LDFLAGS = $(AM_LDFLAGS) +======= +>>>>>>> Ticket 49218 - Certmap - build and schema #//////////////////////////////////////////////////////////////// # # Dynamic Server Libraries @@ -1447,8 +1447,8 @@ libns_dshttpd_la_SOURCES = lib/libaccess/access_plhash.cpp \ 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 +1467,8 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \ 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 +1512,9 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \ 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 +1537,8 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \ 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 +1553,7 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \ 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 \ @@ -1554,8 +1561,13 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \ ldap/servers/slapd/slapi_pal.c \ $(libavl_a_SOURCES) +<<<<<<< HEAD libslapd_la_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) $(SASL_CFLAGS) @db_inc@ $(KERBEROS_CFLAGS) $(PCRE_CFLAGS) $(SDS_CPPFLAGS) $(SVRCORE_INCLUDES) libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LIBS) $(PCRE_LIBS) $(THREADLIB) $(SYSTEMD_LIBS) libsds.la libsvrcore.la +======= +libslapd_la_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) $(SDS_CPPFLAGS) $(SASL_INCLUDES) @db_inc@ $(SVRCORE_INCLUDES) @kerberos_inc@ @pcre_inc@ +libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(SVRCORE_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LINK) $(PCRE_LINK) $(THREADLIB) $(SYSTEMD_LINK) libsds.la +>>>>>>> Ticket 49218 - Certmap - build and schema libslapd_la_LDFLAGS = $(AM_LDFLAGS) $(SLAPD_LDFLAGS) if RUST_ENABLE @@ -1701,6 +1713,16 @@ libaddn_plugin_la_DEPENDENCIES = libslapd.la 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) @pcre_inc@ +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 #------------------------ # @@ -2285,6 +2307,7 @@ ns_slapd_SOURCES = ldap/servers/slapd/abandon.c \ ldap/servers/slapd/unbind.c \ $(GETSOCKETPEER) +<<<<<<< HEAD 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) \ $(NSPR_LINK) $(SASL_LINK) $(LIBNSL) $(LIBSOCKET) $(THREADLIB) $(SYSTEMD_LIBS) $(EVENT_LINK) @@ -2293,6 +2316,12 @@ ns_slapd_LDADD += $(RNSSLAPD_LIB) ns_slapd_CPPFLAGS += -lssl -lcrypto endif ns_slapd_DEPENDENCIES = libslapd.la libldaputil.la +======= +ns_slapd_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) $(SASL_INCLUDES) $(SVRCORE_INCLUDES) +ns_slapd_LDADD = libnunc-stans.la libslapd.la $(LDAPSDK_LINK) $(NSS_LINK) $(LIBADD_DL) \ + $(NSPR_LINK) $(SASL_LINK) $(SVRCORE_LINK) $(LIBNSL) $(LIBSOCKET) $(THREADLIB) $(SYSTEMD_LINK) $(EVENT_LINK) +ns_slapd_DEPENDENCIES = libslapd.la libnunc-stans.la +>>>>>>> Ticket 49218 - Certmap - build and schema # 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 diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif index d1063a4..49f4180 100644 --- a/ldap/schema/01core389.ldif +++ b/ldap/schema/01core389.ldif @@ -339,3 +339,4 @@ objectClasses: ( 2.16.840.1.113730.3.2.327 NAME 'rootDNPluginConfig' DESC 'Netsc 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' ) diff --git a/ldap/servers/slapd/snmp_collator.c b/ldap/servers/slapd/snmp_collator.c index 3dd3af6..699203b 100644 --- a/ldap/servers/slapd/snmp_collator.c +++ b/ldap/servers/slapd/snmp_collator.c @@ -31,6 +31,9 @@ #include "prcvar.h" #include "plstr.h" +#define SLAPI_PRIVATE_V4_ACKNOWLEDGE +#include + #ifdef HPUX /* HP-UX doesn't define SEM_FAILED like other platforms, so * we define it ourselves. */ From 4a27a7bfe53b61e221d12af9606a647b0cc9d5ed Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 16 2020 02:54:34 +0000 Subject: [PATCH 8/11] Ticket 49218 - Certmap - Remove old certmap types Bug Description: This adds support for pluggable certificate mapping libraries. To achieve this, this replaces the existing baked in certificate mapping code. Fix Description: Remove all un-needed certmap types and examples. https://pagure.io/389-ds-base/issue/49218 https://pagure.io/lib389/issue/95 https://pagure.io/lib389/issue/84 Author: wibrown Review by: ??? --- diff --git a/lib/ldaputil/.cvsignore b/lib/ldaputil/.cvsignore deleted file mode 100644 index e7b97c5..0000000 --- a/lib/ldaputil/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -.depends diff --git a/lib/ldaputil/cert.c b/lib/ldaputil/cert.c deleted file mode 100644 index 6c351af..0000000 --- a/lib/ldaputil/cert.c +++ /dev/null @@ -1,504 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - - -#include -/* This was malloc.h - but it's moved to stdlib.h on most platforms, and FBSD is strict */ -/* Make it stdlib.h, and revert to malloc.h with ifdefs if we have issues here. WB 2016 */ -#include - -/* removed for ns security integration -#include -*/ -#include "prmem.h" -#include -#include -#include -#include -#include -#include -#include "ldaputili.h" - -#include "slapi-plugin.h" - -NSAPI_PUBLIC int -ldapu_get_cert(void *SSLendpoint __attribute__((unused)), void **cert __attribute__((unused))) -{ - /* TEMPORARY -- not implemented yet*/ - return LDAPU_FAILED; -} - - -NSAPI_PUBLIC int -ldapu_get_cert_subject_dn(void *cert_in, char **subjectDN) -{ - CERTCertificate *cert = (CERTCertificate *)cert_in; - char *cert_subject = CERT_NameToAscii(&cert->subject); - - if (cert_subject != NULL) - *subjectDN = strdup(cert_subject); - else - *subjectDN = NULL; - - PR_Free(cert_subject); - return *subjectDN ? LDAPU_SUCCESS : LDAPU_ERR_EXTRACT_SUBJECTDN_FAILED; -} - -/* - * Return the Issuer DN as a CERTName. - * The CERTName is owned by the CERTCertificate. - */ -NSAPI_PUBLIC CERTName * -ldapu_get_cert_issuer_dn_as_CERTName(CERTCertificate *cert_in) -{ - return &cert_in->issuer; -} - -/* - * Return the Issuer DN as a string. - * The string should be freed by the caller. - */ -NSAPI_PUBLIC int -ldapu_get_cert_issuer_dn(void *cert_in, char **issuerDN) -{ - *issuerDN = NULL; - CERTName *dn = ldapu_get_cert_issuer_dn_as_CERTName((CERTCertificate *)cert_in); - if (dn != NULL) { - char *cert_issuer = CERT_NameToAscii(dn); - *issuerDN = strdup(cert_issuer); - PR_Free(cert_issuer); - } - return *issuerDN ? LDAPU_SUCCESS : LDAPU_ERR_EXTRACT_ISSUERDN_FAILED; -} - -NSAPI_PUBLIC int -ldapu_get_cert_der(void *cert_in, unsigned char **der, unsigned int *len) -{ - CERTCertificate *cert = (CERTCertificate *)cert_in; - SECItem derCert = ((CERTCertificate *)cert)->derCert; - unsigned char *data = derCert.data; - - *len = derCert.len; - *der = (unsigned char *)malloc(*len); - - if (!*der) - return LDAPU_ERR_OUT_OF_MEMORY; - - memcpy(*der, data, *len); - - return *len ? LDAPU_SUCCESS : LDAPU_ERR_EXTRACT_DERCERT_FAILED; -} - -static int -certmap_name_to_secoid(const char *str) -{ - if (!ldapu_strcasecmp(str, "c")) - return SEC_OID_AVA_COUNTRY_NAME; - if (!ldapu_strcasecmp(str, "o")) - return SEC_OID_AVA_ORGANIZATION_NAME; - if (!ldapu_strcasecmp(str, "cn")) - return SEC_OID_AVA_COMMON_NAME; - if (!ldapu_strcasecmp(str, "l")) - return SEC_OID_AVA_LOCALITY; - if (!ldapu_strcasecmp(str, "st")) - return SEC_OID_AVA_STATE_OR_PROVINCE; - if (!ldapu_strcasecmp(str, "ou")) - return SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME; - if (!ldapu_strcasecmp(str, "uid")) - return SEC_OID_RFC1274_UID; - if (!ldapu_strcasecmp(str, "e")) - return SEC_OID_PKCS9_EMAIL_ADDRESS; - if (!ldapu_strcasecmp(str, "mail")) - return SEC_OID_RFC1274_MAIL; - if (!ldapu_strcasecmp(str, "dc")) - return SEC_OID_AVA_DC; - - return SEC_OID_AVA_UNKNOWN; /* return invalid OID */ -} - -NSAPI_PUBLIC int -ldapu_get_cert_ava_val(void *cert_in, int which_dn, const char *attr, char ***val_out) -{ - CERTCertificate *cert = (CERTCertificate *)cert_in; - CERTName *cert_dn; - CERTRDN **rdns; - CERTRDN **rdn; - CERTAVA **avas; - CERTAVA *ava; - int attr_tag = certmap_name_to_secoid(attr); - char **val; - char **ptr; - int rv; - - *val_out = 0; - - if (attr_tag == SEC_OID_AVA_UNKNOWN) { - return LDAPU_ERR_INVALID_ARGUMENT; - } - - if (which_dn == LDAPU_SUBJECT_DN) - cert_dn = &cert->subject; - else if (which_dn == LDAPU_ISSUER_DN) - cert_dn = &cert->issuer; - else - return LDAPU_ERR_INVALID_ARGUMENT; - - val = (char **)malloc(32 * sizeof(char *)); - - if (!val) - return LDAPU_ERR_OUT_OF_MEMORY; - - ptr = val; - - rdns = cert_dn->rdns; - - if (rdns) { - for (rdn = rdns; *rdn; rdn++) { - avas = (*rdn)->avas; - while ((ava = *avas++) != NULL) { - int tag = CERT_GetAVATag(ava); - - if (tag == attr_tag) { - char buf[BIG_LINE]; - int lenLen; - int vallen; - /* Found it */ - - /* Copied from ns/lib/libsec ... - * XXX this code is incorrect in general - * -- should use a DER template. - */ - lenLen = 2; - if (ava->value.len >= 128) - lenLen = 3; - vallen = ava->value.len - lenLen; - - rv = CERT_RFC1485_EscapeAndQuote(buf, - BIG_LINE, - (char *)ava->value.data + lenLen, - vallen); - - if (rv == SECSuccess) { - *ptr++ = strdup(buf); - } - break; - } - } - } - } - - *ptr = 0; - - if (*val) { - /* At least one value found */ - *val_out = val; - rv = LDAPU_SUCCESS; - } else { - free(val); - rv = LDAPU_FAILED; - } - - return rv; -} - -static void -_rdns_free(char ***rdns) -{ - auto char ***rdn; - for (rdn = rdns; *rdn; ++rdn) { - slapi_ldap_value_free(*rdn); - } - free(rdns); -} - -static char *** -_explode_dn(const char *dn) -{ - auto char ***exp = NULL; - if (dn && *dn) { - auto char **rdns = slapi_ldap_explode_dn(dn, 0); - if (rdns) { - auto size_t expLen = 0; - auto char **rdn; - for (rdn = rdns; *rdn; ++rdn) { - auto char **avas = slapi_ldap_explode_rdn(*rdn, 0); - if (avas && *avas) { - exp = (char ***)ldapu_realloc(exp, sizeof(char **) * (expLen + 2)); - if (exp) { - exp[expLen++] = avas; - } else { - slapi_ldap_value_free(avas); - break; - } - } else { /* parse error */ - if (avas) { - slapi_ldap_value_free(avas); - } - if (exp) { - exp[expLen] = NULL; - _rdns_free(exp); - exp = NULL; - } - break; - } - } - if (exp) { - exp[expLen] = NULL; - } - slapi_ldap_value_free(rdns); - } - } - return exp; -} - -static size_t -_rdns_count(char ***rdns) -{ - auto size_t count = 0; - auto char ***rdn; - for (rdn = rdns; *rdn; ++rdn) { - auto char **ava; - for (ava = *rdn; *ava; ++ava) { - ++count; - } - } - return count; -} - -static int -_replaceAVA(char *attr, char **avas) -{ - if (attr && avas) { - for (; *avas; ++avas) { - if (!ldapu_strcasecmp(*avas, attr)) { - *avas = attr; - return 1; - } - } - } - return 0; -} - -struct _attr_getter_pair -{ -#if NSS_VMAJOR < 3 || (NSS_VMAJOR == 3 && NSS_VMINOR < 15) - char *(*getter)(CERTName *dn); -#else - /* in 3.15.x "const" was added to the declarations */ - char *(*getter)(const CERTName *dn); -#endif - const char *name1; - const char *name2; -} _attr_getter_table[] = - { - {NULL, "OU", "organizationalUnitName"}, - {CERT_GetOrgName, "O", "organizationName"}, - {CERT_GetCommonName, "CN", "commonName"}, - {CERT_GetCertEmailAddress, "E", NULL}, - {CERT_GetCertEmailAddress, "MAIL", "rfc822mailbox"}, - {CERT_GetCertUid, "uid", NULL}, - {CERT_GetCountryName, "C", "country"}, - {CERT_GetStateName, "ST", "state"}, - {CERT_GetLocalityName, "L", "localityName"}, - {CERT_GetDomainComponentName, "DC", "dc"}, - {NULL, NULL, NULL}}; - -static int -_is_OU(const char *attr) -{ - auto struct _attr_getter_pair *descAttr; - for (descAttr = _attr_getter_table; descAttr->name1; ++descAttr) { - if (descAttr->getter == NULL) { /* OU attribute */ - if (!ldapu_strcasecmp(attr, descAttr->name1) || (descAttr->name2 && - !ldapu_strcasecmp(attr, descAttr->name2))) { - return 1; - } - break; - } - } - return 0; -} - -static char ** -_previous_OU(char **ava, char **avas) -{ - while (ava != avas) { - --ava; - if (_is_OU(*ava)) { - return ava; - } - } - return NULL; -} - -static char * -_value_normalize(char *value) -/* Remove leading and trailing spaces, and - change consecutive spaces to a single space. - */ -{ - auto char *t; - auto char *f; - t = f = value; - while (*f == ' ') - ++f; /* ignore leading spaces */ - for (; *f; ++f) { - if (*f != ' ' || t[-1] != ' ') { - *t++ = *f; /* no consecutive spaces */ - } - } - if (t > value && t[-1] == ' ') { - --t; /* ignore trailing space */ - } - *t = '\0'; - return value; -} - -static int -_explode_AVA(char *AVA) -/* Change an attributeTypeAndValue a la , - to the type name, followed immediately by the attribute value, - both normalized. - */ -{ - auto char *value = strchr(AVA, '='); - if (!value) - return LDAPU_FAILED; - *value++ = '\0'; - _value_normalize(AVA); - _value_normalize(value); - { - auto char *typeEnd = AVA + strlen(AVA); - if ((typeEnd + 1) != value) { - memmove(typeEnd + 1, value, strlen(value) + 1); - } - } - return LDAPU_SUCCESS; -} - -static char * -_AVA_value(char *AVA) -{ - return (AVA + strlen(AVA) + 1); -} - -static int -_value_match(char *value, char *desc) -{ - auto const int result = - !ldapu_strcasecmp(_value_normalize(value), desc); - return result; -} - -int -ldapu_member_certificate_match(void *cert, const char *desc) -/* - * Return Values: (same as ldapu_find) - * LDAPU_SUCCESS cert matches desc - * LDAPU_FAILED cert doesn't match desc - * Something went wrong. - */ -{ - auto int err = LDAPU_FAILED; - auto char ***descRDNs; - if (!cert || !desc || desc[0] != '{') - return LDAPU_FAILED; - if (desc[1] == '\0') - return LDAPU_SUCCESS; /* no AVAs */ - descRDNs = _explode_dn(desc + 1); - if (descRDNs) { - auto char **descAVAs = (char **)ldapu_malloc(sizeof(char *) * (_rdns_count(descRDNs) + 1)); - if (!descAVAs) { - err = LDAPU_ERR_OUT_OF_MEMORY; - } else { - auto CERTName *subject = &(((CERTCertificate *)cert)->subject); - auto char **descAVA; - - err = LDAPU_SUCCESS; - { /* extract all the AVAs, but not duplicate types, except OU */ - auto size_t descAVAsLen = 0; - auto char ***descRDN; - descAVAs[0] = NULL; - for (descRDN = descRDNs; err == LDAPU_SUCCESS && *descRDN; ++descRDN) { - for (descAVA = *descRDN; err == LDAPU_SUCCESS && *descAVA; ++descAVA) { - err = _explode_AVA(*descAVA); - if (err == LDAPU_SUCCESS) { - if (_is_OU(*descAVA) || - !_replaceAVA(*descAVA, descAVAs)) { - descAVAs[descAVAsLen++] = *descAVA; - descAVAs[descAVAsLen] = NULL; - } - } - } - } - } - - /* match all the attributes except OU */ - for (descAVA = descAVAs; err == LDAPU_SUCCESS && *descAVA; ++descAVA) { - auto struct _attr_getter_pair *descAttr; - err = LDAPU_FAILED; /* if no match */ - for (descAttr = _attr_getter_table; descAttr->name1; ++descAttr) { - if (!ldapu_strcasecmp(*descAVA, descAttr->name1) || (descAttr->name2 && - !ldapu_strcasecmp(*descAVA, descAttr->name2))) { - if (descAttr->getter == NULL) { /* OU attribute */ - err = LDAPU_SUCCESS; /* for now */ - } else { - auto char *certVal = (*(descAttr->getter))(subject); - if (certVal && _value_match(certVal, _AVA_value(*descAVA))) { - err = LDAPU_SUCCESS; - } - PR_Free(certVal); - } - break; - } - } - } - - /* match the OU attributes */ - if (err == LDAPU_SUCCESS && descAVA != descAVAs) { - /* Iterate over the OUs in the certificate subject */ - auto CERTRDN **certRDN = subject->rdns; - descAVA = _previous_OU(descAVA, descAVAs); - for (; descAVA && *certRDN; ++certRDN) { - auto CERTAVA **certAVA = (*certRDN)->avas; - for (; descAVA && *certAVA; ++certAVA) { - auto const int tag = CERT_GetAVATag(*certAVA); - if (tag == SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME) { - auto const size_t certValLen = (*certAVA)->value.len; - auto const size_t lenLen = (certValLen < 128) ? 2 : 3; - auto const size_t buflen = certValLen - lenLen; - auto char *buf = (char *)ldapu_malloc(buflen + 1); - if (!buf) { - err = LDAPU_ERR_OUT_OF_MEMORY; - descAVA = NULL; - } else { - memcpy(buf, (*certAVA)->value.data + lenLen, buflen); - buf[buflen] = 0; - if (_value_match(buf, _AVA_value(*descAVA))) { - descAVA = _previous_OU(descAVA, descAVAs); - } - free(buf); - } - } - } - } - if (descAVA) { - err = LDAPU_FAILED; /* no match for descAVA in subject */ - } - } - free(descAVAs); - } - _rdns_free(descRDNs); - } - return err; -} diff --git a/lib/ldaputil/certmap.c b/lib/ldaputil/certmap.c deleted file mode 100644 index dc2fdde..0000000 --- a/lib/ldaputil/certmap.c +++ /dev/null @@ -1,1612 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - - -#include -#include -#include -/* This was malloc.h - but it's moved to stdlib.h on most platforms, and FBSD is strict */ -/* Make it stdlib.h, and revert to malloc.h with ifdefs if we have issues here. WB 2016 */ -#include - -/* removed for ns security integration -#include -*/ -#include -#include -#include - -#include -#include -#define DEFINE_LDAPU_STRINGS 1 -#include -#include -#include -#include -#include "ldaputili.h" - -#ifndef BIG_LINE -#define BIG_LINE 1024 -#endif - -/* This is hack, the function is defined in cert/alg1485.c */ -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif - -static char this_dllname[256]; -static const char *LIB_DIRECTIVE = "certmap"; -static const int LIB_DIRECTIVE_LEN = 7; /* strlen("LIB_DIRECTIVE") */ - -static void *ldapu_propval_free(void *propval_in, void *arg); - -typedef struct -{ - FILE *fp; - void *arg; -} LDAPUPrintInfo_t; - -static LDAPUCertMapListInfo_t *certmap_listinfo = 0; -static LDAPUCertMapInfo_t *default_certmap_info = 0; - -static const char *certmap_attrs[] = { - 0, - 0, - 0, - 0}; - -const long CERTMAP_BIT_POS_UNKNOWN = 0; /* unknown OID */ -const long CERTMAP_BIT_POS_CN = 1L << 1; /* Common Name */ -const long CERTMAP_BIT_POS_OU = 1L << 2; /* Organization unit */ -const long CERTMAP_BIT_POS_O = 1L << 3; /* Organization */ -const long CERTMAP_BIT_POS_C = 1L << 4; /* Country */ -const long CERTMAP_BIT_POS_L = 1L << 5; /* Locality */ -const long CERTMAP_BIT_POS_ST = 1L << 6; /* State or Province */ -const long CERTMAP_BIT_POS_MAIL = 1L << 7; /* E-mail Address */ -const long CERTMAP_BIT_POS_UID = 1L << 8; /* UID */ -const long CERTMAP_BIT_POS_DC = 1L << 9; /* DC */ - -const int SEC_OID_AVA_UNKNOWN = 0; /* unknown OID */ - -static long -certmap_secoid_to_bit_pos(int oid) -{ - switch (oid) { - case SEC_OID_AVA_COUNTRY_NAME: - return CERTMAP_BIT_POS_C; - case SEC_OID_AVA_ORGANIZATION_NAME: - return CERTMAP_BIT_POS_O; - case SEC_OID_AVA_COMMON_NAME: - return CERTMAP_BIT_POS_CN; - case SEC_OID_AVA_LOCALITY: - return CERTMAP_BIT_POS_L; - case SEC_OID_AVA_STATE_OR_PROVINCE: - return CERTMAP_BIT_POS_ST; - case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: - return CERTMAP_BIT_POS_OU; - case SEC_OID_RFC1274_UID: - return CERTMAP_BIT_POS_UID; - /* Map "E" and "MAIL" to the same bit position */ - case SEC_OID_PKCS9_EMAIL_ADDRESS: - return CERTMAP_BIT_POS_MAIL; - case SEC_OID_RFC1274_MAIL: - return CERTMAP_BIT_POS_MAIL; - case SEC_OID_AVA_DC: - return CERTMAP_BIT_POS_DC; - default: - return CERTMAP_BIT_POS_UNKNOWN; - } -} - -static const char * -certmap_secoid_to_name(int oid) -{ - switch (oid) { - case SEC_OID_AVA_COUNTRY_NAME: - return "C"; - case SEC_OID_AVA_ORGANIZATION_NAME: - return "O"; - case SEC_OID_AVA_COMMON_NAME: - return "CN"; - case SEC_OID_AVA_LOCALITY: - return "L"; - case SEC_OID_AVA_STATE_OR_PROVINCE: - return "ST"; - case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: - return "OU"; - case SEC_OID_RFC1274_UID: - return "UID"; - /* Map both 'e' and 'mail' to 'mail' in LDAP */ - case SEC_OID_PKCS9_EMAIL_ADDRESS: - return "MAIL"; - case SEC_OID_RFC1274_MAIL: - return "MAIL"; - case SEC_OID_AVA_DC: - return "DC"; - default: - return 0; - } -} - -static void -tolower_string(char *str) -{ - if (str) { - while (*str) { - *str = tolower(*str); - str++; - } - } -} - -static long -certmap_name_to_bit_pos(const char *str) -{ - if (!ldapu_strcasecmp(str, "c")) - return CERTMAP_BIT_POS_C; - if (!ldapu_strcasecmp(str, "o")) - return CERTMAP_BIT_POS_O; - if (!ldapu_strcasecmp(str, "cn")) - return CERTMAP_BIT_POS_CN; - if (!ldapu_strcasecmp(str, "l")) - return CERTMAP_BIT_POS_L; - if (!ldapu_strcasecmp(str, "st")) - return CERTMAP_BIT_POS_ST; - if (!ldapu_strcasecmp(str, "ou")) - return CERTMAP_BIT_POS_OU; - if (!ldapu_strcasecmp(str, "uid")) - return CERTMAP_BIT_POS_UID; - /* Map "E" and "MAIL" to the same bit position */ - if (!ldapu_strcasecmp(str, "e")) - return CERTMAP_BIT_POS_MAIL; - if (!ldapu_strcasecmp(str, "mail")) - return CERTMAP_BIT_POS_MAIL; - if (!ldapu_strcasecmp(str, "dc")) - return CERTMAP_BIT_POS_DC; - - return CERTMAP_BIT_POS_UNKNOWN; -} - -#if 0 /* may need this in the future */ -static int certmap_name_to_secoid (const char *str) -{ - if (!ldapu_strcasecmp(str, "c")) return SEC_OID_AVA_COUNTRY_NAME; - if (!ldapu_strcasecmp(str, "o")) return SEC_OID_AVA_ORGANIZATION_NAME; - if (!ldapu_strcasecmp(str, "cn")) return SEC_OID_AVA_COMMON_NAME; - if (!ldapu_strcasecmp(str, "l")) return SEC_OID_AVA_LOCALITY; - if (!ldapu_strcasecmp(str, "st")) return SEC_OID_AVA_STATE_OR_PROVINCE; - if (!ldapu_strcasecmp(str, "ou")) return SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME; - if (!ldapu_strcasecmp(str, "uid")) return SEC_OID_RFC1274_UID; - if (!ldapu_strcasecmp(str, "e")) return SEC_OID_PKCS9_EMAIL_ADDRESS; - if (!ldapu_strcasecmp(str, "mail")) return SEC_OID_RFC1274_MAIL; - if (!ldapu_strcasecmp(str, "dc")) return SEC_OID_AVA_DC; - - return SEC_OID_AVA_UNKNOWN; /* return invalid OID */ -} -#endif - -NSAPI_PUBLIC int -ldapu_list_alloc(LDAPUList_t **list) -{ - *list = (LDAPUList_t *)calloc(1, sizeof(LDAPUList_t)); - - if (!*list) - return LDAPU_ERR_OUT_OF_MEMORY; - - return LDAPU_SUCCESS; -} - -static int -ldapu_list_add_node(LDAPUList_t *list, LDAPUListNode_t *node) -{ - if (list->head) { - node->prev = list->tail; - list->tail->next = node; - } else { - node->prev = 0; - list->head = node; - } - - node->next = 0; - list->tail = node; - return LDAPU_SUCCESS; -} - -NSAPI_PUBLIC int -ldapu_list_add_info(LDAPUList_t *list, void *info) -{ - LDAPUListNode_t *node; - - /* Allocate the list node and set info in the node. */ - node = (LDAPUListNode_t *)calloc(1, sizeof(LDAPUListNode_t)); - - if (!node) { - return LDAPU_ERR_OUT_OF_MEMORY; - } - - node->info = info; - - return ldapu_list_add_node(list, node); -} - - -static void -ldapu_list_free(LDAPUList_t *list, LDAPUListNodeFn_t free_fn) -{ - if (list) { - auto LDAPUListNode_t *node = list->head; - while (node) { - auto LDAPUListNode_t *next = node->next; - if (free_fn) { - (*free_fn)(node->info, 0); - node->info = 0; - } - node->info = 0; - free(node); - node = next; - } - list->head = 0; - list->tail = 0; - } - return; -} - -NSAPI_PUBLIC int -ldapu_propval_alloc(const char *prop, const char *val, LDAPUPropVal_t **propval) -{ - *propval = (LDAPUPropVal_t *)malloc(sizeof(LDAPUPropVal_t)); - - if (!*propval) - return LDAPU_ERR_OUT_OF_MEMORY; - - (*propval)->prop = prop ? strdup(prop) : 0; - (*propval)->val = val ? strdup(val) : 0; - - if ((!prop || (*propval)->prop) && (!val || (*propval)->val)) { - /* strdup worked */ - return LDAPU_SUCCESS; - } else { - return LDAPU_ERR_OUT_OF_MEMORY; - } -} - - -static int -PresentInComps(long comps_bitmask, int tag) -{ - long bit = certmap_secoid_to_bit_pos(tag); - - if (comps_bitmask & bit) - return 1; - else - return 0; -} - - -static int -dbconf_to_certmap_err(int err) -{ - switch (err) { - case LDAPU_ERR_DBNAME_IS_MISSING: - return LDAPU_ERR_CANAME_IS_MISSING; - case LDAPU_ERR_PROP_IS_MISSING: - return LDAPU_ERR_CAPROP_IS_MISSING; - default: - return err; - } -} - -/* CAUTION: this function hijacks some substructures from db_info and make - * the pointers to it NULL in the db_info. It is safe to deallocate db_info. - */ -static int -dbinfo_to_certinfo(DBConfDBInfo_t *db_info, - LDAPUCertMapInfo_t **certinfo_out) -{ - LDAPUCertMapInfo_t *certinfo = NULL; - LDAPUPropValList_t *propval_list = NULL; - int rv = LDAPU_SUCCESS; - - *certinfo_out = 0; - - certinfo = (LDAPUCertMapInfo_t *)calloc(1, sizeof(LDAPUCertMapInfo_t)); - - if (!certinfo) { - rv = LDAPU_ERR_OUT_OF_MEMORY; - goto error; - } - - /* hijack few structures rather then copy. Make the pointers to the - structures NULL in the original structure so that they don't freed up - when db_info is freed. */ - certinfo->issuerName = db_info->dbname; - db_info->dbname = 0; - - /* Parse the Issuer DN. */ - certinfo->issuerDN = CERT_AsciiToName(db_info->url); - if (NULL == certinfo->issuerDN /* invalid DN */ - && ldapu_strcasecmp(db_info->url, "default") != 0 /* not "default" */) { - rv = LDAPU_ERR_MALFORMED_SUBJECT_DN; - goto error; - } - - /* hijack actual prop-vals from dbinfo -- to avoid strdup calls */ - if (db_info->firstprop) { - LDAPUPropVal_t *propval; - DBPropVal_t *dbpropval; - - dbpropval = db_info->firstprop; - - rv = ldapu_list_alloc(&propval_list); - - if (rv != LDAPU_SUCCESS) { - goto error; - } - - while (dbpropval) { - propval = (LDAPUPropVal_t *)malloc(sizeof(LDAPUPropVal_t)); - - if (!propval) { - rv = LDAPU_ERR_OUT_OF_MEMORY; - goto error; - } - - propval->prop = dbpropval->prop; - dbpropval->prop = 0; - - propval->val = dbpropval->val; - dbpropval->val = 0; - - rv = ldapu_list_add_info(propval_list, propval); - - if (rv != LDAPU_SUCCESS) { - ldapu_propval_free((void *)propval, (void *)propval); - goto error; - } - - dbpropval = dbpropval->next; - } - - certinfo->propval = propval_list; - } - - *certinfo_out = certinfo; - goto done; - -error: - if (propval_list) - ldapu_propval_list_free(propval_list); - if (certinfo) - free(certinfo); - -done: - return rv; -} - -static int -ldapu_binary_cmp_certs(void *subject_cert, - void *entry_cert_binary, - unsigned long entry_cert_len) -{ - SECItem derCert = ((CERTCertificate *)subject_cert)->derCert; - int rv; - - /* binary compare the two certs */ - if (derCert.len == entry_cert_len && - !memcmp(derCert.data, entry_cert_binary, entry_cert_len)) { - rv = LDAPU_SUCCESS; - } else { - rv = LDAPU_ERR_CERT_VERIFY_FAILED; - } - - return rv; -} - - -static int -ldapu_cert_verifyfn_default(void *subject_cert, LDAP *ld, void *certmap_info __attribute__((unused)), LDAPMessage *res, LDAPMessage **entry_out) -{ - LDAPMessage *entry; - struct berval **bvals; - int i; - int rv = LDAPU_ERR_CERT_VERIFY_FAILED; - char *cert_attr = ldapu_strings[LDAPU_STR_ATTR_CERT]; - char *cert_attr_nosubtype = ldapu_strings[LDAPU_STR_ATTR_CERT_NOSUBTYPE]; - - *entry_out = 0; - - for (entry = ldapu_first_entry(ld, res); entry != NULL; - entry = ldapu_next_entry(ld, entry)) { - if (((bvals = ldapu_get_values_len(ld, entry, cert_attr)) == NULL) && - ((bvals = ldapu_get_values_len(ld, entry, cert_attr_nosubtype)) == NULL)) { - rv = LDAPU_ERR_CERT_VERIFY_NO_CERTS; - continue; - } - - for (i = 0; bvals[i] != NULL; i++) { - rv = ldapu_binary_cmp_certs(subject_cert, - bvals[i]->bv_val, - bvals[i]->bv_len); - - if (rv == LDAPU_SUCCESS) { - break; - } - } - - ldapu_value_free_len(ld, bvals); - - if (rv == LDAPU_SUCCESS) { - *entry_out = entry; - break; - } - } - - return rv; -} - -static int -parse_into_bitmask(const char *comps_in, long *bitmask_out, long default_val) -{ - long bitmask; - char *comps = comps_in ? strdup(comps_in) : 0; - - if (!comps) { - /* Not present in the config file */ - bitmask = default_val; - } else if (!*comps) { - /* present but empty */ - bitmask = 0; - } else { - char *ptr = comps; - char *name = comps; - long bit; - int break_loop = 0; - - bitmask = 0; - - while (*name) { - /* advance ptr to delimeter */ - while (*ptr && !isspace(*ptr) && *ptr != ',') - ptr++; - - if (!*ptr) - break_loop = 1; - else - *ptr++ = 0; - - bit = certmap_name_to_bit_pos(name); - bitmask |= bit; - - if (break_loop) - break; - /* skip delimeters */ - while (*ptr && (isspace(*ptr) || *ptr == ',')) - ptr++; - name = ptr; - } - } - - if (comps) - free(comps); - *bitmask_out = bitmask; - /* print_oid_bitmask(bitmask); */ - return LDAPU_SUCCESS; -} - -static int -process_certinfo(LDAPUCertMapInfo_t *certinfo) -{ - int rv = LDAPU_SUCCESS; - char *dncomps = 0; - char *filtercomps = 0; - char *libname = 0; - char *verify = 0; - char *fname = 0; - char *searchAttr = 0; - - if (!ldapu_strcasecmp(certinfo->issuerName, "default")) { - default_certmap_info = certinfo; - } else if (!certinfo->issuerDN) { - return LDAPU_ERR_NO_ISSUERDN_IN_CONFIG_FILE; - } else { - rv = ldapu_list_add_info(certmap_listinfo, certinfo); - } - - if (rv != LDAPU_SUCCESS) - return rv; - - /* look for dncomps property and parse it into the dncomps bitmask */ - rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_DNCOMPS, &dncomps); - - if (rv == LDAPU_SUCCESS && dncomps) { - certinfo->dncompsState = COMPS_HAS_ATTRS; - tolower_string(dncomps); - } else if (rv == LDAPU_FAILED) { - certinfo->dncompsState = COMPS_COMMENTED_OUT; - rv = LDAPU_SUCCESS; - } else if (rv == LDAPU_SUCCESS && !dncomps) { - certinfo->dncompsState = COMPS_EMPTY; - dncomps = strdup(""); /* present but empty */ - } - - rv = parse_into_bitmask(dncomps, &certinfo->dncomps, -1); - - free(dncomps); - dncomps = NULL; - - if (rv != LDAPU_SUCCESS) - return rv; - - /* look for filtercomps property and parse it into the filtercomps bitmask */ - rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_FILTERCOMPS, - &filtercomps); - - if (rv == LDAPU_SUCCESS && filtercomps) { - certinfo->filtercompsState = COMPS_HAS_ATTRS; - tolower_string(filtercomps); - } else if (rv == LDAPU_FAILED) { - certinfo->filtercompsState = COMPS_COMMENTED_OUT; - rv = LDAPU_SUCCESS; - } else if (rv == LDAPU_SUCCESS && !filtercomps) { - certinfo->filtercompsState = COMPS_EMPTY; - filtercomps = strdup(""); /* present but empty */ - } - - rv = parse_into_bitmask(filtercomps, &certinfo->filtercomps, 0); - - free(filtercomps); - filtercomps = NULL; - - if (rv != LDAPU_SUCCESS) - return rv; - - /* look for "CmapLdapAttr" property and store it into searchAttr */ - rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_CERTMAP_LDAP_ATTR, - &searchAttr); - - if (rv == LDAPU_FAILED || !searchAttr) { - rv = LDAPU_SUCCESS; - } else { - certinfo->searchAttr = searchAttr; - - if (searchAttr && !certinfo->searchAttr) - rv = LDAPU_ERR_OUT_OF_MEMORY; - else - rv = LDAPU_SUCCESS; - } - - if (rv != LDAPU_SUCCESS) - return rv; - - /* look for verifycert property and set the default verify function */ - /* The value of the verifycert property is ignored */ - rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_VERIFYCERT, &verify); - - if (rv == LDAPU_SUCCESS) { - if (!ldapu_strcasecmp(verify, "on")) - certinfo->verifyCert = 1; - else if (!ldapu_strcasecmp(verify, "off")) - certinfo->verifyCert = 0; - else if (!verify || !*verify) /* for mail/news backward compatibilty */ - certinfo->verifyCert = 1; /* otherwise, this should be an error */ - else - rv = LDAPU_ERR_MISSING_VERIFYCERT_VAL; - } else if (rv == LDAPU_FAILED) - rv = LDAPU_SUCCESS; - - if (verify) - free(verify); - - if (rv != LDAPU_SUCCESS) - return rv; - - { - PRLibrary *lib = 0; - - /* look for the library property and load it */ - rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_LIBRARY, &libname); - - if (rv == LDAPU_SUCCESS) { - if (libname && *libname) { - lib = PR_LoadLibrary(libname); - if (!lib) - rv = LDAPU_ERR_UNABLE_TO_LOAD_PLUGIN; - } else { - rv = LDAPU_ERR_MISSING_LIBNAME; - } - } else if (rv == LDAPU_FAILED) - rv = LDAPU_SUCCESS; - - if (libname) - free(libname); - if (rv != LDAPU_SUCCESS) - return rv; - - /* look for the InitFn property, find it in the libray and call it */ - rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_INITFN, &fname); - - if (rv == LDAPU_SUCCESS) { - if (fname && *fname) { - /* If lib is NULL, PR_FindSymbol will search all libs loaded - * through PR_LoadLibrary. - */ - CertMapInitFn_t fn = (CertMapInitFn_t)PR_FindSymbol(lib, fname); - - if (!fn) { - rv = LDAPU_ERR_MISSING_INIT_FN_IN_LIB; - } else { - rv = (*fn)(certinfo, certinfo->issuerName, - certinfo->issuerDN, this_dllname); - } - } else { - rv = LDAPU_ERR_MISSING_INIT_FN_NAME; - } - } else if (lib) { - /* If library is specified, init function must be specified */ - /* If init fn is specified, library may not be specified */ - rv = LDAPU_ERR_MISSING_INIT_FN_IN_CONFIG; - } else if (rv == LDAPU_FAILED) { - rv = LDAPU_SUCCESS; - } - - if (fname) - free(fname); - - if (rv != LDAPU_SUCCESS) - return rv; - } - - return rv; -} - -/* This function will read multiple certmap directives and set the information - * in the global certmap_listinfo structure. - */ -int -certmap_read_certconfig_file(const char *file) -{ - DBConfInfo_t *conf_info = 0; - int rv; - - /* Read the config file */ - rv = dbconf_read_config_file_sub(file, LIB_DIRECTIVE, LIB_DIRECTIVE_LEN, - &conf_info); - - /* Convert the conf_info into certmap_listinfo. Some of the - * sub-structures are simply hijacked rather than copied since we are - * going to (carefully) free the conf_info anyway. - */ - - if (rv == LDAPU_SUCCESS && conf_info) { - DBConfDBInfo_t *nextdb; - DBConfDBInfo_t *curdb; - LDAPUCertMapInfo_t *certinfo; - - curdb = conf_info->firstdb; - - while (curdb) { - nextdb = curdb->next; - rv = dbinfo_to_certinfo(curdb, &certinfo); - if (rv != LDAPU_SUCCESS) { - dbconf_free_confinfo(conf_info); - return rv; - } - - rv = process_certinfo(certinfo); - if (rv != LDAPU_SUCCESS) { - ldapu_certinfo_free(certinfo); - dbconf_free_confinfo(conf_info); - return rv; - } - - curdb = nextdb; - } - - dbconf_free_confinfo(conf_info); - } else { - rv = dbconf_to_certmap_err(rv); - } - - return rv; -} - -/* This function will read the "certmap default" directive from the config - * file and set the information in the global certmap_info. - */ -int -certmap_read_default_certinfo(const char *file) -{ - DBConfDBInfo_t *db_info = 0; - int rv; - - rv = dbconf_read_default_dbinfo_sub(file, LIB_DIRECTIVE, LIB_DIRECTIVE_LEN, - &db_info); - - if (rv != LDAPU_SUCCESS) - return rv; - - rv = dbinfo_to_certinfo(db_info, &default_certmap_info); - - dbconf_free_dbinfo(db_info); - return rv; -} - -static int -ldapu_cert_searchfn_default(void *cert, LDAP *ld, void *certmap_info_in, const char *basedn, const char *dn, const char *filter, const char **attrs, LDAPMessage ***res) -{ - int rv = LDAPU_FAILED; - const char *ldapdn; - LDAPUCertMapInfo_t *certmap_info = (LDAPUCertMapInfo_t *)certmap_info_in; - LDAPMessage *single_res = NULL; - LDAPMessage **multiple_res = NULL; - - - if (certmap_info && certmap_info->searchAttr) { - char *subjectDN = 0; - char *certFilter = 0; - int len; - - rv = ldapu_get_cert_subject_dn(cert, &subjectDN); - - if (rv != LDAPU_SUCCESS || !subjectDN) { - return rv; - } - len = strlen(certmap_info->searchAttr) + strlen(subjectDN) + - strlen("=") + 1; - certFilter = (char *)ldapu_malloc(len * sizeof(char)); - if (!certFilter) { - free(subjectDN); - return LDAPU_ERR_OUT_OF_MEMORY; - } - sprintf(certFilter, "%s=%s", certmap_info->searchAttr, subjectDN); - free(subjectDN); - if (ldapu_strcasecmp(basedn, "")) { - rv = ldapu_find(ld, basedn, LDAP_SCOPE_SUBTREE, certFilter, attrs, 0, &single_res); - ldapu_free((void *)certFilter); - if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) { - *res = (LDAPMessage **)ldapu_malloc(2 * sizeof(LDAPMessage *)); - (*res)[0] = single_res; - (*res)[1] = NULL; - return rv; - } else if (single_res) { - ldapu_msgfree(ld, single_res); - single_res = 0; - } - } else { - rv = ldapu_find_entire_tree(ld, LDAP_SCOPE_SUBTREE, certFilter, attrs, 0, &multiple_res); - ldapu_free((void *)certFilter); - if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) { - *res = multiple_res; - return rv; - } else if (multiple_res) { - int n; - for (n = 0; multiple_res[n] != NULL; n++) - ldapu_msgfree(ld, multiple_res[n]); - ldapu_memfree(ld, multiple_res); - } - } - } - - if (dn && *dn) { - /* First do the base level search --- NOT ANY MORE!! */ - /* We actually do the search on the whole subtree hanging from "ldapdn" since we want to - * find all the entries that match the filter. - * If we get more than one matching entry in return, it'll be at verify time that we'll - * choose the correct one among them all. - * However, if certificate verify is not active, certificate mapping will fail and will - * consequently display an error message (something done at 'handle_handshake_done' level, - * for instance). */ - ldapdn = dn; - - if (ldapu_strcasecmp(ldapdn, "")) { - rv = ldapu_find(ld, ldapdn, LDAP_SCOPE_SUBTREE, filter, attrs, 0, &single_res); - if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) { - *res = (LDAPMessage **)ldapu_malloc(2 * sizeof(LDAPMessage *)); - (*res)[0] = single_res; - (*res)[1] = NULL; - return rv; - } else if (single_res) { - ldapu_msgfree(ld, single_res); - single_res = 0; - } - } else { - rv = ldapu_find_entire_tree(ld, LDAP_SCOPE_SUBTREE, filter, attrs, 0, &multiple_res); - if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) { - *res = multiple_res; - return rv; - } else if (multiple_res) { - int n; - for (n = 0; multiple_res[n] != NULL; n++) - ldapu_msgfree(ld, multiple_res[n]); - ldapu_memfree(ld, multiple_res); - } - } - } else { - /* default the dn and filter for subtree search */ - ldapdn = basedn; - if (!filter || !*filter) { - if (certmap_info && certmap_info->searchAttr) { - /* dn & filter returned by the mapping function are both NULL - and 'searchAttr' based search has failed. Don't do brute - force search if 'searchAttr' is being used. Otherwise, - this search will result in all LDAP entries being - returned. - */ - } else { - filter = "objectclass=*"; - } - } - } - - /* For local LDAP DB, the LDAP_SCOPE_BASE search may fail for dn == basedn - * since that object doesn't actually exists. - */ - if ((rv == LDAPU_FAILED || rv == LDAP_NO_SUCH_OBJECT) && filter && (!dn || !*dn)) { - - /* Try the subtree search only if the filter is non-NULL */ - if (ldapu_strcasecmp(ldapdn, "")) { - rv = ldapu_find(ld, ldapdn, LDAP_SCOPE_SUBTREE, filter, 0, 0, &single_res); - if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) { - *res = (LDAPMessage **)ldapu_malloc(2 * sizeof(LDAPMessage *)); - (*res)[0] = single_res; - (*res)[1] = NULL; - return rv; - } else if (single_res) { - ldapu_msgfree(ld, single_res); - single_res = 0; - } - } else { - rv = ldapu_find_entire_tree(ld, LDAP_SCOPE_SUBTREE, filter, 0, 0, &multiple_res); - if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) { - *res = multiple_res; - return rv; - } else if (multiple_res) { - int n; - for (n = 0; multiple_res[n] != NULL; n++) - ldapu_msgfree(ld, multiple_res[n]); - ldapu_memfree(ld, multiple_res); - } - } - } - - if (rv == LDAPU_FAILED) { - /* Not an error but couldn't map the cert */ - rv = LDAPU_ERR_MAPPED_ENTRY_NOT_FOUND; - } else if ((!dn || !*dn) && (rv == LDAP_NO_SUCH_OBJECT)) { - rv = LDAPU_ERR_INVALID_SUFFIX; - } - - return rv; -} - -NSAPI_PUBLIC int -ldapu_issuer_certinfo(const CERTName *issuerDN, void **certmap_info) -{ - *certmap_info = 0; - - if (certmap_listinfo) { - LDAPUListNode_t *cur = certmap_listinfo->head; - while (cur) { - LDAPUCertMapInfo_t *info = (LDAPUCertMapInfo_t *)cur->info; - - if (NULL == info->issuerDN) { - /* no DN to compare to (probably the default certmap info) */ - continue; - } - - if (CERT_CompareName(issuerDN, info->issuerDN) == SECEqual) { - *certmap_info = cur->info; - break; - } - cur = cur->next; - } - } - return *certmap_info ? LDAPU_SUCCESS : LDAPU_FAILED; -} - -NSAPI_PUBLIC int -ldapu_certmap_info_attrval(void *certmap_info_in, - const char *attr, - char **val) -{ - /* Look for given attr in the certmap_info and return its value */ - LDAPUCertMapInfo_t *certmap_info = (LDAPUCertMapInfo_t *)certmap_info_in; - LDAPUListNode_t *curprop = certmap_info->propval ? certmap_info->propval->head : 0; - LDAPUPropVal_t *propval; - int rv = LDAPU_FAILED; - - *val = 0; - while (curprop) { - propval = (LDAPUPropVal_t *)curprop->info; - if (!ldapu_strcasecmp(propval->prop, attr)) { - *val = propval->val ? strdup(propval->val) : 0; - rv = LDAPU_SUCCESS; - break; - } - curprop = curprop->next; - } - - return rv; -} - -static int -AddAVAToBuf(char *buf, int size, int *len, const char *tagName, CERTAVA *ava) -{ - int lenLen; - int taglen; - SECStatus rv; - - buf += *len; - - /* Copied from ns/lib/libsec ... - * XXX this code is incorrect in general - * -- should use a DER template. - */ - lenLen = 2; - if (ava->value.len >= 128) - lenLen = 3; - - taglen = PL_strlen(tagName); - memcpy(buf, tagName, taglen); - buf[taglen++] = '='; - - rv = CERT_RFC1485_EscapeAndQuote(buf + taglen, - size - taglen, - (char *)ava->value.data + lenLen, - ava->value.len - lenLen); - - *len += strlen(buf); - - return (rv == SECSuccess ? LDAPU_SUCCESS : LDAPU_FAILED); -} - -static int -AddToLdapDN(char *ldapdn, int size, int *dnlen, const char *tagName, CERTAVA *ava) -{ - char *dn = ldapdn + *dnlen; - - if (*dnlen) { - strcat(dn, ", "); - dn += 2; - *dnlen += 2; - } - return AddAVAToBuf(ldapdn, size, dnlen, tagName, ava); -} - -static int -AddToFilter(char *filter, int size, int *flen, const char *tagName, CERTAVA *ava) -{ - int rv; - - /* Append opening parenthesis */ - strcat(filter + *flen, " ("); - *flen += 2; - rv = AddAVAToBuf(filter, size, flen, tagName, ava); - - if (rv != LDAPU_SUCCESS) - return rv; - - /* Append closing parenthesis */ - strcat(filter + *flen, ")"); - (*flen)++; - - return rv; -} - -NSAPI_PUBLIC int -ldapu_free_cert_ava_val(char **val) -{ - char **ptr = val; - - if (!val) - return LDAPU_SUCCESS; - - while (*ptr) - free(*ptr++); - free(val); - - return LDAPU_SUCCESS; -} - -static int -ldapu_cert_mapfn_default(void *cert_in, LDAP *ld __attribute__((unused)), void *certmap_info_in, char **ldapDN_out, char **filter_out) -{ - CERTCertificate *cert = (CERTCertificate *)cert_in; - LDAPUCertMapInfo_t *certmap_info = (LDAPUCertMapInfo_t *)certmap_info_in; - int rv = LDAPU_SUCCESS; - - *ldapDN_out = *filter_out = 0; - - if (!certmap_info) { - /* Use subject DN as is -- identity mapping function */ - rv = ldapu_get_cert_subject_dn(cert, ldapDN_out); - - return rv; - } else { - /* - * Iterate over rdns from the subject and collect AVAs depending on - * dnComps and filtercomps to form ldapDN and filter respectively. - * certmap_info->dncomps - */ - CERTName *subject = &cert->subject; - CERTRDN **rdns = subject->rdns; - CERTRDN **lastRdn; - CERTRDN **rdn; - CERTAVA **avas; - CERTAVA *ava; - char ldapdn[BIG_LINE]; - char filter[BIG_LINE]; - int dnlen = 0; /* ldap DN length */ - int flen = 0; /* filter length */ - int numfavas = 0; /* no of avas added to filter */ - - if (rdns == NULL) { - /* error */ - return LDAPU_ERR_INTERNAL; - } - - /* find last RDN */ - lastRdn = rdns; - while (*lastRdn) - lastRdn++; - lastRdn--; - - /* Initialize filter to "(&" */ - strcpy(filter, "(&"); - flen = 2; - - /* - * Loop over subject rdns in the _reverse_ order while forming ldapDN - * and filter. - */ - for (rdn = lastRdn; rdn >= rdns; rdn--) { - avas = (*rdn)->avas; - while ((ava = *avas++) != NULL) { - int tag = CERT_GetAVATag(ava); - const char *tagName = certmap_secoid_to_name(tag); - - if (PresentInComps(certmap_info->dncomps, tag)) { - rv = AddToLdapDN(ldapdn, BIG_LINE, &dnlen, tagName, ava); - if (rv != LDAPU_SUCCESS) - return rv; - } - - if (PresentInComps(certmap_info->filtercomps, tag)) { - rv = AddToFilter(filter, BIG_LINE, &flen, tagName, ava); - if (rv != LDAPU_SUCCESS) - return rv; - numfavas++; - } - } - } - - if (numfavas == 0) { - /* nothing added to filter */ - *filter = 0; - } else if (numfavas == 1) { - /* one ava added to filter -- remove "(& (" from the front and ")" - * from the end. - */ - *filter_out = strdup(filter + 4); - if (!*filter_out) - return LDAPU_ERR_OUT_OF_MEMORY; - (*filter_out)[strlen(*filter_out) - 1] = 0; - } else { - /* Add the closing parenthesis to filter */ - strcat(filter + flen, ")"); - *filter_out = strdup(filter); - } - - if (dnlen >= BIG_LINE) - return LDAPU_FAILED; - ldapdn[dnlen] = 0; - *ldapDN_out = *ldapdn ? strdup(ldapdn) : 0; - - if ((numfavas && !*filter_out) || (dnlen && !*ldapDN_out)) { - /* strdup failed */ - return LDAPU_ERR_OUT_OF_MEMORY; - } - - if ((certmap_info->dncompsState == COMPS_HAS_ATTRS && dnlen == 0) || - (certmap_info->filtercompsState == COMPS_HAS_ATTRS && - numfavas == 0)) { - /* At least one attr in DNComps should be present in the cert */ - /* Same is true for FilterComps */ - rv = LDAPU_ERR_MAPPED_ENTRY_NOT_FOUND; - } - } - - return rv; -} - -NSAPI_PUBLIC int -ldapu_set_cert_mapfn(const CERTName *issuerDN, - CertMapFn_t mapfn) -{ - LDAPUCertMapInfo_t *certmap_info; - int rv; - - /* don't free the certmap_info -- its a pointer to an internal structure */ - rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info); - - /* Don't set the mapping function if certmap_info doesen't exist */ - if (rv != LDAPU_SUCCESS) - return rv; - - certmap_info->mapfn = mapfn; - return LDAPU_SUCCESS; -} - -static CertMapFn_t -ldapu_get_cert_mapfn_sub(LDAPUCertMapInfo_t *certmap_info) -{ - CertMapFn_t mapfn; - - if (certmap_info && certmap_info->mapfn) - mapfn = certmap_info->mapfn; - else if (default_certmap_info && default_certmap_info->mapfn) - mapfn = default_certmap_info->mapfn; - else - mapfn = ldapu_cert_mapfn_default; - - return mapfn; -} - -NSAPI_PUBLIC CertMapFn_t -ldapu_get_cert_mapfn(const CERTName *issuerDN) -{ - LDAPUCertMapInfo_t *certmap_info = 0; - - /* don't free the certmap_info -- its a pointer to an internal structure */ - ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info); - /* certmap_info may be NULL -- use the default */ - - return ldapu_get_cert_mapfn_sub(certmap_info); -} - -NSAPI_PUBLIC int -ldapu_set_cert_searchfn(const CERTName *issuerDN, - CertSearchFn_t searchfn) -{ - LDAPUCertMapInfo_t *certmap_info; - int rv; - - /* don't free the certmap_info -- its a pointer to an internal structure */ - rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info); - - /* Don't set the mapping function if certmap_info doesen't exist */ - if (rv != LDAPU_SUCCESS) - return rv; - - certmap_info->searchfn = searchfn; - return LDAPU_SUCCESS; -} - -static CertSearchFn_t -ldapu_get_cert_searchfn_sub(LDAPUCertMapInfo_t *certmap_info) -{ - CertSearchFn_t searchfn; - - if (certmap_info && certmap_info->searchfn) - searchfn = certmap_info->searchfn; - else if (default_certmap_info && default_certmap_info->searchfn) - searchfn = default_certmap_info->searchfn; - else - searchfn = ldapu_cert_searchfn_default; - - return searchfn; -} - -NSAPI_PUBLIC CertSearchFn_t -ldapu_get_cert_searchfn(const CERTName *issuerDN) -{ - LDAPUCertMapInfo_t *certmap_info = 0; - - /* don't free the certmap_info -- its a pointer to an internal structure */ - ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info); - /* certmap_info may be NULL -- use the default */ - - return ldapu_get_cert_searchfn_sub(certmap_info); -} - -NSAPI_PUBLIC int -ldapu_set_cert_verifyfn(const CERTName *issuerDN, - CertVerifyFn_t verifyfn) -{ - LDAPUCertMapInfo_t *certmap_info; - int rv; - - /* don't free the certmap_info -- its a pointer to an internal structure */ - rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info); - - /* Don't set the verify function if certmap_info doesen't exist */ - if (rv != LDAPU_SUCCESS) - return rv; - - certmap_info->verifyfn = verifyfn; - return LDAPU_SUCCESS; -} - -static CertVerifyFn_t -ldapu_get_cert_verifyfn_sub(LDAPUCertMapInfo_t *certmap_info) -{ - CertVerifyFn_t verifyfn; - - if (certmap_info && certmap_info->verifyfn) - verifyfn = certmap_info->verifyfn; - else if (default_certmap_info && default_certmap_info->verifyfn) - verifyfn = default_certmap_info->verifyfn; - else - verifyfn = ldapu_cert_verifyfn_default; - - return verifyfn; -} - -NSAPI_PUBLIC CertVerifyFn_t -ldapu_get_cert_verifyfn(const CERTName *issuerDN) -{ - LDAPUCertMapInfo_t *certmap_info = 0; - - /* don't free the certmap_info -- its a pointer to an internal structure */ - ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info); - /* certmap_info may be NULL -- use the default */ - - return ldapu_get_cert_verifyfn_sub(certmap_info); -} - -#if 0 /* may need this in the future */ -static int ldapu_certinfo_copy (const LDAPUCertMapInfo_t *from, - const char *newIssuerName, - const char *newIssuerDN, - LDAPUCertMapInfo_t *to) -{ - /* This function is not tested and is not used */ - int rv; - - to->issuerName = newIssuerName ? strdup(newIssuerName) : 0; - to->issuerDN = newIssuerDN ? strdup(newIssuerDN) : 0; - if (from->propval) { - rv = ldapu_list_copy(from->propval, &to->propval, ldapu_propval_copy); - if (rv != LDAPU_SUCCESS) return rv; - } - else { - to->propval = 0; - } - - return process_certinfo(to); -} -#endif - -NSAPI_PUBLIC int -ldapu_cert_to_ldap_entry(void *cert, LDAP *ld, const char *basedn, LDAPMessage **res) -{ - char *ldapDN = 0; - char *filter = 0; - LDAPUCertMapInfo_t *certmap_info; - LDAPMessage **res_array = NULL; - CertMapFn_t mapfn; - CertVerifyFn_t verifyfn; - CertSearchFn_t searchfn; - int rv, i, j; - - *res = 0; - - if (!certmap_attrs[0]) { - /* Initialize certmap_attrs */ - certmap_attrs[0] = ldapu_strings[LDAPU_STR_ATTR_USER]; - certmap_attrs[1] = ldapu_strings[LDAPU_STR_ATTR_CERT]; - certmap_attrs[2] = ldapu_strings[LDAPU_STR_ATTR_CERT_NOSUBTYPE]; - certmap_attrs[3] = 0; - } - - CERTName *issuerDN = ldapu_get_cert_issuer_dn_as_CERTName(cert); - /* ^ don't need to free this; it will be freed with ^ the cert */ - - if (NULL == issuerDN) - return LDAPU_ERR_NO_ISSUERDN_IN_CERT; - - /* don't free the certmap_info -- its a pointer to an internal structure */ - rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info); - - if (!certmap_info) - certmap_info = default_certmap_info; - - /* Get the mapping function from the certmap_info */ - mapfn = ldapu_get_cert_mapfn_sub(certmap_info); - - rv = (*mapfn)(cert, ld, certmap_info, &ldapDN, &filter); - - if (rv != LDAPU_SUCCESS) { - free(ldapDN); - free(filter); - return rv; - } - - /* Get the search function from the certmap_info - certinfo maybe NULL */ - searchfn = ldapu_get_cert_searchfn_sub(certmap_info); - - rv = (*searchfn)(cert, ld, certmap_info, basedn, ldapDN, filter, - certmap_attrs, &res_array); - - free(ldapDN); - free(filter); - - /* - * Get the verify cert function & call it. - */ - j = 0; - if ((rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) && - (certmap_info ? certmap_info->verifyCert : 0)) { - verifyfn = ldapu_get_cert_verifyfn_sub(certmap_info); - - if (verifyfn) { - int verify_rv; - - i = 0; - do { - LDAPMessage *entry; - verify_rv = (*verifyfn)(cert, ld, certmap_info, res_array[i], &entry); - - if (rv == LDAPU_ERR_MULTIPLE_MATCHES) { - if (verify_rv == LDAPU_SUCCESS) { - /* 'entry' points to the matched entry */ - /* Get the 'res' which only contains this entry */ - char *dn = ldapu_get_dn(ld, entry); - if (*res) - ldapu_msgfree(ld, *res); - rv = ldapu_find(ld, dn, LDAP_SCOPE_BASE, 0, certmap_attrs, 0, res); - ldapu_memfree(ld, dn); - } else { - /* Verify failed for multiple matches -- keep rv */ - /* multiple matches err is probably more interesting to - the caller then any other error returned by the verify - fn */ - } - } else /* rv == LDAPU_SUCCESS */ { - if (verify_rv == LDAPU_SUCCESS) { - *res = res_array[0]; - j = 1; - } else { - rv = verify_rv; - } - } - } while ((verify_rv != LDAPU_SUCCESS) && (res_array[++i] != NULL)); - } - } else { - if (rv == LDAPU_SUCCESS) { - *res = res_array[0]; - j = 1; - } - } - - - if (rv != LDAPU_SUCCESS) { - if (*res) { - ldapu_msgfree(ld, *res); - *res = 0; - } - } - - i = j; /* ugaston - if the search had been successful, despite verifyCert being "off", - * mapping is considered successful, so we keep the first (and only) response message. - * If, on the other hand, the search had returned multiple matches, the fact - * of having verifyCert "off" automatically turns the mapping faulty, so we - * don't need to care about keeping any response at all. - */ - - if (res_array) { - while (res_array[i] != NULL) { - ldapu_msgfree(ld, res_array[i]); - res_array[i++] = 0; - } - ldapu_memfree(ld, res_array); - } - return rv; -} - -/* The caller shouldn't free the entry */ -NSAPI_PUBLIC int -ldapu_cert_to_user(void *cert, LDAP *ld, const char *basedn, LDAPMessage **res_out, char **user) -{ - int rv; - LDAPMessage *res; - LDAPMessage *entry; - int numEntries; - char **attrVals = NULL; - - *res_out = 0; - *user = 0; - - rv = ldapu_cert_to_ldap_entry(cert, ld, basedn, &res); - - if (rv != LDAPU_SUCCESS) { - goto done; - } - - if (!res) { - rv = LDAPU_ERR_EMPTY_LDAP_RESULT; - goto done; - } - - /* Extract user login (the 'uid' attr) from 'res' */ - numEntries = ldapu_count_entries(ld, res); - - if (numEntries != 1) { - rv = LDAPU_ERR_MULTIPLE_MATCHES; - goto done; - } - - entry = ldapu_first_entry(ld, res); - - if (!entry) { - rv = LDAPU_ERR_MISSING_RES_ENTRY; - goto done; - } - - attrVals = ldapu_get_values(ld, entry, - ldapu_strings[LDAPU_STR_ATTR_USER]); - - if (!attrVals || !attrVals[0]) { - rv = LDAPU_ERR_MISSING_UID_ATTR; - goto done; - } - - *user = strdup(attrVals[0]); - - /* ldapu_msgfree(res); */ - - if (!*user) { - rv = LDAPU_ERR_OUT_OF_MEMORY; - goto done; - } - - *res_out = res; - -done: - if (attrVals) { - ldapu_value_free(ld, attrVals); - } - - return rv; -} - -static void * -ldapu_propval_free(void *propval_in, void *arg __attribute__((unused))) -{ - LDAPUPropVal_t *propval = (LDAPUPropVal_t *)propval_in; - - if (propval->prop) - free(propval->prop); - if (propval->val) - free(propval->val); - memset((void *)propval, 0, sizeof(LDAPUPropVal_t)); - free(propval); - return 0; -} - -void -ldapu_certinfo_free(void *info_in) -{ - LDAPUCertMapInfo_t *certmap_info = (LDAPUCertMapInfo_t *)info_in; - - if (certmap_info->issuerName) - free(certmap_info->issuerName); - if (certmap_info->issuerDN) - free(certmap_info->issuerDN); - if (certmap_info->propval) - ldapu_list_free(certmap_info->propval, ldapu_propval_free); - if (certmap_info->searchAttr) - free(certmap_info->searchAttr); - memset((void *)certmap_info, 0, sizeof(LDAPUCertMapInfo_t)); - free(certmap_info); -} - -static void * -ldapu_certinfo_free_helper(void *info, void *arg __attribute__((unused))) -{ - ldapu_certinfo_free(info); - return (void *)LDAPU_SUCCESS; -} - -void -ldapu_certmap_listinfo_free(void *_certmap_listinfo) -{ - LDAPUCertMapListInfo_t *list = (LDAPUCertMapListInfo_t *)_certmap_listinfo; - ldapu_list_free(list, ldapu_certinfo_free_helper); -} - -void -ldapu_propval_list_free(void *propval_list) -{ - LDAPUPropValList_t *list = (LDAPUPropValList_t *)propval_list; - ldapu_list_free(list, ldapu_propval_free); - free(list); -} - -int -ldapu_certmap_init(const char *config_file, - const char *dllname, - LDAPUCertMapListInfo_t **certmap_list, - LDAPUCertMapInfo_t **certmap_default) -{ - int rv; - certmap_listinfo = (LDAPUCertMapListInfo_t *)calloc(1, sizeof(LDAPUCertMapListInfo_t)); - - *certmap_list = 0; - *certmap_default = 0; - PR_snprintf(this_dllname, sizeof(this_dllname), "%s", dllname); - - if (!certmap_listinfo) - return LDAPU_ERR_OUT_OF_MEMORY; - - rv = certmap_read_certconfig_file(config_file); - - if (rv == LDAPU_SUCCESS) { - *certmap_list = certmap_listinfo; - *certmap_default = default_certmap_info; - } - - return rv; -} - -NSAPI_PUBLIC int -ldaputil_exit() -{ - if (default_certmap_info) { - ldapu_certinfo_free(default_certmap_info); - default_certmap_info = 0; - } - - if (certmap_listinfo) { - ldapu_certmap_listinfo_free(certmap_listinfo); - certmap_listinfo = 0; - } - - return LDAPU_SUCCESS; -} - - -NSAPI_PUBLIC void -ldapu_free(void *ptr) -{ - if (ptr) - free(ptr); -} - -NSAPI_PUBLIC void -ldapu_free_old(char *ptr) -{ - free((void *)ptr); -} - -NSAPI_PUBLIC void * -ldapu_malloc(int size) -{ - return malloc(size); -} - -NSAPI_PUBLIC char * -ldapu_strdup(const char *ptr) -{ - return strdup(ptr); -} - -NSAPI_PUBLIC void * -ldapu_realloc(void *ptr, int size) -{ - return realloc(ptr, size); -} diff --git a/lib/ldaputil/dbconf.c b/lib/ldaputil/dbconf.c deleted file mode 100644 index 76654e7..0000000 --- a/lib/ldaputil/dbconf.c +++ /dev/null @@ -1,686 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - - -#include -/* This was malloc.h - but it's moved to stdlib.h on most platforms, and FBSD is strict */ -/* Make it stdlib.h, and revert to malloc.h with ifdefs if we have issues here. WB 2016 */ -#include -#include - -#include -#include -#include -#include - -#define BIG_LINE 1024 - -static const char *DB_DIRECTIVE = "directory"; -static const int DB_DIRECTIVE_LEN = 9; /* strlen("DB_DIRECTIVE") */ - -static const char *ENCODED = "encoded"; - -static void -insert_dbinfo_propval(DBConfDBInfo_t *db_info, - DBPropVal_t *propval) -{ - if (db_info->lastprop) { - db_info->lastprop->next = propval; - } else { - db_info->firstprop = propval; - } - - db_info->lastprop = propval; -} - -static void -insert_dbconf_dbinfo(DBConfInfo_t *conf_info, - DBConfDBInfo_t *db_info) -{ - if (conf_info->lastdb) { - conf_info->lastdb->next = db_info; - } else { - conf_info->firstdb = db_info; - } - - conf_info->lastdb = db_info; -} - -void -dbconf_free_propval(DBPropVal_t *propval) -{ - if (propval) { - if (propval->prop) - free(propval->prop); - if (propval->val) - free(propval->val); - memset((void *)propval, 0, sizeof(DBPropVal_t)); - free(propval); - } -} - -NSAPI_PUBLIC void -dbconf_free_dbinfo(DBConfDBInfo_t *db_info) -{ - if (db_info) { - DBPropVal_t *next; - DBPropVal_t *cur; - - if (db_info->dbname) - free(db_info->dbname); - if (db_info->url) - free(db_info->url); - - cur = db_info->firstprop; - - while (cur) { - next = cur->next; - dbconf_free_propval(cur); - cur = next; - } - - memset((void *)db_info, 0, sizeof(DBConfDBInfo_t)); - free(db_info); - } -} - -NSAPI_PUBLIC void -dbconf_free_confinfo(DBConfInfo_t *conf_info) -{ - DBConfDBInfo_t *next; - DBConfDBInfo_t *cur; - - if (conf_info) { - cur = conf_info->firstdb; - - while (cur) { - next = cur->next; - dbconf_free_dbinfo(cur); - cur = next; - } - - memset((void *)conf_info, 0, sizeof(DBConfInfo_t)); - free(conf_info); - } -} - -static int -skip_blank_lines_and_spaces(FILE *fp, char *buf, char **ptr_out, int *eof) -{ - char *ptr = buf; - char *end; - - while (buf && (*buf || fgets(buf, BIG_LINE, fp))) { - ptr = buf; - - /* skip leading whitespace */ - while (*ptr && isspace(*ptr)) - ++ptr; - - /* skip blank line or comment */ - if (!*ptr || *ptr == '#') { - *buf = 0; /* to force reading of next line */ - continue; - } - - /* Non-blank line found */ - break; - } - - *ptr_out = ptr; - if (!*ptr) { - *eof = 1; - } else { - /* skip trailing whitespace */ - end = ptr + strlen(ptr) - 1; - while (isspace(*end)) - *end-- = 0; - } - - return LDAPU_SUCCESS; -} - -static int -dbconf_parse_propval(char *buf, char *ptr, DBConfDBInfo_t *db_info) -{ - char *dbname = db_info->dbname; - int dbname_len = strlen(dbname); - char *prop; - char *val; - DBPropVal_t *propval; - char *delimeter_chars = " \t"; - char *lastchar; - int end_of_prop; - char *encval = 0; /* encoded value */ - char *origprop = 0; - - if ((ptr - buf + dbname_len > BIG_LINE) || - strncmp(ptr, dbname, dbname_len) || - !(ptr[dbname_len] == ':' || isspace(ptr[dbname_len]))) { - /* Not a prop-val for the current db but not an error */ - return LDAPU_ERR_NOT_PROPVAL; - } - - /* remove the last char if it is newline */ - lastchar = strrchr(buf, '\n'); - if (lastchar) - *lastchar = '\0'; - - prop = ptr + dbname_len + 1; - - while (*prop && (isspace(*prop) || *prop == ':')) - ++prop; - - if (!*prop) { - return LDAPU_ERR_PROP_IS_MISSING; - } - - end_of_prop = strcspn(prop, delimeter_chars); - - if (prop[end_of_prop] != '\0') { - /* buf doesn't end here -- val is present */ - prop[end_of_prop] = '\0'; - val = &prop[end_of_prop + 1]; - - while (*val && isspace(*val)) - ++val; - if (*val == '\0') - val = 0; - } else { - val = 0; - } - - /* - * The prop-val line could be one of the following: - * ":prop val" OR ":encoded prop encval" - * If (prop == "encoded") then the val has "prop encval". - * Get the actual prop from val and get encval (i.e. encoded value) - * and decode it. If it is encoded then the val part must be non-NULL. - */ - if (val && *val && !strcmp(prop, ENCODED)) { - /* val has the actual prop followed by the encoded value */ - origprop = prop; - prop = val; - while (*prop && (isspace(*prop) || *prop == ':')) - ++prop; - - if (!*prop) { - return LDAPU_ERR_PROP_IS_MISSING; - } - - end_of_prop = strcspn(prop, delimeter_chars); - - if (prop[end_of_prop] != '\0') { - /* buf doesn't end here -- encval is present */ - prop[end_of_prop] = '\0'; - encval = &prop[end_of_prop + 1]; - - while (*encval && isspace(*encval)) - ++encval; - if (*encval == '\0') - encval = 0; - } else { - encval = 0; - } - - if (!encval) { - /* special case - if encval is null, "encoded" itself is a - * property and what we have in prop now is the value. */ - val = prop; - prop = origprop; - } else { - /* decode the value */ - val = dbconf_decodeval(encval); - } - } - - /* Success - we have prop & val */ - propval = (DBPropVal_t *)malloc(sizeof(DBPropVal_t)); - - if (!propval) { - if (encval && val) - free(val); - return LDAPU_ERR_OUT_OF_MEMORY; - } - memset((void *)propval, 0, sizeof(DBPropVal_t)); - propval->prop = strdup(prop); - propval->val = val ? strdup(val) : 0; - - if (encval && val) - free(val); /* val was allocated by dbconf_decodeval */ - - if (!propval->prop || (val && !propval->val)) { - dbconf_free_propval(propval); - return LDAPU_ERR_OUT_OF_MEMORY; - } - - insert_dbinfo_propval(db_info, propval); - return LDAPU_SUCCESS; -} - -static int -dbconf_read_propval(FILE *fp, char *buf, DBConfDBInfo_t *db_info, int *eof) -{ - int rv; - char *ptr = buf; - - while (buf && (*buf || fgets(buf, BIG_LINE, fp))) { - ptr = buf; - - rv = skip_blank_lines_and_spaces(fp, buf, &ptr, eof); - - if (rv != LDAPU_SUCCESS || *eof) - return rv; - - /* We have a non-blank line which could be prop-val pair for the - * dbname in the db_info. parse the prop-val pair and continue. - */ - rv = dbconf_parse_propval(buf, ptr, db_info); - - if (rv == LDAPU_ERR_NOT_PROPVAL) - return LDAPU_SUCCESS; - if (rv != LDAPU_SUCCESS) - return rv; - - *buf = 0; /* to force reading of next line */ - } - - if (!*buf) - *eof = 1; - - return LDAPU_SUCCESS; -} - -static int -parse_directive(char *buf, const char *directive, const int directive_len, DBConfDBInfo_t **db_info_out) -{ - DBConfDBInfo_t *db_info; - char *dbname; - char *url; - int end_of_dbname; - char *delimeter_chars = " \t"; - char *lastchar; - - /* remove the last char if it is newline */ - lastchar = strrchr(buf, '\n'); - if (lastchar) - *lastchar = '\0'; - - if (strncmp(buf, directive, directive_len) || - !isspace(buf[directive_len])) { - return LDAPU_ERR_DIRECTIVE_IS_MISSING; - } - - dbname = buf + directive_len + 1; - - while (*dbname && isspace(*dbname)) - ++dbname; - - if (!*dbname) { - return LDAPU_ERR_DBNAME_IS_MISSING; - } - - end_of_dbname = strcspn(dbname, delimeter_chars); - - if (dbname[end_of_dbname] != '\0') { - /* buf doesn't end here -- url is present */ - dbname[end_of_dbname] = '\0'; - url = &dbname[end_of_dbname + 1]; - - while (*url && isspace(*url)) - ++url; - - if (*url == '\0') - url = 0; - } else { - url = 0; - } - - /* Success - we have dbname & url */ - db_info = (DBConfDBInfo_t *)malloc(sizeof(DBConfDBInfo_t)); - - if (!db_info) - return LDAPU_ERR_OUT_OF_MEMORY; - memset((void *)db_info, 0, sizeof(DBConfDBInfo_t)); - db_info->dbname = strdup(dbname); - db_info->url = url ? strdup(url) : 0; - - if (!db_info->dbname || (url && !db_info->url)) { - dbconf_free_dbinfo(db_info); - return LDAPU_ERR_OUT_OF_MEMORY; - } - - *db_info_out = db_info; - return LDAPU_SUCCESS; -} - -/* Read the next database info from the file and put it in db_info_out. The - * buf may contain first line of the database info. When this function - * finishes, the buf may contain unprocessed information (which should be - * passed to the next call to read_db_info). - */ -static int -read_db_info(FILE *fp, char *buf, DBConfDBInfo_t **db_info_out, const char *directive, const int directive_len, int *eof) -{ - char *ptr; - DBConfDBInfo_t *db_info; - int rv; - - *db_info_out = 0; - - rv = skip_blank_lines_and_spaces(fp, buf, &ptr, eof); - - if (rv != LDAPU_SUCCESS || *eof) - return rv; - - /* We possibly have a directive of the form "directory " */ - rv = parse_directive(ptr, directive, directive_len, &db_info); - if (rv != LDAPU_SUCCESS) - return rv; - - /* We have parsed the directive successfully -- lets look for additional - * property-value pairs for the database. - */ - if (!fgets(buf, BIG_LINE, fp)) { - *eof = 1; - rv = LDAPU_SUCCESS; - } else { - rv = dbconf_read_propval(fp, buf, db_info, eof); - } - - if (rv != LDAPU_SUCCESS) { - dbconf_free_dbinfo(db_info); - *db_info_out = 0; - } else { - *db_info_out = db_info; - } - - return rv; -} - -int -dbconf_read_config_file_sub(const char *file, - const char *directive, - const int directive_len, - DBConfInfo_t **conf_info_out) -{ - FILE *fp; - DBConfInfo_t *conf_info; - DBConfDBInfo_t *db_info; - char buf[BIG_LINE]; - int rv; - int eof; - - buf[0] = 0; - - if ((fp = fopen(file, "r")) == NULL) { - return LDAPU_ERR_CANNOT_OPEN_FILE; - } - - /* Allocate DBConfInfo_t */ - conf_info = (DBConfInfo_t *)malloc(sizeof(DBConfInfo_t)); - - if (!conf_info) { - fclose(fp); - return LDAPU_ERR_OUT_OF_MEMORY; - } - - memset((void *)conf_info, 0, sizeof(DBConfInfo_t)); - - /* Read each db info */ - eof = 0; - while (!eof && - ((rv = read_db_info(fp, buf, &db_info, directive, directive_len, &eof)) == LDAPU_SUCCESS)) { - insert_dbconf_dbinfo(conf_info, db_info); - } - - if (rv != LDAPU_SUCCESS) { - dbconf_free_confinfo(conf_info); - *conf_info_out = 0; - } else { - *conf_info_out = conf_info; - } - - fclose(fp); - return rv; -} - -NSAPI_PUBLIC int -dbconf_read_config_file(const char *file, DBConfInfo_t **conf_info_out) -{ - return dbconf_read_config_file_sub(file, DB_DIRECTIVE, DB_DIRECTIVE_LEN, - conf_info_out); -} - -int -dbconf_read_default_dbinfo_sub(const char *file, - const char *directive, - const int directive_len, - DBConfDBInfo_t **db_info_out) -{ - FILE *fp; - DBConfDBInfo_t *db_info; - char buf[BIG_LINE]; - int rv; - int eof; - - buf[0] = 0; - - if ((fp = fopen(file, "r")) == NULL) { - return LDAPU_ERR_CANNOT_OPEN_FILE; - } - - /* Read each db info until eof or dbname == default*/ - eof = 0; - - while (!eof && - ((rv = read_db_info(fp, buf, &db_info, directive, directive_len, &eof)) == LDAPU_SUCCESS)) { - if (!strcmp(db_info->dbname, DBCONF_DEFAULT_DBNAME)) - break; - dbconf_free_dbinfo(db_info); - db_info = NULL; - } - - if (rv != LDAPU_SUCCESS) { - *db_info_out = 0; - } else { - *db_info_out = db_info; - } - - fclose(fp); - return rv; -} - - -NSAPI_PUBLIC int -dbconf_read_default_dbinfo(const char *file, - DBConfDBInfo_t **db_info_out) -{ - return dbconf_read_default_dbinfo_sub(file, DB_DIRECTIVE, DB_DIRECTIVE_LEN, - db_info_out); -} - -/* - * ldapu_strcasecmp - is like strcasecmp on UNIX but also accepts null strings. - */ -int -ldapu_strcasecmp(const char *s1, const char *s2) -{ - - if (!s1) - return !s2 ? 0 : 0 - tolower(*s2); - else if (!s2) - return tolower(*s1); - - return strcasecmp(s1, s2); -} - -NSAPI_PUBLIC int -ldapu_dbinfo_attrval(DBConfDBInfo_t *db_info, - const char *attr, - char **val) -{ - /* Look for given attr in the db_info and return its value */ - int rv = LDAPU_ATTR_NOT_FOUND; - DBPropVal_t *next; - - *val = 0; - - if (db_info) { - next = db_info->firstprop; - while (next) { - rv = ldapu_strcasecmp(attr, next->prop); - if (!rv) { - /* Found the property */ - *val = next->val ? strdup(next->val) : 0; - - if (next->val && !*val) { - rv = LDAPU_ERR_OUT_OF_MEMORY; - } else { - rv = LDAPU_SUCCESS; - } - break; - } - next = next->next; - } - } - - return rv; -} - -void -dbconf_print_propval(DBPropVal_t *propval) -{ - if (propval) { - fprintf(stderr, "\tprop: \"%s\"\tval: \"%s\"\n", propval->prop, - propval->val ? propval->val : ""); - } else { - fprintf(stderr, "Null propval\n"); - } -} - -void -dbconf_print_dbinfo(DBConfDBInfo_t *db_info) -{ - DBPropVal_t *next; - - if (db_info) { - fprintf(stderr, "dbname: \"%s\"\n", db_info->dbname); - fprintf(stderr, "url: \t\"%s\"\n", db_info->url ? db_info->url : ""); - next = db_info->firstprop; - while (next) { - dbconf_print_propval(next); - next = next->next; - } - } else { - fprintf(stderr, "Null db_info\n"); - } -} - -void -dbconf_print_confinfo(DBConfInfo_t *conf_info) -{ - DBConfDBInfo_t *next; - - if (conf_info) { - next = conf_info->firstdb; - while (next) { - dbconf_print_dbinfo(next); - next = next->next; - } - } else { - fprintf(stderr, "Null conf_info\n"); - } -} - - -NSAPI_PUBLIC int -dbconf_output_db_directive(FILE *fp, const char *dbname, const char *url) -{ - fprintf(fp, "%s %s %s\n", DB_DIRECTIVE, dbname, url); - return LDAPU_SUCCESS; -} - -NSAPI_PUBLIC int -dbconf_output_propval(FILE *fp, const char *dbname, const char *prop, const char *val, const int encoded) -{ - if (encoded && val && *val) { - char *new_val = dbconf_encodeval(val); - - if (!new_val) - return LDAPU_ERR_OUT_OF_MEMORY; - fprintf(fp, "%s:%s %s %s\n", dbname, ENCODED, - prop, new_val); - free(new_val); - } else { - fprintf(fp, "%s:%s %s\n", dbname, prop, val ? val : ""); - } - - return LDAPU_SUCCESS; -} - - -NSAPI_PUBLIC int -dbconf_get_dbnames(const char *dbmap, char ***dbnames_out, int *cnt_out) -{ - DBConfInfo_t *conf_info = 0; - DBConfDBInfo_t *db = 0; - int cnt = 0; - char **dbnames = 0; - char *heap = 0; - int rv; - - *dbnames_out = 0; - *cnt_out = 0; - - rv = dbconf_read_config_file(dbmap, &conf_info); - - if (rv != LDAPU_SUCCESS) - return rv; - - db = conf_info->firstdb; - - - dbnames = (char **)malloc(32 * 1024); - heap = (char *)dbnames + 2 * 1024; - - if (!dbnames) { - dbconf_free_confinfo(conf_info); - return LDAPU_ERR_OUT_OF_MEMORY; - } - - *dbnames_out = dbnames; - - while (db) { - *dbnames++ = heap; - strcpy(heap, db->dbname); - heap += strlen(db->dbname) + 1; - db = db->next; - cnt++; - } - - *dbnames = NULL; - *cnt_out = cnt; - dbconf_free_confinfo(conf_info); - - return LDAPU_SUCCESS; -} - -NSAPI_PUBLIC int -dbconf_free_dbnames(char **dbnames) -{ - if (dbnames) - free(dbnames); - - return LDAPU_SUCCESS; -} diff --git a/lib/ldaputil/encode.c b/lib/ldaputil/encode.c deleted file mode 100644 index 3219c8d..0000000 --- a/lib/ldaputil/encode.c +++ /dev/null @@ -1,151 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - - -/* This was malloc.h - but it's moved to stdlib.h on most platforms, and FBSD is strict */ -/* Make it stdlib.h, and revert to malloc.h with ifdefs if we have issues here. WB 2016 */ -#include -#include -#include -#include - -/* The magic set of 64 chars in the uuencoded data */ -static unsigned char uuset[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', - 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '+', '/'}; - -static int -do_uuencode(unsigned char *src, unsigned char *dst, int srclen) -{ - int i, r; - unsigned char *p; - - /* To uuencode, we snip 8 bits from 3 bytes and store them as -6 bits in 4 bytes. 6*4 == 8*3 (get it?) and 6 bits per byte -yields nice clean bytes - -It goes like this: - AAAAAAAA BBBBBBBB CCCCCCCC -turns into the standard set of uuencode ascii chars indexed by numbers: - 00AAAAAA 00AABBBB 00BBBBCC 00CCCCCC - -Snip-n-shift, snip-n-shift, etc.... - -*/ - - for (p = dst, i = 0; i < srclen; i += 3) { - /* Do 3 bytes of src */ - register char b0, b1, b2; - - b0 = src[0]; - if (i == srclen - 1) - b1 = b2 = '\0'; - else if (i == srclen - 2) { - b1 = src[1]; - b2 = '\0'; - } else { - b1 = src[1]; - b2 = src[2]; - } - - *p++ = uuset[b0 >> 2]; - *p++ = uuset[(((b0 & 0x03) << 4) | ((b1 & 0xf0) >> 4))]; - *p++ = uuset[(((b1 & 0x0f) << 2) | ((b2 & 0xc0) >> 6))]; - *p++ = uuset[b2 & 0x3f]; - src += 3; - } - *p = 0; /* terminate the string */ - r = (unsigned char *)p - (unsigned char *)dst; /* remember how many we did */ - - /* Always do 4-for-3, but if not round threesome, have to go - clean up the last extra bytes */ - - for (; i != srclen; i--) - *--p = '='; - - return r; -} - -const unsigned char pr2six[256] = { - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}; - -static char * -_uudecode(const char *bufcoded) -{ - register const char *bufin = bufcoded; - register unsigned char *bufout; - register int nprbytes; - unsigned char *bufplain; - int nbytesdecoded; - - /* Find the length */ - while (pr2six[(int)*(bufin++)] <= 63) - ; - nprbytes = bufin - bufcoded - 1; - nbytesdecoded = ((nprbytes + 3) / 4) * 3; - - bufout = (unsigned char *)malloc(nbytesdecoded + 1); - bufplain = bufout; - - bufin = bufcoded; - - while (nprbytes > 0) { - *(bufout++) = (unsigned char)(pr2six[(int)(*bufin)] << 2 | pr2six[(int)bufin[1]] >> 4); - *(bufout++) = (unsigned char)(pr2six[(int)bufin[1]] << 4 | pr2six[(int)bufin[2]] >> 2); - *(bufout++) = (unsigned char)(pr2six[(int)bufin[2]] << 6 | pr2six[(int)bufin[3]]); - bufin += 4; - nprbytes -= 4; - } - - if (nprbytes & 03) { - if (pr2six[(int)bufin[-2]] > 63) - nbytesdecoded -= 2; - else - nbytesdecoded -= 1; - } - bufplain[nbytesdecoded] = '\0'; - - return (char *)bufplain; -} - - -char * -dbconf_encodeval(const char *val) -{ - int len = strlen(val); - char *dst = (char *)malloc(2 * len); - - if (dst) { - do_uuencode((unsigned char *)val, (unsigned char *)dst, len); - } - - return dst; -} - -char * -dbconf_decodeval(const char *val) -{ - return _uudecode(val); -} diff --git a/lib/ldaputil/errors.c b/lib/ldaputil/errors.c deleted file mode 100644 index ada1d31..0000000 --- a/lib/ldaputil/errors.c +++ /dev/null @@ -1,210 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - - -#include -#include - -NSAPI_PUBLIC char * -ldapu_err2string(int err) -{ - char *rv; - - switch (err) { - - /* Error codes defined in certmap.h */ - case LDAPU_SUCCESS: - rv = "success"; - break; - case LDAPU_FAILED: - rv = "ldap search didn't find an ldap entry"; - break; - case LDAPU_CERT_MAP_FUNCTION_FAILED: - rv = "Cert mapping function failed"; - break; - case LDAPU_CERT_SEARCH_FUNCTION_FAILED: - rv = "Cert search function failed"; - break; - case LDAPU_CERT_VERIFY_FUNCTION_FAILED: - rv = "Cert verify function failed"; - break; - case LDAPU_CERT_MAP_INITFN_FAILED: - rv = "Certmap InitFn function failed"; - break; - - - /* Error codes returned by ldapdb.c */ - case LDAPU_ERR_URL_INVALID_PREFIX: - rv = "invalid local ldap database url prefix -- must be ldapdb://"; - break; - case LDAPU_ERR_URL_NO_BASEDN: - rv = "base dn is missing in ldapdb url"; - break; - case LDAPU_ERR_OUT_OF_MEMORY: - rv = "out of memory"; - break; - case LDAPU_ERR_LDAP_INIT_FAILED: - rv = "Couldn't initialize connection to the ldap directory server"; - break; - case LDAPU_ERR_LCACHE_INIT_FAILED: - rv = "Couldn't initialize connection to the local ldap directory"; - break; - case LDAPU_ERR_LDAP_SET_OPTION_FAILED: - rv = "ldap_set_option failed for local ldap database"; - break; - case LDAPU_ERR_NO_DEFAULT_CERTDB: - rv = "default cert database not initialized when using LDAP over SSL"; - break; - - - /* Errors returned by ldapauth.c */ - case LDAPU_ERR_CIRCULAR_GROUPS: - rv = "Circular groups were detected during group membership check"; - break; - case LDAPU_ERR_INVALID_STRING: - rv = "Invalid string"; - break; - case LDAPU_ERR_INVALID_STRING_INDEX: - rv = "Invalid string index"; - break; - case LDAPU_ERR_MISSING_ATTR_VAL: - rv = "Missing attribute value from the search result"; - break; - - - /* Errors returned by dbconf.c */ - case LDAPU_ERR_CANNOT_OPEN_FILE: - rv = "cannot open the config file"; - break; - case LDAPU_ERR_DBNAME_IS_MISSING: - rv = "database name is missing"; - break; - case LDAPU_ERR_PROP_IS_MISSING: - rv = "database property is missing"; - break; - case LDAPU_ERR_DIRECTIVE_IS_MISSING: - rv = "illegal directive in the config file"; - break; - case LDAPU_ERR_NOT_PROPVAL: - rv = "internal error - LDAPU_ERR_NOT_PROPVAL"; - break; - - - /* Error codes returned by certmap.c */ - case LDAPU_ERR_NO_ISSUERDN_IN_CERT: - rv = "cannot extract issuer DN from the cert"; - break; - case LDAPU_ERR_NO_ISSUERDN_IN_CONFIG_FILE: - rv = "issuer DN missing for non-default certmap"; - break; - case LDAPU_ERR_CERTMAP_INFO_MISSING: - rv = "cert to ldap entry mapping information is missing"; - break; - case LDAPU_ERR_MALFORMED_SUBJECT_DN: - rv = "Found malformed subject DN in the certificate"; - break; - case LDAPU_ERR_MAPPED_ENTRY_NOT_FOUND: - rv = "Certificate couldn't be mapped to an ldap entry"; - break; - case LDAPU_ERR_UNABLE_TO_LOAD_PLUGIN: - rv = "Unable to load certmap plugin library"; - break; - case LDAPU_ERR_MISSING_INIT_FN_IN_CONFIG: - rv = "InitFn must be provided when using certmap plugin library"; - break; - case LDAPU_ERR_MISSING_INIT_FN_IN_LIB: - rv = "Could not find InitFn in the certmap plugin library"; - break; - case LDAPU_ERR_CERT_VERIFY_FAILED: - rv = "Could not matching certificate in User's LDAP entry"; - break; - case LDAPU_ERR_CERT_VERIFY_NO_CERTS: - rv = "User's LDAP entry doesn't have any certificates to compare"; - break; - case LDAPU_ERR_MISSING_LIBNAME: - rv = "Library name is missing in the config file"; - break; - case LDAPU_ERR_MISSING_INIT_FN_NAME: - rv = "Init function name is missing in the config file"; - break; - case LDAPU_ERR_WRONG_ARGS: - rv = "ldaputil API function called with wrong arguments"; - break; - case LDAPU_ERR_RENAME_FILE_FAILED: - rv = "Renaming of file failed"; - break; - case LDAPU_ERR_MISSING_VERIFYCERT_VAL: - rv = "VerifyCert property value must be on or off"; - break; - case LDAPU_ERR_CANAME_IS_MISSING: - rv = "Cert issuer name is missing"; - break; - case LDAPU_ERR_CAPROP_IS_MISSING: - rv = "property name is missing"; - break; - case LDAPU_ERR_UNKNOWN_CERT_ATTR: - rv = "unknown cert attribute"; - break; - - - case LDAPU_ERR_EMPTY_LDAP_RESULT: - rv = "ldap search returned empty result"; - break; - case LDAPU_ERR_MULTIPLE_MATCHES: - rv = "ldap search returned multiple matches when one expected"; - break; - case LDAPU_ERR_MISSING_RES_ENTRY: - rv = "Could not extract entry from the ldap search result"; - break; - case LDAPU_ERR_MISSING_UID_ATTR: - rv = "ldap entry is missing the 'uid' attribute value"; - break; - case LDAPU_ERR_INVALID_ARGUMENT: - rv = "invalid argument passed to the certmap API function"; - break; - case LDAPU_ERR_INVALID_SUFFIX: - rv = "invalid LDAP directory suffix"; - break; - - - /* Error codes returned by cert.c */ - case LDAPU_ERR_EXTRACT_SUBJECTDN_FAILED: - rv = "Couldn't extract the subject DN from the certificate"; - break; - case LDAPU_ERR_EXTRACT_ISSUERDN_FAILED: - rv = "Couldn't extract the issuer DN from the certificate"; - break; - case LDAPU_ERR_EXTRACT_DERCERT_FAILED: - rv = "Couldn't extract the original DER encoding from the certificate"; - break; - - - case LDAPU_ERR_NOT_IMPLEMENTED: - rv = "function not implemented yet"; - break; - case LDAPU_ERR_INTERNAL: - rv = "ldaputil internal error"; - break; - - default: - if (err > 0) { - /* LDAP errors are +ve */ - rv = ldap_err2string(err); - } else { - rv = "internal error - unknown error code"; - } - break; - } - - return rv; -} diff --git a/lib/ldaputil/examples/Makefile b/lib/ldaputil/examples/Makefile deleted file mode 100644 index d7aa9d6..0000000 --- a/lib/ldaputil/examples/Makefile +++ /dev/null @@ -1,89 +0,0 @@ -# -# BEGIN COPYRIGHT BLOCK -# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -# Copyright (C) 2005 Red Hat, Inc. -# All rights reserved. -# -# License: GPL (version 3 or any later version). -# See LICENSE for details. -# END COPYRIGHT BLOCK -# -# -# Makefile for certmap example program. -# - -# -# Please set the ARCH variable to one of the following: -# SOLARIS, IRIX, HPUX -# -ARCH = - - -# -# Please set the SROOT to be same as your server root -# -SROOT = - -# -# Uncomment the following if you need the debug build -# -#COMMON_DEFS = -g - -ifndef ARCH -arch: - @echo "Please edit the Makefile and set the variable: ARCH" - @exit 1 -endif - -ifndef SROOT -sroot: - @echo "Please edit the Makefile and set the server root variable: SROOT" - @exit 1 -endif - -ifeq ($(ARCH), SOLARIS) -CC_CMD = cc -DSOLARIS -D_REENTRANT -LD_SHAREDCMD = ld -G -endif - -ifeq ($(ARCH), HPUX) - BIN = certmap.sl -else - BIN = certmap.so -endif - -OBJS = init.o plugin.o - -INCLUDE_FLAGS=-I. -I$(SROOT)/include - -INC_FILES = \ - $(SROOT)/include/certmap.h \ - $(SROOT)/include/ldap.h \ - $(SROOT)/include/lber.h - -all: $(BIN) - -$(INC_FILES): - @echo - @echo "To extend the Certificate to LDAP entry mapping by" - @echo "writing your own functions, you need to download the" - @echo "Certmap API (version 1.0) and LDAP SDK (version 1.0)." - @echo "Please download these from http://???" - @echo "Make sure the following files exist:" - @echo "\t$(SROOT)/include/certmap.h" - @echo "\t$(SROOT)/include/ldap.h" - @echo "\t$(SROOT)/include/lber.h" - @echo - @exit 1 - -$(BIN): $(INC_FILES) $(OBJS) - $(LD_SHAREDCMD) $(OBJS) -o $@ $(EXTRA_LDDEFINES) - -certmap.dll: $(OBJS) - $(LD_SHAREDCMD) $(OBJS) -o $@ $(EXTRA_LDDEFINES) - -.c.o: - $(CC_CMD) $(COMMON_DEFS) $(INCLUDE_FLAGS) -c $< - -clean: - rm -f $(OBJS) certmap.so $(EXTRA_CLEAN) diff --git a/lib/ldaputil/examples/README b/lib/ldaputil/examples/README deleted file mode 100644 index 3ea7a74..0000000 --- a/lib/ldaputil/examples/README +++ /dev/null @@ -1,100 +0,0 @@ -# BEGIN COPYRIGHT BLOCK -# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -# Copyright (C) 2005 Red Hat, Inc. -# All rights reserved. -# -# License: GPL (version 3 or any later version). -# See LICENSE for details. -# END COPYRIGHT BLOCK -# - -This directory contains an example program to demonstrate -writing plugins using the "Certificate to LDAP Mapping" API. -Please read the "Managing Servers" manual to find out -about how certificate to ldap mapping can be configured using -the /userdb/certmap.conf file. Also refer to the -"Certificate to LDAP Mapping API" documentation to find out -about the various API functions and how you can write your -plugin. - -This example demonstrate use of most of the API functions. It -defines a mapping function, a search function, and a verify -function. Read the API doc to learn about these functions. -The init.c file also contains an init function which sets the -mapping, search and verify functions. - -The Mapping Function --------------------- - -The mapping function extracts the attributes "CN", "E", "O" and -"C" from the certificate's subject DN using the function -ldapu_get_cert_ava_val. If the attributes "C" doesn't exists -then it defaults to "US". It then gets the value of a custom -certmap.conf property "defaultOU" using the function -ldapu_certmap_info_attrval. This demonstrates how you can have -your own custom properties defined in the certmap.conf file. -The mapping function then returns an ldapdn of the form: -"cn=, ou=, o=, c=". - -If the "E" attribute has a value, it returns a filter -"mail=". Finally, the mapping function frees the structures -returned by some of the API functions it called. - - -The Search Function -------------------- - -The search function calls a dummy function to get the -certificate's serial number. It then does a subtree search in -the entire directory for the filter -"certSerialNumber=". If this fails, it calls the -default search function. This demonstrates how you can use the -default functions in your custom functions. - -The Verify Function -------------------- - -The verify function returns LDAPU_SUCCESS if only one entry was -returned by the search function. Otherwise, it returns -LDAPU_CERT_VERIFY_FUNCTION_FAILED. - - -Error Reporting ---------------- - -To report errors/warning, there is a function defined called -plugin_ereport. This function demonstrates how to get the -subject DN and the issuer DN from the certificate. - -Build Procedure ---------------- -On UNIX: Edit the Makefile, and set the variables ARCH & SROOT -according to the comments in the Makefile. Download LDAP C SDK -from the mozilla.org site and make the ldap include -files available in /include. Copy the -../include/certmap.h file to the /include directory. -Use 'gmake' to build the plugin. A shared library plugin.so -(plugin.sl on HP) will be created in the current directory. - -On NT: Execute the following command: -NMAKE /f "Certmap.mak" CFG="Certmap - Win32 Debug" -Certmap.dll will be created in the Debug subdirectory. - -Certmap.conf Configuration --------------------------- -Save a copy of certmap.conf file. -Change the certmap.conf file as follows: - -certmap default default -default:defaultOU marketing -default:library -default:InitFn plugin_init_fn - - -After experimenting with this example, restore the old copy of -certmap.conf file. Or else, set the certmap.conf file as follows: - -certmap default default -default:DNComps -default:FilterComps e, mail, uid -default:VerifyCert on diff --git a/lib/ldaputil/examples/init.c b/lib/ldaputil/examples/init.c deleted file mode 100644 index b10473a..0000000 --- a/lib/ldaputil/examples/init.c +++ /dev/null @@ -1,44 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - - -#include -#include -#include -#include -#include "certmap.h" /* Public Certmap API */ -#include "plugin.h" /* must define extern "C" functions */ - - -NSAPI_PUBLIC int -plugin_init_fn(void *certmap_info, const char *issuerName, const CERTName *issuerDN, const char *libname) -{ - static int initialized = 0; - int rv; - - /* Make sure CertmapDLLInit is initialized only once */ - if (!initialized) { - - initialized = 1; - } - - fprintf(stderr, "plugin_init_fn called.\n"); - ldapu_set_cert_mapfn(issuerDN, plugin_mapping_fn); - ldapu_set_cert_verifyfn(issuerDN, plugin_verify_fn); - - if (!default_searchfn) - default_searchfn = ldapu_get_cert_searchfn(issuerDN); - - ldapu_set_cert_searchfn(issuerDN, plugin_search_fn); - return LDAPU_SUCCESS; -} diff --git a/lib/ldaputil/examples/plugin.c b/lib/ldaputil/examples/plugin.c deleted file mode 100644 index baacb70..0000000 --- a/lib/ldaputil/examples/plugin.c +++ /dev/null @@ -1,240 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - - -#include -#include -#include -#include "certmap.h" /* Public Certmap API */ -#include "plugin.h" /* must define extern "C" functions */ - - -CertSearchFn_t default_searchfn = 0; - - -/* plugin_ereport - - This function prints an error message to stderr. It prints the issuerDN - and subjectDN alongwith the given message. - */ -static void -plugin_ereport(const char *msg, void *cert) -{ - int rv; - char *subjectDN; - char *issuerDN; - char *default_subjectDN = "Failed to get the subject DN"; - char *default_issuerDN = "Failed to get the issuer DN"; - - rv = ldapu_get_cert_subject_dn(cert, &subjectDN); - - if (rv != LDAPU_SUCCESS || !subjectDN) { - subjectDN = default_subjectDN; - } - - rv = ldapu_get_cert_issuer_dn(cert, &issuerDN); - - if (rv != LDAPU_SUCCESS || !issuerDN) { - issuerDN = default_issuerDN; - } - - fprintf(stderr, "%s. Issuer: %s, Subject: %s\n", msg, issuerDN, - subjectDN); - - if (default_subjectDN != subjectDN) - ldapu_free(subjectDN); - if (default_issuerDN != issuerDN) - ldapu_free(issuerDN); -} - - -/* plugin_mapping_fn - - This mapping function extracts "CN", "O" and "C" attributes from the - subject DN to form ldapDN. It inserts "ou=" between the - "CN" and the "O" attr-value pair. The can be configured in - the certmap.conf config file. - If the "C" attr is absent, it defaults to "US". - It extracts the "E" attribute to form the filter. - */ -int -plugin_mapping_fn(void *cert, LDAP *ld, void *certmap_info, char **ldapDN, char **filter) -{ - char **cn_val; /* get this from the cert */ - char **o_val; /* get this from the cert */ - char **c_val; /* get this from the cert */ - char **e_val; /* get this from the cert */ - char *ou_val; /* get this from the config file */ - int len; - int rv; - - fprintf(stderr, "plugin_mapping_fn called.\n"); - - rv = ldapu_get_cert_ava_val(cert, LDAPU_SUBJECT_DN, "CN", &cn_val); - - if (rv != LDAPU_SUCCESS || !cn_val) { - plugin_ereport("plugin_mapping_fn: Failed to extract \"CN\" from the cert", cert); - return LDAPU_CERT_MAP_FUNCTION_FAILED; - } - - rv = ldapu_get_cert_ava_val(cert, LDAPU_SUBJECT_DN, "O", &o_val); - - if (rv != LDAPU_SUCCESS || !o_val) { - plugin_ereport("plugin_mapping_fn: Failed to extract \"O\" from the cert", cert); - return LDAPU_CERT_MAP_FUNCTION_FAILED; - } - - rv = ldapu_get_cert_ava_val(cert, LDAPU_SUBJECT_DN, "C", &c_val); - - if (rv != LDAPU_SUCCESS || !c_val) { - plugin_ereport("plugin_mapping_fn: Failed to extract \"C\" from the cert", cert); - } - - rv = ldapu_get_cert_ava_val(cert, LDAPU_SUBJECT_DN, "E", &e_val); - - if (rv != LDAPU_SUCCESS || !e_val) { - /* Don't return error -- just print the warning */ - plugin_ereport("plugin_mapping_fn: Failed to extract \"E\" from the cert", cert); - } - - /* Get the "OU" from the "defaultOU" property from the config file */ - rv = ldapu_certmap_info_attrval(certmap_info, "defaultOU", &ou_val); - - if (rv != LDAPU_SUCCESS || !ou_val) { - plugin_ereport("plugin_mapping_fn: Failed to get \"defaultOU\" from the configuration", cert); - return LDAPU_CERT_MAP_FUNCTION_FAILED; - } - - len = strlen("cn=, ou=, o=, c=") + strlen(cn_val[0]) + strlen(ou_val) + - strlen(o_val[0]) + (c_val ? strlen(c_val[0]) : strlen("US")) + 1; - *ldapDN = (char *)ldapu_malloc(len); - - if (!*ldapDN) { - plugin_ereport("plugin_mapping_fn: Ran out of memory", cert); - return LDAPU_CERT_MAP_FUNCTION_FAILED; - } - - if (e_val) { - len = strlen("mail=") + strlen(e_val[0]) + 1; - *filter = (char *)ldapu_malloc(len); - - if (!*filter) { - free(*ldapDN); - plugin_ereport("plugin_mapping_fn: Ran out of memory", cert); - return LDAPU_CERT_MAP_FUNCTION_FAILED; - } - sprintf(*filter, "mail=%s", e_val[0]); - } else { - *filter = 0; - } - - sprintf(*ldapDN, "cn=%s, ou=%s, o=%s, c=%s", cn_val[0], ou_val, - o_val[0], c_val ? c_val[0] : "US"); - - ldapu_free_cert_ava_val(cn_val); - ldapu_free_cert_ava_val(o_val); - ldapu_free_cert_ava_val(c_val); - ldapu_free_cert_ava_val(e_val); - ldapu_free(ou_val); - - fprintf(stderr, "plugin_mapping_fn Returned:\n\tldapDN: \"%s\"\n\tfilter: \"%s\"\n", - *ldapDN, *filter ? *filter : ""); - - return LDAPU_SUCCESS; -} - - -int -plugin_cert_serial_number(void *cert) -{ - /* Just a stub function. You can get the DER encoded cert by using the - function ldapu_get_cert_der: - */ - unsigned char *derCert; - unsigned int len; - int rv; - int sno; - - rv = ldapu_get_cert_der(cert, &derCert, &len); - - /* extract the serial number from derCert */ - sno = 43534754; /* a fake value for now */ - - ldapu_free((char *)derCert); - - return sno; -} - -/* plugin_search_fn - - This function first does a search based on the cert's serial number. - If that fails, it calls the default search function. - */ -int -plugin_search_fn(void *cert, LDAP *ld, void *certmap_info, const char *suffix, const char *ldapdn, const char *filter, const char **attrs, LDAPMessage **res) -{ - int rv; - char snoFilter[256]; - - fprintf(stderr, "plugin_search_fn called.\n"); - sprintf(snoFilter, "certSerialNumber=%d", - plugin_cert_serial_number(cert)); - - /* Search the entire LDAP tree for "certSerialNumber=" */ - rv = ldap_search_s(ld, suffix, LDAP_SCOPE_SUBTREE, snoFilter, - (char **)attrs, 0, res); - - /* ldap_search_s returns LDAP_SUCCESS (rather than LDAPU_SUCCESS) - if there is no error but there may not be any matching entries. - */ - if (rv == LDAP_SUCCESS) { - /* There was no error but check if any entries matched */ - int numEntries = ldap_count_entries(ld, *res); - - if (numEntries > 0) { - /* at least one entry matched */ - /* change the return value to LDAPU_SUCCESS from LDAP_SUCCESS */ - rv = LDAPU_SUCCESS; - } else { - /* Try the default search function */ - rv = (*default_searchfn)(cert, ld, certmap_info, suffix, ldapdn, - filter, attrs, res); - } - } - - /* It's ok to return the error code from ldap_search_s */ - return rv; -} - -/* - plugin_verify_fn - - This function returns success if only one entry exists in 'res'. - */ -int -plugin_verify_fn(void *cert, LDAP *ld, void *certmap_info, LDAPMessage *res, LDAPMessage **entry) -{ - int rv; - int numEntries; - - fprintf(stderr, "plugin_verify_fn called.\n"); - numEntries = ldap_count_entries(ld, res); - - if (numEntries == 1) { - *entry = ldap_first_entry(ld, res); - rv = LDAPU_SUCCESS; - } else { - plugin_ereport("plugin_verify_fn: Failing because multiple entries matched.", - cert); - *entry = 0; - rv = LDAPU_CERT_VERIFY_FUNCTION_FAILED; - } - - return rv; -} diff --git a/lib/ldaputil/examples/plugin.h b/lib/ldaputil/examples/plugin.h deleted file mode 100644 index e7e5282..0000000 --- a/lib/ldaputil/examples/plugin.h +++ /dev/null @@ -1,35 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - -#ifndef _CERTMAP_PLUGIN_H -#define _CERTMAP_PLUGIN_H - -extern CertSearchFn_t default_searchfn; - -#ifdef __cplusplus -extern "C" { -#endif - -extern int plugin_mapping_fn(void *cert, LDAP *ld, void *certmap_info, char **ldapDN, char **filter); - -extern int plugin_search_fn(void *cert, LDAP *ld, void *certmap_info, const char *basedn, const char *dn, const char *filter, const char **attrs, LDAPMessage **res); - -extern int plugin_verify_fn(void *cert, LDAP *ld, void *certmap_info, LDAPMessage *res, LDAPMessage **entry); - -NSAPI_PUBLIC int plugin_init_fn(void *certmap_info, const char *issuerName, const char *issuerDN, const char *dllname); - -#ifdef __cplusplus -} -#endif - -#endif /* _CERTMAP_PLUGIN_H */ diff --git a/lib/ldaputil/init.c b/lib/ldaputil/init.c deleted file mode 100644 index c7d59d1..0000000 --- a/lib/ldaputil/init.c +++ /dev/null @@ -1,138 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - - -#include -#include -#include -#include - -/*#include "base/file.h"*/ -#include "ldaputil/certmap.h" -/*#include "ldaputil/ldapdb.h"*/ -#include "ldaputil/ldaputil.h" -#include "ldaputil/cert.h" -#include "ldaputil/errors.h" -#include "ldaputil/init.h" - -#include "slapi-plugin.h" - -#ifndef FILE_PATHSEP -#define FILE_PATHSEP '/' -#endif -#ifdef HPUX -#ifdef __ia64 -#define DLL_SUFFIX ".so" -#else -#define DLL_SUFFIX ".sl" -#endif -#else -#define DLL_SUFFIX ".so" -#endif - -static int -load_server_libs(const char *dir) -{ - int rv = LDAPU_SUCCESS; - PRDir *ds; - int suffix_len = strlen(DLL_SUFFIX); - - if ((ds = PR_OpenDir(dir)) != NULL) { - PRDirEntry *d; - - /* Dir exists */ - while ((d = PR_ReadDir(ds, PR_SKIP_BOTH))) { - PRLibrary *lib = 0; - const char *libname = d->name; - int len = strlen(libname); - int is_lib; - - is_lib = (len > suffix_len && !strcmp(libname + len - suffix_len, DLL_SUFFIX)); - - if (is_lib) { - char path[1024]; - - PR_snprintf(path, sizeof(path), "%s%c%s", dir, FILE_PATHSEP, libname); - lib = PR_LoadLibrary(path); - if (!lib) - rv = LDAPU_ERR_UNABLE_TO_LOAD_PLUGIN; - } - } - } else { - /* It's ok if dir doesn't exists */ - } - - return rv; -} - -NSAPI_PUBLIC int -ldaputil_init(const char *config_file, - const char *dllname, - const char *serv_root, - const char *serv_type, - const char *serv_id) -{ - int rv = LDAPU_SUCCESS; - static int initialized = 0; - - /* If already initialized, cleanup the old structures */ - if (initialized) - ldaputil_exit(); - - if (config_file && *config_file) { - char dir[1024]; - - LDAPUCertMapListInfo_t *certmap_list; - LDAPUCertMapInfo_t *certmap_default; - - if (serv_root && *serv_root) { - /* Load common libraries */ - PR_snprintf(dir, sizeof(dir), "%s%clib%c%s", serv_root, FILE_PATHSEP, - FILE_PATHSEP, "common"); - rv = load_server_libs(dir); - - if (rv != LDAPU_SUCCESS) - return rv; - - if (serv_type && *serv_type) { - /* Load server type specific libraries */ - sprintf(dir, "%s%clib%c%s", serv_root, FILE_PATHSEP, - FILE_PATHSEP, serv_type); - rv = load_server_libs(dir); - - if (rv != LDAPU_SUCCESS) - return rv; - - if (serv_id && *serv_id) { - /* Load server instance specific libraries */ - sprintf(dir, "%s%clib%c%s", serv_root, FILE_PATHSEP, - FILE_PATHSEP, serv_id); - rv = load_server_libs(dir); - - if (rv != LDAPU_SUCCESS) - return rv; - } - } - } - - rv = ldapu_certmap_init(config_file, dllname, &certmap_list, - &certmap_default); - } - - initialized = 1; - - if (rv != LDAPU_SUCCESS) - return rv; - - return rv; -} diff --git a/lib/ldaputil/ldapauth.c b/lib/ldaputil/ldapauth.c deleted file mode 100644 index 3420519..0000000 --- a/lib/ldaputil/ldapauth.c +++ /dev/null @@ -1,214 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - -/* - * ldapauth.cpp: Implements LDAP integration in the web server. - * - * Nitin More, John Kristian - */ - -/* #define DBG_PRINT */ - -#include /* for BUFSIZ */ -#include /* for strncpy, strcat */ -#include -#include - -#define DEFINE_LDAPU_STRINGS 1 -#include -#include -#include - -#include - -#include "slapi-plugin.h" - -/* - * ldapu_find - * Description: - * Caller should free res if it is not NULL. - * Arguments: - * ld Pointer to LDAP (assumes connection has been - * established and the client has called the - * appropriate bind routine) - * base basedn (where to start the search) - * scope scope for the search. One of - * LDAP_SCOPE_SUBTREE, LDAP_SCOPE_ONELEVEL, and - * LDAP_SCOPE_BASE - * filter LDAP filter - * attrs A NULL-terminated array of strings indicating which - * attributes to return for each matching entry. Passing - * NULL for this parameter causes all available - * attributes to be retrieved. - * attrsonly A boolean value that should be zero if both attribute - * types and values are to be returned, non-zero if only - * types are wanted. - * res A result parameter which will contain the results of - * the search upon completion of the call. - * Return Values: - * LDAPU_SUCCESS if entry is found - * LDAPU_FAILED if entry is not found - * if error, where can be passed to - * ldap_err2string to get an error string. - */ -int -ldapu_find(LDAP *ld, const char *base, int scope, const char *filter, const char **attrs, int attrsonly, LDAPMessage **res) -{ - int retval; -#ifdef USE_THIS_CODE /* ASYNCHRONOUS */ - int msgid; -#endif - int numEntries; - - *res = 0; - - /* If base is NULL set it to null string */ - if (!base) { - DBG_PRINT1("ldapu_find: basedn is missing -- assuming null string\n"); - base = ""; - } - - if (!filter || !*filter) { - DBG_PRINT1("ldapu_find: filter is missing -- assuming objectclass=*\n"); - filter = ldapu_strings[LDAPU_STR_FILTER_DEFAULT]; - } - - DBG_PRINT2("\tbase:\t\"%s\"\n", base); - DBG_PRINT2("\tfilter:\t\"%s\"\n", filter ? filter : ""); - DBG_PRINT2("\tscope:\t\"%s\"\n", - (scope == LDAP_SCOPE_SUBTREE ? "LDAP_SCOPE_SUBTREE" - : (scope == LDAP_SCOPE_ONELEVEL ? "LDAP_SCOPE_ONELEVEL" - : "LDAP_SCOPE_BASE"))); - - retval = ldapu_search_s(ld, base, scope, filter, (char **)attrs, - attrsonly, res); - - if (retval != LDAP_SUCCESS) { - /* retval = ldap_result2error(ld, *res, 0); */ - DBG_PRINT2("ldapu_search_s: %s\n", ldapu_err2string(retval)); - return (retval); - } - - numEntries = ldapu_count_entries(ld, *res); - - if (numEntries == 1) { - /* success */ - return LDAPU_SUCCESS; - } else if (numEntries == 0) { - /* not found -- but not an error */ - DBG_PRINT1("ldapu_search_s: Entry not found\n"); - return LDAPU_FAILED; - } else if (numEntries > 0) { - /* Found more than one entry! */ - DBG_PRINT1("ldapu_search_s: Found more than one entry\n"); - return LDAPU_ERR_MULTIPLE_MATCHES; - } else { - /* should never get here */ - DBG_PRINT1("ldapu_search_s: should never reach here\n"); - ldapu_msgfree(ld, *res); - return LDAP_OPERATIONS_ERROR; - } -} - - -/* Search function for the cases where base = "" = NULL suffix, that is, search to - * be performed on the entire DIT tree. - * We actually do various searches taking a naming context at a time as the base for - * the search. */ - -int -ldapu_find_entire_tree(LDAP *ld, int scope, const char *filter, const char **attrs, int attrsonly, LDAPMessage ***res) -{ - int retval = LDAPU_FAILED; - int rv, i, num_namingcontexts; - LDAPMessage *result_entry, *result = NULL; - const char *suffix_attr[2] = {"namingcontexts", NULL}; - /* these are private suffixes that may contain pseudo users - e.g. replication manager that may have certs */ - int num_private_suffix = 1; - const char *private_suffix_list[2] = {"cn=config", NULL}; - char **suffix_list, **suffix = NULL; - - rv = ldapu_find(ld, "", LDAP_SCOPE_BASE, "objectclass=*", suffix_attr, 0, &result); - if (rv != LDAP_SUCCESS) { - if (result) - ldapu_msgfree(ld, result); - return rv; - } - - result_entry = ldapu_first_entry(ld, result); - suffix = ldapu_get_values(ld, result_entry, suffix_attr[0]); - suffix_list = suffix; - num_namingcontexts = slapi_ldap_count_values(suffix); - /* add private suffixes to our list of suffixes to search */ - if (num_private_suffix) { - suffix_list = ldapu_realloc(suffix_list, - sizeof(char *) * (num_namingcontexts + num_private_suffix + 1)); - if (!suffix_list) { - if (result) { - ldapu_msgfree(ld, result); - } - retval = LDAPU_FAILED; - return retval; - } - for (i = num_namingcontexts; i < (num_namingcontexts + num_private_suffix); ++i) { - suffix_list[i] = strdup(private_suffix_list[i - num_namingcontexts]); - } - suffix_list[i] = NULL; - num_namingcontexts += num_private_suffix; - suffix = suffix_list; - } - if (result) - ldapu_msgfree(ld, result); - result = 0; - i = 0; - - /* ugaston - the caller function must remember to free the memory allocated here */ - *res = (LDAPMessage **)ldapu_malloc((num_namingcontexts + 1) * sizeof(LDAPMessage *)); - while (suffix && *suffix) { - rv = ldapu_find(ld, *suffix, scope, filter, attrs, attrsonly, &result); - if (scope == LDAP_SCOPE_BASE && rv == LDAP_SUCCESS) { - retval = rv; - (*res)[i++] = result; - break; - } - - switch (rv) { - case LDAP_SUCCESS: - if (retval == LDAP_SUCCESS) { - retval = LDAPU_ERR_MULTIPLE_MATCHES; - (*res)[i++] = result; - break; - } - /* FALLTHROUGH */ - case LDAPU_ERR_MULTIPLE_MATCHES: - retval = rv; - (*res)[i++] = result; - break; - default: - if (retval != LDAP_SUCCESS && retval != LDAPU_ERR_MULTIPLE_MATCHES) { - retval = rv; - } - if (result) - ldapu_msgfree(ld, result); - result = 0; - break; - } - - suffix++; - } - - (*res)[i] = NULL; - ldapu_value_free(ld, suffix_list); - return retval; -} diff --git a/lib/ldaputil/ldapu-changes.html b/lib/ldaputil/ldapu-changes.html deleted file mode 100644 index 00ec08f..0000000 --- a/lib/ldaputil/ldapu-changes.html +++ /dev/null @@ -1,406 +0,0 @@ - - - - - - - - - -
-

-Change Log for the ldaputil library

- -
-Author: Nitin More
- -
-E-mail:  nitin@netscape.com
- -
-Phone: (415) 937-4240
- -
- -
-
- -
- -
Changes since Apr 17, 1997
- - -

Last Update: Aug 25, 1997 - -

All the new changes have been checked into the server3_tier_branch.  -The server3_branch is frozen & contains the version of 'ldaputil' for -the SuiteSpot 3.0 release. -

-Changed:

-Several bug fixes went in since I last modified this file.  The important -ones are: -
    -
  • -79373: Attributes -listed multiple times in certmap.conf were turining that attribute off -and enabling some other attribute.  (For example, if you have "E" -as well as "MAIL" in FilterComps, they cancelled each other).
  • - -
  • -58474: If nested -group checks goes on for 30 recursions, a circular groups error is returned.
  • - -
  • -80004: after -thoroughly testing the certmap utility, several (mostly minor) oddities -were found & fixed.
  • -
- -

-Added:

- -
    -
  • -79370: Group -membership check is optimized now through the new function ldapu_auth_userdn_groupids.  -Use this new function to get the optimization.  This function's algorithm -is as follows:
  • - -
    The first search uses the following filter (w/o the group names!): -
      (| (& (objectclass=groupofuniquenames) -
            (uniquemember=<userDN>)) -
         (& (objectclass=groupofnames)(member=<userDN>))) -
       
    -This gives us all the groups the user is member of.  We ask for only -the "CN" attributes of the returned groups.  We check if "CN" of any -of the returned groups is one of the groups we have.  If yes, we have -succeeded.  If there are no groups returned then we have failed.  -Otherwise, we continue with the nested group check.  To perform that -check, we need DNs of all the groups the user is member of, which we already -have from the previous search.  Now we repeat the search as follows: -
      (| (& (objectclass=groupofuniquenames) -
            (| (uniquemember=<grp1DN>)... -(uniquemember=<grpNDN>)) -
         (& (objectclass=groupofnames) -
            (| (member=<grp1DN>)... (member=<grpNDN>))
    -We check the list of groups returned by this search with the groups in -the ACL and recursively continue until we succeed or no more groups are -returned from the searches. - -

    Advantages of this new function is it checks multiple groups at the -same time.  Previously we were performing 2 ldap lookups per group.  -Now we achieve this in a single ldap lookup! - -

    Caution: this function allows multiple groups -with the same "CN". - -

    To use this function, you need to provide a list of group names in any -form (e.g comma separated string, a hash table, array of strings, etc.) -and a function to compare the name returned by the ldap lookup with your -group names.

- -
Changes since Mar 22, 1997
- - -

Last Update: Apr 17, 1997 - -

Now that all beta releases are out for servers using this library, I -could do some incompatible changes to make this library more flexible. -No more incompatible changes are planned (except for possibly one: see -http://scopus/bugsplat/show_bug.cgi?id=58482). All 3.0 SuiteSpot -servers supporting client auth need to upgrade to this version. -

-Changed:

- -
    -
  • -Exchanged certmap.h & ldaputil.h: ldaputil.h had public API -but when the file was installed on the server root, it was called certmap.h. -Since we already had a certmap.h, this was causing lot of confusion. If -you were including "certmap.h", now include "ldaputil.h" and vice versa.
  • - -
  • -Renamed 'SearchComps' to 'FilterComps': Shouldn't affect your code -but may affect tests and documentation.
  • - -
  • -'VerifyCert' must be either "on" or "off": VerifyCert didn't have -a value. Now it must have a value. If it has a value of "on" then the "verification" -step is on, otherwise it is off.
  • - -
  • -Important bug fixes: One bug was causing stack corruption & -weird unpredictable results. The other important bug was to map 'E' in -cert to 'MAIL' in LDAP.
  • -
- -

-Added:

- -
    -
  • -Settable 'search function': User defined search function can be -set for cert to ldap mapping.
  • - -
  • -ldapu_get_cert_ava_val & ldapu_free_cert_ava_val: API functions -to get & free an attribute's value(s) from either the subject DN or -the issuer DN from a cert.
  • -
- -

-Open Bugs:

- -
    Following bugs may not get fixed by RTM.
- -
    -
  • -51279: 'uniquemember' -bug
  • - -
  • -58474:  -'circular groups' results in infinite loop
  • - -
  • -58478: Don't -allow a space as a valid delimeter for DNComps & FilterComps.
  • - -
  • -58482: Make -the 'search function' configurable.
  • - -
    -
- -
-

-Changes since Mar 18, 1997

- -
-Last Update: Mar 22, 1997
- -
-A query on how to map a verisign certificate prompted these changes.  -I was hoping I don't have to do any major changes when I wrote this document -on Mar 18. These are incompatible changes -- please review them before -you upgrade.  I have checked in this file in CVS under "ns/netsite/lib/ldaputil/ldapu-changes.html". -I have added all the "XYZ_branch" and "XYZ_point" tags to this file so -that you can easily see this file in your tree.  When I make significant -changes to this file/library, I will retag this file for your branch to -make it same as the server3_branch. [Let me know if I shouldn't do it for -your branch].
- -

-Changed:

- -
    -
  • -ldapu_cert_to_ldap_entry: The major change was to allow for the -mapped DN to be NULL and in that case, start the search from the basedn -of the LDAP server. This required API change so that the basedn can be -passed to the ldapu_cert_to_ldap_entry function. This change was required -for correctly mapping certs from verisign w/o writing plugins. The Verisign -certs can be mapped correctly using the following setting in the <ServerRoot>/userdb/certmap.conf -file:
  • - -
      certmap verisign <verisign's DN> -
      verisign:dncomps -
      verisign:searchcomps cn, e
    -The mapped DN will be NULL so basedn will be used.  The filter will -be -
    (& (cn="<user's CN>") (mail="<user's mail>")).  The -new signature of ldapu_cert_to_ldap_entry is as follows: -
        int ldapu_cert_to_ldap_entry(void *cert, LDAP *ld, -const char *basedn, LDAPMessage **res); -
  • -verify cert functions: A major change in how verify cert functions -work.  This is function is now called even when multiple potential -matches are found for the cert.  The mapping is successful if the -verify function can reduce the number of matches to exactly one.  -For example, if there are multiple "Joe Smith" entries, at most one of -those will have the cert in it's "userCertificate" attr.  The verify -function will select that entry.  The verify function is called with -"LDAPMessage *res" containing all the potential matches.  It should -return a pointer to the matched entry in the new "LDAPMessage **entry" -parameter.  The new signature for CertVerifyFn_t is as follows:
  • - -
        typedef int (*CertVerifyFn_t)(void *cert, LDAP *ld, -LDAPMessage *res, -
      - -

                                                           -LDAPMessage **entry); -

  • -typedef int (*CertMapInitiFn_t): Renamed from CertmapInitFn_t.  -Now this has two extra parameters to make it easy to use it in a plugin. -Other API functions require "issuerDN" but this function was called with -"LDAPUCertMapInfo_t *certinfo".  There was no public API function -to get the issuerDN from "certinfo". The new signature for CertMapInitFn_t -is as follows:
  • - -
        typedef int (*CertMapInitFn_t)(void *certmap_info, -const char *issuerName, -
                                                              -const char *issuerDN); -
  • -(ldapauth.h) ldapu_auth_* functions: For multiple matches, these -functions now return LDAPU_ERR_MULTIPLE_MATCHES instead of LDAPU_FAILED. -This change was required to make nested group membership work efficiently -and enable the new functionality of verify cert function.
  • -
- -
- -
- -
-

-Changes since Feb 1, 1997

- -
-Last Update: Mar 18, 1997
- -
-There have been several changes to the netsite/lib/ldaputil recently. If -you use this library, please start using the latest version of ldaputil -on the server3_branch so that all the servers go out with the same API -and behavior. Review the changes before you upgrade. If you don't plan -to upgrade, please let me know.
- -

-Renamed:

-Following structures and functions are renamed. But this shouldn't affect -you unless you have written a certmap plugin. -
-struct CertMappingFunction_t ---> CertMapFn_t
- -
-struct CertVerifyFunction_t ---> CertVerifyFn_t
- -
-ldapu_set_cert_mapping_function ---> ldapu_set_cert_mapfn
- -
-ldapu_get_cert_mapping_function ---> ldapu_get_cert_mapfn
- -
-ldapu_set_cert_verify_function ---> ldapu_set_cert_verifyfn
- -
-ldapu_get_cert_verify_function ---> ldapu_get_cert_verifyfn
- -

-Removed: (from .h)

-Removed the following functions from .h files. They are still in the .c -file as static functions. I don't think these should be public. If you -think otherwise, let me know. -
-ldapu_cert_mapping_function_default
- -
-ldapu_cert_verify_function_default
- -
-ldapu_search_cert_dn
- -
-ldapu_subject_dn_to_ldap_dn
- -

-Changed:

-The following changes may affect you. Please review them carefully before -you upgrade to the latest version of ldaputil. -
    -
  • -ldapu_auth_userdn_groupdn -- added const char *base argument -for group within group membership check
  • - -
  • -ldap_init and bind calls using LDAPDatabase_t *ldb retry once -if the LDAP server is/went down.
  • - -
  • -typedef CertVerifyFn_t has different arguments.
  • - -
  • -DNs from cert with escaped/quoted characters are correctly handled now.
  • - -
  • -cert to ldap entry mapping is optimized by not using string comparisons -during thruntime. A bitmask is created when the config file is read, cert -data is mapped to bits and compared against the bitmask.
  • - -
  • -Only the required attrs are retrieved in most ldap_search_s calls -from ldaputil. Some new functions were added to keep older functions the -same.
  • - -
  • -Fixed a core dump in ldapu_free_LDAPDatabase_t when using the local db.
  • - -
  • -ldaputil functions for initializing connection to the LDAP server and binding -to the server are thread-safe now. This requires linking to netsite/lib/base. -If you don't use libbase, you can turn off the thread-safe code using a -compile time option.
  • -
- -

-Added:

- -
    -
  • -Documentation to functions in ldaputil.h (customer API) - ldaputil.h is -the external public API for customers to write there plugins.
  • - -
  • -ldapu_get_cert_der - returns raw DER encoded cert data
  • - -
  • -ldapu_cert_to_user - Similar to ldapu_cert_to_ldap_entry but only -retrieves the 'uid' and 'userCertificate' attributes from LDAP and also -extracts the user id.
  • - -
  • -ldapu_find_uid_attrs and ldapu_find_group_attrs - Similar -to ldapu_find_uid and ldapu_find_group resp., but only retrieves the specified -attributes. Internally used during password verification and group membership -checks.
  • - -
  • -ldapu_certinfo_delete, ldapu_certinfo_modify and ldapu_certinfo_save -- API for the certmap config file GUI tool which is not yet developed. -Any volunteers?
  • -
- -

-TODO/Bugs:

- -
    -
  • -uniquemember attribute is not handled correctly in the group membership -check. If the user's entry has 'x500UniqueIdentifier' attribute populated, -the group could refer to the user entry by the user's dn followed by '#' -and an unique identifier. For example, the group entry could have:
  • - -
    -uniquemember: cn=Joe Smith,o=Netscape,c=US#jsmith
    - -
    -where, 'jsmith' is one of the values of the 'x500UniqueIdentifier' attribute -for the Joe Smith entry.
    - -
    -
    -
- - - diff --git a/lib/ldaputil/ldaputili.h b/lib/ldaputil/ldaputili.h deleted file mode 100644 index d1d2708..0000000 --- a/lib/ldaputil/ldaputili.h +++ /dev/null @@ -1,68 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - -#ifndef _LDAPU_LDAPUTILI_H -#define _LDAPU_LDAPUTILI_H - -#include - -#include - -#define BIG_LINE 1024 - -extern const int SEC_OID_AVA_UNKNOWN; /* unknown OID */ - -#ifdef __cplusplus -extern "C" { -#endif - -SECStatus CERT_RFC1485_EscapeAndQuote(char *dst, int dstlen, char *src, int srclen); - -extern void *ldapu_list_empty(LDAPUList_t *list, LDAPUListNodeFn_t free_fn, void *arg); -extern void ldapu_list_move(LDAPUList_t *from, LDAPUList_t *into); - -extern int ldapu_get_cert_ava_val(void *cert_in, int which_dn, const char *attr, char ***val_out); - -extern int ldapu_member_certificate_match(void *cert, const char *desc); - -/* Each of several LDAP API functions has a counterpart here. - * They behave the same, but their implementation may be replaced - * by calling ldapu_VTable_set(); as Directory Server does. - */ -#ifdef USE_LDAP_SSL -extern LDAP *ldapu_ssl_init(const char *host, int port, int encrypted); -#else -extern LDAP *ldapu_init(const char *host, int port); -#endif -extern int ldapu_set_option(LDAP *ld, int opt, void *val); -extern int ldapu_simple_bind_s(LDAP *ld, const char *username, const char *passwd); -extern int ldapu_unbind(LDAP *ld); -extern int ldapu_search_s(LDAP *ld, const char *base, int scope, const char *filter, char **attrs, int attrsonly, LDAPMessage **res); -extern int ldapu_count_entries(LDAP *ld, LDAPMessage *chain); -extern LDAPMessage *ldapu_first_entry(LDAP *ld, LDAPMessage *chain); -extern LDAPMessage *ldapu_next_entry(LDAP *ld, LDAPMessage *entry); -extern int ldapu_msgfree(LDAP *ld, LDAPMessage *chain); -extern char *ldapu_get_dn(LDAP *ld, LDAPMessage *entry); -extern void ldapu_memfree(LDAP *ld, void *dn); -extern char *ldapu_first_attribute(LDAP *ld, LDAPMessage *entry, BerElement **ber); -extern char *ldapu_next_attribute(LDAP *ld, LDAPMessage *entry, BerElement *ber); -extern void ldapu_ber_free(LDAP *ld, BerElement *ber, int freebuf); -extern char **ldapu_get_values(LDAP *ld, LDAPMessage *entry, const char *target); -extern struct berval **ldapu_get_values_len(LDAP *ld, LDAPMessage *entry, const char *target); -extern void ldapu_value_free(LDAP *ld, char **vals); -extern void ldapu_value_free_len(LDAP *ld, struct berval **vals); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/lib/ldaputil/vtable.c b/lib/ldaputil/vtable.c deleted file mode 100644 index 15b833a..0000000 --- a/lib/ldaputil/vtable.c +++ /dev/null @@ -1,210 +0,0 @@ -/** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2005 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 -#endif - -#include "ldaputili.h" -#include - -static LDAPUVTable_t ldapu_VTable = {0}; - -/* Replace ldapu_VTable. Subsequently, ldaputil will call the - functions in 'from' (not the LDAP API) to access the directory. - */ -void -ldapu_VTable_set(LDAPUVTable_t *from) -{ - if (from) { - memcpy(&ldapu_VTable, from, sizeof(LDAPUVTable_t)); - } -} - -int -ldapu_set_option(LDAP *ld, int option, void *optdata) -{ - if (ldapu_VTable.ldapuV_set_option) { - return ldapu_VTable.ldapuV_set_option(ld, option, optdata); - } - return LDAP_LOCAL_ERROR; -} - -int -ldapu_simple_bind_s(LDAP *ld, const char *who, const char *passwd) -{ - if (ldapu_VTable.ldapuV_simple_bind_s) { - return ldapu_VTable.ldapuV_simple_bind_s(ld, who, passwd); - } - return LDAP_LOCAL_ERROR; -} - -int -ldapu_unbind(LDAP *ld) -{ - if (ldapu_VTable.ldapuV_unbind) { - return ldapu_VTable.ldapuV_unbind(ld); - } - return LDAP_LOCAL_ERROR; -} - -int -ldapu_search_s(LDAP *ld, const char *base, int scope, const char *filter, char **attrs, int attrsonly, LDAPMessage **res) -{ - if (ldapu_VTable.ldapuV_search_s) { - return ldapu_VTable.ldapuV_search_s(ld, base, scope, filter, attrs, attrsonly, res); - } - return LDAP_LOCAL_ERROR; -} - -int -ldapu_count_entries(LDAP *ld, LDAPMessage *chain) -{ - if (ldapu_VTable.ldapuV_count_entries) { - return ldapu_VTable.ldapuV_count_entries(ld, chain); - } - return 0; -} - -LDAPMessage * -ldapu_first_entry(LDAP *ld, LDAPMessage *chain) -{ - if (ldapu_VTable.ldapuV_first_entry) { - return ldapu_VTable.ldapuV_first_entry(ld, chain); - } - return NULL; -} - -LDAPMessage * -ldapu_next_entry(LDAP *ld, LDAPMessage *entry) -{ - if (ldapu_VTable.ldapuV_next_entry) { - return ldapu_VTable.ldapuV_next_entry(ld, entry); - } - return NULL; -} - -int -ldapu_msgfree(LDAP *ld, LDAPMessage *chain) -{ - if (ldapu_VTable.ldapuV_msgfree) { - return ldapu_VTable.ldapuV_msgfree(ld, chain); - } - return LDAP_SUCCESS; -} - -char * -ldapu_get_dn(LDAP *ld, LDAPMessage *entry) -{ - if (ldapu_VTable.ldapuV_get_dn) { - return ldapu_VTable.ldapuV_get_dn(ld, entry); - } - return NULL; -} - -void -ldapu_memfree(LDAP *ld, void *p) -{ - if (ldapu_VTable.ldapuV_memfree) { - ldapu_VTable.ldapuV_memfree(ld, p); - } -} - -char * -ldapu_first_attribute(LDAP *ld, LDAPMessage *entry, BerElement **ber) -{ - if (ldapu_VTable.ldapuV_first_attribute) { - return ldapu_VTable.ldapuV_first_attribute(ld, entry, ber); - } - return NULL; -} - -char * -ldapu_next_attribute(LDAP *ld, LDAPMessage *entry, BerElement *ber) -{ - if (ldapu_VTable.ldapuV_next_attribute) { - return ldapu_VTable.ldapuV_next_attribute(ld, entry, ber); - } - return NULL; -} - -void -ldapu_ber_free(LDAP *ld, BerElement *ber, int freebuf) -{ - if (ldapu_VTable.ldapuV_ber_free) { - ldapu_VTable.ldapuV_ber_free(ld, ber, freebuf); - } -} - -char ** -ldapu_get_values(LDAP *ld, LDAPMessage *entry, const char *desc) -{ - if (ldapu_VTable.ldapuV_get_values) { - return ldapu_VTable.ldapuV_get_values(ld, entry, desc); - } else if (!ldapu_VTable.ldapuV_value_free && ldapu_VTable.ldapuV_get_values_len) { - auto struct berval **bvals = - ldapu_VTable.ldapuV_get_values_len(ld, entry, desc); - if (bvals) { - auto char **vals = (char **) - ldapu_malloc((ldap_count_values_len(bvals) + 1) * sizeof(char *)); - if (vals) { - auto char **val; - auto struct berval **bval; - for (val = vals, bval = bvals; *bval; ++val, ++bval) { - auto const size_t len = (*bval)->bv_len; - *val = (char *)ldapu_malloc(len + 1); - memcpy(*val, (*bval)->bv_val, len); - (*val)[len] = '\0'; - } - *val = NULL; - ldapu_value_free_len(ld, bvals); - return vals; - } - } - ldapu_value_free_len(ld, bvals); - } - return NULL; -} - -void -ldapu_value_free(LDAP *ld, char **vals) -{ - if (ldapu_VTable.ldapuV_value_free) { - ldapu_VTable.ldapuV_value_free(ld, vals); - } else if (!ldapu_VTable.ldapuV_get_values && vals) { - auto char **val; - for (val = vals; *val; ++val) { - free(*val); - } - free(vals); - } -} - -struct berval ** -ldapu_get_values_len(LDAP *ld, LDAPMessage *entry, const char *desc) -{ - if (ldapu_VTable.ldapuV_get_values_len) { - return ldapu_VTable.ldapuV_get_values_len(ld, entry, desc); - } - return NULL; -} - -void -ldapu_value_free_len(LDAP *ld, struct berval **vals) -{ - if (ldapu_VTable.ldapuV_value_free_len) { - ldapu_VTable.ldapuV_value_free_len(ld, vals); - } else if (!ldapu_VTable.ldapuV_get_values_len && vals) { - auto struct berval **val; - for (val = vals; *val; ++val) { - free(*val); - } - free(vals); - } -} From c80b9dbf0774a2750c56769813a8fae26e856cf3 Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 16 2020 02:54:34 +0000 Subject: [PATCH 9/11] Ticket 49218 - Certmap - support TLS tests Bug Description: This adds support for pluggable certificate mapping libraries. To achieve this, this replaces the existing baked in certificate mapping code. Fix Description: Improve our tls tests to cover more cases, support external signing cas, user certs, and addition of TLS by default to tests. https://pagure.io/389-ds-base/issue/49218 https://pagure.io/lib389/issue/95 https://pagure.io/lib389/issue/84 Author: wibrown Review by: ??? --- diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py index c3dc6f2..e169757 100644 --- a/src/lib389/lib389/__init__.py +++ b/src/lib389/lib389/__init__.py @@ -789,6 +789,10 @@ class DirSrv(SimpleLDAPObject, object): self.log.error("Can't find file: %r, removing extension", prog) prog = prog[:-3] + # We need to tuck the SSLport away because we need to connect + hidden_ssl_port = self.sslport + self.sslport = None + # Create and extract a service keytab args = {SER_HOST: self.host, SER_PORT: self.port, diff --git a/src/lib389/lib389/idm/user.py b/src/lib389/lib389/idm/user.py index 9922fed..0ff7350 100644 --- a/src/lib389/lib389/idm/user.py +++ b/src/lib389/lib389/idm/user.py @@ -175,7 +175,6 @@ class UserAccount(Account): return super(UserAccount, self)._validate(rdn, properties, basedn) - class UserAccounts(DSLdapObjects): """DSLdapObjects that represents all User Account entries in suffix. By default it uses 'ou=People' as rdn. diff --git a/src/lib389/lib389/nss_ssl.py b/src/lib389/lib389/nss_ssl.py index 1d47085..fcbc8bf 100644 --- a/src/lib389/lib389/nss_ssl.py +++ b/src/lib389/lib389/nss_ssl.py @@ -401,7 +401,6 @@ only. '%s/%s' % (self._certdb, PWD_TXT), ] result = ensure_str(check_output(cmd, stderr=subprocess.STDOUT)) - # We can skip the first few lines. They are junk # IE ['', # 'Certificate Nickname Trust Attributes', diff --git a/src/lib389/lib389/tests/nss_ssl_test.py b/src/lib389/lib389/tests/nss_ssl_test.py index 0fbbfd3..72ea0ee 100644 --- a/src/lib389/lib389/tests/nss_ssl_test.py +++ b/src/lib389/lib389/tests/nss_ssl_test.py @@ -88,7 +88,6 @@ def test_nss_ssca_users(topo): assert(ssca._rsa_user_exists(user) is True) assert(ssca._rsa_user_exists('non_existen') is False) - if __name__ == "__main__": CURRENT_FILE = os.path.realpath(__file__) pytest.main("-s -vv %s" % CURRENT_FILE) From f20dd1d0b9fb388d4b84e158d4cd2e5c4928f393 Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 16 2020 02:55:39 +0000 Subject: [PATCH 10/11] Ticket 49218 - Certmap - TLS tests Bug Description: This adds support for pluggable certificate mapping libraries. To achieve this, this replaces the existing baked in certificate mapping code. Fix Description: Add a tls test case proving that our certmap code continues to operate as expected, with proper support for the new v4 plugin type. https://pagure.io/389-ds-base/issue/49218 https://pagure.io/lib389/issue/95 https://pagure.io/lib389/issue/84 Author: wibrown Review by: ??? --- diff --git a/src/lib389/lib389/nss_ssl.py b/src/lib389/lib389/nss_ssl.py index fcbc8bf..807291a 100644 --- a/src/lib389/lib389/nss_ssl.py +++ b/src/lib389/lib389/nss_ssl.py @@ -465,10 +465,13 @@ only. Detect if a self-signed ca exists """ have_ca = False - cert_list = self._rsa_cert_list() - for cert in cert_list: - if self._rsa_cert_key_exists(cert) and self._rsa_cert_is_catrust(cert): - have_ca = True + try: + cert_list = self._rsa_cert_list() + for cert in cert_list: + if self._rsa_cert_key_exists(cert) and self._rsa_cert_is_catrust(cert): + have_ca = True + except subprocess.CalledProcessError: + pass return have_ca def _rsa_key_and_cert_exists(self): diff --git a/src/lib389/lib389/plugins_v4.py b/src/lib389/lib389/plugins_v4.py new file mode 100644 index 0000000..745667a --- /dev/null +++ b/src/lib389/lib389/plugins_v4.py @@ -0,0 +1,62 @@ +# --- 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 --- + +import copy + +from lib389._mapped_object import DSLdapObjects, DSLdapObject + +class DylibPlugin4(DSLdapObject): + _plugin_properties = { + 'nsslapd-pluginEnabled' : 'off', + 'nsslapd-pluginInitfunc' : 'NONE', + 'nsslapd-pluginPath': 'NONE', + } + + def __init__(self, instance, dn=None): + super(DylibPlugin4, self).__init__(instance, dn) + self._rdn_attribute = 'cn' + self._must_attributes = [ + 'cn', + 'nsslapd-pluginPath', + 'nsslapd-pluginInitfunc', + 'nsslapd-pluginEnabled', + ] + self._create_objectclasses = ['top', 'nsDylibPlugin4'] + # We'll mark this protected, and people can just disable the plugins. + self._protected = True + + def enable(self): + self.set('nsslapd-pluginEnabled', 'on') + + def disable(self): + self.set('nsslapd-pluginEnabled', 'off') + + def status(self): + return self.get_attr_val_utf8('nsslapd-pluginEnabled') == 'on' + + def create(self, rdn=None, properties=None, basedn=None): + # When we create plugins, we don't want people to have to consider all + # the little details. Plus, the server during creation needs to be able + # to create these from nothing. + # As a result, all the named plugins carry a default properties + # dictionary that can be used. + + # Copy the plugin internal properties. + internal_properties = copy.deepcopy(self._plugin_properties) + if properties is not None: + internal_properties.update(properties) + return super(DylibPlugin4, self).create(rdn, internal_properties, basedn) + +class CertmapPlugin(DylibPlugin4): + def __init__(self, instance, dn="cn=certmap plugin,cn=plugins,cn=config"): + super(CertmapPlugin, self).__init__(instance, dn) + + + + + diff --git a/src/lib389/lib389/tests/tls_external_test.py b/src/lib389/lib389/tests/tls_external_test.py index 68aaa9d..3c5a811 100644 --- a/src/lib389/lib389/tests/tls_external_test.py +++ b/src/lib389/lib389/tests/tls_external_test.py @@ -8,53 +8,103 @@ # import ldap +import pytest +from lib389 import DirSrv +from lib389.utils import ds_is_older from lib389.topologies import topology_st from lib389.utils import logging +from lib389.nss_ssl import NssSsl, CERT_SUFFIX from lib389.idm.user import UserAccounts -from lib389._constants import DEFAULT_SUFFIX, SECUREPORT_STANDALONE1 +from lib389.plugins_v4 import CertmapPlugin +from lib389.backend import Backends, BACKEND_SAMPLE_ENTRIES +from lib389._constants import DEFAULT_SUFFIX, SECUREPORT_STANDALONE1, INSTALL_LATEST_CONFIG from lib389.config import CertmapLegacy log = logging.getLogger(__name__) +def _check_bind(inst, dn, tls_locs): + + inst_clone = inst.clone() + inst_clone.open(saslmethod='EXTERNAL', + connOnly=True, + certdir=inst.get_ssca_dir(), + userkey=tls_locs['key'], + usercert=tls_locs['crt']) + assert(inst_clone.whoami_s().lower() == "dn: %s" % dn.lower()) + inst_clone.close() + log.debug("PASS: bound as %s" % dn) + +@pytest.mark.skipif(ds_is_older('1.4.0'), reason="Not implemented in 1.4.0") +def test_certmap_plugin_upgrade(topology_st): + standalone = topology_st.standalone + + certmap = CertmapPlugin(standalone) + # Now, reach in and allow deletion! + certmap._protected = False + certmap.delete() + + # Restart the server + standalone.restart() + + # Now assert that the item exists again. + certmap_reload = CertmapPlugin(standalone) + assert certmap_reload.status() == True + +@pytest.mark.skipif(ds_is_older('1.4.0'), reason="Not implemented in 1.4.0") def test_tls_external(topology_st): standalone = topology_st.standalone + standalone.enable_tls() + + ssca = NssSsl(dbpath=topology_st.standalone.get_ssca_dir()) + assert(ssca._rsa_ca_exists() is True) + + inst_db = NssSsl(dirsrv=topology_st.standalone) + assert(inst_db._db_exists() is True) + assert(inst_db._rsa_key_and_cert_exists() is True) - # SETUP TLS - standalone.stop() - assert(standalone.nss_ssl.reinit() is True) - assert(standalone.nss_ssl.create_rsa_ca() is True) - assert(standalone.nss_ssl.create_rsa_key_and_cert() is True) # Create a user - assert(standalone.nss_ssl.create_rsa_user('testuser') is True) + assert(ssca.create_rsa_user('testuser_a') is not None) # Now get the details of where the key and crt are. - tls_locs = standalone.nss_ssl.get_rsa_user('testuser') - # {'ca': ca_path, 'key': key_path, 'crt': crt_path} + testuser_a_tls_locs = ssca.get_rsa_user('testuser_a') + + # This user is added to a different backend to test "without" dncomps + # IE we try to bind to the DN in the cert. + backends = Backends(standalone) + backends.create(properties={ + 'cn': 'certRoot', + 'nsslapd-suffix': CERT_SUFFIX, + BACKEND_SAMPLE_ENTRIES: INSTALL_LATEST_CONFIG + }) - # Start again - standalone.start() + # Manual testing: sudo LDAPTLS_KEY=/opt/dirsrv/etc/dirsrv/ssca/user-testuser_a.key LDAPTLS_CERT=/opt/dirsrv/etc/dirsrv/ssca/user-testuser_a.crt LDAPTLS_CACERT=/opt/dirsrv/etc/dirsrv/ssca/ca.crt ldapwhoami -H ldaps://localhost:63601/ - users = UserAccounts(standalone, DEFAULT_SUFFIX) - user = users.create(properties={ - 'uid': 'testuser', - 'cn' : 'testuser', + c_users = UserAccounts(standalone, CERT_SUFFIX, rdn=None) + testuser_a = c_users.create(rdn='cn=testuser_a', properties={ + 'uid': 'testuser_a', + 'cn' : 'testuser_a', + 'o': 'testing', 'sn' : 'user', - 'uidNumber' : '1000', - 'gidNumber' : '2000', - 'homeDirectory' : '/home/testuser' + 'uidNumber' : '1001', + 'gidNumber' : '2001', + 'homeDirectory' : '/home/testuser_a', + 'nsCertSubjectDn': 'CN=testuser_a,%s' % CERT_SUFFIX, }) + testuser_a.enroll_certificate(testuser_a_tls_locs['crt_der_path']) + + ## REMEMBER the bind logic is in this order: + # If dncomps == None: bind to subject DN in cert + # If dncomps == None, cmapattr set, search object with cmap attr. nsCertSubjectDN + # if dncomps == '', use filter comps ot search an entyr below basedn + # if dncomps == 'attr', use these to construct a DN - standalone.rsa.create() - # Set the secure port and nsslapd-security - standalone.config.set('nsslapd-secureport', '%s' % SECUREPORT_STANDALONE1 ) - standalone.config.set('nsslapd-security', 'on') - standalone.sslport = SECUREPORT_STANDALONE1 # Now turn on the certmap. cm = CertmapLegacy(standalone) certmaps = cm.list() - certmaps['default']['DNComps'] = '' + # This means to use filter comps instead of dn comps + certmaps['default']['DNComps'] = None certmaps['default']['FilterComps'] = ['cn'] certmaps['default']['VerifyCert'] = 'off' cm.set(certmaps) @@ -66,17 +116,43 @@ def test_tls_external(topology_st): standalone.restart(post_open=False) # Now attempt a bind with TLS external - conn = standalone.openConnection(saslmethod='EXTERNAL', connOnly=True, certdir=standalone.get_cert_dir(), userkey=tls_locs['key'], usercert=tls_locs['crt']) + _check_bind(standalone, 'cn=testuser_a,%s' % CERT_SUFFIX, testuser_a_tls_locs) + + # Change the certmap and try and verify the certificate + certmaps['default']['CmapLdapAttr'] = 'nsCertSubjectDN' + cm.set(certmaps) + standalone.restart(post_open=False) + _check_bind(standalone, 'cn=testuser_a,%s' % CERT_SUFFIX, testuser_a_tls_locs) + + # Change the basedn and check it works. + certmaps['default']['basedn'] = 'o=testing,l=lib389,st=Queensland,c=AU' + cm.set(certmaps) + standalone.restart(post_open=False) + _check_bind(standalone, 'cn=testuser_a,%s' % CERT_SUFFIX, testuser_a_tls_locs) + + # Change the certmap and try and verify the certificate + certmaps['default']['VerifyCert'] = 'on' + cm.set(certmaps) + standalone.restart(post_open=False) + _check_bind(standalone, 'cn=testuser_a,%s' % CERT_SUFFIX, testuser_a_tls_locs) - assert(conn.whoami_s() == "dn: uid=testuser,ou=People,dc=example,dc=com") + # Check filter comps + certmaps['default']['DNComps'] = '' + certmaps['default']['CmapLdapAttr'] = None + cm.set(certmaps) + standalone.restart(post_open=False) + _check_bind(standalone, 'cn=testuser_a,%s' % CERT_SUFFIX, testuser_a_tls_locs) - # Backup version of the code: - # ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) - # ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, tls_locs['ca']) - # ldap.set_option(ldap.OPT_X_TLS_KEYFILE, tls_locs['key']) - # ldap.set_option(ldap.OPT_X_TLS_CERTFILE, tls_locs['crt']) - # conn = ldap.initialize(standalone.toLDAPURL()) + # Change the filter comps to check o and cn + certmaps['default']['FilterComps'] = ['cn', 'o'] + cm.set(certmaps) + standalone.restart(post_open=False) + _check_bind(standalone, 'cn=testuser_a,%s' % CERT_SUFFIX, testuser_a_tls_locs) - # sasl_auth = ldap.sasl.external() - # conn.sasl_interactive_bind_s("", sasl_auth) + # Finally, check the dncomps + # The order of these matter as they are extract and appended in *this* order. + certmaps['default']['DNComps'] = ['cn', 'o', 'l', 'st', 'c'] + cm.set(certmaps) + standalone.restart(post_open=False) + _check_bind(standalone, 'cn=testuser_a,%s' % CERT_SUFFIX, testuser_a_tls_locs) From 5924f0607ac55dd7e69597170d76a6049121f434 Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 16 2020 23:58:07 +0000 Subject: [PATCH 11/11] Updates --- diff --git a/Makefile.am b/Makefile.am index 87e0355..df80968 100644 --- a/Makefile.am +++ b/Makefile.am @@ -368,7 +368,7 @@ endif # 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 @@ -1139,25 +1139,6 @@ endif libavl_a_SOURCES = ldap/libraries/libavl/avl.c libavl_a_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) -<<<<<<< HEAD -#------------------------ -# 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) - -======= ->>>>>>> Ticket 49218 - Certmap - build and schema #//////////////////////////////////////////////////////////////// # # Dynamic Server Libraries @@ -1561,13 +1542,8 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \ ldap/servers/slapd/slapi_pal.c \ $(libavl_a_SOURCES) -<<<<<<< HEAD libslapd_la_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) $(SASL_CFLAGS) @db_inc@ $(KERBEROS_CFLAGS) $(PCRE_CFLAGS) $(SDS_CPPFLAGS) $(SVRCORE_INCLUDES) libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LIBS) $(PCRE_LIBS) $(THREADLIB) $(SYSTEMD_LIBS) libsds.la libsvrcore.la -======= -libslapd_la_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) $(SDS_CPPFLAGS) $(SASL_INCLUDES) @db_inc@ $(SVRCORE_INCLUDES) @kerberos_inc@ @pcre_inc@ -libslapd_la_LIBADD = $(LDAPSDK_LINK) $(SASL_LINK) $(SVRCORE_LINK) $(NSS_LINK) $(NSPR_LINK) $(KERBEROS_LINK) $(PCRE_LINK) $(THREADLIB) $(SYSTEMD_LINK) libsds.la ->>>>>>> Ticket 49218 - Certmap - build and schema libslapd_la_LDFLAGS = $(AM_LDFLAGS) $(SLAPD_LDFLAGS) if RUST_ENABLE @@ -1717,7 +1693,7 @@ libaddn_plugin_la_LDFLAGS = -avoid-version #------------------------ libcertmap_plugin_la_SOURCES = ldap/servers/plugins/certmap/certmap.c -libcertmap_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) @pcre_inc@ +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 @@ -2307,21 +2283,15 @@ ns_slapd_SOURCES = ldap/servers/slapd/abandon.c \ ldap/servers/slapd/unbind.c \ $(GETSOCKETPEER) -<<<<<<< HEAD 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_CPPFLAGS = $(AM_CPPFLAGS) $(DSPLUGIN_CPPFLAGS) $(SASL_INCLUDES) $(SVRCORE_INCLUDES) -ns_slapd_LDADD = libnunc-stans.la libslapd.la $(LDAPSDK_LINK) $(NSS_LINK) $(LIBADD_DL) \ - $(NSPR_LINK) $(SASL_LINK) $(SVRCORE_LINK) $(LIBNSL) $(LIBSOCKET) $(THREADLIB) $(SYSTEMD_LINK) $(EVENT_LINK) -ns_slapd_DEPENDENCIES = libslapd.la libnunc-stans.la ->>>>>>> Ticket 49218 - Certmap - build and schema +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 diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c index 78273b8..95d9e8b 100644 --- a/ldap/servers/slapd/main.c +++ b/ldap/servers/slapd/main.c @@ -1041,10 +1041,6 @@ main(int argc, char **argv) goto cleanup; } - /* init the thread data indexes */ - slapi_td_dn_init(); - slapi_td_plugin_lock_init(); - /* * Initialize password storage in entry extension. * Need to be initialized before plugin_startall in case stucked