Coverage report

  %line %branch
org.apache.commons.net.bsd.RCommandClient
0% 
0% 

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

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.