Bash: sudo -S <<< "mypassword" - проблема с интерактивной оболочкой

Я пытаюсь использовать sudo с -S выдать пароль через командную строку.

$ sudo -S <<< "mypassword" command

Это работает, но не допускает интерактивных команд. подобно nano например:

$ sudo -S <<< "mypassword" nano /tmp/foo

Он автоматически закрывает нано-сессию. То же самое с apt-get:

$ sudo -S <<< "mypassword" apt-get install foo

Он закрывается, прежде чем я могу нажать "y", чтобы установить foo. Я знаю, что могу пройти -y с подходящим, но в целом, это расстраивает.

Также пробовал такие вещи, как это, но он по-прежнему не взаимодействует с интерактивной сессией

$ sudo -S <<< "mypassword" -H -u root bash -c "apt-get install foo"

Можно ли использовать -S с sudo без отмены всех интерактивных оболочек?

1 ответ

Файловые дескрипторы наследуются

То, что вы используете, это <<< здесь-строка, и этот тип перенаправления реализуется через временные файлы, которые немедленно отсоединяются (или удаляются). Зная также, что процессы наследуют файловые дескрипторы (и stdin среди них) 1 от родителя к потомку, когда sudo -S выполняется, он читает свои входные данные из временного файла, который был передан вашей исходной оболочки (тот, который читает sudo -S команда). Вы можете увидеть это в действии:

$ sudo -S bash -c 'ls -l /proc/self/fd/0' <<< "mypasswd"
lr-x------ 1 root root 64 Feb 26 13:12 /proc/self/fd/0 -> '/tmp/sh-thd.cUOOXU (deleted)'

Таким образом, nano отчеты Too many errors from stdin ошибка в таком случае. Что можно сделать, это вручную повторно подключить, где stdin идет от.

$ sudo -S bash -c 'exec < /dev/tty; nano /tmp/foobar' <<< "mypasswd"

$ sudo -S bash -c 'nano /tmp/foobar < /dev/tty' <<< "mypasswd"

Любая из двух команд будет nano правильно и другие команды, а также. /dev/tty это специальный файл, представляющий текущее оконечное устройство, и это фактически то же самое, что stdin "нормальной" интерактивной оболочки (и, конечно, я упрощаю это утверждение).

Еще одна вариация на тему $ sudo -S bash -c 'nano /tmp/foobar 0>&1' <<<"mypasswd", stdout фактически указывает на то же терминальное устройство (если вы явно не предоставили перенаправление, чтобы иметь точку stdout где-либо еще). Таким образом, если мы сделаем stdin указать, чтобы быть dup лицензия stdout, это фактически то же решение, что и выше. (И если вам интересно, почему я выделил dup часть, это потому что dup2() syscall является ответственным за все манипулирование файловыми дескрипторами под капотом)


предосторожность

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

$ sudo -S bash -c 'sleep 3m' <<< "ohnomypassword"
^C
$ history 2
 2016  sudo -S bash -c 'sleep 3m' <<< "ohnomypassword"
 2017  history 2

sudo -S больше подходит для использования с другими процессами, где sudo -S будет ожидать ввода через конвейер, в идеале от zenity --password или же dialog --passwordbox "foobar text" 200 200 (см. extra1 и extra2 о диалоге).


1. Если файл открыт с O_CLOEXEC флаг установлен, дочерний процесс или замещенный процесс, порожденный через execve() Тип флага не будет иметь доступа к этому дескриптору файла - то есть он будет закрыт execve()

Другие вопросы по тегам