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