LINUX.ORG.RU

Как организовать запрос root прав при сохранении файла qt

 , ,


1

3

Доброго времени суток и с Новым годом, форумчане.

У меня есть приложение, писаное на qt5, которому могут понадобиться root права при сохранении файла. То есть пользователь сам выбирает в QFileDialog::getSaveFileName(), куда ему сохранять. И если выберет что-то типа в /etc, то ему могут потребоваться root права.

Так вот, как это организовать? То есть запрос root прав должен происходить именно тогда, когда пользователь выберет путь сохранения, по которому без рута нельзя. Кто что посоветует? Есть ли какие-нибудь готовые механизмы для этого?

Я бы посмотрел исходники Qt Install Framework, там когда выбираешь путь для установки вроде /opt, вызывается диалог, запрашивающий пароль суперпользователя.

EXL ★★★★★
()
Ответ на: комментарий от EXL

не могли бы вы ссылочку дать на эти исходники? а то никак найти не могу

zamazan4ik ★★
() автор топика
Ответ на: комментарий от EXL

уже не надо, нашёл. Спасибо.

Но вопрос всё ещё актуален. Может ещё кто чего предложит?

zamazan4ik ★★
() автор топика
Ответ на: комментарий от DeadEye

ну вот смотрите. У меня 2 проблемы : 0) Как мне при сохранении файла узнать, требуются или нет root права для сохранения файла в данной директории 1) Как мне получить root права для данного экземпляра программы?

Как обойти вторую проблему я придумал, но пахнет колхозом и оно мне не нравится : пишем ещё одну прогу, которую будем вызывать из главной и давать ей root права, эта вспомогательная прога будет только сохранять и ничего больше. Но колхоз в том, а что если я ещё придумаю действия, которые требуют рута? что мне тогда делать?

zamazan4ik ★★
() автор топика
Ответ на: комментарий от anonymous

насчёт 1). Получить root права не при запуске, а для выполнения данной операции. То есть мы просто запускаем приложение без рута, что-то там делаем, потом мне захотелось из прилоги сохранить файл в /etc/. Я выбираю имя файла, и тут мне выскакивает окошко для ввода пароля для рута. Если ввожу верно, то сохраняет, иначе нет

zamazan4ik ★★
() автор топика
Ответ на: комментарий от DeadEye

да, проще всего, я согласен. Я много программ видел, которые так и реализованы. Но согласитесь, не хочется давать рут права прилоге, если мы не собираемся через неё делать ничего такого, что требует этих самих прав. А хочется, чтобы мы запрашивали рут только при необходимости этого самого рута

zamazan4ik ★★
() автор топика
Ответ на: комментарий от anonymous

спасибо, проблема 0 решена. Осталась проблема 1

zamazan4ik ★★
() автор топика
Ответ на: комментарий от i_gnatenko_brain

правильно ли я понимаю, что с помощью polkit я через его API могу совершать запрос на получение root прав на выполнение определенных действий?

zamazan4ik ★★
() автор топика
Ответ на: комментарий от zamazan4ik

Как обойти вторую проблему я придумал, но пахнет колхозом и оно мне не нравится : пишем ещё одну прогу, которую будем вызывать из главной и давать ей root права, эта вспомогательная прога будет только сохранять и ничего больше

На самом деле, этот путь наиболее кошерен с точки зрения безопасности

annulen ★★★★★
()
Ответ на: комментарий от zamazan4ik

Нет шансов случайно (например. в результате эксплутатации злоумышленником ошибки в алгоритме) оставить основной программе повышенные привилегии

Прозрачность для пользователя: отдельное suid-приложение вызывает больше доверия, чем огромное гуишное приложение, запрашивающее рутовый пароль

annulen ★★★★★
()
Ответ на: комментарий от zamazan4ik

пишем ещё одну прогу, которую будем вызывать из главной и давать ей root права, эта вспомогательная прога будет только сохранять и ничего больше.

можно эту же самую прогу (в смысле иполняемый файл) вызывать со специальным аргументом командной строки

Harald ★★★★★
()
Ответ на: комментарий от annulen

является ли хорошим такое решение в данной ситуации : есть наша прога, и прога фоновая, которую будем вызывать для выполнения ВСЕХ рутовых действий, которые мы можем сделать с помощью основной проги. То есть из главной проги при любом действии, которое требует root прав мы вызываем эту фоновую прогу с root правами, передавая ей event, в котором будет указан тип действия. ну и все необходимые данные для этого event'а. Эта доп прога смотрит по ивенту, чего от неё хотят, делает это, и возвращает управление в основную программу.

Что в такой схеме может пойти не так?

zamazan4ik ★★
() автор топика
Ответ на: комментарий от zamazan4ik

пишем ещё одну прогу, которую будем вызывать из главной и давать ей root права, эта вспомогательная прога будет только сохранять и ничего больше.

Точнее так: твоя прога сохраняет в какой-то temp, а дальше вызывает вторую чисто для копирования куда надо. Т.е. логика сохранения и все связанное остается в гуевой, а вторая делает чисто одну операцию с файлами.

Pavval ★★★★★
()
Ответ на: комментарий от zamazan4ik

Что в такой схеме может пойти не так?

Желательно, чтобы доп. программа должна была устойчива к невалидным данным на входе, для этого код обработки «ивента» должен быть максимально простым (например, несколько параметров командной строки намного лучше, чем XML или JSON, и тем более чем бинарный пакет)

Вообще доп. программу лучше сделать максимально простой и прогнать через статические и динамические анализаторы на предмет ошибок работы с памятью

annulen ★★★★★
()
Ответ на: комментарий от Pavval

Точнее так: твоя прога сохраняет в какой-то temp, а дальше вызывает вторую чисто для копирования куда надо.

Такой подход уязвим к атаке по времени

annulen ★★★★★
()
Ответ на: комментарий от zamazan4ik

является ли хорошим такое решение в данной ситуации : есть наша прога, и прога фоновая, которую будем вызывать для выполнения ВСЕХ рутовых действий, которые мы можем сделать с помощью основной проги. То есть из главной проги при любом действии, которое требует root прав мы вызываем эту фоновую прогу с root правами, передавая ей event, в котором будет указан тип действия. ну и все необходимые данные для этого event'а. Эта доп прога смотрит по ивенту, чего от неё хотят, делает это, и возвращает управление в основную программу.

Это дыра в безопасности. Сценарий: кто угодно другой прикидывается основной прогой и просит фоновую вы*бать всех гусей. А т.к. фоновую прогу уже запустили и дали ей рута (для какой-то предыдущей операции), то права на гусей у нее уже есть. Имеем privilege escalation.

Pavval ★★★★★
()
Ответ на: комментарий от annulen

Такой подход уязвим к атаке по времени

Хм, да. Но можно защититься путем передачи md5 в командной строке или т.п.

Pavval ★★★★★
()
Ответ на: комментарий от Pavval

Не, можно передать файловый дескриптор записанного в тмп файла вместо имени, и все будет секьюрно

annulen ★★★★★
()
Ответ на: комментарий от annulen

То есть нельзя изменить права работающего экземпляра программы во время работы? Я имею в виду, что мы запускаем программу без рута, потом через gksu/kdesudo/что-то ещё запрашиваем для неё права, и вот она уже обладает root правами.

zamazan4ik ★★
() автор топика
Ответ на: комментарий от annulen

может я что-то неправильно понял, но выше мы обсуждали про вариант 1 прога вызывает вторую с рутом. То есть это 2 разных приложения.

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

zamazan4ik ★★
() автор топика
Ответ на: комментарий от annulen

Ваш комментарий про доверие пользователя я помню, да. Ещё есть пункты против такого подхода?

zamazan4ik ★★
() автор топика
Ответ на: комментарий от zamazan4ik

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

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

Pavval ★★★★★
()
Ответ на: комментарий от Pavval

понял, спасибо. Есть какие-либо ещё рекомендации по написанию приложений, требующих прав суперпользователя? С радостью их выслушаю. Спасибо.

zamazan4ik ★★
() автор топика
Ответ на: комментарий от zamazan4ik

Я думаю - то что проще. Зависит от самоцели, если нужно меньше зависимостей, то лучше разобраться с низкоуровневым api.

Вообще, я почитал доку повнимательней, оно вроде как тоже умеет только подпроцесс запустить с нужными привелегиями. По крайней мере я не увидел api для работы по pid, если найдёшь - скажи, тоже интересно, тогда можно тупо fork юзать, не очень секьюрно, зато очень удобно.

pon4ik ★★★★★
()
Ответ на: комментарий от zamazan4ik

Чем этот вариант плох?

В этом варианте код должен быть написан таким образом: 1) получили привилегии; 2) сразу же выполнили нужную операцию; 3) сразу же сбросили привилегии

В гуишном приложении, особенно событийно-ориентированном (Qt), может быть сложно гарантировать невозможность ухода в event loop или выполнения какого-то другого постороннего кода между 1 и 2 или 2 и 3, а это создаст отличную дыру. Если ты уверен, что весь код с 1 по 3 выполняется синхронно в одном месте программы и никакой случайно вылетевший сигнал не захватит управление под повышенными привилегиями, то можешь делать так (если есть желание разбираться разбираться с polkit).

annulen ★★★★★
()
Ответ на: комментарий от zamazan4ik

0) Как мне при сохранении файла узнать, требуются или нет root права для сохранения файла в данной директории

Два варианта:

1) Просто узнать, какие права выставлены, какому юзеру и группе принадлежит файл и сравнить.

2) Попробовать сохранить так, если получится эксепшн, пересохранять с правами.

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

Psych218 ★★★★★
()
Последнее исправление: Psych218 (всего исправлений: 1)
Ответ на: комментарий от Psych218

ну, на пользователя надеяться сами понимаете, что очень глупо. Надо исходить из того, что юзверь ССЗБ, вот и оберегать его, как только можно.

насчёт Ваших способов: 1) Да, это вариант. QT такое умеет, как мне уже подсказали выше. 2) Не, а вот это плохо пахнет, очень плохо пахнет.

zamazan4ik ★★
() автор топика

я бы сделал так:
1. сохраняю куда хотел пользователь
2. если ошибка - прошу пароль рута и вызов тойже функции сохранения из шага 1
3. если опять ошибка - сообщение «ошибка ...»

x905 ★★★★★
()
Ответ на: комментарий от x905

не, я понимаю. что так может сработать. Но это такой способ пахнет дурно. И что к примеру делать, если ошибка записи не из-за того, что прав нет, а из-за того, что место закончилось или ещё что? То есть он попытается сохранить, вылетает ошибка, он вводит пароль от рута и всё равно не сохранилось. Такой способ оставлю только на крайний случай

zamazan4ik ★★
() автор топика
Ответ на: комментарий от zamazan4ik

ошибка записи имеет код - от него и оттолкнуться
а иначе надо проверять права родительского каталога и\или файла, что привнесет в код множество if (надо будет предусматривать разные ситуации)

x905 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.