2

Following this I have a JAVA code to do sudo -l, but it always hung. Btw, regardless if I use

Reader stdOut = new InputStreamReader (p.getInputStream ())

or

Reader stdOut = new InputStreamReader (p.getErrorStream ())

The output "[sudo] password for john" seems wasn't read by my code. Where did come from?

Here is my code

     Process p= Runtime.getRuntime ().exec (new String[] {"sudo", "-l"});

     Reader stdOut = new InputStreamReader (p.getErrorStream ());
     BufferedReader reader = new BufferedReader(stdOut);

     StringBuffer output = new StringBuffer();
     String line = "";           
     while ((line = reader.readLine())!= null) {
         System.out.println("$$" + line);
         if (line.contains ("password"))  {
               break;
         }
     }

    OutputStream stdIn = p.getOutputStream ();
    stdIn.write ("<my password>\n".getBytes ("US-ASCII"));
    stdIn.flush ();

     while ((line = reader.readLine())!= null) {
         System.out.println(line);
     }
Community
  • 1
  • 1
johnsam
  • 4,192
  • 8
  • 39
  • 58

2 Answers2

1

Sudo normally opens /dev/tty to prompt for and read a password. Redirecting standard input or standard output doesn't affect the tty associated with the process.

Try running sudo with the -S parameter. It causes sudo to write the prompt to standard error and read the password from standard input. See the sudo manual.

Kenster
  • 23,465
  • 21
  • 80
  • 106
  • Not sure why opening /dev/tty is a good idea. Wonder if sudo better uses -S as the default behavior. – johnsam Dec 13 '14 at 18:35
1

readLine blocks until end of line or end of stream is reached, but sudo does not print a line feed or carriage return after password.

So you should read the stream char by char like so:

String line;
char c;
do {
    line = null;
    while ((c = (char) p.getInputStream().read()) != -1) {
      if(c == '\r' || c == '\n') {
          break;
      }
      if(line==null){
          line="";
      }
      line+=String.valueOf(c);
        if (line != null) { 
            if(line.contains("password")) {//Attention: Ask for the very last word,
                                          //including ':' if sudo prints that out
                break;
            }
        }
    }
    if (line != null) { 
        System.out.println("$$" + line);
        if(line.contains("password")) {//Attention: Ask for the very last word,
                                       //including ':' if sudo prints that out
            break;
        }
    }
}while(c != -1);

I think this will work, but also I am sure that the code could written clearer.
Also you should think about using ProcessBuilder, than you are able to merge the output and the error stream

ProcessBuilder.redirectErrorStream(true)
Gren
  • 1,850
  • 1
  • 11
  • 16