Subject: bin/9606: patches to facilitate passive ftp server protocol behind firewall
To: None <gnats-bugs@gnats.netbsd.org>
From: None <srp@zgi.com>
List: netbsd-bugs
Date: 03/12/2000 11:21:53
>Number:         9606
>Category:       bin
>Synopsis:       patches to facilitate passive ftp server protocol behind firewall
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Mar 12 11:21:00 2000
>Last-Modified:
>Originator:     Scott Presnell
>Organization:
self
>Release:        1.4.1 on i386 platform
>Environment:
NetBSD srp4 1.4.1 NetBSD 1.4.1 (RHINE) #16: Sat Mar 11 21:11:18 PST 2000     srp@srp4:/usr/src/sys/arch/i386/compile/RHINE i386

>Description:
My ftp server lives at a "bimap"ed address in private address space,
behind a firewall. To facilitate the passive ftp server protocol I
made the advertized address configurable so clients could contact
the appropriate real IP world address.  I also made the port range
used in a passive protocol connection configurable so that I only
have to open a specific range of ports to connections from the
outside.  These changes are similar parts of other ftp servers,
but use the NetBSD ftpd.conf interface. 

Unified patches follow in fix.  Thanks.  - Scott


>How-To-Repeat:


>Fix:

--- extern.h.orig       Wed Mar  8 08:07:35 2000
+++ extern.h    Wed Mar  8 14:02:43 2000
@@ -90,6 +90,9 @@
        int              modify;        /* Allow dele, mkd, rmd, umask, chmod */
        char            *notify;        /* Files to notify about upon chdir */
        int              passive;       /* Allow pasv */
+       char            *paddr;         /* Passive advertized inet_addr */
+       int              phigh;         /* Passive high port */
+       int              plow;          /* Passive low port */
        unsigned int     timeout;       /* Default timeout */
        mode_t           umask;         /* Umask to use */
 };
--- conf.c.orig Wed Mar  8 08:07:21 2000
+++ conf.c      Wed Mar  8 08:25:59 2000
@@ -107,6 +107,9 @@
        curclass.modify =       1;
        REASSIGN(curclass.notify, NULL);
        curclass.passive =      1;
+       REASSIGN(curclass.paddr, NULL);
+       curclass.phigh = 0;
+       curclass.plow = 0;
        curclass.timeout =      900;            /* 15 minutes */
        curclass.umask =        027;
 
@@ -259,6 +262,32 @@
                                curclass.passive = 0;
                        else
                                curclass.passive = 1;
+               } else if (strcasecmp(word, "paddr") == 0) {
+                       if (none || EMPTYSTR(arg))
+                               arg = NULL;
+                       else
+                               arg = strdup(arg);
+                       REASSIGN(curclass.paddr, arg);
+               } else if (strcasecmp(word, "pports") == 0) {
+                       unsigned int low = 0;
+                       unsigned int high = 0;
+                       if (none || EMPTYSTR(arg)) {
+                               arg = NULL;
+                       } else {
+                               arg = strdup(arg);
+                               if (sscanf(arg, "%d-%d", &low, &high) != 2) {
+                                       syslog(LOG_WARNING,
+                                               "%s line %d: bad pports range '%s'",
+                                                       infile, line, arg);
+                               }
+                               if (low > high) {
+                                       unsigned int temp = low;
+                                       low = high;
+                                       high = temp;
+                               }
+                       }
+                       curclass.plow = low;
+                       curclass.phigh = high;
                } else if (strcasecmp(word, "timeout") == 0) {
                        if (none || EMPTYSTR(arg))
                                continue;
--- ftpd.c.orig Sun Dec 27 20:54:01 1998
+++ ftpd.c      Wed Mar  8 12:27:33 2000
@@ -1579,7 +1579,10 @@
 passive()
 {
        int len;
+       int j;
+       int berror;
        char *p, *a;
+       struct in_addr pasv_advert;
 
        pdata = socket(AF_INET, SOCK_STREAM, 0);
        if (pdata < 0 || !logged_in) {
@@ -1587,19 +1590,44 @@
                return;
        }
        pasv_addr = ctrl_addr;
-       pasv_addr.sin_port = 0;
+       if (curclass.paddr) {
+               pasv_advert.s_addr = inet_addr(curclass.paddr);
+       } else {
+               pasv_advert.s_addr = pasv_addr.sin_addr.s_addr;
+       }
+
        (void) seteuid((uid_t)0);
-       if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
+
+       berror = -1;
+       errno = EADDRINUSE;
+       if (curclass.plow && curclass.phigh) {
+               for (j = curclass.phigh;
+                    (berror < 0) && (errno == EADDRINUSE) &&
+                        (j > curclass.plow);
+                    j--) {
+                       pasv_addr.sin_port = htons(j);
+                       berror = bind(pdata, (struct sockaddr *)&pasv_addr,
+                                       sizeof(pasv_addr));
+               }
+
+       } else {
+               pasv_addr.sin_port = 0;
+               berror = bind(pdata, (struct sockaddr *)&pasv_addr,
+                               sizeof(pasv_addr));
+       }
+
+       if (berror < 0) {
                (void) seteuid((uid_t)pw->pw_uid);
                goto pasv_error;
        }
+
        (void) seteuid((uid_t)pw->pw_uid);
        len = sizeof(pasv_addr);
        if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
                goto pasv_error;
        if (listen(pdata, 1) < 0)
                goto pasv_error;
-       a = (char *) &pasv_addr.sin_addr;
+       a = (char *) &pasv_advert;
        p = (char *) &pasv_addr.sin_port;
 
 #define UC(b) (((int) b) & 0xff)
--- ftpd.8.orig Wed Mar  8 12:18:50 2000
+++ ftpd.8      Wed Mar  8 12:24:33 2000
@@ -448,6 +448,13 @@
 or
 .Sy off
 is given, disallow passive (PASV) connections.  Otherwise, enable them.
+.It Sy paddr Ar class Op Sy inet addr
+When using the passive protocol, advertize this address as the inet
+address to connect: useful when the ftp server is mapped to a different
+network behind a firewall.
+.It Sy pports Ar class Op Sy low-high
+When using the passive protocol, use a port number within this range
+for the connection: useful in limiting port range opening at firewall.
 .It Sy timeout Ar class Ar time
 Set the inactivity timeout period.
 (the default is fifteen minutes).

>Audit-Trail:
>Unformatted: