test-exec.sh revision 323129
1# $OpenBSD: test-exec.sh,v 1.53 2016/04/15 02:57:10 djm 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 224REAL_SSH="$SSH" 225SSH="$SSHLOGWRAP" 226 227# Some test data. We make a copy because some tests will overwrite it. 228# The tests may assume that $DATA exists and is writable and $COPY does 229# not exist. Tests requiring larger data files can call increase_datafile_size 230# [kbytes] to ensure the file is at least that large. 231DATANAME=data 232DATA=$OBJ/${DATANAME} 233cat ${SSHAGENT_BIN} >${DATA} 234chmod u+w ${DATA} 235COPY=$OBJ/copy 236rm -f ${COPY} 237 238increase_datafile_size() 239{ 240 while [ `du -k ${DATA} | cut -f1` -lt $1 ]; do 241 cat ${SSHAGENT_BIN} >>${DATA} 242 done 243} 244 245# these should be used in tests 246export SSH SSHD SSHAGENT SSHADD SSHKEYGEN SSHKEYSCAN SFTP SFTPSERVER SCP 247#echo $SSH $SSHD $SSHAGENT $SSHADD $SSHKEYGEN $SSHKEYSCAN $SFTP $SFTPSERVER $SCP 248 249# Portable specific functions 250have_prog() 251{ 252 saved_IFS="$IFS" 253 IFS=":" 254 for i in $PATH 255 do 256 if [ -x $i/$1 ]; then 257 IFS="$saved_IFS" 258 return 0 259 fi 260 done 261 IFS="$saved_IFS" 262 return 1 263} 264 265jot() { 266 awk "BEGIN { for (i = $2; i < $2 + $1; i++) { printf \"%d\n\", i } exit }" 267} 268 269# Check whether preprocessor symbols are defined in config.h. 270config_defined () 271{ 272 str=$1 273 while test "x$2" != "x" ; do 274 str="$str|$2" 275 shift 276 done 277 egrep "^#define.*($str)" ${BUILDDIR}/config.h >/dev/null 2>&1 278} 279 280md5 () { 281 if have_prog md5sum; then 282 md5sum 283 elif have_prog openssl; then 284 openssl md5 285 elif have_prog cksum; then 286 cksum 287 elif have_prog sum; then 288 sum 289 else 290 wc -c 291 fi 292} 293# End of portable specific functions 294 295# helper 296cleanup () 297{ 298 if [ "x$SSH_PID" != "x" ]; then 299 if [ $SSH_PID -lt 2 ]; then 300 echo bad pid for ssh: $SSH_PID 301 else 302 kill $SSH_PID 303 fi 304 fi 305 if [ -f $PIDFILE ]; then 306 pid=`$SUDO cat $PIDFILE` 307 if [ "X$pid" = "X" ]; then 308 echo no sshd running 309 else 310 if [ $pid -lt 2 ]; then 311 echo bad pid for sshd: $pid 312 else 313 $SUDO kill $pid 314 trace "wait for sshd to exit" 315 i=0; 316 while [ -f $PIDFILE -a $i -lt 5 ]; do 317 i=`expr $i + 1` 318 sleep $i 319 done 320 test -f $PIDFILE && \ 321 fatal "sshd didn't exit port $PORT pid $pid" 322 fi 323 fi 324 fi 325} 326 327start_debug_log () 328{ 329 echo "trace: $@" >$TEST_REGRESS_LOGFILE 330 echo "trace: $@" >$TEST_SSH_LOGFILE 331 echo "trace: $@" >$TEST_SSHD_LOGFILE 332} 333 334save_debug_log () 335{ 336 echo $@ >>$TEST_REGRESS_LOGFILE 337 echo $@ >>$TEST_SSH_LOGFILE 338 echo $@ >>$TEST_SSHD_LOGFILE 339 (cat $TEST_REGRESS_LOGFILE; echo) >>$OBJ/failed-regress.log 340 (cat $TEST_SSH_LOGFILE; echo) >>$OBJ/failed-ssh.log 341 (cat $TEST_SSHD_LOGFILE; echo) >>$OBJ/failed-sshd.log 342} 343 344trace () 345{ 346 start_debug_log $@ 347 if [ "X$TEST_SSH_TRACE" = "Xyes" ]; then 348 echo "$@" 349 fi 350} 351 352verbose () 353{ 354 start_debug_log $@ 355 if [ "X$TEST_SSH_QUIET" != "Xyes" ]; then 356 echo "$@" 357 fi 358} 359 360warn () 361{ 362 echo "WARNING: $@" >>$TEST_SSH_LOGFILE 363 echo "WARNING: $@" 364} 365 366fail () 367{ 368 save_debug_log "FAIL: $@" 369 RESULT=1 370 echo "$@" 371 372} 373 374fatal () 375{ 376 save_debug_log "FATAL: $@" 377 printf "FATAL: " 378 fail "$@" 379 cleanup 380 exit $RESULT 381} 382 383ssh_version () 384{ 385 echo ${SSH_PROTOCOLS} | grep "$1" >/dev/null 386} 387 388RESULT=0 389PIDFILE=$OBJ/pidfile 390 391trap fatal 3 2 392 393if ssh_version 1; then 394 PROTO="2,1" 395else 396 PROTO="2" 397fi 398 399# create server config 400cat << EOF > $OBJ/sshd_config 401 StrictModes no 402 Port $PORT 403 Protocol $PROTO 404 AddressFamily inet 405 ListenAddress 127.0.0.1 406 #ListenAddress ::1 407 PidFile $PIDFILE 408 AuthorizedKeysFile $OBJ/authorized_keys_%u 409 LogLevel DEBUG3 410 AcceptEnv _XXX_TEST_* 411 AcceptEnv _XXX_TEST 412 Subsystem sftp $SFTPSERVER 413EOF 414 415# This may be necessary if /usr/src and/or /usr/obj are group-writable, 416# but if you aren't careful with permissions then the unit tests could 417# be abused to locally escalate privileges. 418if [ ! -z "$TEST_SSH_UNSAFE_PERMISSIONS" ]; then 419 echo "StrictModes no" >> $OBJ/sshd_config 420fi 421 422if [ ! -z "$TEST_SSH_SSHD_CONFOPTS" ]; then 423 trace "adding sshd_config option $TEST_SSH_SSHD_CONFOPTS" 424 echo "$TEST_SSH_SSHD_CONFOPTS" >> $OBJ/sshd_config 425fi 426 427# server config for proxy connects 428cp $OBJ/sshd_config $OBJ/sshd_proxy 429 430# allow group-writable directories in proxy-mode 431echo 'StrictModes no' >> $OBJ/sshd_proxy 432 433# create client config 434cat << EOF > $OBJ/ssh_config 435Host * 436 Protocol $PROTO 437 Hostname 127.0.0.1 438 HostKeyAlias localhost-with-alias 439 Port $PORT 440 User $USER 441 GlobalKnownHostsFile $OBJ/known_hosts 442 UserKnownHostsFile $OBJ/known_hosts 443 RSAAuthentication yes 444 PubkeyAuthentication yes 445 ChallengeResponseAuthentication no 446 HostbasedAuthentication no 447 PasswordAuthentication no 448 RhostsRSAAuthentication no 449 BatchMode yes 450 StrictHostKeyChecking yes 451 LogLevel DEBUG3 452EOF 453 454if [ ! -z "$TEST_SSH_SSH_CONFOPTS" ]; then 455 trace "adding ssh_config option $TEST_SSH_SSH_CONFOPTS" 456 echo "$TEST_SSH_SSH_CONFOPTS" >> $OBJ/ssh_config 457fi 458 459rm -f $OBJ/known_hosts $OBJ/authorized_keys_$USER 460 461if ssh_version 1; then 462 SSH_KEYTYPES="rsa rsa1" 463else 464 SSH_KEYTYPES="rsa ed25519" 465fi 466trace "generate keys" 467for t in ${SSH_KEYTYPES}; do 468 # generate user key 469 if [ ! -f $OBJ/$t ] || [ ${SSHKEYGEN_BIN} -nt $OBJ/$t ]; then 470 rm -f $OBJ/$t 471 ${SSHKEYGEN} -q -N '' -t $t -f $OBJ/$t ||\ 472 fail "ssh-keygen for $t failed" 473 fi 474 475 # known hosts file for client 476 ( 477 printf 'localhost-with-alias,127.0.0.1,::1 ' 478 cat $OBJ/$t.pub 479 ) >> $OBJ/known_hosts 480 481 # setup authorized keys 482 cat $OBJ/$t.pub >> $OBJ/authorized_keys_$USER 483 echo IdentityFile $OBJ/$t >> $OBJ/ssh_config 484 485 # use key as host key, too 486 $SUDO cp $OBJ/$t $OBJ/host.$t 487 echo HostKey $OBJ/host.$t >> $OBJ/sshd_config 488 489 # don't use SUDO for proxy connect 490 echo HostKey $OBJ/$t >> $OBJ/sshd_proxy 491done 492chmod 644 $OBJ/authorized_keys_$USER 493 494# Activate Twisted Conch tests if the binary is present 495REGRESS_INTEROP_CONCH=no 496if test -x "$CONCH" ; then 497 REGRESS_INTEROP_CONCH=yes 498fi 499 500# If PuTTY is present and we are running a PuTTY test, prepare keys and 501# configuration 502REGRESS_INTEROP_PUTTY=no 503if test -x "$PUTTYGEN" -a -x "$PLINK" ; then 504 REGRESS_INTEROP_PUTTY=yes 505fi 506case "$SCRIPT" in 507*putty*) ;; 508*) REGRESS_INTEROP_PUTTY=no ;; 509esac 510 511if test "$REGRESS_INTEROP_PUTTY" = "yes" ; then 512 mkdir -p ${OBJ}/.putty 513 514 # Add a PuTTY key to authorized_keys 515 rm -f ${OBJ}/putty.rsa2 516 puttygen -t rsa -o ${OBJ}/putty.rsa2 < /dev/null > /dev/null 517 puttygen -O public-openssh ${OBJ}/putty.rsa2 \ 518 >> $OBJ/authorized_keys_$USER 519 520 # Convert rsa2 host key to PuTTY format 521 ${SRC}/ssh2putty.sh 127.0.0.1 $PORT $OBJ/rsa > \ 522 ${OBJ}/.putty/sshhostkeys 523 ${SRC}/ssh2putty.sh 127.0.0.1 22 $OBJ/rsa >> \ 524 ${OBJ}/.putty/sshhostkeys 525 526 # Setup proxied session 527 mkdir -p ${OBJ}/.putty/sessions 528 rm -f ${OBJ}/.putty/sessions/localhost_proxy 529 echo "Hostname=127.0.0.1" >> ${OBJ}/.putty/sessions/localhost_proxy 530 echo "PortNumber=$PORT" >> ${OBJ}/.putty/sessions/localhost_proxy 531 echo "ProxyMethod=5" >> ${OBJ}/.putty/sessions/localhost_proxy 532 echo "ProxyTelnetCommand=sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy" >> ${OBJ}/.putty/sessions/localhost_proxy 533 534 REGRESS_INTEROP_PUTTY=yes 535fi 536 537# create a proxy version of the client config 538( 539 cat $OBJ/ssh_config 540 echo proxycommand ${SUDO} sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy 541) > $OBJ/ssh_proxy 542 543# check proxy config 544${SSHD} -t -f $OBJ/sshd_proxy || fatal "sshd_proxy broken" 545 546start_sshd () 547{ 548 # start sshd 549 $SUDO ${SSHD} -f $OBJ/sshd_config "$@" -t || fatal "sshd_config broken" 550 $SUDO ${SSHD} -f $OBJ/sshd_config "$@" -E$TEST_SSHD_LOGFILE 551 552 trace "wait for sshd" 553 i=0; 554 while [ ! -f $PIDFILE -a $i -lt 10 ]; do 555 i=`expr $i + 1` 556 sleep $i 557 done 558 559 test -f $PIDFILE || fatal "no sshd running on port $PORT" 560} 561 562# source test body 563. $SCRIPT 564 565# kill sshd 566cleanup 567if [ $RESULT -eq 0 ]; then 568 verbose ok $tid 569else 570 echo failed $tid 571fi 572exit $RESULT 573