В потоке Java, работающем от имени пользователя root, как мы можем применить права Unix, определенные для вошедшего в систему пользователя? - PullRequest
3 голосов
/ 05 ноября 2008

У нас есть программа Java, запущенная как root в Unix, которая, таким образом, может читать, например, содержимое папок /home/user1 и /home/user2. Однако, если пользователь Unix "user1" вошел в наше приложение, он не сможет получить доступ к данным "/ home / user2". Мы бы хотели напрямую использовать права Unix и не восстанавливать все разрешения в нашем приложении! Итак, можем ли мы ...

  1. попробуйте изменить UID нашего программа в зависимости от пользователя вошел в ? Звучит сложно, и каждый файл доступ в разных темах так UID будет отличаться на каждом нить нашей программы ...
  2. использовать JNI для чтения прав доступа "/home/user2" ... а потом определить если user1 имеет достаточные разрешения на "/home/user2"? (как?).

Ответы [ 7 ]

2 голосов
/ 05 ноября 2008

Используйте SecurityManager!

  1. Поместить текущий идентификатор пользователя Unix в ThreadLocal
  2. Создайте свой собственный SecurityManager, который проверяет пользовательские разрешения Unix на checkRead () и checkWrite ()
  3. System.setSecurityManager (новый MySecurityManager ())
  4. Наслаждайтесь

Обновление

Конечно, нет стандартной библиотеки для чтения прав доступа к Unix-файлу. Это не WORA.

Но я кратко попытался найти готовую к использованию библиотеку и нашел эту: http://jan.newmarch.name/java/posix/ Он использует JNI, но вам не нужно писать свой собственный код JNI, что является большим облегчением. :) Я уверен, что должны быть и другие.

Класс Stat оттуда дает вам всю необходимую информацию доступа: http://jan.newmarch.name/java/posix/posix.Stat.html

Обновление 2

Как уже упоминалось, этот подход не проверяет «нестандартные» функции безопасности Unix, такие как ACL или Posix Capabilities (может быть; не уверен, применимы ли они к файлам). Но если цель полной синхронизации с безопасностью операционной системы установлена, то нам еще больше нужно использовать SecurityManager, потому что это механизм защиты всей JVM! Да, мы можем запустить дочерний SUID-процесс для проверки прав доступа (и продолжать его работу, разговаривая с ним по каналу, работающему при входе пользователя в систему), , но нам нужно сделать это из SecurityManager !

2 голосов
/ 05 ноября 2008

Самый простой и самый переносимый способ - создать дочерний процесс, если он исполняет оболочку, написанную на C, которая изменяет UID, удаляет все привилегии (будьте осторожны, писать оболочку для этого сложно - трудный как написание оболочки setuid), и исполняет другой экземпляр java, с которым вы общаетесь через RMI. Этот экземпляр java будет выполнять все манипуляции с файловой системой от имени пользователя.

Для однопоточных программ Linux вы можете вместо этого использовать setfsuid() / setfsgid(), но это не вариант для переносных или многопоточных программ.

0 голосов
/ 16 июля 2011

У меня точно такая же проблема, как у Микаэля, и я зашел на эту страницу в поисках ответов.

Ни один из ответов не является на 100% удовлетворительным для меня. Итак, я думаю о 4 альтернативах:

  1. Используйте группу Linux, которая имеет доступ ко всем пользователям. Запустите одно приложение Java под этой группой. Это Java-приложение может связываться с «корневым» приложением любым способом.

    Потенциально, это может быть "отелем". например 1 «отель» (приложение с групповыми разрешениями) на 100 пользователей (или в зависимости от обстоятельств). Поэтому, если у вас 10 000 пользователей, вам нужно 100 отелей, что вполне поддается управлению.

  2. Создать JVM для каждого дочернего приложения под собственным идентификатором пользователя. Это похоже на вызов скрипта, но вместо использования stdin / stdio / stderr используйте любой протокол связи. В моем случае я использую XMPP и IO Data (которые, поскольку они уже используются другими компонентами, не имеет значения "где", то есть на какой JVM он работает).

  3. Создание приложения Super-Server 'root'. Это может быть частью исходного «корневого» приложения или отдельной службы, предназначенной для управления службами.

    Супер-сервер отвечает за обработку входящих запросов (то есть он фактически становится обратным прокси-сервером ) для пользовательских суб-приложений и за запуск реальных дочерних приложений (если они не запущены). уже) и передача сообщений между клиентом и дочерними приложениями.

    Кроме того, дочерние приложения могут быть объединены (или даже "пассивированы", если есть такая вещь), во многом благодаря Java EE EJB Container . Таким образом, даже если обслуживают 10 000 пользователей и (потенциально) 10 000 дочерних приложений, максимальное количество работающих дочерних приложений ограничено. Свободные приложения закрываются, чтобы освободить место для других.

  4. То же, что и № 3, но вместо того, чтобы создавать собственный механизм управления службами, интегрируйте его с Upstart (или инфраструктурой управления службами в базовой ОС). то есть есть корневая служба, которая может контролировать Upstart. Upstart может запускать, останавливать, перезапускать, запрашивать состояние дочерних служб, точно так же, как он может управлять mysqld, Apache и т. Д.

Для меня сейчас самым быстрым и простым для реализации будет № 1. Тем не менее, мое идеальное решение было бы № 4, но это займет время и проверить, хорошо ли оно работает. (сама концепция заимствована из inetd / xinetd и EJB, так что я думаю, что это звучит довольно фундаментально)

0 голосов
/ 05 ноября 2008

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

Разумеется, затем вам необходимо аутентифицировать соединение между процессом, выполняющимся от имени пользователя, и процессом, выполняющимся от имени пользователя root.

0 голосов
/ 05 ноября 2008

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

Если вы хотите вызвать setuid в однопоточной Java-программе, хороший пример - http://www2.sys -con.com / itsg / virtualcd / Java / archives / 0510 / Silverman / index.html .

0 голосов
/ 05 ноября 2008

Если ничего не помогло, вы можете запустить скрипт из java и проанализировать результат.

Описано, например, здесь

0 голосов
/ 05 ноября 2008

если вы хотите, чтобы приложению разрешалось только чтение файлов пользователем1, я настоятельно рекомендую, чтобы приложение запускалось как пользователь1.

...