Por que “sudo su” em um script de shell não executa o restante do script como root?


36

Um script de exemplo pode ser o seguinte:

#!/bin/bash
sudo su
ls /root

Ao usar ./test.shcomo usuário normal, execute lscomo superusuário e saia, ele alterna para o root; e quando eu sair, ele executa ls /rootcomo o usuário normal.

Alguém pode me falar sobre o mecanismo?


13
sudo sufaz meus olhos doerem.
gelraen

É usado porque as pessoas não conhecem o sudo o suficiente e, portanto, precisam de uma maneira de executá-lo em sistemas onde o root é protegido por uma senha deliberadamente corrompida. Mas sim sudo "redundifica" o uso de su.
Johan

1
Você não pode simplesmente usar sudo -s?
Joe Z.

@ John, eu costumo usar sudo suporque estou mais acostumado com as opções do suque com as opções sudo. Conheço bem as opções do sudo, mas posso digitar as opções mais rapidamente. Mas sim, acho que isso significa que não conheço o sudo o suficiente.
user606723

1
Acabei de verificar a página de manual do sudo. Parece sudo -ié semelhante a su -quando sudo -sopera como su(sem o traço)
Johan

Respostas:


49

Os comandos em um script são executados um por um, independentemente. O próprio Script como o pai de todos os comandos do script é outro processo independente e o comando su não o altera e não pode ser alterado para root: o comando su cria um novo processo com privilégios de root.

Após a conclusão do comando su, o processo pai, ainda em execução como o mesmo usuário, executará o restante do script.

O que você deseja fazer é escrever um script de wrapper. Os comandos privilegiados vão para o script principal, por exemplo~/main.sh

#!/bin/sh
ls /root

O script do wrapper chama o script principal com permissões de root, assim

#!/bin/sh
su -c ~/main.sh root

Para iniciar esse processo, você executa o wrapper, que, por sua vez, inicia o script principal após alternar o usuário para o usuário raiz.

Essa técnica de invólucro pode ser usada para transformar o script em um invólucro. Basicamente, verifique se está sendo executado como root; caso contrário, use "su" para se reiniciar.

$ 0 é uma maneira prática de fazer um script se referir a si mesmo, e o comando whoami pode nos dizer quem somos (somos root?)

Portanto, o script principal com o invólucro interno se torna

#!/bin/sh
[ `whoami` = root ] || exec su -c $0 root
ls /root

Observe o uso de exec. Significa "substituir este programa por", que efetivamente encerra sua execução e inicia o novo programa, lançado por su, com root, para executar a partir do topo. A instância de substituição é "root", portanto, não executa o lado direito do ||


1
fwiw, um adendo a este ponto. Se eu estivesse escrevendo um script como esse, faria apenas uma instrução if no início que verifique $ EUID e se não for zero sudo em si e saia, caso contrário, continue com a execução do script.
Bratchley #

Concordo e atualizarei a resposta para explicar isso.
Johan

2
Talvez seja um pouco arcaico, mas eu amo caminhos absolutos para todos os executáveis, para que alguém não possa mudar o script ~ / main.sh para algo nefasto. Atacando a parte do usuário do script
artifex

2
Você também pode querer pegar os argumentos que foram passados a ele pela inclusão de uma referência a $ *
Bratchley

@ JoelDavis Eu sempre me deparo com o argumento "e se houver caracteres de espaços nos argumentos". Eu nunca encontrei uma solução satisfatória. Uma vez eu escrevi um script que colocou seus argumentos em um arquivo temporário, um argumento por linha, e depois chamei o que fosse necessário e passei para o script final o argumento de qual arquivo ler para encontrar os argumentos originais.
Johan

20

Use o seguinte no script.

sudo su <<HERE
ls /root
HERE

O código entre o bloco HERE será executado como root.


6
sudo suestá chamando dois programas. Use sudo -s <<HEREDOCou su user <<HEREDOC... Estúpido limite de 5 minutos.
21413 Johan Johan

6

Sem mais argumentos su, o shell de login será executado como root. É o que a primeira linha do seu script realmente faz. Quando você sair, o fechamento do shell de login, su retornos e seu script continua a execução, isto é, com a segunda linha: ls /root. Eu acho que você pode simplesmente sudo ls /rootfazer o que quiser.


Sim, eu sei que posso fazer isso ls, mas isso é apenas uma amostra. Na verdade, preciso fazer muito mais coisas com privilégios de root :-) Então, prefiro a resposta do @ Ankit.
Hongxu Chen

1

Depois de acionar sudo suum novo processo com a eficáciauserid (euid=EUID) de superusuário bifurcado, temos um novo bash sendo executado em diferentes IDs de processo (pid=PID)associados ao mesmo terminal (tname=TTY).

Explicação

Suponha que, após o disparo, ps -A | grep bashvocê tenha 21460 pts/2 00:00:00 bashcomo saída. Agora, quando você executa os ./test.shdois comandos sudo sue ls /rootserá colocado no spool PID 21460. Após a execução, quando você tiver rootcomo usuário ativo atingido ps -A | grep bashnovamente, você notará um novo bash sendo executado PID say, 21570. Sair de root bashirá matar o bash recém-bifurcado, revertendo user's bashe, portanto, executa o comando em spool ls /rootantes de liberar o prompt.


Se o uso de su ou sudo for "persistente" no bash (ou em qualquer outro lugar), isso criará muito mais problemas do que resolveu. Você precisa fazer o mínimo possível como raiz para segurança e proteção. O ponto principal de ter su e sudo (além da segurança!) É fazer você pensar cuidadosamente sobre o que precisa de privilégios de root.
5133 Joe
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.