Subject: bin/12558: ftpd(8) sometimes make PORT command error.
To: None <gnats-bugs@gnats.netbsd.org>
From: Takahiro Kambe <taca@sky.yamashina.kyoto.jp>
List: netbsd-bugs
Date: 04/05/2001 23:42:58
>Number:         12558
>Category:       bin
>Synopsis:       ftpd(8) sometimes make PORT command error.
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Apr 05 07:44:00 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Takahiro Kambe
>Release:        NetBSD-current 2001/4/1
>Organization:
	
>Environment:
	
System: NetBSD edge.sky.yamashina.kyoto.jp 1.5T NetBSD 1.5T (CF-M33) #115: Sun Apr 1 16:23:27 JST 2001 taca@edge.sky.yamashina.kyoto.jp:/usr/src/sys/arch/i386/compile/CF-M33 i386
Architecture: i386
Machine: i386
>Description:
	ftpd(8) sometimes make PORT command error, even if address and port
	have no problem.
>How-To-Repeat:
	With a line bellow in /etc/ftpd.conf:

	checkportcmd all

	Try connect localhost, and repeat chdir and dir.

>Fix:
	At line 1800 in ftpcmd.y, checkport() try to compare IPv4 address,
	but it really compare length of sockaddr.

	The patch bellow also contains logging why checkport() made it error.

--- ftpcmd.y.orig	Thu Apr  5 23:25:59 2001
+++ ftpcmd.y	Thu Apr  5 23:26:38 2001
@@ -1782,24 +1782,53 @@ port_check(const char *cmd, int family)
 	}
 
 	if (family != -1 && his_addr.su_family != family) {
+		syslog(LOG_DEBUG,
+			"port_check: %d is different family from me %d",
+			his_addr.su_family, family);
  port_check_fail:
 		reply(500, "Illegal %s command rejected", cmd);
 		return;
 	}
 
-	if (data_dest.su_family != his_addr.su_family)
+	if (data_dest.su_family != his_addr.su_family) {
+		syslog(LOG_DEBUG,
+			"port_check: data %d is different family from his %d",
+			data_dest.su_family, his_addr.su_family);
 		goto port_check_fail;
+	}
 
 			/* be paranoid, if told so */
 	if (CURCLASS_FLAGS_ISSET(checkportcmd)) {
-		if ((ntohs(data_dest.su_port) < IPPORT_RESERVED) ||
-		    (data_dest.su_len != his_addr.su_len))
+		if ((ntohs(data_dest.su_port) < IPPORT_RESERVED)) {
+			syslog(LOG_DEBUG,
+				"port_check: request reserved port",
+				ntohs(data_dest.su_port));
+			goto port_check_fail;
+		}
+		if (data_dest.su_len != his_addr.su_len) {
+			syslog(LOG_DEBUG,
+				"port_check: su_len mis-match %d and %d",
+				data_dest.su_len, his_addr.su_len);
 			goto port_check_fail;
+		}
+
 		switch (data_dest.su_family) {
 		case AF_INET:
 			if (memcmp(&data_dest.su_addr, &his_addr.su_addr,
-			    data_dest.su_len) != 0)
+			    sizeof(his_addr.su_addr)) != 0) {
+				char *s, *t;
+
+				s = inet_ntoa(data_dest.su_addr);
+				t = inet_ntoa(his_addr.su_addr);
+				syslog(LOG_DEBUG,
+					"port_check: address mismatch %s and %s",
+					(s)? s: "(unknown)",
+					(t)? t: "(unknown)");
+				syslog(LOG_DEBUG,
+					"port_check: length was %d",
+					data_dest.su_len);
 				goto port_check_fail;
+			}
 			break;
 #ifdef INET6
 		case AF_INET6:
@@ -1811,6 +1840,9 @@ port_check(const char *cmd, int family)
 			break;
 #endif
 		default:
+			syslog(LOG_DEBUG,
+				"port_check: unknown family %d",
+				data_dest.su_family);
 			goto port_check_fail;
 		}
 	}
>Release-Note:
>Audit-Trail:
>Unformatted: