【问题标题】:Enter an ssh password using the standard python library (not pexpect)使用标准 python 库(不是 pexpect)输入 ssh 密码
【发布时间】:2014-09-01 12:56:26
【问题描述】:

本质上是在问同样的事情,但答案对我不起作用的相关问题:

Make python enter password when running a csh script

How to interact with ssh using subprocess module

How to execute a process remotely using python

我想通过 ssh 连接到一台远程机器并运行一个命令。例如:

ssh <user>@<ipv6-link-local-addr>%eth0 sudo service fooService status

问题是我试图通过一个只有标准库(没有pexpect)的python脚本来做到这一点。我一直在尝试使用subprocess 模块使其工作,但在请求密码时调用communicate 总是阻塞,即使我将密码作为参数提供给communicate。例如:

proc = subprocess.Popen(
        [
            "ssh",
            "{testUser1}@{testHost1}%eth0".format(**locals()),
            "sudo service cassandra status"],
        shell=False,
        stdin=subprocess.PIPE)
a, b = proc.communicate(input=testPasswd1)
print "a:", a, "b:", b
print "return code: ", proc.returncode

我也尝试了上述的一些变体(例如,删除“input=”,添加/删除subprocess.PIPE 分配给stdoutsterr)。但是,结果总是一样的提示:

ubuntu@<ipv6-link-local-addr>%eth0's password:

我错过了什么吗?或者还有其他方法可以使用 python 标准库来实现吗?

【问题讨论】:

  • 您尝试过this answer 的建议吗?这在 Linux 环境中对我来说很好。如果你在 Windows 上,我想你可能不走运......
  • 您需要提供两次密码,一次用于客户端的 ssh,一次用于服务器端的 sudo。 如何使用子进程模块与 ssh 进行交互对我来说看起来很合理,并且可以针对 sudo 部分进行修改......那它对你不起作用呢?
  • @tdelaney,服务器上没有 sudo 的密码。似乎“如何交互......”解决方案可能有效,但我需要获取其中一个命令的输出,而简单的读取没有返回任何内容。

标签: python ssh subprocess


【解决方案1】:

这个答案只是 Torxed 对this answer 的改编,我建议你去投票。它只是增加了捕获您在远程服务器上执行的命令的输出的能力。

import pty
from os import waitpid, execv, read, write

class ssh():
    def __init__(self, host, execute='echo "done" > /root/testing.txt', 
                 askpass=False, user='root', password=b'SuperSecurePassword'):
        self.exec_ = execute
        self.host = host
        self.user = user
        self.password = password
        self.askpass = askpass
        self.run()

    def run(self):
        command = [
                '/usr/bin/ssh',
                self.user+'@'+self.host,
                '-o', 'NumberOfPasswordPrompts=1',
                self.exec_,
        ]

        # PID = 0 for child, and the PID of the child for the parent    
        pid, child_fd = pty.fork()

        if not pid: # Child process
            # Replace child process with our SSH process
            execv(command[0], command)

        ## if we havn't setup pub-key authentication
        ## we can loop for a password promt and "insert" the password.
        while self.askpass:
            try:
                output = read(child_fd, 1024).strip()
            except:
                break
            lower = output.lower()
            # Write the password
            if b'password:' in lower:
                write(child_fd, self.password + b'\n')
                break
            elif b'are you sure you want to continue connecting' in lower:
                # Adding key to known_hosts
                write(child_fd, b'yes\n')
            else:
                print('Error:',output)

        # See if there's more output to read after the password has been sent,
        # And capture it in a list.
        output = []
        while True:
            try:
                output.append(read(child_fd, 1024).strip())
            except:
                break

        waitpid(pid, 0)
        return ''.join(output)

if __name__ == "__main__":
    s = ssh("some ip", execute="ls -R /etc", askpass=True)
    print s.run()

输出:

/etc:
adduser.conf
adjtime
aliases
alternatives
apm
apt
bash.bashrc
bash_completion.d
<and so on>

【讨论】:

    猜你喜欢
    • 2011-08-03
    • 2015-05-03
    • 1970-01-01
    • 1970-01-01
    • 2022-06-25
    • 2011-05-07
    • 2020-10-02
    • 2023-03-17
    • 2021-03-29
    相关资源
    最近更新 更多