From 063284837c8c366e5502b1b0264b8eb807b61732 Mon Sep 17 00:00:00 2001 From: Joe Robinson Date: Wed, 27 Oct 2010 14:21:09 +0100 Subject: Basic upload functionality to predifined location, with basic file browser --- org/apache/commons/net/bsd/RCommandClient.java | 402 +++++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 org/apache/commons/net/bsd/RCommandClient.java (limited to 'org/apache/commons/net/bsd/RCommandClient.java') diff --git a/org/apache/commons/net/bsd/RCommandClient.java b/org/apache/commons/net/bsd/RCommandClient.java new file mode 100644 index 0000000..50cb87a --- /dev/null +++ b/org/apache/commons/net/bsd/RCommandClient.java @@ -0,0 +1,402 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.net.bsd; + +import java.io.IOException; +import java.io.InputStream; +import java.net.BindException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; + +import org.apache.commons.net.io.SocketInputStream; + +/*** + * RCommandClient is very similar to + * {@link org.apache.commons.net.bsd.RExecClient}, + * from which it is derived, and implements the rcmd() facility that + * first appeared in 4.2BSD Unix. rcmd() is the facility used by the rsh + * (rshell) and other commands to execute a command on another machine + * from a trusted host without issuing a password. The trust relationship + * between two machines is established by the contents of a machine's + * /etc/hosts.equiv file and a user's .rhosts file. These files specify + * from which hosts and accounts on those hosts rcmd() requests will be + * accepted. The only additional measure for establishing trust is that + * all client connections must originate from a port between 512 and 1023. + * Consequently, there is an upper limit to the number of rcmd connections + * that can be running simultaneously. The required ports are reserved + * ports on Unix systems, and can only be bound by a + * process running with root permissions (to accomplish this rsh, rlogin, + * and related commands usualy have the suid bit set). Therefore, on a + * Unix system, you will only be able to successfully use the RCommandClient + * class if the process runs as root. However, there is no such restriction + * on Windows95 and some other systems. The security risks are obvious. + * However, when carefully used, rcmd() can be very useful when used behind + * a firewall. + *

+ * As with virtually all of the client classes in org.apache.commons.net, this + * class derives from SocketClient. But it overrides most of its connection + * methods so that the local Socket will originate from an acceptable + * rshell port. The way to use RCommandClient is to first connect + * to the server, call the {@link #rcommand rcommand() } method, + * and then + * fetch the connection's input, output, and optionally error streams. + * Interaction with the remote command is controlled entirely through the + * I/O streams. Once you have finished processing the streams, you should + * invoke {@link org.apache.commons.net.bsd.RExecClient#disconnect disconnect() } + * to clean up properly. + *

+ * By default the standard output and standard error streams of the + * remote process are transmitted over the same connection, readable + * from the input stream returned by + * {@link org.apache.commons.net.bsd.RExecClient#getInputStream getInputStream() } + * . However, it is + * possible to tell the rshd daemon to return the standard error + * stream over a separate connection, readable from the input stream + * returned by {@link org.apache.commons.net.bsd.RExecClient#getErrorStream getErrorStream() } + * . You + * can specify that a separate connection should be created for standard + * error by setting the boolean separateErrorStream + * parameter of {@link #rcommand rcommand() } to true . + * The standard input of the remote process can be written to through + * the output stream returned by + * {@link org.apache.commons.net.bsd.RExecClient#getOutputStream getOutputStream() } + * . + *

+ *

+ * @author Daniel F. Savarese + * @see org.apache.commons.net.SocketClient + * @see RExecClient + * @see RLoginClient + ***/ + +public class RCommandClient extends RExecClient +{ + /*** + * The default rshell port. Set to 514 in BSD Unix. + ***/ + public static final int DEFAULT_PORT = 514; + + /*** + * The smallest port number an rcmd client may use. By BSD convention + * this number is 512. + ***/ + public static final int MIN_CLIENT_PORT = 512; + + /*** + * The largest port number an rcmd client may use. By BSD convention + * this number is 1023. + ***/ + public static final int MAX_CLIENT_PORT = 1023; + + // Overrides method in RExecClient in order to implement proper + // port number limitations. + @Override + InputStream _createErrorStream() throws IOException + { + int localPort; + ServerSocket server; + Socket socket; + + localPort = MAX_CLIENT_PORT; + server = null; // Keep compiler from barfing + + for (localPort = MAX_CLIENT_PORT; localPort >= MIN_CLIENT_PORT; --localPort) + { + try + { + server = _serverSocketFactory_.createServerSocket(localPort, 1, + getLocalAddress()); + } + catch (SocketException e) + { + continue; + } + break; + } + + if (localPort < MIN_CLIENT_PORT) + throw new BindException("All ports in use."); + + _output_.write(Integer.toString(server.getLocalPort()).getBytes()); + _output_.write('\0'); + _output_.flush(); + + socket = server.accept(); + server.close(); + + if (isRemoteVerificationEnabled() && !verifyRemote(socket)) + { + socket.close(); + throw new IOException( + "Security violation: unexpected connection attempt by " + + socket.getInetAddress().getHostAddress()); + } + + return (new SocketInputStream(socket, socket.getInputStream())); + } + + /*** + * The default RCommandClient constructor. Initializes the + * default port to DEFAULT_PORT . + ***/ + public RCommandClient() + { + setDefaultPort(DEFAULT_PORT); + } + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address using a port in a range + * acceptable to the BSD rshell daemon. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @exception SocketException If the socket timeout could not be set. + * @exception BindException If all acceptable rshell ports are in use. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + ***/ + public void connect(InetAddress host, int port, InetAddress localAddr) + throws SocketException, BindException, IOException + { + int localPort; + + localPort = MAX_CLIENT_PORT; + + for (localPort = MAX_CLIENT_PORT; localPort >= MIN_CLIENT_PORT; --localPort) + { + try + { + _socket_ = + _socketFactory_.createSocket(host, port, localAddr, localPort); + } + catch (BindException be) { + continue; + } + catch (SocketException e) + { + continue; + } + break; + } + + if (localPort < MIN_CLIENT_PORT) + throw new BindException("All ports in use or insufficient permssion."); + + _connectAction_(); + } + + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the current host at a port in a range acceptable + * to the BSD rshell daemon. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @param port The port to connect to on the remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception BindException If all acceptable rshell ports are in use. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + ***/ + @Override + public void connect(InetAddress host, int port) + throws SocketException, IOException + { + connect(host, port, InetAddress.getLocalHost()); + } + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the current host at a port in a range acceptable + * to the BSD rshell daemon. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The name of the remote host. + * @param port The port to connect to on the remote host. + * @exception SocketException If the socket timeout could not be set. + * @exception BindException If all acceptable rshell ports are in use. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception UnknownHostException If the hostname cannot be resolved. + ***/ + @Override + public void connect(String hostname, int port) + throws SocketException, IOException + { + connect(InetAddress.getByName(hostname), port, InetAddress.getLocalHost()); + } + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address using a port in a range + * acceptable to the BSD rshell daemon. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @exception SocketException If the socket timeout could not be set. + * @exception BindException If all acceptable rshell ports are in use. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + ***/ + public void connect(String hostname, int port, InetAddress localAddr) + throws SocketException, IOException + { + connect(InetAddress.getByName(hostname), port, localAddr); + } + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address and port. The + * local port must lie between MIN_CLIENT_PORT and + * MAX_CLIENT_PORT or an IllegalArgumentException will + * be thrown. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param host The remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception IllegalArgumentException If an invalid local port number + * is specified. + ***/ + @Override + public void connect(InetAddress host, int port, + InetAddress localAddr, int localPort) + throws SocketException, IOException, IllegalArgumentException + { + if (localPort < MIN_CLIENT_PORT || localPort > MAX_CLIENT_PORT) + throw new IllegalArgumentException("Invalid port number " + localPort); + super.connect(host, port, localAddr, localPort); + } + + + /*** + * Opens a Socket connected to a remote host at the specified port and + * originating from the specified local address and port. The + * local port must lie between MIN_CLIENT_PORT and + * MAX_CLIENT_PORT or an IllegalArgumentException will + * be thrown. + * Before returning, {@link org.apache.commons.net.SocketClient#_connectAction_ _connectAction_() } + * is called to perform connection initialization actions. + *

+ * @param hostname The name of the remote host. + * @param port The port to connect to on the remote host. + * @param localAddr The local address to use. + * @param localPort The local port to use. + * @exception SocketException If the socket timeout could not be set. + * @exception IOException If the socket could not be opened. In most + * cases you will only want to catch IOException since SocketException is + * derived from it. + * @exception UnknownHostException If the hostname cannot be resolved. + * @exception IllegalArgumentException If an invalid local port number + * is specified. + ***/ + @Override + public void connect(String hostname, int port, + InetAddress localAddr, int localPort) + throws SocketException, IOException, IllegalArgumentException + { + if (localPort < MIN_CLIENT_PORT || localPort > MAX_CLIENT_PORT) + throw new IllegalArgumentException("Invalid port number " + localPort); + super.connect(hostname, port, localAddr, localPort); + } + + + /*** + * Remotely executes a command through the rshd daemon on the server + * to which the RCommandClient is connected. After calling this method, + * you may interact with the remote process through its standard input, + * output, and error streams. You will typically be able to detect + * the termination of the remote process after reaching end of file + * on its standard output (accessible through + * {@link #getInputStream getInputStream() }. Disconnecting + * from the server or closing the process streams before reaching + * end of file will not necessarily terminate the remote process. + *

+ * If a separate error stream is requested, the remote server will + * connect to a local socket opened by RCommandClient, providing an + * independent stream through which standard error will be transmitted. + * The local socket must originate from a secure port (512 - 1023), + * and rcommand() ensures that this will be so. + * RCommandClient will also do a simple security check when it accepts a + * connection for this error stream. If the connection does not originate + * from the remote server, an IOException will be thrown. This serves as + * a simple protection against possible hijacking of the error stream by + * an attacker monitoring the rexec() negotiation. You may disable this + * behavior with + * {@link org.apache.commons.net.bsd.RExecClient#setRemoteVerificationEnabled setRemoteVerificationEnabled()} + * . + *

+ * @param localUsername The user account on the local machine that is + * requesting the command execution. + * @param remoteUsername The account name on the server through which to + * execute the command. + * @param command The command, including any arguments, to execute. + * @param separateErrorStream True if you would like the standard error + * to be transmitted through a different stream than standard output. + * False if not. + * @exception IOException If the rcommand() attempt fails. The exception + * will contain a message indicating the nature of the failure. + ***/ + public void rcommand(String localUsername, String remoteUsername, + String command, boolean separateErrorStream) + throws IOException + { + rexec(localUsername, remoteUsername, command, separateErrorStream); + } + + + /*** + * Same as + * rcommand(localUsername, remoteUsername, command, false); + ***/ + public void rcommand(String localUsername, String remoteUsername, + String command) + throws IOException + { + rcommand(localUsername, remoteUsername, command, false); + } + +} + -- cgit v1.2.3