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:
parent
0a06628ab2
commit
4c450ad7a7
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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 },
|
||||
|
@ -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 **));
|
||||
|
@ -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
|
||||
|
@ -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)");
|
||||
|
@ -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 */
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user