|
|
d906a6 |
autofs-5.0.8 - fix ipv6 libtirpc getport
|
|
|
d906a6 |
|
|
|
d906a6 |
From: Ian Kent <ikent@redhat.com>
|
|
|
d906a6 |
|
|
|
d906a6 |
The method that was being used to obtain a service port number
|
|
|
d906a6 |
when using libtirpc was wrong.
|
|
|
d906a6 |
---
|
|
|
d906a6 |
CHANGELOG | 1
|
|
|
d906a6 |
lib/rpc_subs.c | 283 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
|
|
|
d906a6 |
2 files changed, 267 insertions(+), 17 deletions(-)
|
|
|
d906a6 |
|
|
|
d906a6 |
--- autofs-5.0.7.orig/CHANGELOG
|
|
|
d906a6 |
+++ autofs-5.0.7/CHANGELOG
|
|
|
d906a6 |
@@ -64,6 +64,7 @@
|
|
|
d906a6 |
- fix get_nfs_info() probe.
|
|
|
d906a6 |
- fix portmap lookup.
|
|
|
d906a6 |
- only probe specific nfs version if requested.
|
|
|
d906a6 |
+- fix ipv6 libtirpc getport.
|
|
|
d906a6 |
|
|
|
d906a6 |
25/07/2012 autofs-5.0.7
|
|
|
d906a6 |
=======================
|
|
|
d906a6 |
--- autofs-5.0.7.orig/lib/rpc_subs.c
|
|
|
d906a6 |
+++ autofs-5.0.7/lib/rpc_subs.c
|
|
|
d906a6 |
@@ -234,6 +234,28 @@ static int rpc_do_create_client(struct s
|
|
|
d906a6 |
|
|
|
d906a6 |
return 0;
|
|
|
d906a6 |
}
|
|
|
d906a6 |
+static int rpc_getport(struct conn_info *info,
|
|
|
d906a6 |
+ struct pmap *parms, CLIENT *client)
|
|
|
d906a6 |
+{
|
|
|
d906a6 |
+ enum clnt_stat status;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ /*
|
|
|
d906a6 |
+ * Check to see if server is up otherwise a getport will take
|
|
|
d906a6 |
+ * forever to timeout.
|
|
|
d906a6 |
+ */
|
|
|
d906a6 |
+ status = clnt_call(client, PMAPPROC_NULL,
|
|
|
d906a6 |
+ (xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
|
|
|
d906a6 |
+ info->timeout);
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ if (status == RPC_SUCCESS) {
|
|
|
d906a6 |
+ status = clnt_call(client, PMAPPROC_GETPORT,
|
|
|
d906a6 |
+ (xdrproc_t) xdr_pmap, (caddr_t) parms,
|
|
|
d906a6 |
+ (xdrproc_t) xdr_u_short, (caddr_t) port,
|
|
|
d906a6 |
+ info->timeout);
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ return status;
|
|
|
d906a6 |
+}
|
|
|
d906a6 |
#else
|
|
|
d906a6 |
static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd, CLIENT **client)
|
|
|
d906a6 |
{
|
|
|
d906a6 |
@@ -267,9 +289,6 @@ static int rpc_do_create_client(struct s
|
|
|
d906a6 |
laddr = (struct sockaddr *) &in4_laddr;
|
|
|
d906a6 |
in4_raddr->sin_port = htons(info->port);
|
|
|
d906a6 |
slen = sizeof(struct sockaddr_in);
|
|
|
d906a6 |
- /* Use rpcbind v2 for AF_INET */
|
|
|
d906a6 |
- if (info->program == rpcb_prog)
|
|
|
d906a6 |
- info->version = PMAPVERS;
|
|
|
d906a6 |
} else if (addr->sa_family == AF_INET6) {
|
|
|
d906a6 |
struct sockaddr_in6 *in6_raddr = (struct sockaddr_in6 *) addr;
|
|
|
d906a6 |
in6_laddr.sin6_family = AF_INET6;
|
|
|
d906a6 |
@@ -324,6 +343,244 @@ static int rpc_do_create_client(struct s
|
|
|
d906a6 |
|
|
|
d906a6 |
return 0;
|
|
|
d906a6 |
}
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+/*
|
|
|
d906a6 |
+ * Thankfully nfs-utils had already dealt with this.
|
|
|
d906a6 |
+ * Thanks to Chuck Lever for his nfs-utils patch series, much of
|
|
|
d906a6 |
+ * which is used here.
|
|
|
d906a6 |
+ */
|
|
|
d906a6 |
+static pthread_mutex_t proto_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+static enum clnt_stat rpc_get_netid(const sa_family_t family,
|
|
|
d906a6 |
+ const int protocol, char **netid)
|
|
|
d906a6 |
+{
|
|
|
d906a6 |
+ char *nc_protofmly, *nc_proto, *nc_netid;
|
|
|
d906a6 |
+ struct netconfig *nconf;
|
|
|
d906a6 |
+ struct protoent *proto;
|
|
|
d906a6 |
+ void *handle;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ switch (family) {
|
|
|
d906a6 |
+ case AF_LOCAL:
|
|
|
d906a6 |
+ case AF_INET:
|
|
|
d906a6 |
+ nc_protofmly = NC_INET;
|
|
|
d906a6 |
+ break;
|
|
|
d906a6 |
+ case AF_INET6:
|
|
|
d906a6 |
+ nc_protofmly = NC_INET6;
|
|
|
d906a6 |
+ break;
|
|
|
d906a6 |
+ default:
|
|
|
d906a6 |
+ return RPC_UNKNOWNPROTO;
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ pthread_mutex_lock(&proto_mutex);
|
|
|
d906a6 |
+ proto = getprotobynumber(protocol);
|
|
|
d906a6 |
+ if (!proto) {
|
|
|
d906a6 |
+ pthread_mutex_unlock(&proto_mutex);
|
|
|
d906a6 |
+ return RPC_UNKNOWNPROTO;
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
+ nc_proto = strdup(proto->p_name);
|
|
|
d906a6 |
+ pthread_mutex_unlock(&proto_mutex);
|
|
|
d906a6 |
+ if (!nc_proto)
|
|
|
d906a6 |
+ return RPC_SYSTEMERROR;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ handle = setnetconfig();
|
|
|
d906a6 |
+ while ((nconf = getnetconfig(handle)) != NULL) {
|
|
|
d906a6 |
+ if (nconf->nc_protofmly != NULL &&
|
|
|
d906a6 |
+ strcmp(nconf->nc_protofmly, nc_protofmly) != 0)
|
|
|
d906a6 |
+ continue;
|
|
|
d906a6 |
+ if (nconf->nc_proto != NULL &&
|
|
|
d906a6 |
+ strcmp(nconf->nc_proto, nc_proto) != 0)
|
|
|
d906a6 |
+ continue;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ nc_netid = strdup(nconf->nc_netid);
|
|
|
d906a6 |
+ if (!nc_netid) {
|
|
|
d906a6 |
+ free(nc_proto);
|
|
|
d906a6 |
+ return RPC_SYSTEMERROR;
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ *netid = nc_netid;
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
+ endnetconfig(handle);
|
|
|
d906a6 |
+ free(nc_proto);
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ return RPC_SUCCESS;
|
|
|
d906a6 |
+}
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+static char *rpc_sockaddr2universal(const struct sockaddr *addr)
|
|
|
d906a6 |
+{
|
|
|
d906a6 |
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) addr;
|
|
|
d906a6 |
+ const struct sockaddr_un *sun = (const struct sockaddr_un *) addr;
|
|
|
d906a6 |
+ const struct sockaddr_in *sin = (const struct sockaddr_in *) addr;
|
|
|
d906a6 |
+ char buf[INET6_ADDRSTRLEN + 8 /* for port information */];
|
|
|
d906a6 |
+ uint16_t port;
|
|
|
d906a6 |
+ size_t count;
|
|
|
d906a6 |
+ char *result;
|
|
|
d906a6 |
+ int len;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ switch (addr->sa_family) {
|
|
|
d906a6 |
+ case AF_LOCAL:
|
|
|
d906a6 |
+ return strndup(sun->sun_path, sizeof(sun->sun_path));
|
|
|
d906a6 |
+ case AF_INET:
|
|
|
d906a6 |
+ if (inet_ntop(AF_INET, (const void *)&sin->sin_addr.s_addr,
|
|
|
d906a6 |
+ buf, (socklen_t)sizeof(buf)) == NULL)
|
|
|
d906a6 |
+ goto out_err;
|
|
|
d906a6 |
+ port = ntohs(sin->sin_port);
|
|
|
d906a6 |
+ break;
|
|
|
d906a6 |
+ case AF_INET6:
|
|
|
d906a6 |
+ if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
|
|
|
d906a6 |
+ buf, (socklen_t)sizeof(buf)) == NULL)
|
|
|
d906a6 |
+ goto out_err;
|
|
|
d906a6 |
+ port = ntohs(sin6->sin6_port);
|
|
|
d906a6 |
+ break;
|
|
|
d906a6 |
+ default:
|
|
|
d906a6 |
+ goto out_err;
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ count = sizeof(buf) - strlen(buf);
|
|
|
d906a6 |
+ len = snprintf(buf + strlen(buf), count, ".%u.%u",
|
|
|
d906a6 |
+ (unsigned)(port >> 8), (unsigned)(port & 0xff));
|
|
|
d906a6 |
+ /* before glibc 2.0.6, snprintf(3) could return -1 */
|
|
|
d906a6 |
+ if (len < 0 || (size_t)len > count)
|
|
|
d906a6 |
+ goto out_err;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ result = strdup(buf);
|
|
|
d906a6 |
+ return result;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+out_err:
|
|
|
d906a6 |
+ return NULL;
|
|
|
d906a6 |
+}
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+static int rpc_universal2port(const char *uaddr)
|
|
|
d906a6 |
+{
|
|
|
d906a6 |
+ char *addrstr;
|
|
|
d906a6 |
+ char *p, *endptr;
|
|
|
d906a6 |
+ unsigned long portlo, porthi;
|
|
|
d906a6 |
+ int port = -1;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ addrstr = strdup(uaddr);
|
|
|
d906a6 |
+ if (!addrstr)
|
|
|
d906a6 |
+ return -1;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ p = strrchr(addrstr, '.');
|
|
|
d906a6 |
+ if (!p)
|
|
|
d906a6 |
+ goto out;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ portlo = strtoul(p + 1, &endptr, 10);
|
|
|
d906a6 |
+ if (*endptr != '\0' || portlo > 255)
|
|
|
d906a6 |
+ goto out;
|
|
|
d906a6 |
+ *p = '\0';
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ p = strrchr(addrstr, '.');
|
|
|
d906a6 |
+ if (!p)
|
|
|
d906a6 |
+ goto out;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ porthi = strtoul(p + 1, &endptr, 10);
|
|
|
d906a6 |
+ if (*endptr != '\0' || porthi > 255)
|
|
|
d906a6 |
+ goto out;
|
|
|
d906a6 |
+ *p = '\0';
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ port = (porthi << 8) | portlo;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+out:
|
|
|
d906a6 |
+ free(addrstr);
|
|
|
d906a6 |
+ return port;
|
|
|
d906a6 |
+}
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+static enum clnt_stat rpc_rpcb_getport(CLIENT *client,
|
|
|
d906a6 |
+ struct rpcb *parms,
|
|
|
d906a6 |
+ struct timeval timeout,
|
|
|
d906a6 |
+ unsigned short *port)
|
|
|
d906a6 |
+{
|
|
|
d906a6 |
+ rpcvers_t rpcb_version;
|
|
|
d906a6 |
+ struct rpc_err rpcerr;
|
|
|
d906a6 |
+ int s_port = 0;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ for (rpcb_version = RPCBVERS_4;
|
|
|
d906a6 |
+ rpcb_version >= RPCBVERS_3;
|
|
|
d906a6 |
+ rpcb_version--) {
|
|
|
d906a6 |
+ enum clnt_stat status;
|
|
|
d906a6 |
+ char *uaddr = NULL;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ CLNT_CONTROL(client, CLSET_VERS, (void *) &rpcb_version);
|
|
|
d906a6 |
+ status = CLNT_CALL(client, (rpcproc_t) RPCBPROC_GETADDR,
|
|
|
d906a6 |
+ (xdrproc_t) xdr_rpcb, (void *) parms,
|
|
|
d906a6 |
+ (xdrproc_t) xdr_wrapstring, (void *) &uaddr,
|
|
|
d906a6 |
+ timeout);
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ switch (status) {
|
|
|
d906a6 |
+ case RPC_SUCCESS:
|
|
|
d906a6 |
+ if ((uaddr == NULL) || (uaddr[0] == '\0'))
|
|
|
d906a6 |
+ return RPC_PROGNOTREGISTERED;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ s_port = rpc_universal2port(uaddr);
|
|
|
d906a6 |
+ xdr_free((xdrproc_t) xdr_wrapstring, (char *) &uaddr);
|
|
|
d906a6 |
+ if (s_port == -1) {
|
|
|
d906a6 |
+ return RPC_N2AXLATEFAILURE;
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
+ *port = s_port;
|
|
|
d906a6 |
+ return RPC_SUCCESS;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ case RPC_PROGVERSMISMATCH:
|
|
|
d906a6 |
+ clnt_geterr(client, &rpcerr);
|
|
|
d906a6 |
+ if (rpcerr.re_vers.low > RPCBVERS4)
|
|
|
d906a6 |
+ return status;
|
|
|
d906a6 |
+ continue;
|
|
|
d906a6 |
+ case RPC_PROCUNAVAIL:
|
|
|
d906a6 |
+ case RPC_PROGUNAVAIL:
|
|
|
d906a6 |
+ continue;
|
|
|
d906a6 |
+ default:
|
|
|
d906a6 |
+ /* Most likely RPC_TIMEDOUT or RPC_CANTRECV */
|
|
|
d906a6 |
+ return status;
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ if (s_port == 0)
|
|
|
d906a6 |
+ return RPC_PROGNOTREGISTERED;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ return RPC_PROCUNAVAIL;
|
|
|
d906a6 |
+}
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+static enum clnt_stat rpc_getport(struct conn_info *info,
|
|
|
d906a6 |
+ struct pmap *parms, CLIENT *client,
|
|
|
d906a6 |
+ unsigned short *port)
|
|
|
d906a6 |
+{
|
|
|
d906a6 |
+ enum clnt_stat status;
|
|
|
d906a6 |
+ struct sockaddr *paddr, addr;
|
|
|
d906a6 |
+ struct rpcb rpcb_parms;
|
|
|
d906a6 |
+ char *netid, *raddr;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ if (info->addr)
|
|
|
d906a6 |
+ paddr = info->addr;
|
|
|
d906a6 |
+ else {
|
|
|
d906a6 |
+ if (!clnt_control(client, CLGET_SERVER_ADDR, (char *) &addr))
|
|
|
d906a6 |
+ return RPC_UNKNOWNADDR;
|
|
|
d906a6 |
+ paddr = &addr;
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ netid = NULL;
|
|
|
d906a6 |
+ status = rpc_get_netid(paddr->sa_family, info->proto, &netid);
|
|
|
d906a6 |
+ if (status != RPC_SUCCESS)
|
|
|
d906a6 |
+ return status;
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ raddr = rpc_sockaddr2universal(paddr);
|
|
|
d906a6 |
+ if (!raddr) {
|
|
|
d906a6 |
+ free(netid);
|
|
|
d906a6 |
+ return RPC_UNKNOWNADDR;
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ memset(&rpcb_parms, 0, sizeof(rpcb_parms));
|
|
|
d906a6 |
+ rpcb_parms.r_prog = parms->pm_prog;
|
|
|
d906a6 |
+ rpcb_parms.r_vers = parms->pm_vers;
|
|
|
d906a6 |
+ rpcb_parms.r_netid = netid;
|
|
|
d906a6 |
+ rpcb_parms.r_addr = raddr;
|
|
|
d906a6 |
+ rpcb_parms.r_owner = "";
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ status = rpc_rpcb_getport(client, &rpcb_parms, info->timeout, port);
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ free(netid);
|
|
|
d906a6 |
+ free(raddr);
|
|
|
d906a6 |
+
|
|
|
d906a6 |
+ return status;
|
|
|
d906a6 |
+}
|
|
|
d906a6 |
#endif
|
|
|
d906a6 |
|
|
|
d906a6 |
#if defined(HAVE_GETRPCBYNAME) || defined(HAVE_GETSERVBYNAME)
|
|
|
d906a6 |
@@ -647,20 +904,7 @@ int rpc_portmap_getport(struct conn_info
|
|
|
d906a6 |
return ret;
|
|
|
d906a6 |
}
|
|
|
d906a6 |
|
|
|
d906a6 |
- /*
|
|
|
d906a6 |
- * Check to see if server is up otherwise a getport will take
|
|
|
d906a6 |
- * forever to timeout.
|
|
|
d906a6 |
- */
|
|
|
d906a6 |
- status = clnt_call(client, PMAPPROC_NULL,
|
|
|
d906a6 |
- (xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
|
|
|
d906a6 |
- pmap_info.timeout);
|
|
|
d906a6 |
-
|
|
|
d906a6 |
- if (status == RPC_SUCCESS) {
|
|
|
d906a6 |
- status = clnt_call(client, PMAPPROC_GETPORT,
|
|
|
d906a6 |
- (xdrproc_t) xdr_pmap, (caddr_t) parms,
|
|
|
d906a6 |
- (xdrproc_t) xdr_u_short, (caddr_t) port,
|
|
|
d906a6 |
- pmap_info.timeout);
|
|
|
d906a6 |
- }
|
|
|
d906a6 |
+ status = rpc_getport(&pmap_info, parms, client, port);
|
|
|
d906a6 |
|
|
|
d906a6 |
if (!info->client) {
|
|
|
d906a6 |
/*
|
|
|
d906a6 |
@@ -867,6 +1111,11 @@ static int rpc_get_exports_proto(struct
|
|
|
d906a6 |
clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) &info->timeout);
|
|
|
d906a6 |
|
|
|
d906a6 |
client->cl_auth = authunix_create_default();
|
|
|
d906a6 |
+ if (client->cl_auth == NULL) {
|
|
|
d906a6 |
+ error(LOGOPT_ANY, "auth create failed");
|
|
|
d906a6 |
+ clnt_destroy(client);
|
|
|
d906a6 |
+ return 0;
|
|
|
d906a6 |
+ }
|
|
|
d906a6 |
|
|
|
d906a6 |
vers_entry = 0;
|
|
|
d906a6 |
while (1) {
|