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