Esta questão é sobre entender o(s) motivo(s) por trás de uma inconsistência percebida entre o comportamento documentado e o real ao chamar um executável por meio de sudo . Quando a opção secure_path está habilitada (padrão no meu sistema), o caminho de pesquisa se comporta conforme o esperado. Mas quando a opção está desabilitada, algo estranho acontece: um executável em /usr/local/bin
pode ser alcançado sem um nome de caminho totalmente qualificado, apesar de sua localização não estar no caminho de pesquisa.
Informação do sistema
O seguinte software está atualmente instalado no meu sistema:
## 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
O PAM não define ou atualiza o valor da variável PATH no meu sistema:
[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\
Meu /etc/sudoers
arquivo define um valor secure_path para todos os sudoers:
[me@localhost ~]$ sudo grep --recursive secure_path /etc/sudoers /etc/sudoers.d
/etc/sudoers:Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin
O padrão do Bash é o seguinte valor PATH:
[me@localhost ~]$ env --ignore-environment bash -c 'echo $PATH'
/usr/local/bin:/usr/bin
Por fim, estou conectado ao sistema através do SSH, cujo /etc/ssh/sshd_config
arquivo contém esta linha:
[me@localhost ~]$ sudo grep PATH /etc/sshd_config
# This sshd was compiled with PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
Procedimento de replicação
Para replicar, primeiro crio um script fictício e o instalo em /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
Verifico se o caminho de pesquisa funciona conforme o esperado quando não estiver usando sudo :
## 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!
E usando sudo , nenhuma surpresa aqui também:
## 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!
Então, desabilito secure_path (cuidado aqui! o uso do visudo é recomendado), seja comentando a linha /etc/sudoers
ou criando um arquivo /etc/sudoers.d/local
com as seguintes linhas:
# Disable secure_path if set
Defaults !secure_path
Isso deve impedir que sudo , quando chamado com o --preserve-env
switch, substitua a variável de ambiente PATH pelo valor de secure_path . E funciona como esperado.
No entanto, ao não usar o --preserve-env
switch e não solicitar uma sequência de login completa com o --login
switch (assim, não fornecendo nenhum dos arquivos de inicialização do Bash) e sem atribuição ao PATH em nenhum dos arquivos do ambiente PAM, algo estranho acontece:
## 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!
Então, como é que se which dummy
queixa de dummy não estar no caminho de pesquisa enquanto uma chamada direta para dummy
sem prefixo de caminho o encontra?
Documentação relevante
A seguir estão as referências a várias informações que achei relevantes ao pesquisar essa questão.
A documentação do Sudo diz isso sobre a opção secure_path :
Caminho usado para cada comando executado a partir do sudo. Se você não confia nas pessoas que executam o sudo para ter uma variável de ambiente PATH sã, você pode querer usar isso. Outro uso é se você quiser que o “caminho raiz” seja separado do “caminho do usuário”. Os usuários do grupo especificado pela opção isent_group não são afetados pelo secure_path. Esta opção não é definida por padrão.
De acordo com a documentação do pam_env nas páginas do manual, apenas o /etc/environment
, o /etc/security/pam_env.conf
e ~/.pam_environment
deve ser processado pelo módulo pam_env por padrão, a menos que nomes de arquivo não padrão sejam especificados. Este não é o caso no meu sistema e nenhum desses arquivos define ou atualiza o valor de PATH.
A página man do Bash diz:
PATH O caminho de pesquisa para comandos. É uma lista de diretórios separados por dois pontos nos quais o shell procura por comandos (consulte EXECUÇÃO DE COMANDO abaixo). Um nome de diretório de comprimento zero (nulo) no valor de PATH indica o diretório atual. Um nome de diretório nulo pode aparecer como dois dois-pontos adjacentes ou como dois-pontos iniciais ou finais. O caminho padrão depende do sistema e é definido pelo administrador que instala o bash. Um valor comum é “/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin”.
Esta página da documentação do Bash no gnu.org ( https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html ) explica quando os vários arquivos de inicialização são originados. Na minha demonstração acima, nenhum desses arquivos deve ser originado, pois não estou gerando novos shells em --login
or --interactive
, nem chamando sudo com o --login
switch.
Esta resposta do ServerFault ( https://serverfault.com/questions/833762/where-does-the-bash-path-on-centos-7-get-usr-local-bin-from#answer-838552 ) explica os valores padrão do Bash para a variável PATH. Mesmo que tenha sido respondido para o Bash no CentOS 7, a resposta ainda é relevante para a versão do Bash empacotada com o CentOS 8. De acordo com a resposta aceita, a fonte do bash config-top.h
tem o seguinte:
/* 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
Eu acredito que você está vendo a interação entre
env_reset
esecure_path
.Quando ativado:
secure_path
redefinePATH
para um valor conhecidoenv_reset
redefine a maioria das variáveis de ambiente, incluindoPATH
(o comportamento exato dependerá de outras opções e configurações, incluindosecure_path
)A questão é: o que cada reset afeta?
A segunda,
env_reset
afeta os programas iniciados porsudo
. Por outro lado,secure_path
também afeta asudo
si mesmo. Sem ele,sudo
usa o usuário (chamando)PATH
para procurar programas. Mas:env_reset
estiver ativado (o padrão), ePATH
não está isento de ser redefinido (por exemplo, viaenv_keep
), então,PATH
Então, quando você ligar
which
ouenv
outra coisa, ele não verá oPATH
quesudo
estava usando.