ITS#9855 Implement a module to enable case-insensitive Boolean values

Initial implementation of the ciboolean module
This commit is contained in:
Nadezhda Ivanova 2022-07-06 18:32:36 +03:00
parent 5ef2b93119
commit a0a64e0389
12 changed files with 791 additions and 0 deletions

View file

@ -0,0 +1,75 @@
# $OpenLDAP$
# This work is part of OpenLDAP Software <http://www.openldap.org/>.
#
# Copyright 1998-2022 The OpenLDAP Foundation.
# Copyright 2022 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)
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
SRCDIR = ./
LIBTOOL = $(LDAP_BUILD)/libtool
INSTALL = /usr/bin/install
CC = gcc
OPT = -g -O2
DEFS = -DSLAPD_MOD_CIBOOLEAN=SLAPD_MOD_DYNAMIC
INCS = $(LDAP_INC)
LIBS = $(LDAP_LIB)
PROGRAMS = ciboolean.la
MANPAGES = slapo-ciboolean.5
LTVER = 0:0:0
CLEAN = *.o *.lo *.la .libs
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
.SUFFIXES: .c .o .lo
.c.lo:
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(OPT) $(CPPFLAGS) $(DEFS) $(INCS) -c $<
all: $(PROGRAMS)
d :=
sp :=
dir := tests
include $(dir)/Rules.mk
ciboolean.la: ciboolean.lo
$(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -version-info $(LTVER) \
-rpath $(moduledir) -module -o $@ $? $(LIBS)
clean:
rm -rf $(CLEAN)
install: install-lib install-man
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)

View file

@ -0,0 +1,110 @@
/* ciboolean.c - enable case-insensitive boolean values */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1998-2022 The OpenLDAP Foundation.
* Copyright 2022 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>.
*/
/* ACKNOWLEDGEMENTS:
* This work was developed in 2022 by Nadezhda Ivanova for Symas Corp.
*/
#include "portable.h"
#ifdef SLAPD_MOD_CIBOOLEAN
#include "slap.h"
#include "ac/ctype.h"
static int
cibooleanValidate(
Syntax *syntax,
struct berval *in )
{
/* Allow for case insensitive comparison with TRUE and FALSE */
struct berval bv;
int i;
if( in->bv_len == slap_true_bv.bv_len ) {
bv = slap_true_bv;
} else if( in->bv_len == slap_false_bv.bv_len ) {
bv = slap_false_bv;
} else {
return LDAP_INVALID_SYNTAX;
}
if ( ber_bvstrcasecmp( in, &bv ) != 0 ) {
return LDAP_INVALID_SYNTAX;
}
return LDAP_SUCCESS;
}
static int
cibooleanMatchNormalize(
slap_mask_t use,
Syntax *syntax,
MatchingRule *mr,
struct berval *val,
struct berval *normalized,
void *ctx )
{
struct berval nvalue;
ber_len_t i;
assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
if ( BER_BVISNULL( val ) ) {
return LDAP_INVALID_SYNTAX;
}
nvalue.bv_len = val->bv_len;
nvalue.bv_val = slap_sl_malloc( nvalue.bv_len + 1, ctx );
nvalue.bv_val[nvalue.bv_len] = '\0';
for ( i = 0; i < nvalue.bv_len; i++ ) {
nvalue.bv_val[i] = TOUPPER( val->bv_val[i] );
}
*normalized = nvalue;
return LDAP_SUCCESS;
}
int ciboolean_initialize()
{
MatchingRule *bm = mr_find( "2.5.13.13" );
Syntax *syn = syn_find( "1.3.6.1.4.1.1466.115.121.1.7" );
if ( bm == NULL ) {
Debug( LDAP_DEBUG_ANY,
"ciboolean_initialize: unable to find booleanMatch matching rule\n");
return -1;
}
if ( syn == NULL ) {
Debug( LDAP_DEBUG_ANY,
"ciboolean_initialize: unable to find Boolean syntax\n");
return -1;
}
bm->smr_normalize = cibooleanMatchNormalize;
syn->ssyn_validate = cibooleanValidate;
return 0;
}
#if SLAPD_MOD_CIBOOLEAN == SLAPD_MOD_DYNAMIC
int init_module(int argc, char *argv[])
{
return ciboolean_initialize();
}
#endif
#endif /* SLAPD_MOD_CIBOOLEAN */

View file

@ -0,0 +1,75 @@
.TH SLAPO-CIBOOLEAN 5 "RELEASEDATE" "OpenLDAP"
.\" Copyright 1998-2022 The OpenLDAP Foundation.
.\" Copyright 2022 Symas Corp. All Rights Reserved.
.\" Copying restrictions apply. See LICENSE.
.SH NAME
slapo\-ciboolean \- enable support for case-insensitive boolean values
.SH SYNOPSIS
By default
.BR slapd (8)
is strictly compliant with
.B RFC4517
and the only accepted values for a Boolean attribute are
.B TRUE
and
.B FALSE.
This module allows for case-insensitive comparison and syntax-checking.
.SH DESCRIPTION
The
.B ciboolean
module to
.BR slapd (8)
allows Boolean-type attributes to have values such as
.B True, False, true, false,
and any other combination of upper and lower-case values. Comparison is also case-insensitive, so a search filter of
.B (attribute=false)
will return objects with all versions of
.B FALSE.
When the module is loaded, it installs a new syntax-checker and a new normalizer in the
.B Boolean
syntax.
.SH CONFIGURATION
The
.B ciboolean
module does not have any configuration directives. To enable it, instruct the server to load it with the
.B moduleload
directive in
.B slapd.conf:
.TP
.B moduleload /usr/local/libexec/openldap/ciboolean.la
.SH LIMITATIONS
Adding a normalizer to the syntax changes value storage format in most backend types.
Removing the
.B ciboolean
module from
.BR slapd(8)
configuration will not automatically convert any non-standard values to
.B TRUE
or
.B FALSE,
or update value storage format. Therefore, if
.B ciboolean
is added or removed in configuration, all databases that have been in use before the change need to be fully reloaded to ensure correct operation, including
.B cn=config.
.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 (8)
.SH ACKNOWLEDGEMENTS
This module was developed in 2022 by Nadezhda Ivanova for Symas Corp.

View file

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

View file

@ -0,0 +1,23 @@
sp := $(sp).x
dirstack_$(sp) := $(d)
d := $(dir)
.PHONY: test
CLEAN += clients servers tests/progs tests/schema tests/testdata tests/testrun
test: all clients servers tests/progs
test:
cd tests; \
SRCDIR=$(abspath $(LDAP_SRC)) \
LDAP_BUILD=$(abspath $(LDAP_BUILD)) \
TOPDIR=$(abspath $(SRCDIR)) \
LIBTOOL=$(abspath $(LIBTOOL)) \
$(abspath $(SRCDIR))/tests/run test001-ciboolean
servers clients tests/progs:
ln -s $(abspath $(LDAP_BUILD))/$@ $@
d := $(dirstack_$(sp))
sp := $(basename $(sp))

View file

@ -0,0 +1,10 @@
attributetype (1.3.6.1.4.1.4203.1.12.1.1.7 NAME 'IsBusy'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
SINGLE-VALUE)
objectclass ( 1.3.6.1.4.1.4203.1.12.1.2.3 NAME 'BusyClass'
SUP top
AUXILIARY
MAY ( IsBusy ))

View file

@ -0,0 +1,36 @@
# provider slapd config -- for testing
# $OpenLDAP$
include @SCHEMADIR@/core.schema
include @SCHEMADIR@/cosine.schema
include @SCHEMADIR@/inetorgperson.schema
include data/booleantest.schema
pidfile @TESTDIR@/slapd.m.pid
argsfile @TESTDIR@/slapd.m.args
moduleload ../ciboolean.la
pidfile testrun/slapd.pid
#######################################################################
# database definitions
#######################################################################
database mdb
suffix "dc=example,dc=com"
directory testrun
# root or superuser
rootdn "cn=Manager,dc=example,dc=com"
rootpw secret
database config
rootdn "cn=manager,cn=config"
rootpw secret
database monitor

View file

@ -0,0 +1,111 @@
dn: dc=example,dc=com
objectClass: top
objectClass: organization
objectClass: domainRelatedObject
objectClass: dcObject
dc: example
l: Anytown, Michigan
st: Michigan
o: Example, Inc.
o: EX
o: Ex.
description: The Example, Inc. at Anytown
postalAddress: Example, Inc. $ 535 W. William St. $ Anytown, MI 48109 $ US
telephoneNumber: +1 313 555 1817
associatedDomain: example.com
dn: ou=people,dc=example,dc=com
objectClass: organizationalUnit
ou: people
description: All domain members
dn: cn=user01,ou=people,dc=example,dc=com
cn: user01
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 101
carLicense: 1234ha
sn: user01
mobile: 12345678
mobile: 987654321
IsBusy: FaLse
ou: people
preferredLanguage: English
description: This is user user01
dn: cn=user02,ou=people,dc=example,dc=com
cn: user02
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 102
carLicense: 1234hb
sn: user02
mobile: 12345678
mobile: 987654321
IsBusy: False
ou: people
preferredLanguage: English
description: This is user user02
dn: cn=user03,ou=people,dc=example,dc=com
cn: user03
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 103
carLicense: 1234hc
sn: user03
mobile: 12345678
mobile: 987654321
IsBusy: FALSE
ou: people
preferredLanguage: English
description: This is user user03
dn: cn=user04,ou=people,dc=example,dc=com
cn: user04
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 104
carLicense: 1234ha
sn: user04
mobile: 12345678
mobile: 987654321
IsBusy: TRue
ou: people
preferredLanguage: English
description: This is user user04
dn: cn=user05,ou=people,dc=example,dc=com
cn: user05
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 105
carLicense: 1234hb
sn: user05
mobile: 12345678
mobile: 987654321
IsBusy: True
ou: people
preferredLanguage: English
description: This is user user05
dn: cn=user06,ou=people,dc=example,dc=com
cn: user06
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 106
carLicense: 1234hc
sn: user06
mobile: 12345678
mobile: 987654321
IsBusy: TRUE
ou: people
preferredLanguage: English
description: This is user user03

View file

@ -0,0 +1,45 @@
dn: cn=user02,ou=people,dc=example,dc=com
cn: user02
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 102
carLicense: 1234hb
sn: user02
mobile: 12345678
mobile: 987654321
IsBusy: False
ou: people
preferredLanguage: English
description: This is user user02
dn: cn=user03,ou=people,dc=example,dc=com
cn: user03
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 103
carLicense: 1234hc
sn: user03
mobile: 12345678
mobile: 987654321
IsBusy: FALSE
ou: people
preferredLanguage: English
description: This is user user03
dn: cn=user06,ou=people,dc=example,dc=com
cn: user06
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 106
carLicense: 1234hc
sn: user06
mobile: 12345678
mobile: 987654321
ou: people
preferredLanguage: English
description: This is user user03
IsBusy: false

View file

@ -0,0 +1,45 @@
dn: cn=user01,ou=people,dc=example,dc=com
cn: user01
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 101
carLicense: 1234ha
sn: user01
mobile: 12345678
mobile: 987654321
ou: people
preferredLanguage: English
description: This is user user01
IsBusy: TRUE
dn: cn=user04,ou=people,dc=example,dc=com
cn: user04
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 104
carLicense: 1234ha
sn: user04
mobile: 12345678
mobile: 987654321
IsBusy: TRue
ou: people
preferredLanguage: English
description: This is user user04
dn: cn=user05,ou=people,dc=example,dc=com
cn: user05
objectClass: inetOrgPerson
objectClass: BusyClass
userPassword:: UEBzc3cwcmQ=
roomNumber: 105
carLicense: 1234hb
sn: user05
mobile: 12345678
mobile: 987654321
IsBusy: True
ou: people
preferredLanguage: English
description: This is user user05

View file

@ -0,0 +1,17 @@
#!/bin/sh
## $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2022 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
TOPSRCDIR="$SRCDIR" OBJDIR="${LDAP_BUILD}" SRCDIR="${SRCDIR}/tests" DEFSDIR="${SRCDIR}/scripts" SCRIPTDIR="${TOPDIR}/tests/scripts" "${LDAP_BUILD}/tests/run" $*

View file

@ -0,0 +1,240 @@
#! /bin/sh
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2022 The OpenLDAP Foundation.
## Copyright 2022 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>.
##
## ACKNOWLEDGEMENTS:
## This work was developed in 2022 by Nadezhda Ivanova for Symas Corp.
echo "running defines.sh"
. $SRCDIR/scripts/defines.sh
echo ""
rm -rf $TESTDIR
mkdir -p $TESTDIR $DBDIR1
echo "Starting slapd on TCP/IP port $PORT1..."
. $CONFFILTER $BACKEND < data/slapd.conf > $CONF1
$SLAPD -f $CONF1 -h $URI1 -d $LVL > $LOG1 2>&1 &
PID=$!
if test $WAIT != 0 ; then
echo PID $PID
read foo
fi
KILLPIDS="$PID"
sleep 1
echo "Using ldapsearch to check that slapd is running..."
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 5 seconds for slapd to start..."
sleep 5
done
if test $RC != 0 ; then
echo "ldapsearch failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Using ldapadd to populate the database..."
$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD < \
data/test001-add.ldif > $TESTOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
cat /dev/null > $SEARCHOUT
echo "Searching base=\"$BASEDN\"..."
echo "# searching base=\"$BASEDN\"..." >> $SEARCHOUT
$LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" >> $SEARCHOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "Search failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Filtering ldapsearch results..."
$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
echo "Filtering original ldif used to create database..."
$LDIFFILTER < data/test001-add.ldif > $LDIFFLT
echo "Comparing filter output..."
$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
if test $? != 0 ; then
echo "comparison failed - database population didn't succeed"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
#
# Do some modifications
#
echo "Modifying database \"$BASEDN\" with TRUE..."
$LDAPMODIFY -v -D "cn=Manager,$BASEDN" -H $URI1 -w $PASSWD \
-M >> $TESTOUT 2>&1 << EOMODS
dn: cn=user01,ou=people,$BASEDN
changetype: modify
replace: IsBusy
IsBusy: TRUE
EOMODS
RC=$?
if test $RC != 0 ; then
echo "Modify failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Modifying database \"$BASEDN\" with false..."
$LDAPMODIFY -v -D "cn=Manager,$BASEDN" -H $URI1 -w $PASSWD \
-M >> $TESTOUT 2>&1 << EOMODS
dn: cn=user06,ou=people,$BASEDN
changetype: modify
replace: IsBusy
IsBusy: false
EOMODS
RC=$?
if test $RC != 0 ; then
echo "Modify failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Modifying database \"$BASEDN\"with TRUA..."
$LDAPMODIFY -v -D "cn=Manager,$BASEDN" -H $URI1 -w $PASSWD \
-M >> $TESTOUT 2>&1 << EOMODS
dn: cn=user02,ou=people,$BASEDN
changetype: modify
replace: IsBusy
IsBusy: TRUA
EOMODS
RC=$?
if test $RC != 21 ; then
echo "Modify with an incorrect value failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
cat /dev/null > $SEARCHOUT
echo " base=\"$BASEDN\"..."
echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
$LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" -M "(IsBusy=false)" '*' ref \
>> $SEARCHOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "Search failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Filtering ldapsearch results..."
$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
echo "Filtering partial ldif used to create database..."
$LDIFFILTER < data/test001-search_1.ldif > $LDIFFLT
echo "Comparing filter output..."
$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
if test $? != 0 ; then
echo "comparison failed - search for (IsBusy=false) didn't succeed"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
cat /dev/null > $SEARCHOUT
echo " base=\"$BASEDN\"..."
echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
$LDAPSEARCH -S "" -H $URI1 -b "$BASEDN" -M "(IsBusy=TRUE)" '*' ref \
>> $SEARCHOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "Search failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Filtering ldapsearch results..."
$LDIFFILTER < $SEARCHOUT > $SEARCHFLT
echo "Filtering partial ldif used to create database..."
$LDIFFILTER < data/test001-search_2.ldif > $LDIFFLT
echo "Comparing filter output..."
$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
if test $? != 0 ; then
echo "comparison failed - search for (IsBusy=TRUE) didn't succeed"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
echo "Modifying cn=config, setting olcReadOnly to True"
$LDAPMODIFY -v -D "cn=manager,cn=config" -H $URI1 -w $PASSWD \
-M >> $TESTOUT 2>&1 << EOMODS
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcReadOnly
olcReadOnly: True
EOMODS
RC=$?
if test $RC != 0 ; then
echo "Modify failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Modifying database \"$BASEDN\" to verify olcReadOnly value"
$LDAPMODIFY -v -D "cn=Manager,$BASEDN" -H $URI1 -w $PASSWD \
-M >> $TESTOUT 2>&1 << EOMODS
dn: cn=user06,ou=people,$BASEDN
changetype: modify
replace: IsBusy
IsBusy: false
EOMODS
RC=$?
if test $RC != 53 ; then
echo "Modify 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