Exit status 4 received for JSch exec channel - java

I'm coding an app to manage some remote devices. I have trouble using JSch to restart dhcpdaemon. I do:
#Override
public void createSession(String hostname) throws JSchException {
this.session = jsch.getSession(username, hostname, 22);
this.session.setPassword(password);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
this.hostname = hostname;
}
private final String RESTART_COMMAND = "/etc/init.d/isc-dhcp-server restart";
public int reloadDHCPDaemon() throws IOException, JSchException, InterruptedException {
int exitStatus = -1;
String command = RESTART_COMMAND;
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setPty(true);
channel.setCommand(command);
channel.connect();
Thread.sleep(1000);
if (channel.isClosed() == true) {
exitStatus = channel.getExitStatus();
channel.disconnect();
}
return exitStatus;
}
I'm getting 4 as an exit status no matter if the command ended successfully or not. The same code but with other commands, for example cp works fine. Can somone help me?

Related

Authentication using a key encrypted with a passphrase in JSch

I'd like to use JSch to open an SFTP connection to download some files.
String SFTPPRIVATEKEY = "/folder/privatekeyfile";
String SFTPUSER = "user";
String SFTPPASS = "";
String SFTPHOST = "server.tld";
String SFTPPORT = "22";
int usePrivateKey = 1;
public boolean connect() {
boolean isConnected = false;
try {
JSch jsch = new JSch();
if (usePrivateKey) {
jsch.addIdentity(SFTPPRIVATEKEY);
}
session = jsch.getSession(SFTPUSER,SFTPHOST,SFTPPORT);
if (!usePrivateKey) {
session.setPassword(SFTPPASS);
}
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
if (session.isConnected() == true) {
log.println("Connection to Session server is successfully");
}
channel = session.openChannel("sftp");
channel.connect();
channelSftp = (ChannelSftp)channel;
isConnected = true;
} catch (JSchException e) {
log.println("SFTPClient Connect ERROR: "+e.getMessage());
e.printStackTrace();
}
return isConnected;
}
If i run my code i get:
com.jcraft.jsch.JSchException: USERAUTH fail
I tried to connect using sftp on the shell on the same client where my Java code runs. I run
sftp -i privatekeyfile user#server.tld
It prompts for a passphrase for the privatekeyfile. I entered the passphrase and the connection works great.
But JSch did not connect. I found no option to set the passphrase in JSch. Maybe this is the problem?
Can some of you help?
Thanks
There's JSch.addIdentity overload that takes the passphrase:
public void addIdentity(String prvkey, String passphrase)
Obligatory warning: Do not use StrictHostKeyChecking=no to blindly accept all host keys. That is a security flaw. You lose a protection against MITM attacks. For the correct (and secure) approach, see: How to resolve Java UnknownHostKey, while using JSch SFTP library?

SSH tunneling 2 gateways via JSch

I wonder if its possible to extend the answer in SSH tunneling via JSch to a case where I have two gateways (two points) before the final host.
What I tried was
import com.jcraft.jsch.*;
import java.io.InputStream;
public class Main {
public static void main(String[] args){
Main t=new Main();
try{
t.go();
} catch(Exception ex){
ex.printStackTrace();
}
}
public void go() throws Exception{
StringBuilder outputBuffer = new StringBuilder();
String Gateway1="192.168.0.101"; // First level target
String user1="root";
String password="12qwaszx";
String Gateway2="192.168.0.102"; // The host of the second target
String user2 = "root";
String secondPassword="12qwaszx";
String endpoint = "10.81.77.52";
String finaluser="admin";
String finaluserpass="admin";
JSch jsch=new JSch();
Session session=jsch.getSession(user1, Gateway1, 22);
session.setPassword(password);
localUserInfo lui=new localUserInfo();
session.setUserInfo(lui);
session.setConfig("StrictHostKeyChecking", "no");
// create port from 2233 on local system to port 22 on tunnelRemoteHost
session.setPortForwardingL(2233, Gateway2, 22);
session.connect();
session.openChannel("direct-tcpip");
// create a session connected to port 2233 on the local host.
Session secondSession = jsch.getSession(user2, "localhost", 2233);
secondSession.setPassword(secondPassword);
secondSession.setUserInfo(lui);
secondSession.setConfig("StrictHostKeyChecking", "no");
secondSession.setPortForwardingL(2233, endpoint, 22);
secondSession.connect(); // now we're connected to the secondary system
secondSession.openChannel("direct-tcpip");
Session finalSession = jsch.getSession(finaluser, "localhost", 2233);
finalSession.setPassword(finaluserpass);
finalSession.setUserInfo(lui);
finalSession.setConfig("StrictHostKeyChecking", "no");
finalSession.connect();
Channel channel=secondSession.openChannel("exec");
((ChannelExec)channel).setCommand("show system information | match \"System Name\"");
channel.setInputStream(null);
InputStream stdout=channel.getInputStream();
channel.connect();
if (channel.isConnected()){
System.out.println("connected");
}
while (true) {
byte[] tmpArray=new byte[1024];
while(stdout.available() > 0){
int i=stdout.read(tmpArray, 0, 1024);
if(i<0)break;
outputBuffer.append(new String(tmpArray, 0, i));
}
if(channel.isClosed()){
System.out.println("exit-status: "+channel.getExitStatus());
break;
}
}
stdout.close();
channel.disconnect();
secondSession.disconnect();
session.disconnect();
System.out.print(outputBuffer.toString());
}
class localUserInfo implements UserInfo {
String passwd;
public String getPassword(){ return passwd; }
public boolean promptYesNo(String str){return true;}
public String getPassphrase(){ return null; }
public boolean promptPassphrase(String message){return true; }
public boolean promptPassword(String message){return true;}
public void showMessage(String message){}
}
}
But despite my efforts, I don't actually get to connect to the endpoint. Getting
com.jcraft.jsch.JSchException: PortForwardingL: local port 127.0.0.1:2233 cannot be bound.
at com.jcraft.jsch.PortWatcher.<init>(PortWatcher.java:158)
at com.jcraft.jsch.PortWatcher.addPort(PortWatcher.java:110)
at com.jcraft.jsch.Session.setPortForwardingL(Session.java:1847)
at com.jcraft.jsch.Session.setPortForwardingL(Session.java:1828)
at com.jcraft.jsch.Session.setPortForwardingL(Session.java:1809)
at com.jcraft.jsch.Session.setPortForwardingL(Session.java:1792)
at Main.go(Main.java:36)
at Main.main(Main.java:9)
Caused by: java.net.BindException: Address already in use: JVM_Bind
at java.net.DualStackPlainSocketImpl.bind0(Native Method)
at java.net.DualStackPlainSocketImpl.socketBind(DualStackPlainSocketImpl.java:106)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:190)
at java.net.ServerSocket.bind(ServerSocket.java:375)
at java.net.ServerSocket.<init>(ServerSocket.java:237)
at com.jcraft.jsch.PortWatcher.<init>(PortWatcher.java:150)
... 7 more
Process finished with exit code 0
Please, if anyone could help me. I need to Get to the endpoint by ssh tunneling two gateways.
I swear I didn't meant it,
but the problem was that the first lport was equal to the second.
it worked like bellow:
session.setPortForwardingL(2222, Gateway2, 22);
session.connect();
session.openChannel("direct-tcpip");
Session secondSession = jsch.getSession(user2, "localhost", 2222);

Running multiple commands as root with Jsch()

Im having problems running multiple commands as the root user, using the exec channel. I dont get any exceptions, however the second command is not being executed for some reason.
Here is my code
try {
JSch jsch = new JSch();
String command1 = "touch 1.txt; touch 2.txt";
//"sudo chmod 755 script.sh; sudo sh script.sh";
String user = "user";
String host = "10.68.228.140";
String privateKey = "/home/user/.ssh/blabla";
jsch.addIdentity(privateKey);
System.out.println("identity added ");
Session session = null;
while(session == null) {
Thread.sleep(1000);
session = jsch.getSession(user, host);
}
System.out.println("session created ");
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
while(!session.isConnected()) {
Thread.sleep(1000);
session.connect();
}
System.out.println("session connected.....");
Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp sftpChannel = (ChannelSftp)channel;
sftpChannel.put("/home/user/script.sh", "/home/user");
sftpChannel.disconnect();
channel.disconnect();
Channel channel1 = session.openChannel("exec");
((ChannelExec) channel1).setCommand(command);
channel1.connect();
channel1.disconnect();
session.disconnect();
} catch(JSchException e){
e.printStackTrace();
} catch(SftpException se){
se.printStackTrace();
}
catch(Exception e) {
}
So if I leave it like this, everything is fine. The two files are created on the remote machine. But if I give as command the commented line, then the script is not executed. (It changes only mode)
Could you give me a help please? I've been stuck with this all day now.

Multiple commands using JSch

My requirement is as follow:
I have to login to Unix box using my credentials and once login, I have to do sudo to different user. Once sudo is successful, I have to invoke shell in nohup. On completion of executions, close channel and session both.
I tried the first step which is connect using sudo command, but I don't know how to invoke shell script after the sudo command.
In the below code I am able to execute sudo command, but after getting sudo access how can I execute a shell in nohup with user masteruser. So that required files created my shell has owner as masteruser.
public class SSHUploader {
Session session = null;
public SSHUploader(){
}
public void connect(){
try {
JSch jsch = new JSch();
session = jsch.getSession("user", "xxx.xxx.xx.xx", 22);
session.setPassword("test");
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void executeCommand(String script) throws JSchException, IOException{
System.out.println("Execute sudo");
String sudo_pass = "test";
ChannelExec channel = (ChannelExec) session.openChannel("exec");
((ChannelExec) channel).setCommand( script);
InputStream in = channel.getInputStream();
OutputStream out = channel.getOutputStream();
((ChannelExec) channel).setErrStream(System.err);
channel.connect();
out.write((sudo_pass + "\n").getBytes());
out.flush();
byte[] tmp = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0)
break;
System.out.print(new String(tmp, 0, i));
}
if (channel.isClosed()) {
System.out.println("exit-status: " + channel.getExitStatus());
break;
}
try {
Thread.sleep(1000);
} catch (Exception ee) {
System.out.println(ee);
}
}
channel.disconnect();
System.out.println("Sudo disconnect");
}
public void disconnect(){
session.disconnect();
}
public static void main(String... args) throws JSchException, IOException {
SSHUploader up = new SSHUploader();
up.connect();
up.executeCommand("sudo -u masteruser bash");
up.disconnect();
}
}
For executing multiple commands in sequence, you can create a command string like below:
String script ="pbrun su - user; cd /home/scripts;./sample_script.sh”
Execute it and pass this string to your method above.
The post may be old, but I found another easy way that allows you to retrieve the output of each command separately. Note that this code has to be executed once the session has been opened, as shown in the examples (http://www.jcraft.com/jsch/examples/Exec.java.html):
for (String command : commands) {
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setInputStream(null);
channel.setErrStream(System.err);
channel.setCommand(command);
channel.connect();
printOutput(channel);
channel.disconnect();
}
Where printOutput uses channel.getInputStream() to read the result of the command.
Another solution which I find elegant is to use connection from type shell instead of exec.
But you will need to wait for the correct prompt to appear after each command like shown in the following example:
public static void main(String[] args) throws Exception{
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
Session session = null;
ChannelShell channel = null;
try {
JSch jsch = new JSch();
session = jsch.getSession("username", "192.168.1.1", 22);
session.setConfig(config);
session.setPassword("password");
session.connect();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
channel = (ChannelShell) session.openChannel("shell");
channel.setOutputStream(outputStream);
PrintStream stream = new PrintStream(channel.getOutputStream());
channel.connect();
stream.println("touch delme.txt");
stream.flush();
String response = waitForPrompt(outputStream, "$");
System.out.println(response);
stream.println("sudo chown root delme.txt");
stream.flush();
response = waitForPrompt(outputStream, ":");
System.out.println(response);
stream.println("mysecretrootpassword");
stream.flush();
response = waitForPrompt(outputStream, "$");
System.out.println(response);
stream.println("ls -la delme.txt");
stream.flush();
response = waitForPrompt(outputStream, "$");
System.out.println(response);
} finally {
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
}
}
}
static public String waitForPrompt(ByteArrayOutputStream outputStream, String prompt) throws Exception {
int retries = NUMBER_OF_RETRIES;
for (int x = 1; x < retries; x++) {
TimeUnit.SECONDS.sleep(1);
if (outputStream.toString().indexOf(prompt) > 0) {
String responseString = outputStream.toString();
outputStream.reset();
return responseString;
}
}
throw new Exception("Prompt failed to show after specified timeout");
}

SFTP file transfer using Java JSch

Here is my code, which retrieves content of the file, on the remote server and display as output.
package sshexample;
import com.jcraft.jsch.*;
import java.io.*;
public class SSHexample
{
public static void main(String[] args)
{
String user = "user";
String password = "password";
String host = "192.168.100.103";
int port=22;
String remoteFile="sample.txt";
try
{
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("Creating SFTP Channel.");
ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp");
sftpChannel.connect();
System.out.println("SFTP Channel created.");
InputStream out= null;
out= sftpChannel.get(remoteFile);
BufferedReader br = new BufferedReader(new InputStreamReader(out));
String line;
while ((line = br.readLine()) != null)
{
System.out.println(line);
}
br.close();
sftpChannel.disconnect();
session.disconnect();
}
catch(JSchException | SftpException | IOException e)
{
System.out.println(e);
}
}
}
Now how to implement this program that the file is copied in the localhost and how to copy a file from localhost to the server.
Here how to make work the transfer of files for any format of files.
The most trivial way to upload a file over SFTP with JSch is:
JSch jsch = new JSch();
Session session = jsch.getSession(user, host);
session.setPassword(password);
session.connect();
ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp");
sftpChannel.connect();
sftpChannel.put("C:/source/local/path/file.zip", "/target/remote/path/file.zip");
Similarly for a download:
sftpChannel.get("/source/remote/path/file.zip", "C:/target/local/path/file.zip");
You may need to deal with UnknownHostKey exception.
Usage:
sftp("file:/C:/home/file.txt", "ssh://user:pass#host/home");
sftp("ssh://user:pass#host/home/file.txt", "file:/C:/home");
Implementation
Below code works for me
public static void sftpsript(String filepath) {
try {
String user ="demouser"; // username for remote host
String password ="demo123"; // password of the remote host
String host = "demo.net"; // remote host address
JSch jsch = new JSch();
Session session = jsch.getSession(user, host);
session.setPassword(password);
session.connect();
ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp");
sftpChannel.connect();
sftpChannel.put("I:/demo/myOutFile.txt", "/tmp/QA_Auto/myOutFile.zip");
sftpChannel.disconnect();
session.disconnect();
}catch(Exception ex){
ex.printStackTrace();
}
}
OR using StrictHostKeyChecking as "NO" (security consequences)
public static void sftpsript(String filepath) {
try {
String user ="demouser"; // username for remote host
String password ="demo123"; // password of the remote host
String host = "demo.net"; // remote host address
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, 22);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);;
session.setPassword(password);
System.out.println("user=="+user+"\n host=="+host);
session.connect();
ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp");
sftpChannel.connect();
sftpChannel.put("I:/demo/myOutFile.txt", "/tmp/QA_Auto/myOutFile.zip");
sftpChannel.disconnect();
session.disconnect();
}catch(Exception ex){
ex.printStackTrace();
}
}

Categories