1263970Sdes#	$OpenBSD: forward-control.sh,v 1.2 2013/11/18 05:09:32 naddy Exp $
2248613Sdes#	Placed in the Public Domain.
3248613Sdes
4248613Sdestid="sshd control of local and remote forwarding"
5248613Sdes
6248613SdesLFWD_PORT=3320
7248613SdesRFWD_PORT=3321
8248613SdesCTL=$OBJ/ctl-sock
9248613SdesREADY=$OBJ/ready
10248613Sdes
11248613Sdeswait_for_file_to_appear() {
12248613Sdes	_path=$1
13248613Sdes	_n=0
14248613Sdes	while test ! -f $_path ; do
15248613Sdes		test $_n -eq 1 && trace "waiting for $_path to appear"
16248613Sdes		_n=`expr $_n + 1`
17248613Sdes		test $_n -ge 20 && return 1
18248613Sdes		sleep 1
19248613Sdes	done
20248613Sdes	return 0
21248613Sdes}
22248613Sdes
23248613Sdeswait_for_process_to_exit() {
24248613Sdes	_pid=$1
25248613Sdes	_n=0
26248613Sdes	while kill -0 $_pid 2>/dev/null ; do
27248613Sdes		test $_n -eq 1 && trace "waiting for $_pid to exit"
28248613Sdes		_n=`expr $_n + 1`
29248613Sdes		test $_n -ge 20 && return 1
30248613Sdes		sleep 1
31248613Sdes	done
32248613Sdes	return 0
33248613Sdes}
34248613Sdes
35248613Sdes# usage: check_lfwd protocol Y|N message
36248613Sdescheck_lfwd() {
37248613Sdes	_proto=$1
38248613Sdes	_expected=$2
39248613Sdes	_message=$3
40248613Sdes	rm -f $READY
41248613Sdes	${SSH} -oProtocol=$_proto -F $OBJ/ssh_proxy \
42248613Sdes	    -L$LFWD_PORT:127.0.0.1:$PORT \
43248613Sdes	    -o ExitOnForwardFailure=yes \
44248613Sdes	    -n host exec sh -c \'"sleep 60 & echo \$! > $READY ; wait "\' \
45248613Sdes	    >/dev/null 2>&1 &
46248613Sdes	_sshpid=$!
47248613Sdes	wait_for_file_to_appear $READY || \
48248613Sdes		fatal "check_lfwd ssh fail: $_message"
49248613Sdes	${SSH} -F $OBJ/ssh_config -p $LFWD_PORT \
50248613Sdes	    -oConnectionAttempts=4 host true >/dev/null 2>&1
51248613Sdes	_result=$?
52248613Sdes	kill $_sshpid `cat $READY` 2>/dev/null
53248613Sdes	wait_for_process_to_exit $_sshpid
54248613Sdes	if test "x$_expected" = "xY" -a $_result -ne 0 ; then
55248613Sdes		fail "check_lfwd failed (expecting success): $_message"
56248613Sdes	elif test "x$_expected" = "xN" -a $_result -eq 0 ; then
57248613Sdes		fail "check_lfwd succeeded (expecting failure): $_message"
58248613Sdes	elif test "x$_expected" != "xY" -a "x$_expected" != "xN" ; then
59248613Sdes		fatal "check_lfwd invalid argument \"$_expected\""
60248613Sdes	else
61248613Sdes		verbose "check_lfwd done (expecting $_expected): $_message"
62248613Sdes	fi
63248613Sdes}
64248613Sdes
65248613Sdes# usage: check_rfwd protocol Y|N message
66248613Sdescheck_rfwd() {
67248613Sdes	_proto=$1
68248613Sdes	_expected=$2
69248613Sdes	_message=$3
70248613Sdes	rm -f $READY
71248613Sdes	${SSH} -oProtocol=$_proto -F $OBJ/ssh_proxy \
72248613Sdes	    -R$RFWD_PORT:127.0.0.1:$PORT \
73248613Sdes	    -o ExitOnForwardFailure=yes \
74248613Sdes	    -n host exec sh -c \'"sleep 60 & echo \$! > $READY ; wait "\' \
75248613Sdes	    >/dev/null 2>&1 &
76248613Sdes	_sshpid=$!
77248613Sdes	wait_for_file_to_appear $READY
78248613Sdes	_result=$?
79248613Sdes	if test $_result -eq 0 ; then
80248613Sdes		${SSH} -F $OBJ/ssh_config -p $RFWD_PORT \
81248613Sdes		    -oConnectionAttempts=4 host true >/dev/null 2>&1
82248613Sdes		_result=$?
83248613Sdes		kill $_sshpid `cat $READY` 2>/dev/null
84248613Sdes		wait_for_process_to_exit $_sshpid
85248613Sdes	fi
86248613Sdes	if test "x$_expected" = "xY" -a $_result -ne 0 ; then
87248613Sdes		fail "check_rfwd failed (expecting success): $_message"
88248613Sdes	elif test "x$_expected" = "xN" -a $_result -eq 0 ; then
89248613Sdes		fail "check_rfwd succeeded (expecting failure): $_message"
90248613Sdes	elif test "x$_expected" != "xY" -a "x$_expected" != "xN" ; then
91248613Sdes		fatal "check_rfwd invalid argument \"$_expected\""
92248613Sdes	else
93248613Sdes		verbose "check_rfwd done (expecting $_expected): $_message"
94248613Sdes	fi
95248613Sdes}
96248613Sdes
97248613Sdesstart_sshd
98248613Sdescp ${OBJ}/sshd_proxy ${OBJ}/sshd_proxy.bak
99248613Sdescp ${OBJ}/authorized_keys_${USER} ${OBJ}/authorized_keys_${USER}.bak
100248613Sdes
101248613Sdes# Sanity check: ensure the default config allows forwarding
102248613Sdesfor p in 1 2 ; do
103248613Sdes	check_lfwd $p Y "proto $p, default configuration"
104248613Sdes	check_rfwd $p Y "proto $p, default configuration"
105248613Sdesdone
106248613Sdes
107248613Sdes# Usage: all_tests yes|local|remote|no Y|N Y|N Y|N Y|N Y|N Y|N
108248613Sdesall_tests() {
109248613Sdes	_tcpfwd=$1
110248613Sdes	_plain_lfwd=$2
111248613Sdes	_plain_rfwd=$3
112248613Sdes	_nopermit_lfwd=$4
113248613Sdes	_nopermit_rfwd=$5
114248613Sdes	_permit_lfwd=$6
115248613Sdes	_permit_rfwd=$7
116248613Sdes	_badfwd=127.0.0.1:22
117248613Sdes	_goodfwd=127.0.0.1:${PORT}
118248613Sdes	for _proto in 1 2 ; do
119248613Sdes		cp ${OBJ}/authorized_keys_${USER}.bak \
120248613Sdes		    ${OBJ}/authorized_keys_${USER}
121248613Sdes		_prefix="proto $_proto, AllowTcpForwarding=$_tcpfwd"
122248613Sdes		# No PermitOpen
123248613Sdes		( cat ${OBJ}/sshd_proxy.bak ;
124248613Sdes		  echo "AllowTcpForwarding $_tcpfwd" ) \
125248613Sdes		    > ${OBJ}/sshd_proxy
126248613Sdes		check_lfwd $_proto $_plain_lfwd "$_prefix"
127248613Sdes		check_rfwd $_proto $_plain_rfwd "$_prefix"
128248613Sdes		# PermitOpen via sshd_config that doesn't match
129248613Sdes		( cat ${OBJ}/sshd_proxy.bak ;
130248613Sdes		  echo "AllowTcpForwarding $_tcpfwd" ;
131248613Sdes		  echo "PermitOpen $_badfwd" ) \
132248613Sdes		    > ${OBJ}/sshd_proxy
133248613Sdes		check_lfwd $_proto $_nopermit_lfwd "$_prefix, !PermitOpen"
134248613Sdes		check_rfwd $_proto $_nopermit_rfwd "$_prefix, !PermitOpen"
135248613Sdes		# PermitOpen via sshd_config that does match
136248613Sdes		( cat ${OBJ}/sshd_proxy.bak ;
137248613Sdes		  echo "AllowTcpForwarding $_tcpfwd" ;
138248613Sdes		  echo "PermitOpen $_badfwd $_goodfwd" ) \
139248613Sdes		    > ${OBJ}/sshd_proxy
140248613Sdes		# NB. permitopen via authorized_keys should have same
141248613Sdes		# success/fail as via sshd_config
142248613Sdes		# permitopen via authorized_keys that doesn't match
143248613Sdes		sed "s/^/permitopen=\"$_badfwd\" /" \
144248613Sdes		    < ${OBJ}/authorized_keys_${USER}.bak \
145248613Sdes		    > ${OBJ}/authorized_keys_${USER} || fatal "sed 1 fail"
146248613Sdes		( cat ${OBJ}/sshd_proxy.bak ;
147248613Sdes		  echo "AllowTcpForwarding $_tcpfwd" ) \
148248613Sdes		    > ${OBJ}/sshd_proxy
149248613Sdes		check_lfwd $_proto $_nopermit_lfwd "$_prefix, !permitopen"
150248613Sdes		check_rfwd $_proto $_nopermit_rfwd "$_prefix, !permitopen"
151248613Sdes		# permitopen via authorized_keys that does match
152248613Sdes		sed "s/^/permitopen=\"$_badfwd\",permitopen=\"$_goodfwd\" /" \
153248613Sdes		    < ${OBJ}/authorized_keys_${USER}.bak \
154248613Sdes		    > ${OBJ}/authorized_keys_${USER} || fatal "sed 2 fail"
155248613Sdes		( cat ${OBJ}/sshd_proxy.bak ;
156248613Sdes		  echo "AllowTcpForwarding $_tcpfwd" ) \
157248613Sdes		    > ${OBJ}/sshd_proxy
158248613Sdes		check_lfwd $_proto $_permit_lfwd "$_prefix, permitopen"
159248613Sdes		check_rfwd $_proto $_permit_rfwd "$_prefix, permitopen"
160248613Sdes	done
161248613Sdes}
162248613Sdes
163248613Sdes#                      no-permitopen mismatch-permitopen match-permitopen
164248613Sdes#   AllowTcpForwarding  local remote        local remote     local remote
165248613Sdesall_tests          yes      Y      Y            N      Y         Y      Y
166248613Sdesall_tests        local      Y      N            N      N         Y      N
167248613Sdesall_tests       remote      N      Y            N      Y         N      Y
168248613Sdesall_tests           no      N      N            N      N         N      N
169