这个问题是关于理解通过调用可执行文件时记录的行为与实际行为之间不一致背后的原因须藤。当。。。的时候安全路径选项启用(我的系统上默认),搜索路径的行为符合预期。但是,当禁用该选项时,会发生一些奇怪的情况:/usr/local/bin
尽管可执行文件的位置不在搜索路径中,但无需完全限定的路径名即可访问该可执行文件。
系统信息
我的系统上当前安装了以下软件:
## Yeah... still haven't migrated to Alma
[me@localhost ~]$ cat /etc/centos-release
CentOS Linux release 8.5.2111
[me@localhost ~]$ bash --version | head -1
GNU bash, version 4.4.20(1)-release (x86_64-redhat-linux-gnu)
[me@localhost ~]$ sudo --version
Sudo version 1.8.29
Sudoers policy plugin version 1.8.29
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.29
[me@localhost ~]$ ssh -V
OpenSSH_8.0p1, OpenSSL 1.1.1k FIPS 25 Mar 2021
PAM 不会在我的系统上设置或更新 PATH 变量的值:
[me@localhost ~]$ grep --recursive 'pam_env\.so' /etc/pam.d
/etc/pam.d/fingerprint-auth:auth required pam_env.so
/etc/pam.d/smartcard-auth:auth required pam_env.so
/etc/pam.d/su:auth required pam_env.so
/etc/pam.d/password-auth:auth required pam_env.so
/etc/pam.d/system-auth:auth required pam_env.so
[me@localhost ~]$ sudo cat /etc/security/pam_env.conf /etc/environment | grep PATH
# be useful to be set: NNTPSERVER, LESS, PATH, PAGER, MANPAGER .....
#PATH DEFAULT=${HOME}/bin:/usr/local/bin:/bin\
我的/etc/sudoers
文件设置了安全路径对所有 sudoers 的价值:
[me@localhost ~]$ sudo grep --recursive secure_path /etc/sudoers /etc/sudoers.d
/etc/sudoers:Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin
Bash 默认为以下 PATH 值:
[me@localhost ~]$ env --ignore-environment bash -c 'echo $PATH'
/usr/local/bin:/usr/bin
最后,我通过 SSH 连接到系统,其/etc/ssh/sshd_config
文件包含以下行:
[me@localhost ~]$ sudo grep PATH /etc/sshd_config
# This sshd was compiled with PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
复制过程
为了复制,我首先创建一个虚拟脚本并将其安装在/usr/local/bin
:
[me@localhost ~]$ cat > dummy <<EOF
#!/usr/bin/bash
echo 'Found!'
EOF
[me@localhost ~]$ sudo install --owner=root --group=root --mode=755 dummy /usr/local/bin
我验证在不使用时搜索路径是否按预期工作须藤:
## The /usr/local/bin location is part of my search path
[me@localhost ~]$ echo $PATH
/home/me/.local/bin:/home/me/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
## This is expected
[me@localhost ~]$ dummy
Found!
并使用须藤,这也不足为奇:
## Sudo's secure_path value
[me@localhost ~]$ sudo --user=other env | grep PATH
PATH=/usr/bin:/bin:/usr/sbin:/sbin
## This is expected
[me@localhost ~]$ sudo --user=other which dummy
which: no dummy in (/sbin:/bin:/usr/sbin:/usr/bin)
## This too, of course
[me@localhost ~]$ sudo --user=other dummy
sudo: dummy: command not found
## Indeed, a fully qualified path name is required
[me@localhost ~]$ sudo --user=other /usr/local/bin/dummy
Found!
然后,我禁用安全路径(这里要小心!使用维苏多建议),通过注释该行/etc/sudoers
或创建/etc/sudoers.d/local
包含以下行的文件:
# Disable secure_path if set
Defaults !secure_path
这应该可以防止须藤,当使用--preserve-env
开关调用时,使用以下值覆盖 PATH 环境变量安全路径。它按预期工作。
然而,当不使用该--preserve-env
开关,并且不提示使用该开关的完整登录序列--login
(从而不获取任何 Bash 的启动文件),并且没有在任何 PAM 环境文件中分配给 PATH 时,会发生一些奇怪的情况:
## Not sure where this PATH value is from, neither from sudo's secure_path option
## (not set), PAM environment files (contain no assignment to PATH), Bash startup
## scripts (not sourced), nor Bash or sshd default PATH values (no match).
[me@localhost ~]$ sudo --user=other env | grep PATH
PATH=/usr/bin:/bin:/usr/sbin:/sbin
## Regardless, this is expected
[me@localhost ~]$ sudo --user=other which dummy
which: no dummy in (/usr/bin:/bin:/usr/sbin:/sbin)
## But wait! What?!?
[me@localhost ~]$ sudo --user=other dummy
Found!
那么,如何which dummy
抱怨假的不在搜索路径中,而直接调用dummy
没有路径前缀的方法可以找到它?
相关文件
以下是我在研究这个问题时发现的相关各种信息的参考。
Sudo 文档说明了这一点安全路径选项:
从 sudo 运行的每个命令所使用的路径。如果您不相信运行 sudo 的人有一个正常的 PATH 环境变量,您可能需要使用它。另一个用途是如果您希望将“根路径”与“用户路径”分开。 except_group 选项指定的组中的用户不受 secure_path 的影响。默认情况下未设置此选项。
按照pam_env手册页中的文档中,只有/etc/environment
、/etc/security/pam_env.conf
和~/.pam_environment
应该由pam_env默认为模块,除非指定了非默认文件名。我的系统上并非如此,这些文件都没有设置或更新 PATH 的值。
Bash 的手册页说道:
PATH 命令的搜索路径。它是一个以冒号分隔的目录列表,shell 在其中查找命令(请参阅下面的命令执行)。 PATH 值中的零长度(空)目录名指示当前目录。空目录名称可能显示为两个相邻的冒号,或者开头或结尾的冒号。默认路径与系统相关,由安装 bash 的管理员设置。常见的值是“/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin”。
gnu.org 上的 Bash 文档页面 (https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html) 解释了各种启动文件的来源时间。在上面的演示中,不应获取这些文件中的任何一个,因为我既没有在--login
or中生成新的 shell --interactive
,也没有调用须藤与--login
开关。
此服务器故障答案(https://serverfault.com/questions/833762/where-does-the-bash-path-on-centos-7-get-usr-local-bin-from#answer-838552) 解释了 Bash 的 PATH 变量的默认值。尽管它是针对 CentOS 7 上的 Bash 的答案,但答案仍然与 CentOS 8 打包的 Bash 版本相关。根据已接受的答案,bash 源代码config-top.h
如下:
/* The default value of the PATH variable. */
#ifndef DEFAULT_PATH_VALUE
#define DEFAULT_PATH_VALUE \
"/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:."
#endif
/* The value for PATH when invoking `command -p'. This is only used when
the Posix.2 confstr () function, or CS_PATH define are not present. */
#ifndef STANDARD_UTILS_PATH
#define STANDARD_UTILS_PATH \
"/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc"
#endif
答案1
env_reset
我相信您已经看到和之间的相互作用secure_path
。
启用后:
secure_path
重置PATH
为已知良好值env_reset
重置大多数环境变量,包括PATH
(确切的行为将取决于其他选项和配置,包括secure_path
)
问题是:每次重置会影响什么?
第二,env_reset
影响由 启动的程序sudo
。另一方面,secure_path
也影响着sudo
自身。如果没有它,sudo
则使用(呼叫)用户的PATH
来查找程序。但:
- 当启动程序时,
- 如果
env_reset
启用(默认),并且PATH
不能免于重置(例如通过env_keep
),那么,- 该计划将从...开始
- 重置值为
PATH
- (以及其他环境变量)
- 重置值为
- 该计划将从...开始
- 如果
因此,当您拨打电话which
或env
进行其他操作时,它不会看到PATH
本身sudo
正在使用的。