| %line | %branch | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| org.apache.commons.net.bsd.RExecClient |
|
|
| 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.ServerSocket; |
|
| 21 | import java.net.Socket; |
|
| 22 | import org.apache.commons.net.io.SocketInputStream; |
|
| 23 | import org.apache.commons.net.SocketClient; |
|
| 24 | import java.io.OutputStream; |
|
| 25 | ||
| 26 | /*** |
|
| 27 | * RExecClient implements the rexec() facility that first appeared in |
|
| 28 | * 4.2BSD Unix. This class will probably only be of use for connecting |
|
| 29 | * to Unix systems and only when the rexecd daemon is configured to run, |
|
| 30 | * which is a rarity these days because of the security risks involved. |
|
| 31 | * However, rexec() can be very useful for performing administrative tasks |
|
| 32 | * on a network behind a firewall. |
|
| 33 | * <p> |
|
| 34 | * As with virtually all of the client classes in org.apache.commons.net, this |
|
| 35 | * class derives from SocketClient, inheriting its connection methods. |
|
| 36 | * The way to use RExecClient is to first connect |
|
| 37 | * to the server, call the {@link #rexec rexec() } method, and then |
|
| 38 | * fetch the connection's input, output, and optionally error streams. |
|
| 39 | * Interaction with the remote command is controlled entirely through the |
|
| 40 | * I/O streams. Once you have finished processing the streams, you should |
|
| 41 | * invoke {@link #disconnect disconnect() } to clean up properly. |
|
| 42 | * <p> |
|
| 43 | * By default the standard output and standard error streams of the |
|
| 44 | * remote process are transmitted over the same connection, readable |
|
| 45 | * from the input stream returned by |
|
| 46 | * {@link #getInputStream getInputStream() }. However, it is |
|
| 47 | * possible to tell the rexecd daemon to return the standard error |
|
| 48 | * stream over a separate connection, readable from the input stream |
|
| 49 | * returned by {@link #getErrorStream getErrorStream() }. You |
|
| 50 | * can specify that a separate connection should be created for standard |
|
| 51 | * error by setting the boolean <code> separateErrorStream </code> |
|
| 52 | * parameter of {@link #rexec rexec() } to <code> true </code>. |
|
| 53 | * The standard input of the remote process can be written to through |
|
| 54 | * the output stream returned by |
|
| 55 | * {@link #getOutputStream getOutputSream() }. |
|
| 56 | * <p> |
|
| 57 | * <p> |
|
| 58 | * @author Daniel F. Savarese |
|
| 59 | * @see SocketClient |
|
| 60 | * @see RCommandClient |
|
| 61 | * @see RLoginClient |
|
| 62 | ***/ |
|
| 63 | ||
| 64 | public class RExecClient extends SocketClient |
|
| 65 | { |
|
| 66 | /*** |
|
| 67 | * The default rexec port. Set to 512 in BSD Unix. |
|
| 68 | ***/ |
|
| 69 | public static final int DEFAULT_PORT = 512; |
|
| 70 | ||
| 71 | private boolean __remoteVerificationEnabled; |
|
| 72 | ||
| 73 | /*** |
|
| 74 | * If a separate error stream is requested, <code>_errorStream_</code> |
|
| 75 | * will point to an InputStream from which the standard error of the |
|
| 76 | * remote process can be read (after a call to rexec()). Otherwise, |
|
| 77 | * <code> _errorStream_ </code> will be null. |
|
| 78 | ***/ |
|
| 79 | protected InputStream _errorStream_; |
|
| 80 | ||
| 81 | // This can be overridden in local package to implement port range |
|
| 82 | // limitations of rcmd and rlogin |
|
| 83 | InputStream _createErrorStream() throws IOException |
|
| 84 | { |
|
| 85 | ServerSocket server; |
|
| 86 | Socket socket; |
|
| 87 | ||
| 88 | 0 | server = _socketFactory_.createServerSocket(0, 1, getLocalAddress()); |
| 89 | ||
| 90 | 0 | _output_.write(Integer.toString(server.getLocalPort()).getBytes()); |
| 91 | 0 | _output_.write('\0'); |
| 92 | 0 | _output_.flush(); |
| 93 | ||
| 94 | 0 | socket = server.accept(); |
| 95 | 0 | server.close(); |
| 96 | ||
| 97 | 0 | if (__remoteVerclass="keyword">ificationEnabled && !verclass="keyword">ifyRemote(socket)) |
| 98 | { |
|
| 99 | 0 | socket.close(); |
| 100 | 0 | throw new IOException( |
| 101 | "Security violation: unexpected connection attempt by " + |
|
| 102 | socket.getInetAddress().getHostAddress()); |
|
| 103 | } |
|
| 104 | ||
| 105 | 0 | return (new SocketInputStream(socket, socket.getInputStream())); |
| 106 | } |
|
| 107 | ||
| 108 | ||
| 109 | /*** |
|
| 110 | * The default RExecClient constructor. Initializes the |
|
| 111 | * default port to <code> DEFAULT_PORT </code>. |
|
| 112 | ***/ |
|
| 113 | public RExecClient() |
|
| 114 | 0 | { |
| 115 | 0 | _errorStream_ = null; |
| 116 | 0 | setDefaultPort(DEFAULT_PORT); |
| 117 | 0 | } |
| 118 | ||
| 119 | ||
| 120 | /*** |
|
| 121 | * Returns the InputStream from which the standard outputof the remote |
|
| 122 | * process can be read. The input stream will only be set after a |
|
| 123 | * successful rexec() invocation. |
|
| 124 | * <p> |
|
| 125 | * @return The InputStream from which the standard output of the remote |
|
| 126 | * process can be read. |
|
| 127 | ***/ |
|
| 128 | public InputStream getInputStream() |
|
| 129 | { |
|
| 130 | 0 | return _input_; |
| 131 | } |
|
| 132 | ||
| 133 | ||
| 134 | /*** |
|
| 135 | * Returns the OutputStream through which the standard input of the remote |
|
| 136 | * process can be written. The output stream will only be set after a |
|
| 137 | * successful rexec() invocation. |
|
| 138 | * <p> |
|
| 139 | * @return The OutputStream through which the standard input of the remote |
|
| 140 | * process can be written. |
|
| 141 | ***/ |
|
| 142 | public OutputStream getOutputStream() |
|
| 143 | { |
|
| 144 | 0 | return _output_; |
| 145 | } |
|
| 146 | ||
| 147 | ||
| 148 | /*** |
|
| 149 | * Returns the InputStream from which the standard error of the remote |
|
| 150 | * process can be read if a separate error stream is requested from |
|
| 151 | * the server. Otherwise, null will be returned. The error stream |
|
| 152 | * will only be set after a successful rexec() invocation. |
|
| 153 | * <p> |
|
| 154 | * @return The InputStream from which the standard error of the remote |
|
| 155 | * process can be read if a separate error stream is requested from |
|
| 156 | * the server. Otherwise, null will be returned. |
|
| 157 | ***/ |
|
| 158 | public InputStream getErrorStream() |
|
| 159 | { |
|
| 160 | 0 | return _errorStream_; |
| 161 | } |
|
| 162 | ||
| 163 | ||
| 164 | /*** |
|
| 165 | * Remotely executes a command through the rexecd daemon on the server |
|
| 166 | * to which the RExecClient is connected. After calling this method, |
|
| 167 | * you may interact with the remote process through its standard input, |
|
| 168 | * output, and error streams. You will typically be able to detect |
|
| 169 | * the termination of the remote process after reaching end of file |
|
| 170 | * on its standard output (accessible through |
|
| 171 | * {@link #getInputStream getInputStream() }. Disconnecting |
|
| 172 | * from the server or closing the process streams before reaching |
|
| 173 | * end of file will not necessarily terminate the remote process. |
|
| 174 | * <p> |
|
| 175 | * If a separate error stream is requested, the remote server will |
|
| 176 | * connect to a local socket opened by RExecClient, providing an |
|
| 177 | * independent stream through which standard error will be transmitted. |
|
| 178 | * RExecClient will do a simple security check when it accepts a |
|
| 179 | * connection for this error stream. If the connection does not originate |
|
| 180 | * from the remote server, an IOException will be thrown. This serves as |
|
| 181 | * a simple protection against possible hijacking of the error stream by |
|
| 182 | * an attacker monitoring the rexec() negotiation. You may disable this |
|
| 183 | * behavior with {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()} |
|
| 184 | * . |
|
| 185 | * <p> |
|
| 186 | * @param username The account name on the server through which to execute |
|
| 187 | * the command. |
|
| 188 | * @param password The plain text password of the user account. |
|
| 189 | * @param command The command, including any arguments, to execute. |
|
| 190 | * @param separateErrorStream True if you would like the standard error |
|
| 191 | * to be transmitted through a different stream than standard output. |
|
| 192 | * False if not. |
|
| 193 | * @exception IOException If the rexec() attempt fails. The exception |
|
| 194 | * will contain a message indicating the nature of the failure. |
|
| 195 | ***/ |
|
| 196 | public void rexec(String username, String password, |
|
| 197 | String command, boolean separateErrorStream) |
|
| 198 | throws IOException |
|
| 199 | { |
|
| 200 | int ch; |
|
| 201 | ||
| 202 | 0 | if (separateErrorStream) |
| 203 | { |
|
| 204 | 0 | _errorStream_ = _createErrorStream(); |
| 205 | } |
|
| 206 | else |
|
| 207 | { |
|
| 208 | 0 | _output_.write('\0'); |
| 209 | } |
|
| 210 | ||
| 211 | 0 | _output_.write(username.getBytes()); |
| 212 | 0 | _output_.write('\0'); |
| 213 | 0 | _output_.write(password.getBytes()); |
| 214 | 0 | _output_.write('\0'); |
| 215 | 0 | _output_.write(command.getBytes()); |
| 216 | 0 | _output_.write('\0'); |
| 217 | 0 | _output_.flush(); |
| 218 | ||
| 219 | 0 | ch = _input_.read(); |
| 220 | 0 | if (ch > 0) |
| 221 | { |
|
| 222 | 0 | StringBuffer buffer = new StringBuffer(); |
| 223 | ||
| 224 | 0 | while ((ch = _input_.read()) != -1 && ch != '\n') |
| 225 | 0 | buffer.append((char)ch); |
| 226 | ||
| 227 | 0 | throw new IOException(buffer.toString()); |
| 228 | } |
|
| 229 | 0 | else if (ch < 0) |
| 230 | { |
|
| 231 | 0 | throw new IOException("Server closed connection."); |
| 232 | } |
|
| 233 | 0 | } |
| 234 | ||
| 235 | ||
| 236 | /*** |
|
| 237 | * Same as <code> rexec(username, password, command, false); </code> |
|
| 238 | ***/ |
|
| 239 | public void rexec(String username, String password, |
|
| 240 | String command) |
|
| 241 | throws IOException |
|
| 242 | { |
|
| 243 | 0 | rexec(username, password, command, false); |
| 244 | 0 | } |
| 245 | ||
| 246 | /*** |
|
| 247 | * Disconnects from the server, closing all associated open sockets and |
|
| 248 | * streams. |
|
| 249 | * <p> |
|
| 250 | * @exception IOException If there an error occurs while disconnecting. |
|
| 251 | ***/ |
|
| 252 | public void disconnect() throws IOException |
|
| 253 | { |
|
| 254 | 0 | if (_errorStream_ != null) |
| 255 | 0 | _errorStream_.close(); |
| 256 | 0 | _errorStream_ = null; |
| 257 | 0 | super.disconnect(); |
| 258 | 0 | } |
| 259 | ||
| 260 | ||
| 261 | /*** |
|
| 262 | * Enable or disable verification that the remote host connecting to |
|
| 263 | * create a separate error stream is the same as the host to which |
|
| 264 | * the standard out stream is connected. The default is for verification |
|
| 265 | * to be enabled. You may set this value at any time, whether the |
|
| 266 | * client is currently connected or not. |
|
| 267 | * <p> |
|
| 268 | * @param enable True to enable verification, false to disable verification. |
|
| 269 | ***/ |
|
| 270 | public final void setRemoteVerificationEnabled(boolean enable) |
|
| 271 | { |
|
| 272 | 0 | __remoteVerificationEnabled = enable; |
| 273 | 0 | } |
| 274 | ||
| 275 | /*** |
|
| 276 | * Return whether or not verification of the remote host providing a |
|
| 277 | * separate error stream is enabled. The default behavior is for |
|
| 278 | * verification to be enabled. |
|
| 279 | * <p> |
|
| 280 | * @return True if verification is enabled, false if not. |
|
| 281 | ***/ |
|
| 282 | public final boolean isRemoteVerificationEnabled() |
|
| 283 | { |
|
| 284 | 0 | return __remoteVerificationEnabled; |
| 285 | } |
|
| 286 | ||
| 287 | } |
|
| 288 |
| This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |