10

I am trying to connect my remote unix machine and execute some ssh commands using a java program.

connection = new Connection(hostname);                                                  
connection.connect();
boolean isAuthenticated = connection.authenticateWithPassword(username, password);
if (isAuthenticated == false)
    throw new IOException("Authentication failed.");    
Session session = connection.openSession();
session.execCommand("sudo su - weblogic");  

Here it needs password again & ofcrs, I can't provide because there is no terminal. So created a user.sh file @ my unix user home direcotry (/home/..../bharat) with below content.

echo <mypassword> | sudo -S su - weblogic
sudo -S su - weblogic

but now if I call bash user.sh like below

session.execCommand("bash user.sh"); 

after logging in with my user in java, it gives below error & could not figure out the resolution for this yet.

sudo: sorry, you must have a tty to run sudo
sudo: sorry, you must have a tty to run sudo

Please help :)

The Response of Send("cd /u02/app/oracle/xyz/admin/domains/11.1.1.9/xxxx_xx_xxx_xxx.domain/shared/logs/xxxx"); is below -

Highlighted Red ==> shows the response, I am getting as of now.

Highlighted Blue ==> Expected response.

Highlighted Green ==> works fine if I send 4 smaller commands by splitting the same command.

enter image description here

Bharat
  • 750
  • 1
  • 9
  • 20

1 Answers1

5

As you and @rkosegi say, su needs a terminal session for the password.

It looks like the Ganymed SSH-2 library in the example? This has an option for a shell session. Clearly you now need to handle reading and writing through stdout and stdin directly though.

For example, with a couple of methods to keep it simpler:

public class SshTerminal {
    private Connection connection;
    private Session session;

    private Reader reader;
    private PrintWriter writer;
    private String lastResponse;

    public SshTerminal(String hostname, String username, String password)
            throws JSchException, IOException {
        connection = new Connection(hostname);
        connection.connect();
        boolean isAuthenticated = connection.authenticateWithPassword(username,
                password);
        if (isAuthenticated == false)
            throw new IOException("Authentication failed.");
        session = connection.openSession();
        session.requestDumbPTY();
        session.startShell();

        writer = new PrintWriter(session.getStdin());
        reader = new InputStreamReader(session.getStdout());
    }

    public void send(String command) {
        writer.print(command + "\n");
        writer.flush();
    }

    public void waitFor(String expected) throws IOException {
        StringBuilder buf = new StringBuilder();
        char[] chars = new char[256];
        while (buf.indexOf(expected) < 0) {
            int length = reader.read(chars);
            System.out.print(new String(chars, 0, length));
            buf.append(chars, 0, length);
        }

        int echoEnd = buf.indexOf("\n");
        int nextPrompt = buf.lastIndexOf("\n");
        if (nextPrompt > echoEnd)
            lastResponse = buf.substring(echoEnd + 1, nextPrompt);
        else
            lastResponse = "";
    }

    public String getLastResponse() {
        return lastResponse;
    }

    public void disconnect() {
        session.close();
        connection.close();
    }
}

This then worked fine:

    SshTerminal term = new SshTerminal(host, username, password);

    term.waitFor("$ ");
    term.send("su -");
    term.waitFor("Password: ");
    term.send(rootPassword);
    term.waitFor("# ");
    term.send("ls /root");
    term.waitFor("# ");
    term.send("cat /file-not-found 2>&1");
    term.waitFor("# ");

    term.send("cat /var/log/messages");
    term.waitFor("# ");
    String logFileContent = term.getLastResponse();

    term.send("exit");
    term.waitFor("$ ");
    term.send("exit");

    term.disconnect();

    String[] lines = logFileContent.split("\n");
    for (int i = 0; i < lines.length; i++)
        logger.info("Line {} out of {}: {}", i + 1, lines.length, lines[i]);

That includes examples of parsing the lines in a response, and forcing error output through.

Clearly some of the responses there might be different in your environment.

df778899
  • 10,703
  • 1
  • 24
  • 36
  • Thx a lot man for giving your time & replying. I will surely try this and let you know. :) – Bharat Jun 10 '18 at 15:17
  • Sir your solution works fine. However there are 2 problem I am facing. [1] I wanted to read line by line so that I can use log4j to print 1 line of out to 1 line of log. [2] "waitFor" method prints only the output NOT in case of error something. I tried everything i knew, could not get it done. Please help man :) – Bharat Jun 12 '18 at 06:38
  • 1
    Hopefully the update to the answer has examples of both parsing lines, and seeing error output. Note the extra bit of code in `waitFor()` to store the `lastResponse`. For the error output, the simplest way to read both `stdout` and `stderr` is probably to redirect `stderr` (stream 2) to `stdout` (stream 1) from the command line - look for the `2>&1` in the example. That said, I didn't need to do special anything to see error output here, so not certain if that's the problem. – df778899 Jun 12 '18 at 19:03
  • Sir, I am dealing with a very wearied problem. PFB : I am hitting "send("cd /u02/app/oracle/xyz/admin/domains/11.1.1.9/xxxx_xx_xxx_xxx.domain/shared/logs/xxxx"); then wait method prints some wearied strings in between whenever commands exceeds a specific length. – Bharat Jun 20 '18 at 09:11
  • I am attaching the image of the response I got form the above command. – Bharat Jun 20 '18 at 09:15
  • Please let me know what do you think sir :) – Bharat Jun 20 '18 at 09:23
  • 1
    Sounds like the terminal width - the command prompt is trying to scroll the text of the command. The `session.requestDumbPTY();` defaults this, so it may work to specify a large width directly - e.g. `session.requestPTY("dumb", 500, 0, 0, 0, null);` instead. – df778899 Jun 20 '18 at 18:13