    View Javadoc
    1   package org.apache.commons.net.bsd;
    2
    3   /* ====================================================================
    4    * The Apache Software License, Version 1.1
    5    *
    6    * Copyright (c) 2001 The Apache Software Foundation.  All rights
    7    * reserved.
    8    *
    9    * Redistribution and use in source and binary forms, with or without
    10   * modification, are permitted provided that the following conditions
    11   * are met:
    12   *
    13   * 1. Redistributions of source code must retain the above copyright
    14   *    notice, this list of conditions and the following disclaimer.
    15   *
    16   * 2. Redistributions in binary form must reproduce the above copyright
    17   *    notice, this list of conditions and the following disclaimer in
    18   *    the documentation and/or other materials provided with the
    19   *    distribution.
    20   *
    21   * 3. The end-user documentation included with the redistribution,
    22   *    if any, must include the following acknowledgment:
    23   *       "This product includes software developed by the
    24   *        Apache Software Foundation (http://www.apache.org/)."
    25   *    Alternately, this acknowledgment may appear in the software itself,
    26   *    if and wherever such third-party acknowledgments normally appear.
    27   *
    28   * 4. The names "Apache" and "Apache Software Foundation" and
    29   *    "Apache Commons" must not be used to endorse or promote products
    30   *    derived from this software without prior written permission. For
    31   *    written permission, please contact apache@apache.org.
    32   *
    33   * 5. Products derived from this software may not be called "Apache",
    34   *    nor may "Apache" appear in their name, without
    35   *    prior written permission of the Apache Software Foundation.
    36   *
    37   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
    38   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    39   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    40   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
    41   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    42   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    43   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    44   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    45   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    46   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    47   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    48   * SUCH DAMAGE.
    49   * ====================================================================
    50   *
    51   * This software consists of voluntary contributions made by many
    52   * individuals on behalf of the Apache Software Foundation.  For more
    53   * information on the Apache Software Foundation, please see
    54   * <http://www.apache.org/>;.
    55   */
    56
    57  import java.io.IOException;
    58  import java.io.InputStream;
    59  import java.net.ServerSocket;
    60  import java.net.Socket;
    61  import org.apache.commons.net.io.SocketInputStream;
    62  import org.apache.commons.net.SocketClient;
    63  import java.io.OutputStream;
    64
    65  /****
    66   * RExecClient implements the rexec() facility that first appeared in
    67   * 4.2BSD Unix.  This class will probably only be of use for connecting
    68   * to Unix systems and only when the rexecd daemon is configured to run,
    69   * which is a rarity these days because of the security risks involved.
    70   * However, rexec() can be very useful for performing administrative tasks
    71   * on a network behind a firewall.
    72   * <p>
    73   * As with virtually all of the client classes in org.apache.commons.net, this
    74   * class derives from SocketClient, inheriting its connection methods.
    75   * The way to use RExecClient is to first connect
    76   * to the server, call the <a href="#rexec"> rexec() </a> method, and then
    77   * fetch the connection's input, output, and optionally error streams.
    78   * Interaction with the remote command is controlled entirely through the
    79   * I/O streams.  Once you have finished processing the streams, you should
    80   * invoke <a href="#disconnect"> disconnect() </a> to clean up properly.
    81   * <p>
    82   * By default the standard output and standard error streams of the
    83   * remote process are transmitted over the same connection, readable
    84   * from the input stream returned by
    85   * <a href="#getInputStream"> getInputStream() </a>.  However, it is
    86   * possible to tell the rexecd daemon to return the standard error
    87   * stream over a separate connection, readable from the input stream
    88   * returned by <a href="#getErrorStream"> getErrorStream() </a>.  You
    89   * can specify that a separate connection should be created for standard
    90   * error by setting the boolean <code> separateErrorStream </code>
    91   * parameter of <a href="#rexec"> rexec() </a> to <code> true </code>.
    92   * The standard input of the remote process can be written to through
    93   * the output stream returned by
    94   * <a href="#getOutputStream"> getOutputSream() </a>.
    95   * <p>
    96   * <p>
    97   * @author Daniel F. Savarese
    98   * @see SocketClient
    99   * @see RCommandClient
    100  * @see RLoginClient
    101  ***/
    102
    103 public class RExecClient extends SocketClient
    104 {
    105     /****
    106      * The default rexec port.  Set to 512 in BSD Unix.
    107      ***/
    108     public static final int DEFAULT_PORT = 512;
    109
    110     private boolean __remoteVerificationEnabled;
    111
    112     /****
    113      * If a separate error stream is requested, <code>_errorStream_</code>
    114      * will point to an InputStream from which the standard error of the
    115      * remote process can be read (after a call to rexec()).  Otherwise,
    116      * <code> _errorStream_ </code> will be null.
    117      ***/
    118     protected InputStream _errorStream_;
    119
    120     // This can be overridden in local package to implement port range
    121     // limitations of rcmd and rlogin
    122     InputStream _createErrorStream() throws IOException
    123     {
    124         ServerSocket server;
    125         Socket socket;
    126
    127         server = _socketFactory_.createServerSocket(0, 1, getLocalAddress());
    128
    129         _output_.write(Integer.toString(server.getLocalPort()).getBytes());
    130         _output_.write('\0');
    131         _output_.flush();
    132
    133         socket = server.accept();
    134         server.close();
    135
    136         if (__remoteVerificationEnabled && !verifyRemote(socket))
    137         {
    138             socket.close();
    139             throw new IOException(
    140                 "Security violation: unexpected connection attempt by " +
    141                 socket.getInetAddress().getHostAddress());
    142         }
    143
    144         return (new SocketInputStream(socket, socket.getInputStream()));
    145     }
    146
    147
    148     /****
    149      * The default RExecClient constructor.  Initializes the
    150      * default port to <code> DEFAULT_PORT </code>.
    151      ***/
    152     public RExecClient()
    153     {
    154         _errorStream_ = null;
    155         setDefaultPort(DEFAULT_PORT);
    156     }
    157
    158
    159     /****
    160      * Returns the InputStream from which the standard outputof the remote
    161      * process can be read.  The input stream will only be set after a
    162      * successful rexec() invocation.
    163      * <p>
    164      * @return The InputStream from which the standard output of the remote
    165      * process can be read.
    166      ***/
    167     public InputStream getInputStream()
    168     {
    169         return _input_;
    170     }
    171
    172
    173     /****
    174      * Returns the OutputStream through which the standard input of the remote
    175      * process can be written.  The output stream will only be set after a
    176      * successful rexec() invocation.
    177      * <p>
    178      * @return The OutputStream through which the standard input of the remote
    179      * process can be written.
    180      ***/
    181     public OutputStream getOutputStream()
    182     {
    183         return _output_;
    184     }
    185
    186
    187     /****
    188      * Returns the InputStream from which the standard error of the remote
    189      * process can be read if a separate error stream is requested from
    190      * the server.  Otherwise, null will be returned.  The error stream
    191      * will only be set after a successful rexec() invocation.
    192      * <p>
    193      * @return The InputStream from which the standard error of the remote
    194      * process can be read if a separate error stream is requested from
    195      * the server.  Otherwise, null will be returned.
    196      ***/
    197     public InputStream getErrorStream()
    198     {
    199         return _errorStream_;
    200     }
    201
    202
    203     /****
    204      * Remotely executes a command through the rexecd daemon on the server
    205      * to which the RExecClient is connected.  After calling this method,
    206      * you may interact with the remote process through its standard input,
    207      * output, and error streams.  You will typically be able to detect
    208      * the termination of the remote process after reaching end of file
    209      * on its standard output (accessible through
    210      * <a href="#getInputStream"> getInputStream() </a>.    Disconnecting
    211      * from the server or closing the process streams before reaching
    212      * end of file will not necessarily terminate the remote process.
    213      * <p>
    214      * If a separate error stream is requested, the remote server will
    215      * connect to a local socket opened by RExecClient, providing an
    216      * independent stream through which standard error will be transmitted.
    217      * RExecClient will do a simple security check when it accepts a
    218      * connection for this error stream.  If the connection does not originate
    219      * from the remote server, an IOException will be thrown.  This serves as
    220      * a simple protection against possible hijacking of the error stream by
    221      * an attacker monitoring the rexec() negotiation.  You may disable this
    222      * behavior with <a href="#setRemoteVerificationEnabled">
    223      * setRemoteVerificationEnabled()</a>.
    224      * <p>
    225      * @param username  The account name on the server through which to execute
    226      *                  the command.
    227      * @param password  The plain text password of the user account.
    228      * @param command   The command, including any arguments, to execute.
    229      * @param separateErrorStream True if you would like the standard error
    230      *        to be transmitted through a different stream than standard output.
    231      *        False if not.
    232      * @exception IOException If the rexec() attempt fails.  The exception
    233      *            will contain a message indicating the nature of the failure.
    234      ***/
    235     public void rexec(String username, String password,
    236                       String command, boolean separateErrorStream)
    237     throws IOException
    238     {
    239         int ch;
    240
    241         if (separateErrorStream)
    242         {
    243             _errorStream_ = _createErrorStream();
    244         }
    245         else
    246         {
    247             _output_.write('\0');
    248         }
    249
    250         _output_.write(username.getBytes());
    251         _output_.write('\0');
    252         _output_.write(password.getBytes());
    253         _output_.write('\0');
    254         _output_.write(command.getBytes());
    255         _output_.write('\0');
    256         _output_.flush();
    257
    258         ch = _input_.read();
    259         if (ch > 0)
    260         {
    261             StringBuffer buffer = new StringBuffer();
    262
    263             while ((ch = _input_.read()) != -1 && ch != '\n')
    264                 buffer.append((char)ch);
    265
    266             throw new IOException(buffer.toString());
    267         }
    268         else if (ch < 0)
    269         {
    270             throw new IOException("Server closed connection.");
    271         }
    272     }
    273
    274
    275     /****
    276      * Same as <code> rexec(username, password, command, false); </code>
    277      ***/
    278     public void rexec(String username, String password,
    279                       String command)
    280     throws IOException
    281     {
    282         rexec(username, password, command, false);
    283     }
    284
    285     /****
    286      * Disconnects from the server, closing all associated open sockets and
    287      * streams.
    288      * <p>
    289      * @exception IOException If there an error occurs while disconnecting.
    290      ***/
    291     public void disconnect() throws IOException
    292     {
    293         if (_errorStream_ != null)
    294             _errorStream_.close();
    295         _errorStream_ = null;
    296         super.disconnect();
    297     }
    298
    299
    300     /****
    301      * Enable or disable verification that the remote host connecting to
    302      * create a separate error stream is the same as the host to which
    303      * the standard out stream is connected.  The default is for verification
    304      * to be enabled.  You may set this value at any time, whether the
    305      * client is currently connected or not.
    306      * <p>
    307      * @param enable True to enable verification, false to disable verification.
    308      ***/
    309     public final void setRemoteVerificationEnabled(boolean enable)
    310     {
    311         __remoteVerificationEnabled = enable;
    312     }
    313
    314     /****
    315      * Return whether or not verification of the remote host providing a
    316      * separate error stream is enabled.  The default behavior is for
    317      * verification to be enabled.
    318      * <p>
    319      * @return True if verification is enabled, false if not.
    320      ***/
    321     public final boolean isRemoteVerificationEnabled()
    322     {
    323         return __remoteVerificationEnabled;
    324     }
    325
    326 }
    327

This page was automatically generated by Maven