openldap/tests/scripts/test090-auditlog
Arran Cudbard-Bell 163da8d217
slapo-auditlog: Add olcAuditlogNonBlocking to avoid blocking when logging to named pipes
The default behaviour of fopen() when called on a named pipe which does not have any reader, is to block, until a reader opens the pipe.  This blocks slapo-auditlog when it attempts to write output.  Depending on how critical the audit log  is, it may be preferable to discard audit log output and continue processing requests if there's no reader available.

For clarity the call to fopen() is removed and replaced with open()/fdopen(), allowing us to specify O_* flags as opposed to using fopen() or open()/fdopen(). 0666 are the base permissions used by fopen() when files are created.
2025-07-03 11:18:51 -06:00

419 lines
10 KiB
Bash
Executable file

#! /bin/sh
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2025 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>.
echo "running defines.sh"
. $SRCDIR/scripts/defines.sh
if test $AUDITLOG = auditlogno; then
echo "Auditlog overlay not available, test skipped"
exit 0
fi
mkdir -p $TESTDIR $DBDIR1 $TESTDIR/confdir
$SLAPPASSWD -g -n >$CONFIGPWF
echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
echo "Starting slapd on TCP/IP port $PORT1..."
. $CONFFILTER $BACKEND < $NAKEDCONF > $CONF1
$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 1
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
cat /dev/null > $TESTOUT
if [ "$AUDITLOG" = auditlogmod ]; then
echo "Inserting auditlog overlay on provider..."
$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: ../servers/slapd/overlays
olcModuleLoad: auditlog.la
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed for moduleLoad ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
fi
indexInclude="" mainInclude="" nullExclude=""
test $INDEXDB = indexdb || indexInclude="# "
test $MAINDB = maindb || mainInclude="# "
case $BACKEND in
null) nullExclude="# " ;;
esac
AUDITLOGFILE="$TESTDIR/audit.log"
echo "Running ldapadd to build slapd config database..."
$LDAPADD -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \
>> $TESTOUT 2>&1 <<EOF
dn: olcDatabase={1}$BACKEND,cn=config
objectClass: olcDatabaseConfig
${nullExclude}objectClass: olc${BACKEND}Config
olcDatabase: {1}$BACKEND
olcSuffix: $BASEDN
olcRootDN: cn=Manager,$BASEDN
olcRootPW:: c2VjcmV0
olcMonitoring: TRUE
${nullExclude}olcDbDirectory: $TESTDIR/db.1.a/
${indexInclude}olcDbIndex: objectClass eq
${indexInclude}olcDbIndex: cn pres,eq,sub
${indexInclude}olcDbIndex: uid pres,eq,sub
${indexInclude}olcDbIndex: sn pres,eq,sub
${mainInclude}olcDbMode: 384
dn: olcOverlay={0}auditlog,olcDatabase={1}$BACKEND,cn=config
objectClass: olcOverlayConfig
objectClass: olcAuditlogConfig
olcOverlay: {0}auditlog
olcAuditlogFile: $AUDITLOGFILE
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Running ldapadd to build slapd database..."
$LDAPADD -H $URI1 \
-D "cn=Manager,$BASEDN" -w secret \
>> $TESTOUT 2>&1 << EOF
dn: $BASEDN
objectClass: organization
objectClass: dcObject
o: Example, Inc.
dc: example
dn: ou=People,$BASEDN
objectClass: organizationalUnit
ou: People
dn: cn=John Doe,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: John Doe
sn: Doe
givenName: John
mail: john.doe@example.com
dn: cn=Jane Smith,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: Jane Smith
sn: Smith
givenName: Jane
mail: jane.smith@example.com
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Testing ADD operations are logged..."
$LDAPADD -H $URI1 \
-D "cn=Manager,$BASEDN" -w secret \
>> $TESTOUT 2>&1 << EOF
dn: cn=Bob Jones,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: Bob Jones
sn: Jones
givenName: Bob
mail: bob.jones@example.com
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Verifying ADD operation was logged..."
grep "# add " "$AUDITLOGFILE" > /dev/null
RC=$?
if test $RC != 0 ; then
echo "Auditlog does not contain ADD operations!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
grep "cn=Bob Jones" "$AUDITLOGFILE" > /dev/null
RC=$?
if test $RC != 0 ; then
echo "Auditlog does not contain Bob Jones ADD entry!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
echo "Testing MODIFY operations are logged..."
$LDAPMODIFY -H $URI1 \
-D "cn=Manager,$BASEDN" -w secret \
>> $TESTOUT 2>&1 << EOF
dn: cn=John Doe,ou=People,$BASEDN
changetype: modify
replace: mail
mail: john.doe.new@example.com
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapmodify failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Verifying MODIFY operation was logged..."
grep "# modify " "$AUDITLOGFILE" > /dev/null
RC=$?
if test $RC != 0 ; then
echo "Auditlog does not contain MODIFY operations!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
grep "john.doe.new@example.com" "$AUDITLOGFILE" > /dev/null
RC=$?
if test $RC != 0 ; then
echo "Auditlog does not contain the modified email address!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
echo "Testing MODRDN operations are logged..."
$LDAPMODIFY -H $URI1 \
-D "cn=Manager,$BASEDN" -w secret \
>> $TESTOUT 2>&1 << EOF
dn: cn=Jane Smith,ou=People,$BASEDN
changetype: modrdn
newrdn: cn=Jane Brown
deleteoldrdn: 1
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapmodify modrdn failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Verifying MODRDN operation was logged..."
grep "# modrdn " "$AUDITLOGFILE" > /dev/null
RC=$?
if test $RC != 0 ; then
echo "Auditlog does not contain MODRDN operations!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
grep "newrdn: cn=Jane Brown" "$AUDITLOGFILE" > /dev/null
RC=$?
if test $RC != 0 ; then
echo "Auditlog does not contain the new RDN!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
echo "Testing DELETE operations are logged..."
$LDAPMODIFY -H $URI1 \
-D "cn=Manager,$BASEDN" -w secret \
>> $TESTOUT 2>&1 << EOF
dn: cn=Bob Jones,ou=People,$BASEDN
changetype: delete
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapmodify failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Verifying DELETE operation was logged..."
grep "# delete " "$AUDITLOGFILE" > /dev/null
RC=$?
if test $RC != 0 ; then
echo "Auditlog does not contain DELETE operations!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
echo "Cleaning up audit log"
rm -f "$AUDITLOGFILE"
if test "$OS_WINDOWS" == "yes"; then
echo "Skipping non-blocking tests on Windows..."
else
echo "Creating named pipe for blocking/non-blocking test"
PIPEFILE="$TESTDIR/audit.pipe"
mknod "$PIPEFILE" p
echo "Testing non-blocking mode configuration..."
$LDAPMODIFY -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \
>> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}auditlog,olcDatabase={1}$BACKEND,cn=config
changetype: modify
replace: olcAuditlogFile
olcAuditlogFile: $PIPEFILE
-
replace: olcAuditlogNonBlocking
olcAuditlogNonBlocking: TRUE
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapmodify failed for non-blocking config ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Testing operation with non-blocking mode and no pipe reader (should succeed)..."
$LDAPADD -H $URI1 \
-D "cn=Manager,$BASEDN" -w secret \
>> $TESTOUT 2>&1 << EOF
dn: cn=NonBlocking Test,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: NonBlocking Test
sn: Test
givenName: NonBlocking
mail: nonblocking.test@example.com
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed with non-blocking mode and no reader ($RC)! This should have succeeded."
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Now testing non-blocking mode with pipe reader available..."
cat $PIPEFILE > $TESTDIR/pipe.log &
CATPID=$!
echo "Adding entry with non-blocking mode and active reader..."
$LDAPADD -H $URI1 \
-D "cn=Manager,$BASEDN" -w secret \
>> $TESTOUT 2>&1 << EOF
dn: cn=Test User,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: Test User
sn: User
givenName: Test
mail: test.user@example.com
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed with non-blocking mode and reader ($RC)!"
kill $CATPID 2>/dev/null
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Verifying entry was logged to named pipe..."
sleep 1
kill $CATPID 2>/dev/null
wait $CATPID 2>/dev/null
if [ ! -f $TESTDIR/pipe.log ]; then
echo "Named pipe log file was not created!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
grep "cn=Test User" $TESTDIR/pipe.log > /dev/null
RC=$?
if test $RC != 0 ; then
echo "Auditlog does not contain new entries with non-blocking mode and reader!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit 1
fi
echo "Testing blocking mode and no pipe reader (should timeout)..."
$LDAPMODIFY -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \
>> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}auditlog,olcDatabase={1}$BACKEND,cn=config
changetype: modify
replace: olcAuditlogFile
olcAuditlogFile: $PIPEFILE
-
replace: olcAuditlogNonBlocking
olcAuditlogNonBlocking: FALSE
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapmodify failed for blocking config ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Adding entry with blocking mode and no active reader..."
timeout 1 $LDAPADD -H $URI1 \
-D "cn=Manager,$BASEDN" -w secret \
>> $TESTOUT 2>&1 << EOF
dn: cn=Blocking Test,ou=People,$BASEDN
objectClass: inetOrgPerson
cn: Blocking Test
sn: Test
givenName: Blocking
mail: blocking.test@example.com
EOF
RC=$?
if test $RC != 124 ; then
echo "Blocking mode result: $BLOCKING_RC (should be timeout/error)"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
# Briefly open the pipe, so that blocking writes are unblocked, and we can kill slapd cleanly
exec 3<>"$PIPEFILE"
echo "Cleaning up named pipe and audit logs..."
rm -f $PIPEFILE $TESTDIR/pipe.log "$AUDITLOGFILE"
fi
test $KILLSERVERS != no && kill -HUP $KILLPIDS
echo ">>>>> Test succeeded"
test $KILLSERVERS != no && wait
exit 0