diff options
Diffstat (limited to 'contrib/slapd-modules/variant')
41 files changed, 5078 insertions, 0 deletions
diff --git a/contrib/slapd-modules/variant/Makefile b/contrib/slapd-modules/variant/Makefile new file mode 100644 index 0000000..07effed --- /dev/null +++ b/contrib/slapd-modules/variant/Makefile @@ -0,0 +1,77 @@ +# $OpenLDAP$ +# This work is part of OpenLDAP Software <http://www.openldap.org/>. +# +# Copyright 1998-2022 The OpenLDAP Foundation. +# Copyright 2017 Ondřej Kuzník, Symas Corp. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted only as authorized by the OpenLDAP +# Public License. +# +# A copy of this license is available in the file LICENSE in the +# top-level directory of the distribution or, alternatively, at +# <http://www.OpenLDAP.org/license.html>. + +LDAP_SRC = ../../.. +LDAP_BUILD = $(LDAP_SRC) +SRCDIR = ./ +LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd +LDAP_LIB = $(LDAP_BUILD)/libraries/libldap/libldap.la \ + $(LDAP_BUILD)/libraries/liblber/liblber.la + +LIBTOOL = $(LDAP_BUILD)/libtool +INSTALL = /usr/bin/install +CC = gcc +OPT = -g -O2 +DEFS = -DSLAPD_OVER_VARIANT=SLAPD_MOD_DYNAMIC +INCS = $(LDAP_INC) +LIBS = $(LDAP_LIB) + +PROGRAMS = variant.la +MANPAGES = slapo-variant.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 $< + +variant.la: variant.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/variant/slapo-variant.5 b/contrib/slapd-modules/variant/slapo-variant.5 new file mode 100644 index 0000000..a480744 --- /dev/null +++ b/contrib/slapd-modules/variant/slapo-variant.5 @@ -0,0 +1,472 @@ +.TH SLAPO-VARIANT 5 "RELEASEDATE" "OpenLDAP" +.\" Copyright 2016-2017 Symas Corp. All Rights Reserved. +.\" Copying restrictions apply. See LICENSE. +.SH NAME +slapo\-variant \- share values between entries +.SH SYNOPSIS +olcOverlay=variant +.SH DESCRIPTION +The +.B variant +overlay to +.BR slapd (8) +allows attributes/values to be shared between several entries. In some ways +this is similar to +.BR slapo-collect (5) +with the exception that the source and target attributes can be different. +.LP +The overlay operates on configured +.B variant +entries which can have several +.B attributes +each configured to borrow values from an attribute in the +.B alternate +entry. +.LP +Two types of +.B variant +entries can be configured, +.B regular +and +.BR regex , +where the latter are configured with a regular expression and patterns to +locate each alternate entry, with access to the variant DN and first nine +submatches captured by the regular expression. +.LP +For most purposes (see +.BR LIMITATIONS , +especially for +.B regex +variants), the resulting entry is completely transparent to the operations +performed on it, e.g. a modify operation on the +.B variant +attribute gets transformed +into an operation on the +.B alternate +entry+attribute. As such, the usual ACL rules apply, appropriate +access to both the +.B variant +and +.B alternate +entry is checked. +.LP +As a special case, +.B Add +and +.B Delete +operations will not affect the +.B alternate +entries. Should an attempt be made to add a configured +.B variant +entry with the +.B variant +attributes already populated, the operation will be rejected with a +.B Constraint +.BR Violation . + +.SH CONFIGURATION LAYOUT + +The overlay has to be instantiated under a database adding an entry of +.B olcOverlay=variant +with objectClass of +.BR olcVariantConfig . + +The overlay configuration subtree consists of the following levels: +.RS +.TP +.B objectClass=olcVariantConfig +Main overlay configuration. Created directly under the database +configuration entry. +.TP +.B objectClass=olcVariantVariant +Specifies a +.B regular variant +entry and must be a child of an entry with +.BR objectClass=olcVariantConfig . +There may be as many such entries as necessary provided they all specify a +different DN in the +.BR olcVariantEntry +attribute. +.TP +.B objectClass=olcVariantAttribute +Specifies a +.B regular variant +attribute together with information where the +.B alternate +attribute is stored. Must be a child of an entry with +.BR objectClass=olcVariantVariant . +There may be as many such entries as necessary provided they all specify a +different attribute in +.BR olcVariantVariantAttribute . +.TP +.B objectClass=olcVariantRegex +Specifies a +.B regex variant +entry and must be a child of an entry with +.BR objectClass=olcVariantConfig . +There may be as many such entries as necessary provided they all specify a +different DN in the +.BR olcVariantEntryRegex +attribute. +.TP +.B objectClass=olcVariantAttributePattern +Specifies a +.B regex variant +attribute together with information where the +.B alternate +attribute is stored. Must be a child of an entry with +.BR objectClass=olcVariantRegex . +There may be as many such entries as necessary provided they all specify a +different attribute in +.BR olcVariantVariantAttribute . +.RE + +In the case of +.BR slapd.conf (5), +the variant definition is delimited by the keyword +.B variantDN +followed by an arbitrary number of +.B variantSpec +providing the attribute definitions following it. Each new +.B variantDN +line starts configuring a new variant. + +.SH OVERLAY CONFIGURATION ENTRY + +The top entry +.RB ( olcVariantConfig ) +has the following options available: + +.RS +.TP +.B olcVariantPassReplication: TRUE | FALSE +If set to +.BR TRUE , +.B search +operations with the +.B SyncReplication +control will be passed unchanged so that replication can be unaffected. +Defaults to +.B FALSE +while unset. The +.BR slapd.conf (5) +equivalent is +.BR passReplication . +.RE + +.SH VARIANT CONFIGURATION ENTRY + +The +.B regular variant entry +configuration +.RB ( olcVariantVariant ) +has the following options available: + +.RS +.TP +.B olcVariantEntry: <dn> +Mandatory attribute, indicates that the named entry is to be treated as a +.B variant +entry. The +.BR slapd.conf (5) +equivalent is +.BR variantDN . +.TP +.B name: <reference> +Name of the entry for reference, usually the attribute present in the +configuration entry's RDN. There is no +.BR slapd.conf (5) +equivalent as this has no effect on the overlay operation. +.RE + +Similarly, the +.B regex variant entry +configuration +.RB ( olcVariantRegex ) +has these options available: + +.RS +.TP +.B olcVariantRegex: <regex> +Mandatory attribute, indicates that the entries whose normalised DN matches is +to be treated as a +.B regex variant +entry. The (POSIX.2) regex can use submatches to capture parts of the DN for +later use in locating the +.B alternative +.BR entry . +The +.BR slapd.conf (5) +equivalent is +.BR variantRegex . +.TP +.B name: <reference> +Name of the entry for reference, usually the attribute present in the +configuration entry's RDN. There is no +.BR slapd.conf (5) +equivalent as this has no effect on the overlay operation. +.RE + +.SH CONFIGURATION PRECEDENCE + +While several +.B regex variants +can match the same entry, only one can apply at a time. The list of the +.B regular variants +is checked first. Should none match, the list of +.B regex variants +is checked in the order they have been configured using only the first one that +matches. + +.SH VARIANT ATTRIBUTE CONFIGURATION ENTRY + +The +.B regular variant +attribute configuration +.RB ( olcVariantAttribute ) +and +.B regex variant +attribute configuration +.RB ( olcVariantAttributePattern ) +have the following options available: + +.RS +.TP +.B name: <reference> +Name of the attribute configuration for reference and/or documentation, if +present, usually found in the configuration entry's RDN. There is no +.BR slapd.conf (5) +equivalent as this has no effect on the overlay operation. +.TP +.B olcVariantVariantAttribute: <attr> +Mandatory attribute, indicates that the named attribute is not present in +the +.B variant +entry but is to be retrieved from the +.B alternate +entry. +.TP +.B olcVariantAlternativeAttribute: <attr> +Mandatory attribute, indicates that the values of the named attribute is to +be retrieved from the +.B alternate +entry for use as the values of the +.B variant +attribute. The syntaxes of the corresponding +.B variant +and +.B alternate +attributes have to match or the configuration will be rejected. +.TP +.B olcVariantAlternativeEntry: <dn> +Attribute mandatory for +.B regular +.BR variants , +indicates the +.B alternate +entry to use when retrieving the attribute from. +.TP +.B olcVariantAlternativeEntryPattern: <pattern> +Attribute mandatory for +.B regex +.BR variants , +indicates the +.B alternate +entry to use when retrieving the attribute from. Substitution patterns +.RB ( $n ) +can be used to insert parts of the variant entry's DN. +.B $0 +will place the entire variant DN, +.B $1 +to +.B $9 +can be used to place respective capture patterns from the +.B variant +entry. +.TP +.B variantSpec <attr> <attr2> <dn> +.BR slapd.conf (5) +only. The equivalent to options above, where +.B <attr> +represents the +.BR olcVariantVariantAttribute , +.B <attr2> +represents the +.B olcVariantAlternativeAttribute +and +.B <dn> +has the same meaning as the content of +.BR olcVariantAlternativeEntry . +Has to follow a +.B variantDN +line in the overlay's configuration. +.TP +.B variantRegexSpec <attr> <attr2> <pattern> +.BR slapd.conf (5) +only. The equivalent to options above, where +.B <attr> +represents the +.BR olcVariantVariantAttribute , +.B <attr2> +represents the +.B olcVariantAlternativeAttribute +and +.B <pattern> +has the same meaning as the content of +.BR olcVariantAlternativeEntryPattern . +Has to follow a +.B variantRegex +line in the overlay's configuration. +.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}variant,$DATABASE +objectClass: olcVariantConfig +olcOverlay: variant +# Let replication requests pass through unmodified +olcVariantPassReplication: TRUE + +# when an operation considers dc=example,dc=com +dn: name=example,olcOverlay={x}variant,$DATABASE +objectClass: olcVariantVariant +olcVariantEntry: dc=example,dc=com + +# share the Headquarters' address as the company address +dn: olcVariantVariantAttribute=postaladdress,name={0}example,olcOverlay={x}variant,$DATABASE +objectClass: olcVariantVariantAttribute +olcVariantVariantAttribute: postaladdress +olcVariantAlternativeAttribute: postaladdress +olcVariantAlternativeEntry: ou=Headquarters,dc=example,dc=com + +# populate telephonenumber from CEO's home phone +dn: name=Take phone from CEO entry,name={0}example,olcOverlay={x}variant,$DATABASE +objectClass: olcVariantVariantAttribute +olcVariantVariantAttribute: telephonenumber +olcVariantAlternativeAttribute: homephone +olcVariantAlternativeEntry: cn=John Doe,ou=People,dc=example,dc=com + +# Match all entries with example in the DN +# +# It will not match dc=example,dc=com as that's already configured as a regular +# variant +dn: name=example 2,olcOverlay={x}variant,$DATABASE +objectClass: olcVariantRegex +olcVariantEntryRegex: .*example[^,]*,(.*) + +dn: olcVariantVariantAttribute=location,name={1}example 2,olcOverlay={x}variant,$DATABASE +objectClass: olcVariantAttributePattern +olcVariantVariantAttribute: location +olcVariantAlternativeAttribute: location +olcVariantAlternativeEntryPattern: ou=object with location,$1 +.fi + +The +.BR slapd.conf (5) +equivalent of the above follows (note that the converted +.B cn=config +will differ in the first variant attribute configuration entry): + +.nf +overlay variant +passReplication TRUE + +variantDN dc=example,dc=com +variantSpec telephonenumber homephone "cn=John Doe,ou=People,dc=example,dc=com" +variantSpec postaladdress postaladdress ou=Headquarters,dc=example,dc=com + +variantRegex .*example[^,]*,(.*) +variantRegexSpec location location "ou=object with location,$1" +.fi + +.SH REPLICATION + +There are two ways that a database with +.BR slapo-variant (5) +might be replicated, either replicating the data as stored in the database, +or as seen by the clients interacting with the server. + +The former can be achieved by setting the overlay option +.B olcVariantPassReplication +on the provider and configuring +.BR slapo-syncprov (5) +to appear before (with a lower index than) +.BR slapo-variant (5). +This is the preferred way and the only to work with +.B regex variants +or support multi-provider replication, +but care must be taken to configure +.BR slapo-variant (5) +correctly on each replica. + +The latter is mostly possible by keeping the option +.B olcVariantPassReplication +set to +.B FALSE +on the provider and configuring +.BR slapo-syncprov (5) +to appear after (with a higher index than) +.BR slapo-variant (5). +However, it will only really work for replication set-ups that do not +utilise +.B regex +.BR variants , +delta-replication nor the refresh and persist mode and is therefore +discouraged. + +.SH LIMITATIONS +For +.B regex +.BR variants , +the +.B Search +operation will only apply if the search scope is set to +.BR base . + +The +.B ModRDN +operation is not currently handled and will always modify only the entry in +question, not the configured +.B alternate +entry. + +The +.B Modify +operation is not atomic with respect to the alternate entries. Currently, +the overlay processes the operations on the entry, sends the result message +and, if successful, starts modifying the +.B alternate +entries accordingly. +There is currently no support to indicate whether modifications to the +.B alternate +entries have been successful or whether they have finished. + +The only control explicitly handled is the +.B SyncReplication +control if enabled through the +.B olcVariantPassReplication +setting, adding any controls to an operation that is handled by the overlay +might lead to unexpected behaviour and is therefore discouraged. + +.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 regex (7), +.BR slapd (8) +.SH ACKNOWLEDGEMENTS +This module was developed in 2016-2017 by Ondřej Kuzník for Symas Corp. diff --git a/contrib/slapd-modules/variant/tests/Rules.mk b/contrib/slapd-modules/variant/tests/Rules.mk new file mode 100644 index 0000000..c25c1d2 --- /dev/null +++ b/contrib/slapd-modules/variant/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/variant/tests/data/additional-config.ldif b/contrib/slapd-modules/variant/tests/data/additional-config.ldif new file mode 100644 index 0000000..6a286fe --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/additional-config.ldif @@ -0,0 +1,23 @@ +dn: name={4}test002,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantVariant +olcVariantEntry: cn=Gern Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com + +dn: name=attribute 1,name={4}test002,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantVariantAttribute: cn +olcVariantAlternativeAttribute: description +olcVariantAlternativeEntry: dc=example,dc=com + +dn: name=attribute 2,name={4}test002,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantVariantAttribute: pager +olcVariantAlternativeAttribute: telephonenumber +olcVariantAlternativeEntry: dc=example,dc=com + +dn: name={0}attribute 1,name={4}test002,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcVariantVariantAttribute +olcVariantVariantAttribute: description diff --git a/contrib/slapd-modules/variant/tests/data/config.ldif b/contrib/slapd-modules/variant/tests/data/config.ldif new file mode 100644 index 0000000..6e323b9 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/config.ldif @@ -0,0 +1,89 @@ +dn: olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectClass: olcOverlayConfig +objectclass: olcVariantConfig + +dn: olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcVariantPassReplication +olcVariantPassReplication: TRUE + +dn: name={0}variant,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantVariant +olcVariantEntry: ou=People,dc=example,dc=com + +# a basic variant +dn: olcVariantVariantAttribute=description,name={0}variant,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantAlternativeAttribute: description +olcVariantAlternativeEntry: dc=example,dc=com + +# a nonexistent alternate +dn: olcVariantVariantAttribute=seealso,name={0}variant,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantAlternativeAttribute: seealso +olcVariantAlternativeEntry: ou=Societies,dc=example,dc=com + +dn: name={1}variant,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantVariant +olcVariantEntry: ou=Groups,dc=example,dc=com + +# recursive retrieval is not done +dn: olcVariantVariantAttribute=description,name={1}variant,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantAlternativeAttribute: description +olcVariantAlternativeEntry: ou=People,dc=example,dc=com + +# a variant taking data from a different attribute (after the changes below) +dn: olcVariantVariantAttribute=st,name={1}variant,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantAlternativeAttribute: st +olcVariantAlternativeEntry: cn=Manager,dc=example,dc=com + +# configuration changes +dn: olcVariantVariantAttribute={1}st,name={1}variant,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcVariantAlternativeAttribute +olcVariantAlternativeAttribute: ou +- +replace: olcVariantAlternativeEntry +olcVariantAlternativeEntry: ou=Alumni Association,ou=People,dc=example,dc=com +- + +# a regex variant +dn: name={2}regex,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantRegex +olcVariantEntryRegex: (.*),(ou=.*technology.*)(,)dc=example,dc=com + +dn: olcVariantVariantAttribute=ou,name={2}regex,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttributePattern +olcVariantAlternativeAttribute: ou +olcVariantAlternativeEntryPattern: $2$3dc=example$3dc=com + +# Duplicate description into title +dn: olcVariantVariantAttribute=title,name={2}regex,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttributePattern +olcVariantAlternativeAttribute: description +olcVariantAlternativeEntryPattern: $0 + +# everything +dn: name={3}regex,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantRegex +olcVariantEntryRegex: .* + +dn: olcVariantVariantAttribute=l,name={3}regex,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttributePattern +olcVariantAlternativeAttribute: l +olcVariantAlternativeEntryPattern: dc=example,dc=com + diff --git a/contrib/slapd-modules/variant/tests/data/hidden.ldif b/contrib/slapd-modules/variant/tests/data/hidden.ldif new file mode 100644 index 0000000..d219746 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/hidden.ldif @@ -0,0 +1,4 @@ +dn: ou=Groups,dc=example,dc=com +changetype: modify +add: description +description: This is hidden by the overlay config diff --git a/contrib/slapd-modules/variant/tests/data/test001-01-same-dn.ldif b/contrib/slapd-modules/variant/tests/data/test001-01-same-dn.ldif new file mode 100644 index 0000000..880e035 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test001-01-same-dn.ldif @@ -0,0 +1,4 @@ +dn: name=variant,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantVariant +olcVariantEntry: ou=Groups,dc=example,dc=com diff --git a/contrib/slapd-modules/variant/tests/data/test001-01a-same-dn.ldif b/contrib/slapd-modules/variant/tests/data/test001-01a-same-dn.ldif new file mode 100644 index 0000000..0fb8b2b --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test001-01a-same-dn.ldif @@ -0,0 +1,4 @@ +dn: name={0}variant,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcVariantEntry +olcVariantEntry: ou=Groups,dc=example,dc=com diff --git a/contrib/slapd-modules/variant/tests/data/test001-02-same-attribute.ldif b/contrib/slapd-modules/variant/tests/data/test001-02-same-attribute.ldif new file mode 100644 index 0000000..8447018 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test001-02-same-attribute.ldif @@ -0,0 +1,6 @@ +dn: olcVariantAlternativeAttribute=description,name={1}variant,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantVariantAttribute: description +olcVariantAlternativeAttribute: description +olcVariantAlternativeEntry: ou=People,dc=example,dc=com diff --git a/contrib/slapd-modules/variant/tests/data/test001-03-different-types.ldif b/contrib/slapd-modules/variant/tests/data/test001-03-different-types.ldif new file mode 100644 index 0000000..dfbde5b --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test001-03-different-types.ldif @@ -0,0 +1,4 @@ +dn: olcVariantVariantAttribute={1}st,name={1}variant,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: modify +replace: olcVariantAlternativeAttribute +olcVariantAlternativeAttribute: userPassword diff --git a/contrib/slapd-modules/variant/tests/data/test002-01-entry.ldif b/contrib/slapd-modules/variant/tests/data/test002-01-entry.ldif new file mode 100644 index 0000000..21b5b14 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test002-01-entry.ldif @@ -0,0 +1,16 @@ +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 +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 diff --git a/contrib/slapd-modules/variant/tests/data/test002-02-regex.ldif b/contrib/slapd-modules/variant/tests/data/test002-02-regex.ldif new file mode 100644 index 0000000..8f0f439 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test002-02-regex.ldif @@ -0,0 +1,7 @@ +dn: cn=Rosco P. Coltrane, ou=Information Technology Division, ou=People, dc=example,dc=com +changetype: add +objectclass: OpenLDAPperson +cn: Rosco P. Coltrane +sn: Coltrane +uid: rosco +title: Chief Investigator, ITD diff --git a/contrib/slapd-modules/variant/tests/data/test003-out.ldif b/contrib/slapd-modules/variant/tests/data/test003-out.ldif new file mode 100644 index 0000000..1c3ca5d --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test003-out.ldif @@ -0,0 +1,124 @@ +# Test 1, list two unrelated entries +dn: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +cn: Mark Elliot +cn: Mark A Elliot +sn: Elliot +uid: melliot +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 199 Outer Drive $ Ypsilanti, MI 48198 +homePhone: +1 313 555 0388 +drink: Gasoline +title: Director, UM Alumni Association +mail: melliot@mail.alumni.example.com +pager: +1 313 555 7671 +facsimileTelephoneNumber: +1 313 555 7762 +telephoneNumber: +1 313 555 4177 + +dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc + =com +objectClass: OpenLDAPperson +cn: Bjorn Jensen +cn: Biiff Jensen +sn: Jensen +uid: bjorn +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: Ympvcm4= +homePostalAddress: 19923 Seven Mile Rd. $ South Lyon, MI 49999 +drink: Iced Tea +description: Hiker, biker +title: Director, Embedded Systems +postalAddress: Info Tech Division $ 535 W. William St. $ Anytown, MI 48103 +mail: bjorn@mailgw.example.com +homePhone: +1 313 555 5444 +pager: +1 313 555 4474 +facsimileTelephoneNumber: +1 313 555 2177 +telephoneNumber: +1 313 555 0355 + + +# Test 2, list some of the variant entries, checking that attributes have been populated +dn: ou=Groups,dc=example,dc=com +objectClass: organizationalUnit +ou: Groups +st: Alumni Association + +dn: ou=People,dc=example,dc=com +objectClass: organizationalUnit +objectClass: extensibleObject +ou: People +uidNumber: 0 +gidNumber: 0 +description: The Example, Inc. at Anytown + +dn: cn=Manager,dc=example,dc=com +objectClass: person +cn: Manager +cn: Directory Manager +cn: Dir Man +sn: Manager +description: Manager of the directory +userPassword:: c2VjcmV0 + + +# Return $BASEDN, location is rewritten to end +dn: dc=example,dc=com +objectClass: top +objectClass: organization +objectClass: domainRelatedObject +objectClass: dcObject +dc: example +st: Michigan +o: Example, Inc. +o: EX +o: Ex. +description: The Example, Inc. at Anytown +postalAddress: Example, Inc. $ 535 W. William St. $ Anytown, MI 48109 $ US +telephoneNumber: +1 313 555 1817 +associatedDomain: example.com +l: Anytown, Michigan + + +# Make sure only the first regex applies +dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc + =com +objectClass: OpenLDAPperson +cn: Bjorn Jensen +cn: Biiff Jensen +sn: Jensen +uid: bjorn +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: Ympvcm4= +homePostalAddress: 19923 Seven Mile Rd. $ South Lyon, MI 49999 +drink: Iced Tea +description: Hiker, biker +postalAddress: Info Tech Division $ 535 W. William St. $ Anytown, MI 48103 +mail: bjorn@mailgw.example.com +homePhone: +1 313 555 5444 +pager: +1 313 555 4474 +facsimileTelephoneNumber: +1 313 555 2177 +telephoneNumber: +1 313 555 0355 +title: Hiker, biker +ou: Information Technology Division + + +# Exercise the last regex +dn: cn=ITD Staff,ou=Groups,dc=example,dc=com +owner: cn=Manager,dc=example,dc=com +description: All ITD Staff +cn: ITD Staff +objectClass: groupOfUniqueNames +uniqueMember: cn=Manager,dc=example,dc=com +uniqueMember: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc= + example,dc=com +uniqueMember: cn=James A Jones 2,ou=Information Technology Division,ou=People, + dc=example,dc=com +uniqueMember: cn=John Doe,ou=Information Technology Division,ou=People,dc=exam + ple,dc=com +l: Anytown, Michigan + + +# Test 3, check filters pick up the new data +dn: ou=Groups,dc=example,dc=com +st: Alumni Association + diff --git a/contrib/slapd-modules/variant/tests/data/test005-changes.ldif b/contrib/slapd-modules/variant/tests/data/test005-changes.ldif new file mode 100644 index 0000000..767f48a --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test005-changes.ldif @@ -0,0 +1,35 @@ +dn: ou=People,dc=example,dc=com +changetype: modify +add: description +description: Everyone's heard of them +- +increment: uidNumber +uidNumber: 1 +- + +dn: ou=Groups,dc=example,dc=com +changetype: modify +add: st +st: Alabama +- + +# check regex +dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc + =com +changetype: modify +replace: description +description: A mouthful +- +add: ou +ou: The IT Crowd +- + +# have the two mods merge +dn: dc=example,dc=com +changetype: modify +add: l +l: Locally +- +replace: st +st: Antarctica +- diff --git a/contrib/slapd-modules/variant/tests/data/test005-modify-missing.ldif b/contrib/slapd-modules/variant/tests/data/test005-modify-missing.ldif new file mode 100644 index 0000000..ce9c007 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test005-modify-missing.ldif @@ -0,0 +1,4 @@ +dn: cn=Gern Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com +changetype: modify +replace: description +description: Ghost diff --git a/contrib/slapd-modules/variant/tests/data/test005-out.ldif b/contrib/slapd-modules/variant/tests/data/test005-out.ldif new file mode 100644 index 0000000..67e441b --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test005-out.ldif @@ -0,0 +1,206 @@ +# Test1: list entries that should have been changed by ldapmodify +dn: dc=example,dc=com +objectclass: top +objectclass: organization +objectclass: domainRelatedObject +objectclass: dcobject +dc: example +l: Anytown, Michigan +l: Locally +o: Example, Inc. +o: EX +o: Ex. +description: The Example, Inc. at Anytown +description: Everyone's heard of them +postaladdress: Example, Inc. $ 535 W. William St. $ Anytown, MI 48109 $ US +telephonenumber: +1 313 555 1817 +associateddomain: example.com +st: Antarctica + +dn: ou=People,dc=example,dc=com +objectclass: organizationalUnit +objectclass: extensibleObject +ou: People +uidNumber: 1 +gidNumber: 0 +description: The Example, Inc. at Anytown +description: Everyone's heard of them + +dn: ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: organizationalUnit +ou: Alumni Association +ou: Alabama + +dn: ou=Groups,dc=example,dc=com +objectClass: organizationalUnit +ou: Groups +st: alumni association +st: alabama + +dn: ou=Information Technology Division,ou=People,dc=example,dc=com +objectClass: organizationalUnit +ou: Information Technology Division +ou: The IT Crowd +description:: aMODwoPDgsKCw4PCgsOCwotFVlZQw4PCg8OCwoPDg8KCw4LCv0zDg8KDw4LCgsOD + woLDgsKKT8ODwoPDgsKDw4PCgsOCwqs6w4PCg8OCwoLDg8KCw4LCjUQkw4PCg8OCwoLDg8KCw4LCi + 01QUcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4 + LCgsODwoLDgsKLRCQoZitEJMODwoPDgsKCw4PCgsOCwrfDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoP + Dg8KCw4LCgcODwoPDgsKDw4PCgsOCwqHDg8KDw4LCgsODwoLDgsKLRCQkZitEJMODwoPDgsKCw4PC + gsOCwrfDg8KDw4LCg8ODwoLDgsKQw4PCg8OCwoPDg8KCw4LCisODwoPDgsKCw4PCgsOCwotFUVZqU + MODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKAw4PCg8OCwoLDg8KCw4LCik85dCTDg8KDw4 + LCgsODwoLDgsKFQ8ODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4L + Cvzl0JMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPD + gsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKLRCTDg8KDw4LCgsODwoLDgsKDw4PCg8OCwoLDg8KCw + 4LCuMODwoPDgsKDw4PCgsOCwoR0Q8ODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LChMODwo + PDgsKDw4PCgsOCwoFOdTrDg8KDw4LCg8ODwoLDgsKHw4PCg8OCwoPDg8KCw4LChMODwoPDgsKDw4P + CgsOCwoFOw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwrtHw4PCg8OCwoLDg8KCw4LChcOD + woPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsK4dMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODw + oLDgsKtR8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwo + PDgsKDw4PCgsOCwr9SfGrDg8KDw4LCgsODwoLDgsKLQGgxw4PCg8OCwoPDg8KCw4LCoWhQw4PCg8O + CwoPDg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKT8ODwoPDgsKCw4PCgsOC + wotEJDDDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHTDg8KDw4LCgsODwoLDgsKDw4PCg + 8OCwoPDg8KCw4LCuHXDg8KDw4LCgsODwoLDgsKLRCRqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4 + PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpPDg8K + Dw4LCg8ODwoLDgsKQXV9eW8ODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoPD + g8KCw4LCgsODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODw + oPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgs + OCwoxWV8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKxw4PCg8OCwoLDg8KCw4LCi3wkw4P + Cg8OCwoLDg8KCw4LCjcODwoPDgsKCw4PCgsOCwofDg8KDw4LCg8ODwoLDgsKof8ODwoPDgsKDw4PC + gsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCg8ODwoPDgsKDw4PCgsOCwrh5w4PCg + 8OCwoLDg8KCw4LChzQzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PCgsOCworDg8KDw4LCgsODwo + LDgsKIw4PCg8OCwoLDg8KCw4LCuDFBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNdDF + Bw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPD + gsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw + 4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgs + KCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKAdcODwoPDgsKDw4PCgsOCwqhtw4PCg8OCwoLDg8KCw4L + ChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCsMODwoPDgsKC + w4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCt + sODwoPDgsKDw4PCgsOCwq7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4 + PCgsOCwoPDg8KDw4LCg8ODwoLDgsKoZsODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4w4P + Cg8OCwoLDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwpUzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PC + gsOCworDg8KDw4LCgsODwoLDgsKISDJBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNN + DJBw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwo + PDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8O + DwoPDgsKDw4PCgsOCwojDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCnEzDg8KDw4LCgsOD + woLDgsKLSEBmw4PCg8OCwoLDg8KCw4LCg3lwdSTDg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw + 4LCv8ODwoPDgsKCw4PCgsOCwobDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgs + KCw4PCgsOCwp/Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwoj + Dg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCwpPDg8KDw4LCgsOD + woLDgsKBw4PCg8OCwoPDg8KCw4LCv1rDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODw + oPDgsKCw4PCgsOCwodqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwoBqaMODwoPDgsKCw4 + PCgsOCwpBQw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDIMODwoPDgsKCw4PCgsOCwopPw4PCg8OCwoL + Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKOacODwoPDgsKCw4PCgsOCwrhf + XsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCw + oLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKGw4PCg8OCwoLDg8KCw4LCgM + ODwoPDgsKCw4PCgsOCwoRJw4PCg8OCwoLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsO + DwoLDgsKIw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQ9w4PCg8OCwoLDg8KCw4LCgcOD + woPDgsKDw4PCgsOCwr9aw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQxw4PCg8OCwoLDg + 8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LCm0 + 7Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsK + Cw4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD + gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODw + oPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgs + OCwo7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCkMODwoPDgsKDw4PCgsOCwojDg8KDw4L + CgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsK+ + S8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKww4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDw + 4PCgsOCwoTDg8KDw4LCgsODwoLDgsKKT1DDg8KDw4LCg8ODwoLDgsKoRsODwoPDgsKCw4PCgsOCwo + vDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwrZ0Y8ODwoPDgsK + Cw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/dF/Dg8KDw4LCgsODwoLDgsKhdHpPw4PCg8OCwoLDg8KC + w4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PCg8OCwoPDg8KCw4LCqC1Jw4PCg8OCwoLDg8KCw4LChcODw + oPDgsKDw4PCgsOCwoB1RMODwoPDgsKCw4PCgsOCwqFwek/Dg8KDw4LCgsODwoLDgsKLw4PCg8OCwo + PDg8KCw4LCj1DDg8KDw4LCg8ODwoLDgsKoScODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK + AdTPDg8KDw4LCgsODwoLDgsKhbHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PC + g8OCwoPDg8KCw4LCqEnDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHXDg8KDw4LCgsODw + oLDgsKhaHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo9Qw4PCg8OCwoPDg8KCw4LCqM + ODwoPDgsKDw4PCgsOCwrpIw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoB1M8ODwoPDgsK + Dw4PCgsOCwoBfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD + gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgjPDg8KDw4LCg8ODwoLDgsKAX17Dg + 8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCg8ODwo + LDgsKoJ8ODwoPDgsKDw4PCgsOCwq3Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoP + DgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4aHU5w4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PC + gsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw + 4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgs + KIw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpLDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoL + Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoB0IcODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKA + w4PCg8OCwoPDg8KCw4LCtMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKAdGbDg8KDw4LCg + sODwoLDgsKLQGY9dGY9dTPDg8KDw4LCg8ODwoLDgsKAX17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwo + LDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPDgsKDw4PCgsO + CwoIzw4PCg8OCwoPDg8KCw4LCgF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwovDg8KD + w4LCg8ODwoLDgsK/Ri9BUC9BRi9BWi9BZC9BWzBBZC9BZTBBZC9BZC9BbzBBZC9BeTBBw4PCg8OCw + oLDg8KCw4LCgzBBMUFhMUFrMUE= +description:: UF7Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOC + wozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg + 8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCqFDDg8KDw4LCg8ODwoLDgsKpRsODwoPDgsKDw4PCgsOCwo + zDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8O + DwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKCw4PCgsOCwotEJCDDg8KDw4LCgsODwoLDgsKD + w4PCg8OCwoPDg8KCw4LCrMODwoPDgsKCw4PCgsOCwotUJCRTw4PCg8OCwoLDg8KCw4LCi1wkJFbDg + 8KDw4LCgsODwoLDgsKJTCRXVVBSU8ODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsKdT8ODwo + PDgsKCw4PCgsOCwoN8JDB1w4PCg8OCwoPDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8O + DwoLDgsKBTsODwoPDgsKDw4PCgsOCwqktw4PCg8OCwoLDg8KCw4LCg3wkMHTDg8KDw4LCgsODwoLD + gsKDfCQww4PCg8OCwoLDg8KCw4LChTPDg8KDw4LCg8ODwoLDgsK2OTXDg8KDw4LCg8ODwoLDgsKAw + 4PCg8OCwoPDg8KCw4LCgU7Dg8KDw4LCgsODwoLDgsKEIMODwoPDgsKCw4PCgsOCwqFIw4PCg8OCwo + PDg8KCw4LChU7Dg8KDw4LCgsODwoLDgsKJNcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8ODwoLDgsK + BTsODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKD + w4PCgsOCwr9TXMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw + 4LChMODwoPDgsKCw4PCgsOCwpHDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLIEjDg8 + KDw4LCg8ODwoLDgsKFTlDDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ngw4PCg8OCwoL + Dg8KCw4LCi8ODwoPDgsKDw4PCgsOCwpjDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCm3Rx + w4PCg8OCwoLDg8KCw4LCizvDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi8ODwoPDgsKDw + 4PCgsOCwr9XaMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGdGLDg8KDw4LCgsODwo + LDgsKLf2zDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi1D + Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8OD + woLDgsKow4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwq10SmgoT03Dg8KDw4LCgsODwoLDg + sKLw4PCg8OCwoPDg8KCw4LCjcODwoPDgsKDw4PCgsOCwqggTMODwoPDgsKCw4PCgsOCwoXDg8KDw4 + LCg8ODwoLDgsKAdDrDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLTSBQUcODwoPDgsK + Dw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKL + RCQoZitEJCDDg8KDw4LCgsODwoLDgsK3w4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwoHDg + 8KDw4LCg8ODwoLDgsKhw4PCg8OCwoLDg8KCw4LCi0QkJGYrRCTDg8KDw4LCgsODwoLDgsK3w4PCg8 + OCwoPDg8KCw4LCkMODwoPDgsKDw4PCgsOCworDg8KDw4LCgsODwoLDgsKLRSBRVmpQw4PCg8OCwoP + Dg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKTzl0JHXDg8KDw4LCgsODwoLD + gsKhOXQkw4PCg8OCwoLDg8KCw4LChW/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODw + oPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKhRMODwoPDgsKDw4PCgsOCwoVOw4PCg8OCwoLDg8 + KCw4LCi8ODwoPDgsKDw4PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ncw4P + Cg8OCwoLDg8KCw4LCiUQkw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsOD + woLDgsKEw4PCg8OCwoPDg8KCw4LCtjPDg8KDw4LCg8ODwoLDgsK2w4PCg8OCwoLDg8KCw4LCjUQkw + 4PCg8OCwoLDg8KCw4LCiyBEw4PCg8OCwoPDg8KCw4LChU5Qw4PCg8OCwoLDg8KCw4LCi8ODwoPDgs + KDw4PCgsOCwr9TYMODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4L + ChcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCkMODwoPDgsKC + w4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCj8ODwoPDgsKDw4PCgsOCwr9Ta + MODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw4LChMODwoPDgs + KCw4PCgsOCwr3Dg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4L + Cj1DDg8KDw4LCg8ODwoLDgsK/U2zDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCqMODwoPD + gsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKtw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCw + p9oMMODwoPDgsKDw4PCgsOCwolMw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4 + LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCq0vDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4L + CgMODwoPDgsKCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi0QkOcODwoPD + gsKCw4PCgsOCwrDDg8KDw4LCg8ODwoLDgsKEdEU5w4PCg8OCwoLDg8KCw4LCtTR0PcODwoPDgsKCw + 4PCgsOCwovDg8KDw4LCg8ODwoLDgsKNw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwo5Lw4 + PCg8OCwoLDg8KCw4LCi0AgUMODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKsw4PCg8OCwoL + Dg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHUow4PCg8OCwoLDg8KCw4LC + i8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCgsODwoLDgsKJw4PCg8OCwoLDg8KCw4LCtTTDg8KDw4LCg + 8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKDw4PCgsOCwrtWw4PCg8OCwoLDg8KCw4LCi8 + ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCnw== + + +dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc + =com +objectClass: OpenLDAPperson +cn: Bjorn Jensen +cn: Biiff Jensen +sn: Jensen +uid: bjorn +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: Ympvcm4= +homePostalAddress: 19923 Seven Mile Rd. $ South Lyon, MI 49999 +drink: Iced Tea +description: Hiker, biker +postalAddress: Info Tech Division $ 535 W. William St. $ Anytown, MI 48103 +mail: bjorn@mailgw.example.com +homePhone: +1 313 555 5444 +pager: +1 313 555 4474 +facsimileTelephoneNumber: +1 313 555 2177 +telephoneNumber: +1 313 555 0355 +title: Hiker, biker +ou: Information Technology Division +ou: The IT Crowd + diff --git a/contrib/slapd-modules/variant/tests/data/test005-variant-missing.ldif b/contrib/slapd-modules/variant/tests/data/test005-variant-missing.ldif new file mode 100644 index 0000000..54fd3a5 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test005-variant-missing.ldif @@ -0,0 +1,4 @@ +dn: ou=People,dc=example,dc=com +changetype: modify +replace: seealso +seealso: dc=example,dc=com diff --git a/contrib/slapd-modules/variant/tests/data/test006-config.ldif b/contrib/slapd-modules/variant/tests/data/test006-config.ldif new file mode 100644 index 0000000..c668134 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test006-config.ldif @@ -0,0 +1,61 @@ +dn: name={4}Mark,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantVariant +olcVariantEntry: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com + +dn: olcVariantVariantAttribute=description,name={4}Mark,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantAlternativeAttribute: cn +olcVariantAlternativeEntry: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com + +dn: name={5}Elliot,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantVariant +olcVariantEntry: sn=Elliot,ou=Add & Delete,dc=example,dc=com + +dn: olcVariantVariantAttribute=title,name={5}Elliot,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantAlternativeAttribute: cn +olcVariantAlternativeEntry: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com + +dn: olcVariantVariantAttribute=description,name={5}Elliot,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantAlternativeAttribute: description +olcVariantAlternativeEntry: cn=Added by Bjorn,ou=Add & Delete,dc=example,dc=com + +dn: name={6}Doe,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantVariant +olcVariantEntry: sn=Doe,ou=Add & Delete,dc=example,dc=com + +dn: olcVariantVariantAttribute=title,name={6}Doe,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantAlternativeAttribute: cn +olcVariantAlternativeEntry: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc=com + +dn: olcVariantVariantAttribute=description,name={6}Doe,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantAlternativeAttribute: description +olcVariantAlternativeEntry: cn=Added by Bjorn,ou=Add & Delete,dc=example,dc=com + +dn: name={7}Group,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantVariant +olcVariantEntry: cn=Group,ou=Add & Delete,dc=example,dc=com + +dn: olcVariantVariantAttribute=seeAlso,name={7}Group,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantAlternativeAttribute: member +olcVariantAlternativeEntry: cn=Alumni Assoc Staff,ou=Groups,dc=example,dc=com + +dn: olcVariantVariantAttribute=description,name={7}Group,olcOverlay={0}variant,olcDatabase={1}@BACKEND@,cn=config +changetype: add +objectclass: olcVariantAttribute +olcVariantAlternativeAttribute: description +olcVariantAlternativeEntry: cn=Alumni Assoc Staff,ou=Groups,dc=example,dc=com diff --git a/contrib/slapd-modules/variant/tests/data/test006-out.ldif b/contrib/slapd-modules/variant/tests/data/test006-out.ldif new file mode 100644 index 0000000..03910c0 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test006-out.ldif @@ -0,0 +1,151 @@ +# reading Mark Elliot as anonymous + +# reading the same as various users +dn: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +cn: Mark A Elliot +sn: Elliot +uid: melliot +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 199 Outer Drive $ Ypsilanti, MI 48198 +homePhone: +1 313 555 0388 +drink: Gasoline +title: Director, UM Alumni Association +mail: melliot@mail.alumni.example.com +pager: +1 313 555 7671 +facsimileTelephoneNumber: +1 313 555 7762 +telephoneNumber: +1 313 555 4177 +description: Mark A Elliot + +dn: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com +objectClass: OpenLDAPperson +cn: Mark Elliot +sn: Elliot +uid: melliot +postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109 +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +homePostalAddress: 199 Outer Drive $ Ypsilanti, MI 48198 +homePhone: +1 313 555 0388 +drink: Gasoline +title: Director, UM Alumni Association +mail: melliot@mail.alumni.example.com +pager: +1 313 555 7671 +facsimileTelephoneNumber: +1 313 555 7762 +telephoneNumber: +1 313 555 4177 +description: Mark Elliot + + +# Add & Delete subtree contents as seen by Babs +dn: ou=Add & Delete,dc=example,dc=com +objectClass: organizationalUnit +ou: Add & Delete + +dn: sn=Doe,ou=Add & Delete,dc=example,dc=com +objectClass: OpenLDAPperson +cn: John +uid: jd +sn: Doe +title: John Doe + +dn: sn=Elliot,ou=Add & Delete,dc=example,dc=com +objectClass: OpenLDAPperson +cn: Mark +uid: me +sn: Elliot +title: Mark A Elliot + +dn: cn=group,ou=Add & Delete,dc=example,dc=com +objectClass: groupOfNames +member: dc=example,dc=com +cn: group +description: All Alumni Assoc Staff +seeAlso: cn=Manager,dc=example,dc=com +seeAlso: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com + + +# Add & Delete subtree contents as seen by Bjorn +dn: ou=Add & Delete,dc=example,dc=com +objectClass: organizationalUnit +ou: Add & Delete + +dn: sn=Doe,ou=Add & Delete,dc=example,dc=com +objectClass: OpenLDAPperson +cn: John +uid: jd +sn: Doe +title: Jonathon Doe + +dn: sn=Elliot,ou=Add & Delete,dc=example,dc=com +objectClass: OpenLDAPperson +cn: Mark +uid: me +sn: Elliot +title: Mark Elliot + +dn: cn=group,ou=Add & Delete,dc=example,dc=com +objectClass: groupOfNames +member: dc=example,dc=com +cn: group +description: All Alumni Assoc Staff +seeAlso: cn=Manager,dc=example,dc=com +seeAlso: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com + + +# Final state of ou=Add & Delete,dc=example,dc=com as seen by the Manager +dn: ou=Add & Delete,dc=example,dc=com +objectClass: organizationalUnit +ou: Add & Delete + +dn: cn=Added by Bjorn,ou=Add & Delete,dc=example,dc=com +objectClass: inetOrgPerson +sn: Jensen +cn: Added by Bjorn +description: added by jaj (should succeed) + +dn: sn=Doe,ou=Add & Delete,dc=example,dc=com +objectClass: OpenLDAPperson +cn: John +uid: jd +sn: Doe +description: added by jaj (should succeed) +title: John Doe +title: Jonathon Doe + +dn: sn=Elliot,ou=Add & Delete,dc=example,dc=com +objectClass: OpenLDAPperson +cn: Mark +uid: me +sn: Elliot +description: added by jaj (should succeed) +title: Mark Elliot +title: Mark A Elliot + +dn: cn=group,ou=Add & Delete,dc=example,dc=com +objectClass: groupOfNames +member: dc=example,dc=com +cn: group +description: All Alumni Assoc Staff +description: another one added by bjorn (should succeed) +seeAlso: cn=Manager,dc=example,dc=com +seeAlso: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com +seeAlso: cn=Bjorn Jensen,ou=Information Technology DivisioN,ou=People,dc=examp + le,dc=com +seeAlso: cn=Barbara Jensen,ou=Information Technology DivisioN,ou=People,dc=exa + mple,dc=com + diff --git a/contrib/slapd-modules/variant/tests/data/test007-out.ldif b/contrib/slapd-modules/variant/tests/data/test007-out.ldif new file mode 100644 index 0000000..cf1aac8 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test007-out.ldif @@ -0,0 +1,6 @@ +# Testing searches against attribute supertypes... +dn: ou=Groups,dc=example,dc=com +objectClass: organizationalUnit +ou: Groups +st: Alumni Association + diff --git a/contrib/slapd-modules/variant/tests/data/test010-out.ldif b/contrib/slapd-modules/variant/tests/data/test010-out.ldif new file mode 100644 index 0000000..28603e1 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test010-out.ldif @@ -0,0 +1,52 @@ +# Test 1, trigger sizelimit without overlay interference +dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc + =com +objectClass: OpenLDAPperson +cn: Bjorn Jensen +cn: Biiff Jensen +sn: Jensen +uid: bjorn +seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com +userPassword:: Ympvcm4= +homePostalAddress: 19923 Seven Mile Rd. $ South Lyon, MI 49999 +drink: Iced Tea +description: Hiker, biker +title: Director, Embedded Systems +postalAddress: Info Tech Division $ 535 W. William St. $ Anytown, MI 48103 +mail: bjorn@mailgw.example.com +homePhone: +1 313 555 5444 +pager: +1 313 555 4474 +facsimileTelephoneNumber: +1 313 555 2177 +telephoneNumber: +1 313 555 0355 +Size limit exceeded (4) + +# Test 2, check sizelimit is not triggered when it matches the number of entries returned +dn: ou=Groups,dc=example,dc=com +objectClass: organizationalUnit +ou: Groups +st: Alumni Association + +dn: ou=People,dc=example,dc=com +objectClass: organizationalUnit +objectClass: extensibleObject +ou: People +uidNumber: 0 +gidNumber: 0 +description: The Example, Inc. at Anytown + +dn: cn=Manager,dc=example,dc=com +objectClass: person +cn: Manager +cn: Directory Manager +cn: Dir Man +sn: Manager +description: Manager of the directory +userPassword:: c2VjcmV0 + +# Test 3, check sizelimit will stop at the right time +dn: ou=Groups,dc=example,dc=com +objectClass: organizationalUnit +ou: Groups +st: Alumni Association +Size limit exceeded (4) + diff --git a/contrib/slapd-modules/variant/tests/data/test011-out.ldif b/contrib/slapd-modules/variant/tests/data/test011-out.ldif new file mode 100644 index 0000000..07604f8 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test011-out.ldif @@ -0,0 +1,10 @@ +# ldapsearch does not return anything tangible in the output if it enounters a referral + +# Asking for the referral will return LDAP_REFERRAL +Referral (10) +Matched DN: cn=Gern Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com +Referral: ldap://hostB/cn=Gern%20Jensen,ou=Information%20Technology%20Division,ou=People,dc=example,dc=com??sub +# Asking for anything under a referral will do the same +Referral (10) +Matched DN: cn=Gern Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com +Referral: ldap://hostB/cn=child,cn=Gern%20Jensen,ou=Information%20Technology%20Division,ou=People,dc=example,dc=com??sub diff --git a/contrib/slapd-modules/variant/tests/data/test012-data.ldif b/contrib/slapd-modules/variant/tests/data/test012-data.ldif new file mode 100644 index 0000000..8b8d8b3 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test012-data.ldif @@ -0,0 +1,13 @@ +dn: dc=demonstration,dc=com +changetype: add +objectclass: organization +objectclass: domainRelatedObject +objectclass: dcobject +o: demo +associateddomain: demonstration.com + +dn: ou=Societies,dc=demonstration,dc=com +changetype: add +objectclass: organizationalUnit +ou: Societies +seealso: dc=example,dc=com diff --git a/contrib/slapd-modules/variant/tests/data/test012-out.ldif b/contrib/slapd-modules/variant/tests/data/test012-out.ldif new file mode 100644 index 0000000..bd31fa0 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/test012-out.ldif @@ -0,0 +1,9 @@ +dn: ou=People,dc=example,dc=com +objectClass: organizationalUnit +objectClass: extensibleObject +ou: People +uidNumber: 0 +gidNumber: 0 +seealso: dc=example,dc=com +description: The Example, Inc. at Anytown + diff --git a/contrib/slapd-modules/variant/tests/data/variant.conf b/contrib/slapd-modules/variant/tests/data/variant.conf new file mode 100644 index 0000000..dba6c46 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/data/variant.conf @@ -0,0 +1,17 @@ +overlay variant +passReplication TRUE + +variantDN ou=People,dc=example,dc=com +variantSpec seealso seealso ou=Societies,dc=example,dc=com +variantSpec description description dc=example,dc=com + +variantRegex "(.*),(ou=.*technology.*)(,)dc=example,dc=com" +variantRegexSpec title description $0 +variantRegexSpec ou ou "$2$3dc=example$3dc=com" + +variantDN ou=Groups,dc=example,dc=com +variantSpec st ou "ou=Alumni Association,ou=People,dc=example,dc=com" +variantSpec description description ou=People,dc=example,dc=com + +variantRegex .* +variantRegexSpec l l dc=example,dc=com diff --git a/contrib/slapd-modules/variant/tests/run b/contrib/slapd-modules/variant/tests/run new file mode 100755 index 0000000..6a38431 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/run @@ -0,0 +1,229 @@ +#!/bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 1998-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +USAGE="$0 [-b <backend>] [-c] [-k] [-l #] [-p] [-s {ro|rp}] [-u] [-w] <script>" + +TOPSRCDIR="${SRCDIR-$LDAP_SRC}" +SRCDIR="${TOPSRCDIR}/tests" +eval `grep EGREP_CMD= ${LDAP_BUILD}/tests/run` +eval `$EGREP_CMD -e '^LN_S=' ${LDAP_BUILD}/tests/run` + +export SRCDIR TOPSRCDIR LN_S EGREP_CMD + +. "${SRCDIR}/scripts/defines.sh" + +BACKEND= +CLEAN=no +WAIT=0 +KILLSERVERS=yes +PRESERVE=${PRESERVE-no} +SYNCMODE=${SYNCMODE-rp} +USERDATA=no +LOOP=1 +COUNTER=1 + +while test $# -gt 0 ; do + case "$1" in + -b | -backend) + BACKEND="$2" + shift; shift ;; + + -c | -clean) + CLEAN=yes + shift ;; + + -k | -kill) + KILLSERVERS=no + shift ;; + -l | -loop) + NUM="`echo $2 | sed 's/[0-9]//g'`" + if [ -z "$NUM" ]; then + LOOP=$2 + else + echo "Loop variable not an int: $2" + echo "$USAGE"; exit 1 + fi + shift ; + shift ;; + + -p | -preserve) + PRESERVE=yes + shift ;; + + -s | -syncmode) + case "$2" in + ro | rp) + SYNCMODE="$2" + ;; + *) + echo "unknown sync mode $2" + echo "$USAGE"; exit 1 + ;; + esac + shift; shift ;; + + -u | -userdata) + USERDATA=yes + shift ;; + + -w | -wait) + WAIT=1 + shift ;; + + -) + shift + break ;; + + -*) + echo "$USAGE"; exit 1 + ;; + + *) + break ;; + esac +done + +eval `$EGREP_CMD -e '^AC' ${LDAP_BUILD}/tests/run` +export `$EGREP_CMD -e '^AC' ${LDAP_BUILD}/tests/run | sed 's/=.*//'` + +if test -z "$BACKEND" ; then + for b in mdb ; do + if eval "test \"\$AC_$b\" != no" ; then + BACKEND=$b + break + fi + done + if test -z "$BACKEND" ; then + echo "No suitable default database backend configured" >&2 + exit 1 + fi +fi + +BACKENDTYPE=`eval 'echo $AC_'$BACKEND` +if test "x$BACKENDTYPE" = "x" ; then + BACKENDTYPE="unknown" +fi + +# Backend features. indexdb: indexing and unchecked limit. +# maindb: main storage backend. Currently index,limits,mode,paged results. +INDEXDB=noindexdb MAINDB=nomaindb +case $BACKEND in + mdb) INDEXDB=indexdb MAINDB=maindb ;; + ndb) INDEXDB=indexdb ;; +esac + +export BACKEND BACKENDTYPE INDEXDB MAINDB \ + WAIT KILLSERVERS PRESERVE SYNCMODE USERDATA \ + SRCDIR + +if test $# = 0 ; then + echo "$USAGE"; exit 1 +fi + +# need defines.sh for the definitions of the directories +. $SRCDIR/scripts/defines.sh + +SCRIPTDIR="${TOPDIR}/tests/scripts" + +export SCRIPTDIR + +SCRIPTNAME="$1" +shift + +if test -x "${SCRIPTDIR}/${SCRIPTNAME}" ; then + SCRIPT="${SCRIPTDIR}/${SCRIPTNAME}" +elif test -x "`echo ${SCRIPTDIR}/test*-${SCRIPTNAME}`"; then + SCRIPT="`echo ${SCRIPTDIR}/test*-${SCRIPTNAME}`" +elif test -x "`echo ${SCRIPTDIR}/${SCRIPTNAME}-*`"; then + SCRIPT="`echo ${SCRIPTDIR}/${SCRIPTNAME}-*`" +else + echo "run: ${SCRIPTNAME} not found (or not executable)" + exit 1; +fi + +if test ! -r ${DATADIR}/test.ldif ; then + ${LN_S} ${SRCDIR}/data ${DATADIR} +fi +if test ! -r ${SCHEMADIR}/core.schema ; then + ${LN_S} ${TOPSRCDIR}/servers/slapd/schema ${SCHEMADIR} +fi +if test ! -r ./data; then + ${LN_S} ${TOPDIR}/tests/data ./ +fi + +if test -d ${TESTDIR} ; then + if test $PRESERVE = no ; then + echo "Cleaning up test run directory leftover from previous run." + /bin/rm -rf ${TESTDIR} + elif test $PRESERVE = yes ; then + echo "Cleaning up only database directories leftover from previous run." + /bin/rm -rf ${TESTDIR}/db.* + fi +fi +if test $BACKEND = ndb ; then + mysql --user root <<EOF + drop database if exists db_1; + drop database if exists db_2; + drop database if exists db_3; + drop database if exists db_4; + drop database if exists db_5; + drop database if exists db_6; +EOF +fi +mkdir -p ${TESTDIR} + +if test $USERDATA = yes ; then + if test ! -d userdata ; then + echo "User data directory (userdata) does not exist." + exit 1 + fi + cp -R userdata/* ${TESTDIR} +fi + +# disable LDAP initialization +LDAPNOINIT=true; export LDAPNOINIT + +echo "Running ${SCRIPT} for ${BACKEND}..." +while [ $COUNTER -le $LOOP ]; do + if [ $LOOP -gt 1 ]; then + echo "Running $COUNTER of $LOOP iterations" + fi + $SCRIPT $* + RC=$? + + if test $CLEAN = yes ; then + echo "Cleaning up test run directory from this run." + /bin/rm -rf ${TESTDIR} + echo "Cleaning up symlinks." + /bin/rm -f ${DATADIR} ${SCHEMADIR} + fi + + if [ $RC -ne 0 ]; then + if [ $LOOP -gt 1 ]; then + echo "Failed after $COUNTER of $LOOP iterations" + fi + exit $RC + else + COUNTER=`expr $COUNTER + 1` + if [ $COUNTER -le $LOOP ]; then + echo "Cleaning up test run directory from this run." + /bin/rm -rf ${TESTDIR} + fi + fi +done +exit $RC diff --git a/contrib/slapd-modules/variant/tests/scripts/all b/contrib/slapd-modules/variant/tests/scripts/all new file mode 100755 index 0000000..d6d6dc7 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/all @@ -0,0 +1,102 @@ +#! /bin/sh +# $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 1998-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. + +. $SRCDIR/scripts/defines.sh + +TB="" TN="" +if test -t 1 ; then + TB=`$SHTOOL echo -e "%B" 2>/dev/null` + TN=`$SHTOOL echo -e "%b" 2>/dev/null` +fi + +FAILCOUNT=0 +SKIPCOUNT=0 +SLEEPTIME=10 + +echo ">>>>> Executing all LDAP tests for $BACKEND" + +if [ -n "$NOEXIT" ]; then + echo "Result Test" > $TESTWD/results +fi + +for CMD in ${SCRIPTDIR}/test*; do + case "$CMD" in + *~) continue;; + *.bak) continue;; + *.orig) continue;; + *.sav) continue;; + *) test -f "$CMD" || continue;; + esac + + # remove cruft from prior test + if test $PRESERVE = yes ; then + /bin/rm -rf $TESTDIR/db.* + else + /bin/rm -rf $TESTDIR + fi + if test $BACKEND = ndb ; then + mysql --user root <<EOF + drop database if exists db_1; + drop database if exists db_2; + drop database if exists db_3; + drop database if exists db_4; + drop database if exists db_5; + drop database if exists db_6; +EOF + fi + + BCMD=`basename $CMD` + if [ -x "$CMD" ]; then + echo ">>>>> Starting ${TB}$BCMD${TN} for $BACKEND..." + $CMD + RC=$? + if test $RC -eq 0 ; then + echo ">>>>> $BCMD completed ${TB}OK${TN} for $BACKEND." + else + echo ">>>>> $BCMD ${TB}failed${TN} for $BACKEND" + FAILCOUNT=`expr $FAILCOUNT + 1` + + if [ -n "$NOEXIT" ]; then + echo "Continuing." + else + echo "(exit $RC)" + exit $RC + fi + fi + else + echo ">>>>> Skipping ${TB}$BCMD${TN} for $BACKEND." + SKIPCOUNT=`expr $SKIPCOUNT + 1` + RC="-" + fi + + if [ -n "$NOEXIT" ]; then + echo "$RC $BCMD" >> $TESTWD/results + fi + +# echo ">>>>> waiting $SLEEPTIME seconds for things to exit" +# sleep $SLEEPTIME + echo "" +done + +if [ -n "$NOEXIT" ]; then + if [ "$FAILCOUNT" -gt 0 ]; then + cat $TESTWD/results + echo "$FAILCOUNT tests for $BACKEND ${TB}failed${TN}. Please review the test log." + else + echo "All executed tests for $BACKEND ${TB}succeeded${TN}." + fi +fi + +echo "$SKIPCOUNT tests for $BACKEND were ${TB}skipped${TN}." diff --git a/contrib/slapd-modules/variant/tests/scripts/common.sh b/contrib/slapd-modules/variant/tests/scripts/common.sh new file mode 100755 index 0000000..3b155ad --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/common.sh @@ -0,0 +1,115 @@ +#! /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-2017 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 $LDIFORDERED +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 + +echo "Making a modification that will be hidden by the test config..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/hidden.ldif >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +$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`/../variant.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`/../variant.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 variant 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/variant/tests/scripts/test001-config b/contrib/slapd-modules/variant/tests/scripts/test001-config new file mode 100755 index 0000000..7a5559f --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test001-config @@ -0,0 +1,209 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Applying invalid changes to config (should fail)..." +for CHANGE in data/test001-*.ldif; do + echo "... $CHANGE" + . $CONFFILTER $BACKEND $MONITORDB < $CHANGE | \ + $LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 + RC=$? + case $RC in + 0) + echo "ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; + 80) + echo "ldapmodify failed ($RC)" + ;; + *) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; + esac +done + +# We run this search after the changes above and before restart so we can also +# check the reconfiguration attempts actually had no side effects +echo "Saving search output before server restart..." +echo "# search output from dynamically configured server..." >> $SERVER3OUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + >> $SERVER3OUT 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 ../variant.la' \ + -e '/database.*monitor/i\ +include data/variant.conf' \ + > $CONF2 +echo "database config" >>$CONF2 +echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF2 + +$SLAPADD -f $CONF2 -l $LDIFORDERED +$SLAPD -Tt -f $CONF2 -F $TESTDIR/conftest -d $LVL >> $LOG2 2>&1 +RC=$? +if test $RC != 0 ; then + echo "slaptest failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Starting slapd on TCP/IP port $PORT2..." +$SLAPD -F $TESTDIR/conftest -h $URI2 -d $LVL >> $LOG2 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}variant,olcDatabase={1}$BACKEND,cn=config" \ + >> $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..." >> $SERVER2OUT +$LDAPSEARCH -D cn=config -H $URI2 -y $CONFIGPWF \ + -b "olcOverlay={0}variant,olcDatabase={1}$BACKEND,cn=config" \ + >> $SERVER2OUT 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 a < $SERVER2OUT > $SERVER2FLT +echo "Filtering expected entries..." +$LDIFFILTER -s a < $SERVER1OUT > $SERVER1FLT +echo "Comparing filter output..." +$CMP $SERVER2FLT $SERVER1FLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +rm $SERVER1OUT $SERVER2OUT + +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..." >> $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 + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SERVER1OUT > $SERVER1FLT +$LDIFFILTER -s e < $SERVER2OUT > $SERVER2FLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $SERVER3OUT > $SERVER3FLT +echo "Comparing filter output..." +$CMP $SERVER3FLT $SERVER1FLT > $CMPOUT && \ +$CMP $SERVER3FLT $SERVER2FLT > $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/variant/tests/scripts/test002-add-delete b/contrib/slapd-modules/variant/tests/scripts/test002-add-delete new file mode 100755 index 0000000..bd316b2 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test002-add-delete @@ -0,0 +1,113 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Adding entry..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test002-01-entry.ldif >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Configuring entry as variant..." +. $CONFFILTER $BACKEND $MONITORDB < data/additional-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 "Removing entry..." +$LDAPDELETE -D $MANAGERDN -H $URI1 -w $PASSWD \ + "cn=Gern Jensen,ou=Information Technology Division,ou=People,$BASEDN" \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapdelete failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Adding entry again (should fail)..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test002-01-entry.ldif >> $TESTOUT 2>&1 +RC=$? +case $RC in +0) + echo "ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; +19) + echo "ldapmodify failed ($RC)" + ;; +*) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; +esac + +echo "Adding a regex entry (should fail)..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test002-02-regex.ldif >> $TESTOUT 2>&1 +RC=$? +case $RC in +0) + echo "ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; +19) + echo "ldapmodify failed ($RC)" + ;; +*) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; +esac + +echo "Adding entry with offending attributes removed..." +grep -v '^description:' data/test002-01-entry.ldif | \ +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/variant/tests/scripts/test003-search b/contrib/slapd-modules/variant/tests/scripts/test003-search new file mode 100755 index 0000000..2284ab7 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test003-search @@ -0,0 +1,113 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Testing searches against regular entries..." +echo "# Testing searches against regular entries..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + "(|(name=Elliot)(description=*hiker*))" \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches listing variants..." +echo >> $SEARCHOUT +echo "# Testing searches listing variants..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -s one -H $URI1 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -s base -H $URI1 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo >> $SEARCHOUT +$LDAPSEARCH -s base -H $URI1 \ + -b "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" \ + '(ou=Information Technology Division)' \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo >> $SEARCHOUT +$LDAPSEARCH -b "cn=ITD Staff,ou=Groups,$BASEDN" -s base -H $URI1 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches filtering on variants..." +echo >> $SEARCHOUT +echo "# Testing searches filtering on variants..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + "(st=Alumni Association)" st \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test003-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/variant/tests/scripts/test004-compare b/contrib/slapd-modules/variant/tests/scripts/test004-compare new file mode 100755 index 0000000..c87d347 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test004-compare @@ -0,0 +1,63 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Comparing a regular entry..." +$LDAPCOMPARE -H $URI1 \ + "cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN" \ + "cn:Mark Elliot" >> $TESTOUT 2>&1 +RC=$? +if test $RC != 6 && test $RC,$BACKEND != 5,null ; then + echo "ldapcompare failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +echo "Comparing a variant entry..." +$LDAPCOMPARE -H $URI1 \ + "ou=People,$BASEDN" \ + "description:The Example, Inc. at Anytown" >> $TESTOUT 2>&1 +RC=$? +if test $RC != 6 && test $RC,$BACKEND != 5,null ; then + echo "ldapcompare failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +echo "Comparing a regex entry..." +$LDAPCOMPARE -H $URI1 \ + "cn=Barbara Jensen,ou=Information Technology Division,ou=People,$BASEDN" \ + "ou:Information Technology Division" >> $TESTOUT 2>&1 +RC=$? +if test $RC != 6 && test $RC,$BACKEND != 5,null ; then + echo "ldapcompare failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/variant/tests/scripts/test005-modify b/contrib/slapd-modules/variant/tests/scripts/test005-modify new file mode 100755 index 0000000..4cbf289 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test005-modify @@ -0,0 +1,120 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Modifying entry..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test005-changes.ldif >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +# for now, overlay returns success just after the modifications to the main +# entry succeed, ignoring the rest should they fail +echo "Modifying a nonexistent variant of an existing entry..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test005-variant-missing.ldif >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Configuring nonexistent entry as variant..." +. $CONFFILTER $BACKEND $MONITORDB < data/additional-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 "Modifying an existing variant of above missing entry..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test005-modify-missing.ldif >> $TESTOUT 2>&1 +RC=$? +case $RC in +0) + echo "ldapmodify should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; +32) + echo "ldapmodify failed ($RC)" + ;; +*) + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; +esac + +echo "Reading affected entries back..." +echo "# Reading affected entries back..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + '(|(description=*heard*)(st=*)(ou=alabama)(ou=*IT*))' \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo >>$SEARCHOUT +$LDAPSEARCH -H $URI1 -s base \ + -b "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test005-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/variant/tests/scripts/test006-acl b/contrib/slapd-modules/variant/tests/scripts/test006-acl new file mode 100755 index 0000000..6b34fb8 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test006-acl @@ -0,0 +1,323 @@ +#! /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. + +case "$BACKEND" in ldif | null) + echo "$BACKEND backend does not support access controls, test skipped" + exit 0 +esac + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +CONF=$ACLCONF +. ${SCRIPTDIR}/common.sh + +echo "Applying test-specific configuration..." +. $CONFFILTER $BACKEND $MONITORDB < data/test006-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 + +$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \ + $TESTOUT 2>&1 << EOMODS +dn: ou=Add & Delete,dc=example,dc=com +changetype: add +objectClass: organizationalUnit +ou: Add & Delete + +dn: cn=group,ou=Add & Delete,dc=example,dc=com +changetype: add +objectclass: groupOfNames +member: dc=example,dc=com + +dn: sn=Doe,ou=Add & Delete,dc=example,dc=com +changetype: add +objectclass: OpenLDAPperson +cn: John +uid: jd + +dn: sn=Elliot,ou=Add & Delete,dc=example,dc=com +changetype: add +objectclass: OpenLDAPperson +cn: Mark +uid: me +EOMODS +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing search ACL processing..." + +echo "# Try to read an entry inside the Alumni Association container. +# It should give us noSuchObject if we're not bound..." \ +>> $SEARCHOUT +# FIXME: temporarily remove the "No such object" message to make +# the test succeed even if SLAP_ACL_HONOR_DISCLOSE is not #define'd +$LDAPSEARCH -b "$MELLIOTDN" -H $URI1 "(objectclass=*)" \ + 2>&1 | grep -v "No such object" >> $SEARCHOUT + +echo >>$SEARCHOUT +echo "# ... and should return appropriate attributes if we're bound as anyone +# under Example." \ +>> $SEARCHOUT +$LDAPSEARCH -b "$MELLIOTDN" -H $URI1 \ + -D "$BABSDN" -w bjensen "(objectclass=*)" >> $SEARCHOUT 2>&1 + +$LDAPSEARCH -b "$MELLIOTDN" -H $URI1 \ + -D "$BJORNSDN" -w bjorn "(objectclass=*)" >> $SEARCHOUT 2>&1 + +echo >>$SEARCHOUT +echo "# Add & Delete subtree contents as seen by Babs" >> $SEARCHOUT +$LDAPSEARCH -b "ou=Add & Delete,dc=example,dc=com" -H $URI1 \ + -D "$BABSDN" -w bjensen "(objectclass=*)" >> $SEARCHOUT 2>&1 + +echo >>$SEARCHOUT +echo "# Add & Delete subtree contents as seen by Bjorn" >> $SEARCHOUT +$LDAPSEARCH -b "ou=Add & Delete,dc=example,dc=com" -H $URI1 \ + -D "$BJORNSDN" -w bjorn "(objectclass=*)" >> $SEARCHOUT 2>&1 + +echo "Testing modifications..." +echo "... ACL on the alternative entry" +$LDAPMODIFY -D "$BJORNSDN" -H $URI1 -w bjorn >> \ + $TESTOUT 2>&1 << EOMODS +dn: cn=group,ou=Add & Delete,dc=example,dc=com +changetype: modify +add: seealso +seealso: $BJORNSDN +EOMODS +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +$LDAPMODIFY -D "$BABSDN" -H $URI1 -w bjensen >> \ + $TESTOUT 2>&1 << EOMODS +dn: cn=Alumni Assoc Staff, ou=Groups, dc=example, dc=com +changetype: modify +add: description +description: added by bjensen (should fail) +EOMODS +RC=$? +case $RC in +50) + ;; +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 + +$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \ + $TESTOUT 2>&1 << EOMODS +dn: cn=group,ou=Add & Delete,dc=example,dc=com +changetype: modify +add: seealso +seealso: $BABSDN +EOMODS +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +$LDAPMODIFY -D "$BJORNSDN" -H $URI1 -w bjorn >> \ + $TESTOUT 2>&1 << EOMODS +dn: cn=Alumni Assoc Staff, ou=Groups, dc=example, dc=com +changetype: modify +add: description +description: added by bjorn (removed later) +EOMODS +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +$LDAPMODIFY -D "$BABSDN" -H $URI1 -w bjensen >> \ + $TESTOUT 2>&1 << EOMODS +dn: cn=Group,ou=Add & Delete,dc=example,dc=com +changetype: modify +delete: description +description: added by bjorn (removed later) +EOMODS +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +$LDAPMODIFY -D "$BJORNSDN" -H $URI1 -w bjorn >> \ + $TESTOUT 2>&1 << EOMODS +dn: cn=Added by Bjorn,ou=Add & Delete,dc=example,dc=com +changetype: add +objectClass: inetOrgPerson +sn: Jensen +EOMODS +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +$LDAPMODIFY -D "$BJORNSDN" -H $URI1 -w bjorn >> \ + $TESTOUT 2>&1 << EOMODS +dn: cn=Group,ou=Add & Delete,dc=example,dc=com +changetype: modify +add: description +description: another one added by bjorn (should succeed) +EOMODS +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "... ACL on the variant entry" +$LDAPMODIFY -D "$BABSDN" -H $URI1 -w bjensen >> \ + $TESTOUT 2>&1 << EOMODS +dn: cn=Group,ou=Add & Delete,dc=example,dc=com +changetype: modify +add: description +description: added by bjensen (should fail) +EOMODS +RC=$? +case $RC in +50) + ;; +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 + +$LDAPMODIFY -D "$BJORNSDN" -H $URI1 -w bjorn >> \ + $TESTOUT 2>&1 << EOMODS +dn: sn=Doe,ou=Add & Delete,dc=example,dc=com +changetype: modify +add: description +description: added by bjorn (will be removed) +EOMODS +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +$LDAPMODIFY -D "$BABSDN" -H $URI1 -w bjensen >> \ + $TESTOUT 2>&1 << EOMODS +dn: cn=Added by Bjorn,ou=Add & Delete,dc=example,dc=com +changetype: modify +replace: description +description: added by bjensen (should fail) +EOMODS +RC=$? +case $RC in +50) + ;; +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 + +$LDAPMODIFY -D "$JAJDN" -H $URI1 -w jaj >> \ + $TESTOUT 2>&1 << EOMODS +dn: sn=Elliot,ou=Add & Delete,dc=example,dc=com +changetype: modify +delete: description +description: added by bjorn (will be removed) +- +add: description +description: added by jaj (should succeed) +EOMODS +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +sleep $SLEEP0 + +echo >>$SEARCHOUT +echo "Using ldapsearch to retrieve all the entries..." +echo "# Using ldapsearch to retrieve all the entries..." >> $SEARCHOUT +$LDAPSEARCH -S "" -b "ou=Add & Delete,dc=example,dc=com" \ + -D "$MANAGERDN" -H $URI1 -w $PASSWD \ + 'objectClass=*' >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test006-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 - operations did not complete correctly" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/variant/tests/scripts/test007-subtypes b/contrib/slapd-modules/variant/tests/scripts/test007-subtypes new file mode 100755 index 0000000..177fc33 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test007-subtypes @@ -0,0 +1,67 @@ +#! /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 supertype of a variant attribute..." +$LDAPCOMPARE -H $URI1 \ + "ou=Groups,$BASEDN" \ + "name:Alumni Association" >> $TESTOUT 2>&1 +RC=$? +if test $RC != 6 && test $RC,$BACKEND != 5,null ; then + echo "ldapcompare failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +echo "Testing searches against attribute supertypes..." +echo "# Testing searches against attribute supertypes..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + "(&(name=groups)(name=Alumni Association))" \ + >> $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/test007-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/variant/tests/scripts/test008-variant-replication b/contrib/slapd-modules/variant/tests/scripts/test008-variant-replication new file mode 100755 index 0000000..63e2d7e --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test008-variant-replication @@ -0,0 +1,194 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +if test "$SYNCPROV" = syncprovno; then + echo "Syncrepl provider overlay not available, test skipped" + exit 0 +fi + +. ${SCRIPTDIR}/common.sh + +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + > $TESTOUT 2>&1 <<EOMOD +dn: olcOverlay={0}variant,olcDatabase={1}$BACKEND,cn=config +changetype: modify +replace: olcVariantPassReplication +olcVariantPassReplication: FALSE +EOMOD +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +if test "$SYNCPROV" = syncprovmod; then + $LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + > $TESTOUT 2>&1 <<EOMOD +dn: cn=module{0},cn=config +changetype: modify +add: olcModuleLoad +olcModuleLoad: $LDAP_BUILD/servers/slapd/overlays/syncprov.la +EOMOD + + RC=$? + if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + fi +fi + +echo "Configuring syncprov on the provider..." +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + > $TESTOUT 2>&1 <<EOMOD +dn: olcOverlay=syncprov,olcDatabase={1}$BACKEND,cn=config +changetype: add +objectclass: olcSyncProvConfig +EOMOD +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +mkdir $DBDIR4 + +echo "Starting consumer slapd on TCP/IP port $PORT4..." +. $CONFFILTER $BACKEND $MONITORDB < $P1SRCONSUMERCONF > $CONF4 +$SLAPD -f $CONF4 -h $URI4 -d $LVL > $LOG4 2>&1 & +CONSUMERPID=$! +if test $WAIT != 0 ; then + echo CONSUMERPID $CONSUMERPID + read foo +fi +KILLPIDS="$KILLPIDS $CONSUMERPID" + +sleep $SLEEP0 + +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$BASEDN" -H $URI4 \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 0 ; then + break + fi + echo "Waiting ${SLEEP1} seconds for consumer to start replication..." + sleep ${SLEEP1} +done + +echo "Waiting ${SLEEP1} seconds for consumer to finish replicating..." +sleep ${SLEEP1} + +echo "Testing searches against regular entries..." +echo "# Testing searches against regular entries..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI4 \ + "(|(name=Elliot)(description=*hiker*))" \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches listing replicated variants..." +echo >> $SEARCHOUT +echo "# Testing searches listing replicated variants..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -s one -H $URI4 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +# regex variants do not replicate correctly and this is documented +echo >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -s base -H $URI1 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +# regex variants do not replicate correctly and this is documented +echo >> $SEARCHOUT +$LDAPSEARCH -s base -H $URI1 \ + -b "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" \ + '(ou=Information Technology Division)' \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +# regex variants do not replicate correctly and this is documented +echo >> $SEARCHOUT +$LDAPSEARCH -b "cn=ITD Staff,ou=Groups,$BASEDN" -s base -H $URI1 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches filtering on replicated variants..." +echo >> $SEARCHOUT +echo "# Testing searches filtering on replicated variants..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI4 \ + "(st=Alumni Association)" st \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test003-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/variant/tests/scripts/test009-ignored-replication b/contrib/slapd-modules/variant/tests/scripts/test009-ignored-replication new file mode 100755 index 0000000..aefbfa9 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test009-ignored-replication @@ -0,0 +1,227 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +if test "$SYNCPROV" = syncprovno; then + echo "Syncrepl provider overlay not available, test skipped" + exit 0 +fi + +. ${SCRIPTDIR}/common.sh + +if test "$SYNCPROV" = syncprovmod; then + $LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + > $TESTOUT 2>&1 <<EOMOD +dn: cn=module{0},cn=config +changetype: modify +add: olcModuleLoad +olcModuleLoad: $LDAP_BUILD/servers/slapd/overlays/syncprov.la +EOMOD + + RC=$? + if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + fi +fi + +echo "Configuring syncprov on the provider..." +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + > $TESTOUT 2>&1 <<EOMOD +dn: olcOverlay={0}syncprov,olcDatabase={1}$BACKEND,cn=config +changetype: add +objectclass: olcSyncProvConfig +EOMOD +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +mkdir $DBDIR4 $TESTDIR/confdir-consumer + +echo "Starting consumer slapd on TCP/IP port $PORT4..." +. $CONFFILTER $BACKEND $MONITORDB < $P1SRCONSUMERCONF > $CONF4 + +echo "database config" >>$CONF4 +echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >>$CONF4 + +$SLAPD -f $CONF4 -F $TESTDIR/confdir-consumer -h $URI4 -d $LVL > $LOG4 2>&1 & +CONSUMERPID=$! +if test $WAIT != 0 ; then + echo CONSUMERPID $CONSUMERPID + read foo +fi +KILLPIDS="$KILLPIDS $CONSUMERPID" + +sleep $SLEEP0 + +echo "Setting up variant overlay on consumer..." +$LDAPSEARCH -D cn=config -H $URI4 -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 $URI4 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 <<EOMOD +dn: cn=module{0},cn=config +changetype: modify +add: olcModuleLoad +olcModuleLoad: `pwd`/../variant.la +EOMOD + ;; +32) + $LDAPMODIFY -v -D cn=config -H $URI4 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 <<EOMOD +dn: cn=module,cn=config +changetype: add +objectClass: olcModuleList +olcModuleLoad: `pwd`/../variant.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 + +. $CONFFILTER $BACKEND $MONITORDB < $OVERLAY_CONFIG | \ +$LDAPMODIFY -v -D cn=config -H $URI4 -y $CONFIGPWF \ + > $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$BASEDN" -H $URI4 \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 0 ; then + break + fi + echo "Waiting ${SLEEP1} seconds for consumer to start replication..." + sleep ${SLEEP1} +done + +echo "Waiting ${SLEEP1} seconds for consumer to finish replicating..." +sleep ${SLEEP1} + +echo "Testing searches against regular entries..." +echo "# Testing searches against regular entries..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI4 \ + "(|(name=Elliot)(description=*hiker*))" \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches listing replicated variants..." +echo >> $SEARCHOUT +echo "# Testing searches listing replicated variants..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -s one -H $URI4 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -s base -H $URI4 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo >> $SEARCHOUT +$LDAPSEARCH -s base -H $URI4 \ + -b "cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" \ + '(ou=Information Technology Division)' \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo >> $SEARCHOUT +$LDAPSEARCH -b "cn=ITD Staff,ou=Groups,$BASEDN" -s base -H $URI4 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing searches filtering on replicated variants..." +echo >> $SEARCHOUT +echo "# Testing searches filtering on replicated variants..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI4 \ + "(st=Alumni Association)" st \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test003-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/variant/tests/scripts/test010-limits b/contrib/slapd-modules/variant/tests/scripts/test010-limits new file mode 100755 index 0000000..5828922 --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test010-limits @@ -0,0 +1,99 @@ +#! /bin/sh +## $OpenLDAP$ +## This work is part of OpenLDAP Software <http://www.openldap.org/>. +## +## Copyright 2016-2022 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## <http://www.OpenLDAP.org/license.html>. +## +## ACKNOWLEDGEMENTS: +## This module was written in 2016 by Ondřej Kuzník for Symas Corp. + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +. ${SCRIPTDIR}/common.sh + +echo "Testing searches against regular entries..." +echo "# Testing searches against regular entries..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + -z 1 "(|(name=Elliot)(description=*hiker*))" \ + >> $SEARCHOUT 2>&1 +RC=$? +case $RC in +0) + echo "ldapsearch should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; +4) + echo "sizelimit reached ($RC)" + ;; +*) + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; +esac + +echo "Testing searches listing variants where limits just fit..." +echo "# Testing searches listing variants where limits just fit..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -s one -H $URI1 \ + -z 3 >> $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 variants going over the specified limit..." +echo "# Testing searches filtering on variants going over the specified limit..." >> $SEARCHOUT +$LDAPSEARCH -b "$BASEDN" -H $URI1 \ + -z 1 "(name=Alumni Association)" \ + >> $SEARCHOUT 2>&1 +RC=$? +case $RC in +0) + echo "ldapsearch should have failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 + ;; +4) + echo "sizelimit reached ($RC)" + ;; +*) + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + ;; +esac + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test010-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER -s e < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER -s e < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0 diff --git a/contrib/slapd-modules/variant/tests/scripts/test011-referral b/contrib/slapd-modules/variant/tests/scripts/test011-referral new file mode 100755 index 0000000..37d6d8c --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test011-referral @@ -0,0 +1,169 @@ +#! /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 + +TESTDN="cn=Gern Jensen,ou=Information Technology Division,ou=People,$BASEDN" + +echo "Adding referral..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + >> $TESTOUT 2>&1 <<EOMOD +dn: $TESTDN +changetype: add +objectclass: referral +objectclass: extensibleObject +ref: ldap://hostB HostB +EOMOD +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Configuring referral as variant..." +. $CONFFILTER $BACKEND $MONITORDB < data/additional-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 "Retrieving a referral variant..." +echo "# Retrieving a referral variant..." >> $SEARCHOUT +$LDAPSEARCH -LLL -b "$BASEDN" -H $URI1 \ + '(cn=Gern Jensen)' >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch: unexpected result ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Retrieving a referral variant (returns a referral)..." +echo "# Retrieving a referral variant (returns a referral)..." >> $SEARCHOUT +$LDAPSEARCH -b "$TESTDN" -H $URI1 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 10 ; then + echo "ldapsearch: unexpected result ($RC)! (referral expected)" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Modifying a referral variant (returns a referral)..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + >> $TESTOUT 2>&1 <<EOMOD +dn: $TESTDN +changetype: modify +delete: description +EOMOD +RC=$? +if test $RC != 10 ; then + echo "ldapmodify: unexpected result ($RC)! (referral expected)" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Comparing a referral variant (returns a referral)..." +$LDAPCOMPARE -H $URI1 "$TESTDN" \ + "description:The Example, Inc. at Anytown" >> $TESTOUT 2>&1 +RC=$? +if test $RC != 10; then + echo "ldapcompare: unexpected result ($RC)! (referral expected)" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +echo "Reconfiguring variant underneath a referral..." +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + >> $TESTOUT 2>&1 <<EOMOD +dn: name={4}test002,olcOverlay={0}variant,olcDatabase={1}$BACKEND,cn=config +changetype: modify +replace: olcVariantEntry +olcVariantEntry: cn=child,$TESTDN +EOMOD +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Retrieving a variant under a referral (returns a referral)..." +echo "# Retrieving a variant under a referral (returns a referral)..." >> $SEARCHOUT +$LDAPSEARCH -b "cn=child,$TESTDN" -H $URI1 \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 10 ; then + echo "ldapsearch: unexpected result ($RC)! (referral expected)" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Modifying a variant under a referral (returns a referral)..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + >> $TESTOUT 2>&1 <<EOMOD +dn: cn=child,$TESTDN +changetype: modify +delete: description +EOMOD +RC=$? +if test $RC != 10 ; then + echo "ldapmodify: unexpected result ($RC)! (referral expected)" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Comparing a variant under a referral (returns a referral)..." +$LDAPCOMPARE -H $URI1 "cn=child,$TESTDN" \ + "description:The Example, Inc. at Anytown" >> $TESTOUT 2>&1 +RC=$? +if test $RC != 10; then + echo "ldapcompare: unexpected result ($RC)! (referral expected)" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +test $KILLSERVERS != no && kill -HUP $KILLPIDS + +LDIF=data/test011-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER < $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/variant/tests/scripts/test012-crossdb b/contrib/slapd-modules/variant/tests/scripts/test012-crossdb new file mode 100755 index 0000000..8854a1b --- /dev/null +++ b/contrib/slapd-modules/variant/tests/scripts/test012-crossdb @@ -0,0 +1,90 @@ +#! /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 "Setting up another database and variant using an alternate there..." +mkdir $DBDIR2 +$LDAPMODIFY -v -D cn=config -H $URI1 -y $CONFIGPWF \ + <<EOMOD >> $TESTOUT 2>&1 +dn: olcDatabase=ldif,cn=config +changetype: add +objectclass: olcLdifConfig +olcSuffix: dc=demonstration,dc=com +olcDbDirectory: $DBDIR2 +olcRootDn: $MANAGERDN + +dn: olcVariantVariantAttribute={1}seealso,name={0}variant,olcOverlay={0}variant,olcDatabase={1}$BACKEND,cn=config +changetype: modify +replace: olcVariantAlternativeEntry +olcVariantAlternativeEntry: ou=Societies,dc=demonstration,dc=com +EOMOD +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Adding alternate entry..." +$LDAPMODIFY -D $MANAGERDN -H $URI1 -w $PASSWD \ + -f data/test012-data.ldif >> $TESTOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Checking the variant gets resolved correctly..." +echo "# Testing a search against a variant using another DB..." >> $SEARCHOUT +#$LDAPSEARCH -b "$BASEDN" -H $URI1 \ +# "seealso=dc=example,dc=com" \ +$LDAPSEARCH -b "ou=People,$BASEDN" -s base -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 + +LDIF=data/test012-out.ldif + +echo "Filtering ldapsearch results..." +$LDIFFILTER < $SEARCHOUT > $SEARCHFLT +echo "Filtering expected entries..." +$LDIFFILTER < $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/variant/variant.c b/contrib/slapd-modules/variant/variant.c new file mode 100644 index 0000000..edf4832 --- /dev/null +++ b/contrib/slapd-modules/variant/variant.c @@ -0,0 +1,1424 @@ +/* variant.c - variant overlay */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * Copyright 2016-2021 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 the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * <http://www.OpenLDAP.org/license.html>. + */ +/* ACKNOWLEDGEMENTS: + * This work was developed in 2016-2017 by Ondřej Kuzník for Symas Corp. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_VARIANT + +#include "slap.h" +#include "slap-config.h" +#include "ldap_queue.h" + +typedef enum variant_type_t { + VARIANT_INFO_PLAIN = 1 << 0, + VARIANT_INFO_REGEX = 1 << 1, + + VARIANT_INFO_ALL = ~0 +} variant_type_t; + +typedef struct variant_info_t { + int passReplication; + LDAP_STAILQ_HEAD(variant_list, variantEntry_info) variants, regex_variants; +} variant_info_t; + +typedef struct variantEntry_info { + variant_info_t *ov; + struct berval dn; + variant_type_t type; + regex_t *regex; + LDAP_SLIST_HEAD(attribute_list, variantAttr_info) attributes; + LDAP_STAILQ_ENTRY(variantEntry_info) next; +} variantEntry_info; + +typedef struct variantAttr_info { + variantEntry_info *variant; + struct berval dn; + AttributeDescription *attr, *alternative; + LDAP_SLIST_ENTRY(variantAttr_info) next; +} variantAttr_info; + +static int +variant_build_dn( + Operation *op, + variantAttr_info *vai, + int nmatch, + regmatch_t *pmatch, + struct berval *out ) +{ + struct berval dn, *ndn = &op->o_req_ndn; + char *dest, *p, *prev, *end = vai->dn.bv_val + vai->dn.bv_len; + size_t len = vai->dn.bv_len; + int rc; + + p = vai->dn.bv_val; + while ( (p = memchr( p, '$', end - p )) != NULL ) { + len -= 1; + p += 1; + + if ( ( *p >= '0' ) && ( *p <= '9' ) ) { + int i = *p - '0'; + + len += ( pmatch[i].rm_eo - pmatch[i].rm_so ); + } else if ( *p != '$' ) { + /* Should have been checked at configuration time */ + assert(0); + } + len -= 1; + p += 1; + } + + dest = dn.bv_val = ch_realloc( out->bv_val, len + 1 ); + dn.bv_len = len; + + prev = vai->dn.bv_val; + while ( (p = memchr( prev, '$', end - prev )) != NULL ) { + len = p - prev; + AC_MEMCPY( dest, prev, len ); + dest += len; + p += 1; + + if ( ( *p >= '0' ) && ( *p <= '9' ) ) { + int i = *p - '0'; + len = pmatch[i].rm_eo - pmatch[i].rm_so; + + AC_MEMCPY( dest, ndn->bv_val + pmatch[i].rm_so, len ); + dest += len; + } else if ( *p == '$' ) { + *dest++ = *p; + } + prev = p + 1; + } + len = end - prev; + AC_MEMCPY( dest, prev, len ); + dest += len; + *dest = '\0'; + + rc = dnNormalize( 0, NULL, NULL, &dn, out, NULL ); + ch_free( dn.bv_val ); + + return rc; +} + +static int +variant_build_entry( + Operation *op, + variantEntry_info *vei, + struct berval *dn, + Entry **ep, + int nmatch, + regmatch_t *pmatch ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + BackendDB *be_orig = op->o_bd, *db; + struct berval ndn = BER_BVNULL; + variantAttr_info *vai; + Attribute *a; + BerVarray nvals; + Entry *e; + unsigned int i; + int rc; + + assert( ep ); + assert( !*ep ); + + rc = overlay_entry_get_ov( op, dn, NULL, NULL, 0, &e, on ); + if ( rc == LDAP_SUCCESS && is_entry_referral( e ) ) { + overlay_entry_release_ov( op, e, 0, on ); + rc = LDAP_REFERRAL; + } + + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + *ep = entry_dup( e ); + overlay_entry_release_ov( op, e, 0, on ); + + LDAP_SLIST_FOREACH( vai, &vei->attributes, next ) { + if ( vei->type == VARIANT_INFO_REGEX ) { + rc = variant_build_dn( op, vai, nmatch, pmatch, &ndn ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + } else { + ndn = vai->dn; + } + + (void)attr_delete( &(*ep)->e_attrs, vai->attr ); + op->o_bd = be_orig; + + /* only select backend if not served by ours, would retrace all + * overlays again */ + db = select_backend( &ndn, 0 ); + if ( db && db != be_orig->bd_self ) { + op->o_bd = db; + rc = be_entry_get_rw( op, &ndn, NULL, vai->alternative, 0, &e ); + } else { + rc = overlay_entry_get_ov( + op, &ndn, NULL, vai->alternative, 0, &e, on ); + } + + switch ( rc ) { + case LDAP_SUCCESS: + break; + case LDAP_INSUFFICIENT_ACCESS: + case LDAP_NO_SUCH_ATTRIBUTE: + case LDAP_NO_SUCH_OBJECT: + rc = LDAP_SUCCESS; + continue; + break; + default: + goto done; + break; + } + + a = attr_find( e->e_attrs, vai->alternative ); + + /* back-ldif doesn't check the attribute exists in the entry before + * returning it */ + if ( a ) { + if ( a->a_nvals ) { + nvals = a->a_nvals; + } else { + nvals = a->a_vals; + } + + for ( i = 0; i < a->a_numvals; i++ ) { + if ( backend_access( op, e, &ndn, vai->alternative, &nvals[i], + ACL_READ, NULL ) != LDAP_SUCCESS ) { + continue; + } + + rc = attr_merge_one( *ep, vai->attr, &a->a_vals[i], &nvals[i] ); + if ( rc != LDAP_SUCCESS ) { + break; + } + } + } + + if ( db && db != be_orig->bd_self ) { + be_entry_release_rw( op, e, 0 ); + } else { + overlay_entry_release_ov( op, e, 0, on ); + } + if ( rc != LDAP_SUCCESS ) { + goto done; + } + } + +done: + op->o_bd = be_orig; + if ( rc != LDAP_SUCCESS && *ep ) { + entry_free( *ep ); + *ep = NULL; + } + if ( vei->type == VARIANT_INFO_REGEX ) { + ch_free( ndn.bv_val ); + } + + return rc; +} + +static int +variant_find_config( + Operation *op, + variant_info_t *ov, + struct berval *ndn, + int which, + variantEntry_info **veip, + size_t nmatch, + regmatch_t *pmatch ) +{ + variantEntry_info *vei; + + assert( veip ); + + if ( which & VARIANT_INFO_PLAIN ) { + int diff; + + LDAP_STAILQ_FOREACH( vei, &ov->variants, next ) { + dnMatch( &diff, 0, NULL, NULL, ndn, &vei->dn ); + if ( diff ) continue; + + *veip = vei; + return LDAP_SUCCESS; + } + } + + if ( which & VARIANT_INFO_REGEX ) { + LDAP_STAILQ_FOREACH( vei, &ov->regex_variants, next ) { + if ( regexec( vei->regex, ndn->bv_val, nmatch, pmatch, 0 ) ) { + continue; + } + + *veip = vei; + return LDAP_SUCCESS; + } + } + + return SLAP_CB_CONTINUE; +} + +static int +variant_op_add( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + variant_info_t *ov = on->on_bi.bi_private; + variantEntry_info *vei; + int rc; + + /* Replication always uses the rootdn */ + if ( ov->passReplication && SLAPD_SYNC_IS_SYNCCONN(op->o_connid) && + be_isroot( op ) ) { + return SLAP_CB_CONTINUE; + } + + Debug( LDAP_DEBUG_TRACE, "variant_op_add: " + "dn=%s\n", op->o_req_ndn.bv_val ); + + rc = variant_find_config( + op, ov, &op->o_req_ndn, VARIANT_INFO_ALL, &vei, 0, NULL ); + if ( rc == LDAP_SUCCESS ) { + variantAttr_info *vai; + + LDAP_SLIST_FOREACH( vai, &vei->attributes, next ) { + Attribute *a; + for ( a = op->ora_e->e_attrs; a; a = a->a_next ) { + if ( a->a_desc == vai->attr ) { + rc = LDAP_CONSTRAINT_VIOLATION; + send_ldap_error( op, rs, rc, + "variant: trying to add variant attributes" ); + goto done; + } + } + } + } + rc = SLAP_CB_CONTINUE; + +done: + Debug( LDAP_DEBUG_TRACE, "variant_op_add: " + "finished with %d\n", + rc ); + return rc; +} + +static int +variant_op_compare( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + variant_info_t *ov = on->on_bi.bi_private; + variantEntry_info *vei; + regmatch_t pmatch[10]; + int rc, nmatch = sizeof(pmatch) / sizeof(regmatch_t); + + Debug( LDAP_DEBUG_TRACE, "variant_op_compare: " + "dn=%s\n", op->o_req_ndn.bv_val ); + + rc = variant_find_config( + op, ov, &op->o_req_ndn, VARIANT_INFO_ALL, &vei, nmatch, pmatch ); + if ( rc == LDAP_SUCCESS ) { + Entry *e = NULL; + + rc = variant_build_entry( op, vei, &op->o_req_ndn, &e, nmatch, pmatch ); + /* in case of error, just let the backend deal with the mod and the + * client should get a meaningful error back */ + if ( rc != LDAP_SUCCESS ) { + rc = SLAP_CB_CONTINUE; + } else { + rc = slap_compare_entry( op, e, op->orc_ava ); + + entry_free( e ); + e = NULL; + } + } + + if ( rc != SLAP_CB_CONTINUE ) { + rs->sr_err = rc; + send_ldap_result( op, rs ); + } + + Debug( LDAP_DEBUG_TRACE, "variant_op_compare: " + "finished with %d\n", rc ); + return rc; +} + +static int +variant_cmp_op( const void *l, const void *r ) +{ + const Operation *left = l, *right = r; + int diff; + + dnMatch( &diff, 0, NULL, NULL, (struct berval *)&left->o_req_ndn, + (void *)&right->o_req_ndn ); + + return diff; +} + +static int +variant_run_mod( void *nop, void *arg ) +{ + SlapReply nrs = { REP_RESULT }; + slap_callback cb = { 0 }; + Operation *op = nop; + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + int *rc = arg; + + cb.sc_response = slap_null_cb; + op->o_callback = &cb; + + Debug( LDAP_DEBUG_TRACE, "variant_run_mod: " + "running mod on dn=%s\n", + op->o_req_ndn.bv_val ); + *rc = on->on_info->oi_orig->bi_op_modify( op, &nrs ); + Debug( LDAP_DEBUG_TRACE, "variant_run_mod: " + "finished with %d\n", *rc ); + + return ( *rc != LDAP_SUCCESS ); +} + +/** Move the Modifications back to the original Op so that they can be disposed + * of by the original creator + */ +static int +variant_reassign_mods( void *nop, void *arg ) +{ + Operation *op = nop, *orig_op = arg; + Modifications *mod; + + assert( op->orm_modlist ); + + for ( mod = op->orm_modlist; mod->sml_next; mod = mod->sml_next ) + /* get the tail mod */; + + mod->sml_next = orig_op->orm_modlist; + orig_op->orm_modlist = op->orm_modlist; + + return LDAP_SUCCESS; +} + +void +variant_free_op( void *op ) +{ + ch_free( ((Operation *)op)->o_req_ndn.bv_val ); + ch_free( op ); +} + +static int +variant_op_mod( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + variant_info_t *ov = on->on_bi.bi_private; + variantEntry_info *vei; + variantAttr_info *vai; + Avlnode *ops = NULL; + Entry *e = NULL; + Modifications *mod, *nextmod; + regmatch_t pmatch[10]; + int rc, nmatch = sizeof(pmatch) / sizeof(regmatch_t); + + /* Replication always uses the rootdn */ + if ( ov->passReplication && SLAPD_SYNC_IS_SYNCCONN(op->o_connid) && + be_isroot( op ) ) { + return SLAP_CB_CONTINUE; + } + + Debug( LDAP_DEBUG_TRACE, "variant_op_mod: " + "dn=%s\n", op->o_req_ndn.bv_val ); + + rc = variant_find_config( + op, ov, &op->o_req_ndn, VARIANT_INFO_ALL, &vei, nmatch, pmatch ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "variant_op_mod: " + "not a variant\n" ); + rc = SLAP_CB_CONTINUE; + goto done; + } + + rc = variant_build_entry( op, vei, &op->o_req_ndn, &e, nmatch, pmatch ); + /* in case of error, just let the backend deal with the mod and the client + * should get a meaningful error back */ + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "variant_op_mod: " + "failed to retrieve entry\n" ); + rc = SLAP_CB_CONTINUE; + goto done; + } + + rc = acl_check_modlist( op, e, op->orm_modlist ); + entry_free( e ); + + if ( !rc ) { + rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + send_ldap_error( op, rs, rc, "" ); + return rc; + } + + for ( mod = op->orm_modlist; mod; mod = nextmod ) { + Operation needle = { .o_req_ndn = BER_BVNULL }, *nop; + + nextmod = mod->sml_next; + + LDAP_SLIST_FOREACH( vai, &vei->attributes, next ) { + if ( vai->attr == mod->sml_desc ) { + break; + } + } + + if ( vai ) { + if ( vei->type == VARIANT_INFO_REGEX ) { + rc = variant_build_dn( + op, vai, nmatch, pmatch, &needle.o_req_ndn ); + if ( rc != LDAP_SUCCESS ) { + continue; + } + } else { + needle.o_req_ndn = vai->dn; + } + + nop = ldap_avl_find( ops, &needle, variant_cmp_op ); + if ( nop == NULL ) { + nop = ch_calloc( 1, sizeof(Operation) ); + *nop = *op; + + ber_dupbv( &nop->o_req_ndn, &needle.o_req_ndn ); + nop->o_req_dn = nop->o_req_ndn; + nop->orm_modlist = NULL; + + rc = ldap_avl_insert( &ops, nop, variant_cmp_op, ldap_avl_dup_error ); + assert( rc == 0 ); + } + mod->sml_desc = vai->alternative; + + op->orm_modlist = nextmod; + mod->sml_next = nop->orm_modlist; + nop->orm_modlist = mod; + + if ( vei->type == VARIANT_INFO_REGEX ) { + ch_free( needle.o_req_ndn.bv_val ); + } + } + } + + if ( !ops ) { + Debug( LDAP_DEBUG_TRACE, "variant_op_mod: " + "no variant attributes in mod\n" ); + return SLAP_CB_CONTINUE; + } + + /* + * First run original Operation + * This will take care of making sure the entry exists as well. + * + * FIXME? + * Since we cannot make the subsequent Ops atomic wrt. this one, we just + * let it send the response as well. After all, the changes on the main DN + * have finished by then + */ + rc = on->on_info->oi_orig->bi_op_modify( op, rs ); + if ( rc == LDAP_SUCCESS ) { + /* FIXME: if a mod fails, should we attempt to apply the rest? */ + ldap_avl_apply( ops, variant_run_mod, &rc, -1, AVL_INORDER ); + } + + ldap_avl_apply( ops, variant_reassign_mods, op, -1, AVL_INORDER ); + ldap_avl_free( ops, variant_free_op ); + +done: + Debug( LDAP_DEBUG_TRACE, "variant_op_mod: " + "finished with %d\n", rc ); + return rc; +} + +static int +variant_search_response( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = op->o_callback->sc_private; + variant_info_t *ov = on->on_bi.bi_private; + variantEntry_info *vei; + int rc; + + if ( rs->sr_type == REP_RESULT ) { + ch_free( op->o_callback ); + op->o_callback = NULL; + } + + if ( rs->sr_type != REP_SEARCH ) { + return SLAP_CB_CONTINUE; + } + + rc = variant_find_config( + op, ov, &rs->sr_entry->e_nname, VARIANT_INFO_PLAIN, &vei, 0, NULL ); + if ( rc == LDAP_SUCCESS ) { + rs->sr_nentries--; + return rc; + } + + return SLAP_CB_CONTINUE; +} + +static int +variant_op_search( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + variant_info_t *ov = on->on_bi.bi_private; + variantEntry_info *vei; + slap_callback *cb; + Entry *e = NULL; + regmatch_t pmatch[10]; + int variantInScope = 0, rc = SLAP_CB_CONTINUE, + nmatch = sizeof(pmatch) / sizeof(regmatch_t); + + if ( ov->passReplication && ( op->o_sync > SLAP_CONTROL_IGNORED ) ) { + return SLAP_CB_CONTINUE; + } + + Debug( LDAP_DEBUG_TRACE, "variant_op_search: " + "dn=%s, scope=%d\n", + op->o_req_ndn.bv_val, op->ors_scope ); + + LDAP_STAILQ_FOREACH( vei, &ov->variants, next ) { + if ( !dnIsSuffixScope( &vei->dn, &op->o_req_ndn, op->ors_scope ) ) + continue; + + variantInScope = 1; + + rc = variant_build_entry( op, vei, &vei->dn, &e, 0, NULL ); + if ( rc == LDAP_NO_SUCH_OBJECT || rc == LDAP_REFERRAL ) { + rc = SLAP_CB_CONTINUE; + continue; + } else if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "variant_op_search: " + "failed to retrieve entry: dn=%s\n", + vei->dn.bv_val ); + goto done; + } + + if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) { + Debug( LDAP_DEBUG_TRACE, "variant_op_search: " + "entry matched: dn=%s\n", + vei->dn.bv_val ); + rs->sr_entry = e; + rs->sr_attrs = op->ors_attrs; + rc = send_search_entry( op, rs ); + } + entry_free( e ); + e = NULL; + } + + /* Three options: + * - the entry has been handled above, in that case vei->type is VARIANT_INFO_PLAIN + * - the entry matches a regex, use the first one and we're finished + * - no configuration matches entry - do nothing + */ + if ( op->ors_scope == LDAP_SCOPE_BASE && + variant_find_config( op, ov, &op->o_req_ndn, VARIANT_INFO_ALL, &vei, + nmatch, pmatch ) == LDAP_SUCCESS && + vei->type == VARIANT_INFO_REGEX ) { + rc = variant_build_entry( op, vei, &op->o_req_ndn, &e, nmatch, pmatch ); + if ( rc == LDAP_NO_SUCH_OBJECT || rc == LDAP_REFERRAL ) { + rc = SLAP_CB_CONTINUE; + } else if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "variant_op_search: " + "failed to retrieve entry: dn=%s\n", + vei->dn.bv_val ); + goto done; + } else { + if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) { + Debug( LDAP_DEBUG_TRACE, "variant_op_search: " + "entry matched: dn=%s\n", + vei->dn.bv_val ); + rs->sr_entry = e; + rs->sr_attrs = op->ors_attrs; + rc = send_search_entry( op, rs ); + } + entry_free( e ); + e = NULL; + goto done; + } + } + rc = SLAP_CB_CONTINUE; + + if ( variantInScope ) { + cb = ch_calloc( 1, sizeof(slap_callback) ); + cb->sc_private = on; + cb->sc_response = variant_search_response; + cb->sc_next = op->o_callback; + + op->o_callback = cb; + } + +done: + if ( rc != SLAP_CB_CONTINUE ) { + rs->sr_err = (rc == LDAP_SUCCESS) ? rc : LDAP_OTHER; + send_ldap_result( op, rs ); + } + Debug( LDAP_DEBUG_TRACE, "variant_op_search: " + "finished with %d\n", rc ); + return rc; +} + +/* Configuration */ + +static ConfigLDAPadd variant_ldadd; +static ConfigLDAPadd variant_regex_ldadd; +static ConfigLDAPadd variant_attr_ldadd; + +static ConfigDriver variant_set_dn; +static ConfigDriver variant_set_regex; +static ConfigDriver variant_set_alt_dn; +static ConfigDriver variant_set_alt_pattern; +static ConfigDriver variant_set_attribute; +static ConfigDriver variant_add_alt_attr; +static ConfigDriver variant_add_alt_attr_regex; + +static ConfigCfAdd variant_cfadd; + +enum +{ + VARIANT_ATTR = 1, + VARIANT_ATTR_ALT, + + VARIANT_LAST, +}; + +static ConfigTable variant_cfg[] = { + { "passReplication", "on|off", 2, 2, 0, + ARG_ON_OFF|ARG_OFFSET, + (void *)offsetof( variant_info_t, passReplication ), + "( OLcfgOvAt:FIXME.1 NAME 'olcVariantPassReplication' " + "DESC 'Whether to let searches with replication control " + "pass unmodified' " + "SYNTAX OMsBoolean " + "SINGLE-VALUE )", + NULL, NULL + }, + { "variantDN", "dn", 2, 2, 0, + ARG_DN|ARG_QUOTE|ARG_MAGIC, + variant_set_dn, + "( OLcfgOvAt:FIXME.2 NAME 'olcVariantEntry' " + "DESC 'DN of the variant entry' " + "EQUALITY distinguishedNameMatch " + "SYNTAX OMsDN " + "SINGLE-VALUE )", + NULL, NULL + }, + { "variantRegex", "regex", 2, 2, 0, + ARG_BERVAL|ARG_QUOTE|ARG_MAGIC, + variant_set_regex, + "( OLcfgOvAt:FIXME.6 NAME 'olcVariantEntryRegex' " + "DESC 'Pattern for the variant entry' " + "EQUALITY caseExactMatch " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL + }, + /* These have no equivalent in slapd.conf */ + { "", NULL, 2, 2, 0, + ARG_STRING|ARG_MAGIC|VARIANT_ATTR, + variant_set_attribute, + "( OLcfgOvAt:FIXME.3 NAME 'olcVariantVariantAttribute' " + "DESC 'Attribute to fill in the entry' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL + }, + { "", NULL, 2, 2, 0, + ARG_STRING|ARG_MAGIC|VARIANT_ATTR_ALT, + variant_set_attribute, + "( OLcfgOvAt:FIXME.4 NAME 'olcVariantAlternativeAttribute' " + "DESC 'Attribute to take from the alternative entry' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL + }, + { "", NULL, 2, 2, 0, + ARG_DN|ARG_QUOTE|ARG_MAGIC, + variant_set_alt_dn, + "( OLcfgOvAt:FIXME.5 NAME 'olcVariantAlternativeEntry' " + "DESC 'DN of the alternative entry' " + "EQUALITY distinguishedNameMatch " + "SYNTAX OMsDN " + "SINGLE-VALUE )", + NULL, NULL + }, + { "", NULL, 2, 2, 0, + ARG_BERVAL|ARG_QUOTE|ARG_MAGIC, + variant_set_alt_pattern, + "( OLcfgOvAt:FIXME.7 NAME 'olcVariantAlternativeEntryPattern' " + "DESC 'Replacement pattern to locate the alternative entry' " + "EQUALITY caseExactMatch " + "SYNTAX OMsDirectoryString " + "SINGLE-VALUE )", + NULL, NULL + }, + /* slapd.conf alternatives for the four above */ + { "variantSpec", "attr attr2 dn", 4, 4, 0, + ARG_QUOTE|ARG_MAGIC, + variant_add_alt_attr, + NULL, NULL, NULL + }, + { "variantRegexSpec", "attr attr2 pattern", 4, 4, 0, + ARG_QUOTE|ARG_MAGIC, + variant_add_alt_attr_regex, + NULL, NULL, NULL + }, + + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + +static ConfigOCs variant_ocs[] = { + { "( OLcfgOvOc:FIXME.1 " + "NAME 'olcVariantConfig' " + "DESC 'Variant overlay configuration' " + "SUP olcOverlayConfig " + "MAY ( olcVariantPassReplication ) )", + Cft_Overlay, variant_cfg, NULL, variant_cfadd }, + { "( OLcfgOvOc:FIXME.2 " + "NAME 'olcVariantVariant' " + "DESC 'Variant configuration' " + "MUST ( olcVariantEntry ) " + "MAY ( name ) " + "SUP top " + "STRUCTURAL )", + Cft_Misc, variant_cfg, variant_ldadd }, + { "( OLcfgOvOc:FIXME.3 " + "NAME 'olcVariantAttribute' " + "DESC 'Variant attribute description' " + "MUST ( olcVariantVariantAttribute $ " + "olcVariantAlternativeAttribute $ " + "olcVariantAlternativeEntry " + ") " + "MAY name " + "SUP top " + "STRUCTURAL )", + Cft_Misc, variant_cfg, variant_attr_ldadd }, + { "( OLcfgOvOc:FIXME.4 " + "NAME 'olcVariantRegex' " + "DESC 'Variant configuration' " + "MUST ( olcVariantEntryRegex ) " + "MAY ( name ) " + "SUP top " + "STRUCTURAL )", + Cft_Misc, variant_cfg, variant_regex_ldadd }, + { "( OLcfgOvOc:FIXME.5 " + "NAME 'olcVariantAttributePattern' " + "DESC 'Variant attribute description' " + "MUST ( olcVariantVariantAttribute $ " + "olcVariantAlternativeAttribute $ " + "olcVariantAlternativeEntryPattern " + ") " + "MAY name " + "SUP top " + "STRUCTURAL )", + Cft_Misc, variant_cfg, variant_attr_ldadd }, + + { NULL, 0, NULL } +}; + +static int +variant_set_dn( ConfigArgs *ca ) +{ + variantEntry_info *vei2, *vei = ca->ca_private; + slap_overinst *on = (slap_overinst *)ca->bi; + variant_info_t *ov = on->on_bi.bi_private; + int diff; + + if ( ca->op == SLAP_CONFIG_EMIT ) { + value_add_one( &ca->rvalue_vals, &vei->dn ); + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + ber_memfree( vei->dn.bv_val ); + BER_BVZERO( &vei->dn ); + return LDAP_SUCCESS; + } + + if ( !vei ) { + vei = ch_calloc( 1, sizeof(variantEntry_info) ); + vei->ov = ov; + vei->type = VARIANT_INFO_PLAIN; + LDAP_SLIST_INIT(&vei->attributes); + LDAP_STAILQ_ENTRY_INIT(vei, next); + LDAP_STAILQ_INSERT_TAIL(&ov->variants, vei, next); + + ca->ca_private = vei; + } + vei->dn = ca->value_ndn; + ber_memfree( ca->value_dn.bv_val ); + + /* Each DN should only be listed once */ + LDAP_STAILQ_FOREACH( vei2, &vei->ov->variants, next ) { + if ( vei == vei2 ) continue; + + dnMatch( &diff, 0, NULL, NULL, &vei->dn, &vei2->dn ); + if ( !diff ) { + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } + } + + return LDAP_SUCCESS; +} + +static int +variant_set_regex( ConfigArgs *ca ) +{ + variantEntry_info *vei2, *vei = ca->ca_private; + slap_overinst *on = (slap_overinst *)ca->bi; + variant_info_t *ov = on->on_bi.bi_private; + + if ( ca->op == SLAP_CONFIG_EMIT ) { + ca->value_bv = vei->dn; + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + ber_memfree( vei->dn.bv_val ); + BER_BVZERO( &vei->dn ); + regfree( vei->regex ); + return LDAP_SUCCESS; + } + + if ( !vei ) { + vei = ch_calloc( 1, sizeof(variantEntry_info) ); + vei->ov = ov; + vei->type = VARIANT_INFO_REGEX; + LDAP_SLIST_INIT(&vei->attributes); + LDAP_STAILQ_ENTRY_INIT(vei, next); + LDAP_STAILQ_INSERT_TAIL(&ov->regex_variants, vei, next); + + ca->ca_private = vei; + } + vei->dn = ca->value_bv; + + /* Each regex should only be listed once */ + LDAP_STAILQ_FOREACH( vei2, &vei->ov->regex_variants, next ) { + if ( vei == vei2 ) continue; + + if ( !ber_bvcmp( &ca->value_bv, &vei2->dn ) ) { + ch_free( vei ); + ca->ca_private = NULL; + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } + } + + vei->regex = ch_calloc( 1, sizeof(regex_t) ); + if ( regcomp( vei->regex, vei->dn.bv_val, REG_EXTENDED ) ) { + ch_free( vei->regex ); + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } + + return LDAP_SUCCESS; +} + +static int +variant_set_alt_dn( ConfigArgs *ca ) +{ + variantAttr_info *vai = ca->ca_private; + + if ( ca->op == SLAP_CONFIG_EMIT ) { + value_add_one( &ca->rvalue_vals, &vai->dn ); + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + ber_memfree( vai->dn.bv_val ); + BER_BVZERO( &vai->dn ); + return LDAP_SUCCESS; + } + + vai->dn = ca->value_ndn; + ber_memfree( ca->value_dn.bv_val ); + + return LDAP_SUCCESS; +} + +static int +variant_set_alt_pattern( ConfigArgs *ca ) +{ + variantAttr_info *vai = ca->ca_private; + char *p = ca->value_bv.bv_val, + *end = ca->value_bv.bv_val + ca->value_bv.bv_len; + + if ( ca->op == SLAP_CONFIG_EMIT ) { + ca->value_bv = vai->dn; + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + ber_memfree( vai->dn.bv_val ); + BER_BVZERO( &vai->dn ); + return LDAP_SUCCESS; + } + + while ( (p = memchr( p, '$', end - p )) != NULL ) { + p += 1; + + if ( ( ( *p >= '0' ) && ( *p <= '9' ) ) || ( *p == '$' ) ) { + p += 1; + } else { + Debug( LDAP_DEBUG_ANY, "variant_set_alt_pattern: " + "invalid replacement pattern supplied '%s'\n", + ca->value_bv.bv_val ); + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } + } + + vai->dn = ca->value_bv; + + return LDAP_SUCCESS; +} + +static int +variant_set_attribute( ConfigArgs *ca ) +{ + variantAttr_info *vai2, *vai = ca->ca_private; + char *s = ca->value_string; + const char *text; + AttributeDescription **ad; + int rc; + + if ( ca->type == VARIANT_ATTR ) { + ad = &vai->attr; + } else { + ad = &vai->alternative; + } + + if ( ca->op == SLAP_CONFIG_EMIT ) { + ca->value_string = ch_strdup( (*ad)->ad_cname.bv_val ); + return LDAP_SUCCESS; + } else if ( ca->op == LDAP_MOD_DELETE ) { + *ad = NULL; + return LDAP_SUCCESS; + } + + if ( *s == '{' ) { + s = strchr( s, '}' ); + if ( !s ) { + ca->reply.err = LDAP_UNDEFINED_TYPE; + return ca->reply.err; + } + s += 1; + } + + rc = slap_str2ad( s, ad, &text ); + ber_memfree( ca->value_string ); + if ( rc ) { + return rc; + } + + /* Both attributes have to share the same syntax */ + if ( vai->attr && vai->alternative && + vai->attr->ad_type->sat_syntax != + vai->alternative->ad_type->sat_syntax ) { + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } + + if ( ca->type == VARIANT_ATTR ) { + /* Each attribute should only be listed once */ + LDAP_SLIST_FOREACH( vai2, &vai->variant->attributes, next ) { + if ( vai == vai2 ) continue; + if ( vai->attr == vai2->attr ) { + ca->reply.err = LDAP_CONSTRAINT_VIOLATION; + return ca->reply.err; + } + } + } + + return LDAP_SUCCESS; +} + +static int +variant_add_alt_attr( ConfigArgs *ca ) +{ + slap_overinst *on = (slap_overinst *)ca->bi; + variant_info_t *ov = on->on_bi.bi_private; + variantEntry_info *vei = + LDAP_STAILQ_LAST( &ov->variants, variantEntry_info, next ); + variantAttr_info *vai; + struct berval dn, ndn; + int rc; + + vai = ch_calloc( 1, sizeof(variantAttr_info) ); + vai->variant = vei; + LDAP_SLIST_ENTRY_INIT( vai, next ); + ca->ca_private = vai; + + ca->value_string = ch_strdup( ca->argv[1] ); + ca->type = VARIANT_ATTR; + rc = variant_set_attribute( ca ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + ca->value_string = ch_strdup( ca->argv[2] ); + ca->type = VARIANT_ATTR_ALT; + rc = variant_set_attribute( ca ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + dn.bv_val = ca->argv[3]; + dn.bv_len = strlen( dn.bv_val ); + rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + ca->type = 0; + BER_BVZERO( &ca->value_dn ); + ca->value_ndn = ndn; + rc = variant_set_alt_dn( ca ); + if ( rc != LDAP_SUCCESS ) { + ch_free( ndn.bv_val ); + goto done; + } + +done: + if ( rc == LDAP_SUCCESS ) { + LDAP_SLIST_INSERT_HEAD( &vei->attributes, vai, next ); + } else { + ca->reply.err = rc; + } + + return rc; +} + +static int +variant_add_alt_attr_regex( ConfigArgs *ca ) +{ + slap_overinst *on = (slap_overinst *)ca->bi; + variant_info_t *ov = on->on_bi.bi_private; + variantEntry_info *vei = + LDAP_STAILQ_LAST( &ov->regex_variants, variantEntry_info, next ); + variantAttr_info *vai; + int rc; + + vai = ch_calloc( 1, sizeof(variantAttr_info) ); + vai->variant = vei; + LDAP_SLIST_ENTRY_INIT( vai, next ); + ca->ca_private = vai; + + ca->value_string = ch_strdup( ca->argv[1] ); + ca->type = VARIANT_ATTR; + rc = variant_set_attribute( ca ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + ca->value_string = ch_strdup( ca->argv[2] ); + ca->type = VARIANT_ATTR_ALT; + rc = variant_set_attribute( ca ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + + ca->type = 0; + ber_str2bv( ca->argv[3], 0, 1, &ca->value_bv ); + rc = variant_set_alt_pattern( ca ); + if ( rc != LDAP_SUCCESS ) { + goto done; + } + +done: + if ( rc == LDAP_SUCCESS ) { + LDAP_SLIST_INSERT_HEAD( &vei->attributes, vai, next ); + } else { + ca->reply.err = rc; + } + + return rc; +} + +static int +variant_ldadd_cleanup( ConfigArgs *ca ) +{ + variantEntry_info *vei = ca->ca_private; + slap_overinst *on = (slap_overinst *)ca->bi; + variant_info_t *ov = on->on_bi.bi_private; + + if ( ca->reply.err != LDAP_SUCCESS ) { + assert( LDAP_SLIST_EMPTY(&vei->attributes) ); + ch_free( vei ); + return LDAP_SUCCESS; + } + + if ( vei->type == VARIANT_INFO_PLAIN ) { + LDAP_STAILQ_INSERT_TAIL(&ov->variants, vei, next); + } else { + LDAP_STAILQ_INSERT_TAIL(&ov->regex_variants, vei, next); + } + + return LDAP_SUCCESS; +} + +static int +variant_ldadd( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) +{ + slap_overinst *on; + variant_info_t *ov; + variantEntry_info *vei; + + if ( cei->ce_type != Cft_Overlay || !cei->ce_bi || + cei->ce_bi->bi_cf_ocs != variant_ocs ) + return LDAP_CONSTRAINT_VIOLATION; + + on = (slap_overinst *)cei->ce_bi; + ov = on->on_bi.bi_private; + + vei = ch_calloc( 1, sizeof(variantEntry_info) ); + vei->ov = ov; + vei->type = VARIANT_INFO_PLAIN; + LDAP_SLIST_INIT(&vei->attributes); + LDAP_STAILQ_ENTRY_INIT(vei, next); + + ca->bi = cei->ce_bi; + ca->ca_private = vei; + config_push_cleanup( ca, variant_ldadd_cleanup ); + /* config_push_cleanup is only run in the case of online config but we use it to + * save the new config when done with the entry */ + ca->lineno = 0; + + return LDAP_SUCCESS; +} + +static int +variant_regex_ldadd( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) +{ + slap_overinst *on; + variant_info_t *ov; + variantEntry_info *vei; + + if ( cei->ce_type != Cft_Overlay || !cei->ce_bi || + cei->ce_bi->bi_cf_ocs != variant_ocs ) + return LDAP_CONSTRAINT_VIOLATION; + + on = (slap_overinst *)cei->ce_bi; + ov = on->on_bi.bi_private; + + vei = ch_calloc( 1, sizeof(variantEntry_info) ); + vei->ov = ov; + vei->type = VARIANT_INFO_REGEX; + LDAP_SLIST_INIT(&vei->attributes); + LDAP_STAILQ_ENTRY_INIT(vei, next); + + ca->bi = cei->ce_bi; + ca->ca_private = vei; + config_push_cleanup( ca, variant_ldadd_cleanup ); + /* config_push_cleanup is only run in the case of online config but we use it to + * save the new config when done with the entry */ + ca->lineno = 0; + + return LDAP_SUCCESS; +} + +static int +variant_attr_ldadd_cleanup( ConfigArgs *ca ) +{ + variantAttr_info *vai = ca->ca_private; + variantEntry_info *vei = vai->variant; + + if ( ca->reply.err != LDAP_SUCCESS ) { + ch_free( vai ); + return LDAP_SUCCESS; + } + + LDAP_SLIST_INSERT_HEAD(&vei->attributes, vai, next); + + return LDAP_SUCCESS; +} + +static int +variant_attr_ldadd( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) +{ + variantEntry_info *vei; + variantAttr_info *vai; + CfEntryInfo *parent = cei->ce_parent; + + if ( cei->ce_type != Cft_Misc || !parent || !parent->ce_bi || + parent->ce_bi->bi_cf_ocs != variant_ocs ) + return LDAP_CONSTRAINT_VIOLATION; + + vei = (variantEntry_info *)cei->ce_private; + + vai = ch_calloc( 1, sizeof(variantAttr_info) ); + vai->variant = vei; + LDAP_SLIST_ENTRY_INIT(vai, next); + + ca->ca_private = vai; + config_push_cleanup( ca, variant_attr_ldadd_cleanup ); + /* config_push_cleanup is only run in the case of online config but we use it to + * save the new config when done with the entry */ + ca->lineno = 0; + + return LDAP_SUCCESS; +} + +static int +variant_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca ) +{ + slap_overinst *on = (slap_overinst *)ca->bi; + variant_info_t *ov = on->on_bi.bi_private; + variantEntry_info *vei; + variantAttr_info *vai; + Entry *e; + struct berval rdn; + int i = 0; + + LDAP_STAILQ_FOREACH( vei, &ov->variants, next ) { + int j = 0; + rdn.bv_len = snprintf( + ca->cr_msg, sizeof(ca->cr_msg), "name={%d}variant", i++ ); + rdn.bv_val = ca->cr_msg; + + ca->ca_private = vei; + e = config_build_entry( + op, rs, p->e_private, ca, &rdn, &variant_ocs[1], NULL ); + assert( e ); + + LDAP_SLIST_FOREACH( vai, &vei->attributes, next ) { + rdn.bv_len = snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "olcVariantVariantAttribute={%d}%s", j++, + vai->attr->ad_cname.bv_val ); + rdn.bv_val = ca->cr_msg; + + ca->ca_private = vai; + config_build_entry( + op, rs, e->e_private, ca, &rdn, &variant_ocs[2], NULL ); + } + } + + LDAP_STAILQ_FOREACH( vei, &ov->regex_variants, next ) { + int j = 0; + rdn.bv_len = snprintf( + ca->cr_msg, sizeof(ca->cr_msg), "name={%d}regex", i++ ); + rdn.bv_val = ca->cr_msg; + + ca->ca_private = vei; + e = config_build_entry( + op, rs, p->e_private, ca, &rdn, &variant_ocs[3], NULL ); + assert( e ); + + LDAP_SLIST_FOREACH( vai, &vei->attributes, next ) { + rdn.bv_len = snprintf( ca->cr_msg, sizeof(ca->cr_msg), + "olcVariantVariantAttribute={%d}%s", j++, + vai->attr->ad_cname.bv_val ); + rdn.bv_val = ca->cr_msg; + + ca->ca_private = vai; + config_build_entry( + op, rs, e->e_private, ca, &rdn, &variant_ocs[4], NULL ); + } + } + return LDAP_SUCCESS; +} + +static slap_overinst variant; + +static int +variant_db_init( BackendDB *be, ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + variant_info_t *ov; + + if ( SLAP_ISGLOBALOVERLAY(be) ) { + Debug( LDAP_DEBUG_ANY, "variant overlay must be instantiated within " + "a database.\n" ); + return 1; + } + + ov = ch_calloc( 1, sizeof(variant_info_t) ); + LDAP_STAILQ_INIT(&ov->variants); + LDAP_STAILQ_INIT(&ov->regex_variants); + + on->on_bi.bi_private = ov; + + return LDAP_SUCCESS; +} + +static int +variant_db_destroy( BackendDB *be, ConfigReply *cr ) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + variant_info_t *ov = on->on_bi.bi_private; + + if ( ov ) { + while ( !LDAP_STAILQ_EMPTY( &ov->variants ) ) { + variantEntry_info *vei = LDAP_STAILQ_FIRST( &ov->variants ); + LDAP_STAILQ_REMOVE_HEAD( &ov->variants, next ); + + while ( !LDAP_SLIST_EMPTY( &vei->attributes ) ) { + variantAttr_info *vai = LDAP_SLIST_FIRST( &vei->attributes ); + LDAP_SLIST_REMOVE_HEAD( &vei->attributes, next ); + + ber_memfree( vai->dn.bv_val ); + ch_free( vai ); + } + ber_memfree( vei->dn.bv_val ); + ch_free( vei ); + } + while ( !LDAP_STAILQ_EMPTY( &ov->regex_variants ) ) { + variantEntry_info *vei = LDAP_STAILQ_FIRST( &ov->regex_variants ); + LDAP_STAILQ_REMOVE_HEAD( &ov->regex_variants, next ); + + while ( !LDAP_SLIST_EMPTY( &vei->attributes ) ) { + variantAttr_info *vai = LDAP_SLIST_FIRST( &vei->attributes ); + LDAP_SLIST_REMOVE_HEAD( &vei->attributes, next ); + + ber_memfree( vai->dn.bv_val ); + ch_free( vai ); + } + ber_memfree( vei->dn.bv_val ); + ch_free( vei ); + } + ch_free( ov ); + } + + return LDAP_SUCCESS; +} + +int +variant_initialize() +{ + int rc; + + variant.on_bi.bi_type = "variant"; + variant.on_bi.bi_db_init = variant_db_init; + variant.on_bi.bi_db_destroy = variant_db_destroy; + + variant.on_bi.bi_op_add = variant_op_add; + variant.on_bi.bi_op_compare = variant_op_compare; + variant.on_bi.bi_op_modify = variant_op_mod; + variant.on_bi.bi_op_search = variant_op_search; + + variant.on_bi.bi_cf_ocs = variant_ocs; + + rc = config_register_schema( variant_cfg, variant_ocs ); + if ( rc ) return rc; + + return overlay_register( &variant ); +} + +#if SLAPD_OVER_VARIANT == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return variant_initialize(); +} +#endif + +#endif /* SLAPD_OVER_VARIANT */ |