Cara menghentikan skrip agar tidak berjalan jika tidak root (dan gema "Tidak berjalan sebagai root! Keluar ...")

17

Inilah sumber saya:

#!/bin/bash

echo "Running script to free general cached memory!"
echo "";
echo "Script must be run as root!";
echo "";
echo "Clearing swap!";
swapoff -a && swapon -a;
echo "";
echo "Clear inodes and page file!";
echo 1 > /proc/sys/vm/drop_caches;
echo "";

Itu membersihkan cache dan semacamnya, dan itu menggemakan bahwa itu perlu dijalankan sebagai root di terminal. Saya pada dasarnya hanya ingin skrip berhenti berjalan jika mendeteksi itu tidak dieksekusi sebagai root.

Contoh:

"Running script to free general cached memory!"
"Warning: script must be run as root or with elevated privileges!"
"Error: script not running as root or with sudo! Exiting..."

Jika dijalankan dengan privilege yang ditinggikan, itu hanya berjalan seperti biasa. Ada ide? Terima kasih!

M. Knepper
sumber
Kemungkinan duplikat dari Cara menghambat root dari menjalankan skrip
muru
2
@muru, kecuali pertanyaan lain yang berlawanan: gagal skrip jika dijalankan sebagai root.
Stéphane Chazelas
3
@ StéphaneChazelas ah, salahku. Ditarik
muru
Alternatifnya adalah membatasi jumlah pekerjaan yang dilakukan sebagai rootdengan awalan awalan semua perintah yang harus dijalankan rootbersama sudo.
reinierpost

Jawaban:

46
#!/bin/sh

if [ "$(id -u)" -ne 0 ]; then
        echo 'This script must be run by root' >&2
        exit 1
fi

cat <<HEADER
Host:          $(hostname)
Time at start: $(date)

Running cache maintenance...
HEADER

swapoff -a && swapon -a
echo 1 >/proc/sys/vm/drop_caches

cat <<FOOTER
Cache maintenance done.
Time at end:   $(date)
FOOTER

Pengguna root memiliki UID 0 (terlepas dari nama akun "root"). Jika UID efektif dikembalikan oleh id -utidak nol, pengguna tidak menjalankan script dengan hak akses root. Gunakan id -ruuntuk menguji terhadap ID asli (UID pengguna yang menggunakan skrip).

Jangan gunakan $EUIDdalam skrip karena ini dapat dimodifikasi oleh pengguna yang tidak memiliki hak pribadi:

$ bash -c 'echo $EUID'
1000

$ EUID=0 bash -c 'echo $EUID'
0

Jika pengguna melakukan ini, itu jelas tidak akan mengarah pada peningkatan hak istimewa, tetapi dapat menyebabkan perintah dalam skrip tidak dapat melakukan apa yang seharusnya mereka lakukan dan file dibuat dengan pemilik yang salah dll.

Kusalananda
sumber
1
Catatan: pada Solaris 5.10, /bin/id -umemberi/bin/id: illegal option -- u Usage: id [-ap] [user]
jrw32982 mendukung Monica
1
@ jrw32982 Anda harusnya /usr/xpg4/binlebih awal $PATHuntuk mendapatkan akses ke utilitas POSIX di Solaris.
Kusalananda
1
Intinya adalah bahwa -uopsi idtidak universal dan oleh karena itu solusi ini bersifat universal hanya dengan peringatan bahwa versi POSIX idharus muncul terlebih dahulu di PATH Anda.
jrw32982 mendukung Monica
1
@ jrw32982 Untuk skrip Anda untuk mengambil utilitas POSIX yang benar pada Solaris, modifikasi $PATHdi bagian atas skrip sehingga /usr/xpg4/binsebelumnya /bin. Jika Anda bersikeras menggunakan non-POSIX id, maka jelas Anda harus datang dengan solusi yang lebih portabel.
Kusalananda
1
@ Harry Ya, agar skrip dapat menggunakan PATH=$( getconf PATH )atau mengatur beberapa jalur default eksplisit lainnya, atau menggunakan jalur eksplisit untuk memanggil id.
Kusalananda
19

Saya pikir yang Anda inginkan adalah untuk memastikan bahwa Anda memiliki hak pengguna super, yaitu id pengguna efektif Anda adalah 0.

zshdan bashmembuatnya tersedia dalam $EUIDvariabel, sehingga Anda dapat melakukan:

if ((EUID != 0)); then
  echo >&2 "Error: script not running as root or with sudo! Exiting..."
  exit 1
fi

Dengan setiap kerang mirip POSIX, Anda dapat menggunakan idperintah standar:

if [ "$(id -u)" -ne 0 ]; then
  echo >&2 "Error: script not running as root or with sudo! Exiting..."
  exit 1
fi

Perhatikan bahwa semua id -unatau whoamiatau $USERNAMEvariabel dalam zshakan memberi Anda nama pengguna pertama untuk uid. Pada sistem yang memiliki pengguna lain dengan id 0, itu mungkin tidak rootbahkan jika prosesnya adalah keturunan dari yang telah diautentikasi root.

$USERbiasanya akan memberi Anda pengguna yang diautentikasi, tetapi mengandalkannya cukup rapuh. Itu tidak diatur oleh shell, tetapi biasanya diatur oleh perintah otentikasi (seperti login, su(pada sistem GNU / Linux, belum tentu yang lain) sudo,, sshd(yang dari openssh setidaknya) ...). Namun tidak selalu (mengubah uid tidak secara otomatis mengatur variabel itu, itu harus dilakukan secara eksplisit oleh aplikasi mengubah uid) dan itu bisa juga telah dimodifikasi oleh beberapa proses lain dalam keturunan shell. $LOGNAME, dengan peringatan yang sama lebih dapat diandalkan karena ditentukan oleh POSIX (berasal dari FIPS 151-2)

Stéphane Chazelas
sumber
12

Anda dapat menggunakan $USERatau whoamiuntuk memeriksa pengguna saat ini.

if [[ "$USER" != "root" ]]; then
    echo "Error: script not running as root or with sudo! Exiting..."
    exit 1
fi

if [[ $(whoami) != "root" ]]; then
    echo "Warning: script must be run as root or with elevated privileges!"
    exit 1
fi

if [[ $(id -u) != "0" ]]; then
    echo "Error: script not running as root or with sudo! Exiting..."
    exit 1
fi
Jesse_b
sumber
1
NP. Saya sarankan secara harfiah hanya membaca langsung melalui manual bash [ gnu.org/software/bash/manual/bashref.html] . Ini sebenarnya sangat mudah siap. Untuk jawaban ini khususnya saya sarankan referensi: 3.2.4.2 Conditional Constructs 3.5.4 Command Substitution
Jesse_b
9
Perintah id -udengan atau tanpa -nopsi adalah alternatif untuk menggunakan whoami. Tanpa -n dan membandingkan ke nol adalah kecocokan yang lebih baik dengan tes yang sebenarnya dilakukan kernel. Semua kernel peduli adalah id, bukan nama dari file kata sandi.
icarus
6
Saya percaya bahwa menggunakan $(id -u)lebih baik. Dalam beberapa kasus (jahat), $USERbisa saja salah.
Basile Starynkevitch
1
Bagi mereka yang tertarik pada tautan yang disediakan oleh @Jesse_b: ada kesalahan ketik. Seharusnya gnu.org/software/bash/manual/bashref.html
Kryten
1
Beberapa sistem tidak menggunakan "root" sebagai nama akun istimewa yang memiliki 0. 0. QNAP muncul dalam pikiran sebagai satu. Jadi, Anda hanya harus memeriksa uid 0, dan bukan nama akun root.
roaima
10

Apa yang sebenarnya Anda inginkan adalah menentukan apakah Anda memiliki akses untuk melakukan operasi ini. Ini dianggap praktik buruk untuk memeriksa apakah Anda root atau tidak sebagai pengganti itu.

Jika sistem telah dikonfigurasi untuk memungkinkan pengguna non-root untuk memodifikasi swap dan drop cache halaman, mengapa pengguna itu tidak boleh menjalankan skrip Anda?

Sebagai gantinya, Anda bisa mencoba operasi dan keluar dengan pesan bermanfaat jika gagal:

if ! ( swapoff -a && swapon -a )
then
  echo "Failed to clear swap (rerun as root?)" >&2
  exit 1
fi

if ! echo 1 > /proc/sys/vm/drop_caches
then 
  echo "Failed to free page cache (rerun as root?)" >&2
  exit 1
fi
pria lain itu
sumber
Pengguna non-root mematikan swap?
Kusalananda
2
Iya. Anda dapat mengatur ini dengan SELinux. Demikian juga, Anda dapat menonaktifkan proses root dari melakukannya.
pria lain
1
Anda mungkin tidak ingin exitsetelah sesuatu gagal, jika pengguna ingin melakukan sebanyak yang mereka bisa dengan hak istimewa mereka saat ini. (Tetapi untuk sistem tipikal di mana semua ini membutuhkan root, keluar akan lebih bermanfaat / kurang berisik.)
Peter Cordes
2
Saya tidak akan mengatakan "praktik buruk" untuk memeriksa apakah Anda root atau tidak. Terutama jika itu persis apa yang Anda ingin tahu. Saya mengambil pendapat Anda bahwa yang terbaik adalah memeriksa apakah Anda memiliki izin yang memadai untuk melakukan apa yang Anda inginkan.
Erik Bennett