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