1 autofs-5.0.8 - fix ipv6 libtirpc getport
3 From: Ian Kent <ikent@redhat.com>
5 The method that was being used to obtain a service port number
6 when using libtirpc was wrong.
9 lib/rpc_subs.c | 283 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
10 2 files changed, 267 insertions(+), 17 deletions(-)
12 diff --git a/CHANGELOG b/CHANGELOG
13 index 68db340..9c87373 100644
17 - fix task manager not getting signaled.
18 - allow --with-systemd to take a path arg.
19 - fix WITH_LIBTIRPC function name.
20 +- fix ipv6 libtirpc getport.
22 17/10/2013 autofs-5.0.8
23 =======================
24 diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c
25 index 46b3e8d..2365b6e 100644
28 @@ -234,6 +234,28 @@ static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, i
32 +static int rpc_getport(struct conn_info *info,
33 + struct pmap *parms, CLIENT *client)
35 + enum clnt_stat status;
38 + * Check to see if server is up otherwise a getport will take
39 + * forever to timeout.
41 + status = clnt_call(client, PMAPPROC_NULL,
42 + (xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
45 + if (status == RPC_SUCCESS) {
46 + status = clnt_call(client, PMAPPROC_GETPORT,
47 + (xdrproc_t) xdr_pmap, (caddr_t) parms,
48 + (xdrproc_t) xdr_u_short, (caddr_t) port,
55 static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd, CLIENT **client)
57 @@ -267,9 +289,6 @@ static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, i
58 laddr = (struct sockaddr *) &in4_laddr;
59 in4_raddr->sin_port = htons(info->port);
60 slen = sizeof(struct sockaddr_in);
61 - /* Use rpcbind v2 for AF_INET */
62 - if (info->program == rpcb_prog)
63 - info->version = PMAPVERS;
64 } else if (addr->sa_family == AF_INET6) {
65 struct sockaddr_in6 *in6_raddr = (struct sockaddr_in6 *) addr;
66 in6_laddr.sin6_family = AF_INET6;
67 @@ -324,6 +343,244 @@ static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, i
73 + * Thankfully nfs-utils had already dealt with this.
74 + * Thanks to Chuck Lever for his nfs-utils patch series, much of
75 + * which is used here.
77 +static pthread_mutex_t proto_mutex = PTHREAD_MUTEX_INITIALIZER;
79 +static enum clnt_stat rpc_get_netid(const sa_family_t family,
80 + const int protocol, char **netid)
82 + char *nc_protofmly, *nc_proto, *nc_netid;
83 + struct netconfig *nconf;
84 + struct protoent *proto;
90 + nc_protofmly = NC_INET;
93 + nc_protofmly = NC_INET6;
96 + return RPC_UNKNOWNPROTO;
99 + pthread_mutex_lock(&proto_mutex);
100 + proto = getprotobynumber(protocol);
102 + pthread_mutex_unlock(&proto_mutex);
103 + return RPC_UNKNOWNPROTO;
105 + nc_proto = strdup(proto->p_name);
106 + pthread_mutex_unlock(&proto_mutex);
108 + return RPC_SYSTEMERROR;
110 + handle = setnetconfig();
111 + while ((nconf = getnetconfig(handle)) != NULL) {
112 + if (nconf->nc_protofmly != NULL &&
113 + strcmp(nconf->nc_protofmly, nc_protofmly) != 0)
115 + if (nconf->nc_proto != NULL &&
116 + strcmp(nconf->nc_proto, nc_proto) != 0)
119 + nc_netid = strdup(nconf->nc_netid);
122 + return RPC_SYSTEMERROR;
127 + endnetconfig(handle);
130 + return RPC_SUCCESS;
133 +static char *rpc_sockaddr2universal(const struct sockaddr *addr)
135 + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) addr;
136 + const struct sockaddr_un *sun = (const struct sockaddr_un *) addr;
137 + const struct sockaddr_in *sin = (const struct sockaddr_in *) addr;
138 + char buf[INET6_ADDRSTRLEN + 8 /* for port information */];
144 + switch (addr->sa_family) {
146 + return strndup(sun->sun_path, sizeof(sun->sun_path));
148 + if (inet_ntop(AF_INET, (const void *)&sin->sin_addr.s_addr,
149 + buf, (socklen_t)sizeof(buf)) == NULL)
151 + port = ntohs(sin->sin_port);
154 + if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
155 + buf, (socklen_t)sizeof(buf)) == NULL)
157 + port = ntohs(sin6->sin6_port);
163 + count = sizeof(buf) - strlen(buf);
164 + len = snprintf(buf + strlen(buf), count, ".%u.%u",
165 + (unsigned)(port >> 8), (unsigned)(port & 0xff));
166 + /* before glibc 2.0.6, snprintf(3) could return -1 */
167 + if (len < 0 || (size_t)len > count)
170 + result = strdup(buf);
177 +static int rpc_universal2port(const char *uaddr)
181 + unsigned long portlo, porthi;
184 + addrstr = strdup(uaddr);
188 + p = strrchr(addrstr, '.');
192 + portlo = strtoul(p + 1, &endptr, 10);
193 + if (*endptr != '\0' || portlo > 255)
197 + p = strrchr(addrstr, '.');
201 + porthi = strtoul(p + 1, &endptr, 10);
202 + if (*endptr != '\0' || porthi > 255)
206 + port = (porthi << 8) | portlo;
213 +static enum clnt_stat rpc_rpcb_getport(CLIENT *client,
214 + struct rpcb *parms,
215 + struct timeval timeout,
216 + unsigned short *port)
218 + rpcvers_t rpcb_version;
219 + struct rpc_err rpcerr;
222 + for (rpcb_version = RPCBVERS_4;
223 + rpcb_version >= RPCBVERS_3;
225 + enum clnt_stat status;
226 + char *uaddr = NULL;
228 + CLNT_CONTROL(client, CLSET_VERS, (void *) &rpcb_version);
229 + status = CLNT_CALL(client, (rpcproc_t) RPCBPROC_GETADDR,
230 + (xdrproc_t) xdr_rpcb, (void *) parms,
231 + (xdrproc_t) xdr_wrapstring, (void *) &uaddr,
236 + if ((uaddr == NULL) || (uaddr[0] == '\0'))
237 + return RPC_PROGNOTREGISTERED;
239 + s_port = rpc_universal2port(uaddr);
240 + xdr_free((xdrproc_t) xdr_wrapstring, (char *) &uaddr);
241 + if (s_port == -1) {
242 + return RPC_N2AXLATEFAILURE;
245 + return RPC_SUCCESS;
247 + case RPC_PROGVERSMISMATCH:
248 + clnt_geterr(client, &rpcerr);
249 + if (rpcerr.re_vers.low > RPCBVERS4)
252 + case RPC_PROCUNAVAIL:
253 + case RPC_PROGUNAVAIL:
256 + /* Most likely RPC_TIMEDOUT or RPC_CANTRECV */
262 + return RPC_PROGNOTREGISTERED;
264 + return RPC_PROCUNAVAIL;
267 +static enum clnt_stat rpc_getport(struct conn_info *info,
268 + struct pmap *parms, CLIENT *client,
269 + unsigned short *port)
271 + enum clnt_stat status;
272 + struct sockaddr *paddr, addr;
273 + struct rpcb rpcb_parms;
274 + char *netid, *raddr;
277 + paddr = info->addr;
279 + if (!clnt_control(client, CLGET_SERVER_ADDR, (char *) &addr))
280 + return RPC_UNKNOWNADDR;
285 + status = rpc_get_netid(paddr->sa_family, info->proto, &netid);
286 + if (status != RPC_SUCCESS)
289 + raddr = rpc_sockaddr2universal(paddr);
292 + return RPC_UNKNOWNADDR;
295 + memset(&rpcb_parms, 0, sizeof(rpcb_parms));
296 + rpcb_parms.r_prog = parms->pm_prog;
297 + rpcb_parms.r_vers = parms->pm_vers;
298 + rpcb_parms.r_netid = netid;
299 + rpcb_parms.r_addr = raddr;
300 + rpcb_parms.r_owner = "";
302 + status = rpc_rpcb_getport(client, &rpcb_parms, info->timeout, port);
311 #if defined(HAVE_GETRPCBYNAME) || defined(HAVE_GETSERVBYNAME)
312 @@ -647,20 +904,7 @@ int rpc_portmap_getport(struct conn_info *info,
317 - * Check to see if server is up otherwise a getport will take
318 - * forever to timeout.
320 - status = clnt_call(client, PMAPPROC_NULL,
321 - (xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
322 - pmap_info.timeout);
324 - if (status == RPC_SUCCESS) {
325 - status = clnt_call(client, PMAPPROC_GETPORT,
326 - (xdrproc_t) xdr_pmap, (caddr_t) parms,
327 - (xdrproc_t) xdr_u_short, (caddr_t) port,
328 - pmap_info.timeout);
330 + status = rpc_getport(&pmap_info, parms, client, port);
334 @@ -867,6 +1111,11 @@ static int rpc_get_exports_proto(struct conn_info *info, exports *exp)
335 clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) &info->timeout);
337 client->cl_auth = authunix_create_default();
338 + if (client->cl_auth == NULL) {
339 + error(LOGOPT_ANY, "auth create failed");
340 + clnt_destroy(client);