user1700434
user1700434

Reputation: 151

sudo commands with JAVA/shellscripts

I am trying to do a simple shutdown program in JAVA and I can't believe that I couldn't find an answer to this anywhere else.

I first tried using sudo in my java program:

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class themain{
public static void main(String[] args){
    Process ls=null;
    BufferedReader input=null;
    String line=null;
    String[] cmd = {"sudo shutdown -h +20"};


        try {

               ls= Runtime.getRuntime().exec(cmd);
               input = new BufferedReader(new InputStreamReader(ls.getInputStream()));

            } catch (IOException e1) {
                e1.printStackTrace();  
                System.exit(1);
            }


           try {
                   while( (line=input.readLine())!=null)
                    System.out.println(line);

            } catch (IOException e1) {
                e1.printStackTrace();  
                System.exit(0);
            }        
}

} 

Then I tried executing a shell script with this code in it:

 sudo shutdown -h +20

The new java program now looked like this:

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class themain{
public static void main(String[] args){
    Process ls=null;
    BufferedReader input=null;
    String line=null;
    String[] cmd = {"sh shutdown.sh"};


        try {

               ls= Runtime.getRuntime().exec(cmd);
               input = new BufferedReader(new InputStreamReader(ls.getInputStream()));

            } catch (IOException e1) {
                e1.printStackTrace();  
                System.exit(1);
            }


           try {
                   while( (line=input.readLine())!=null)
                    System.out.println(line);

            } catch (IOException e1) {
                e1.printStackTrace();  
                System.exit(0);
            }        
}

}

This of course didn't work either... Is there anyway I could invoke a password graphical password prompt? And I want this program to work on every computer, so I don't want to mess up my individual sudoers file...

Regards, and thanks

Upvotes: 1

Views: 5025

Answers (2)

barwnikk
barwnikk

Reputation: 976

package me.barwnikk.library.linuxcommandroot;

import java.awt.BorderLayout;
import java.io.IOException;
import java.io.InputStream;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;

public class LinuxCommand {
    static InputStream is;
    static byte[] buff = new byte[8192];
    static int n;
    public static String getPasswdForRoot() throws IOException {
        Process p = Runtime.getRuntime().exec(new String[]{"sh","-c","sudo -S id"});
        is = p.getErrorStream();
        n = is.read(buff, 0, 8192);
        String text = new String(buff,0,n);
        if(text.contains("root"))return null; //not set password
        JPanel panel = new JPanel(new BorderLayout());
        JLabel lab = new JLabel(text);
        panel.add(lab,BorderLayout.NORTH);
        JPasswordField password = new JPasswordField();
        panel.add(password,BorderLayout.SOUTH);
        JOptionPane.showMessageDialog(null, panel);
        byte[] passwd = (new String(password.getPassword())+"\r\n").getBytes();
        p.getOutputStream().write(passwd);
        p.getOutputStream().flush();
        n = is.read(buff, 0, 8192);
        if(n==-1) return new String(password.getPassword());
        text = new String(buff,0,n);
        while(true) {
            lab.setText(text);
            JOptionPane.showMessageDialog(null, panel);
            p = Runtime.getRuntime().exec(new String[]{"sh","-c","sudo -S id"});
            is = p.getErrorStream();
            n = is.read(buff, 0, 8192);
            passwd = (new String(password.getPassword())+"\n").getBytes();
            p.getOutputStream().write(passwd);
            p.getOutputStream().flush();
            n = is.read(buff, 0, 8192);
            if(n==-1) return new String(password.getPassword());
            text = new String(buff,0,n);
        }
    }
    public static Process runFromRoot(String command, String password) throws IOException {
        byte[] passwd = (password+"\n").getBytes(); //for OutputStream better is byte[]
        Process p = Runtime.getRuntime().exec(new String[]{"sh","-c","sudo -S "+command});
        p.getOutputStream().write(passwd);
        p.getOutputStream().flush();
        return p;
    }
}

It's a mini api to get root password (user must write correct). Sample of usage:

public static void main(String[] args) throws IOException, InterruptedException {
    String password = LinuxCommand.getPasswdForRoot();
    System.out.println("stdout of 'id':");
    Process p = LinuxCommand.runFromRoot("id",password);
    System.out.print(streamToString(p.getInputStream()));
    System.out.println("stdout of 'fdisk -l':");
    p = LinuxCommand.runFromRoot("fdisk -l",password);
    System.out.print(streamToString(p.getInputStream()));
}

Method streamToString:

public static String streamToString(InputStream stream) {
    String read = "";
    try {
        while((n=stream.read(buff, 0, 8192))!=-1) {
            read+=new String(buff,0,n);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return read;
}

Sample return in my test (in polish):

stdout of 'id':
uid=0(root) gid=0(root) grupy=0(root)
stdout of 'fdisk -l':

Disk /dev/sda: 640.1 GB, 640135028736 bytes
głowic: 255, sektorów/ścieżkę: 63, cylindrów: 77825, w sumie sektorów: 1250263728
Jednostka = sektorów, czyli 1 * 512 = 512 bajtów
Rozmiar sektora (logiczny/fizyczny) w bajtach: 512 / 4096
Rozmiar we/wy (minimalny/optymalny) w bajtach: 4096 / 4096
Identyfikator dysku: 0xc56b9eef

Urządzenie Rozruch   Początek      Koniec   Bloków   ID  System
/dev/sda1            2048    37064703    18531328   27  Hidden NTFS WinRE
/dev/sda2   *    37064704    37269503      102400    7  HPFS/NTFS/exFAT
/dev/sda3        37269504   456711884   209721190+   7  HPFS/NTFS/exFAT
/dev/sda4       456711946  1250258624   396773339+   f  W95 Rozsz. (LBA)
Partycja 4 nie zaczyna się na granicy bloku fizycznego.
/dev/sda5       456711948   810350729   176819391    7  HPFS/NTFS/exFAT
Partycja 5 nie zaczyna się na granicy bloku fizycznego.
/dev/sda6       810350793   862802954    26226081    7  HPFS/NTFS/exFAT
Partycja 6 nie zaczyna się na granicy bloku fizycznego.
/dev/sda7       862803018  1020078408    78637695+  83  Linux
Partycja 7 nie zaczyna się na granicy bloku fizycznego.
/dev/sda8      1020079368  1229791814   104856223+   7  HPFS/NTFS/exFAT
/dev/sda9      1229791878  1250258624    10233373+   7  HPFS/NTFS/exFAT
Partycja 9 nie zaczyna się na granicy bloku fizycznego.

For you:

LinuxCommand.runFromRoot("shutdown -h 20",getPasswdForRoot());

This api create and write to Process password.

Upvotes: 0

Brian Agnew
Brian Agnew

Reputation: 272427

Note this thread, and in particular:

The password for 'sudo' needs to be presented thought the keyboard or it needs to be presented though a process defined by the SUDO_ASKPASS environment variable using "sudo -A". By invoking your script through Java your script won't get access to the keyboard so you must set the environment variable to point to a program that returns the password terminated by a "\n". Rather than use 'sudo' directly you can use 'gksudo' which will bring up a dialogue prompting the user for the password. This is my preferred solution.

Upvotes: 2

Related Questions