test-exec.sh revision 295367
1#	$OpenBSD: test-exec.sh,v 1.51 2015/03/03 22:35:19 markus Exp $
2#	Placed in the Public Domain.
3
4#SUDO=sudo
5
6# Unbreak GNU head(1)
7_POSIX2_VERSION=199209
8export _POSIX2_VERSION
9
10case `uname -s 2>/dev/null` in
11OSF1*)
12	BIN_SH=xpg4
13	export BIN_SH
14	;;
15CYGWIN_NT-5.0)
16	os=cygwin
17	TEST_SSH_IPV6=no
18	;;
19CYGWIN*)
20	os=cygwin
21	;;
22esac
23
24if [ ! -z "$TEST_SSH_PORT" ]; then
25	PORT="$TEST_SSH_PORT"
26else
27	PORT=4242
28fi
29
30if [ -x /usr/ucb/whoami ]; then
31	USER=`/usr/ucb/whoami`
32elif whoami >/dev/null 2>&1; then
33	USER=`whoami`
34elif logname >/dev/null 2>&1; then
35	USER=`logname`
36else
37	USER=`id -un`
38fi
39
40OBJ=$1
41if [ "x$OBJ" = "x" ]; then
42	echo '$OBJ not defined'
43	exit 2
44fi
45if [ ! -d $OBJ ]; then
46	echo "not a directory: $OBJ"
47	exit 2
48fi
49SCRIPT=$2
50if [ "x$SCRIPT" = "x" ]; then
51	echo '$SCRIPT not defined'
52	exit 2
53fi
54if [ ! -f $SCRIPT ]; then
55	echo "not a file: $SCRIPT"
56	exit 2
57fi
58if $TEST_SHELL -n $SCRIPT; then
59	true
60else
61	echo "syntax error in $SCRIPT"
62	exit 2
63fi
64unset SSH_AUTH_SOCK
65
66SRC=`dirname ${SCRIPT}`
67
68# defaults
69SSH=ssh
70SSHD=sshd
71SSHAGENT=ssh-agent
72SSHADD=ssh-add
73SSHKEYGEN=ssh-keygen
74SSHKEYSCAN=ssh-keyscan
75SFTP=sftp
76SFTPSERVER=/usr/libexec/openssh/sftp-server
77SCP=scp
78
79# Interop testing
80PLINK=plink
81PUTTYGEN=puttygen
82CONCH=conch
83
84if [ "x$TEST_SSH_SSH" != "x" ]; then
85	SSH="${TEST_SSH_SSH}"
86fi
87if [ "x$TEST_SSH_SSHD" != "x" ]; then
88	SSHD="${TEST_SSH_SSHD}"
89fi
90if [ "x$TEST_SSH_SSHAGENT" != "x" ]; then
91	SSHAGENT="${TEST_SSH_SSHAGENT}"
92fi
93if [ "x$TEST_SSH_SSHADD" != "x" ]; then
94	SSHADD="${TEST_SSH_SSHADD}"
95fi
96if [ "x$TEST_SSH_SSHKEYGEN" != "x" ]; then
97	SSHKEYGEN="${TEST_SSH_SSHKEYGEN}"
98fi
99if [ "x$TEST_SSH_SSHKEYSCAN" != "x" ]; then
100	SSHKEYSCAN="${TEST_SSH_SSHKEYSCAN}"
101fi
102if [ "x$TEST_SSH_SFTP" != "x" ]; then
103	SFTP="${TEST_SSH_SFTP}"
104fi
105if [ "x$TEST_SSH_SFTPSERVER" != "x" ]; then
106	SFTPSERVER="${TEST_SSH_SFTPSERVER}"
107fi
108if [ "x$TEST_SSH_SCP" != "x" ]; then
109	SCP="${TEST_SSH_SCP}"
110fi
111if [ "x$TEST_SSH_PLINK" != "x" ]; then
112	# Find real binary, if it exists
113	case "${TEST_SSH_PLINK}" in
114	/*) PLINK="${TEST_SSH_PLINK}" ;;
115	*) PLINK=`which ${TEST_SSH_PLINK} 2>/dev/null` ;;
116	esac
117fi
118if [ "x$TEST_SSH_PUTTYGEN" != "x" ]; then
119	# Find real binary, if it exists
120	case "${TEST_SSH_PUTTYGEN}" in
121	/*) PUTTYGEN="${TEST_SSH_PUTTYGEN}" ;;
122	*) PUTTYGEN=`which ${TEST_SSH_PUTTYGEN} 2>/dev/null` ;;
123	esac
124fi
125if [ "x$TEST_SSH_CONCH" != "x" ]; then
126	# Find real binary, if it exists
127	case "${TEST_SSH_CONCH}" in
128	/*) CONCH="${TEST_SSH_CONCH}" ;;
129	*) CONCH=`which ${TEST_SSH_CONCH} 2>/dev/null` ;;
130	esac
131fi
132
133SSH_PROTOCOLS=`$SSH -Q protocol-version`
134if [ "x$TEST_SSH_PROTOCOLS" != "x" ]; then
135	SSH_PROTOCOLS="${TEST_SSH_PROTOCOLS}"
136fi
137
138# Path to sshd must be absolute for rexec
139case "$SSHD" in
140/*) ;;
141*) SSHD=`which $SSHD` ;;
142esac
143
144case "$SSHAGENT" in
145/*) ;;
146*) SSHAGENT=`which $SSHAGENT` ;;
147esac
148
149# Record the actual binaries used.
150SSH_BIN=${SSH}
151SSHD_BIN=${SSHD}
152SSHAGENT_BIN=${SSHAGENT}
153SSHADD_BIN=${SSHADD}
154SSHKEYGEN_BIN=${SSHKEYGEN}
155SSHKEYSCAN_BIN=${SSHKEYSCAN}
156SFTP_BIN=${SFTP}
157SFTPSERVER_BIN=${SFTPSERVER}
158SCP_BIN=${SCP}
159
160if [ "x$USE_VALGRIND" != "x" ]; then
161	mkdir -p $OBJ/valgrind-out
162	VG_TEST=`basename $SCRIPT .sh`
163
164	# Some tests are difficult to fix.
165	case "$VG_TEST" in
166	connect-privsep|reexec)
167		VG_SKIP=1 ;;
168	esac
169
170	if [ x"$VG_SKIP" = "x" ]; then
171		VG_IGNORE="/bin/*,/sbin/*,/usr/*,/var/*"
172		VG_LOG="$OBJ/valgrind-out/${VG_TEST}."
173		VG_OPTS="--track-origins=yes --leak-check=full"
174		VG_OPTS="$VG_OPTS --trace-children=yes"
175		VG_OPTS="$VG_OPTS --trace-children-skip=${VG_IGNORE}"
176		VG_PATH="valgrind"
177		if [ "x$VALGRIND_PATH" != "x" ]; then
178			VG_PATH="$VALGRIND_PATH"
179		fi
180		VG="$VG_PATH $VG_OPTS"
181		SSH="$VG --log-file=${VG_LOG}ssh.%p $SSH"
182		SSHD="$VG --log-file=${VG_LOG}sshd.%p $SSHD"
183		SSHAGENT="$VG --log-file=${VG_LOG}ssh-agent.%p $SSHAGENT"
184		SSHADD="$VG --log-file=${VG_LOG}ssh-add.%p $SSHADD"
185		SSHKEYGEN="$VG --log-file=${VG_LOG}ssh-keygen.%p $SSHKEYGEN"
186		SSHKEYSCAN="$VG --log-file=${VG_LOG}ssh-keyscan.%p $SSHKEYSCAN"
187		SFTP="$VG --log-file=${VG_LOG}sftp.%p ${SFTP}"
188		SCP="$VG --log-file=${VG_LOG}scp.%p $SCP"
189		cat > $OBJ/valgrind-sftp-server.sh << EOF
190#!/bin/sh
191exec $VG --log-file=${VG_LOG}sftp-server.%p $SFTPSERVER "\$@"
192EOF
193		chmod a+rx $OBJ/valgrind-sftp-server.sh
194		SFTPSERVER="$OBJ/valgrind-sftp-server.sh"
195	fi
196fi
197
198# Logfiles.
199# SSH_LOGFILE should be the debug output of ssh(1) only
200# SSHD_LOGFILE should be the debug output of sshd(8) only
201# REGRESS_LOGFILE is the output of the test itself stdout and stderr
202if [ "x$TEST_SSH_LOGFILE" = "x" ]; then
203	TEST_SSH_LOGFILE=$OBJ/ssh.log
204fi
205if [ "x$TEST_SSHD_LOGFILE" = "x" ]; then
206	TEST_SSHD_LOGFILE=$OBJ/sshd.log
207fi
208if [ "x$TEST_REGRESS_LOGFILE" = "x" ]; then
209	TEST_REGRESS_LOGFILE=$OBJ/regress.log
210fi
211
212# truncate logfiles
213>$TEST_SSH_LOGFILE
214>$TEST_SSHD_LOGFILE
215>$TEST_REGRESS_LOGFILE
216
217# Create wrapper ssh with logging.  We can't just specify "SSH=ssh -E..."
218# because sftp and scp don't handle spaces in arguments.
219SSHLOGWRAP=$OBJ/ssh-log-wrapper.sh
220echo "#!/bin/sh" > $SSHLOGWRAP
221echo "exec ${SSH} -E${TEST_SSH_LOGFILE} "'"$@"' >>$SSHLOGWRAP
222
223chmod a+rx $OBJ/ssh-log-wrapper.sh
224SSH="$SSHLOGWRAP"
225
226# Some test data.  We make a copy because some tests will overwrite it.
227# The tests may assume that $DATA exists and is writable and $COPY does
228# not exist.  Tests requiring larger data files can call increase_datafile_size
229# [kbytes] to ensure the file is at least that large.
230DATANAME=data
231DATA=$OBJ/${DATANAME}
232cat ${SSHAGENT_BIN} >${DATA}
233chmod u+w ${DATA}
234COPY=$OBJ/copy
235rm -f ${COPY}
236
237increase_datafile_size()
238{
239	while [ `du -k ${DATA} | cut -f1` -lt $1 ]; do
240		cat ${SSHAGENT_BIN} >>${DATA}
241	done
242}
243
244# these should be used in tests
245export SSH SSHD SSHAGENT SSHADD SSHKEYGEN SSHKEYSCAN SFTP SFTPSERVER SCP
246#echo $SSH $SSHD $SSHAGENT $SSHADD $SSHKEYGEN $SSHKEYSCAN $SFTP $SFTPSERVER $SCP
247
248# Portable specific functions
249have_prog()
250{
251	saved_IFS="$IFS"
252	IFS=":"
253	for i in $PATH
254	do
255		if [ -x $i/$1 ]; then
256			IFS="$saved_IFS"
257			return 0
258		fi
259	done
260	IFS="$saved_IFS"
261	return 1
262}
263
264jot() {
265	awk "BEGIN { for (i = $2; i < $2 + $1; i++) { printf \"%d\n\", i } exit }"
266}
267
268# Check whether preprocessor symbols are defined in config.h.
269config_defined ()
270{
271	str=$1
272	while test "x$2" != "x" ; do
273		str="$str|$2"
274		shift
275	done
276	egrep "^#define.*($str)" ${BUILDDIR}/config.h >/dev/null 2>&1
277}
278
279md5 () {
280	if have_prog md5sum; then
281		md5sum
282	elif have_prog openssl; then
283		openssl md5
284	elif have_prog cksum; then
285		cksum
286	elif have_prog sum; then
287		sum
288	else
289		wc -c
290	fi
291}
292# End of portable specific functions
293
294# helper
295cleanup ()
296{
297	if [ "x$SSH_PID" != "x" ]; then
298		if [ $SSH_PID -lt 2 ]; then
299			echo bad pid for ssh: $SSH_PID
300		else
301			kill $SSH_PID
302		fi
303	fi
304	if [ -f $PIDFILE ]; then
305		pid=`$SUDO cat $PIDFILE`
306		if [ "X$pid" = "X" ]; then
307			echo no sshd running
308		else
309			if [ $pid -lt 2 ]; then
310				echo bad pid for sshd: $pid
311			else
312				$SUDO kill $pid
313				trace "wait for sshd to exit"
314				i=0;
315				while [ -f $PIDFILE -a $i -lt 5 ]; do
316					i=`expr $i + 1`
317					sleep $i
318				done
319				test -f $PIDFILE && \
320				    fatal "sshd didn't exit port $PORT pid $pid"
321			fi
322		fi
323	fi
324}
325
326start_debug_log ()
327{
328	echo "trace: $@" >$TEST_REGRESS_LOGFILE
329	echo "trace: $@" >$TEST_SSH_LOGFILE
330	echo "trace: $@" >$TEST_SSHD_LOGFILE
331}
332
333save_debug_log ()
334{
335	echo $@ >>$TEST_REGRESS_LOGFILE
336	echo $@ >>$TEST_SSH_LOGFILE
337	echo $@ >>$TEST_SSHD_LOGFILE
338	(cat $TEST_REGRESS_LOGFILE; echo) >>$OBJ/failed-regress.log
339	(cat $TEST_SSH_LOGFILE; echo) >>$OBJ/failed-ssh.log
340	(cat $TEST_SSHD_LOGFILE; echo) >>$OBJ/failed-sshd.log
341}
342
343trace ()
344{
345	start_debug_log $@
346	if [ "X$TEST_SSH_TRACE" = "Xyes" ]; then
347		echo "$@"
348	fi
349}
350
351verbose ()
352{
353	start_debug_log $@
354	if [ "X$TEST_SSH_QUIET" != "Xyes" ]; then
355		echo "$@"
356	fi
357}
358
359warn ()
360{
361	echo "WARNING: $@" >>$TEST_SSH_LOGFILE
362	echo "WARNING: $@"
363}
364
365fail ()
366{
367	save_debug_log "FAIL: $@"
368	RESULT=1
369	echo "$@"
370
371}
372
373fatal ()
374{
375	save_debug_log "FATAL: $@"
376	printf "FATAL: "
377	fail "$@"
378	cleanup
379	exit $RESULT
380}
381
382ssh_version ()
383{
384	echo ${SSH_PROTOCOLS} | grep "$1" >/dev/null
385}
386
387RESULT=0
388PIDFILE=$OBJ/pidfile
389
390trap fatal 3 2
391
392if ssh_version 1; then
393	PROTO="2,1"
394else
395	PROTO="2"
396fi
397
398# create server config
399cat << EOF > $OBJ/sshd_config
400	StrictModes		no
401	Port			$PORT
402	Protocol		$PROTO
403	AddressFamily		inet
404	ListenAddress		127.0.0.1
405	#ListenAddress		::1
406	PidFile			$PIDFILE
407	AuthorizedKeysFile	$OBJ/authorized_keys_%u
408	LogLevel		DEBUG3
409	AcceptEnv		_XXX_TEST_*
410	AcceptEnv		_XXX_TEST
411	Subsystem	sftp	$SFTPSERVER
412EOF
413
414if [ ! -z "$TEST_SSH_SSHD_CONFOPTS" ]; then
415	trace "adding sshd_config option $TEST_SSH_SSHD_CONFOPTS"
416	echo "$TEST_SSH_SSHD_CONFOPTS" >> $OBJ/sshd_config
417fi
418
419# server config for proxy connects
420cp $OBJ/sshd_config $OBJ/sshd_proxy
421
422# allow group-writable directories in proxy-mode
423echo 'StrictModes no' >> $OBJ/sshd_proxy
424
425# create client config
426cat << EOF > $OBJ/ssh_config
427Host *
428	Protocol		$PROTO
429	Hostname		127.0.0.1
430	HostKeyAlias		localhost-with-alias
431	Port			$PORT
432	User			$USER
433	GlobalKnownHostsFile	$OBJ/known_hosts
434	UserKnownHostsFile	$OBJ/known_hosts
435	RSAAuthentication	yes
436	PubkeyAuthentication	yes
437	ChallengeResponseAuthentication	no
438	HostbasedAuthentication	no
439	PasswordAuthentication	no
440	RhostsRSAAuthentication	no
441	BatchMode		yes
442	StrictHostKeyChecking	yes
443	LogLevel		DEBUG3
444EOF
445
446if [ ! -z "$TEST_SSH_SSH_CONFOPTS" ]; then
447	trace "adding ssh_config option $TEST_SSH_SSH_CONFOPTS"
448	echo "$TEST_SSH_SSH_CONFOPTS" >> $OBJ/ssh_config
449fi
450
451rm -f $OBJ/known_hosts $OBJ/authorized_keys_$USER
452
453if ssh_version 1; then
454	SSH_KEYTYPES="rsa rsa1"
455else
456	SSH_KEYTYPES="rsa ed25519"
457fi
458trace "generate keys"
459for t in ${SSH_KEYTYPES}; do
460	# generate user key
461	if [ ! -f $OBJ/$t ] || [ ${SSHKEYGEN_BIN} -nt $OBJ/$t ]; then
462		rm -f $OBJ/$t
463		${SSHKEYGEN} -q -N '' -t $t  -f $OBJ/$t ||\
464			fail "ssh-keygen for $t failed"
465	fi
466
467	# known hosts file for client
468	(
469		printf 'localhost-with-alias,127.0.0.1,::1 '
470		cat $OBJ/$t.pub
471	) >> $OBJ/known_hosts
472
473	# setup authorized keys
474	cat $OBJ/$t.pub >> $OBJ/authorized_keys_$USER
475	echo IdentityFile $OBJ/$t >> $OBJ/ssh_config
476
477	# use key as host key, too
478	$SUDO cp $OBJ/$t $OBJ/host.$t
479	echo HostKey $OBJ/host.$t >> $OBJ/sshd_config
480
481	# don't use SUDO for proxy connect
482	echo HostKey $OBJ/$t >> $OBJ/sshd_proxy
483done
484chmod 644 $OBJ/authorized_keys_$USER
485
486# Activate Twisted Conch tests if the binary is present
487REGRESS_INTEROP_CONCH=no
488if test -x "$CONCH" ; then
489	REGRESS_INTEROP_CONCH=yes
490fi
491
492# If PuTTY is present and we are running a PuTTY test, prepare keys and
493# configuration
494REGRESS_INTEROP_PUTTY=no
495if test -x "$PUTTYGEN" -a -x "$PLINK" ; then
496	REGRESS_INTEROP_PUTTY=yes
497fi
498case "$SCRIPT" in
499*putty*)	;;
500*)		REGRESS_INTEROP_PUTTY=no ;;
501esac
502
503if test "$REGRESS_INTEROP_PUTTY" = "yes" ; then
504	mkdir -p ${OBJ}/.putty
505
506	# Add a PuTTY key to authorized_keys
507	rm -f ${OBJ}/putty.rsa2
508	puttygen -t rsa -o ${OBJ}/putty.rsa2 < /dev/null > /dev/null
509	puttygen -O public-openssh ${OBJ}/putty.rsa2 \
510	    >> $OBJ/authorized_keys_$USER
511
512	# Convert rsa2 host key to PuTTY format
513	${SRC}/ssh2putty.sh 127.0.0.1 $PORT $OBJ/rsa > \
514	    ${OBJ}/.putty/sshhostkeys
515	${SRC}/ssh2putty.sh 127.0.0.1 22 $OBJ/rsa >> \
516	    ${OBJ}/.putty/sshhostkeys
517
518	# Setup proxied session
519	mkdir -p ${OBJ}/.putty/sessions
520	rm -f ${OBJ}/.putty/sessions/localhost_proxy
521	echo "Hostname=127.0.0.1" >> ${OBJ}/.putty/sessions/localhost_proxy
522	echo "PortNumber=$PORT" >> ${OBJ}/.putty/sessions/localhost_proxy
523	echo "ProxyMethod=5" >> ${OBJ}/.putty/sessions/localhost_proxy
524	echo "ProxyTelnetCommand=sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy" >> ${OBJ}/.putty/sessions/localhost_proxy
525
526	REGRESS_INTEROP_PUTTY=yes
527fi
528
529# create a proxy version of the client config
530(
531	cat $OBJ/ssh_config
532	echo proxycommand ${SUDO} sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy
533) > $OBJ/ssh_proxy
534
535# check proxy config
536${SSHD} -t -f $OBJ/sshd_proxy	|| fatal "sshd_proxy broken"
537
538start_sshd ()
539{
540	# start sshd
541	$SUDO ${SSHD} -f $OBJ/sshd_config "$@" -t || fatal "sshd_config broken"
542	$SUDO ${SSHD} -f $OBJ/sshd_config "$@" -E$TEST_SSHD_LOGFILE
543
544	trace "wait for sshd"
545	i=0;
546	while [ ! -f $PIDFILE -a $i -lt 10 ]; do
547		i=`expr $i + 1`
548		sleep $i
549	done
550
551	test -f $PIDFILE || fatal "no sshd running on port $PORT"
552}
553
554# source test body
555. $SCRIPT
556
557# kill sshd
558cleanup
559if [ $RESULT -eq 0 ]; then
560	verbose ok $tid
561else
562	echo failed $tid
563fi
564exit $RESULT
565