Introduction
This article presents a way to implement a remote connection to a server via SSH (secure shell) and to execute an interactive command through a pseudo terminal in Java.
Background
Programs which implement a remote connection to a server to execute a command via SSH (secure shell) in Java are very common, but most of them can only execute the "exec" command (non interactive cmd, in other words, execute command and hand over the control as soon as the cmd is finished, such as "date" to display the current time, and can not execute "ls' to display the file list under a designated directory (opt/3com/VCX/vcxdata/). This article will show a way to execute those commands, and further, interactive commands (such as "su root", which will claim the password, and we will input the password according to the output we get in real time).
Using the Code
First, import an external jar package sshtools. Then, declare an instance of SshClient
and SessionChannelClient
. You may have noticed that the way to get session output is a little different. We do not declare an object of ChannelOutputStream
; instead, an object of SessionOutputReader
, a point to which I will return.
import com.sshtools.j2ssh.SshClient;
import com.sshtools.j2ssh.authentication.PasswordAuthenticationClient;
import com.sshtools.j2ssh.session.SessionChannelClient;
import com.sshtools.j2ssh.session.SessionOutputReader;
import com.sshtools.j2ssh.transport.IgnoreHostKeyVerification;
As we are going to login to the 3com VCX server through SSH, the server IP, user name, and password are required, and set as shown below:
final private String username = "root";
final private String password = "pvadmin";
final private String hostname = "172.31.50.102";
private int outputPos = 0 ;
After executing the command, we get the output as a string. The previous output will be included in the current string to avoid the output being displayed over and over. We set outputPos
as the offset from where the output will be displayed.
ssh = new SshClient();
try{
ssh.connect(hostname, new IgnoreHostKeyVerification());
Create an SSH client to connect to server via SSH, and ignore the host key verification.
PasswordAuthenticationClient pwd = new PasswordAuthenticationClient();
pwd.setUsername(username);
pwd.setPassword(password);
int result = ssh.authenticate(pwd);
The result must be 4; otherwise, it means the SSH connection is not set up properly.
if (result == 4)
{
logCat.info("Connected to host");
session = ssh.openSessionChannel();
sor = new SessionOutputReader(session);
Open a session channel after connecting to the server successfully, and create an instance of the session output reader of the session.
if (session.requestPseudoTerminal("gogrid",80,24, 0 , 0, ""))
Create a pseudo terminal to connect to the server. The terminal type could be dumb, xterm, gogrid, vt100, vt220, vt320 etc., but I strongly recommend to choose "gogrid", for the others will result in confusing characters.
Here is the the prototype of the requested pseudo terminal:
boolean requestPseudoTerminal(String term, int cols,
int rows, int width, int height, String modes)
if (session.startShell())
{
in = (session.getInputStream());
logCat.info(in);
out = session.getOutputStream();
out.write("cd opt/3com/vcx/vcxdata/\n".getBytes());
out.write("ls\n".getBytes());
If it succeeds in starting the shell, execute the following command: "cd /opt/3com/vcx/vcxdata/". Then, "ls" to display the file list under that directory.
Thread.currentThread().sleep(1000*2);
String answer = null;
String aux = null;
aux = sor.getOutput();
answer = aux.substring(outputPos);
outputPos = aux.length();
logCat.info(answer);
After executing the command, check the output.
Similarly, we can execute interactive commands according to the last output prompt of the server in real time. For example, we get the cworks privilege, then we want to get back to the root privilege using the "su root" command, and the password prompt will be claimed. We check the output, and when we get the password prompt, we input the password.
out.write("su cworks\n".getBytes());
out.write("su root\n".getBytes());
Thread.currentThread().sleep(1000*2);
String answer = null;
String aux = null;
aux = sor.getOutput();
answer = aux.substring(outputPos);
outputPos = aux.length();
logCat.info(answer);
String str[] = answer.split("\n");
String prompt = str[str.length-1];
prompt = prompt.trim();
if (prompt.contains("Password:"))
{
out.write("pvadmin\n".getBytes());
}
And again, check what we have got this time:
Thread.currentThread().sleep(1000*2);
aux = sor.getOutput();
answer = aux.substring(outputPos);
logCat.info(answer);
Thanks to SessionOutputReader
, we can read the output stream of the session in real time. So, we can decide what command we should input according to the output prompt of the server, which is the very essence of being interactive.
Points of Interest
I will be glad if this is helpful to you. And thank you for your advice, which helped me make this article better.
Reference: http://upcommons.upc.edu/pfc/bitstream/2099.1/3790/1/53848-1.pdf.