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