forward-control.sh 7.6 KB

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