%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. |