diff options
Diffstat (limited to '')
30 files changed, 1747 insertions, 0 deletions
diff --git a/contrib/slapd-modules/alias/Makefile b/contrib/slapd-modules/alias/Makefile new file mode 100644 index 0000000..c1be15b --- /dev/null +++ b/contrib/slapd-modules/alias/Makefile @@ -0,0 +1,82 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 1998-2023 The OpenLDAP Foundation. +# Copyright 2023 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 + +PLAT = UNIX +NT_LIB = -L$(LDAP_BUILD)/servers/slapd -lslapd +NT_LDFLAGS = -no-undefined -avoid-version +UNIX_LDFLAGS = -version-info $(LTVER) + +LIBTOOL = $(LDAP_BUILD)/libtool +INSTALL = /usr/bin/install +CC = gcc +OPT = -g -O2 +DEFS = -DSLAPD_OVER_ALIAS=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $($(PLAT)_LIB) $(LDAP_LIB) +LD_FLAGS = $(LDFLAGS) $($(PLAT)_LDFLAGS) -rpath $(moduledir) -module + +PROGRAMS = alias.la +MANPAGES = slapo-alias.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 $< + +alias.la: alias.lo + $(LIBTOOL) --mode=link $(CC) $(LD_FLAGS) -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/alias/alias.c b/contrib/slapd-modules/alias/alias.c new file mode 100644 index 0000000..c5707ff --- /dev/null +++ b/contrib/slapd-modules/alias/alias.c @@ -0,0 +1,673 @@ +/* alias.c - expose an attribute under a different name */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2016-2023 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 2023 by Ondřej Kuzník for Symas Corp. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_ALIAS + +#include <inttypes.h> +#include <ac/stdlib.h> + +#include "slap.h" +#include "slap-config.h" +#include "lutil.h" +#include "ldap_queue.h" + +typedef struct alias_mapping_t { + AttributeDescription *source; + AttributeDescription *alias; +} alias_mapping; + +typedef struct alias_info_t { + alias_mapping *mappings; +} alias_info; + +typedef struct alias_sc_private_t { + slap_overinst *on; + AttributeName *attrs_orig, *attrs_new; +} alias_sc_private; + +static alias_mapping * +attribute_mapped( alias_info *ov, AttributeDescription *ad ) +{ + alias_mapping *m; + + for ( m = ov->mappings; m && m->source; m++ ) { + if ( ad == m->alias ) return m; + } + + return NULL; +} + +static int +alias_op_add( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + alias_info *ov = on->on_bi.bi_private; + Entry *e = op->ora_e; + Attribute *a; + int rc = LDAP_SUCCESS; + + if ( !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, "alias_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++ ) { + AttributeDescription *ad = NULL; + + /* If we can't resolve the attribute, ignore it */ + if ( slap_bv2ad( &rDN[i]->la_attr, &ad, &p ) ) { + continue; + } + + if ( attribute_mapped( ov, ad ) ) { + rc = LDAP_CONSTRAINT_VIOLATION; + break; + } + } + + ldap_rdnfree_x( rDN, op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + send_ldap_error( op, rs, rc, + "trying to add a virtual attribute in RDN" ); + return rc; + } + } + + for ( a = e->e_attrs; a; a = a->a_next ) { + if ( attribute_mapped( ov, a->a_desc ) ) { + rc = LDAP_CONSTRAINT_VIOLATION; + send_ldap_error( op, rs, rc, + "trying to add a virtual attribute" ); + return LDAP_CONSTRAINT_VIOLATION; + } + } + + return SLAP_CB_CONTINUE; +} + +static int +alias_op_compare( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + alias_info *ov = on->on_bi.bi_private; + alias_mapping *alias = attribute_mapped( ov, op->orc_ava->aa_desc ); + + if ( alias ) + op->orc_ava->aa_desc = alias->source; + + return SLAP_CB_CONTINUE; +} + +static int +alias_op_mod( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + alias_info *ov = on->on_bi.bi_private; + Modifications *mod; + int rc = LDAP_CONSTRAINT_VIOLATION; + + for ( mod = op->orm_modlist; mod; mod = mod->sml_next ) { + if ( attribute_mapped( ov, mod->sml_desc ) ) { + send_ldap_error( op, rs, rc, + "trying to modify a virtual attribute" ); + return LDAP_CONSTRAINT_VIOLATION; + } + } + + return SLAP_CB_CONTINUE; +} + +static int +alias_op_modrdn( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + alias_info *ov = on->on_bi.bi_private; + LDAPRDN rDN; + const char *p; + int i, rc = SLAP_CB_CONTINUE; + + 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, "alias_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++ ) { + AttributeDescription *ad = NULL; + + /* If we can't resolve the attribute, ignore it */ + if ( slap_bv2ad( &rDN[i]->la_attr, &ad, &p ) ) { + continue; + } + + if ( attribute_mapped( ov, ad ) ) { + rc = LDAP_CONSTRAINT_VIOLATION; + break; + } + } + + ldap_rdnfree_x( rDN, op->o_tmpmemctx ); + if ( rc != LDAP_SUCCESS ) { + send_ldap_error( op, rs, rc, + "trying to add a virtual attribute in RDN" ); + return rc; + } + + return SLAP_CB_CONTINUE; +} + +static int +alias_response_cleanup( Operation *op, SlapReply *rs ) +{ + alias_sc_private *data = op->o_callback->sc_private; + + if ( rs->sr_type == REP_RESULT || op->o_abandon || + rs->sr_err == SLAPD_ABANDON ) + { + if ( op->ors_attrs == data->attrs_new ) + op->ors_attrs = data->attrs_orig; + + ch_free( data->attrs_new ); + ch_free( op->o_callback ); + op->o_callback = NULL; + } + + return SLAP_CB_CONTINUE; +} + +static int +alias_response( Operation *op, SlapReply *rs ) +{ + alias_sc_private *data = op->o_callback->sc_private; + slap_overinst *on = data->on; + alias_info *ov = on->on_bi.bi_private; + Entry *e = NULL, *e_orig = rs->sr_entry; + alias_mapping *mapping; + int rc = SLAP_CB_CONTINUE; + + if ( rs->sr_type != REP_SEARCH || !e_orig ) { + return rc; + } + + for ( mapping = ov->mappings; mapping && mapping->source; mapping++ ) { + Attribute *source, *a; + int operational = is_at_operational( mapping->source->ad_type ), + keep_source = 0; + slap_mask_t requested = operational ? + SLAP_OPATTRS_YES : SLAP_USERATTRS_YES; + + if ( !(requested & rs->sr_attr_flags) && + !ad_inlist( mapping->alias, rs->sr_attrs ) ) + continue; + + /* TODO: deal with multiple aliases from the same source */ + if ( (requested & rs->sr_attr_flags) || + ad_inlist( mapping->source, data->attrs_orig ) ) { + keep_source = 1; + } + + if ( operational ) { + source = attr_find( rs->sr_operational_attrs, mapping->source ); + } + if ( !source ) { + operational = 0; + source = attr_find( e_orig->e_attrs, mapping->source ); + } + if ( !source ) + continue; + + if ( operational ) { + if ( !keep_source ) { + source->a_desc = mapping->alias; + } else { + Attribute **ap; + + a = attr_dup( source ); + a->a_desc = mapping->alias; + + for ( ap = &rs->sr_operational_attrs; *ap; ap=&(*ap)->a_next ); + *ap = a; + } + continue; + } + + if ( !e ) { + if ( rs->sr_flags & REP_ENTRY_MODIFIABLE ) { + e = e_orig; + } else { + e = entry_dup( e_orig ); + } + } + + a = attr_find( e->e_attrs, mapping->source ); + if ( !keep_source ) { + a->a_desc = mapping->alias; + } else { + attr_merge( e, mapping->alias, a->a_vals, a->a_nvals ); + } + } + + 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; + } + + return rc; +} + +static int +alias_filter( alias_info *ov, Filter *f ) +{ + int changed = 0; + + switch ( f->f_choice ) { + case LDAP_FILTER_AND: + case LDAP_FILTER_OR: { + for ( f = f->f_and; f; f = f->f_next ) { + int result = alias_filter( ov, f ); + if ( result < 0 ) { + return result; + } + changed += result; + } + } break; + + case LDAP_FILTER_NOT: + return alias_filter( ov, f->f_not ); + + case LDAP_FILTER_PRESENT: { + alias_mapping *alias = attribute_mapped( ov, f->f_desc ); + if ( alias ) { + f->f_desc = alias->source; + changed = 1; + } + } break; + + case LDAP_FILTER_APPROX: + case LDAP_FILTER_EQUALITY: + case LDAP_FILTER_GE: + case LDAP_FILTER_LE: { + alias_mapping *alias = attribute_mapped( ov, f->f_av_desc ); + if ( alias ) { + f->f_av_desc = alias->source; + changed = 1; + } + } break; + + case LDAP_FILTER_SUBSTRINGS: { + alias_mapping *alias = attribute_mapped( ov, f->f_sub_desc ); + if ( alias ) { + f->f_sub_desc = alias->source; + changed = 1; + } + } break; + + case LDAP_FILTER_EXT: { + alias_mapping *alias = attribute_mapped( ov, f->f_mr_desc ); + if ( alias ) { + f->f_mr_desc = alias->source; + changed = 1; + } + } break; + + default: + return -1; + } + return changed; +} + +static int +alias_op_search( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + alias_info *ov = on->on_bi.bi_private; + alias_mapping *mapping; + AttributeName *an_orig = NULL, *an_new = NULL; + int mapped, an_length = 0; + + if ( get_manageDSAit( op ) ) + return SLAP_CB_CONTINUE; + + /* + * 1. check filter: traverse, map aliased attributes + * 2. unparse filter + * 3. check all requested attributes -> register callback if one matches + */ + if ( (mapped = alias_filter( ov, op->ors_filter )) < 0 ) { + send_ldap_error( op, rs, LDAP_OTHER, + "alias_op_search: failed to process filter" ); + return LDAP_OTHER; + } + + if ( mapped ) { + op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); + filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); + } + + mapped = 0; + for ( mapping = ov->mappings; mapping && mapping->source; mapping++ ) { + int operational = is_at_operational( mapping->source->ad_type ); + slap_mask_t requested = operational ? + SLAP_OPATTRS_YES : SLAP_USERATTRS_YES; + + if ( requested & slap_attr_flags( op->ors_attrs ) ) { + mapped = 1; + } else if ( ad_inlist( mapping->alias, op->ors_attrs ) ) { + mapped = 1; + if ( !an_length ) { + for ( ; !BER_BVISNULL( &op->ors_attrs[an_length].an_name ); an_length++ ) + /* Count */; + } + + an_new = ch_realloc( an_new, (an_length+2)*sizeof(AttributeName) ); + if ( !an_orig ) { + int i; + an_orig = op->ors_attrs; + for ( i=0; i < an_length; i++ ) { + an_new[i] = an_orig[i]; + } + } + + an_new[an_length].an_name = mapping->source->ad_cname; + an_new[an_length].an_desc = mapping->source; + an_length++; + + BER_BVZERO( &an_new[an_length].an_name ); + } + } + + if ( mapped ) { + /* We have something to map back */ + slap_callback *cb = op->o_tmpcalloc( 1, + sizeof(slap_callback)+sizeof(alias_sc_private), + op->o_tmpmemctx ); + alias_sc_private *data = (alias_sc_private *)(cb+1); + + data->on = on; + + cb->sc_response = alias_response; + cb->sc_private = data; + cb->sc_next = op->o_callback; + cb->sc_cleanup = alias_response_cleanup; + + if ( an_new ) { + data->attrs_orig = an_orig; + data->attrs_new = an_new; + op->ors_attrs = an_new; + } + + op->o_callback = cb; + } + + return SLAP_CB_CONTINUE; +} + +/* Configuration */ + +static ConfigDriver alias_config_mapping; + +static ConfigTable alias_cfg[] = { + { "alias_attribute", "attr> <attr", 3, 3, 0, + ARG_MAGIC, + alias_config_mapping, + "( OLcfgCtAt:10.1 NAME 'olcAliasMapping' " + "DESC 'Alias definition' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", + NULL, NULL + }, + + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + +/* + * FIXME: There is no reason to keep olcAliasMapping MAY (making this overlay + * a noop) except we can't enforce a MUST with slaptest+slapd.conf. + */ +static ConfigOCs alias_ocs[] = { + { "( OLcfgCtOc:10.1 " + "NAME 'olcAliasConfig' " + "DESC 'Alias overlay configuration' " + "MAY ( olcAliasMapping ) " + "SUP olcOverlayConfig )", + Cft_Overlay, alias_cfg }, + + { NULL, 0, NULL } +}; + +static int +alias_config_mapping( ConfigArgs *ca ) +{ + slap_overinst *on = (slap_overinst *)ca->bi; + alias_info *ov = on->on_bi.bi_private; + AttributeDescription *source = NULL, *alias = NULL; + AttributeType *sat, *aat; + const char *text; + int i, rc = LDAP_CONSTRAINT_VIOLATION; + + if ( ca->op == SLAP_CONFIG_EMIT ) { + alias_mapping *mapping; + + for ( mapping = ov->mappings; mapping && mapping->source; mapping++ ) { + char buf[SLAP_TEXT_BUFLEN]; + struct berval bv = { .bv_val = buf, .bv_len = SLAP_TEXT_BUFLEN }; + bv.bv_len = snprintf( buf, bv.bv_len, "%s %s", + mapping->source->ad_cname.bv_val, + mapping->alias->ad_cname.bv_val ); + value_add_one( &ca->rvalue_vals, &bv ); + } + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + if ( ca->valx < 0 ) { + ch_free( ov->mappings ); + ov->mappings = NULL; + } else { + i = ca->valx; + do { + ov->mappings[i] = ov->mappings[i+1]; + i++; + } while ( ov->mappings[i].source ); + } + return LDAP_SUCCESS; + } + + rc = slap_str2ad( ca->argv[1], &source, &text ); + if ( rc ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "cannot resolve attribute '%s': \"%s\"", + ca->argv[1], text ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + goto done; + } + + rc = slap_str2ad( ca->argv[2], &alias, &text ); + if ( rc ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "cannot resolve attribute '%s': \"%s\"", + ca->argv[2], text ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + goto done; + } + + sat = source->ad_type; + aat = alias->ad_type; + if ( sat == aat ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "cannot map attribute %s to itself", + source->ad_cname.bv_val ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + rc = LDAP_CONSTRAINT_VIOLATION; + goto done; + } + + /* The types have to match */ + if ( is_at_operational( sat ) != is_at_operational( aat ) || + is_at_single_value( sat ) != is_at_single_value( aat ) || + sat->sat_syntax != aat->sat_syntax || + sat->sat_equality != aat->sat_equality || + sat->sat_approx != aat->sat_approx || + sat->sat_ordering != aat->sat_ordering || + sat->sat_substr != aat->sat_substr ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "attributes %s and %s syntax and/or " + "default matching rules don't match", + source->ad_cname.bv_val, + alias->ad_cname.bv_val ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + rc = LDAP_CONSTRAINT_VIOLATION; + goto done; + } + + if ( !ov->mappings ) { + ov->mappings = ch_calloc( 2, sizeof(alias_mapping) ); + ov->mappings[0].source = source; + ov->mappings[0].alias = alias; + } else { + int i; + + for ( i = 0; ov->mappings[i].source; i++ ) { + if ( alias == ov->mappings[i].alias ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "attribute %s already mapped from %s", + alias->ad_cname.bv_val, + ov->mappings[i].source->ad_cname.bv_val ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + rc = LDAP_CONSTRAINT_VIOLATION; + goto done; + } + if ( alias == ov->mappings[i].source ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "cannot use %s as alias source, already mapped from %s", + source->ad_cname.bv_val, + ov->mappings[i].source->ad_cname.bv_val ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + rc = LDAP_CONSTRAINT_VIOLATION; + goto done; + } + if ( source == ov->mappings[i].alias ) { + snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "cannot use %s as alias, it is aliased to %s", + alias->ad_cname.bv_val, + ov->mappings[i].alias->ad_cname.bv_val ); + Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); + rc = LDAP_CONSTRAINT_VIOLATION; + goto done; + } + } + + if ( ca->valx < 0 || ca->valx > i ) + ca->valx = i; + + i++; + ov->mappings = ch_realloc( ov->mappings, (i + 1) * sizeof(alias_mapping) ); + do { + ov->mappings[i] = ov->mappings[i-1]; + } while ( --i > ca->valx ); + ov->mappings[i].source = source; + ov->mappings[i].alias = alias; + } + + rc = LDAP_SUCCESS; +done: + ca->reply.err = rc; + return rc; +} + +static slap_overinst alias; + +static int +alias_db_init( BackendDB *be, ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + alias_info *ov; + + /* TODO: can this be global? */ + if ( SLAP_ISGLOBALOVERLAY(be) ) { + Debug( LDAP_DEBUG_ANY, "alias overlay must be instantiated " + "within a database.\n" ); + return 1; + } + + ov = ch_calloc( 1, sizeof(alias_info) ); + on->on_bi.bi_private = ov; + + return LDAP_SUCCESS; +} + +static int +alias_db_destroy( BackendDB *be, ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + alias_info *ov = on->on_bi.bi_private; + + if ( ov && ov->mappings ) { + ch_free( ov->mappings ); + } + ch_free( ov ); + + return LDAP_SUCCESS; +} + +int +alias_initialize() +{ + int rc; + + alias.on_bi.bi_type = "alias"; + alias.on_bi.bi_db_init = alias_db_init; + alias.on_bi.bi_db_destroy = alias_db_destroy; + + alias.on_bi.bi_op_add = alias_op_add; + alias.on_bi.bi_op_compare = alias_op_compare; + alias.on_bi.bi_op_modify = alias_op_mod; + alias.on_bi.bi_op_modrdn = alias_op_modrdn; + alias.on_bi.bi_op_search = alias_op_search; + + alias.on_bi.bi_cf_ocs = alias_ocs; + + rc = config_register_schema( alias_cfg, alias_ocs ); + if ( rc ) return rc; + + return overlay_register( &alias ); +} + +#if SLAPD_OVER_ALIAS == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return alias_initialize(); +} +#endif + +#endif /* SLAPD_OVER_ALIAS */ diff --git a/contrib/slapd-modules/alias/slapo-alias.5 b/contrib/slapd-modules/alias/slapo-alias.5 new file mode 100644 index 0000000..4f5fb29 --- /dev/null +++ b/contrib/slapd-modules/alias/slapo-alias.5 @@ -0,0 +1,121 @@ +.TH SLAPO-ALIAS 5 "RELEASEDATE" "OpenLDAP" +.\" Copyright 2023 Symas Corp. All Rights Reserved. +.\" Copying restrictions apply. See LICENSE. +.SH NAME +slapo\-alias \- expose an attribute under a different name +.SH SYNOPSIS +olcOverlay=alias +.SH DESCRIPTION +The +.B alias +overlay to +.BR slapd (8) +allows migrations for existing attributes exposed through a name that is +now deprecated where using +.BR slapo-rwm (5) +is not applicable. For this reason, the aliased attributes are not writable +in any way. In particular: + +.RS +.TP +.B Search + +Instances of the aliased attribute in the +.B Search +request filter are replaced by the source attribute. + +If the attribute is requested, the values are copied from the source +attribute, however unlike with +.BR slapo-rwm (5), +if the source attribute is also requested, both will be returned. +.TP +.B Compare +The request is mapped to the source attribute before processing. +.TP +.B Add, Modify, ModRDN +Requests affecting aliased attributes are rejected with a +.B Constraint +.BR Violation . +.RE + + +.SH CONFIGURATION LAYOUT + +The overlay has to be instantiated under a database adding an entry of +.B olcOverlay=alias +with objectClass of +.BR olcAliasConfig. + +These are the available options: + +.RS +.TP +.B olcAliasMapping: <source-attribute> <aliased-attribute> +Any time +.B aliased-attribute +is requested (explicitly or through +.B * + +shorthands), the values of +.B source-attribute +are returned. The attributes need to be compatible i.e. both have to be +operational or neither should, same with the +.B SINGLE-VALUE +option, syntax or matching rules. The +.BR slapd.conf (5) +equivalent is +.BR alias_attribute . +It can be provided multiple times. +.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}alias,$DATABASE +objectClass: olcAliasConfig +olcOverlay: alias +olcAliasMapping: source-attribute aliased-attribute +.fi + +The +.BR slapd.conf (5) +equivalent of the above follows: + +.nf +overlay alias + +alias_attribute source-attribute aliased-attribute +.fi + +.SH NOTES +When mapping an operational attribute, you might need to use +.BR slapo-dsaschema (5) +contrib module to provide its definition into the schema. + +.SH BUGS AND LIMITATIONS +Setting ACLs that differ between the aliased and its source attribute is not +supported, they have to match or risk information disclosure. + +It is also expected that the aliased attributes are never physically present in +the database. + +.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 slapo-dsaschema (5), +.BR slapd (8) +.SH ACKNOWLEDGEMENTS +This module was developed in 2023 by Ondřej Kuzník for Symas Corp. diff --git a/contrib/slapd-modules/alias/tests/Rules.mk b/contrib/slapd-modules/alias/tests/Rules.mk new file mode 100644 index 0000000..c25c1d2 --- /dev/null +++ b/contrib/slapd-modules/alias/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/alias/tests/data/alias.conf b/contrib/slapd-modules/alias/tests/data/alias.conf new file mode 100644 index 0000000..5997666 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/alias.conf @@ -0,0 +1,4 @@ +overlay alias + +alias_attribute pager mobile + diff --git a/contrib/slapd-modules/alias/tests/data/config.ldif b/contrib/slapd-modules/alias/tests/data/config.ldif new file mode 100644 index 0000000..9c676a9 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/config.ldif @@ -0,0 +1,5 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectClass: olcOverlayConfig +objectclass: olcAliasConfig +olcAliasMapping: pager mobile diff --git a/contrib/slapd-modules/alias/tests/data/test001-00a-invalid.ldif b/contrib/slapd-modules/alias/tests/data/test001-00a-invalid.ldif new file mode 100644 index 0000000..f0eff6b --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test001-00a-invalid.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: description invalidAttr diff --git a/contrib/slapd-modules/alias/tests/data/test001-00b-invalid.ldif b/contrib/slapd-modules/alias/tests/data/test001-00b-invalid.ldif new file mode 100644 index 0000000..f351ced --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test001-00b-invalid.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: invalidAttr description diff --git a/contrib/slapd-modules/alias/tests/data/test001-01a-same-alias.ldif b/contrib/slapd-modules/alias/tests/data/test001-01a-same-alias.ldif new file mode 100644 index 0000000..db851ff --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test001-01a-same-alias.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: fax mobile diff --git a/contrib/slapd-modules/alias/tests/data/test001-01b-same-attr.ldif b/contrib/slapd-modules/alias/tests/data/test001-01b-same-attr.ldif new file mode 100644 index 0000000..07275be --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test001-01b-same-attr.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: c countryname diff --git a/contrib/slapd-modules/alias/tests/data/test001-01c-chained.ldif b/contrib/slapd-modules/alias/tests/data/test001-01c-chained.ldif new file mode 100644 index 0000000..92d466d --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test001-01c-chained.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: mobile fax diff --git a/contrib/slapd-modules/alias/tests/data/test001-01d-chained.ldif b/contrib/slapd-modules/alias/tests/data/test001-01d-chained.ldif new file mode 100644 index 0000000..efeaac0 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test001-01d-chained.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: fax pager diff --git a/contrib/slapd-modules/alias/tests/data/test001-02a-operational.ldif b/contrib/slapd-modules/alias/tests/data/test001-02a-operational.ldif new file mode 100644 index 0000000..1c10aa6 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test001-02a-operational.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: seeAlso entryDN diff --git a/contrib/slapd-modules/alias/tests/data/test001-02b-single.ldif b/contrib/slapd-modules/alias/tests/data/test001-02b-single.ldif new file mode 100644 index 0000000..fe464e7 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test001-02b-single.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: displayName employeeType diff --git a/contrib/slapd-modules/alias/tests/data/test001-02c-syntax.ldif b/contrib/slapd-modules/alias/tests/data/test001-02c-syntax.ldif new file mode 100644 index 0000000..8c24f5d --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test001-02c-syntax.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: dc description diff --git a/contrib/slapd-modules/alias/tests/data/test001-02d-matching.ldif b/contrib/slapd-modules/alias/tests/data/test001-02d-matching.ldif new file mode 100644 index 0000000..7f80402 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test001-02d-matching.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: memberUid mail diff --git a/contrib/slapd-modules/alias/tests/data/test001-02e-no-ordering.ldif b/contrib/slapd-modules/alias/tests/data/test001-02e-no-ordering.ldif new file mode 100644 index 0000000..ce2a7ae --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test001-02e-no-ordering.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: gidNumber ipServicePort diff --git a/contrib/slapd-modules/alias/tests/data/test002-add-rdn.ldif b/contrib/slapd-modules/alias/tests/data/test002-add-rdn.ldif new file mode 100644 index 0000000..23e17c0 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test002-add-rdn.ldif @@ -0,0 +1,5 @@ +dn: mobile=\+1 313 555 4474,dc=example,dc=com +changetype: add +objectClass: OpenLDAPperson +cn: Just a phone +sn: Mobile diff --git a/contrib/slapd-modules/alias/tests/data/test002-add.ldif b/contrib/slapd-modules/alias/tests/data/test002-add.ldif new file mode 100644 index 0000000..330bd9a --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test002-add.ldif @@ -0,0 +1,18 @@ +dn: cn=Gern Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com +changetype: add +objectclass: testPerson +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 +mobile: +1 313 555 8866 diff --git a/contrib/slapd-modules/alias/tests/data/test002-delete.ldif b/contrib/slapd-modules/alias/tests/data/test002-delete.ldif new file mode 100644 index 0000000..e6932e4 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test002-delete.ldif @@ -0,0 +1,3 @@ +dn: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com +changetype: modify +delete: mobile diff --git a/contrib/slapd-modules/alias/tests/data/test002-modify.ldif b/contrib/slapd-modules/alias/tests/data/test002-modify.ldif new file mode 100644 index 0000000..730dcbb --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test002-modify.ldif @@ -0,0 +1,4 @@ +dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +changetype: modify +add: mobile +mobile: +1 313 555 3665 diff --git a/contrib/slapd-modules/alias/tests/data/test002-modrdn.ldif b/contrib/slapd-modules/alias/tests/data/test002-modrdn.ldif new file mode 100644 index 0000000..1ad729b --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test002-modrdn.ldif @@ -0,0 +1,5 @@ +dn: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=example + ,dc=com +changetype: modrdn +newrdn: mobile=\+1 313 555 4474 +deleteoldrdn: 0 diff --git a/contrib/slapd-modules/alias/tests/data/test003-config.ldif b/contrib/slapd-modules/alias/tests/data/test003-config.ldif new file mode 100644 index 0000000..322fcd5 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test003-config.ldif @@ -0,0 +1,4 @@ +dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +add: olcAliasMapping +olcAliasMapping: title employeeType diff --git a/contrib/slapd-modules/alias/tests/data/test003-out.ldif b/contrib/slapd-modules/alias/tests/data/test003-out.ldif new file mode 100644 index 0000000..0aa02e6 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/data/test003-out.ldif @@ -0,0 +1,66 @@ +# Listing aliased attribute... +dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example, + dc=com +mobile: +1 313 555 3233 + + +# A search when aliased attribute is not requested... +dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example, + dc=com +pager: +1 313 555 3233 + + +# A search when both are requested (explicitly)... +dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example, + dc=com +pager: +1 313 555 3233 +mobile: +1 313 555 3233 + + +# A search when both are requested (implicitly)... +dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example, + dc=com +objectClass: OpenLDAPperson +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 +mobile: +1 313 555 3233 + + +# Testing searches filtering on aliased attributes... +dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example, + dc=com +mobile: +1 313 555 3233 + +dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc + =com +mobile: +1 313 555 4474 + +dn: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com +mobile: +1 313 555 1220 + + +# Testing search with new attributes... +dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc + =com +employeeType: Director, Embedded Systems +mobile: +1 313 555 4474 + +dn: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com +employeeType: Director, UM Alumni Association +mobile: +1 313 555 7671 + diff --git a/contrib/slapd-modules/alias/tests/run b/contrib/slapd-modules/alias/tests/run new file mode 100755 index 0000000..239bff7 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/run @@ -0,0 +1,17 @@ +#!/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>. + +TOPSRCDIR="$SRCDIR" OBJDIR="${LDAP_BUILD}" SRCDIR="${SRCDIR}/tests" DEFSDIR="${SRCDIR}/scripts" SCRIPTDIR="${TOPDIR}/tests/scripts" "${LDAP_BUILD}/tests/run" $* + diff --git a/contrib/slapd-modules/alias/tests/scripts/all b/contrib/slapd-modules/alias/tests/scripts/all new file mode 100755 index 0000000..5af7083 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/scripts/all @@ -0,0 +1,93 @@ +#! /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;; + *.py) 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 + + 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/alias/tests/scripts/common.sh b/contrib/slapd-modules/alias/tests/scripts/common.sh new file mode 100755 index 0000000..a2e2922 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/scripts/common.sh @@ -0,0 +1,105 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2023 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 2022 by Ondřej Kuzník for Symas Corp. + +OVERLAY_CONFIG=${OVERLAY_CONFIG-data/config.ldif} + +mkdir -p $TESTDIR $DBDIR1 + +echo "Running slapadd to build slapd database..." +. $CONFFILTER $BACKEND $MONITORDB < $CONF > $ADDCONF +$SLAPADD -f $ADDCONF -l $LDIF +RC=$? +if test $RC != 0 ; then + echo "slapadd failed ($RC)!" + exit $RC +fi + +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`/../alias.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`/../alias.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 alias 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 diff --git a/contrib/slapd-modules/alias/tests/scripts/test001-config b/contrib/slapd-modules/alias/tests/scripts/test001-config new file mode 100755 index 0000000..fa68e67 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/scripts/test001-config @@ -0,0 +1,248 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2023 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 2023 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 + ;; + 17|19) + 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 ../alias.la' \ + -e '/database.*monitor/i\ +include data/alias.conf' \ + > $CONF2 +echo "database config" >>$CONF2 +echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF2 + +$SLAPADD -f $CONF2 -l $LDIFORDERED +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}alias,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}alias,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/alias/tests/scripts/test002-add-delete b/contrib/slapd-modules/alias/tests/scripts/test002-add-delete new file mode 100755 index 0000000..c080859 --- /dev/null +++ b/contrib/slapd-modules/alias/tests/scripts/test002-add-delete @@ -0,0 +1,76 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2023 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 2023 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Applying changes affecting aliased attribute (should fail)..." +for CHANGE in data/test002-*.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 + ;; + 19) + echo "ldapmodify failed ($RC)" + ;; + *) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; + esac +done + +echo "Saving search output..." +# We're just making sure no modifications made it to the DB, bypass +# the overlay to be able to compare with ldif used to populate it. +$LDAPSEARCH -M -b "$BASEDN" -H $URI1 >> $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 + +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/alias/tests/scripts/test003-search b/contrib/slapd-modules/alias/tests/scripts/test003-search new file mode 100755 index 0000000..467ec9f --- /dev/null +++ b/contrib/slapd-modules/alias/tests/scripts/test003-search @@ -0,0 +1,151 @@ +#! /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 aliased attribute..." +$LDAPCOMPARE -H $URI1 \ + "cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN" \ + "mobile:+1 313 555 7671" >> $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 + +$LDAPCOMPARE -H $URI1 \ + "cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN" \ + "mobile:+1 313 555 4177" >> $TESTOUT 2>&1 +RC=$? +if test $RC != 5 ; then + echo "ldapcompare should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +echo "Listing alias attribute specifically..." +echo "# Listing aliased attribute..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 "uid=bjensen" mobile \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Not asking for alias attribute..." +echo >> $SEARCHOUT +echo "# A search when aliased attribute is not requested..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 "uid=bjensen" pager \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Retrieving both the aliased attribute and the source..." +echo >> $SEARCHOUT +echo "# A search when both are requested (explicitly)..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 "uid=bjensen" mobile pager \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Retrieving both the aliased attribute and the source..." +echo >> $SEARCHOUT +echo "# A search when both are requested (implicitly)..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 "uid=bjensen" \ + >> $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 aliased attributes..." +echo >> $SEARCHOUT +echo "# Testing searches filtering on aliased attributes..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + "(|(mobile=+1 313 555 3233)(mobile=*4474)(&(mobile=*)(uid=jdoe)))" \ + mobile \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Reconfiguring alias 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 with new attributes..." +echo >> $SEARCHOUT +echo "# Testing search with new attributes..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + "employeetype=*director*" \ + employeetype mobile \ + >> $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 |