- updated to 5.0.8
[packages/autofs.git] / autofs-5.0.8-fix-ipv6-libtirpc-getport.patch
CommitLineData
15dae982
JR
1autofs-5.0.8 - fix ipv6 libtirpc getport
2
3From: Ian Kent <ikent@redhat.com>
4
5The method that was being used to obtain a service port number
6when using libtirpc was wrong.
7---
8 CHANGELOG | 1
9 lib/rpc_subs.c | 283 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
10 2 files changed, 267 insertions(+), 17 deletions(-)
11
12diff --git a/CHANGELOG b/CHANGELOG
13index 68db340..9c87373 100644
14--- a/CHANGELOG
15+++ b/CHANGELOG
16@@ -5,6 +5,7 @@
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.
21
22 17/10/2013 autofs-5.0.8
23 =======================
24diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c
25index 46b3e8d..2365b6e 100644
26--- a/lib/rpc_subs.c
27+++ b/lib/rpc_subs.c
28@@ -234,6 +234,28 @@ static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, i
29
30 return 0;
31 }
32+static int rpc_getport(struct conn_info *info,
33+ struct pmap *parms, CLIENT *client)
34+{
35+ enum clnt_stat status;
36+
37+ /*
38+ * Check to see if server is up otherwise a getport will take
39+ * forever to timeout.
40+ */
41+ status = clnt_call(client, PMAPPROC_NULL,
42+ (xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
43+ info->timeout);
44+
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,
49+ info->timeout);
50+ }
51+
52+ return status;
53+}
54 #else
55 static int rpc_do_create_client(struct sockaddr *addr, struct conn_info *info, int *fd, CLIENT **client)
56 {
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
68
69 return 0;
70 }
71+
72+/*
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.
76+ */
77+static pthread_mutex_t proto_mutex = PTHREAD_MUTEX_INITIALIZER;
78+
79+static enum clnt_stat rpc_get_netid(const sa_family_t family,
80+ const int protocol, char **netid)
81+{
82+ char *nc_protofmly, *nc_proto, *nc_netid;
83+ struct netconfig *nconf;
84+ struct protoent *proto;
85+ void *handle;
86+
87+ switch (family) {
88+ case AF_LOCAL:
89+ case AF_INET:
90+ nc_protofmly = NC_INET;
91+ break;
92+ case AF_INET6:
93+ nc_protofmly = NC_INET6;
94+ break;
95+ default:
96+ return RPC_UNKNOWNPROTO;
97+ }
98+
99+ pthread_mutex_lock(&proto_mutex);
100+ proto = getprotobynumber(protocol);
101+ if (!proto) {
102+ pthread_mutex_unlock(&proto_mutex);
103+ return RPC_UNKNOWNPROTO;
104+ }
105+ nc_proto = strdup(proto->p_name);
106+ pthread_mutex_unlock(&proto_mutex);
107+ if (!nc_proto)
108+ return RPC_SYSTEMERROR;
109+
110+ handle = setnetconfig();
111+ while ((nconf = getnetconfig(handle)) != NULL) {
112+ if (nconf->nc_protofmly != NULL &&
113+ strcmp(nconf->nc_protofmly, nc_protofmly) != 0)
114+ continue;
115+ if (nconf->nc_proto != NULL &&
116+ strcmp(nconf->nc_proto, nc_proto) != 0)
117+ continue;
118+
119+ nc_netid = strdup(nconf->nc_netid);
120+ if (!nc_netid) {
121+ free(nc_proto);
122+ return RPC_SYSTEMERROR;
123+ }
124+
125+ *netid = nc_netid;
126+ }
127+ endnetconfig(handle);
128+ free(nc_proto);
129+
130+ return RPC_SUCCESS;
131+}
132+
133+static char *rpc_sockaddr2universal(const struct sockaddr *addr)
134+{
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 */];
139+ uint16_t port;
140+ size_t count;
141+ char *result;
142+ int len;
143+
144+ switch (addr->sa_family) {
145+ case AF_LOCAL:
146+ return strndup(sun->sun_path, sizeof(sun->sun_path));
147+ case AF_INET:
148+ if (inet_ntop(AF_INET, (const void *)&sin->sin_addr.s_addr,
149+ buf, (socklen_t)sizeof(buf)) == NULL)
150+ goto out_err;
151+ port = ntohs(sin->sin_port);
152+ break;
153+ case AF_INET6:
154+ if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
155+ buf, (socklen_t)sizeof(buf)) == NULL)
156+ goto out_err;
157+ port = ntohs(sin6->sin6_port);
158+ break;
159+ default:
160+ goto out_err;
161+ }
162+
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)
168+ goto out_err;
169+
170+ result = strdup(buf);
171+ return result;
172+
173+out_err:
174+ return NULL;
175+}
176+
177+static int rpc_universal2port(const char *uaddr)
178+{
179+ char *addrstr;
180+ char *p, *endptr;
181+ unsigned long portlo, porthi;
182+ int port = -1;
183+
184+ addrstr = strdup(uaddr);
185+ if (!addrstr)
186+ return -1;
187+
188+ p = strrchr(addrstr, '.');
189+ if (!p)
190+ goto out;
191+
192+ portlo = strtoul(p + 1, &endptr, 10);
193+ if (*endptr != '\0' || portlo > 255)
194+ goto out;
195+ *p = '\0';
196+
197+ p = strrchr(addrstr, '.');
198+ if (!p)
199+ goto out;
200+
201+ porthi = strtoul(p + 1, &endptr, 10);
202+ if (*endptr != '\0' || porthi > 255)
203+ goto out;
204+ *p = '\0';
205+
206+ port = (porthi << 8) | portlo;
207+
208+out:
209+ free(addrstr);
210+ return port;
211+}
212+
213+static enum clnt_stat rpc_rpcb_getport(CLIENT *client,
214+ struct rpcb *parms,
215+ struct timeval timeout,
216+ unsigned short *port)
217+{
218+ rpcvers_t rpcb_version;
219+ struct rpc_err rpcerr;
220+ int s_port = 0;
221+
222+ for (rpcb_version = RPCBVERS_4;
223+ rpcb_version >= RPCBVERS_3;
224+ rpcb_version--) {
225+ enum clnt_stat status;
226+ char *uaddr = NULL;
227+
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,
232+ timeout);
233+
234+ switch (status) {
235+ case RPC_SUCCESS:
236+ if ((uaddr == NULL) || (uaddr[0] == '\0'))
237+ return RPC_PROGNOTREGISTERED;
238+
239+ s_port = rpc_universal2port(uaddr);
240+ xdr_free((xdrproc_t) xdr_wrapstring, (char *) &uaddr);
241+ if (s_port == -1) {
242+ return RPC_N2AXLATEFAILURE;
243+ }
244+ *port = s_port;
245+ return RPC_SUCCESS;
246+
247+ case RPC_PROGVERSMISMATCH:
248+ clnt_geterr(client, &rpcerr);
249+ if (rpcerr.re_vers.low > RPCBVERS4)
250+ return status;
251+ continue;
252+ case RPC_PROCUNAVAIL:
253+ case RPC_PROGUNAVAIL:
254+ continue;
255+ default:
256+ /* Most likely RPC_TIMEDOUT or RPC_CANTRECV */
257+ return status;
258+ }
259+ }
260+
261+ if (s_port == 0)
262+ return RPC_PROGNOTREGISTERED;
263+
264+ return RPC_PROCUNAVAIL;
265+}
266+
267+static enum clnt_stat rpc_getport(struct conn_info *info,
268+ struct pmap *parms, CLIENT *client,
269+ unsigned short *port)
270+{
271+ enum clnt_stat status;
272+ struct sockaddr *paddr, addr;
273+ struct rpcb rpcb_parms;
274+ char *netid, *raddr;
275+
276+ if (info->addr)
277+ paddr = info->addr;
278+ else {
279+ if (!clnt_control(client, CLGET_SERVER_ADDR, (char *) &addr))
280+ return RPC_UNKNOWNADDR;
281+ paddr = &addr;
282+ }
283+
284+ netid = NULL;
285+ status = rpc_get_netid(paddr->sa_family, info->proto, &netid);
286+ if (status != RPC_SUCCESS)
287+ return status;
288+
289+ raddr = rpc_sockaddr2universal(paddr);
290+ if (!raddr) {
291+ free(netid);
292+ return RPC_UNKNOWNADDR;
293+ }
294+
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 = "";
301+
302+ status = rpc_rpcb_getport(client, &rpcb_parms, info->timeout, port);
303+
304+ free(netid);
305+ free(raddr);
306+
307+ return status;
308+}
309 #endif
310
311 #if defined(HAVE_GETRPCBYNAME) || defined(HAVE_GETSERVBYNAME)
312@@ -647,20 +904,7 @@ int rpc_portmap_getport(struct conn_info *info,
313 return ret;
314 }
315
316- /*
317- * Check to see if server is up otherwise a getport will take
318- * forever to timeout.
319- */
320- status = clnt_call(client, PMAPPROC_NULL,
321- (xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
322- pmap_info.timeout);
323-
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);
329- }
330+ status = rpc_getport(&pmap_info, parms, client, port);
331
332 if (!info->client) {
333 /*
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);
336
337 client->cl_auth = authunix_create_default();
338+ if (client->cl_auth == NULL) {
339+ error(LOGOPT_ANY, "auth create failed");
340+ clnt_destroy(client);
341+ return 0;
342+ }
343
344 vers_entry = 0;
345 while (1) {
This page took 0.229325 seconds and 4 git commands to generate.