Эквивалент setuid для пользователей без полномочий root

Есть ли у Linux некоторый C-интерфейс, похожий на setuid, который позволяет программе переключаться на другого пользователя, используя, например, имя пользователя/пароль? Проблема с setuid заключается в том, что она может использоваться только суперпользователями.

Я запускаю простую веб-службу, которая требует выполнения заданий в качестве зарегистрированного пользователя. Таким образом, основной процесс выполняется как root, и после того, как пользователь введет в него вилки и вызовет setuid, чтобы переключиться на соответствующий uid. Тем не менее, я не совсем уверен в том, что основной proc работает от root. Я бы предпочел, чтобы он работал как другой пользователь и имел некоторый механизм для переключения на другого пользователя, подобного su (но без запуска нового процесса).

2 ответа

Нет, нет возможности изменить UID, используя только имя пользователя и пароль. (Понятие "пароль" не распознается ядром каким-либо образом - оно существует только в пользовательском пространстве.) Чтобы переключиться с одного не-корневого UID на другой, вы должны стать root как промежуточный шаг, обычно exec() -выпуск двоичного файла setuid.

Другим вариантом в вашей ситуации может быть запуск основного сервера как непривилегированного пользователя и его связь с внутренним процессом, выполняемым с правами root.


Во-первых, setuid() может определенно использоваться не-суперпользователями. Технически все, что вам нужно в Linux, - это CAP_SETUID (и/или CAP_SETGID) возможность для переключения на любого пользователя. Во-вторых, setuid() и setgid() могут изменять идентификатор процесса между реальным (пользователем, выполнившим процесс), эффективным (владельцем двоичного файла setuid/setgid) и сохраненными идентификаторами.

Однако ничто из этого не имеет отношения к вашей ситуации.

Существует относительно простое, но чрезвычайно надежное решение: иметь вспомогательный помощник setuid, раздвоенный и выполненный вашим демоном службы, прежде чем он создает какие-либо потоки, и использовать пару сокетов домена Unix для связи между помощником и службой, служба, передающая как свои учетные данные, так и дескрипторы файла конечной точки канала помощнику, когда исполняются двоичные файлы пользователя. Помощник будет проверять все на безопасном уровне, и если все будет в порядке, оно будет вилять и исполнять желаемый помощник пользователя, причем указанные конечные точки подключения подключаются к стандартным входам, стандартным выводам и стандартной ошибке.

Процедура запуска службы помощника как можно раньше следующая:

  • Создайте пару сокетов Unix , используемую для привилегированных сообщений между службой и помощником.

  • Fork.

  • В дочернем элементе закройте все лишние дескрипторы файлов, сохранив только один конец пары сокетов. Переназначить стандартный ввод, вывод и ошибку на /dev/null.

  • В родительском элементе закройте дочерний конец пары сокетов.

  • В дочернем случае выполните привилегированный вспомогательный двоичный файл.

  • Родитель отправляет простое сообщение, возможно, без каких-либо данных, но с вспомогательным сообщением /dev/random, но помните, что это ограниченный ресурс (может блокироваться, если для ядра не хватает случайности). Я бы просто прочитал, скажем 1024 бита (128 байт) из /dev/urandom, и используйте это.

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

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

    • Создает необходимые каналы (один для подачи стандартного ввода в двоичный файл пользователя, один для возврата стандартного вывода из двоичного файла пользователя)

    • Отправляет сообщение помощнику, содержащему

      • Идентичность для запуска двоичного файла как; имена пользователей (и групп), или UID и GID (ы)
      • Путь к двоичному
      • Параметры командной строки, заданные двоичным
      • Вспомогательное сообщение, содержащее дескрипторы файла для пользовательских двоичных конечных точек данных.

    Всякий раз, когда хелпер получает такое сообщение, он вилки. В дочернем элементе он заменяет стандартный ввод и вывод файловыми дескрипторами в вспомогательном сообщении, меняет идентификатор с помощью setresgid() и setresuid() и/или initgroups(), меняет рабочий каталог на нужное место и выполняет двоичный файл пользователя. Родительский вспомогательный процесс закрывает дескрипторы файла в вспомогательном сообщении и ждет следующего сообщения.

    Если помощник завершает работу, когда из сокета больше не будет входа, он автоматически выйдет, когда служба выйдет.

    Я мог бы предоставить примерный код, если есть достаточный интерес. Там много деталей, чтобы получить право, поэтому код немного утомительно, чтобы писать. Однако, правильно написано, оно более безопасно, чем, например, Apache SuEXEC.

licensed under cc by-sa 3.0 with attribution.