diff options
Diffstat (limited to 'contrib/slapd-modules/emptyds')
-rw-r--r-- | contrib/slapd-modules/emptyds/Makefile | 78 | ||||
-rw-r--r-- | contrib/slapd-modules/emptyds/README | 66 | ||||
-rw-r--r-- | contrib/slapd-modules/emptyds/emptyds.c | 325 | ||||
-rw-r--r-- | contrib/slapd-modules/emptyds/slapo-emptyds.5 | 68 | ||||
-rw-r--r-- | contrib/slapd-modules/emptyds/tests/Rules.mk | 23 | ||||
-rw-r--r-- | contrib/slapd-modules/emptyds/tests/data/emptyds.conf | 54 | ||||
-rw-r--r-- | contrib/slapd-modules/emptyds/tests/data/test001.ldif | 71 | ||||
-rw-r--r-- | contrib/slapd-modules/emptyds/tests/data/test001.out | 54 | ||||
-rwxr-xr-x | contrib/slapd-modules/emptyds/tests/run | 218 | ||||
-rwxr-xr-x | contrib/slapd-modules/emptyds/tests/scripts/all | 92 | ||||
-rwxr-xr-x | contrib/slapd-modules/emptyds/tests/scripts/test001-emptyds | 137 |
11 files changed, 1186 insertions, 0 deletions
diff --git a/contrib/slapd-modules/emptyds/Makefile b/contrib/slapd-modules/emptyds/Makefile new file mode 100644 index 0000000..654f856 --- /dev/null +++ b/contrib/slapd-modules/emptyds/Makefile @@ -0,0 +1,78 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 1998-2022 The OpenLDAP Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +SRCDIR = ./ +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap/libldap.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +INSTALL = /usr/bin/install +CC = gcc +OPT = -g -O2 +DEFS = -DSLAPD_OVER_EDS=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = emptyds.la +MANPAGES = slapo-emptyds.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 $< + +all: $(PROGRAMS) + +emptyds.la: emptyds.lo + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -version-info $(LTVER) \ + -rpath $(moduledir) -module -o $@ $? $(LIBS) + +clean: + rm -rf $(CLEAN) + +install: install-lib install-man FORCE + +install-lib: $(PROGRAMS) + mkdir -p $(DESTDIR)$(moduledir) + for p in $(PROGRAMS) ; do \ + $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \ + done + +install-man: $(MANPAGES) + mkdir -p $(DESTDIR)$(man5dir) + $(INSTALL) -m 644 $(MANPAGES) $(DESTDIR)$(man5dir) + +FORCE: + diff --git a/contrib/slapd-modules/emptyds/README b/contrib/slapd-modules/emptyds/README new file mode 100644 index 0000000..914d4e7 --- /dev/null +++ b/contrib/slapd-modules/emptyds/README @@ -0,0 +1,66 @@ +emptyds Overlay README + +DESCRIPTION + This package contains an OpenLDAP overlay called "emptyds" (empty + directory string) that eliminates empty values of type directory string + (OID 1.3.6.1.4.1.1466.115.121.1.15) from the list of the values in the + following manner: + + - add: All empty attribute values will be removed before the add request + is executed + - mod-replace: A replace with empty values will be modified to a replace + without values. As result the attribute will be deleted + - mod-add: All empty attribute values will be removed before the mod-add + request is executed + - mod-delete: All empty attribute values will be removed before the + mod-delete request is executed + + If removing all empty values from a modification makes it a no-op, that + modification is removed from the list. + + At module load time the emptyds overlay manipulates the syntax checking + so that it intercepts the syntax check and allows empty values for + attributes of type directory string only. Non-empty values continue to + go through the normal check routines. It is therefore very important to + configure the overlays in a way that ensures that the emptyds overlay gets + the control over the operation before any other overlay. Otherwise it + could come to the situation with empty attribute values in the data base. + + David Hawes' addpartial overlay has been used as starting point for this + overlay. + +BUILDING + A Makefile is included, please set your LDAP_SRC directory properly. + +INSTALLATION + After compiling the emptyds overlay, add the following to your + slapd.conf: + + ### slapd.conf + ... + moduleload emptyds.la + ... + overlay emptyds + ... + # before database directive... + # this overlay must be the last overlay in the config file to ensure that + # requests are modified before other overlays get them. + ... + ### end slapd.conf + +CAVEATS + - In order to ensure that emptyds does what it needs to do, it must be + the last overlay configured so it will run before the other overlays. + +--- +Copyright 2014-2022 The OpenLDAP Foundation. +Portions Copyright (C) DAASI International GmbH, Tamim Ziai. +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 file LICENSE in the +top-level directory of the distribution or, alternatively, at +http://www.OpenLDAP.org/license.html. diff --git a/contrib/slapd-modules/emptyds/emptyds.c b/contrib/slapd-modules/emptyds/emptyds.c new file mode 100644 index 0000000..bb3202e --- /dev/null +++ b/contrib/slapd-modules/emptyds/emptyds.c @@ -0,0 +1,325 @@ +/* emptyds.c */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2014-2022 The OpenLDAP Foundation. + * Portions Copyright (C) 2014 DAASI International GmbH, Tamim Ziai. + * Portions Copyright (C) 2022 Ondřej Kuzník, Symas Corporation. + * 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 file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * http://www.OpenLDAP.org/license.html. + */ +/* ACKNOLEDGEDMENTS: + * This work was initially developed by Tamim Ziai of DAASI International GmbH + * for inclusion in OpenLDAP Software. + */ +/* slapo-emptyds + * + * This is an OpenLDAP overlay that accepts empty strings as attribute values + * without syntax violation but never actually stores them. This allows + * applications that used to work with LDAP implementations allowing empty + * strings (such as Novel eDirectory) to continue to work with OpenLDAP without + * any modifications. Add and modify change types will be proceeded as follows, + * other operations will be forwarded without modifications: + * + * changeType: add changeType: add + * sn: <empty> --> sn: blah + * sn: blah + * + * changeType: modify changeType: modify + * add: sn --> add: sn + * sn: <empty> sn: blah + * sn: blah + * + * changeType: modify changeType: modify + * delete: sn --> delete: sn + * sn: <empty> sn: blah + * sn: blah + * + * changeType: modify changeType: modify + * replace: sn --> replace: sn + * sn: <empty> + * + */ + +#include "portable.h" +#include "slap.h" + +static slap_overinst emptyds; + +static const char ds_oid[] = "1.3.6.1.4.1.1466.115.121.1.15"; + +static slap_syntax_validate_func *ssyn_validate_original = NULL; +static slap_syntax_transform_func *ssyn_pretty_original = NULL; +static int emptyds_instances = 0; + +static unsigned int +remove_empty_values( Modification *m, Attribute *a ) +{ + BerVarray vals = m ? m->sm_values : a->a_vals, + nvals = m ? m->sm_nvalues : a->a_nvals; + unsigned int i, j, numvals = m ? m->sm_numvals : a->a_numvals; + + for ( i = 0; i < numvals && !BER_BVISEMPTY( &vals[i] ); i++ ) + /* Find first empty */; + + if ( i == numvals ) return i; + + /* + * We have an empty value at index i, move all of them to the end of the + * list, preserving the order of non-empty values. + */ + j = i + 1; + for ( j = i + 1; j < numvals; j++ ) { + struct berval tmp; + + if ( BER_BVISEMPTY( &vals[j] ) ) continue; + + tmp = vals[i]; + vals[i] = vals[j]; + vals[j] = tmp; + + if ( nvals && vals != nvals ) { + tmp = nvals[i]; + nvals[i] = nvals[j]; + nvals[j] = tmp; + } + + if ( m && a && m->sm_values != a->a_vals ) { + tmp = a->a_vals[i]; + a->a_vals[i] = a->a_vals[j]; + a->a_vals[j] = tmp; + + if ( a->a_nvals && a->a_vals != a->a_nvals ) { + tmp = a->a_nvals[i]; + a->a_nvals[i] = a->a_nvals[j]; + a->a_nvals[j] = tmp; + } + } + i++; + } + + /* Free empty vals */ + for ( ; j && i < j--; ) { + ber_memfree( vals[j].bv_val ); + if ( nvals && vals != nvals ) { + ber_memfree( nvals[j].bv_val ); + BER_BVZERO( &nvals[j] ); + } + + if ( m && a && m->sm_values != a->a_vals ) { + if ( m->sm_values[j].bv_val != a->a_vals[j].bv_val ) { + ber_memfree( a->a_vals[j].bv_val ); + BER_BVZERO( &a->a_vals[j] ); + + if ( a->a_nvals && a->a_vals != a->a_nvals ) { + ber_memfree( a->a_nvals[j].bv_val ); + BER_BVZERO( &a->a_nvals[j] ); + } + } + } + BER_BVZERO( &vals[j] ); + } + + return i; +} + +/** + * Remove all operations with empty strings. + */ +static int +emptyds_op_add( Operation *op, SlapReply *rs ) +{ + Attribute **ap, **nexta, *a; + Modifications **mlp, **nextp = NULL, *ml; + Entry *e = op->ora_e; + + /* + * op->ora_modlist can be NULL, at least accesslog doesn't always populate + * it on an add. + */ + for ( ap = &e->e_attrs, a = e->e_attrs, mlp = &op->ora_modlist, + ml = op->ora_modlist; + a != NULL; + ap = nexta, a = *ap, mlp = nextp, ml = ml ? *mlp : NULL ) { + AttributeType *at = a->a_desc->ad_type; + unsigned int remaining; + + nexta = &a->a_next; + if ( ml ) { + nextp = &ml->sml_next; + } + + if ( at->sat_syntax != slap_schema.si_syn_directoryString || + at->sat_atype.at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) + continue; + + remaining = remove_empty_values( &ml->sml_mod, a ); + if ( remaining == a->a_numvals ) continue; + /* Empty values found */ + + if ( !remaining ) { + /* All values are empty */ + *ap = a->a_next; + a->a_next = NULL; + nexta = ap; + + if ( ml ) { + *mlp = ml->sml_next; + ml->sml_next = NULL; + nextp = mlp; + /* Values are generally shared with attribute */ + slap_mods_free( ml, ml->sml_values != a->a_vals ); + } + attr_free( a ); + } else { + a->a_numvals = remaining; + if ( ml ) { + ml->sml_mod.sm_numvals = remaining; + } + } + } + + return SLAP_CB_CONTINUE; +} + +static int +emptyds_op_modify( Operation *op, SlapReply *rs ) +{ + Modifications **mlp, **nextp, *ml; + + for ( mlp = &op->orm_modlist, ml = op->orm_modlist; ml != NULL; + mlp = nextp, ml = *mlp ) { + AttributeType *at = ml->sml_desc->ad_type; + unsigned int remaining; + + nextp = &ml->sml_next; + + if ( at->sat_syntax != slap_schema.si_syn_directoryString || + at->sat_atype.at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) + continue; + + remaining = remove_empty_values( &ml->sml_mod, NULL ); + if ( remaining == ml->sml_numvals ) continue; + + if ( !remaining ) { + /* All values are empty */ + if ( ml->sml_op == LDAP_MOD_REPLACE ) { + /* Replace is kept */ + if ( ml->sml_nvalues && ml->sml_nvalues != ml->sml_values ) { + ber_bvarray_free( ml->sml_nvalues ); + } + if ( ml->sml_values ) { + ber_bvarray_free( ml->sml_values ); + } + + ml->sml_numvals = 0; + ml->sml_values = NULL; + ml->sml_nvalues = NULL; + } else { + /* Remove modification */ + *mlp = ml->sml_next; + ml->sml_next = NULL; + nextp = mlp; + slap_mods_free( ml, 1 ); + } + } else { + ml->sml_numvals = remaining; + } + } + + return SLAP_CB_CONTINUE; +} + +static int +emptyds_ssyn_validate( Syntax *syntax, struct berval *in ) +{ + if ( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) { + return LDAP_SUCCESS; + } + return ssyn_validate_original( syntax, in ); +} + +static int +emptyds_ssyn_pretty( Syntax *syntax, + struct berval *in, + struct berval *out, + void *memctx ) +{ + if ( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) { + return LDAP_SUCCESS; + } + return ssyn_pretty_original( syntax, in, out, memctx ); +} + +static int +emptyds_db_init( BackendDB *be, ConfigReply *cr ) +{ + Syntax *syntax = syn_find( ds_oid ); + + if ( syntax == NULL ) { + Debug( LDAP_DEBUG_TRACE, "emptyds_db_init: " + "Syntax %s not found\n", + ds_oid ); + } else { + Debug( LDAP_DEBUG_TRACE, "emptyds_db_init: " + "Found syntax: %s\n", + syntax->ssyn_bvoid.bv_val ); + if ( ssyn_validate_original == NULL && syntax->ssyn_validate != NULL ) { + ssyn_validate_original = syntax->ssyn_validate; + syntax->ssyn_validate = emptyds_ssyn_validate; + } + if ( ssyn_pretty_original == NULL && syntax->ssyn_pretty != NULL ) { + ssyn_pretty_original = syntax->ssyn_pretty; + syntax->ssyn_pretty = &emptyds_ssyn_pretty; + } + } + + emptyds_instances++; + return LDAP_SUCCESS; +} + +static int +emptyds_db_destroy( BackendDB *be, ConfigReply *cr ) +{ + Syntax *syntax = syn_find( ds_oid ); + + if ( --emptyds_instances == 0 && syntax != NULL ) { + if ( syntax->ssyn_validate == emptyds_ssyn_validate ) { + syntax->ssyn_validate = ssyn_validate_original; + } + ssyn_validate_original = NULL; + + if ( syntax->ssyn_pretty == emptyds_ssyn_pretty ) { + syntax->ssyn_pretty = ssyn_pretty_original; + } + ssyn_pretty_original = NULL; + } + + assert( emptyds_instances >= 0 ); + return LDAP_SUCCESS; +} + +int +emptyds_init() +{ + emptyds.on_bi.bi_type = "emptyds"; + emptyds.on_bi.bi_op_add = emptyds_op_add; + emptyds.on_bi.bi_op_modify = emptyds_op_modify; + emptyds.on_bi.bi_db_init = emptyds_db_init; + emptyds.on_bi.bi_db_destroy = emptyds_db_destroy; + + return overlay_register( &emptyds ); +} + +int +init_module( int argc, char *argv[] ) +{ + return emptyds_init(); +} diff --git a/contrib/slapd-modules/emptyds/slapo-emptyds.5 b/contrib/slapd-modules/emptyds/slapo-emptyds.5 new file mode 100644 index 0000000..75b1059 --- /dev/null +++ b/contrib/slapd-modules/emptyds/slapo-emptyds.5 @@ -0,0 +1,68 @@ +.TH SLAPO-EDS 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 2022 The OpenLDAP Foundation, All Rights Reserved. +.\" Copyright 2018 Tamim Ziai +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.\" $OpenLDAP$ +.SH NAME +slapo-emptyds \- Remove Empty values from Directory String attributes +Overlay to slapd +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +Some non-conformant clients will provide empty values for Directory String +attributes with certain operations. This overlay makes empty values acceptable +for the Directory String syntax and will adjust all operations to make sure +these values are never actually stored in the database. +.LP +.nf +.ft tt + dn: cn=alex,cn=people,dc=example,dc=org + changeType: add changeType: add + sn: <empty> --> sn: blah + sn: blah + + dn: cn=alex,cn=people,dc=example,dc=org + changeType: modify changeType: modify + add: sn --> add: sn + sn: <empty> sn: blah + sn: blah + + dn: cn=alex,cn=people,dc=example,dc=org + changeType: modify changeType: modify + delete: sn --> delete: sn + sn: <empty> sn: blah + sn: blah + + dn: cn=alex,cn=people,dc=example,dc=org + changeType: modify changeType: modify + replace: sn --> replace: sn + sn: <empty> + + dn: cn=alex,cn=people,dc=example,dc=org + changeType: modify changeType: modify + replace: sn --> replace: sn + sn: <empty> sn: blah + sn: blah +.ft +.fi +.LP +.SH CONFIGURATION +This overlay has no specific configuration, however in order to ensure that it +does what it needs to do, it should be the last overlay configured so it will +run before the other overlays. +.SH EXAMPLES +.LP +.RS +.nf +overlay emptyds +.RE +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.SH SEE ALSO +.BR slapd.conf (5). +.SH ACKNOWLEDGEMENTS +This module was written in 2014 by Tamim Ziai for DAASI International and +updated in 2022 by Ondřej Kuzník for inclusion in the OpenLDAP project. +.so ../Project diff --git a/contrib/slapd-modules/emptyds/tests/Rules.mk b/contrib/slapd-modules/emptyds/tests/Rules.mk new file mode 100644 index 0000000..c25c1d2 --- /dev/null +++ b/contrib/slapd-modules/emptyds/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/emptyds/tests/data/emptyds.conf b/contrib/slapd-modules/emptyds/tests/data/emptyds.conf new file mode 100644 index 0000000..221fe81 --- /dev/null +++ b/contrib/slapd-modules/emptyds/tests/data/emptyds.conf @@ -0,0 +1,54 @@ +# basic slapd config -- for testing of slapo-emptyds +# $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>. + +include @SCHEMADIR@/core.schema +include @SCHEMADIR@/cosine.schema +include @SCHEMADIR@/inetorgperson.schema +include @SCHEMADIR@/openldap.schema +include @SCHEMADIR@/nis.schema +include @DATADIR@/test.schema +# +pidfile @TESTDIR@/slapd.1.pid +argsfile @TESTDIR@/slapd.1.args + +#mod#modulepath ../servers/slapd/back-@BACKEND@/ +#mod#moduleload back_@BACKEND@.la +#accesslogmod#modulepath ../servers/slapd/overlays/ +#accesslogmod#moduleload accesslog.la +moduleload ../emptyds.la + +database @BACKEND@ +suffix "dc=example,dc=com" +rootdn "cn=Manager,dc=example,dc=com" +rootpw secret +#~null~#directory @TESTDIR@/db.1.a + +overlay accesslog +logdb cn=log +logops writes +logsuccess true + +overlay emptyds + +database @BACKEND@ +suffix "cn=log" +rootdn "cn=Manager,dc=example,dc=com" +#~null~#directory @TESTDIR@/db.1.b + +## This one makes no difference except we want to make sure we can +## safely instantiate the overlay on multiple databases +overlay emptyds + +database monitor diff --git a/contrib/slapd-modules/emptyds/tests/data/test001.ldif b/contrib/slapd-modules/emptyds/tests/data/test001.ldif new file mode 100644 index 0000000..b7f289a --- /dev/null +++ b/contrib/slapd-modules/emptyds/tests/data/test001.ldif @@ -0,0 +1,71 @@ +# slapd prevents us from adding the same value multiple times +dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com +changetype: modify +add: description +description: one +description: +description: two +description: three +description: four +# a space is distinct from an empty value +description:: ICAg +- +replace: drink +drink: Earl Grey, hot +- +delete: description +description: +- +replace: drink +drink: Earl Grey, hot + +# there is no such restriction on deletes, so we exercise this part of the overlay here +dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com +changetype: modify +delete: description +description: +description: four +description: +description: three +description: two +description: +description: +description: one +description: +- +add: description +description: + +dn: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com +changetype: modify +replace: drink +drink: + +dn: cn=All Staff,ou=Groups,dc=example,dc=com +changetype: modify +delete: member +- +add: member +# an empty DN should not be stripped +member: +member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com + +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: +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 +description: +description: More than you think +facsimiletelephonenumber: +1 313 555 7557 +telephonenumber: +1 313 555 8343 +mail: gjensen@mailgw.example.com +homephone: +1 313 555 8844 +testTime: 20050304001801.234Z diff --git a/contrib/slapd-modules/emptyds/tests/data/test001.out b/contrib/slapd-modules/emptyds/tests/data/test001.out new file mode 100644 index 0000000..6f41247 --- /dev/null +++ b/contrib/slapd-modules/emptyds/tests/data/test001.out @@ -0,0 +1,54 @@ +dn: reqStart=timestamp,cn=log +reqDN: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com +reqMod: description:+ one +reqMod: description:+ two +reqMod: description:+ three +reqMod: description:+ four +# "description:+ " that's a space, then 3 spaces for value +reqMod:: ZGVzY3JpcHRpb246KyAgICA= +reqMod: drink:= Earl Grey, hot +# second mod was removed, so we have two replaces in succession now and need +# to separate them (":") +reqMod:: Og== +reqMod: drink:= Earl Grey, hot + +dn: reqStart=timestamp,cn=log +reqDN: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com +reqMod: description:- four +reqMod: description:- three +reqMod: description:- two +reqMod: description:- one +# second mod is removed + +dn: reqStart=timestamp,cn=log +reqDN: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com +reqMod: drink:= + +dn: reqStart=timestamp,cn=log +reqDN: cn=All Staff,ou=Groups,dc=example,dc=com +reqMod: member:- +# "member:+ " adding an empty DN +reqMod:: bWVtYmVyOisg +reqMod: member:+ cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example + ,dc=com + +dn: reqStart=timestamp,cn=log +reqDN: cn=Gern Jensen,ou=Information Technology Division,ou=People,dc=example, + dc=com +reqMod: objectClass:+ testPerson +reqMod: cn:+ Gern Jensen +reqMod: sn:+ Jensen +reqMod: uid:+ gjensen +reqMod: postalAddress:+ ITD $ 535 W. William St $ Anytown, MI 48103 +reqMod: seeAlso:+ cn=All Staff,ou=Groups,dc=example,dc=com +reqMod: drink:+ Coffee +reqMod: homePostalAddress:+ 844 Brown St. Apt. 4 $ Anytown, MI 48104 +reqMod: description:+ Very odd +reqMod: description:+ More than you think +reqMod: facsimileTelephoneNumber:+ +1 313 555 7557 +reqMod: telephoneNumber:+ +1 313 555 8343 +reqMod: mail:+ gjensen@mailgw.example.com +reqMod: homePhone:+ +1 313 555 8844 +reqMod: testTime:+ 20050304001801.234Z +reqMod: structuralObjectClass:+ testPerson + diff --git a/contrib/slapd-modules/emptyds/tests/run b/contrib/slapd-modules/emptyds/tests/run new file mode 100755 index 0000000..e28820c --- /dev/null +++ b/contrib/slapd-modules/emptyds/tests/run @@ -0,0 +1,218 @@ +#!/bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 1998-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +USAGE="$0 [-b <backend>] [-c] [-k] [-l #] [-p] [-s {ro|rp}] [-u] [-w] <script>" + +TOPSRCDIR="${SRCDIR-$LDAP_SRC}" +SRCDIR="${TOPSRCDIR}/tests" +eval `grep EGREP_CMD= ${LDAP_BUILD}/tests/run` +eval `$EGREP_CMD -e '^LN_S=' ${LDAP_BUILD}/tests/run` + +export SRCDIR TOPSRCDIR LN_S EGREP_CMD + +. "${SRCDIR}/scripts/defines.sh" + +BACKEND= +CLEAN=no +WAIT=0 +KILLSERVERS=yes +PRESERVE=${PRESERVE-no} +SYNCMODE=${SYNCMODE-rp} +USERDATA=no +LOOP=1 +COUNTER=1 + +while test $# -gt 0 ; do + case "$1" in + -b | -backend) + BACKEND="$2" + shift; shift ;; + + -c | -clean) + CLEAN=yes + shift ;; + + -k | -kill) + KILLSERVERS=no + shift ;; + -l | -loop) + NUM="`echo $2 | sed 's/[0-9]//g'`" + if [ -z "$NUM" ]; then + LOOP=$2 + else + echo "Loop variable not an int: $2" + echo "$USAGE"; exit 1 + fi + shift ; + shift ;; + + -p | -preserve) + PRESERVE=yes + shift ;; + + -s | -syncmode) + case "$2" in + ro | rp) + SYNCMODE="$2" + ;; + *) + echo "unknown sync mode $2" + echo "$USAGE"; exit 1 + ;; + esac + shift; shift ;; + + -u | -userdata) + USERDATA=yes + shift ;; + + -w | -wait) + WAIT=1 + shift ;; + + -) + shift + break ;; + + -*) + echo "$USAGE"; exit 1 + ;; + + *) + break ;; + esac +done + +eval `$EGREP_CMD -e '^AC' ${LDAP_BUILD}/tests/run` +export `$EGREP_CMD -e '^AC' ${LDAP_BUILD}/tests/run | sed 's/=.*//'` + +if test -z "$BACKEND" ; then + for b in mdb ; do + if eval "test \"\$AC_$b\" != no" ; then + BACKEND=$b + break + fi + done + if test -z "$BACKEND" ; then + echo "No suitable default database backend configured" >&2 + exit 1 + fi +fi + +BACKENDTYPE=`eval 'echo $AC_'$BACKEND` +if test "x$BACKENDTYPE" = "x" ; then + BACKENDTYPE="unknown" +fi + +# Backend features. indexdb: indexing and unchecked limit. +# maindb: main storage backend. Currently index,limits,mode,paged results. +INDEXDB=noindexdb MAINDB=nomaindb +case $BACKEND in + mdb) INDEXDB=indexdb MAINDB=maindb ;; +esac + +export BACKEND BACKENDTYPE INDEXDB MAINDB \ + WAIT KILLSERVERS PRESERVE SYNCMODE USERDATA \ + SRCDIR + +if test $# = 0 ; then + echo "$USAGE"; exit 1 +fi + +# need defines.sh for the definitions of the directories +. $SRCDIR/scripts/defines.sh + +SCRIPTDIR="${TOPDIR}/tests/scripts" + +export SCRIPTDIR + +SCRIPTNAME="$1" +shift + +if test -x "${SCRIPTDIR}/${SCRIPTNAME}" ; then + SCRIPT="${SCRIPTDIR}/${SCRIPTNAME}" +elif test -x "`echo ${SCRIPTDIR}/test*-${SCRIPTNAME}`"; then + SCRIPT="`echo ${SCRIPTDIR}/test*-${SCRIPTNAME}`" +elif test -x "`echo ${SCRIPTDIR}/${SCRIPTNAME}-*`"; then + SCRIPT="`echo ${SCRIPTDIR}/${SCRIPTNAME}-*`" +else + echo "run: ${SCRIPTNAME} not found (or not executable)" + exit 1; +fi + +if test ! -r ${DATADIR}/test.ldif ; then + ${LN_S} ${SRCDIR}/data ${DATADIR} +fi +if test ! -r ${SCHEMADIR}/core.schema ; then + ${LN_S} ${TOPSRCDIR}/servers/slapd/schema ${SCHEMADIR} +fi +if test ! -r ./data; then + ${LN_S} ${TOPDIR}/tests/data ./ +fi + +if test -d ${TESTDIR} ; then + if test $PRESERVE = no ; then + echo "Cleaning up test run directory leftover from previous run." + /bin/rm -rf ${TESTDIR} + elif test $PRESERVE = yes ; then + echo "Cleaning up only database directories leftover from previous run." + /bin/rm -rf ${TESTDIR}/db.* + fi +fi +mkdir -p ${TESTDIR} + +if test $USERDATA = yes ; then + if test ! -d userdata ; then + echo "User data directory (userdata) does not exist." + exit 1 + fi + cp -R userdata/* ${TESTDIR} +fi + +# disable LDAP initialization +LDAPNOINIT=true; export LDAPNOINIT + +echo "Running ${SCRIPT} for ${BACKEND}..." +while [ $COUNTER -le $LOOP ]; do + if [ $LOOP -gt 1 ]; then + echo "Running $COUNTER of $LOOP iterations" + fi + $SCRIPT $* + RC=$? + + if test $CLEAN = yes ; then + echo "Cleaning up test run directory from this run." + /bin/rm -rf ${TESTDIR} + echo "Cleaning up symlinks." + /bin/rm -f ${DATADIR} ${SCHEMADIR} + fi + + if [ $RC -ne 0 ]; then + if [ $LOOP -gt 1 ]; then + echo "Failed after $COUNTER of $LOOP iterations" + fi + exit $RC + else + COUNTER=`expr $COUNTER + 1` + if [ $COUNTER -le $LOOP ]; then + echo "Cleaning up test run directory from this run." + /bin/rm -rf ${TESTDIR} + fi + fi +done +exit $RC diff --git a/contrib/slapd-modules/emptyds/tests/scripts/all b/contrib/slapd-modules/emptyds/tests/scripts/all new file mode 100755 index 0000000..a5c1774 --- /dev/null +++ b/contrib/slapd-modules/emptyds/tests/scripts/all @@ -0,0 +1,92 @@ +#! /bin/sh +# $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 1998-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. + +. $SRCDIR/scripts/defines.sh + +TB="" TN="" +if test -t 1 ; then + TB=`$SHTOOL echo -e "%B" 2>/dev/null` + TN=`$SHTOOL echo -e "%b" 2>/dev/null` +fi + +FAILCOUNT=0 +SKIPCOUNT=0 +SLEEPTIME=10 + +echo ">>>>> Executing all LDAP tests for $BACKEND" + +if [ -n "$NOEXIT" ]; then + echo "Result Test" > $TESTWD/results +fi + +for CMD in ${SCRIPTDIR}/test*; do + case "$CMD" in + *~) continue;; + *.bak) continue;; + *.orig) continue;; + *.sav) continue;; + *) test -f "$CMD" || continue;; + esac + + # remove cruft from prior test + if test $PRESERVE = yes ; then + /bin/rm -rf $TESTDIR/db.* + else + /bin/rm -rf $TESTDIR + fi + + 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/emptyds/tests/scripts/test001-emptyds b/contrib/slapd-modules/emptyds/tests/scripts/test001-emptyds new file mode 100755 index 0000000..b8d715a --- /dev/null +++ b/contrib/slapd-modules/emptyds/tests/scripts/test001-emptyds @@ -0,0 +1,137 @@ +#! /bin/sh +# $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 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 2019 by Tamim Ziai for DAASI International + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +LDIF=${TOPDIR}/tests/data/test001.out + +if test $ACCESSLOG = accesslogno; then + echo "Accesslog overlay not available, test skipped" + exit 0 +fi + +mkdir -p $TESTDIR $DBDIR1A $DBDIR1B + +. $CONFFILTER $BACKEND < "${TOPDIR}/tests/data/emptyds.conf" > $CONF1 + +echo "Running slapadd to build slapd database... " +$SLAPADD -f $CONF1 -l $LDIFORDERED +RC=$? +if test $RC != 0 ; then + echo "slapadd failed ($RC)!" + exit $RC +fi + +echo "Starting slapd on TCP/IP port $PORT1..." +$SLAPD -f $CONF1 -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 "Checking add/modify handling... " + +$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \ + > $TESTOUT -f "${TOPDIR}/tests/data/test001.ldif" +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Checking modrdn handling (should still fail with invalidDNSyntax)... " + +$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \ + >> $TESTOUT 2>&1 <<EOMOD +dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com +changetype: modrdn +newrdn: cn= +deleteoldrdn: 0 +EOMOD +RC=$? +case $RC in +34) + echo " ldapmodify failed ($RC)" + ;; +0) + echo " ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; +*) + echo " ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; +esac + +echo "Dumping accesslog..." + +$LDAPSEARCH -b "cn=log" -H $URI1 \ + 'objectClass=auditWriteObject' reqDN reqMod | \ + grep -v -e 'entryCSN' -e '\(create\|modify\)Timestamp' \ + -e '\(modifier\|creator\)sName' -e 'entryUUID' | \ + sed -e 's/reqStart=[^,]*,/reqStart=timestamp,/' \ + > $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +# Expectations: +# - all empty values for directoryString pruned +# - empty adds/deletes removed, empty replaces kept +# - remaining values keep the same order as submitted +# - other syntaxes (especially DNs) are kept intact +echo "Filtering ldapsearch results..." +$LDIFFILTER < $SEARCHOUT > $SEARCHFLT +$LDIFFILTER < $LDIF > $LDIFFLT + +echo "Comparing filter output..." +$CMP $LDIFFLT $SEARCHFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 |