[英]Using sudo with Python script
每次执行脚本时,我都在尝试编写一个小脚本来挂载 VirtualBox 共享文件夹。 我想用 Python 来做,因为我正在尝试学习它来编写脚本。
问题是我需要权限才能启动 mount 命令。 我可以将脚本作为 sudo 运行,但我更喜欢它自己制作 sudo。
我已经知道将密码写入 .py 文件是不安全的,但我们谈论的是一个根本不重要的虚拟机:我只想单击 .py 脚本并让它工作。
这是我的尝试:
#!/usr/bin/env python
import subprocess
sudoPassword = 'mypass'
command = 'mount -t vboxsf myfolder /home/myuser/myfolder'
subprocess.Popen('sudo -S' , shell=True,stdout=subprocess.PIPE)
subprocess.Popen(sudoPassword , shell=True,stdout=subprocess.PIPE)
subprocess.Popen(command , shell=True,stdout=subprocess.PIPE)
我的 python 版本是 2.6
许多答案都集中在如何使您的解决方案起作用,而很少有人认为您的解决方案是一种非常糟糕的方法。 如果你真的想“练习学习”,为什么不练习使用好的解决方案呢? 硬编码您的密码正在学习错误的方法!
如果你真的想要的是一个无密码的mount
该卷,也许sudo
是没有必要的! 那么我可以建议其他方法吗?
按照mensi的建议使用/etc/fstab
。 使用选项user
和noauto
让普通用户挂载该卷。
使用Polkit
进行无密码操作:使用<allow_any>yes</allow_any>
为您的脚本配置一个.policy
文件, <allow_any>yes</allow_any>
/usr/share/polkit-1/actions
编辑/etc/sudoers
以允许您的用户在不输入密码的情况下使用sudo
。 正如@Anders 建议的那样,您可以将此类使用限制为特定命令,从而避免您的帐户中无限制的无密码 root 权限。 有关/etc/sudoers
更多详细信息,请参阅此答案。
以上所有都允许无密码 root 权限,不需要您对密码进行硬编码。 选择任何方法,我可以更详细地解释它。
至于为什么硬编码密码是一个非常糟糕的主意,这里有一些很好的链接供进一步阅读:
sudoPassword = 'mypass'
command = 'mount -t vboxsf myfolder /home/myuser/myfolder'
p = os.system('echo %s|sudo -S %s' % (sudoPassword, command))
试试这个,让我知道它是否有效。 :-)
还有这个:
os.popen("sudo -S %s"%(command), 'w').write('mypass')
将密码传递给sudo
的标准输入:
#!/usr/bin/env python
from subprocess import Popen, PIPE
sudo_password = 'mypass'
command = 'mount -t vboxsf myfolder /home/myuser/myfolder'.split()
p = Popen(['sudo', '-S'] + command, stdin=PIPE, stderr=PIPE,
universal_newlines=True)
sudo_prompt = p.communicate(sudo_password + '\n')[1]
注意:您可能可以配置无密码 sudo 或SUDO_ASKPASS
命令,而不是在源代码中硬编码您的密码。
在 sudo 命令中使用 -S 选项,它告诉从“标准输入”而不是终端设备读取密码。
告诉 Popen 从 PIPE 读取标准输入。
通过将密码用作通信方法的参数,将密码发送到进程的标准输入管道。 不要忘记在密码末尾添加一个新行字符“\\n”。
sp = Popen(cmd , shell=True, stdin=PIPE)
out, err = sp.communicate(_user_pass+'\n')
subprocess.Popen
创建一个进程并打开管道和东西。 你正在做的是:
sudo -S
mypass
mount -t vboxsf myfolder /home/myuser/myfolder
这显然是行不通的。 您需要将参数传递给 Popen。 如果您查看其文档,您会注意到第一个参数实际上是一个参数列表。
我将它用于 python 3.5。 我是使用子进程模块做到的。使用这样的密码是非常不安全的。
subprocess模块将命令作为字符串列表,因此可以使用split()预先创建一个列表,或者稍后传递整个列表。 阅读文档以获取更多信息。
#!/usr/bin/env python
import subprocess
sudoPassword = 'mypass'
command = 'mount -t vboxsf myfolder /home/myuser/myfolder'.split()
cmd1 = subprocess.Popen(['echo',sudoPassword], stdout=subprocess.PIPE)
cmd2 = subprocess.Popen(['sudo','-S'] + command, stdin=cmd1.stdout, stdout=subprocess.PIPE)
output = cmd2.stdout.read.decode()
有时需要回车:
os.popen("sudo -S %s"%(command), 'w').write('mypass\n')
请尝试模块 pexpect。 这是我的代码:
import pexpect
remove = pexpect.spawn('sudo dpkg --purge mytool.deb')
remove.logfile = open('log/expect-uninstall-deb.log', 'w')
remove.logfile.write('try to dpkg --purge mytool\n')
if remove.expect(['(?i)password.*']) == 0:
# print "successfull"
remove.sendline('mypassword')
time.sleep(2)
remove.expect(pexpect.EOF,5)
else:
raise AssertionError("Fail to Uninstall deb package !")
要限制您以 sudo 身份运行的内容,您可以运行
python non_sudo_stuff.py
sudo -E python -c "import os; os.system('sudo echo 1')"
无需存储密码。 -E
参数将您当前用户的 env 传递给进程。 请注意,您的 shell 在第二个命令之后将具有 sudo 特权,因此请谨慎使用!
我知道最好不要在脚本中对 sudo 密码进行硬编码。 但是,由于某种原因,如果您没有修改/etc/sudoers
或更改文件所有者的权限,Pexpect 是一个可行的选择。
这是一个 Python 函数sudo_exec
供您参考:
import platform, os, logging
import subprocess, pexpect
log = logging.getLogger(__name__)
def sudo_exec(cmdline, passwd):
osname = platform.system()
if osname == 'Linux':
prompt = r'\[sudo\] password for %s: ' % os.environ['USER']
elif osname == 'Darwin':
prompt = 'Password:'
else:
assert False, osname
child = pexpect.spawn(cmdline)
idx = child.expect([prompt, pexpect.EOF], 3)
if idx == 0: # if prompted for the sudo password
log.debug('sudo password was asked.')
child.sendline(passwd)
child.expect(pexpect.EOF)
return child.before
它适用于 python 2.7 和 3.8:
from subprocess import Popen, PIPE
from shlex import split
proc = Popen(split('sudo -S %s' % command), bufsize=0, stdout=PIPE, stdin=PIPE, stderr=PIPE)
proc.stdin.write((password +'\n').encode()) # write as bytes
proc.stdin.flush() # need if not bufsize=0 (unbuffered stdin)
如果标准输入缓冲,没有.flush()
密码将不会到达sudo
。 在python 2.7 Popen
默认使用bufsize=0
和stdin.flush()
是没有必要的。
为了安全使用,在受保护的目录中创建密码文件:
mkdir --mode=700 ~/.prot_dir
nano ~/.prot_dir/passwd.txt
chmod 600 ~/.prot_dir/passwd.txt
从 ~/.prot_dir/passwd.txt 开始你的 py-script 读取密码
with open(os.environ['HOME'] +'/.prot_dir/passwd.txt') as f:
password = f.readline().rstrip()
import os
os.system("echo TYPE_YOUR_PASSWORD_HERE | sudo -S TYPE_YOUR_LINUX_COMMAND")
打开您的 ide 并运行上述代码。 请将 TYPE_YOUR_PASSWORD_HERE 和 TYPE_YOUR_LINUX_COMMAND 更改为您的 linux 管理员密码和您想要的 linux 命令,然后运行您的 python 脚本。 您的 output 将显示在终端上。 快乐编码:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.