-----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).