Подтвердить что ты не робот

Каков наилучший способ проверить, имеет ли пользователь Python script root-подобные привилегии?

У меня есть Python script, который будет делать много вещей, которые потребуют привилегий на уровне корневого уровня, таких как перемещение файлов в /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.")

Это лучший способ сделать чек? Существуют ли другие рекомендации?

4b9b3361

Ответ 1

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

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 в любом случае.

Ответ 2

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

Ответ 3

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

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

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

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

Ответ 4

Вы можете запросить пользователя для доступа к 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).

Ответ 5

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

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

Пол Хоффман, вы правы, я только обратился к одной части вашего вопроса, посвященной внутренним характеристикам, но это был бы не достойный язык сценариев, если бы он не мог справиться с 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-подобную чрезмерную общность модуля подпроцесса.

Ответ 6

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

import os
user = os.getenv("SUDO_USER")
if user is None:
    print "This program need 'sudo'"
    exit()

Ответ 7

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

if not 'SUDO_UID' in os.environ.keys():
  print "this program requires super user priv."
  sys.exit(1)

Ответ 8

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