Взгляните на samba , чтобы получить пример этого.Демон samba запускается от имени пользователя root, но разветвляется и принимает учетные данные обычного пользователя как можно скорее.
У систем Unix есть два отдельных набора учетных данных: идентификаторы реального пользователя / группы и эффективные идентификаторы пользователя / группы.Реальный набор определяет, кто вы на самом деле, а эффективный набор определяет, к чему вы можете получить доступ.Вы можете изменить действующий uid / gid по своему усмотрению, если вы являетесь пользователем root, в том числе обычным пользователем и обратно, поскольку ваши реальные идентификаторы пользователей / групп остаются корневыми во время перехода.Таким образом, альтернативный способ сделать это в одном процессе - использовать seteuid/gid
для применения разрешений разных пользователей туда и обратно по мере необходимости.Если ваш серверный сервер работает от имени пользователя root или имеет CAP_SETUID
, то это будет разрешено.
Однако обратите внимание, что если у вас есть возможность переключать эффективный uid / gid на прихоть, а ваше приложение подрывается, то этоSubversion может, например, переключить эффективный uid / gid обратно на 0, и вы можете столкнуться с серьезной уязвимостью безопасности.Вот почему целесообразно как можно скорее удалить все привилегии навсегда, включая вашего реального пользователя uid / gid.
По этой причине нормально и безопаснее иметь один прослушивающий сокет, работающий от имени пользователя root, а затем forkвыключите и измените действительные и эффективные идентификаторы пользователей, вызвав setuid
.Тогда это не может измениться назад.У вашего разветвленного процесса будет сокет, который был accept()
ed, так как он является форком.Каждый процесс просто закрывает файловые дескрипторы, которые им не нужны;сокеты остаются в живых, так как на них ссылаются файловые дескрипторы в противоположных процессах.
Вы также можете попытаться применить права доступа, проверив их индивидуально самостоятельно, но я надеюсь, что очевидно, что это потенциально подвержено ошибкам, имеет множество крайних вариантов и с большей вероятностью пойдет не так (например, он не будет работать с POSIX ACL, если вы не реализуете это специально).
Итак, у вас есть три варианта:
- Вилка и
setgid()
/ setuid()
пользователю, которого вы хотите.Если требуется связь, используйте pipe(2)
или socketpair(2)
перед тем, как разветвляться. - Не разветвляйтесь и
seteuid()
/ setegid()
вокруг, если это необходимо (менее безопасно: с большей вероятностью скомпрометировать сервер случайно). - Не связывайтесь с системными учетными данными;выполнить принудительное разрешение вручную (менее безопасно: более вероятно, что авторизация будет неправильной).
Если вам нужно связаться с демоном, тогда, возможно, будет сложнее сделать это через сокет или канал,Первый вариант - это правильный безопасный способ сделать это.Посмотрите , например, как ssh делает разделение привилегий .Вы также можете подумать, можете ли вы изменить свою архитектуру, чтобы вместо какого-либо взаимодействия процесс мог просто разделить часть памяти или дискового пространства.
Вы упоминаете, что рассматривали возможность запуска отдельного процесса для каждого пользователя, но вам нужен одинпрослушивает порт TCP.Вы все еще можете сделать это.Просто попросите главного демона прослушивать порт TCP и отправлять запросы каждому демону пользователя и связываться по мере необходимости (например, через доменные сокеты Unix).На самом деле это почти то же самое, что иметь разветвляющегося главного демона;Я думаю, что последнее оказалось бы проще реализовать.
Дополнительная информация: справочная страница credentials(7)
.Также обратите внимание, что в Linux есть файловая система uid / gids;это почти то же самое, что и эффективный uid / gids, за исключением других вещей, таких как отправка сигналов.Если ваши пользователи не имеют доступа к оболочке и не могут запустить произвольный код, вам не нужно беспокоиться о разнице.