'nohup mycommand &' via Java code - java

I am trying to run the following command using Ganymed-SSH2 (ch.ethz.ssh2):
nohup sudo mycommand &
It works when I run directly from command line, but nothing happens when I run it using the Java code below.
Connection connection = new Connection(server);
connection.connect();
if (!connection.authenticateWithPassword(userName, password)) {
throw new IOException("Failed to authenticate with user " + userName + "on host: " + connection.getHostname());
}
Session session = connection.openSession();
session.requestDumbPTY();
session.execCommand("nohup sudo mycommand &");
session.close();
connection.close();
The command works via the execCommand() method if I exclude the & (but this won't give me my required results), but nothing happens with & there.
Any ideas what is going wrong?
(Note: sudo does not require a password)

I've found a good hint to solve this issue reading the nohup wikipedia page. Combine nohup and ssh require stdin / std[out|err] to be redirected.
If your server doesn't have Defaults requiretty in /etc/sudoers you can simply use:
sess.execCommand("nohup sudo <yourCommand> 2>&1 >nohup.out </dev/null &");
Entire code:
import ch.ethz.ssh2.*
String hostname = "localhost";
String username = "gsus";
File keyfile = new File("/home/gsus/.ssh/id_rsa");
String keyfilePass = "";
try {
Connection conn = new Connection(hostname);
conn.connect();
boolean isAuthenticated=conn.authenticateWithPublicKey(username,keyfile,keyfilePass);
if (isAuthenticated == false)
throw new IOException("Authentication failed.");
Session sess=conn.openSession();
//Don't use this
//sess.requestDumbPTY();
sess.execCommand("nohup sudo ping -c 100 www.yahoo.com 2>&1 >nohup.out </dev/null &");
sess.close();
conn.close();
}
catch ( IOException e) {
e.printStackTrace(System.err);
System.exit(2);
}
If instead your server /etc/sudoers file contains Defaults requiretty (#user5222688) you have to switch using session.startShell()
import ch.ethz.ssh2.*
String hostname = "localhost";
String username = "gsus";
File keyfile = new File("/home/gsus/.ssh/id_rsa");
String keyfilePass = "";
try {
Connection conn = new Connection(hostname);
conn.connect();
boolean isAuthenticated=conn.authenticateWithPublicKey(username,keyfile,keyfilePass);
if (isAuthenticated == false)
throw new IOException("Authentication failed.");
Session sess=conn.openSession();
sess.requestPTY("xterm");
sess.startShell();
InputStream stdout = new StreamGobbler(sess.getStdout());
BufferedReader input = new BufferedReader(new InputStreamReader(stdout));
OutputStream out = sess.getStdin();
out.write("nohup sudo <yourCommand> 2>&1 >nohup.out </dev/null &\n".getBytes());
out.flush();
while (!input.readLine().contains("stderr")) {
//Simply move on the stdout of the shell till our command is returned
}
sess.close();
conn.close();
}
catch (IOException e) {
e.printStackTrace(System.err);
System.exit(2);
}

Related

Unable to access the cmd prompt in remote machine using openchannel in java

I'm trying to access the cmd prompt in administrator mode and run a batch file in the remote machine,but right now I'm not able to access the cmd prompt through openchannel. Did anybody tried to access it from remote machine in java?
Here is the code
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch();
session = jsch.getSession(user, ip, 22);
session.setPassword(password);
session.setTimeout(timeOut);
session.setConfig(config);
session.connect();
System.out.println("session connected");
//open command prompt to run the command = "C:\\executeBatchFile.bat" file
Channel channel = (ChannelExec) session.openChannel("exec");
((ChannelExec)channel).setCommand("cmd.exe /c \"echo %cd%\"\\executeBatchFile.bat");
channel.connect();
InputStream outputstream_from_the_channel = channel.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(outputstream_from_the_channel));
String jarOutput;
while ((jarOutput = reader.readLine()) != null)
{
System.out.println("Inside while loop");
System.out.println(jarOutput + "\n");
}
reader.close();
session.disconnect();
Expected behavior :set command should run as an administrator(though I have logged in as admin),come back to the c:drive (cd) and execute the batch file ie; C:executeBatchFile.bat
Actual behaviour : command gives the user path(not as admin) when I print the jarOutput. ie; C:\Users\Admin\executeBatchFile.bat
could you suggest any solution on the same?
This has been resolved using PsExec command instead of JSCH
String pscommand=E:\\Tool\\psexec -u user -p pwd \\\\ip -s -d cmd.exe /c C:\\executescript.bat
process = Runtime.getRuntime().exec(pscommand);
InputStream es = process.getErrorStream();
BufferedReader errReader = new BufferedReader(new InputStreamReader(es));
String line;
// Read STDOUT into a buffer.
while ((line = errReader.readLine()) != null)
{
system.out.println(line);
}
Could any one tell me how to open the cmd prompt in administrator mode(I logged in using admin credentials only but still it does not open in admin mode).Here I need to run the script in administrator.

Invoke WLST commands with JSch

I'm trying to run a restart server command on WLST through a remote Java web app.
This is what I'm trying to execute:
StringBuilder sb = new StringBuilder();
sb.append("/u01/app/oracle/jdk1.8.0_65/bin/./java -cp /u01/app/oracle/product/Oracle_Home/wlserver/server/lib/weblogic.jar weblogic.WLST");
sb.append(";connect(\'weblogic\',\'" + consolePass + "\',\'" + fullAddress + "\')");
sb.append(";domainRuntime()");
sb.append(";cd(\'/ServerLifeCycleRuntimes/" + serverName + "\')");
sb.append(";cmo.shutdown())");
sb.append(";start(" + serverName + ",'Server')");
String command = sb.toString();
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
session.setUserInfo(new OracleUserInfo(pass));
session.connect();
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command);
channel.setInputStream(null);
((ChannelExec) channel).setErrStream(System.err);
InputStream in = channel.getInputStream();
channel.connect();
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()) {
if (in.available() > 0)
continue;
System.out.println("exit-status: " + channel.getExitStatus());
break;
}
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
}
channel.disconnect();
session.disconnect();
I'm using ';' to separate the commands, since I thought it was required to run multiple commands.
Unfortunately, it gives a syntax error on line 2.
bash: -c: line 0: syntax error near unexpected token 'weblogic','password','t3://host:7001''
bash: -c: line 0:/u01/app/oracle/jdk1.8.0_65/bin/./java -cp /u01/app/oracle/product/Oracle_Home/wlserver/server/lib/weblogic.jar weblogic.WLST;connect('weblogic','password','t3://host:7001')'
I tried to add \n after the first line, and the result was that the first line was executed (so it entered WLST), but none of the remaining commands were.
StringBuilder sb = new StringBuilder();
sb.append("/u01/app/oracle/jdk1.8.0_65/bin/./java -cp /u01/app/oracle/product/Oracle_Home/wlserver/server/lib/weblogic.jar weblogic.WLST\n");
sb.append(";connect(\'weblogic\',\'" + consolePass + "\',\'" + fullAddress + "\')\n");
sb.append(";domainRuntime()\n");
sb.append(";cd(\'/ServerLifeCycleRuntimes/" + serverName + "\')\n");
sb.append(";cmo.shutdown())\n");
String command = sb.toString();
Result:
Initializing WebLogic Scripting Tool (WLST) ...
Welcome to WebLogic Server Administration Scripting Shell
Type help() for help on available commands
wls:/offline>
I tested the command manually and it worked. The problem seems to be with JSch with WLST interface, since it opens another shell interface.
Any ideas how I could run WLST commands with JSch?
PS1: I know my JSch code works because I have a feature on the same app to deploy. Basically, it runs a jscp to upload the war, and then ssh to execute the weblogic.Deployer -deploy command.
PS2: I do have a .py script to do that, but as of now, it must be on the server to be executed. I'm thinking about doing an jscp to a temp folder, run the script and then delete. But I'm curious to find out how to run multiple commands on WLST with JSch.
Thanks in advance.
UPDATE
Code working (Thanks Martin)
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command);
InputStream in = channel.getInputStream();
OutputStream out = channel.getOutputStream();
((ChannelExec) channel).setErrStream(System.err);
channel.connect();
for (String wlstCommand : wlstCommands) {
out.write((wlstCommand).getBytes());
}
out.flush();
The ; can indeed by used in *nix based system to execute multiple commands in one shell command-line.
But what you are executing are not shell commands. Those are WLST commands, right? So you have to feed them to WLST.
Like this:
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand("java -cp /.../weblogic.jar weblogic.WLST");
OutputStream out = channel.getOutputStream();
channel.connect();
out.write(("connect('weblogic'...)\n").getBytes());
out.write(("domainRuntime()\n").getBytes());
...
It's basically the same as generic Providing input/subcommands to command executed over SSH with JSch.

jcraft with copSSH throws Algorithm negotiation fail error in windows environment

I'm developing java program to connect with windows server over ssh. For this I used jcraft on java. And the ssh server is copSSH. The implementation throws
Error: com.jcraft.jsch.JSchException: Algorithm negotiation fail
error on java. At the same time it shows
fatal: Unable to negotiate with 192.168.28.111: no matching cipher
found. Their offer: aes128-cbc,3des-cbc,blowfish-cbc [preauth]
on CopSSH.
Java code block
public void sshExecPassword(String host, String USERNAME, String PASSWORD, String command) {
App objApp = new App();
int port = 22;
try {
/**
* Create a new Jsch object This object will execute shell commands
* or scripts on server
*/
JSch jsch = new JSch();
/*
* Open a new session, with your username, host and port Set the
* password and call connect. session.connect() opens a new
* connection to remote SSH server. Once the connection is
* established, you can initiate a new channel. this channel is
* needed to connect to remotely execution program
*/
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
Session session = jsch.getSession(USERNAME, host, port);
session.setConfig(config);
session.setPassword(PASSWORD);
session.connect();
// create the excution channel over the session
ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
// Gets an InputStream for this channel. All data arriving in as
// messages from the remote side can be read from this stream.
InputStream in = channelExec.getInputStream();
// Set the command that you want to execute
// In our case its the remote shell script
String str = command;
channelExec.setCommand(str);
channelExec.connect();
// Read the output from the input stream we set above
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// retrieve the exit status of the remote command corresponding to
// this channel
int exitStatus = channelExec.getExitStatus();
// Safely disconnect channel and disconnect session. If not done
// then it may cause resource leak
channelExec.disconnect();
session.disconnect();
if (exitStatus < 0) {
System.out.println("Done, but exit status not set! " + exitStatus);
objApp.writeLogs("120","Done, but exit status not set! ");
} else if (exitStatus > 0) {
System.out.println("Done, but with error!");
objApp.writeLogs("120","Done, but with error!");
} else {
System.out.println("Done!");
objApp.writeLogs("121","SSH connection successful");
}
} catch (Exception e) {
System.err.println("Error: " + e);
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw, true);
e.printStackTrace(pw);
objApp.writeLogs("120", sw.getBuffer().toString());
}
}
And the CopSSH host following versions
OpenSSH_7.1p2, OpenSSL 1.0.2e 3 Dec 2015
Can any one suggest a fix for it?
That happens due to lacking support for legacy ciphers in more recent releases of OpenSSH. Check this Copssh FAQ for a solution. Background information can also be found here.
Latest jcraft jar fix the issue

Java code to run command on remote Linux with sesu access

I need java code that logs into linux box with my credentials, then do a sesu , and then execute a shell script. Permission to execute the shell script if for only sesu user, hence sesu-ing after login is critical. I used te following code which can help me execute a command with my credential scope, however, I need sesu login following my login. Please suggest a way.
I tried adding the sesu command in teh command list, but it prompts for a password. I want a way to pass the password as well and completly automate it.
import java.io.InputStream;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
public class SSHCommandExecutor {
/** * #param args */
public static void main(String[] args) {
String host = "xxxxxxx";
String user = "xxxxxxx";
String password = "xxxxxxx";
String command1 = "cd /test; ./test.sh";
try {
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, 22);
session.setPassword(password);
session.setConfig(config);
session.connect();
System.out.println("Connected");
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command1);
channel.setInputStream(null);
((ChannelExec) channel).setErrStream(System.err);
InputStream in = channel.getInputStream();
channel.connect();
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) {}
}
channel.disconnect();
session.disconnect();
System.out.println("DONE");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Variant A: Using JSch all the way
This minimal script (test.sh) requests an input from stdin before putting out one line of data:
#!/bin/bash
echo -n "Is this a good question (y/n)? "
read answer
if echo "$answer" | grep -iq "^y" ;then
echo Yes
else
echo No
fi
So it should be equivalent to your call requesting a password to be given. Now have a look at this code on how to send data into that process
String command1 = "cd /home/jan; ./test.sh";
try {
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, 22);
session.setPassword(password);
session.setConfig(config);
session.connect();
System.out.println("Connected");
ChannelExec channel = (ChannelExec)session.openChannel("exec");
OutputStream o = channel.getOutputStream();
PrintWriter pw = new PrintWriter(o);
InputStream in = channel.getInputStream();
((ChannelExec) channel).setCommand(command1);
channel.connect();
// 1 - Reading the prompt to input password
byte[] buf = new byte[255];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
// 2 - Send (password) data and flush stream
pw.println("y");
pw.flush();
// 3 - Read result
BufferedReader br = new BufferedReader(new InputStreamReader(in));
System.out.println(br.readLine());
// 4 - Clean up
channel.disconnect();
session.disconnect();
Variant B: Shell magic
String command1 = "cd /test; echo 'password' | ./test.sh";
or
String command1 = "cd /test; ./test.sh <<< 'password'";
(of cause you'd need to specify correct password there)
To run remote script with root privileges even if login user does not have them see here:
https://askubuntu.com/questions/155791/how-do-i-sudo-a-command-in-a-script-without-being-asked-for-a-password

JSch : channel never closed or EOF

I am new to JSch and I have a problem with some of my script I try to execute remotely and which seems to never end (and does not do the same thing as when I run it using putty).
I have redirected error and output stream to my System.out and see indeed error when the script is executed but the script is finished! Therefore I don't understand why the channel is still open (isClosed and isEOF are false).
When I run the command when connecting in SSH with putty the script execute correctly and does not show any errors. When I do ssh user#host "my command" using ssh command in Ubuntu I get the same output (std + err) as when I use JSch but the ssh command does not hangs!
Do you have any idea of what I do wrong, why does I have different output/behavior? Here is the java code I run (by the way I CAN'T send several command with different channel on the same sessions and I have no idea why, I therefore open one session for each cmd).
public static void runCommand(String user, String password, String cmd) throws JSchException, IOException{
Session session = jSsh.getSession(user, SERVER, SSH_PORT);
session.setPassword(password);
session.setConfig(SSH_PROPERTIES);
session.connect();
SshCommand sshCmd = new SshCommand(session, cmd);
runCommand(sshCmd);
session.disconnect();
}
private static void runCommand(SshCommand sshCmd) throws IOException, JSchException{
Session session = sshCmd.getSshSession();
String cmd = sshCmd.getCmd();
UtilityLogger.log(Level.FINE, "Running command on ssh : "+cmd);
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setCommand(cmd);
channel.setInputStream(null);
InputStream in = channel.getInputStream();
InputStream err = channel.getErrStream();
UtilityLogger.log(Level.FINEST, "Connecting to channel");
channel.connect();
UtilityLogger.log(Level.FINEST, "Channel connected");
byte[] tmp = new byte[1024];
byte[] tmp2 = new byte[1024];
while (true) {
//Flush channel
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0)
break;
UtilityLogger.log(Level.FINE, new String(tmp, 0, i));
}
//Flush Error stream
while (err.available() > 0) {
int i = err.read(tmp2, 0, 1024);
if (i < 0)
break;
UtilityLogger.log(Level.FINE, new String(tmp2, 0, i));
}
if(DONT_WAIT_PROCESS_END)
break;
if (channel.isEOF()) {
UtilityLogger.log(Level.FINE, "Channel exit-status: " + channel.getExitStatus());
break;
}
}
try{Thread.sleep(TIME_BETWEEN_COMMAND);}catch(Exception ee){}
channel.disconnect();
UtilityLogger.log(Level.FINEST, "Channel disconnected");
}
Try appending "exit;" after your commands even while using exec channels.
Our app did not receive an EOF on the exec, too. Appending an exit; to the command did not solve the problem.
It had something to do with the stderr output. Redirecting stderr to stdout solved (workarounded?!) the problem.
So we appended 2>&1 to the command:
${command} 2>&1

Categories