Script shell / bash: descarte corretamente os privilégios

5

Ok, em primeiro lugar, sei que esta pergunta já foi feita algumas vezes aqui, mas as respostas dadas não me satisfizeram inteiramente. A situação é a seguinte: Eu escrevi muitos scripts para automatizar várias tarefas de manutenção, com o objetivo de ser totalmente automático e não requerer interação alguma vez, uma vez iniciado. Agora, frequentemente privilégios de root são necessários para várias tarefas (como montagem de material, etc.) mas muito mais frequentemente eu não gosto que comandos ou blocos inteiros sejam executados com direitos de superusuário (como wget, ou extrair um arquivo obtido da web, etc.), para limitar os danos no pior dos casos. Então, obviamente, para satisfazer meus objetivos, o script tem que ser chamado usando sudo ou su e descarta privilégios e os recupera, dependendo dos comandos.

Agora eu considerei algumas opções, mas elas não me satisfizeram totalmente e, portanto, eu gostaria de consultar especialistas aqui, para saber qual seria a melhor solução (com o objetivo de que o código seja facilmente compreensível e logicamente estruturado para outros assim também uma vez publicados):

1.) Fatore os bits a serem executados como usuário não raiz em um arquivo externo e execute esse arquivo a partir do script principal usando su <user> -c /path/to/file . Esse methoed, no entanto, tem algumas desvantagens: Primeiro, estraga a estrutura lógica do script e torna as coisas mais difíceis de entender e ler, além de criar problemas com a definição e o uso de variáveis.

2.) Defina um alias ou uma função para encurtar su <user> -c "command" . Esta é uma idéia muito ruim, pois 80% dos scripts teriam esse prefixo de privilégio. Além disso, comandos multi-line são problemáticos (como se estruturas que contêm comandos que eu não quero rodar como root).

3.) Algo parecido com su <user> << EOF << ... EOF , que lida corretamente com blocos inteiros de código. Essa seria a solução mais elegante (porque a estrutura lógica do script não é destruída) se não houvesse um problema que me incomodasse: Sintaxe destacando. Todos os editores principais eu tentei usar uma cor para o bloco inteiro dentro do doc aqui. Não é exatamente bom ler um script em que 80% não possuem realce de sintaxe.

Não há uma maneira realmente elegante de lidar com esse problema? Algo como su <user> -c ( ...) sem aspas seria legal. Ou devo talvez mudar para outro shell? (agora eu uso o bash, ouvi dizer que o zsh tem um recurso que permite configurar variáveis EUID ou algo assim?) Se não houver uma solução elegante, qual abordagem seria preferível?

    
por GEO 09.11.2014 / 15:17

3 respostas

3

Com zsh , se estiver em execução como root e você definir

EUID=1000

Ele irá definir o euid para 1000. O uid real ainda será definido como 0, então você pode voltar para o EUID 0. Qualquer programa que você execute também poderá recuperar privilégios executando setuid() , mas se a intenção é evitar danos não intencionais ao invés de proteger contra software malicioso, então isso deve ser suficiente.

#! /bin/zsh -
GID=1000 # optional
EUID=1000 # drop *effective* privileges

some-potentially-harmful-command-that-doesnt-need-superuser

and-another

EUID=0 some-command-that-needs-superuser

more-non-privileged-commands

EUID=0 UID=1000 # now drop privileges with no coming back 
# alternatively:
# USERNAME=stephane # sets uid, gid, supplementary groups... based on the user db

Observe que você pode definir o EUID / UID ... pela duração de um comando com

UID=1000 the-command

Mas não UID ou USERNAME if the-command está embutido ou uma função como zsh não separaria um processo diferente, portanto não seria possível restaurar o ID do usuário real.

Você também pode definir EUID / UID / USERNAME em uma subshell com:

(EUID=0 USERNAME=stephane; untrusted-application)

(definimos EUID como 0 para poder mudar de usuário depois).

    
por 11.11.2014 / 14:51
2

Uma solução seria um pouco de programação dinâmica : crie os vários fragmentos de código não privilegiados como arquivos separados e use um pré-processador para criar o arquivo final. Desta forma, o programa pode ser lido trivialmente como bits separados ou como um todo. A comunicação entre os processos teria que ser feita usando arquivos, o que é um pouco mais incômodo, mas torna muito menos provável que vaze informações privilegiadas para o arquivo não privilegiado (já que é preciso "vazar" explicitamente cada informação).

privileged.sh :

echo "Privileged user: $(whoami)"
su - somebody <<'EOF'
%unprivileged.sh%
EOF

unprivileged.sh :

echo "Unprivileged user: $(whoami)"

preprocessor.sh :

while IFS= read -r line
do
    if [[ $line =~ ^%([^%]*)%$ ]]
    then
        cat "${BASH_REMATCH[1]}"
    else
        printf '%s\n' "$line"
    fi
done < privileged.sh > program.sh

Execução de teste:

$ bash preprocessor.sh 
$ sudo bash program.sh 
Privileged user: root
Unprivileged user: somebody
    
por 09.11.2014 / 18:31
0

3.) Something like su << EOF << ... EOF which would properly handle entire blocks of code. This would be the most elegant solution (because the logical structure of the script is not destroyed) if there was not one problem that bugs me: Syntax highlighting. All major editors I tried use one color for the entire block inside the here doc. It is not exactly nice to read through a script where 80% have no syntax highlighting.

Você deve ser capaz de definir o destaque da sintaxe personalizada em vim para que ele faça o que você quer, o artigo este artigo também pode ser de interesse.

    
por 09.11.2014 / 16:00