autofs-5.0.7 - fix portmap lookup From: Ian Kent The autofs RPC library has fallen behind some. When using IPv6 (rpbbind) version 3 or 4 is available whereas with IPv4 (portmap) verions 2 and 3 are available. autofs uses the version defined by PMAPVERS in the portmap include files whereas it should be using the RPCBVERS defines when using libtirpc. In addition /etc/rpc should be used for program number lookup and /etc/services should be used to lookup rpcbind/protmap port number. This incompatibility only shows up when using IPv6 only. --- CHANGELOG | 1 + aclocal.m4 | 2 + configure | 13 +++++++ include/config.h.in | 6 +++ lib/rpc_subs.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 108 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 940a109..ecd29e7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -79,6 +79,7 @@ - setup program map env from macro table. - add short host name standard marco variable. - fix get_nfs_info() probe. +- fix portmap lookup. 25/07/2012 autofs-5.0.7 ======================= diff --git a/aclocal.m4 b/aclocal.m4 index 637a775..3e6f223 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -428,6 +428,8 @@ if test "$af_have_libtirpc" = "yes"; then TIRPCLIB="-ltirpc" fi +AC_CHECK_FUNCS([getrpcbyname getservbyname]) + # restore flags CFLAGS="$af_check_libtirpc_save_cflags" LDFLAGS="$af_check_libtirpc_save_ldflags" diff --git a/configure b/configure index e6d5d4a..70996ee 100755 --- a/configure +++ b/configure @@ -3228,6 +3228,19 @@ $as_echo "#define TIRPC_WORKAROUND 1" >>confdefs.h TIRPCLIB="-ltirpc" fi +for ac_func in getrpcbyname getservbyname +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + # restore flags CFLAGS="$af_check_libtirpc_save_cflags" LDFLAGS="$af_check_libtirpc_save_ldflags" diff --git a/include/config.h.in b/include/config.h.in index 8a52080..7037b24 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -21,6 +21,12 @@ /* define if you have E4FSCK */ #undef HAVE_E4FSCK +/* Define to 1 if you have the `getrpcbyname' function. */ +#undef HAVE_GETRPCBYNAME + +/* Define to 1 if you have the `getservbyname' function. */ +#undef HAVE_GETSERVBYNAME + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c index f5742e8..46b3e8d 100644 --- a/lib/rpc_subs.c +++ b/lib/rpc_subs.c @@ -43,6 +43,14 @@ } while (0) #endif +#ifdef WITH_LIBTIRPC +const rpcprog_t rpcb_prog = RPCBPROG; +const rpcvers_t rpcb_version = RPCBVERS; +#else +const rpcprog_t rpcb_prog = PMAPPROG; +const rpcvers_t rpcb_version = PMAPVERS; +#endif + #include "mount.h" #include "rpc_subs.h" #include "automount.h" @@ -259,6 +267,9 @@ static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, i laddr = (struct sockaddr *) &in4_laddr; in4_raddr->sin_port = htons(info->port); slen = sizeof(struct sockaddr_in); + /* Use rpcbind v2 for AF_INET */ + if (info->program == rpcb_prog) + info->version = PMAPVERS; } else if (addr->sa_family == AF_INET6) { struct sockaddr_in6 *in6_raddr = (struct sockaddr_in6 *) addr; in6_laddr.sin6_family = AF_INET6; @@ -315,6 +326,63 @@ static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, i } #endif +#if defined(HAVE_GETRPCBYNAME) || defined(HAVE_GETSERVBYNAME) +static pthread_mutex_t rpcb_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +static rpcprog_t rpc_getrpcbyname(const rpcprog_t program) +{ +#ifdef HAVE_GETRPCBYNAME + static const char *rpcb_pgmtbl[] = { + "rpcbind", "portmap", "portmapper", "sunrpc", NULL, + }; + struct rpcent *entry; + rpcprog_t prog_number; + unsigned int i; + + pthread_mutex_lock(&rpcb_mutex); + for (i = 0; rpcb_pgmtbl[i] != NULL; i++) { + entry = getrpcbyname(rpcb_pgmtbl[i]); + if (entry) { + prog_number = entry->r_number; + pthread_mutex_unlock(&rpcb_mutex); + return prog_number; + } + } + pthread_mutex_unlock(&rpcb_mutex); +#endif + return program; +} + +static unsigned short rpc_getrpcbport(const int proto) +{ +#ifdef HAVE_GETSERVBYNAME + static const char *rpcb_netnametbl[] = { + "rpcbind", "portmapper", "sunrpc", NULL, + }; + struct servent *entry; + struct protoent *p_ent; + unsigned short port; + unsigned int i; + + pthread_mutex_lock(&rpcb_mutex); + p_ent = getprotobynumber(proto); + if (!p_ent) + goto done; + for (i = 0; rpcb_netnametbl[i] != NULL; i++) { + entry = getservbyname(rpcb_netnametbl[i], p_ent->p_name); + if (entry) { + port = entry->s_port; + pthread_mutex_unlock(&rpcb_mutex); + return port; + } + } +done: + pthread_mutex_unlock(&rpcb_mutex); +#endif + return (unsigned short) PMAPPORT; +} + /* * Create an RPC client */ @@ -510,9 +578,15 @@ int rpc_portmap_getclient(struct conn_info *info, info->host = host; info->addr = addr; info->addr_len = addr_len; - info->program = PMAPPROG; - info->port = PMAPPORT; - info->version = PMAPVERS; + info->program = rpc_getrpcbyname(rpcb_prog); + info->port = ntohs(rpc_getrpcbport(proto)); + /* + * When using libtirpc we might need to change the rpcbind version + * to qurey AF_INET addresses. Since we might not have an address + * yet set AF_INET rpcbind version in rpc_do_create_client() when + * we always have an address. + */ + info->version = rpcb_version; info->proto = proto; info->send_sz = RPCSMALLMSGSIZE; info->recv_sz = RPCSMALLMSGSIZE; @@ -555,9 +629,15 @@ int rpc_portmap_getport(struct conn_info *info, pmap_info.host = info->host; pmap_info.addr = info->addr; pmap_info.addr_len = info->addr_len; - pmap_info.port = PMAPPORT; - pmap_info.program = PMAPPROG; - pmap_info.version = PMAPVERS; + pmap_info.port = ntohs(rpc_getrpcbport(info->proto)); + pmap_info.program = rpc_getrpcbyname(rpcb_prog); + /* + * When using libtirpc we might need to change the rpcbind + * version to qurey AF_INET addresses. Since we might not + * have an address yet set AF_INET rpcbind version in + * rpc_do_create_client() when we always have an address. + */ + pmap_info.version = rpcb_version; pmap_info.proto = info->proto; pmap_info.send_sz = RPCSMALLMSGSIZE; pmap_info.recv_sz = RPCSMALLMSGSIZE;