51

每次执行脚本时,我都在尝试编写一个小脚本来挂载 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

4

11 回答 11

75

许多答案都集中在如何使您的解决方案发挥作用,而很少有人认为您的解决方案是一种非常糟糕的方法。如果你真的想“练习来学习”,为什么不练习使用好的解决方案呢?硬编码您的密码正在学习错误的方法!

如果您真正想要的是mount该卷的无密码,则可能根本sudo不需要!那么我可以建议其他方法吗?

  • /etc/fstab按照mensi 的建议使用。使用选项usernoauto让普通用户安装该卷。

  • 用于Polkit无密码操作:.policy为您的脚本配置一个文件,<allow_any>yes</allow_any>并放置在/usr/share/polkit-1/actions

  • 编辑/etc/sudoers以允许您的用户在sudo不输入密码的情况下使用。正如@Anders 所建议的那样,您可以将此类使用限制为特定命令,从而避免您的帐户中无限制的无密码根权限。有关更多详细信息,请参阅此答案/etc/sudoers

以上所有都允许无密码的 root 权限,没有一个需要你硬编码你的密码。选择任何方法,我可以更详细地解释它。

至于为什么硬编码密码是一个非常糟糕的主意,这里有一些很好的链接供进一步阅读:

于 2014-06-17T07:23:03.970 回答
47
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')

于 2012-10-24T08:45:14.340 回答
19

要将密码传递给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命令,而不是在源代码中硬编码您的密码。

于 2014-05-16T04:13:37.823 回答
5
  • 在 sudo 命令中使用 -S 选项,该选项告诉从“stdin”而不是终端设备读取密码。

  • 告诉 Popen 从 PIPE 读取标准输入。

  • 通过将密码用作通信方法的参数,将密码发送到进程的标准输入管道。不要忘记在密码末尾添加一个换行符“\n”。

sp = Popen(cmd , shell=True, stdin=PIPE)
out, err = sp.communicate(_user_pass+'\n')   
于 2014-12-19T20:03:48.413 回答
4

subprocess.Popen创建一个进程并打开管道和东西。你正在做的是:

  • 启动一个进程sudo -S
  • 启动一个进程mypass
  • 启动一个进程mount -t vboxsf myfolder /home/myuser/myfolder

这显然行不通。您需要将参数传递给 Popen。如果您查看它的文档,您会注意到第一个参数实际上是参数列表。

于 2012-10-24T08:45:13.570 回答
2

我将它用于 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()
于 2018-04-05T10:28:15.120 回答
1

有时需要回车:

os.popen("sudo -S %s"%(command), 'w').write('mypass\n')
于 2013-08-27T13:55:22.160 回答
1

请尝试模块 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 !")
于 2013-11-07T07:24:34.300 回答
1

要限制您作为 sudo 运行的内容,您可以运行

python non_sudo_stuff.py
sudo -E python -c "import os; os.system('sudo echo 1')"

无需存储密码。该-E参数将您当前用户的环境传递给进程。请注意,您的 shell 在第二个命令之后将具有 sudo 权限,因此请谨慎使用!

于 2017-12-07T21:21:02.973 回答
0

我知道最好不要在脚本中硬编码 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
于 2014-09-29T09:38:35.047 回答
0

它适用于 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.7Popen中默认使用bufsize=0并且stdin.flush()不需要。

为了安全使用,请在受保护的目录中创建密码文件:

mkdir --mode=700 ~/.prot_dir
nano ~/.prot_dir/passwd.txt
chmod 600 ~/.prot_dir/passwd.txt 

在启动您的 py 脚本时,从 ~/.prot_dir/passwd.txt 读取密码

with open(os.environ['HOME'] +'/.prot_dir/passwd.txt') as f:
    password = f.readline().rstrip()
于 2020-09-30T19:53:07.530 回答