Запустите os.system, как будто Python не был выполнен с помощью sudo

Когда я запускаю следующую команду, все работает как положено. Нет ошибки, и я получаю системное уведомление "Hello":

$ python3
>>> import os
>>> os.system("notify-send Hello")
0

Тем не менее, когда я делаю это:

$ sudo python3
>>> import os
>>> os.system("notify-send Hello")

Сценарий застревает и ничего не происходит.

Затем я попытался сделать это:

$ sudo python3
>>> import os
>>> os.seteuid(1000)
>>> os.system("notify-send Hello")

(1000 моя обычная учетная запись без полномочий root)
Но все же сценарий застревает и ничего не происходит.

Я также попробовал это:

$ sudo python3
>>> import os
>>> os.system("su my-user-name -c 'notify-send Hello'")

и это:

$ sudo python3
>>> import os
>>> os.seteuid(1000)
>>> os.system("su my-user-name -c 'notify-send Hello'")

У них у всех одна и та же проблема...

Я не ищу альтернативный способ создания уведомлений. Меня не интересует subprocess или такие вещи, как notify2 которые вызывают совершенно новую категорию проблем в моей системе. О, и, пожалуйста, не говорите мне не использовать sudo. У меня есть причины.

1 ответ

Решение

Детали реализации, которые я обнаружил методом проб и ошибок: notify-send требует XDG_RUNTIME_DIR переменная окружения для работы - по крайней мере, в следующих версиях:

$ dpkg -l | grep libnotify
ii  libnotify-bin                              0.7.7-3                                      amd64        sends desktop notifications to a notification daemon (Utilities)
ii  libnotify4:amd64                           0.7.7-3                                      amd64        sends desktop notifications to a notification daemon

Сначала я определил, что нужна какая-то переменная окружения, используя env -i notify-send hello, который не произвел уведомления.

Затем я разделил среду на части с помощью модифицированной версии этого скрипта.

Как вы получите эту переменную среды, зависит от вас, но вам нужно запустить notify-send как правильный пользователь и с этой переменной.

Вот пример скрипта Python, я отказываюсь использовать os.system из-за проблем с безопасностью:

import os
import pwd
import subprocess
import sys


def main():
    if len(sys.argv) != 2:
        raise SystemExit(f'usage `{sys.argv[0]} USER`')
    if os.getuid() != 0:
        raise SystemExit('expected to run as root')

    # find the `gnome-session` executable, we'll use that to grab
    # XDG_RUNTIME_DIR
    cmd = ('pgrep', '-u', sys.argv[1], 'gnome-session')
    pid = int(subprocess.check_output(cmd))

    # read that process's environment
    with open(f'/proc/{pid}/environ') as f:
        for line in f.read().split('\0'):
            if line.startswith('XDG_RUNTIME_DIR='):
                _, _, xdg_runtime_dir = line.partition('=')
                break
        else:
            raise SystemExit('Could not find XDG_RUNTIME_DIR')

    # run the notify send as the right user
    uid = pwd.getpwnam(sys.argv[1]).pw_uid
    os.seteuid(uid)
    os.environ['XDG_RUNTIME_DIR'] = xdg_runtime_dir
    os.execvp('notify-send', ('notify-send', 'ohai'))


if __name__ == '__main__':
    exit(main())

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: этот скрипт делает некоторые очень хакерские вещи, которые я не обязательно предлагал бы в производственном коде. В частности:

  • Обстреливая pgrep, чтобы найти процесс
  • чтение переменных окружения другого процесса
  • sudo

Пример использования:

$ python3 t.py
usage `t.py USER`
$ python3 t.py asottile
expected to run as root
$ sudo python3 t.py asottile
# (I get a notification for `ohai`)
Другие вопросы по тегам