如何在java中为OS X运行sudo命令

时间:2016-05-23 10:12:42

标签: java bash macos

我正在使用javafx中的app,我正在尝试使用终端中的命令打开一个应用程序,我正在使用我的java代码运行命令我的命令有一些变量它有我的安装程序文件的路径并不总是相同,因为更新版本时文件名可能不同 这是一个示例,因为我正在运行命令,它不是我正在运行的确切命令,但命令格式是相同的。

Process process = Runtime.getRuntime().exec("echo password | sudo -S open -a safari");
    String line;
    BufferedReader input = new BufferedReader(new InputStreamReader(pb.getInputStream()));
    while ((line = input.readLine()) != null) {
        System.out.println(line);
    }
    input.close();

该过程没有给出任何输出它停在那里没有任何反应。 我从终端试过的同样的命令,它工作正常。

我已尝试过此链接中提及的内容

How to execute bash command with sudo privileges in Java?

但它也没有奏效。

我也在运行命令,如" chmod + x"从我的java代码这些命令运行正常。 我的原始命令如下所示: -

runCommand = "echo" + " " + password + "| sudo -S " + "\"" + a.getAbsolutePath() + "\"" + " --deploymentFile="
                            + "\"" + b.getAbsolutePath() + "\"";

其中a.getAbsolutePath()是安装程序文件的路径,b.getAbsolutePath()是我们用于安装应用程序的部署文件的路径。

pb.getInputStream()

打印命令,当我复制并粘贴它时终端运行正常。

pb.getErrorStream()

没有任何帮助。

我试过了

String[] cmd = {"/bin/bash","-c","echo tester| sudo -S ","\"",a.getAbsolutePath(),"\"","\""," --deploymentFile=","\"",b.getAbsolutePath()};

String[] cmd = {"/bin/bash","-c","echo tester| sudo -S",a.getAbsolutePath(),"--deploymentFile=","\"",b.getAbsolutePath()};

也 这里我得到了以下错误

getErrorStreamusage: sudo -h | -K | -k | -L | -V
getErrorStreamusage: sudo -v [-AknS] [-g groupname|#gid] [-p prompt] [-u user name|#uid]
getErrorStreamusage: sudo -l[l] [-AknS] [-g groupname|#gid] [-p prompt] [-U user name] [-u
getErrorStream            user name|#uid] [-g groupname|#gid] [command]
getErrorStreamusage: sudo [-AbEHknPS] [-C fd] [-g groupname|#gid] [-p prompt] [-u user
getErrorStream            name|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] [<command>]
getErrorStreamusage: sudo -e [-AknS] [-C fd] [-g groupname|#gid] [-p prompt] [-u user
getErrorStream            name|#uid] file ...

5 个答案:

答案 0 :(得分:10)

<强>须藤

我强烈建议编辑sudoers文件,并允许运行应用程序的用户通过sudo使用特定命令而不提示输入密码,而不是进行echo passwd | sudo ...构造。

这样就可以避免在应用程序或配置文件中以明文(或最好稍微混淆)存储密码,并且您无需使用调用sudo等的shell脚本调用shell。

可以通过命令visudo编辑Sudoers。在这里看一下它是如何在unbuntu上完成的例子,但它在任何unix上都是一样的。 https://askubuntu.com/questions/159007/how-do-i-run-specific-sudo-commands-without-a-password

其他参考:https://www.sudo.ws/man/1.8.16/sudoers.man.html

我认为你虽然提出了错误的问题......

Mac上的授权

在需要执行需要额外权限的操作的mac应用程序上,不应该使用sudo来开始。

应用程序应该使用授权服务。

参考文献:

答案 1 :(得分:3)

我认为你必须使用应用程序的完整路径。这应该有效:

Runtime rt = Runtime.getRuntime();
rt.exec("echo password | sudo -S open -a /Applications/Safari.app");

<强>更新

根据您的评论,您可以尝试拆分该过程。 open需要交互式会话的机会很大。

创建一个脚本(例如openSafari.sh),以用户身份打开Safari。

#!/etc/bash
echo $1 | sudo -S open -a /Applications/Safari.app &

使其可执行:chmod +x openSafari.sh,并从java调用该脚本。

Runtime rt = Runtime.getRuntime();
rt.exec("/pathTo/openSafari.sh 'sudoPassword'");

答案 2 :(得分:3)

我会建议这样做 - 如果你破坏了东西,不要对我大喊大叫:)

但你要求的是:

String[] cmd = {"/bin/bash","-c","echo password | sudo -S open -a <path to app>"};
Process pb = Runtime.getRuntime().exec(cmd);

答案 3 :(得分:3)

Runtime.exec()方法直接运行给定命令 ,而不是通过shell运行。您使用的特定重载会在空白处对命令进行标记,并将生成的标记解释为命令的名称和参数。调用执行的唯一命令......

Runtime.getRuntime().exec("echo password | sudo -S open -a safari");

...因此echo;其他一切都是争论。结果是进程的标准输出的以下输出:

  

密码| sudo -S open -a safari

至少有几种方法可以实现您想要的效果。对原始代码的最简单修改可能是

Process process = Runtime.getRuntime().exec(
        new String[] { "bash", "-c", "echo password | sudo -S open -a safari" });

通过显式调用shell来运行命令,从而实现了您的想法。

但这是一个重大的安全风险 ,因为密码将以明文形式显示在进程列表中。您可以直接让您的Java程序输入密码,然后避免涉及bash

Process process = Runtime.getRuntime().exec("/usr/bin/sudo -S open -a safari");
Writer toSudo = new OutputStreamWriter(process.getOutputStream());
String password = "password";

toSudo.write(password);
toSudo.write('\n');  // sudo's docs demand a newline after the password
toSudo.close();      // but closing the stream might be sufficient

其他考虑因素:

  • 如所示,给出sudo命令的完整路径是明智的,以避免运行在路径中首先发现的不同sudo。由于您要为特权帐户提供密码,因此尽量减少运行恶意程序的可能性非常重要。

  • 避免在程序或配置文件中存储密码也是明智的。因此,涉及向sudo提供密码的解决方案还应包括以交互方式从用户输入密码。

  • 具有安全意识的Java程序通常更喜欢将密码保存在char数组而不是String中,以便在不再需要时可以主动擦除密码。 String无法更改,并且它们可能无限期地在虚拟机内部停留(甚至比许多其他对象更多)。

  • 一般来说,无论您是否对内容做任何事情,都需要同时消耗Process的输入和错误流。如果您不这样做,那么外部进程可能会阻塞和/或可能无法退出。然而,这可能不是safari的问题,因为我认为它通常不会在这些流上产生任何输出。

答案 4 :(得分:0)

也许可以使用这个

How to setup a SUDO_ASKPASS environment variable?

您可以在流程调用

中设置SUDO_PROMPT环境变量

将其与你如何使用jon bollinger,maciej等进程的修复结合起来。

然后为您的用户提供密码提示,或者使用您的凭据访问pki。 (对于上帝的爱,至少aes会加密它,如果你去pki)

正如你所说,这是为了在其他机器上运行,它基本上是一个糟糕的uac提示,这听起来不像是一个非常mac / linux的解决方案。 swa66是最好的方式,但这会很快而且很脏。