ab3a3d
autofs-5.0.7 - fix portmap lookup
ab3a3d
ab3a3d
From: Ian Kent <ikent@redhat.com>
ab3a3d
ab3a3d
The autofs RPC library has fallen behind some.
ab3a3d
ab3a3d
When using IPv6 (rpbbind) version 3 or 4 is available whereas with IPv4
ab3a3d
(portmap) verions 2 and 3 are available.
ab3a3d
ab3a3d
autofs uses the version defined by PMAPVERS in the portmap include files
ab3a3d
whereas it should be using the RPCBVERS defines when using libtirpc.
ab3a3d
ab3a3d
In addition /etc/rpc should be used for program number lookup and
ab3a3d
/etc/services should be used to lookup rpcbind/protmap port number.
ab3a3d
ab3a3d
This incompatibility only shows up when using IPv6 only.
ab3a3d
---
ab3a3d
 CHANGELOG           |    1 
ab3a3d
 aclocal.m4          |    2 +
d906a6
 configure           |   80 +++++++++++++++++++++++++++++++++++++++++++++
ab3a3d
 include/config.h.in |    6 +++
ab3a3d
 lib/rpc_subs.c      |   92 ++++++++++++++++++++++++++++++++++++++++++++++++----
d906a6
 5 files changed, 175 insertions(+), 6 deletions(-)
ab3a3d
ab3a3d
--- autofs-5.0.7.orig/CHANGELOG
ab3a3d
+++ autofs-5.0.7/CHANGELOG
ab3a3d
@@ -62,6 +62,7 @@
ab3a3d
 - try and cleanup after dumpmaps.
ab3a3d
 - teach dumpmaps to output simple key value pairs.
ab3a3d
 - fix get_nfs_info() probe.
ab3a3d
+- fix portmap lookup.
ab3a3d
 
ab3a3d
 25/07/2012 autofs-5.0.7
ab3a3d
 =======================
ab3a3d
--- autofs-5.0.7.orig/aclocal.m4
ab3a3d
+++ autofs-5.0.7/aclocal.m4
ab3a3d
@@ -421,6 +421,8 @@ if test "$af_have_libtirpc" = "yes"; the
ab3a3d
     TIRPCLIB="-ltirpc"
ab3a3d
 fi
ab3a3d
 
ab3a3d
+AC_CHECK_FUNCS([getrpcbyname getservbyname])
ab3a3d
+
ab3a3d
 # restore flags
ab3a3d
 CFLAGS="$af_check_libtirpc_save_cflags"
ab3a3d
 LDFLAGS="$af_check_libtirpc_save_ldflags"
ab3a3d
--- autofs-5.0.7.orig/configure
ab3a3d
+++ autofs-5.0.7/configure
d906a6
@@ -1559,6 +1559,73 @@ fi
d906a6
 
d906a6
 } # ac_fn_c_try_link
d906a6
 
d906a6
+# ac_fn_c_check_func LINENO FUNC VAR
d906a6
+# ----------------------------------
d906a6
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
d906a6
+ac_fn_c_check_func ()
d906a6
+{
d906a6
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
d906a6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
d906a6
+$as_echo_n "checking for $2... " >&6; }
d906a6
+if eval \${$3+:} false; then :
d906a6
+  $as_echo_n "(cached) " >&6
d906a6
+else
d906a6
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
d906a6
+/* end confdefs.h.  */
d906a6
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
d906a6
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
d906a6
+#define $2 innocuous_$2
d906a6
+
d906a6
+/* System header to define __stub macros and hopefully few prototypes,
d906a6
+    which can conflict with char $2 (); below.
d906a6
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
d906a6
+    <limits.h> exists even on freestanding compilers.  */
d906a6
+
d906a6
+#ifdef __STDC__
d906a6
+# include <limits.h>
d906a6
+#else
d906a6
+# include <assert.h>
d906a6
+#endif
d906a6
+
d906a6
+#undef $2
d906a6
+
d906a6
+/* Override any GCC internal prototype to avoid an error.
d906a6
+   Use char because int might match the return type of a GCC
d906a6
+   builtin and then its argument prototype would still apply.  */
d906a6
+#ifdef __cplusplus
d906a6
+extern "C"
d906a6
+#endif
d906a6
+char $2 ();
d906a6
+/* The GNU C library defines this for functions which it implements
d906a6
+    to always fail with ENOSYS.  Some functions are actually named
d906a6
+    something starting with __ and the normal name is an alias.  */
d906a6
+#if defined __stub_$2 || defined __stub___$2
d906a6
+choke me
d906a6
+#endif
d906a6
+
d906a6
+int
d906a6
+main ()
d906a6
+{
d906a6
+return $2 ();
d906a6
+  ;
d906a6
+  return 0;
d906a6
+}
d906a6
+_ACEOF
d906a6
+if ac_fn_c_try_link "$LINENO"; then :
d906a6
+  eval "$3=yes"
d906a6
+else
d906a6
+  eval "$3=no"
d906a6
+fi
d906a6
+rm -f core conftest.err conftest.$ac_objext \
d906a6
+    conftest$ac_exeext conftest.$ac_ext
d906a6
+fi
d906a6
+eval ac_res=\$$3
d906a6
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
d906a6
+$as_echo "$ac_res" >&6; }
d906a6
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
d906a6
+
d906a6
+} # ac_fn_c_check_func
d906a6
+
d906a6
 # ac_fn_c_try_cpp LINENO
d906a6
 # ----------------------
d906a6
 # Try to preprocess conftest.$ac_ext, and return whether this succeeded.
d906a6
@@ -3161,6 +3228,19 @@ $as_echo "#define TIRPC_WORKAROUND 1" >>
ab3a3d
     TIRPCLIB="-ltirpc"
ab3a3d
 fi
ab3a3d
 
ab3a3d
+for ac_func in getrpcbyname getservbyname
ab3a3d
+do :
ab3a3d
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ab3a3d
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
ab3a3d
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
ab3a3d
+  cat >>confdefs.h <<_ACEOF
ab3a3d
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
ab3a3d
+_ACEOF
ab3a3d
+
ab3a3d
+fi
ab3a3d
+done
ab3a3d
+
ab3a3d
+
ab3a3d
 # restore flags
ab3a3d
 CFLAGS="$af_check_libtirpc_save_cflags"
ab3a3d
 LDFLAGS="$af_check_libtirpc_save_ldflags"
ab3a3d
--- autofs-5.0.7.orig/include/config.h.in
ab3a3d
+++ autofs-5.0.7/include/config.h.in
ab3a3d
@@ -21,6 +21,12 @@
ab3a3d
 /* define if you have E4FSCK */
ab3a3d
 #undef HAVE_E4FSCK
ab3a3d
 
ab3a3d
+/* Define to 1 if you have the `getrpcbyname' function. */
ab3a3d
+#undef HAVE_GETRPCBYNAME
ab3a3d
+
ab3a3d
+/* Define to 1 if you have the `getservbyname' function. */
ab3a3d
+#undef HAVE_GETSERVBYNAME
ab3a3d
+
ab3a3d
 /* Define to 1 if you have the <inttypes.h> header file. */
ab3a3d
 #undef HAVE_INTTYPES_H
ab3a3d
 
ab3a3d
--- autofs-5.0.7.orig/lib/rpc_subs.c
ab3a3d
+++ autofs-5.0.7/lib/rpc_subs.c
ab3a3d
@@ -43,6 +43,14 @@
ab3a3d
                 } while (0)
ab3a3d
 #endif
ab3a3d
 
ab3a3d
+#ifdef WITH_LIBTIRPC
ab3a3d
+const rpcprog_t rpcb_prog = RPCBPROG;
ab3a3d
+const rpcvers_t rpcb_version = RPCBVERS;
ab3a3d
+#else
ab3a3d
+const rpcprog_t rpcb_prog = PMAPPROG;
ab3a3d
+const rpcvers_t rpcb_version = PMAPVERS;
ab3a3d
+#endif
ab3a3d
+
ab3a3d
 #include "mount.h"
ab3a3d
 #include "rpc_subs.h"
ab3a3d
 #include "automount.h"
ab3a3d
@@ -259,6 +267,9 @@ static int rpc_do_create_client(struct s
ab3a3d
 		laddr = (struct sockaddr *) &in4_laddr;
ab3a3d
 		in4_raddr->sin_port = htons(info->port);
ab3a3d
 		slen = sizeof(struct sockaddr_in);
ab3a3d
+		/* Use rpcbind v2 for AF_INET */
ab3a3d
+		if (info->program == rpcb_prog)
ab3a3d
+			info->version = PMAPVERS;
ab3a3d
 	} else if (addr->sa_family == AF_INET6) {
ab3a3d
 		struct sockaddr_in6 *in6_raddr = (struct sockaddr_in6 *) addr;
ab3a3d
 		in6_laddr.sin6_family = AF_INET6;
ab3a3d
@@ -315,6 +326,63 @@ static int rpc_do_create_client(struct s
ab3a3d
 }
ab3a3d
 #endif
ab3a3d
 
ab3a3d
+#if defined(HAVE_GETRPCBYNAME) || defined(HAVE_GETSERVBYNAME)
ab3a3d
+static pthread_mutex_t rpcb_mutex = PTHREAD_MUTEX_INITIALIZER;
ab3a3d
+#endif
ab3a3d
+
ab3a3d
+static rpcprog_t rpc_getrpcbyname(const rpcprog_t program)
ab3a3d
+{
ab3a3d
+#ifdef HAVE_GETRPCBYNAME
ab3a3d
+	static const char *rpcb_pgmtbl[] = {
ab3a3d
+		"rpcbind", "portmap", "portmapper", "sunrpc", NULL,
ab3a3d
+	};
ab3a3d
+	struct rpcent *entry;
ab3a3d
+	rpcprog_t prog_number;
ab3a3d
+	unsigned int i;
ab3a3d
+
ab3a3d
+	pthread_mutex_lock(&rpcb_mutex);
ab3a3d
+	for (i = 0; rpcb_pgmtbl[i] != NULL; i++) {
ab3a3d
+		entry = getrpcbyname(rpcb_pgmtbl[i]);
ab3a3d
+		if (entry) {
ab3a3d
+			prog_number = entry->r_number;
ab3a3d
+			pthread_mutex_unlock(&rpcb_mutex);
ab3a3d
+			return prog_number;
ab3a3d
+		}
ab3a3d
+	}
ab3a3d
+	pthread_mutex_unlock(&rpcb_mutex);
ab3a3d
+#endif
ab3a3d
+	return program;
ab3a3d
+}
ab3a3d
+
ab3a3d
+static unsigned short rpc_getrpcbport(const int proto)
ab3a3d
+{
ab3a3d
+#ifdef HAVE_GETSERVBYNAME
ab3a3d
+	static const char *rpcb_netnametbl[] = {
ab3a3d
+		"rpcbind", "portmapper", "sunrpc", NULL,
ab3a3d
+	};
ab3a3d
+	struct servent *entry;
ab3a3d
+	struct protoent *p_ent;
ab3a3d
+	unsigned short port;
ab3a3d
+	unsigned int i;
ab3a3d
+
ab3a3d
+	pthread_mutex_lock(&rpcb_mutex);
ab3a3d
+	p_ent = getprotobynumber(proto);
ab3a3d
+	if (!p_ent)
ab3a3d
+		goto done;
ab3a3d
+	for (i = 0; rpcb_netnametbl[i] != NULL; i++) {
ab3a3d
+		entry = getservbyname(rpcb_netnametbl[i], p_ent->p_name);
ab3a3d
+		if (entry) {
ab3a3d
+			port = entry->s_port;
ab3a3d
+			pthread_mutex_unlock(&rpcb_mutex);
ab3a3d
+			return port;
ab3a3d
+		}
ab3a3d
+	}
ab3a3d
+done:
ab3a3d
+	pthread_mutex_unlock(&rpcb_mutex);
ab3a3d
+#endif
ab3a3d
+	return (unsigned short) PMAPPORT;
ab3a3d
+}
ab3a3d
+
ab3a3d
 /*
ab3a3d
  * Create an RPC client
ab3a3d
  */
ab3a3d
@@ -510,9 +578,15 @@ int rpc_portmap_getclient(struct conn_in
ab3a3d
 	info->host = host;
ab3a3d
 	info->addr = addr;
ab3a3d
 	info->addr_len = addr_len;
ab3a3d
-	info->program = PMAPPROG;
ab3a3d
-	info->port = PMAPPORT;
ab3a3d
-	info->version = PMAPVERS;
ab3a3d
+	info->program = rpc_getrpcbyname(rpcb_prog);
ab3a3d
+	info->port = ntohs(rpc_getrpcbport(proto));
ab3a3d
+	/*
ab3a3d
+	 * When using libtirpc we might need to change the rpcbind version
ab3a3d
+	 * to qurey AF_INET addresses. Since we might not have an address
ab3a3d
+	 * yet set AF_INET rpcbind version in rpc_do_create_client() when
ab3a3d
+	 * we always have an address.
ab3a3d
+	 */
ab3a3d
+	info->version = rpcb_version;
ab3a3d
 	info->proto = proto;
ab3a3d
 	info->send_sz = RPCSMALLMSGSIZE;
ab3a3d
 	info->recv_sz = RPCSMALLMSGSIZE;
ab3a3d
@@ -555,9 +629,15 @@ int rpc_portmap_getport(struct conn_info
ab3a3d
 		pmap_info.host = info->host;
ab3a3d
 		pmap_info.addr = info->addr;
ab3a3d
 		pmap_info.addr_len = info->addr_len;
ab3a3d
-		pmap_info.port = PMAPPORT;
ab3a3d
-		pmap_info.program = PMAPPROG;
ab3a3d
-		pmap_info.version = PMAPVERS;
ab3a3d
+		pmap_info.port = ntohs(rpc_getrpcbport(info->proto));
ab3a3d
+		pmap_info.program = rpc_getrpcbyname(rpcb_prog);
ab3a3d
+		/*
ab3a3d
+		 * When using libtirpc we might need to change the rpcbind
ab3a3d
+		 * version to qurey AF_INET addresses. Since we might not
ab3a3d
+		 * have an address yet set AF_INET rpcbind version in
ab3a3d
+		 * rpc_do_create_client() when we always have an address.
ab3a3d
+		 */
ab3a3d
+		pmap_info.version = rpcb_version;
ab3a3d
 		pmap_info.proto = info->proto;
ab3a3d
 		pmap_info.send_sz = RPCSMALLMSGSIZE;
ab3a3d
 		pmap_info.recv_sz = RPCSMALLMSGSIZE;