SSH Output always empty - java

I've been trying to figure out this problem for hours now and I cant seem to figure it out. I'm trying to use JSch to SSH to a Linux computer from an Android phone. The commands always work fine but the output of the channel is usually empty. Sometimes it displays the output but most of the time it doesn't. Here's the code that I found online.
String userName = "user";
String password = "test123";
String connectionIP = "192.168.1.13";
JSch jsch = new JSch();
Session session;
session = jsch.getSession(userName, connectionIP, 22);
session.setPassword(password);
// Avoid asking for key confirmation
Properties prop = new Properties();
prop.put("StrictHostKeyChecking", "no");
session.setConfig(prop);
session.connect();
// SSH Channel
ChannelExec channelssh = (ChannelExec) session.openChannel("exec");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
channelssh.setOutputStream(baos);
// Execute command
channelssh.setCommand("ls");
channelssh.connect();
channelssh.disconnect();
RESULT = baos.toString();
RESULT is usually empty. If I change the command to mkdir or something of that nature the files show up on the Linux computer which leads me to believe that the command part is working correctly. The problem seems to lie within the ByteArrayOutputStream. I've also tested the connectionip, username and password on a different computer through Terminal so I know the credentials are correct. I've Googled this problem to death, any input would help me out significantly!

Found the answer I was reading the wrong stream. Heres the proper code for others with this problem.
InputStream inputStream = channelssh.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null)
{
stringBuilder.append(line);
stringBuilder.append('\n');
}
return stringBuilder.toString();

The exec-channel will be run on the other thread, so you need to wait for its termination before invoking Channel#disconnect().

Related

execute multiple command with jsch session and channelexec

I struggled to get this working but eventually got the script to execute a command (executing a sh script) on a remote unix server. I am trying to execute a second command and keep getting an error either with creating a new channel or using the same.
try {
((ChannelExec) channel).setCommand(command);
PrintStream out= new PrintStream(channel.getOutputStream());
InputStream in = channel.getInputStream();
channel.connect();
BufferedReader scriptReader= new BufferedReader(new InputStreamReader(in));
scriptOutput = scriptReader.readLine();
sb = new StringBuilder();
while ((scriptOutput = scriptReader.readLine())!= null) {
sb.append(scriptOutput + "\n");
This is the first snippet of the channel execute which works fine. Now the next method snippet is called immediately after consuming the above inputstream:
try {
StringBuilder sb = new StringBuilder();
command = new_command;
((ChannelExec) channel).setCommand(command);
InputStream in = channel.getInputStream();
channel.connect();
BufferedReader scriptReader= new BufferedReader(new InputStreamReader(in));
scriptOutput = scriptReader.readLine();
//StringBuilder sb = new StringBuilder();
for(int c=0; c < consumerList.size(); c++){
....
Now this returns the following error:
com.jcraft.jsch.JSchException: channel is not opened.
Now if I create a new channel with the same session I get a null response from returned stream. I did test the command in the remote shell and it works fine:
int counter = 0;
Channel channelII = session.openChannel("exec");
try {
StringBuilder sb = new StringBuilder();
command = new_command;
((ChannelExec) channelII).setCommand(command);
InputStream in = channelII.getInputStream();
channelII.connect();
BufferedReader scriptReader= new BufferedReader(
new InputStreamReader(in));
scriptOutput = scriptReader.readLine();
the second command is the following and I want to be able to repeatedly execute it for different consumer groups:
/usr/kafka/bin/kafka-consumer-groups.sh --bootstrap-server
192.xxx.xx.xxx:9092 --describe -group consumergroup1
EDIT:
response of second command:
TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET
LAG CONSUMER-ID HOST
CLIENT-ID
output.influxDB 1 94919 2781796
2686877 - -
-
output.influxDB 0 94919 2781798
2686879 - -
-
output.influxDB 2 94918 2781795
2686877 - -
-
Thank you to Nicholas and Martin for their responses. I figured out what was wrong and wanted to post an answer as I do realize that little things like this do crop up for us 'dumb' programmers out there who ask ridiculous questions that incur negative votes. The output for the second command was returning a warning / error response in the first line and by not including the following I was not seeing that and reading the next line was empty. I know it's stupid and should have figured this out before posting because that is the point of this site: post questions that are beyond the knowledge of others. But since I should have innately known this:
Anyway ensure the following line is included:
((ChannelExec)channelII).setErrStream(System.err);
and also read the stream with a loop and not just test with reading the first line.
while ((scriptOutput = scriptReader.readLine())!= null) {
sb.append(scriptOutput + "\n");
}
I hope this can at least be a lesson to some if not a solution.

JSch - How to capture stream from remote server using PortForwarding L?

I tried to use InputStream and Buffer[], also BufferedReader, also PipedInputStream. For all cases i got null:
sessionB = jSch.getSession(username, "localhost", forwardedPort);
sessionB.connect();
if(sessionB.isConnected()) {
System.out.println("Connected host B!");
channel = (ChannelExec) sessionB.openChannel("exec");
br = new BufferedReader(new
InputStreamReader(channel.getInputStream()));
((ChannelExec)channel).setCommand("command");
((ChannelExec)channel).setErrStream(System.err);
channel.connect();
if(channel.isConnected()) {
System.out.println("Channel is connected!");
}
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}
And console output:
Connected host A! Connected host B! Channel is connected!
Problem: I got nothing printed (System.out.println(line);)
There is a way to get that stream from exec channel over portforwarding ? Thanks for your help
get/setInputStream and get/setOutputStream only concern the standard input/output of the command, nothing to do with port forwarding.
The port forwarding is done through two functions setPortForwardingL and setPortForwardingR.
You should have something like that in your code.
int assinged_port=session.setPortForwardingL(lport, rhost, rport);
As always, there is very few documentation on JSCH but a lot of detailed examples for L forwarding and R forwarding
The port forwarding is done on the session so I'm not sure you also need an active connection. But if you do, you should consider opening a 'shell' connection instead of an 'exec'. Then you wouldn't have to run a useless command just to maintain the connection.
PS: Some code is missing so it's difficult to say something precise on the example given in the question.
Thanks for your help. I solved it using Pipes, i share what i did:
PipedInputStream en = new PipedInputStream();
pin = new PipedOutputStream((PipedInputStream) en);
BufferedReader br = new BufferedReader(new InputStreamReader((PipedInputStream)
channel.getInputStream()));
channel.connect(5*1000);
String received=null;
while((received=br.readLine())!=null) {
System.out.println(received);
}

How to run Jsch multiple commands from shell-channel using String input instead of console

I am writing a program using JSch library, and have to open a shell channel and execute few commands that are stored in String.
I need to feed the input commands from String variable rather than console.
I have come across a post Jsch : Command Output unavailable
In code given, its working fine for commands like pwd,whoami etc, but its going for a hang when i am trying to do a sudo -u hiveuser -i.
Here is the code:
public static void main(String[] args) throws Exception
{
JSch jsch = new JSch();
String host = "my.host.server";
String user = "myLoginId";
String pswd = "myPASSword";
Session session=jsch.getSession(user,host, 22);
session.setPassword(pswd);
session.setConfig("StrictHostKeyChecking", "no");
session.setConfig("PreferredAuthentications","publickey,keyboard-interactive,password");
session.connect();
System.out.println("Connected");
Channel channel = session.openChannel("shell");
OutputStream ops = channel.getOutputStream();
PrintStream ps = new PrintStream(ops);
channel.connect();
ps.println("sudo -iu hiveuser");
ps.println(pswd);
ps.println("hive");
ps.println("desc table myHiveTable;");
ps.flush();
ps.close();
InputStream in = channel.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
System.out.println("Opening...");
String jarOutput;
while ((jarOutput = reader.readLine()) != null)
System.out.println(jarOutput);
reader.close();
channel.disconnect();
session.disconnect();
}
You could try echoing in the password:
echo password | sudo -iu hiveuser --stdin

Providing input/subcommands to command executed over SSH with JSch

I'm trying to manage router via Java application using Jcraft Jsch library.
I'm trying to send Router Config via TFTP server. The problem is in my Java code because this works with PuTTY.
This my Java code:
int port=22;
String name ="R1";
String ip ="192.168.18.100";
String password ="root";
JSch jsch = new JSch();
Session session = jsch.getSession(name, ip, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
System.out.println("Establishing Connection...");
session.connect();
System.out.println("Connection established.");
ChannelExec channelExec = (ChannelExec)session.openChannel("exec");
InputStream in = channelExec.getInputStream();
channelExec.setCommand("enable");
channelExec.setCommand("copy run tftp : ");
//Setting the ip of TFTP server
channelExec.setCommand("192.168.50.1 : ");
// Setting the name of file
channelExec.setCommand("Config.txt ");
channelExec.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
int index = 0;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
session.disconnect();
I get
Line has an invalid autocommand '192.168.50.1'
The problem is how can I run those successive commands.
Calling ChannelExec.setCommand multiple times has no effect.
And even if it had, I'd guess that the 192.168.50.1 : and Config.txt are not commands, but inputs to the copy run tftp : command, aren't they?
If that's the case, you need to write them to the command input.
Something like this:
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channelExec.setCommand("copy run tftp : ");
OutputStream out = channelExec.getOutputStream();
channelExec.connect();
out.write(("192.168.50.1 : \n").getBytes());
out.write(("Config.txt \n").getBytes());
out.flush();
In general, it's always better to check if the command has better "API" than feeding the commands to input. Commands usually have command-line arguments/switches that serve the desired purpose better.
A related question: Provide inputs to individual prompts separately with JSch.

pass enter key from Java to Shell script

I am trying a Java program to run multiple commands in unix environment. I would need to pass 'ENTER' after each command. Is there some way to pass enter in the InputStream.
JSch jsch=new JSch();
Session session=jsch.getSession("MYUSERNAME", "SERVER", 22);
session.setPassword("MYPASSWORD");
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
Channel channel= session.openChannel("shell");
channel.setInputStream(getInputStream("ls -l"));
channel.setInputStream(getInputStream("\r\n"));
channel.setInputStream(getInputStream("pwd"));
channel.setInputStream(getInputStream("\r\n"));
channel.connect();
When I do ls -l, I want to add enter here, so that the command is executed.
getInputStream is a method to convert String into InputStream.
Any help will be appreciated.
According to the JSch javadoc, you must call setInputStream() or getOutputStream() before connect(). You can only do one of these, once.
For your purposes, getOutputStream() seems more appropriate. Once you have an OutputStream, you can wrap it in a PrintWriter to make sending commands easier.
Similarly you can use channel.getInputStream() to acquire an InputStream from which you can read results.
OutputStream os = channel.getOutputStream();
PrintWriter writer = new PrintWriter(os);
InputStream is = channel.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
channel.connect();
writer.println("ls -l");
String response = reader.readLine();
while(response != null) {
// do something with response
response = reader.readLine();
}
writer.println("pwd");
If you're determined to use setInputStream() instead of getOutputStream() then you can only do that once, so you'll have to put all your lines into one String:
channel.setInputStream(getInputStream("ls -l\npwd\n"));
(I don't think you need \r, but add it back in if necessary)
If you're not familiar with working with streams, writers and readers, do some study on these before working with JSch.

Categories