    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.net.ftp;
    019
    020import java.io.BufferedReader;
    021import java.io.BufferedWriter;
    022import java.io.IOException;
    023import java.io.InputStreamReader;
    024import java.io.OutputStreamWriter;
    025import java.net.Inet6Address;
    026import java.net.InetAddress;
    027import java.net.InetSocketAddress;
    028import java.net.ServerSocket;
    029import java.net.Socket;
    030
    031import javax.net.ssl.HostnameVerifier;
    032import javax.net.ssl.KeyManager;
    033import javax.net.ssl.SSLContext;
    034import javax.net.ssl.SSLException;
    035import javax.net.ssl.SSLHandshakeException;
    036import javax.net.ssl.SSLSocket;
    037import javax.net.ssl.SSLSocketFactory;
    038import javax.net.ssl.TrustManager;
    039
    040import org.apache.commons.net.util.Base64;
    041import org.apache.commons.net.util.SSLContextUtils;
    042import org.apache.commons.net.util.SSLSocketUtils;
    043import org.apache.commons.net.util.TrustManagerUtils;
    044
    045/**
    046 * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to see wire-level SSL details.
    047 *
    048 * Warning: the hostname is not verified against the certificate by default, use {@link #setHostnameVerifier(HostnameVerifier)} or
    049 * {@link #setEndpointCheckingEnabled(boolean)} (on Java 1.7+) to enable verification. Verification is only performed on client mode connections.
    050 *
    051 * @since 2.0
    052 */
    053public class FTPSClient extends FTPClient {
    054
    055// From http://www.iana.org/assignments/port-numbers
    056
    057//    ftps-data   989/tcp    ftp protocol, data, over TLS/SSL
    058//    ftps-data   989/udp    ftp protocol, data, over TLS/SSL
    059//    ftps        990/tcp    ftp protocol, control, over TLS/SSL
    060//    ftps        990/udp    ftp protocol, control, over TLS/SSL
    061
    062    public static final int DEFAULT_FTPS_DATA_PORT = 989;
    063    public static final int DEFAULT_FTPS_PORT = 990;
    064
    065    /** The value that I can set in PROT command (C = Clear, P = Protected) */
    066    private static final String[] PROT_COMMAND_VALUE = { "C", "E", "S", "P" };
    067    /** Default PROT Command */
    068    private static final String DEFAULT_PROT = "C";
    069    /** Default secure socket protocol name, i.e. TLS */
    070    private static final String DEFAULT_PROTOCOL = "TLS";
    071
    072    /** The AUTH (Authentication/Security Mechanism) command. */
    073    private static final String CMD_AUTH = "AUTH";
    074    /** The ADAT (Authentication/Security Data) command. */
    075    private static final String CMD_ADAT = "ADAT";
    076    /** The PROT (Data Channel Protection Level) command. */
    077    private static final String CMD_PROT = "PROT";
    078    /** The PBSZ (Protection Buffer Size) command. */
    079    private static final String CMD_PBSZ = "PBSZ";
    080    /** The MIC (Integrity Protected Command) command. */
    081    private static final String CMD_MIC = "MIC";
    082    /** The CONF (Confidentiality Protected Command) command. */
    083    private static final String CMD_CONF = "CONF";
    084    /** The ENC (Privacy Protected Command) command. */
    085    private static final String CMD_ENC = "ENC";
    086    /** The CCC (Clear Command Channel) command. */
    087    private static final String CMD_CCC = "CCC";
    088
    089    /** @deprecated - not used - may be removed in a future release */
    090    @Deprecated
    091    public static String KEYSTORE_ALGORITHM;
    092    /** @deprecated - not used - may be removed in a future release */
    093    @Deprecated
    094    public static String TRUSTSTORE_ALGORITHM;
    095    /** @deprecated - not used - may be removed in a future release */
    096    @Deprecated
    097    public static String PROVIDER;
    098    /** @deprecated - not used - may be removed in a future release */
    099    @Deprecated
    100    public static String STORE_TYPE;
    101    /** The security mode. (True - Implicit Mode / False - Explicit Mode) */
    102    private final boolean isImplicit;
    103    /** The secure socket protocol to be used, e.g. SSL/TLS. */
    104    private final String protocol;
    105    /** The AUTH Command value */
    106    private String auth = DEFAULT_PROTOCOL;
    107    /** The context object. */
    108    private SSLContext context;
    109    /** The socket object. */
    110    private Socket plainSocket;
    111    /** Controls whether a new SSL session may be established by this socket. Default true. */
    112    private boolean isCreation = true;
    113    /** The use client mode flag. */
    114    private boolean isClientMode = true;
    115
    116    /** The need client auth flag. */
    117    private boolean isNeedClientAuth;
    118
    119    /** The want client auth flag. */
    120    private boolean isWantClientAuth;
    121
    122    /** The cipher suites */
    123    private String[] suites;
    124
    125    /** The protocol versions */
    126    private String[] protocols;
    127
    128    /**
    129     * The FTPS {@link TrustManager} implementation, default validate only {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}.
    130     */
    131    private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager();
    132
    133    /** The {@link KeyManager}, default null (i.e. use system default). */
    134    private KeyManager keyManager;
    135
    136    /** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no verification). */
    137    private HostnameVerifier hostnameVerifier;
    138
    139    /** Use Java 1.7+ HTTPS Endpoint Identification Algorithm. */
    140    private boolean tlsEndpointChecking;
    141
    142    /**
    143     * Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}.
    144     *
    145     * Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit (isImplicit = false)
    146     */
    147    public FTPSClient() {
    148        this(DEFAULT_PROTOCOL, false);
    149    }
    150
    151    /**
    152     * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS Calls {@link #FTPSClient(String, boolean)}
    153     *
    154     * @param isImplicit The security mode (Implicit/Explicit).
    155     */
    156    public FTPSClient(final boolean isImplicit) {
    157        this(DEFAULT_PROTOCOL, isImplicit);
    158    }
    159
    160    /**
    161     * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS The default TrustManager is set from
    162     * {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}
    163     *
    164     * @param isImplicit The security mode(Implicit/Explicit).
    165     * @param context    A pre-configured SSL Context
    166     */
    167    public FTPSClient(final boolean isImplicit, final SSLContext context) {
    168        this(DEFAULT_PROTOCOL, isImplicit);
    169        this.context = context;
    170    }
    171
    172    /**
    173     * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS and isImplicit {@code false} Calls {@link #FTPSClient(boolean, SSLContext)}
    174     *
    175     * @param context A pre-configured SSL Context
    176     */
    177    public FTPSClient(final SSLContext context) {
    178        this(false, context);
    179    }
    180
    181    /**
    182     * Constructor for FTPSClient, using explict mode, calls {@link #FTPSClient(String, boolean)}.
    183     *
    184     * @param protocol the protocol to use
    185     */
    186    public FTPSClient(final String protocol) {
    187        this(protocol, false);
    188    }
    189
    190    /**
    191     * Constructor for FTPSClient allowing specification of protocol and security mode. If isImplicit is true, the port is set to {@link #DEFAULT_FTPS_PORT}
    192     * i.e. 990. The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}
    193     *
    194     * @param protocol   the protocol
    195     * @param isImplicit The security mode(Implicit/Explicit).
    196     */
    197    public FTPSClient(final String protocol, final boolean isImplicit) {
    198        this.protocol = protocol;
    199        this.isImplicit = isImplicit;
    200        if (isImplicit) {
    201            setDefaultPort(DEFAULT_FTPS_PORT);
    202        }
    203    }
    204
    205    /**
    206     * Because there are so many connect() methods, the _connectAction_() method is provided as a means of performing some action immediately after establishing
    207     * a connection, rather than reimplementing all of the connect() methods.
    208     *
    209     * @throws IOException If it throw by _connectAction_.
    210     * @see org.apache.commons.net.SocketClient#_connectAction_()
    211     */
    212    @Override
    213    protected void _connectAction_() throws IOException {
    214        // Implicit mode.
    215        if (isImplicit) {
    216            applySocketAttributes();
    217            sslNegotiation();
    218        }
    219        super._connectAction_();
    220        // Explicit mode.
    221        if (!isImplicit) {
    222            execAUTH();
    223            sslNegotiation();
    224        }
    225    }
    226
    227    /**
    228     * Returns a socket of the data connection. Wrapped as an {@link SSLSocket}, which carries out handshake processing.
    229     *
    230     * @param command The int representation of the FTP command to send.
    231     * @param arg     The arguments to the FTP command. If this parameter is set to null, then the command is sent with no arguments.
    232     * @return corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the establishment and
    233     *         initialization of the connection.
    234     * @throws IOException If there is any problem with the connection.
    235     * @see FTPClient#_openDataConnection_(int, String)
    236     * @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd, String)} instead
    237     */
    238    @Override
    239    // Strictly speaking this is not needed, but it works round a Clirr bug
    240    // So rather than invoke the parent code, we do it here
    241    @Deprecated
    242    protected Socket _openDataConnection_(final int command, final String arg) throws IOException {
    243        return _openDataConnection_(FTPCommand.getCommand(command), arg);
    244    }
    245
    246    /**
    247     * Returns a socket of the data connection. Wrapped as an {@link SSLSocket}, which carries out handshake processing.
    248     *
    249     * @param command The textual representation of the FTP command to send.
    250     * @param arg     The arguments to the FTP command. If this parameter is set to null, then the command is sent with no arguments.
    251     * @return corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the establishment and
    252     *         initialization of the connection.
    253     * @throws IOException If there is any problem with the connection.
    254     * @see FTPClient#_openDataConnection_(int, String)
    255     * @since 3.2
    256     */
    257    @Override
    258    protected Socket _openDataConnection_(final String command, final String arg) throws IOException {
    259        final Socket socket = openDataSecureConnection(command, arg);
    260        _prepareDataSocket_(socket);
    261        if (socket instanceof SSLSocket) {
    262            final SSLSocket sslSocket = (SSLSocket) socket;
    263
    264            sslSocket.setUseClientMode(isClientMode);
    265            sslSocket.setEnableSessionCreation(isCreation);
    266
    267            // server mode
    268            if (!isClientMode) {
    269                sslSocket.setNeedClientAuth(isNeedClientAuth);
    270                sslSocket.setWantClientAuth(isWantClientAuth);
    271            }
    272            if (suites != null) {
    273                sslSocket.setEnabledCipherSuites(suites);
    274            }
    275            if (protocols != null) {
    276                sslSocket.setEnabledProtocols(protocols);
    277            }
    278            sslSocket.startHandshake();
    279        }
    280
    281        return socket;
    282    }
    283
    284    /**
    285     * Performs any custom initialization for a newly created SSLSocket (before the SSL handshake happens). Called by {@link #_openDataConnection_(int, String)}
    286     * immediately after creating the socket. The default implementation is a no-op
    287     *
    288     * @param socket the socket to set up
    289     * @throws IOException on error
    290     * @since 3.1
    291     */
    292    protected void _prepareDataSocket_(final Socket socket) throws IOException {
    293    }
    294
    295    /**
    296     * Check the value that can be set in PROT Command value.
    297     *
    298     * @param prot Data Channel Protection Level.
    299     * @return True - A set point is right / False - A set point is not right
    300     */
    301    private boolean checkPROTValue(final String prot) {
    302        for (final String element : PROT_COMMAND_VALUE) {
    303            if (element.equals(prot)) {
    304                return true;
    305            }
    306        }
    307        return false;
    308    }
    309
    310    /**
    311     * Close open sockets.
    312     *
    313     * @param socket    main socket for proxy if enabled
    314     * @param sslSocket ssl socket
    315     * @throws IOException closing sockets is not successful
    316     */
    317    private void closeSockets(final Socket socket, final Socket sslSocket) throws IOException {
    318        if (socket != null) {
    319            socket.close();
    320        }
    321        if (sslSocket != null) {
    322            sslSocket.close();
    323        }
    324    }
    325
    326    /**
    327     * Create SSL socket from plain socket.
    328     *
    329     * @param socket
    330     * @return SSL Socket
    331     * @throws IOException
    332     */
    333    private SSLSocket createSSLSocket(final Socket socket) throws IOException {
    334        if (socket != null) {
    335            final SSLSocketFactory f = context.getSocketFactory();
    336            return (SSLSocket) f.createSocket(socket, _hostname_, socket.getPort(), false);
    337        }
    338        return null;
    339    }
    340
    341    /**
    342     * Closes the connection to the FTP server and restores connection parameters to the default values.
    343     * <p>
    344     * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} to reset the factories that may have been changed during the session, e.g.
    345     * by {@link #execPROT(String)}
    346     *
    347     * @throws IOException If an error occurs while disconnecting.
    348     * @since 3.0
    349     */
    350    @Override
    351    public void disconnect() throws IOException {
    352        super.disconnect();
    353        if (plainSocket != null) {
    354            plainSocket.close();
    355        }
    356        setSocketFactory(null);
    357        setServerSocketFactory(null);
    358    }
    359
    360    /**
    361     * Send the ADAT command with the specified authentication data.
    362     *
    363     * @param data The data to send with the command.
    364     * @return server reply.
    365     * @throws IOException If an I/O error occurs while sending the command.
    366     * @since 3.0
    367     */
    368    public int execADAT(final byte[] data) throws IOException {
    369        if (data != null) {
    370            return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data));
    371        }
    372        return sendCommand(CMD_ADAT);
    373    }
    374
    375    /**
    376     * AUTH command.
    377     *
    378     * @throws SSLException If it server reply code not equal "234" and "334".
    379     * @throws IOException  If an I/O error occurs while either sending the command.
    380     */
    381    protected void execAUTH() throws SSLException, IOException {
    382        final int replyCode = sendCommand(CMD_AUTH, auth);
    383        if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) {
    384            // replyCode = 334
    385            // I carry out an ADAT command.
    386        } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) {
    387            throw new SSLException(getReplyString());
    388        }
    389    }
    390
    391    /**
    392     * Send the AUTH command with the specified mechanism.
    393     *
    394     * @param mechanism The mechanism name to send with the command.
    395     * @return server reply.
    396     * @throws IOException If an I/O error occurs while sending the command.
    397     * @since 3.0
    398     */
    399    public int execAUTH(final String mechanism) throws IOException {
    400        return sendCommand(CMD_AUTH, mechanism);
    401    }
    402
    403    /**
    404     * Send the CCC command to the server. The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned to a plain
    405     * {@link Socket} instances
    406     *
    407     * @return server reply.
    408     * @throws IOException If an I/O error occurs while sending the command.
    409     * @since 3.0
    410     */
    411    public int execCCC() throws IOException {
    412        final int repCode = sendCommand(CMD_CCC);
    413// This will be performed by sendCommand(String, String)
    414//        if (FTPReply.isPositiveCompletion(repCode)) {
    415//            _socket_.close();
    416//            _socket_ = plainSocket;
    417//            _controlInput_ = new BufferedReader(
    418//                new InputStreamReader(
    419//                    _socket_.getInputStream(), getControlEncoding()));
    420//            _controlOutput_ = new BufferedWriter(
    421//                new OutputStreamWriter(
    422//                    _socket_.getOutputStream(), getControlEncoding()));
    423//        }
    424        return repCode;
    425    }
    426
    427    /**
    428     * Send the CONF command with the specified data.
    429     *
    430     * @param data The data to send with the command.
    431     * @return server reply.
    432     * @throws IOException If an I/O error occurs while sending the command.
    433     * @since 3.0
    434     */
    435    public int execCONF(final byte[] data) throws IOException {
    436        if (data != null) {
    437            return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data));
    438        }
    439        return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)?
    440    }
    441
    442    /**
    443     * Send the ENC command with the specified data.
    444     *
    445     * @param data The data to send with the command.
    446     * @return server reply.
    447     * @throws IOException If an I/O error occurs while sending the command.
    448     * @since 3.0
    449     */
    450    public int execENC(final byte[] data) throws IOException {
    451        if (data != null) {
    452            return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data));
    453        }
    454        return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)?
    455    }
    456
    457    /**
    458     * Send the MIC command with the specified data.
    459     *
    460     * @param data The data to send with the command.
    461     * @return server reply.
    462     * @throws IOException If an I/O error occurs while sending the command.
    463     * @since 3.0
    464     */
    465    public int execMIC(final byte[] data) throws IOException {
    466        if (data != null) {
    467            return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data));
    468        }
    469        return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)?
    470    }
    471
    472    /**
    473     * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer.
    474     *
    475     * @param pbsz Protection Buffer Size.
    476     * @throws SSLException If the server reply code does not equal "200".
    477     * @throws IOException  If an I/O error occurs while sending the command.
    478     * @see #parsePBSZ(long)
    479     */
    480    public void execPBSZ(final long pbsz) throws SSLException, IOException {
    481        if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number
    482            throw new IllegalArgumentException();
    483        }
    484        final int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz));
    485        if (FTPReply.COMMAND_OK != status) {
    486            throw new SSLException(getReplyString());
    487        }
    488    }
    489
    490    /**
    491     * PROT command.
    492     * <ul>
    493     * <li>C - Clear</li>
    494     * <li>S - Safe(SSL protocol only)</li>
    495     * <li>E - Confidential(SSL protocol only)</li>
    496     * <li>P - Private</li>
    497     * </ul>
    498     * <b>N.B.</b> the method calls {@link #setSocketFactory(javax.net.SocketFactory)} and {@link #setServerSocketFactory(javax.net.ServerSocketFactory)}
    499     *
    500     * @param prot Data Channel Protection Level, if {@code null}, use {@link #DEFAULT_PROT}.
    501     * @throws SSLException If the server reply code does not equal {@code 200}.
    502     * @throws IOException  If an I/O error occurs while sending the command.
    503     */
    504    public void execPROT(String prot) throws SSLException, IOException {
    505        if (prot == null) {
    506            prot = DEFAULT_PROT;
    507        }
    508        if (!checkPROTValue(prot)) {
    509            throw new IllegalArgumentException();
    510        }
    511        if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) {
    512            throw new SSLException(getReplyString());
    513        }
    514        if (DEFAULT_PROT.equals(prot)) {
    515            setSocketFactory(null);
    516            setServerSocketFactory(null);
    517        } else {
    518            setSocketFactory(new FTPSSocketFactory(context));
    519            setServerSocketFactory(new FTPSServerSocketFactory(context));
    520            initSslContext();
    521        }
    522    }
    523
    524    /**
    525     * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234
    526     *
    527     * @param prefix the prefix to find
    528     * @param reply  where to find the prefix
    529     * @return the remainder of the string after the prefix, or null if the prefix was not present.
    530     */
    531    private String extractPrefixedData(final String prefix, final String reply) {
    532        final int idx = reply.indexOf(prefix);
    533        if (idx == -1) {
    534            return null;
    535        }
    536        // N.B. Cannot use trim before substring as leading space would affect the offset.
    537        return reply.substring(idx + prefix.length()).trim();
    538    }
    539
    540    /**
    541     * Return AUTH command use value.
    542     *
    543     * @return AUTH command use value.
    544     */
    545    public String getAuthValue() {
    546        return this.auth;
    547    }
    548
    549    /**
    550     * Returns the names of the cipher suites which could be enabled for use on this connection. When the underlying {@link Socket} is not an {@link SSLSocket}
    551     * instance, returns null.
    552     *
    553     * @return An array of cipher suite names, or <code>null</code>
    554     */
    555    public String[] getEnabledCipherSuites() {
    556        if (_socket_ instanceof SSLSocket) {
    557            return ((SSLSocket) _socket_).getEnabledCipherSuites();
    558        }
    559        return null;
    560    }
    561
    562    /**
    563     * Returns the names of the protocol versions which are currently enabled for use on this connection. When the underlying {@link Socket} is not an
    564     * {@link SSLSocket} instance, returns null.
    565     *
    566     * @return An array of protocols, or <code>null</code>
    567     */
    568    public String[] getEnabledProtocols() {
    569        if (_socket_ instanceof SSLSocket) {
    570            return ((SSLSocket) _socket_).getEnabledProtocols();
    571        }
    572        return null;
    573    }
    574
    575    /**
    576     * Returns true if new SSL sessions may be established by this socket. When the underlying {@link Socket} instance is not SSL-enabled (i.e. an instance of
    577     * {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) enabled, this returns False.
    578     *
    579     * @return true - Indicates that sessions may be created; this is the default. false - indicates that an existing session must be resumed.
    580     */
    581    public boolean getEnableSessionCreation() {
    582        if (_socket_ instanceof SSLSocket) {
    583            return ((SSLSocket) _socket_).getEnableSessionCreation();
    584        }
    585        return false;
    586    }
    587
    588    /**
    589     * Get the currently configured {@link HostnameVerifier}. The verifier is only used on client mode connections.
    590     *
    591     * @return A HostnameVerifier instance.
    592     * @since 3.4
    593     */
    594    public HostnameVerifier getHostnameVerifier() {
    595        return hostnameVerifier;
    596    }
    597
    598    /**
    599     * Gets the {@link KeyManager} instance.
    600     *
    601     * @return The {@link KeyManager} instance
    602     */
    603    private KeyManager getKeyManager() {
    604        return keyManager;
    605    }
    606
    607    /**
    608     * Returns true if the socket will require client authentication. When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
    609     *
    610     * @return true - If the server mode socket should request that the client authenticate itself.
    611     */
    612    public boolean getNeedClientAuth() {
    613        if (_socket_ instanceof SSLSocket) {
    614            return ((SSLSocket) _socket_).getNeedClientAuth();
    615        }
    616        return false;
    617    }
    618
    619    /**
    620     * Get the currently configured {@link TrustManager}.
    621     *
    622     * @return A TrustManager instance.
    623     */
    624    public TrustManager getTrustManager() {
    625        return trustManager;
    626    }
    627
    628    /**
    629     * Returns true if the socket is set to use client mode in its first handshake. When the underlying {@link Socket} is not an {@link SSLSocket} instance,
    630     * returns false.
    631     *
    632     * @return true - If the socket should start its first handshake in "client" mode.
    633     */
    634    public boolean getUseClientMode() {
    635        if (_socket_ instanceof SSLSocket) {
    636            return ((SSLSocket) _socket_).getUseClientMode();
    637        }
    638        return false;
    639    }
    640
    641    /**
    642     * Returns true if the socket will request client authentication. When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
    643     *
    644     * @return true - If the server mode socket should request that the client authenticate itself.
    645     */
    646    public boolean getWantClientAuth() {
    647        if (_socket_ instanceof SSLSocket) {
    648            return ((SSLSocket) _socket_).getWantClientAuth();
    649        }
    650        return false;
    651    }
    652
    653    /**
    654     * Performs a lazy init of the SSL context
    655     *
    656     * @throws IOException
    657     */
    658    private void initSslContext() throws IOException {
    659        if (context == null) {
    660            context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager());
    661        }
    662    }
    663
    664    /**
    665     * Return whether or not endpoint identification using the HTTPS algorithm on Java 1.7+ is enabled. The default behavior is for this to be disabled.
    666     *
    667     * This check is only performed on client mode connections.
    668     *
    669     * @return True if enabled, false if not.
    670     * @since 3.4
    671     */
    672    public boolean isEndpointCheckingEnabled() {
    673        return tlsEndpointChecking;
    674    }
    675
    676    /**
    677     * Establishes a data connection with the FTP server, returning a Socket for the connection if successful. If a restart offset has been set with
    678     * {@link #setRestartOffset(long)}, a REST command is issued to the server with the offset as an argument before establishing the data connection. Active
    679     * mode connections also cause a local PORT command to be issued.
    680     *
    681     * @param command The text representation of the FTP command to send.
    682     * @param arg     The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
    683     * @return A Socket corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the
    684     *         establishment and initialization of the connection.
    685     * @throws IOException If an I/O error occurs while either sending a command to the server or receiving a reply from the server.
    686     * @since 3.1
    687     */
    688    private Socket openDataSecureConnection(final String command, final String arg) throws IOException {
    689        if (getDataConnectionMode() != ACTIVE_LOCAL_DATA_CONNECTION_MODE && getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) {
    690            return null;
    691        }
    692
    693        final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address;
    694
    695        final Socket socket;
    696        Socket sslSocket = null;
    697        final int soTimeoutMillis = DurationUtils.toMillisInt(getDataTimeout());
    698        if (getDataConnectionMode() == ACTIVE_LOCAL_DATA_CONNECTION_MODE) {
    699            // if no activePortRange was set (correctly) -> getActivePort() = 0
    700            // -> new ServerSocket(0) -> bind to any free local port
    701            try (final ServerSocket server = _serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress())) {
    702                // Try EPRT only if remote server is over IPv6, if not use PORT,
    703                // because EPRT has no advantage over PORT on IPv4.
    704                // It could even have the disadvantage,
    705                // that EPRT will make the data connection fail, because
    706                // today's intelligent NAT Firewalls are able to
    707                // substitute IP addresses in the PORT command,
    708                // but might not be able to recognize the EPRT command.
    709                if (isInet6Address) {
    710                    if (!FTPReply.isPositiveCompletion(eprt(getReportHostAddress(), server.getLocalPort()))) {
    711                        return null;
    712                    }
    713                } else if (!FTPReply.isPositiveCompletion(port(getReportHostAddress(), server.getLocalPort()))) {
    714                    return null;
    715                }
    716
    717                if ((getRestartOffset() > 0) && !restart(getRestartOffset())) {
    718                    return null;
    719                }
    720
    721                if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
    722                    return null;
    723                }
    724
    725                // For now, let's just use the data timeout value for waiting for
    726                // the data connection. It may be desirable to let this be a
    727                // separately configurable value. In any case, we really want
    728                // to allow preventing the accept from blocking indefinitely.
    729                if (soTimeoutMillis >= 0) {
    730                    server.setSoTimeout(soTimeoutMillis);
    731                }
    732                socket = server.accept();
    733
    734                // Ensure the timeout is set before any commands are issued on the new socket
    735                if (soTimeoutMillis >= 0) {
    736                    socket.setSoTimeout(soTimeoutMillis);
    737                }
    738                if (getReceiveDataSocketBufferSize() > 0) {
    739                    socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
    740                }
    741                if (getSendDataSocketBufferSize() > 0) {
    742                    socket.setSendBufferSize(getSendDataSocketBufferSize());
    743                }
    744            }
    745        } else { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE
    746
    747            // Try EPSV command first on IPv6 - and IPv4 if enabled.
    748            // When using IPv4 with NAT it has the advantage
    749            // to work with more rare configurations.
    750            // E.g. if FTP server has a static PASV address (external network)
    751            // and the client is coming from another internal network.
    752            // In that case the data connection after PASV command would fail,
    753            // while EPSV would make the client succeed by taking just the port.
    754            final boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address;
    755            if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE) {
    756                _parseExtendedPassiveModeReply(_replyLines.get(0));
    757            } else {
    758                if (isInet6Address) {
    759                    return null; // Must use EPSV for IPV6
    760                }
    761                // If EPSV failed on IPV4, revert to PASV
    762                if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) {
    763                    return null;
    764                }
    765                _parsePassiveModeReply(_replyLines.get(0));
    766            }
    767
    768            if (getProxy() != null) {
    769                socket = new Socket(getProxy());
    770            } else {
    771                socket = _socketFactory_.createSocket();
    772            }
    773
    774            if (getReceiveDataSocketBufferSize() > 0) {
    775                socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
    776            }
    777            if (getSendDataSocketBufferSize() > 0) {
    778                socket.setSendBufferSize(getSendDataSocketBufferSize());
    779            }
    780            if (getPassiveLocalIPAddress() != null) {
    781                socket.bind(new InetSocketAddress(getPassiveLocalIPAddress(), 0));
    782            }
    783
    784            // For now, let's just use the data timeout value for waiting for
    785            // the data connection. It may be desirable to let this be a
    786            // separately configurable value. In any case, we really want
    787            // to allow preventing the accept from blocking indefinitely.
    788            if (soTimeoutMillis >= 0) {
    789                socket.setSoTimeout(soTimeoutMillis);
    790            }
    791
    792            socket.connect(new InetSocketAddress(getPassiveHost(), getPassivePort()), connectTimeout);
    793
    794            if (getProxy() != null) {
    795                sslSocket = context.getSocketFactory().createSocket(socket, getPassiveHost(), getPassivePort(), true);
    796            }
    797
    798            if ((getRestartOffset() > 0) && !restart(getRestartOffset())) {
    799                closeSockets(socket, sslSocket);
    800                return null;
    801            }
    802
    803            if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
    804                closeSockets(socket, sslSocket);
    805                return null;
    806            }
    807        }
    808
    809        if (isRemoteVerificationEnabled() && !verifyRemote(socket)) {
    810            // Grab the host before we close the socket to avoid NET-663
    811            final InetAddress socketHost = socket.getInetAddress();
    812
    813            closeSockets(socket, sslSocket);
    814
    815            throw new IOException(
    816                    "Host attempting data connection " + socketHost.getHostAddress() + " is not same as server " + getRemoteAddress().getHostAddress());
    817        }
    818
    819        return getProxy() != null ? sslSocket : socket;
    820    }
    821
    822    /**
    823     * Parses the given ADAT response line and base64-decodes the data.
    824     *
    825     * @param reply The ADAT reply to parse.
    826     * @return the data in the reply, base64-decoded.
    827     * @since 3.0
    828     */
    829    public byte[] parseADATReply(final String reply) {
    830        if (reply == null) {
    831            return null;
    832        }
    833        return Base64.decodeBase64(extractPrefixedData("ADAT=", reply));
    834    }
    835
    836    /**
    837     * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. Issues the command and parses the response to return the negotiated value.
    838     *
    839     * @param pbsz Protection Buffer Size.
    840     * @throws SSLException If the server reply code does not equal "200".
    841     * @throws IOException  If an I/O error occurs while sending the command.
    842     * @return the negotiated value.
    843     * @see #execPBSZ(long)
    844     * @since 3.0
    845     */
    846    public long parsePBSZ(final long pbsz) throws SSLException, IOException {
    847        execPBSZ(pbsz);
    848        long minvalue = pbsz;
    849        final String remainder = extractPrefixedData("PBSZ=", getReplyString());
    850        if (remainder != null) {
    851            final long replysz = Long.parseLong(remainder);
    852            if (replysz < minvalue) {
    853                minvalue = replysz;
    854            }
    855        }
    856        return minvalue;
    857    }
    858
    859    /**
    860     * Send an FTP command. A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned to a plain
    861     * {@link Socket}
    862     *
    863     * @param command The FTP command.
    864     * @return server reply.
    865     * @throws IOException  If an I/O error occurs while sending the command.
    866     * @throws SSLException if a CCC command fails
    867     * @see org.apache.commons.net.ftp.FTP#sendCommand(String)
    868     */
    869    // Would like to remove this method, but that will break any existing clients that are using CCC
    870    @Override
    871    public int sendCommand(final String command, final String args) throws IOException {
    872        final int repCode = super.sendCommand(command, args);
    873        /* If CCC is issued, restore socket i/o streams to unsecured versions */
    874        if (CMD_CCC.equals(command)) {
    875            if (FTPReply.COMMAND_OK != repCode) {
    876                throw new SSLException(getReplyString());
    877            }
    878            _socket_.close();
    879            _socket_ = plainSocket;
    880            _controlInput_ = new BufferedReader(new InputStreamReader(_socket_.getInputStream(), getControlEncoding()));
    881            _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_socket_.getOutputStream(), getControlEncoding()));
    882        }
    883        return repCode;
    884    }
    885
    886    /**
    887     * Set AUTH command use value. This processing is done before connected processing.
    888     *
    889     * @param auth AUTH command use value.
    890     */
    891    public void setAuthValue(final String auth) {
    892        this.auth = auth;
    893    }
    894
    895    /**
    896     * Controls which particular cipher suites are enabled for use on this connection. Called before server negotiation.
    897     *
    898     * @param cipherSuites The cipher suites.
    899     */
    900    public void setEnabledCipherSuites(final String[] cipherSuites) {
    901        suites = cipherSuites.clone();
    902    }
    903
    904    /**
    905     * Controls which particular protocol versions are enabled for use on this connection. I perform setting before a server negotiation.
    906     *
    907     * @param protocolVersions The protocol versions.
    908     */
    909    public void setEnabledProtocols(final String[] protocolVersions) {
    910        protocols = protocolVersions.clone();
    911    }
    912
    913    /**
    914     * Controls whether a new SSL session may be established by this socket.
    915     *
    916     * @param isCreation The established socket flag.
    917     */
    918    public void setEnabledSessionCreation(final boolean isCreation) {
    919        this.isCreation = isCreation;
    920    }
    921
    922    /**
    923     * Automatic endpoint identification checking using the HTTPS algorithm is supported on Java 1.7+. The default behavior is for this to be disabled.
    924     *
    925     * This check is only performed on client mode connections.
    926     *
    927     * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+.
    928     * @since 3.4
    929     */
    930    public void setEndpointCheckingEnabled(final boolean enable) {
    931        tlsEndpointChecking = enable;
    932    }
    933
    934    /**
    935     * Override the default {@link HostnameVerifier} to use. The verifier is only used on client mode connections.
    936     *
    937     * @param newHostnameVerifier The HostnameVerifier implementation to set or <code>null</code> to disable.
    938     * @since 3.4
    939     */
    940    public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier) {
    941        hostnameVerifier = newHostnameVerifier;
    942    }
    943
    944    /**
    945     * Set a {@link KeyManager} to use
    946     *
    947     * @param keyManager The KeyManager implementation to set.
    948     * @see org.apache.commons.net.util.KeyManagerUtils
    949     */
    950    public void setKeyManager(final KeyManager keyManager) {
    951        this.keyManager = keyManager;
    952    }
    953
    954    // DEPRECATED - for API compatibility only - DO NOT USE
    955
    956    /**
    957     * Configures the socket to require client authentication.
    958     *
    959     * @param isNeedClientAuth The need client auth flag.
    960     */
    961    public void setNeedClientAuth(final boolean isNeedClientAuth) {
    962        this.isNeedClientAuth = isNeedClientAuth;
    963    }
    964
    965    /**
    966     * Override the default {@link TrustManager} to use; if set to {@code null}, the default TrustManager from the JVM will be used.
    967     *
    968     * @param trustManager The TrustManager implementation to set, may be {@code null}
    969     * @see org.apache.commons.net.util.TrustManagerUtils
    970     */
    971    public void setTrustManager(final TrustManager trustManager) {
    972        this.trustManager = trustManager;
    973    }
    974
    975    /**
    976     * Configures the socket to use client (or server) mode in its first handshake.
    977     *
    978     * @param isClientMode The use client mode flag.
    979     */
    980    public void setUseClientMode(final boolean isClientMode) {
    981        this.isClientMode = isClientMode;
    982    }
    983
    984    /**
    985     * Configures the socket to request client authentication, but only if such a request is appropriate to the cipher suite negotiated.
    986     *
    987     * @param isWantClientAuth The want client auth flag.
    988     */
    989    public void setWantClientAuth(final boolean isWantClientAuth) {
    990        this.isWantClientAuth = isWantClientAuth;
    991    }
    992
    993    /**
    994     * SSL/TLS negotiation. Acquires an SSL socket of a control connection and carries out handshake processing.
    995     *
    996     * @throws IOException If server negotiation fails
    997     */
    998    protected void sslNegotiation() throws IOException {
    999        plainSocket = _socket_;
    1000        initSslContext();
    1001        final SSLSocket socket = createSSLSocket(_socket_);
    1002        socket.setEnableSessionCreation(isCreation);
    1003        socket.setUseClientMode(isClientMode);
    1004
    1005        // client mode
    1006        if (isClientMode) {
    1007            if (tlsEndpointChecking) {
    1008                SSLSocketUtils.enableEndpointNameVerification(socket);
    1009            }
    1010        } else { // server mode
    1011            socket.setNeedClientAuth(isNeedClientAuth);
    1012            socket.setWantClientAuth(isWantClientAuth);
    1013        }
    1014
    1015        if (protocols != null) {
    1016            socket.setEnabledProtocols(protocols);
    1017        }
    1018        if (suites != null) {
    1019            socket.setEnabledCipherSuites(suites);
    1020        }
    1021        socket.startHandshake();
    1022
    1023        // TODO the following setup appears to duplicate that in the super class methods
    1024        _socket_ = socket;
    1025        _controlInput_ = new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding()));
    1026        _controlOutput_ = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), getControlEncoding()));
    1027
    1028        if (isClientMode && (hostnameVerifier != null && !hostnameVerifier.verify(_hostname_, socket.getSession()))) {
    1029            throw new SSLHandshakeException("Hostname doesn't match certificate");
    1030        }
    1031    }
    1032
    1033}
    1034/* kate: indent-width 4; replace-tabs on; */