This is an automated email from the ASF dual-hosted git repository.

johnnyv pushed a commit to branch FTPSERVER-491
in repository https://gitbox.apache.org/repos/asf/mina-ftpserver.git


The following commit(s) were added to refs/heads/FTPSERVER-491 by this push:
     new 967b857  Adds additional SSL checks for FTPSERVER-491
967b857 is described below

commit 967b85730e81509877c1f87b46c9f15a7c579f1e
Author: johnnyv <john...@apache.org>
AuthorDate: Wed May 8 23:30:52 2019 -0400

    Adds additional SSL checks for FTPSERVER-491
---
 .../org/apache/ftpserver/command/impl/AUTH.java    | 126 +++--
 .../ftpserver/impl/IODataConnectionFactory.java    | 584 ++++++++++-----------
 2 files changed, 336 insertions(+), 374 deletions(-)

diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/AUTH.java 
b/core/src/main/java/org/apache/ftpserver/command/impl/AUTH.java
index 070ef48..58ab386 100644
--- a/core/src/main/java/org/apache/ftpserver/command/impl/AUTH.java
+++ b/core/src/main/java/org/apache/ftpserver/command/impl/AUTH.java
@@ -55,71 +55,63 @@ public class AUTH extends AbstractCommand {
     /**
      * Execute command
      */
-    public void execute(final FtpIoSession session,
-            final FtpServerContext context, final FtpRequest request)
-            throws IOException, FtpException {
-
-        // reset state variables
-        session.resetState();
-
-        // argument check
-        if (!request.hasArgument()) {
-            session.write(LocalizedFtpReply.translate(session, request, 
context,
-                    FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS,
-                    "AUTH", null));
-            return;
-        }
-
-        // check SSL configuration
-        if (session.getListener().getSslConfiguration() == null) {
-            session.write(LocalizedFtpReply.translate(session, request, 
context,
-                    431, "AUTH", null));
-            return;
-        }
-
-        // check that we don't already have a SSL filter in place due to 
running
-        // in implicit mode
-        // or because the AUTH command has already been issued. This is what 
the
-        // RFC says:
-
-        // "Some servers will allow the AUTH command to be reissued in order
-        // to establish new authentication. The AUTH command, if accepted,
-        // removes any state associated with prior FTP Security commands.
-        // The server must also require that the user reauthorize (that is,
-        // reissue some or all of the USER, PASS, and ACCT commands) in this
-        // case (see section 4 for an explanation of "authorize" in this
-        // context)."
-
-        // Here we choose not to support reissued AUTH
-        if (session.getFilterChain().contains(SslFilter.class)) {
-            session.write(LocalizedFtpReply.translate(session, request, 
context,
-                    534, "AUTH", null));
-            return;
-        }
-
-        // check parameter
-        String authType = request.getArgument().toUpperCase();
-        if (VALID_AUTH_TYPES.contains(authType)) {
-            if(authType.equals("TLS-C")) {
-                authType = "TLS";
-            } else if(authType.equals("TLS-P")) {
-                authType = "SSL";
-            }
-
-            try {
-                secureSession(session, authType);
-                session.write(LocalizedFtpReply.translate(session, request, 
context,
-                        234, "AUTH." + authType, null));
-            } catch (FtpException ex) {
-                throw ex;
-            } catch (Exception ex) {
-                LOG.warn("AUTH.execute()", ex);
-                throw new FtpException("AUTH.execute()", ex);
-            }
-        } else {
-            session.write(LocalizedFtpReply.translate(session, request, 
context,
-                    FtpReply.REPLY_502_COMMAND_NOT_IMPLEMENTED, "AUTH", null));
-        }
+    public void execute(final FtpIoSession session, final FtpServerContext 
context, final FtpRequest request) throws IOException, FtpException {
+
+       // reset state variables
+       session.resetState();
+
+       // argument check
+       if (!request.hasArgument()) {
+           session.write(LocalizedFtpReply.translate(session, request, 
context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "AUTH", 
null));
+           return;
+       }
+
+       // check SSL configuration
+       if (session.getListener().getSslConfiguration() == null) {
+           session.write(LocalizedFtpReply.translate(session, request, 
context, 431, "AUTH", null));
+           return;
+       }
+
+       // check that we don't already have a SSL filter in place due to running
+       // in implicit mode
+       // or because the AUTH command has already been issued. This is what the
+       // RFC says:
+
+       // "Some servers will allow the AUTH command to be reissued in order
+       // to establish new authentication. The AUTH command, if accepted,
+       // removes any state associated with prior FTP Security commands.
+       // The server must also require that the user reauthorize (that is,
+       // reissue some or all of the USER, PASS, and ACCT commands) in this
+       // case (see section 4 for an explanation of "authorize" in this
+       // context)."
+
+       // Here we choose not to support reissued AUTH
+       if (session.getFilterChain().contains(SslFilter.class)) {
+           session.write(LocalizedFtpReply.translate(session, request, 
context, 534, "AUTH", null));
+           return;
+       }
+
+       // check parameter
+       String authType = request.getArgument().toUpperCase();
+       if (VALID_AUTH_TYPES.contains(authType)) {
+           if (authType.equals("TLS-C")) {
+               authType = "TLS";
+           } else if (authType.equals("TLS-P")) {
+               authType = "SSL";
+           }
+
+           try {
+               secureSession(session, authType);
+               session.write(LocalizedFtpReply.translate(session, request, 
context, 234, "AUTH." + authType, null));
+           } catch (FtpException ex) {
+               throw ex;
+           } catch (Exception ex) {
+               LOG.warn("AUTH.execute()", ex);
+               throw new FtpException("AUTH.execute()", ex);
+           }
+       } else {
+           session.write(LocalizedFtpReply.translate(session, request, 
context, FtpReply.REPLY_502_COMMAND_NOT_IMPLEMENTED, "AUTH", null));
+       }
     }
 
     private void secureSession(final FtpIoSession session, final String type)
@@ -143,6 +135,10 @@ public class AUTH extends AbstractCommand {
             if (ssl.getEnabledCipherSuites() != null) {
                 sslFilter.setEnabledCipherSuites(ssl.getEnabledCipherSuites());
             }
+            
+            if(ssl.getEnabledProtocol() != null ) {
+               sslFilter.setEnabledProtocols(new String[] 
{ssl.getEnabledProtocol()});
+            }
 
             session.getFilterChain().addFirst(SSL_SESSION_FILTER_NAME,
                     sslFilter);
diff --git 
a/core/src/main/java/org/apache/ftpserver/impl/IODataConnectionFactory.java 
b/core/src/main/java/org/apache/ftpserver/impl/IODataConnectionFactory.java
index 068e4c2..3da1cf3 100644
--- a/core/src/main/java/org/apache/ftpserver/impl/IODataConnectionFactory.java
+++ b/core/src/main/java/org/apache/ftpserver/impl/IODataConnectionFactory.java
@@ -41,15 +41,13 @@ import org.slf4j.LoggerFactory;
 /**
  * <strong>Internal class, do not use directly.</strong>
  * 
- * We can get the FTP data connection using this class. It uses either PORT or
- * PASV command.
+ * We can get the FTP data connection using this class. It uses either PORT or 
PASV command.
  *
  * @author <a href="http://mina.apache.org";>Apache MINA Project</a>
  */
 public class IODataConnectionFactory implements ServerDataConnectionFactory {
 
-    private final Logger LOG = LoggerFactory
-            .getLogger(IODataConnectionFactory.class);
+    private final Logger LOG = 
LoggerFactory.getLogger(IODataConnectionFactory.class);
 
     private FtpServerContext serverContext;
 
@@ -73,161 +71,136 @@ public class IODataConnectionFactory implements 
ServerDataConnectionFactory {
 
     FtpIoSession session;
 
-    public IODataConnectionFactory(final FtpServerContext serverContext,
-            final FtpIoSession session) {
-        this.session = session;
-        this.serverContext = serverContext;
-        if ((session != null) && (session.getListener() != null) && 
-            
session.getListener().getDataConnectionConfiguration().isImplicitSsl()) {
-            secure = true;
-        }
+    public IODataConnectionFactory(final FtpServerContext serverContext, final 
FtpIoSession session) {
+       this.session = session;
+       this.serverContext = serverContext;
+       if ((session != null) && (session.getListener() != null) && 
session.getListener().getDataConnectionConfiguration().isImplicitSsl()) {
+           secure = true;
+       }
     }
 
     /**
-     * Close data socket.
-     * This method must be idempotent as we might call it multiple times 
during disconnect.
+     * Close data socket. This method must be idempotent as we might call it 
multiple times during disconnect.
      */
     public synchronized void closeDataConnection() {
 
-        // close client socket if any
-        if (dataSoc != null) {
-            try {
-                dataSoc.close();
-            } catch (Exception ex) {
-                LOG.warn("FtpDataConnection.closeDataSocket()", ex);
-            }
-            dataSoc = null;
-        }
-
-        // close server socket if any
-        if (servSoc != null) {
-            try {
-                servSoc.close();
-            } catch (Exception ex) {
-                LOG.warn("FtpDataConnection.closeDataSocket()", ex);
-            }
-
-            if (session != null) {
-                DataConnectionConfiguration dcc = session.getListener()
-                        .getDataConnectionConfiguration();
-                if (dcc != null) {
-                    dcc.releasePassivePort(port);
-                }
-            }
-
-            servSoc = null;
-        }
-
-        // reset request time
-        requestTime = 0L;
+       // close client socket if any
+       if (dataSoc != null) {
+           try {
+               dataSoc.close();
+           } catch (Exception ex) {
+               LOG.warn("FtpDataConnection.closeDataSocket()", ex);
+           }
+           dataSoc = null;
+       }
+
+       // close server socket if any
+       if (servSoc != null) {
+           try {
+               servSoc.close();
+           } catch (Exception ex) {
+               LOG.warn("FtpDataConnection.closeDataSocket()", ex);
+           }
+
+           if (session != null) {
+               DataConnectionConfiguration dcc = 
session.getListener().getDataConnectionConfiguration();
+               if (dcc != null) {
+                   dcc.releasePassivePort(port);
+               }
+           }
+
+           servSoc = null;
+       }
+
+       // reset request time
+       requestTime = 0L;
     }
 
     /**
      * Port command.
      */
-    public synchronized void initActiveDataConnection(
-            final InetSocketAddress address) {
+    public synchronized void initActiveDataConnection(final InetSocketAddress 
address) {
 
-        // close old sockets if any
-        closeDataConnection();
+       // close old sockets if any
+       closeDataConnection();
 
-        // set variables
-        passive = false;
-        this.address = address.getAddress();
-        port = address.getPort();
-        requestTime = System.currentTimeMillis();
+       // set variables
+       passive = false;
+       this.address = address.getAddress();
+       port = address.getPort();
+       requestTime = System.currentTimeMillis();
     }
 
     private SslConfiguration getSslConfiguration() {
-        DataConnectionConfiguration dataCfg = session.getListener()
-                .getDataConnectionConfiguration();
+       DataConnectionConfiguration dataCfg = 
session.getListener().getDataConnectionConfiguration();
 
-        SslConfiguration configuration = dataCfg.getSslConfiguration();
+       SslConfiguration configuration = dataCfg.getSslConfiguration();
 
-        // fall back if no configuration has been provided on the data 
connection config
-        if (configuration == null) {
-            configuration = session.getListener().getSslConfiguration();
-        }
+       // fall back if no configuration has been provided on the data 
connection config
+       if (configuration == null) {
+           configuration = session.getListener().getSslConfiguration();
+       }
 
-        return configuration;
+       return configuration;
     }
 
     /**
-     * Initiate a data connection in passive mode (server listening). 
+     * Initiate a data connection in passive mode (server listening).
      */
-    public synchronized InetSocketAddress initPassiveDataConnection()
-            throws DataConnectionException {
-        LOG.debug("Initiating passive data connection");
-        // close old sockets if any
-        closeDataConnection();
-
-        // get the passive port
-        int passivePort = session.getListener()
-                .getDataConnectionConfiguration().requestPassivePort();
-        if (passivePort == -1) {
-            servSoc = null;
-            throw new DataConnectionException(
-                    "Cannot find an available passive port.");
-        }
-
-        // open passive server socket and get parameters
-        try {
-            DataConnectionConfiguration dataCfg = session.getListener()
-                    .getDataConnectionConfiguration();
-
-            String passiveAddress = dataCfg.getPassiveAddress();
-
-            if (passiveAddress == null) {
-                address = serverControlAddress;
-            } else {
-                address = resolveAddress(dataCfg.getPassiveAddress());
-            }
-
-            if (secure) {
-                LOG
-                        .debug(
-                                "Opening SSL passive data connection on 
address \"{}\" and port {}",
-                                address, passivePort);
-                SslConfiguration ssl = getSslConfiguration();
-                if (ssl == null) {
-                    throw new DataConnectionException(
-                            "Data connection SSL required but not 
configured.");
-                }
-
-                // this method does not actually create the SSL socket, due to 
a JVM bug 
-                // (https://issues.apache.org/jira/browse/FTPSERVER-241).
-                // Instead, it creates a regular
-                // ServerSocket that will be wrapped as a SSL socket in 
createDataSocket()
-                servSoc = new ServerSocket(passivePort, 0, address);
-                LOG
-                        .debug(
-                                "SSL Passive data connection created on 
address \"{}\" and port {}",
-                                address, passivePort);
-            } else {
-                LOG
-                        .debug(
-                                "Opening passive data connection on address 
\"{}\" and port {}",
-                                address, passivePort);
-                servSoc = new ServerSocket(passivePort, 0, address);
-                LOG
-                        .debug(
-                                "Passive data connection created on address 
\"{}\" and port {}",
-                                address, passivePort);
-            }
-            port = servSoc.getLocalPort();
-            servSoc.setSoTimeout(dataCfg.getIdleTime() * 1000);
-
-            // set different state variables
-            passive = true;
-            requestTime = System.currentTimeMillis();
-
-            return new InetSocketAddress(address, port);
-        } catch (Exception ex) {
-            closeDataConnection();
-            throw new DataConnectionException(
-                    "Failed to initate passive data connection: "
-                            + ex.getMessage(), ex);
-        }
+    public synchronized InetSocketAddress initPassiveDataConnection() throws 
DataConnectionException {
+       LOG.debug("Initiating passive data connection");
+       // close old sockets if any
+       closeDataConnection();
+
+       // get the passive port
+       int passivePort = 
session.getListener().getDataConnectionConfiguration().requestPassivePort();
+       if (passivePort == -1) {
+           servSoc = null;
+           throw new DataConnectionException("Cannot find an available passive 
port.");
+       }
+
+       // open passive server socket and get parameters
+       try {
+           DataConnectionConfiguration dataCfg = 
session.getListener().getDataConnectionConfiguration();
+
+           String passiveAddress = dataCfg.getPassiveAddress();
+
+           if (passiveAddress == null) {
+               address = serverControlAddress;
+           } else {
+               address = resolveAddress(dataCfg.getPassiveAddress());
+           }
+
+           if (secure) {
+               LOG.debug("Opening SSL passive data connection on address 
\"{}\" and port {}", address, passivePort);
+               SslConfiguration ssl = getSslConfiguration();
+               if (ssl == null) {
+                   throw new DataConnectionException("Data connection SSL 
required but not configured.");
+               }
+
+               // this method does not actually create the SSL socket, due to 
a JVM bug
+               // (https://issues.apache.org/jira/browse/FTPSERVER-241).
+               // Instead, it creates a regular
+               // ServerSocket that will be wrapped as a SSL socket in 
createDataSocket()
+               servSoc = new ServerSocket(passivePort, 0, address);
+               LOG.debug("SSL Passive data connection created on address 
\"{}\" and port {}", address, passivePort);
+           } else {
+               LOG.debug("Opening passive data connection on address \"{}\" 
and port {}", address, passivePort);
+               servSoc = new ServerSocket(passivePort, 0, address);
+               LOG.debug("Passive data connection created on address \"{}\" 
and port {}", address, passivePort);
+           }
+           port = servSoc.getLocalPort();
+           servSoc.setSoTimeout(dataCfg.getIdleTime() * 1000);
+
+           // set different state variables
+           passive = true;
+           requestTime = System.currentTimeMillis();
+
+           return new InetSocketAddress(address, port);
+       } catch (Exception ex) {
+           closeDataConnection();
+           throw new DataConnectionException("Failed to initate passive data 
connection: " + ex.getMessage(), ex);
+       }
     }
 
     /*
@@ -236,7 +209,7 @@ public class IODataConnectionFactory implements 
ServerDataConnectionFactory {
      * @see org.apache.ftpserver.FtpDataConnectionFactory2#getInetAddress()
      */
     public InetAddress getInetAddress() {
-        return address;
+       return address;
     }
 
     /*
@@ -245,7 +218,7 @@ public class IODataConnectionFactory implements 
ServerDataConnectionFactory {
      * @see org.apache.ftpserver.FtpDataConnectionFactory2#getPort()
      */
     public int getPort() {
-        return port;
+       return port;
     }
 
     /*
@@ -254,7 +227,7 @@ public class IODataConnectionFactory implements 
ServerDataConnectionFactory {
      * @see org.apache.ftpserver.FtpDataConnectionFactory2#openConnection()
      */
     public DataConnection openConnection() throws Exception {
-        return new IODataConnection(createDataSocket(), session, this);
+       return new IODataConnection(createDataSocket(), session, this);
     }
 
     /**
@@ -262,151 +235,145 @@ public class IODataConnectionFactory implements 
ServerDataConnectionFactory {
      */
     private synchronized Socket createDataSocket() throws Exception {
 
-        // get socket depending on the selection
-        dataSoc = null;
-        DataConnectionConfiguration dataConfig = session.getListener()
-                .getDataConnectionConfiguration();
-        try {
-            if (!passive) {
-                if (secure) {
-                    LOG.debug("Opening secure active data connection");
-                    SslConfiguration ssl = getSslConfiguration();
-                    if (ssl == null) {
-                        throw new FtpException(
-                                "Data connection SSL not configured");
-                    }
-
-                    // get socket factory
-                    SSLSocketFactory socFactory = ssl.getSocketFactory();
-
-                    // create socket
-                    SSLSocket ssoc = (SSLSocket) socFactory.createSocket();
-                    ssoc.setUseClientMode(false);
-
-                    // initialize socket
-                    if (ssl.getEnabledCipherSuites() != null) {
-                        
ssoc.setEnabledCipherSuites(ssl.getEnabledCipherSuites());
-                    }
-                    dataSoc = ssoc;
-                } else {
-                    LOG.debug("Opening active data connection");
-                    dataSoc = new Socket();
-                }
-
-                dataSoc.setReuseAddress(true);
-
-                InetAddress localAddr = resolveAddress(dataConfig
-                        .getActiveLocalAddress());
-
-                // if no local address has been configured, make sure we use 
the same as the client connects from
-                if(localAddr == null) {
-                    localAddr = 
((InetSocketAddress)session.getLocalAddress()).getAddress();
-                }       
-
-                SocketAddress localSocketAddress = new 
InetSocketAddress(localAddr, dataConfig.getActiveLocalPort());
-                
-                LOG.debug("Binding active data connection to {}", 
localSocketAddress);
-                dataSoc.bind(localSocketAddress);
-
-                dataSoc.connect(new InetSocketAddress(address, port));
-            } else {
-
-                if (secure) {
-                    LOG.debug("Opening secure passive data connection");
-                    // this is where we wrap the unsecured socket as a 
SSLSocket. This is 
-                    // due to the JVM bug described in FTPSERVER-241.
-
-                    // get server socket factory
-                    SslConfiguration ssl = getSslConfiguration();
-                    
-                    // we've already checked this, but let's do it again
-                    if (ssl == null) {
-                        throw new FtpException(
-                                "Data connection SSL not configured");
-                    }
-
-                    SSLSocketFactory ssocketFactory = ssl.getSocketFactory();
-
-                    Socket serverSocket = servSoc.accept();
-
-                    SSLSocket sslSocket = (SSLSocket) ssocketFactory
-                            .createSocket(serverSocket, serverSocket
-                                    .getInetAddress().getHostAddress(),
-                                    serverSocket.getPort(), true);
-                    sslSocket.setUseClientMode(false);
-
-                    // initialize server socket
-                    if (ssl.getClientAuth() == ClientAuth.NEED) {
-                        sslSocket.setNeedClientAuth(true);
-                    } else if (ssl.getClientAuth() == ClientAuth.WANT) {
-                        sslSocket.setWantClientAuth(true);
-                    }
-
-                    if (ssl.getEnabledCipherSuites() != null) {
-                        sslSocket.setEnabledCipherSuites(ssl
-                                .getEnabledCipherSuites());
-                    }
-
-                    dataSoc = sslSocket;
-                } else {
-                    LOG.debug("Opening passive data connection");
-
-                    dataSoc = servSoc.accept();
-                }
-                
-                if (dataConfig.isPassiveIpCheck()) {
-                                       // Let's make sure we got the 
connection from the same
-                                       // client that we are expecting
-                                       InetAddress remoteAddress = 
((InetSocketAddress) session.getRemoteAddress()).getAddress();
-                                       InetAddress dataSocketAddress = 
dataSoc.getInetAddress();
-                                       if 
(!dataSocketAddress.equals(remoteAddress)) {
-                                               LOG.warn("Passive IP Check 
failed. Closing data connection from "
-                                                       + dataSocketAddress
-                                                       + " as it does not 
match the expected address "
-                                                       + remoteAddress);
-                                               closeDataConnection();
-                                               return null;
-                                       }
-                               }
-                
-                DataConnectionConfiguration dataCfg = session.getListener()
-                    .getDataConnectionConfiguration();
-                
-                dataSoc.setSoTimeout(dataCfg.getIdleTime() * 1000);
-                LOG.debug("Passive data connection opened");
-            }
-        } catch (Exception ex) {
-            closeDataConnection();
-            LOG.warn("FtpDataConnection.getDataSocket()", ex);
-            throw ex;
-        }
-        dataSoc.setSoTimeout(dataConfig.getIdleTime() * 1000);
-
-        // Make sure we initiate the SSL handshake, or we'll
-        // get an error if we turn out not to send any data
-        // e.g. during the listing of an empty directory
-        if (dataSoc instanceof SSLSocket) {
-            ((SSLSocket) dataSoc).startHandshake();
-        }
-
-        return dataSoc;
+       // get socket depending on the selection
+       dataSoc = null;
+       DataConnectionConfiguration dataConfig = 
session.getListener().getDataConnectionConfiguration();
+       try {
+           if (!passive) {
+               if (secure) {
+                   LOG.debug("Opening secure active data connection");
+                   SslConfiguration ssl = getSslConfiguration();
+                   if (ssl == null) {
+                       throw new FtpException("Data connection SSL not 
configured");
+                   }
+
+                   // get socket factory
+                   SSLSocketFactory socFactory = ssl.getSocketFactory();
+
+                   // create socket
+                   SSLSocket ssoc = (SSLSocket) socFactory.createSocket();
+                   ssoc.setUseClientMode(false);
+
+                   // initialize socket
+                   if (ssl.getEnabledCipherSuites() != null) {
+                       
ssoc.setEnabledCipherSuites(ssl.getEnabledCipherSuites());
+                   }
+
+                   if (ssl.getEnabledProtocol() != null) {
+                       ssoc.setEnabledProtocols(new String[] { 
ssl.getEnabledProtocol() });
+                   }
+                   dataSoc = ssoc;
+               } else {
+                   LOG.debug("Opening active data connection");
+                   dataSoc = new Socket();
+               }
+
+               dataSoc.setReuseAddress(true);
+
+               InetAddress localAddr = 
resolveAddress(dataConfig.getActiveLocalAddress());
+
+               // if no local address has been configured, make sure we use 
the same as the client connects from
+               if (localAddr == null) {
+                   localAddr = ((InetSocketAddress) 
session.getLocalAddress()).getAddress();
+               }
+
+               SocketAddress localSocketAddress = new 
InetSocketAddress(localAddr, dataConfig.getActiveLocalPort());
+
+               LOG.debug("Binding active data connection to {}", 
localSocketAddress);
+               dataSoc.bind(localSocketAddress);
+
+               dataSoc.connect(new InetSocketAddress(address, port));
+           } else {
+
+               if (secure) {
+                   LOG.debug("Opening secure passive data connection");
+                   // this is where we wrap the unsecured socket as a 
SSLSocket. This is
+                   // due to the JVM bug described in FTPSERVER-241.
+
+                   // get server socket factory
+                   SslConfiguration ssl = getSslConfiguration();
+
+                   // we've already checked this, but let's do it again
+                   if (ssl == null) {
+                       throw new FtpException("Data connection SSL not 
configured");
+                   }
+
+                   SSLSocketFactory ssocketFactory = ssl.getSocketFactory();
+
+                   Socket serverSocket = servSoc.accept();
+
+                   SSLSocket sslSocket = (SSLSocket) 
ssocketFactory.createSocket(serverSocket, 
serverSocket.getInetAddress().getHostAddress(), serverSocket.getPort(), true);
+                   sslSocket.setUseClientMode(false);
+
+                   // initialize server socket
+                   if (ssl.getClientAuth() == ClientAuth.NEED) {
+                       sslSocket.setNeedClientAuth(true);
+                   } else if (ssl.getClientAuth() == ClientAuth.WANT) {
+                       sslSocket.setWantClientAuth(true);
+                   }
+
+                   if (ssl.getEnabledCipherSuites() != null) {
+                       
sslSocket.setEnabledCipherSuites(ssl.getEnabledCipherSuites());
+                   }
+
+                   if (ssl.getEnabledProtocol() != null) {
+                       sslSocket.setEnabledProtocols(new String[] { 
ssl.getEnabledProtocol() });
+                   }
+
+                   dataSoc = sslSocket;
+               } else {
+                   LOG.debug("Opening passive data connection");
+
+                   dataSoc = servSoc.accept();
+               }
+
+               if (dataConfig.isPassiveIpCheck()) {
+                   // Let's make sure we got the connection from the same
+                   // client that we are expecting
+                   InetAddress remoteAddress = ((InetSocketAddress) 
session.getRemoteAddress()).getAddress();
+                   InetAddress dataSocketAddress = dataSoc.getInetAddress();
+                   if (!dataSocketAddress.equals(remoteAddress)) {
+                       LOG.warn("Passive IP Check failed. Closing data 
connection from " + dataSocketAddress + " as it does not match the expected 
address " + remoteAddress);
+                       closeDataConnection();
+                       return null;
+                   }
+               }
+
+               DataConnectionConfiguration dataCfg = 
session.getListener().getDataConnectionConfiguration();
+
+               dataSoc.setSoTimeout(dataCfg.getIdleTime() * 1000);
+               LOG.debug("Passive data connection opened");
+           }
+       } catch (Exception ex) {
+           closeDataConnection();
+           LOG.warn("FtpDataConnection.getDataSocket()", ex);
+           throw ex;
+       }
+       dataSoc.setSoTimeout(dataConfig.getIdleTime() * 1000);
+
+       // Make sure we initiate the SSL handshake, or we'll
+       // get an error if we turn out not to send any data
+       // e.g. during the listing of an empty directory
+       if (dataSoc instanceof SSLSocket) {
+           ((SSLSocket) dataSoc).startHandshake();
+       }
+
+       return dataSoc;
     }
 
     /*
-     *  (non-Javadoc)
-     *   Returns an InetAddress object from a hostname or IP address.
+     * (non-Javadoc) Returns an InetAddress object from a hostname or IP 
address.
      */
-    private InetAddress resolveAddress(String host)
-            throws DataConnectionException {
-        if (host == null) {
-            return null;
-        } else {
-            try {
-                return InetAddress.getByName(host);
-            } catch (UnknownHostException ex) {
-                throw new DataConnectionException("Failed to resolve address", 
ex);
-            }
-        }
+    private InetAddress resolveAddress(String host) throws 
DataConnectionException {
+       if (host == null) {
+           return null;
+       } else {
+           try {
+               return InetAddress.getByName(host);
+           } catch (UnknownHostException ex) {
+               throw new DataConnectionException("Failed to resolve address", 
ex);
+           }
+       }
     }
 
     /*
@@ -415,14 +382,14 @@ public class IODataConnectionFactory implements 
ServerDataConnectionFactory {
      * @see org.apache.ftpserver.DataConnectionFactory#isSecure()
      */
     public boolean isSecure() {
-        return secure;
+       return secure;
     }
 
     /**
      * Set the security protocol.
      */
     public void setSecure(final boolean secure) {
-        this.secure = secure;
+       this.secure = secure;
     }
 
     /*
@@ -431,14 +398,14 @@ public class IODataConnectionFactory implements 
ServerDataConnectionFactory {
      * @see org.apache.ftpserver.DataConnectionFactory#isZipMode()
      */
     public boolean isZipMode() {
-        return isZip;
+       return isZip;
     }
 
     /**
      * Set zip mode.
      */
     public void setZipMode(final boolean zip) {
-        isZip = zip;
+       isZip = zip;
     }
 
     /**
@@ -446,42 +413,41 @@ public class IODataConnectionFactory implements 
ServerDataConnectionFactory {
      */
     public synchronized boolean isTimeout(final long currTime) {
 
-        // data connection not requested - not a timeout
-        if (requestTime == 0L) {
-            return false;
-        }
-
-        // data connection active - not a timeout
-        if (dataSoc != null) {
-            return false;
-        }
-
-        // no idle time limit - not a timeout
-        int maxIdleTime = session.getListener()
-                .getDataConnectionConfiguration().getIdleTime() * 1000;
-        if (maxIdleTime == 0) {
-            return false;
-        }
-
-        // idle time is within limit - not a timeout
-        if ((currTime - requestTime) < maxIdleTime) {
-            return false;
-        }
-
-        return true;
+       // data connection not requested - not a timeout
+       if (requestTime == 0L) {
+           return false;
+       }
+
+       // data connection active - not a timeout
+       if (dataSoc != null) {
+           return false;
+       }
+
+       // no idle time limit - not a timeout
+       int maxIdleTime = 
session.getListener().getDataConnectionConfiguration().getIdleTime() * 1000;
+       if (maxIdleTime == 0) {
+           return false;
+       }
+
+       // idle time is within limit - not a timeout
+       if ((currTime - requestTime) < maxIdleTime) {
+           return false;
+       }
+
+       return true;
     }
 
     /**
      * Dispose data connection - close all the sockets.
      */
     public void dispose() {
-        closeDataConnection();
+       closeDataConnection();
     }
 
     /**
      * Sets the server's control address.
      */
     public void setServerControlAddress(final InetAddress 
serverControlAddress) {
-        this.serverControlAddress = serverControlAddress;
+       this.serverControlAddress = serverControlAddress;
     }
 }

Reply via email to