sudo no script não interativo

8

Eu tenho um script que executa três funções: A && B && C .

A função B precisa ser executada como um superusuário, enquanto A e C não.

Eu tenho várias soluções, mas nenhuma delas é satisfatória:

  1. sudo o script inteiro: sudo 'A && B && C'

    Parece uma má ideia executar A e C como superusuário, se não for necessário

  2. torne o script interativo: A && sudo B && C

    Talvez eu tenha que digitar minha senha, mas quero que meu script seja não interativo, pois cada função pode levar algum tempo, e eu não quero o script para esperar por mim. Bem, também é por isso que é um script no primeiro lugar, então eu não tenho que vê-lo correr.

  3. A solução estúpida: sudo : && A && sudo -n B && C

    Primeiro, parece estúpido executar um no-op sudo primeiro, e também preciso cruzar meu dedo que A não vai demorar mais de $sudo_timeout .

  4. Solução hipotética (desejo que você me diga que existe):

    sudo --store-cred 'A && sudo --use-cred-from-parent-sudo B && C'

    Isso solicitaria minha senha no começo e, em seguida, usaria essa senha credenciais somente quando necessário.

Qual sua opinião sobre tudo isso? Eu ficaria muito surpreso que não há solução para esse problema, como eu acho que é um problema bastante comum (o que sobre make all && sudo make install )

    
por Antoine Pelisse 16.03.2015 / 21:24

5 respostas

7

Acho que a melhor coisa a fazer é iniciar o script com sudo e, em seguida, iniciar os processos que você deseja executar como um usuário normal explicitamente com su user ou sudo -u user :

#!/usr/bin/env bash

## Detect the user who launched the script
usr=$(env | grep SUDO_USER | cut -d= -f 2)

## Exit if the script was not launched by root or through sudo
if [ -z $usr ] && [ $USER = "root" ]
then
    echo "The script needs to run as root" && exit 1
fi

## Run the job(s) that don't need root
sudo -u $usr commandA

## Run the job that needs to be run as root
commandB
    
por 17.03.2015 / 14:13
9

Adicione seu script ao arquivo /etc/sudoers com o atributo NOPASSWD , para que seja permitido que ele seja executado sem solicitar uma senha. Você pode vincular isso a um usuário específico (ou conjunto de usuários) ou permitir que ele seja executado com sudo por qualquer pessoa em seu sistema.

Uma linha de amostra para um script chamado /usr/local/bin/bossy pode ser algo como isto

ALL ALL = (root) NOPASSWD: /usr/local/bin/bossy

E você usaria algo assim

A && sudo bossy && C

Para este exemplo, assumi PATH includes /usr/local/bin . Se não, use apenas o caminho completo para o script, por exemplo, sudo /usr/local/bin/bossy

    
por 16.03.2015 / 23:44
0

Você pode querer usar a opção !requiretty em sudo , bem como a opção NOPASSWD . Mas tenha em mente que isso reduz a segurança.

    
por 16.03.2015 / 21:26
0

Com base na minha resposta para Pré-autorizar o sudo? (Então pode ser executado mais tarde) , escreva dois scripts:

  • ABC_script :

    #!/bin/sh
    sudo -b ./B_script
    A  &&  > A_is_done
    while [ ! -f B_is_done ]
    do
            sleep 60
    done
    rm -f B_is_done
    C
    
  • B_script :

    #!/bin/sh
    while [ ! -f A_is_done ]
    do
            sleep 60
    done
    rm -f A_is_done
    B  &&  > B_is_done
    

Executar ./ABC_script :

  • Ele será executado em sudo -b ./B_script . Isso pede a senha ( imediatamente depois de executar ABC_script ). Supondo que a senha correta seja digitada, Ele gera B_script no b ackground (porque -b foi especificado) como root. Isso parece ser equivalente a sudo sh -c "./B_script &" .
  • B_script começa a ser executado de forma assíncrona, em paralelo com ABC_script . B_script testa a existência de um arquivo chamado A_is_done e faz um loop até aparecer.
  • Em paralelo, ABC_script runs A . Se / quando A terminar com êxito, o script criará um arquivo chamado A_is_done .
  • ABC_script , em seguida, testa a existência de um arquivo chamado B_is_done e faz um loop até aparecer.
  • Em paralelo, B_script detecta a existência de A_is_done e interrompe o loop. Exclui o arquivo A_is_done e executa B . Lembre-se, B_script está sendo executado como root, portanto, ele executa B como root. Se / quando B terminar com sucesso, o script cria um arquivo chamado B_is_done e sai.
  • Em paralelo, ABC_script detecta a existência de B_is_done e interrompe o loop. Exclui o arquivo B_is_done . Lembre-se, B_script foi executado como root, portanto, B_is_done é de propriedade de root, e você deseja usar rm -f para evitar a solicitação de confirmação. ABC_script , em seguida, executa C e sai.

Notas para mais refinamento:

  • ABC_script provavelmente deve executar B_script por um caminho absoluto em vez de ./ .
  • Em vez de A_is_done e B_is_done , ABC_script provavelmente deve gerar nomes de arquivos únicos e aleatórios.
  • É preciso haver uma provisão para o script que está girando em espera para ser notificado se o programa que está esperando terminou, mas falhou. (Neste momento, se A falhar, ambos os scripts entrarão em um loop de espera infinito.) Isso pode ser tão simples quanto mudar

    A  &&  > A_is_done
    

    para

    A; echo $? > A_is_done
    

    e, em seguida, modificando o spin-espera para ler os arquivos X_is_done , e prossiga se contiver 0 e saia de outra forma.

por 17.03.2015 / 05:15
-2

Seja burro. use muitas linhas.

if A; then

    if sudo B ; then
        C
    fi
fi
    
por 16.03.2015 / 21:53