Mengapa "sudo su" dalam skrip shell tidak menjalankan sisa skrip sebagai root?

36

Contoh skrip bisa seperti di bawah ini:

#!/bin/bash
sudo su
ls /root

Saat menggunakan ./test.shsebagai pengguna normal, alih-alih jalankan lssebagai pengguna super dan keluar, ia beralih ke root; dan ketika saya logout, dijalankan ls /rootsebagai pengguna normal.

Adakah yang bisa memberi tahu saya tentang mekanisme itu?

Hongxu Chen
sumber
13
sudo sumembuat mataku sakit.
gelraen
Ini digunakan karena orang tidak mengenal sudo dengan cukup baik, sehingga mereka membutuhkan cara untuk menjalankan su pada sistem di mana root diamankan dengan kata sandi yang sengaja rusak. Tapi ya sudo "redundifikasi" penggunaan su.
Johan
1
Tidak bisakah Anda menggunakan saja sudo -s?
Joe Z.
@ Johan, saya sering menggunakan sudo sukarena saya lebih terbiasa dengan pilihan sudaripada saya dari mereka sudo. Saya tahu opsi sudo dengan cukup baik, tapi saya bisa mengetikkan su lebih cepat. Tapi ya saya kira itu berarti saya tidak cukup tahu sudo.
user606723
1
Saya baru saja memeriksa halaman manual sudo. Tampaknya sudo -imirip dengan su -saat sudo -sberoperasi seperti su(tanpa tanda hubung)
Johan

Jawaban:

49

Perintah dalam sebuah skrip mengeksekusi satu per satu, secara independen. Script itu sendiri sebagai induk dari semua perintah dalam skrip, adalah proses independen lainnya dan perintah su tidak dan tidak dapat mengubahnya menjadi root: perintah su menciptakan proses baru dengan hak akses root.

Setelah perintah su selesai, proses induk, masih berjalan sebagai pengguna yang sama, akan mengeksekusi sisa skrip.

Yang ingin Anda lakukan adalah menulis skrip wrapper. Perintah istimewa masuk ke skrip utama, misalnya~/main.sh

#!/bin/sh
ls /root

Skrip wrapper memanggil skrip utama dengan izin root, seperti ini

#!/bin/sh
su -c ~/main.sh root

Untuk meluncurkan proses ini, Anda menjalankan pembungkus, yang pada gilirannya meluncurkan skrip utama setelah mengalihkan pengguna ke pengguna root.

Teknik pembungkus ini dapat digunakan untuk mengubah skrip menjadi pembungkus di sekitarnya. Pada dasarnya periksa untuk melihat apakah itu berjalan sebagai root, jika tidak, gunakan "su" untuk meluncurkan kembali sendiri.

$ 0 adalah cara praktis untuk membuat skrip merujuk pada dirinya sendiri, dan perintah whoami dapat memberi tahu kita siapa kita (apakah kita root?)

Jadi skrip utama dengan pembungkus bawaan menjadi

#!/bin/sh
[ `whoami` = root ] || exec su -c $0 root
ls /root

Perhatikan penggunaan exec. Ini berarti "ganti program ini dengan", yang secara efektif mengakhiri pelaksanaannya dan memulai program baru, diluncurkan oleh su, dengan root, untuk berjalan dari atas. Instance pengganti adalah "root" sehingga tidak menjalankan sisi kanan ||

Johan
sumber
1
fwiw, tambahan untuk poin ini. Jika saya menulis skrip seperti itu saya hanya akan melakukan pernyataan if di awal yang memeriksa $ EUID dan jika bukan nol sudo itu sendiri dan keluar, kalau tidak lanjutkan dengan eksekusi skrip.
Bratchley
Setuju, dan saya akan memperbarui jawaban untuk menjelaskan ini.
Johan
2
Mungkin ini sedikit kuno tetapi saya suka jalur absolut untuk setiap eksekusi sehingga seseorang tidak dapat mengubah script ~ / main.sh menjadi sesuatu yang jahat. Menyerang bagian USER dari skrip
artifex
2
Anda mungkin juga ingin menangkap argumen yang diteruskan dengan memasukkan referensi ke $ *
Bratchley
@ JoelDavis saya selalu menemukan "bagaimana jika ada spasi karakter dalam argumen". Saya belum pernah menemukan solusi yang memuaskan. Setelah saya menulis sebuah skrip yang mengeluarkan argumennya menjadi file temp, satu argumen per baris, dan kemudian menyebut apa pun yang diperlukan dan meneruskan ke skrip akhir itu argumen file apa yang akan dibaca untuk menemukan argumen aslinya.
Johan
20

Gunakan skrip berikut dalam.

sudo su <<HERE
ls /root
HERE

Kode antara blok HERE akan dijalankan sebagai root.

Ankit
sumber
6
sudo sumemanggil dua program. Gunakan sudo -s <<HEREDOCatau su user <<HEREDOC... Batas bodoh 5 menit.
Johan
6

Tanpa argumen lebih lanjut suakan menjalankan shell login untuk root. Itulah yang dilakukan baris pertama skrip Anda. Ketika Anda keluar, login shell menutup, kembali su dan script Anda terus eksekusi, yaitu dengan baris kedua: ls /root. Saya pikir Anda bisa sudo ls /rootmelakukan apa yang Anda inginkan.

Bananguin
sumber
Ya, saya tahu saya bisa melakukan ini ls, tetapi ini hanya contoh. Sebenarnya saya perlu melakukan lebih banyak hal dengan privilege root :-) Jadi saya lebih suka jawaban @ Ankit.
Hongxu Chen
1

Setelah Anda sudo sumenjalankan proses baru dengan efektif userid (euid=EUID)forked super user, maka kami memiliki bash baru yang berjalan di id proses yang berbeda (pid=PID)terkait dengan terminal yang sama (tname=TTY).

Penjelasan

Misalkan setelah menembak ps -A | grep bashAnda memiliki 21460 pts/2 00:00:00 bashsebagai output. Sekarang, ketika Anda menjalankan ./test.shkedua perintah sudo sudan ls /rootakan spooled ke PID 21460. Setelah eksekusi ketika Anda rootsebagai pengguna aktif menekan ps -A | grep bashlagi, Anda akan melihat bash baru berjalan PID say, 21570. Keluar dari root bashakan membunuh bash baru bercabang kembali ke user's bashdan karenanya menjalankan perintah spooled ls /rootsebelum melepaskan prompt.

sundeep
sumber
Jika menggunakan su atau sudo "persisten" di bash (atau di mana pun) itu akan menciptakan lebih banyak masalah daripada yang dipecahkan. Anda perlu melakukan seminimal mungkin sebagai root untuk keselamatan dan keamanan. Poin utama memiliki su dan sudo (selain keamanan!) Adalah membuat Anda berpikir dengan hati-hati tentang apa yang perlu di-root privilege.
Joe