-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


        Sup all?

        In light of the recent WU-ftpd exploits and general security
concearns, I decided to change to a different ftpd.(duh)  The largest
feature about wu-ftpd that I needed was the ability to specify the passive
port range so as to be able to write firewall rulesets with default deny
and only a small range of open ports for passive ftp.

        I decided to integrate the suppport for that into freebsd's native
ftpd so that I could use an ftpd that I had faith in.  So here it
is.  These patches are against a brand new -stable so they should work
well.  Flames, Praise, Wine are all welcome ;) (nothing like the napa
valley or a good aussie red)

        I even updated the man page for easy integration.

        If somebody commits this, please tell me...

thanks

Visigoth


Damieon Stark
Sr. Unix Systems Administrator
[EMAIL PROTECTED]

PGP Public Key: www.telemere.net/~visigoth/visigoth.asc

____________________________________________________________________________
                                        |
M$ -Where do you want to go today?      |
Linux -Where do you want to go tomorrow?|   FreeBSD - The POWER to serve
Freebsd -Are you guys comming or what?  |   http://www.freebsd.org
                                        |
                                        |
- ----------------------------------------------------------------------------

-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 5.0i for non-commercial use
Charset: noconv

iQA/AwUBOVocbjnmC/+RTnGeEQLFUgCg5sKoRD2gj7P+hIssj4zujPgdd/IAoLPk
xosQMqmtehAjA6sQb8/DjTI7
=zbKS
-----END PGP SIGNATURE-----
--- /usr/src/libexec/ftpd/ftpd.c.old    Wed Jun 28 10:08:42 2000
+++ /usr/src/libexec/ftpd/ftpd.c        Wed Jun 28 09:49:05 2000
@@ -125,8 +125,9 @@
 union sockunion his_addr;
 union sockunion pasv_addr;
 
 int    daemon_mode;
+int     pass_port_opt,min_pport,max_pport;
 int    data;
 jmp_buf        errcatch, urgcatch;
 int    logged_in;
 struct passwd *pw;
@@ -158,8 +159,9 @@
 char   tmpline[7];
 char   *hostname;
 #ifdef VIRTUAL_HOSTING
 char   *ftpuser;
+char    *opt_ptr;
 
 int    epsvall = 0;
 
 static struct ftphost {
@@ -289,9 +291,9 @@
        LastArgv = envp[-1] + strlen(envp[-1]);
 #endif /* OLD_SETPROCTITLE */
 
 
-       while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:46")) != -1) {
+       while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:P:46")) != -1) {
                switch (ch) {
                case 'D':
                        daemon_mode++;
                        break;
@@ -335,8 +337,21 @@
                case 'p':
                        pid_file = optarg;
                        break;
 
+                case 'P':
+                        pass_port_opt++;
+                        if((min_pport = strtod(optarg, &opt_ptr )) == 0 )
+                        errx(1,"Unrecognized passive port number!\n");
+      
+                        opt_ptr++;
+                        if((max_pport = strtod(opt_ptr,NULL)) == 0 )
+                        errx(1,"Unrecognized passive port number!\n");
+                        
+                        if( min_pport > max_pport )
+                        errx(1,"Portrange from %d to %d 
+invalid!\n",min_pport,max_pport);
+                        break;
+
                case 'u':
                    {
                        long val = 0;
 
@@ -2323,9 +2338,9 @@
  */
 void
 passive()
 {
-       int len;
+       int len,next;
        char *p, *a;
 
        if (pdata >= 0)         /* close old port if one set */
                close(pdata);
@@ -2337,33 +2352,57 @@
        }
 
        (void) seteuid((uid_t)0);
 
+        if (pass_port_opt < 1) {  /* if passive ports are in use don't bother
+                                with IP[V6]_PORTRANGE.  Doesn't affect port
+                                asignment, but saves little cpu? ;) */
+
 #ifdef IP_PORTRANGE
-       if (ctrl_addr.su_family == AF_INET) {
-           int on = restricted_data_ports ? IP_PORTRANGE_HIGH
+           if (ctrl_addr.su_family == AF_INET) {
+               int on = restricted_data_ports ? IP_PORTRANGE_HIGH
                                           : IP_PORTRANGE_DEFAULT;
 
-           if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
+               if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
                            (char *)&on, sizeof(on)) < 0)
                    goto pasv_error;
-       }
+           }
 #endif
 #ifdef IPV6_PORTRANGE
-       if (ctrl_addr.su_family == AF_INET6) {
-           int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH
+           if (ctrl_addr.su_family == AF_INET6) {
+               int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH
                                           : IPV6_PORTRANGE_DEFAULT;
 
-           if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
+               if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
                            (char *)&on, sizeof(on)) < 0)
                    goto pasv_error;
-       }
+           }
 #endif
-
+       }
        pasv_addr = ctrl_addr;
-       pasv_addr.su_port = 0;
-       if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) < 0)
+
+        if (pass_port_opt) {
+            for(next = min_pport; next <= max_pport; next++) {
+                pasv_addr.su_port = htons(next);
+                if (bind(pdata, (struct sockaddr *)&pasv_addr,
+                                        pasv_addr.su_len) < 0 ) {
+                    if (errno == EADDRINUSE )
+                        continue; /* try next available passive port */
+                    else
+                        goto pasv_error; /* error other than EADDRINUSE! */
+                }
+                break;                  /* bind() success */
+            }
+            if ( next > max_pport )
+                goto pasv_error;    /* unsuccessful at getting pasv port */
+
+        } else {             /* not specifying passive port range */
+
+
+           pasv_addr.su_port = 0;
+           if (bind(pdata, (struct sockaddr *)&pasv_addr,pasv_addr.su_len) < 0)
                goto pasv_error;
+       }
 
        (void) seteuid((uid_t)pw->pw_uid);
 
        len = sizeof(pasv_addr);
@@ -2405,9 +2444,9 @@
 long_passive(cmd, pf)
        char *cmd;
        int pf;
 {
-       int len;
+       int len,next;
        char *p, *a;
 
        if (pdata >= 0)         /* close old port if one set */
                close(pdata);
@@ -2446,35 +2485,59 @@
        }
 
        (void) seteuid((uid_t)0);
 
-       pasv_addr = ctrl_addr;
-       pasv_addr.su_port = 0;
-       len = pasv_addr.su_len;
+       if (pass_port_opt < 1) {  /* if passive ports are in use don't bother
+                                with IP_PORTRANGE.  Doesn't affect port
+                                asignment, but saves little cpu? ;) */
 
 #ifdef IP_PORTRANGE
-       if (ctrl_addr.su_family == AF_INET) {
-           int on = restricted_data_ports ? IP_PORTRANGE_HIGH
+           if (ctrl_addr.su_family == AF_INET) {
+               int on = restricted_data_ports ? IP_PORTRANGE_HIGH
                                           : IP_PORTRANGE_DEFAULT;
 
-           if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
+               if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
                            (char *)&on, sizeof(on)) < 0)
                    goto pasv_error;
-       }
+           }
 #endif
 #ifdef IPV6_PORTRANGE
-       if (ctrl_addr.su_family == AF_INET6) {
-           int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH
+           if (ctrl_addr.su_family == AF_INET6) {
+               int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH
                                           : IPV6_PORTRANGE_DEFAULT;
 
-           if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
+               if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
                            (char *)&on, sizeof(on)) < 0)
                    goto pasv_error;
-       }
+           }
 #endif
+       }
+
+       pasv_addr = ctrl_addr;
+       len = pasv_addr.su_len;
+
+        if (pass_port_opt) {
+            for(next = min_pport; next <= max_pport; next++) {
+                pasv_addr.su_port = htons(next);
+                if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0 ) {
+                    if (errno == EADDRINUSE )
+                        continue; /* try next available passive port */
+                    else
+                        goto pasv_error; /* error other than EADDRINUSE! */
+                }
+                break;                  /* bind() success */
+            }
+            if ( next > max_pport )
+                goto pasv_error;    /* unsuccessful at getting pasv port */
+
+        } else {             /* not specifying passive port range */
 
-       if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0)
+
+           pasv_addr.su_port = 0;
+           if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0)
                goto pasv_error;
+
+       }
 
        (void) seteuid((uid_t)pw->pw_uid);
 
        if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
--- /usr/src/libexec/ftpd/ftpd.8.old    Wed Jun 28 10:11:14 2000
+++ /usr/src/libexec/ftpd/ftpd.8        Wed Jun 28 10:21:39 2000
@@ -53,8 +53,9 @@
 .Op Fl T Ar maxtimeout
 .Op Fl t Ar timeout
 .Op Fl a Ar address
 .Op Fl p Ar file
+.Op Fl P Ar minport-maxport
 .Sh DESCRIPTION
 .Nm Ftpd
 is the
 Internet File Transfer Protocol
@@ -122,8 +123,17 @@
 seconds with the
 .Fl T
 option.
 The default limit is 2 hours.
+.It Fl P
+With this option set
+.Nm
+allows the administrator to specify a range of ports 
+.Ar minport-maxport
+to be used for
+incomming passive data connections.  This allows a default deny firewall
+on an ftp server to just allow a range of ports, and tightens up security in
+general.
 .It Fl t
 The inactivity timeout period is set to
 .Ar timeout
 seconds (the default is 15 minutes).

Reply via email to