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