1# $OpenBSD: test-exec.sh,v 1.87 2021/09/01 00:50:27 dtucker Exp $ 2# Placed in the Public Domain. 3 4#SUDO=sudo 5 6if [ ! -x "$TEST_SSH_ELAPSED_TIMES" ]; then 7 STARTTIME=`date '+%s'` 8fi 9 10if [ ! -z "$TEST_SSH_PORT" ]; then 11 PORT="$TEST_SSH_PORT" 12else 13 PORT=4242 14fi 15 16OBJ=$1 17if [ "x$OBJ" = "x" ]; then 18 echo '$OBJ not defined' 19 exit 2 20fi 21if [ ! -d $OBJ ]; then 22 echo "not a directory: $OBJ" 23 exit 2 24fi 25SCRIPT=$2 26if [ "x$SCRIPT" = "x" ]; then 27 echo '$SCRIPT not defined' 28 exit 2 29fi 30if [ ! -f $SCRIPT ]; then 31 echo "not a file: $SCRIPT" 32 exit 2 33fi 34if sh -n $SCRIPT; then 35 true 36else 37 echo "syntax error in $SCRIPT" 38 exit 2 39fi 40unset SSH_AUTH_SOCK 41 42USER=`id -un` 43 44SRC=`dirname ${SCRIPT}` 45 46# defaults 47SSH=ssh 48SSHD=sshd 49SSHAGENT=ssh-agent 50SSHADD=ssh-add 51SSHKEYGEN=ssh-keygen 52SSHKEYSCAN=ssh-keyscan 53SFTP=sftp 54SFTPSERVER=/usr/libexec/sftp-server 55SCP=scp 56 57# Interop testing 58PLINK=/usr/local/bin/plink 59PUTTYGEN=/usr/local/bin/puttygen 60CONCH=/usr/local/bin/conch 61 62# Tools used by multiple tests 63NC=nc 64OPENSSL_BIN="${OPENSSL_BIN:-openssl}" 65 66if [ "x$TEST_SSH_SSH" != "x" ]; then 67 SSH="${TEST_SSH_SSH}" 68fi 69if [ "x$TEST_SSH_SSHD" != "x" ]; then 70 SSHD="${TEST_SSH_SSHD}" 71fi 72if [ "x$TEST_SSH_SSHAGENT" != "x" ]; then 73 SSHAGENT="${TEST_SSH_SSHAGENT}" 74fi 75if [ "x$TEST_SSH_SSHADD" != "x" ]; then 76 SSHADD="${TEST_SSH_SSHADD}" 77fi 78if [ "x$TEST_SSH_SSHKEYGEN" != "x" ]; then 79 SSHKEYGEN="${TEST_SSH_SSHKEYGEN}" 80fi 81if [ "x$TEST_SSH_SSHKEYSCAN" != "x" ]; then 82 SSHKEYSCAN="${TEST_SSH_SSHKEYSCAN}" 83fi 84if [ "x$TEST_SSH_SFTP" != "x" ]; then 85 SFTP="${TEST_SSH_SFTP}" 86fi 87if [ "x$TEST_SSH_SFTPSERVER" != "x" ]; then 88 SFTPSERVER="${TEST_SSH_SFTPSERVER}" 89fi 90if [ "x$TEST_SSH_SCP" != "x" ]; then 91 SCP="${TEST_SSH_SCP}" 92fi 93if [ "x$TEST_SSH_PLINK" != "x" ]; then 94 PLINK="${TEST_SSH_PLINK}" 95fi 96if [ "x$TEST_SSH_PUTTYGEN" != "x" ]; then 97 PUTTYGEN="${TEST_SSH_PUTTYGEN}" 98fi 99if [ "x$TEST_SSH_CONCH" != "x" ]; then 100 CONCH="${TEST_SSH_CONCH}" 101fi 102if [ "x$TEST_SSH_PKCS11_HELPER" != "x" ]; then 103 SSH_PKCS11_HELPER="${TEST_SSH_PKCS11_HELPER}" 104fi 105if [ "x$TEST_SSH_SK_HELPER" != "x" ]; then 106 SSH_SK_HELPER="${TEST_SSH_SK_HELPER}" 107fi 108if [ "x$TEST_SSH_OPENSSL" != "x" ]; then 109 OPENSSL_BIN="${TEST_SSH_OPENSSL}" 110fi 111 112# Path to sshd must be absolute for rexec 113case "$SSHD" in 114/*) ;; 115*) SSHD=`which $SSHD` ;; 116esac 117 118case "$SSHAGENT" in 119/*) ;; 120*) SSHAGENT=`which $SSHAGENT` ;; 121esac 122 123# Logfiles. 124# SSH_LOGFILE should be the debug output of ssh(1) only 125# SSHD_LOGFILE should be the debug output of sshd(8) only 126# REGRESS_LOGFILE is the output of the test itself stdout and stderr 127if [ "x$TEST_SSH_LOGFILE" = "x" ]; then 128 TEST_SSH_LOGFILE=$OBJ/ssh.log 129fi 130if [ "x$TEST_SSHD_LOGFILE" = "x" ]; then 131 TEST_SSHD_LOGFILE=$OBJ/sshd.log 132fi 133if [ "x$TEST_REGRESS_LOGFILE" = "x" ]; then 134 TEST_REGRESS_LOGFILE=$OBJ/regress.log 135fi 136 137# truncate logfiles 138>$TEST_SSH_LOGFILE 139>$TEST_SSHD_LOGFILE 140>$TEST_REGRESS_LOGFILE 141 142# Create wrapper ssh with logging. We can't just specify "SSH=ssh -E..." 143# because sftp and scp don't handle spaces in arguments. scp and sftp like 144# to use -q so we remove those to preserve our debug logging. In the rare 145# instance where -q is desirable -qq is equivalent and is not removed. 146SSHLOGWRAP=$OBJ/ssh-log-wrapper.sh 147cat >$SSHLOGWRAP <<EOD 148#!/bin/sh 149for i in "\$@";do shift;case "\$i" in -q):;; *) set -- "\$@" "\$i";;esac;done 150exec ${SSH} -E${TEST_SSH_LOGFILE} "\$@" 151EOD 152 153chmod a+rx $OBJ/ssh-log-wrapper.sh 154REAL_SSH="$SSH" 155REAL_SSHD="$SSHD" 156SSH="$SSHLOGWRAP" 157 158# Some test data. We make a copy because some tests will overwrite it. 159# The tests may assume that $DATA exists and is writable and $COPY does 160# not exist. Tests requiring larger data files can call increase_datafile_size 161# [kbytes] to ensure the file is at least that large. 162DATANAME=data 163DATA=$OBJ/${DATANAME} 164cat ${SSHAGENT} >${DATA} 165COPY=$OBJ/copy 166rm -f ${COPY} 167 168increase_datafile_size() 169{ 170 while [ `du -k ${DATA} | cut -f1` -lt $1 ]; do 171 cat ${SSHAGENT} >>${DATA} 172 done 173} 174 175# these should be used in tests 176export SSH SSHD SSHAGENT SSHADD SSHKEYGEN SSHKEYSCAN SFTP SFTPSERVER SCP 177export SSH_PKCS11_HELPER SSH_SK_HELPER 178#echo $SSH $SSHD $SSHAGENT $SSHADD $SSHKEYGEN $SSHKEYSCAN $SFTP $SFTPSERVER $SCP 179 180stop_sshd () 181{ 182 if [ -f $PIDFILE ]; then 183 pid=`$SUDO cat $PIDFILE` 184 if [ "X$pid" = "X" ]; then 185 echo no sshd running 186 else 187 if [ $pid -lt 2 ]; then 188 echo bad pid for sshd: $pid 189 else 190 $SUDO kill $pid 191 trace "wait for sshd to exit" 192 i=0; 193 while [ -f $PIDFILE -a $i -lt 5 ]; do 194 i=`expr $i + 1` 195 sleep $i 196 done 197 if test -f $PIDFILE; then 198 if $SUDO kill -0 $pid; then 199 echo "sshd didn't exit " \ 200 "port $PORT pid $pid" 201 else 202 echo "sshd died without cleanup" 203 fi 204 exit 1 205 fi 206 fi 207 fi 208 fi 209} 210 211# helper 212cleanup () 213{ 214 if [ "x$SSH_PID" != "x" ]; then 215 if [ $SSH_PID -lt 2 ]; then 216 echo bad pid for ssh: $SSH_PID 217 else 218 kill $SSH_PID 219 fi 220 fi 221 stop_sshd 222 if [ ! -z "$TEST_SSH_ELAPSED_TIMES" ]; then 223 now=`date '+%s'` 224 elapsed=$(($now - $STARTTIME)) 225 echo elapsed $elapsed `basename $SCRIPT .sh` 226 fi 227} 228 229start_debug_log () 230{ 231 echo "trace: $@" >$TEST_REGRESS_LOGFILE 232 echo "trace: $@" >$TEST_SSH_LOGFILE 233 echo "trace: $@" >$TEST_SSHD_LOGFILE 234} 235 236save_debug_log () 237{ 238 echo $@ >>$TEST_REGRESS_LOGFILE 239 echo $@ >>$TEST_SSH_LOGFILE 240 echo $@ >>$TEST_SSHD_LOGFILE 241 (cat $TEST_REGRESS_LOGFILE; echo) >>$OBJ/failed-regress.log 242 (cat $TEST_SSH_LOGFILE; echo) >>$OBJ/failed-ssh.log 243 (cat $TEST_SSHD_LOGFILE; echo) >>$OBJ/failed-sshd.log 244} 245 246trace () 247{ 248 start_debug_log $@ 249 if [ "X$TEST_SSH_TRACE" = "Xyes" ]; then 250 echo "$@" 251 fi 252} 253 254verbose () 255{ 256 start_debug_log $@ 257 if [ "X$TEST_SSH_QUIET" != "Xyes" ]; then 258 echo "$@" 259 fi 260} 261 262 263fail () 264{ 265 save_debug_log "FAIL: $@" 266 RESULT=1 267 echo "$@" 268 if test "x$TEST_SSH_FAIL_FATAL" != "x" ; then 269 cleanup 270 exit $RESULT 271 fi 272} 273 274fatal () 275{ 276 save_debug_log "FATAL: $@" 277 printf "FATAL: " 278 fail "$@" 279 cleanup 280 exit $RESULT 281} 282 283# Skip remaining tests in script. 284skip () 285{ 286 echo "SKIPPED: $@" 287 cleanup 288 exit $RESULT 289} 290 291RESULT=0 292PIDFILE=$OBJ/pidfile 293 294trap fatal 3 2 295 296# create server config 297cat << EOF > $OBJ/sshd_config 298 Port $PORT 299 AddressFamily inet 300 ListenAddress 127.0.0.1 301 #ListenAddress ::1 302 PidFile $PIDFILE 303 AuthorizedKeysFile $OBJ/authorized_keys_%u 304 LogLevel DEBUG3 305 AcceptEnv _XXX_TEST_* 306 AcceptEnv _XXX_TEST 307 Subsystem sftp $SFTPSERVER 308EOF 309 310# This may be necessary if /usr/src and/or /usr/obj are group-writable, 311# but if you aren't careful with permissions then the unit tests could 312# be abused to locally escalate privileges. 313if [ ! -z "$TEST_SSH_UNSAFE_PERMISSIONS" ]; then 314 echo " StrictModes no" >> $OBJ/sshd_config 315else 316 # check and warn if excessive permissions are likely to cause failures. 317 unsafe="" 318 dir="${OBJ}" 319 while test ${dir} != "/"; do 320 if test -d "${dir}" && ! test -h "${dir}"; then 321 perms=`ls -ld ${dir}` 322 case "${perms}" in 323 ?????w????*|????????w?*) unsafe="${unsafe} ${dir}" ;; 324 esac 325 fi 326 dir=`dirname ${dir}` 327 done 328 if ! test -z "${unsafe}"; then 329 cat <<EOD 330 331WARNING: Unsafe (group or world writable) directory permissions found: 332${unsafe} 333 334These could be abused to locally escalate privileges. If you are 335sure that this is not a risk (eg there are no other users), you can 336bypass this check by setting TEST_SSH_UNSAFE_PERMISSIONS=1 337 338EOD 339 fi 340fi 341 342if [ ! -z "$TEST_SSH_MODULI_FILE" ]; then 343 trace "adding modulifile='$TEST_SSH_MODULI_FILE' to sshd_config" 344 echo " ModuliFile '$TEST_SSH_MODULI_FILE'" >> $OBJ/sshd_config 345fi 346 347if [ ! -z "$TEST_SSH_SSHD_CONFOPTS" ]; then 348 trace "adding sshd_config option $TEST_SSH_SSHD_CONFOPTS" 349 echo "$TEST_SSH_SSHD_CONFOPTS" >> $OBJ/sshd_config 350fi 351 352# server config for proxy connects 353cp $OBJ/sshd_config $OBJ/sshd_proxy 354 355# allow group-writable directories in proxy-mode 356echo 'StrictModes no' >> $OBJ/sshd_proxy 357 358# create client config 359cat << EOF > $OBJ/ssh_config 360Host * 361 Hostname 127.0.0.1 362 HostKeyAlias localhost-with-alias 363 Port $PORT 364 User $USER 365 GlobalKnownHostsFile $OBJ/known_hosts 366 UserKnownHostsFile $OBJ/known_hosts 367 PubkeyAuthentication yes 368 ChallengeResponseAuthentication no 369 HostbasedAuthentication no 370 PasswordAuthentication no 371 BatchMode yes 372 StrictHostKeyChecking yes 373 LogLevel DEBUG3 374EOF 375 376if [ ! -z "$TEST_SSH_SSH_CONFOPTS" ]; then 377 trace "adding ssh_config option $TEST_SSH_SSH_CONFOPTS" 378 echo "$TEST_SSH_SSH_CONFOPTS" >> $OBJ/ssh_config 379fi 380 381rm -f $OBJ/known_hosts $OBJ/authorized_keys_$USER 382 383SSH_SK_PROVIDER= 384if [ -f "${SRC}/misc/sk-dummy/obj/sk-dummy.so" ] ; then 385 SSH_SK_PROVIDER="${SRC}/misc/sk-dummy/obj/sk-dummy.so" 386elif [ -f "${SRC}/misc/sk-dummy/sk-dummy.so" ] ; then 387 SSH_SK_PROVIDER="${SRC}/misc/sk-dummy/sk-dummy.so" 388fi 389export SSH_SK_PROVIDER 390 391if ! test -z "$SSH_SK_PROVIDER"; then 392 EXTRA_AGENT_ARGS='-P/*' # XXX want realpath(1)... 393 echo "SecurityKeyProvider $SSH_SK_PROVIDER" >> $OBJ/ssh_config 394 echo "SecurityKeyProvider $SSH_SK_PROVIDER" >> $OBJ/sshd_config 395 echo "SecurityKeyProvider $SSH_SK_PROVIDER" >> $OBJ/sshd_proxy 396fi 397export EXTRA_AGENT_ARGS 398 399maybe_filter_sk() { 400 if test -z "$SSH_SK_PROVIDER" ; then 401 grep -v ^sk 402 else 403 cat 404 fi 405} 406 407SSH_KEYTYPES=`$SSH -Q key-plain | maybe_filter_sk` 408SSH_HOSTKEY_TYPES=`$SSH -Q key-plain | maybe_filter_sk` 409 410for t in ${SSH_KEYTYPES}; do 411 # generate user key 412 if [ ! -f $OBJ/$t ] || [ ${SSHKEYGEN} -nt $OBJ/$t ]; then 413 trace "generating key type $t" 414 rm -f $OBJ/$t 415 ${SSHKEYGEN} -q -N '' -t $t -f $OBJ/$t ||\ 416 fail "ssh-keygen for $t failed" 417 else 418 trace "using cached key type $t" 419 fi 420 421 # setup authorized keys 422 cat $OBJ/$t.pub >> $OBJ/authorized_keys_$USER 423 echo IdentityFile $OBJ/$t >> $OBJ/ssh_config 424done 425 426for t in ${SSH_HOSTKEY_TYPES}; do 427 # known hosts file for client 428 ( 429 printf 'localhost-with-alias,127.0.0.1,::1 ' 430 cat $OBJ/$t.pub 431 ) >> $OBJ/known_hosts 432 433 # use key as host key, too 434 (umask 077; $SUDO cp $OBJ/$t $OBJ/host.$t) 435 echo HostKey $OBJ/host.$t >> $OBJ/sshd_config 436 437 # don't use SUDO for proxy connect 438 echo HostKey $OBJ/$t >> $OBJ/sshd_proxy 439done 440chmod 644 $OBJ/authorized_keys_$USER 441 442# Activate Twisted Conch tests if the binary is present 443REGRESS_INTEROP_CONCH=no 444if test -x "$CONCH" ; then 445 REGRESS_INTEROP_CONCH=yes 446fi 447 448# If PuTTY is present, new enough and we are running a PuTTY test, prepare 449# keys and configuration. 450REGRESS_INTEROP_PUTTY=no 451if test -x "$PUTTYGEN" -a -x "$PLINK" && 452 "$PUTTYGEN" --help 2>&1 | grep -- --new-passphrase >/dev/null; then 453 REGRESS_INTEROP_PUTTY=yes 454fi 455case "$SCRIPT" in 456*putty*) ;; 457*) REGRESS_INTEROP_PUTTY=no ;; 458esac 459 460if test "$REGRESS_INTEROP_PUTTY" = "yes" ; then 461 mkdir -p ${OBJ}/.putty 462 463 # Add a PuTTY key to authorized_keys 464 rm -f ${OBJ}/putty.rsa2 465 if ! "$PUTTYGEN" -t rsa -o ${OBJ}/putty.rsa2 \ 466 --random-device=/dev/urandom \ 467 --new-passphrase /dev/null < /dev/null > /dev/null; then 468 echo "Your installed version of PuTTY is too old to support --new-passphrase, skipping test" >&2 469 exit 1 470 fi 471 "$PUTTYGEN" -O public-openssh ${OBJ}/putty.rsa2 \ 472 >> $OBJ/authorized_keys_$USER 473 474 # Convert rsa2 host key to PuTTY format 475 cp $OBJ/ssh-rsa $OBJ/ssh-rsa_oldfmt 476 ${SSHKEYGEN} -p -N '' -m PEM -f $OBJ/ssh-rsa_oldfmt >/dev/null 477 ${SRC}/ssh2putty.sh 127.0.0.1 $PORT $OBJ/ssh-rsa_oldfmt > \ 478 ${OBJ}/.putty/sshhostkeys 479 ${SRC}/ssh2putty.sh 127.0.0.1 22 $OBJ/ssh-rsa_oldfmt >> \ 480 ${OBJ}/.putty/sshhostkeys 481 rm -f $OBJ/ssh-rsa_oldfmt 482 483 # Setup proxied session 484 mkdir -p ${OBJ}/.putty/sessions 485 rm -f ${OBJ}/.putty/sessions/localhost_proxy 486 echo "Protocol=ssh" >> ${OBJ}/.putty/sessions/localhost_proxy 487 echo "HostName=127.0.0.1" >> ${OBJ}/.putty/sessions/localhost_proxy 488 echo "PortNumber=$PORT" >> ${OBJ}/.putty/sessions/localhost_proxy 489 echo "ProxyMethod=5" >> ${OBJ}/.putty/sessions/localhost_proxy 490 echo "ProxyTelnetCommand=sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy" >> ${OBJ}/.putty/sessions/localhost_proxy 491 echo "ProxyLocalhost=1" >> ${OBJ}/.putty/sessions/localhost_proxy 492fi 493 494# create a proxy version of the client config 495( 496 cat $OBJ/ssh_config 497 echo proxycommand ${SUDO} env SSH_SK_HELPER=\"$SSH_SK_HELPER\" sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy 498) > $OBJ/ssh_proxy 499 500# check proxy config 501${SSHD} -t -f $OBJ/sshd_proxy || fatal "sshd_proxy broken" 502 503start_sshd () 504{ 505 # start sshd 506 $SUDO ${SSHD} -f $OBJ/sshd_config "$@" -t || fatal "sshd_config broken" 507 $SUDO env SSH_SK_HELPER="$SSH_SK_HELPER" \ 508 ${SSHD} -f $OBJ/sshd_config "$@" -E$TEST_SSHD_LOGFILE 509 510 trace "wait for sshd" 511 i=0; 512 while [ ! -f $PIDFILE -a $i -lt 10 ]; do 513 i=`expr $i + 1` 514 sleep $i 515 done 516 517 test -f $PIDFILE || fatal "no sshd running on port $PORT" 518} 519 520# source test body 521. $SCRIPT 522 523# kill sshd 524cleanup 525if [ $RESULT -eq 0 ]; then 526 verbose ok $tid 527else 528 echo failed $tid 529fi 530exit $RESULT 531