Exscript ssh2.interact() seems to be broken under linux
I can establish normal SSH2 sessions with Exscript. However, when I use conn.interact(), I get exscript tracebacks... fancy super-useful tracebacks courtesy of loguru
$ python testme_exscript.py
Interacting...
2021-12-26 15:51:45.849 | ERROR | __main__:<module>:144 - An error has been caught in function '<module>', process 'MainProcess' (66656), thread 'MainThread' (140387668304256):
Traceback (most recent call last):
> File "testme_exscript.py", line 144, in <module>
main()
└ <function main at 0x7fae8a198ea0>
File "testme_exscript.py", line 134, in main
conn.interact(key_handlers={}, handle_window_size=False)
│ └ <function SSH2.interact at 0x7fae87ad1950>
└ <Exscript.protocols.ssh2.SSH2 object at 0x7fae8a1b8ac8>
File "/opt/virtual_env/py37_test/lib/python3.7/site-packages/Exscript/protocols/ssh2.py", line 449, in interact
return self._open_shell(self.shell, key_handlers, handle_window_size)
│ │ │ │ │ └ False
│ │ │ │ └ {}
│ │ │ └ <paramiko.Channel 0 (open) window=2097099 -> <paramiko.Transport at 0x8a1b8fd0 (cipher aes128-ctr, 128 bits) (active; 1 open ...
│ │ └ <Exscript.protocols.ssh2.SSH2 object at 0x7fae8a1b8ac8>
│ └ <function Protocol._open_shell at 0x7fae87abeea0>
└ <Exscript.protocols.ssh2.SSH2 object at 0x7fae8a1b8ac8>
File "/opt/virtual_env/py37_test/lib/python3.7/site-packages/Exscript/protocols/protocol.py", line 1231, in _open_shell
return self._open_posix_shell(channel, key_handlers, handle_window_size)
│ │ │ │ └ False
│ │ │ └ {}
│ │ └ <paramiko.Channel 0 (open) window=2097099 -> <paramiko.Transport at 0x8a1b8fd0 (cipher aes128-ctr, 128 bits) (active; 1 open ...
│ └ <function Protocol._open_posix_shell at 0x7fae87abed90>
└ <Exscript.protocols.ssh2.SSH2 object at 0x7fae8a1b8ac8>
File "/opt/virtual_env/py37_test/lib/python3.7/site-packages/Exscript/protocols/protocol.py", line 1145, in _open_posix_shell
with os.fdopen(sys.stdin.fileno(), 'r', 0) as stdin:
│ │ │ │ └ <method 'fileno' of '_io.TextIOWrapper' objects>
│ │ │ └ <_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>
│ │ └ <module 'sys' (built-in)>
│ └ <function fdopen at 0x7fae8cdac730>
└ <module 'os' from '/opt/virtual_env/py37_test/lib/python3.7/os.py'>
File "/opt/virtual_env/py37_test/lib/python3.7/os.py", line 1026, in fdopen
return io.open(fd, *args, **kwargs)
│ │ │ │ └ {}
│ │ │ └ ('r', 0)
│ │ └ 0
│ └ <built-in function open>
└ <module 'io' from '/opt/virtual_env/py37_test/lib/python3.7/io.py'>
ValueError: can't have unbuffered text I/O
Sadly, I don't know enough linux / exscript details to contribute to fixing the problem, but interact() is definitely broken in exscript 2.6.3.
Background:
- OS: Debian 11
- Python: 3.7.0
- Exscript: 2.6.3
With libtelnet being deprecated as of 3.11 and removal slated for 3.13 I was looking for an alternative package. Exscript is suggested in the PEP which lead me to this issue.
I modified my local Protocol.py in Exscript and was able to get interactive working with two changes.
Change 1 on line 1145: set mode to rb instead of r
https://github.com/knipknap/exscript/blob/a20e83ae3a78ea7e5ba25f07c1d9de4e9b961e83/Exscript/protocols/protocol.py#L1145
Change 2 on line 1145: the first change will now require a bytes object instead of str, so instead of sending data send bytes(data, 'utf-8')
https://github.com/knipknap/exscript/blob/a20e83ae3a78ea7e5ba25f07c1d9de4e9b961e83/Exscript/protocols/protocol.py#L1199
My script now works with this:
import sys
from Exscript import Account
from Exscript.protocols import Telnet
account = Account('username', 'password')
conn = Telnet(stdout=sys.stdout)
conn.set_prompt('/ #')
conn.connect('<ip_address>')
conn.authenticate(account)
conn.interact() # blocking
conn.close()
I'm not confident this won't cause issues else where, but I figured I would share a possible solution.