All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.net.bsd.RExecClient Maven / Gradle / Ivy

Go to download

Apache Commons Net library contains a collection of network utilities and protocol implementations. Supported protocols include: Echo, Finger, FTP, NNTP, NTP, POP3(S), SMTP(S), Telnet, Whois

There is a newer version: 20030805.205232
Show newest version
/*
 * 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.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import org.apache.commons.net.SocketClient;
import org.apache.commons.net.io.SocketInputStream;

/***
 * RExecClient implements the rexec() facility that first appeared in
 * 4.2BSD Unix.  This class will probably only be of use for connecting
 * to Unix systems and only when the rexecd daemon is configured to run,
 * which is a rarity these days because of the security risks involved.
 * However, rexec() can be very useful for performing administrative tasks
 * on a network behind a firewall.
 * 

* As with virtually all of the client classes in org.apache.commons.net, this * class derives from SocketClient, inheriting its connection methods. * The way to use RExecClient is to first connect * to the server, call the {@link #rexec rexec()} 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 #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 #getInputStream getInputStream()}. However, it is * possible to tell the rexecd daemon to return the standard error * stream over a separate connection, readable from the input stream * returned by {@link #getErrorStream getErrorStream()}. You * can specify that a separate connection should be created for standard * error by setting the boolean separateErrorStream * parameter of {@link #rexec rexec()} to true . * The standard input of the remote process can be written to through * the output stream returned by * {@link #getOutputStream getOutputSream()}. * * @see SocketClient * @see RCommandClient * @see RLoginClient ***/ public class RExecClient extends SocketClient { /** * @since 3.3 */ protected static final char NULL_CHAR = '\0'; /*** * The default rexec port. Set to 512 in BSD Unix. ***/ public static final int DEFAULT_PORT = 512; private boolean __remoteVerificationEnabled; /*** * If a separate error stream is requested, _errorStream_ * will point to an InputStream from which the standard error of the * remote process can be read (after a call to rexec()). Otherwise, * _errorStream_ will be null. ***/ protected InputStream _errorStream_; // This can be overridden in local package to implement port range // limitations of rcmd and rlogin InputStream _createErrorStream() throws IOException { ServerSocket server; Socket socket; server = _serverSocketFactory_.createServerSocket(0, 1, getLocalAddress()); _output_.write(Integer.toString(server.getLocalPort()).getBytes("UTF-8")); // $NON-NLS-1$ _output_.write(NULL_CHAR); _output_.flush(); socket = server.accept(); server.close(); if (__remoteVerificationEnabled && !verifyRemote(socket)) { socket.close(); throw new IOException( "Security violation: unexpected connection attempt by " + socket.getInetAddress().getHostAddress()); } return (new SocketInputStream(socket, socket.getInputStream())); } /*** * The default RExecClient constructor. Initializes the * default port to DEFAULT_PORT . ***/ public RExecClient() { _errorStream_ = null; setDefaultPort(DEFAULT_PORT); } /*** * Returns the InputStream from which the standard output of the remote * process can be read. The input stream will only be set after a * successful rexec() invocation. * * @return The InputStream from which the standard output of the remote * process can be read. ***/ public InputStream getInputStream() { return _input_; } /*** * Returns the OutputStream through which the standard input of the remote * process can be written. The output stream will only be set after a * successful rexec() invocation. * * @return The OutputStream through which the standard input of the remote * process can be written. ***/ public OutputStream getOutputStream() { return _output_; } /*** * Returns the InputStream from which the standard error of the remote * process can be read if a separate error stream is requested from * the server. Otherwise, null will be returned. The error stream * will only be set after a successful rexec() invocation. * * @return The InputStream from which the standard error of the remote * process can be read if a separate error stream is requested from * the server. Otherwise, null will be returned. ***/ public InputStream getErrorStream() { return _errorStream_; } /*** * Remotely executes a command through the rexecd daemon on the server * to which the RExecClient 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 RExecClient, providing an * independent stream through which standard error will be transmitted. * RExecClient will 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 #setRemoteVerificationEnabled setRemoteVerificationEnabled()} * . * * @param username The account name on the server through which to execute * the command. * @param password The plain text password of the user account. * @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. * @throws IOException If the rexec() attempt fails. The exception * will contain a message indicating the nature of the failure. ***/ public void rexec(String username, String password, String command, boolean separateErrorStream) throws IOException { int ch; if (separateErrorStream) { _errorStream_ = _createErrorStream(); } else { _output_.write(NULL_CHAR); } _output_.write(username.getBytes(getCharset())); _output_.write(NULL_CHAR); _output_.write(password.getBytes(getCharset())); _output_.write(NULL_CHAR); _output_.write(command.getBytes(getCharset())); _output_.write(NULL_CHAR); _output_.flush(); ch = _input_.read(); if (ch > 0) { StringBuilder buffer = new StringBuilder(); while ((ch = _input_.read()) != -1 && ch != '\n') { buffer.append((char)ch); } throw new IOException(buffer.toString()); } else if (ch < 0) { throw new IOException("Server closed connection."); } } /*** * Same as rexec(username, password, command, false); * @param username the user name * @param password the password * @param command the command to run * @throws IOException if an error occurs ***/ public void rexec(String username, String password, String command) throws IOException { rexec(username, password, command, false); } /*** * Disconnects from the server, closing all associated open sockets and * streams. * * @throws IOException If there an error occurs while disconnecting. ***/ @Override public void disconnect() throws IOException { if (_errorStream_ != null) { _errorStream_.close(); } _errorStream_ = null; super.disconnect(); } /*** * Enable or disable verification that the remote host connecting to * create a separate error stream is the same as the host to which * the standard out stream is connected. The default is for verification * to be enabled. You may set this value at any time, whether the * client is currently connected or not. * * @param enable True to enable verification, false to disable verification. ***/ public final void setRemoteVerificationEnabled(boolean enable) { __remoteVerificationEnabled = enable; } /*** * Return whether or not verification of the remote host providing a * separate error stream is enabled. The default behavior is for * verification to be enabled. * * @return True if verification is enabled, false if not. ***/ public final boolean isRemoteVerificationEnabled() { return __remoteVerificationEnabled; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy