Как программно получить полномочия пользователя root?

Я пишу некоторое программное обеспечение (в C++, для LINUX/MAC OSX), который работает как непривилегированный пользователь, но нуждается в полномочиях пользователя root в какой-то момент (для создания нового виртуального устройства).

При запущении этой программы, поскольку корень не является опцией (главным образом для проблем безопасности), и я должен знать идентификационные данные (uid) "настоящего" пользователя.

Существует ли способ подражать поведению команды "sudo" (попросите пароль пользователя) временно получить полномочия пользователя root и выполнить конкретную задачу? Если так, какие функции я использовал бы?

Большое спасибо за Вашу справку!

32
задан abatishchev 29 August 2010 в 19:34
поделиться

6 ответов

Оригинальный ответ

Вы можете рассмотреть возможность использования переключателя setuid в самом исполняемом файле. В Википедии есть статья об этом, которая даже показывает вам разницу между geteuid() и getuid() довольно эффективно, первый предназначен для выяснения того, кого вы "имитируете", а второй - кто вы "есть". Процесс sudo, например, geteuid должен вернуть 0 (root), а getuid - id вашего пользователя, однако его подпроцессы действительно запускаются от имени root (вы можете проверить это с помощью sudo id -u -r).

Я не думаю, что есть способ легко программно получить доступ root - в конце концов, применяя принцип наименьших привилегий, зачем вам это нужно? Обычной практикой является запуск только ограниченных частей кода с повышенными привилегиями. Многие демоны и т.д. также настроены в современных системах на запуск от имени собственного пользователя с большинством необходимых привилегий. Только для очень специфических операций (монтирование и т.д.) действительно необходимы привилегии root.

Обновление 2013 года

Мой первоначальный ответ остается в силе (хотя мой "я" 2013 года может быть лучше, чем мой 2010 года), но если вы разрабатываете приложение, требующее root-доступ, вы можете рассмотреть, какой именно root-доступ необходим, и рассмотреть возможность использования POSIX Capabilities (man page). Они отличаются от capability-based security, реализованной в L4 и др. POSIX capabilities позволяют вашему приложению получить подмножество полномочий root. Например, CAP_SYS_MODULE позволит вам вставлять модули ядра, но не даст вам никаких других полномочий root. Это используется в дистрибутивах, например, Fedora имеет функцию полного удаления setuid binaries с неразборчивым root-доступом.

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

15
ответ дан 27 November 2019 в 20:47
поделиться

Если вам каждый раз нужны привилегии суперпользователя, лучше всего запустить вашу программу от имени суперпользователя и удалить их (в подпроцессе) с помощью setuid и сетгид . Это то, что делает apache, когда ему нужно привязаться к ограниченному порту 80.

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

sudo add_interface args

и пусть sudo выполняет аутентификацию за вас. Вместо sudo вы можете использовать графический интерфейс, такой как gksu, gksudo, kdesu или kdesudo. Я бы сам не стал пытаться реализовать безопасный ввод пароля; это может быть сложной проблемой, и вы, вероятно, оставите зияющие дыры в безопасности и проблемы с функциональностью (поддерживаете ли вы считыватели отпечатков пальцев?).

Другой альтернативой является polkit , ранее называвшийся PolicyKit.

20
ответ дан 27 November 2019 в 20:47
поделиться

Обычно это делается путем создания вашего двоичного файла suid-root.

Один из способов сделать это так, чтобы атаки на вашу программу были затруднены, - это минимизировать код, который работает как root, например:

int privileged_server(int argc, char **argv);
int unprivileged_client(int argc, char **argv, int comlink);


int main(int argc, char **argv) {
    int sockets[2];
    pid_t child;
    socketpair(AF_INET, SOCK_STREAM, 0);  /* or is it AF_UNIX? */

    child = fork();
    if (child < 0) {
        perror("fork");
        exit(3);
    } elseif (child == 0) {
        close(sockets[0]);
        dup2(sockets[1], 0);
        close(sockets[1]);
        dup2(0, 1);
        dup2(0, 2); /* or not */
        _exit(privileged_server(argc, argv));
    } else {
        close(sockets[1]);
        int rtn;
        setuid(getuid());
        rtn = unprivileged_client(argc, argv, sockets[0]);
        wait(child);
        return rtn;
    }
}

Теперь непривилегированный код общается с привилегированным кодом через fd comlink (который является подключенным сокетом ). Соответствующий привилегированный код использует stdin / stdout в качестве конца comlink.

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

4
ответ дан 27 November 2019 в 20:47
поделиться

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

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

0
ответ дан 27 November 2019 в 20:47
поделиться

Вы не можете получить привилегии root, вы должны начать с ними и снижать свои привилегии по мере необходимости. Обычный способ сделать это - установить программу с установленным битом "setuid": это запускает программу с эффективным userid владельца файла. Если вы выполните ls -l на sudo, вы увидите, что программа установлена именно так:

-rwsr-xr-x 2 root root 123504 2010-02-25 18:22 /usr/bin/sudo

Пока ваша программа работает с привилегиями root, вы можете вызвать системный вызов setuid(2), чтобы изменить свой эффективный идентификатор на какой-нибудь непривилегированный. Я полагаю (но не пробовал), что вы можете установить свою программу от имени root с включенным битом setuid, немедленно понизить привилегии, а затем восстановить их по мере необходимости (возможно, однако, что после понижения привилегий вы не сможете их восстановить).

Лучшее решение - вычленить часть вашей программы, которая должна работать от имени root, и установить ее с включенным битом setuid. Конечно, вам нужно будет принять разумные меры предосторожности, чтобы его нельзя было вызвать вне вашей основной программы.

8
ответ дан 27 November 2019 в 20:47
поделиться

Возможно, вы захотите взглянуть на эти API:

setuid, seteuid, setgid, setegid, ...

Они определены в заголовке в системах Linux (мало что знаю о MAC, но вам следует там тоже есть похожий заголовок).

Одна проблема, которую я вижу, заключается в том, что процесс должен иметь достаточные привилегии для изменения своих идентификаторов пользователя / группы. В противном случае вызовы вышеуказанных функций приведут к ошибке с errorno , установленным на EPERM .

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

2
ответ дан 27 November 2019 в 20:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: