Skip to content

Commit 74369b2

Browse files
committed
upstream: regression test for "interactive" ssh with a PTY attached,
using tmux would have likely caught the ControlPersist regression in 10.1. feedback nicm@ OpenBSD-Regress-ID: d4d709c08657769cb5691893cc98f34b6f537e76
1 parent a204650 commit 74369b2

File tree

2 files changed

+156
-2
lines changed

2 files changed

+156
-2
lines changed

regress/Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ clean:
1919
for F in $(CLEANFILES); do rm -f $(OBJ)$$F; done
2020
rm -rf $(OBJ).putty
2121
rm -rf $(OBJ).dropbear
22+
rm -rf $(OBJ).fakehome
2223

2324
distclean: clean
2425

@@ -115,7 +116,8 @@ LTESTS= connect \
115116
penalty \
116117
penalty-expire \
117118
connect-bigconf \
118-
ssh-pkcs11
119+
ssh-pkcs11 \
120+
ssh-tty
119121

120122
INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers
121123
INTEROP_TESTS+= dropbear-ciphers dropbear-kex dropbear-server
@@ -153,7 +155,7 @@ CLEANFILES= *.core actual agent-key.* authorized_keys_${USERNAME} \
153155
t2.out t3.out t6.out1 t6.out2 t7.out t7.out.pub \
154156
t8.out t8.out.pub t9.out t9.out.pub \
155157
timestamp testdata user_*key* user_ca* user_key* \
156-
pin.sh nopin.sh wrongpin.sh key.pub
158+
pin.sh nopin.sh wrongpin.sh key.pub test.sh ctl-sock
157159

158160
# Enable all malloc(3) randomisations and checks
159161
TEST_ENV= "MALLOC_OPTIONS=CFGJRSUX"

regress/ssh-tty.sh

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# $OpenBSD: ssh-tty.sh,v 1.1 2025/10/20 00:45:10 djm Exp $
2+
# Placed in the Public Domain.
3+
4+
# Basic TTY smoke test
5+
6+
tid="ssh-tty"
7+
8+
# Fake home directory to avoid user shell configuration.
9+
FAKEHOME="$OBJ/.fakehome"
10+
rm -rf "$FAKEHOME"
11+
mkdir -m 0700 -p "$FAKEHOME"
12+
13+
# tmux stuff
14+
TMUX=tmux
15+
test -x $TMUX || skip "tmux not found"
16+
CLEANENV="env -i HOME=$HOME LOGNAME=$USER USER=$USER PATH=$PATH SHELL=$SHELL"
17+
TMUX_TEST="$CLEANENV $TMUX -f/dev/null -Lopenssh-regress-ssh-tty"
18+
sess="regress-ssh-tty$$"
19+
20+
# Multiplexing control socket.
21+
CTL=$OBJ/ctl-sock
22+
23+
# Some randomish strings used for signalling back and forth.
24+
# We use the octal variants via printf(1).
25+
MAGIC1="XY23zzY"
26+
MAGIC1_OCTAL="\130\131\062\063\172\172\131"
27+
MAGIC2="99sMarT86"
28+
MAGIC2_OCTAL="\071\071\163\115\141\162\124\070\066"
29+
MAGIC3="woLF1701d"
30+
MAGIC3_OCTAL="\167\157\114\106\061\067\060\061\144"
31+
MAGIC4="lUh4thX4evR"
32+
MAGIC4_OCTAL="\154\125\150\064\164\150\130\064\145\166\122"
33+
34+
# Wait for a mux process to become ready.
35+
wait_for_mux_ready()
36+
{
37+
for i in 1 2 3 4 5 6 7 8 9; do
38+
${SSH} -F $OBJ/ssh_config -S $CTL -Ocheck otherhost \
39+
>/dev/null 2>&1 && return 0
40+
sleep $i
41+
done
42+
fatal "mux never becomes ready"
43+
}
44+
45+
# Wait for a mux process to have finished.
46+
wait_for_mux_done()
47+
{
48+
for i in 1 2 3 4 5 6 7 8 9; do
49+
test -S $CTL || return 0
50+
sleep $i
51+
done
52+
fatal "mux socket never removed"
53+
}
54+
55+
# Wait for a regex to appear in terminal output.
56+
wait_for_regex() {
57+
string="$1"
58+
errors_are_fatal="$2"
59+
for x in 1 2 3 4 5 6 7 8 9 10 ; do
60+
$TMUX_TEST capture-pane -pt $sess | grep "$string" >/dev/null
61+
[ $? -eq 0 ] && return
62+
sleep 1
63+
done
64+
if test -z "$errors_are_fatal"; then
65+
fail "failed to match \"$string\" in terminal output"
66+
return
67+
fi
68+
fatal "failed to match \"$string\" in terminal output"
69+
}
70+
71+
# Check that a regex does *not* appear in terminal output
72+
not_in_term() {
73+
string="$1"
74+
error="$2"
75+
errors_are_fatal="$3"
76+
$TMUX_TEST capture-pane -pt $sess | grep "$string" > /dev/null
77+
[ $? -ne 0 ] && return
78+
if test -z "$errors_are_fatal"; then
79+
fail "$error"
80+
return
81+
fi
82+
fatal "$error"
83+
}
84+
85+
trap "$TMUX_TEST kill-session -t $sess 2>/dev/null" EXIT
86+
87+
run_test() {
88+
tag="$1"
89+
ssh_args="$2"
90+
# Prepare a tmux session.
91+
$TMUX_TEST kill-session -t $sess 2>/dev/null
92+
$TMUX_TEST new-session -d -s $sess
93+
#echo XXXXXXXXXX $sess; sleep 10
94+
95+
# Command to start SSH; sent as keystrokes to tmux session.
96+
RCMD="$CLEANENV $SHELL"
97+
CMD="$SSH -F $OBJ/ssh_proxy $ssh_args -S $CTL x -tt $RCMD"
98+
99+
verbose "${tag}: start connection"
100+
# arrange for the shell to print something after ssh completes.
101+
$TMUX_TEST send-keys -t $sess "$CMD && printf '$MAGIC1_OCTAL\n'" ENTER
102+
wait_for_mux_ready
103+
104+
verbose "${tag}: send string"
105+
$TMUX_TEST send-keys -t $sess "printf '$MAGIC2_OCTAL\n'" ENTER
106+
wait_for_regex "$MAGIC2"
107+
108+
verbose "${tag}: ^c interrupts process"
109+
# ^c should interrupt the sleep and prevent the magic string
110+
# from appearing.
111+
$TMUX_TEST send-keys -t $sess "sleep 30 || printf '$MAGIC3_OCTAL\n'"
112+
$TMUX_TEST send-keys -t $sess ENTER
113+
$TMUX_TEST send-keys -t $sess "C-c"
114+
# send another string to let us know that the sleep has finished.
115+
$TMUX_TEST send-keys -t $sess "printf '$MAGIC4_OCTAL\n'" ENTER
116+
wait_for_regex "$MAGIC4"
117+
not_in_term "$MAGIC3" "^c did not interrupt"
118+
119+
verbose "${tag}: ~? produces help"
120+
$TMUX_TEST send-keys -t $sess ENTER "~?"
121+
wait_for_regex "^Supported escape sequences:$"
122+
123+
verbose "${tag}: ~. terminates session"
124+
$TMUX_TEST send-keys -t $sess ENTER "~."
125+
wait_for_mux_done
126+
not_in_term "$MAGIC1" "ssh unexpectedly exited successfully after ~."
127+
128+
verbose "${tag}: restart session"
129+
$TMUX_TEST send-keys -t $sess "$CMD && printf '$MAGIC1_OCTAL\n'" ENTER
130+
wait_for_mux_ready
131+
132+
verbose "${tag}: eof terminates session successfully"
133+
$TMUX_TEST send-keys -t $sess ENTER "C-d"
134+
wait_for_regex "$MAGIC1"
135+
}
136+
137+
# Make sure tmux is working as expected before we start.
138+
$TMUX_TEST kill-session -t $sess 2>/dev/null
139+
$TMUX_TEST new-session -d -s $sess
140+
# Make sure the session doesn't contain the magic strings we will use
141+
# for signalling or any #? output.
142+
not_in_term "$MAGIC1" "terminal already contains magic1 string" fatal
143+
not_in_term "$MAGIC2" "terminal already contains magic2 string" fatal
144+
not_in_term "$MAGIC3" "terminal already contains magic3 string" fatal
145+
not_in_term "$MAGIC4" "terminal already contains magic4 string" fatal
146+
not_in_term "^Supported escape" "terminal already contains escape help" fatal
147+
$TMUX_TEST send-keys -t $sess "printf '$MAGIC1_OCTAL\n'" ENTER
148+
wait_for_regex "$MAGIC1" fatal
149+
$TMUX_TEST kill-session -t $sess 2>/dev/null
150+
151+
run_test "basic" "-oControlMaster=yes"
152+
run_test "ControlPersist" "-oControlMaster=auto -oControlPersist=1s"

0 commit comments

Comments
 (0)