You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by wr...@apache.org on 2007/10/03 01:09:37 UTC

svn commit: r581430 - in /httpd/mod_ftp/trunk: include/mod_ftp.h modules/ftp/ftp_commands.c

Author: wrowe
Date: Tue Oct  2 16:09:36 2007
New Revision: 581430

URL: http://svn.apache.org/viewvc?rev=581430&view=rev
Log:
Introduce EPSV command handling (EPSV, ESPV ALL, EPSV 1, EPSV 2).

EPSV ALL creates a contract we must enforce for any subsequent 
PASV/PORT/EPRT request, for the lifetime of the control connection.

RFC2428

Modified:
    httpd/mod_ftp/trunk/include/mod_ftp.h
    httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c

Modified: httpd/mod_ftp/trunk/include/mod_ftp.h
URL: http://svn.apache.org/viewvc/httpd/mod_ftp/trunk/include/mod_ftp.h?rev=581430&r1=581429&r2=581430&view=diff
==============================================================================
--- httpd/mod_ftp/trunk/include/mod_ftp.h (original)
+++ httpd/mod_ftp/trunk/include/mod_ftp.h Tue Oct  2 16:09:36 2007
@@ -327,6 +327,8 @@
     apr_bucket_brigade *next_bb;
     char *next_request;
     apr_size_t next_reqsize;
+
+    int all_epsv; /* refuse PORT/PASV/EPRT due to prior EPSV ALL command */
 };
 
 #define FTP_DEFAULT_UMASK (APR_GWRITE | APR_WWRITE)

Modified: httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c
URL: http://svn.apache.org/viewvc/httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c?rev=581430&r1=581429&r2=581430&view=diff
==============================================================================
--- httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c (original)
+++ httpd/mod_ftp/trunk/modules/ftp/ftp_commands.c Tue Oct  2 16:09:36 2007
@@ -1389,6 +1389,11 @@
     apr_port_t port;
     int found_port;
 
+    if (fc->all_epsv) {
+        fc->response_notes = apr_pstrdup(r->pool, "Restricted by EPSV ALL ");
+        return FTP_REPLY_COMMAND_UNRECOGNIZED;
+    }
+
     if (fc->csock) {
         apr_socket_close(fc->csock);
         fc->csock = NULL;
@@ -1492,6 +1497,96 @@
 }
 
 
+static int ftp_cmd_epsv(request_rec *r, const char *arg)
+{
+    ftp_connection *fc = ftp_get_module_config(r->request_config);
+    conn_rec *c = r->connection;
+    ftp_server_config *fsc = 
+        ftp_get_module_config(c->base_server->module_config);
+    int res;
+    apr_sockaddr_t *sa;
+    const char *addr;
+    int family = 0;
+
+    if (strcmp(arg, "ALL")) {
+        /* A contract to never respond to other data connection methods */
+        fc->all_epsv = 1;
+        return FTP_REPLY_COMMAND_OK;
+    }
+
+    if (strcmp(arg, "1")) {
+        if (c->local_addr->family == AF_INET
+#if APR_HAVE_IPV6
+            || (c->local_addr->family == AF_INET6 &&
+                IN6_IS_ADDR_V4MAPPED((struct in6_addr *)
+                                     c->local_addr->ipaddr_ptr))
+#endif
+            ) {
+            /* httpd assures us local_ip is in ipv4 notation for mapped addrs */
+            addr = c->local_ip;
+            family = APR_INET;
+        }
+        else {
+            return FTP_REPLY_BAD_PROTOCOL;
+        }
+    }
+    else if (strcmp(arg, "2")) {
+#if APR_HAVE_IPV6
+        family = AF_INET6;
+        if (c->local_addr->family == AF_INET6 &&
+            IN6_IS_ADDR_V4MAPPED((struct in6_addr *)
+                                 c->local_addr->ipaddr_ptr)) {
+            /* httpd assures us local_ip is in ipv4 notation for mapped addrs */
+            addr = c->local_ip;
+            family = APR_INET;
+        }
+        else if (c->local_addr->family == AF_INET6) {
+            addr = c->local_ip;
+            family = AF_INET6;
+        }
+        else
+#endif
+        {
+            return FTP_REPLY_BAD_PROTOCOL;
+        }
+    }
+    else if (!*arg) {
+        if (fsc->pasv_bindaddr) {
+            addr = fsc->pasv_bindaddr;
+            family = fsc->pasv_bindfamily;
+        }
+#if APR_HAVE_IPV6
+        else if (c->local_addr->family == AF_INET6 &&
+                 IN6_IS_ADDR_V4MAPPED((struct in6_addr *)
+                                      c->local_addr->ipaddr_ptr)) {
+            /* httpd assures us local_ip is in ipv4 notation for mapped addrs */
+            addr = c->local_ip;
+            family = APR_INET;
+        }
+#endif
+        else {
+            addr = c->local_ip;
+            family = c->local_addr->family;
+        }
+    }
+    else {
+        return FTP_REPLY_BAD_PROTOCOL;
+    }
+
+    if ( ( res = init_pasv_socket(r, family, addr) ) ) {
+        return res;
+    }
+
+    apr_socket_addr_get(&sa, APR_LOCAL, fc->csock);
+
+    fc->response_notes = apr_psprintf(r->pool,
+                                     "Entering Extended Passive Mode (|||%u|)",
+                                      sa->port);
+
+    return FTP_REPLY_EXTENDED_PASSIVE_MODE;
+}
+
+
 static int ftp_cmd_pasv(request_rec *r, const char *arg)
 {
     ftp_connection *fc = ftp_get_module_config(r->request_config);
@@ -1620,6 +1715,11 @@
 #endif
     int res, val[6];
 
+    if (fc->all_epsv) {
+        fc->response_notes = apr_pstrdup(r->pool, "Restricted by EPSV ALL ");
+        return FTP_REPLY_COMMAND_UNRECOGNIZED;
+    }
+
     if (fc->csock) {
         apr_socket_close(fc->csock);
         fc->csock = NULL;
@@ -2553,7 +2653,7 @@
                  FTP_NEED_LOGIN|FTP_TAKE1,
                  "<sp> <d>af<d>addr<d>port<d>");
 
-    ftp_hook_cmd("EPSV", NULL, FTP_HOOK_LAST, 
+    ftp_hook_cmd("EPSV", ftp_cmd_epsv, FTP_HOOK_LAST, 
                  FTP_NEED_LOGIN|FTP_TAKE0|FTP_TAKE1,
                  "[ <sp> af|ALL ]");