1# $OpenBSD: forward-control.sh,v 1.8 2021/05/07 09:23:40 dtucker Exp $ 2# Placed in the Public Domain. 3 4tid="sshd control of local and remote forwarding" 5 6LFWD_PORT=3320 7RFWD_PORT=3321 8CTL=$OBJ/ctl-sock 9READY=$OBJ/ready 10 11wait_for_file_to_appear() { 12 _path=$1 13 _n=0 14 while test ! -f $_path ; do 15 test $_n -eq 1 && trace "waiting for $_path to appear" 16 _n=`expr $_n + 1` 17 test $_n -ge 20 && return 1 18 sleep 1 19 done 20 return 0 21} 22 23wait_for_process_to_exit() { 24 _pid=$1 25 _n=0 26 while kill -0 $_pid 2>/dev/null ; do 27 test $_n -eq 1 && trace "waiting for $_pid to exit" 28 _n=`expr $_n + 1` 29 test $_n -ge 20 && return 1 30 sleep 1 31 done 32 return 0 33} 34 35# usage: check_lfwd Y|N message 36check_lfwd() { 37 _expected=$1 38 _message=$2 39 rm -f $READY 40 ${SSH} -F $OBJ/ssh_proxy \ 41 -L$LFWD_PORT:127.0.0.1:$PORT \ 42 -o ExitOnForwardFailure=yes \ 43 -n host exec sh -c \'"sleep 60 & echo \$! > $READY ; wait "\' \ 44 >/dev/null 2>&1 & 45 _sshpid=$! 46 wait_for_file_to_appear $READY || \ 47 fatal "check_lfwd ssh fail: $_message" 48 ${SSH} -F $OBJ/ssh_config -p $LFWD_PORT \ 49 -oConnectionAttempts=10 host true >/dev/null 2>&1 50 _result=$? 51 kill $_sshpid `cat $READY` 2>/dev/null 52 wait_for_process_to_exit $_sshpid 53 if test "x$_expected" = "xY" -a $_result -ne 0 ; then 54 fail "check_lfwd failed (expecting success): $_message" 55 elif test "x$_expected" = "xN" -a $_result -eq 0 ; then 56 fail "check_lfwd succeeded (expecting failure): $_message" 57 elif test "x$_expected" != "xY" -a "x$_expected" != "xN" ; then 58 fatal "check_lfwd invalid argument \"$_expected\"" 59 else 60 verbose "check_lfwd done (expecting $_expected): $_message" 61 fi 62} 63 64# usage: check_rfwd Y|N message 65check_rfwd() { 66 _expected=$1 67 _message=$2 68 rm -f $READY 69 ${SSH} -F $OBJ/ssh_proxy \ 70 -R127.0.0.1:$RFWD_PORT:127.0.0.1:$PORT \ 71 -o ExitOnForwardFailure=yes \ 72 -n host exec sh -c \'"sleep 60 & echo \$! > $READY ; wait "\' \ 73 >/dev/null 2>&1 & 74 _sshpid=$! 75 wait_for_file_to_appear $READY 76 _result=$? 77 if test $_result -eq 0 ; then 78 ${SSH} -F $OBJ/ssh_config -p $RFWD_PORT \ 79 -oConnectionAttempts=10 host true >/dev/null 2>&1 80 _result=$? 81 kill $_sshpid `cat $READY` 2>/dev/null 82 wait_for_process_to_exit $_sshpid 83 fi 84 if test "x$_expected" = "xY" -a $_result -ne 0 ; then 85 fail "check_rfwd failed (expecting success): $_message" 86 elif test "x$_expected" = "xN" -a $_result -eq 0 ; then 87 fail "check_rfwd succeeded (expecting failure): $_message" 88 elif test "x$_expected" != "xY" -a "x$_expected" != "xN" ; then 89 fatal "check_rfwd invalid argument \"$_expected\"" 90 else 91 verbose "check_rfwd done (expecting $_expected): $_message" 92 fi 93} 94 95start_sshd 96cp ${OBJ}/sshd_proxy ${OBJ}/sshd_proxy.bak 97cp ${OBJ}/authorized_keys_${USER} ${OBJ}/authorized_keys_${USER}.bak 98 99# Sanity check: ensure the default config allows forwarding 100check_lfwd Y "default configuration" 101check_rfwd Y "default configuration" 102 103# Usage: lperm_tests yes|local|remote|no Y|N Y|N Y|N Y|N Y|N Y|N 104lperm_tests() { 105 _tcpfwd=$1 106 _plain_lfwd=$2 107 _plain_rfwd=$3 108 _nopermit_lfwd=$4 109 _nopermit_rfwd=$5 110 _permit_lfwd=$6 111 _permit_rfwd=$7 112 _badfwd1=127.0.0.1:22 113 _badfwd2=127.0.0.2:22 114 _goodfwd=127.0.0.1:${PORT} 115 cp ${OBJ}/authorized_keys_${USER}.bak ${OBJ}/authorized_keys_${USER} 116 _prefix="AllowTcpForwarding=$_tcpfwd" 117 118 # No PermitOpen 119 ( cat ${OBJ}/sshd_proxy.bak ; 120 echo "AllowTcpForwarding $_tcpfwd" ) \ 121 > ${OBJ}/sshd_proxy 122 check_lfwd $_plain_lfwd "$_prefix" 123 check_rfwd $_plain_rfwd "$_prefix" 124 125 # PermitOpen via sshd_config that doesn't match 126 ( cat ${OBJ}/sshd_proxy.bak ; 127 echo "AllowTcpForwarding $_tcpfwd" ; 128 echo "PermitOpen $_badfwd1 $_badfwd2" ) \ 129 > ${OBJ}/sshd_proxy 130 check_lfwd $_nopermit_lfwd "$_prefix, !PermitOpen" 131 check_rfwd $_nopermit_rfwd "$_prefix, !PermitOpen" 132 # PermitOpen via sshd_config that does match 133 ( cat ${OBJ}/sshd_proxy.bak ; 134 echo "AllowTcpForwarding $_tcpfwd" ; 135 echo "PermitOpen $_badfwd1 $_goodfwd $_badfwd2" ) \ 136 > ${OBJ}/sshd_proxy 137 check_lfwd $_plain_lfwd "$_prefix, PermitOpen" 138 check_rfwd $_plain_rfwd "$_prefix, PermitOpen" 139 140 # permitopen keys option. 141 # NB. permitopen via authorized_keys should have same 142 # success/fail as via sshd_config 143 # permitopen via authorized_keys that doesn't match 144 sed "s/^/permitopen=\"$_badfwd1\",permitopen=\"$_badfwd2\" /" \ 145 < ${OBJ}/authorized_keys_${USER}.bak \ 146 > ${OBJ}/authorized_keys_${USER} || fatal "sed 1 fail" 147 ( cat ${OBJ}/sshd_proxy.bak ; 148 echo "AllowTcpForwarding $_tcpfwd" ) \ 149 > ${OBJ}/sshd_proxy 150 check_lfwd $_nopermit_lfwd "$_prefix, !permitopen" 151 check_rfwd $_nopermit_rfwd "$_prefix, !permitopen" 152 # permitopen via authorized_keys that does match 153 sed "s/^/permitopen=\"$_badfwd1\",permitopen=\"$_goodfwd\" /" \ 154 < ${OBJ}/authorized_keys_${USER}.bak \ 155 > ${OBJ}/authorized_keys_${USER} || fatal "sed 2 fail" 156 ( cat ${OBJ}/sshd_proxy.bak ; 157 echo "AllowTcpForwarding $_tcpfwd" ) \ 158 > ${OBJ}/sshd_proxy 159 check_lfwd $_permit_lfwd "$_prefix, permitopen" 160 check_rfwd $_permit_rfwd "$_prefix, permitopen" 161 162 # Check port-forwarding flags in authorized_keys. 163 # These two should refuse all. 164 sed "s/^/no-port-forwarding /" \ 165 < ${OBJ}/authorized_keys_${USER}.bak \ 166 > ${OBJ}/authorized_keys_${USER} || fatal "sed 3 fail" 167 ( cat ${OBJ}/sshd_proxy.bak ; 168 echo "AllowTcpForwarding $_tcpfwd" ) \ 169 > ${OBJ}/sshd_proxy 170 check_lfwd N "$_prefix, no-port-forwarding" 171 check_rfwd N "$_prefix, no-port-forwarding" 172 sed "s/^/restrict /" \ 173 < ${OBJ}/authorized_keys_${USER}.bak \ 174 > ${OBJ}/authorized_keys_${USER} || fatal "sed 4 fail" 175 ( cat ${OBJ}/sshd_proxy.bak ; 176 echo "AllowTcpForwarding $_tcpfwd" ) \ 177 > ${OBJ}/sshd_proxy 178 check_lfwd N "$_prefix, restrict" 179 check_rfwd N "$_prefix, restrict" 180 # This should pass the same cases as _nopermit* 181 sed "s/^/restrict,port-forwarding /" \ 182 < ${OBJ}/authorized_keys_${USER}.bak \ 183 > ${OBJ}/authorized_keys_${USER} || fatal "sed 5 fail" 184 ( cat ${OBJ}/sshd_proxy.bak ; 185 echo "AllowTcpForwarding $_tcpfwd" ) \ 186 > ${OBJ}/sshd_proxy 187 check_lfwd $_plain_lfwd "$_prefix, restrict,port-forwarding" 188 check_rfwd $_plain_rfwd "$_prefix, restrict,port-forwarding" 189} 190 191# permit-open none mismatch match 192# AllowTcpForwarding local remote local remote local remote 193lperm_tests yes Y Y N Y Y Y 194lperm_tests local Y N N N Y N 195lperm_tests remote N Y N Y N Y 196lperm_tests no N N N N N N 197 198# Usage: rperm_tests yes|local|remote|no Y|N Y|N Y|N Y|N Y|N Y|N 199rperm_tests() { 200 _tcpfwd=$1 201 _plain_lfwd=$2 202 _plain_rfwd=$3 203 _nopermit_lfwd=$4 204 _nopermit_rfwd=$5 205 _permit_lfwd=$6 206 _permit_rfwd=$7 207 _badfwd1=127.0.0.1:22 208 _badfwd2=127.0.0.2:${RFWD_PORT} 209 _goodfwd=127.0.0.1:${RFWD_PORT} 210 cp ${OBJ}/authorized_keys_${USER}.bak ${OBJ}/authorized_keys_${USER} 211 _prefix="AllowTcpForwarding=$_tcpfwd" 212 213 # PermitListen via sshd_config that doesn't match 214 ( cat ${OBJ}/sshd_proxy.bak ; 215 echo "AllowTcpForwarding $_tcpfwd" ; 216 echo "PermitListen $_badfwd1 $_badfwd2" ) \ 217 > ${OBJ}/sshd_proxy 218 check_lfwd $_nopermit_lfwd "$_prefix, !PermitListen" 219 check_rfwd $_nopermit_rfwd "$_prefix, !PermitListen" 220 # PermitListen via sshd_config that does match 221 ( cat ${OBJ}/sshd_proxy.bak ; 222 echo "AllowTcpForwarding $_tcpfwd" ; 223 echo "PermitListen $_badfwd1 $_goodfwd $_badfwd2" ) \ 224 > ${OBJ}/sshd_proxy 225 check_lfwd $_plain_lfwd "$_prefix, PermitListen" 226 check_rfwd $_plain_rfwd "$_prefix, PermitListen" 227} 228 229# permit-remote-open none mismatch match 230# AllowTcpForwarding local remote local remote local remote 231rperm_tests yes Y Y Y N Y Y 232rperm_tests local Y N Y N Y N 233rperm_tests remote N Y N N N Y 234rperm_tests no N N N N N N 235 236