สคริปต์จะตรวจสอบได้อย่างไรว่ามันถูกเรียกใช้ในฐานะรูท


104

ฉันกำลังเขียนสคริปต์ทุบตีง่าย ๆ แต่ฉันต้องการให้ตรวจสอบว่ามันถูกเรียกใช้เป็น root หรือไม่ ฉันรู้ว่าอาจเป็นวิธีที่ง่ายมากในการทำเช่นนั้น แต่ฉันไม่รู้ว่าทำอย่างไร

เพียงเพื่อจะชัดเจน:
อะไรวิธีง่ายๆในการเขียนสคริปต์foo.shเพื่อให้คำสั่ง./foo.shผล0และคำสั่งsudo ./foo.shผล1?

คำตอบ:


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

7
ฉันยอมรับสาเหตุนี้ (หลังจากการทดสอบบางอย่าง) โดยใช้ตัวแปรระบบ EUID กลายเป็น (ประมาณ 100 ครั้ง) เร็วกว่าเรียกใช้คำสั่ง (id -u) แต่คำตอบทั้งหมดใช้ได้ผลดีมาก
Malabarba

18
นอกจากนี้$UIDและ$EUIDเป็น bashisms เชลล์ที่เข้ากันได้ POSIX ส่วนใหญ่ไม่มีตัวแปรเหล่านั้นและคุณจำเป็นต้องใช้id(1)แทน
David Foerster

3
ในสคริปต์ทุบตีคุณสามารถใช้if ((EUID)); thenดูความคิดเห็น @ geirha ของ
jfs

7
@Andrew: sudoตัวแปรที่ถูกเปลี่ยนตัวก่อนที่พวกเขาจะถูกส่งผ่านไปยัง หากคุณเรียกใช้sudo sh -c 'echo $EUID'คุณจะเห็นผลลัพธ์ที่คาดหวัง
M. Dudley

6
@Andrew - ฉันรู้ว่าฉันทางปลายที่นี่ แต่สำหรับลูกหลาน: $EUIDเป็น Bashism (ตามที่กล่าวไว้ข้างต้นโดย @DavidFoerster) และคุณ/bin/shมีแนวโน้มที่เชื่อมโยงไปยังไม่/bin/dash จะให้ผลลัพธ์ที่คาดหวัง /bin/bashsudo bash -c 'echo $EUID'
Adrian Günter

118

ผู้ใช้รูทไม่จำเป็นต้องตั้งชื่อ "root" ผลตอบแทนที่ได้ชื่อผู้ใช้ครั้งแรกกับรหัสผู้ใช้whoami มีชื่อของผู้ใช้ที่ล็อกอินซึ่งสามารถมี ID ผู้ใช้แต่มีชื่ออื่น0$USER0

โปรแกรมเดียวที่เชื่อถือได้เพื่อตรวจสอบว่าบัญชีนั้นเข้าสู่ระบบในฐานะรูทหรือไม่:

id -u

ฉันใช้-uสำหรับรหัสผู้ใช้ที่มีประสิทธิภาพไม่ใช่-rสำหรับID ผู้ใช้จริง สิทธิ์ที่กำหนดโดยมีประสิทธิภาพ ID ผู้ใช้ไม่ได้จริงอย่างใดอย่างหนึ่ง

การทดสอบ

/etc/passwdมีชื่อผู้ใช้ต่อไปนี้พร้อม ID ผู้ใช้0ตามลำดับที่กำหนด:

rootx
root2

เข้าสู่ระบบในฐานะroot2ให้ผลต่อไป:

  • whoami: rootx
  • echo $USER: root2(ส่งคืนสตริงว่างถ้าโปรแกรมเริ่มต้นในสภาพแวดล้อมที่ว่างเช่นenv -i sh -c 'echo $USER')
  • id -u: 0 อย่างที่คุณเห็นโปรแกรมอื่นล้มเหลวในการตรวจสอบนี้id -uผ่านไปแล้วเท่านั้น

สคริปต์ที่อัปเดตจะมีลักษณะดังนี้:

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

5
คุณไม่จำเป็นต้องid -uทุบตีaskubuntu.com/questions/30148/ …
jfs

5
ฉันมักจะพยายามที่จะอยู่เป็นตาม POSIX ที่เป็นไปได้โดยใช้sh( dash) bashเป็นล่ามแทน แต่ยิงดีช่วยประหยัดส้อมอีก :)
Lekensteyn

หลังจากที่เย็นชาไปครู่หนึ่งฉันกลับมาแล้วดู วิธีการของ Lekensteyn นั้นดูเหมือนจะดีกว่า คำตอบของเขาคือคำตอบที่ยอมรับใหม่ +1 ให้กับคุณ Lekensteyn, esp. สำหรับการลบเครื่องหมายที่ยากต่อการออกจากคำถามนี้;)
โธมัสวอร์ด

ขอบคุณที่รอมานานสำหรับการตอบคำถามของฉัน: DI ได้รับ Gold Populist Badge และ Bronze คำตอบที่ดีสำหรับคำตอบนี้ :) ฉันสงสัยว่าคำถามนี้ได้รับความนิยมถึง 345 ครั้งในหนึ่งวัน!
Lekensteyn

3
ฉันเห็นเวอร์ชันที่สั้นกว่า, [ -w / ]. ความคิดยังคงเหมือนเดิม หมายเหตุ: ใน chroots บางอย่าง[ -w /etc/shadow ]จะล้มเหลวเพราะ/etc/shadowเป็นที่ไม่มีอยู่จริงดังนั้นวิธีการที่มี/เป็นที่ต้องการ วิธีที่ดีกว่าจะตรวจสอบความต้องการที่แท้จริงของสิทธิ์การรูท หากสคริปต์ต้องการเขียนให้/etc/someconfigตรวจสอบว่าไฟล์นั้นสามารถเขียนได้หรือไฟล์นั้นไม่มีอยู่และ/etcสามารถเขียนได้
Lekensteyn

30

ดังที่@Lekensteyn กล่าวว่าคุณควรใช้ ID ผู้ใช้ที่มีประสิทธิภาพ คุณไม่จำเป็นต้องโทรid -uด้วยการทุบตี:

#!/bin/bash

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

ข้อเสนอแนะของ @ geirha จากความคิดเห็นที่ใช้การประเมินผลเลขคณิต:

#!/bin/bash

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

7
โดยทั่วไปแล้วควรใช้((..))สำหรับการทดสอบตัวเลขและ[[..]]สำหรับการทดสอบสตริงและไฟล์ดังนั้นฉันจะทำif (( EUID != 0 )); thenแทนหรือเพียงif ((EUID)); then
geirha

@geirha: ฉันได้เพิ่มข้อเสนอแนะของคุณ
jfs

2
EUID$EUIDควรจะเป็น แทนการใช้ใช้(( $EUID != 0 )) [ $EUID != 0 ]มันจะทำงานด้วยdashเช่นกัน
Lekensteyn

2
@Lekensteyn: EUIDทำงานได้ดี คำถามคือแท็กไม่ได้bash dashคำสั่งenv -i sh -c '[ $EUID != 0 ]'ล้มเหลว แต่ใช้env -i bash -c '(( EUID != 0 ))'งานได้ btw dashไม่สามารถใช้กับอักขระที่ไม่ใช่ ascii บางตัวใน Ubuntu stackoverflow.com/questions/5160125/…เป็น 2011 และมีคนที่ใช้ภาษาอื่น
jfs

หลังจากมองย้อนกลับไปในขณะที่กำลังเบื่ออย่างน่ากลัวและการทดสอบฉันจะใช้วิธีนี้ตามที่ระบุไว้ที่นี่พร้อมกับ$EUIDสิ่งต่าง ๆ จากจุดนี้ไปข้างหน้า ฉันเปลี่ยนผลตอบรับที่ยอมรับแล้ว
โธมัสวอร์ด

20

คุณสามารถทำได้โดยใช้whoamiคำสั่งซึ่งส่งกลับผู้ใช้ปัจจุบัน:

#!/bin/bash

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

...

เล่นดังกล่าวข้างต้นจะพิมพ์หากผู้ใช้ปัจจุบันไม่ได้You must be root to do this.root


หมายเหตุ:ทางเลือกในบางกรณีคือเพียงตรวจสอบ$USERตัวแปร:

if [ $USER != 'root' ]

ฉันจะดูรหัสดูว่ามันไม่ทำให้สคริปต์ล้มเหลวหรือบางอย่าง หากได้ผลฉันจะยอมรับคำตอบของคุณ :)
โธมัสวอร์ด

4
@ George Edison: ฉันไม่แนะนำให้ใช้$USERโดยเฉพาะในลักษณะนี้ $USERถูกตั้งค่าโดยล็อกอินเชลล์ไม่จำเป็นต้องเผยแพร่ไปยังโปรแกรม ( env -i sh -c 'echo $USER') ด้วยวิธี$USERนี้จะว่างเปล่าและเกิดข้อผิดพลาดทางไวยากรณ์
Lekensteyn

1
@Lekensteyn ไม่เพียง แต่ถูก$USERกำหนดโดยเชลล์ แต่ยังเป็นสิ่งที่ง่ายต่อการปลอมแปลง Whoami จะส่งคืนผู้ใช้จริง
Paul de Vrieze

2
@ PauldeVrieze จุดประสงค์ของการหลอกลวงคืออะไร?
htorque

1
@ andrewsomething: $USERตีความโดยเชลล์ของคุณตัวอย่างของคุณควรsudo sh -c 'echo $USER'มีความหมาย @ George: มันทำให้สมมติฐานผิดที่whoamiมักจะกลับมาrootสำหรับโพสต์ 0.
sam hocevar

11

เมื่อพิจารณาถึงประสิทธิภาพคุณอาจทดสอบEUIDตัวแปรสภาพแวดล้อมก่อนจากนั้นหากไม่มีอยู่ให้เรียกidคำสั่งมาตรฐาน:

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

ด้วยวิธีนี้หรือทางลัดคุณหลีกเลี่ยงการโทรคำสั่งระบบก่อนที่จะสอบถามแบบสอบถามของตัวแปรในหน่วยความจำ

การใช้รหัสซ้ำ:

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

ฉันเกรงว่าคุณจะไม่ได้ทำการเปรียบเทียบมันดีฉันมีและมันใช้เวลาเหมือนid -uกัน ดูสคริปต์มาตรฐานพร้อมกับผลลัพธ์ด้านล่างได้ที่นี่: pastebin.com/srC3LWQy
LinuxSecurityFreak


2

วิธีง่าย ๆ ในการทำให้สคริปต์ที่รันได้โดยรูทคือการเริ่มต้นสคริปต์ด้วยบรรทัด:
#!/bin/su root


1
อย่าทำอย่างนี้ มันพยายามที่จะเข้าสู่ระบบโดยตรงในขณะที่รูทในขณะที่ sudo อาจจำเป็นต้องใช้ในหลาย ๆ ระบบเพราะอดีตเป็นสิ่งต้องห้าม นอกจากนี้ Shebang ยังมีวัตถุประสงค์เพื่อให้แน่ใจว่าสคริปต์ของคุณทำงานในสคริปต์ที่ออกแบบมาในขณะที่วิธีการของคุณจะทำให้สคริปต์ทำงานในเชลล์เริ่มต้นของรูทซึ่งไม่สามารถคาดการณ์ได้ว่าสคริปต์นั้นรันโดยผู้อื่นที่ไม่ใช่ผู้เขียน ดังนั้นการใช้ shebang เพื่อยกระดับสิทธิ์ของสคริปต์จะทำให้การพกพาของเซิร์ฟเวอร์เสียหายอย่างรุนแรงและส่งผลให้เกิดข้อผิดพลาดในหลาย ๆ ระบบ (su: การตรวจสอบสิทธิ์ล้มเหลว)
StarCrashr


1

ตัวอย่างนี้จะ:

  • ตรวจสอบเซสชันต่าง ๆ
  • แนะนำให้ใช้ sudo !!
  • และส่งคืนข้อผิดพลาด
if ["$ (whoami & 2> / dev / null)"! = "root"] && ["$ (id -un & 2> / dev / null)"! = "root"]
      แล้วก็
      echo "คุณต้องรูทเพื่อใช้งานสคริปต์นี้!"
      echo "ใช้ 'sudo !!'"
      ทางออก 1
Fi

1

คำตอบนี้เป็นเพียงการบันทึกความคิดด้วยอาจเป็นประโยชน์สำหรับคุณบางคน หากคุณต้องการสคริปต์ที่รันจาก GUI บนเดสก์ท็อปและต้องการสิทธิ์รูทลองด้วยวิธีนี้:

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

ด้วยวิธีนี้คุณจะได้รับหน้าต่างโต้ตอบที่ดีเพื่อขอรหัสผ่านผู้ใช้รูท เช่นเดียวกับ sudo บรรทัดคำสั่ง

อาจไม่สามารถใช้ได้ในระบบของคุณแล้วติดตั้งด้วยgksudosudo apt-get install gksu


0

รหัสนี้ทำงานภายใต้ทั้ง Bash และหุ้น Bourne sh (ทดสอบภายใต้ FreeBSD) ที่ไม่ได้กำหนด EUID หาก EUID มีอยู่ค่าจะถูกส่งคืนมิฉะนั้นคำสั่ง 'id' จะถูกเรียกใช้ มันสั้นกว่าตัวอย่าง "หรือ" ด้านบนเนื่องจากใช้เชลล์ในตัว ": -"

รูตในดวลจุดโทษ:

# echo $EUID

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

In bash:
[chaapala@tenfwd2 ese]$ euid=${EUID:-`id -u`}
[chaapala@tenfwd2 ese]$ echo $euid
10260
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.