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