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