Как скрипт может проверить, запускается ли он от имени root?

105

Я пишу простой bash-скрипт, но мне нужно проверить, запущен ли он от имени пользователя root или нет. Я знаю, что, вероятно, есть очень простой способ сделать это, но я понятия не имею, как.

Просто чтобы быть ясно:
Что простой способ , чтобы написать сценарий foo.sh , так что команда ./foo.shвыводит 0, и команда sudo ./foo.shвыводит 1?

Malabarba
источник

Ответы:

151
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root" 
   exit 1
fi
aneeshep
источник
7
Я принимаю эту единственную причину (после некоторого тестирования) с использованием системной переменной EUID, которая оказалась (примерно в 100 раз) быстрее, чем выполнение команды (id -u), но все ответы работали отлично.
Малабарба
18
Также $UIDи $EUIDесть башмизы. Просто POSIX-совместимые оболочки не имеют этих переменных, и вам нужно использовать их id(1)вместо этого.
Дэвид Фёрстер
3
в сценарии bash вы можете использовать if ((EUID)); then, см . комментарий @ geirha
jfs
7
@Andrew: переменные подставляются до того, как они будут переданы sudo. Если вы запустите, sudo sh -c 'echo $EUID'вы увидите ожидаемые результаты.
М. Дадли
6
@ Эндрю - я знаю, что опаздываю, но для потомков: $EUIDэто Bashism (как упомянуто выше @DavidFoerster), а ваша /bin/sh, скорее всего, является ссылкой /bin/dash, а не /bin/bash. sudo bash -c 'echo $EUID'даст ожидаемый результат.
Адриан Гюнтер
118

Пользователь root не обязательно должен называться «root». whoamiвозвращает первое имя пользователя с идентификатором пользователя 0. $USERсодержит имя вошедшего в систему пользователя, который может иметь идентификатор пользователя 0, но иметь другое имя.

Единственная надежная программа, которая проверяет, вошел ли аккаунт как root или нет:

id -u

Я использую -uдля эффективного идентификатора пользователя, а не -rдля реального идентификатора пользователя. Права доступа определяются с помощью эффективного идентификатора пользователя, а не реальные один.

тесты

/etc/passwdсодержит следующие имена пользователей с идентификатором пользователя 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
Lekensteyn
источник
5
Вам не нужно id -uв bash askubuntu.com/questions/30148/…
jfs
5
Я всегда стараюсь быть максимально совместимым с POSIX, используя sh( dash) вместо интерпретатора bash. Но удачный выстрел спасает еще один форк :)
Лекенштейн
После некоторого простуды я вернулся и посмотрел. Метод Лекенштейна действительно кажется лучше. Его ответ теперь новый принятый ответ. +1 тебе, Лекенштейн, особенно для того, чтобы получить этот трудный знак из этого вопроса;)
Томас Уорд
Спасибо за то, что так долго ждал моего вопроса: я получил значок «Золотой популист» и бронзовый «Хороший ответ» за этот ответ :) Интересно, как этот вопрос получил 345 просмотров за день!
Лекенштейн
3
Я видел более короткие версии [ -w / ]. Идея остается прежней. Примечание: в некоторых chroot [ -w /etc/shadow ]произойдет сбой, потому что /etc/shadowне существует, поэтому подход с /предпочтительным. Лучше бы проверить фактическую потребность в правах доступа root. Если сценарию необходимо выполнить запись /etc/someconfig, просто проверьте, доступен ли для записи этот файл ИЛИ файл не существует и /etcдоступен для записи.
Лекенштейн
30

Как сказал @Lekensteyn, вы должны использовать эффективный идентификатор пользователя. Вам не нужно звонить id -uв Bash:

#!/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
JFS
источник
8
В общем, следует использовать ((..))для проверки чисел, а также [[..]]для проверки строк и файлов, так что я бы сделал if (( EUID != 0 )); thenвместо этого, или простоif ((EUID)); then
Geirha
@geirha: я добавил ваше предложение.
Jfs
2
EUIDдолжен стать $EUID. Вместо использования (( $EUID != 0 ))используйте [ $EUID != 0 ]. С этим тоже будет работать dash.
Лекенштейн
2
@Lekensteyn: EUIDработает просто отлично. Вопрос маркируется bashне dash. Команда env -i sh -c '[ $EUID != 0 ]'не выполняется, но env -i bash -c '(( EUID != 0 ))'работает. Кстати, 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
@ Джордж Эдисон: я рекомендую против использования $USER, особенно таким образом. $USERустанавливается оболочкой входа в систему, она не обязательно распространяется в программу ( env -i sh -c 'echo $USER'). Таким образом, $USERпусто и возникает синтаксическая ошибка.
Лекенштейн
1
@Lekensteyn Не только $USERустанавливается оболочкой, но и легко подделывается. Whoami вернет фактического пользователя.
Поль де Вриз
2
@PauldeVrieze Какой смысл обманывать эту проверку?
hrqueque
1
@andrewsomething: $USERинтерпретируется вашей оболочкой, ваш пример должен sudo sh -c 'echo $USER'быть значимым. @ Джордж: он делает неверное предположение, что whoamiвсегда будет возвращаться rootдля UID 0.
Сэм Хоцевар
10

Принимая во внимание эффективность, вы можете сначала протестировать EUIDпеременную окружения, а затем, если она не существует, вызвать стандартную idкоманду:

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

Таким образом, из-за сочетания клавиш OR вы не будете вызывать системную команду, отдавая приоритет запросу переменной в памяти.

Повторное использование кода:

function amIRoot() {
  ! ((${EUID:-0} || "$(id -u)"))
}
Luchostein
источник
1
Боюсь, вы не оценили это, ну, у меня есть, и это занимает столько же времени, сколько и id -u. Посмотрите стендовый скрипт вместе с результатами ниже его: pastebin.com/srC3LWQy
LinuxSecurityFreak
((${EUID:-0} || "$(id -u)"))всегда работаетid -u , так же, как ((1 || $(echo hi >&2; echo 1)))и ((0 || $(echo hi >&2; echo 1)))оба печати hi. Арифметика внешней оболочки &&и ||управляющие операторы; в a || "$(b)", bтолько работает, если "$(b)"работает. Большинство расширений, включая подстановку команд, регулируются семантикой короткого замыкания управляющих операторов. В арифметике оболочки есть операторы, которые оказались записанными по буквам, &&а ||также - которые также являются короткими замыканиями, что ((1 || 0/0))не является ошибкой - но арифметика оболочки возникает после расширения вложенных подстановок команд.
Элия ​​Каган
9
#!/bin/bash
[[ $(id -u) != 0 ]] 
echo $?
Жоау Пинту
источник
2

Один простой способ сделать скрипт доступным только для пользователя root - запустить скрипт со строкой:
#!/bin/su root

alexandre1985
источник
1
Не делай этого. Он пытается войти в систему напрямую как root, тогда как sudo может потребоваться во многих системах, потому что первое запрещено. Кроме того, shebang предназначен для обеспечения того, чтобы ваш скрипт выполнялся в том виде, для которого он был спроектирован, в то время как ваш метод вызовет выполнение скрипта в оболочке root по умолчанию, что невозможно предсказать, если скрипт запускается кем-либо кроме автора. Следовательно, использование shebang для повышения привилегий скрипта серьезно нарушит его переносимость и приведет к ошибкам во многих системах. (su: Ошибка аутентификации)
StarCrashr
1
#!/bin/bash
uid=`id -u`
if [ "$uid" == "0" ]
then
    echo 1
else
    echo 0
fi
Делан Азабани
источник
1

Этот фрагмент будет:

  • Проверьте на разных сессиях
  • предложить использовать sudo !!
  • и вернуть ошибку
if ["$ (whoami & 2> / dev / null)"! = "root"] && ["$ (id -un & 2> / dev / null)"! = "root"]
      тогда
      echo "Вы должны быть пользователем root, чтобы запустить этот скрипт!"
      echo "использовать 'sudo !!'"
      выход 1
фи
rubo77
источник
1

Этот ответ просто для того, чтобы сохранить идею, может быть полезным для некоторых из вас. Если вам нужен скрипт, который запускается из графического интерфейса рабочего стола и требует привилегий root, попробуйте этот способ:

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

Таким образом, вы получите красивое диалоговое окно с просьбой ввести пароль пользователя root. Так же, как с командной строкой sudo.

gksudoМожет быть недоступен в вашей системе , то установите его sudo apt-get install gksu.

gertas
источник
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
Клейтон Хаапала
источник