org.kepler.ssh.GsiSshExec.java Source code

Java tutorial

Introduction

Here is the source code for org.kepler.ssh.GsiSshExec.java

Source

/*
 * Copyright (c) 2004-2010 The Regents of the University of California.
 * All rights reserved.
 *
 * '$Author: berkley $'
 * '$Date: 2010-04-27 17:12:36 -0700 (Tue, 27 Apr 2010) $'
 * '$Revision: 24000 $'
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the above
 * copyright notice and the following two paragraphs appear in all copies
 * of this software.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 * ENHANCEMENTS, OR MODIFICATIONS.
 *
 */
package org.kepler.ssh;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.sshtools.common.configuration.SshToolsConnectionProfile;
import com.sshtools.common.hosts.DialogKnownHostsKeyVerification;
import com.sshtools.j2ssh.SftpClient;
import com.sshtools.j2ssh.SshClient;
import com.sshtools.j2ssh.authentication.AuthenticationProtocolState;
import com.sshtools.j2ssh.authentication.EKEYXAuthenticationClient;
import com.sshtools.j2ssh.authentication.GSSAuthenticationClient;
import com.sshtools.j2ssh.authentication.SshAuthenticationClient;
import com.sshtools.j2ssh.configuration.SshConnectionProperties;
import com.sshtools.j2ssh.connection.ChannelInputStream;
import com.sshtools.j2ssh.session.SessionChannelClient;

/**
 * This class provides functionality to use an GSISSH session to execute remote
 * commands and to transfer files on a remote machine.
 * <p>
 * To create a gsissh session the code needs a valid proxy certificate and a
 * valid CA certificate/ trusted certificate for the server.
 * The code searches for the proxy
 * certificates and CA certificates at default locations based on the
 * specifications of underlying jglobus package --
 * http://www-unix.globus.org/cog/distribution/1.6.0/docs/configuring.html
 * By default it looks for proxy certificates in the system's temp directory
 * and for CA certificates(trusted certificates) in
 * ${user.home}/.globus/certificates and /etc/grid-security/certificates.
 * You can alter the default file and search path by creating appropriate
 * entries in $HOME/.globus/cog.properties. Please refer to
 * http://www-unix.globus.org/cog/distribution/1.6.0/docs/configuring.html
 * for more configuration details.
 * <p>
 *
 * You can create several sessions to different sites and use any of them
 * referring to it with its user@host:port. If port is not specified defaults
 * to 2222. Once instantiated the GsiSsh object can be used by anyone anytime
 * to copy file or execute commands without authenticating again.
 * <p>
 *
 * @author Chandrika Sivaramakrishnan
 *
 *  This uses a modified code of the open source product GSI-SSHTerm.
 *  http://www.ngs.ac.uk/tools/gsisshterm
 *  Since GSI-SSHTerm is a terminal product most of the error scenarios and
 *  user interaction scenarios are handled using GUI popups. This part of
 *  the GSI-SSHTerm code hasn't been modified and hence this code will fail when
 *  user interaction are to be handled through command prompt. For example,
 *  when kepler is run without gui. In such cases use this with an existing
 *  valid proxy certificate
 */
public class GsiSshExec extends RemoteExec {

    // variables specific to GSI SSH
    protected SshClient sshClient;
    protected SshConnectionProperties connectionProfile = new SshToolsConnectionProfile();

    //variables common to SshExec and GsiSshExec
    private int timeout = 0; // timeout in seconds
    private boolean forcedCleanUp = false;
    private static String cleanUpInfoCmd = new String("echo $$; ");
    // restart timer if stdout has data
    private boolean timeoutRestartOnStdout = false;
    // restart timer if stderr has data
    private boolean timeoutRestartOnStderr = false;

    private boolean pseudoTerminal = false;
    private String protocolPath = "";
    private String cmdLineOptions = "";
    private String targetStr = "";
    private List availableAuthMethods;

    //Logging
    private static final Log log = LogFactory.getLog(GsiSshExec.class.getName());
    private static final boolean isDebugging = log.isDebugEnabled();

    public GsiSshExec(String user, String host) {
        //session = SshSessionFactory.getSession(user, host, 22);
        //session is not cached currently
        sshClient = GsiSshSessionFactory.getSshClient(user, host, 2222);
        connectionProfile.setHost(host);
        connectionProfile.setUsername(user);

        targetStr = connectionProfile.getUsername() + "@" + connectionProfile.getHost();
    }

    public GsiSshExec(String user, String host, int port) {
        sshClient = GsiSshSessionFactory.getSshClient(user, host, port);
        connectionProfile.setHost(host);
        connectionProfile.setUsername(user);
        connectionProfile.setPort(port);

        targetStr = connectionProfile.getUsername() + "@" + connectionProfile.getHost() + ":"
                + connectionProfile.getPort();
    }

    public GsiSshExec(String target) {
        // get USER
        String user, host;
        int port = 2222;

        int atPos = target.indexOf('@');
        if (atPos >= 0) {
            user = target.substring(0, target.indexOf('@'));
        } else {
            user = System.getProperty("user.name");
        }

        // get the HOST and PORT
        int colonPos = target.indexOf(':');
        if (colonPos >= 0 && colonPos > atPos) {
            host = target.substring(atPos + 1, colonPos);
            String portStr = target.substring(colonPos + 1);
            try {
                port = Integer.parseInt(portStr);
            } catch (java.lang.NumberFormatException ex) {
                log.error("The port should be a number or omitted in " + target);
            }
        } else {
            host = target.substring(atPos + 1);
        }

        sshClient = GsiSshSessionFactory.getSshClient(user, host, port);
        connectionProfile.setHost(host);
        connectionProfile.setUsername(user);
        connectionProfile.setPort(port);

        targetStr = connectionProfile.getUsername() + "@" + connectionProfile.getHost() + ":"
                + connectionProfile.getPort();

    }

    public int copyFrom(String sourcePath, File localPath, boolean recursive) throws SshException {
        int numberOfCopiedFiles = 0;
        if (recursive) {
            throw new SshException("Recursive copy is not supported on grid servers");
        }
        if (!openConnection())
            throw new SshException("Ssh connection could not be opened for copying.");
        try {
            SftpClient sftpclient = new SftpClient(sshClient);
            if (localPath == null) {
                sftpclient.get(sourcePath);
            } else {
                String path = localPath.getAbsolutePath();
                int index = -1;
                if (localPath.isDirectory()) {
                    index = sourcePath.lastIndexOf('/');
                    if (index > -1 && index < sourcePath.length() - 1) {
                        path = path + System.getProperty("file.separator") + sourcePath.substring(index + 1);
                    } else {
                        path = path + System.getProperty("file.separator") + sourcePath;
                    }
                }
                sftpclient.get(sourcePath, path);
            }
            numberOfCopiedFiles = 1;
        } catch (Exception e) {
            throw new SshException("Exception caught at while copying file: " + sourcePath + "\n" + e);
        }
        return 0;
    }

    /**
     * Copy _one_ local file to a remote directory Input: file of type File
     * (which can be a directory) Input must not have wildcards. targetPath is
     * either a directory or filename
     *
     * @return number of files copied successfully SshException is thrown in
     *         case of error.
     */
    protected int _copyTo(File lfile, String targetPath, boolean recursive) throws SshException {

        if (!lfile.exists()) {
            throw new SshException("File does not exist: " + lfile);
        }

        // check: recursive traversal of directories enabled?
        if (lfile.isDirectory()) {
            //         if (!recursive)
            //            throw new SshException("File " + lfile
            //                  + " is a directory. Set recursive copy!");
            throw new SshException(
                    lfile.getName() + " is a directory. Recursive copy is not supported on grid servers");
        }

        if (!openConnection())
            throw new SshException("Ssh connection could not be opened for copying.");

        // at this point we have a living, opened session to the remote machine
        int numberOfCopiedFiles = 0;
        try {
            String path = lfile.getAbsolutePath();
            SftpClient sftpclient = new SftpClient(sshClient);

            //by default preserves file attributes
            if (targetPath == null || targetPath.trim().equals("")) {
                sftpclient.put(path);
            } else {
                sftpclient.put(path, targetPath);
            }
            // if there is no exception return 1
            numberOfCopiedFiles = 1;
        } catch (Exception e) {
            throw new SshException("Exception caught at while copying file: " + lfile + "\n" + e);
        }

        return numberOfCopiedFiles;
    }

    public int executeCmd(String command, OutputStream streamOut, OutputStream streamErr) throws ExecException {
        return executeCmd(command, streamOut, streamErr, null);
    }

    public int executeCmd(String command, OutputStream streamOut, OutputStream streamErr, String thirdPartyTarget)
            throws ExecException {

        int exitCode = -1;
        SessionChannelClient sessionChannel;
        _streamReaderThread readerThread;
        boolean commandSuccess;
        ChannelInputStream stderrInputStream;

        // get the pwd to the third party if necessary
        String thirdPartyPwd = getPwdToThirdParty(thirdPartyTarget);
        // Form the command
        String updatedCmd = forcedCleanUp ? cleanUpInfoCmd + command : command;

        openConnection();
        log.debug("Connected");

        //int result = copyTo(new File("C:\\Chandrika\\test.txt"),"/home/chandrika",false);
        //return result;

        try {

            // Create piped stream if password has to be fed
            PipedInputStream pis = null;
            PipedOutputStream pos = null;
            if (thirdPartyPwd != null) {
                try {
                    pis = new PipedInputStream();
                    pos = new PipedOutputStream(pis);
                } catch (IOException ex) {
                    log.error("Error when creating the piped stream for password feededing: " + ex);
                    throw new ExecException("Error when creating the piped stream for password feededing: " + ex);
                }
                // setting pseudo terminal to true so that prompt for password
                // can be read
                // SshExec uses ptyexec.c instead of using pseudo terminal
                pseudoTerminal = true;
            }

            // Open channel and execute command
            synchronized (sshClient) {

                // Once authenticated the user's shell can be started
                // Open a session channel
                sessionChannel = sshClient.openSessionChannel();
                // create pseudo terminal if user has asked for it
                if (pseudoTerminal) {
                    sessionChannel.requestPseudoTerminal("vt100", 80, 24, 640, 480, null);
                }
                if (thirdPartyPwd != null) {
                    sessionChannel.bindInputStream(pis);
                }
                stderrInputStream = (ChannelInputStream) sessionChannel.getStderrInputStream();
                readerThread = new _streamReaderThread(sessionChannel, sessionChannel.getInputStream(), streamOut,
                        thirdPartyPwd, pos);
                readerThread.start();
                commandSuccess = sessionChannel.executeCommand(updatedCmd);
            }

            log.debug("boolean command excution result is" + commandSuccess);
            // command has finished executing. wait for the reader thread to
            // finish reading output
            // It will timeout at the latest if the command does not finish
            // 3 ways to finish:
            // - command terminates
            // - timeout
            // - IOException when reading the command's output or writing
            // the caller's output
            readerThread.join();

            // on timeout finish here with a nice Exception
            if (readerThread.timeoutHappened()) {
                log.error("Timeout: " + timeout + "s elapsed for command " + command);
                if (sessionChannel.isOpen()) {
                    sessionChannel.close(); //closes channels and frees channel
                }
                if (forcedCleanUp) {
                    // time for clean-up ;-)
                    kill(readerThread.getProcessID(), true);
                }
                throw new ExecTimeoutException(command);
            }

            // if we cannot process output, still wait for the channel to be
            // closed
            // !!! This can lead to hang-up !!!
            while (!sessionChannel.isClosed()) {
                try {
                    log.debug("Waiting for channel to close");
                    Thread.sleep(500);
                } catch (Exception e) {
                }
            }
            Integer temp = sessionChannel.getExitCode();
            if (temp != null) {
                exitCode = temp.intValue();
            }
            // disconnect for now.
            //Remove this once session cache is implemented. If session is cached,
            //should call closeConnection to close the session
            //closeConnection();

            if (exitCode != 0 && forcedCleanUp) {
                kill(readerThread.getProcessID(), true);
            }
            //update streamErr with contents from stderrInputStream
            byte[] b = new byte[1024];
            int numread = stderrInputStream.read(b, 0, 1024);
            while (numread != -1) {
                streamErr.write(b, 0, numread);
                numread = stderrInputStream.read(b, 0, 1024);
            }

            // FORDEBUG
            /*System.out.println("Output===" + streamOut.toString());
            System.out.println("==Checking for error==");
            System.out.println("Error== " + streamErr.toString());
            System.out.println("Exiting GsiExec " );
            */// FORDEBUG

        } catch (Exception e) {
            throw new ExecException("Exception occured while executing command " + command + "\n" + e);
        }
        return exitCode;
    }

    public List getAvailableAuthMethods() throws SshException {
        try {
            if (sshClient == null) {
                return null;
            } else if (!sshClient.isConnected()) {
                openConnection(false);
            } else {
                log.debug("Connection already opened");
            }
            synchronized (sshClient) {
                availableAuthMethods = sshClient.getAvailableAuthMethods(connectionProfile.getUsername());
            }
            return availableAuthMethods;
        } catch (Exception e) {
            log.error(
                    "Error getting the supported authentication mechanism for " + targetStr + "\n" + e.toString());
            throw new SshException("Unable to connect to / get the list of authentication from " + targetStr);
        }
    }

    public boolean openConnection() throws SshException {
        return openConnection(true);
    }

    public boolean openConnection(boolean authenticate) throws SshException {
        if (null == sshClient)
            return false;
        if (sshClient.isConnected() && sshClient.isAuthenticated())
            return true;

        //Two step process - 1. Connect 2.authenticate
        synchronized (sshClient) {
            //log.debug("BEGIN: Open connection");
            if (!sshClient.isConnected()) {
                try {
                    // Should pass instance of SshToolsConnectionProfile when using gss
                    // authentication
                    //System.out.println("Connecting using sshClient.connect()........");
                    sshClient.connect(connectionProfile, new DialogKnownHostsKeyVerification(null));
                    //log.debug("###Connection established successfully");
                    // //TODO:Run long running job to test if session would be alive
                } catch (Exception e) {
                    //log.debug("END: Open connection.Error connecting to "+ targetStr);
                    throw new SshException("Error connecting to " + targetStr + " \n" + e);
                }
            }
            /*
             * Once this code has executed and returned the connection is ready for
             * authentication
             */
            if (authenticate && !sshClient.isAuthenticated()) {
                boolean result = authenticate(false);
                //log.debug("END: Open connection. Returning connection after call to authenticate");
                return result;
            } else {
                //log.debug("END: Open connection. Returning connection without authenticating");
                return true;
            }
        }
    }

    public boolean authenticate(boolean externalkeyx) throws SshException {
        boolean authenticated = false;
        if (null == sshClient)
            return authenticated;

        SshAuthenticationClient authClient;
        // If the server supports external key exchange authenticate using that
        //if(externalkeyx){
        if (availableAuthMethods != null && availableAuthMethods.contains("external-keyx")) {
            authClient = new EKEYXAuthenticationClient();
            authClient.setHostname(connectionProfile.getHost());
            authClient.setUsername(connectionProfile.getUsername());
            authClient.setProperties(connectionProfile);
            int result;
            try {
                log.debug("Authenticating using external-keyx");
                result = sshClient.authenticate(authClient, connectionProfile.getHost());
                log.debug("Authentication complete");

            } catch (Exception e) {
                throw new SshException("Exception authenticating to " + targetStr + " using external-keyx \n" + e);
            }
            if (result == AuthenticationProtocolState.COMPLETE) {
                log.debug("Authentication to host " + connectionProfile.getHost()
                        + " using external-keyx was successful");
                return true;
            }
        }

        authClient = new GSSAuthenticationClient();
        // username and host name have to be set explicitly even though they
        // are in properties - bug in GSI-SSHTerm code?
        authClient.setHostname(connectionProfile.getHost());
        authClient.setUsername(connectionProfile.getUsername());
        authClient.setProperties(connectionProfile);

        // Authenticate the user
        // Authentication result could be partial- when does this occur?
        // TODO:Handle partial authentication
        int result;
        try {
            log.debug("Authenticating using gssapi");
            result = sshClient.authenticate(authClient, connectionProfile.getHost());
            log.debug("Authenticating using gssapi complete");
        } catch (Exception e) {
            throw new SshException("Exception authenticating to " + targetStr + "\n" + e);
        }
        if (result == AuthenticationProtocolState.COMPLETE) {
            log.debug("Authentication to host " + connectionProfile.getHost() + "  using gssapi was successful");
            return true;
        } else {
            throw new SshException("Authentication failed for: " + targetStr);
        }

    }

    public void closeConnection() {

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

    public void setForcedCleanUp(boolean forcedCleanUp) {
        this.forcedCleanUp = forcedCleanUp;
    }

    public void setTimeout(int seconds, boolean stdout, boolean stderr) {
        this.timeout = seconds;
        timeoutRestartOnStdout = stdout;
        timeoutRestartOnStderr = stderr;

    }

    /**
     * addIdentity, useless for local exec 
     */
    public void addIdentity(String identity) {
        // do nothing 
    }

    /**
     * port forwarding not working on local exec
     */
    public void setPortForwardingL(String spec) throws ExecException {
        // do nothing
    }

    /**
     * port forwarding not working on local exec
     */
    public void setPortForwardingR(String spec) throws ExecException {
        // do nothing
    }

    @Override
    public boolean getForcedCleanUp() {
        return forcedCleanUp;
    }

    @Override
    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int seconds) {
        timeout = seconds;
    }

    // ////////////Private class///////////////////////
    private class _streamReaderThread extends Thread {
        private InputStreamReader isr; // 'char' reader from the remote command
        private OutputStreamWriter osw; // 'char' writer to the caller's output
        // stream

        private boolean cleanUpInfoProcessed = !forcedCleanUp; // false: will
        // consume first
        // line for
        // process ID
        private String pwd; // the password to be fed to the command
        private PipedOutputStream pos; // the pipe-in to the stdin of the
        // remote
        // command
        private SessionChannelClient channel;

        private StringBuffer processID; // the remote command's shell's process
        // id (to kill if needed)
        private boolean timeoutReached; // becomes true on timeout

        public _streamReaderThread(SessionChannelClient sessionChannel, InputStream in, OutputStream out,
                String pwd, PipedOutputStream pos) {
            try {
                isr = new InputStreamReader(in, "utf-8");
                osw = new OutputStreamWriter(out, "utf-8");
            } catch (UnsupportedEncodingException ex) {
                // get the default encoding
                isr = new InputStreamReader(in);
                osw = new OutputStreamWriter(out);
            }

            channel = sessionChannel;
            this.pwd = pwd;
            this.pos = pos;
        }

        public String getProcessID() {
            return processID.toString();
        }

        public boolean timeoutHappened() {
            return timeoutReached;
        }

        public void run() {
            log.debug("In run");
            char[] tmp = new char[1024];
            boolean checkForPwd = (pwd != null);
            processID = new StringBuffer();

            // variables for the timeout checking
            long start = System.currentTimeMillis();
            long current = 0;
            long maxtime = timeout * 1000L;

            while (true) { // read command's output until termination or
                // timeout
                int len = 0;
                int j = 0;
                try {
                    while (isr.ready()) { // we do not want to block on read
                        // because we are counting for
                        // timeout
                        //System.out.println("In isr.ready");
                        len = isr.read(tmp, 0, 1024);

                        if (len < 0) {
                            if (isDebugging)
                                log.debug("Read error on stdout stream: " + len);
                            break; // break the reading loop
                        }
                        j = 0;

                        // first line is remote process id in case of
                        // forcedCleanUp. Filter here
                        if (!cleanUpInfoProcessed) {
                            // if (isDebugging)
                            // log.debug("cleanup info string: " + new
                            // String(tmp, 0, len));
                            for (; j < len; j++) {
                                if (tmp[j] == '\n') {
                                    cleanUpInfoProcessed = true; // done
                                    j++;
                                    if (isDebugging)
                                        log.debug("Remote process id = " + processID);
                                    break; // break the reading loop
                                }
                                processID.append(tmp[j]);
                            }
                            // Note: j<=len here
                        }

                        // print the buffer to the output stream
                        osw.write(tmp, j, len - j);
                        osw.flush(); // send it really if someone is polling
                        // it
                        // above us
                        if (timeoutRestartOnStdout)
                            start = System.currentTimeMillis(); // restart
                        // timeout timer
                        //System.out.println(" %%% "
                        //      + new String(tmp, j, len - j));
                        // if (timeoutRestartOnStdout)
                        // start = System.currentTimeMillis(); // restart
                        // // timeout timer
                        String tempStr = new String(tmp, j, len - j);
                        if (tempStr.contains("RSA key fingerprint is") && tempStr.trim().endsWith("(yes/no)?")) {
                            boolean userInput = promptYesNo(tempStr);
                            // boolean userInput = true;
                            log.debug("Prompt for host verification: " + tempStr);
                            if (userInput) {
                                pos.write("yes\n".getBytes());
                                pos.flush();
                                log.info("Added destination server to known_hosts of source");
                                continue;
                            } else {
                                pos.write("no\n".getBytes());
                                pos.flush();
                                pos.close();
                                log.error("Failed to accept RSA key fingerprint");
                                break;
                            }
                        }

                        if (checkForPwd && containsPasswordRequest(tmp, j, len)) {
                            // now feed the password to the process
                            try {

                                pos.write(pwd.getBytes());
                                // log.info("Sent password ");
                                pos.write("\n".getBytes());
                                // log.info("Sent newline ");
                                pos.flush();
                                // log.info("Flushed pos ");
                                pos.close();
                                log.info("Sent password to third party.");
                            } catch (IOException ex) {
                                log.error("Error when feeding the password to the piped stream: " + ex);
                            } catch (Exception e) {
                                log.error("Error when feeding the password to the piped stream: " + e);
                            }
                            checkForPwd = false;
                        }
                    } // end while isr.ready
                } catch (IOException ex) {
                    log.error("Error on the remote streams. Exiting reader thread: " + ex);
                    break; // exit the loop
                }
                if (channel.isClosed()) {
                    System.out.println("Channel is closed");
                    break; // exit the loop
                }
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                }

                // check timeout
                current = System.currentTimeMillis();
                if (timeout > 0 && maxtime < current - start) {
                    log.debug("Reader thread detected timeout: " + timeout + "s elapsed");
                    timeoutReached = true;
                    break; // exit the loop
                }
            } // end of while (true)

            try {
                osw.close();
            } catch (IOException ex) {
                log.error("Cannot flush and close the output stream: " + ex);
            }
        } // end method run()

        /**
         * Look for one of the strings password/passphrase/passcode in the
         * char[] array. Return true if found any. Case insensitive search.
         * Possible bug: we do not find the password text if it is broken into
         * two in two consecutive calls.
         */
        private boolean containsPasswordRequest(char[] buf, int startPos, int endPos) {
            // look for strings password/passphrase/passcode
            int i = startPos;
            while (i < endPos - 3) {
                if (Character.toLowerCase(buf[i]) == 'p' && Character.toLowerCase(buf[i + 1]) == 'a'
                        && Character.toLowerCase(buf[i + 2]) == 's' && Character.toLowerCase(buf[i + 3]) == 's') {

                    // found "pass", look further for word/code/phrase
                    if (i < endPos - 7 && Character.toLowerCase(buf[i + 4]) == 'w'
                            && Character.toLowerCase(buf[i + 5]) == 'o' && Character.toLowerCase(buf[i + 6]) == 'r'
                            && Character.toLowerCase(buf[i + 7]) == 'd') {
                        log.info("PWDSearch: found request for password.");
                        return true;
                    } else if (i < endPos - 7 && Character.toLowerCase(buf[i + 4]) == 'c'
                            && Character.toLowerCase(buf[i + 5]) == 'o' && Character.toLowerCase(buf[i + 6]) == 'd'
                            && Character.toLowerCase(buf[i + 7]) == 'e') {
                        log.info("PWDSearch: found request for passcode.");
                        return true;
                    } else if (i < endPos - 9 && Character.toLowerCase(buf[i + 4]) == 'p'
                            && Character.toLowerCase(buf[i + 5]) == 'h' && Character.toLowerCase(buf[i + 6]) == 'r'
                            && Character.toLowerCase(buf[i + 7]) == 'a' && Character.toLowerCase(buf[i + 8]) == 's'
                            && Character.toLowerCase(buf[i + 9]) == 'e') {
                        log.info("PWDSearch: found request for passphrase.");
                        return true;
                    }
                }
                i = i + 1;
            }
            return false;
        }
    } // end inner class _streamReaderThread

    private boolean promptYesNo(String str) {
        //      Object[] options = { "yes", "no" };
        //      int foo = JOptionPane.showOptionDialog(null, str, "Warning",
        //            JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null,
        //            options, options[0]);
        //      return foo == 0;
        return true; // Used for prompts like confirming machine's rsa finger print
    }

    private String getPwdToThirdParty(String target) throws ExecException {
        String pwd = null;
        if (target == null || target.trim().length() == 0)
            return null;
        //check if target is a ssh server
        ExecInterface temp = ExecFactory.getExecObject(target);
        if (temp instanceof SshExec) {
            pwd = SshSession.getPwdToThirdParty(target);
        }
        // For grid servers we are currently supporting
        // grid auth only thro' existing proxy. so return null
        return pwd;
    }

}