Meminta hak istimewa root dari dalam skrip

23

Saya memiliki skrip yang dapat dijalankan sebagai sudo script.shataupkexec script.sh

Akan jauh lebih baik dari sudut pandang pengguna jika skrip meminta kata sandi dari pengguna saat menjalankannya dengan nama script.sh.

Bagaimana saya bisa "menanamkan" permintaan ke pkexecatau sudountuk menjalankan seluruh skrip dengan privilege root?

Perhatikan bahwa menjalankan semuanya dengan sudo sh -cmungkin bukan solusi terbaik karena saya memiliki fungsi dalam skrip.

Sergiy Kolodyazhnyy
sumber

Jawaban:

55

Ini akan berhasil:

echo "$(whoami)"

[ "$UID" -eq 0 ] || exec sudo "$0" "$@"

contoh:

./test.sh 
blade
[sudo] password for blade: 
root
blade19899
sumber
3
Apa yang baik tentang ini adalah rekursi dengan exec- panggilan itu sendiri tetapi pada saat yang sama mengganti proses, jadi kami tidak menelurkan banyak contoh skrip
Sergiy Kolodyazhnyy
1
Rekursi untuk menyelamatkan !!! Ingatkan saya untuk menambahkan hadiah untuk yang ini dalam beberapa hari!
Fabby
6
Sesuatu yang harus diperhatikan ketika melakukan ini adalah eskalasi hak istimewa; pada dasarnya, semakin banyak perintah yang Anda jalankan sebagai root, semakin banyak peluang bagi peretas jahat untuk mengeksploitasi sesuatu untuk mendapatkan akses ke akun root. Saya tidak mengatakan itu selalu salah untuk membuat keseluruhan skrip berjalan sebagai root, tetapi ada baiknya memikirkannya sebelum Anda memutuskan untuk melakukannya. Saya pikir akan lebih baik (walaupun tidak perlu) jika jawabannya akan menyentuh itu.
David Z
Jika Anda memiliki nilai batas waktu yang ditetapkan di / etc / sudoers, maka Anda dapat menempatkan sudo di depan setiap perintah dalam skrip yang benar-benar membutuhkan akses root dan hanya akan bertanya sekali. Satu hal yang sering saya lakukan adalah memanggil skrip seperti itu dari gui tidak akan berhasil karena sudo mendapat / dev / null untuk input kata sandi dan gagal. Itulah yang dirancang gksudo dan kdesudo untuk ditangani karena mereka akan menggunakan gui untuk meminta kata sandi.
Joe
1
@ Coder256: Saya rasa suntingan Anda tidak benar. "$@"akan diperluas ke beberapa kata, satu untuk setiap parameter.
jwodder
12

Jika Anda ingin dialog yang cantik, coba sesuatu seperti ini. Saya merobek ini langsung dari sesuatu yang saya tulis, jadi ada hal-hal tambahan yang Anda mungkin tidak perlu atau inginkan, tetapi itu menunjukkan ide umum:

brand="My Software"

# Check that the script is running as root. If not, then prompt for the sudo
# password and re-execute this script with sudo.
if [ "$(id -nu)" != "root" ]; then
    sudo -k
    pass=$(whiptail --backtitle "$brand Installer" --title "Authentication required" --passwordbox "Installing $brand requires administrative privilege. Please authenticate to begin the installation.\n\n[sudo] Password for user $USER:" 12 50 3>&2 2>&1 1>&3-)
    exec sudo -S -p '' "$0" "$@" <<< "$pass"
    exit 1
fi

dialog sudo

Ini menggunakan whiptail, yang dapat Anda instal jika Anda belum memilikinya:

sudo apt-get install whiptail
Michael Hampton
sumber
1
Mengapa Anda menyimpan kata sandi dalam suatu variabel?
heemayl
10
Jangan panggil exec echo [PASSWORD]! Ini akan memunculkan proses dengan kata sandi pada baris perintah yang dapat dilihat oleh pengguna mana pun. Baik menggunakan perintah built-in echo(memaksa versi built-in dengan builtin echo) atau bashism <<<(seperti :) sudo ... <<< "$pass"; Sh dan kerang lain memiliki Dokumen Di Sini untuk kasus ini. Juga, kutip kata sandi kalau-kalau mengandung karakter khusus.
David Foerster
Atau, masukkan whiptailperintah ke skrip terpisah dan gunakan sesuatu seperti SUDO_ASKPASS=/path/to/askpass-with-whiptail.sh sudo -A -p "My password prompt" -- "$0" "$@"untuk sudoberurusan dengan prompt kata sandi kustom.
David Foerster
@ DavidFoerster Itu bisa berhasil, tetapi Anda perlu dua skrip, atau Anda menulis skrip askpass ke file sementara dan meneruskannya ke sudo.
Michael Hampton
Ok, tetapi orang lain sudah mencatat bahwa tidak diinginkan untuk mengirimkan kata sandi ke variabel. Cara id mendekati ini adalah dengan melewatkan keluaran dialog ke bernama pipe seperti yang saya tunjukkan di sini askubuntu.com/a/704643/295286
Sergiy Kolodyazhnyy
11

Jawaban blade19899 memang jalan yang harus ditempuh, namun orang juga bisa memanggil sudo bashshebang:

#!/usr/bin/sudo bash
# ...

Peringatan yang jelas adalah ini akan berfungsi hanya selama skrip dipanggil dengan ./scriptdan akan gagal segera setelah skrip dipanggil dengan bash script.

kos
sumber
5
Ini adalah salah satu alasan mengapa Anda tidak boleh mengetik bash scriptpada baris perintah untuk memanggil skrip. Jika skrip menentukan apa pun selain bashdalam #!baris, maka memohon dengan bash scriptitu akan gagal. Jika saya mencoba memanggil skrip python menggunakannya bash script.pyjuga akan gagal.
kasperd
1
Anda dapat menjalankannya dengan perl script. Perl, dalam upaya untuk menjadi benar-benar baik, memeriksa garis shebang, dan jika tidak menjalankan perl, ia menjalankan program yang benar.
tbodt
Ini buruk karena menjalankan setiap perintah dalam skrip dengan sudo. Lebih baik mengisolasi beberapa perintah yang benar-benar membutuhkan sudo dan menambahkannya jika perlu. Jangan sertakan evaluasi fungsi dalam panggilan sudo ini; mereka harus sejelas dan seminimal mungkin.
Douglas Diadakan
@DouglasHeld Sementara saya mungkin setuju dengan itu, inilah pertanyaan yang ditanyakan: "Bagaimana saya bisa" menanamkan "permintaan ke pkexec atau sudo untuk menjalankan seluruh skrip dengan privilege root?". Cukup yakin akan ada kasus penggunaan di mana bisa melakukan ini akan bermanfaat.
kos
6

Saya kata pengantar perintah dalam skrip yang membutuhkan akses root sudo- jika pengguna belum mendapatkan izin, skrip meminta kata sandi pada saat itu.

contoh

#!/bin/sh 
mem=$(free  | awk '/Mem:/ {print $4}')
swap=$(free | awk '/Swap:/ {print $3}')

if [ $mem -lt $swap ]; then
    echo "ERROR: not enough RAM to write swap back, nothing done" >&2
    exit 1
fi

sudo swapoff -a && 
sudo swapon -a

Script ini dapat dijalankan sebagai sudo <scriptname>atau sebagai <scriptname>. Dalam kedua kasus itu akan meminta kata sandi, hanya sekali.

Charles Green
sumber
2
Masalahnya di sini adalah bahwa mungkin ada beberapa perintah yang membutuhkan akses root, yang berarti memanggil sudo25 perintah yang berbeda berlebihan - lebih mudah untuk memanggil sudo sekali. Namun di sini, alasan skrip Anda memanggil sudo hanya satu kali adalah karena sudo memiliki waktu habis 15 menit - perintah yang membutuhkan waktu lebih lama dari itu perlu disusun ulang. Cara Anda bekerja dengan baik. . . bukan cara saya membutuhkannya untuk bekerja.
Sergiy Kolodyazhnyy
@Serg Untuk skrip kecil, cara saya cepat dan mudah - Saya benar-benar bukan programmer yang elegan!
Charles Green
Anda adalah programmer terbaik yang memposting di halaman ini. Anda menggunakan sudo persis seperti yang seharusnya digunakan - hanya jika diperlukan dan dengan hasil yang sangat jelas diharapkan.
Douglas Diadakan
4

Tampaknya tidak ada orang lain yang membahas masalah nyata di sini. Menempatkan di sudodalam skrip Anda yang kemudian Anda bagikan mempromosikan kebiasaan pengguna yang buruk . (Saya berasumsi Anda mendistribusikannya karena Anda menyebut "dari sudut pandang pengguna.")

Yang benar adalah bahwa ada pedoman dalam menggunakan aplikasi dan skrip yang mirip dengan prinsip keamanan di perbankan: Jangan pernah memberikan informasi pribadi Anda kepada seseorang yang memanggil Anda dan mengatakan mereka memanggil "dari bank Anda" , dan yang ada untuk alasan yang sama.

Aturan untuk aplikasi adalah:

Jangan pernah mengetik kata sandi Anda ketika diminta kecuali Anda yakin apa yang sedang dilakukan dengannya. Ini berlaku tiga kali lipat bagi siapa pun yang memiliki sudoakses.

Jika Anda mengetik kata sandi karena Anda menjalankan sudoperintah, bagus. Jika Anda mengetiknya karena Anda menjalankan perintah SSH, baiklah. Jika Anda mengetiknya saat Anda masuk ke komputer, tentu saja bagus.

Jika Anda hanya menjalankan skrip asing atau yang dapat dieksekusi dan memasukkan kata sandi Anda ketika diminta, Anda tidak tahu apa yang dilakukan skrip itu. Bisa jadi menyimpannya dalam file temp di plaintext, untuk semua yang Anda tahu, dan bahkan mungkin gagal untuk membersihkan sendiri.

Jelas ada kekhawatiran terpisah dan tambahan tentang menjalankan seperangkat perintah yang tidak diketahui root, tetapi yang saya bicarakan di sini adalah menjaga keamanan kata sandi itu sendiri . Bahkan dengan anggapan aplikasi / skrip tidak berbahaya, Anda masih ingin kata sandi Anda ditangani dengan aman untuk mencegah aplikasi lain menggunakannya dan menggunakannya dengan jahat.

Jadi, tanggapan pribadi saya terhadap hal ini adalah, hal terbaik untuk dimasukkan ke dalam naskah Anda jika perlu di-root, adalah:

#!/bin/bash
[ "$UID" -eq 0 ] || { echo "This script must be run as root."; exit 1;}

# do privileged stuff, etc.
Wildcard
sumber
Meskipun saya sepenuhnya setuju dengan Anda, pengguna yang menjalankan sesuatu tanpa mengetahui apa fungsinya sudo script_namesama rapuhnya, sama saja. Mungkin ide ini mempromosikan kebiasaan buruk - saya tidak akan mengatakan apa-apa tentang itu. Tetapi kuncinya adalah mengetahui apa yang dilakukan suatu program, dan itulah tanggung jawab pengguna. Itulah gagasan di balik perangkat lunak open-source. Adapun skrip saya sendiri, baik. . . skrip adalah teks biasa - pengguna dapat membacanya jika mereka ingin tahu fungsinya
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy mirip, tetapi jika Anda mengetikkan kata sandi langsung ke dalam skrip, sebenarnya lebih buruk. Skrip yang dijalankan dengan sudo masih tidak tahu kata sandi Anda.
Wildcard
1

Saya melakukannya dengan cara ini:

echo -n "Enter password for sudo rights: "
read -s pass

echo $pass | sudo -S [your command here]
Ditimbang
sumber
4
Setidaknya kutip variabel Anda.
muru
Dan mengutip variabel Anda mungkin bahkan tidak membantu jika kata sandi Anda dimulai dengan tanda hubung.
Wildcard