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
This commit is contained in:
Paul Traina 1995-08-05 19:12:05 +00:00
parent 0a06628ab2
commit 4c450ad7a7
11 changed files with 130 additions and 18 deletions

View File

@ -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}

View File

@ -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

View File

@ -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;

View File

@ -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>

View File

@ -2143,6 +2143,18 @@ setpassive()
code = passivemode;
}
/*
* 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
*/

View File

@ -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 },

View File

@ -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 **));

View File

@ -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

View File

@ -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 @@ initconn()
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)");

View File

@ -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 */

View File

@ -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");