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