使用标准Python库输入SSH密码(非pexpect)
这里有一些相关的问题,它们基本上在问同样的事情,但给出的答案对我没有用:
我想通过ssh连接到一台远程机器并运行一个命令。例如:
ssh <user>@<ipv6-link-local-addr>%eth0 sudo service fooService status
问题是,我想通过一个Python脚本来实现这个功能,而且只使用标准库(不使用pexpect
)。我一直在尝试使用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
的赋值给stdout
和stderr
。但是,结果总是出现相同的提示:
ubuntu@<ipv6-link-local-addr>%eth0's password:
我是不是漏掉了什么?或者有没有其他方法可以使用Python的标准库来实现这个功能?
1 个回答
9
这个回答其实是对Torxed的这个回答的改编,我建议你去给它点个赞。这个改编的内容主要是增加了一个功能,让你可以获取在远程服务器上执行命令的输出结果。
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>