Subject: bin/34658: [dM] identd truncates queries to first segment
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
List: netbsd-bugs
Date: 09/29/2006 07:10:00
>Number:         34658
>Category:       bin
>Synopsis:       [dM] identd truncates queries to first segment
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Sep 29 07:10:00 +0000 2006
>Originator:     der Mouse
>Release:        NetBSD 4.99.1, i386 snapshot of 09-06 or shortly before
>Organization:
	Dis-
>Environment:
	NetBSD-current/i386, but any using Peter Postma's identd, at
	least as of identd.c,v 1.29.
>Description:
	identd does not read the entire query before responding, unless
	it all happens to come in fast enough to get returned by a
	single recv() (which basically means, all in a single packet).
	This leads to corrupted queries if the sender is slow.
>How-To-Repeat:
	Send a query other than all at once.  For example, here's a
	query that works, because it's all sent at once:

	% echo 22,51851^M | nc 10.0.1.22 113
	22,51851:USERID:UNIX:root

	whereas here's one that doesn't:

	% (echo -n 22, ; sleep 1 ; echo 51851^M) | nc 10.0.1.22 113
	0,0:ERROR:INVALID-PORT

	(the response comes back before the sleep finishes,
	demonstrating even more clearly that identd isn't waiting).
>Fix:
	This is relative to identd.c,v 1.29.
--- identd.c.orig	2006-09-29 03:03:09.000000000 -0400
+++ identd.c	2006-09-29 03:03:15.000000000 -0400
@@ -325,6 +325,7 @@
 	socklen_t len;
 	uid_t uid;
 	ssize_t n;
+	ssize_t qlen;
 
 	lport = fport = 0;
 
@@ -352,14 +353,25 @@
 	}
 
 	/* Receive data from the client. */
-	if ((n = recv(fd, buf, sizeof(buf) - 1, 0)) < 0) {
-		fatal("recv");
-	} else if (n == 0) {
-		maybe_syslog(LOG_NOTICE, "recv: EOF");
-		iderror(fd, 0, 0, "UNKNOWN-ERROR");
-		return 1;
+	qlen = 0;
+	while (1) {
+		if ((n = recv(fd, &buf[qlen], sizeof(buf)-qlen, 0)) < 0) {
+			fatal("recv");
+		} else if (n == 0) {
+			maybe_syslog(LOG_NOTICE, "recv: EOF");
+			iderror(fd, 0, 0, "UNKNOWN-ERROR");
+			return 1;
+		}
+		/* 1413 is not clear on what to do if data follows the first
+		   CRLF before we respond.  We do not consider the query
+		   complete until we get a CRLF _at the end of the buffer_. */
+		qlen += n;
+		if ( (qlen >= 2) &&
+		     (buf[qlen-2] == '\r') &&
+		     (buf[qlen-1] == '\n') )
+			break;
 	}
-	buf[n] = '\0';
+	buf[qlen-2] = '\0';
 
 	/* Get local and remote ports from the received data. */
 	p = buf;

/~\ The ASCII				der Mouse
\ / Ribbon Campaign
 X  Against HTML	       mouse@rodents.montreal.qc.ca
/ \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B