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