问题
I'm trying to connect to a host, then change the user using "su - john" and then execute a command as john. Is it possible with using only JSch?
The problem is that after I create a session and open the channel and execute the aforementioned command it should request password, but nothing happens.
This is how I connect to the remote machine:
String address = "myremote.computer.com";
JSch jsch = new JSch();
String user = "tom";
String host = address;
String password = "l33tpaSSw0rd";
Session session = jsch.getSession( user, host, 22 );
java.util.Properties config = new java.util.Properties();
config.put( "StrictHostKeyChecking", "no" );
session.setConfig( config );
session.setPassword( password );
session.connect();
Then I execute commands via runSshCommand()
method which looks like this:
try
{
Channel channel = session.openChannel( "exec" );
channel.setInputStream( null );
channel.setOutputStream( System.out );
( (ChannelExec) channel ).setCommand( command );
channel.connect();
InputStream in = channel.getInputStream();
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() )
{
break;
}
try
{
Thread.sleep( 1000 );
}
catch ( Exception ee )
{
}
}
channel.disconnect();
}
catch ( Exception e )
{
e.printStackTrace();
}
Do I have to create another channel, when I change users, or how to make this work?
Because if I use
runSshCommand("su - john",session);
runSshCommand("tail -1 ~/mylog.log",session);
it just executes the "su" command but it doesn't finish the change of users and afterwards executing "tail" will result in an error because "tom" hasn't got the file :/
Basically I would like my application to connect to the machine, change user, read one file and return the data. Can anyone shed some light, please?
回答1:
You have several problems here.
First, each channel in a SSH connection is independent of the other ones, and the command in each exec channel is executed in its own shell (command line interpreter). So any changes you are doing in one channel have no effect at all to the other channels. You also can't do stuff like this:
runSshCommand("cd Documents", session);
runSshCommand("ls -l", session);
(Actually you can do this, but it will not show the contents of the Documents
directory, but of the home directory.)
For cd
, you can work around by passing both commands as one "command", to be used in the same exec
channel:
runSshCommand("cd Documents; ls -l");
(Instead of the ;
you can also use a line break \n
to separate the commands, or whatever else your shell accepts.)
For su
this will not work, where we come to the second problem.
su
is not a command which changes the state of the current shell (like cd
), but a command which opens a new shell inside the existing one. It will only return to the outer shell when you leave the shell started by su
(e.g. by exit
, logout
or end-of-file), and then you are again the same user as before.
To pass commands to the "inner shell", you'll have to pass them to the shells input. Or use the -c
(--command
) argument of su
:
runSshCommand("su -c 'tail -1 ~/mylog.log' - john ",session);
You might then run in the third problem: su
will ask for john's password, and might refuse to read it from the standard input, but try to read it from the terminal. And your channel has no pseudo-terminal. You can try to use cannel.setPty(true) and then actually write your password to the output stream, though I'm not sure that this will work.
Alternatives: Instead of su -c
you can use sudo
, which can be configured not to ask for a password for certain commands and users (otherwise you'll have the same terminal problem again). Or you could directly log in as john
, or make the logfile readable for tom. (Also, I hope your real password is better than the one in your source code.)
来源:https://stackoverflow.com/questions/16343117/java-jsch-changing-user-on-remote-machine-and-execute-command