eee6c5c5965df6d5bd27ea52603333aa9f51eac9
[packages/autofs.git] / autofs-5.0.8-fix-ipv6-libtirpc-getport.patch
1 autofs-5.0.8 - fix ipv6 libtirpc getport
2
3 From: Ian Kent <ikent@redhat.com>
4
5 The method that was being used to obtain a service port number
6 when using libtirpc was wrong.
7 ---
8  CHANGELOG      |    1 
9  lib/rpc_subs.c |  283 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
10  2 files changed, 267 insertions(+), 17 deletions(-)
11
12 diff --git a/CHANGELOG b/CHANGELOG
13 index 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  =======================
24 diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c
25 index 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.141807 seconds and 2 git commands to generate.