    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.BindException;
    60  import java.net.InetAddress;
    61  import java.net.ServerSocket;
    62  import java.net.Socket;
    63  import java.net.SocketException;
    64  import org.apache.commons.net.io.SocketInputStream;
    65  import org.apache.commons.net.SocketClient;
    66
    67  /****
    68   * RCommandClient is very similar to
    69   * <a href="org.apache.commons.net.bsd.RExecClient.html"> RExecClient </a>,
    70   * from which it is derived, and implements the rcmd() facility that
    71   * first appeared in 4.2BSD Unix.  rcmd() is the facility used by the rsh
    72   * (rshell) and other commands to execute a command on another machine
    73   * from a trusted host without issuing a password.  The trust relationship
    74   * between two machines is established by the contents of a machine's
    75   * /etc/hosts.equiv file and a user's .rhosts file.  These files specify
    76   * from which hosts and accounts on those hosts rcmd() requests will be
    77   * accepted.  The only additional measure for establishing trust is that
    78   * all client connections must originate from a port between 512 and 1023.
    79   * Consequently, there is an upper limit to the number of rcmd connections
    80   * that can be running simultaneously.   The required ports are reserved
    81   * ports on Unix systems, and can only be bound by a
    82   * process running with root permissions (to accomplish this rsh, rlogin,
    83   * and related commands usualy have the suid bit set).  Therefore, on a
    84   * Unix system, you will only be able to successfully use the RCommandClient
    85   * class if the process runs as root.  However, there is no such restriction
    86   * on Windows95 and some other systems.  The security risks are obvious.
    87   * However, when carefully used, rcmd() can be very useful when used behind
    88   * a firewall.
    89   * <p>
    90   * As with virtually all of the client classes in org.apache.commons.net, this
    91   * class derives from SocketClient.  But it overrides most of its connection
    92   * methods so that the local Socket will originate from an acceptable
    93   * rshell port.  The way to use RCommandClient is to first connect
    94   * to the server, call the <a href="#rcommand"> rcommand() </a> method,
    95   * and then
    96   * fetch the connection's input, output, and optionally error streams.
    97   * Interaction with the remote command is controlled entirely through the
    98   * I/O streams.  Once you have finished processing the streams, you should
    99   * invoke <a href="org.apache.commons.net.bsd.RExecClient.html#disconnect">
    100  * disconnect() </a> to clean up properly.
    101  * <p>
    102  * By default the standard output and standard error streams of the
    103  * remote process are transmitted over the same connection, readable
    104  * from the input stream returned by
    105  * <a href="org.apache.commons.net.bsd.RExecClient.html#getInputStream">
    106  * getInputStream() </a>.  However, it is
    107  * possible to tell the rshd daemon to return the standard error
    108  * stream over a separate connection, readable from the input stream
    109  * returned by <a href="org.apache.commons.net.bsd.RExecClient.html#getErrorStream">
    110  * getErrorStream() </a>.  You
    111  * can specify that a separate connection should be created for standard
    112  * error by setting the boolean <code> separateErrorStream </code>
    113  * parameter of <a href="#rcommand"> rcommand() </a> to <code> true </code>.
    114  * The standard input of the remote process can be written to through
    115  * the output stream returned by
    116  * <a href="org.apache.commons.net.bsd.RExecClient.html#getOutputStream">
    117  * getOutputSream() </a>.
    118  * <p>
    119  * <p>
    120  * @author Daniel F. Savarese
    121  * @see SocketClient
    122  * @see RExecClient
    123  * @see RLoginClient
    124  ***/
    125
    126 public class RCommandClient extends RExecClient
    127 {
    128     /****
    129      * The default rshell port.  Set to 514 in BSD Unix.
    130      ***/
    131     public static final int DEFAULT_PORT = 514;
    132
    133     /****
    134      * The smallest port number an rcmd client may use.  By BSD convention
    135      * this number is 512.
    136      ***/
    137     public static final int MIN_CLIENT_PORT = 512;
    138
    139     /****
    140      * The largest port number an rcmd client may use.  By BSD convention
    141      * this number is 1023.
    142      ***/
    143     public static final int MAX_CLIENT_PORT = 1023;
    144
    145     // Overrides method in RExecClient in order to implement proper
    146     // port number limitations.
    147     InputStream _createErrorStream() throws IOException
    148     {
    149         int localPort;
    150         ServerSocket server;
    151         Socket socket;
    152
    153         localPort = MAX_CLIENT_PORT;
    154         server = null; // Keep compiler from barfing
    155
    156         for (localPort = MAX_CLIENT_PORT; localPort >= MIN_CLIENT_PORT; --localPort)
    157         {
    158             try
    159             {
    160                 server = _socketFactory_.createServerSocket(localPort, 1,
    161                          getLocalAddress());
    162             }
    163             catch (SocketException e)
    164             {
    165                 continue;
    166             }
    167             break;
    168         }
    169
    170         if (localPort < MIN_CLIENT_PORT)
    171             throw new BindException("All ports in use.");
    172
    173         _output_.write(Integer.toString(server.getLocalPort()).getBytes());
    174         _output_.write('\0');
    175         _output_.flush();
    176
    177         socket = server.accept();
    178         server.close();
    179
    180         if (isRemoteVerificationEnabled() && !verifyRemote(socket))
    181         {
    182             socket.close();
    183             throw new IOException(
    184                 "Security violation: unexpected connection attempt by " +
    185                 socket.getInetAddress().getHostAddress());
    186         }
    187
    188         return (new SocketInputStream(socket, socket.getInputStream()));
    189     }
    190
    191     /****
    192      * The default RCommandClient constructor.  Initializes the
    193      * default port to <code> DEFAULT_PORT </code>.
    194      ***/
    195     public RCommandClient()
    196     {
    197         setDefaultPort(DEFAULT_PORT);
    198     }
    199
    200
    201     /****
    202      * Opens a Socket connected to a remote host at the specified port and
    203      * originating from the specified local address using a port in a range
    204      * acceptable to the BSD rshell daemon.
    205      * Before returning, <a href="org.apache.commons.net.SocketClient.html#_connectAction_"> _connectAction_() </a>
    206      * is called to perform connection initialization actions.
    207      * <p>
    208      * @param host  The remote host.
    209      * @param port  The port to connect to on the remote host.
    210      * @param localAddr  The local address to use.
    211      * @exception SocketException If the socket timeout could not be set.
    212      * @exception BindException If all acceptable rshell ports are in use.
    213      * @exception IOException If the socket could not be opened.  In most
    214      *  cases you will only want to catch IOException since SocketException is
    215      *  derived from it.
    216      ***/
    217     public void connect(InetAddress host, int port, InetAddress localAddr)
    218     throws SocketException, BindException, IOException
    219     {
    220         int localPort;
    221
    222         localPort = MAX_CLIENT_PORT;
    223
    224         for (localPort = MAX_CLIENT_PORT; localPort >= MIN_CLIENT_PORT; --localPort)
    225         {
    226             try
    227             {
    228                 _socket_ =
    229                     _socketFactory_.createSocket(host, port, localAddr, localPort);
    230             }
    231             catch (SocketException e)
    232             {
    233                 continue;
    234             }
    235             break;
    236         }
    237
    238         if (localPort < MIN_CLIENT_PORT)
    239             throw new BindException("All ports in use or insufficient permssion.");
    240
    241         _connectAction_();
    242     }
    243
    244
    245
    246     /****
    247      * Opens a Socket connected to a remote host at the specified port and
    248      * originating from the current host at a port in a range acceptable
    249      * to the BSD rshell daemon.
    250      * Before returning, <a href="org.apache.commons.net.SocketClient.html#_connectAction_"> _connectAction_() </a>
    251      * is called to perform connection initialization actions.
    252      * <p>
    253      * @param host  The remote host.
    254      * @param port  The port to connect to on the remote host.
    255      * @exception SocketException If the socket timeout could not be set.
    256      * @exception BindException If all acceptable rshell ports are in use.
    257      * @exception IOException If the socket could not be opened.  In most
    258      *  cases you will only want to catch IOException since SocketException is
    259      *  derived from it.
    260      ***/
    261     public void connect(InetAddress host, int port)
    262     throws SocketException, IOException
    263     {
    264         connect(host, port, InetAddress.getLocalHost());
    265     }
    266
    267
    268     /****
    269      * Opens a Socket connected to a remote host at the specified port and
    270      * originating from the current host at a port in a range acceptable
    271      * to the BSD rshell daemon.
    272      * Before returning, <a href="org.apache.commons.net.SocketClient.html#_connectAction_"> _connectAction_() </a>
    273      * is called to perform connection initialization actions.
    274      * <p>
    275      * @param hostname  The name of the remote host.
    276      * @param port  The port to connect to on the remote host.
    277      * @exception SocketException If the socket timeout could not be set.
    278      * @exception BindException If all acceptable rshell ports are in use.
    279      * @exception IOException If the socket could not be opened.  In most
    280      *  cases you will only want to catch IOException since SocketException is
    281      *  derived from it.
    282      * @exception UnknownHostException If the hostname cannot be resolved.
    283      ***/
    284     public void connect(String hostname, int port)
    285     throws SocketException, IOException
    286     {
    287         connect(InetAddress.getByName(hostname), port, InetAddress.getLocalHost());
    288     }
    289
    290
    291     /****
    292      * Opens a Socket connected to a remote host at the specified port and
    293      * originating from the specified local address using a port in a range
    294      * acceptable to the BSD rshell daemon.
    295      * Before returning, <a href="org.apache.commons.net.SocketClient.html#_connectAction_"> _connectAction_() </a>
    296      * is called to perform connection initialization actions.
    297      * <p>
    298      * @param host  The remote host.
    299      * @param port  The port to connect to on the remote host.
    300      * @param localAddr  The local address to use.
    301      * @exception SocketException If the socket timeout could not be set.
    302      * @exception BindException If all acceptable rshell ports are in use.
    303      * @exception IOException If the socket could not be opened.  In most
    304      *  cases you will only want to catch IOException since SocketException is
    305      *  derived from it.
    306      ***/
    307     public void connect(String hostname, int port, InetAddress localAddr)
    308     throws SocketException, IOException
    309     {
    310         connect(InetAddress.getByName(hostname), port, localAddr);
    311     }
    312
    313
    314     /****
    315      * Opens a Socket connected to a remote host at the specified port and
    316      * originating from the specified local address and port. The
    317      * local port must lie between <code> MIN_CLIENT_PORT </code> and
    318      * <code> MAX_CLIENT_PORT </code> or an IllegalArgumentException will
    319      * be thrown.
    320      * Before returning, <a href="org.apache.commons.net.SocketClient.html#_connectAction_"> _connectAction_() </a>
    321      * is called to perform connection initialization actions.
    322      * <p>
    323      * @param host  The remote host.
    324      * @param port  The port to connect to on the remote host.
    325      * @param localAddr  The local address to use.
    326      * @param localPort  The local port to use.
    327      * @exception SocketException If the socket timeout could not be set.
    328      * @exception IOException If the socket could not be opened.  In most
    329      *  cases you will only want to catch IOException since SocketException is
    330      *  derived from it.
    331      * @exception IllegalArgumentException If an invalid local port number
    332      *            is specified.
    333      ***/
    334     public void connect(InetAddress host, int port,
    335                         InetAddress localAddr, int localPort)
    336     throws SocketException, IOException, IllegalArgumentException
    337     {
    338         if (localPort < MIN_CLIENT_PORT || localPort > MAX_CLIENT_PORT)
    339             throw new IllegalArgumentException("Invalid port number " + localPort);
    340         super.connect(host, port, localAddr, localPort);
    341     }
    342
    343
    344     /****
    345      * Opens a Socket connected to a remote host at the specified port and
    346      * originating from the specified local address and port. The
    347      * local port must lie between <code> MIN_CLIENT_PORT </code> and
    348      * <code> MAX_CLIENT_PORT </code> or an IllegalArgumentException will
    349      * be thrown.
    350      * Before returning, <a href="org.apache.commons.net.SocketClient.html#_connectAction_"> _connectAction_() </a>
    351      * is called to perform connection initialization actions.
    352      * <p>
    353      * @param hostname  The name of the remote host.
    354      * @param port  The port to connect to on the remote host.
    355      * @param localAddr  The local address to use.
    356      * @param localPort  The local port to use.
    357      * @exception SocketException If the socket timeout could not be set.
    358      * @exception IOException If the socket could not be opened.  In most
    359      *  cases you will only want to catch IOException since SocketException is
    360      *  derived from it.
    361      * @exception UnknownHostException If the hostname cannot be resolved.
    362      * @exception IllegalArgumentException If an invalid local port number
    363      *            is specified.
    364      ***/
    365     public void connect(String hostname, int port,
    366                         InetAddress localAddr, int localPort)
    367     throws SocketException, IOException, IllegalArgumentException
    368     {
    369         if (localPort < MIN_CLIENT_PORT || localPort > MAX_CLIENT_PORT)
    370             throw new IllegalArgumentException("Invalid port number " + localPort);
    371         super.connect(hostname, port, localAddr, localPort);
    372     }
    373
    374
    375     /****
    376      * Remotely executes a command through the rshd daemon on the server
    377      * to which the RCommandClient is connected.  After calling this method,
    378      * you may interact with the remote process through its standard input,
    379      * output, and error streams.  You will typically be able to detect
    380      * the termination of the remote process after reaching end of file
    381      * on its standard output (accessible through
    382      * <a href="#getInputStream"> getInputStream() </a>.  Disconnecting
    383      * from the server or closing the process streams before reaching
    384      * end of file will not necessarily terminate the remote process.
    385      * <p>
    386      * If a separate error stream is requested, the remote server will
    387      * connect to a local socket opened by RCommandClient, providing an
    388      * independent stream through which standard error will be transmitted.
    389      * The local socket must originate from a secure port (512 - 1023),
    390      * and rcommand() ensures that this will be so.
    391      * RCommandClient will also do a simple security check when it accepts a
    392      * connection for this error stream.  If the connection does not originate
    393      * from the remote server, an IOException will be thrown.  This serves as
    394      * a simple protection against possible hijacking of the error stream by
    395      * an attacker monitoring the rexec() negotiation.  You may disable this
    396      * behavior with
    397      * <a href="org.apache.commons.net.bsd.RExecClient.html#setRemoteVerificationEnabled">
    398      * setRemoteVerificationEnabled()</a>.
    399      * <p>
    400      * @param localUsername  The user account on the local machine that is
    401      *        requesting the command execution.
    402      * @param remoteUsername  The account name on the server through which to
    403      *        execute the command.
    404      * @param command   The command, including any arguments, to execute.
    405      * @param separateErrorStream True if you would like the standard error
    406      *        to be transmitted through a different stream than standard output.
    407      *        False if not.
    408      * @exception IOException If the rcommand() attempt fails.  The exception
    409      *            will contain a message indicating the nature of the failure.
    410      ***/
    411     public void rcommand(String localUsername, String remoteUsername,
    412                          String command, boolean separateErrorStream)
    413     throws IOException
    414     {
    415         rexec(localUsername, remoteUsername, command, separateErrorStream);
    416     }
    417
    418
    419     /****
    420      * Same as
    421      * <code> rcommand(localUsername, remoteUsername, command, false); </code>
    422      ***/
    423     public void rcommand(String localUsername, String remoteUsername,
    424                          String command)
    425     throws IOException
    426     {
    427         rcommand(localUsername, remoteUsername, command, false);
    428     }
    429
    430 }
    431

This page was automatically generated by Maven