28

I'm using ProcessBuilder to execute bash commands:

import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try {
            Process pb = new ProcessBuilder("gedit").start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

But I want to make something like this:

Process pb = new ProcessBuilder("sudo", "gedit").start();

How to pass superuser password to bash?

("gksudo", "gedit") will not do the trick, because it was deleted since Ubuntu 13.04 and I need to do this with available by default commands.

EDIT

gksudo came back to Ubuntu 13.04 with the last update.

Vare Zon
  • 309
  • 1
  • 6
  • 13
  • 1
    What a GREAT idea to remove gksudo! Congratulations, Ubuntu! As a workaround I can suggest ``xterm -e 'sudo -i gedit'``. Or install ``gksu`` package. Or even run your whole java program as root. – Aleks-Daniel Jakimenko-A. Sep 09 '13 at 22:39
  • @Aleks-DanielJakimenko using xterm is actually a good idea... Thanks. `sudo app.jar` will work as it should? From the opening application to closing it? – Vare Zon Sep 09 '13 at 22:52
  • Yeah, ``sudo app.jar`` should give it sudo priveleges for everything. Just note that everything you do is going to be under root, so if you create a file from your java program it wont be visible to other users because user will have no privileges for it. Just take care of it. – Aleks-Daniel Jakimenko-A. Sep 09 '13 at 22:55
  • 3
    Solution here: http://codeflex.co/java-run-sudo-command-on-remote-linux-host/ – JavaGoPro Mar 08 '18 at 14:54

6 Answers6

42

I think you can use this, but I'm a bit hesitant to post it. So I'll just say:

Use this at your own risk, not recommended, don't sue me, etc...

public static void main(String[] args) throws IOException {

    String[] cmd = {"/bin/bash","-c","echo password| sudo -S ls"};
    Process pb = Runtime.getRuntime().exec(cmd);

    String line;
    BufferedReader input = new BufferedReader(new InputStreamReader(pb.getInputStream()));
    while ((line = input.readLine()) != null) {
        System.out.println(line);
    }
    input.close();
}
Erik Pragt
  • 13,513
  • 11
  • 58
  • 64
  • `Exception in thread "main" java.io.IOException: Cannot run program "/bash/bin": error=2` When I changed `/bash/bin` to `bash` it compiles without errors but with any effect at all. – Vare Zon Sep 09 '13 at 23:16
  • Yes, that's because 'echo password' should be replaced by echoing your real password. I fixed the /bin/bash thing also. – Erik Pragt Sep 09 '13 at 23:17
  • I know that I should replace it and I did ;) Still not working. It is just and nothing happens. – Vare Zon Sep 09 '13 at 23:23
  • 4
    Ok, now it is working :) `{"/bin/bash","-c","echo \"password\"| sudo -S ls"};` Thank you. – Vare Zon Sep 09 '13 at 23:30
  • 1
    Yeah, I also just tested it again! For me it was working/not working because my sudo was remembering me. Uncached it using sudo -K. Could you upvote so people know this is the answer? – Erik Pragt Sep 09 '13 at 23:32
  • Btw, I didn't have to escape the quotes, not sure if that's needed. Glad it works! – Erik Pragt Sep 09 '13 at 23:33
  • @EricPragt It requires 15 reputation :( But I accepted this answer :) – Vare Zon Sep 09 '13 at 23:34
  • 1
    This `String[] cmd = {"/bin/bash","-c","echo password| sudo -S ls"};` works perfectly for me! Thanks!! –  Mar 21 '16 at 12:53
  • 2
    This code works perfectly, but is not a good solution, because it exposes the password in the command line and other process can see it. – kato2 Nov 23 '16 at 23:21
  • @passerbywhu this comment made my day :-) Thanks for saying that! – Erik Pragt Feb 27 '20 at 13:12
  • @kato2 / All, I could see only the "sudo -S " and the child process in the process list. I could not see the password that is being echoed here. Do we have any ways of checking it? and do we have any other possible solution that is industry standard? Note : I do not hard code the password & is echoed from a different input source. – Sree Karthik S R Dec 30 '20 at 13:59
14

Edit /etc/sudoers with visudo and grant your user a NOPASSWD right for a specific script:

username ALL=(ALL) NOPASSWD: /opt/yourscript.sh

JointEffort
  • 583
  • 7
  • 21
9

My solution, doesn't exposes the password in the command line, it just feed the password to the output stream of the process. This is a more flexible solution because allows you to request the password to the user when it is needed.

public static boolean runWithPrivileges() {
    InputStreamReader input;
    OutputStreamWriter output;

    try {
        //Create the process and start it.
        Process pb = new ProcessBuilder(new String[]{"/bin/bash", "-c", "/usr/bin/sudo -S /bin/cat /etc/sudoers 2>&1"}).start();
        output = new OutputStreamWriter(pb.getOutputStream());
        input = new InputStreamReader(pb.getInputStream());

        int bytes, tryies = 0;
        char buffer[] = new char[1024];
        while ((bytes = input.read(buffer, 0, 1024)) != -1) {
            if(bytes == 0)
                continue;
            //Output the data to console, for debug purposes
            String data = String.valueOf(buffer, 0, bytes);
            System.out.println(data);
            // Check for password request
            if (data.contains("[sudo] password")) {
                // Here you can request the password to user using JOPtionPane or System.console().readPassword();
                // I'm just hard coding the password, but in real it's not good.
                char password[] = new char[]{'t','e','s','t'};
                output.write(password);
                output.write('\n');
                output.flush();
                // erase password data, to avoid security issues.
                Arrays.fill(password, '\0');
                tryies++;
            }
        }

        return tryies < 3;
    } catch (IOException ex) {
    }

    return false;
}
kato2
  • 535
  • 4
  • 15
  • By slightly modifying the Code I think this does the best job. What I do especially like about this solution is the security issue being solved as you do not print the password in the Console directly. – Cedric Nov 28 '18 at 17:38
7

Do not try to write a system password plainly in a file, especially for a user that have the sudo privilege, just as @jointEffort answered, issued privilege should be solved by system administrators not by app writers.

sudo allow you to grant privileges for specific command to specific user, which is precisely enough, check this post

and you can choose to manage the privilege in a separated file other than the main sudoers file if you want just append #includedirs /etc/sudoers.d/ in the main /etc/sudoers file(most Linux distributions have already done that) and make a file like ifconfig-user with:

 USER_NAME ALL=(ALL) NOPASSWD: /sbin/ifconfig

Another thing, remember to edit the config file with visudo in case you lost control of your system when there is syntax error.

Christophe Roussy
  • 16,299
  • 4
  • 85
  • 85
armnotstrong
  • 8,605
  • 16
  • 65
  • 130
2

I know this is an old thread but i just want to put this here:

you can use sudo -S *command* as a command that you pass to create the Process instance. Then get the output stream and write the password to it, and add at the end of it a new line and a c. return (\n\r). The return may not be required but i passed it just in case. Also it is a good idea to flush the stream, to make sure everything is written to it. I've done it a few times and it works like a charm. And DO NOT forget to close streams :).

fedorqui
  • 275,237
  • 103
  • 548
  • 598
mcrius
  • 21
  • 1
1

Once you spawn a process you can extract the input and output streams. Just feed the password to the output stream (you output it into the proccess's input). So the code would look something like -

Process pb = new ProcessBuilder("gedit").start();
OutputStream out = pb.getOutputStream();
out.write(password);
David says Reinstate Monica
  • 19,209
  • 22
  • 79
  • 122
  • 1
    Actually, that won't work. The sudo command needs to get the command from the actual keyboard, not from an input stream... – Erik Pragt Sep 09 '13 at 22:57
  • @ErikPragt Are you sure? I've never heard of something like that. From what I understand the sudo command shouldnt have a clue where its coming from, it just gets it from an input stream and thats it. – David says Reinstate Monica Sep 09 '13 at 22:57
  • 2
    Well, if you look at the -S option in Sudo, I think that sort of implies that: "-S The -S (stdin) option causes sudo to read the password from the standard input instead of the terminal device. The password must be followed by a newline character.". That is, unless I read this wrong. But no, I'm not sure. – Erik Pragt Sep 09 '13 at 23:00
  • @ErikPragt So he can just tack on a newline char at the end of the output. – David says Reinstate Monica Sep 09 '13 at 23:02
  • 1
    @Dgrin91, I tried your solution on my mac, but it doesn't work, the password is not passed to the process. See here: https://gist.github.com/bodiam/6502781 – Erik Pragt Sep 09 '13 at 23:14
  • @VareZon Not really sure. Try putting a newline at the end. It could very well be that Erik is right. – David says Reinstate Monica Sep 09 '13 at 23:17
  • this works just fine with `sudo -S`. Also see @kato2's answer. – Jorn Jan 13 '20 at 16:06