简体   繁体   English

Java应用程序是否有获得root权限的方法?

[英]Is there a way for a Java app to gain root permissions?

When running Files.walk(Paths.get("/var/")).count() as an unprivileged user, the execution might throw an exception as there are folders inside /var/ that need root permission to be traversed. 当运行Files.walk(Paths.get("/var/")).count()作为非特权用户时,执行可能会抛出异常,因为/var/中的文件夹需要遍历root权限。

I am not looking for a way to execute a bash command as root (eg sudo find /var ), using Process , etc. 不是在寻找一种以root身份执行bash命令的方法(例如sudo find /var ),使用Process等。

I just want to make sure Files.walk(Paths.get("/var/")).count() does not throw an AccessDeniedException : 我只想确保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

This is just an example. 这只是一个例子。 Using filter(...) it is possible to work around the exception. 使用filter(...)可以解决异常问题。 But this example can be expanded to other use cases too. 但是这个例子也可以扩展到其他用例。

So in short Is this possible at all, for CLI, JavaFX, etc. apps to gain root permission after they have been executed from command line via a method such as java -jar app.jar ? 所以简而言之这是否可能,CLI,JavaFX等应用程序在通过java -jar app.jar等方法从命令行执行后获得root权限?

If what you want is actually skipping the paths where you have no access, you have two approaches: 如果你想要的实际上是跳过你无法访问的路径,你有两种方法:

Streams

In the answer to this question it is explained how to obtain the stream of all files of a subtree you can access. 在这个问题的答案中,解释了如何获取可以访问的子树的所有文件的流。

But this example can be expanded to other use cases too. 但是这个例子也可以扩展到其他用例。

FileVisitor FileVisitor的

Using a FileVisitor adds a lot of code, but grants you much more flexibility when walking directory trees. 使用FileVisitor会添加大量代码,但在处理目录树时可以提供更大的灵活性。 To solve the same problem you can replace Files.walk() with: 要解决同样的问题,您可以将Files.walk()替换为:

Files.walkFileTree(Path start, FileVisitor<? super Path> visitor);

extending SimpleFileVisitor (to count the files) and overriding some methods. 扩展SimpleFileVisitor(计算文件)并覆盖一些方法。

You can: 您可以:

  1. Override the visitFileFailed method, to handle the case you cannot access a file for some reasons; 覆盖visitFileFailed方法,处理由于某些原因无法访问文件的情况; (Lukasz_Plawny's advice) (Lukasz_Plawny的建议)
  2. (optional) Override the preVisitDirectory method, checking for permissions before accessing the directory: if you can't access it, you can simply skip its subtree (keep in mind that you may be able to access a directory, but not all its files); (可选)覆盖preVisitDirectory方法,在访问目录之前检查权限:如果无法访问它,则可以简单地跳过其子树(请记住,您可以访问目录,但不能访问其所有文件) ;

eg 1 例如1

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
    // you can log the exception 'exc'
    return FileVisitResult.SKIP_SUBTREE;
}

eg 2 例如2

@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {

    if(!Files.isReadable(dir))
        return FileVisitResult.SKIP_SUBTREE;

    return FileVisitResult.CONTINUE;

}

FileVisitor docs FileVisitor文档

FileVisitor tutorial FileVisitor教程

Hope it helps. 希望能帮助到你。

Just a few completely untested ideas: 只是一些完全没有经过考验的想法:

1) Run your app with root priviledges to begin with: 1)使用root权限运行您的应用程序以开始:

sudo java -jar myapp.jar

2) Let your app start a launcher-class that requests root permissions and then continues running the rest of your app: 2)让你的应用启动一个请求root权限的启动器类,然后继续运行你的应用程序的其余部分:

java -jar myapp.jar

This in turn does execute a shell command, but only an xterm that prompts for root password, and then continues to run a java program with root permissions: 这反过来执行一个shell命令,但只有一个提示root密码的xterm,然后继续运行具有root权限的java程序:

xterm -e "sudo sh -c 'java -jar /tmp/myrootapp.jar'"

or perhaps use something nicer-looking using gksudo. 或者使用gksudo使用更好看的东西。 Mind the ' and " . 记住'"

Maybe the myapp.jar extracts itself into a temporary directory . 也许myapp.jar自己提取到一个临时目录中 myapp.jar contains myrootapp.jar and thus it can launch it as described above. myapp.jar包含myrootapp.jar ,因此它可以如上所述启动它。 /tmp should of course be retrieved from within java, and preferably be a directory with a random name that only the user running myapp.jar has access to in order to prevent myrootapp.jar injection. /tmp当然应该从java中检索,并且最好是具有随机名称的目录,只有运行myapp.jar的用户才能访问以防止myrootapp.jar注入。

Cross-platform 跨平台

You mentioned /var/ yourself, so I assumed you were on some sort of Linux. 你提到/var/你自己,所以我以为你是在某种Linux上。 If this is supposed to work cross-platform, eg on Macintosh or Microsoft Windows too, you need to do some sort of system identification first. 如果这应该跨平台工作,例如在Macintosh或Microsoft Windows上,则需要先进行某种系统识别。 Then you can apply StrategyPattern in code to handle the various ways of letting myrootapp.jar obtain root or administrator permissions. 然后,您可以在代码中应用StrategyPattern来处理让myrootapp.jar获取root权限或管理员权限的各种方法。

There is no easy way to change permissions. 没有简单的方法来更改权限。 Java is not good at these tasks. Java并不擅长这些任务。 There are only some tricks like check permissions on start and try to change permissions via su/sudo then restart application or using Java-gnome. 在启动时只有一些技巧,如检查权限,并尝试通过su / sudo更改权限,然后重新启动应用程序或使用Java-gnome。 Please read a bit more here: Java: Ask root privileges on Ubuntu 请在这里阅读更多内容: Java:在Ubuntu上询问root权限

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM