1. 关于 Sudo
app-admin/sudo包允许系统管理员授予其他用户执行一些程序的权限,正常情况下,非系统管理员用户不具备这些程序的执行权限。与设置程序setuid位域方式不同的是,sudo在谁具有某条命令的执行权限以及何时执行方面可以实现更为严密地控制。
使用sudo可以制作一份清晰的列表来申明哪些用户具有执行哪一个程序的权限。而如果采取设置程序setuid位的方式,则任何用户(或者某一组内任意用户,这依赖于所用的权限位的设置)都可以拥有这一程序的权限。使用sudo,可以在用户运行某一程序时进行口令验证,并且也可以基于用户所在位置(位于本机或通过SSH远程登录的计算机)进行微调。
sudo还有一个额外的功能,它可以记录任何使用sudo运行某一程序的尝试(无论是否成功)。这在追踪是谁导致系统致命性错误之时很有帮助,所谓的系统致命性错误是指那种让你耗费10个小时来修正的错误:)
sudo的配置是由/etc/sudoers文件管理的。该文件无法直接由nano /etc/sudoers或者vim /etc/sudoers或者其他一些你喜欢的编辑器。要想修改这份文件,应当使用visudo。
visudo可以:确保不会有两位系统管理员同时编辑/etc/sudoers文件;维持该文件的操作权限;提供对该文件的语法检查,防止手误而导致致命性错误。
这份指南只对sudo的使用给出快速的入门指导,sudo包的功能远不止本指南所讲述的,譬如它具有让当前用户以其他用户的身份编辑文件(sudoedit),在非交互式脚本中以超级用户的身份来运行某些程序(sudo程序在后台读取标准输入中的密码,而不是接受来自键盘的输入)等特殊功能。
要获得更多有关sudo与sudoers的知识,请查阅man。
sudo最难掌握的地方是/etc/sudoers语法,其基本语法如下:
代码 2.1: 基本/etc/sudoers语法 |
user host = commands |
这一语法告诉sudo这样一些信息:用户,以user标识;所登录主机host;commands表示root用户可以执行的任何一组命令列表。基于实例来讲会更清晰一些,譬如使得用户swift可以在本地系统(非SSH远程登录)上执行emerge的语法如下:
代码 2.2: /etc/sudoers示例 |
swift localhost = /usr/bin/emerge |
警示:不要允许用户运行可以提升其操作权限的命令。譬如,若允许用户可以像root用户那样执行emerge,实际上就是授予了该用户完全的系统控制权限,因为他可以利用emerge来修改那些可以限制用户权限的文件系统。所以,如果你对你的sudo用户不是完全的放心,就不要授予他们任何权限。
配置文件中的用户(user)名可以替换为用户组(group)名,这时,应当在组名之前加上%前缀。譬如,要允许wheel组内任一用户可以执行emerge,配置语句应写为:
代码 2.3: 允许wheel组员运行emerge |
%wheel localhost = /usr/bin/emerge |
在一行配置语句中可以让一个用户拥有多条命令的root执行权限(不必每条命令只对应一个用户或组)。譬如,要允许同一个用户具有emerge、ebuild、emerge-webrsync命令的root执行权限,配置语法为:
代码 2.4: 同一用户对应多条命令 |
swift localhost = /usr/bin/emerge, /usr/bin/ebuild, /usr/sbin/emerge-webrsync |
可以更精确的设定命令,而不是仅仅光秃秃的一个命令。这样可以限制某一命令的一些选项的使用。在sudoers文件中,sudo工具容许在路径名或命令行参数中使用shell风格的通配符。但是要注意,这里不支持正则表达式作为参数。
现在来测试一下:
代码 2.5: 尝试以普通用户身份使用sudo更新系统 |
$ sudo emerge -uDN world We trust you have received the usual lecture from the local System Administrator. It usually boils down to these three things: #1) Respect the privacy of others. #2) Think before you type. #3) With great power comes great responsibility. Password: (Enter the user password, not root!) |
sudo所需要输入执行sudo命令的用户自身的口令,而非root用户口令。这样,即使你偶尔离开,但终端依然不会被居心险恶的人利用。
必须要清楚sudo不会修改${PATH}变量:sudo之后尾随的任何命令都是基于当前用户环境运行的。譬如,如果想让普通用户运行/sbin目录下的命令,应当在sudo命令行中给出完整路径:
代码 2.6: 使用完整路径执行程序 |
$ sudo /usr/sbin/emerge-webrsync
|
在更大一些的环境中,不得不频繁键入各个用户名(主机或命令列表),这可能是令人畏惧的任务。为了简化/etc/sudoers的管理,你可以定义一些别名(alias)。定义别名的语法相当简单:
代码 2.7: 在 /etc/sudoers 中定义别名 |
Host_Alias hostalias = hostname1, hostname2, ... User_Alias useralias = user1, user2, ... Cmnd_Alias cmndalias = command1, command2, ... |
在任何位置都可以使用的一个通用的别名是ALL(为了区分别名与非别名文本,建议将别名的字母都大写)。顾名思义,ALL别名表示所有可能的设置。
一个有关ALL别名的简单示例是容许所有用户都可以在本机上执行shutdown命令:
代码 2.8: 允许任何用户执行 shutdown |
ALL localhost = /sbin/shutdown |
另一个例子是无论用户swift从哪里登录本机,都允许他可以像root用户那样执行emerge:
代码 2.9: 允许一名用户运行程序,而无论他从哪里登录本机 |
swift ALL = /usr/bin/emerge |
更有趣的例子是定义一组用户,让他们可以运行一些软件包管理程序(譬如emerge和ebuild);再定义一组系统管理员,让他们可以修改除root用户之外的所有用户的密码。如下:
代码 2.10: 用户与命令的别名 |
User_Alias SOFTWAREMAINTAINERS = swift, john, danny User_Alias PASSWORDMAINTAINERS = swift, sysop Cmnd_Alias SOFTWARECOMMANDS = /usr/bin/emerge, /usr/bin/ebuild Cmnd_Alias PASSWORDCOMMANDS = /usr/bin/passwd [a-zA-Z0-9_-]*, !/usr/bin/passwd root SOFTWAREMAINTAINERS localhost = SOFTWARECOMMANDS PASSWORDMAINTAINERS localhost = PASSWORDCOMMANDS |
让一名用户像其他用户(非root用户)那样地运行程序是可行的。这非常有趣,你可以使用另一个用户(譬如网络服务器apache)的身份来运行程序或执行一些系统管理操作(比如杀死僵死进程)。
在/etc/sudoers文件中,在命令列表之前,可以在( 与 )之间列举需要改变身份的用户。
代码 2.11: 非root用户命令执行权限语法 |
users hosts = (run-as) commands |
譬如要设定允许swift可以像apache或gorg用户那样执行kill命令,语法如下:
代码 2.12: 非root用户命令执行权限示例 |
Cmnd_Alias KILL = /bin/kill, /usr/bin/pkill swift ALL = (apache, gorg) KILL |
使用这一设定,用户可以运行sudo -u来选择他想担当的角色:
代码 2.13: 像apache用户那样运行pkill |
$ sudo -u apache pkill apache
|
可以使用Runas_Alias指令为这些要切换身份的用户设置别名,它的用法与前面所讲的别名设置指令的用法相似。
默认情况下,sudo要求用户提供自己的系统登录口令来验证其身份。一旦输入了相应口令(密码),sudo会记忆它5分钟,用户要把任务集中在这段时间内来完成,否则就要每5分钟重复输入一次口令。
当然,这种默认行为是可以改变的:可以在/etc/sudoers中设定Defaults:指令来修改一名用户的默认行为。
例如,要将默认的5分钟修改为0分钟(即不记忆所输入口令):
代码 2.14: 更改时限 |
Defaults:swift timestamp_timeout=0 |
如果将timestamp_timeout设置为-1,sudo会永远记住用户口令,直至系统重新启动。
有一个设置可以在使用sudo时要输入所执行命令的所属用户口令,而不是执行sudo命令的用户口令。这一功能可由runaspw指令进行设定。下面示例演示了runaspw的用法,同时也演示了重复输入口令次数限制的设定方法:
代码 2.15: 需要root口令而非用户john的口令 |
Defaults:john runaspw, passwd_tries=2 |
还有一个有趣的功能是保持DISPLAY变量不变,这样就可以运行一些X Window工具了:
代码 2.16: 保持DISPLAY变量的值不变 |
Defaults:john env_keep=DISPLAY |
使用Defaults:指令可以更改许多默认设置,要知详情,可在sudo手册中搜索Defaults。
如果很想允许一名用户使用sudo运行一些程序时无需输入任何口令,应当在命令列表前冠以NOPASSWD:,例如:
代码 2.17: 允许像root那样使用emerge,而无需口令 |
swift localhost = NOPASSWD: /usr/bin/emerge |
运行sudo -l可以查看当前用户的sudo权限:
代码 3.1: 列出权限 |
$ sudo -l
User swift may run the following commands on this host:
(root) /usr/libexec/xfsm-shutdown-helper
(root) /usr/bin/emerge
(root) /usr/bin/passwd [a-zA-Z0-9_-]*
(root) !/usr/bin/passwd root
(apache) /usr/bin/pkill
(apache) /bin/kill
|
若在/etc/sudoers中设定了任何命令都不需要输入口令,那么在使用sudo -l时也不需要输入口令。否则,在口令未被sudo记忆时,依然要输入相应口令。
默认情况下,sudo的验证口令会维持在5分钟内有效。如果用户想延长这一时间,可以运行sudo -v重设时间戳,这样就会又开始一个5分钟口令记忆时间。
代码 3.2: sudo口令时限延长 |
$ sudo -v
|
相反,若要停掉当前时间戳,可使用sudo -k.