繁体   English   中英

将管道命令和 sudo 与 Python 子进程结合使用时出现问题

[英]Issue when combining pipe command and sudo with Python Subprocess

我正在尝试利用 Python 模块subprocess在 Mac 上自动执行终端命令。 具体来说,我正在运行某个命令来在我的机器上创建端口映射 但是,有问题的命令需要 root 权限和管道:

echo "
rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
" | sudo pfctl -ef - 

为了使用subprocess将我的 root 密码传递给 shell 命令,我按照此处找到的代码示例创建了以下脚本:

from subprocess import PIPE, Popen
p = Popen(['echo', '"rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080"\n'], stdin=PIPE, stderr=PIPE, universal_newlines=True)
p2 = Popen(['sudo', '-S']+['pfctl', '-ef', '-'], stdin=p.stdout, stderr=PIPE, universal_newlines=True) 
return p2.communicate('my_root_password\n')[1] 

请注意,为了将echo输出的管道传输到命令pfctl -ef -我已经创建了两个Popen对象,并将第一个对象的stdout传递给了第二个的stdin参数,如subprocess docs 中所推荐的,并且我正在使用Popen.communicate将 root 密码写入标准输入。

但是,我上面的脚本不起作用,因为在终端中仍然提示我输入我的 root 密码 奇怪的是,当使用没有管道的命令时,我能够成功地将我的 root 密码写入 stdin,例如,在运行sudo pfctl -s nat (以显示我当前的端口映射设置)时:

p = Popen(['sudo', '-S']+'pfctl -s nat'.split(), stdin=PIPE, stderr=PIPE, universal_newlines=True)
print(p.communicate('root_password\n')[1])

上面的代码有效,因为映射配置在没有任何密码提示的情况下显示。

如何更改我的第一个 Python 脚本,以便在我已经使用Popen.communicate将密码写入标准输入后,不会提示我输入我的 root 密码?


我在 macOS Sierra 10.12.5 上运行此代码

我认为这只是管道未正确连接的一个简单案例。 您没有为第一个进程的stdout指定管道,因此从外观上看,输出只是打印到终端然后进程完成。

当第二个进程开始时,它会提示输入密码,据我所知正确接收。 然而, communicate方法然后关闭输入并等待进程完成。 据我所知,第一个进程的输出永远不会到达第二个进程,这就是您的脚本不起作用的原因。 而不是创建一个单独的echo过程,为什么不给你需要的所有文本数据communicate

看起来您遇到的另一个问题(我没有要检查的 MAC)是sudo将提示直接打印到终端(即通过/dev/tty而不是stdout )。 在我的sudo版本(在 Debian 上)添加-S选项会导致它打印提示到stderr 但是看起来-S选项不会在 MAC 上执行此操作。 而是尝试使用-p ''禁用提示。

把所有东西放在一起,这应该有效:

from subprocess import PIPE, Popen
from getpass import getpass

password = getpass()

cmd = ['sudo', '-k', '-S', '-p', '', 'pfctl', '-ef', '-']
p = Popen(cmd, stdin=PIPE, stderr=PIPE, universal_newlines=True) 
text = password + '\n'
text += 'rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080\n'
p.communicate(text)

安全注意事项

此答案已更新为不使用纯文本密码。 请参阅下面的评论,了解为什么这是一个坏主意的一个很好的例子! 另请注意,使用 Python 在内存中存储密码并不完全安全,就像将内存交换到磁盘一样,这将包括纯文本形式的密码。 对于较低级别的语言,将使用mlock系统调用来防止任何包含密码的内存被交换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM