1#! /bin/sh
2# $OpenLDAP$
3## This work is part of OpenLDAP Software <http://www.openldap.org/>.
4##
5## Copyright 1998-2021 The OpenLDAP Foundation.
6## All rights reserved.
7##
8## Redistribution and use in source and binary forms, with or without
9## modification, are permitted only as authorized by the OpenLDAP
10## Public License.
11##
12## A copy of this license is available in the file LICENSE in the
13## top-level directory of the distribution or, alternatively, at
14## <http://www.OpenLDAP.org/license.html>.
15
16echo "running defines.sh"
17. $SRCDIR/scripts/defines.sh
18
19if test $SYNCPROV = syncprovno; then
20	echo "Syncrepl provider overlay not available, test skipped"
21	exit 0
22fi
23if test $ACCESSLOG = accesslogno; then
24	echo "Accesslog overlay not available, test skipped"
25	exit 0
26fi
27
28MMR=2
29
30XDIR=$TESTDIR/srv
31TMP=$TESTDIR/tmp
32
33mkdir -p $TESTDIR
34
35$SLAPPASSWD -g -n >$CONFIGPWF
36
37if test x"$SYNCMODE" = x ; then
38	SYNCMODE=rp
39fi
40case "$SYNCMODE" in
41	ro)
42		SYNCTYPE="type=refreshOnly interval=00:00:00:03"
43		;;
44	rp)
45		SYNCTYPE="type=refreshAndPersist interval=00:00:00:03"
46		;;
47	*)
48		echo "unknown sync mode $SYNCMODE"
49		exit 1;
50		;;
51esac
52
53#
54# Test delta-sync mmr
55# - start servers
56# - configure over ldap
57# - populate over ldap
58# - configure syncrepl over ldap
59# - break replication
60# - modify each server separately
61# - restore replication
62# - compare results
63#
64
65nullExclude=""
66test $BACKEND = null && nullExclude="# "
67
68KILLPIDS=
69
70echo "Initializing server configurations..."
71n=1
72while [ $n -le $MMR ]; do
73
74DBDIR=${XDIR}$n/db
75CFDIR=${XDIR}$n/slapd.d
76
77mkdir -p ${XDIR}$n $DBDIR.1 $DBDIR.2 $CFDIR
78
79o=`expr 3 - $n`
80cat > $TMP <<EOF
81dn: cn=config
82objectClass: olcGlobal
83cn: config
84olcServerID: $n
85
86EOF
87
88if [ "$SYNCPROV" = syncprovmod -o "$ACCESSLOG" = accesslogmod ]; then
89  cat <<EOF >> $TMP
90dn: cn=module,cn=config
91objectClass: olcModuleList
92cn: module
93olcModulePath: $TESTWD/../servers/slapd/overlays
94EOF
95  if [ "$SYNCPROV" = syncprovmod ]; then
96  echo "olcModuleLoad: syncprov.la" >> $TMP
97  fi
98  if [ "$ACCESSLOG" = accesslogmod ]; then
99  echo "olcModuleLoad: accesslog.la" >> $TMP
100  fi
101  echo "" >> $TMP
102fi
103
104if [ "$BACKENDTYPE" = mod ]; then
105cat <<EOF >> $TMP
106dn: cn=module,cn=config
107objectClass: olcModuleList
108cn: module
109olcModulePath: $TESTWD/../servers/slapd/back-$BACKEND
110olcModuleLoad: back_$BACKEND.la
111
112EOF
113fi
114MYURI=`eval echo '$URI'$n`
115PROVIDERURI=`eval echo '$URI'$o`
116if test $INDEXDB = indexdb ; then
117INDEX1="olcDbIndex: objectClass,entryCSN,reqStart,reqDN,reqResult eq"
118INDEX2="olcDbIndex: objectClass,entryCSN,entryUUID eq"
119else
120INDEX1=
121INDEX2=
122fi
123cat >> $TMP <<EOF
124dn: cn=schema,cn=config
125objectclass: olcSchemaconfig
126cn: schema
127
128include: file://$ABS_SCHEMADIR/core.ldif
129
130include: file://$ABS_SCHEMADIR/cosine.ldif
131
132include: file://$ABS_SCHEMADIR/inetorgperson.ldif
133
134include: file://$ABS_SCHEMADIR/openldap.ldif
135
136include: file://$ABS_SCHEMADIR/nis.ldif
137
138dn: olcDatabase={0}config,cn=config
139objectClass: olcDatabaseConfig
140olcDatabase: {0}config
141olcRootPW:< file://$CONFIGPWF
142
143dn: olcDatabase={1}$BACKEND,cn=config
144objectClass: olcDatabaseConfig
145${nullExclude}objectClass: olc${BACKEND}Config
146olcDatabase: {1}$BACKEND
147olcSuffix: cn=log
148${nullExclude}olcDbDirectory: ${DBDIR}.1
149olcRootDN: $MANAGERDN
150$INDEX1
151
152dn: olcOverlay=syncprov,olcDatabase={1}$BACKEND,cn=config
153objectClass: olcOverlayConfig
154objectClass: olcSyncProvConfig
155olcOverlay: syncprov
156olcSpNoPresent: TRUE
157olcSpReloadHint: TRUE
158
159dn: olcDatabase={2}$BACKEND,cn=config
160objectClass: olcDatabaseConfig
161${nullExclude}objectClass: olc${BACKEND}Config
162olcDatabase: {2}$BACKEND
163olcSuffix: $BASEDN
164${nullExclude}olcDbDirectory: ${DBDIR}.2
165olcRootDN: $MANAGERDN
166olcRootPW: $PASSWD
167olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
168  credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE retry="3 +" timeout=3
169olcMirrorMode: TRUE
170$INDEX2
171
172dn: olcOverlay=syncprov,olcDatabase={2}$BACKEND,cn=config
173objectClass: olcOverlayConfig
174objectClass: olcSyncProvConfig
175olcOverlay: syncprov
176olcSpSessionlogSource: cn=log
177
178dn: olcOverlay=accesslog,olcDatabase={2}$BACKEND,cn=config
179objectClass: olcOverlayConfig
180objectClass: olcAccessLogConfig
181olcOverlay: accesslog
182olcAccessLogDB: cn=log
183olcAccessLogOps: writes
184olcAccessLogSuccess: TRUE
185
186EOF
187$SLAPADD -F $CFDIR -n 0  -d-1< $TMP > $TESTOUT 2>&1
188PORT=`eval echo '$PORT'$n`
189echo "Starting server $n on TCP/IP port $PORT..."
190cd ${XDIR}${n}
191LOG=`eval echo '$LOG'$n`
192$SLAPD -F slapd.d -h $MYURI -d $LVL > $LOG 2>&1 &
193PID=$!
194if test $WAIT != 0 ; then
195    echo PID $PID
196    read foo
197fi
198KILLPIDS="$PID $KILLPIDS"
199cd $TESTWD
200
201echo "Using ldapsearch to check that server $n is running..."
202for i in 0 1 2 3 4 5; do
203	$LDAPSEARCH -s base -b "" -H $MYURI \
204		'objectclass=*' > /dev/null 2>&1
205	RC=$?
206	if test $RC = 0 ; then
207		break
208	fi
209	echo "Waiting 5 seconds for slapd to start..."
210	sleep 5
211done
212
213if test $RC != 0 ; then
214	echo "ldapsearch failed ($RC)!"
215	test $KILLSERVERS != no && kill -HUP $KILLPIDS
216	exit $RC
217fi
218
219if [ $n = 1 ]; then
220echo "Using ldapadd for context on server 1..."
221$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDEREDCP \
222	>> $TESTOUT 2>&1
223RC=$?
224if test $RC != 0 ; then
225	echo "ldapadd failed for server $n database ($RC)!"
226	test $KILLSERVERS != no && kill -HUP $KILLPIDS
227	exit $RC
228fi
229fi
230
231n=`expr $n + 1`
232done
233
234echo "Using ldapadd to populate server 1..."
235$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDEREDNOCP \
236	>> $TESTOUT 2>&1
237RC=$?
238if test $RC != 0 ; then
239	echo "ldapadd failed for server 1 database ($RC)!"
240	test $KILLSERVERS != no && kill -HUP $KILLPIDS
241	exit $RC
242fi
243
244echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
245sleep $SLEEP1
246
247n=1
248while [ $n -le $MMR ]; do
249URI=`eval echo '$URI'$n`
250
251echo "Using ldapsearch to read all the entries from server $n..."
252$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD  \
253	'objectclass=*' > $TESTDIR/server$n.out 2>&1
254RC=$?
255
256if test $RC != 0 ; then
257	echo "ldapsearch failed at server $n ($RC)!"
258	test $KILLSERVERS != no && kill -HUP $KILLPIDS
259	exit $RC
260fi
261$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
262n=`expr $n + 1`
263done
264
265n=2
266while [ $n -le $MMR ]; do
267echo "Comparing retrieved entries from server 1 and server $n..."
268$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
269
270if test $? != 0 ; then
271	echo "test failed - server 1 and server $n databases differ"
272	test $KILLSERVERS != no && kill -HUP $KILLPIDS
273	exit 1
274fi
275n=`expr $n + 1`
276done
277
278echo "Using ldapadd to populate server 2..."
279$LDAPADD -D "$MANAGERDN" -H $URI2 -w $PASSWD -f $LDIFADD1 \
280	>> $TESTOUT 2>&1
281RC=$?
282if test $RC != 0 ; then
283	echo "ldapadd failed for server 2 database ($RC)!"
284	test $KILLSERVERS != no && kill -HUP $KILLPIDS
285	exit $RC
286fi
287
288THEDN="cn=James A Jones 2,ou=Alumni Association,ou=People,dc=example,dc=com"
289sleep 1
290for i in 1 2 3; do
291	$LDAPSEARCH -S "" -b "$THEDN" -H $URI1 \
292		-s base '(objectClass=*)' entryCSN > "${PROVIDEROUT}.$i" 2>&1
293	RC=$?
294
295	if test $RC = 0 ; then
296		break
297	fi
298
299	if test $RC != 32 ; then
300		echo "ldapsearch failed at slave ($RC)!"
301		test $KILLSERVERS != no && kill -HUP $KILLPIDS
302		exit $RC
303	fi
304
305	echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
306	sleep $SLEEP1
307done
308
309n=1
310while [ $n -le $MMR ]; do
311URI=`eval echo '$URI'$n`
312
313echo "Using ldapsearch to read all the entries from server $n..."
314$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD  \
315	'objectclass=*' > $TESTDIR/server$n.out 2>&1
316RC=$?
317
318if test $RC != 0 ; then
319	echo "ldapsearch failed at server $n ($RC)!"
320	test $KILLSERVERS != no && kill -HUP $KILLPIDS
321	exit $RC
322fi
323$LDIFFILTER < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
324n=`expr $n + 1`
325done
326
327n=2
328while [ $n -le $MMR ]; do
329echo "Comparing retrieved entries from server 1 and server $n..."
330$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
331
332if test $? != 0 ; then
333	echo "test failed - server 1 and server $n databases differ"
334	test $KILLSERVERS != no && kill -HUP $KILLPIDS
335	exit 1
336fi
337n=`expr $n + 1`
338done
339
340echo "Retrieving syncrepl cookie..."
341cookie=`$LDAPRSEARCH -b "$BASEDN" -D "$MANAGERDN" -H $URI1 -w $PASSWD \
342    -E "sync=ro" 'objectclass=*' 1.1 | grep cookie | sed "s/.*cookie: //"`
343
344if test -z "$cookie"; then
345	echo "Failed to retrieve cookie from server!"
346	test $KILLSERVERS != no && kill -HUP $KILLPIDS
347	exit 1
348fi
349
350echo "Deleting an entry from server 1..."
351$LDAPDELETE -D "$MANAGERDN" -H $URI1 -w $PASSWD \
352    "cn=Mark Elliot,ou=Alumni Association,ou=People,$BASEDN" \
353	>> $TESTOUT 2>&1
354RC=$?
355if test $RC != 0 ; then
356	echo "ldapdelete failed for server 1 database ($RC)!"
357	test $KILLSERVERS != no && kill -HUP $KILLPIDS
358	exit $RC
359fi
360
361
362echo "Restarting servers..."
363kill -HUP $KILLPIDS
364wait
365KILLPIDS=""
366n=1
367while [ $n -le $MMR ]; do
368o=`expr 3 - $n`
369MYURI=`eval echo '$URI'$n`
370PROVIDERURI=`eval echo '$URI'$o`
371
372echo "Starting server $n again..."
373cd ${XDIR}${n}
374LOG=`eval echo '$LOG'$n`
375echo "RESTART" >> $LOG
376#if test $n = 2; then
377#echo $SLAPD -F slapd.d -h $MYURI -d $LVL
378#else
379$SLAPD -F slapd.d -h $MYURI -d $LVL > $LOG 2>&1 &
380#fi
381PID=$!
382if test $WAIT != 0 ; then
383    echo PID $PID
384    read foo
385fi
386KILLPIDS="$PID $KILLPIDS"
387cd $TESTWD
388
389echo "Using ldapsearch to check that server $n is running..."
390for i in 0 1 2 3 4 5; do
391	$LDAPSEARCH -s base -b "" -H $MYURI \
392		'objectclass=*' > /dev/null 2>&1
393	RC=$?
394	if test $RC = 0 ; then
395		break
396	fi
397	echo "Waiting 5 seconds for slapd to start..."
398	sleep 5
399done
400
401echo "Breaking replication between server $n and $o..."
402$LDAPMODIFY -D cn=config -H $MYURI -y $CONFIGPWF > $TESTOUT 2>&1 <<EOF
403dn: olcDatabase={2}$BACKEND,cn=config
404changetype: modify
405replace: olcSyncRepl
406olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
407  credentials=InvalidPw searchbase="$BASEDN" $SYNCTYPE retry="3 +" timeout=3
408-
409replace: olcMirrorMode
410olcMirrorMode: TRUE
411
412EOF
413RC=$?
414if test $RC != 0 ; then
415	echo "ldapmodify failed for server $n config ($RC)!"
416	test $KILLSERVERS != no && kill -HUP $KILLPIDS
417	exit $RC
418fi
419n=`expr $n + 1`
420done
421
422echo "Using ldapmodify to force conflicts between server 1 and 2..."
423$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
424	>> $TESTOUT 2>&1 << EOF
425dn: $THEDN
426changetype: modify
427add: description
428description: Amazing
429
430EOF
431RC=$?
432if test $RC != 0 ; then
433	echo "ldapmodify failed for server 1 database ($RC)!"
434	test $KILLSERVERS != no && kill -HUP $KILLPIDS
435	exit $RC
436fi
437
438$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
439	>> $TESTOUT 2>&1 << EOF
440dn: $THEDN
441changetype: modify
442add: description
443description: Stupendous
444
445EOF
446RC=$?
447if test $RC != 0 ; then
448	echo "ldapmodify failed for server 2 database ($RC)!"
449	test $KILLSERVERS != no && kill -HUP $KILLPIDS
450	exit $RC
451fi
452
453$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
454	>> $TESTOUT 2>&1 << EOF
455dn: $THEDN
456changetype: modify
457delete: description
458description: Outstanding
459-
460add: description
461description: Mindboggling
462
463EOF
464RC=$?
465if test $RC != 0 ; then
466	echo "ldapmodify failed for server 1 database ($RC)!"
467	test $KILLSERVERS != no && kill -HUP $KILLPIDS
468	exit $RC
469fi
470
471$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
472	>> $TESTOUT 2>&1 << EOF
473dn: $THEDN
474changetype: modify
475delete: description
476description: OutStanding
477-
478add: description
479description: Bizarre
480
481EOF
482RC=$?
483if test $RC != 0 ; then
484	echo "ldapmodify failed for server 2 database ($RC)!"
485	test $KILLSERVERS != no && kill -HUP $KILLPIDS
486	exit $RC
487fi
488
489$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
490	>> $TESTOUT 2>&1 << EOF
491dn: $THEDN
492changetype: modify
493add: carLicense
494carLicense: 123-XYZ
495-
496add: employeeNumber
497employeeNumber: 32
498
499EOF
500RC=$?
501if test $RC != 0 ; then
502	echo "ldapmodify failed for server 1 database ($RC)!"
503	test $KILLSERVERS != no && kill -HUP $KILLPIDS
504	exit $RC
505fi
506
507$LDAPMODIFY -D "$MANAGERDN" -H $URI2 -w $PASSWD \
508	>> $TESTOUT 2>&1 << EOF
509dn: $THEDN
510changetype: modify
511add: employeeType
512employeeType: deadwood
513-
514add: employeeNumber
515employeeNumber: 64
516
517EOF
518RC=$?
519if test $RC != 0 ; then
520	echo "ldapmodify failed for server 2 database ($RC)!"
521	test $KILLSERVERS != no && kill -HUP $KILLPIDS
522	exit $RC
523fi
524
525$LDAPMODIFY -D "$MANAGERDN" -H $URI1 -w $PASSWD \
526	>> $TESTOUT 2>&1 << EOF
527dn: $THEDN
528changetype: modify
529replace: sn
530sn: Replaced later
531-
532replace: sn
533sn: Surname
534EOF
535RC=$?
536if test $RC != 0 ; then
537	echo "ldapmodify failed for server 1 database ($RC)!"
538	test $KILLSERVERS != no && kill -HUP $KILLPIDS
539	exit $RC
540fi
541
542echo "Deleting an entry from both servers..."
543$LDAPDELETE -D "$MANAGERDN" -H $URI1 -w $PASSWD \
544    "cn=John Doe,ou=Information Technology Division,ou=People,$BASEDN" \
545	>> $TESTOUT 2>&1
546RC=$?
547if test $RC != 0 ; then
548	echo "ldapdelete failed for server 1 database ($RC)!"
549	test $KILLSERVERS != no && kill -HUP $KILLPIDS
550	exit $RC
551fi
552
553$LDAPDELETE -D "$MANAGERDN" -H $URI2 -w $PASSWD \
554    "cn=John Doe,ou=Information Technology Division,ou=People,$BASEDN" \
555	>> $TESTOUT 2>&1
556RC=$?
557if test $RC != 0 ; then
558	echo "ldapdelete failed for server 2 database ($RC)!"
559	test $KILLSERVERS != no && kill -HUP $KILLPIDS
560	exit $RC
561fi
562
563echo "Restoring replication between server 1 and 2..."
564n=1
565while [ $n -le $MMR ]; do
566o=`expr 3 - $n`
567MYURI=`eval echo '$URI'$n`
568PROVIDERURI=`eval echo '$URI'$o`
569$LDAPMODIFY -D cn=config -H $MYURI -y $CONFIGPWF > $TESTOUT 2>&1 <<EOF
570dn: olcDatabase={2}$BACKEND,cn=config
571changetype: modify
572replace: olcSyncRepl
573olcSyncRepl: rid=001 provider=$PROVIDERURI binddn="$MANAGERDN" bindmethod=simple
574  credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE retry="3 +" timeout=3
575-
576replace: olcMirrorMode
577olcMirrorMode: TRUE
578
579EOF
580RC=$?
581if test $RC != 0 ; then
582	echo "ldapmodify failed for server $n config ($RC)!"
583	test $KILLSERVERS != no && kill -HUP $KILLPIDS
584	exit $RC
585fi
586n=`expr $n + 1`
587done
588
589echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
590sleep $SLEEP1
591
592echo 2 >$TESTDIR/repl.test
593echo 1 >>$TESTDIR/repl.test
594
595n=1
596while [ $n -le $MMR ]; do
597URI=`eval echo '$URI'$n`
598
599echo "Using ldapsearch to read all the entries from server $n..."
600$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD  \
601	'objectclass=*' > $TESTDIR/server$n.out 2>&1
602RC=$?
603
604if test $RC != 0 ; then
605	echo "ldapsearch failed at server $n ($RC)!"
606	test $KILLSERVERS != no && kill -HUP $KILLPIDS
607	exit $RC
608fi
609$LDIFFILTER -s a < $TESTDIR/server$n.out > $TESTDIR/server$n.flt
610
611echo "Checking server $n can remember which entries have been deleted even after it's been restarted..."
612$LDAPRSEARCH -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
613    -E "sync=ro/$cookie" 'objectclass=*' 1.1 | awk '/syncUUIDs/ {count++} END {print count}' >$TESTDIR/repl.out
614$LDAPRSEARCH -b "$BASEDN" -D "$MANAGERDN" -H $URI -w $PASSWD \
615    -E "sync=ro/$cookie" 'objectclass=*' 1.1 | grep SyncDone | awk '/refreshDeletes=1/ {count++} END {print count}' >>$TESTDIR/repl.out
616
617$CMP $TESTDIR/repl.out $TESTDIR/repl.test > $CMPOUT
618
619if test $? != 0 ; then
620	echo "test failed - server did not respond with delete phase"
621	test $KILLSERVERS != no && kill -HUP $KILLPIDS
622	exit 1
623fi
624n=`expr $n + 1`
625done
626
627n=2
628while [ $n -le $MMR ]; do
629echo "Comparing retrieved entries from server 1 and server $n..."
630$CMP $PROVIDERFLT $TESTDIR/server$n.flt > $CMPOUT
631
632if test $? != 0 ; then
633	echo "test failed - server 1 and server $n databases differ"
634	test $KILLSERVERS != no && kill -HUP $KILLPIDS
635	exit 1
636fi
637n=`expr $n + 1`
638done
639
640test $KILLSERVERS != no && kill -HUP $KILLPIDS
641
642echo ">>>>> Test succeeded"
643
644test $KILLSERVERS != no && wait
645
646exit 0
647