I want to connect a Linux server and execute a command, but when I send the command sh and su - it requires password, but my program sends password just before it asks. How can i solve this problem?
public class Stream
{
public void getStream(String fileName)
{
String user = usernametext.getText();
String host = hostiptext.getText();
String password = pass.getText();
String command4 = "sh\nsu -\nmypassword\n";
try
{
System.out.println("preparing the host information for stream.");
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, 22);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.connect(10 * 1000);
Channel channel = session.openChannel("shell");
InputStream is = new ByteArrayInputStream(command4.getBytes());
channel.setInputStream(is);
channel.setOutputStream(System.out);
channel.connect(15 * 1000);
session.connect(10 * 10);
channel.disconnect();
session.disconnect();
}
catch (Exception ex)
{
System.out.println("Exception found while streaming.");
}
}
}
As you are using a shell channel why do you need to call another sh?
Any how I do the above is to pass individual command and then read the inputStream until you get back to the prompt and then you can set the next input e.g. the password or what ever.
Pseudo-code being
write "su -"
readUntil "password:"
write "******"
readUntil prompt
etc.
Related
I am trying to implement a shell terminal in a webapp using websocket in spring. I am able to send a single command to the JSch "exec" channel and send the output back to the websocket.
The problem I am having is:
I am not able to retain the state of the shell like working directory, when I send a second command. How can I retain the previous state? I have tried using the same session but it does not work.
public String sendCommand(String command) {
StringBuilder outputBuffer = new StringBuilder();
try {
Channel channel = sesConnection.openChannel("exec");
((ChannelExec) channel).setCommand(command);
InputStream commandOutput = channel.getInputStream();
channel.connect();
int readByte = commandOutput.read();
while (readByte != 0xffffffff) {
outputBuffer.append((char) readByte);
readByte = commandOutput.read();
}
channel.disconnect();
} catch (IOException ioX) {
logWarning(ioX.getMessage());
return null;
} catch (JSchException jschX) {
logWarning(jschX.getMessage());
return null;
}
return outputBuffer.toString();
}
To send back to the websocket, in the controller I have :
private SSHManager getSSHInstance() {
String errorMessage = null;
if (sshInstance == null) {
sshInstance = new SSHManager(username, password, host, "", port);
errorMessage = sshInstance.connect();
System.out.println("Instance created");
if (errorMessage != null) {
throw new RuntimeException("Could not create an ssh connection");
}
}
System.out.println("Returning created instance");
return sshInstance;
}
#MessageMapping("/user")
#SendTo("/topic/user")
public UserResponse getResponse(String command) {
SSHManager currInstance = getSSHInstance();
String result = currInstance.sendCommand(command);
return new UserResponse(result);
}
I tried using the "shell" channel instead of "exec" which worked for getting the input and output through standard input and output stream but I could not get the real-time input and output from/back to the websocket and UI. I am not sure how to proceed from here. Any direction on where/what to look would be very helpful.
Here is my code for the SSH terminal through standard input/output stream:
import com.jcraft.jsch.*;
public class Terminal{
public static void main(String[] args){
try{
JSch jsch=new JSch();
String host = "127.0.0.1";
String user = "user";
String password = "pass";
Session session=jsch.getSession(user, host, 5679);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.connect(10000);
Channel channel=session.openChannel("shell");
channel.setInputStream(System.in);
channel.setOutputStream(System.out);
channel.connect(3*1000);
}
catch(Exception e){
System.out.println(e.getMessage());
}
}
}
To send the command from the UI, I have the following:
function sendCommand() {
if (stompClient != null) {
stompClient.send("/app/user", {}, JSON.stringify({'command': $("#command").val()}));
}
}
If you want to implement an interactive shell, you have to use the "shell" channel, not the "exec" channel. The "exec" channel is intended for automating individual commands.
Some references:
What is the difference between the 'shell' channel and the 'exec' channel in JSch
JSch Shell.java example
This question already has an answer here:
"reject HostKey" when connecting to remote host through jumphost with JSch
(1 answer)
Closed 3 years ago.
I have config file under ~/.ssh/config contains :
Host jumbHost
HostName x.domain.com
Host host1
HostName y1.domain.com
ProxyJump jumbHost
How could I use JSch to tunnel to x.domain.com server by host1 in order to execute commands ?
Note: y1.domain.com doesn't have public IP
I tried to use jsch.setConfigRepository(config_file_path) but it seems there are more config I need to set or methods to use.
It will be very useful if described using example.
EDIT:
So I can ssh to x.domain.com server when I get session using jsch.getSession(user,"host1"); or something like that
Thanks in advance
Thanks KevinO and Martin Prikryl for your value tips and help
Based on your descriptions and links I was able to apply needed config to enable access to x.domain.com using host1 name and then execute commands on y1.domain.com
For record, this is how I end up with
public class Main {
public static void main(String args[]) throws Exception {
try {
String user = "user_name";
String host = "host1";
String command = "hostname";
JSch jsch = new JSch();
ConfigRepository configRepository = OpenSSHConfig.parseFile(System.getProperty("user.home") + "/.ssh/config");
jsch.setConfigRepository(configRepository);
jsch.addIdentity(new File(System.getProperty("user.home") + "/.ssh/id_rsa").getAbsolutePath());
Session sessionProxy = jsch.getSession(user,configRepository.getConfig(host).getValue("ProxyJump"),22);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
sessionProxy.setConfig(config);
sessionProxy.connect();
int assignedPort = sessionProxy.setPortForwardingL(0, configRepository.getConfig(host).getHostname(), 22);
Session sessionTunnel = jsch.getSession(user, "127.0.0.1", assignedPort);
sessionTunnel.connect();
Channel channel = sessionTunnel.openChannel("exec");
((ChannelExec) channel).setCommand(command);
channel.setInputStream(null);
((ChannelExec) channel).setErrStream(System.err);
InputStream input = channel.getInputStream();
channel.connect();
try {
InputStreamReader inputReader = new InputStreamReader(input);
BufferedReader bufferedReader = new BufferedReader(inputReader);
String line = null;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(">>> output: " + line);
}
bufferedReader.close();
inputReader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
channel.disconnect();
sessionTunnel.disconnect();
sessionProxy.disconnect();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I want to connect my unix server using java code. first it will connect to my server location. inside that it'll connect to my server name. but at that time it'll ask for confirmation (yes/no) and password I don't know how to do?
Here's my code that I have done.please help me out on this
public static void main (String args[]) {
String user = "user";
String password = "password";
String host = "hostName";
int port=22;
//String remoteFile="/home/john/test.txt";
//String yes="yes";
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();
Channel channel = session.openChannel("exec");
// After this it'll ask for confirmation and password
((ChannelExec)channel).setCommand("ssh myServerName");
channel.connect();
InputStream output = channel.getInputStream();
System.out.println("aafter stream");
int readByte = output.read();
StringBuilder outputBuffer = new StringBuilder();
while (readByte != 0xffffffff) {
//System.out.println("read byte" + readByte);
outputBuffer.append((char)readByte);
readByte = output.read();
}
System.out.println(outputBuffer.toString());
channel.disconnect();
} catch (Exception e){
System.err.print("error message" + e);
}
}
You need to get the OutputStream of JSch secured channel and insert the password in it.
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand("sudo -S -p '' " + command);
channel.setInputStream(null);
OutputStream out = channel.getOutputStream();
((ChannelExec) channel).setErrStream(System.err);
InputStream in = channel.getInputStream();
((ChannelExec) channel).setPty(true);
channel.connect();
out.write((password + "\n").getBytes());
out.flush();
Complete source code here: http://codeflex.co/java-run-sudo-command-on-remote-linux-host/
try {
session = jsch.getSession(user, host, port);
}
catch (JSchException e) {
throw new TransferException("Failed to open session - " + params, e);
}
session.setPassword(password);
// Create UserInfo instance in order to support SFTP connection to any machine
// without a key username and password will be given via UserInfo interface.
UserInfo userInfo = new SftpUserInfo();
session.setUserInfo(userInfo);
try {
session.connect(connectTimeout);
}
catch (JSchException e) {
throw new TransferException("Failed to connect to session - " + params, e);
}
boolean isSessionConnected = session.isConnected();
Set the password programmatically like seen above.
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.
I'm using the following code to make an SSH connection and download a file to the SSH server through curl. It gives me an exception without a message. Not really sure what to do at this point.
try{
JSch jsch=new JSch();
String host=selectedItem.getHost();
String user="down2home";
int port = selectedItem.getPort();
String password = selectedItem.getPass();
String dlurl = dlurlField.getText().toString();
Session session=jsch.getSession(user, host, port);
session.setPassword(password);
UserInfo ui = new MyUserInfo(){
};
ByteArrayOutputStream out = new ByteArrayOutputStream();
String command = "curl -L --create-dirs -o /home/paul/Desktop/geeknights/geeknights.mp3 "+dlurl+"\r\n";
out.write(command.getBytes());
out.flush();
InputStream in = new ByteArrayInputStream(out.toByteArray());
session.setUserInfo(ui);
session.connect(30*1000); // making a connection with timeout.
Channel channel=session.openChannel("shell");
channel.setInputStream(in);
channel.setOutputStream(System.out);
channel.connect(3*1000);
}
catch(Exception e){
String errorMessage = (e.getMessage()==null)?"Message is empty":e.getMessage();
Log.e("Exception:", errorMessage );
}
Traceback:
06-08 00:33:16.561: E/Exception:(9293): Message is empty
Turned out to be a NetworkOnMainThreadException. Not sure why it wouldn't give me that message with e.getMessage()