如何从脚本中编辑/etc/sudoers?

147

我需要从一个脚本中编辑/etc/sudoers文件,以添加/删除白名单。

假设我有一个在普通文件上有效的命令,我如何将其应用到/etc/sudoers文件上?

我是否可以复制并修改它,然后使用visudo将原始文件替换为修改后的副本?或者在$EDITOR中提供自己的脚本?

还是只需使用相同的锁和cp命令?

这个问题更多地关注潜在的问题而不是只找出可行的方法。

14个回答

195

旧帖子,不过关于这个问题:

echo 'foobar ALL=(ALL:ALL) ALL' | sudo EDITOR='tee -a' visudo

14
这是一个很好的回答。整个子Shell应该以root身份执行,例如 echo "$USER ALL=NOPASSWD:/usr/bin/rsync" | (sudo su -c 'EDITOR="tee" visudo -f /etc/sudoers.d/rsync') - simon
3
这个答案非常有效!我将其用于Debian软件包中的postinst脚本。谢谢!由于此处始终是root用户,因此它变得简短而方便:echo "$CONFIGLINE" | (EDITOR="tee -a" visudo) - Boris Däppen
7
我想指出@BorisDäppen答案中的一个重大细节:EDITOR="tee"-a标志:它将附加行到文件中,而不仅仅是覆盖第一行。起初我没有注意到这个区别,也无法找到追加的方法。我希望通过直接指出这一点能够帮助其他人;-) - Jean-Philippe Murray
4
有人能解释一下这个命令是怎么工作的吗?我的意思是,编辑器后面不是需要分号才对吗?我知道这样会破坏命令。EDITOR是一个shell变量,visudo是另一个命令,所以我们在同一行命令中传递了EDITOR和visudo。这到底是如何工作的? - Sagar
2
为了防止重复记录:if [ -z "$(grep 'foobar ALL=(ALL:ALL) ALL' /etc/sudoers )" ]; then echo "foobar ALL=(ALL:ALL) ALL" | sudo EDITOR='tee -a' visudo; fi; - muratgozel
显示剩余9条评论

46

使用visudo和自定义编辑器来解决这个问题。这可以解决Brian的解决方案中出现的所有竞争条件和“黑客攻击”问题。

#!/bin/sh
if [ -z "$1" ]; then
  echo "Starting up visudo with this script as first parameter"
  export EDITOR=$0 && sudo -E visudo
else
  echo "Changing sudoers"
  echo "# Dummy change to sudoers" >> $1
fi

这个脚本将在sudoers文件末尾添加一行文本“#Dummy change to sudoers”。没有黑客技巧,也没有竞态条件。

下面是注释版,可以解释脚本的实际工作原理:

if [ -z "$1" ]; then

  # When you run the script, you will run this block since $1 is empty.

  echo "Starting up visudo with this script as first parameter"

  # We first set this script as the EDITOR and then starts visudo.
  # Visudo will now start and use THIS SCRIPT as its editor
  export EDITOR=$0 && sudo -E visudo
else

  # When visudo starts this script, it will provide the name of the sudoers 
  # file as the first parameter and $1 will be non-empty. Because of that, 
  # visudo will run this block.

  echo "Changing sudoers"

  # We change the sudoers file and then exit  
  echo "# Dummy change to sudoers" >> $1
fi

7
需要确保已经使用了 --enable-env-editor 参数编译 sudo,否则它只会在编辑器变量设置为少数几个已知值之一时才使用。 - Caleb
它在我的Ubuntu 12.04上运行良好,但我不明白它是如何工作的。有人能解释一下如何正确使用它以及它的实际工作原理吗?谢谢。 - MountainX
想指出的是,在我的12.04版本上似乎无法运行。我创建了一个bash脚本,为其添加了+x权限,并使用以下输出执行该文件:visudo: 无法运行/tmp/edit_sudoers:Exec格式错误 visudo:/etc/sudoers.tmp未更改 - Jose Diaz-Gonzalez
这对我非常有效,尽管我只是作为root登录并从第一个命令中删除了sudo -E - merlin2011
我很喜欢这个答案,但对我没有用。我认为我的sudo没有编译必要的标志。 - Mnebuerquo
不确定是不是sudo编译的问题,但在CentOS 7上对我也不起作用。脚本运行,一切看起来都已经运行(我的调试echo命令已打印等),但sudoers文件实际上并未更改。在@JoseDiaz-Gonzalez提到的exec错误之前,我还必须在我的脚本顶部添加一个shebang才能消除它。 - Kenny83

31

你应该在一个临时文件上进行编辑,然后使用visudo -c -f sudoers.temp来确认更改是否有效,然后将其复制到/etc/sudoers的顶部。

#!/bin/sh
if [ -f "/etc/sudoers.tmp" ]; then
    exit 1
fi
touch /etc/sudoers.tmp
edit_sudoers /tmp/sudoers.new
visudo -c -f /tmp/sudoers.new
if [ "$?" -eq "0" ]; then
    cp /tmp/sudoers.new /etc/sudoers
fi
rm /etc/sudoers.tmp

看起来你正在使用sudoers.tmp作为锁文件,不确定这如何确认更改是有效的。我们应该检查visudo的退出状态以确保没有错误,对吧? - converter42
/etc/sudoers.tmp 是 visudo 在交互模式下检查的锁定文件。visudo -c -f 如果出现错误,则返回 1,因此需要检查返回代码。 - Brian C. Lane
我担心使用sudoers.tmp,因为它看起来像是使用visudo的内部接口,即一种hack。这是标准的吗,也就是说,保证总是使用sudoers.tmp作为锁定文件?还是他们将来有更改的自由? - n-alexander
它也会产生竞态条件,对吗? - n-alexander
2
需要使用lockfile而不是test/touch。 - n-alexander
2
手册上说它使用 /tmp/sudoers.tmp,因此这是目前的标准。当然,将来可能会更改。是的,你是对的,存在竞态条件。 - Brian C. Lane

25

在大多数发行版(至少是基于Debian、Redhat、openSUSE等)中,您可以将自定义脚本插入到/etc/sudoers.d/目录中,并赋予其0440权限-有关更多信息,请参见man sudo(“从sudo内部包含其他文件”)或官方网站上的相同信息。

这可能会有所帮助。


它难道不是被注释掉了吗? - user636044
4
我认为不行。请参考sudoers(5)手册其他评论 - pevik
你说得对!感谢提供链接和出色的回答。 - user636044
3
我同样在CentOS 7中使用那个目录。 - Alexander Bird

11

visudo是编辑/etc/sudoers文件的人机界面。你可以通过直接替换文件来达到相同的效果,但是你必须自己处理并发编辑和语法验证。注意r--r-----权限。


10

如果您的sudo允许在/etc/sudoers.d中添加条目,则可以使用@dragon788的答案:

https://superuser.com/a/1027257/26022

基本上,您可以使用visudo验证文件,然后将其复制到/etc/sudoers.d中,以确保您不会为任何人破坏sudo

visudo -c -q -f filename

这将检查它,并在其有效时返回成功(0),因此您可以将其与if&&和其他脚本布尔运算一起使用。验证后,只需将其复制到/etc/sudoers.d中,然后它应该就能正常工作了。确保它归根所有且不可被其他人写入。


9

有很多答案,一直使用sudo工具,但直到现在才需要自动化设置配置。 我使用了上面某些答案的混合方式,将我的配置行写入/etc/sudoers.d包含位置的文件中,这样我就不必修改主sudoers文件,然后检查该文件的语法,以下是一个简单的示例:

将您的行写入sudoers包含文件中:

sudo bash -c 'echo "your_user ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/99_sudo_include_file'

检查您的sudoers包含文件是否通过visudo语法检查:

sudo visudo -cf /etc/sudoers.d/99_sudo_include_file

只需省略星号,那里不应该有星号^^ - Sonata
它成功返回(0) -- 已收到 - Yu Da Chi

5
这是我想到的解决方案。它是一个快速而简单的解决方案,但它有效...
echo "username ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers

它将echo输出导入到在sudo下运行的tee中。然后,Tee将输出附加到sudoers文件中。


1
与visudo相比,这不是一个适当的解决方案,因为visudo可以自动进行健全性检查。 - aderchox
感谢您提供如此清晰的答案。非常不错。 - Jafar Amini

5

设置自定义编辑器。基本上,它将是一个脚本,接受文件名(在本例中为/etc/sudoers.tmp),并在原地修改和保存该文件。因此,您可以直接写入该文件。完成后,退出脚本,visudo会负责为您修改实际的sudoers文件。

sudo EDITOR=/path/to/my_dummy_editor.sh visudo

我理解的是dummy_editor.sh文件只需要包含类似这样的内容,对吗?#!/bin/sh; echo "# my changes to sudoers" >> $1; exit 0 对我来说似乎可以工作。 - MountainX

4
我认为最直接的解决方案是:
创建一个名为addsudoers.sh的脚本。
#!/bin/sh

while [ -n "$1" ]; do
    echo "$1    ALL=(ALL:ALL) ALL" >> /etc/sudoers;
    shift # shift all parameters
done

并且使用您想要添加的用户调用它:

root prompt> ./addsudoers.sh user1 user2

要了解完整的解释,请查看此答案:通过Shell脚本将用户添加到sudoers

祝好!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接