Esta pergunta foi feita de maneira diferente em outros fóruns. Mas não houve uma explicação decente por que você não pode fazer o abaixo no bash.
#!/bin/bash
command1
SWITCH_USER_TO rag
command2
command3
Geralmente, a maneira sugerida é
#!/bin/bash
command1
sudo -u rag command2
sudo -u rag command3
mas por que não é possível bash
mudar para um usuário diferente em algum momento durante a execução do script bash e executar o restante dos comandos como um usuário diferente?
Respostas:
As informações já estão na minha outra resposta , mas estão um pouco enterradas lá. Então pensei em adicionar aqui.
bash
não tem provisão para alterar usuários, maszsh
sim.Em
zsh
, você altera os usuários atribuindo valores a essas variáveis:$EUID
: altere o ID do usuário efetivo (e nada mais). Geralmente, você pode alterar o seu euid entre o seu ID do usuário real e o ID do usuário salvo (se chamado de um executável setuid) ou mudar para qualquer coisa se o seu euid for 0.$UID
: altere o ID do usuário efetivo, o ID do usuário real e o ID do usuário salvo salvo para o novo valor. A menos que esse novo valor seja 0, não há retorno, já que todos os três foram definidos com o mesmo valor, não há como alterá-lo para outra coisa.$EGID
e$GID
: a mesma coisa, exceto para identificações de grupo.$USERNAME
. Isso é como usarsudo
orsu
. Ele define seu euid, ruid, ssuid para o uid desse usuário. Ele também define os grupos egid, rgid e ssgid e suplementares com base nas associações ao grupo, conforme definido no banco de dados do usuário. Por exemplo$UID
, a menos que você defina$USERNAME
comoroot
, não há como voltar, mas por exemplo$UID
, você pode alterar o usuário apenas por um subshell.Se você executar esses scripts como "root":
Agora, para alterar o usuário como em
sudo
ousu
, só podemos fazer isso usando subshells, caso contrário, só podemos fazer uma vez:fonte
Ofertas do kernel
man 2 setuid
e amigos.Agora, ele funciona no processo de chamada. Mais importante, você não pode elevar seus privilégios. É por isso
su
esudo
têm conjunto de bits SETUID assim que funcionam sempre com privilégios mais elevados (root
) e soltar para o usuário desejado em conformidade.Essa combinação significa que você não pode alterar o UID do shell executando outro programa para fazer isso (é por isso que você não pode esperar
sudo
ou qualquer outro programa faça isso) e você não pode (como shell) fazê-lo sozinho, a menos que está disposto a executar como root ou o mesmo usuário para o qual deseja mudar, o que não faz sentido. Além disso, uma vez que você remove privilégios, não há caminho de volta.fonte
Bem, você sempre pode fazer:
(ʘ‿ʘ)
Isso começou como uma piada, pois implementa o que é solicitado, embora provavelmente não exatamente como o esperado, e não é praticamente útil. Mas como ele evoluiu para algo que funciona até certo ponto e envolve alguns hacks legais, aqui está uma pequena explicação:
Como disse Miroslav , se deixarmos de lado os recursos no estilo Linux (que de qualquer forma não ajudariam aqui), a única maneira de um processo sem privilégios mudar o uid é executando um executável setuid.
Depois de obter o privilégio de superusuário (executando um executável setuid cujo proprietário é root, por exemplo), você pode alternar o ID do usuário efetivo entre o ID do usuário original, 0 e qualquer outro ID, a menos que você renuncie ao ID do usuário definido salvo ( como as coisas gostam
sudo
ousu
costuma fazer).Por exemplo:
Agora eu tenho um
env
comando que me permite executar qualquer comando com um ID de usuário efetivo e salvar o ID de usuário definido 0 (meu ID de usuário real ainda é 1000):perl
possui wrappers parasetuid
/seteuid
(aqueles$>
e$<
variáveis).O mesmo acontece com o zsh:
Embora acima, esses
id
comandos sejam chamados com um ID do usuário real e o conjunto salvo seja 0 (embora se eu tivesse usado o meu em./env
vezsudo
disso, apenas o conjunto definido seria salvo, enquanto o ID do usuário real permaneceria 1000), o que significa que se fossem comandos não confiáveis, eles ainda poderiam causar algum dano; portanto, você gostaria de escrevê-lo como:(isto é, define todos os uids (conjunto efetivo, real e salvo) apenas para a execução desses comandos.
bash
não tem como alterar os IDs do usuário. Portanto, mesmo se você tivesse um executável setuid para chamar seubash
script, isso não ajudaria.Com
bash
, você fica executando um executável setuid toda vez que deseja alterar o uid.A idéia no script acima é uma chamada para SWITCH_TO_USER, para executar uma nova instância do bash para executar o restante do script.
SWITCH_TO_USER someuser
é mais ou menos uma função que executa o script novamente como um usuário diferente (usandosudo
), mas pula o início do script atéSWITCH_TO_USER someuser
.Onde fica complicado é que queremos manter o estado do bash atual depois de iniciar o novo bash como um usuário diferente.
Vamos dividir:
Vamos precisar de pseudônimos. Um dos truques deste script é pular a parte do script até o
SWITCH_TO_USER someuser
, com algo como:Esse formulário é semelhante ao
#if 0
usado em C, que é uma maneira de comentar completamente algum código.:
é um no-op que retorna true. Então: || :
, o segundo:
nunca é executado. No entanto, é analisado. E<< 'xxx'
é uma forma de documento aqui, onde (porquexxx
é citado), nenhuma expansão ou interpretação é feita.Poderíamos ter feito:
Mas isso significaria que o documento aqui teria que ser escrito e passado como padrão para
:
.:||:
evita isso.Agora, onde fica hacky é que usamos o fato de
bash
expandir aliases muito cedo em seu processo de análise. Terskip
um alias para a:||: << 'SWITCH_TO_USER someuther'
parte do construto comentando .Vamos continuar:
Aqui está a definição do SWITCH_TO_USER função . Veremos abaixo que SWITCH_TO_USER acabará por ser um alias envolvido nessa função.
Essa função faz a maior parte da reexecução do script. No final, vemos que ele é reexecutado (no mesmo processo por causa de
exec
)bash
com a_x
variável em seu ambiente (usamosenv
aqui porquesudo
geralmente higieniza seu ambiente e não permite a passagem de envios arbitrários). Issobash
avalia o conteúdo dessa$_x
variável como código bash e origina o próprio script._x
é definido anteriormente como:Todo o
declare
,alias
,shopt -p
set +o
de saída tornar-se um dump do estado interno do shell. Ou seja, eles despejam a definição de todas as variáveis, funções, aliases e opções como código de shell pronto para ser avaliado. Além disso, adicionamos a configuração dos parâmetros posicionais ($1
,$2
...) com base no valor do$_a
matriz (veja abaixo), e alguns limpam para que a grande$_x
variável não permaneça no ambiente pelo restante do script.Você notará que a primeira parte até
set +x
é agrupada em um grupo de comandos cujo stderr é redirecionado para/dev/null
({...} 2> /dev/null
). Isso porque, se em algum momento do scriptset -x
(ouset -o xtrace
) for executado, não queremos que esse preâmbulo gere rastreamentos, pois queremos torná-lo o menos invasivo possível. Portanto, executamos umset +x
(depois de ter certeza de despejar asxtrace
configurações da opção (incluindo ) antecipadamente) em que os rastreamentos são enviados para / dev / null.O
eval "$_X"
stderr também é redirecionado para / dev / null por razões semelhantes, mas também para evitar erros na gravação de tentativa de variáveis especiais somente leitura.Vamos continuar com o script:
Esse é o nosso truque descrito acima. Na invocação inicial do script, ele será cancelado (veja abaixo).
Agora, o alias envolve o SWITCH_TO_USER. O principal motivo é poder passar os parâmetros posicionais (
$1
,$2
...) para o novobash
que interpretará o restante do script. Não foi possível fazê-lo naSWITCH_TO_USER
função porque, dentro da função,"$@"
estão os argumentos para as funções, não os dos scripts. O redirecionamento stderr para / dev / null é novamente para ocultar xtraces, eeval
é para contornar um errobash
. Então chamamos aSWITCH_TO_USER
função .Essa parte cancela o
skip
alias (substitui-o:
pelo comando no-op), a menos que a$_u
variável esteja definida.Esse é o nosso
skip
apelido. Na primeira invocação, será apenas:
(o não-op). Em subsequence re-invocações, será algo como::||: << 'SWITCH_TO_USER root'
.Então, aqui, como exemplo, nesse ponto, reinvocamos o script como
root
usuário, e o script restaurará o estado salvo e pularemos para esseSWITCH_TO_USER root
linha e continuaremos.O que isso significa é que ele deve ser escrito exatamente como stat, com
SWITCH_TO_USER
no início da linha e com exatamente um espaço entre argumentos.A maior parte do estado, stdin, stdout e stderr será preservada, mas não os outros descritores de arquivo, porque
sudo
normalmente os fecha, a menos que explicitamente configurado para não. Então, por exemplo:normalmente não funcionará.
Observe também que se você fizer:
Isso só funciona se você tiver o direito de
sudo
comoalice
ealice
tem o direito desudo
comobob
ebob
comoroot
.Portanto, na prática, isso não é realmente útil. Usar em
su
vez desudo
(ou umasudo
configuração em quesudo
autentica o usuário de destino em vez do chamador) pode fazer um pouco mais de sentido, mas isso ainda significa que você precisa saber as senhas de todos esses caras.fonte
ioshcc
? Você deveria ter digitado apenas uma linha.O comando "sudo -u ram sh" pode ser usado para mudar para o usuário "ram", executando o comando "sh" ou shell. O comando "exit" retornará ao usuário original.
fonte