Package org.apache.commons.net.bsd

Source Code of org.apache.commons.net.bsd.RExecClient

package org.apache.commons.net.bsd;

/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
*    "Apache Commons" must not be used to endorse or promote products
*    derived from this software without prior written permission. For
*    written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without
*    prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import org.apache.commons.net.io.SocketInputStream;
import org.apache.commons.net.SocketClient;
import java.io.OutputStream;

/***
* RExecClient implements the rexec() facility that first appeared in
* 4.2BSD Unix.  This class will probably only be of use for connecting
* to Unix systems and only when the rexecd daemon is configured to run,
* which is a rarity these days because of the security risks involved.
* However, rexec() can be very useful for performing administrative tasks
* on a network behind a firewall.
* <p>
* As with virtually all of the client classes in org.apache.commons.net, this
* class derives from SocketClient, inheriting its connection methods.
* The way to use RExecClient is to first connect
* to the server, call the <a href="#rexec"> rexec() </a> method, and then
* fetch the connection's input, output, and optionally error streams.
* Interaction with the remote command is controlled entirely through the
* I/O streams.  Once you have finished processing the streams, you should
* invoke <a href="#disconnect"> disconnect() </a> to clean up properly.
* <p>
* By default the standard output and standard error streams of the
* remote process are transmitted over the same connection, readable
* from the input stream returned by
* <a href="#getInputStream"> getInputStream() </a>.  However, it is
* possible to tell the rexecd daemon to return the standard error
* stream over a separate connection, readable from the input stream
* returned by <a href="#getErrorStream"> getErrorStream() </a>.  You
* can specify that a separate connection should be created for standard
* error by setting the boolean <code> separateErrorStream </code>
* parameter of <a href="#rexec"> rexec() </a> to <code> true </code>.
* The standard input of the remote process can be written to through
* the output stream returned by
* <a href="#getOutputStream"> getOutputSream() </a>.
* <p>
* <p>
* @author Daniel F. Savarese
* @see SocketClient
* @see RCommandClient
* @see RLoginClient
***/

public class RExecClient extends SocketClient
{
    /***
     * The default rexec port.  Set to 512 in BSD Unix.
     ***/
    public static final int DEFAULT_PORT = 512;

    private boolean __remoteVerificationEnabled;

    /***
     * If a separate error stream is requested, <code>_errorStream_</code>
     * will point to an InputStream from which the standard error of the
     * remote process can be read (after a call to rexec()).  Otherwise,
     * <code> _errorStream_ </code> will be null.
     ***/
    protected InputStream _errorStream_;

    // This can be overridden in local package to implement port range
    // limitations of rcmd and rlogin
    InputStream _createErrorStream() throws IOException
    {
        ServerSocket server;
        Socket socket;

        server = _socketFactory_.createServerSocket(0, 1, getLocalAddress());

        _output_.write(Integer.toString(server.getLocalPort()).getBytes());
        _output_.write('\0');
        _output_.flush();

        socket = server.accept();
        server.close();

        if (__remoteVerificationEnabled && !verifyRemote(socket))
        {
            socket.close();
            throw new IOException(
                "Security violation: unexpected connection attempt by " +
                socket.getInetAddress().getHostAddress());
        }

        return (new SocketInputStream(socket, socket.getInputStream()));
    }


    /***
     * The default RExecClient constructor.  Initializes the
     * default port to <code> DEFAULT_PORT </code>.
     ***/
    public RExecClient()
    {
        _errorStream_ = null;
        setDefaultPort(DEFAULT_PORT);
    }


    /***
     * Returns the InputStream from which the standard outputof the remote
     * process can be read.  The input stream will only be set after a
     * successful rexec() invocation.
     * <p>
     * @return The InputStream from which the standard output of the remote
     * process can be read.
     ***/
    public InputStream getInputStream()
    {
        return _input_;
    }


    /***
     * Returns the OutputStream through which the standard input of the remote
     * process can be written.  The output stream will only be set after a
     * successful rexec() invocation.
     * <p>
     * @return The OutputStream through which the standard input of the remote
     * process can be written.
     ***/
    public OutputStream getOutputStream()
    {
        return _output_;
    }


    /***
     * Returns the InputStream from which the standard error of the remote
     * process can be read if a separate error stream is requested from
     * the server.  Otherwise, null will be returned.  The error stream
     * will only be set after a successful rexec() invocation.
     * <p>
     * @return The InputStream from which the standard error of the remote
     * process can be read if a separate error stream is requested from
     * the server.  Otherwise, null will be returned.
     ***/
    public InputStream getErrorStream()
    {
        return _errorStream_;
    }


    /***
     * Remotely executes a command through the rexecd daemon on the server
     * to which the RExecClient is connected.  After calling this method,
     * you may interact with the remote process through its standard input,
     * output, and error streams.  You will typically be able to detect
     * the termination of the remote process after reaching end of file
     * on its standard output (accessible through
     * <a href="#getInputStream"> getInputStream() </a>.    Disconnecting
     * from the server or closing the process streams before reaching
     * end of file will not necessarily terminate the remote process.
     * <p>
     * If a separate error stream is requested, the remote server will
     * connect to a local socket opened by RExecClient, providing an
     * independent stream through which standard error will be transmitted.
     * RExecClient will do a simple security check when it accepts a
     * connection for this error stream.  If the connection does not originate
     * from the remote server, an IOException will be thrown.  This serves as
     * a simple protection against possible hijacking of the error stream by
     * an attacker monitoring the rexec() negotiation.  You may disable this
     * behavior with <a href="#setRemoteVerificationEnabled">
     * setRemoteVerificationEnabled()</a>.
     * <p>
     * @param username  The account name on the server through which to execute
     *                  the command.
     * @param password  The plain text password of the user account.
     * @param command   The command, including any arguments, to execute.
     * @param separateErrorStream True if you would like the standard error
     *        to be transmitted through a different stream than standard output.
     *        False if not.
     * @exception IOException If the rexec() attempt fails.  The exception
     *            will contain a message indicating the nature of the failure.
     ***/
    public void rexec(String username, String password,
                      String command, boolean separateErrorStream)
    throws IOException
    {
        int ch;

        if (separateErrorStream)
        {
            _errorStream_ = _createErrorStream();
        }
        else
        {
            _output_.write('\0');
        }

        _output_.write(username.getBytes());
        _output_.write('\0');
        _output_.write(password.getBytes());
        _output_.write('\0');
        _output_.write(command.getBytes());
        _output_.write('\0');
        _output_.flush();

        ch = _input_.read();
        if (ch > 0)
        {
            StringBuffer buffer = new StringBuffer();

            while ((ch = _input_.read()) != -1 && ch != '\n')
                buffer.append((char)ch);

            throw new IOException(buffer.toString());
        }
        else if (ch < 0)
        {
            throw new IOException("Server closed connection.");
        }
    }


    /***
     * Same as <code> rexec(username, password, command, false); </code>
     ***/
    public void rexec(String username, String password,
                      String command)
    throws IOException
    {
        rexec(username, password, command, false);
    }

    /***
     * Disconnects from the server, closing all associated open sockets and
     * streams.
     * <p>
     * @exception IOException If there an error occurs while disconnecting.
     ***/
    public void disconnect() throws IOException
    {
        if (_errorStream_ != null)
            _errorStream_.close();
        _errorStream_ = null;
        super.disconnect();
    }


    /***
     * Enable or disable verification that the remote host connecting to
     * create a separate error stream is the same as the host to which
     * the standard out stream is connected.  The default is for verification
     * to be enabled.  You may set this value at any time, whether the
     * client is currently connected or not.
     * <p>
     * @param enable True to enable verification, false to disable verification.
     ***/
    public final void setRemoteVerificationEnabled(boolean enable)
    {
        __remoteVerificationEnabled = enable;
    }

    /***
     * Return whether or not verification of the remote host providing a
     * separate error stream is enabled.  The default behavior is for
     * verification to be enabled.
     * <p>
     * @return True if verification is enabled, false if not.
     ***/
    public final boolean isRemoteVerificationEnabled()
    {
        return __remoteVerificationEnabled;
    }

}
TOP

Related Classes of org.apache.commons.net.bsd.RExecClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.