Search code examples
pythonsshpexpectssh-tunnel

Pexpect ssh tunnel with an interactive logon to a host via a proxy doesn't accept the password


I'm writing a script that would have to run a remote script on a bunch of remote private hosts in different domains.

Each of the hosts being is isolated from the rest of the infrastructure. They are running in a private network segment that is only exposed through a proxy jumphost I need to ssh via. The authentication to the jumpbox is passwordless, so there're no issues with that, however the second hop I do in a subshell to the actual host I need to execute the script on doesn't really accept the password. I suspect this to be an issue with either the way I handle my pexpect tunnel, or how I escape my passwords (containing all sorts of special characters and generated dynamically).

cmd = 'ssh -o ProxyCommand="ssh -o StrictHostKeyChecking=no {}@a{}@{} nc {}} 22" -o StrictHostKeyChecking=no {}@a{}@{} -t sudo su'.format(username, domain, jumphost, remotehost, username, domain, remotehost)
    child = pexpect.spawn(cmd)
    child.expect('.*')
    child.sendline('yes')
    child.expect('.*')
    child.sendline('yes')
    child.expect('assword:')
    child.sendline(password)
    child.expect('assword')
    child.sendline(password)
    child.expect('root@.*# ')
    child.sendline('<execute remote code here>')

Whenever I do tests from the console and at any given point I do child.interact() I always get the password prompt, however the expect statements always return 0 (the index of the expect expression in the provided list) and I get back the number of bytes I'm writing, but upon interact() I always get a password prompt. What am I missing here?


Solution

  • I figured it out - sendline() sends just whatever arguments pass to it and a newline char, but doesn't send a return carriage character as well. All I had to do is either sendline(password+'\r') or send(password+'\r\n').

    I was assuming (apparently wrong) that sendline would append a \r AND \n to the line, not just the \n. Let this be a lesson for someone else who's stuck on the same stupid thing.