Làm thế nào một kịch bản có thể kiểm tra nếu nó đang được chạy như root?


104

Tôi đang viết một tập lệnh bash đơn giản, nhưng tôi cần nó để kiểm tra xem nó có được chạy dưới quyền root hay không. Tôi biết có lẽ có một cách rất đơn giản để làm điều đó, nhưng tôi không biết làm thế nào.


Nói rõ hơn: Cách đơn giản để viết tập lệnh foo.sh , sao cho lệnh ./foo.shxuất ra 0và lệnh sudo ./foo.shxuất ra 1?

Câu trả lời:


148
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root" 
   exit 1
fi

7
Tôi chấp nhận một nguyên nhân này (sau một số thử nghiệm) bằng cách sử dụng biến hệ thống EUID hóa ra nhanh hơn (khoảng 100 lần) so với chạy lệnh (id -u), nhưng tất cả các câu trả lời đều hoạt động tốt.
Malabarba

18
Ngoài ra, $UID$EUIDlà bashism. Chỉ các shell tuân thủ POSIX không có các biến đó và bạn cần sử dụng id(1)thay thế.
David Foerster

3
trong tập lệnh bash, bạn có thể sử dụng if ((EUID)); then, xem bình luận của @ geirha
jfs

7
@Andrew: Các biến được thay thế trước khi chúng được truyền tới sudo. Nếu bạn chạy sudo sh -c 'echo $EUID'bạn sẽ thấy kết quả mong đợi của bạn.
M. Dudley

6
@ Andrew - Tôi biết tôi là cách cuối ở đây, nhưng cho hậu thế: $EUIDlà một Bashism (như đã đề cập ở trên bởi @DavidFoerster), và bạn /bin/shrất có thể là một liên kết đến /bin/dash, không phải /bin/bash. sudo bash -c 'echo $EUID'sẽ mang lại kết quả mong đợi.
Adrian Günter

118

Người dùng root không phải đặt tên là "root". whoamitrả về tên người dùng đầu tiên với ID người dùng 0. $USERchứa tên của người dùng đã đăng nhập, có thể có ID người dùng 0, nhưng có một tên khác.

Chương trình đáng tin cậy duy nhất để kiểm tra xem tài khoản đã đăng nhập bằng root hay chưa:

id -u

Tôi sử dụng -ucho ID người dùng hiệu quả , không phải -rcho ID người dùng thực . Quyền được xác định bởi ID người dùng hiệu quả , không phải ID thực .

Xét nghiệm

/etc/passwdchứa các tên người dùng sau với ID người dùng 0theo thứ tự đã cho:

rootx
root2

Đăng nhập như là root2, cho kết quả tiếp theo:

  • whoami: rootx
  • echo $USER: root2(điều này trả về một chuỗi rỗng nếu chương trình được bắt đầu trong một môi trường trống, vd env -i sh -c 'echo $USER')
  • id -u: 0 Như bạn có thể thấy, các chương trình khác đã thất bại trong kiểm tra này, chỉ id -uđược thông qua.

Kịch bản cập nhật sẽ trông như thế này:

#!/bin/bash
if ! [ $(id -u) = 0 ]; then
   echo "I am not root!"
   exit 1
fi

5
Bạn không cần phải id -utrong bash askubuntu.com/questions/30148/...
JFS

5
Tôi luôn cố gắng duy trì tuân thủ POSIX nhất có thể, sử dụng sh( dash) làm thông dịch viên thay vì bash. Nhưng bắn tốt, cứu một ngã ba khác :)
Lekensteyn

Sau khi ra ngoài một lúc, tôi quay lại và nhìn. Phương pháp của Lekensteyn thực sự có vẻ tốt hơn. Câu trả lời của ông bây giờ là câu trả lời mới được chấp nhận. +1 cho bạn, Lekensteyn, đặc biệt. để nhận được huy hiệu khó có được từ câu hỏi này;)
Thomas Ward

Cảm ơn vì đã chờ đợi câu trả lời của tôi rất lâu
Lekensteyn

3
Tôi đã thấy các phiên bản ngắn hơn , [ -w / ]. Ý tưởng vẫn như cũ. Lưu ý: trong một số chroots nhất định, [ -w /etc/shadow ]sẽ thất bại vì /etc/shadowkhông tồn tại, do đó phương pháp tiếp cận /được ưu tiên. Một cách tốt hơn sẽ kiểm tra nhu cầu thực tế cho quyền root. Nếu tập lệnh cần ghi vào /etc/someconfig, chỉ cần kiểm tra xem tập tin đó có thể ghi được HOẶC tập tin không tồn tại và /etccó thể ghi được không.
Lekensteyn

30

Như @Lekensteyn nói rằng bạn nên sử dụng ID người dùng hiệu quả. Bạn không cần phải gọi id -utrong bash:

#!/bin/bash

if [[ $EUID -ne 0 ]]; then
   echo "You must be root to do this." 1>&2
   exit 100
fi

Đề xuất của @ geirha từ các ý kiến ​​sử dụng đánh giá số học:

#!/bin/bash

if (( EUID != 0 )); then
   echo "You must be root to do this." 1>&2
   exit 100
fi

7
Nói chung, người ta nên sử dụng ((..))để kiểm tra số và [[..]]kiểm tra chuỗi và tệp, vì vậy tôi sẽ if (( EUID != 0 )); thenthay vào đó, hoặc chỉif ((EUID)); then
geirha

@geirha: Tôi đã thêm đề xuất của bạn.
jfs

2
EUIDnên trở thành $EUID. Thay vì sử dụng (( $EUID != 0 )), sử dụng [ $EUID != 0 ]. Nó sẽ làm việc với dashquá.
Lekensteyn

2
@Lekensteyn: EUIDhoạt động tốt. Câu hỏi được gắn thẻ bashkhông dash. Lệnh env -i sh -c '[ $EUID != 0 ]'thất bại, nhưng env -i bash -c '(( EUID != 0 ))'hoạt động. btw, dashkhông hoạt động đối với một số ký tự không phải ascii trên Ubuntu stackoverflow.com/questions/5160125/ Nhật Bản là năm 2011 và có những người sử dụng các ngôn ngữ khác.
jfs

Sau khi nhìn lại điều này trong khi chán kinh khủng, và thử nghiệm, tôi sẽ sử dụng phương pháp này như được liệt kê ở đây với những $EUIDthứ từ thời điểm này trở đi. Tôi đã thay đổi câu trả lời được chấp nhận như là kết quả.
Thomas Ward

20

Bạn có thể thực hiện điều này bằng cách sử dụng whoamilệnh, trả về người dùng hiện tại:

#!/bin/bash

if [ `whoami` != 'root' ]
  then
    echo "You must be root to do this."
    exit
fi

...

Chạy ở trên sẽ in You must be root to do this.nếu người dùng hiện tại không root.


Lưu ý: một sự thay thế trong một số trường hợp là chỉ cần kiểm tra $USERbiến:

if [ $USER != 'root' ]

Tôi sẽ xem mã, xem nó không làm cho kịch bản bị lỗi hay sao. Nếu nó hoạt động, tôi sẽ chấp nhận câu trả lời của bạn :)
Thomas Ward

4
@George Edison: Tôi khuyên bạn không nên sử dụng $USER, đặc biệt là theo cách này. $USERđược thiết lập bởi shell đăng nhập, nó không cần truyền đến chương trình ( env -i sh -c 'echo $USER'). Theo cách đó, $USERtrống và một lỗi cú pháp xảy ra.
Lekensteyn

1
@Lekensteyn Không chỉ được $USERthiết lập bởi shell, nó cũng là một thứ dễ bị giả mạo. Whoami sẽ trả lại người dùng thực tế.
Paul de Vrieze

2
@PauldeVrieze Điểm đánh lừa kiểm tra đó là gì?
htorque

1
@andrews Something: $USERđược diễn giải bởi shell của bạn, ví dụ của bạn phải sudo sh -c 'echo $USER'có ý nghĩa. @George: nó đưa ra giả định sai whoamisẽ luôn quay trở lại rootvới UID 0.
sam hocevar

11

Cân nhắc hiệu quả, trước tiên, bạn có thể kiểm tra EUIDbiến môi trường và sau đó, nếu nó không tồn tại, hãy gọi idlệnh tiêu chuẩn :

if ((${EUID:-0} || "$(id -u)")); then
  echo You are not root.
else
  echo Hello, root.
fi

Bằng cách này, do phím tắt OR , bạn tránh gọi lệnh hệ thống, ưu tiên truy vấn của biến trong bộ nhớ.

Tái sử dụng mã:

function amIRoot() {
  ! ((${EUID:-0} || "$(id -u)"))
}

Tôi e rằng bạn đã không điểm chuẩn nó, tôi cũng có và điều này mất cùng thời gian với id -u. Xem tập lệnh băng ghế dự bị cùng với kết quả bên dưới tại đây: pastebin.com/srC3LWQy
LinuxSecurityFreak


2

Một cách đơn giản để làm cho tập lệnh chỉ có thể chạy được bằng root là bắt đầu tập lệnh với dòng:
#!/bin/su root


1
Đừng làm điều này. Nó cố gắng đăng nhập trực tiếp với quyền root, trong khi sudo có thể được yêu cầu trên nhiều hệ thống vì trước đây bị cấm. Hơn nữa, shebang nhằm đảm bảo tập lệnh của bạn chạy trong tập lệnh được thiết kế, trong khi phương thức của bạn sẽ khiến tập lệnh chạy trong trình bao mặc định của root, không thể dự đoán được nếu tập lệnh được chạy bởi bất kỳ ai khác ngoài tác giả. Do đó, việc sử dụng shebang để nâng cao các đặc quyền của tập lệnh sẽ phá vỡ nghiêm trọng tính di động của nó và dẫn đến lỗi trên nhiều hệ thống. (su: Lỗi xác thực)
StarCrashr


1

Đoạn trích này sẽ:

  • Kiểm tra các phiên khác nhau
  • đề nghị sử dụng sudo !!
  • và trả lại lỗi
if ["$ (whoami & 2> / dev / null)"! = "root"] && ["$ (id -un & 2> / dev / null)"! = "root"]
      sau đó
      echo "Bạn phải root để chạy tập lệnh này!"
      tiếng vang "sử dụng 'sudo !!'"
      thoát 1
fi

1

Câu trả lời này chỉ là để lưu một ý tưởng có thể hữu ích cho một số bạn. Nếu bạn cần tập lệnh chạy từ GUI trên máy tính để bàn và yêu cầu quyền root, hãy thử theo cách này:

#!/bin/bash
if ! [ $(id -u) = 0 ]; then
   gksudo -w $0 $@
   exit
fi

#here go superuser commands, e.g. (switch intel cpu into powersave mode):
echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo
cpupower frequency-set -g powersave

Bằng cách này, bạn sẽ nhận được cửa sổ hộp thoại đẹp yêu cầu bạn nhập mật khẩu người dùng root. Giống như với sudo dòng lệnh.

gksudothể không có sẵn trong hệ thống của bạn sau đó cài đặt nó với sudo apt-get install gksu.


0

Mã này hoạt động theo cả Bash và stock Bourne sh (được thử nghiệm theo FreeBSD) không xác định EUID. Nếu EUID tồn tại, giá trị của nó được trả về, nếu không lệnh 'id' sẽ được chạy. Nó ngắn hơn một chút so với ví dụ "hoặc" ở trên, vì nó sử dụng lớp vỏ tích hợp ": -".

Root trong sh:

# echo $EUID

# euid=${EUID:-`id -u`}
# echo $euid
0

In bash:
[chaapala@tenfwd2 ese]$ euid=${EUID:-`id -u`}
[chaapala@tenfwd2 ese]$ echo $euid
10260
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.