1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
3 | /* $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $ */ |
---|
4 | |
---|
5 | /*- |
---|
6 | * Copyright (c) 2010, Oracle America, Inc. |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions are met: |
---|
11 | * - Redistributions of source code must retain the above copyright notice, |
---|
12 | * this list of conditions and the following disclaimer. |
---|
13 | * - Redistributions in binary form must reproduce the above copyright notice, |
---|
14 | * this list of conditions and the following disclaimer in the documentation |
---|
15 | * and/or other materials provided with the distribution. |
---|
16 | * - Neither the name of the "Oracle America, Inc." nor the names of its |
---|
17 | * contributors may be used to endorse or promote products derived |
---|
18 | * from this software without specific prior written permission. |
---|
19 | * |
---|
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
---|
24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
30 | * POSSIBILITY OF SUCH DAMAGE. |
---|
31 | */ |
---|
32 | |
---|
33 | /* #ident "@(#)rpcb_clnt.c 1.27 94/04/24 SMI" */ |
---|
34 | |
---|
35 | |
---|
36 | #if defined(LIBC_SCCS) && !defined(lint) |
---|
37 | static char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro"; |
---|
38 | #endif |
---|
39 | #include <sys/cdefs.h> |
---|
40 | __FBSDID("$FreeBSD$"); |
---|
41 | |
---|
42 | /* |
---|
43 | * rpcb_clnt.c |
---|
44 | * interface to rpcbind rpc service. |
---|
45 | */ |
---|
46 | |
---|
47 | #include "namespace.h" |
---|
48 | #include "reentrant.h" |
---|
49 | #include <sys/types.h> |
---|
50 | #include <sys/socket.h> |
---|
51 | #include <sys/un.h> |
---|
52 | #include <sys/utsname.h> |
---|
53 | #include <rpc/rpc.h> |
---|
54 | #include <rpc/rpcb_prot.h> |
---|
55 | #include <rpc/nettype.h> |
---|
56 | #include <netconfig.h> |
---|
57 | #ifdef PORTMAP |
---|
58 | #include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */ |
---|
59 | #include <rpc/pmap_prot.h> |
---|
60 | #endif /* PORTMAP */ |
---|
61 | #include <stdio.h> |
---|
62 | #include <errno.h> |
---|
63 | #include <stdlib.h> |
---|
64 | #include <string.h> |
---|
65 | #include <unistd.h> |
---|
66 | #include <netdb.h> |
---|
67 | #include <syslog.h> |
---|
68 | #include "un-namespace.h" |
---|
69 | |
---|
70 | #include "rpc_com.h" |
---|
71 | #include "mt_misc.h" |
---|
72 | |
---|
73 | static struct timeval tottimeout = { 60, 0 }; |
---|
74 | static const struct timeval rmttimeout = { 3, 0 }; |
---|
75 | static struct timeval rpcbrmttime = { 15, 0 }; |
---|
76 | |
---|
77 | extern bool_t xdr_wrapstring(XDR *, char **); |
---|
78 | |
---|
79 | static const char nullstring[] = "\000"; |
---|
80 | |
---|
81 | #define CACHESIZE 6 |
---|
82 | |
---|
83 | struct address_cache { |
---|
84 | char *ac_host; |
---|
85 | char *ac_netid; |
---|
86 | char *ac_uaddr; |
---|
87 | struct netbuf *ac_taddr; |
---|
88 | struct address_cache *ac_next; |
---|
89 | }; |
---|
90 | |
---|
91 | static struct address_cache *front; |
---|
92 | static int cachesize; |
---|
93 | |
---|
94 | #define CLCR_GET_RPCB_TIMEOUT 1 |
---|
95 | #define CLCR_SET_RPCB_TIMEOUT 2 |
---|
96 | |
---|
97 | |
---|
98 | extern int __rpc_lowvers; |
---|
99 | |
---|
100 | static struct address_cache *check_cache(const char *, const char *); |
---|
101 | static void delete_cache(struct netbuf *); |
---|
102 | static void add_cache(const char *, const char *, struct netbuf *, char *); |
---|
103 | static CLIENT *getclnthandle(const char *, const struct netconfig *, char **); |
---|
104 | static CLIENT *local_rpcb(void); |
---|
105 | static struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *); |
---|
106 | |
---|
107 | /* |
---|
108 | * This routine adjusts the timeout used for calls to the remote rpcbind. |
---|
109 | * Also, this routine can be used to set the use of portmapper version 2 |
---|
110 | * only when doing rpc_broadcasts |
---|
111 | * These are private routines that may not be provided in future releases. |
---|
112 | */ |
---|
113 | bool_t |
---|
114 | __rpc_control(request, info) |
---|
115 | int request; |
---|
116 | void *info; |
---|
117 | { |
---|
118 | switch (request) { |
---|
119 | case CLCR_GET_RPCB_TIMEOUT: |
---|
120 | *(struct timeval *)info = tottimeout; |
---|
121 | break; |
---|
122 | case CLCR_SET_RPCB_TIMEOUT: |
---|
123 | tottimeout = *(struct timeval *)info; |
---|
124 | break; |
---|
125 | case CLCR_SET_LOWVERS: |
---|
126 | __rpc_lowvers = *(int *)info; |
---|
127 | break; |
---|
128 | case CLCR_GET_LOWVERS: |
---|
129 | *(int *)info = __rpc_lowvers; |
---|
130 | break; |
---|
131 | default: |
---|
132 | return (FALSE); |
---|
133 | } |
---|
134 | return (TRUE); |
---|
135 | } |
---|
136 | |
---|
137 | /* |
---|
138 | * It might seem that a reader/writer lock would be more reasonable here. |
---|
139 | * However because getclnthandle(), the only user of the cache functions, |
---|
140 | * may do a delete_cache() operation if a check_cache() fails to return an |
---|
141 | * address useful to clnt_tli_create(), we may as well use a mutex. |
---|
142 | */ |
---|
143 | /* |
---|
144 | * As it turns out, if the cache lock is *not* a reader/writer lock, we will |
---|
145 | * block all clnt_create's if we are trying to connect to a host that's down, |
---|
146 | * since the lock will be held all during that time. |
---|
147 | */ |
---|
148 | |
---|
149 | /* |
---|
150 | * The routines check_cache(), add_cache(), delete_cache() manage the |
---|
151 | * cache of rpcbind addresses for (host, netid). |
---|
152 | */ |
---|
153 | |
---|
154 | static struct address_cache * |
---|
155 | check_cache(host, netid) |
---|
156 | const char *host, *netid; |
---|
157 | { |
---|
158 | struct address_cache *cptr; |
---|
159 | |
---|
160 | /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ |
---|
161 | |
---|
162 | for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { |
---|
163 | if (!strcmp(cptr->ac_host, host) && |
---|
164 | !strcmp(cptr->ac_netid, netid)) { |
---|
165 | #ifdef ND_DEBUG |
---|
166 | fprintf(stderr, "Found cache entry for %s: %s\n", |
---|
167 | host, netid); |
---|
168 | #endif |
---|
169 | return (cptr); |
---|
170 | } |
---|
171 | } |
---|
172 | return ((struct address_cache *) NULL); |
---|
173 | } |
---|
174 | |
---|
175 | static void |
---|
176 | delete_cache(addr) |
---|
177 | struct netbuf *addr; |
---|
178 | { |
---|
179 | struct address_cache *cptr, *prevptr = NULL; |
---|
180 | |
---|
181 | /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ |
---|
182 | for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { |
---|
183 | if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) { |
---|
184 | free(cptr->ac_host); |
---|
185 | free(cptr->ac_netid); |
---|
186 | free(cptr->ac_taddr->buf); |
---|
187 | free(cptr->ac_taddr); |
---|
188 | if (cptr->ac_uaddr) |
---|
189 | free(cptr->ac_uaddr); |
---|
190 | if (prevptr) |
---|
191 | prevptr->ac_next = cptr->ac_next; |
---|
192 | else |
---|
193 | front = cptr->ac_next; |
---|
194 | free(cptr); |
---|
195 | cachesize--; |
---|
196 | break; |
---|
197 | } |
---|
198 | prevptr = cptr; |
---|
199 | } |
---|
200 | } |
---|
201 | |
---|
202 | static void |
---|
203 | add_cache(host, netid, taddr, uaddr) |
---|
204 | const char *host, *netid; |
---|
205 | char *uaddr; |
---|
206 | struct netbuf *taddr; |
---|
207 | { |
---|
208 | struct address_cache *ad_cache, *cptr, *prevptr; |
---|
209 | |
---|
210 | ad_cache = (struct address_cache *) |
---|
211 | malloc(sizeof (struct address_cache)); |
---|
212 | if (!ad_cache) { |
---|
213 | return; |
---|
214 | } |
---|
215 | ad_cache->ac_host = strdup(host); |
---|
216 | ad_cache->ac_netid = strdup(netid); |
---|
217 | ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL; |
---|
218 | ad_cache->ac_taddr = (struct netbuf *)malloc(sizeof (struct netbuf)); |
---|
219 | if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr || |
---|
220 | (uaddr && !ad_cache->ac_uaddr)) { |
---|
221 | goto out; |
---|
222 | } |
---|
223 | ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len; |
---|
224 | ad_cache->ac_taddr->buf = (char *) malloc(taddr->len); |
---|
225 | if (ad_cache->ac_taddr->buf == NULL) { |
---|
226 | out: |
---|
227 | if (ad_cache->ac_host) |
---|
228 | free(ad_cache->ac_host); |
---|
229 | if (ad_cache->ac_netid) |
---|
230 | free(ad_cache->ac_netid); |
---|
231 | if (ad_cache->ac_uaddr) |
---|
232 | free(ad_cache->ac_uaddr); |
---|
233 | if (ad_cache->ac_taddr) |
---|
234 | free(ad_cache->ac_taddr); |
---|
235 | free(ad_cache); |
---|
236 | return; |
---|
237 | } |
---|
238 | memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len); |
---|
239 | #ifdef ND_DEBUG |
---|
240 | fprintf(stderr, "Added to cache: %s : %s\n", host, netid); |
---|
241 | #endif |
---|
242 | |
---|
243 | /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */ |
---|
244 | |
---|
245 | rwlock_wrlock(&rpcbaddr_cache_lock); |
---|
246 | if (cachesize < CACHESIZE) { |
---|
247 | ad_cache->ac_next = front; |
---|
248 | front = ad_cache; |
---|
249 | cachesize++; |
---|
250 | } else { |
---|
251 | /* Free the last entry */ |
---|
252 | cptr = front; |
---|
253 | prevptr = NULL; |
---|
254 | while (cptr->ac_next) { |
---|
255 | prevptr = cptr; |
---|
256 | cptr = cptr->ac_next; |
---|
257 | } |
---|
258 | |
---|
259 | #ifdef ND_DEBUG |
---|
260 | fprintf(stderr, "Deleted from cache: %s : %s\n", |
---|
261 | cptr->ac_host, cptr->ac_netid); |
---|
262 | #endif |
---|
263 | free(cptr->ac_host); |
---|
264 | free(cptr->ac_netid); |
---|
265 | free(cptr->ac_taddr->buf); |
---|
266 | free(cptr->ac_taddr); |
---|
267 | if (cptr->ac_uaddr) |
---|
268 | free(cptr->ac_uaddr); |
---|
269 | |
---|
270 | if (prevptr) { |
---|
271 | prevptr->ac_next = NULL; |
---|
272 | ad_cache->ac_next = front; |
---|
273 | front = ad_cache; |
---|
274 | } else { |
---|
275 | front = ad_cache; |
---|
276 | ad_cache->ac_next = NULL; |
---|
277 | } |
---|
278 | free(cptr); |
---|
279 | } |
---|
280 | rwlock_unlock(&rpcbaddr_cache_lock); |
---|
281 | } |
---|
282 | |
---|
283 | /* |
---|
284 | * This routine will return a client handle that is connected to the |
---|
285 | * rpcbind. If targaddr is non-NULL, the "universal address" of the |
---|
286 | * host will be stored in *targaddr; the caller is responsible for |
---|
287 | * freeing this string. |
---|
288 | * On error, returns NULL and free's everything. |
---|
289 | */ |
---|
290 | static CLIENT * |
---|
291 | getclnthandle(host, nconf, targaddr) |
---|
292 | const char *host; |
---|
293 | const struct netconfig *nconf; |
---|
294 | char **targaddr; |
---|
295 | { |
---|
296 | CLIENT *client; |
---|
297 | struct netbuf *addr, taddr; |
---|
298 | struct netbuf addr_to_delete; |
---|
299 | struct __rpc_sockinfo si; |
---|
300 | struct addrinfo hints, *res, *tres; |
---|
301 | struct address_cache *ad_cache; |
---|
302 | char *tmpaddr; |
---|
303 | |
---|
304 | /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */ |
---|
305 | |
---|
306 | /* Get the address of the rpcbind. Check cache first */ |
---|
307 | client = NULL; |
---|
308 | addr_to_delete.len = 0; |
---|
309 | rwlock_rdlock(&rpcbaddr_cache_lock); |
---|
310 | ad_cache = NULL; |
---|
311 | if (host != NULL) |
---|
312 | ad_cache = check_cache(host, nconf->nc_netid); |
---|
313 | if (ad_cache != NULL) { |
---|
314 | addr = ad_cache->ac_taddr; |
---|
315 | client = clnt_tli_create(RPC_ANYFD, nconf, addr, |
---|
316 | (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); |
---|
317 | if (client != NULL) { |
---|
318 | if (targaddr) |
---|
319 | *targaddr = strdup(ad_cache->ac_uaddr); |
---|
320 | rwlock_unlock(&rpcbaddr_cache_lock); |
---|
321 | return (client); |
---|
322 | } |
---|
323 | addr_to_delete.len = addr->len; |
---|
324 | addr_to_delete.buf = (char *)malloc(addr->len); |
---|
325 | if (addr_to_delete.buf == NULL) { |
---|
326 | addr_to_delete.len = 0; |
---|
327 | } else { |
---|
328 | memcpy(addr_to_delete.buf, addr->buf, addr->len); |
---|
329 | } |
---|
330 | } |
---|
331 | rwlock_unlock(&rpcbaddr_cache_lock); |
---|
332 | if (addr_to_delete.len != 0) { |
---|
333 | /* |
---|
334 | * Assume this may be due to cache data being |
---|
335 | * outdated |
---|
336 | */ |
---|
337 | rwlock_wrlock(&rpcbaddr_cache_lock); |
---|
338 | delete_cache(&addr_to_delete); |
---|
339 | rwlock_unlock(&rpcbaddr_cache_lock); |
---|
340 | free(addr_to_delete.buf); |
---|
341 | } |
---|
342 | if (!__rpc_nconf2sockinfo(nconf, &si)) { |
---|
343 | rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; |
---|
344 | return NULL; |
---|
345 | } |
---|
346 | |
---|
347 | memset(&hints, 0, sizeof hints); |
---|
348 | hints.ai_family = si.si_af; |
---|
349 | hints.ai_socktype = si.si_socktype; |
---|
350 | hints.ai_protocol = si.si_proto; |
---|
351 | |
---|
352 | #ifdef CLNT_DEBUG |
---|
353 | printf("trying netid %s family %d proto %d socktype %d\n", |
---|
354 | nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype); |
---|
355 | #endif |
---|
356 | |
---|
357 | if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { |
---|
358 | client = local_rpcb(); |
---|
359 | if (! client) { |
---|
360 | #ifdef ND_DEBUG |
---|
361 | clnt_pcreateerror("rpcbind clnt interface"); |
---|
362 | #endif |
---|
363 | return (NULL); |
---|
364 | } else { |
---|
365 | struct sockaddr_un sun; |
---|
366 | if (targaddr) { |
---|
367 | *targaddr = malloc(sizeof(sun.sun_path)); |
---|
368 | if (*targaddr == NULL) { |
---|
369 | CLNT_DESTROY(client); |
---|
370 | return (NULL); |
---|
371 | } |
---|
372 | strncpy(*targaddr, _PATH_RPCBINDSOCK, |
---|
373 | sizeof(sun.sun_path)); |
---|
374 | } |
---|
375 | return (client); |
---|
376 | } |
---|
377 | } else { |
---|
378 | if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) { |
---|
379 | rpc_createerr.cf_stat = RPC_UNKNOWNHOST; |
---|
380 | return NULL; |
---|
381 | } |
---|
382 | } |
---|
383 | |
---|
384 | for (tres = res; tres != NULL; tres = tres->ai_next) { |
---|
385 | taddr.buf = tres->ai_addr; |
---|
386 | taddr.len = taddr.maxlen = tres->ai_addrlen; |
---|
387 | |
---|
388 | #ifdef ND_DEBUG |
---|
389 | { |
---|
390 | char *ua; |
---|
391 | |
---|
392 | ua = taddr2uaddr(nconf, &taddr); |
---|
393 | fprintf(stderr, "Got it [%s]\n", ua); |
---|
394 | free(ua); |
---|
395 | } |
---|
396 | #endif |
---|
397 | |
---|
398 | #ifdef ND_DEBUG |
---|
399 | { |
---|
400 | int i; |
---|
401 | |
---|
402 | fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n", |
---|
403 | taddr.len, taddr.maxlen); |
---|
404 | fprintf(stderr, "\tAddress is "); |
---|
405 | for (i = 0; i < taddr.len; i++) |
---|
406 | fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]); |
---|
407 | fprintf(stderr, "\n"); |
---|
408 | } |
---|
409 | #endif |
---|
410 | client = clnt_tli_create(RPC_ANYFD, nconf, &taddr, |
---|
411 | (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0); |
---|
412 | #ifdef ND_DEBUG |
---|
413 | if (! client) { |
---|
414 | clnt_pcreateerror("rpcbind clnt interface"); |
---|
415 | } |
---|
416 | #endif |
---|
417 | |
---|
418 | if (client) { |
---|
419 | tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL; |
---|
420 | add_cache(host, nconf->nc_netid, &taddr, tmpaddr); |
---|
421 | if (targaddr) |
---|
422 | *targaddr = tmpaddr; |
---|
423 | break; |
---|
424 | } |
---|
425 | } |
---|
426 | if (res) |
---|
427 | freeaddrinfo(res); |
---|
428 | return (client); |
---|
429 | } |
---|
430 | |
---|
431 | /* XXX */ |
---|
432 | #define IN4_LOCALHOST_STRING "127.0.0.1" |
---|
433 | #define IN6_LOCALHOST_STRING "::1" |
---|
434 | |
---|
435 | /* |
---|
436 | * This routine will return a client handle that is connected to the local |
---|
437 | * rpcbind. Returns NULL on error and free's everything. |
---|
438 | */ |
---|
439 | static CLIENT * |
---|
440 | local_rpcb() |
---|
441 | { |
---|
442 | CLIENT *client; |
---|
443 | static struct netconfig *loopnconf; |
---|
444 | static char *hostname; |
---|
445 | int sock; |
---|
446 | size_t tsize; |
---|
447 | struct netbuf nbuf; |
---|
448 | struct sockaddr_un sun; |
---|
449 | |
---|
450 | /* |
---|
451 | * Try connecting to the local rpcbind through a local socket |
---|
452 | * first. If this doesn't work, try all transports defined in |
---|
453 | * the netconfig file. |
---|
454 | */ |
---|
455 | memset(&sun, 0, sizeof sun); |
---|
456 | sock = _socket(AF_LOCAL, SOCK_STREAM, 0); |
---|
457 | if (sock < 0) |
---|
458 | goto try_nconf; |
---|
459 | sun.sun_family = AF_LOCAL; |
---|
460 | strcpy(sun.sun_path, _PATH_RPCBINDSOCK); |
---|
461 | nbuf.len = sun.sun_len = SUN_LEN(&sun); |
---|
462 | nbuf.maxlen = sizeof (struct sockaddr_un); |
---|
463 | nbuf.buf = &sun; |
---|
464 | |
---|
465 | tsize = __rpc_get_t_size(AF_LOCAL, 0, 0); |
---|
466 | client = clnt_vc_create(sock, &nbuf, (rpcprog_t)RPCBPROG, |
---|
467 | (rpcvers_t)RPCBVERS, tsize, tsize); |
---|
468 | |
---|
469 | if (client != NULL) { |
---|
470 | /* Mark the socket to be closed in destructor */ |
---|
471 | (void) CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL); |
---|
472 | return client; |
---|
473 | } |
---|
474 | |
---|
475 | /* Nobody needs this socket anymore; free the descriptor. */ |
---|
476 | _close(sock); |
---|
477 | |
---|
478 | try_nconf: |
---|
479 | |
---|
480 | /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */ |
---|
481 | mutex_lock(&loopnconf_lock); |
---|
482 | if (loopnconf == NULL) { |
---|
483 | struct netconfig *nconf, *tmpnconf = NULL; |
---|
484 | void *nc_handle; |
---|
485 | int fd; |
---|
486 | |
---|
487 | nc_handle = setnetconfig(); |
---|
488 | if (nc_handle == NULL) { |
---|
489 | /* fails to open netconfig file */ |
---|
490 | syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); |
---|
491 | rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; |
---|
492 | mutex_unlock(&loopnconf_lock); |
---|
493 | return (NULL); |
---|
494 | } |
---|
495 | while ((nconf = getnetconfig(nc_handle)) != NULL) { |
---|
496 | #ifdef INET6 |
---|
497 | if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0 || |
---|
498 | #else |
---|
499 | if (( |
---|
500 | #endif |
---|
501 | strcmp(nconf->nc_protofmly, NC_INET) == 0) && |
---|
502 | (nconf->nc_semantics == NC_TPI_COTS || |
---|
503 | nconf->nc_semantics == NC_TPI_COTS_ORD)) { |
---|
504 | fd = __rpc_nconf2fd(nconf); |
---|
505 | /* |
---|
506 | * Can't create a socket, assume that |
---|
507 | * this family isn't configured in the kernel. |
---|
508 | */ |
---|
509 | if (fd < 0) |
---|
510 | continue; |
---|
511 | _close(fd); |
---|
512 | tmpnconf = nconf; |
---|
513 | if (!strcmp(nconf->nc_protofmly, NC_INET)) |
---|
514 | hostname = IN4_LOCALHOST_STRING; |
---|
515 | else |
---|
516 | hostname = IN6_LOCALHOST_STRING; |
---|
517 | } |
---|
518 | } |
---|
519 | if (tmpnconf == NULL) { |
---|
520 | rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; |
---|
521 | mutex_unlock(&loopnconf_lock); |
---|
522 | return (NULL); |
---|
523 | } |
---|
524 | loopnconf = getnetconfigent(tmpnconf->nc_netid); |
---|
525 | /* loopnconf is never freed */ |
---|
526 | endnetconfig(nc_handle); |
---|
527 | } |
---|
528 | mutex_unlock(&loopnconf_lock); |
---|
529 | client = getclnthandle(hostname, loopnconf, NULL); |
---|
530 | return (client); |
---|
531 | } |
---|
532 | |
---|
533 | /* |
---|
534 | * Set a mapping between program, version and address. |
---|
535 | * Calls the rpcbind service to do the mapping. |
---|
536 | */ |
---|
537 | bool_t |
---|
538 | rpcb_set(program, version, nconf, address) |
---|
539 | rpcprog_t program; |
---|
540 | rpcvers_t version; |
---|
541 | const struct netconfig *nconf; /* Network structure of transport */ |
---|
542 | const struct netbuf *address; /* Services netconfig address */ |
---|
543 | { |
---|
544 | CLIENT *client; |
---|
545 | bool_t rslt = FALSE; |
---|
546 | RPCB parms; |
---|
547 | char uidbuf[32]; |
---|
548 | |
---|
549 | /* parameter checking */ |
---|
550 | if (nconf == NULL) { |
---|
551 | rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; |
---|
552 | return (FALSE); |
---|
553 | } |
---|
554 | if (address == NULL) { |
---|
555 | rpc_createerr.cf_stat = RPC_UNKNOWNADDR; |
---|
556 | return (FALSE); |
---|
557 | } |
---|
558 | client = local_rpcb(); |
---|
559 | if (! client) { |
---|
560 | return (FALSE); |
---|
561 | } |
---|
562 | |
---|
563 | /* convert to universal */ |
---|
564 | /*LINTED const castaway*/ |
---|
565 | parms.r_addr = taddr2uaddr((struct netconfig *) nconf, |
---|
566 | (struct netbuf *)address); |
---|
567 | if (!parms.r_addr) { |
---|
568 | CLNT_DESTROY(client); |
---|
569 | rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; |
---|
570 | return (FALSE); /* no universal address */ |
---|
571 | } |
---|
572 | parms.r_prog = program; |
---|
573 | parms.r_vers = version; |
---|
574 | parms.r_netid = nconf->nc_netid; |
---|
575 | /* |
---|
576 | * Though uid is not being used directly, we still send it for |
---|
577 | * completeness. For non-unix platforms, perhaps some other |
---|
578 | * string or an empty string can be sent. |
---|
579 | */ |
---|
580 | (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); |
---|
581 | parms.r_owner = uidbuf; |
---|
582 | |
---|
583 | CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb, |
---|
584 | (char *)(void *)&parms, (xdrproc_t) xdr_bool, |
---|
585 | (char *)(void *)&rslt, tottimeout); |
---|
586 | |
---|
587 | CLNT_DESTROY(client); |
---|
588 | free(parms.r_addr); |
---|
589 | return (rslt); |
---|
590 | } |
---|
591 | |
---|
592 | /* |
---|
593 | * Remove the mapping between program, version and netbuf address. |
---|
594 | * Calls the rpcbind service to do the un-mapping. |
---|
595 | * If netbuf is NULL, unset for all the transports, otherwise unset |
---|
596 | * only for the given transport. |
---|
597 | */ |
---|
598 | bool_t |
---|
599 | rpcb_unset(program, version, nconf) |
---|
600 | rpcprog_t program; |
---|
601 | rpcvers_t version; |
---|
602 | const struct netconfig *nconf; |
---|
603 | { |
---|
604 | CLIENT *client; |
---|
605 | bool_t rslt = FALSE; |
---|
606 | RPCB parms; |
---|
607 | char uidbuf[32]; |
---|
608 | |
---|
609 | client = local_rpcb(); |
---|
610 | if (! client) { |
---|
611 | return (FALSE); |
---|
612 | } |
---|
613 | |
---|
614 | parms.r_prog = program; |
---|
615 | parms.r_vers = version; |
---|
616 | if (nconf) |
---|
617 | parms.r_netid = nconf->nc_netid; |
---|
618 | else { |
---|
619 | /*LINTED const castaway*/ |
---|
620 | parms.r_netid = (char *) &nullstring[0]; /* unsets all */ |
---|
621 | } |
---|
622 | /*LINTED const castaway*/ |
---|
623 | parms.r_addr = (char *) &nullstring[0]; |
---|
624 | (void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid()); |
---|
625 | parms.r_owner = uidbuf; |
---|
626 | |
---|
627 | CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb, |
---|
628 | (char *)(void *)&parms, (xdrproc_t) xdr_bool, |
---|
629 | (char *)(void *)&rslt, tottimeout); |
---|
630 | |
---|
631 | CLNT_DESTROY(client); |
---|
632 | return (rslt); |
---|
633 | } |
---|
634 | |
---|
635 | /* |
---|
636 | * From the merged list, find the appropriate entry |
---|
637 | */ |
---|
638 | static struct netbuf * |
---|
639 | got_entry(relp, nconf) |
---|
640 | rpcb_entry_list_ptr relp; |
---|
641 | const struct netconfig *nconf; |
---|
642 | { |
---|
643 | struct netbuf *na = NULL; |
---|
644 | rpcb_entry_list_ptr sp; |
---|
645 | rpcb_entry *rmap; |
---|
646 | |
---|
647 | for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) { |
---|
648 | rmap = &sp->rpcb_entry_map; |
---|
649 | if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) && |
---|
650 | (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) && |
---|
651 | (nconf->nc_semantics == rmap->r_nc_semantics) && |
---|
652 | (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) { |
---|
653 | na = uaddr2taddr(nconf, rmap->r_maddr); |
---|
654 | #ifdef ND_DEBUG |
---|
655 | fprintf(stderr, "\tRemote address is [%s].\n", |
---|
656 | rmap->r_maddr); |
---|
657 | if (!na) |
---|
658 | fprintf(stderr, |
---|
659 | "\tCouldn't resolve remote address!\n"); |
---|
660 | #endif |
---|
661 | break; |
---|
662 | } |
---|
663 | } |
---|
664 | return (na); |
---|
665 | } |
---|
666 | |
---|
667 | /* |
---|
668 | * Quick check to see if rpcbind is up. Tries to connect over |
---|
669 | * local transport. |
---|
670 | */ |
---|
671 | static bool_t |
---|
672 | __rpcbind_is_up() |
---|
673 | { |
---|
674 | struct netconfig *nconf; |
---|
675 | struct sockaddr_un sun; |
---|
676 | void *localhandle; |
---|
677 | int sock; |
---|
678 | |
---|
679 | nconf = NULL; |
---|
680 | localhandle = setnetconfig(); |
---|
681 | while ((nconf = getnetconfig(localhandle)) != NULL) { |
---|
682 | if (nconf->nc_protofmly != NULL && |
---|
683 | strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) |
---|
684 | break; |
---|
685 | } |
---|
686 | if (nconf == NULL) |
---|
687 | return (FALSE); |
---|
688 | |
---|
689 | endnetconfig(localhandle); |
---|
690 | |
---|
691 | memset(&sun, 0, sizeof sun); |
---|
692 | sock = _socket(AF_LOCAL, SOCK_STREAM, 0); |
---|
693 | if (sock < 0) |
---|
694 | return (FALSE); |
---|
695 | sun.sun_family = AF_LOCAL; |
---|
696 | strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path)); |
---|
697 | sun.sun_len = SUN_LEN(&sun); |
---|
698 | |
---|
699 | if (_connect(sock, (struct sockaddr *)&sun, sun.sun_len) < 0) { |
---|
700 | _close(sock); |
---|
701 | return (FALSE); |
---|
702 | } |
---|
703 | |
---|
704 | _close(sock); |
---|
705 | return (TRUE); |
---|
706 | } |
---|
707 | |
---|
708 | /* |
---|
709 | * An internal function which optimizes rpcb_getaddr function. It also |
---|
710 | * returns the client handle that it uses to contact the remote rpcbind. |
---|
711 | * |
---|
712 | * The algorithm used: If the transports is TCP or UDP, it first tries |
---|
713 | * version 2 (portmap), 4 and then 3 (svr4). This order should be |
---|
714 | * changed in the next OS release to 4, 2 and 3. We are assuming that by |
---|
715 | * that time, version 4 would be available on many machines on the network. |
---|
716 | * With this algorithm, we get performance as well as a plan for |
---|
717 | * obsoleting version 2. |
---|
718 | * |
---|
719 | * For all other transports, the algorithm remains as 4 and then 3. |
---|
720 | * |
---|
721 | * XXX: Due to some problems with t_connect(), we do not reuse the same client |
---|
722 | * handle for COTS cases and hence in these cases we do not return the |
---|
723 | * client handle. This code will change if t_connect() ever |
---|
724 | * starts working properly. Also look under clnt_vc.c. |
---|
725 | */ |
---|
726 | struct netbuf * |
---|
727 | __rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) |
---|
728 | rpcprog_t program; |
---|
729 | rpcvers_t version; |
---|
730 | const struct netconfig *nconf; |
---|
731 | const char *host; |
---|
732 | CLIENT **clpp; |
---|
733 | struct timeval *tp; |
---|
734 | { |
---|
735 | static bool_t check_rpcbind = TRUE; |
---|
736 | CLIENT *client = NULL; |
---|
737 | RPCB parms; |
---|
738 | enum clnt_stat clnt_st; |
---|
739 | char *ua = NULL; |
---|
740 | rpcvers_t vers; |
---|
741 | struct netbuf *address = NULL; |
---|
742 | rpcvers_t start_vers = RPCBVERS4; |
---|
743 | struct netbuf servaddr; |
---|
744 | |
---|
745 | /* parameter checking */ |
---|
746 | if (nconf == NULL) { |
---|
747 | rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; |
---|
748 | return (NULL); |
---|
749 | } |
---|
750 | |
---|
751 | parms.r_addr = NULL; |
---|
752 | |
---|
753 | /* |
---|
754 | * Use default total timeout if no timeout is specified. |
---|
755 | */ |
---|
756 | if (tp == NULL) |
---|
757 | tp = &tottimeout; |
---|
758 | |
---|
759 | #ifdef PORTMAP |
---|
760 | /* Try version 2 for TCP or UDP */ |
---|
761 | if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { |
---|
762 | u_short port = 0; |
---|
763 | struct netbuf remote; |
---|
764 | rpcvers_t pmapvers = 2; |
---|
765 | struct pmap pmapparms; |
---|
766 | |
---|
767 | /* |
---|
768 | * Try UDP only - there are some portmappers out |
---|
769 | * there that use UDP only. |
---|
770 | */ |
---|
771 | if (strcmp(nconf->nc_proto, NC_TCP) == 0) { |
---|
772 | struct netconfig *newnconf; |
---|
773 | |
---|
774 | if ((newnconf = getnetconfigent("udp")) == NULL) { |
---|
775 | rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; |
---|
776 | return (NULL); |
---|
777 | } |
---|
778 | client = getclnthandle(host, newnconf, &parms.r_addr); |
---|
779 | freenetconfigent(newnconf); |
---|
780 | } else { |
---|
781 | client = getclnthandle(host, nconf, &parms.r_addr); |
---|
782 | } |
---|
783 | if (client == NULL) |
---|
784 | return (NULL); |
---|
785 | |
---|
786 | /* |
---|
787 | * Set version and retry timeout. |
---|
788 | */ |
---|
789 | CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); |
---|
790 | CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers); |
---|
791 | |
---|
792 | pmapparms.pm_prog = program; |
---|
793 | pmapparms.pm_vers = version; |
---|
794 | pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? |
---|
795 | IPPROTO_UDP : IPPROTO_TCP; |
---|
796 | pmapparms.pm_port = 0; /* not needed */ |
---|
797 | clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, |
---|
798 | (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, |
---|
799 | (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, |
---|
800 | *tp); |
---|
801 | if (clnt_st != RPC_SUCCESS) { |
---|
802 | if ((clnt_st == RPC_PROGVERSMISMATCH) || |
---|
803 | (clnt_st == RPC_PROGUNAVAIL)) |
---|
804 | goto try_rpcbind; /* Try different versions */ |
---|
805 | rpc_createerr.cf_stat = RPC_PMAPFAILURE; |
---|
806 | clnt_geterr(client, &rpc_createerr.cf_error); |
---|
807 | goto error; |
---|
808 | } else if (port == 0) { |
---|
809 | address = NULL; |
---|
810 | rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; |
---|
811 | goto error; |
---|
812 | } |
---|
813 | port = htons(port); |
---|
814 | CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote); |
---|
815 | if (((address = (struct netbuf *) |
---|
816 | malloc(sizeof (struct netbuf))) == NULL) || |
---|
817 | ((address->buf = (char *) |
---|
818 | malloc(remote.len)) == NULL)) { |
---|
819 | rpc_createerr.cf_stat = RPC_SYSTEMERROR; |
---|
820 | clnt_geterr(client, &rpc_createerr.cf_error); |
---|
821 | if (address) { |
---|
822 | free(address); |
---|
823 | address = NULL; |
---|
824 | } |
---|
825 | goto error; |
---|
826 | } |
---|
827 | memcpy(address->buf, remote.buf, remote.len); |
---|
828 | memcpy(&((char *)address->buf)[sizeof (short)], |
---|
829 | (char *)(void *)&port, sizeof (short)); |
---|
830 | address->len = address->maxlen = remote.len; |
---|
831 | goto done; |
---|
832 | } |
---|
833 | #endif /* PORTMAP */ |
---|
834 | |
---|
835 | try_rpcbind: |
---|
836 | /* |
---|
837 | * Check if rpcbind is up. This prevents needless delays when |
---|
838 | * accessing applications such as the keyserver while booting |
---|
839 | * disklessly. |
---|
840 | */ |
---|
841 | if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { |
---|
842 | if (!__rpcbind_is_up()) { |
---|
843 | rpc_createerr.cf_stat = RPC_PMAPFAILURE; |
---|
844 | rpc_createerr.cf_error.re_errno = 0; |
---|
845 | goto error; |
---|
846 | } |
---|
847 | check_rpcbind = FALSE; |
---|
848 | } |
---|
849 | |
---|
850 | /* |
---|
851 | * Now we try version 4 and then 3. |
---|
852 | * We also send the remote system the address we used to |
---|
853 | * contact it in case it can help to connect back with us |
---|
854 | */ |
---|
855 | parms.r_prog = program; |
---|
856 | parms.r_vers = version; |
---|
857 | /*LINTED const castaway*/ |
---|
858 | parms.r_owner = (char *) &nullstring[0]; /* not needed; */ |
---|
859 | /* just for xdring */ |
---|
860 | parms.r_netid = nconf->nc_netid; /* not really needed */ |
---|
861 | |
---|
862 | /* |
---|
863 | * If a COTS transport is being used, try getting address via CLTS |
---|
864 | * transport. This works only with version 4. |
---|
865 | */ |
---|
866 | if (nconf->nc_semantics == NC_TPI_COTS_ORD || |
---|
867 | nconf->nc_semantics == NC_TPI_COTS) { |
---|
868 | |
---|
869 | void *handle; |
---|
870 | struct netconfig *nconf_clts; |
---|
871 | rpcb_entry_list_ptr relp = NULL; |
---|
872 | |
---|
873 | if (client == NULL) { |
---|
874 | /* This did not go through the above PORTMAP/TCP code */ |
---|
875 | if ((handle = __rpc_setconf("datagram_v")) != NULL) { |
---|
876 | while ((nconf_clts = __rpc_getconf(handle)) |
---|
877 | != NULL) { |
---|
878 | if (strcmp(nconf_clts->nc_protofmly, |
---|
879 | nconf->nc_protofmly) != 0) { |
---|
880 | continue; |
---|
881 | } |
---|
882 | client = getclnthandle(host, nconf_clts, |
---|
883 | &parms.r_addr); |
---|
884 | break; |
---|
885 | } |
---|
886 | __rpc_endconf(handle); |
---|
887 | } |
---|
888 | if (client == NULL) |
---|
889 | goto regular_rpcbind; /* Go the regular way */ |
---|
890 | } else { |
---|
891 | /* This is a UDP PORTMAP handle. Change to version 4 */ |
---|
892 | vers = RPCBVERS4; |
---|
893 | CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); |
---|
894 | } |
---|
895 | /* |
---|
896 | * We also send the remote system the address we used to |
---|
897 | * contact it in case it can help it connect back with us |
---|
898 | */ |
---|
899 | if (parms.r_addr == NULL) { |
---|
900 | /*LINTED const castaway*/ |
---|
901 | parms.r_addr = (char *) &nullstring[0]; /* for XDRing */ |
---|
902 | } |
---|
903 | |
---|
904 | CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); |
---|
905 | |
---|
906 | clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST, |
---|
907 | (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, |
---|
908 | (xdrproc_t) xdr_rpcb_entry_list_ptr, |
---|
909 | (char *)(void *)&relp, *tp); |
---|
910 | if (clnt_st == RPC_SUCCESS) { |
---|
911 | if ((address = got_entry(relp, nconf)) != NULL) { |
---|
912 | xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, |
---|
913 | (char *)(void *)&relp); |
---|
914 | CLNT_CONTROL(client, CLGET_SVC_ADDR, |
---|
915 | (char *)(void *)&servaddr); |
---|
916 | __rpc_fixup_addr(address, &servaddr); |
---|
917 | goto done; |
---|
918 | } |
---|
919 | /* Entry not found for this transport */ |
---|
920 | xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, |
---|
921 | (char *)(void *)&relp); |
---|
922 | /* |
---|
923 | * XXX: should have perhaps returned with error but |
---|
924 | * since the remote machine might not always be able |
---|
925 | * to send the address on all transports, we try the |
---|
926 | * regular way with regular_rpcbind |
---|
927 | */ |
---|
928 | goto regular_rpcbind; |
---|
929 | } else if ((clnt_st == RPC_PROGVERSMISMATCH) || |
---|
930 | (clnt_st == RPC_PROGUNAVAIL)) { |
---|
931 | start_vers = RPCBVERS; /* Try version 3 now */ |
---|
932 | goto regular_rpcbind; /* Try different versions */ |
---|
933 | } else { |
---|
934 | rpc_createerr.cf_stat = RPC_PMAPFAILURE; |
---|
935 | clnt_geterr(client, &rpc_createerr.cf_error); |
---|
936 | goto error; |
---|
937 | } |
---|
938 | } |
---|
939 | |
---|
940 | regular_rpcbind: |
---|
941 | |
---|
942 | /* Now the same transport is to be used to get the address */ |
---|
943 | if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || |
---|
944 | (nconf->nc_semantics == NC_TPI_COTS))) { |
---|
945 | /* A CLTS type of client - destroy it */ |
---|
946 | CLNT_DESTROY(client); |
---|
947 | client = NULL; |
---|
948 | } |
---|
949 | |
---|
950 | if (client == NULL) { |
---|
951 | client = getclnthandle(host, nconf, &parms.r_addr); |
---|
952 | if (client == NULL) { |
---|
953 | goto error; |
---|
954 | } |
---|
955 | } |
---|
956 | if (parms.r_addr == NULL) { |
---|
957 | /*LINTED const castaway*/ |
---|
958 | parms.r_addr = (char *) &nullstring[0]; |
---|
959 | } |
---|
960 | |
---|
961 | /* First try from start_vers and then version 3 (RPCBVERS) */ |
---|
962 | |
---|
963 | CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime); |
---|
964 | for (vers = start_vers; vers >= RPCBVERS; vers--) { |
---|
965 | /* Set the version */ |
---|
966 | CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); |
---|
967 | clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, |
---|
968 | (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, |
---|
969 | (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp); |
---|
970 | if (clnt_st == RPC_SUCCESS) { |
---|
971 | if ((ua == NULL) || (ua[0] == 0)) { |
---|
972 | /* address unknown */ |
---|
973 | rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; |
---|
974 | goto error; |
---|
975 | } |
---|
976 | address = uaddr2taddr(nconf, ua); |
---|
977 | #ifdef ND_DEBUG |
---|
978 | fprintf(stderr, "\tRemote address is [%s]\n", ua); |
---|
979 | if (!address) |
---|
980 | fprintf(stderr, |
---|
981 | "\tCouldn't resolve remote address!\n"); |
---|
982 | #endif |
---|
983 | xdr_free((xdrproc_t)xdr_wrapstring, |
---|
984 | (char *)(void *)&ua); |
---|
985 | |
---|
986 | if (! address) { |
---|
987 | /* We don't know about your universal address */ |
---|
988 | rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; |
---|
989 | goto error; |
---|
990 | } |
---|
991 | CLNT_CONTROL(client, CLGET_SVC_ADDR, |
---|
992 | (char *)(void *)&servaddr); |
---|
993 | __rpc_fixup_addr(address, &servaddr); |
---|
994 | goto done; |
---|
995 | } else if (clnt_st == RPC_PROGVERSMISMATCH) { |
---|
996 | struct rpc_err rpcerr; |
---|
997 | |
---|
998 | clnt_geterr(client, &rpcerr); |
---|
999 | if (rpcerr.re_vers.low > RPCBVERS4) |
---|
1000 | goto error; /* a new version, can't handle */ |
---|
1001 | } else if (clnt_st != RPC_PROGUNAVAIL) { |
---|
1002 | /* Cant handle this error */ |
---|
1003 | rpc_createerr.cf_stat = clnt_st; |
---|
1004 | clnt_geterr(client, &rpc_createerr.cf_error); |
---|
1005 | goto error; |
---|
1006 | } |
---|
1007 | } |
---|
1008 | |
---|
1009 | error: |
---|
1010 | if (client) { |
---|
1011 | CLNT_DESTROY(client); |
---|
1012 | client = NULL; |
---|
1013 | } |
---|
1014 | done: |
---|
1015 | if (nconf->nc_semantics != NC_TPI_CLTS) { |
---|
1016 | /* This client is the connectionless one */ |
---|
1017 | if (client) { |
---|
1018 | CLNT_DESTROY(client); |
---|
1019 | client = NULL; |
---|
1020 | } |
---|
1021 | } |
---|
1022 | if (clpp) { |
---|
1023 | *clpp = client; |
---|
1024 | } else if (client) { |
---|
1025 | CLNT_DESTROY(client); |
---|
1026 | } |
---|
1027 | if (parms.r_addr != NULL && parms.r_addr != nullstring) |
---|
1028 | free(parms.r_addr); |
---|
1029 | return (address); |
---|
1030 | } |
---|
1031 | |
---|
1032 | |
---|
1033 | /* |
---|
1034 | * Find the mapped address for program, version. |
---|
1035 | * Calls the rpcbind service remotely to do the lookup. |
---|
1036 | * Uses the transport specified in nconf. |
---|
1037 | * Returns FALSE (0) if no map exists, else returns 1. |
---|
1038 | * |
---|
1039 | * Assuming that the address is all properly allocated |
---|
1040 | */ |
---|
1041 | bool_t |
---|
1042 | rpcb_getaddr(program, version, nconf, address, host) |
---|
1043 | rpcprog_t program; |
---|
1044 | rpcvers_t version; |
---|
1045 | const struct netconfig *nconf; |
---|
1046 | struct netbuf *address; |
---|
1047 | const char *host; |
---|
1048 | { |
---|
1049 | struct netbuf *na; |
---|
1050 | |
---|
1051 | if ((na = __rpcb_findaddr_timed(program, version, |
---|
1052 | (struct netconfig *) nconf, (char *) host, |
---|
1053 | (CLIENT **) NULL, (struct timeval *) NULL)) == NULL) |
---|
1054 | return (FALSE); |
---|
1055 | |
---|
1056 | if (na->len > address->maxlen) { |
---|
1057 | /* Too long address */ |
---|
1058 | free(na->buf); |
---|
1059 | free(na); |
---|
1060 | rpc_createerr.cf_stat = RPC_FAILED; |
---|
1061 | return (FALSE); |
---|
1062 | } |
---|
1063 | memcpy(address->buf, na->buf, (size_t)na->len); |
---|
1064 | address->len = na->len; |
---|
1065 | free(na->buf); |
---|
1066 | free(na); |
---|
1067 | return (TRUE); |
---|
1068 | } |
---|
1069 | |
---|
1070 | /* |
---|
1071 | * Get a copy of the current maps. |
---|
1072 | * Calls the rpcbind service remotely to get the maps. |
---|
1073 | * |
---|
1074 | * It returns only a list of the services |
---|
1075 | * It returns NULL on failure. |
---|
1076 | */ |
---|
1077 | rpcblist * |
---|
1078 | rpcb_getmaps(nconf, host) |
---|
1079 | const struct netconfig *nconf; |
---|
1080 | const char *host; |
---|
1081 | { |
---|
1082 | rpcblist_ptr head = NULL; |
---|
1083 | CLIENT *client; |
---|
1084 | enum clnt_stat clnt_st; |
---|
1085 | rpcvers_t vers = 0; |
---|
1086 | |
---|
1087 | client = getclnthandle(host, nconf, NULL); |
---|
1088 | if (client == NULL) { |
---|
1089 | return (head); |
---|
1090 | } |
---|
1091 | clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, |
---|
1092 | (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, |
---|
1093 | (char *)(void *)&head, tottimeout); |
---|
1094 | if (clnt_st == RPC_SUCCESS) |
---|
1095 | goto done; |
---|
1096 | |
---|
1097 | if ((clnt_st != RPC_PROGVERSMISMATCH) && |
---|
1098 | (clnt_st != RPC_PROGUNAVAIL)) { |
---|
1099 | rpc_createerr.cf_stat = RPC_RPCBFAILURE; |
---|
1100 | clnt_geterr(client, &rpc_createerr.cf_error); |
---|
1101 | goto done; |
---|
1102 | } |
---|
1103 | |
---|
1104 | /* fall back to earlier version */ |
---|
1105 | CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); |
---|
1106 | if (vers == RPCBVERS4) { |
---|
1107 | vers = RPCBVERS; |
---|
1108 | CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); |
---|
1109 | if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, |
---|
1110 | (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, |
---|
1111 | (char *)(void *)&head, tottimeout) == RPC_SUCCESS) |
---|
1112 | goto done; |
---|
1113 | } |
---|
1114 | rpc_createerr.cf_stat = RPC_RPCBFAILURE; |
---|
1115 | clnt_geterr(client, &rpc_createerr.cf_error); |
---|
1116 | |
---|
1117 | done: |
---|
1118 | CLNT_DESTROY(client); |
---|
1119 | return (head); |
---|
1120 | } |
---|
1121 | |
---|
1122 | /* |
---|
1123 | * rpcbinder remote-call-service interface. |
---|
1124 | * This routine is used to call the rpcbind remote call service |
---|
1125 | * which will look up a service program in the address maps, and then |
---|
1126 | * remotely call that routine with the given parameters. This allows |
---|
1127 | * programs to do a lookup and call in one step. |
---|
1128 | */ |
---|
1129 | enum clnt_stat |
---|
1130 | rpcb_rmtcall(nconf, host, prog, vers, proc, xdrargs, argsp, |
---|
1131 | xdrres, resp, tout, addr_ptr) |
---|
1132 | const struct netconfig *nconf; /* Netconfig structure */ |
---|
1133 | const char *host; /* Remote host name */ |
---|
1134 | rpcprog_t prog; |
---|
1135 | rpcvers_t vers; |
---|
1136 | rpcproc_t proc; /* Remote proc identifiers */ |
---|
1137 | xdrproc_t xdrargs, xdrres; /* XDR routines */ |
---|
1138 | caddr_t argsp, resp; /* Argument and Result */ |
---|
1139 | struct timeval tout; /* Timeout value for this call */ |
---|
1140 | const struct netbuf *addr_ptr; /* Preallocated netbuf address */ |
---|
1141 | { |
---|
1142 | CLIENT *client; |
---|
1143 | enum clnt_stat stat; |
---|
1144 | struct r_rpcb_rmtcallargs a; |
---|
1145 | struct r_rpcb_rmtcallres r; |
---|
1146 | rpcvers_t rpcb_vers; |
---|
1147 | |
---|
1148 | stat = 0; |
---|
1149 | client = getclnthandle(host, nconf, NULL); |
---|
1150 | if (client == NULL) { |
---|
1151 | return (RPC_FAILED); |
---|
1152 | } |
---|
1153 | /*LINTED const castaway*/ |
---|
1154 | CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout); |
---|
1155 | a.prog = prog; |
---|
1156 | a.vers = vers; |
---|
1157 | a.proc = proc; |
---|
1158 | a.args.args_val = argsp; |
---|
1159 | a.xdr_args = xdrargs; |
---|
1160 | r.addr = NULL; |
---|
1161 | r.results.results_val = resp; |
---|
1162 | r.xdr_res = xdrres; |
---|
1163 | |
---|
1164 | for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) { |
---|
1165 | CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers); |
---|
1166 | stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT, |
---|
1167 | (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a, |
---|
1168 | (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout); |
---|
1169 | if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) { |
---|
1170 | struct netbuf *na; |
---|
1171 | /*LINTED const castaway*/ |
---|
1172 | na = uaddr2taddr((struct netconfig *) nconf, r.addr); |
---|
1173 | if (!na) { |
---|
1174 | stat = RPC_N2AXLATEFAILURE; |
---|
1175 | /*LINTED const castaway*/ |
---|
1176 | ((struct netbuf *) addr_ptr)->len = 0; |
---|
1177 | goto error; |
---|
1178 | } |
---|
1179 | if (na->len > addr_ptr->maxlen) { |
---|
1180 | /* Too long address */ |
---|
1181 | stat = RPC_FAILED; /* XXX A better error no */ |
---|
1182 | free(na->buf); |
---|
1183 | free(na); |
---|
1184 | /*LINTED const castaway*/ |
---|
1185 | ((struct netbuf *) addr_ptr)->len = 0; |
---|
1186 | goto error; |
---|
1187 | } |
---|
1188 | memcpy(addr_ptr->buf, na->buf, (size_t)na->len); |
---|
1189 | /*LINTED const castaway*/ |
---|
1190 | ((struct netbuf *)addr_ptr)->len = na->len; |
---|
1191 | free(na->buf); |
---|
1192 | free(na); |
---|
1193 | break; |
---|
1194 | } else if ((stat != RPC_PROGVERSMISMATCH) && |
---|
1195 | (stat != RPC_PROGUNAVAIL)) { |
---|
1196 | goto error; |
---|
1197 | } |
---|
1198 | } |
---|
1199 | error: |
---|
1200 | CLNT_DESTROY(client); |
---|
1201 | if (r.addr) |
---|
1202 | xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr); |
---|
1203 | return (stat); |
---|
1204 | } |
---|
1205 | |
---|
1206 | /* |
---|
1207 | * Gets the time on the remote host. |
---|
1208 | * Returns 1 if succeeds else 0. |
---|
1209 | */ |
---|
1210 | bool_t |
---|
1211 | rpcb_gettime(host, timep) |
---|
1212 | const char *host; |
---|
1213 | time_t *timep; |
---|
1214 | { |
---|
1215 | CLIENT *client = NULL; |
---|
1216 | void *handle; |
---|
1217 | struct netconfig *nconf; |
---|
1218 | rpcvers_t vers; |
---|
1219 | enum clnt_stat st; |
---|
1220 | |
---|
1221 | |
---|
1222 | if ((host == NULL) || (host[0] == 0)) { |
---|
1223 | time(timep); |
---|
1224 | return (TRUE); |
---|
1225 | } |
---|
1226 | |
---|
1227 | if ((handle = __rpc_setconf("netpath")) == NULL) { |
---|
1228 | rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; |
---|
1229 | return (FALSE); |
---|
1230 | } |
---|
1231 | rpc_createerr.cf_stat = RPC_SUCCESS; |
---|
1232 | while (client == NULL) { |
---|
1233 | if ((nconf = __rpc_getconf(handle)) == NULL) { |
---|
1234 | if (rpc_createerr.cf_stat == RPC_SUCCESS) |
---|
1235 | rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; |
---|
1236 | break; |
---|
1237 | } |
---|
1238 | client = getclnthandle(host, nconf, NULL); |
---|
1239 | if (client) |
---|
1240 | break; |
---|
1241 | } |
---|
1242 | __rpc_endconf(handle); |
---|
1243 | if (client == (CLIENT *) NULL) { |
---|
1244 | return (FALSE); |
---|
1245 | } |
---|
1246 | |
---|
1247 | st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, |
---|
1248 | (xdrproc_t) xdr_void, NULL, |
---|
1249 | (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout); |
---|
1250 | |
---|
1251 | if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) { |
---|
1252 | CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); |
---|
1253 | if (vers == RPCBVERS4) { |
---|
1254 | /* fall back to earlier version */ |
---|
1255 | vers = RPCBVERS; |
---|
1256 | CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); |
---|
1257 | st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, |
---|
1258 | (xdrproc_t) xdr_void, NULL, |
---|
1259 | (xdrproc_t) xdr_int, (char *)(void *)timep, |
---|
1260 | tottimeout); |
---|
1261 | } |
---|
1262 | } |
---|
1263 | CLNT_DESTROY(client); |
---|
1264 | return (st == RPC_SUCCESS? TRUE: FALSE); |
---|
1265 | } |
---|
1266 | |
---|
1267 | /* |
---|
1268 | * Converts taddr to universal address. This routine should never |
---|
1269 | * really be called because local n2a libraries are always provided. |
---|
1270 | */ |
---|
1271 | char * |
---|
1272 | rpcb_taddr2uaddr(nconf, taddr) |
---|
1273 | struct netconfig *nconf; |
---|
1274 | struct netbuf *taddr; |
---|
1275 | { |
---|
1276 | CLIENT *client; |
---|
1277 | char *uaddr = NULL; |
---|
1278 | |
---|
1279 | |
---|
1280 | /* parameter checking */ |
---|
1281 | if (nconf == NULL) { |
---|
1282 | rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; |
---|
1283 | return (NULL); |
---|
1284 | } |
---|
1285 | if (taddr == NULL) { |
---|
1286 | rpc_createerr.cf_stat = RPC_UNKNOWNADDR; |
---|
1287 | return (NULL); |
---|
1288 | } |
---|
1289 | client = local_rpcb(); |
---|
1290 | if (! client) { |
---|
1291 | return (NULL); |
---|
1292 | } |
---|
1293 | |
---|
1294 | CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR, |
---|
1295 | (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, |
---|
1296 | (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout); |
---|
1297 | CLNT_DESTROY(client); |
---|
1298 | return (uaddr); |
---|
1299 | } |
---|
1300 | |
---|
1301 | /* |
---|
1302 | * Converts universal address to netbuf. This routine should never |
---|
1303 | * really be called because local n2a libraries are always provided. |
---|
1304 | */ |
---|
1305 | struct netbuf * |
---|
1306 | rpcb_uaddr2taddr(nconf, uaddr) |
---|
1307 | struct netconfig *nconf; |
---|
1308 | char *uaddr; |
---|
1309 | { |
---|
1310 | CLIENT *client; |
---|
1311 | struct netbuf *taddr; |
---|
1312 | |
---|
1313 | |
---|
1314 | /* parameter checking */ |
---|
1315 | if (nconf == NULL) { |
---|
1316 | rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; |
---|
1317 | return (NULL); |
---|
1318 | } |
---|
1319 | if (uaddr == NULL) { |
---|
1320 | rpc_createerr.cf_stat = RPC_UNKNOWNADDR; |
---|
1321 | return (NULL); |
---|
1322 | } |
---|
1323 | client = local_rpcb(); |
---|
1324 | if (! client) { |
---|
1325 | return (NULL); |
---|
1326 | } |
---|
1327 | |
---|
1328 | taddr = (struct netbuf *)calloc(1, sizeof (struct netbuf)); |
---|
1329 | if (taddr == NULL) { |
---|
1330 | CLNT_DESTROY(client); |
---|
1331 | return (NULL); |
---|
1332 | } |
---|
1333 | if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR, |
---|
1334 | (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, |
---|
1335 | (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, |
---|
1336 | tottimeout) != RPC_SUCCESS) { |
---|
1337 | free(taddr); |
---|
1338 | taddr = NULL; |
---|
1339 | } |
---|
1340 | CLNT_DESTROY(client); |
---|
1341 | return (taddr); |
---|
1342 | } |
---|