Есть ли способ для приложения Java получить права root?
При запуске Files.walk(Paths.get("/var/")).count()
в качестве непривилегированного пользователя выполнение может вызвать исключение, так как есть папки внутри /var/
, для которых требуется разрешение root.
Я не ищет способ выполнить команду bash как root (например, sudo find /var
), используя Process
и т.д.
Я просто хочу убедиться, что Files.walk(Paths.get("/var/")).count()
не выбрасывает AccessDeniedException
:
Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0
at sun.reflect.NativeMethodAccessorImpl.invoke
at sun.reflect.DelegatingMethodAccessorImpl.invoke
at java.lang.reflect.Method.invoke
at org.springframework.boot.devtools.restart.RestartLauncher.run
Caused by: java.io.UncheckedIOException: java.nio.file.AccessDeniedException: /var/cache/httpd
at java.nio.file.FileTreeIterator.fetchNextIfNeeded
at java.nio.file.FileTreeIterator.hasNext
at java.util.Iterator.forEachRemaining
at java.util.Spliterators$IteratorSpliterator.forEachRemaining
at java.util.stream.AbstractPipeline.copyInto
at java.util.stream.AbstractPipeline.wrapAndCopyInto
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential
at java.util.stream.AbstractPipeline.evaluate
at java.util.stream.LongPipeline.reduce
at java.util.stream.LongPipeline.sum
at java.util.stream.ReferencePipeline.count
at com.example.DemoApplication.main
... 5 more
Caused by: java.nio.file.AccessDeniedException: /var/cache/httpd
at sun.nio.fs.UnixException.translateToIOException
at sun.nio.fs.UnixException.rethrowAsIOException
at sun.nio.fs.UnixException.rethrowAsIOException
at sun.nio.fs.UnixFileSystemProvider.newDirectoryStream
at java.nio.file.Files.newDirectoryStream
at java.nio.file.FileTreeWalker.visit
at java.nio.file.FileTreeWalker.next
at java.nio.file.FileTreeIterator.fetchNextIfNeeded
Это просто пример. Используя filter(...)
, можно обойти исключение. Но этот пример можно расширить и в других случаях использования.
Итак, возможно ли это вообще, для приложений CLI, JavaFX и т.д., чтобы получить права root после того, как они были выполнены из командной строки с помощью метода, такого как java -jar app.jar
?
Ответы
Ответ 1
Если то, что вы хотите, фактически пропускает пути, в которых у вас нет доступа, вы имеете два подхода:
Струйные
В ответе на этот вопрос объясняется, как получить поток всех файлов поддерева, к которым вы можете получить доступ.
Но этот пример может быть расширен и в других случаях использования.
FileVisitor
Использование FileVisitor
добавляет много кода, но при использовании дерева каталогов вы получаете гораздо большую гибкость. Чтобы решить ту же проблему, вы можете заменить Files.walk()
на:
Files.walkFileTree(Path start, FileVisitor<? super Path> visitor);
расширение SimpleFileVisitor (для подсчета файлов) и переопределение некоторых методов.
Вы можете:
- Переопределить метод
visitFileFailed
, для обработки дела вы не можете получить доступ к файлу по некоторым причинам; (Lukasz_Plawny совет)
- (необязательно) Переопределите метод
preVisitDirectory
, проверяя разрешения перед доступом к каталогу: если вы не можете получить к нему доступ, вы можете просто пропустить его поддерево (помните, что вы можете получить доступ к каталогу, но не все его файлы);
например. 1
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
// you can log the exception 'exc'
return FileVisitResult.SKIP_SUBTREE;
}
например. 2
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
if(!Files.isReadable(dir))
return FileVisitResult.SKIP_SUBTREE;
return FileVisitResult.CONTINUE;
}
Документы FileVisitor
Учебник FileVisitor
Надеюсь, что это поможет.
Ответ 2
Всего несколько непроверенных идей:
1) Запустите приложение с привилегиями root, чтобы начать с:
sudo java -jar myapp.jar
2) Пусть ваше приложение запускает класс-пуск, который запрашивает права root, а затем продолжает работу с остальной частью вашего приложения:
java -jar myapp.jar
Это, в свою очередь, выполняет команду оболочки, но только xterm, которая запрашивает пароль root, а затем продолжает запускать java-программу с правами root:
xterm -e "sudo sh -c 'java -jar /tmp/myrootapp.jar'"
или, возможно, использовать что-то приятное, используя gksudo. Обратите внимание на '
и "
.
Возможно, myapp.jar
извлекает себя в временный каталог. myapp.jar
содержит myrootapp.jar
, и поэтому он может запускать его, как описано выше. /tmp
, конечно, должен быть извлечен из java и предпочтительно быть каталогом со случайным именем, к которому имеет доступ только пользователь, на котором запущен myapp.jar
, чтобы предотвратить myrootapp.jar
инъекцию.
Кросс-платформенная
Вы упомянули /var/
самостоятельно, поэтому я предположил, что вы на каком-то Linux. Если предполагается, что он работает на межплатформенной платформе, например. на Macintosh или Microsoft Windows, вы должны сначала выполнить некоторую идентификацию системы. Затем вы можете применить StrategyPattern в коде, чтобы обрабатывать различные способы предоставления myrootapp.jar
получения прав root или администратора.
Ответ 3
Нет простого способа изменить разрешения. Java не подходит для этих задач. Есть только некоторые трюки, такие как проверка разрешений при запуске и попытка изменения разрешений через su/sudo, а затем перезапуск приложения или использование Java-gnome. Пожалуйста, прочитайте еще немного: Java: спросите права root на Ubuntu