diff options
Diffstat (limited to 'contrib/slapd-modules/datamorph')
37 files changed, 5447 insertions, 0 deletions
diff --git a/contrib/slapd-modules/datamorph/Makefile b/contrib/slapd-modules/datamorph/Makefile new file mode 100644 index 0000000..82bce49 --- /dev/null +++ b/contrib/slapd-modules/datamorph/Makefile @@ -0,0 +1,77 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 1998-2022 The OpenLDAP Foundation. +# Copyright 2017 Ondřej Kuzník, Symas Corp. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +SRCDIR = ./ +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap/libldap.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +INSTALL = /usr/bin/install +CC = gcc +OPT = -g -O2 +DEFS = -DSLAPD_OVER_DATAMORPH=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = datamorph.la +MANPAGES = slapo-datamorph.5 +CLEAN = *.o *.lo *.la .libs +LTVER = 0:0:0 + +prefix=/usr/local +exec_prefix=$(prefix) +ldap_subdir=/openldap + +libdir=$(exec_prefix)/lib +libexecdir=$(exec_prefix)/libexec +moduledir = $(libexecdir)$(ldap_subdir) +mandir = $(exec_prefix)/share/man +man5dir = $(mandir)/man5 + +all: $(PROGRAMS) + +d := +sp := +dir := tests +include $(dir)/Rules.mk + +.SUFFIXES: .c .o .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(OPT) $(CPPFLAGS) $(DEFS) $(INCS) -c $< + +datamorph.la: datamorph.lo + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf $(CLEAN) + +install: install-lib install-man FORCE + +install-lib: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + +install-man: $(MANPAGES) + mkdir -p $(DESTDIR)$(man5dir) + $(INSTALL) -m 644 $(MANPAGES) $(DESTDIR)$(man5dir) + +FORCE: + diff --git a/contrib/slapd-modules/datamorph/datamorph.c b/contrib/slapd-modules/datamorph/datamorph.c new file mode 100644 index 0000000..7767586 --- /dev/null +++ b/contrib/slapd-modules/datamorph/datamorph.c @@ -0,0 +1,2091 @@ +/* datamorph.c - enumerated and native integer value support */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2016-2022 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was developed in 2016 by Ondřej Kuzník for Symas Corp. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_DATAMORPH + +#include <inttypes.h> +#include <ac/stdlib.h> + +#if defined(__linux__) +#include <endian.h> + +#elif defined(sun) + +#define be16toh(x) BE_16(x) +#define le16toh(x) LE_16(x) +#define htobe16(x) BE_16(x) +#define htole16(x) LE_16(x) + +#define be32toh(x) BE_32(x) +#define le32toh(x) LE_32(x) +#define htobe32(x) BE_32(x) +#define htole32(x) LE_32(x) + +#define be64toh(x) BE_64(x) +#define le64toh(x) LE_64(x) +#define htobe64(x) BE_64(x) +#define htole64(x) LE_64(x) + +#elif defined(__NetBSD__) || defined(__FreeBSD__) +#include <sys/endian.h> + +#elif defined(__OpenBSD__) +#include <sys/endian.h> + +#define be16toh(x) betoh16(x) +#define le16toh(x) letoh16(x) + +#define be32toh(x) betoh32(x) +#define le32toh(x) letoh32(x) + +#define be64toh(x) betoh64(x) +#define le64toh(x) letoh64(x) + +#elif defined(__BYTE_ORDER__) && \ + ( defined(__GNUC__) || defined(__clang__) ) + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define be16toh(x) __builtin_bswap16(x) +#define le16toh(x) (x) +#define htobe16(x) __builtin_bswap16(x) +#define htole16(x) (x) + +#define be32toh(x) __builtin_bswap32(x) +#define le32toh(x) (x) +#define htobe32(x) __builtin_bswap32(x) +#define htole32(x) (x) + +#define be64toh(x) __builtin_bswap64(x) +#define le64toh(x) (x) +#define htobe64(x) __builtin_bswap64(x) +#define htole64(x) (x) + +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define be16toh(x) (x) +#define le16toh(x) __builtin_bswap16(x) +#define htobe16(x) (x) +#define htole16(x) __builtin_bswap16(x) + +#define be32toh(x) (x) +#define le32toh(x) __builtin_bswap32(x) +#define htobe32(x) (x) +#define htole32(x) __builtin_bswap32(x) + +#define be64toh(x) (x) +#define le64toh(x) __builtin_bswap64(x) +#define htobe64(x) (x) +#define htole64(x) __builtin_bswap64(x) + +#else +#error "Only support pure big and little endian at the moment" +#endif + +#else +#error "I lack the way to check my endianness and convert to/from big-endian" +#endif + +#include "slap.h" +#include "slap-config.h" +#include "lutil.h" +#include "ldap_queue.h" + +typedef enum datamorph_type_t { + DATAMORPH_UNSET, + DATAMORPH_ENUM, + DATAMORPH_INT, +} datamorph_type; + +typedef enum datamorph_flags_t { + DATAMORPH_FLAG_SIGNED = 1 << 0, + DATAMORPH_FLAG_LOWER = 1 << 1, + DATAMORPH_FLAG_UPPER = 1 << 2, +} datamorph_flags; + +typedef union datamorph_interval_bound_t { + int64_t i; + uint64_t u; +} datamorph_interval_bound; + +typedef struct transformation_info_t { + AttributeDescription *attr; + datamorph_type type; + union { + struct { + Avlnode *to_db; + struct berval from_db[256]; + } maps; +#define ti_enum info.maps + struct { + datamorph_flags flags; + unsigned int size; + datamorph_interval_bound lower, upper; + } interval; +#define ti_int info.interval + } info; +} transformation_info; + +typedef struct datamorph_enum_mapping_t { + struct berval wire_value; + uint8_t db_value; + transformation_info *transformation; +} datamorph_enum_mapping; + +typedef struct datamorph_info_t { + Avlnode *transformations; + transformation_info *wip_transformation; +} datamorph_info; + +static int +transformation_mapping_cmp( const void *l, const void *r ) +{ + const datamorph_enum_mapping *left = l, *right = r; + + return ber_bvcmp( &left->wire_value, &right->wire_value ); +} + +static int +transformation_info_cmp( const void *l, const void *r ) +{ + const transformation_info *left = l, *right = r; + + return ( left->attr == right->attr ) ? 0 : + ( left->attr < right->attr ) ? -1 : + 1; +} + +static int +transform_to_db_format_one( + Operation *op, + transformation_info *definition, + struct berval *value, + struct berval *outval ) +{ + switch ( definition->type ) { + case DATAMORPH_ENUM: { + datamorph_enum_mapping *mapping, needle = { .wire_value = *value }; + struct berval db_value = { .bv_len = 1 }; + + mapping = ldap_avl_find( definition->ti_enum.to_db, &needle, + transformation_mapping_cmp ); + if ( !mapping ) { + Debug( LDAP_DEBUG_ANY, "transform_to_db_format_one: " + "value '%s' not mapped\n", + value->bv_val ); + return LDAP_CONSTRAINT_VIOLATION; + } + + db_value.bv_val = (char *)&mapping->db_value; + ber_dupbv( outval, &db_value ); + assert( outval->bv_val ); + break; + } + + case DATAMORPH_INT: { + union { + char s[8]; + uint8_t be8; + uint16_t be16; + uint32_t be32; + uint64_t be64; + } buf; + struct berval db_value = { .bv_val = buf.s }; + char *ptr = value->bv_val + value->bv_len; + uint64_t unsigned_value; + int64_t signed_value; + + assert( definition->ti_int.size == 1 || + definition->ti_int.size == 2 || + definition->ti_int.size == 4 || + definition->ti_int.size == 8 ); + + /* Read number */ + if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + signed_value = strtoll( value->bv_val, &ptr, 10 ); + } else { + unsigned_value = strtoull( value->bv_val, &ptr, 10 ); + } + if ( *value->bv_val == '\0' || *ptr != '\0' ) { + Debug( LDAP_DEBUG_ANY, "transform_to_db_format_one: " + "value '%s' not an integer\n", + value->bv_val ); + return LDAP_CONSTRAINT_VIOLATION; + } + /* Check it's within configured bounds */ + if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + if ( signed_value < definition->ti_int.lower.i || + signed_value > definition->ti_int.upper.i ) { + Debug( LDAP_DEBUG_ANY, "transform_to_db_format_one: " + "value '%s' doesn't fit configured constraints\n", + value->bv_val ); + return LDAP_CONSTRAINT_VIOLATION; + } + } else { + if ( unsigned_value < definition->ti_int.lower.u || + unsigned_value > definition->ti_int.upper.u ) { + Debug( LDAP_DEBUG_ANY, "transform_to_db_format_one: " + "value '%s' doesn't fit configured constraints\n", + value->bv_val ); + return LDAP_CONSTRAINT_VIOLATION; + } + } + + db_value.bv_len = definition->ti_int.size; + switch ( definition->ti_int.size ) { + case 1: { + if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + buf.be8 = (unsigned char)((char)signed_value); + } else { + buf.be8 = unsigned_value; + } + break; + } + case 2: { + uint16_t h16; + if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + h16 = signed_value; + } else { + h16 = unsigned_value; + } + buf.be16 = htobe16( h16 ); + break; + } + case 4: { + uint32_t h32; + if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + h32 = signed_value; + } else { + h32 = unsigned_value; + } + buf.be32 = htobe32( h32 ); + break; + } + case 8: { + uint64_t h64; + if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + h64 = signed_value; + } else { + h64 = unsigned_value; + } + buf.be64 = htobe64( h64 ); + break; + } + } + ber_dupbv( outval, &db_value ); + assert( outval->bv_val ); + break; + } + + default: + assert(0); + } + + return LDAP_SUCCESS; +} + +static int +transform_to_db_format( + Operation *op, + transformation_info *definition, + BerVarray values, + int numvals, + BerVarray *out ) +{ + struct berval *value; + int i, rc = LDAP_SUCCESS; + + if ( numvals == 0 ) { + for ( value = values; value; value++, numvals++ ) + ; /* Count them */ + } + + assert( out ); + *out = ch_calloc( numvals + 1, sizeof(struct berval) ); + + for ( i = 0; i < numvals; i++ ) { + rc = transform_to_db_format_one( + op, definition, &values[i], &(*out)[i] ); + if ( rc ) { + break; + } + } + + if ( rc ) { + for ( ; i >= 0; i-- ) { + ch_free((*out)[i].bv_val); + } + ch_free(*out); + } + + return rc; +} + +static int +transform_from_db_format_one( + Operation *op, + transformation_info *definition, + struct berval *value, + struct berval *outval ) +{ + switch ( definition->type ) { + case DATAMORPH_ENUM: { + uint8_t index = value->bv_val[0]; + struct berval *val = &definition->info.maps.from_db[index]; + + if ( !BER_BVISNULL( val ) ) { + ber_dupbv( outval, val ); + assert( outval->bv_val ); + } else { + Debug( LDAP_DEBUG_ANY, "transform_from_db_format_one: " + "DB value %d has no mapping!\n", + index ); + /* FIXME: probably still need to return an error */ + BER_BVZERO( outval ); + } + break; + } + + case DATAMORPH_INT: { + char buf[24]; + struct berval wire_value = { .bv_val = buf }; + union lens_t { + uint8_t be8; + uint16_t be16; + uint32_t be32; + uint64_t be64; + } *lens = (union lens_t *)value->bv_val; + uint64_t unsigned_value; + int64_t signed_value; + + if ( value->bv_len != definition->ti_int.size ) { + Debug( LDAP_DEBUG_ANY, "transform_from_db_format_one(%s): " + "unexpected DB value of length %lu when configured " + "for %u!\n", + definition->attr->ad_cname.bv_val, value->bv_len, + definition->ti_int.size ); + /* FIXME: probably still need to return an error */ + BER_BVZERO( outval ); + break; + } + + assert( definition->ti_int.size == 1 || + definition->ti_int.size == 2 || + definition->ti_int.size == 4 || + definition->ti_int.size == 8 ); + + switch ( definition->ti_int.size ) { + case 1: { + if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + signed_value = (int8_t)lens->be8; + } else { + unsigned_value = (uint8_t)lens->be8; + } + break; + } + case 2: { + uint16_t h16 = be16toh( lens->be16 ); + if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + signed_value = (int16_t)h16; + } else { + unsigned_value = (uint16_t)h16; + } + break; + } + case 4: { + uint32_t h32 = be32toh( lens->be32 ); + if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + signed_value = (int32_t)h32; + } else { + unsigned_value = (uint32_t)h32; + } + break; + } + case 8: { + uint64_t h64 = be64toh( lens->be64 ); + if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + signed_value = (int64_t)h64; + } else { + unsigned_value = (uint64_t)h64; + } + break; + } + } + if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + wire_value.bv_len = sprintf( buf, "%" PRId64, signed_value ); + } else { + wire_value.bv_len = sprintf( buf, "%" PRIu64, unsigned_value ); + } + ber_dupbv( outval, &wire_value ); + assert( outval->bv_val ); + break; + } + + default: + assert(0); + } + + return LDAP_SUCCESS; +} + +static int +transform_from_db_format( + Operation *op, + transformation_info *definition, + BerVarray values, + int numvals, + BerVarray *out ) +{ + struct berval *value; + int i, rc = LDAP_SUCCESS; + + if ( numvals == 0 ) { + for ( value = values; value; value++, numvals++ ) + ; /* Count them */ + } + + assert( out ); + *out = ch_calloc( numvals + 1, sizeof(struct berval) ); + + for ( i = 0; i < numvals; i++ ) { + struct berval bv; + rc = transform_from_db_format_one( op, definition, &values[i], &bv ); + if ( !BER_BVISNULL( &bv ) ) { + ber_bvarray_add( out, &bv ); + } + if ( rc ) { + break; + } + } + + if ( rc ) { + for ( ; i >= 0; i-- ) { + ch_free( (*out)[i].bv_val ); + } + ch_free( *out ); + } + + return rc; +} + +static int +datamorph_filter( Operation *op, datamorph_info *ov, Filter *f ) +{ + switch ( f->f_choice ) { + case LDAP_FILTER_PRESENT: + /* The matching rules are not in place, + * so the filter will be ignored */ + case LDAP_FILTER_APPROX: + case LDAP_FILTER_SUBSTRINGS: + default: + break; + return LDAP_SUCCESS; + + case LDAP_FILTER_AND: + case LDAP_FILTER_OR: { + for ( f = f->f_and; f; f = f->f_next ) { + int rc = datamorph_filter( op, ov, f ); + if ( rc != LDAP_SUCCESS ) { + return rc; + } + } + } break; + + case LDAP_FILTER_NOT: + return datamorph_filter( op, ov, f->f_not ); + + case LDAP_FILTER_EQUALITY: + case LDAP_FILTER_GE: + case LDAP_FILTER_LE: { + transformation_info *t, needle = { .attr = f->f_ava->aa_desc }; + + t = ldap_avl_find( + ov->transformations, &needle, transformation_info_cmp ); + if ( t ) { + struct berval new_val; + int rc = transform_to_db_format_one( + op, t, &f->f_ava->aa_value, &new_val ); + ch_free( f->f_ava->aa_value.bv_val ); + + if ( rc != LDAP_SUCCESS ) { + f->f_choice = SLAPD_FILTER_COMPUTED; + f->f_result = SLAPD_COMPARE_UNDEFINED; + } else { + f->f_ava->aa_value = new_val; + } + } + } break; + } + return LDAP_SUCCESS; +} + +static int +datamorph_op_add( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + datamorph_info *ov = on->on_bi.bi_private; + Entry *e = op->ora_e; + Attribute *a, *next; + AttributeDescription *stop = NULL; + int rc = LDAP_SUCCESS; + + if ( !BER_BVISNULL( &e->e_nname ) && !BER_BVISEMPTY( &e->e_nname ) ) { + LDAPRDN rDN; + const char *p; + int i; + + rc = ldap_bv2rdn_x( &e->e_nname, &rDN, (char **)&p, LDAP_DN_FORMAT_LDAP, + op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "datamorph_op_add: " + "can't parse rdn: dn=%s\n", + op->o_req_ndn.bv_val ); + return SLAP_CB_CONTINUE; + } + + for ( i = 0; rDN[i]; i++ ) { + transformation_info needle = {}; + + /* If we can't resolve the attribute, ignore it */ + if ( slap_bv2ad( &rDN[i]->la_attr, &needle.attr, &p ) ) { + continue; + } + + if ( ldap_avl_find( ov->transformations, &needle, + transformation_info_cmp ) ) { + rc = LDAP_CONSTRAINT_VIOLATION; + Debug( LDAP_DEBUG_TRACE, "datamorph_op_add: " + "attempted to add transformed attribute in RDN\n" ); + break; + } + } + + ldap_rdnfree_x( rDN, op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + send_ldap_error( op, rs, rc, + "datamorph: trying to add transformed attribute in RDN" ); + return rc; + } + } + + for ( a = e->e_attrs; a && a->a_desc != stop; a = next ) { + transformation_info *t, needle = { .attr = a->a_desc }; + BerVarray new_vals; + + next = a->a_next; + + t = ldap_avl_find( ov->transformations, &needle, transformation_info_cmp ); + if ( !t ) continue; + + rc = transform_to_db_format( + op, t, a->a_vals, a->a_numvals, &new_vals ); + if ( rc != LDAP_SUCCESS ) { + goto fail; + } + + (void)attr_delete( &e->e_attrs, needle.attr ); + + rc = attr_merge( e, needle.attr, new_vals, NULL ); + ber_bvarray_free( new_vals ); + if ( rc != LDAP_SUCCESS ) { + goto fail; + } + if ( !stop ) { + stop = needle.attr; + } + } + + return SLAP_CB_CONTINUE; + +fail: + send_ldap_error( + op, rs, rc, "datamorph: trying to add values outside definitions" ); + return rc; +} + +static int +datamorph_op_compare( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + datamorph_info *ov = on->on_bi.bi_private; + transformation_info *t, needle = { .attr = op->orc_ava->aa_desc }; + int rc = SLAP_CB_CONTINUE; + + t = ldap_avl_find( ov->transformations, &needle, transformation_info_cmp ); + if ( t ) { + struct berval new_val; + + rc = transform_to_db_format_one( + op, t, &op->orc_ava->aa_value, &new_val ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "datamorph_op_compare: " + "transformation failed for '%s', rc=%d\n", + op->orc_ava->aa_value.bv_val, rc ); + rs->sr_err = rc = LDAP_COMPARE_FALSE; + send_ldap_result( op, rs ); + return rc; + } + ch_free( op->orc_ava->aa_value.bv_val ); + op->orc_ava->aa_value = new_val; + } + + return SLAP_CB_CONTINUE; +} + +static int +datamorph_op_mod( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + datamorph_info *ov = on->on_bi.bi_private; + Modifications *mod; + int rc = SLAP_CB_CONTINUE; + + for ( mod = op->orm_modlist; mod; mod = mod->sml_next ) { + transformation_info *t, needle = { .attr = mod->sml_desc }; + BerVarray new_vals = NULL; + + if ( mod->sml_numvals == 0 ) continue; /* Nothing to transform */ + + t = ldap_avl_find( ov->transformations, &needle, transformation_info_cmp ); + if ( !t ) continue; + + assert( !mod->sml_nvalues ); + rc = transform_to_db_format( + op, t, mod->sml_values, mod->sml_numvals, &new_vals ); + if ( rc != LDAP_SUCCESS ) { + goto fail; + } + ber_bvarray_free( mod->sml_values ); + mod->sml_values = new_vals; + } + + return SLAP_CB_CONTINUE; + +fail: + Debug( LDAP_DEBUG_TRACE, "datamorph_op_mod: " + "dn=%s failed rc=%d\n", + op->o_req_ndn.bv_val, rc ); + send_ldap_error( op, rs, rc, + "datamorph: trying to operate on values outside definitions" ); + return rc; +} + +static int +datamorph_op_modrdn( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + datamorph_info *ov = on->on_bi.bi_private; + LDAPRDN rDN; + const char *p; + int i, rc; + + rc = ldap_bv2rdn_x( &op->orr_nnewrdn, &rDN, (char **)&p, + LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "datamorph_op_modrdn: " + "can't parse rdn for dn=%s\n", + op->o_req_ndn.bv_val ); + return SLAP_CB_CONTINUE; + } + + for ( i = 0; rDN[i]; i++ ) { + transformation_info needle = {}; + + /* If we can't resolve the attribute, ignore it */ + if ( slap_bv2ad( &rDN[i]->la_attr, &needle.attr, &p ) ) { + continue; + } + + if ( ldap_avl_find( + ov->transformations, &needle, transformation_info_cmp ) ) { + rc = LDAP_CONSTRAINT_VIOLATION; + Debug( LDAP_DEBUG_TRACE, "datamorph_op_modrdn: " + "attempted to add transformed values in RDN\n" ); + break; + } + } + + ldap_rdnfree_x( rDN, op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + send_ldap_error( op, rs, rc, + "datamorph: trying to put transformed values in RDN" ); + return rc; + } + + return SLAP_CB_CONTINUE; +} + +static int +datamorph_response( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + datamorph_info *ov = on->on_bi.bi_private; + Entry *e = NULL, *e_orig = rs->sr_entry; + AttributeDescription *stop = NULL; + Attribute *a, *next = NULL; + int rc = SLAP_CB_CONTINUE; + + if ( rs->sr_type != REP_SEARCH ) { + return rc; + } + + for ( a = e_orig->e_attrs; a && a->a_desc != stop; a = next ) { + transformation_info *t, needle = { .attr = a->a_desc }; + BerVarray new_vals; + + next = a->a_next; + + t = ldap_avl_find( ov->transformations, &needle, transformation_info_cmp ); + if ( !t ) continue; + + rc = transform_from_db_format( + op, t, a->a_vals, a->a_numvals, &new_vals ); + if ( rc != LDAP_SUCCESS ) { + break; + } + if ( !e ) { + if ( rs->sr_flags & REP_ENTRY_MODIFIABLE ) { + e = e_orig; + } else { + e = entry_dup( e_orig ); + } + } + + (void)attr_delete( &e->e_attrs, needle.attr ); + + rc = attr_merge( e, needle.attr, new_vals, NULL ); + ber_bvarray_free( new_vals ); + if ( rc != LDAP_SUCCESS ) { + break; + } + if ( !stop ) { + stop = needle.attr; + } + } + + if ( rc == LDAP_SUCCESS ) { + rc = SLAP_CB_CONTINUE; + if ( e && e != e_orig ) { + rs_replace_entry( op, rs, on, e ); + rs->sr_flags &= ~REP_ENTRY_MASK; + rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED; + } + } else if ( e && e != e_orig ) { + entry_free( e ); + } + + return rc; +} + +static int +datamorph_op_search( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + datamorph_info *ov = on->on_bi.bi_private; + int rc = SLAP_CB_CONTINUE; + + /* + * 1. check all requested attributes -> register callback if one matches + * 2. check filter: parse filter, traverse, for configured attributes: + * - presence -> do not touch + * - ava -> replace assertion value with db value if possible, assertion with undefined otherwise + * - inequality -> ??? + * - anything else -> undefined + * - might just check for equality and leave the rest to syntax? + * 3. unparse filter + */ + if ( datamorph_filter( op, ov, op->ors_filter ) ) { + send_ldap_error( + op, rs, LDAP_OTHER, "datamorph: failed to process filter" ); + return LDAP_OTHER; + } + + return rc; +} + +static int +datamorph_entry_release_rw( Operation *op, Entry *e, int rw ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + int rc = LDAP_SUCCESS; + + if ( on->on_next ) { + rc = overlay_entry_release_ov( op, e, rw, on->on_next ); + } else if ( on->on_info->oi_orig->bi_entry_release_rw ) { + /* FIXME: there should be a better way */ + rc = on->on_info->oi_orig->bi_entry_release_rw( op, e, rw ); + } else { + entry_free( e ); + } + + return rc; +} + +static int +datamorph_entry_get_rw( + Operation *op, + struct berval *ndn, + ObjectClass *oc, + AttributeDescription *at, + int rw, + Entry **ep ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + datamorph_info *ov = on->on_bi.bi_private; + Entry *e_orig, *e = NULL; + int rc; + + if ( on->on_next ) { + rc = overlay_entry_get_ov( op, ndn, oc, at, rw, ep, on->on_next ); + } else { + /* FIXME: there should be a better way */ + rc = on->on_info->oi_orig->bi_entry_get_rw( op, ndn, oc, at, rw, ep ); + } + e_orig = *ep; + + if ( rc == LDAP_SUCCESS && e_orig ) { + AttributeDescription *stop = NULL; + Attribute *a; + + for ( a = e_orig->e_attrs; a; a = a->a_next ) { + transformation_info *t, needle = { .attr = a->a_desc }; + BerVarray new_vals; + + t = ldap_avl_find( + ov->transformations, &needle, transformation_info_cmp ); + if ( !t ) continue; + + rc = transform_from_db_format( + op, t, a->a_vals, a->a_numvals, &new_vals ); + if ( rc != LDAP_SUCCESS ) { + goto fail; + } + if ( !e ) { + e = entry_dup( e_orig ); + } + + (void)attr_delete( &e->e_attrs, needle.attr ); + + rc = attr_merge( e, needle.attr, new_vals, NULL ); + ber_bvarray_free( new_vals ); + if ( rc != LDAP_SUCCESS ) { + goto fail; + } + if ( !stop ) { + stop = needle.attr; + } + } + } + if ( e ) { + datamorph_entry_release_rw( op, e_orig, rw ); + *ep = e; + } + + return rc; + +fail: + if ( e ) { + entry_free( e ); + } + (void)datamorph_entry_release_rw( op, *ep, rw ); + return rc; +} + +/* Schema */ + +static int +datamorphBlobValidate( Syntax *syntax, struct berval *in ) +{ + /* any value allowed */ + return LDAP_SUCCESS; +} + +int +datamorphBinarySignedOrderingMatch( int *matchp, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *value, + void *assertedValue ) +{ + struct berval *asserted = assertedValue; + ber_len_t v_len = value->bv_len; + ber_len_t av_len = asserted->bv_len; + + /* Ordering: + * 1. Negative always before non-negative + * 2. Shorter before longer + * 3. Rest ordered by memory contents (they are big-endian numbers) + */ + int match = ( *value->bv_val >= 0 ) - ( *asserted->bv_val >= 0 ); + + if ( match == 0 ) match = (int)v_len - (int)av_len; + + if ( match == 0 ) match = memcmp( value->bv_val, asserted->bv_val, v_len ); + + /* If used in extensible match filter, match if value < asserted */ + if ( flags & SLAP_MR_EXT ) match = ( match >= 0 ); + + *matchp = match; + return LDAP_SUCCESS; +} + +/* Index generation function: Ordered index */ +int +datamorphUnsignedIndexer( slap_mask_t use, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *prefix, + BerVarray values, + BerVarray *keysp, + void *ctx ) +{ + int i; + BerVarray keys; + + for ( i = 0; values[i].bv_val != NULL; i++ ) { + /* just count them */ + } + + /* we should have at least one value at this point */ + assert( i > 0 ); + + keys = slap_sl_malloc( sizeof(struct berval) * ( i + 1 ), ctx ); + + for ( i = 0; values[i].bv_val != NULL; i++ ) { + ber_dupbv_x( &keys[i], &values[i], ctx ); + } + + BER_BVZERO( &keys[i] ); + + *keysp = keys; + + return LDAP_SUCCESS; +} + +/* Index generation function: Ordered index */ +int +datamorphUnsignedFilter( + slap_mask_t use, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *prefix, + void *assertedValue, + BerVarray *keysp, + void *ctx ) +{ + BerVarray keys; + BerValue *value = assertedValue; + + keys = slap_sl_malloc( sizeof(struct berval) * 2, ctx ); + ber_dupbv_x( &keys[0], value, ctx ); + + BER_BVZERO( &keys[1] ); + + *keysp = keys; + + return LDAP_SUCCESS; +} + +/* Index generation function: Ordered index */ +int +datamorphSignedIndexer( + slap_mask_t use, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *prefix, + BerVarray values, + BerVarray *keysp, + void *ctx ) +{ + int i; + BerVarray keys; + + for ( i = 0; values[i].bv_val != NULL; i++ ) { + /* just count them */ + } + + /* we should have at least one value at this point */ + assert( i > 0 ); + + keys = slap_sl_malloc( sizeof(struct berval) * ( i + 1 ), ctx ); + + for ( i = 0; values[i].bv_val != NULL; i++ ) { + keys[i].bv_len = values[i].bv_len + 1; + keys[i].bv_val = slap_sl_malloc( keys[i].bv_len, ctx ); + + /* if positive (highest bit is not set), note that in the first byte */ + *keys[i].bv_val = ~( *values[i].bv_val & 0x80 ); + AC_MEMCPY( keys[i].bv_val + 1, values[i].bv_val, values[i].bv_len ); + } + + BER_BVZERO( &keys[i] ); + + *keysp = keys; + + return LDAP_SUCCESS; +} + +/* Index generation function: Ordered index */ +int +datamorphSignedFilter( + slap_mask_t use, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *prefix, + void *assertedValue, + BerVarray *keysp, + void *ctx ) +{ + BerVarray keys; + BerValue *value = assertedValue; + + keys = slap_sl_malloc( sizeof(struct berval) * 2, ctx ); + + keys[0].bv_len = value->bv_len + 1; + keys[0].bv_val = slap_sl_malloc( keys[0].bv_len, ctx ); + + /* if positive (highest bit is not set), note that in the first byte */ + *keys[0].bv_val = ~( *value->bv_val & 0x80 ); + AC_MEMCPY( keys[0].bv_val + 1, value->bv_val, value->bv_len ); + + BER_BVZERO( &keys[1] ); + + *keysp = keys; + + return LDAP_SUCCESS; +} + +#define DATAMORPH_ARC "1.3.6.1.4.1.4203.666.11.12" + +#define DATAMORPH_SYNTAXES DATAMORPH_ARC ".1" +#define DATAMORPH_SYNTAX_BASE DATAMORPH_SYNTAXES ".1" +#define DATAMORPH_SYNTAX_ENUM DATAMORPH_SYNTAXES ".2" +#define DATAMORPH_SYNTAX_INT DATAMORPH_SYNTAXES ".3" +#define DATAMORPH_SYNTAX_SIGNED_INT DATAMORPH_SYNTAXES ".4" + +#define DATAMORPH_MATCHES DATAMORPH_ARC ".2" +#define DATAMORPH_MATCH_EQUALITY DATAMORPH_MATCHES ".1" +#define DATAMORPH_MATCH_SIGNED_EQUALITY DATAMORPH_MATCHES ".2" +#define DATAMORPH_MATCH_ORDERING DATAMORPH_MATCHES ".3" +#define DATAMORPH_MATCH_SIGNED_ORDERING DATAMORPH_MATCHES ".4" + +static char *datamorph_sups[] = { + DATAMORPH_SYNTAX_BASE, + NULL +}; + +static char *datamorphSyntaxes[] = { + DATAMORPH_SYNTAX_SIGNED_INT, + DATAMORPH_SYNTAX_ENUM, + DATAMORPH_SYNTAX_INT, + + NULL +}; + +static slap_syntax_defs_rec datamorph_syntax_defs[] = { + { "( " DATAMORPH_SYNTAX_BASE " DESC 'Fixed size value' )", + 0, NULL, NULL, NULL + }, + { "( " DATAMORPH_SYNTAX_ENUM " DESC 'Enumerated value' )", + 0, datamorph_sups, datamorphBlobValidate, NULL + }, + { "( " DATAMORPH_SYNTAX_INT " DESC 'Fixed-size integer' )", + 0, datamorph_sups, datamorphBlobValidate, NULL + }, + { "( " DATAMORPH_SYNTAX_SIGNED_INT " DESC 'Fixed-size signed integer' )", + 0, datamorph_sups, datamorphBlobValidate, NULL + }, + + { NULL, 0, NULL, NULL, NULL } +}; + +static Syntax *datamorph_base_syntax; + +static slap_mrule_defs_rec datamorph_mrule_defs[] = { + { "( " DATAMORPH_MATCH_EQUALITY + " NAME 'fixedSizeIntegerMatch'" + " SYNTAX " DATAMORPH_SYNTAX_INT " )", + SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_ORDERED_INDEX, + datamorphSyntaxes + 1, + NULL, NULL, octetStringOrderingMatch, + datamorphUnsignedIndexer, datamorphUnsignedFilter, + NULL + }, + + { "( " DATAMORPH_MATCH_SIGNED_EQUALITY + " NAME 'fixedSizeSignedIntegerMatch'" + " SYNTAX " DATAMORPH_SYNTAX_SIGNED_INT " )", + SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_ORDERED_INDEX, + NULL, + NULL, NULL, datamorphBinarySignedOrderingMatch, + datamorphSignedIndexer, datamorphSignedFilter, + NULL + }, + + { "( " DATAMORPH_MATCH_ORDERING + " NAME 'fixedSizeIntegerOrderingMatch'" + " SYNTAX " DATAMORPH_SYNTAX_INT " )", + SLAP_MR_ORDERING|SLAP_MR_EXT|SLAP_MR_ORDERED_INDEX, + datamorphSyntaxes + 1, + NULL, NULL, octetStringOrderingMatch, + datamorphUnsignedIndexer, datamorphUnsignedFilter, + "octetStringMatch" }, + + { "( " DATAMORPH_MATCH_SIGNED_ORDERING + " NAME 'fixedSizeSignedIntegerOrderingMatch'" + " SYNTAX " DATAMORPH_SYNTAX_SIGNED_INT " )", + SLAP_MR_ORDERING|SLAP_MR_EXT|SLAP_MR_ORDERED_INDEX, + NULL, + NULL, NULL, datamorphBinarySignedOrderingMatch, + datamorphSignedIndexer, datamorphSignedFilter, + "octetStringMatch" }, + + { NULL, SLAP_MR_NONE, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +}; + +/* Configuration */ + +static ConfigLDAPadd datamorph_ldadd_enum; +static ConfigLDAPadd datamorph_ldadd_interval; +static ConfigLDAPadd datamorph_ldadd_mapping; + +static ConfigDriver datamorph_set_attribute; +static ConfigDriver datamorph_set_size; +static ConfigDriver datamorph_set_signed; +static ConfigDriver datamorph_set_bounds; +static ConfigDriver datamorph_set_index; +static ConfigDriver datamorph_set_value; +static ConfigDriver datamorph_add_mapping; +static ConfigDriver datamorph_add_transformation; + +static ConfigCfAdd datamorph_cfadd; + +enum { + DATAMORPH_INT_SIZE = 1, + DATAMORPH_INT_SIGNED, + DATAMORPH_INT_LOWER, + DATAMORPH_INT_UPPER, + + DATAMORPH_INT_LAST, +}; + +static ConfigTable datamorph_cfg[] = { + { "datamorph_attribute", "attr", 2, 2, 0, + ARG_STRING|ARG_QUOTE|ARG_MAGIC, + datamorph_set_attribute, + "( OLcfgCtAt:7.1 NAME 'olcDatamorphAttribute' " + "DESC 'Attribute to transform' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL + }, + { "datamorph_size", "<1|2|4|8>", 2, 2, 0, + ARG_INT|ARG_MAGIC|DATAMORPH_INT_SIZE, + datamorph_set_size, + "( OLcfgCtAt:7.2 NAME 'olcDatamorphIntegerBytes' " + "DESC 'Integer size in bytes' " + "EQUALITY integerMatch " + "SYNTAX OMsInteger " + "SINGLE-VALUE )", + NULL, NULL + }, + { "datamorph_signed", "TRUE|FALSE", 2, 2, 0, + ARG_ON_OFF|ARG_MAGIC|DATAMORPH_INT_SIGNED, + datamorph_set_signed, + "( OLcfgCtAt:7.3 NAME 'olcDatamorphIntegerSigned' " + "DESC 'Whether integers maintain sign' " + "EQUALITY booleanMatch " + "SYNTAX OMsBoolean " + "SINGLE-VALUE )", + NULL, NULL + }, + { "datamorph_lower_bound", "int", 2, 2, 0, + ARG_BERVAL|ARG_MAGIC|DATAMORPH_INT_LOWER, + datamorph_set_bounds, + "( OLcfgCtAt:7.4 NAME 'olcDatamorphIntegerLowerBound' " + "DESC 'Lowest valid value for the attribute' " + "EQUALITY integerMatch " + "SYNTAX OMsInteger " + "SINGLE-VALUE )", + NULL, NULL + }, + { "datamorph_upper_bound", "int", 2, 2, 0, + ARG_BERVAL|ARG_MAGIC|DATAMORPH_INT_UPPER, + datamorph_set_bounds, + "( OLcfgCtAt:7.5 NAME 'olcDatamorphIntegerUpperBound' " + "DESC 'Highest valid value for the attribute' " + "EQUALITY integerMatch " + "SYNTAX OMsInteger " + "SINGLE-VALUE )", + NULL, NULL + }, + + /* These have no equivalent in slapd.conf */ + { "", NULL, 2, 2, 0, + ARG_INT|ARG_MAGIC, + datamorph_set_index, + "( OLcfgCtAt:7.6 NAME 'olcDatamorphIndex' " + "DESC 'Internal DB value' " + "EQUALITY integerMatch " + "SYNTAX OMsInteger " + "SINGLE-VALUE )", + NULL, NULL + }, + { "", NULL, 2, 2, 0, + ARG_BERVAL|ARG_QUOTE|ARG_MAGIC, + datamorph_set_value, + "( OLcfgCtAt:7.7 NAME 'olcDatamorphValue' " + "DESC 'Wire value' " + "EQUALITY caseExactMatch " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL + }, + + /* slapd.conf alternative for the two above */ + { "datamorph_value", "int> <name", 3, 3, 0, + ARG_QUOTE|ARG_MAGIC, + datamorph_add_mapping, + NULL, NULL, NULL + }, + + /* slapd.conf alternative for objectclasses below */ + { "datamorph", "enum|int> <attr", 3, 3, 0, + ARG_QUOTE|ARG_MAGIC, + datamorph_add_transformation, + NULL, NULL, NULL + }, + + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + +static ConfigOCs datamorph_ocs[] = { + { "( OLcfgCtOc:7.1 " + "NAME 'olcDatamorphConfig' " + "DESC 'Datamorph overlay configuration' " + "SUP olcOverlayConfig )", + Cft_Overlay, datamorph_cfg, NULL, datamorph_cfadd }, + { "( OLcfgCtOc:7.2 " + "NAME 'olcTransformation' " + "DESC 'Transformation configuration' " + "MUST ( olcDatamorphAttribute ) " + "SUP top " + "ABSTRACT )", + Cft_Misc, datamorph_cfg, NULL }, + { "( OLcfgCtOc:7.3 " + "NAME 'olcDatamorphEnum' " + "DESC 'Configuration for an enumerated attribute' " + "SUP olcTransformation " + "STRUCTURAL )", + Cft_Misc, datamorph_cfg, datamorph_ldadd_enum }, + { "( OLcfgCtOc:7.4 " + "NAME 'olcDatamorphInteger' " + "DESC 'Configuration for a compact integer attribute' " + "MUST ( olcDatamorphIntegerBytes ) " + "MAY ( olcDatamorphIntegerLowerBound $ " + "olcDatamorphIntegerUpperBound $ " + "olcDatamorphIntegerSigned " + ") " + "SUP olcTransformation " + "STRUCTURAL )", + Cft_Misc, datamorph_cfg, datamorph_ldadd_interval }, + { "( OLcfgCtOc:7.5 " + "NAME 'olcDatamorphEnumValue' " + "DESC 'Configuration for an enumerated attribute' " + "MUST ( olcDatamorphIndex $ " + "olcDatamorphValue " + ") " + "STRUCTURAL )", + Cft_Misc, datamorph_cfg, datamorph_ldadd_mapping }, + + { NULL, 0, NULL } +}; + +static void +datamorph_mapping_free( void *arg ) +{ + datamorph_enum_mapping *mapping = arg; + + ch_free( mapping->wire_value.bv_val ); + ch_free( mapping ); +} + +static void +datamorph_info_free( void *arg ) +{ + transformation_info *info = arg; + + if ( info->type == DATAMORPH_ENUM ) { + ldap_avl_free( info->ti_enum.to_db, datamorph_mapping_free ); + } + ch_free( info ); +} + +static int +datamorph_set_attribute( ConfigArgs *ca ) +{ + transformation_info needle = {}, *info = ca->ca_private; + slap_overinst *on = (slap_overinst *)ca->bi; + datamorph_info *ov = on->on_bi.bi_private; + char *s = ca->value_string; + const char *text; + int rc = LDAP_SUCCESS; + + if ( ca->op == SLAP_CONFIG_EMIT ) { + ca->value_string = info->attr->ad_cname.bv_val; + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + info = ldap_avl_delete( &ov->transformations, info, + transformation_info_cmp ); + assert( info ); + + info->attr = NULL; + return LDAP_SUCCESS; + } + + if ( *s == '{' ) { + s = strchr( s, '}' ); + if ( !s ) { + rc = LDAP_UNDEFINED_TYPE; + goto done; + } + s += 1; + } + + rc = slap_str2ad( s, &info->attr, &text ); + ch_free( ca->value_string ); + if ( rc ) { + goto done; + } + + /* The type has to be set appropriately */ + if ( !info->attr->ad_type->sat_syntax->ssyn_sups || + info->attr->ad_type->sat_syntax->ssyn_sups[0] != + datamorph_base_syntax ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "improper syntax for attribute %s", + info->attr->ad_cname.bv_val ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + rc = LDAP_CONSTRAINT_VIOLATION; + goto done; + } + + needle.attr = info->attr; + if ( ldap_avl_find( ov->transformations, &needle, transformation_info_cmp ) ) { + rc = LDAP_CONSTRAINT_VIOLATION; + goto done; + } + +done: + if ( rc ) { + ca->reply.err = rc; + } + return rc; +} + +static int +datamorph_set_size( ConfigArgs *ca ) +{ + transformation_info *info = ca->ca_private; + + if ( !info ) { + slap_overinst *on = (slap_overinst *)ca->bi; + datamorph_info *ov = on->on_bi.bi_private; + info = ov->wip_transformation; + assert( ca->op == SLAP_CONFIG_ADD ); + } + + if ( ca->op == SLAP_CONFIG_EMIT ) { + ca->value_int = info->ti_int.size; + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + info->ti_int.size = 0; + return LDAP_SUCCESS; + } + + if ( ca->value_int != 1 && + ca->value_int != 2 && + ca->value_int != 4 && + ca->value_int != 8 ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), "invalid size %d", + ca->value_int ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } + info->ti_int.size = ca->value_int; + + return LDAP_SUCCESS; +} + +static int +datamorph_set_signed( ConfigArgs *ca ) +{ + transformation_info *info = ca->ca_private; + + if ( !info ) { + slap_overinst *on = (slap_overinst *)ca->bi; + datamorph_info *ov = on->on_bi.bi_private; + info = ov->wip_transformation; + assert( ca->op == SLAP_CONFIG_ADD ); + } + + if ( ca->op == SLAP_CONFIG_EMIT ) { + ca->value_int = info->ti_int.flags & DATAMORPH_FLAG_SIGNED; + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + info->ti_int.flags &= ~DATAMORPH_FLAG_SIGNED; + return LDAP_SUCCESS; + } + + info->ti_int.flags &= ~DATAMORPH_FLAG_SIGNED; + if ( ca->value_int ) { + info->ti_int.flags |= DATAMORPH_FLAG_SIGNED; + } + + return LDAP_SUCCESS; +} + +static int +datamorph_set_bounds( ConfigArgs *ca ) +{ + transformation_info *info = ca->ca_private; + datamorph_interval_bound *bound; + uint64_t unsigned_bound; + int64_t signed_bound; + char *ptr = ca->value_bv.bv_val + ca->value_bv.bv_len; + int flag; + + if ( !info ) { + slap_overinst *on = (slap_overinst *)ca->bi; + datamorph_info *ov = on->on_bi.bi_private; + info = ov->wip_transformation; + assert( ca->op == SLAP_CONFIG_ADD ); + } + + switch ( ca->type ) { + case DATAMORPH_INT_LOWER: + bound = &info->ti_int.lower; + flag = DATAMORPH_FLAG_LOWER; + break; + case DATAMORPH_INT_UPPER: + bound = &info->ti_int.upper; + flag = DATAMORPH_FLAG_UPPER; + break; + default: + assert(0); + } + + if ( ca->op == SLAP_CONFIG_EMIT ) { + char buf[24]; + struct berval bv = { .bv_val = buf }; + + if ( !(info->ti_int.flags & flag) ) { + /* Bound not set, do not emit */ + return LDAP_SUCCESS; + } + if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + bv.bv_len = sprintf( buf, "%" PRId64, bound->i ); + } else { + bv.bv_len = sprintf( buf, "%" PRIu64, bound->u ); + } + ber_dupbv_x( &ca->value_bv, &bv, ca->ca_op->o_tmpmemctx ); + + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + info->ti_int.flags &= ~flag; + if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + bound->i = (flag == DATAMORPH_FLAG_LOWER) ? INT64_MIN : INT64_MAX; + } else { + bound->u = (flag == DATAMORPH_FLAG_LOWER) ? 0 : UINT64_MAX; + } + return LDAP_SUCCESS; + } + + /* FIXME: if attributes in the Add operation come in the wrong order + * (signed=true after the bound definition), we can't check the interval + * sanity. */ + /* + if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + signed_bound = strtoll( ca->value_bv.bv_val, &ptr, 10 ); + } else { + unsigned_bound = strtoull( ca->value_bv.bv_val, &ptr, 10 ); + } + */ + /* Also, no idea what happens in the case of big-endian, hopefully, + * it behaves the same */ + unsigned_bound = strtoull( ca->value_bv.bv_val, &ptr, 10 ); + signed_bound = (int64_t)unsigned_bound; + + if ( *ca->value_bv.bv_val == '\0' || *ptr != '\0' ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "failed to parse '%s' as integer", + ca->value_bv.bv_val ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } + ch_free( ca->value_bv.bv_val ); + + info->ti_int.flags |= flag; + switch ( info->ti_int.size ) { + case 1: + if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + /* See FIXME above + if ( signed_bound < INT8_MIN || signed_bound > INT8_MAX ) { + goto fail; + } + */ + } else { + /* See FIXME above + if ( unsigned_bound > UINT8_MAX ) { + goto fail; + } + */ + } + break; + case 2: + if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + /* See FIXME above + if ( signed_bound < INT16_MIN || signed_bound > INT16_MAX ) { + goto fail; + } + */ + } else { + /* See FIXME above + if ( unsigned_bound > UINT16_MAX ) { + goto fail; + } + */ + } + break; + case 4: + if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + /* See FIXME above + if ( signed_bound < INT32_MIN || signed_bound > INT32_MAX ) { + goto fail; + } + */ + } else { + /* See FIXME above + if ( unsigned_bound > UINT32_MAX ) { + goto fail; + } + */ + } + break; + case 8: + break; + default: + /* Should only happen in these two cases: + * 1. datamorph_size not yet encountered for this one (when + * processing slapd.conf) + * 2. When someone runs a fun modification on the config entry + * messing with more attributes at once + * + * The error message is expected to be helpful only for the former, + * so use the slapd.conf name. + */ + snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "datamorph_size has to be set first!" ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } + if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { + bound->i = signed_bound; + } else { + bound->u = unsigned_bound; + } + + return LDAP_SUCCESS; +} + +static int +datamorph_set_value( ConfigArgs *ca ) +{ + datamorph_enum_mapping *mapping = ca->ca_private; + char *s = ca->value_bv.bv_val; + + if ( ca->op == SLAP_CONFIG_EMIT ) { + /* We generate the value as part of the RDN, don't add anything */ + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + ch_free( mapping->wire_value.bv_val ); + BER_BVZERO( &mapping->wire_value ); + /* TODO: remove from info->ti_enum.to_db? */ + return LDAP_SUCCESS; + } + + /* As long as this attribute can be in the RDN, + * we have to expect the '{n}' prefix */ + if ( *s == '{' ) { + ber_len_t len; + s = memchr( s, '}', ca->value_bv.bv_len ); + if ( !s ) { + ca->reply.err = LDAP_UNDEFINED_TYPE; + return ca->reply.err; + } + s += 1; + + len = ca->value_bv.bv_len - ( s - ca->value_bv.bv_val ); + ber_str2bv( s, len, 1, &mapping->wire_value ); + ch_free( ca->value_bv.bv_val ); + } else { + mapping->wire_value = ca->value_bv; + } + + return LDAP_SUCCESS; +} + +static int +datamorph_set_index( ConfigArgs *ca ) +{ + datamorph_enum_mapping *mapping = ca->ca_private; + struct berval *from_db = mapping->transformation->ti_enum.from_db; + + if ( ca->op == SLAP_CONFIG_EMIT ) { + ca->value_int = mapping->db_value; + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + BER_BVZERO( &from_db[mapping->db_value] ); + return LDAP_SUCCESS; + } + + if ( ca->value_int < 0 || ca->value_int >= 256 ) { + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } else if ( !BER_BVISNULL( &from_db[ca->value_int] ) ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), "duplicate index %d", + ca->value_int ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } + mapping->db_value = ca->value_int; + from_db[ca->value_int] = mapping->wire_value; + + return LDAP_SUCCESS; +} + +/* Called when processing slapd.conf only, + * cn=config uses the objectclass to decide which type we're dealing with. + */ +static int +datamorph_add_transformation( ConfigArgs *ca ) +{ + slap_overinst *on = (slap_overinst *)ca->bi; + datamorph_info *ov = on->on_bi.bi_private; + transformation_info *info; + + if ( ov->wip_transformation ) { + /* We checked everything as were processing the lines */ + int rc = ldap_avl_insert( &ov->transformations, ov->wip_transformation, + transformation_info_cmp, ldap_avl_dup_error ); + assert( rc == LDAP_SUCCESS ); + } + + info = ch_calloc( 1, sizeof(transformation_info) ); + ov->wip_transformation = ca->ca_private = info; + + if ( !strcasecmp( ca->argv[1], "enum" ) ) { + info->type = DATAMORPH_ENUM; + } else if ( !strcasecmp( ca->argv[1], "int" ) ) { + info->type = DATAMORPH_INT; + } else { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "unknown transformation type '%s'", ca->argv[1] ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } + + ca->value_string = strdup( ca->argv[2] ); + + return datamorph_set_attribute( ca ); +} + +static int +datamorph_add_mapping( ConfigArgs *ca ) +{ + slap_overinst *on = (slap_overinst *)ca->bi; + datamorph_info *ov = on->on_bi.bi_private; + transformation_info *info = ov->wip_transformation; + datamorph_enum_mapping *mapping; + int rc = LDAP_CONSTRAINT_VIOLATION; + + if ( !info ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), "no attribute configured" ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + goto done; + } + + mapping = ch_calloc( 1, sizeof(datamorph_enum_mapping) ); + mapping->transformation = info; + ca->ca_private = mapping; + + ber_str2bv( ca->argv[2], 0, 1, &ca->value_bv ); + rc = datamorph_set_value( ca ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + rc = lutil_atoix( &ca->value_int, ca->argv[1], 0 ); + if ( rc != LDAP_SUCCESS ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), "invalid integer %s", + ca->argv[1] ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + goto done; + } + + rc = datamorph_set_index( ca ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + +done: + if ( rc == LDAP_SUCCESS ) { + rc = ldap_avl_insert( &info->ti_enum.to_db, mapping, + transformation_mapping_cmp, ldap_avl_dup_error ); + } + if ( rc ) { + ca->reply.err = rc; + } + + return rc; +} + +static int +datamorph_ldadd_info_cleanup( ConfigArgs *ca ) +{ + slap_overinst *on = (slap_overinst *)ca->bi; + datamorph_info *ov = on->on_bi.bi_private; + transformation_info *info = ca->ca_private; + + if ( ca->reply.err != LDAP_SUCCESS ) { + /* Not reached since cleanup is only called on success */ +fail: + ch_free( info ); + return LDAP_SUCCESS; + } + + if ( ldap_avl_insert( &ov->transformations, info, transformation_info_cmp, + ldap_avl_dup_error ) ) { + goto fail; + } + return LDAP_SUCCESS; +} + +static int +datamorph_ldadd_transformation( + CfEntryInfo *cei, + Entry *e, + ConfigArgs *ca, + datamorph_type type ) +{ + transformation_info *info; + + if ( cei->ce_type != Cft_Overlay || !cei->ce_bi || + cei->ce_bi->bi_cf_ocs != datamorph_ocs ) + return LDAP_CONSTRAINT_VIOLATION; + + info = ch_calloc( 1, sizeof(transformation_info) ); + info->type = type; + + ca->bi = cei->ce_bi; + ca->ca_private = info; + config_push_cleanup( ca, datamorph_ldadd_info_cleanup ); + /* config_push_cleanup is only run in the case of online config but we use it to + * enable the new config when done with the entry */ + ca->lineno = 0; + + return LDAP_SUCCESS; +} + +static int +datamorph_ldadd_enum( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) +{ + return datamorph_ldadd_transformation( cei, e, ca, DATAMORPH_ENUM ); +} + +static int +datamorph_ldadd_interval( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) +{ + return datamorph_ldadd_transformation( cei, e, ca, DATAMORPH_INT ); +} + +static int +datamorph_ldadd_mapping_cleanup( ConfigArgs *ca ) +{ + datamorph_enum_mapping *mapping = ca->ca_private; + transformation_info *info = mapping->transformation; + + if ( ca->reply.err != LDAP_SUCCESS ) { + /* Not reached since cleanup is only called on success */ +fail: + datamorph_mapping_free( mapping ); + return LDAP_SUCCESS; + } + + if ( ldap_avl_insert( &info->ti_enum.to_db, mapping, transformation_mapping_cmp, + ldap_avl_dup_error ) ) { + goto fail; + } + info->ti_enum.from_db[mapping->db_value] = mapping->wire_value; + + return LDAP_SUCCESS; +} + +static int +datamorph_ldadd_mapping( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) +{ + transformation_info *info; + datamorph_enum_mapping *mapping; + CfEntryInfo *parent = cei->ce_parent; + + if ( cei->ce_type != Cft_Misc || !parent || !parent->ce_bi || + parent->ce_bi->bi_cf_ocs != datamorph_ocs ) + return LDAP_CONSTRAINT_VIOLATION; + + info = cei->ce_private; + + mapping = ch_calloc( 1, sizeof(datamorph_enum_mapping) ); + mapping->transformation = info; + + ca->ca_private = mapping; + config_push_cleanup( ca, datamorph_ldadd_mapping_cleanup ); + /* config_push_cleanup is only run in the case of online config but we use it to + * enable the new config when done with the entry */ + ca->lineno = 0; + + return LDAP_SUCCESS; +} + +struct datamorph_cfadd_args { + Operation *op; + SlapReply *rs; + Entry *p; + ConfigArgs *ca; + int index; +}; + +static int +datamorph_config_build_enum( void *item, void *arg ) +{ + datamorph_enum_mapping *mapping = item; + struct datamorph_cfadd_args *args = arg; + struct berval rdn; + Entry *e; + char *p; + ber_len_t index; + + rdn.bv_len = snprintf( args->ca->cr_msg, sizeof(args->ca->cr_msg), + "olcDatamorphValue={%d}", args->index++ ); + rdn.bv_val = args->ca->cr_msg; + p = rdn.bv_val + rdn.bv_len; + + rdn.bv_len += mapping->wire_value.bv_len; + for ( index = 0; index < mapping->wire_value.bv_len; index++ ) { + if ( RDN_NEEDSESCAPE(mapping->wire_value.bv_val[index]) ) { + rdn.bv_len++; + *p++ = '\\'; + } + *p++ = mapping->wire_value.bv_val[index]; + } + *p = '\0'; + + args->ca->ca_private = mapping; + args->ca->ca_op = args->op; + e = config_build_entry( args->op, args->rs, args->p->e_private, args->ca, + &rdn, &datamorph_ocs[4], NULL ); + assert( e ); + + return LDAP_SUCCESS; +} + +static int +datamorph_config_build_attr( void *item, void *arg ) +{ + transformation_info *info = item; + struct datamorph_cfadd_args *args = arg; + struct berval rdn; + ConfigOCs *oc; + Entry *e; + + rdn.bv_len = snprintf( args->ca->cr_msg, sizeof(args->ca->cr_msg), + "olcDatamorphAttribute={%d}%s", args->index++, + info->attr->ad_cname.bv_val ); + rdn.bv_val = args->ca->cr_msg; + + switch ( info->type ) { + case DATAMORPH_ENUM: + oc = &datamorph_ocs[2]; + break; + case DATAMORPH_INT: + oc = &datamorph_ocs[3]; + break; + default: + assert(0); + break; + } + + args->ca->ca_private = info; + args->ca->ca_op = args->op; + e = config_build_entry( + args->op, args->rs, args->p->e_private, args->ca, &rdn, oc, NULL ); + assert( e ); + + if ( info->type == DATAMORPH_ENUM ) { + struct datamorph_cfadd_args new_args = *args; + new_args.p = e; + new_args.index = 0; + + return ldap_avl_apply( info->ti_enum.to_db, datamorph_config_build_enum, + &new_args, 1, AVL_PREORDER ); + } + + return LDAP_SUCCESS; +} + +static int +datamorph_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca ) +{ + slap_overinst *on = (slap_overinst *)ca->bi; + datamorph_info *ov = on->on_bi.bi_private; + struct datamorph_cfadd_args args = { + .op = op, + .rs = rs, + .p = p, + .ca = ca, + .index = 0, + }; + + if ( ov->wip_transformation ) { + /* There is one last item that is unfinished */ + int rc = ldap_avl_insert( &ov->transformations, ov->wip_transformation, + transformation_info_cmp, ldap_avl_dup_error ); + assert( rc == LDAP_SUCCESS ); + } + + return ldap_avl_apply( ov->transformations, &datamorph_config_build_attr, &args, + 1, AVL_PREORDER ); +} + +static slap_overinst datamorph; + +static int +datamorph_db_init( BackendDB *be, ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + datamorph_info *ov; + + /* TODO: can this be global? */ + if ( SLAP_ISGLOBALOVERLAY(be) ) { + Debug( LDAP_DEBUG_ANY, "datamorph overlay must be instantiated " + "within a database.\n" ); + return 1; + } + + ov = ch_calloc( 1, sizeof(datamorph_info) ); + on->on_bi.bi_private = ov; + + return LDAP_SUCCESS; +} + +static int +datamorph_db_destroy( BackendDB *be, ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + datamorph_info *ov = on->on_bi.bi_private; + + if ( ov ) { + ldap_avl_free( ov->transformations, datamorph_info_free ); + } + ch_free( ov ); + + return LDAP_SUCCESS; +} + +int +datamorph_initialize() +{ + int rc, i; + + datamorph.on_bi.bi_type = "datamorph"; + datamorph.on_bi.bi_db_init = datamorph_db_init; + datamorph.on_bi.bi_db_destroy = datamorph_db_destroy; + + datamorph.on_bi.bi_op_add = datamorph_op_add; + datamorph.on_bi.bi_op_compare = datamorph_op_compare; + datamorph.on_bi.bi_op_modify = datamorph_op_mod; + datamorph.on_bi.bi_op_modrdn = datamorph_op_modrdn; + datamorph.on_bi.bi_op_search = datamorph_op_search; + datamorph.on_response = datamorph_response; + + datamorph.on_bi.bi_entry_release_rw = datamorph_entry_release_rw; + datamorph.on_bi.bi_entry_get_rw = datamorph_entry_get_rw; + + datamorph.on_bi.bi_cf_ocs = datamorph_ocs; + + for ( i = 0; datamorph_syntax_defs[i].sd_desc != NULL; i++ ) { + rc = register_syntax( &datamorph_syntax_defs[i] ); + + if ( rc ) { + Debug( LDAP_DEBUG_ANY, "datamorph_initialize: " + "error registering syntax %s\n", + datamorph_syntax_defs[i].sd_desc ); + return rc; + } + } + + datamorph_base_syntax = syn_find( DATAMORPH_SYNTAX_BASE ); + assert( datamorph_base_syntax ); + + for ( i = 0; datamorph_mrule_defs[i].mrd_desc != NULL; i++ ) { + rc = register_matching_rule( &datamorph_mrule_defs[i] ); + + if ( rc ) { + Debug( LDAP_DEBUG_ANY, "datamorph_initialize: " + "error registering matching rule %s\n", + datamorph_mrule_defs[i].mrd_desc ); + return rc; + } + } + + rc = config_register_schema( datamorph_cfg, datamorph_ocs ); + if ( rc ) return rc; + + return overlay_register( &datamorph ); +} + +#if SLAPD_OVER_DATAMORPH == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return datamorph_initialize(); +} +#endif + +#endif /* SLAPD_OVER_DATAMORPH */ diff --git a/contrib/slapd-modules/datamorph/slapo-datamorph.5 b/contrib/slapd-modules/datamorph/slapo-datamorph.5 new file mode 100644 index 0000000..0ce0c6a --- /dev/null +++ b/contrib/slapd-modules/datamorph/slapo-datamorph.5 @@ -0,0 +1,338 @@ +.TH SLAPO-DATAMORPH 5 "RELEASEDATE" "OpenLDAP" +.\" Copyright 2016-2017 Symas Corp. All Rights Reserved. +.\" Copying restrictions apply. See LICENSE. +.SH NAME +slapo\-datamorph \- store enumerated values and fixed size integers +.SH SYNOPSIS +olcOverlay=datamorph +.SH DESCRIPTION +The +.B datamorph +overlay to +.BR slapd (8) +allows attributes with a few pre-defined values to be saved more +space-efficiently as well as signed or unsigned integer attributes. + +.LP +The overlay operates on configured attributes that must have their syntax +compatible with +.BR 1.3.6.1.4.1.4203.666.11.12.1.1 , +there are three such syntaxes defined by the overlay: +.B 1.3.6.1.4.1.4203.666.11.12.1.2 +(Enumerated value), +.B 1.3.6.1.4.1.4203.666.11.12.1.3 +(Fixed-size integer), and +.B 1.3.6.1.4.1.4203.666.11.12.1.4 +(Fixed-size signed integer). +.LP + +While transforming the request, if a value for an attribute is not permitted by the configuration, the behaviour depends on the operation: + +.RS +.TP +.B Search +The affected value assertions in a +.B Search +request filter are replaced by a filter returning +.B Undefined . +.TP +.B Compare +Request returns +.B Compare +.BR False . +.TP +.B Add, Modify +Requests are rejected with a +.B Constraint +.BR Violation . +.RE + +The supported allowed matching rules for the attribute types above are: + +.RS +.TP +.B EQUALITY fixedSizeIntegerMatch +Appropriate for syntaxes +.B 1.3.6.1.4.1.4203.666.11.12.1.2 +(Enumerated value), and +.B 1.3.6.1.4.1.4203.666.11.12.1.3 +(Fixed-size integer). +.TP +.B EQUALITY fixedSizeSignedIntegerMatch +Appropriate for syntax +.B 1.3.6.1.4.1.4203.666.11.12.1.4 +(Fixed-size signed integer) only. +.TP +.B ORDERING fixedSizeIntegerOrderingMatch +Appropriate for syntaxes +.B 1.3.6.1.4.1.4203.666.11.12.1.2 +(Enumerated value), and +.B 1.3.6.1.4.1.4203.666.11.12.1.3 +(Fixed-size integer). Enumerated value attributes are compared according to +their stored database value. +.TP +.B ORDERING fixedSizeSignedIntegerOrderingMatch +Appropriate for syntax +.B 1.3.6.1.4.1.4203.666.11.12.1.4 +(Fixed-size signed integer) only. + + +.SH CONFIGURATION LAYOUT + +The overlay has to be instantiated under a database adding an entry of +.B olcOverlay=datamorph +with objectClass of +.BR olcDatamorphConfig. + +The overlay configuration subtree consists of the following levels: +.RS +.TP +.B objectClass=olcDatamorphConfig +Main overlay configuration. Created directly under the database +configuration entry. +.TP +.B objectClass=olcDatamorphInteger +Specifies a +.B fixed-size integer +attribute and must be a child of an entry with +.BR objectClass=olcDatamorphConfig . +There may be as many such entries as necessary provided they all specify a +different attribute in the +.B olcDatamorphAttribute +attribute. +.TP +.B objectClass=olcDatamorphEnum +Specifies an +.B enumerated +attribute and must be a child of an entry with +.BR objectClass=olcDatamorphConfig . +There may be as many such entries as necessary provided they all specify a +different attribute in the +.B olcDatamorphAttribute +attribute. +.TP +.B objectClass=olcDatamorphEnumValue +Specifies a permitted value for the enumerated attribute and its database +representation. Must be a child of an entry with +.BR objectClass=olcDatamorphEnum . +There may be as many such entries as necessary provided they all specify a +different value and index in the corresponding fields. +.RE + +In the case of +.BR slapd.conf (5), +the attribute definition is delimited by the keyword +.B datamorph +to define an integer or enumerated attribute followed by an arbitrary number of +.B datamorph_value +lines in the case of an enumerated one. Each new +.B datamorph +line starts configuring a new attribute. + +.SH ENUMERATED ATTRIBUTE CONFIGURATION ENTRY + +The enumerated attribute entry configuration +.RB ( olcDatamorphEnum ) +only has the following option available: + +.RS +.TP +.B olcDatamorphAttribute: <attribute> +Mandatory attribute, indicates that the named attribute is to be handled by the +overlay. The +.BR slapd.conf (5) +equivalent is +.B datamorph "int" +.BR <attribute> . +.RE + +The children of this entry then define how the string values map to the +database values. They use the objectclass +.BR olcDatamorphEnumValue , +which asks for the following attributes: + +.RS +.TP +.B olcDatamorphValue: <value> +A permitted value for the attribute being configured. +.TP +.B olcDatamorphIndex: <0-255> +The corresponding database value. +.RE + +The +.BR slapd.conf (5) +equivalent of the above two is +.B datamorph_value <0-255> <value> +.RB . + +.SH FIXED-WIDTH INTEGER CONFIGURATION ENTRY + +The fixed-width integer configuration entry +.RB ( olcDatamorphInteger ) +has the following options available: + +.RS +.TP +.B olcDatamorphAttribute: <attribute> +Mandatory attribute, indicates that the named attribute is to be handled by the +overlay. The +.BR slapd.conf (5) +equivalent is +.B datamorph "int" +.BR <attribute> . +.TP +.B olcDatamorphIntegerBytes: <1|2|4|8> +Size of the integer as stored in the backend. The +.BR slapd.conf (5) +equivalent is +.B datamorph_size +.BR <1|2|4|8> . +.TP +.B olcDatamorphIntegerSigned: <TRUE|FALSE> +Whether the integer is to be treated as signed. Note that the overlay will not +enforce consistency between this option and the attribute's syntax. The +.BR slapd.conf (5) +equivalent is +.B datamorph_signed +.BR <TRUE|FALSE> . +.TP +.B olcDatamorphIntegerLowerBound: <number> +The lowest value that the configured attribute will be allowed to have. This +affects all operations where values are mentioned. The +.BR slapd.conf (5) +equivalent is +.B datamorph_lower_bound +.BR <number> . +.TP +.B olcDatamorphIntegerUpperBound: <number> +The highest value that the configured attribute will be allowed to have. This +affects all operations where values are mentioned. The +.BR slapd.conf (5) +equivalent is +.B datamorph_upper_bound +.BR <number> . +.RE + +.SH EXAMPLE + +The following is an example of a configured overlay, substitute +.B $DATABASE +for the DN of the database it is attached to and +.B {x} +with the desired position of the overlay in the overlay stack. + +.nf +dn: olcOverlay={x}datamorph,$DATABASE +objectClass: olcDatamorphConfig +olcOverlay: datamorph + +# to handle attribute 'enumeratedAttribute' +dn: olcDatamorphAttribute=enumeratedAttribute,olcOverlay={x}datamorph,$DATABASE +objectClass: olcDatamorphEnum + +# value 'value1' corresponds to 'AQ==' (0x01) +dn: olcDatamorphValue=value1,olcDatamorphAttribute={0}enumeratedAttribute,olcOv + erlay={x}datamorph,$DATABASE +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 1 + +# value 'value11' corresponds to 'Cw==' (0x0B) +dn: olcDatamorphValue=value11,olcDatamorphAttribute={0}enumeratedAttribute,olcO + verlay={x}datamorph,$DATABASE +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 11 + +# handle attribute 'signedInteger' as a 2-byte signed integer with values +# between -20000 and 30000 (inclusive on both sides) +dn: olcDatamorphAttribute=signedInteger,olcOverlay={x}datamorph,$DATABASE +objectclass: olcDatamorphInteger +olcDatamorphIntegerBytes: 2 +olcDatamorphIntegerSigned: TRUE +olcDatamorphIntegerLowerBound: -20000 +olcDatamorphIntegerUpperBound: 30000 + +# handle attribute 'shortInteger' as a 1-byte unsigned integer with only values +# 0 and 1 allowed (effectively a true/false) +dn: olcDatamorphAttribute=shortInteger,olcOverlay={x}datamorph,$DATABASE +objectclass: olcDatamorphInteger +olcDatamorphIntegerBytes: 1 +olcDatamorphIntegerUpperBound: 1 +olcDatamorphIntegerSigned: FALSE +.fi + +The +.BR slapd.conf (5) +equivalent of the above follows: + +.nf +overlay datamorph + +datamorph enum enumeratedAttribute +datamorph_value 1 value1 +datamorph_value 11 value11 + +datamorph int signedInteger +datamorph_size 2 +datamorph_signed TRUE +datamorph_lower_bound -20000 +datamorph_upper_bound 30000 + +datamorph int shortInteger +datamorph_size 1 +datamorph_signed no +datamorph_upper_bound 1 +.fi + +.SH REPLICATION + +Given that there are syntaxes and matching rules provided by the overlay, it +should be configured on each replica to guarantee consistency. + +.SH BUGS AND LIMITATIONS +Due to the fact that overlays are not active in the +.BR slapcat (8) +nor +.BR slapadd (8) +processes, backups of the database will be made exactly as stored. This means +that backups made using +.BR ldapsearch (1) +cannot be used by +.BR slapadd (8) +nor can backups made using +.BR slapcat (8) +be loaded using +.BR ldapadd (8). + +Value based ACLs that involve values of the transformed attributes are not +supported. + +The overlay will refuse operations that add or rename entries with any of the +configured attributes in their RDN. + +No controls are explicitly handled in the overlay, attaching any controls that +reference configured attributes might lead to unexpected behaviour and is +therefore discouraged. + +Increment modification of the configured attributes is not supported either. + +If a transformation is configured to be signed yet the attribute's schema uses the +unsigned syntax and matching rules, inequality matching will not work as +intended and will treat negative numbers as higher than positive numbers. + +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.TP +ETCDIR/slapd.d +default slapd configuration directory +.SH SEE ALSO +.BR slapd-config (5), +.BR slapd.conf (5), +.BR slapd.overlays (5), +.BR slapd (8), +.BR slapcat (8), +.BR slapadd (8) +.SH ACKNOWLEDGEMENTS +This module was developed in 2016 by Ondřej Kuzník for Symas Corp. diff --git a/contrib/slapd-modules/datamorph/tests/Rules.mk b/contrib/slapd-modules/datamorph/tests/Rules.mk new file mode 100644 index 0000000..c25c1d2 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/Rules.mk @@ -0,0 +1,23 @@ +sp := $(sp).x +dirstack_$(sp) := $(d) +d := $(dir) + +.PHONY: test + +CLEAN += clients servers tests/progs tests/schema tests/testdata tests/testrun + +test: all clients servers tests/progs + +test: + cd tests; \ + SRCDIR=$(abspath $(LDAP_SRC)) \ + LDAP_BUILD=$(abspath $(LDAP_BUILD)) \ + TOPDIR=$(abspath $(SRCDIR)) \ + LIBTOOL=$(abspath $(LIBTOOL)) \ + $(abspath $(SRCDIR))/tests/run all + +servers clients tests/progs: + ln -s $(abspath $(LDAP_BUILD))/$@ $@ + +d := $(dirstack_$(sp)) +sp := $(basename $(sp)) diff --git a/contrib/slapd-modules/datamorph/tests/data/config.ldif b/contrib/slapd-modules/datamorph/tests/data/config.ldif new file mode 100644 index 0000000..91f2e60 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/config.ldif @@ -0,0 +1,108 @@ +dn: cn=datamorph,cn=schema,cn=config +changetype: add +objectClass: olcSchemaConfig +olcAttributeTypes: ( 1.3.6.1.4.1.4203.666.11.12.123.1 + NAME 'enumerated' + DESC 'Enumerated attribute' + EQUALITY fixedSizeIntegerMatch + ORDERING fixedSizeIntegerOrderingMatch + SYNTAX 1.3.6.1.4.1.4203.666.11.12.1.2 ) +olcAttributeTypes: ( 1.3.6.1.4.1.4203.666.11.12.123.2 + NAME 'number' + DESC 'Integer attribute' + EQUALITY fixedSizeIntegerMatch + ORDERING fixedSizeIntegerOrderingMatch + SYNTAX 1.3.6.1.4.1.4203.666.11.12.1.3 ) +olcAttributeTypes: ( 1.3.6.1.4.1.4203.666.11.12.123.3 + NAME 'signed' + DESC 'Signed integer attribute' + EQUALITY fixedSizeSignedIntegerMatch + ORDERING fixedSizeSignedIntegerOrderingMatch + SYNTAX 1.3.6.1.4.1.4203.666.11.12.1.4 ) +olcObjectClasses: ( 1.3.6.1.4.1.4203.666.11.12.123.4 + NAME 'transformedObject' + DESC 'Testing objectclass' + SUP top AUXILIARY + MAY ( enumerated $ number $ signed ) ) + +dn: olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectClass: olcOverlayConfig +objectclass: olcDatamorphConfig + +# a basic enum +dn: olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnum + +dn: olcDatamorphValue=bjensen,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 1 + +dn: olcDatamorphValue=bjorn,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 11 + +dn: olcDatamorphValue=dots,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 12 + +dn: olcDatamorphValue=jaj,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 13 + +dn: olcDatamorphValue=jjones,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 14 + +dn: olcDatamorphValue=jdoe,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 10 + +dn: olcDatamorphValue=jen,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 101 + +dn: olcDatamorphValue=johnd,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 20 + +dn: olcDatamorphValue=melliot,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 51 + +dn: olcDatamorphValue=uham,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 31 + +dn: olcDatamorphValue=\5Cno \22name\22,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 200 + +# an interval +dn: olcDatamorphAttribute=signed,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphInteger +olcDatamorphIntegerBytes: 2 +olcDatamorphIntegerSigned: TRUE +olcDatamorphIntegerLowerBound: -20000 +olcDatamorphIntegerUpperBound: 30000 + +# an number interval (essentially TRUE/FALSE) +dn: olcDatamorphAttribute=number,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphInteger +olcDatamorphIntegerBytes: 1 +olcDatamorphIntegerUpperBound: 1 +olcDatamorphIntegerSigned: FALSE diff --git a/contrib/slapd-modules/datamorph/tests/data/datamorph.conf b/contrib/slapd-modules/datamorph/tests/data/datamorph.conf new file mode 100644 index 0000000..7cc4899 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/datamorph.conf @@ -0,0 +1,49 @@ +overlay datamorph + +# they depend on the syntaxes defined by the overlay +attributetype ( 1.3.6.1.4.1.4203.666.11.12.123.1 NAME 'enumerated' + DESC 'Enumerated attribute' + EQUALITY fixedSizeIntegerMatch + ORDERING fixedSizeIntegerOrderingMatch + SYNTAX 1.3.6.1.4.1.4203.666.11.12.1.2 ) + +attributetype ( 1.3.6.1.4.1.4203.666.11.12.123.2 NAME 'number' + DESC 'Integer attribute' + EQUALITY fixedSizeIntegerMatch + ORDERING fixedSizeIntegerOrderingMatch + SYNTAX 1.3.6.1.4.1.4203.666.11.12.1.3 ) + +attributetype ( 1.3.6.1.4.1.4203.666.11.12.123.3 NAME 'signed' + DESC 'Signed integer attribute' + EQUALITY fixedSizeSignedIntegerMatch + ORDERING fixedSizeSignedIntegerOrderingMatch + SYNTAX 1.3.6.1.4.1.4203.666.11.12.1.4 ) + +objectclass ( 1.3.6.1.4.1.4203.666.11.12.123.4 NAME 'transformedObject' + DESC 'Testing objectclass' + SUP top AUXILIARY + MAY ( enumerated $ number $ signed ) ) + +datamorph eNuM enumerated +datamorph_value 1 bjensen +datamorph_value 11 bjorn +datamorph_value 12 dots +datamorph_value "13" jaj +datamorph_value 14 jjones +datamorph_value 10 jdoe +datamorph_value 101 jen +datamorph_value 20 johnd +datamorph_value 51 "melliot" +datamorph_value 31 uham +datamorph_value 200 "\\no \"name\"" + +datamorph int signed +datamorph_size 2 +datamorph_signed TRUE +datamorph_lower_bound -20000 +datamorph_upper_bound 30000 + +datamorph iNT number +datamorph_size 1 +datamorph_signed no +datamorph_upper_bound 1 diff --git a/contrib/slapd-modules/datamorph/tests/data/test.ldif b/contrib/slapd-modules/datamorph/tests/data/test.ldif new file mode 100644 index 0000000..67971f3 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test.ldif @@ -0,0 +1,434 @@ +#LEAD COMMENT +dn: dc=example,dc=com +#EMBEDDED COMMENT +objectClass: top +objectClass: organization +objectClass: domainRelatedObject +objectClass: dcobject +dc: example +l: Anytown, Michigan +st: Michigan +o: Example, Inc. +o: EX +o: Ex. +description: The Example, Inc. at Anytown +postalAddress: Example, Inc. $ 535 W. William St. $ Anytown, MI 48109 $ US +telephoneNumber: +1 313 555 1817 +associatedDomain: example.com + +dn: ou=People,dc=example,dc=com +objectClass: organizationalUnit +objectClass: extensibleObject +ou: People +uidNumber: 0 +gidNumber: 0 +signed:: sm4= +number:: AA== + +dn: ou=Groups,dc=example,dc=com +objectClass: organizationalUnit +ou: Groups + +dn: ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: organizationalUnit +ou: Alumni Association + +dn: ou=Information Technology Division,ou=People,dc=example,dc=com +objectClass: organizationalUnit +ou: Information Technology Division +description:: aMODwoPDgsKCw4PCgsOCwotFVlZQw4PCg8OCwoPDg8KCw4LCv0zDg8KDw4LCgsOD + woLDgsKKT8ODwoPDgsKDw4PCgsOCwqs6w4PCg8OCwoLDg8KCw4LCjUQkw4PCg8OCwoLDg8KCw4LCi + 01QUcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4 + LCgsODwoLDgsKLRCQoZitEJMODwoPDgsKCw4PCgsOCwrfDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoP + Dg8KCw4LCgcODwoPDgsKDw4PCgsOCwqHDg8KDw4LCgsODwoLDgsKLRCQkZitEJMODwoPDgsKCw4PC + gsOCwrfDg8KDw4LCg8ODwoLDgsKQw4PCg8OCwoPDg8KCw4LCisODwoPDgsKCw4PCgsOCwotFUVZqU + MODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKAw4PCg8OCwoLDg8KCw4LCik85dCTDg8KDw4 + LCgsODwoLDgsKFQ8ODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4L + Cvzl0JMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPD + gsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKLRCTDg8KDw4LCgsODwoLDgsKDw4PCg8OCwoLDg8KCw + 4LCuMODwoPDgsKDw4PCgsOCwoR0Q8ODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LChMODwo + PDgsKDw4PCgsOCwoFOdTrDg8KDw4LCg8ODwoLDgsKHw4PCg8OCwoPDg8KCw4LChMODwoPDgsKDw4P + CgsOCwoFOw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwrtHw4PCg8OCwoLDg8KCw4LChcOD + woPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsK4dMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODw + oLDgsKtR8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwo + PDgsKDw4PCgsOCwr9SfGrDg8KDw4LCgsODwoLDgsKLQGgxw4PCg8OCwoPDg8KCw4LCoWhQw4PCg8O + CwoPDg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKT8ODwoPDgsKCw4PCgsOC + wotEJDDDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHTDg8KDw4LCgsODwoLDgsKDw4PCg + 8OCwoPDg8KCw4LCuHXDg8KDw4LCgsODwoLDgsKLRCRqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4 + PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpPDg8K + Dw4LCg8ODwoLDgsKQXV9eW8ODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoPD + g8KCw4LCgsODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODw + oPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgs + OCwoxWV8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKxw4PCg8OCwoLDg8KCw4LCi3wkw4P + Cg8OCwoLDg8KCw4LCjcODwoPDgsKCw4PCgsOCwofDg8KDw4LCg8ODwoLDgsKof8ODwoPDgsKDw4PC + gsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCg8ODwoPDgsKDw4PCgsOCwrh5w4PCg + 8OCwoLDg8KCw4LChzQzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PCgsOCworDg8KDw4LCgsODwo + LDgsKIw4PCg8OCwoLDg8KCw4LCuDFBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNdDF + Bw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPD + gsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw + 4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgs + KCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKAdcODwoPDgsKDw4PCgsOCwqhtw4PCg8OCwoLDg8KCw4L + ChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCsMODwoPDgsKC + w4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCt + sODwoPDgsKDw4PCgsOCwq7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4 + PCgsOCwoPDg8KDw4LCg8ODwoLDgsKoZsODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4w4P + Cg8OCwoLDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwpUzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PC + gsOCworDg8KDw4LCgsODwoLDgsKISDJBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNN + DJBw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwo + PDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8O + DwoPDgsKDw4PCgsOCwojDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCnEzDg8KDw4LCgsOD + woLDgsKLSEBmw4PCg8OCwoLDg8KCw4LCg3lwdSTDg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw + 4LCv8ODwoPDgsKCw4PCgsOCwobDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgs + KCw4PCgsOCwp/Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwoj + Dg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCwpPDg8KDw4LCgsOD + woLDgsKBw4PCg8OCwoPDg8KCw4LCv1rDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODw + oPDgsKCw4PCgsOCwodqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwoBqaMODwoPDgsKCw4 + PCgsOCwpBQw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDIMODwoPDgsKCw4PCgsOCwopPw4PCg8OCwoL + Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKOacODwoPDgsKCw4PCgsOCwrhf + XsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCw + oLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKGw4PCg8OCwoLDg8KCw4LCgM + ODwoPDgsKCw4PCgsOCwoRJw4PCg8OCwoLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsO + DwoLDgsKIw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQ9w4PCg8OCwoLDg8KCw4LCgcOD + woPDgsKDw4PCgsOCwr9aw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQxw4PCg8OCwoLDg + 8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LCm0 + 7Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsK + Cw4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD + gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODw + oPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgs + OCwo7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCkMODwoPDgsKDw4PCgsOCwojDg8KDw4L + CgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsK+ + S8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKww4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDw + 4PCgsOCwoTDg8KDw4LCgsODwoLDgsKKT1DDg8KDw4LCg8ODwoLDgsKoRsODwoPDgsKCw4PCgsOCwo + vDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwrZ0Y8ODwoPDgsK + Cw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/dF/Dg8KDw4LCgsODwoLDgsKhdHpPw4PCg8OCwoLDg8KC + w4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PCg8OCwoPDg8KCw4LCqC1Jw4PCg8OCwoLDg8KCw4LChcODw + oPDgsKDw4PCgsOCwoB1RMODwoPDgsKCw4PCgsOCwqFwek/Dg8KDw4LCgsODwoLDgsKLw4PCg8OCwo + PDg8KCw4LCj1DDg8KDw4LCg8ODwoLDgsKoScODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK + AdTPDg8KDw4LCgsODwoLDgsKhbHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PC + g8OCwoPDg8KCw4LCqEnDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHXDg8KDw4LCgsODw + oLDgsKhaHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo9Qw4PCg8OCwoPDg8KCw4LCqM + ODwoPDgsKDw4PCgsOCwrpIw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoB1M8ODwoPDgsK + Dw4PCgsOCwoBfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD + gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgjPDg8KDw4LCg8ODwoLDgsKAX17Dg + 8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCg8ODwo + LDgsKoJ8ODwoPDgsKDw4PCgsOCwq3Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoP + DgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4aHU5w4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PC + gsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw + 4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgs + KIw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpLDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoL + Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoB0IcODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKA + w4PCg8OCwoPDg8KCw4LCtMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKAdGbDg8KDw4LCg + sODwoLDgsKLQGY9dGY9dTPDg8KDw4LCg8ODwoLDgsKAX17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwo + LDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPDgsKDw4PCgsO + CwoIzw4PCg8OCwoPDg8KCw4LCgF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwovDg8KD + w4LCg8ODwoLDgsK/Ri9BUC9BRi9BWi9BZC9BWzBBZC9BZTBBZC9BZC9BbzBBZC9BeTBBw4PCg8OCw + oLDg8KCw4LCgzBBMUFhMUFrMUE= +description:: UF7Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOC + wozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg + 8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCqFDDg8KDw4LCg8ODwoLDgsKpRsODwoPDgsKDw4PCgsOCwo + zDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8O + DwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKCw4PCgsOCwotEJCDDg8KDw4LCgsODwoLDgsKD + w4PCg8OCwoPDg8KCw4LCrMODwoPDgsKCw4PCgsOCwotUJCRTw4PCg8OCwoLDg8KCw4LCi1wkJFbDg + 8KDw4LCgsODwoLDgsKJTCRXVVBSU8ODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsKdT8ODwo + PDgsKCw4PCgsOCwoN8JDB1w4PCg8OCwoPDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8O + DwoLDgsKBTsODwoPDgsKDw4PCgsOCwqktw4PCg8OCwoLDg8KCw4LCg3wkMHTDg8KDw4LCgsODwoLD + gsKDfCQww4PCg8OCwoLDg8KCw4LChTPDg8KDw4LCg8ODwoLDgsK2OTXDg8KDw4LCg8ODwoLDgsKAw + 4PCg8OCwoPDg8KCw4LCgU7Dg8KDw4LCgsODwoLDgsKEIMODwoPDgsKCw4PCgsOCwqFIw4PCg8OCwo + PDg8KCw4LChU7Dg8KDw4LCgsODwoLDgsKJNcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8ODwoLDgsK + BTsODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKD + w4PCgsOCwr9TXMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw + 4LChMODwoPDgsKCw4PCgsOCwpHDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLIEjDg8 + KDw4LCg8ODwoLDgsKFTlDDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ngw4PCg8OCwoL + Dg8KCw4LCi8ODwoPDgsKDw4PCgsOCwpjDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCm3Rx + w4PCg8OCwoLDg8KCw4LCizvDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi8ODwoPDgsKDw + 4PCgsOCwr9XaMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGdGLDg8KDw4LCgsODwo + LDgsKLf2zDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi1D + Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8OD + woLDgsKow4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwq10SmgoT03Dg8KDw4LCgsODwoLDg + sKLw4PCg8OCwoPDg8KCw4LCjcODwoPDgsKDw4PCgsOCwqggTMODwoPDgsKCw4PCgsOCwoXDg8KDw4 + LCg8ODwoLDgsKAdDrDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLTSBQUcODwoPDgsK + Dw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKL + RCQoZitEJCDDg8KDw4LCgsODwoLDgsK3w4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwoHDg + 8KDw4LCg8ODwoLDgsKhw4PCg8OCwoLDg8KCw4LCi0QkJGYrRCTDg8KDw4LCgsODwoLDgsK3w4PCg8 + OCwoPDg8KCw4LCkMODwoPDgsKDw4PCgsOCworDg8KDw4LCgsODwoLDgsKLRSBRVmpQw4PCg8OCwoP + Dg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKTzl0JHXDg8KDw4LCgsODwoLD + gsKhOXQkw4PCg8OCwoLDg8KCw4LChW/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODw + oPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKhRMODwoPDgsKDw4PCgsOCwoVOw4PCg8OCwoLDg8 + KCw4LCi8ODwoPDgsKDw4PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ncw4P + Cg8OCwoLDg8KCw4LCiUQkw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsOD + woLDgsKEw4PCg8OCwoPDg8KCw4LCtjPDg8KDw4LCg8ODwoLDgsK2w4PCg8OCwoLDg8KCw4LCjUQkw + 4PCg8OCwoLDg8KCw4LCiyBEw4PCg8OCwoPDg8KCw4LChU5Qw4PCg8OCwoLDg8KCw4LCi8ODwoPDgs + KDw4PCgsOCwr9TYMODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4L + ChcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCkMODwoPDgsKC + w4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCj8ODwoPDgsKDw4PCgsOCwr9Ta + MODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw4LChMODwoPDgs + KCw4PCgsOCwr3Dg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4L + Cj1DDg8KDw4LCg8ODwoLDgsK/U2zDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCqMODwoPD + gsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKtw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCw + p9oMMODwoPDgsKDw4PCgsOCwolMw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4 + LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCq0vDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4L + CgMODwoPDgsKCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi0QkOcODwoPD + gsKCw4PCgsOCwrDDg8KDw4LCg8ODwoLDgsKEdEU5w4PCg8OCwoLDg8KCw4LCtTR0PcODwoPDgsKCw + 4PCgsOCwovDg8KDw4LCg8ODwoLDgsKNw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwo5Lw4 + PCg8OCwoLDg8KCw4LCi0AgUMODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKsw4PCg8OCwoL + Dg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHUow4PCg8OCwoLDg8KCw4LC + i8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCgsODwoLDgsKJw4PCg8OCwoLDg8KCw4LCtTTDg8KDw4LCg + 8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKDw4PCgsOCwrtWw4PCg8OCwoLDg8KCw4LCi8 + ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCnw== + +dn: cn=All Staff,ou=Groups,dc=example,dc=com +member: cn=Manager,dc=example,dc=com +member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=exam + ple,dc=com +member: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com +member: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc + =com +member: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com +member: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com +member: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=exa + mple,dc=com +member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com +member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com +member: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=exampl + e,dc=com +owner: cn=Manager,dc=example,dc=com +cn: All Staff +description: Everyone in the sample data +objectClass: groupofnames + +dn: cn=Alumni Assoc Staff,ou=Groups,dc=example,dc=com +member: cn=Manager,dc=example,dc=com +member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +member: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com +member: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com +member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com +member: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com +member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com +owner: cn=Manager,dc=example,dc=com +description: All Alumni Assoc Staff +cn: Alumni Assoc Staff +objectClass: groupofnames + +dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example, + dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Barbara Jensen +cn: Babs Jensen +sn:: IEplbnNlbiA= +uid: bjensen +title: Mythical Manager, Research Systems +postalAddress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Anyt + own, MI 48103-4943 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: YmplbnNlbg== +mail: bjensen@mailgw.example.com +homePostalAddress: 123 Wesley $ Anytown, MI 48103 +description: Mythical manager of the rsdd unix project +drink: water +homePhone: +1 313 555 2333 +pager: +1 313 555 3233 +facsimileTelephoneNumber: +1 313 555 2274 +telephoneNumber: +1 313 555 9022 +enumerated:: AQ== + +dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc + =com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Bjorn Jensen +cn: Biiff Jensen +sn: Jensen +uid: bjorn +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: Ympvcm4= +homePostalAddress: 19923 Seven Mile Rd. $ South Lyon, MI 49999 +drink: Iced Tea +description: Hiker, biker +title: Director, Embedded Systems +postalAddress: Info Tech Division $ 535 W. William St. $ Anytown, MI 48103 +mail: bjorn@mailgw.example.com +homePhone: +1 313 555 5444 +pager: +1 313 555 4474 +facsimileTelephoneNumber: +1 313 555 2177 +telephoneNumber: +1 313 555 0355 +enumerated:: Cw== + +dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Dorothy Stevens +cn: Dot Stevens +sn: Stevens +uid: dots +title: Secretary, UM Alumni Association +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +drink: Lemonade +homePostalAddress: 377 White St. Apt. 3 $ Anytown, MI 48104 +description: Very tall +facsimileTelephoneNumber: +1 313 555 3223 +telephoneNumber: +1 313 555 3664 +mail: dots@mail.alumni.example.com +homePhone: +1 313 555 0454 +enumerated:: DA== + +dn: cn=ITD Staff,ou=Groups,dc=example,dc=com +owner: cn=Manager,dc=example,dc=com +description: All ITD Staff +cn: ITD Staff +objectClass: groupofuniquenames +uniqueMember: cn=Manager,dc=example,dc=com +uniqueMember: cn=Bjorn Jensen,OU=Information Technology Division,ou=People,dc= + example,dc=com +uniqueMember: cn=James A Jones 2,ou=Information Technology Division,ou=People, + dc=example,dc=com +uniqueMember: cn=John Doe,ou=Information Technology Division,ou=People,dc=exam + ple,dc=com + +dn: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: James A Jones 1 +cn: James Jones +cn: Jim Jones +sn: Jones +uid: jaj +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: amFq +homePostalAddress: 3882 Beverly Rd. $ Anytown, MI 48105 +homePhone: +1 313 555 4772 +description: Outstanding +title: Mad Cow Researcher, UM Alumni Association +pager: +1 313 555 3923 +mail: jaj@mail.alumni.example.com +facsimileTelephoneNumber: +1 313 555 4332 +telephoneNumber: +1 313 555 0895 +enumerated:: DQ== + +dn: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=example + ,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: James A Jones 2 +cn: James Jones +cn: Jim Jones +sn: Doe +uid: jjones +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 933 Brooks $ Anytown, MI 48104 +homePhone: +1 313 555 8838 +title: Senior Manager, Information Technology Division +description: Not around very much +mail: jjones@mailgw.example.com +postalAddress: Info Tech Division $ 535 W William $ Anytown, MI 48103 +pager: +1 313 555 2833 +facsimileTelephoneNumber: +1 313 555 8688 +telephoneNumber: +1 313 555 7334 +enumerated:: Dg== + +dn: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Jane Doe +cn: Jane Alverson +sn: Doe +uid: jdoe +title: Programmer Analyst, UM Alumni Association +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 123 Anystreet $ Anytown, MI 48104 +drink: diet coke +description: Enthusiastic +mail: jdoe@woof.net +homePhone: +1 313 555 5445 +pager: +1 313 555 1220 +facsimileTelephoneNumber: +1 313 555 2311 +telephoneNumber: +1 313 555 4774 +enumerated:: Cg== + +dn: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Jennifer Smith +cn: Jen Smith +sn: Smith +uid: jen +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +drink: Sam Adams +homePostalAddress: 1000 Maple #44 $ Anytown, MI 48103 +title: Telemarketer, UM Alumni Association +mail: jen@mail.alumni.example.com +homePhone: +1 313 555 2333 +pager: +1 313 555 6442 +facsimileTelephoneNumber: +1 313 555 2756 +telephoneNumber: +1 313 555 8232 +enumerated:: ZQ== + +dn: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: John Doe +cn: Jonathon Doe +sn: Doe +uid: johnd +postalAddress: ITD $ 535 W. William $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 912 East Bllvd $ Anytown, MI 48104 +title: System Administrator, Information Technology Division +description: overworked! +mail: johnd@mailgw.example.com +homePhone: +1 313 555 3774 +pager: +1 313 555 6573 +facsimileTelephoneNumber: +1 313 555 4544 +telephoneNumber: +1 313 555 9394 +enumerated:: FA== + +dn: cn=Manager,dc=example,dc=com +objectClass: person +cn: Manager +cn: Directory Manager +cn: Dir Man +sn: Manager +description: Manager of the directory +userPassword:: c2VjcmV0 + +dn: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Mark Elliot +cn: Mark A Elliot +sn: Elliot +uid: melliot +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 199 Outer Drive $ Ypsilanti, MI 48198 +homePhone: +1 313 555 0388 +drink: Gasoline +title: Director, UM Alumni Association +mail: melliot@mail.alumni.example.com +pager: +1 313 555 7671 +facsimileTelephoneNumber: +1 313 555 7762 +telephoneNumber: +1 313 555 4177 +enumerated:: Mw== + +dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Ursula Hampster +sn: Hampster +uid: uham +title: Secretary, UM Alumni Association +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 123 Anystreet $ Anytown, MI 48104 +mail: uham@mail.alumni.example.com +homePhone: +1 313 555 8421 +pager: +1 313 555 2844 +facsimileTelephoneNumber: +1 313 555 9700 +telephoneNumber: +1 313 555 5331 +enumerated:: Hw== + diff --git a/contrib/slapd-modules/datamorph/tests/data/test001-01-same-attr.ldif b/contrib/slapd-modules/datamorph/tests/data/test001-01-same-attr.ldif new file mode 100644 index 0000000..b9ba88f --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test001-01-same-attr.ldif @@ -0,0 +1,3 @@ +dn: olcDatamorphAttribute=enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnum diff --git a/contrib/slapd-modules/datamorph/tests/data/test001-02-same-index.ldif b/contrib/slapd-modules/datamorph/tests/data/test001-02-same-index.ldif new file mode 100644 index 0000000..1dac5dc --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test001-02-same-index.ldif @@ -0,0 +1,4 @@ +dn: olcDatamorphValue=nope,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 1 diff --git a/contrib/slapd-modules/datamorph/tests/data/test001-02a-same-index.ldif b/contrib/slapd-modules/datamorph/tests/data/test001-02a-same-index.ldif new file mode 100644 index 0000000..f31ab0a --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test001-02a-same-index.ldif @@ -0,0 +1,4 @@ +dn: olcDatamorphValue={0}bjensen,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcDatamorphIndex +olcDatamorphIndex: 11 diff --git a/contrib/slapd-modules/datamorph/tests/data/test001-03-invalid-attr.ldif b/contrib/slapd-modules/datamorph/tests/data/test001-03-invalid-attr.ldif new file mode 100644 index 0000000..01f21c2 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test001-03-invalid-attr.ldif @@ -0,0 +1,3 @@ +dn: olcDatamorphAttribute=uid,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnum diff --git a/contrib/slapd-modules/datamorph/tests/data/test002-config.ldif b/contrib/slapd-modules/datamorph/tests/data/test002-config.ldif new file mode 100644 index 0000000..2aed906 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test002-config.ldif @@ -0,0 +1,9 @@ +dn: olcDatamorphValue=gjensen,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcDatamorphEnumValue +olcDatamorphIndex: 55 + +dn: olcDatamorphAttribute={1}signed,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +delete: olcDatamorphIntegerUpperBound +olcDatamorphIntegerUpperBound: 30000 diff --git a/contrib/slapd-modules/datamorph/tests/data/test002-entry.ldif b/contrib/slapd-modules/datamorph/tests/data/test002-entry.ldif new file mode 100644 index 0000000..0df14c4 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test002-entry.ldif @@ -0,0 +1,31 @@ +dn: cn=Gern Jensen,ou=Information Technology Division,ou=People,dc=example,dc= + com +changetype: add +objectClass: testPerson +objectClass: transformedObject +cn: Gern Jensen +sn: Jensen +uid: gjensen +title: Chief Investigator, ITD +postalAddress: ITD $ 535 W. William St $ Anytown, MI 48103 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +drink: Coffee +homePostalAddress: 844 Brown St. Apt. 4 $ Anytown, MI 48104 +description: Very odd +facsimileTelephonenumber: +1 313 555 7557 +telephoneNumber: +1 313 555 8343 +mail: gjensen@mailgw.example.com +homePhone: +1 313 555 8844 +testTime: 20050304001801.234Z +enumerated: gjensen + +dn: ou=New Unit,dc=example,dc=com +changetype: add +objectClass: organizationalUnit +objectClass: extensibleObject +ou: New Unit +uidNumber: 32345 +gidNumber: 1 +signed: 32345 +number: 1 + diff --git a/contrib/slapd-modules/datamorph/tests/data/test002-fail.ldif b/contrib/slapd-modules/datamorph/tests/data/test002-fail.ldif new file mode 100644 index 0000000..f834997 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test002-fail.ldif @@ -0,0 +1,23 @@ +dn: uid=bjensen+cn=Barbara Jensen+enumerated=bjensen,ou=Information Technology Division,ou=People,dc=example, + dc=com +changetype: add +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Barbara Jensen +cn: Babs Jensen +sn:: IEplbnNlbiA= +uid: bjensen +title: Mythical Manager, Research Systems +postalAddress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Anyt + own, MI 48103-4943 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: YmplbnNlbg== +mail: bjensen@mailgw.example.com +homePostalAddress: 123 Wesley $ Anytown, MI 48103 +description: Mythical manager of the rsdd unix project +drink: water +homePhone: +1 313 555 2333 +pager: +1 313 555 3233 +facsimileTelephoneNumber: +1 313 555 2274 +telephoneNumber: +1 313 555 9022 + diff --git a/contrib/slapd-modules/datamorph/tests/data/test002-transformed-rdn.ldif b/contrib/slapd-modules/datamorph/tests/data/test002-transformed-rdn.ldif new file mode 100644 index 0000000..cbcb14a --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test002-transformed-rdn.ldif @@ -0,0 +1,5 @@ +dn: ou=New Unit,dc=www+number=1,dc=example,dc=com +changetype: add +objectClass: organizationalUnit +ou: New Unit + diff --git a/contrib/slapd-modules/datamorph/tests/data/test003-config.ldif b/contrib/slapd-modules/datamorph/tests/data/test003-config.ldif new file mode 100644 index 0000000..f74717c --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test003-config.ldif @@ -0,0 +1,30 @@ +dn: olcDatamorphValue={2}dots,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcDatamorphIndex +olcDatamorphIndex: 110 + +dn: olcDatamorphValue={3}jaj,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcDatamorphIndex +olcDatamorphIndex: 12 + +dn: olcDatamorphValue={4}jjones,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcDatamorphIndex +olcDatamorphIndex: 13 + +dn: olcDatamorphValue={2}dots,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcDatamorphIndex +olcDatamorphIndex: 14 + +dn: olcDatamorphAttribute={1}signed,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcDatamorphIntegerSigned +olcDatamorphIntegerSigned: FALSE +- +replace: olcDatamorphIntegerUpperBound +olcDatamorphIntegerUpperBound: 50000 +- +replace: olcDatamorphIntegerLowerBound +olcDatamorphIntegerLowerBound: 50 diff --git a/contrib/slapd-modules/datamorph/tests/data/test003-out.ldif b/contrib/slapd-modules/datamorph/tests/data/test003-out.ldif new file mode 100644 index 0000000..3dbd8bc --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test003-out.ldif @@ -0,0 +1,125 @@ +# List regular entries +dn: dc=example,dc=com +objectClass: top +objectClass: organization +objectClass: domainRelatedObject +objectClass: dcobject +dc: example +l: Anytown, Michigan +st: Michigan +o: Example, Inc. +o: EX +o: Ex. +description: The Example, Inc. at Anytown +postalAddress: Example, Inc. $ 535 W. William St. $ Anytown, MI 48109 $ US +telephoneNumber: +1 313 555 1817 +associatedDomain: example.com + +dn: ou=Groups,dc=example,dc=com +objectClass: organizationalUnit +ou: Groups + + +# List entries with transformed attributes +dn: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: John Doe +cn: Jonathon Doe +sn: Doe +uid: johnd +postalAddress: ITD $ 535 W. William $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 912 East Bllvd $ Anytown, MI 48104 +title: System Administrator, Information Technology Division +description: overworked! +mail: johnd@mailgw.example.com +homePhone: +1 313 555 3774 +pager: +1 313 555 6573 +facsimileTelephoneNumber: +1 313 555 4544 +telephoneNumber: +1 313 555 9394 +enumerated: johnd + +dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc + =com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Bjorn Jensen +cn: Biiff Jensen +sn: Jensen +uid: bjorn +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: Ympvcm4= +homePostalAddress: 19923 Seven Mile Rd. $ South Lyon, MI 49999 +drink: Iced Tea +description: Hiker, biker +title: Director, Embedded Systems +postalAddress: Info Tech Division $ 535 W. William St. $ Anytown, MI 48103 +mail: bjorn@mailgw.example.com +homePhone: +1 313 555 5444 +pager: +1 313 555 4474 +facsimileTelephoneNumber: +1 313 555 2177 +telephoneNumber: +1 313 555 0355 +enumerated: bjorn + +dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example, + dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Barbara Jensen +cn: Babs Jensen +sn:: IEplbnNlbiA= +uid: bjensen +title: Mythical Manager, Research Systems +postalAddress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Anyt + own, MI 48103-4943 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: YmplbnNlbg== +mail: bjensen@mailgw.example.com +homePostalAddress: 123 Wesley $ Anytown, MI 48103 +description: Mythical manager of the rsdd unix project +drink: water +homePhone: +1 313 555 2333 +pager: +1 313 555 3233 +facsimileTelephoneNumber: +1 313 555 2274 +telephoneNumber: +1 313 555 9022 +enumerated: bjensen + +dn: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=example + ,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: James A Jones 2 +cn: James Jones +cn: Jim Jones +sn: Doe +uid: jjones +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 933 Brooks $ Anytown, MI 48104 +homePhone: +1 313 555 8838 +title: Senior Manager, Information Technology Division +description: Not around very much +mail: jjones@mailgw.example.com +postalAddress: Info Tech Division $ 535 W William $ Anytown, MI 48103 +pager: +1 313 555 2833 +facsimileTelephoneNumber: +1 313 555 8688 +telephoneNumber: +1 313 555 7334 +enumerated: jjones + + +# Search for transformed attributes listing only those +dn: ou=People,dc=example,dc=com +signed: -19858 + +dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example, + dc=com +enumerated: bjensen + + +# Search for transformed attributes after reconfiguring mapping +dn: ou=People,dc=example,dc=com +signed: 45678 + +dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +enumerated: jaj + diff --git a/contrib/slapd-modules/datamorph/tests/data/test005-01-fail.ldif b/contrib/slapd-modules/datamorph/tests/data/test005-01-fail.ldif new file mode 100644 index 0000000..694aacc --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test005-01-fail.ldif @@ -0,0 +1,5 @@ +# invalid enum value +dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +changetype: modify +replace: enumerated +enumerated: 2dots diff --git a/contrib/slapd-modules/datamorph/tests/data/test005-02-fail.ldif b/contrib/slapd-modules/datamorph/tests/data/test005-02-fail.ldif new file mode 100644 index 0000000..1ce687f --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test005-02-fail.ldif @@ -0,0 +1,5 @@ +# enums are case sensitive +dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +changetype: modify +replace: enumerated +enumerated: Dots diff --git a/contrib/slapd-modules/datamorph/tests/data/test005-03-fail.ldif b/contrib/slapd-modules/datamorph/tests/data/test005-03-fail.ldif new file mode 100644 index 0000000..54bb9b5 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test005-03-fail.ldif @@ -0,0 +1,5 @@ +# value does not exist in entry +dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +changetype: modify +delete: enumerated +enumerated: uham diff --git a/contrib/slapd-modules/datamorph/tests/data/test005-03a-fail.ldif b/contrib/slapd-modules/datamorph/tests/data/test005-03a-fail.ldif new file mode 100644 index 0000000..601d895 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test005-03a-fail.ldif @@ -0,0 +1,5 @@ +# value does not exist in entry +dn: ou=People,dc=example,dc=com +changetype: modify +delete: signed +signed: 2 diff --git a/contrib/slapd-modules/datamorph/tests/data/test005-04-fail.ldif b/contrib/slapd-modules/datamorph/tests/data/test005-04-fail.ldif new file mode 100644 index 0000000..d97effc --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test005-04-fail.ldif @@ -0,0 +1,10 @@ +# a value outside the bounds +dn: ou=People,dc=example,dc=com +changetype: modify +replace: signed +signed: 2 +- +replace: number +number: -1 +- + diff --git a/contrib/slapd-modules/datamorph/tests/data/test005-04a-fail.ldif b/contrib/slapd-modules/datamorph/tests/data/test005-04a-fail.ldif new file mode 100644 index 0000000..63b3263 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test005-04a-fail.ldif @@ -0,0 +1,6 @@ +# a value outside the bounds +dn: ou=People,dc=example,dc=com +changetype: modify +replace: signed +signed: 32000 +- diff --git a/contrib/slapd-modules/datamorph/tests/data/test005-changes.ldif b/contrib/slapd-modules/datamorph/tests/data/test005-changes.ldif new file mode 100644 index 0000000..17a72da --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test005-changes.ldif @@ -0,0 +1,30 @@ +dn: ou=People,dc=example,dc=com +changetype: modify +replace: signed +signed: -1 +- +replace: number +number: 1 +- + +dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +changetype: modify +replace: enumerated +enumerated: jaj +- + +dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com +changetype: modify +add: enumerated +enumerated: bjorn +enumerated: uham +- + +dn: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc=com +changetype: modify +delete: enumerated +enumerated: johnd +- +add: enumerated +enumerated: melliot +- diff --git a/contrib/slapd-modules/datamorph/tests/data/test005-out.ldif b/contrib/slapd-modules/datamorph/tests/data/test005-out.ldif new file mode 100644 index 0000000..4c8c360 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test005-out.ldif @@ -0,0 +1,212 @@ +# Test1: list entries that should have been changed by ldapmodify +dn: ou=People,dc=example,dc=com +objectClass: organizationalUnit +objectClass: extensibleObject +ou: People +uidNumber: 0 +gidNumber: 0 +signed: -1 +number: 1 + +dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example, + dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Barbara Jensen +cn: Babs Jensen +sn:: IEplbnNlbiA= +uid: bjensen +title: Mythical Manager, Research Systems +postalAddress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Anyt + own, MI 48103-4943 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: YmplbnNlbg== +mail: bjensen@mailgw.example.com +homePostalAddress: 123 Wesley $ Anytown, MI 48103 +description: Mythical manager of the rsdd unix project +drink: water +homePhone: +1 313 555 2333 +pager: +1 313 555 3233 +facsimileTelephoneNumber: +1 313 555 2274 +telephoneNumber: +1 313 555 9022 +enumerated: bjensen +enumerated: bjorn +enumerated: uham + +dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc + =com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Bjorn Jensen +cn: Biiff Jensen +sn: Jensen +uid: bjorn +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: Ympvcm4= +homePostalAddress: 19923 Seven Mile Rd. $ South Lyon, MI 49999 +drink: Iced Tea +description: Hiker, biker +title: Director, Embedded Systems +postalAddress: Info Tech Division $ 535 W. William St. $ Anytown, MI 48103 +mail: bjorn@mailgw.example.com +homePhone: +1 313 555 5444 +pager: +1 313 555 4474 +facsimileTelephoneNumber: +1 313 555 2177 +telephoneNumber: +1 313 555 0355 +enumerated: bjorn + +dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Dorothy Stevens +cn: Dot Stevens +sn: Stevens +uid: dots +title: Secretary, UM Alumni Association +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +drink: Lemonade +homePostalAddress: 377 White St. Apt. 3 $ Anytown, MI 48104 +description: Very tall +facsimileTelephoneNumber: +1 313 555 3223 +telephoneNumber: +1 313 555 3664 +mail: dots@mail.alumni.example.com +homePhone: +1 313 555 0454 +enumerated: jaj + +dn: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: James A Jones 1 +cn: James Jones +cn: Jim Jones +sn: Jones +uid: jaj +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: amFq +homePostalAddress: 3882 Beverly Rd. $ Anytown, MI 48105 +homePhone: +1 313 555 4772 +description: Outstanding +title: Mad Cow Researcher, UM Alumni Association +pager: +1 313 555 3923 +mail: jaj@mail.alumni.example.com +facsimileTelephoneNumber: +1 313 555 4332 +telephoneNumber: +1 313 555 0895 +enumerated: jaj + +dn: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=example + ,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: James A Jones 2 +cn: James Jones +cn: Jim Jones +sn: Doe +uid: jjones +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 933 Brooks $ Anytown, MI 48104 +homePhone: +1 313 555 8838 +title: Senior Manager, Information Technology Division +description: Not around very much +mail: jjones@mailgw.example.com +postalAddress: Info Tech Division $ 535 W William $ Anytown, MI 48103 +pager: +1 313 555 2833 +facsimileTelephoneNumber: +1 313 555 8688 +telephoneNumber: +1 313 555 7334 +enumerated: jjones + +dn: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Jane Doe +cn: Jane Alverson +sn: Doe +uid: jdoe +title: Programmer Analyst, UM Alumni Association +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 123 Anystreet $ Anytown, MI 48104 +drink: diet coke +description: Enthusiastic +mail: jdoe@woof.net +homePhone: +1 313 555 5445 +pager: +1 313 555 1220 +facsimileTelephoneNumber: +1 313 555 2311 +telephoneNumber: +1 313 555 4774 +enumerated: jdoe + +dn: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Jennifer Smith +cn: Jen Smith +sn: Smith +uid: jen +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +drink: Sam Adams +homePostalAddress: 1000 Maple #44 $ Anytown, MI 48103 +title: Telemarketer, UM Alumni Association +mail: jen@mail.alumni.example.com +homePhone: +1 313 555 2333 +pager: +1 313 555 6442 +facsimileTelephoneNumber: +1 313 555 2756 +telephoneNumber: +1 313 555 8232 +enumerated: jen + +dn: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: John Doe +cn: Jonathon Doe +sn: Doe +uid: johnd +postalAddress: ITD $ 535 W. William $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 912 East Bllvd $ Anytown, MI 48104 +title: System Administrator, Information Technology Division +description: overworked! +mail: johnd@mailgw.example.com +homePhone: +1 313 555 3774 +pager: +1 313 555 6573 +facsimileTelephoneNumber: +1 313 555 4544 +telephoneNumber: +1 313 555 9394 +enumerated: melliot + +dn: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Mark Elliot +cn: Mark A Elliot +sn: Elliot +uid: melliot +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 199 Outer Drive $ Ypsilanti, MI 48198 +homePhone: +1 313 555 0388 +drink: Gasoline +title: Director, UM Alumni Association +mail: melliot@mail.alumni.example.com +pager: +1 313 555 7671 +facsimileTelephoneNumber: +1 313 555 7762 +telephoneNumber: +1 313 555 4177 +enumerated: melliot + +dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +objectClass: transformedObject +cn: Ursula Hampster +sn: Hampster +uid: uham +title: Secretary, UM Alumni Association +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 123 Anystreet $ Anytown, MI 48104 +mail: uham@mail.alumni.example.com +homePhone: +1 313 555 8421 +pager: +1 313 555 2844 +facsimileTelephoneNumber: +1 313 555 9700 +telephoneNumber: +1 313 555 5331 +enumerated: uham + diff --git a/contrib/slapd-modules/datamorph/tests/data/test007-config.ldif b/contrib/slapd-modules/datamorph/tests/data/test007-config.ldif new file mode 100644 index 0000000..3820831 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/data/test007-config.ldif @@ -0,0 +1,30 @@ +dn: olcDatamorphValue={2}dots,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcDatamorphIndex +olcDatamorphIndex: 110 + +dn: olcDatamorphValue={4}jjones,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcDatamorphIndex +olcDatamorphIndex: 14 + +dn: olcDatamorphValue={3}jaj,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcDatamorphIndex +olcDatamorphIndex: 13 + +dn: olcDatamorphValue={2}dots,olcDatamorphAttribute={0}enumerated,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcDatamorphIndex +olcDatamorphIndex: 12 + +dn: olcDatamorphAttribute={1}signed,olcOverlay={0}datamorph,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcDatamorphIntegerSigned +olcDatamorphIntegerSigned: TRUE +- +replace: olcDatamorphIntegerLowerBound +olcDatamorphIntegerLowerBound: -20000 +- +replace: olcDatamorphIntegerUpperBound +olcDatamorphIntegerUpperBound: 30000 diff --git a/contrib/slapd-modules/datamorph/tests/run b/contrib/slapd-modules/datamorph/tests/run new file mode 100755 index 0000000..6a38431 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/run @@ -0,0 +1,229 @@ +#!/bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 1998-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +USAGE="$0 [-b <backend>] [-c] [-k] [-l #] [-p] [-s {ro|rp}] [-u] [-w] <script>" + +TOPSRCDIR="${SRCDIR-$LDAP_SRC}" +SRCDIR="${TOPSRCDIR}/tests" +eval `grep EGREP_CMD= ${LDAP_BUILD}/tests/run` +eval `$EGREP_CMD -e '^LN_S=' ${LDAP_BUILD}/tests/run` + +export SRCDIR TOPSRCDIR LN_S EGREP_CMD + +. "${SRCDIR}/scripts/defines.sh" + +BACKEND= +CLEAN=no +WAIT=0 +KILLSERVERS=yes +PRESERVE=${PRESERVE-no} +SYNCMODE=${SYNCMODE-rp} +USERDATA=no +LOOP=1 +COUNTER=1 + +while test $# -gt 0 ; do + case "$1" in + -b | -backend) + BACKEND="$2" + shift; shift ;; + + -c | -clean) + CLEAN=yes + shift ;; + + -k | -kill) + KILLSERVERS=no + shift ;; + -l | -loop) + NUM="`echo $2 | sed 's/[0-9]//g'`" + if [ -z "$NUM" ]; then + LOOP=$2 + else + echo "Loop variable not an int: $2" + echo "$USAGE"; exit 1 + fi + shift ; + shift ;; + + -p | -preserve) + PRESERVE=yes + shift ;; + + -s | -syncmode) + case "$2" in + ro | rp) + SYNCMODE="$2" + ;; + *) + echo "unknown sync mode $2" + echo "$USAGE"; exit 1 + ;; + esac + shift; shift ;; + + -u | -userdata) + USERDATA=yes + shift ;; + + -w | -wait) + WAIT=1 + shift ;; + + -) + shift + break ;; + + -*) + echo "$USAGE"; exit 1 + ;; + + *) + break ;; + esac +done + +eval `$EGREP_CMD -e '^AC' ${LDAP_BUILD}/tests/run` +export `$EGREP_CMD -e '^AC' ${LDAP_BUILD}/tests/run | sed 's/=.*//'` + +if test -z "$BACKEND" ; then + for b in mdb ; do + if eval "test \"\$AC_$b\" != no" ; then + BACKEND=$b + break + fi + done + if test -z "$BACKEND" ; then + echo "No suitable default database backend configured" >&2 + exit 1 + fi +fi + +BACKENDTYPE=`eval 'echo $AC_'$BACKEND` +if test "x$BACKENDTYPE" = "x" ; then + BACKENDTYPE="unknown" +fi + +# Backend features. indexdb: indexing and unchecked limit. +# maindb: main storage backend. Currently index,limits,mode,paged results. +INDEXDB=noindexdb MAINDB=nomaindb +case $BACKEND in + mdb) INDEXDB=indexdb MAINDB=maindb ;; + ndb) INDEXDB=indexdb ;; +esac + +export BACKEND BACKENDTYPE INDEXDB MAINDB \ + WAIT KILLSERVERS PRESERVE SYNCMODE USERDATA \ + SRCDIR + +if test $# = 0 ; then + echo "$USAGE"; exit 1 +fi + +# need defines.sh for the definitions of the directories +. $SRCDIR/scripts/defines.sh + +SCRIPTDIR="${TOPDIR}/tests/scripts" + +export SCRIPTDIR + +SCRIPTNAME="$1" +shift + +if test -x "${SCRIPTDIR}/${SCRIPTNAME}" ; then + SCRIPT="${SCRIPTDIR}/${SCRIPTNAME}" +elif test -x "`echo ${SCRIPTDIR}/test*-${SCRIPTNAME}`"; then + SCRIPT="`echo ${SCRIPTDIR}/test*-${SCRIPTNAME}`" +elif test -x "`echo ${SCRIPTDIR}/${SCRIPTNAME}-*`"; then + SCRIPT="`echo ${SCRIPTDIR}/${SCRIPTNAME}-*`" +else + echo "run: ${SCRIPTNAME} not found (or not executable)" + exit 1; +fi + +if test ! -r ${DATADIR}/test.ldif ; then + ${LN_S} ${SRCDIR}/data ${DATADIR} +fi +if test ! -r ${SCHEMADIR}/core.schema ; then + ${LN_S} ${TOPSRCDIR}/servers/slapd/schema ${SCHEMADIR} +fi +if test ! -r ./data; then + ${LN_S} ${TOPDIR}/tests/data ./ +fi + +if test -d ${TESTDIR} ; then + if test $PRESERVE = no ; then + echo "Cleaning up test run directory leftover from previous run." + /bin/rm -rf ${TESTDIR} + elif test $PRESERVE = yes ; then + echo "Cleaning up only database directories leftover from previous run." + /bin/rm -rf ${TESTDIR}/db.* + fi +fi +if test $BACKEND = ndb ; then + mysql --user root <<EOF + drop database if exists db_1; + drop database if exists db_2; + drop database if exists db_3; + drop database if exists db_4; + drop database if exists db_5; + drop database if exists db_6; +EOF +fi +mkdir -p ${TESTDIR} + +if test $USERDATA = yes ; then + if test ! -d userdata ; then + echo "User data directory (userdata) does not exist." + exit 1 + fi + cp -R userdata/* ${TESTDIR} +fi + +# disable LDAP initialization +LDAPNOINIT=true; export LDAPNOINIT + +echo "Running ${SCRIPT} for ${BACKEND}..." +while [ $COUNTER -le $LOOP ]; do + if [ $LOOP -gt 1 ]; then + echo "Running $COUNTER of $LOOP iterations" + fi + $SCRIPT $* + RC=$? + + if test $CLEAN = yes ; then + echo "Cleaning up test run directory from this run." + /bin/rm -rf ${TESTDIR} + echo "Cleaning up symlinks." + /bin/rm -f ${DATADIR} ${SCHEMADIR} + fi + + if [ $RC -ne 0 ]; then + if [ $LOOP -gt 1 ]; then + echo "Failed after $COUNTER of $LOOP iterations" + fi + exit $RC + else + COUNTER=`expr $COUNTER + 1` + if [ $COUNTER -le $LOOP ]; then + echo "Cleaning up test run directory from this run." + /bin/rm -rf ${TESTDIR} + fi + fi +done +exit $RC diff --git a/contrib/slapd-modules/datamorph/tests/scripts/all b/contrib/slapd-modules/datamorph/tests/scripts/all new file mode 100755 index 0000000..d6d6dc7 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/scripts/all @@ -0,0 +1,102 @@ +#! /bin/sh +# $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 1998-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. + +. $SRCDIR/scripts/defines.sh + +TB="" TN="" +if test -t 1 ; then + TB=`$SHTOOL echo -e "%B" 2>/dev/null` + TN=`$SHTOOL echo -e "%b" 2>/dev/null` +fi + +FAILCOUNT=0 +SKIPCOUNT=0 +SLEEPTIME=10 + +echo ">>>>> Executing all LDAP tests for $BACKEND" + +if [ -n "$NOEXIT" ]; then + echo "Result Test" > $TESTWD/results +fi + +for CMD in ${SCRIPTDIR}/test*; do + case "$CMD" in + *~) continue;; + *.bak) continue;; + *.orig) continue;; + *.sav) continue;; + *) test -f "$CMD" || continue;; + esac + + # remove cruft from prior test + if test $PRESERVE = yes ; then + /bin/rm -rf $TESTDIR/db.* + else + /bin/rm -rf $TESTDIR + fi + if test $BACKEND = ndb ; then + mysql --user root <<EOF + drop database if exists db_1; + drop database if exists db_2; + drop database if exists db_3; + drop database if exists db_4; + drop database if exists db_5; + drop database if exists db_6; +EOF + fi + + BCMD=`basename $CMD` + if [ -x "$CMD" ]; then + echo ">>>>> Starting ${TB}$BCMD${TN} for $BACKEND..." + $CMD + RC=$? + if test $RC -eq 0 ; then + echo ">>>>> $BCMD completed ${TB}OK${TN} for $BACKEND." + else + echo ">>>>> $BCMD ${TB}failed${TN} for $BACKEND" + FAILCOUNT=`expr $FAILCOUNT + 1` + + if [ -n "$NOEXIT" ]; then + echo "Continuing." + else + echo "(exit $RC)" + exit $RC + fi + fi + else + echo ">>>>> Skipping ${TB}$BCMD${TN} for $BACKEND." + SKIPCOUNT=`expr $SKIPCOUNT + 1` + RC="-" + fi + + if [ -n "$NOEXIT" ]; then + echo "$RC $BCMD" >> $TESTWD/results + fi + +# echo ">>>>> waiting $SLEEPTIME seconds for things to exit" +# sleep $SLEEPTIME + echo "" +done + +if [ -n "$NOEXIT" ]; then + if [ "$FAILCOUNT" -gt 0 ]; then + cat $TESTWD/results + echo "$FAILCOUNT tests for $BACKEND ${TB}failed${TN}. Please review the test log." + else + echo "All executed tests for $BACKEND ${TB}succeeded${TN}." + fi +fi + +echo "$SKIPCOUNT tests for $BACKEND were ${TB}skipped${TN}." diff --git a/contrib/slapd-modules/datamorph/tests/scripts/common.sh b/contrib/slapd-modules/datamorph/tests/scripts/common.sh new file mode 100755 index 0000000..a468732 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/scripts/common.sh @@ -0,0 +1,152 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +OVERLAY_CONFIG=${OVERLAY_CONFIG-data/config.ldif} + +mkdir -p $TESTDIR $DBDIR1 + +mkdir $TESTDIR/confdir +. $CONFFILTER $BACKEND $MONITORDB < $CONF > $CONF1 + +$SLAPPASSWD -g -n >$CONFIGPWF +echo "database config" >>$CONF1 +echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF1 + +echo "Starting slapd on TCP/IP port $PORT1 for configuration..." +$SLAPD -f $CONF1 -F $TESTDIR/confdir -h $URI1 -d $LVL > $LOG1 2>&1 & +PID=$! +if test $WAIT != 0 ; then + echo PID $PID + read foo +fi +KILLPIDS="$PID" + +sleep $SLEEP0 + +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 0 ; then + break + fi + echo "Waiting ${SLEEP1} seconds for slapd to start..." + sleep ${SLEEP1} +done + +$LDAPSEARCH -D cn=config -H $URI1 -y $CONFIGPWF \ + -s base -b 'cn=module{0},cn=config' 1.1 >$TESTOUT 2>&1 +RC=$? +case $RC in +0) + $LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 <<EOMOD +dn: cn=module{0},cn=config +changetype: modify +add: olcModuleLoad +olcModuleLoad: `pwd`/../datamorph.la +EOMOD + ;; +32) + $LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 <<EOMOD +dn: cn=module,cn=config +changetype: add +objectClass: olcModuleList +olcModuleLoad: `pwd`/../datamorph.la +EOMOD + ;; +*) + echo "Failed testing for module load entry" + exit $RC; + ;; +esac + +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Loading test datamorph configuration..." +. $CONFFILTER $BACKEND $MONITORDB < $OVERLAY_CONFIG | \ +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + > $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +if test $INDEXDB = indexdb ; then + echo "Configure indexing for transformed attributes..." + $LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 <<EOMOD +dn: olcDatabase={1}$BACKEND,cn=config +changetype: modify +add: olcDbIndex +olcDbIndex: enumerated pres,eq +olcDbIndex: number pres,eq +olcDbIndex: signed pres,eq +EOMOD + RC=$? + if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + fi +else + echo "Skipping indexing setup for this database" +fi + +echo "Stopping slapd on TCP/IP port $PORT1..." +kill -HUP $KILLPIDS +KILLPIDS="" +sleep $SLEEP0 + +echo "Running slapadd to build slapd database..." +$SLAPADD -F $TESTDIR/confdir -l data/test.ldif +RC=$? +if test $RC != 0 ; then + echo "slapadd failed ($RC)!" + exit $RC +fi + +echo "Starting slapd on TCP/IP port $PORT1..." +$SLAPD -F $TESTDIR/confdir -h $URI1 -d $LVL >> $LOG1 2>&1 & +PID=$! +if test $WAIT != 0 ; then + echo PID $PID + read foo +fi +KILLPIDS="$PID" + +sleep $SLEEP0 + +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 0 ; then + break + fi + echo "Waiting ${SLEEP1} seconds for slapd to start..." + sleep ${SLEEP1} +done diff --git a/contrib/slapd-modules/datamorph/tests/scripts/test001-config b/contrib/slapd-modules/datamorph/tests/scripts/test001-config new file mode 100755 index 0000000..c4bfdf0 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/scripts/test001-config @@ -0,0 +1,248 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Applying invalid changes to config (should fail)..." +for CHANGE in data/test001-*.ldif; do + echo "... $CHANGE" + . $CONFFILTER $BACKEND $MONITORDB < $CHANGE | \ + $LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 + RC=$? + case $RC in + 0) + echo "ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; + 80) + echo "ldapmodify failed ($RC)" + ;; + *) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; + esac +done + +# We run this search after the changes above and before restart so we can also +# check the reconfiguration attempts actually had no side effects +echo "Saving search output before server restart..." +echo "# search output from dynamically configured server..." >> $SERVER6OUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + >> $SERVER6OUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Stopping slapd on TCP/IP port $PORT1..." +kill -HUP $KILLPIDS +KILLPIDS="" +sleep $SLEEP0 +echo "Starting slapd on TCP/IP port $PORT1..." +$SLAPD -F $TESTDIR/confdir -h $URI1 -d $LVL >> $LOG1 2>&1 & +PID=$! +if test $WAIT != 0 ; then + echo PID $PID + read foo +fi +KILLPIDS="$PID" + +sleep $SLEEP0 + +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 0 ; then + break + fi + echo "Waiting ${SLEEP1} seconds for slapd to start..." + sleep ${SLEEP1} +done + +echo "Testing slapd.conf support..." +mkdir $TESTDIR/conftest $DBDIR2 +. $CONFFILTER $BACKEND $MONITORDB < $CONFTWO \ + | sed -e '/^argsfile.*/a\ +moduleload ../datamorph.la' \ + -e '/database.*monitor/i\ +include data/datamorph.conf' \ + > $CONF2 +echo "database config" >>$CONF2 +echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF2 + +$SLAPADD -f $CONF2 -l data/test.ldif +RC=$? +if test $RC != 0 ; then + echo "slapadd failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Starting slapd on TCP/IP port $PORT2..." +$SLAPD -f $CONF2 -h $URI2 -d $LVL >> $LOG2 2>&1 & +PID=$! +if test $WAIT != 0 ; then + echo PID $PID + read foo +fi + +sleep $SLEEP0 + +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 0 ; then + break + fi + echo "Waiting ${SLEEP1} seconds for slapd to start..." + sleep ${SLEEP1} +done + +echo "# search output from server running from slapd.conf..." >> $SERVER2OUT +$LDAPSEARCH -b "$BASEDN" -H $URI2 \ + >> $SERVER2OUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Stopping slapd on TCP/IP port $PORT2..." +kill -HUP $PID + +$SLAPD -Tt -f $CONF2 -F $TESTDIR/conftest -d $LVL >> $LOG3 2>&1 + +echo "Starting slapd on TCP/IP port $PORT2..." +$SLAPD -F $TESTDIR/conftest -h $URI2 -d $LVL >> $LOG3 2>&1 & +PID=$! +if test $WAIT != 0 ; then + echo PID $PID + read foo +fi +KILLPIDS="$KILLPIDS $PID" + +sleep $SLEEP0 + +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 0 ; then + break + fi + echo "Waiting ${SLEEP1} seconds for slapd to start..." + sleep ${SLEEP1} +done + +echo "Gathering overlay configuration from both servers..." +echo "# overlay configuration from dynamically configured server..." >> $SERVER1OUT +$LDAPSEARCH -D cn=config -H $URI1 -y $CONFIGPWF \ + -b "olcOverlay={0}datamorph,olcDatabase={1}$BACKEND,cn=config" \ + | sed -e "s/ {[0-9]*}/ /" -e "s/={[0-9]*}/=/g" \ + >> $SERVER1OUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "# overlay configuration from server configured from slapd.conf..." >> $SERVER3OUT +$LDAPSEARCH -D cn=config -H $URI2 -y $CONFIGPWF \ + -b "olcOverlay={0}datamorph,olcDatabase={1}$BACKEND,cn=config" \ + | sed -e "s/ {[0-9]*}/ /" -e "s/={[0-9]*}/=/g" \ + >> $SERVER3OUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +# We've already filtered out the ordering markers, now sort the entries +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SERVER3OUT > $SERVER3FLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $SERVER1OUT > $SERVER1FLT +echo "Comparing filter output..." +$CMP $SERVER3FLT $SERVER1FLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +rm $SERVER1OUT $SERVER3OUT + +echo "Comparing search output on both servers..." +echo "# search output from dynamically configured server..." >> $SERVER1OUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + >> $SERVER1OUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "# search output from server configured from slapd.conf..." >> $SERVER3OUT +$LDAPSEARCH -b "$BASEDN" -H $URI2 \ + >> $SERVER3OUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SERVER1OUT > $SERVER1FLT +$LDIFFILTER -s e < $SERVER2OUT > $SERVER2FLT +$LDIFFILTER -s e < $SERVER3OUT > $SERVER3FLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $SERVER6OUT > $SERVER6FLT +echo "Comparing filter output..." +$CMP $SERVER6FLT $SERVER1FLT > $CMPOUT && \ +$CMP $SERVER6FLT $SERVER2FLT > $CMPOUT && \ +$CMP $SERVER6FLT $SERVER3FLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/datamorph/tests/scripts/test002-add-delete b/contrib/slapd-modules/datamorph/tests/scripts/test002-add-delete new file mode 100755 index 0000000..f947d09 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/scripts/test002-add-delete @@ -0,0 +1,147 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Adding entries (should fail this time)..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -c -f data/test002-entry.ldif >> $TESTOUT 2>&1 +RC=$? +case $RC in +0) + echo "ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; +19) + echo "ldapmodify failed ($RC)" + ;; +*) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; +esac + +echo "Adding other entries (should fail)..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test002-fail.ldif >> $TESTOUT 2>&1 +RC=$? +case $RC in +0) + echo "ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; +19) + echo "ldapmodify failed ($RC)" + ;; +*) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; +esac + +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test002-transformed-rdn.ldif >> $TESTOUT 2>&1 +RC=$? +case $RC in +0) + echo "ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; +32) + echo "ldapmodify failed ($RC)" + ;; +*) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; +esac + +echo "Configuring new value..." +. $CONFFILTER $BACKEND $MONITORDB < data/test002-config.ldif | \ +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Adding some of the entries again..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test002-entry.ldif >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Saving search output..." +$LDAPSEARCH -H $URI1 -b "$BASEDN" \ + "(|(cn=Gern Jensen)(ou=New Unit))" \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Removing entry..." +$LDAPDELETE -D $MANAGERDN -H $URI1 -w $PASSWD \ + "cn=Gern Jensen,ou=Information Technology Division,ou=People,$BASEDN" \ + "ou=New Unit,$BASEDN" \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapdelete failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test002-entry.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s ae < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s ae < $LDIF | grep -v '^changetype:' > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/datamorph/tests/scripts/test003-search b/contrib/slapd-modules/datamorph/tests/scripts/test003-search new file mode 100755 index 0000000..9afe677 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/scripts/test003-search @@ -0,0 +1,106 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Testing searches against regular entries..." +echo "# Testing searches against regular entries..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 "(|(ou=Groups)(st=*))" \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches listing transformed attributes..." +echo >> $SEARCHOUT +echo "# Testing searches listing transformed attributes..." >> $SEARCHOUT +$LDAPSEARCH -b "ou=Information Technology Division,ou=People,$BASEDN" -s one \ + -H $URI1 >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches filtering on transformed attributes..." +echo >> $SEARCHOUT +echo "# Testing searches filtering on transformed attributes..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + "(|(enumerated=bjensen)(&(signed=-19858)(signed<=0)(signed>=-20000)))" \ + enumerated signed \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Reconfiguring transformation definition..." +. $CONFFILTER $BACKEND $MONITORDB < data/test003-config.ldif | \ +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches filtering on the new values..." +echo >> $SEARCHOUT +echo "# Testing searches filtering on the new values..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + "(|(enumerated=not a value)(enumerated=jaj)(&(signed=45678)(!(signed>=50000))(signed>=44444)))" \ + enumerated signed \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test003-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/datamorph/tests/scripts/test004-compare b/contrib/slapd-modules/datamorph/tests/scripts/test004-compare new file mode 100755 index 0000000..d4b535b --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/scripts/test004-compare @@ -0,0 +1,62 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Comparing a regular entry..." +$LDAPCOMPARE -H $URI1 \ + "cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN" \ + "cn:Mark Elliot" >> $TESTOUT 2>&1 +RC=$? +if test $RC != 6 && test $RC,$BACKEND != 5,null ; then + echo "ldapcompare failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +echo "Comparing a transformed enum entry..." +$LDAPCOMPARE -H $URI1 \ + "cn=Jane Doe,ou=Alumni Association,ou=People,$BASEDN" \ + "enumerated:jdoe" >> $TESTOUT 2>&1 +RC=$? +if test $RC != 6 && test $RC,$BACKEND != 5,null ; then + echo "ldapcompare failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +echo "Comparing a transformed interval entry..." +$LDAPCOMPARE -H $URI1 "ou=People,$BASEDN" \ + "signed:-19858" >> $TESTOUT 2>&1 +RC=$? +if test $RC != 6 && test $RC,$BACKEND != 5,null ; then + echo "ldapcompare failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/datamorph/tests/scripts/test005-modify b/contrib/slapd-modules/datamorph/tests/scripts/test005-modify new file mode 100755 index 0000000..94cf1c0 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/scripts/test005-modify @@ -0,0 +1,89 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Modifying entry..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test005-changes.ldif >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Applying invalid changes (should fail)..." +for CHANGE in data/test005-*fail.ldif; do + echo "... $CHANGE" + $LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f $CHANGE >> $TESTOUT 2>&1 + RC=$? + case $RC in + 0) + echo "ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; + 16|19) + echo "ldapmodify failed ($RC)" + ;; + *) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; + esac +done + +echo "Reading affected entries back..." +echo "# Reading affected entries back..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + '(|(objectClass=OpenLDAPperson)(ou=people))' \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test005-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/datamorph/tests/scripts/test006-modrdn b/contrib/slapd-modules/datamorph/tests/scripts/test006-modrdn new file mode 100755 index 0000000..56e2f2a --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/scripts/test006-modrdn @@ -0,0 +1,52 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Renaming an entry to add new value (should fail)..." +$LDAPMODRDN -D $MANAGERDN -H $URI1 -w $PASSWD \ + "cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN" \ + "cn=Mark Elliot+enumerated=melliot" \ + >> $TESTOUT 2>&1 +RC=$? +case $RC in +0) + echo "ldapmodrdn should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; +19) + echo "ldapmodrdn failed ($RC)" + ;; +*) + echo "ldapmodrdn failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; +esac + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/datamorph/tests/scripts/test007-transformed-replication b/contrib/slapd-modules/datamorph/tests/scripts/test007-transformed-replication new file mode 100755 index 0000000..5b2ea4d --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/scripts/test007-transformed-replication @@ -0,0 +1,296 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +if test "$SYNCPROV" = syncprovno; then + echo "Syncrepl provider overlay not available, test skipped" + exit 0 +fi + +. ${SCRIPTDIR}/common.sh + +if test "$SYNCPROV" = syncprovmod; then + $LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + > $TESTOUT 2>&1 <<EOMOD +dn: cn=module,cn=config +changetype: add +objectClass: olcModuleList +olcModuleLoad: $LDAP_BUILD/servers/slapd/overlays/syncprov.la +EOMOD + + RC=$? + if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + fi +fi + +mkdir $DBDIR4 $TESTDIR/confdir-consumer + +echo "Starting consumer slapd on TCP/IP port $PORT4..." +. $CONFFILTER $BACKEND $MONITORDB < $P1SRCONSUMERCONF > $CONF4 + +echo "database config" >>$CONF4 +echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF4 + +$SLAPD -f $CONF4 -F $TESTDIR/confdir-consumer -h $URI4 -d $LVL > $LOG4 2>&1 & +CONSUMERPID=$! +if test $WAIT != 0 ; then + echo CONSUMERPID $CONSUMERPID + read foo +fi +KILLPIDS="$KILLPIDS $CONSUMERPID" + +sleep $SLEEP0 + +echo "Setting up overlay on consumer..." +$LDAPMODIFY -v -D cn=config -H $URI4 -y $CONFIGPWF \ + > $TESTOUT 2>&1 <<EOMOD +dn: cn=module,cn=config +changetype: add +objectClass: olcModuleList +olcModuleLoad: `pwd`/../datamorph.la +EOMOD +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Configuring syncprov on provider..." +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + > $TESTOUT 2>&1 <<EOMOD +dn: olcOverlay=syncprov,olcDatabase={1}$BACKEND,cn=config +changetype: add +objectclass: olcSyncProvConfig +EOMOD +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +. $CONFFILTER $BACKEND $MONITORDB < $OVERLAY_CONFIG | \ +$LDAPMODIFY -v -D cn=config -H $URI4 -y $CONFIGPWF \ + > $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$BASEDN" -H $URI4 \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 0 ; then + break + fi + echo "Waiting ${SLEEP1} seconds for consumer to start replication..." + sleep ${SLEEP1} +done + +echo "Waiting ${SLEEP1} seconds for consumer to finish replicating..." +sleep ${SLEEP1} + +echo "Testing searches against regular replicated entries..." +echo "# Testing searches against regular replicated entries..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI4 "(|(ou=Groups)(st=*))" \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches listing replicated transformed attributes..." +echo >> $SEARCHOUT +echo "# Testing searches listing replicated transformed attributes..." >> $SEARCHOUT +$LDAPSEARCH -b "ou=Information Technology Division,ou=People,$BASEDN" \ + -s one -H $URI4 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches filtering on replicated transformed attributes..." +echo >> $SEARCHOUT +echo "# Testing searches filtering on replicated transformed attributes..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI4 \ + "(|(enumerated=bjensen)(&(signed=-19858)(signed<=0)(signed>=-20000)))" \ + enumerated signed \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Reconfiguring transformation definition..." +. $CONFFILTER $BACKEND $MONITORDB < data/test003-config.ldif | \ +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +. $CONFFILTER $BACKEND $MONITORDB < data/test003-config.ldif | \ +$LDAPMODIFY -v -D cn=config -H $URI4 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches filtering on the new replicated values..." +echo >> $SEARCHOUT +echo "# Testing searches filtering on the new replicated values..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI4 \ + "(|(enumerated=not a value)(enumerated=jaj)(&(signed=45678)(!(signed>=50000))(signed>=44444)))" \ + enumerated signed \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +LDIF=data/test003-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +rm $SEARCHOUT + +echo "Reverting part of the above configuration for remainder of the test..." +. $CONFFILTER $BACKEND $MONITORDB < data/test007-config.ldif | \ +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +. $CONFFILTER $BACKEND $MONITORDB < data/test007-config.ldif | \ +$LDAPMODIFY -v -D cn=config -H $URI4 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Modifying entry..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test005-changes.ldif >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Applying invalid changes (should fail)..." +for CHANGE in data/test005-*fail.ldif; do + echo "... $CHANGE" + $LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f $CHANGE >> $TESTOUT 2>&1 + RC=$? + case $RC in + 0) + echo "ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; + 16|19) + echo "ldapmodify failed ($RC)" + ;; + *) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; + esac +done + +echo "Waiting ${SLEEP1} seconds for consumer to finish replicating..." +sleep ${SLEEP1} + +echo "Reading affected entries back..." +echo "# Reading affected entries back..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + '(|(objectClass=OpenLDAPperson)(ou=people))' \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test005-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/datamorph/tests/scripts/test008-ignored-replication b/contrib/slapd-modules/datamorph/tests/scripts/test008-ignored-replication new file mode 100755 index 0000000..a1fcb71 --- /dev/null +++ b/contrib/slapd-modules/datamorph/tests/scripts/test008-ignored-replication @@ -0,0 +1,299 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +if test "$SYNCPROV" = syncprovno; then + echo "Syncrepl provider overlay not available, test skipped" + exit 0 +fi + +. ${SCRIPTDIR}/common.sh + +if test "$SYNCPROV" = syncprovmod; then + $LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + > $TESTOUT 2>&1 <<EOMOD +dn: cn=module,cn=config +changetype: add +objectClass: olcModuleList +olcModuleLoad: $LDAP_BUILD/servers/slapd/overlays/syncprov.la +EOMOD + + RC=$? + if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + fi +fi + +mkdir $DBDIR4 $TESTDIR/confdir-consumer + +echo "Starting consumer slapd on TCP/IP port $PORT4..." +. $CONFFILTER $BACKEND $MONITORDB < $P1SRCONSUMERCONF > $CONF4 + +echo "database config" >>$CONF4 +echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF4 + +$SLAPD -f $CONF4 -F $TESTDIR/confdir-consumer -h $URI4 -d $LVL > $LOG4 2>&1 & +CONSUMERPID=$! +if test $WAIT != 0 ; then + echo CONSUMERPID $CONSUMERPID + read foo +fi +KILLPIDS="$KILLPIDS $CONSUMERPID" + +sleep $SLEEP0 + +echo "Setting up overlay on consumer..." +$LDAPMODIFY -v -D cn=config -H $URI4 -y $CONFIGPWF \ + > $TESTOUT 2>&1 <<EOMOD +dn: cn=module,cn=config +changetype: add +objectClass: olcModuleList +olcModuleLoad: `pwd`/../datamorph.la +EOMOD +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Configuring syncprov on provider..." +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + > $TESTOUT 2>&1 <<EOMOD +dn: olcOverlay={0}syncprov,olcDatabase={1}$BACKEND,cn=config +changetype: add +objectclass: olcSyncProvConfig +EOMOD +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +. $CONFFILTER $BACKEND $MONITORDB < $OVERLAY_CONFIG | \ +$LDAPMODIFY -v -D cn=config -H $URI4 -y $CONFIGPWF \ + > $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$BASEDN" -H $URI4 \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 0 ; then + break + fi + echo "Waiting ${SLEEP1} seconds for consumer to start replication..." + sleep ${SLEEP1} +done + +echo "Waiting ${SLEEP1} seconds for consumer to finish replicating..." +sleep ${SLEEP1} + +echo "Testing searches against regular replicated entries..." +echo "# Testing searches against regular replicated entries..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI4 "(|(ou=Groups)(st=*))" \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches listing replicated transformed attributes..." +echo >> $SEARCHOUT +echo "# Testing searches listing replicated transformed attributes..." >> $SEARCHOUT +$LDAPSEARCH -b "ou=Information Technology Division,ou=People,$BASEDN" -s one \ + -H $URI4 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches filtering on replicated transformed attributes..." +echo >> $SEARCHOUT +echo "# Testing searches filtering on replicated transformed attributes..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI4 \ + "(|(enumerated=bjensen)(&(signed=-19858)(signed<=0)(signed>=-20000)))" \ + enumerated signed \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Reconfiguring transformation definition..." +. $CONFFILTER $BACKEND $MONITORDB < data/test003-config.ldif | \ +sed 's/{0}datamorph/{1}datamorph/' | \ +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +. $CONFFILTER $BACKEND $MONITORDB < data/test003-config.ldif | \ +$LDAPMODIFY -v -D cn=config -H $URI4 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches filtering on the new replicated values..." +echo >> $SEARCHOUT +echo "# Testing searches filtering on the new replicated values..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI4 \ + "(|(enumerated=not a value)(enumerated=jaj)(&(signed=45678)(!(signed>=50000))(signed>=44444)))" \ + enumerated signed \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +LDIF=data/test003-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +rm $SEARCHOUT + +echo "Reverting part of the above configuration for remainder of the test..." +. $CONFFILTER $BACKEND $MONITORDB < data/test007-config.ldif | \ +sed 's/{0}datamorph/{1}datamorph/' | \ +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +. $CONFFILTER $BACKEND $MONITORDB < data/test007-config.ldif | \ +$LDAPMODIFY -v -D cn=config -H $URI4 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Modifying entry..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test005-changes.ldif >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Applying invalid changes (should fail)..." +for CHANGE in data/test005-*fail.ldif; do + echo "... $CHANGE" + $LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f $CHANGE >> $TESTOUT 2>&1 + RC=$? + case $RC in + 0) + echo "ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; + 16|19) + echo "ldapmodify failed ($RC)" + ;; + *) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; + esac +done + +echo "Waiting ${SLEEP1} seconds for consumer to finish replicating..." +sleep ${SLEEP1} + +echo "Reading affected entries back..." +echo "# Reading affected entries back..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + '(|(objectClass=OpenLDAPperson)(ou=people))' \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test005-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 |