Meneruskan fungsi dan variabel ke sudo su - <user> << EOF

9

Saya telah mendeklarasikan fungsi dan variabel di bash / ksh dan saya perlu meneruskannya ke 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
sumber

Jawaban:

4

sudo su -, yang merupakan cara penulisan yang rumit sudo -i, membangun lingkungan yang murni. Itulah inti dari shell login. Bahkan dataran sudomenghapus sebagian besar variabel dari lingkungan. Selanjutnya sudoadalah perintah eksternal; tidak ada cara untuk meningkatkan hak istimewa dalam skrip shell itu sendiri, hanya untuk menjalankan program eksternal ( sudo) dengan hak istimewa tambahan, dan itu berarti setiap variabel shell (yaitu variabel yang tidak diekspor) dan fungsi yang didefinisikan dalam shell induk tidak akan tersedia di cangkang anak.

Anda dapat melewati variabel lingkungan dengan tidak menggunakan shell login ( sudo bashbukan sudo su -atau sudo -i) dan mengkonfigurasi sudo untuk membiarkan variabel-variabel ini melalui (dengan Defaults !env_resetatau Defaults env_keep=…dalam sudoersfile). Ini tidak akan membantu Anda untuk fungsi (walaupun bash memiliki fasilitas ekspor fungsi, sudo memblokirnya).

Cara normal untuk mendapatkan fungsi Anda di child shell adalah dengan mendefinisikannya di sana. Berhati-hatilah mengutip: jika Anda menggunakan <<EOFuntuk dokumen di sini, konten dokumen di sini pertama kali diperluas oleh shell induk, dan hasil ekspansi itu menjadi skrip yang dilihat oleh shell anak. Yaitu, jika Anda menulis

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

ini menampilkan nama pengguna asli, bukan target pengguna. Untuk menghindari fase ekspansi pertama ini, kutip penanda dokumen di sini setelah <<operator:

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

Jadi jika Anda tidak perlu meneruskan data dari shell induk ke shell anak, Anda dapat menggunakan dokumen yang dikutip di sini:

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

Meskipun Anda dapat menggunakan penanda dokumen yang tidak dikutip di sini untuk meneruskan data dari shell induk ke shell anak, ini hanya berfungsi jika data tidak mengandung karakter khusus apa pun. Itu karena dalam naskah suka

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

output whoamimenjadi sedikit kode shell, bukan string. Misalnya, jika whoamiperintah dikembalikan "; rm -rf /; "truemaka shell anak akan menjalankan perintah echo ""; rm -rf /; "true".

Jika Anda perlu meneruskan data dari shell induk, cara sederhana adalah mengirimkannya sebagai argumen. Panggil cangkang anak secara eksplisit dan berikan parameter posisi:

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

Jika Anda memiliki beberapa variabel untuk dilewati, akan lebih mudah dibaca untuk meneruskannya dengan nama. Panggil envsecara eksplisit untuk mengatur variabel lingkungan untuk shell anak.

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

Perhatikan bahwa jika Anda mengharapkan /etc/profiledan target pengguna ~/.profileuntuk dibaca, Anda harus membacanya secara eksplisit, atau menelepon bash --loginalih-alih sh.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
1

Ini tidak berfungsi karena fungsi log_ftidak dideklarasikan di sudo su -shell yang Anda luncurkan. Sebagai gantinya:

extVAR="yourName"

sudo su - <user> << EOF

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

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

Anda harus mendapatkan fungsi yang didefinisikan dalam subkulit root. Itu mungkin bisa, tapi .... Saya tidak tahu apa yang sebagian besar dari barang itu lakukan. Setidaknya - selama tidak sudoatau sukebutuhan stdin untuk membaca password - yang harus mendapatkan log_f()menyatakan.

Saya percaya bahwa Anda bermaksud untuk memperluas nilai-nilai tersebut ke dalam input shell root. Jika Anda tidak bermaksud melakukannya maka Anda harus mengutip EOFdan vars sendiri.

mikeserv
sumber
1

Dalam kasus saya saya butuhkan untuk melewati array dan memiliki beberapa masalah, tapi telah sukses setelah beberapa saat oleh bergema nilai-nilai array ke env-key dan membungkus kode dimaksud dalam bash -c '<intended code>', dan pada dasarnya memilikinya menciptakan array, misalnya .: INNER_KEY=($<env_key>).

Untuk examlpe:

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

Masalahnya adalah saya tidak bisa langsung melakukan sesuatu seperti berikut (tidak menggunakan bash -c '...'):

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