test-exec.sh revision 262566
1#	$OpenBSD: test-exec.sh,v 1.47 2013/11/09 05:41:34 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# 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
133# Path to sshd must be absolute for rexec
134case "$SSHD" in
135/*) ;;
136*) SSHD=`which $SSHD` ;;
137esac
138
139case "$SSHAGENT" in
140/*) ;;
141*) SSHAGENT=`which $SSHAGENT` ;;
142esac
143
144# Logfiles.
145# SSH_LOGFILE should be the debug output of ssh(1) only
146# SSHD_LOGFILE should be the debug output of sshd(8) only
147# REGRESS_LOGFILE is the output of the test itself stdout and stderr
148if [ "x$TEST_SSH_LOGFILE" = "x" ]; then
149	TEST_SSH_LOGFILE=$OBJ/ssh.log
150fi
151if [ "x$TEST_SSHD_LOGFILE" = "x" ]; then
152	TEST_SSHD_LOGFILE=$OBJ/sshd.log
153fi
154if [ "x$TEST_REGRESS_LOGFILE" = "x" ]; then
155	TEST_REGRESS_LOGFILE=$OBJ/regress.log
156fi
157
158# truncate logfiles
159>$TEST_SSH_LOGFILE
160>$TEST_SSHD_LOGFILE
161>$TEST_REGRESS_LOGFILE
162
163# Create wrapper ssh with logging.  We can't just specify "SSH=ssh -E..."
164# because sftp and scp don't handle spaces in arguments.
165SSHLOGWRAP=$OBJ/ssh-log-wrapper.sh
166echo "#!/bin/sh" > $SSHLOGWRAP
167echo "exec ${SSH} -E${TEST_SSH_LOGFILE} "'"$@"' >>$SSHLOGWRAP
168
169chmod a+rx $OBJ/ssh-log-wrapper.sh
170SSH="$SSHLOGWRAP"
171
172# Some test data.  We make a copy because some tests will overwrite it.
173# The tests may assume that $DATA exists and is writable and $COPY does
174# not exist.  Tests requiring larger data files can call increase_datafile_size
175# [kbytes] to ensure the file is at least that large.
176DATANAME=data
177DATA=$OBJ/${DATANAME}
178cat ${SSHAGENT} >${DATA}
179chmod u+w ${DATA}
180COPY=$OBJ/copy
181rm -f ${COPY}
182
183increase_datafile_size()
184{
185	while [ `du -k ${DATA} | cut -f1` -lt $1 ]; do
186		cat ${SSHAGENT} >>${DATA}
187	done
188}
189
190# these should be used in tests
191export SSH SSHD SSHAGENT SSHADD SSHKEYGEN SSHKEYSCAN SFTP SFTPSERVER SCP
192#echo $SSH $SSHD $SSHAGENT $SSHADD $SSHKEYGEN $SSHKEYSCAN $SFTP $SFTPSERVER $SCP
193
194# Portable specific functions
195have_prog()
196{
197	saved_IFS="$IFS"
198	IFS=":"
199	for i in $PATH
200	do
201		if [ -x $i/$1 ]; then
202			IFS="$saved_IFS"
203			return 0
204		fi
205	done
206	IFS="$saved_IFS"
207	return 1
208}
209
210jot() {
211	awk "BEGIN { for (i = $2; i < $2 + $1; i++) { printf \"%d\n\", i } exit }"
212}
213
214# Check whether preprocessor symbols are defined in config.h.
215config_defined ()
216{
217	str=$1
218	while test "x$2" != "x" ; do
219		str="$str|$2"
220		shift
221	done
222	egrep "^#define.*($str)" ${BUILDDIR}/config.h >/dev/null 2>&1
223}
224
225md5 () {
226	if have_prog md5sum; then
227		md5sum
228	elif have_prog openssl; then
229		openssl md5
230	elif have_prog cksum; then
231		cksum
232	elif have_prog sum; then
233		sum
234	else
235		wc -c
236	fi
237}
238# End of portable specific functions
239
240# helper
241cleanup ()
242{
243	if [ -f $PIDFILE ]; then
244		pid=`$SUDO cat $PIDFILE`
245		if [ "X$pid" = "X" ]; then
246			echo no sshd running
247		else
248			if [ $pid -lt 2 ]; then
249				echo bad pid for ssh: $pid
250			else
251				$SUDO kill $pid
252				trace "wait for sshd to exit"
253				i=0;
254				while [ -f $PIDFILE -a $i -lt 5 ]; do
255					i=`expr $i + 1`
256					sleep $i
257				done
258				test -f $PIDFILE && \
259				    fatal "sshd didn't exit port $PORT pid $pid"
260			fi
261		fi
262	fi
263}
264
265start_debug_log ()
266{
267	echo "trace: $@" >$TEST_REGRESS_LOGFILE
268	echo "trace: $@" >$TEST_SSH_LOGFILE
269	echo "trace: $@" >$TEST_SSHD_LOGFILE
270}
271
272save_debug_log ()
273{
274	echo $@ >>$TEST_REGRESS_LOGFILE
275	echo $@ >>$TEST_SSH_LOGFILE
276	echo $@ >>$TEST_SSHD_LOGFILE
277	(cat $TEST_REGRESS_LOGFILE; echo) >>$OBJ/failed-regress.log
278	(cat $TEST_SSH_LOGFILE; echo) >>$OBJ/failed-ssh.log
279	(cat $TEST_SSHD_LOGFILE; echo) >>$OBJ/failed-sshd.log
280}
281
282trace ()
283{
284	start_debug_log $@
285	if [ "X$TEST_SSH_TRACE" = "Xyes" ]; then
286		echo "$@"
287	fi
288}
289
290verbose ()
291{
292	start_debug_log $@
293	if [ "X$TEST_SSH_QUIET" != "Xyes" ]; then
294		echo "$@"
295	fi
296}
297
298warn ()
299{
300	echo "WARNING: $@" >>$TEST_SSH_LOGFILE
301	echo "WARNING: $@"
302}
303
304fail ()
305{
306	save_debug_log "FAIL: $@"
307	RESULT=1
308	echo "$@"
309
310}
311
312fatal ()
313{
314	save_debug_log "FATAL: $@"
315	printf "FATAL: "
316	fail "$@"
317	cleanup
318	exit $RESULT
319}
320
321RESULT=0
322PIDFILE=$OBJ/pidfile
323
324trap fatal 3 2
325
326# create server config
327cat << EOF > $OBJ/sshd_config
328	StrictModes		no
329	Port			$PORT
330	Protocol		2,1
331	AddressFamily		inet
332	ListenAddress		127.0.0.1
333	#ListenAddress		::1
334	PidFile			$PIDFILE
335	AuthorizedKeysFile	$OBJ/authorized_keys_%u
336	LogLevel		DEBUG3
337	AcceptEnv		_XXX_TEST_*
338	AcceptEnv		_XXX_TEST
339	Subsystem	sftp	$SFTPSERVER
340EOF
341
342if [ ! -z "$TEST_SSH_SSHD_CONFOPTS" ]; then
343	trace "adding sshd_config option $TEST_SSH_SSHD_CONFOPTS"
344	echo "$TEST_SSH_SSHD_CONFOPTS" >> $OBJ/sshd_config
345fi
346
347# server config for proxy connects
348cp $OBJ/sshd_config $OBJ/sshd_proxy
349
350# allow group-writable directories in proxy-mode
351echo 'StrictModes no' >> $OBJ/sshd_proxy
352
353# create client config
354cat << EOF > $OBJ/ssh_config
355Host *
356	Protocol		2,1
357	Hostname		127.0.0.1
358	HostKeyAlias		localhost-with-alias
359	Port			$PORT
360	User			$USER
361	GlobalKnownHostsFile	$OBJ/known_hosts
362	UserKnownHostsFile	$OBJ/known_hosts
363	RSAAuthentication	yes
364	PubkeyAuthentication	yes
365	ChallengeResponseAuthentication	no
366	HostbasedAuthentication	no
367	PasswordAuthentication	no
368	RhostsRSAAuthentication	no
369	BatchMode		yes
370	StrictHostKeyChecking	yes
371	LogLevel		DEBUG3
372EOF
373
374if [ ! -z "$TEST_SSH_SSH_CONFOPTS" ]; then
375	trace "adding ssh_config option $TEST_SSH_SSHD_CONFOPTS"
376	echo "$TEST_SSH_SSH_CONFOPTS" >> $OBJ/ssh_config
377fi
378
379rm -f $OBJ/known_hosts $OBJ/authorized_keys_$USER
380
381trace "generate keys"
382for t in rsa rsa1; do
383	# generate user key
384	if [ ! -f $OBJ/$t ] || [ ${SSHKEYGEN} -nt $OBJ/$t ]; then
385		rm -f $OBJ/$t
386		${SSHKEYGEN} -q -N '' -t $t  -f $OBJ/$t ||\
387			fail "ssh-keygen for $t failed"
388	fi
389
390	# known hosts file for client
391	(
392		printf 'localhost-with-alias,127.0.0.1,::1 '
393		cat $OBJ/$t.pub
394	) >> $OBJ/known_hosts
395
396	# setup authorized keys
397	cat $OBJ/$t.pub >> $OBJ/authorized_keys_$USER
398	echo IdentityFile $OBJ/$t >> $OBJ/ssh_config
399
400	# use key as host key, too
401	$SUDO cp $OBJ/$t $OBJ/host.$t
402	echo HostKey $OBJ/host.$t >> $OBJ/sshd_config
403
404	# don't use SUDO for proxy connect
405	echo HostKey $OBJ/$t >> $OBJ/sshd_proxy
406done
407chmod 644 $OBJ/authorized_keys_$USER
408
409# Activate Twisted Conch tests if the binary is present
410REGRESS_INTEROP_CONCH=no
411if test -x "$CONCH" ; then
412	REGRESS_INTEROP_CONCH=yes
413fi
414
415# If PuTTY is present and we are running a PuTTY test, prepare keys and
416# configuration
417REGRESS_INTEROP_PUTTY=no
418if test -x "$PUTTYGEN" -a -x "$PLINK" ; then
419	REGRESS_INTEROP_PUTTY=yes
420fi
421case "$SCRIPT" in
422*putty*)	;;
423*)		REGRESS_INTEROP_PUTTY=no ;;
424esac
425
426if test "$REGRESS_INTEROP_PUTTY" = "yes" ; then
427	mkdir -p ${OBJ}/.putty
428
429	# Add a PuTTY key to authorized_keys
430	rm -f ${OBJ}/putty.rsa2
431	puttygen -t rsa -o ${OBJ}/putty.rsa2 < /dev/null > /dev/null
432	puttygen -O public-openssh ${OBJ}/putty.rsa2 \
433	    >> $OBJ/authorized_keys_$USER
434
435	# Convert rsa2 host key to PuTTY format
436	${SRC}/ssh2putty.sh 127.0.0.1 $PORT $OBJ/rsa > \
437	    ${OBJ}/.putty/sshhostkeys
438	${SRC}/ssh2putty.sh 127.0.0.1 22 $OBJ/rsa >> \
439	    ${OBJ}/.putty/sshhostkeys
440
441	# Setup proxied session
442	mkdir -p ${OBJ}/.putty/sessions
443	rm -f ${OBJ}/.putty/sessions/localhost_proxy
444	echo "Hostname=127.0.0.1" >> ${OBJ}/.putty/sessions/localhost_proxy
445	echo "PortNumber=$PORT" >> ${OBJ}/.putty/sessions/localhost_proxy
446	echo "ProxyMethod=5" >> ${OBJ}/.putty/sessions/localhost_proxy
447	echo "ProxyTelnetCommand=sh ${SRC}/sshd-log-wrapper.sh ${SSHD} ${TEST_SSHD_LOGFILE} -i -f $OBJ/sshd_proxy" >> ${OBJ}/.putty/sessions/localhost_proxy
448
449	REGRESS_INTEROP_PUTTY=yes
450fi
451
452# create a proxy version of the client config
453(
454	cat $OBJ/ssh_config
455	echo proxycommand ${SUDO} sh ${SRC}/sshd-log-wrapper.sh ${SSHD} ${TEST_SSHD_LOGFILE} -i -f $OBJ/sshd_proxy
456) > $OBJ/ssh_proxy
457
458# check proxy config
459${SSHD} -t -f $OBJ/sshd_proxy	|| fatal "sshd_proxy broken"
460
461start_sshd ()
462{
463	# start sshd
464	$SUDO ${SSHD} -f $OBJ/sshd_config "$@" -t || fatal "sshd_config broken"
465	$SUDO ${SSHD} -f $OBJ/sshd_config "$@" -E$TEST_SSHD_LOGFILE
466
467	trace "wait for sshd"
468	i=0;
469	while [ ! -f $PIDFILE -a $i -lt 10 ]; do
470		i=`expr $i + 1`
471		sleep $i
472	done
473
474	test -f $PIDFILE || fatal "no sshd running on port $PORT"
475}
476
477# source test body
478. $SCRIPT
479
480# kill sshd
481cleanup
482if [ $RESULT -eq 0 ]; then
483	verbose ok $tid
484else
485	echo failed $tid
486fi
487exit $RESULT
488