Executando uma função de script Bash com Sudo

14

Eu tenho um script que faz várias coisas diferentes, a maioria das quais não requer nenhum privilégio especial. No entanto, uma seção específica, que eu tenho em uma função, precisa de privilégios de root.

Eu não desejo exigir que todo o script seja executado como root e quero poder chamar essa função, com privilégios de root, a partir do script. Solicitar uma senha, se necessário, não é um problema, pois é basicamente interativo. No entanto, quando tento usar sudo functionx , recebo:

sudo: functionx: command not found

Como eu esperava, export não fez diferença. Eu gostaria de poder executar a função diretamente no script em vez de quebrá-la e executá-la como um script separado por vários motivos.

Existe alguma maneira de tornar minha função "visível" para o sudo sem extraí-la, encontrar o diretório apropriado e depois executá-lo como um script independente?

A função é sobre uma página longa e contém várias strings, algumas com aspas duplas e algumas com uma única aspas. Também depende de uma função de menu definida em outro lugar no script principal.

Eu só esperaria que alguém com o sudo ANY pudesse executar a função, já que uma das coisas que faz é alterar as senhas.

    
por BryKKan 11.03.2016 / 05:54

5 respostas

12

Admito que não há uma maneira simples e intuitiva de fazer isso, e isso é um pouco hacky. Mas você pode fazer assim:

function hello()
{
    echo "Hello!"
}

# Test that it works.
hello

FUNC=$(declare -f hello)
sudo bash -c "$FUNC; hello"

Ou mais simplesmente:

sudo bash -c "$(declare -f hello); hello"

Funciona para mim:

$ bash --version
GNU bash, version 4.3.42(1)-release (x86_64-apple-darwin14.5.0)
$ hello
Hello!
$
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Hello!

Basicamente, declare -f retornará o conteúdo da função, que você passa para bash -c inline.

Se você quiser exportar todas as funções da instância externa do bash, altere FUNC=$(declare -f hello) para FUNC=$(declare -f) .

Editar

Para abordar os comentários sobre citações, consulte este exemplo:

$ hello()
> {
> echo "This 'is a' test."
> }
$ declare -f hello
hello ()
{
    echo "This 'is a' test."
}
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Password:
This 'is a' test.
    
por 11.03.2016 / 06:13
3

O "problema" é que sudo limpa o ambiente (com exceção de um punhado de variáveis permitidas) e define algumas variáveis para valores seguros predefinidos para proteger contra riscos de segurança. em outras palavras, isso não é realmente um problema. É uma característica.

Por exemplo, se você definir PATH="/path/to/myevildirectory:$PATH" e sudo não definiu PATH como um valor pré-definido, qualquer script que não especificasse o nome completo do caminho para TODOS os comandos executados (ou seja, a maioria dos scripts) seria em /path/to/myevildirectory antes de qualquer outro diretório. Coloque comandos como ls ou grep ou outras ferramentas comuns e você poderá facilmente fazer o que quiser no sistema.

A maneira mais fácil / melhor é reescrever a função como um script e salvá-la em algum lugar no caminho (ou especificar o caminho completo para o script na linha de comando sudo - o que você precisará fazer de qualquer maneira a menos que sudo esteja configurado para permitir que você execute QUALQUER comando como root) e torne-o executável com chmod +x /path/to/scriptname.sh

Reescrever uma função shell como um script é tão simples quanto apenas salvar os comandos dentro da definição da função em um arquivo (sem as linhas function ... , { e } ).

    
por 11.03.2016 / 06:32
1

Eu escrevi minha própria função Sudo bash para fazer isso, funciona para chamar funções e aliases:

function Sudo {
        local firstArg=$1
        if [ $(type -t $firstArg) = function ]
        then
                shift && command sudo bash -c "$(declare -f $firstArg);$firstArg $*"
        elif [ $(type -t $firstArg) = alias ]
        then
                alias sudo='\sudo '
                eval "sudo $@"
        else
                command sudo "$@"
        fi
}
    
por 19.04.2018 / 14:03
1

Esta é uma variação da resposta de Will . Envolve um processo adicional de cat , mas oferece o conforto de heredoc. Em poucas palavras, é assim:

f () 
{
    echo ok;
}

cat <<EOS | sudo bash
$(declare -f f)
f
EOS

Se você quiser mais comida para pensar, tente o seguinte:

#!/bin/bash

f () 
{ 
    x="a b"; 
    menu "$x"; 
    y="difficult thing"; 
    echo "a $y to parse"; 
}

menu () 
{
    [ "$1" == "a b" ] && 
    echo "here's the menu"; 
}

cat <<EOS | sudo bash
$(declare -f f)
$(declare -f menu)
f
EOS

A saída é:

here's the menu
a difficult thing to pass

Aqui temos a função menu correspondente àquela da questão, que é "definida em outro lugar no script principal". Se o "outro lugar" significa que sua definição já foi lida neste estágio quando a função exigindo sudo está sendo executada, então a situação é análoga. Mas pode não ter sido lido ainda. Pode haver outra função que ainda acione sua definição. Nesse caso, declare -f menu precisa ser substituído por algo mais sofisticado ou o script inteiro corrigido de forma que a função menu já esteja declarada.

    
por 25.01.2018 / 22:08
0

Supondo que seu script seja (a) autocontido ou (b) possa criar seus componentes com base em sua localização (em vez de lembrar onde seu diretório inicial está), você poderia fazer algo assim:

  • use o nome de caminho $0 do script, use-o no comando sudo e passe adiante uma opção que o script verificará para chamar a atualização de senha. Contanto que você dependa de encontrar o script no caminho (em vez de apenas executar ./myscript ), você deve obter um nome de caminho absoluto em $0 .
  • como o sudo executa o script, ele acessa as funções necessárias no script.
  • na parte superior do script (em vez disso, depois das declarações de função), o script verificaria seu uid e perceberia que ele era executado como o usuário root , e vendo que ele tem o opção definida para avisar para atualizar a senha, faça isso.

Os scripts podem se repetir por vários motivos: alterar privilégios é um deles.

    
por 11.03.2016 / 21:06