channelExec.setCommand() Not Working when executing shell commands - java

I'm executing .sh file in a remote server and it is not working properly. For that i used JSch and java. and this is how i tried.
ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
InputStream in = channelExec.getInputStream();
channelExec.setCommand("cd /home");

Here is a full example http://myitlearnings.com/java-code-to-run-a-remote-script-on-remote-host-using-ssh/ .
Add this below statement, so the security measure is by passed // By default StrictHostKeyChecking is set to yes as a security measure.
session.setConfig("StrictHostKeyChecking", "no");
Add full code base (ip not required while sharing the code) and error message received. Add Proper exception handling, so we will get to know what is the error you are getting and can assist better

Related

StrictHostChecking with JSCH API [duplicate]

I'm running a java program where I transfer a file from one folder to another, using Java SFTP. The problem I'm having is that I'm getting the following error in my Java SFTP (using JSch) :
C:\Oracle\Middleware\Oracle_Home\oracle_common\jdk\bin\javaw.exe
-server -classpath C:\JDeveloper\mywork\Java_Hello_World.adf;C:\JDeveloper\mywork\Java_Hello_World\Client\classes;C:\Users\ADMIN\Downloads\jsch-0.1.53.jar
-Djavax.net.ssl.trustStore=C:\Users\IBM_AD~1\AppData\Local\Temp\trustStore5840796204189742395.jks
FileTransfer com.jcraft.jsch.JSchException: UnknownHostKey: 127.0.0.1.
RSA key fingerprint is a2:39:3f:44:88:e9:1f:d7:d1:71:f4:85:98:fb:90:dc
at com.jcraft.jsch.Session.checkHost(Session.java:797) at
com.jcraft.jsch.Session.connect(Session.java:342) at
com.jcraft.jsch.Session.connect(Session.java:183) at
FileTransfer.main(FileTransfer.java:33) Process exited with exit code
0.
The following is my code so far:
FileTransfer fileTransfer = new FileTransfer();
JSch jsch = new JSch();
try {
String host = "127.0.0.1";
int port = 22;
String user = "user";
Session session = jsch.getSession(user, host, port);
session = jsch.getSession("username", "127.0.0.1", 22);
session.connect(); // bug here , java.net.ConnectException
ChannelSftp sftp = null;
sftp = (ChannelSftp)session.openChannel("sftp") ; //channel;
//extra config code
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
// end extra config code
sftp.rename("C:\\Users\\ADMIN\\Desktop\\Work\\ConnectOne_Bancorp\\Java_Work\\SFTP_1\\house.bmp", "C:\\Users\\ADMIN\\Desktop\\Work\\ConnectOne_Bancorp\\Java_Work\\SFTP_2\\house.bmp");
session.disconnect();
} catch (JSchException e) {
e.printStackTrace();
} catch (SftpException e) {
e.printStackTrace();
} //end-catch
My Cygwin is set up, and I checked (with netstat -a -b ) that it's running.
You are trying to skip a host key checking by setting StrictHostKeyChecking to no.
But you have to do that before the checking, i.e. before the session.connect().
Anyway, you should never do this, unless you do not care about security. The host key checking is there to protect you from man-in-the-middle attacks.
Instead, set up an expected host key to let JSch verify it.
For example:
Call JSch.setKnownHosts providing a path to a .ssh/known_hosts-like file.
To generate the .ssh/known_hosts-like file, you can use an ssh-keyscan command from OpenSSH. If you are connecting from a *nix server, you should have the command available, just run
ssh-keyscan example.com > known_hosts
It will have a format like:
example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0hVqZOvZ7yWgie9OHdTORJVI5fJJoH1yEGamAd5G3werH0z7e9ybtq1mGUeRkJtea7bzru0ISR0EZ9HIONoGYrDmI7S+BiwpDBUKjva4mAsvzzvsy6Ogy/apkxm6Kbcml8u4wjxaOw3NKzKqeBvR3pc+nQVA+SJUZq8D2XBRd4EDUFXeLzwqwen9G7gSLGB1hJkSuRtGRfOHbLUuCKNR8RV82i3JvlSnAwb3MwN0m3WGdlJA8J+5YAg4e6JgSKrsCObZK7W1R6iuyuH1zA+dtAHyDyYVHB4FnYZPL0hgz2PSb9c+iDEiFcT/lT4/dQ+kRW6DYn66lS8peS8zCJ9CSQ==
And reference the generated known_hosts file in your JSch code.
If you are on Windows, you can get a Windows build of ssh-keyscan from Win32-OpenSSH project or Git for Windows.
Call JSch.getHostKeyRepository().add() to provide the expected host key (e.g. hard-coded, as your other credentials).
See Creating JSch HostKey instance from a public key in .pub format.
jsch version : 0.1.55
my problem solved by running :
ssh-keyscan -t rsa <HOST_NAME> >> ~/.ssh/known_hosts
ssh-keyscan -t rsa <IP_ADDRESS_OF_HOST_NAME> >> ~/.ssh/known_hosts
**in my case jsch was looking for ip address in known_hosts file
jsch.setKnownHosts(System.getProperty("user.home")+"/.ssh/known_hosts");
Aside: by "Cygwin" I assume you mean sshd or sftpd, because Cygwin itself doesn't do SSH.
Anyway, if you want Jsch client to accept any key from the host, move the .setConfig calls that sets StrictHostKeyChecking no so it is before session.connect(). Alternatively you must provide access to a store containing the correct key(s) for your hosts(s) as #Martin explains -- and you should always do that when connecting to anything other than "localhost" or possibly a machine certain to be on the same, physically-secure network segment (such as a wired LAN hub within a single room).

How to check whether user exists in Linux (JSch)

I am connecting/creating users in Linux machine using JSch. I am successfully able to connect Linux machine and create users. But i'm not able to check whether that user already exists or not in machine, while creating user. For this i tried command: id -u name
And my implementation is:
System.out.println("Connected");
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand("id -u name");
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
InputStream in=channel.getInputStream();
channel.connect();
But it doesn't tell whether its true or false. How to do this using JSch to check whether user exists in Linux?.
You are reading the InputStream that will have the user's id if you are asking for an existing user, but if you are asking for a user that is not in the system, the output will be written in the error stream. If you want to read one stream, you could modify your command to print the exit status of the last command executed.
session.connect();
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setCommand("id -u name; echo $?");
channel.connect();
The output if you ask for an exist user will have 2 lines, the first one will be the user's id, and the second one will be 0 that means executed successfully, if the user doesn't exists the content of the stream will be different of 0 that means command failed to execute.

How to create a bot that simulate an SSH shell user interaction?

I'm trying to realize a bot that simulates an user that write/read on a ssh console in Java.
I'm using the JSCH library to manage the ssh connection.
This is the code from which I started:
JSch jsch = new JSch();
Session session = jsch.getSession(username, ipAddress, port);
session.setPassword(password);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect(connectionTimeoutInMillis);
Channel channel = session.openChannel("shell");
InputStream is = new InputStream();
OutputStream out= new OutputStream();
channel.setInputStream(is);
channel.setOutputStream(out);
channel.connect();
channel.disconnect();
is.close();
out.close();
session.disconnect();
Obviously the InputStream and OutputStream in the code are wrong, I need to use something that the bot can use to send a String (a command line) and to receive a String(the result of the command execution), what type of streams should I use to obtain this?
Furthermore I noticed that if I send a command and use the System.out as output stream in many cases the output is empty because (I'm almost sure about this) the Java application terminates before that the command execution has produced the result. What is the best practice to tell to JSCH channel listener "wait till the command execution has completed" and then go on? I could use a Thread.sleep(someTime) after the command execution but I don't like much it for obvious reasons.
Consider using a third-party Expect-like Java library to ease the interaction with a remote shell. Here is a good set of options you can try:
Expect4J
ExpectJ
Expect-for-Java
You can also take a look at my own open source project which I created some time ago as the successor to the existing ones. It's called ExpectIt. The advantages of my library are stated on the project home page.
Here is an example of interacting with a public remote SSH service using JSch. It should be easy to adopt it for your use case.
JSch jSch = new JSch();
Session session = jSch.getSession("new", "sdf.org");
session.connect();
Channel channel = session.openChannel("shell");
Expect expect = new ExpectBuilder()
.withOutput(channel.getOutputStream())
.withInputs(channel.getInputStream(), channel.getExtInputStream())
.withErrorOnTimeout(true)
.build();
try {
expect.expect(contains("[RETURN]"));
expect.sendLine();
String ipAddress = expect.expect(regexp("Trying (.*)\\.\\.\\.")).group(1);
System.out.println("Captured IP: " + ipAddress);
expect.expect(contains("login:"));
expect.sendLine("new");
expect.expect(contains("(Y/N)"));
expect.send("N");
expect.expect(regexp(": $"));
expect.send("\b");
expect.expect(regexp("\\(y\\/n\\)"));
expect.sendLine("y");
expect.expect(contains("Would you like to sign the guestbook?"));
expect.send("n");
expect.expect(contains("[RETURN]"));
expect.sendLine();
} finally {
session.close();
ssh.close();
expect.close();
}
Here is the link to the complete workable example.

Setting ASCII mode in Jsch

I need to overcome a Unix - Windows file format (LF to CRLF) issue I'm currently having.
The ftp client I am using is Jsch from Jcraft.
The documentation online is very bare, although I have come across a flag that can be set
SSH_FXF_TEXT_MODE
that enables ASCII mode, but I don't see where I should set this in the code itself, nor do I see it mentioned in these Javadocs
Below is my own attempt at a workaround.
The "Newly Added" line shows how I take the file and convert it to an ASCII encoded string, which I then transfer across using the channelSftp put method.
Originally I would have just put the file itself across.
final JSch jsch = new JSch();
final Session session = jsch.getSession(username, host);
session.setPassword(password);
session.connect();
final Channel channel = session.openChannel("sftp");
channel.connect();
final ChannelSftp channelSftp = (ChannelSftp) channel;
channelSftp.cd(destDir);
File file = new File(pathName);
String content = FileUtils.readFileToString(file, "US-ASCII"); // Newly Added
channelSftp.put(content, fileToTransfer.getName());
Please note that I omitted exception handling and other practices just for clarity of the code snippet.
Will this workaround succeed, or will Jsch's seemingly default binary mode override the ASCII encoded string and transfer it as usual?
I will test it, I was just wondering if any of you could tell straight off?
Or indeed knew how/where to set the Text_Mode flag! :)
Also, the version of Jsch I am using is jsch-0.1.49.jar.
The text mode flag was added to SFTP protocol version 4. Jsch currently supports SFTP protocol version 3, which doesn't specify a text-mode flag.
You can see a list of SFTP specification revisions here. The RFC for protocol version 3 is here. Note that OpenSSH, the most widely used SFTP server, only supports protocol version 3 as well, and doesn't support line terminator conversion. So having the flag in Jsch wouldn't be very useful.

Convert from FTP to SFTP

I have the below code which works for FTP. How do I make it to work for SFTP
((ChannelExec) channel).setCommand(cmd);
channel.setXForwarding(true);
channel.setInputStream(System.in);
InputStream in=channel.getInputStream();
channel.connect();
return in;
I know that I need to use ChannelSftp instead of Channel class, but I get type cast error in the setcommand line.
Cannot cast type ChannelSftp to ChannelExec
The first thing to understand is SFTP is different than FTP or FTP/s. SFTP works off of SSH whereas FTP/s uses SSL.
That being said, JSCH provides a pretty straight forward way to use SFTP, including setting X forwarding. Take a look at the examples as well as the linked question from mabbas.
Based upon your comment, it appears that you actually want a remote shell to be invoked/executed against, try the following to see if it'll do what you need:
//connect to the remote shell
Channel channel=session.openChannel("shell");
((ChannelShell)channel).setAgentForwarding(true);
channel.setInputStream(System.in); //Send commands here
channel.setOutputStream(System.out); //output responses here
channel.connect();
You won't be able to use ChannelSftp as it does not have a setCommand or exec method
If you're using JSCH, they have several example programs which illustrate how to use the library. The SFTP client example illustrates how to open an SFTP session.
Session session=jsch.getSession(user, host, port);
...
session.connect();
Channel channel=session.openChannel("sftp");
channel.connect();
ChannelSftp c=(ChannelSftp)channel;
That's all you have to do. ChannelSftp contains functions to send and receive files, get file listings, and so on. You don't have to access the channel's input or output streams.

Categories