JSch: Is there a way to expose user environment va

2019-01-20 03:00发布

问题:

I am trying to run commands which uses local Linux logical paths like cat $test_dir/test.dat, but the logical path $test_dir (which is a user environment variable) is not available via ChannelExec. But when I use interactive ChannelShell, I am able to see the user variables and the commands run fine on the interactive session. I can view system level environment variable only from "exec" session. Is that even possible using JSch library, if yes then how shall I achieve it and if not what library shall I use to achieve this?

Adding my class code below: `public class SecureShell {

private static final Logger logger = LogManager.getLogger(SecureShell.class);

private String uName;
private String pWord;
private String hName;
private int port;

private Session session = null;
private Channel channel = null;

/**Create an instance to start and stop the remote shell and execute commands remotely via java.
 * 
 * @param uName
 *          host username 
 * @param pWord
 *          host password
 * @param hName
 *          host name
 * @param port
 *          host port number
 */
public SecureShell(String uName, String pWord, String hName, int port) {
    this.uName = uName;
    this.pWord = pWord;
    this.hName = hName;
    this.port = port;
}

/**Create an instance to start and stop the remote shell and execute commands remotely via java.
 * 
 *@param uName
 *          host username 
 * @param pWord
 *          host password
 * @param hName
 *          host name
 */
public SecureShell(String uName, String pWord, String hName) {
    this.uName = uName;
    this.pWord = pWord;
    this.hName = hName;
    this.port = 22;
}

/**Start the session with the host.
 * @return
 *      true if the session started successfully, false otherwise
 */
public boolean startSession() {
    JSch jsch = new JSch();
    try {
        session = jsch.getSession(uName, hName, port);

        java.util.Properties config = new java.util.Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.setPassword(pWord);
        session.connect();

    } catch (JSchException jsche) {
        logger.error(jsche.getMessage());
        return false;
    } 

    return true;
}

/** Execute commands on the host;
 * @param command
 *          command to be executed on the host.
 * @return
 *      status of the execution
 */
public int execute(String command) {

    int status = -1;
    if(session != null && session.isConnected()) {
        try {
            channel = session.openChannel("exec");
            //((ChannelExec)channel).setEnv("LC_XXX", "xxxxxxx");
            ((ChannelExec)channel).setPty(true);
            ((ChannelExec) channel).setCommand(command);

            InputStream in = channel.getInputStream();

            channel.connect();

             byte[] buffer = new byte[1024];
             while(true){
                 while(in.available()>0){
                     int i=in.read(buffer, 0, 1024);
                     System.out.print(new String(buffer, 0, i));
                     if(i<0)
                         break;
                }
                 if(channel.isClosed()){
                     if(in.available()>0) 
                         continue; 
                     status = channel.getExitStatus();
                     break;
                 }
            }
        } catch (JSchException jsche) {
            logger.error(jsche.getMessage());
        } catch (IOException ioe) {
            logger.error(ioe.getMessage());
        } finally {
            if(channel!=null && channel.isConnected())
                channel.disconnect();
        } 
    }

    return status;
}

/**Stop the session with the remote.
 * 
 */
public void stopSession() {

    if(session!=null && session.isConnected())
        session.disconnect();
}

public static void main(String[] args) {
    SecureShell ssh  = new SecureShell("user", "password", "hostname");
    ssh.startSession();
    System.out.println(ssh.execute("env"));
    ssh.stopSession();
}

}`

回答1:

Since you're not opening up an interactive shell, your environment variables won't be set. However, you can use the bash command with --login (man bash for more details) to get the results you want

bash --login -c 'command arg1 ...'"


回答2:

The "exec" channel in the JSch (rightfully) does not allocate a pseudo terminal (PTY) for the session by default. As a consequence a different set of startup scripts is (might be) sourced. And/or different branches in the scripts are taken, based on absence/presence of the TERM environment variable. So the environment might differ from the interactive JSch "shell" session or when you use your SSH client.


Ways to fix this:

  1. Fix your startup scripts to set the environment variables the same for both interactive and non-interactive sessions.

  2. Another (not recommended) approach is to force the pseudo terminal allocation for the "exec" channel using the .setPty method:

    Channel channel=session.openChannel("exec");
    ((ChannelExec)channel).setPty(true);
    

    Using the pseudo terminal to automate a command execution can bring you nasty side effects. See for example

    • Is there a simple way to get rid of junk values that come when you SSH using Python's Paramiko library and fetch output from CLI of a remote machine?
    • Remove of unwanted characters when i am using jsch to run command
    • Removing shell stuff (like prompts) from command output in JSch

For a similar issues, see

  • Certain Unix commands fail with "... not found", when executed through Java using JSch
  • Commands executed using JSch behaves differently than in SSH terminal (bypasses confirm prompt message of "yes/"no")


标签: java ssh jsch