JNI + setuid问题

时间:2011-05-12 23:15:55

标签: java unix java-native-interface setuid

我有一个以用户www运行的Web应用程序。但是,有一点需要代表用户Alice和Bob从Linux文件系统中读取文件。

执行此操作的一种方法是启动shell(Runtime.exec())并调用C setuid可执行文件来更改userid并读取文件。

有没有办法用JNI实现这个目标(网络应用程序需要以www而不是root身份运行)?我尝试编写一个在Linux上调用本机方法的Java JNI程序(我使这些本机方法由root拥有并设置了setuid位)。但除非我以root身份运行Java程序,否则它不会让我切换用户ID。有什么东西我错过了吗?有没有办法实现这个目标?

谢谢!

2 个答案:

答案 0 :(得分:3)

没有。那没有。 setuidsetgid只能在两种情况下使用(在普通的Linux上):

  1. 该过程是root。
  2. 该过程是从其模式中setuidsetgid位的文件启动的。
  3. 在前一种情况下,该过程可能会毫不犹豫地将这些功能称为采用任何身份。在后一种情况下,我只在父进程的uid / gid和它启动的文件的uid / gid之间来回切换。

    也就是说,如果是setuid,它可以采用文件的uid,如果是setgid,那就是gid。

    由于你在java中,exec-ed程序是java本身,你不希望 是setuid或setgid,除非你想创建一个巨大的安全暴露。< / p>

    您可以编写一个通过JNI调用接口启动JVM的C或C ++程序,并将该程序设置为setuid或setgid,然后在那里调用的JNI代码可以进行适当的切换调用。

答案 1 :(得分:-1)

是的,这是可能的。你可以在这里看到一个例子:

https://github.com/kebernet/pretty/blob/master/src/main/java/com/reachcall/util/SetUID.java

以下是代码示例:

CLibrary INSTANCE = (CLibrary) Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);

   public static int setuid(int uid) {
        if (Platform.isWindows()) {
            return OK;
        }

        return CLibrary.INSTANCE.setuid(uid);
    }

bmargulies的答案不正确(或不完全正确)。 UNIX中的非root进程可以设置uid或gid,如果它具有各自的功能:

http://man7.org/linux/man-pages/man7/capabilities.7.html

  

CAP_SETUID

     
      
  • 对进程UID进行任意操作(setuid(2),               setreuid(2),setresuid(2),setfsuid(2));
  •   

从操作系统的角度来看,您的程序作为“java”进程运行,必须为java可执行文件本身启用此setguid功能:

$ sudo setcap cap_setuid,cap_setgid+ep /usr/java/latest/bin/java

另请注意,java可执行文件所在的文件系统未使用“ nosuid ”选项安装。

回到原来的问题

  
    

网络应用需要以www而非root身份运行

  

通常,让Web服务具有setuid功能并不是一个好主意。 最好将uid放在启动Web应用程序的shell包装器脚本中。