Fix check-iprop races
[heimdal.git] / tests / kdc / check-iprop.in
blob1cc397c9378755e3ef1b80263d43aaa767040b4f
1 #!/bin/sh
3 # Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
4 # (Royal Institute of Technology, Stockholm, Sweden).
5 # All rights reserved.
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
11 # 1. Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
18 # 3. Neither the name of the Institute nor the names of its contributors
19 # may be used to endorse or promote products derived from this software
20 # without specific prior written permission.
22 # THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 # ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 # SUCH DAMAGE.
34 top_builddir="@top_builddir@"
35 env_setup="@env_setup@"
36 objdir="@objdir@"
38 db_type=@db_type@
40 . ${env_setup}
42 # If there is no useful db support compile in, disable test
43 ${have_db} || exit 77
46 # Dont run this test in AFS, since it lacks support for AF_UNIX
47 expr "X`/bin/pwd || pwd`" : "X/afs/.*" > /dev/null 2>/dev/null && exit 77
49 R=TEST.H5L.SE
51 port=@port@
53 cache="FILE:${objdir}/cache.krb5"
54 keytabfile=${objdir}/iprop.keytab
55 keytab="FILE:${keytabfile}"
57 kdc="${kdc} --addresses=localhost -P $port"
58 kadmin="${kadmin} -r $R"
59 kinit="${kinit} -c $cache ${afs_no_afslog}"
61 slave_ver_from_master_old=
62 slave_ver_from_master_new=
63 slave_ver_old=
64 slave_ver_new=
65 get_iprop_ver () {
66 min_change=${1:-1}
67 slave_ver_from_master_new=`grep '^iprop/' iprop-stats | head -1 | awk '{print $3}'`
68 slave_ver_new=`grep 'up-to-date with version:' iprop-slave-status | awk '{print $4}'`
69 if [ -z "$slave_ver_from_master_new" -o -z "$slave_ver_new" ]; then
70 return 1
72 if [ x"$slave_ver_from_master_new" != x"$slave_ver_new" ]; then
73 return 1
75 if [ x"$slave_ver_from_master_old" != x ]; then
76 change=`expr "$slave_ver_from_master_new" - "$slave_ver_from_master_old"`
77 if [ "$change" -lt "$min_change" ]; then
78 return 1
81 slave_ver_from_master_old=$slave_ver_from_master_new
82 slave_ver_old=$slave_ver_new
83 return 0
86 waitsec=65
87 sleeptime=2
88 wait_for () {
89 msg=$1
90 shift
91 t=0
92 while ! "$@"; do
93 sleep $sleeptime;
94 t=`expr $t + $sleeptime`
95 if [ $t -gt $waitsec ]; then
96 echo "Waited too long for $msg"
97 exit 1
99 done
100 return 0
103 check_pidfile_is_dead () {
104 if test ! -f lt-${1}.pid -a ! -f ${1}.pid; then
105 return 0
107 _pid=`cat lt-${1}.pid ${1}.pid 2>/dev/null`
108 if [ -z "$_pid" ]; then
109 return 0
111 if kill -0 $_pid 2>/dev/null; then
112 return 1
114 return 0
117 wait_for_slave () {
118 wait_for "iprop versions to change and/or slave to catch up" get_iprop_ver "$@"
121 wait_for_master_down () {
122 wait_for "master to exit" check_pidfile_is_dead ipropd-master
125 wait_for_slave_down () {
126 wait_for "slave to exit" check_pidfile_is_dead ipropd-slave
129 KRB5_CONFIG="${objdir}/krb5.conf"
130 export KRB5_CONFIG
132 rm -f ${keytabfile}
133 rm -f current-db*
134 rm -f current*.log
135 rm -f out-*
136 rm -f mkey.file*
137 rm -f messages.log
139 > messages.log
141 echo Creating database
142 ${kadmin} -l \
143 init \
144 --realm-max-ticket-life=1day \
145 --realm-max-renewable-life=1month \
146 ${R} || exit 1
148 ${kadmin} -l add -p foo --use-defaults user@${R} || exit 1
150 ${kadmin} -l add --random-key --use-defaults iprop/localhost@${R} || exit 1
151 ${kadmin} -l ext -k ${keytab} iprop/localhost@${R} || exit 1
152 ${kadmin} -l add --random-key --use-defaults iprop/slave.test.h5l.se@${R} || exit 1
153 ${kadmin} -l ext -k ${keytab} iprop/slave.test.h5l.se@${R} || exit 1
155 echo foo > ${objdir}/foopassword
157 echo "Test log recovery"
158 ${kadmin} -l add --random-key --use-defaults recovtest@${R} || exit 1
159 # Test theory: save the log, make a change and save the record it
160 # produced, restore the log, append to it the saved record, then get
162 # Save the log
163 cp current.log current.log.tmp
164 ls -l current.log.tmp | awk '{print $5}' > tmp
165 read sz < tmp
166 # Make a change
167 ${kadmin} -l mod -a requires-pre-auth recovtest@${R} || exit 1
168 ${kadmin} -l get recovtest@${R} | grep 'Attributes: requires-pre-auth$' > /dev/null || exit 1
169 # Save the resulting log record
170 ls -l current.log | awk '{print $5}' > tmp
171 read nsz < tmp
172 rm tmp
173 dd bs=1 if=current.log skip=$sz of=current.log.tmp.saved-record count=`expr $nsz - $sz` 2>/dev/null
174 # Undo the change
175 ${kadmin} -l mod -a -requires-pre-auth recovtest@${R} || exit 1
176 ${kadmin} -l get recovtest@${R} | grep 'Attributes:.$' > /dev/null || exit 1
177 # Restore the log
178 cp current.log current.log.save
179 mv current.log.tmp current.log
180 # Append the saved record
181 cat current.log.tmp.saved-record >> current.log
182 rm current.log.tmp.saved-record
183 # Check that we still see the principal as modified
184 ${kadmin} -l get recovtest@${R} | grep 'Attributes: requires-pre-auth$' > /dev/null || exit 1
186 # -- foo
187 ipds=
188 ipdm=
189 kdcpid=
191 > iprop-stats
192 rm -f iprop-slave-status
194 ipropd_slave="${ipropd_slave} --status-file=iprop-slave-status"
196 trap "echo 'killing ipropd s + m + kdc'; kill -9 \${ipdm} \${ipds} \${kdcpid} >/dev/null 2>/dev/null; tail messages.log ; tail iprop-stats; exit 1;" EXIT
198 echo Starting kdc ; > messages.log
199 ${kdc} --detach --testing || { echo "kdc failed to start"; exit 1; }
200 kdcpid=`getpid kdc`
202 echo "starting master" ; > messages.log
203 env ${HEIM_MALLOC_DEBUG} \
204 ${ipropd_master} --hostname=localhost -k ${keytab} \
205 --database=${objdir}/current-db --detach ||
206 { echo "ipropd-master failed to start"; exit 1; }
207 ipdm=`getpid ipropd-master`
209 echo "starting slave" ; > messages.log
210 env ${HEIM_MALLOC_DEBUG} \
211 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
212 ${ipropd_slave} --hostname=slave.test.h5l.se -k ${keytab} --detach localhost ||
213 { echo "ipropd-slave failed to start"; exit 1; }
214 ipds=`getpid ipropd-slave`
215 sh ${wait_kdc} ipropd-slave messages.log 'slave status change: up-to-date' || exit 1
216 get_iprop_ver || exit 1
218 echo "checking slave is up"
219 ${EGREP} 'iprop/slave.test.h5l.se@TEST.H5L.SE.*Up' iprop-stats >/dev/null || exit 1
220 ${EGREP} 'up-to-date with version' iprop-slave-status >/dev/null || { echo "slave to up to date" ; cat iprop-slave-status ; exit 1; }
222 # ----------------- checking: pushing lives changes
224 echo "Add host"
225 ${kadmin} -l add --random-key --use-defaults host/foo@${R} || exit 1
226 wait_for_slave
227 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
228 ${kadmin} -l get host/foo@${R} > /dev/null || exit 1
230 echo "Rollover host keys"
231 ${kadmin} -l cpw -r --keepold host/foo@${R} || exit 1
232 ${kadmin} -l cpw -r --keepold host/foo@${R} || exit 1
233 ${kadmin} -l cpw -r --keepold host/foo@${R} || exit 1
234 wait_for_slave 3
235 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
236 ${kadmin} -l get host/foo@${R} | \
237 ${EGREP} Keytypes: | cut -d: -f2 | tr ' ' '
238 ' | sed 's/^.*[[]\(.*\)[]].*$/\1/' | grep '[0-9]' | sort -nu | tr -d '
239 ' | ${EGREP} 1234 > /dev/null || exit 1
241 echo "Delete 3DES keys"
242 ${kadmin} -l del_enctype host/foo@${R} des3-cbc-sha1
243 wait_for_slave
244 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
245 ${kadmin} -l get host/foo@${R} | \
246 ${EGREP} Keytypes: | cut -d: -f2 | tr ' ' '
247 ' | sed 's/^.*[[]\(.*\)[]].*$/\1/' | grep '[0-9]' | sort -nu | tr -d '
248 ' | ${EGREP} 1234 > /dev/null || exit 1
249 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
250 ${kadmin} -l get host/foo@${R} | \
251 ${EGREP} 'Keytypes:.*des3-cbc-sha1' > /dev/null && exit 1
253 echo "Change policy host"
254 ${kadmin} -l modify --policy=default host/foo@${R} || exit 1
255 wait_for_slave
256 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
257 ${kadmin} -l get host/foo@${R} > /dev/null 2>/dev/null || exit 1
259 echo "Rename host"
260 ${kadmin} -l rename host/foo@${R} host/bar@${R} || exit 1
261 wait_for_slave
262 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
263 ${kadmin} -l get host/foo@${R} > /dev/null 2>/dev/null && exit 1
264 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
265 ${kadmin} -l get host/bar@${R} > /dev/null || exit 1
267 echo "Delete host"
268 ${kadmin} -l delete host/bar@${R} || exit 1
269 wait_for_slave
270 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
271 ${kadmin} -l get host/bar@${R} > /dev/null 2>/dev/null && exit 1
273 # See note below in LMDB sanity checking
274 echo "Re-add host"
275 ${kadmin} -l add --random-key --use-defaults host/foo@${R} || exit 1
276 ${kadmin} -l add --random-key --use-defaults host/bar@${R} || exit 1
278 echo "kill slave and remove log and database"
279 > iprop-stats
280 sh ${leaks_kill} ipropd-slave $ipds || exit 1
281 rm -f iprop-slave-status
283 wait_for_slave_down
284 ${EGREP} 'iprop/slave.test.h5l.se@TEST.H5L.SE.*Down' iprop-stats >/dev/null || exit 1
286 # ----------------- checking: slave is missing changes while down
288 rm current.slave.log current-db.slave* || exit 1
290 echo "doing changes while slave is down"
291 ${kadmin} -l cpw --random-password user@${R} > /dev/null || exit 1
292 ${kadmin} -l cpw --random-password user@${R} > /dev/null || exit 1
294 echo "Makeing a copy of the master log file"
295 cp ${objdir}/current.log ${objdir}/current.log.tmp
297 # ----------------- checking: checking that master and slaves resyncs
299 echo "starting slave again" ; > messages.log
300 > iprop-stats
301 env ${HEIM_MALLOC_DEBUG} \
302 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
303 ${ipropd_slave} --hostname=slave.test.h5l.se -k ${keytab} --detach localhost ||
304 { echo "ipropd-slave failed to start"; exit 1; }
305 ipds=`getpid ipropd-slave`
307 echo "checking slave is up again"
308 wait_for "slave to start and connect to master" \
309 ${EGREP} 'iprop/slave.test.h5l.se@TEST.H5L.SE.*Up' iprop-stats >/dev/null
310 wait_for_slave 2
311 ${EGREP} 'up-to-date with version' iprop-slave-status >/dev/null || { echo "slave not up to date" ; cat iprop-slave-status ; exit 1; }
312 echo "checking for replay problems"
313 ${EGREP} 'Entry already exists in database' messages.log && exit 1
315 echo "compare versions on master and slave logs (no lock)"
316 KRB5_CONFIG=${objdir}/krb5-slave.conf \
317 ${iprop_log} last-version -n > slave-last.tmp
318 ${iprop_log} last-version -n > master-last.tmp
319 cmp master-last.tmp slave-last.tmp || exit 1
321 echo "kill slave and remove log and database"
322 sh ${leaks_kill} ipropd-slave $ipds || exit 1
323 wait_for_slave_down
325 rm current.slave.log current-db.slave* || exit 1
326 > iprop-stats
327 rm -f iprop-slave-status
328 echo "starting slave" ; > messages.log
329 env ${HEIM_MALLOC_DEBUG} \
330 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
331 ${ipropd_slave} --hostname=slave.test.h5l.se -k ${keytab} --detach localhost ||
332 { echo "ipropd-slave failed to start"; exit 1; }
333 ipds=`getpid ipropd-slave`
334 wait_for_slave 0
336 echo "checking slave is up again"
337 wait_for "slave to start and connect to master" \
338 ${EGREP} 'iprop/slave.test.h5l.se@TEST.H5L.SE.*Up' iprop-stats >/dev/null
339 ${EGREP} 'up-to-date with version' iprop-slave-status >/dev/null || { echo "slave not up to date" ; cat iprop-slave-status ; exit 1; }
340 echo "checking for replay problems"
341 ${EGREP} 'Entry already exists in database' messages.log && exit 1
343 # ----------------- checking: checking live truncation of master log
345 ${kadmin} -l cpw --random-password user@${R} > /dev/null || exit 1
346 wait_for_slave
348 echo "live truncate on master log"
349 ${iprop_log} truncate -K 5 || exit 1
350 wait_for_slave 0
352 echo "Killing master and slave"
353 sh ${leaks_kill} ipropd-master $ipdm || exit 1
354 sh ${leaks_kill} ipropd-slave $ipds || exit 1
356 rm -f iprop-slave-status
358 wait_for_slave_down
359 wait_for_master_down
361 echo "compare versions on master and slave logs"
362 KRB5_CONFIG=${objdir}/krb5-slave.conf \
363 ${iprop_log} last-version > slave-last.tmp
364 ${iprop_log} last-version > master-last.tmp
365 cmp master-last.tmp slave-last.tmp || exit 1
367 # ----------------- checking: master going backward
368 > iprop-stats
369 > messages.log
371 echo "Going back to old version of the master log file"
372 cp ${objdir}/current.log.tmp ${objdir}/current.log
374 echo "starting master" ; > messages.log
375 env ${HEIM_MALLOC_DEBUG} \
376 ${ipropd_master} --hostname=localhost -k ${keytab} \
377 --database=${objdir}/current-db --detach ||
378 { echo "ipropd-master failed to start"; exit 1; }
379 ipdm=`getpid ipropd-master`
381 echo "starting slave" ; > messages.log
382 env ${HEIM_MALLOC_DEBUG} \
383 KRB5_CONFIG="${objdir}/krb5-slave.conf" \
384 ${ipropd_slave} --hostname=slave.test.h5l.se -k ${keytab} --detach localhost ||
385 { echo "ipropd-slave failed to start"; exit 1; }
386 ipds=`getpid ipropd-slave`
387 wait_for_slave -1
389 echo "checking slave is up again"
390 wait_for "slave to start and connect to master" \
391 ${EGREP} 'iprop/slave.test.h5l.se@TEST.H5L.SE.*Up' iprop-stats >/dev/null
392 ${EGREP} 'up-to-date with version' iprop-slave-status >/dev/null || { echo "slave to up to date" ; cat iprop-slave-status ; exit 1; }
393 echo "checking for replay problems"
394 ${EGREP} 'Entry already exists in database' messages.log && exit 1
396 echo "pushing one change"
397 ${kadmin} -l cpw --random-password user@${R} > /dev/null || exit 1
398 wait_for_slave
400 echo "Killing master"
401 sh ${leaks_kill} ipropd-master $ipdm || exit 1
403 wait_for_master_down
405 wait_for "slave to disconnect" \
406 ${EGREP} 'disconnected' iprop-slave-status >/dev/null
408 if ! tail -30 messages.log | grep 'disconnected for server' > /dev/null; then
409 echo "client didnt disconnect"
410 exit 1
413 echo "probing for slave pid"
414 kill -0 ${ipds} || { echo "slave no longer there"; exit 1; }
416 > messages.log
418 echo "Staring master again" ; > messages.log
419 env ${HEIM_MALLOC_DEBUG} \
420 ${ipropd_master} --hostname=localhost -k ${keytab} \
421 --database=${objdir}/current-db --detach ||
422 { echo "ipropd-master failed to start"; exit 1; }
423 ipdm=`getpid ipropd-master`
425 echo "probing for slave pid"
426 kill -0 ${ipds} || { echo "slave no longer there"; exit 1; }
429 echo "pushing one change"
430 ${kadmin} -l cpw --random-password user@${R} > /dev/null || exit 1
431 wait_for_slave
433 echo "shutting down all services"
435 trap "" EXIT
436 sh ${leaks_kill} kdc $kdcpid || exit 1
437 sh ${leaks_kill} ipropd-master $ipdm || exit 1
438 sh ${leaks_kill} ipropd-slave $ipds || exit 1
440 rm -f iprop-slave-status
442 echo "compare versions on master and slave logs"
443 KRB5_CONFIG=${objdir}/krb5-slave.conf \
444 ${iprop_log} last-version > slave-last.tmp
445 ${iprop_log} last-version > master-last.tmp
446 cmp master-last.tmp slave-last.tmp || exit 1
448 if [ "$db_type" = lmdb ]; then
449 # Sanity check that we have the same number of principals at the HDB
450 # and LMDB levels.
452 echo "checking that principals in DB == entries in LMDB"
453 princs=`${kadmin} -l list '*' | wc -l`
454 entries=`mdb_stat -n current-db.mdb | grep 'Entries:' | awk '{print $2}'`
455 [ "`expr 1 + "$princs"`" -eq "$entries" ] || exit 1
458 exit 0