有没有办法让 Java 应用获得 root 权限?
Is there a way for a Java app to gain root permissions?
当运行 Files.walk(Paths.get("/var/")).count()
为非特权用户时,执行可能会抛出异常,因为/var/
中有文件夹需要root权限才能遍历。
我 不是 正在寻找一种以 root 身份执行 bash 命令的方法(例如 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 等应用程序在通过 java -jar app.jar
等方法从命令行执行后获得 root 权限是否有可能?
只是一些完全未经检验的想法:
1) 运行 您的应用以 root 权限开头:
sudo java -jar myapp.jar
2) 让您的应用启动一个启动器-class 请求 root 权限,然后继续 运行您应用的其余部分:
java -jar myapp.jar
这反过来会执行一个 shell 命令,但只是一个提示输入 root 密码的 xterm,然后继续 运行 一个具有 root 权限的 java 程序:
xterm -e "sudo sh -c 'java -jar /tmp/myrootapp.jar'"
或者使用 gksudo 来使用更漂亮的东西。注意 '
和 "
.
也许 myapp.jar
将自己提取到 temporary directory。 myapp.jar
包含 myrootapp.jar
,因此它可以如上所述启动它。 /tmp
当然应该从 java 中检索,最好是一个只有用户 运行ning myapp.jar
可以访问的随机名称的目录,以防止 myrootapp.jar
注入.
跨平台
你自己提到了 /var/
,所以我假设你在某种 Linux 上。如果这应该跨平台工作,例如在 Macintosh 或 Microsoft Windows 上,您也需要先进行某种系统识别。然后你可以在代码中应用 StrategyPattern 来处理让 myrootapp.jar
获得 root 或管理员权限的各种方式。
如果你想要的实际上是跳过你无法访问的路径,你有两种方法:
流
说明了如何获取一个子树下所有你能访问的文件的流
But this example can be expanded to other use cases too.
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;
}
希望对您有所帮助。
没有简单的方法来更改权限。 Java 不擅长这些任务。只有一些技巧,比如在启动时检查权限并尝试通过 su/sudo 更改权限,然后重新启动应用程序或使用 Java-gnome。请在这里阅读更多内容:Java: Ask root privileges on Ubuntu
当运行 Files.walk(Paths.get("/var/")).count()
为非特权用户时,执行可能会抛出异常,因为/var/
中有文件夹需要root权限才能遍历。
我 不是 正在寻找一种以 root 身份执行 bash 命令的方法(例如 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 等应用程序在通过 java -jar app.jar
等方法从命令行执行后获得 root 权限是否有可能?
只是一些完全未经检验的想法:
1) 运行 您的应用以 root 权限开头:
sudo java -jar myapp.jar
2) 让您的应用启动一个启动器-class 请求 root 权限,然后继续 运行您应用的其余部分:
java -jar myapp.jar
这反过来会执行一个 shell 命令,但只是一个提示输入 root 密码的 xterm,然后继续 运行 一个具有 root 权限的 java 程序:
xterm -e "sudo sh -c 'java -jar /tmp/myrootapp.jar'"
或者使用 gksudo 来使用更漂亮的东西。注意 '
和 "
.
也许 myapp.jar
将自己提取到 temporary directory。 myapp.jar
包含 myrootapp.jar
,因此它可以如上所述启动它。 /tmp
当然应该从 java 中检索,最好是一个只有用户 运行ning myapp.jar
可以访问的随机名称的目录,以防止 myrootapp.jar
注入.
跨平台
你自己提到了 /var/
,所以我假设你在某种 Linux 上。如果这应该跨平台工作,例如在 Macintosh 或 Microsoft Windows 上,您也需要先进行某种系统识别。然后你可以在代码中应用 StrategyPattern 来处理让 myrootapp.jar
获得 root 或管理员权限的各种方式。
如果你想要的实际上是跳过你无法访问的路径,你有两种方法:
流
But this example can be expanded to other use cases too.
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;
}
希望对您有所帮助。
没有简单的方法来更改权限。 Java 不擅长这些任务。只有一些技巧,比如在启动时检查权限并尝试通过 su/sudo 更改权限,然后重新启动应用程序或使用 Java-gnome。请在这里阅读更多内容:Java: Ask root privileges on Ubuntu