1*535af610SEd Maste# $OpenBSD: forward-control.sh,v 1.12 2023/07/28 05:33:15 djm Exp $ 2ce3adf43SDag-Erling Smørgrav# Placed in the Public Domain. 3ce3adf43SDag-Erling Smørgrav 4ce3adf43SDag-Erling Smørgravtid="sshd control of local and remote forwarding" 5ce3adf43SDag-Erling Smørgrav 6ce3adf43SDag-Erling SmørgravLFWD_PORT=3320 7ce3adf43SDag-Erling SmørgravRFWD_PORT=3321 8ce3adf43SDag-Erling SmørgravCTL=$OBJ/ctl-sock 938a52bd3SEd MasteWAIT_SECONDS=20 10ce3adf43SDag-Erling Smørgrav 11ce3adf43SDag-Erling Smørgravwait_for_process_to_exit() { 12ce3adf43SDag-Erling Smørgrav _pid=$1 13ce3adf43SDag-Erling Smørgrav _n=0 14ce3adf43SDag-Erling Smørgrav while kill -0 $_pid 2>/dev/null ; do 15ce3adf43SDag-Erling Smørgrav test $_n -eq 1 && trace "waiting for $_pid to exit" 16ce3adf43SDag-Erling Smørgrav _n=`expr $_n + 1` 1738a52bd3SEd Maste test $_n -ge $WAIT_SECONDS && return 1 18ce3adf43SDag-Erling Smørgrav sleep 1 19ce3adf43SDag-Erling Smørgrav done 20ce3adf43SDag-Erling Smørgrav return 0 21ce3adf43SDag-Erling Smørgrav} 22ce3adf43SDag-Erling Smørgrav 2338a52bd3SEd Mastemux_cmd() { 2438a52bd3SEd Maste ${SSH} -F $OBJ/ssh_proxy -S $CTL -O $1 host 2>&1 2538a52bd3SEd Maste} 2638a52bd3SEd Maste 2738a52bd3SEd Mastecontrolmaster_pid() { 2838a52bd3SEd Maste mux_cmd check | cut -f2 -d= | cut -f1 -d')' 2938a52bd3SEd Maste} 3038a52bd3SEd Maste 314f52dfbbSDag-Erling Smørgrav# usage: check_lfwd Y|N message 32ce3adf43SDag-Erling Smørgravcheck_lfwd() { 334f52dfbbSDag-Erling Smørgrav _expected=$1 344f52dfbbSDag-Erling Smørgrav _message=$2 354f52dfbbSDag-Erling Smørgrav ${SSH} -F $OBJ/ssh_proxy \ 36ce3adf43SDag-Erling Smørgrav -L$LFWD_PORT:127.0.0.1:$PORT \ 37ce3adf43SDag-Erling Smørgrav -o ExitOnForwardFailure=yes \ 3838a52bd3SEd Maste -MS $CTL -o ControlPersist=yes \ 39*535af610SEd Maste -Nf host 4038a52bd3SEd Maste mux_cmd check >/dev/null || fatal "check_lfwd ssh fail: $_message" 41ce3adf43SDag-Erling Smørgrav ${SSH} -F $OBJ/ssh_config -p $LFWD_PORT \ 4219261079SEd Maste -oConnectionAttempts=10 host true >/dev/null 2>&1 43ce3adf43SDag-Erling Smørgrav _result=$? 4438a52bd3SEd Maste _sshpid=`controlmaster_pid` 4538a52bd3SEd Maste mux_cmd exit >/dev/null 46ce3adf43SDag-Erling Smørgrav wait_for_process_to_exit $_sshpid 47ce3adf43SDag-Erling Smørgrav if test "x$_expected" = "xY" -a $_result -ne 0 ; then 48ce3adf43SDag-Erling Smørgrav fail "check_lfwd failed (expecting success): $_message" 49ce3adf43SDag-Erling Smørgrav elif test "x$_expected" = "xN" -a $_result -eq 0 ; then 50ce3adf43SDag-Erling Smørgrav fail "check_lfwd succeeded (expecting failure): $_message" 51ce3adf43SDag-Erling Smørgrav elif test "x$_expected" != "xY" -a "x$_expected" != "xN" ; then 52ce3adf43SDag-Erling Smørgrav fatal "check_lfwd invalid argument \"$_expected\"" 53ce3adf43SDag-Erling Smørgrav else 54ce3adf43SDag-Erling Smørgrav verbose "check_lfwd done (expecting $_expected): $_message" 55ce3adf43SDag-Erling Smørgrav fi 56ce3adf43SDag-Erling Smørgrav} 57ce3adf43SDag-Erling Smørgrav 584f52dfbbSDag-Erling Smørgrav# usage: check_rfwd Y|N message 59ce3adf43SDag-Erling Smørgravcheck_rfwd() { 604f52dfbbSDag-Erling Smørgrav _expected=$1 614f52dfbbSDag-Erling Smørgrav _message=$2 624f52dfbbSDag-Erling Smørgrav ${SSH} -F $OBJ/ssh_proxy \ 63190cef3dSDag-Erling Smørgrav -R127.0.0.1:$RFWD_PORT:127.0.0.1:$PORT \ 64ce3adf43SDag-Erling Smørgrav -o ExitOnForwardFailure=yes \ 6538a52bd3SEd Maste -MS $CTL -o ControlPersist=yes \ 66*535af610SEd Maste -Nf host 6738a52bd3SEd Maste mux_cmd check >/dev/null 68ce3adf43SDag-Erling Smørgrav _result=$? 6938a52bd3SEd Maste _sshpid=`controlmaster_pid` 70ce3adf43SDag-Erling Smørgrav if test $_result -eq 0; then 71ce3adf43SDag-Erling Smørgrav ${SSH} -F $OBJ/ssh_config -p $RFWD_PORT \ 7219261079SEd Maste -oConnectionAttempts=10 host true >/dev/null 2>&1 73ce3adf43SDag-Erling Smørgrav _result=$? 7438a52bd3SEd Maste mux_cmd exit >/dev/null 75ce3adf43SDag-Erling Smørgrav wait_for_process_to_exit $_sshpid 76ce3adf43SDag-Erling Smørgrav fi 77ce3adf43SDag-Erling Smørgrav if test "x$_expected" = "xY" -a $_result -ne 0 ; then 78ce3adf43SDag-Erling Smørgrav fail "check_rfwd failed (expecting success): $_message" 79ce3adf43SDag-Erling Smørgrav elif test "x$_expected" = "xN" -a $_result -eq 0 ; then 80ce3adf43SDag-Erling Smørgrav fail "check_rfwd succeeded (expecting failure): $_message" 81ce3adf43SDag-Erling Smørgrav elif test "x$_expected" != "xY" -a "x$_expected" != "xN" ; then 82ce3adf43SDag-Erling Smørgrav fatal "check_rfwd invalid argument \"$_expected\"" 83ce3adf43SDag-Erling Smørgrav else 84ce3adf43SDag-Erling Smørgrav verbose "check_rfwd done (expecting $_expected): $_message" 85ce3adf43SDag-Erling Smørgrav fi 86ce3adf43SDag-Erling Smørgrav} 87ce3adf43SDag-Erling Smørgrav 88ce3adf43SDag-Erling Smørgravstart_sshd 89ce3adf43SDag-Erling Smørgravcp ${OBJ}/sshd_proxy ${OBJ}/sshd_proxy.bak 90ce3adf43SDag-Erling Smørgravcp ${OBJ}/authorized_keys_${USER} ${OBJ}/authorized_keys_${USER}.bak 91ce3adf43SDag-Erling Smørgrav 92ce3adf43SDag-Erling Smørgrav# Sanity check: ensure the default config allows forwarding 934f52dfbbSDag-Erling Smørgravcheck_lfwd Y "default configuration" 944f52dfbbSDag-Erling Smørgravcheck_rfwd Y "default configuration" 95ce3adf43SDag-Erling Smørgrav 96190cef3dSDag-Erling Smørgrav# Usage: lperm_tests yes|local|remote|no Y|N Y|N Y|N Y|N Y|N Y|N 97190cef3dSDag-Erling Smørgravlperm_tests() { 98ce3adf43SDag-Erling Smørgrav _tcpfwd=$1 99ce3adf43SDag-Erling Smørgrav _plain_lfwd=$2 100ce3adf43SDag-Erling Smørgrav _plain_rfwd=$3 101ce3adf43SDag-Erling Smørgrav _nopermit_lfwd=$4 102ce3adf43SDag-Erling Smørgrav _nopermit_rfwd=$5 103ce3adf43SDag-Erling Smørgrav _permit_lfwd=$6 104ce3adf43SDag-Erling Smørgrav _permit_rfwd=$7 105190cef3dSDag-Erling Smørgrav _badfwd1=127.0.0.1:22 106190cef3dSDag-Erling Smørgrav _badfwd2=127.0.0.2:22 107ce3adf43SDag-Erling Smørgrav _goodfwd=127.0.0.1:${PORT} 1084f52dfbbSDag-Erling Smørgrav cp ${OBJ}/authorized_keys_${USER}.bak ${OBJ}/authorized_keys_${USER} 1094f52dfbbSDag-Erling Smørgrav _prefix="AllowTcpForwarding=$_tcpfwd" 110190cef3dSDag-Erling Smørgrav 111ce3adf43SDag-Erling Smørgrav # No PermitOpen 112ce3adf43SDag-Erling Smørgrav ( cat ${OBJ}/sshd_proxy.bak ; 113ce3adf43SDag-Erling Smørgrav echo "AllowTcpForwarding $_tcpfwd" ) \ 114ce3adf43SDag-Erling Smørgrav > ${OBJ}/sshd_proxy 1154f52dfbbSDag-Erling Smørgrav check_lfwd $_plain_lfwd "$_prefix" 1164f52dfbbSDag-Erling Smørgrav check_rfwd $_plain_rfwd "$_prefix" 117190cef3dSDag-Erling Smørgrav 118ce3adf43SDag-Erling Smørgrav # PermitOpen via sshd_config that doesn't match 119ce3adf43SDag-Erling Smørgrav ( cat ${OBJ}/sshd_proxy.bak ; 120ce3adf43SDag-Erling Smørgrav echo "AllowTcpForwarding $_tcpfwd" ; 121190cef3dSDag-Erling Smørgrav echo "PermitOpen $_badfwd1 $_badfwd2" ) \ 122ce3adf43SDag-Erling Smørgrav > ${OBJ}/sshd_proxy 1234f52dfbbSDag-Erling Smørgrav check_lfwd $_nopermit_lfwd "$_prefix, !PermitOpen" 1244f52dfbbSDag-Erling Smørgrav check_rfwd $_nopermit_rfwd "$_prefix, !PermitOpen" 125ce3adf43SDag-Erling Smørgrav # PermitOpen via sshd_config that does match 126ce3adf43SDag-Erling Smørgrav ( cat ${OBJ}/sshd_proxy.bak ; 127ce3adf43SDag-Erling Smørgrav echo "AllowTcpForwarding $_tcpfwd" ; 128190cef3dSDag-Erling Smørgrav echo "PermitOpen $_badfwd1 $_goodfwd $_badfwd2" ) \ 129ce3adf43SDag-Erling Smørgrav > ${OBJ}/sshd_proxy 130190cef3dSDag-Erling Smørgrav check_lfwd $_plain_lfwd "$_prefix, PermitOpen" 131190cef3dSDag-Erling Smørgrav check_rfwd $_plain_rfwd "$_prefix, PermitOpen" 132190cef3dSDag-Erling Smørgrav 133190cef3dSDag-Erling Smørgrav # permitopen keys option. 134ce3adf43SDag-Erling Smørgrav # NB. permitopen via authorized_keys should have same 135ce3adf43SDag-Erling Smørgrav # success/fail as via sshd_config 136ce3adf43SDag-Erling Smørgrav # permitopen via authorized_keys that doesn't match 137190cef3dSDag-Erling Smørgrav sed "s/^/permitopen=\"$_badfwd1\",permitopen=\"$_badfwd2\" /" \ 138ce3adf43SDag-Erling Smørgrav < ${OBJ}/authorized_keys_${USER}.bak \ 139ce3adf43SDag-Erling Smørgrav > ${OBJ}/authorized_keys_${USER} || fatal "sed 1 fail" 140ce3adf43SDag-Erling Smørgrav ( cat ${OBJ}/sshd_proxy.bak ; 141ce3adf43SDag-Erling Smørgrav echo "AllowTcpForwarding $_tcpfwd" ) \ 142ce3adf43SDag-Erling Smørgrav > ${OBJ}/sshd_proxy 1434f52dfbbSDag-Erling Smørgrav check_lfwd $_nopermit_lfwd "$_prefix, !permitopen" 1444f52dfbbSDag-Erling Smørgrav check_rfwd $_nopermit_rfwd "$_prefix, !permitopen" 145ce3adf43SDag-Erling Smørgrav # permitopen via authorized_keys that does match 146190cef3dSDag-Erling Smørgrav sed "s/^/permitopen=\"$_badfwd1\",permitopen=\"$_goodfwd\" /" \ 147ce3adf43SDag-Erling Smørgrav < ${OBJ}/authorized_keys_${USER}.bak \ 148ce3adf43SDag-Erling Smørgrav > ${OBJ}/authorized_keys_${USER} || fatal "sed 2 fail" 149ce3adf43SDag-Erling Smørgrav ( cat ${OBJ}/sshd_proxy.bak ; 150ce3adf43SDag-Erling Smørgrav echo "AllowTcpForwarding $_tcpfwd" ) \ 151ce3adf43SDag-Erling Smørgrav > ${OBJ}/sshd_proxy 1524f52dfbbSDag-Erling Smørgrav check_lfwd $_permit_lfwd "$_prefix, permitopen" 1534f52dfbbSDag-Erling Smørgrav check_rfwd $_permit_rfwd "$_prefix, permitopen" 154190cef3dSDag-Erling Smørgrav 15547dd1d1bSDag-Erling Smørgrav # Check port-forwarding flags in authorized_keys. 15647dd1d1bSDag-Erling Smørgrav # These two should refuse all. 15747dd1d1bSDag-Erling Smørgrav sed "s/^/no-port-forwarding /" \ 15847dd1d1bSDag-Erling Smørgrav < ${OBJ}/authorized_keys_${USER}.bak \ 15947dd1d1bSDag-Erling Smørgrav > ${OBJ}/authorized_keys_${USER} || fatal "sed 3 fail" 16047dd1d1bSDag-Erling Smørgrav ( cat ${OBJ}/sshd_proxy.bak ; 16147dd1d1bSDag-Erling Smørgrav echo "AllowTcpForwarding $_tcpfwd" ) \ 16247dd1d1bSDag-Erling Smørgrav > ${OBJ}/sshd_proxy 16347dd1d1bSDag-Erling Smørgrav check_lfwd N "$_prefix, no-port-forwarding" 16447dd1d1bSDag-Erling Smørgrav check_rfwd N "$_prefix, no-port-forwarding" 16547dd1d1bSDag-Erling Smørgrav sed "s/^/restrict /" \ 16647dd1d1bSDag-Erling Smørgrav < ${OBJ}/authorized_keys_${USER}.bak \ 16747dd1d1bSDag-Erling Smørgrav > ${OBJ}/authorized_keys_${USER} || fatal "sed 4 fail" 16847dd1d1bSDag-Erling Smørgrav ( cat ${OBJ}/sshd_proxy.bak ; 16947dd1d1bSDag-Erling Smørgrav echo "AllowTcpForwarding $_tcpfwd" ) \ 17047dd1d1bSDag-Erling Smørgrav > ${OBJ}/sshd_proxy 17147dd1d1bSDag-Erling Smørgrav check_lfwd N "$_prefix, restrict" 17247dd1d1bSDag-Erling Smørgrav check_rfwd N "$_prefix, restrict" 17347dd1d1bSDag-Erling Smørgrav # This should pass the same cases as _nopermit* 17447dd1d1bSDag-Erling Smørgrav sed "s/^/restrict,port-forwarding /" \ 17547dd1d1bSDag-Erling Smørgrav < ${OBJ}/authorized_keys_${USER}.bak \ 17647dd1d1bSDag-Erling Smørgrav > ${OBJ}/authorized_keys_${USER} || fatal "sed 5 fail" 17747dd1d1bSDag-Erling Smørgrav ( cat ${OBJ}/sshd_proxy.bak ; 17847dd1d1bSDag-Erling Smørgrav echo "AllowTcpForwarding $_tcpfwd" ) \ 17947dd1d1bSDag-Erling Smørgrav > ${OBJ}/sshd_proxy 18047dd1d1bSDag-Erling Smørgrav check_lfwd $_plain_lfwd "$_prefix, restrict,port-forwarding" 18147dd1d1bSDag-Erling Smørgrav check_rfwd $_plain_rfwd "$_prefix, restrict,port-forwarding" 182ce3adf43SDag-Erling Smørgrav} 183ce3adf43SDag-Erling Smørgrav 184190cef3dSDag-Erling Smørgrav# permit-open none mismatch match 185ce3adf43SDag-Erling Smørgrav# AllowTcpForwarding local remote local remote local remote 186190cef3dSDag-Erling Smørgravlperm_tests yes Y Y N Y Y Y 187190cef3dSDag-Erling Smørgravlperm_tests local Y N N N Y N 188190cef3dSDag-Erling Smørgravlperm_tests remote N Y N Y N Y 189190cef3dSDag-Erling Smørgravlperm_tests no N N N N N N 190190cef3dSDag-Erling Smørgrav 191190cef3dSDag-Erling Smørgrav# Usage: rperm_tests yes|local|remote|no Y|N Y|N Y|N Y|N Y|N Y|N 192190cef3dSDag-Erling Smørgravrperm_tests() { 193190cef3dSDag-Erling Smørgrav _tcpfwd=$1 194190cef3dSDag-Erling Smørgrav _plain_lfwd=$2 195190cef3dSDag-Erling Smørgrav _plain_rfwd=$3 196190cef3dSDag-Erling Smørgrav _nopermit_lfwd=$4 197190cef3dSDag-Erling Smørgrav _nopermit_rfwd=$5 198190cef3dSDag-Erling Smørgrav _permit_lfwd=$6 199190cef3dSDag-Erling Smørgrav _permit_rfwd=$7 200190cef3dSDag-Erling Smørgrav _badfwd1=127.0.0.1:22 201190cef3dSDag-Erling Smørgrav _badfwd2=127.0.0.2:${RFWD_PORT} 202190cef3dSDag-Erling Smørgrav _goodfwd=127.0.0.1:${RFWD_PORT} 203190cef3dSDag-Erling Smørgrav cp ${OBJ}/authorized_keys_${USER}.bak ${OBJ}/authorized_keys_${USER} 204190cef3dSDag-Erling Smørgrav _prefix="AllowTcpForwarding=$_tcpfwd" 205190cef3dSDag-Erling Smørgrav 206190cef3dSDag-Erling Smørgrav # PermitListen via sshd_config that doesn't match 207190cef3dSDag-Erling Smørgrav ( cat ${OBJ}/sshd_proxy.bak ; 208190cef3dSDag-Erling Smørgrav echo "AllowTcpForwarding $_tcpfwd" ; 209190cef3dSDag-Erling Smørgrav echo "PermitListen $_badfwd1 $_badfwd2" ) \ 210190cef3dSDag-Erling Smørgrav > ${OBJ}/sshd_proxy 211190cef3dSDag-Erling Smørgrav check_lfwd $_nopermit_lfwd "$_prefix, !PermitListen" 212190cef3dSDag-Erling Smørgrav check_rfwd $_nopermit_rfwd "$_prefix, !PermitListen" 213190cef3dSDag-Erling Smørgrav # PermitListen via sshd_config that does match 214190cef3dSDag-Erling Smørgrav ( cat ${OBJ}/sshd_proxy.bak ; 215190cef3dSDag-Erling Smørgrav echo "AllowTcpForwarding $_tcpfwd" ; 216190cef3dSDag-Erling Smørgrav echo "PermitListen $_badfwd1 $_goodfwd $_badfwd2" ) \ 217190cef3dSDag-Erling Smørgrav > ${OBJ}/sshd_proxy 218190cef3dSDag-Erling Smørgrav check_lfwd $_plain_lfwd "$_prefix, PermitListen" 219190cef3dSDag-Erling Smørgrav check_rfwd $_plain_rfwd "$_prefix, PermitListen" 220190cef3dSDag-Erling Smørgrav} 221190cef3dSDag-Erling Smørgrav 222190cef3dSDag-Erling Smørgrav# permit-remote-open none mismatch match 223190cef3dSDag-Erling Smørgrav# AllowTcpForwarding local remote local remote local remote 224190cef3dSDag-Erling Smørgravrperm_tests yes Y Y Y N Y Y 225190cef3dSDag-Erling Smørgravrperm_tests local Y N Y N Y N 226190cef3dSDag-Erling Smørgravrperm_tests remote N Y N N N Y 227190cef3dSDag-Erling Smørgravrperm_tests no N N N N N N 228190cef3dSDag-Erling Smørgrav 229