[英]Using sudo with Python script
I'm trying to write a small script to mount a VirtualBox shared folder each time I execute the script.每次执行脚本时,我都在尝试编写一个小脚本来挂载 VirtualBox 共享文件夹。 I want to do it with Python, because I'm trying to learn it for scripting.
我想用 Python 来做,因为我正在尝试学习它来编写脚本。
The problem is that I need privileges to launch mount command.问题是我需要权限才能启动 mount 命令。 I could run the script as sudo, but I prefer it to make sudo by its own.
我可以将脚本作为 sudo 运行,但我更喜欢它自己制作 sudo。
I already know that it is not safe to write your password into a.py file, but we are talking about a virtual machine that is not critical at all: I just want to click the.py script and get it working.我已经知道将密码写入 .py 文件是不安全的,但我们谈论的是一个根本不重要的虚拟机:我只想单击 .py 脚本并让它工作。
This is my attempt:这是我的尝试:
#!/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)
My python version is 2.6我的 python 版本是 2.6
Many answers focus on how to make your solution work, while very few suggest that your solution is a very bad approach .许多答案都集中在如何使您的解决方案起作用,而很少有人认为您的解决方案是一种非常糟糕的方法。 If you really want to "practice to learn", why not practice using good solutions?
如果你真的想“练习学习”,为什么不练习使用好的解决方案呢? Hardcoding your password is learning the wrong approach!
硬编码您的密码正在学习错误的方法!
If what you really want is a password-less mount
for that volume, maybe sudo
isn't needed at all !如果你真的想要的是一个无密码的
mount
该卷,也许sudo
是没有必要的! So may I suggest other approaches?那么我可以建议其他方法吗?
Use /etc/fstab
as mensi suggested.按照mensi的建议使用
/etc/fstab
。 Use options user
and noauto
to let regular users mount that volume.使用选项
user
和noauto
让普通用户挂载该卷。
Use Polkit
for passwordless actions: Configure a .policy
file for your script with <allow_any>yes</allow_any>
and drop at /usr/share/polkit-1/actions
使用
Polkit
进行无密码操作:使用<allow_any>yes</allow_any>
为您的脚本配置一个.policy
文件, <allow_any>yes</allow_any>
/usr/share/polkit-1/actions
Edit /etc/sudoers
to allow your user to use sudo
without typing your password.编辑
/etc/sudoers
以允许您的用户在不输入密码的情况下使用sudo
。 As @Anders suggested, you can restrict such usage to specific commands, thus avoiding unlimited passwordless root priviledges in your account.正如@Anders 建议的那样,您可以将此类使用限制为特定命令,从而避免您的帐户中无限制的无密码 root 权限。 See this answer for more details on
/etc/sudoers
.有关
/etc/sudoers
更多详细信息,请参阅此答案。
All the above allow passwordless root privilege, none require you to hardcode your password.以上所有都允许无密码 root 权限,不需要您对密码进行硬编码。 Choose any approach and I can explain it in more detail.
选择任何方法,我可以更详细地解释它。
As for why it is a very bad idea to hardcode passwords, here are a few good links for further reading:至于为什么硬编码密码是一个非常糟糕的主意,这里有一些很好的链接供进一步阅读:
sudoPassword = 'mypass'
command = 'mount -t vboxsf myfolder /home/myuser/myfolder'
p = os.system('echo %s|sudo -S %s' % (sudoPassword, command))
Try this and let me know if it works.试试这个,让我知道它是否有效。 :-)
:-)
And this one:还有这个:
os.popen("sudo -S %s"%(command), 'w').write('mypass')
To pass the password to sudo
's stdin:将密码传递给
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]
Note: you could probably configure passwordless sudo or SUDO_ASKPASS
command instead of hardcoding your password in the source code.注意:您可能可以配置无密码 sudo 或
SUDO_ASKPASS
命令,而不是在源代码中硬编码您的密码。
Use -S option in the sudo command which tells to read the password from 'stdin' instead of the terminal device.在 sudo 命令中使用 -S 选项,它告诉从“标准输入”而不是终端设备读取密码。
Tell Popen to read stdin from PIPE.告诉 Popen 从 PIPE 读取标准输入。
Send the Password to the stdin PIPE of the process by using it as an argument to communicate method.通过将密码用作通信方法的参数,将密码发送到进程的标准输入管道。 Do not forget to add a new line character, '\\n', at the end of the password.
不要忘记在密码末尾添加一个新行字符“\\n”。
sp = Popen(cmd , shell=True, stdin=PIPE)
out, err = sp.communicate(_user_pass+'\n')
subprocess.Popen
creates a process and opens pipes and stuff. subprocess.Popen
创建一个进程并打开管道和东西。 What you are doing is:你正在做的是:
sudo -S
sudo -S
mypass
mypass
mount -t vboxsf myfolder /home/myuser/myfolder
mount -t vboxsf myfolder /home/myuser/myfolder
which is obviously not going to work.这显然是行不通的。 You need to pass the arguments to Popen.
您需要将参数传递给 Popen。 If you look at its documentation , you will notice that the first argument is actually a list of the arguments.
如果您查看其文档,您会注意到第一个参数实际上是一个参数列表。
I used this for python 3.5.我将它用于 python 3.5。 I did it using subprocess module.Using the password like this is very insecure .
我是使用子进程模块做到的。使用这样的密码是非常不安全的。
The subprocess module takes command as a list of strings so either create a list beforehand using split() or pass the whole list later. subprocess模块将命令作为字符串列表,因此可以使用split()预先创建一个列表,或者稍后传递整个列表。 Read the documentation for moreinformation.
阅读文档以获取更多信息。
#!/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')
Please try module pexpect.请尝试模块 pexpect。 Here is my code:
这是我的代码:
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 !")
To limit what you run as sudo, you could run要限制您以 sudo 身份运行的内容,您可以运行
python non_sudo_stuff.py
sudo -E python -c "import os; os.system('sudo echo 1')"
without needing to store the password.无需存储密码。 The
-E
parameter passes your current user's env to the process. -E
参数将您当前用户的 env 传递给进程。 Note that your shell will have sudo priveleges after the second command, so use with caution!请注意,您的 shell 在第二个命令之后将具有 sudo 特权,因此请谨慎使用!
I know it is always preferred not to hardcode the sudo password in the script.我知道最好不要在脚本中对 sudo 密码进行硬编码。 However, for some reason, if you have no permission to modify
/etc/sudoers
or change file owner, Pexpect is a feasible alternative.但是,由于某种原因,如果您没有修改
/etc/sudoers
或更改文件所有者的权限,Pexpect 是一个可行的选择。
Here is a Python function sudo_exec
for your reference:这是一个 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
It works in python 2.7 and 3.8:它适用于 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)
without .flush()
password will not reach sudo
if stdin buffered.如果标准输入缓冲,没有
.flush()
密码将不会到达sudo
。 In python 2.7 Popen
by default used bufsize=0
and stdin.flush()
was not needed.在python 2.7
Popen
默认使用bufsize=0
和stdin.flush()
是没有必要的。
For secure using, create password file in protected directory:为了安全使用,在受保护的目录中创建密码文件:
mkdir --mode=700 ~/.prot_dir
nano ~/.prot_dir/passwd.txt
chmod 600 ~/.prot_dir/passwd.txt
at start your py-script read password from ~/.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")
Open your ide and run the above code.打开您的 ide 并运行上述代码。 Please change TYPE_YOUR_PASSWORD_HERE and TYPE_YOUR_LINUX_COMMAND to your linux admin password and your desired linux command after that run your python script.
请将 TYPE_YOUR_PASSWORD_HERE 和 TYPE_YOUR_LINUX_COMMAND 更改为您的 linux 管理员密码和您想要的 linux 命令,然后运行您的 python 脚本。 Your output will show on terminal.
您的 output 将显示在终端上。 Happy Coding:)
快乐编码:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.