Subject: bin/9158: Allow ftpd(8) tp specify passive port range.
To: None <gnats-bugs@gnats.netbsd.org>
From: Takahiro Kambe <taca@sky.yamashina.kyoto.jp>
List: netbsd-bugs
Date: 01/10/2000 04:22:00
>Number:         9158
>Category:       bin
>Synopsis:       Allow ftpd(8) tp specify passive port range.
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Mon Jan 10 04:20:59 2000
>Last-Modified:
>Originator:     Takahiro Kambe
>Organization:
	
>Release:        NetBSD-current 2000/01/09
>Environment:
	
System: NetBSD land.sky.yamashina.kyoto.jp 1.4P NetBSD 1.4P (LAND) #167: Mon Jan 10 11:08:46 JST 2000 taca@land.sky.yamashina.kyoto.jp:/usr/src/sys/arch/i386/compile/LAND i386


>Description:
	Allow ftpd(8) tp specify passive port range.
	It makes easy to write access list of a router.
>How-To-Repeat:
	Not a bug.
>Fix:
	Attached diff is a sample fix.

Index: libexec/extern.h
diff -u libexec/extern.h.orig libexec/extern.h
--- extern.h.orig	Sun Jan  9 03:42:21 2000
+++ extern.h	Mon Jan 10 20:02:49 2000
@@ -159,6 +159,9 @@
 
 struct ftpclass {
 	int		 checkportcmd;	/* Check PORT commands are valid */
+	int		 passive_port;	/* next passive port */
+	int		 pasv_port_min;	/* minumum port number for passive mode */
+	int		 pasv_port_max;	/* maximum port number for passive mode */
 	char		*classname;	/* Current class */
 	struct ftpconv	*conversions;	/* List of conversions */
 	char		*display;	/* Files to display upon chdir */
Index: libexec/conf.c
diff -u libexec/conf.c.orig libexec/conf.c
--- conf.c.orig	Mon Jan 10 01:51:56 2000
+++ conf.c	Mon Jan 10 20:17:54 2000
@@ -89,6 +89,9 @@
 		free(conv);
 	}
 	curclass.checkportcmd = 0;
+	curclass.passive_port = 0;
+	curclass.pasv_port_min = 0;
+	curclass.pasv_port_max = 0;
 	REASSIGN(curclass.classname, NULL);
 	curclass.conversions =	NULL;
 	REASSIGN(curclass.display, NULL);
@@ -127,6 +130,7 @@
 	size_t		 line;
 	unsigned int	 timeout;
 	struct ftpconv	*conv, *cnext;
+	int		port_min, port_max;
 
 	init_curclass();
 	REASSIGN(curclass.classname, xstrdup(findclass));
@@ -189,6 +193,30 @@
 				}
 			}
 
+		} else if (strcasecmp(word, "passive_port_range") == 0) {
+			if (!none && !EMPTYSTR(arg)) {
+				port_min = atoi(arg);
+				NEXTWORD(p, arg);
+				if (EMPTYSTR(arg)) {
+					syslog(LOG_WARNING,
+					       "%s line %d: port range format error",
+					       infile, (int)line);
+					continue;
+				}
+				port_max = atoi(arg);
+				if (port_min <= IPPORT_RESERVED ||
+				    port_max <= IPPORT_RESERVED ||
+				    port_min > IPPORT_ANONMAX ||
+				    port_max > IPPORT_ANONMAX ||
+				    port_min >= port_max) {
+					syslog(LOG_WARNING,
+					       "%s line %d: port range value error",
+					       infile, (int)line);
+					continue;
+				}
+				curclass.pasv_port_min = port_min;
+				curclass.pasv_port_max = port_max;
+			}
 		} else if (strcasecmp(word, "conversion") == 0) {
 			char *suffix, *types, *disable, *convcmd;
 
Index: libexec/ftpd.c
diff -u libexec/ftpd.c.orig libexec/ftpd.c
--- ftpd.c.orig	Sun Jan  9 03:42:21 2000
+++ ftpd.c	Mon Jan 10 20:04:11 2000
@@ -2239,6 +2239,7 @@
 {
 	int len;
 	char *p, *a;
+	int port;
 
 	if (pdata >= 0)
 		close(pdata);
@@ -2248,10 +2249,33 @@
 		return;
 	}
 	pasv_addr = ctrl_addr;
-	pasv_addr.su_port = 0;
 	len = pasv_addr.su_len;
-	if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0) {
-		goto pasv_error;
+	if (curclass.pasv_port_min == 0 && curclass.pasv_port_max == 0) {
+		pasv_addr.su_port = 0;
+		if (bind(pdata, (struct sockaddr *)&pasv_addr, len) == 0)
+			goto pasv_error;
+	} else {
+		if (curclass.passive_port == 0) {
+#ifdef NO_RANDOM_INIT
+			curclass.passive_port = curclass.pasv_port_min;
+#else
+			srand(getpid());
+			curclass.passive_port = rand() % (curclass.pasv_port_max - curclass.pasv_port_min) + curclass.pasv_port_min;
+#endif
+		}
+		port = curclass.passive_port;
+		pasv_addr.su_port = htons(port);
+		while (bind(pdata, (struct sockaddr *)&pasv_addr, len) != 0) {
+			if (errno != EADDRINUSE)
+				goto pasv_error;
+			port++;
+			if (port > curclass.pasv_port_max)
+				port = curclass.pasv_port_min;
+			else if (port == curclass.passive_port)
+				goto pasv_error;
+			pasv_addr.su_port = htons(port);
+		}
+		curclass.passive_port = port;
 	}
 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
 		goto pasv_error;
@@ -2282,6 +2306,7 @@
 {
 	int len;
 	register char *p, *a;
+	int port;
 
 	if (!logged_in) {
 		syslog(LOG_NOTICE, "long passive but not logged in");
@@ -2324,9 +2349,33 @@
 		return;
 	}
 	pasv_addr = ctrl_addr;
-	pasv_addr.su_port = 0;
-	if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0) {
-		goto pasv_error;
+	if (curclass.pasv_port_min == 0 && curclass.pasv_port_max == 0) {
+		pasv_addr.su_port = 0;
+		if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0) {
+			goto pasv_error;
+		}
+	} else {
+		if (curclass.passive_port == 0) {
+#ifdef NO_RANDOM_INIT
+			curclass.passive_port = curclass.pasv_port_min;
+#else
+			srand(getpid());
+			curclass.passive_port = rand() % (curclass.pasv_port_max - curclass.pasv_port_min) + curclass.pasv_port_min;
+#endif
+		}
+		port = curclass.passive_port;
+		pasv_addr.su_port = htons(port);
+		while (bind(pdata, (struct sockaddr *)&pasv_addr, len) != 0) {
+			if (errno != EADDRINUSE)
+				goto pasv_error;
+			port++;
+			if (port > curclass.pasv_port_max)
+				port = curclass.pasv_port_min;
+			else if (port == curclass.passive_port)
+				goto pasv_error;
+			pasv_addr.su_port = htons(port);
+		}
+		curclass.passive_port = port;
 	}
 	len = pasv_addr.su_len;
 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
Index: libexec/ftpd.conf.5
diff -u libexec/ftpd.conf.5.orig libexec/ftpd.conf.5
--- ftpd.conf.5.orig	Mon Jan 10 01:51:56 2000
+++ ftpd.conf.5	Mon Jan 10 21:10:29 2000
@@ -116,6 +116,14 @@
 or
 .Sy off
 is given, disable this feature, otherwise enable it.
+.It Sy passive_port_range Ar class Sy min Sy max
+Set the range of port number, which will be used for passive data 
+port.
+.Sy max
+must be greater than
+.Sy min
+and those number must be greater than
+.Dv IPPORT_RESERVED .
 .It Sy classtype Ar class Ar type
 Set the class type of
 .Ar class
>Audit-Trail:
>Unformatted: