ITS#10104 Add slapo-alias to contrib

This commit is contained in:
Ondřej Kuzník 2023-09-25 09:44:35 +01:00
parent 2c73d3a534
commit d615deb6f6
33 changed files with 1753 additions and 0 deletions

View file

@ -9,3 +9,4 @@ OLcfgCt{Oc|At}:6 adremap
OLcfgCt{Oc|At}:7 rbac
OLcfgCt{Oc|At}:8 datamorph
OLcfgCt{Oc|At}:9 variant
OLcfgCt{Oc|At}:10 alias

View file

@ -0,0 +1,3 @@
# test suite
clients
servers

View file

@ -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:

View file

@ -0,0 +1,671 @@
/* 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 );
} else {
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 */

View file

@ -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.

View file

@ -0,0 +1,4 @@
progs
schema
testdata
testrun

View file

@ -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))

View file

@ -0,0 +1,4 @@
overlay alias
alias_attribute pager mobile

View file

@ -0,0 +1,5 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: add
objectClass: olcOverlayConfig
objectclass: olcAliasConfig
olcAliasMapping: pager mobile

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: description invalidAttr

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: invalidAttr description

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: fax mobile

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: c countryname

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: mobile fax

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: fax pager

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: seeAlso entryDN

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: displayName employeeType

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: dc description

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: memberUid mail

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: gidNumber ipServicePort

View file

@ -0,0 +1,5 @@
dn: mobile=\+1 313 555 4474,dc=example,dc=com
changetype: add
objectClass: OpenLDAPperson
cn: Just a phone
sn: Mobile

View file

@ -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

View file

@ -0,0 +1,3 @@
dn: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com
changetype: modify
delete: mobile

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,4 @@
dn: olcOverlay={0}alias,olcDatabase={1}@BACKEND@,cn=config
changetype: modify
add: olcAliasMapping
olcAliasMapping: title employeeType

View file

@ -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

View file

@ -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" $*

View file

@ -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}."

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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