Как лучше всего проверить, есть ли у пользователя скрипта привилегии типа root? - PullRequest
57 голосов
/ 11 мая 2010

У меня есть скрипт на Python, который будет выполнять много вещей, для которых потребуются привилегии root-уровня, такие как перемещение файлов в / etc, установка с помощью apt-get и так далее. В настоящее время у меня есть:

if os.geteuid() != 0:
    exit("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.")

Это лучший способ сделать чек? Есть ли другие лучшие практики?

Ответы [ 9 ]

58 голосов
/ 11 мая 2010

os.geteuid получает эффективный идентификатор пользователя, который именно то, что вы хотите, поэтому я не могу придумать лучшего способа выполнить такую ​​проверку. Один бит, который неуверен в том, что он «похож на корень» в заголовке: ваш код проверяет на точно root, нет «нравится» в этом, и действительно, я бы не знал, что такое «root» но не root »будет означать - так что, если вы имеете в виду нечто иное, чем« именно root », возможно, вы можете уточнить, спасибо!

28 голосов
/ 11 мая 2010

В соответствии с принципом «Проще просить прощения, чем разрешения»:

try:
    os.rename('/etc/foo', '/etc/bar')
except IOError as e:
    if (e[0] == errno.EPERM):
       print >> sys.stderr, "You need root permissions to do this, laterz!"
       sys.exit(1)

Если вы обеспокоены непереносимостью os.geteuid(), то вам, вероятно, вообще не стоит связываться с /etc.

10 голосов
/ 23 ноября 2013

Вы можете запросить у пользователя доступ к sudo:

import os, subprocess

def prompt_sudo():
    ret = 0
    if os.geteuid() != 0:
        msg = "[sudo] password for %u:"
        ret = subprocess.check_call("sudo -v -p '%s'" % msg, shell=True)
    return ret

if prompt_sudo() != 0:
    # the user wasn't authenticated as a sudoer, exit?

Переключатель sudo -v обновляет кэшированные учетные данные пользователя (см. man sudo).

7 голосов
/ 11 мая 2010

Если вы действительно хотите, чтобы ваш код был устойчивым в самых разных конфигурациях Linux, я бы посоветовал вам рассмотреть крайние случаи, когда кто-то может использовать SELinux, или ACL файловой системы, или функции "возможностей", которые были в ядро Linux начиная с версии 2.2 или около того. Возможно, ваш процесс запущен в какой-либо оболочке, в которой используется SELinux, или в библиотеке некоторых возможностей Linux, например libcap2 libcap-ng или fscaps или elfcap через нечто более экзотическое, например замечательную и печально недооцененную систему systrace от Niels Provos.

Все это способы, которыми ваш код может выполняться без полномочий root, и все же вашему процессу мог быть делегирован необходимый доступ для выполнения его работы без EUID == 0.

Так что я бы посоветовал вам подумать о написании кода более Pythonical, оборачивая операции, которые могут завершиться неудачей из-за разрешений или других проблем с кодом обработки исключений. Если вы планируете выполнять различные операции (например, с использованием модуля subprocess), вы можете предложить префикс всех таких вызовов с sudo (например, в качестве параметра командной строки, среды или файла .rc). Если он запускается в интерактивном режиме, вы можете предложить повторно выполнить любые команды, которые вызывают исключения, связанные с разрешениями, используя sudo (опционально, только если вы найдете sudo в os.environ ['PATH']).

В целом верно, что большинство систем Linux и UNIX по-прежнему осуществляют большую часть администрирования привилегированным пользователем с правами root. Тем не менее, это старая школа, и мы, программисты, должны стараться поддерживать новые модели. Попытка выполнить ваши операции и позволить обработке исключений выполнять свою работу, позволяет вашему коду работать в любой системе, которая прозрачно разрешает необходимые вам операции, и знание и готовность к использованию sudo - приятное прикосновение (как это, безусловно, самый распространенный инструмент для контролируемого делегирования системных привилегий).

3 голосов
/ 12 мая 2010

Ответ на вторую часть вопроса

(извините, поле для комментариев было слишком маленьким)

Пол Хоффман, вы правы, я затронул только одну часть вашего вопроса, касающуюся встроенных функций, но это не был бы достойный язык сценариев, если бы он не мог обработать apt-get. Предпочтительная библиотека немного многословна, но она выполняет свою работу:

>>> apt_get = ['/usr/bin/apt-get', 'install', 'python']
>>> p = subprocess.Popen(apt_get, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> p.wait()
100                 # Houston, we have a problem.
>>> p.stderr.read()
'E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)'
'E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?\n'

Но Popen - обобщенный инструмент, для удобства его можно обернуть:

$ cat apt.py
import errno
import subprocess

def get_install(package):
    cmd = '/usr/bin/apt-get install'.split()
    cmd.append(package)
    output_kw = {'stdout': subprocess.PIPE, 'stderr': subprocess.PIPE}
    p = subprocess.Popen(cmd, **output_kw)
    status = p.wait()
    error = p.stderr.read().lower()
    if status and 'permission denied' in error:
        raise OSError(errno.EACCES, 'Permission denied running apt-get')
    # other conditions here as you require
$ python
>>> import apt
>>> apt.get_install('python')
Traceback ...
OSError: [Errno 13] Permission denied running apt-get

И теперь мы вернулись к обработке исключений. Я не буду комментировать Java-подобную сверхобобщенность модуля подпроцесса.

2 голосов
/ 03 октября 2014

Мое приложение работает с этим кодом:

import os
user = os.getenv("SUDO_USER")
if user is None:
    print "This program need 'sudo'"
    exit()
2 голосов
/ 15 июля 2013

Мне нравится проверять sudo в переменных среды:

if not 'SUDO_UID' in os.environ.keys():
  print "this program requires super user priv."
  sys.exit(1)
0 голосов
/ 03 октября 2018

Для Linux:

def is_root():
    return os.geteuid() == 0
0 голосов
/ 11 мая 2010

Все зависит от того, насколько портативным вы хотите, чтобы ваше приложение было. Если вы имеете в виду бизнес, мы должны предположить, что учетная запись администратора не всегда равна 0. Это означает, что проверки на euid 0 недостаточно. Проблема в том, что существуют ситуации, когда одна команда будет вести себя так, как если бы вы были пользователем root, а следующая потерпит неудачу с отказано в разрешении (подумайте SELinux & co.) Поэтому действительно лучше изящно потерпеть неудачу и проверять EPERM errno всякий раз, когда это уместно.

...