Setting ASCII mode in Jsch - java

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.

Related

channelExec.setCommand() Not Working when executing shell commands

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

JSCH SFTP file transfer - Data in the file is getting corrupted

I am facing problem while transferring the file using JSCH in java. The data in the file is getting corrupted, and this is happening intermittently . I mean sometimes the file is getting uploaded properly and majority times we noticed data is being corrupted when the file size is greater than 5 MB.
The program is behaving differently in different scenarios.
Windows-10 : Program works perfectly fine without issues for all sizes of files.
Unix : Program works fine for files less than 2 MB. But for files that are greater than 2 MB, sometimes the file is able to upload correctly, but majority times we see the data being corrupted.
I am still not getting what is causing the data corruption ? I don't think code has the issue as program works fine in windows environment, and sometimes in unix environment as well.
Is there any problem with the way the program reads the data and writes to remote server or any other thing I am missing here? Please help.
public boolean putFile(String report, String user, String password, String location,
String folder) throws Exception {
boolean status=true;
JSch shell = new JSch();
Session session = null;
session = shell.getSession(user, location, 22);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
Channel channel = null;
channel = session.openChannel("shell");
channel.setInputStream(null);
channel.setOutputStream(null);
channel = session.openChannel("sftp");
channel.connect();
ChannelSftp sftp = (ChannelSftp) channel;
sftp.cd(folder);
File outputFile = new File(report);
FileInputStream fileInputStream = new FileInputStream(outputFile);
sftp.put(fileInputStream, outputFile.getName());
session.disconnect();
return status;
}
There was a bug in the jsch version we were using. Read through the change log of jsch releases, and updated the version. That solved the problem.

JSCH to write to named pipe

I'm trying to write to write to a named pipe over a connection facilitated by jsch.
// connect to server
JSch ssh = new JSch();
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
System.out.println("Establishing Connection...");
session.connect();
System.out.println("Connection established.");
System.out.println("Crating SFTP Channel.");
ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp");
sftpChannel.connect();
System.out.println("SFTP Channel created.");
// write to pipe
OutputStream strm = sftpChannel.put(remoteFile);
// failed attempts
// BufferedWriter wrtr = new BufferedWriter(new PrintWriter(new OutputStreamWriter(strm)));
// PrintWriter wrtr = new PrintWriter(new BufferedOutputStream(strm));
// Current version
BufferedWriter wrtr = new BufferedWriter(new PrintWriter(strm));
wrtr.write("hello world");
wrtr.flush();
session.disconnect();
sftpChannel.disconnect();
wrtr.close();
The connect to server part is essentially an exact copy from: SSH connection with Java
The code will even wait for something to be reading the pipe on the other side, meaning that if I don't use:
cat pipe
It will wait till I do so, and then once I have it will print out nothing and the cat pipe call will be over. Essentially it appears that I'm writing "" to the pipe instead of "hello world"
Any help would be much appreciated, thanks.
I suspect that if you talked to any SFTP server software author, he'd tell you that interacting with named pipes through SFTP isn't supported, and that you're on your own. Having said that, you could try requesting append mode for the put operation:
OutputStream strm = sftpChannel.put(remoteFile, ChannelSftp.APPEND);
^^^^^^^^^^^^^^^^^^
BufferedWriter wrtr = new BufferedWriter(new PrintWriter(strm));
wrtr.write("hello world");
It might work, or it might not. It depends on the SFTP server.
At the protocol level, an SFTP write request specifies what file to write to, where in the file to write it, and what data to write. Based on the the OpenSSH 5.8 source code that I have at hand, that version of the SFTP server program will always seek to the correct location in the file before writing data to it. Pipes don't support seeking, so the sftp-server program would report a seek failure to the client without trying to write the data.
However, the OpenSSH 6.6 version of sftp-server will omit the seek if the file was opened in append mode. I haven't tested it, but it may be possible to write to a named pipe using that version of the server, if the client requests append mode for the file in the first place. And by extension, it may work for some other versions of the OpenSSH server as well.

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.

How to SSH to a server behind another SSH server using JSch?

I need to be able to ssh from a Java program into a remote server, and from there SSH to another server. I have credentials for both servers on my client.
The commands will be passed automatically from within the app as regular strings (no user input). I need to be able to run those custom commands on the second server and be able to decide what commands to issue during runtime, based on the output and some simple logic.
Can I use JSch to do that and if yes, where should I start look into? (Examples, info)
=============================================================
ADDED:
Exception in thread "main" com.jcraft.jsch.JSchException:
UnknownHostKey: host.net. RSA key fingerprint is 'blahblahblah'
as till now, I am solving this problem by modifying the known_hosts file and adding host manually in there.
Can I bypass this little problem by settings an option somewhere telling the JSch to press YES automatically when this YES-NO question is asked?
To connect to a second server behind a firewall, there are in principle two options.
The naive one would be to call ssh on the first server (from an exec channel), indicating the right server. This would need agent forwarding with JSch, and also doesn't provide the JSch API to access the second server, only the ssh command line.
The better one would be to use the connection to the first server to build up a TCP Tunnel, and use this tunnel to connect to the second server. The JSch Wiki contains a ProxySSH class (together with some example code) which allows to use a JSch session as a tunnel for a second JSch session. (Disclaimer: This class was written mainly by me, with some support from the JSch author.)
When you have your connection to the second server, use either a shell channel or a series of exec channels to execute your commands. (See Shell, Exec or Subsystem Channel in the JSch Wiki for an overview, and the Javadocs for details.)
For your unknown-host-key problem:
The secure version would be to collect all host keys (in a secure way) before and put them in the known_hosts file. (If you simply trust the key which is presented to you, you are vulnerable to a man-in-the-middle attack. If these are of no concern in your network, since it is physically secured, good for you.)
The convenient version is setting the configuration option StrictHostKeyChecking to no - this will add unknown host keys to the host keys file:
JSch.setConfig("StrictHostKeyChecking", "no");
(You can also set it individually on the sessions, if you only want to set it for the proxied sessions and not for the tunnel session. Or override it for the tunnel session with yesor ask - there the MITM danger might be greater.)
A middle way would be to enable actually asking the user (which then should compare the fingerprints to some list) - for this, implement the UserInfo interface and provide the object to the session. (The JSch Wiki contains an example implementation using Swing JOptionPanes, which you can simply use if your client program runs on a system with GUI.)
For the saving of accepted host keys to work, you must use the JSch.setKnownHosts method with a file name argument, not the one with an InputStream argument - else your accepting will have to be repeated for each restart of your client.
Use an SSH tunnel, aka local port forwarding, to open an SSH/SFTP connection to B via A.
Session sessionA = jsch.getSession("usernameA", "hostA");
// ...
sessionA.connect();
int forwardedPort = sessionA.setPortForwardingL(0, "hostB", 22);
Session sessionB = jsch.getSession("usernameB", "localhost", forwardedPort);
// ...
sessionB.connect();
// Use sessionB here for shell/exec/sftp
You may need to deal with UnknownHostKey exception.
This can help anyone. Works fine:
public static void sesionA(){
try {
Session sessionA = jSch.getSession(username, hostA);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
sessionA.setConfig(config);
sessionA.setPassword(passwordA);
sessionA.connect();
if(sessionA.isConnected()) {
System.out.println("Connected host A!");
forwardedPort = 2222;
sessionA.setPortForwardingL(forwardedPort, hostB, 22);
}
} catch (JSchException e) {
e.printStackTrace();
}
}
public static void sesionB(){
try {
Session sessionB = jSch.getSession(username, "localhost", forwardedPort);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
sessionB.setConfig(config);
sessionB.setPassword(passwordB);
sessionB.connect();
if(sessionB.isConnected()) {
System.out.println("Connected host B!");
}
}
}

Categories