Transférer la fonction et les variables dans sudo su - <user> << EOF

9

J'ai déclaré des fonctions et des variables dans bash / ksh et je dois les transmettre dans sudo su - {user} << EOF:

#!/bin/bash

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

extVAR="yourName"

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

Réponses:

4

sudo su -, qui est une manière compliquée d'écrire sudo -i, construit un environnement vierge. C'est le point d'un shell de connexion. Même un simple sudosupprime la plupart des variables de l'environnement. De plus, sudoc'est une commande externe; il n'y a aucun moyen d'élever les privilèges dans le script shell lui-même, uniquement pour exécuter un programme externe ( sudo) avec des privilèges supplémentaires, et cela signifie que les variables shell (c'est-à-dire les variables non exportées) et les fonctions définies dans le shell parent ne seront pas disponibles dans la coquille d'enfant.

Vous pouvez transmettre des variables d'environnement en n'appelant pas un shell de connexion ( sudo bashau lieu de sudo su -ou sudo -i) et en configurant sudo pour laisser passer ces variables (avec Defaults !env_resetou Defaults env_keep=…dans le sudoersfichier). Cela ne vous aidera pas pour les fonctions (bien que bash dispose d'une fonction d'exportation de fonctions, sudo la bloque).

La manière normale d'obtenir vos fonctions dans le shell enfant serait de les définir là-bas. Prenez soin de citer: si vous utilisez <<EOFpour le document ici, le contenu du document ici est d'abord développé par le shell parent, et le résultat de cette expansion devient le script que le shell enfant voit. Autrement dit, si vous écrivez

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

cela affiche le nom de l'utilisateur d'origine, pas l'utilisateur cible. Pour éviter cette première phase d'expansion, citez le marqueur de document ici après l' <<opérateur:

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

Donc, si vous n'avez pas besoin de transmettre des données du shell parent au shell enfant, vous pouvez utiliser un document cité ici:

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

Bien que vous puissiez utiliser un marqueur de document non cité ici pour transmettre des données du shell parent au shell enfant, cela ne fonctionne que si les données ne contiennent aucun caractère spécial. C'est parce que dans un script comme

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

la sortie de whoamidevient un peu de code shell, pas une chaîne. Par exemple, si la whoamicommande est retournée, "; rm -rf /; "truele shell enfant exécutera la commande echo ""; rm -rf /; "true".

Si vous devez transmettre des données à partir du shell parent, un moyen simple consiste à les passer en arguments. Appelez explicitement le shell enfant et passez-lui les paramètres positionnels:

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

Si vous avez plusieurs variables à passer, il sera plus lisible de les passer par leur nom. Appelez envexplicitement pour définir les variables d'environnement pour le shell enfant.

#!/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

Notez que si vous vous attendiez à ce /etc/profileque l'utilisateur cible ~/.profilesoit lu, vous devrez les lire explicitement ou appeler à la bash --loginplace de sh.

Gilles 'SO- arrête d'être méchant'
la source
1

Cela ne fonctionne pas car la fonction log_fn'est pas déclarée dans le sudo su -shell que vous lancez. Au lieu:

extVAR="yourName"

sudo su - <user> << EOF

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

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

Vous devez obtenir la fonction définie dans le sous-shell racine. Cela pourrait le faire, mais ... Je ne sais pas ce que la plupart de ces choses font. Au moins - tant que ni sudoni n'a subesoin de stdin pour lire un mot de passe - cela devrait être log_f()déclaré.

J'espère que vous entendez étendre ces valeurs dans l'entrée du shell racine, soit dit en passant. Si vous ne voulez pas le faire, vous devez citer EOFet les vars eux-mêmes.

mikeserv
la source
1

Dans mon cas , je devais passer un tableau et avait quelques problèmes, mais avec un succès après un certain temps en faisant écho aux valeurs du tableau à un env-key et enveloppant le code destiné à bash -c '<intended code>', et ont essentiellement il recréer le tableau, par exemple .: INNER_KEY=($<env_key>).

Par exemple:

#!/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

Le problème était que je ne pouvais pas faire directement quelque chose comme ceci (sans utiliser bash -c '...'):

FOO=($PLUGINS);
for pl in ${FOO[@]};
...
johanmynhardt
la source