From nobody@FreeBSD.org  Mon Aug 29 19:28:51 2011
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id B9C9E106564A
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 29 Aug 2011 19:28:51 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id 90B818FC14
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 29 Aug 2011 19:28:51 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id p7TJSpJT072573
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 29 Aug 2011 19:28:51 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id p7TJSp5i072572;
	Mon, 29 Aug 2011 19:28:51 GMT
	(envelope-from nobody)
Message-Id: <201108291928.p7TJSp5i072572@red.freebsd.org>
Date: Mon, 29 Aug 2011 19:28:51 GMT
From: Dylan Simon <dylan@dylex.net>
To: freebsd-gnats-submit@FreeBSD.org
Subject: ypserv -P [bin/109494] breaks tcp
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         160295
>Category:       bin
>Synopsis:       [patch] ypserv(8): ypserv -P [bin/109494] breaks tcp
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    hrs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Aug 29 19:30:15 UTC 2011
>Closed-Date:    
>Last-Modified:  Tue Aug 21 02:42:19 UTC 2012
>Originator:     Dylan Simon
>Release:        7.4
>Organization:
NYU
>Environment:
FreeBSD lust.cns.nyu.edu 7.4-RELEASE-p2 FreeBSD 7.4-RELEASE-p2 #14: Sun Jul 24 18:28:27 EDT 2011     dylan@lust.cns.nyu.edu:/usr/obj/usr/src/sys/SIN  amd64
>Description:
The -P argument to ypserv breaks NIS over TCP.  After starting
ypserv -P 666 I see:

tcp4       0      0 *.666                  *.*                    CLOSED

From the code ( http://svnweb.freebsd.org/base/stable/7/usr.sbin/ypserv/yp_main.c?r1=172506&r2=177753 )
the problem is rather obvious: the sock variable is used for both the
udp and tcp sockets, and so while transp = svcudp_create(sock); works
fine (after losing the tcp socket), transp = svctcp_create(sock, 0, 0);
doesn't work at all on the already open udp socket.

Here are the relevant calls.  Notice fd 4 is never touched again:
socket(PF_INET,SOCK_STREAM,0)                    = 4 (0x4)
bind(4,{ AF_INET 0.0.0.0:666 },16)               = 0 (0x0)
socket(PF_INET,SOCK_DGRAM,0)                     = 5 (0x5)
bind(5,{ AF_INET 0.0.0.0:666 },16)               = 0 (0x0)
getsockopt(0x5,0x0,0x13,0x7fffffffe4ec,0x7fffffffe4e0,0x7fffffffe340) = 0 (0x0)
setsockopt(0x5,0x0,0x13,0x7fffffffe4e8,0x4,0x7fffffffe458) = 0 (0x0)
bind(5,{ AF_INET 0.0.0.0:0 },16)                 ERR#22 'Invalid argument'
setsockopt(0x5,0x0,0x13,0x7fffffffe4ec,0x4,0x7fffffffe458) = 0 (0x0)
listen(0x5,0x80,0x13,0x8007dd42c,0xffffff80ec8b4d40,0x7fffffffe458) ERR#45 'Operation not supported'
getsockopt(0x5,0x0,0x13,0x7fffffffe4ec,0x7fffffffe4e0,0x800a00728) = 0 (0x0)
setsockopt(0x5,0x0,0x13,0x7fffffffe4e8,0x4,0x7fffffffe458) = 0 (0x0)
bind(5,{ AF_INET 0.0.0.0:0 },16)                 ERR#22 'Invalid argument'
setsockopt(0x5,0x0,0x13,0x7fffffffe4ec,0x4,0x7fffffffe458) = 0 (0x0)
listen(0x5,0x80,0x13,0x8007dd42c,0xffffff80ec8b4d40,0x7fffffffe458) ERR#45 'Operation not supported'
>How-To-Repeat:
Run ypserv -P <port>
Perform TCP NIS request from client
>Fix:
Use a different variable for each socket.

>Release-Note:
>Audit-Trail:

From: Dylan Alex Simon <dylan@dylex.net>
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/160295: ypserv -P [bin/109494] breaks tcp
Date: Tue, 30 Aug 2011 12:15:19 -0400

 --6TrnltStXW4iwmi0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 Attached is a patch that seems to work.  However, there seems to be another
 bug using ypserv -d where it exits ypproc_all_2_svc at the end even though it
 hasn't forked (PR #10970 collateral?), so I can't test completely.  (I'm
 trying to get automount maps in linux to pull from FreeBSD NIS, which still
 isn't working.)
 
 --6TrnltStXW4iwmi0
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename="yp_main.c.diff"
 
 --- yp_main.c.orig	2011-08-30 11:15:33.595224119 -0400
 +++ yp_main.c	2011-08-30 11:15:21.375092957 -0400
 @@ -84,16 +84,6 @@
  int do_dns = 0;
  int resfd;
  
 -struct socktype {
 -	const char *st_name;
 -	int	   st_type;
 -};
 -static struct socktype stlist[] = {
 -	{ "tcp", SOCK_STREAM },
 -	{ "udp", SOCK_DGRAM },
 -	{ NULL, 0 }
 -};
 -
  static
  void _msgout(char* msg)
  {
 @@ -235,14 +225,13 @@
  main(int argc, char *argv[])
  {
  	register SVCXPRT *transp = NULL;
 -	int sock;
 +	int sock_udp = -1, sock_tcp = -1;
  	int proto = 0;
  	struct sockaddr_in saddr;
  	socklen_t asize = sizeof (saddr);
  	int ch;
  	in_port_t yp_port = 0;
  	char *errstr;
 -	struct socktype *st;
  
  	while ((ch = getopt(argc, argv, "hdnp:P:")) != -1) {
  		switch (ch) {
 @@ -282,7 +271,10 @@
  		if (getsockopt(0, SOL_SOCKET, SO_TYPE,
  				(char *)&_rpcfdtype, &ssize) == -1)
  			exit(1);
 -		sock = 0;
 +		if (_rpcfdtype == SOCK_DGRAM)
 +			sock_udp = 0;
 +		else if (_rpcfdtype == SOCK_STREAM)
 +			sock_tcp = 0;
  		_rpcpmstart = 1;
  		proto = 0;
  		openlog("ypserv", LOG_PID, LOG_DAEMON);
 @@ -293,46 +285,49 @@
  			}
  			openlog("ypserv", LOG_PID, LOG_DAEMON);
  		}
 -		sock = RPC_ANYSOCK;
 +		sock_udp = sock_tcp = RPC_ANYSOCK;
  		(void) pmap_unset(YPPROG, YPVERS);
  		(void) pmap_unset(YPPROG, 1);
  	}
  
  	/*
  	 * Initialize TCP/UDP sockets.
 +	 * Really should only do this if !_rpcpmstart.
  	 */
 -	memset((char *)&saddr, 0, sizeof(saddr));
 -	saddr.sin_family = AF_INET;
 -	saddr.sin_addr.s_addr = htonl(INADDR_ANY);
 -	saddr.sin_port = htons(yp_port);
 -	for (st = stlist; st->st_name != NULL; st++) {
 -		/* Do not bind the socket if the user didn't specify a port */
 -		if (yp_port == 0)
 -			break;
 +	if (yp_port)
 +	{
 +		memset((char *)&saddr, 0, sizeof(saddr));
 +		saddr.sin_family = AF_INET;
 +		saddr.sin_addr.s_addr = htonl(INADDR_ANY);
 +		saddr.sin_port = htons(yp_port);
 +
 +		sock_udp = socket(AF_INET, SOCK_DGRAM, 0);
 +		if (sock_udp == -1) {
 +			_msgout("cannot create a udp socket");
 +			exit(1);
 +		}
  
 -		sock = socket(AF_INET, st->st_type, 0);
 -		if (sock == -1) {
 -			if ((asprintf(&errstr, "cannot create a %s socket",
 -			    st->st_name)) == -1)
 -				err(1, "unexpected failure in asprintf()");
 -			_msgout(errstr);
 -			free((void *)errstr);
 +		if (bind(sock_udp, (struct sockaddr *) &saddr, sizeof(saddr))
 +		    == -1) {
 +			_msgout("cannot bind udp socket");
  			exit(1);
  		}
 -		if (bind(sock, (struct sockaddr *) &saddr, sizeof(saddr))
 +
 +		sock_tcp = socket(AF_INET, SOCK_STREAM, 0);
 +		if (sock_tcp == -1) {
 +			_msgout("cannot create a tcp socket");
 +			exit(1);
 +		}
 +
 +		if (bind(sock_tcp, (struct sockaddr *) &saddr, sizeof(saddr))
  		    == -1) {
 -			if ((asprintf(&errstr, "cannot bind %s socket",
 -			    st->st_name)) == -1)
 -				err(1, "unexpected failure in asprintf()");
 -			_msgout(errstr);
 -			free((void *)errstr);
 +			_msgout("cannot bind tcp socket");
  			exit(1);
  		}
 -		errstr = NULL;
  	}
  
  	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
 -		transp = svcudp_create(sock);
 +		transp = svcudp_create(sock_udp);
  		if (transp == NULL) {
  			_msgout("cannot create udp service");
  			exit(1);
 @@ -350,7 +345,7 @@
  	}
  
  	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
 -		transp = svctcp_create(sock, 0, 0);
 +		transp = svctcp_create(sock_tcp, 0, 0);
  		if (transp == NULL) {
  			_msgout("cannot create tcp service");
  			exit(1);
 
 --6TrnltStXW4iwmi0--

From: Dylan Alex Simon <dylan@dylex.net>
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re:  bin/160295: [patch] ypserv:
Date: Mon, 20 Aug 2012 22:10:38 -0400

 Someone has done a rewrite to this exact section of code without fixing this
 bug.  This bug completely breaks NIS over TCP which completely disables many
 (non-freebsd) clients.  It is serious and blatantly obvious how the code is
 broken.  It has been a year.  Please somebody fix it.
Responsible-Changed-From-To: freebsd-bugs->hrs 
Responsible-Changed-By: hrs 
Responsible-Changed-When: Tue Aug 21 02:41:22 UTC 2012 
Responsible-Changed-Why:  
I'll take this. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=160295 
>Unformatted:
