Subject: Feature Request (passive mode port range)

From: Michael Douglass <[email-masked]>
Date: Sun, 16 Nov 1997 14:48:59 -0600

For those with an eye to security, I would like to request a feature.  The
feature is the ability to give a range of ports to use when setting up
PASV connections.  The reason is so that we can specify a very specific
range of ports and allow only those ports through our firewall.  Here
is quick hack that I did to beta 15 to give me this functionality.
(Note that I also am not using the seteuid() code in my section, as per
my previous email.)

Note: Instead of deleting the old bind() lines, I simply preprocessored
them out.

diff -c -r1.1 ftpd.c
*** /tmp/T0koRkq_       Sun Nov 16 14:47:28 1997
--- ftpd.c      Sun Nov 16 14:37:20 1997
***************
*** 3293,3298 ****
--- 3293,3300 ----
  #endif
      register char *p,
       *a;
+     long pport = 32000;
+     int  port_range = 1000;

  /* H* fix: if we already *have* a passive socket, close it first.  Prevents
     a whole variety of entertaining clogging attacks. */
***************
*** 3308,3313 ****
--- 3310,3316 ----
          return;
      }
      pasv_addr = ctrl_addr;
+ #if 0
      pasv_addr.sin_port = 0;
      delay_signaling(); /* we can't allow any signals while euid==0: kinch */
      (void) seteuid((uid_t) 0);                /* XXX: not needed if > 1024 */
***************
*** 3318,3323 ****
--- 3321,3338 ----
      }
      (void) seteuid((uid_t) pw->pw_uid);
      enable_signaling(); /* we can allow signals once again: kinch */
+ #else
+     for( ;port_range; port_range-- ) {
+         pasv_addr.sin_port = htons(pport + port_range);
+         if (bind(pdata, (struct sockaddr *) &pasv_addr, sizeof(pasv_addr)) < 0){
+             if( errno != EADDRINUSE ) {
+                 goto pasv_error;
+             }
+         } else {
+             break;
+         }
+     }
+ #endif
      len = sizeof(pasv_addr);
      if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
          goto pasv_error;

-- 
Michael Douglass
Texas Networking, Inc.

 "The past is a foreign country; they do things differently there."
      L. P. Hartley, British author. The Go-Between, Prologue (1953).

---

From: [email-masked]
Date: Mon, 17 Nov 1997 12:23:03 -0500 (EST)

Michael,
There is a patch available via the wuftp patch site that has exactly
what you are looking for. I have attached it below. I am using it now
with a change (not included) where I read the port numbers from the
ftpaccess file.

From: [email-masked] (Pedro Melo)
To: [email-masked]
Subject: Patch for passive mode in Beta12

Hi!

I've made a patch (check the attachment) for Beta12 that some of you might
find interesting. So far it is working ok.

When the client ask for PASV, the server must bind to a port and wait the
connection from the client. With the original code, the port would randomly
selected. This patch makes the ftpd bind to a port in a certain range
(defined at compile time for now).

What's the benefit? Basically I only have to open a certain range of ports
in my firewall to allow PASV mode to work.

If you find anything wrong with this patch, please let me know.

Thanks!

Melo

PS: the patch is to the file src/ftpd.c in beta12.
PS2: to change the range of port numbers you want, change PASSIVE_BASE 
     (base port) and PASSIVE_SPAN (number of ports to open). In my patch, I

     open 500 ports from 3000 to 3499
--
************** Pedro Melo ([email-masked]) BOFH ******************
*   TELENET, Servicos de Telecomunicacoes, SA - Tel +351 1 3139190   *
* finger [email-masked] or search key servers for PGP key *
*           It's management's job to support the geniuses,           *
*                      not to tell them what to do                   *
**********************************************************************

----=_32f772a74898931990505dbd9.MFSBCHJLHS
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

*** ftpd.c.orig	Tue Feb  4 17:11:09 1997
--- ftpd.c	Tue Feb  4 17:09:25 1997
***************
*** 396,401 ****
--- 396,403 ----
      struct sockaddr_in *virtual_ptr;
  #endif
  
+     srandom(getpid());
+ 
  #ifdef AUX
      setcompat(COMPAT_POSIX | COMPAT_BSDSETUGID);
  #endif
***************
*** 3212,3217 ****
--- 3214,3222 ----
   * response by Jon Postel in a telephone conversation with Rick Adams on 25
   * Jan 89. */
  
+ #define PASSIVE_BASE 3000
+ #define PASSIVE_SPAN 500
+ 
  void
  #ifdef __STDC__
  passive(void)
***************
*** 3219,3225 ****
  passive()
  #endif
  {
!     int len;
      register char *p,
       *a;
  
--- 3224,3230 ----
  passive()
  #endif
  {
!     int len, bind_error;
      register char *p,
       *a;
  
***************
*** 3234,3247 ****
          return;
      }
      pasv_addr = ctrl_addr;
!     pasv_addr.sin_port = 0;
      delay_signaling(); /* we can't allow any signals while euid==0: kinch */
      (void) seteuid((uid_t) 0);		/* XXX: not needed if > 1024 */
!     if (bind(pdata, (struct sockaddr *) &pasv_addr, sizeof(pasv_addr)) < 0) {
!         (void) seteuid((uid_t) pw->pw_uid);
!         enable_signaling(); /* we can allow signals once again: kinch */
!         goto pasv_error;
      }
      (void) seteuid((uid_t) pw->pw_uid);
      enable_signaling(); /* we can allow signals once again: kinch */
      len = sizeof(pasv_addr);
--- 3239,3259 ----
          return;
      }
      pasv_addr = ctrl_addr;
! 
      delay_signaling(); /* we can't allow any signals while euid==0: kinch */
      (void) seteuid((uid_t) 0);		/* XXX: not needed if > 1024 */
!     do {
! 	pasv_addr.sin_port = PASSIVE_BASE + random() % PASSIVE_SPAN;
! 	if (log_commands) syslog(LOG_DEBUG, "PASV trying %d", pasv_addr.sin_port);
! 	bind_error = bind(pdata, (struct sockaddr *) &pasv_addr, sizeof(pasv_addr));
!     } while(errno==EADDRINUSE);
!     if (bind_error < 0) {
!        	(void) seteuid((uid_t) pw->pw_uid);
!        	enable_signaling(); /* we can allow signals once again: kinch */
!        	goto pasv_error;
      }
+     if (log_commands) syslog(LOG_DEBUG, "PASV got %d", pasv_addr.sin_port);
+ 
      (void) seteuid((uid_t) pw->pw_uid);
      enable_signaling(); /* we can allow signals once again: kinch */
      len = sizeof(pasv_addr);

----=_32f772a74898931990505dbd9.MFSBCHJLHS--

-- 
Doug Courtney
[email-masked]
(732)576-5572