libtirpc really does a terrible job of protocol fallback.

When trying to connect to rpcbind/portmap, it iterates over the
protocols listed in /etc/netconfig (nice choice of name, oh yeah) and
tries to create a socket for each in turn.  Then it selects the last
protocol for which that succeeded (yes, the last, not the first).

Only then does it try to connect.  So there is no fallback at all for
connection.

I'm attaching a patch to fix connection fallback, but unfortunately it
is not sufficient to make svc_reg() with portmap.

Ben.

-- 
Ben Hutchings
Once a job is fouled up, anything done to improve it makes it worse.
--- libtirpc-0.2.1.orig/src/rpcb_clnt.c
+++ libtirpc-0.2.1/src/rpcb_clnt.c
@@ -459,17 +459,21 @@
 
 /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
 	mutex_lock(&loopnconf_lock);
-	if (loopnconf == NULL) {
+	if (loopnconf != NULL) {
+		mutex_unlock(&loopnconf_lock);
+		client = getclnthandle(hostname, loopnconf, NULL);
+	} else {
 		struct netconfig *nconf, *tmpnconf = NULL;
 		void *nc_handle;
 		int fd;
 
+		mutex_unlock(&loopnconf_lock);
+
 		nc_handle = setnetconfig();
 		if (nc_handle == NULL) {
 			/* fails to open netconfig file */
 			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
-			mutex_unlock(&loopnconf_lock);
 			return (NULL);
 		}
 		while ((nconf = getnetconfig(nc_handle)) != NULL) {
@@ -489,24 +493,31 @@
 				if (fd < 0)
 					continue;
  				close(fd);
-				tmpnconf = nconf;
 				if (!strcmp(nconf->nc_protofmly, NC_INET))
 					hostname = IN4_LOCALHOST_STRING;
 				else
 					hostname = IN6_LOCALHOST_STRING;
+				client = getclnthandle(hostname, nconf, NULL);
+				if (client == NULL)
+					continue;
+				tmpnconf = getnetconfigent(nconf->nc_netid);
+				break;
 			}
 		}
+		endnetconfig(nc_handle);
 		if (tmpnconf == NULL) {
  			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
-			mutex_unlock(&loopnconf_lock);
 			return (NULL);
 		}
-		loopnconf = getnetconfigent(tmpnconf->nc_netid);
-		/* loopnconf is never freed */
-		endnetconfig(nc_handle);
+		mutex_lock(&loopnconf_lock);
+		if (loopnconf == NULL)
+			/* loopnconf is never freed */
+			loopnconf = tmpnconf;
+		else
+			/* free the duplicate */
+			freenetconfigent(tmpnconf);
+		mutex_unlock(&loopnconf_lock);
 	}
-	mutex_unlock(&loopnconf_lock);
-	client = getclnthandle(hostname, loopnconf, NULL);
 	return (client);
 }
 

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to