I am trying to connect to a device using SSH. Earlier I was trying PXSSH but it was throwing EOF Exception. Please refer here: PXSSH Connection fails sometimes randomly after upgrading to Python3. Now I am trying to use pexpect to connect the device but I am facing the same problem. The code I have written is below:
class MyPXSSH(spawn):
def __init__(self, *args, **kwargs):
super(MyPXSSH, self).__init__(None, *args, **kwargs)
self.PROMPT = r"\[PEXPECT\][\$\#] "
self.PROMPT_SET_SH = r"PS1='[PEXPECT]\$ '"
self.PROMPT_SET_CSH = r"set prompt='[PEXPECT]\$ '"
def login(self, server, username=None, password='', port=None,
cmd='ssh', sync_multiplier=5, check_local_ip=False,
auto_prompt_reset=True):
if not check_local_ip:
cmd += " -o'NoHostAuthenticationForLocalhost=yes' -o RSAAuthentication=no" \
" -o UserKnownHostsFile=/dev/null -o PubkeyAuthentication=no -o CheckHostIP=no" \
" -o StrictHostKeyChecking=no -q"
cmd += " -p {} {}@{}".format(port, username, server)
spawn._spawn(self, cmd)
expect_list = [r"(?i)are you sure you want to continue connecting", r"[$#]", "password:", pexpect.EOF, pexpect.TIMEOUT]
i = self.expect(expect_list)
if i == 0:
self.sendline('yes')
i = self.expect(expect_list)
if i == 2:
self.sendline(password)
i = self.expect(expect_list)
if i == 2:
self.sendline(password)
i = self.expect(expect_list)
if i == 2:
log.error("PERMISSION DENIED. PLEASE CHECK PASSWORD.")
return False
elif i == 3 or i == 1:
if not self.isalive():
raise Exception("Error connecting...")
log.info("CONNECTED!")
log.info("HERE 1")
pass
elif i == 4:
return False
elif i == 3 or i == 1:
if not self.isalive():
log.info(">>>> STATE: {}".format(i))
raise Exception("Error connecting...")
log.info("CONNECTED!")
log.info("HERE 2")
pass
elif i == 4:
return False
elif i == 3 or i == 4:
raise Exception("Error connecting...")
if not self.isalive():
raise Exception("Error connecting...")
self.sendline()
self.expect([pexpect.TIMEOUT, r'[$#]'], timeout=10)
if auto_prompt_reset and not self.set_unique_prompt():
raise Exception("failed to set prompt!")
log.info("CONNECTED!")
return True
def prompt(self, timeout=-1):
if timeout == -1:
timeout = self.timeout
i = self.expect([self.PROMPT, TIMEOUT], timeout=timeout)
if i==1:
return False
return True
def set_unique_prompt(self):
self.sendline("unset PROMPT_COMMAND")
self.sendline(self.PROMPT_SET_SH) # sh-style
i = self.expect ([TIMEOUT, self.PROMPT], timeout=10)
if i == 0: # csh-style
self.sendline(self.PROMPT_SET_CSH)
i = self.expect([TIMEOUT, self.PROMPT], timeout=10)
if i == 0:
return False
return True
The connection does receive a password prompt but then after sending password it returns EOF.
Notes:
OS: macOS
Code works with Python 2.7 and Pexpect 4.2.0 but fails with Python 3.9.4 with Pexpect 4.8.0
Code also works with other ssh clients like Paramiko. [Cannot use Paramiko because of some other problems with the types of commands that can be sent and some other required features that are supported by pexpect but not Paramiko]
LOGS:
2021-07-14 19:01:56 - device.py:124 - INFO - Attemping to connect to device on port 10022.
user@localhost's password: password
2021-07-14 19:01:57 - ssh.py:55 - INFO - >>>> STATE: 3
2021-07-14 19:01:57 - ssh.py:113 - CRITICAL - Error connecting...
user@localhost's password: password
2021-07-14 19:02:27 - ssh.py:55 - INFO - >>>> STATE: 3
2021-07-14 19:02:27 - ssh.py:113 - CRITICAL - Error connecting...
EDIT: output of ssh with -vv
debug1: Next authentication method: password
user@localhost's password: password
debug2: we sent a password packet, wait for reply
debug1: Authentication succeeded (password).
Authenticated to localhost ([::1]:10022).
debug2: fd 6 setting O_NONBLOCK
debug1: channel 0: new [client-session]
debug2: channel 0: send open
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: pledge: network
debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0
debug2: callback start
debug2: fd 5 setting TCP_NODELAY
debug2: client_session2_setup: id 0
debug2: channel 0: request shell confirm 1
debug2: callback done
debug2: channel 0: open confirm rwindow 0 rmax 32768
debug2: channel 0: rcvd adjust 2097152
debug2: channel_input_status_confirm: type 99 id 0
debug2: shell request accepted on channel 0
debug2: channel 0: read<=0 rfd 6 len 0
debug2: channel 0: read failed
debug2: channel 0: close_read
debug2: channel 0: input open -> drain
debug2: channel 0: ibuf empty
debug2: channel 0: send eof
debug2: channel 0: input drain -> closed
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
debug2: channel 0: obuf empty
debug2: channel 0: close_write
debug2: channel 0: output drain -> closed
debug2: channel 0: rcvd close
debug2: channel 0: almost dead
debug2: channel 0: gc: notify user
debug2: channel 0: gc: user detached
debug2: channel 0: send close
debug2: channel 0: is dead
debug2: channel 0: garbage collecting
debug1: channel 0: free: client-session, nchannels 1
debug1: fd 0 clearing O_NONBLOCK
Transferred: sent 1896, received 2064 bytes, in 0.0 seconds
Bytes per second: sent 123695.8, received 134656.1
debug1: Exit status 0