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; */