summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpst <pst@FreeBSD.org>1995-08-05 19:12:05 +0000
committerpst <pst@FreeBSD.org>1995-08-05 19:12:05 +0000
commit0e79ca4d900784f6fb111f73eee3ea92efdc87be (patch)
tree0bb9b657884348aa946f639d6e015b17af89ad79
parentf87a14f2ec9b2da3dd881d031cc3eb22beded92e (diff)
downloadFreeBSD-src-0e79ca4d900784f6fb111f73eee3ea92efdc87be.zip
FreeBSD-src-0e79ca4d900784f6fb111f73eee3ea92efdc87be.tar.gz
Use data ports in the range 40000..44999 by default to enhance FTP usability
in a firewall environment. Original idea by Mark Tracy (?). Reviewed by: wollman Submitted by: pst
-rw-r--r--libexec/ftpd/Makefile1
-rw-r--r--libexec/ftpd/ftpd.88
-rw-r--r--libexec/ftpd/ftpd.c45
-rw-r--r--usr.bin/ftp/Makefile1
-rw-r--r--usr.bin/ftp/cmds.c12
-rw-r--r--usr.bin/ftp/cmdtab.c2
-rw-r--r--usr.bin/ftp/extern.h1
-rw-r--r--usr.bin/ftp/ftp.115
-rw-r--r--usr.bin/ftp/ftp.c55
-rw-r--r--usr.bin/ftp/ftp_var.h1
-rw-r--r--usr.bin/ftp/main.c7
11 files changed, 130 insertions, 18 deletions
diff --git a/libexec/ftpd/Makefile b/libexec/ftpd/Makefile
index adcc919..a218380 100644
--- a/libexec/ftpd/Makefile
+++ b/libexec/ftpd/Makefile
@@ -5,6 +5,7 @@ MAN8= ftpd.8
SRCS= ftpd.c ftpcmd.c logwtmp.c popen.c skey-stuff.c
CFLAGS+=-DSETPROCTITLE -DSKEY -DSTATS
+CFLAGS+=-DFTP_DATA_BOTTOM=40000 -DFTP_DATA_TOP=44999
LDADD= -lskey -lmd -lcrypt
DPADD= ${LIBSKEY} ${LIBMD} ${LIBCRYPT}
diff --git a/libexec/ftpd/ftpd.8 b/libexec/ftpd/ftpd.8
index 2471961..6e5b199 100644
--- a/libexec/ftpd/ftpd.8
+++ b/libexec/ftpd/ftpd.8
@@ -42,6 +42,7 @@ Internet File Transfer Protocol server
.Nm ftpd
.Op Fl dl
.Op Fl S
+.Op Fl U
.Op Fl T Ar maxtimeout
.Op Fl t Ar timeout
.Sh DESCRIPTION
@@ -74,6 +75,13 @@ logs all anonymous transfers to the file
.Pa /var/log/ftpd
when this file exists.
.
+.It Fl U
+In previous versions of
+.Nm ftpd ,
+when a passive mode client requested a data connection to the server,
+the server would use data ports in the range 1024..4999. Now, by default,
+the server will use data ports in the range 40000..44999. Specifying this
+option will revert to the old behavior.
.It Fl T
A client may also request a different timeout period;
the maximum period allowed may be set to
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index f6fc379..8776124 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: ftpd.c,v 1.9 1995/05/22 11:03:55 davidg Exp $
+ * $Id: ftpd.c,v 1.10 1995/05/30 05:45:58 rgrimes Exp $
*/
#ifndef lint
@@ -113,6 +113,7 @@ int debug;
int timeout = 900; /* timeout after 15 minutes of inactivity */
int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
int logging;
+int restricted_data_ports = 1;
int guest;
#ifdef STATS
int stats;
@@ -260,7 +261,7 @@ main(argc, argv, envp)
#ifdef STATS
while ((ch = getopt(argc, argv, "dlSt:T:u:v")) != EOF) {
#else
- while ((ch = getopt(argc, argv, "dlt:T:u:v")) != EOF) {
+ while ((ch = getopt(argc, argv, "dlUt:T:u:v")) != EOF) {
#endif
switch (ch) {
case 'd':
@@ -271,6 +272,10 @@ main(argc, argv, envp)
logging++; /* > 1 == extra logging */
break;
+ case 'U':
+ restricted_data_ports = 0;
+ break;
+
case 't':
timeout = atoi(optarg);
if (maxtimeout < timeout)
@@ -1518,6 +1523,7 @@ void
passive()
{
int len;
+ u_short port;
char *p, *a;
pdata = socket(AF_INET, SOCK_STREAM, 0);
@@ -1525,14 +1531,37 @@ passive()
perror_reply(425, "Can't open passive connection");
return;
}
- pasv_addr = ctrl_addr;
- pasv_addr.sin_port = 0;
- (void) seteuid((uid_t)0);
- if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
+
+ if (restricted_data_ports) {
+ for (port = FTP_DATA_BOTTOM; port <= FTP_DATA_TOP; port++) {
+ pasv_addr = ctrl_addr;
+ pasv_addr.sin_port = htons(port);
+ (void) seteuid((uid_t)0);
+ if (bind(pdata, (struct sockaddr *)&pasv_addr,
+ sizeof(pasv_addr)) < 0) {
+ (void) seteuid((uid_t)pw->pw_uid);
+ if (errno == EADDRINUSE)
+ continue;
+ else
+ goto pasv_error;
+ }
+ (void) seteuid((uid_t)pw->pw_uid);
+ break;
+ }
+ if (port > FTP_DATA_TOP)
+ goto pasv_error;
+ } else {
+ pasv_addr = ctrl_addr;
+ pasv_addr.sin_port = 0;
+ (void) seteuid((uid_t)0);
+ if (bind(pdata, (struct sockaddr *)&pasv_addr,
+ sizeof(pasv_addr)) < 0) {
+ (void) seteuid((uid_t)pw->pw_uid);
+ goto pasv_error;
+ }
(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;
diff --git a/usr.bin/ftp/Makefile b/usr.bin/ftp/Makefile
index dc8197f..e9d0a62 100644
--- a/usr.bin/ftp/Makefile
+++ b/usr.bin/ftp/Makefile
@@ -4,5 +4,6 @@ PROG= ftp
SRCS= cmds.c cmdtab.c ftp.c main.c ruserpass.c domacro.c
LINKS= ${BINDIR}/ftp ${BINDIR}/pftp
MLINKS= ftp.1 pftp.1
+CFLAGS+=-DFTP_DATA_BOTTOM=40000 -DFTP_DATA_TOP=44999
.include <bsd.prog.mk>
diff --git a/usr.bin/ftp/cmds.c b/usr.bin/ftp/cmds.c
index 34cca4c..9756042 100644
--- a/usr.bin/ftp/cmds.c
+++ b/usr.bin/ftp/cmds.c
@@ -2144,6 +2144,18 @@ setpassive()
}
/*
+ * Restrict FTP data port range to a high group of "safe" ports
+ */
+void
+setrestrict()
+{
+ restricted_data_ports = !restricted_data_ports;
+ printf("Data port range restrictions %s.\n",
+ onoff(restricted_data_ports));
+ code = restricted_data_ports;
+}
+
+/*
* get size of file on remote machine
*/
/*VARARGS*/
diff --git a/usr.bin/ftp/cmdtab.c b/usr.bin/ftp/cmdtab.c
index a55cd86..fd9afb2 100644
--- a/usr.bin/ftp/cmdtab.c
+++ b/usr.bin/ftp/cmdtab.c
@@ -90,6 +90,7 @@ char regethelp[] = "get file restarting at end of local file";
char remotehelp[] = "get help from remote server";
char renamehelp[] = "rename file";
char restarthelp[]= "restart file transfer at bytecount";
+char restricthelp[]= "toggle restriction of data port range";
char rmdirhelp[] = "remove directory on the remote machine";
char rmtstatushelp[]="show status of remote machine";
char runiquehelp[] = "toggle store unique for local files";
@@ -166,6 +167,7 @@ struct cmd cmdtab[] = {
{ "rename", renamehelp, 0, 1, 1, renamefile },
{ "reset", resethelp, 0, 1, 1, reset },
{ "restart", restarthelp, 1, 1, 1, restart },
+ { "restrict", restricthelp, 0, 0, 0, setrestrict },
{ "rmdir", rmdirhelp, 0, 1, 1, removedir },
{ "runique", runiquehelp, 0, 0, 1, setrunique },
{ "send", sendhelp, 1, 1, 1, put },
diff --git a/usr.bin/ftp/extern.h b/usr.bin/ftp/extern.h
index 30ba06b..fb9aecf 100644
--- a/usr.bin/ftp/extern.h
+++ b/usr.bin/ftp/extern.h
@@ -124,6 +124,7 @@ void setpassive __P(());
void setpeer __P((int, char **));
void setport __P((int, char **));
void setprompt __P((int, char **));
+void setrestrict __P(());
void setrunique __P((int, char **));
void setstruct __P((int, char **));
void setsunique __P((int, char **));
diff --git a/usr.bin/ftp/ftp.1 b/usr.bin/ftp/ftp.1
index 4790407..4a3df6a 100644
--- a/usr.bin/ftp/ftp.1
+++ b/usr.bin/ftp/ftp.1
@@ -45,6 +45,7 @@ file transfer program
.Op Fl d
.Op Fl i
.Op Fl n
+.Op Fl U
.Op Fl p
.Op Fl g
.Op Ar host
@@ -86,6 +87,8 @@ multiple file transfers.
Enables debugging.
.It Fl g
Disables file name globbing.
+.It Fl U
+Disable data port range restrictions.
.It Fl p
Enable passive mode operation for use behind connection filtering firewalls.
.El
@@ -733,6 +736,18 @@ On
.Ux
systems, marker is usually a byte
offset into the file.
+.It Ic restrict
+Toggle data port range restrictions.
+When not operating in passive mode, the
+.Nm ftp ,
+client program requests that the remote server open a connection back
+to the client host on a separate data port. In previous versions, that
+remote port fell in the range 1024..4999. However, most firewall setups
+filter that range of TCP ports because other services reside there.
+The default behavior now is for the client to request that the server
+connect back to the client using the port range 40000..44999. Firewall
+administrators can chose to allow TCP connections in that range, if they
+deem it to not be a security risk.
.It Ic rmdir Ar directory-name
Delete a directory on the remote machine.
.It Ic runique
diff --git a/usr.bin/ftp/ftp.c b/usr.bin/ftp/ftp.c
index 10327c5..137e8c2 100644
--- a/usr.bin/ftp/ftp.c
+++ b/usr.bin/ftp/ftp.c
@@ -1000,7 +1000,9 @@ initconn()
char *p, *a;
int result, len, tmpno = 0;
int on = 1;
+ int count;
u_long a1,a2,a3,a4,p1,p2;
+ static u_short last_port = FTP_DATA_BOTTOM;
if (passivemode) {
data = socket(AF_INET, SOCK_STREAM, 0);
@@ -1051,9 +1053,6 @@ initconn()
}
noport:
- data_addr = myctladdr;
- if (sendport)
- data_addr.sin_port = 0; /* let system pick one */
if (data != -1)
(void) close(data);
data = socket(AF_INET, SOCK_STREAM, 0);
@@ -1063,15 +1062,53 @@ noport:
sendport = 1;
return (1);
}
- if (!sendport)
- if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
+ data_addr = myctladdr;
+ if (sendport) {
+ if (restricted_data_ports) {
+ for (count = 0;
+ count < FTP_DATA_TOP-FTP_DATA_BOTTOM; count++) {
+ last_port++;
+ if (last_port < FTP_DATA_BOTTOM ||
+ last_port > FTP_DATA_TOP)
+ last_port = FTP_DATA_BOTTOM;
+
+ data_addr.sin_port = htons(last_port);
+ if (bind(data, (struct sockaddr *)&data_addr,
+ sizeof(data_addr)) < 0) {
+ if (errno == EADDRINUSE)
+ continue;
+ else {
+ warn("bind");
+ goto bad;
+ }
+ }
+ break;
+ }
+ if (count >= FTP_DATA_TOP-FTP_DATA_BOTTOM) {
+ perror("ftp: all data ports in use");
+ goto bad;
+ }
+ } else {
+ data_addr.sin_port = 0; /* use any port */
+ if (bind(data, (struct sockaddr *)&data_addr,
+ sizeof(data_addr)) < 0) {
+ warn("bind");
+ goto bad;
+ }
+ }
+ } else {
+ if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof (on)) < 0) {
warn("setsockopt (reuse address)");
goto bad;
}
- if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
- warn("bind");
- goto bad;
- }
+ if (bind(data, (struct sockaddr *)&data_addr,
+ sizeof (data_addr)) < 0) {
+ warn("bind");
+ goto bad;
+ }
+ }
+
if (options & SO_DEBUG &&
setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
warn("setsockopt (ignored)");
diff --git a/usr.bin/ftp/ftp_var.h b/usr.bin/ftp/ftp_var.h
index 5778f69..85895a8 100644
--- a/usr.bin/ftp/ftp_var.h
+++ b/usr.bin/ftp/ftp_var.h
@@ -67,6 +67,7 @@ int code; /* return/reply code for ftp command */
int crflag; /* if 1, strip car. rets. on ascii gets */
char pasv[64]; /* passive port for proxy data connection */
int passivemode; /* passive mode enabled */
+int restricted_data_ports; /* restrict data port range */
char *altarg; /* argv[1] with no shell-like preprocessing */
char ntin[17]; /* input translation table */
char ntout[17]; /* output translation table */
diff --git a/usr.bin/ftp/main.c b/usr.bin/ftp/main.c
index 7df165c..cca7a919 100644
--- a/usr.bin/ftp/main.c
+++ b/usr.bin/ftp/main.c
@@ -82,13 +82,14 @@ main(argc, argv)
interactive = 1;
autologin = 1;
passivemode = 0;
+ restricted_data_ports = 1;
cp = strrchr(argv[0], '/');
cp = (cp == NULL) ? argv[0] : cp+1;
if (strcmp(cp, "pftp") == 0)
passivemode = 1;
- while ((ch = getopt(argc, argv, "dginptv")) != EOF) {
+ while ((ch = getopt(argc, argv, "dginptvU")) != EOF) {
switch (ch) {
case 'd':
options |= SO_DEBUG;
@@ -119,6 +120,10 @@ main(argc, argv)
verbose++;
break;
+ case 'U':
+ restricted_data_ports = 0;
+ break;
+
default:
(void)fprintf(stderr,
"usage: ftp [-dginptv] [host [port]]\n");
OpenPOWER on IntegriCloud