Função de encaminhamento e variáveis ​​para sudo su - <usuário> << EOF


9

Declarei funções e variáveis ​​no bash / ksh e preciso encaminhá-las para sudo su - {user} << EOF:

#!/bin/bash

log_f() {
echo "LOG line: $@"
}

extVAR="yourName"

sudo su - <user> << EOF
  intVAR=$(date)
  log_f ${intVAR} ${extVAR}
EOF

Respostas:


4

sudo su -, que é uma maneira complicada de escrever sudo -i, constrói um ambiente primitivo. Esse é o objetivo de um shell de login. Mesmo uma planície sudoremove a maioria das variáveis ​​do ambiente. Além disso, sudoé um comando externo; não há como elevar privilégios no próprio script do shell, apenas para executar um programa externo ( sudo) com privilégios extras, e isso significa que quaisquer variáveis ​​do shell (ou seja, variáveis ​​não exportadas) e funções definidas no shell pai não estarão disponíveis no a concha do filho.

Você pode passar variáveis ​​de ambiente não invocando um shell de login (em sudo bashvez de sudo su -ou sudo -i) e configurando o sudo para permitir que essas variáveis passem (com Defaults !env_resetou Defaults env_keep=…no sudoersarquivo). Isso não ajudará você em funções (embora o bash tenha um recurso de exportação de funções, o sudo o bloqueia).

A maneira normal de obter suas funções no shell filho seria defini-las lá. Lembre-se de citar: se você usar <<EOFo documento here, o conteúdo do documento here será expandido primeiro pelo shell pai, e o resultado dessa expansão se tornará o script que o shell filho visualiza. Ou seja, se você escrever

sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF

isso exibe o nome do usuário original, não o usuário de destino. Para evitar essa primeira fase de expansão, cite o marcador de documento aqui após o <<operador:

sudo -u "$target_user" -i <<'EOF'
echo "$(whoami)"
EOF

Portanto, se você não precisar passar dados do shell pai para o shell filho, use um documento aqui citado:

#!/bin/bash
sudo -u "$target_user" -i  <<'EOF'
log_f() {
echo "LOG line: $@"
}
intVAR=$(date)
log_f "${intVAR}"
EOF

Embora você possa usar um marcador de documento aqui não citado para passar dados do shell pai para o shell filho, isso só funciona se os dados não contiverem nenhum caractere especial. Isso porque em um script como

sudo -u "$target_user" -i <<EOF
echo "$(whoami)"
EOF

a saída de whoamise torna um pouco de código de shell, não uma string. Por exemplo, se o whoamicomando retornasse "; rm -rf /; "true, o shell filho executaria o comando echo ""; rm -rf /; "true".

Se você precisar passar dados do shell pai, uma maneira simples é passá-los como argumentos. Invoque o shell filho explicitamente e passe parâmetros posicionais:

#!/bin/bash
extVAR="yourName"
sudo -u "$target_user" -i sh  _ "$extVAR" <<'EOF'
  log_f() {
  echo "LOG line: $@"
  }
  intVAR=$(date)
  log_f "${intVAR}" "${1}"
EOF

Se você tiver várias variáveis ​​para passar, será mais legível passá-las pelo nome. Chame envexplicitamente para definir variáveis ​​de ambiente para o shell filho.

#!/bin/bash
extVAR="yourName"
sudo -u "$target_user" -i env extVAR="$extVAR" sh <<'EOF'
  log_f() {
  echo "LOG line: $@"
  }
  intVAR=$(date)
  log_f "${intVAR}" "${1}"
EOF

Observe que, se você esperava que /etc/profileo usuário de destino ~/.profilefosse lido, precisará lê-los explicitamente ou ligar em bash --loginvez de sh.


1

Isso não funciona porque a função log_fnão está declarada no sudo su -shell que você inicia. Em vez de:

extVAR="yourName"

sudo su - <user> << EOF

log_f() {
echo "LOG line: $@"
}

  intVAR=$(date)
  log_f ${intVAR} ${extVAR}
EOF

Você precisa obter a função definida no subshell raiz. Isso pode funcionar, mas ... Eu não sei o que a maioria dessas coisas faz. Pelo menos - contanto que sudonem o sustdin precise ler uma senha - isso deve ser log_f()declarado.

Confio que você pretenda expandir esses valores na entrada do shell raiz, a propósito. Se você não pretende fazê-lo, deve citar EOFos próprios vars.


1

No meu caso eu precisava para passar um array e teve alguns problemas, mas teve sucesso depois de um tempo por ecoando os valores da matriz a uma envtecla e envolvendo o código destina-se em bash -c '<intended code>', e, basicamente, tem que recriar o array, por exemplo .: INNER_KEY=($<env_key>).

Por exemplo:

#!/usr/bin/env bash
PLUGINS=(foo bar baz)
sudo -u <some-user> -i env PLUGINS="`echo ${PLUGINS[@]}`" sh <<'EOF'
  bash -c '
    FOO=($PLUGINS);
    echo values: \[${FOO[@]}\];

    for pl in ${FOO[@]};
      do echo value: $pl;
    done;
  '
EOF

O problema era que eu não podia fazer diretamente algo como o seguinte (não usando bash -c '...'):

FOO=($PLUGINS);
for pl in ${FOO[@]};
...
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.