Coverage report

| %line | %branch
--- | --- | ---
org.apache.commons.net.bsd.RCommandClient |
0% |
0% |

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.BindException;
21 |  |
     import java.net.InetAddress;
22 |  |
     import java.net.ServerSocket;
23 |  |
     import java.net.Socket;
24 |  |
     import java.net.SocketException;
25 |  |
26 |  |
     import org.apache.commons.net.io.SocketInputStream;
27 |  |
28 |  |
     /***
29 |  |
      * RCommandClient is very similar to
30 |  |
      * {@link org.apache.commons.net.bsd.RExecClient},
31 |  |
      * from which it is derived, and implements the rcmd() facility that
32 |  |
      * first appeared in 4.2BSD Unix.  rcmd() is the facility used by the rsh
33 |  |
      * (rshell) and other commands to execute a command on another machine
34 |  |
      * from a trusted host without issuing a password.  The trust relationship
35 |  |
      * between two machines is established by the contents of a machine's
36 |  |
      * /etc/hosts.equiv file and a user's .rhosts file.  These files specify
37 |  |
      * from which hosts and accounts on those hosts rcmd() requests will be
38 |  |
      * accepted.  The only additional measure for establishing trust is that
39 |  |
      * all client connections must originate from a port between 512 and 1023.
40 |  |
      * Consequently, there is an upper limit to the number of rcmd connections
41 |  |
      * that can be running simultaneously.   The required ports are reserved
42 |  |
      * ports on Unix systems, and can only be bound by a
43 |  |
      * process running with root permissions (to accomplish this rsh, rlogin,
44 |  |
      * and related commands usualy have the suid bit set).  Therefore, on a
45 |  |
      * Unix system, you will only be able to successfully use the RCommandClient
46 |  |
      * class if the process runs as root.  However, there is no such restriction
47 |  |
      * on Windows95 and some other systems.  The security risks are obvious.
48 |  |
      * However, when carefully used, rcmd() can be very useful when used behind
49 |  |
      * a firewall.
50 |  |
      * <p>
51 |  |
      * As with virtually all of the client classes in org.apache.commons.net, this
52 |  |
      * class derives from SocketClient.  But it overrides most of its connection
53 |  |
      * methods so that the local Socket will originate from an acceptable
54 |  |
      * rshell port.  The way to use RCommandClient is to first connect
55 |  |
      * to the server, call the {@link #rcommand  rcommand() } method,
56 |  |
      * and then
57 |  |
      * fetch the connection's input, output, and optionally error streams.
58 |  |
      * Interaction with the remote command is controlled entirely through the
59 |  |
      * I/O streams.  Once you have finished processing the streams, you should
60 |  |
      * invoke {@link org.apache.commons.net.bsd.RExecClient#disconnect disconnect() }
61 |  |
      *  to clean up properly.
62 |  |
      * <p>
63 |  |
      * By default the standard output and standard error streams of the
64 |  |
      * remote process are transmitted over the same connection, readable
65 |  |
      * from the input stream returned by
66 |  |
      * {@link org.apache.commons.net.bsd.RExecClient#getInputStream getInputStream() }
67 |  |
      * .  However, it is
68 |  |
      * possible to tell the rshd daemon to return the standard error
69 |  |
      * stream over a separate connection, readable from the input stream
70 |  |
      * returned by {@link org.apache.commons.net.bsd.RExecClient#getErrorStream getErrorStream() }
71 |  |
      * .  You
72 |  |
      * can specify that a separate connection should be created for standard
73 |  |
      * error by setting the boolean <code> separateErrorStream </code>
74 |  |
      * parameter of {@link #rcommand  rcommand() } to <code> true </code>.
75 |  |
      * The standard input of the remote process can be written to through
76 |  |
      * the output stream returned by
77 |  |
      * {@link org.apache.commons.net.bsd.RExecClient#getOutputStream getOutputStream() }
78 |  |
      * .
79 |  |
      * <p>
80 |  |
      * <p>
81 |  |
      * @author Daniel F. Savarese
82 |  |
      * @see org.apache.commons.net.SocketClient
83 |  |
      * @see RExecClient
84 |  |
      * @see RLoginClient
85 |  |
      ***/
86 |  |
87 |  |
     public class RCommandClient extends RExecClient
88 |  |
     {
89 |  |
         /***
90 |  |
          * The default rshell port.  Set to 514 in BSD Unix.
91 |  |
          ***/
92 |  |
         public static final int DEFAULT_PORT = 514;
93 |  |
94 |  |
         /***
95 |  |
          * The smallest port number an rcmd client may use.  By BSD convention
96 |  |
          * this number is 512.
97 |  |
          ***/
98 |  |
         public static final int MIN_CLIENT_PORT = 512;
99 |  |
100 |  |
         /***
101 |  |
          * The largest port number an rcmd client may use.  By BSD convention
102 |  |
          * this number is 1023.
103 |  |
          ***/
104 |  |
         public static final int MAX_CLIENT_PORT = 1023;
105 |  |
106 |  |
         // Overrides method in RExecClient in order to implement proper
107 |  |
         // port number limitations.
108 |  |
         InputStream _createErrorStream() throws IOException
109 |  |
         {
110 |  |
             int localPort;
111 |  |
             ServerSocket server;
112 |  |
             Socket socket;
113 |  |
114 | 0 |
             localPort = MAX_CLIENT_PORT;
115 | 0 |
             server = null; // Keep compiler from barfing
116 |  |
117 | 0 |
             for (localPort = MAX_CLIENT_PORT; localPort >= MIN_CLIENT_PORT; --localPort)
118 |  |
             {
119 |  |
                 try
120 |  |
                 {
121 | 0 |
                     server = _socketFactory_.createServerSocket(localPort, 1,
122 |  |
                              getLocalAddress());
123 |  |
                 }
124 | 0 |
                 catch (SocketException e)
125 |  |
                 {
126 | 0 |
                     continue;
127 | 0 |
                 }
128 |  |
                 break;
129 |  |
             }
130 |  |
131 | 0 |
             if (localPort < MIN_CLIENT_PORT)
132 | 0 |
                 throw new BindException("All ports in use.");
133 |  |
134 | 0 |
             _output_.write(Integer.toString(server.getLocalPort()).getBytes());
135 | 0 |
             _output_.write('\0');
136 | 0 |
             _output_.flush();
137 |  |
138 | 0 |
             socket = server.accept();
139 | 0 |
             server.close();
140 |  |
141 | 0 |
             if (isRemoteVerclass="keyword">ificationEnabled() && !verclass="keyword">ifyRemote(socket))
142 |  |
             {
143 | 0 |
                 socket.close();
144 | 0 |
                 throw new IOException(
145 |  |
                     "Security violation: unexpected connection attempt by " +
146 |  |
                     socket.getInetAddress().getHostAddress());
147 |  |
             }
148 |  |
149 | 0 |
             return (new SocketInputStream(socket, socket.getInputStream()));
150 |  |
         }
151 |  |
152 |  |
         /***
153 |  |
          * The default RCommandClient constructor.  Initializes the
154 |  |
          * default port to <code> DEFAULT_PORT </code>.
155 |  |
          ***/
156 |  |
         public RCommandClient()
157 | 0 |
         {
158 | 0 |
             setDefaultPort(DEFAULT_PORT);
159 | 0 |
         }
160 |  |
161 |  |
162 |  |
         /***
163 |  |
          * Opens a Socket connected to a remote host at the specified port and
164 |  |
          * originating from the specified local address using a port in a range
165 |  |
          * acceptable to the BSD rshell daemon.
166 |  |
          * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_  _connectAction_() }
167 |  |
          * is called to perform connection initialization actions.
168 |  |
          * <p>
169 |  |
          * @param host  The remote host.
170 |  |
          * @param port  The port to connect to on the remote host.
171 |  |
          * @param localAddr  The local address to use.
172 |  |
          * @exception SocketException If the socket timeout could not be set.
173 |  |
          * @exception BindException If all acceptable rshell ports are in use.
174 |  |
          * @exception IOException If the socket could not be opened.  In most
175 |  |
          *  cases you will only want to catch IOException since SocketException is
176 |  |
          *  derived from it.
177 |  |
          ***/
178 |  |
         public void connect(InetAddress host, int port, InetAddress localAddr)
179 |  |
         throws SocketException, BindException, IOException
180 |  |
         {
181 |  |
             int localPort;
182 |  |
183 | 0 |
             localPort = MAX_CLIENT_PORT;
184 |  |
185 | 0 |
             for (localPort = MAX_CLIENT_PORT; localPort >= MIN_CLIENT_PORT; --localPort)
186 |  |
             {
187 |  |
                 try
188 |  |
                 {
189 | 0 |
                     _socket_ =
190 |  |
                         _socketFactory_.createSocket(host, port, localAddr, localPort);
191 |  |
                 }
192 | 0 |
                 catch (SocketException e)
193 |  |
                 {
194 | 0 |
                     continue;
195 | 0 |
                 }
196 |  |
                 break;
197 |  |
             }
198 |  |
199 | 0 |
             if (localPort < MIN_CLIENT_PORT)
200 | 0 |
                 throw new BindException("All ports in use or insufficient permssion.");
201 |  |
202 | 0 |
             _connectAction_();
203 | 0 |
         }
204 |  |
205 |  |
206 |  |
207 |  |
         /***
208 |  |
          * Opens a Socket connected to a remote host at the specified port and
209 |  |
          * originating from the current host at a port in a range acceptable
210 |  |
          * to the BSD rshell daemon.
211 |  |
          * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_  _connectAction_() }
212 |  |
          * is called to perform connection initialization actions.
213 |  |
          * <p>
214 |  |
          * @param host  The remote host.
215 |  |
          * @param port  The port to connect to on the remote host.
216 |  |
          * @exception SocketException If the socket timeout could not be set.
217 |  |
          * @exception BindException If all acceptable rshell ports are in use.
218 |  |
          * @exception IOException If the socket could not be opened.  In most
219 |  |
          *  cases you will only want to catch IOException since SocketException is
220 |  |
          *  derived from it.
221 |  |
          ***/
222 |  |
         public void connect(InetAddress host, int port)
223 |  |
         throws SocketException, IOException
224 |  |
         {
225 | 0 |
             connect(host, port, InetAddress.getLocalHost());
226 | 0 |
         }
227 |  |
228 |  |
229 |  |
         /***
230 |  |
          * Opens a Socket connected to a remote host at the specified port and
231 |  |
          * originating from the current host at a port in a range acceptable
232 |  |
          * to the BSD rshell daemon.
233 |  |
          * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_  _connectAction_() }
234 |  |
          * is called to perform connection initialization actions.
235 |  |
          * <p>
236 |  |
          * @param hostname  The name of the remote host.
237 |  |
          * @param port  The port to connect to on the remote host.
238 |  |
          * @exception SocketException If the socket timeout could not be set.
239 |  |
          * @exception BindException If all acceptable rshell ports are in use.
240 |  |
          * @exception IOException If the socket could not be opened.  In most
241 |  |
          *  cases you will only want to catch IOException since SocketException is
242 |  |
          *  derived from it.
243 |  |
          * @exception UnknownHostException If the hostname cannot be resolved.
244 |  |
          ***/
245 |  |
         public void connect(String hostname, int port)
246 |  |
         throws SocketException, IOException
247 |  |
         {
248 | 0 |
             connect(InetAddress.getByName(hostname), port, InetAddress.getLocalHost());
249 | 0 |
         }
250 |  |
251 |  |
252 |  |
         /***
253 |  |
          * Opens a Socket connected to a remote host at the specified port and
254 |  |
          * originating from the specified local address using a port in a range
255 |  |
          * acceptable to the BSD rshell daemon.
256 |  |
          * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_  _connectAction_() }
257 |  |
          * is called to perform connection initialization actions.
258 |  |
          * <p>
259 |  |
          * @param hostname  The remote host.
260 |  |
          * @param port  The port to connect to on the remote host.
261 |  |
          * @param localAddr  The local address to use.
262 |  |
          * @exception SocketException If the socket timeout could not be set.
263 |  |
          * @exception BindException If all acceptable rshell ports are in use.
264 |  |
          * @exception IOException If the socket could not be opened.  In most
265 |  |
          *  cases you will only want to catch IOException since SocketException is
266 |  |
          *  derived from it.
267 |  |
          ***/
268 |  |
         public void connect(String hostname, int port, InetAddress localAddr)
269 |  |
         throws SocketException, IOException
270 |  |
         {
271 | 0 |
             connect(InetAddress.getByName(hostname), port, localAddr);
272 | 0 |
         }
273 |  |
274 |  |
275 |  |
         /***
276 |  |
          * Opens a Socket connected to a remote host at the specified port and
277 |  |
          * originating from the specified local address and port. The
278 |  |
          * local port must lie between <code> MIN_CLIENT_PORT </code> and
279 |  |
          * <code> MAX_CLIENT_PORT </code> or an IllegalArgumentException will
280 |  |
          * be thrown.
281 |  |
          * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_  _connectAction_() }
282 |  |
          * is called to perform connection initialization actions.
283 |  |
          * <p>
284 |  |
          * @param host  The remote host.
285 |  |
          * @param port  The port to connect to on the remote host.
286 |  |
          * @param localAddr  The local address to use.
287 |  |
          * @param localPort  The local port to use.
288 |  |
          * @exception SocketException If the socket timeout could not be set.
289 |  |
          * @exception IOException If the socket could not be opened.  In most
290 |  |
          *  cases you will only want to catch IOException since SocketException is
291 |  |
          *  derived from it.
292 |  |
          * @exception IllegalArgumentException If an invalid local port number
293 |  |
          *            is specified.
294 |  |
          ***/
295 |  |
         public void connect(InetAddress host, int port,
296 |  |
                             InetAddress localAddr, int localPort)
297 |  |
         throws SocketException, IOException, IllegalArgumentException
298 |  |
         {
299 | 0 |
             if (localPort < MIN_CLIENT_PORT || localPort > MAX_CLIENT_PORT)
300 | 0 |
                 throw new IllegalArgumentException("Invalid port number " + localPort);
301 | 0 |
             super.connect(host, port, localAddr, localPort);
302 | 0 |
         }
303 |  |
304 |  |
305 |  |
         /***
306 |  |
          * Opens a Socket connected to a remote host at the specified port and
307 |  |
          * originating from the specified local address and port. The
308 |  |
          * local port must lie between <code> MIN_CLIENT_PORT </code> and
309 |  |
          * <code> MAX_CLIENT_PORT </code> or an IllegalArgumentException will
310 |  |
          * be thrown.
311 |  |
          * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_  _connectAction_() }
312 |  |
          * is called to perform connection initialization actions.
313 |  |
          * <p>
314 |  |
          * @param hostname  The name of the remote host.
315 |  |
          * @param port  The port to connect to on the remote host.
316 |  |
          * @param localAddr  The local address to use.
317 |  |
          * @param localPort  The local port to use.
318 |  |
          * @exception SocketException If the socket timeout could not be set.
319 |  |
          * @exception IOException If the socket could not be opened.  In most
320 |  |
          *  cases you will only want to catch IOException since SocketException is
321 |  |
          *  derived from it.
322 |  |
          * @exception UnknownHostException If the hostname cannot be resolved.
323 |  |
          * @exception IllegalArgumentException If an invalid local port number
324 |  |
          *            is specified.
325 |  |
          ***/
326 |  |
         public void connect(String hostname, int port,
327 |  |
                             InetAddress localAddr, int localPort)
328 |  |
         throws SocketException, IOException, IllegalArgumentException
329 |  |
         {
330 | 0 |
             if (localPort < MIN_CLIENT_PORT || localPort > MAX_CLIENT_PORT)
331 | 0 |
                 throw new IllegalArgumentException("Invalid port number " + localPort);
332 | 0 |
             super.connect(hostname, port, localAddr, localPort);
333 | 0 |
         }
334 |  |
335 |  |
336 |  |
         /***
337 |  |
          * Remotely executes a command through the rshd daemon on the server
338 |  |
          * to which the RCommandClient is connected.  After calling this method,
339 |  |
          * you may interact with the remote process through its standard input,
340 |  |
          * output, and error streams.  You will typically be able to detect
341 |  |
          * the termination of the remote process after reaching end of file
342 |  |
          * on its standard output (accessible through
343 |  |
          * {@link #getInputStream  getInputStream() }.  Disconnecting
344 |  |
          * from the server or closing the process streams before reaching
345 |  |
          * end of file will not necessarily terminate the remote process.
346 |  |
          * <p>
347 |  |
          * If a separate error stream is requested, the remote server will
348 |  |
          * connect to a local socket opened by RCommandClient, providing an
349 |  |
          * independent stream through which standard error will be transmitted.
350 |  |
          * The local socket must originate from a secure port (512 - 1023),
351 |  |
          * and rcommand() ensures that this will be so.
352 |  |
          * RCommandClient will also do a simple security check when it accepts a
353 |  |
          * connection for this error stream.  If the connection does not originate
354 |  |
          * from the remote server, an IOException will be thrown.  This serves as
355 |  |
          * a simple protection against possible hijacking of the error stream by
356 |  |
          * an attacker monitoring the rexec() negotiation.  You may disable this
357 |  |
          * behavior with
358 |  |
          * {@link org.apache.commons.net.bsd.RExecClient#setRemoteVerificationEnabled setRemoteVerificationEnabled()}
359 |  |
          * .
360 |  |
          * <p>
361 |  |
          * @param localUsername  The user account on the local machine that is
362 |  |
          *        requesting the command execution.
363 |  |
          * @param remoteUsername  The account name on the server through which to
364 |  |
          *        execute the command.
365 |  |
          * @param command   The command, including any arguments, to execute.
366 |  |
          * @param separateErrorStream True if you would like the standard error
367 |  |
          *        to be transmitted through a different stream than standard output.
368 |  |
          *        False if not.
369 |  |
          * @exception IOException If the rcommand() attempt fails.  The exception
370 |  |
          *            will contain a message indicating the nature of the failure.
371 |  |
          ***/
372 |  |
         public void rcommand(String localUsername, String remoteUsername,
373 |  |
                              String command, boolean separateErrorStream)
374 |  |
         throws IOException
375 |  |
         {
376 | 0 |
             rexec(localUsername, remoteUsername, command, separateErrorStream);
377 | 0 |
         }
378 |  |
379 |  |
380 |  |
         /***
381 |  |
          * Same as
382 |  |
          * <code> rcommand(localUsername, remoteUsername, command, false); </code>
383 |  |
          ***/
384 |  |
         public void rcommand(String localUsername, String remoteUsername,
385 |  |
                              String command)
386 |  |
         throws IOException
387 |  |
         {
388 | 0 |
             rcommand(localUsername, remoteUsername, command, false);
389 | 0 |
         }
390 |  |
391 |  |
     }
392 |  |

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.