4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 * Copyright 2014 Gary Mills
29 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
30 * Use is subject to license terms.
33 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
34 /* All Rights Reserved */
36 * Portions of this source code were derived from Berkeley
37 * 4.3 BSD under license from the Regents of the University of
42 * interface to rpcbind rpc service.
49 #include <rpc/rpcb_prot.h>
50 #include <netconfig.h>
53 #include <rpc/nettype.h>
55 #include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */
56 #include <rpc/pmap_prot.h>
62 static struct timeval tottimeout
= { 60, 0 };
63 static const struct timeval rmttimeout
= { 3, 0 };
64 static struct timeval rpcbrmttime
= { 15, 0 };
66 extern bool_t
xdr_wrapstring(XDR
*, char **);
68 static const char nullstring
[] = "\000";
70 extern CLIENT
*_clnt_tli_create_timed(int, const struct netconfig
*,
71 struct netbuf
*, rpcprog_t
, rpcvers_t
, uint_t
, uint_t
,
72 const struct timeval
*);
74 static CLIENT
*_getclnthandle_timed(char *, struct netconfig
*, char **,
79 * The life time of a cached entry should not exceed 5 minutes
80 * since automountd attempts an unmount every 5 minutes.
81 * It is arbitrarily set a little lower (3 min = 180 sec)
82 * to reduce the time during which an entry is stale.
87 struct address_cache
{
91 struct netbuf
*ac_taddr
;
92 struct address_cache
*ac_next
;
96 static struct address_cache
*front
;
100 extern int authdes_cachesz
;
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.
108 __rpc_control(int request
, void *info
)
111 case CLCR_GET_RPCB_TIMEOUT
:
112 *(struct timeval
*)info
= tottimeout
;
114 case CLCR_SET_RPCB_TIMEOUT
:
115 tottimeout
= *(struct timeval
*)info
;
117 case CLCR_GET_LOWVERS
:
118 *(int *)info
= lowvers
;
120 case CLCR_SET_LOWVERS
:
121 lowvers
= *(int *)info
;
123 case CLCR_GET_RPCB_RMTTIME
:
124 *(struct timeval
*)info
= rpcbrmttime
;
126 case CLCR_SET_RPCB_RMTTIME
:
127 rpcbrmttime
= *(struct timeval
*)info
;
129 case CLCR_GET_CRED_CACHE_SZ
:
130 *(int *)info
= authdes_cachesz
;
132 case CLCR_SET_CRED_CACHE_SZ
:
133 authdes_cachesz
= *(int *)info
;
142 * It might seem that a reader/writer lock would be more reasonable here.
143 * However because getclnthandle(), the only user of the cache functions,
144 * may do a delete_cache() operation if a check_cache() fails to return an
145 * address useful to clnt_tli_create(), we may as well use a mutex.
148 * As it turns out, if the cache lock is *not* a reader/writer lock, we will
149 * block all clnt_create's if we are trying to connect to a host that's down,
150 * since the lock will be held all during that time.
152 extern rwlock_t rpcbaddr_cache_lock
;
155 * The routines check_cache(), add_cache(), delete_cache() manage the
156 * cache of rpcbind addresses for (host, netid).
159 static struct address_cache
*
160 check_cache(char *host
, char *netid
)
162 struct address_cache
*cptr
;
164 /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
166 assert(RW_READ_HELD(&rpcbaddr_cache_lock
));
167 for (cptr
= front
; cptr
!= NULL
; cptr
= cptr
->ac_next
) {
168 if ((strcmp(cptr
->ac_host
, host
) == 0) &&
169 (strcmp(cptr
->ac_netid
, netid
) == 0) &&
170 (time(NULL
) <= cptr
->ac_maxtime
)) {
178 delete_cache(struct netbuf
*addr
)
180 struct address_cache
*cptr
, *prevptr
= NULL
;
182 /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
183 assert(RW_WRITE_HELD(&rpcbaddr_cache_lock
));
184 for (cptr
= front
; cptr
!= NULL
; cptr
= cptr
->ac_next
) {
185 if (!memcmp(cptr
->ac_taddr
->buf
, addr
->buf
, addr
->len
)) {
187 free(cptr
->ac_netid
);
188 free(cptr
->ac_taddr
->buf
);
189 free(cptr
->ac_taddr
);
190 free(cptr
->ac_uaddr
);
192 prevptr
->ac_next
= cptr
->ac_next
;
194 front
= cptr
->ac_next
;
204 add_cache(char *host
, char *netid
, struct netbuf
*taddr
, char *uaddr
)
206 struct address_cache
*ad_cache
, *cptr
, *prevptr
;
208 ad_cache
= malloc(sizeof (struct address_cache
));
212 ad_cache
->ac_maxtime
= time(NULL
) + CACHE_TTL
;
213 ad_cache
->ac_host
= strdup(host
);
214 ad_cache
->ac_netid
= strdup(netid
);
215 ad_cache
->ac_uaddr
= uaddr
? strdup(uaddr
) : NULL
;
216 ad_cache
->ac_taddr
= malloc(sizeof (struct netbuf
));
217 if (!ad_cache
->ac_host
|| !ad_cache
->ac_netid
|| !ad_cache
->ac_taddr
||
218 (uaddr
&& !ad_cache
->ac_uaddr
)) {
222 ad_cache
->ac_taddr
->len
= ad_cache
->ac_taddr
->maxlen
= taddr
->len
;
223 ad_cache
->ac_taddr
->buf
= malloc(taddr
->len
);
224 if (ad_cache
->ac_taddr
->buf
== NULL
) {
228 (void) memcpy(ad_cache
->ac_taddr
->buf
, taddr
->buf
, taddr
->len
);
230 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */
232 (void) rw_wrlock(&rpcbaddr_cache_lock
);
233 if (cachesize
< CACHESIZE
) {
234 ad_cache
->ac_next
= front
;
238 /* Free the last entry */
241 while (cptr
->ac_next
) {
243 cptr
= cptr
->ac_next
;
247 free(cptr
->ac_netid
);
248 free(cptr
->ac_taddr
->buf
);
249 free(cptr
->ac_taddr
);
250 free(cptr
->ac_uaddr
);
253 prevptr
->ac_next
= NULL
;
254 ad_cache
->ac_next
= front
;
258 ad_cache
->ac_next
= NULL
;
262 (void) rw_unlock(&rpcbaddr_cache_lock
);
265 free(ad_cache
->ac_host
);
266 free(ad_cache
->ac_netid
);
267 free(ad_cache
->ac_uaddr
);
268 free(ad_cache
->ac_taddr
);
271 syslog(LOG_ERR
, "add_cache : out of memory.");
275 * This routine will return a client handle that is connected to the
276 * rpcbind. Returns NULL on error and free's everything.
279 getclnthandle(char *host
, struct netconfig
*nconf
, char **targaddr
)
281 return (_getclnthandle_timed(host
, nconf
, targaddr
, NULL
));
285 * Same as getclnthandle() except it takes an extra timeout argument.
286 * This is for bug 4049792: clnt_create_timed does not timeout.
288 * If tp is NULL, use default timeout to get a client handle.
291 _getclnthandle_timed(char *host
, struct netconfig
*nconf
, char **targaddr
,
294 CLIENT
*client
= NULL
;
296 struct netbuf addr_to_delete
;
297 struct nd_addrlist
*nas
;
298 struct nd_hostserv rpcbind_hs
;
299 struct address_cache
*ad_cache
;
304 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */
306 /* Get the address of the rpcbind. Check cache first */
307 addr_to_delete
.len
= 0;
308 (void) rw_rdlock(&rpcbaddr_cache_lock
);
309 ad_cache
= check_cache(host
, nconf
->nc_netid
);
310 if (ad_cache
!= NULL
) {
311 addr
= ad_cache
->ac_taddr
;
312 client
= _clnt_tli_create_timed(RPC_ANYFD
, nconf
, addr
,
313 RPCBPROG
, RPCBVERS4
, 0, 0, tp
);
314 if (client
!= NULL
) {
317 * case where a client handle is created
318 * without a targaddr and the handle is
319 * requested with a targaddr
321 if (ad_cache
->ac_uaddr
!= NULL
) {
322 *targaddr
= strdup(ad_cache
->ac_uaddr
);
323 if (*targaddr
== NULL
) {
325 "_getclnthandle_timed: strdup "
327 rpc_createerr
.cf_stat
=
330 &rpcbaddr_cache_lock
);
337 (void) rw_unlock(&rpcbaddr_cache_lock
);
340 if (rpc_createerr
.cf_stat
== RPC_SYSTEMERROR
) {
341 (void) rw_unlock(&rpcbaddr_cache_lock
);
344 addr_to_delete
.len
= addr
->len
;
345 addr_to_delete
.buf
= malloc(addr
->len
);
346 if (addr_to_delete
.buf
== NULL
) {
347 addr_to_delete
.len
= 0;
349 (void) memcpy(addr_to_delete
.buf
, addr
->buf
, addr
->len
);
352 (void) rw_unlock(&rpcbaddr_cache_lock
);
353 if (addr_to_delete
.len
!= 0) {
355 * Assume this may be due to cache data being
358 (void) rw_wrlock(&rpcbaddr_cache_lock
);
359 delete_cache(&addr_to_delete
);
360 (void) rw_unlock(&rpcbaddr_cache_lock
);
361 free(addr_to_delete
.buf
);
363 rpcbind_hs
.h_host
= host
;
364 rpcbind_hs
.h_serv
= "rpcbind";
366 if ((neterr
= netdir_getbyname(nconf
, &rpcbind_hs
, &nas
)) != 0) {
367 if (neterr
== ND_NOHOST
)
368 rpc_createerr
.cf_stat
= RPC_UNKNOWNHOST
;
370 rpc_createerr
.cf_stat
= RPC_N2AXLATEFAILURE
;
373 /* XXX nas should perhaps be cached for better performance */
375 for (j
= 0; j
< nas
->n_cnt
; j
++) {
376 addr
= &(nas
->n_addrs
[j
]);
377 client
= _clnt_tli_create_timed(RPC_ANYFD
, nconf
, addr
, RPCBPROG
,
378 RPCBVERS4
, 0, 0, tp
);
384 tmpaddr
= targaddr
? taddr2uaddr(nconf
, addr
) : NULL
;
385 add_cache(host
, nconf
->nc_netid
, addr
, tmpaddr
);
390 netdir_free((char *)nas
, ND_ADDRLIST
);
395 * This routine will return a client handle that is connected to the local
396 * rpcbind. Returns NULL on error.
401 static struct netconfig
*loopnconf
;
402 extern mutex_t loopnconf_lock
;
404 /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
405 (void) mutex_lock(&loopnconf_lock
);
406 if (loopnconf
== NULL
) {
407 struct netconfig
*nconf
, *tmpnconf
= NULL
;
410 nc_handle
= setnetconfig();
411 if (nc_handle
== NULL
) {
412 /* fails to open netconfig file */
413 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
414 (void) mutex_unlock(&loopnconf_lock
);
417 while (nconf
= getnetconfig(nc_handle
)) {
418 if (strcmp(nconf
->nc_protofmly
, NC_LOOPBACK
) == 0) {
420 if (nconf
->nc_semantics
== NC_TPI_CLTS
)
424 if (tmpnconf
== NULL
) {
425 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
426 (void) mutex_unlock(&loopnconf_lock
);
429 loopnconf
= getnetconfigent(tmpnconf
->nc_netid
);
430 /* loopnconf is never freed */
431 (void) endnetconfig(nc_handle
);
433 (void) mutex_unlock(&loopnconf_lock
);
434 return (getclnthandle(HOST_SELF_CONNECT
, loopnconf
, NULL
));
438 * Set a mapping between program, version and address.
439 * Calls the rpcbind service to do the mapping.
442 rpcb_set(const rpcprog_t program
, const rpcvers_t version
,
443 const struct netconfig
*nconf
, const struct netbuf
*address
)
450 /* parameter checking */
452 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
455 if (address
== NULL
) {
456 rpc_createerr
.cf_stat
= RPC_UNKNOWNADDR
;
459 client
= local_rpcb();
463 parms
.r_addr
= taddr2uaddr((struct netconfig
*)nconf
,
464 (struct netbuf
*)address
); /* convert to universal */
466 rpc_createerr
.cf_stat
= RPC_N2AXLATEFAILURE
;
467 return (FALSE
); /* no universal address */
469 parms
.r_prog
= program
;
470 parms
.r_vers
= version
;
471 parms
.r_netid
= nconf
->nc_netid
;
473 * Though uid is not being used directly, we still send it for
474 * completeness. For non-unix platforms, perhaps some other
475 * string or an empty string can be sent.
477 (void) sprintf(uidbuf
, "%d", (int)geteuid());
478 parms
.r_owner
= uidbuf
;
480 CLNT_CALL(client
, RPCBPROC_SET
, (xdrproc_t
)xdr_rpcb
, (char *)&parms
,
481 (xdrproc_t
)xdr_bool
, (char *)&rslt
, tottimeout
);
483 CLNT_DESTROY(client
);
489 * Remove the mapping between program, version and netbuf address.
490 * Calls the rpcbind service to do the un-mapping.
491 * If netbuf is NULL, unset for all the transports, otherwise unset
492 * only for the given transport.
495 rpcb_unset(const rpcprog_t program
, const rpcvers_t version
,
496 const struct netconfig
*nconf
)
503 client
= local_rpcb();
507 parms
.r_prog
= program
;
508 parms
.r_vers
= version
;
510 parms
.r_netid
= nconf
->nc_netid
;
512 parms
.r_netid
= (char *)&nullstring
[0]; /* unsets all */
513 parms
.r_addr
= (char *)&nullstring
[0];
514 (void) sprintf(uidbuf
, "%d", (int)geteuid());
515 parms
.r_owner
= uidbuf
;
517 CLNT_CALL(client
, RPCBPROC_UNSET
, (xdrproc_t
)xdr_rpcb
, (char *)&parms
,
518 (xdrproc_t
)xdr_bool
, (char *)&rslt
, tottimeout
);
520 CLNT_DESTROY(client
);
525 * From the merged list, find the appropriate entry
527 static struct netbuf
*
528 got_entry(rpcb_entry_list_ptr relp
, struct netconfig
*nconf
)
530 struct netbuf
*na
= NULL
;
531 rpcb_entry_list_ptr sp
;
534 for (sp
= relp
; sp
!= NULL
; sp
= sp
->rpcb_entry_next
) {
535 rmap
= &sp
->rpcb_entry_map
;
536 if ((strcmp(nconf
->nc_proto
, rmap
->r_nc_proto
) == 0) &&
537 (strcmp(nconf
->nc_protofmly
, rmap
->r_nc_protofmly
) == 0) &&
538 (nconf
->nc_semantics
== rmap
->r_nc_semantics
) &&
539 (rmap
->r_maddr
!= NULL
) && (rmap
->r_maddr
[0] != '\0')) {
540 na
= uaddr2taddr(nconf
, rmap
->r_maddr
);
548 * Quick check to see if rpcbind is up. Tries to connect over
552 __rpcbind_is_up(void)
556 struct t_call
*sndcall
;
557 struct netconfig
*netconf
;
560 if ((fd
= t_open("/dev/ticotsord", O_RDWR
, NULL
)) == -1)
563 if (t_bind(fd
, NULL
, NULL
) == -1) {
568 /* LINTED pointer cast */
569 if ((sndcall
= (struct t_call
*)t_alloc(fd
, T_CALL
, 0)) == NULL
) {
574 if ((netconf
= getnetconfigent("ticotsord")) == NULL
) {
575 (void) t_free((char *)sndcall
, T_CALL
);
579 addr
= uaddr2taddr(netconf
, "localhost.rpc");
580 freenetconfigent(netconf
);
581 if (addr
== NULL
|| addr
->buf
== NULL
) {
583 (void) t_free((char *)sndcall
, T_CALL
);
587 sndcall
->addr
.maxlen
= addr
->maxlen
;
588 sndcall
->addr
.len
= addr
->len
;
589 sndcall
->addr
.buf
= addr
->buf
;
591 if (t_connect(fd
, sndcall
, NULL
) == -1)
596 sndcall
->addr
.maxlen
= sndcall
->addr
.len
= 0;
597 sndcall
->addr
.buf
= NULL
;
598 (void) t_free((char *)sndcall
, T_CALL
);
608 * An internal function which optimizes rpcb_getaddr function. It returns
609 * the universal address of the remote service or NULL. It also optionally
610 * returns the client handle that it uses to contact the remote rpcbind.
611 * The caller will re-purpose the client handle to contact the remote service.
613 * The algorithm used: First try version 4. Then try version 3 (svr4).
614 * Finally, if the transport is TCP or UDP, try version 2 (portmap).
615 * Version 4 is now available with all current systems on the network.
616 * With this algorithm, we get performance as well as a plan for
617 * obsoleting version 2.
619 * XXX: Due to some problems with t_connect(), we do not reuse the same client
620 * handle for COTS cases and hence in these cases we do not return the
621 * client handle. This code will change if t_connect() ever
622 * starts working properly. Also look under clnt_vc.c.
625 __rpcb_findaddr_timed(rpcprog_t program
, rpcvers_t version
,
626 struct netconfig
*nconf
, char *host
, CLIENT
**clpp
, struct timeval
*tp
)
628 static bool_t check_rpcbind
= TRUE
;
629 CLIENT
*client
= NULL
;
631 enum clnt_stat clnt_st
;
634 struct netbuf
*address
= NULL
;
636 rpcb_entry_list_ptr relp
= NULL
;
637 bool_t tmp_client
= FALSE
;
639 /* parameter checking */
641 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
643 * Setting rpc_createerr.cf_stat is sufficient.
644 * No details in rpc_createerr.cf_error needed.
652 * Use default total timeout if no timeout is specified.
658 * Check if rpcbind is up. This prevents needless delays when
659 * accessing applications such as the keyserver while booting
662 if (check_rpcbind
&& strcmp(nconf
->nc_protofmly
, NC_LOOPBACK
) == 0) {
663 if (!__rpcbind_is_up()) {
664 rpc_createerr
.cf_stat
= RPC_PMAPFAILURE
;
665 rpc_createerr
.cf_error
.re_errno
= 0;
666 rpc_createerr
.cf_error
.re_terrno
= 0;
669 check_rpcbind
= FALSE
;
673 * First try version 4.
675 parms
.r_prog
= program
;
676 parms
.r_vers
= version
;
677 parms
.r_owner
= (char *)&nullstring
[0]; /* not needed; */
678 /* just for xdring */
679 parms
.r_netid
= nconf
->nc_netid
; /* not really needed */
682 * If a COTS transport is being used, try getting address via CLTS
683 * transport. This works only with version 4.
685 if (nconf
->nc_semantics
== NC_TPI_COTS_ORD
||
686 nconf
->nc_semantics
== NC_TPI_COTS
) {
688 if ((handle
= __rpc_setconf("datagram_v")) != NULL
) {
689 struct netconfig
*nconf_clts
;
691 while ((nconf_clts
= __rpc_getconf(handle
)) != NULL
) {
692 if (strcmp(nconf_clts
->nc_protofmly
,
693 nconf
->nc_protofmly
) != 0) {
697 * Sets rpc_createerr.cf_error members
700 client
= _getclnthandle_timed(host
, nconf_clts
,
704 __rpc_endconf(handle
);
707 /* Sets rpc_createerr.cf_error members on failure */
708 client
= _getclnthandle_timed(host
, nconf
, &parms
.r_addr
, tp
);
711 if (client
!= NULL
) {
713 /* Set rpcbind version 4 */
715 CLNT_CONTROL(client
, CLSET_VERS
, (char *)&vers
);
718 * We also send the remote system the address we used to
719 * contact it in case it can help it connect back with us
721 if (parms
.r_addr
== NULL
) {
722 parms
.r_addr
= strdup(""); /* for XDRing */
723 if (parms
.r_addr
== NULL
) {
724 syslog(LOG_ERR
, "__rpcb_findaddr_timed: "
726 /* Construct a system error */
727 rpc_createerr
.cf_error
.re_errno
= errno
;
728 rpc_createerr
.cf_error
.re_terrno
= 0;
729 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
734 CLNT_CONTROL(client
, CLSET_RETRY_TIMEOUT
,
735 (char *)&rpcbrmttime
);
737 /* Sets error structure members in client handle */
738 clnt_st
= CLNT_CALL(client
, RPCBPROC_GETADDRLIST
,
739 (xdrproc_t
)xdr_rpcb
, (char *)&parms
,
740 (xdrproc_t
)xdr_rpcb_entry_list_ptr
, (char *)&relp
, *tp
);
743 case RPC_SUCCESS
: /* Call succeeded */
744 address
= got_entry(relp
, nconf
);
745 xdr_free((xdrproc_t
)xdr_rpcb_entry_list_ptr
,
747 if (address
!= NULL
) {
748 /* Program number and version number matched */
751 /* Program and version not found for this transport */
753 * XXX: should have returned with RPC_PROGUNAVAIL
754 * or perhaps RPC_PROGNOTREGISTERED error but
755 * since the remote machine might not always be able
756 * to send the address on all transports, we try the
757 * regular way with version 3, then 2
759 /* Try the next version */
761 case RPC_PROGVERSMISMATCH
: /* RPC protocol mismatch */
762 clnt_geterr(client
, &rpc_createerr
.cf_error
);
763 if (rpc_createerr
.cf_error
.re_vers
.low
> vers
) {
764 rpc_createerr
.cf_stat
= clnt_st
;
765 goto error
; /* a new version, can't handle */
767 /* Try the next version */
769 case RPC_PROCUNAVAIL
: /* Procedure unavailable */
770 case RPC_PROGUNAVAIL
: /* Program not available */
771 case RPC_TIMEDOUT
: /* Call timed out */
772 /* Try the next version */
775 clnt_geterr(client
, &rpc_createerr
.cf_error
);
776 rpc_createerr
.cf_stat
= RPC_PMAPFAILURE
;
785 } /* End of version 4 */
787 /* Destroy a temporary client */
788 if (client
!= NULL
&& tmp_client
) {
789 CLNT_DESTROY(client
);
800 /* Now the same transport is to be used to get the address */
801 if (client
== NULL
) {
802 /* Sets rpc_createerr.cf_error members on failure */
803 client
= _getclnthandle_timed(host
, nconf
, &parms
.r_addr
, tp
);
806 if (client
!= NULL
) {
807 if (parms
.r_addr
== NULL
) {
808 parms
.r_addr
= strdup(""); /* for XDRing */
809 if (parms
.r_addr
== NULL
) {
810 syslog(LOG_ERR
, "__rpcb_findaddr_timed: "
812 /* Construct a system error */
813 rpc_createerr
.cf_error
.re_errno
= errno
;
814 rpc_createerr
.cf_error
.re_terrno
= 0;
815 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
820 CLNT_CONTROL(client
, CLSET_RETRY_TIMEOUT
,
821 (char *)&rpcbrmttime
);
822 vers
= RPCBVERS
; /* Set the version */
823 CLNT_CONTROL(client
, CLSET_VERS
, (char *)&vers
);
825 /* Sets error structure members in client handle */
826 clnt_st
= CLNT_CALL(client
, RPCBPROC_GETADDR
,
827 (xdrproc_t
)xdr_rpcb
, (char *)&parms
,
828 (xdrproc_t
)xdr_wrapstring
, (char *)&ua
, *tp
);
831 case RPC_SUCCESS
: /* Call succeeded */
834 address
= uaddr2taddr(nconf
, ua
);
836 xdr_free((xdrproc_t
)xdr_wrapstring
,
839 if (address
!= NULL
) {
842 /* NULL universal address */
843 /* But client call was successful */
844 clnt_geterr(client
, &rpc_createerr
.cf_error
);
845 rpc_createerr
.cf_stat
= RPC_PROGNOTREGISTERED
;
848 clnt_geterr(client
, &rpc_createerr
.cf_error
);
849 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
851 /* Try the next version */
853 case RPC_PROGVERSMISMATCH
: /* RPC protocol mismatch */
854 clnt_geterr(client
, &rpc_createerr
.cf_error
);
855 if (rpc_createerr
.cf_error
.re_vers
.low
> vers
) {
856 rpc_createerr
.cf_stat
= clnt_st
;
857 goto error
; /* a new version, can't handle */
859 /* Try the next version */
861 case RPC_PROCUNAVAIL
: /* Procedure unavailable */
862 case RPC_PROGUNAVAIL
: /* Program not available */
863 case RPC_TIMEDOUT
: /* Call timed out */
864 /* Try the next version */
867 clnt_geterr(client
, &rpc_createerr
.cf_error
);
868 rpc_createerr
.cf_stat
= RPC_PMAPFAILURE
;
871 } /* End of version 3 */
876 /* Try version 2 for TCP or UDP */
877 if (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0) {
879 struct netbuf remote
;
881 struct pmap pmapparms
;
884 * Try UDP only - there are some portmappers out
885 * there that use UDP only.
887 if (strcmp(nconf
->nc_proto
, NC_TCP
) == 0) {
888 struct netconfig
*newnconf
;
890 if (client
!= NULL
) {
891 CLNT_DESTROY(client
);
896 if ((handle
= __rpc_setconf("udp")) == NULL
) {
897 /* Construct an unknown protocol error */
898 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
903 * The following to reinforce that you can
904 * only request for remote address through
905 * the same transport you are requesting.
906 * ie. requesting unversial address
907 * of IPv4 has to be carried through IPv4.
908 * Can't use IPv6 to send out the request.
909 * The mergeaddr in rpcbind can't handle
913 if ((newnconf
= __rpc_getconf(handle
))
915 __rpc_endconf(handle
);
917 * Construct an unknown protocol
920 rpc_createerr
.cf_stat
=
925 * here check the protocol family to
926 * be consistent with the request one
928 if (strcmp(newnconf
->nc_protofmly
,
929 nconf
->nc_protofmly
) == 0)
933 /* Sets rpc_createerr.cf_error members on failure */
934 client
= _getclnthandle_timed(host
, newnconf
,
936 __rpc_endconf(handle
);
939 if (client
== NULL
) {
941 * rpc_createerr. cf_error members were set by
944 rpc_createerr
.cf_stat
= RPC_PROGNOTREGISTERED
;
950 * Set version and retry timeout.
952 CLNT_CONTROL(client
, CLSET_RETRY_TIMEOUT
, (char *)&rpcbrmttime
);
953 CLNT_CONTROL(client
, CLSET_VERS
, (char *)&pmapvers
);
955 pmapparms
.pm_prog
= program
;
956 pmapparms
.pm_vers
= version
;
957 pmapparms
.pm_prot
= (strcmp(nconf
->nc_proto
, NC_TCP
) != 0) ?
958 IPPROTO_UDP
: IPPROTO_TCP
;
959 pmapparms
.pm_port
= 0; /* not needed */
961 /* Sets error structure members in client handle */
962 clnt_st
= CLNT_CALL(client
, PMAPPROC_GETPORT
,
963 (xdrproc_t
)xdr_pmap
, (caddr_t
)&pmapparms
,
964 (xdrproc_t
)xdr_u_short
, (caddr_t
)&port
, *tp
);
966 if (clnt_st
!= RPC_SUCCESS
) {
967 clnt_geterr(client
, &rpc_createerr
.cf_error
);
968 rpc_createerr
.cf_stat
= RPC_RPCBFAILURE
;
970 } else if (port
== 0) {
971 /* Will be NULL universal address */
972 /* But client call was successful */
973 clnt_geterr(client
, &rpc_createerr
.cf_error
);
974 rpc_createerr
.cf_stat
= RPC_PROGNOTREGISTERED
;
978 CLNT_CONTROL(client
, CLGET_SVC_ADDR
, (char *)&remote
);
979 if (((address
= malloc(sizeof (struct netbuf
))) == NULL
) ||
980 ((address
->buf
= malloc(remote
.len
)) == NULL
)) {
981 /* Construct a system error */
982 rpc_createerr
.cf_error
.re_errno
= errno
;
983 rpc_createerr
.cf_error
.re_terrno
= 0;
984 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
989 (void) memcpy(address
->buf
, remote
.buf
, remote
.len
);
990 (void) memcpy(&address
->buf
[sizeof (short)], &port
,
992 address
->len
= address
->maxlen
= remote
.len
;
996 * This is not NC_INET.
997 * Always an error for version 2.
999 if (client
!= NULL
&& clnt_st
!= RPC_SUCCESS
) {
1000 /* There is a client that failed */
1001 clnt_geterr(client
, &rpc_createerr
.cf_error
);
1002 rpc_createerr
.cf_stat
= clnt_st
;
1004 /* Something else */
1005 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
1007 * Setting rpc_createerr.cf_stat is sufficient.
1008 * No details in rpc_createerr.cf_error needed.
1014 /* Return NULL address and NULL client */
1016 if (client
!= NULL
) {
1017 CLNT_DESTROY(client
);
1022 /* Return an address and optional client */
1023 if (client
!= NULL
&& tmp_client
) {
1024 /* This client is the temporary one */
1025 CLNT_DESTROY(client
);
1030 } else if (client
!= NULL
) {
1031 CLNT_DESTROY(client
);
1039 * Find the mapped address for program, version.
1040 * Calls the rpcbind service remotely to do the lookup.
1041 * Uses the transport specified in nconf.
1042 * Returns FALSE (0) if no map exists, else returns 1.
1044 * Assuming that the address is all properly allocated
1047 rpcb_getaddr(const rpcprog_t program
, const rpcvers_t version
,
1048 const struct netconfig
*nconf
, struct netbuf
*address
, const char *host
)
1052 if ((na
= __rpcb_findaddr_timed(program
, version
,
1053 (struct netconfig
*)nconf
, (char *)host
, NULL
, NULL
)) == NULL
)
1056 if (na
->len
> address
->maxlen
) {
1057 /* Too long address */
1058 netdir_free((char *)na
, ND_ADDR
);
1059 rpc_createerr
.cf_stat
= RPC_FAILED
;
1062 (void) memcpy(address
->buf
, na
->buf
, (int)na
->len
);
1063 address
->len
= na
->len
;
1064 netdir_free((char *)na
, ND_ADDR
);
1069 * Get a copy of the current maps.
1070 * Calls the rpcbind service remotely to get the maps.
1072 * It returns only a list of the services
1073 * It returns NULL on failure.
1076 rpcb_getmaps(const struct netconfig
*nconf
, const char *host
)
1078 rpcblist_ptr head
= NULL
;
1080 enum clnt_stat clnt_st
;
1083 client
= getclnthandle((char *)host
,
1084 (struct netconfig
*)nconf
, NULL
);
1088 clnt_st
= CLNT_CALL(client
, RPCBPROC_DUMP
,
1089 (xdrproc_t
)xdr_void
, NULL
,
1090 (xdrproc_t
)xdr_rpcblist_ptr
,
1091 (char *)&head
, tottimeout
);
1092 if (clnt_st
== RPC_SUCCESS
)
1095 if ((clnt_st
!= RPC_PROGVERSMISMATCH
) &&
1096 (clnt_st
!= RPC_PROGUNAVAIL
)) {
1097 rpc_createerr
.cf_stat
= RPC_RPCBFAILURE
;
1098 clnt_geterr(client
, &rpc_createerr
.cf_error
);
1102 /* fall back to earlier version */
1103 CLNT_CONTROL(client
, CLGET_VERS
, (char *)&vers
);
1104 if (vers
== RPCBVERS4
) {
1106 CLNT_CONTROL(client
, CLSET_VERS
, (char *)&vers
);
1107 if (CLNT_CALL(client
, RPCBPROC_DUMP
,
1108 (xdrproc_t
)xdr_void
,
1109 NULL
, (xdrproc_t
)xdr_rpcblist_ptr
,
1110 (char *)&head
, tottimeout
) == RPC_SUCCESS
)
1113 rpc_createerr
.cf_stat
= RPC_RPCBFAILURE
;
1114 clnt_geterr(client
, &rpc_createerr
.cf_error
);
1117 CLNT_DESTROY(client
);
1122 * rpcbinder remote-call-service interface.
1123 * This routine is used to call the rpcbind remote call service
1124 * which will look up a service program in the address maps, and then
1125 * remotely call that routine with the given parameters. This allows
1126 * programs to do a lookup and call in one step.
1129 rpcb_rmtcall(const struct netconfig
*nconf
, const char *host
,
1130 const rpcprog_t prog
, const rpcvers_t vers
, const rpcproc_t proc
,
1131 const xdrproc_t xdrargs
, const caddr_t argsp
, const xdrproc_t xdrres
,
1132 const caddr_t resp
, const struct timeval tout
, struct netbuf
*addr_ptr
)
1135 enum clnt_stat stat
;
1136 struct r_rpcb_rmtcallargs a
;
1137 struct r_rpcb_rmtcallres r
;
1140 client
= getclnthandle((char *)host
, (struct netconfig
*)nconf
, NULL
);
1142 return (RPC_FAILED
);
1143 CLNT_CONTROL(client
, CLSET_RETRY_TIMEOUT
, (char *)&rmttimeout
);
1147 a
.args
.args_val
= argsp
;
1148 a
.xdr_args
= xdrargs
;
1150 r
.results
.results_val
= resp
;
1153 for (rpcb_vers
= RPCBVERS4
; rpcb_vers
>= RPCBVERS
; rpcb_vers
--) {
1154 CLNT_CONTROL(client
, CLSET_VERS
, (char *)&rpcb_vers
);
1155 stat
= CLNT_CALL(client
, RPCBPROC_CALLIT
,
1156 (xdrproc_t
)xdr_rpcb_rmtcallargs
, (char *)&a
,
1157 (xdrproc_t
)xdr_rpcb_rmtcallres
, (char *)&r
, tout
);
1158 if ((stat
== RPC_SUCCESS
) && (addr_ptr
!= NULL
)) {
1161 na
= uaddr2taddr((struct netconfig
*)nconf
, r
.addr
);
1163 stat
= RPC_N2AXLATEFAILURE
;
1164 ((struct netbuf
*)addr_ptr
)->len
= 0;
1167 if (na
->len
> addr_ptr
->maxlen
) {
1168 /* Too long address */
1169 stat
= RPC_FAILED
; /* XXX A better error no */
1170 netdir_free((char *)na
, ND_ADDR
);
1171 ((struct netbuf
*)addr_ptr
)->len
= 0;
1174 (void) memcpy(addr_ptr
->buf
, na
->buf
, (int)na
->len
);
1175 ((struct netbuf
*)addr_ptr
)->len
= na
->len
;
1176 netdir_free((char *)na
, ND_ADDR
);
1179 if ((stat
!= RPC_PROGVERSMISMATCH
) &&
1180 (stat
!= RPC_PROGUNAVAIL
))
1184 CLNT_DESTROY(client
);
1186 xdr_free((xdrproc_t
)xdr_wrapstring
, (char *)&r
.addr
);
1191 * Gets the time on the remote host.
1192 * Returns 1 if succeeds else 0.
1195 rpcb_gettime(const char *host
, time_t *timep
)
1197 CLIENT
*client
= NULL
;
1199 struct netconfig
*nconf
;
1203 if ((host
== NULL
) || (host
[0] == '\0')) {
1208 if ((handle
= __rpc_setconf("netpath")) == NULL
) {
1209 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
1212 rpc_createerr
.cf_stat
= RPC_SUCCESS
;
1213 while (client
== NULL
) {
1214 if ((nconf
= __rpc_getconf(handle
)) == NULL
) {
1215 if (rpc_createerr
.cf_stat
== RPC_SUCCESS
)
1216 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
1219 client
= getclnthandle((char *)host
, nconf
, NULL
);
1223 __rpc_endconf(handle
);
1227 st
= CLNT_CALL(client
, RPCBPROC_GETTIME
,
1228 (xdrproc_t
)xdr_void
, NULL
,
1229 (xdrproc_t
)xdr_time_t
, (char *)timep
, tottimeout
);
1231 if ((st
== RPC_PROGVERSMISMATCH
) || (st
== RPC_PROGUNAVAIL
)) {
1232 CLNT_CONTROL(client
, CLGET_VERS
, (char *)&vers
);
1233 if (vers
== RPCBVERS4
) {
1234 /* fall back to earlier version */
1236 CLNT_CONTROL(client
, CLSET_VERS
, (char *)&vers
);
1237 st
= CLNT_CALL(client
, RPCBPROC_GETTIME
,
1238 (xdrproc_t
)xdr_void
, NULL
,
1239 (xdrproc_t
)xdr_time_t
, (char *)timep
,
1243 CLNT_DESTROY(client
);
1244 return (st
== RPC_SUCCESS
? TRUE
: FALSE
);
1248 * Converts taddr to universal address. This routine should never
1249 * really be called because local n2a libraries are always provided.
1252 rpcb_taddr2uaddr(struct netconfig
*nconf
, struct netbuf
*taddr
)
1257 /* parameter checking */
1258 if (nconf
== NULL
) {
1259 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
1262 if (taddr
== NULL
) {
1263 rpc_createerr
.cf_stat
= RPC_UNKNOWNADDR
;
1266 client
= local_rpcb();
1270 CLNT_CALL(client
, RPCBPROC_TADDR2UADDR
, (xdrproc_t
)xdr_netbuf
,
1271 (char *)taddr
, (xdrproc_t
)xdr_wrapstring
, (char *)&uaddr
,
1273 CLNT_DESTROY(client
);
1278 * Converts universal address to netbuf. This routine should never
1279 * really be called because local n2a libraries are always provided.
1282 rpcb_uaddr2taddr(struct netconfig
*nconf
, char *uaddr
)
1285 struct netbuf
*taddr
;
1287 /* parameter checking */
1288 if (nconf
== NULL
) {
1289 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
1292 if (uaddr
== NULL
) {
1293 rpc_createerr
.cf_stat
= RPC_UNKNOWNADDR
;
1296 client
= local_rpcb();
1300 taddr
= calloc(1, sizeof (struct netbuf
));
1301 if (taddr
== NULL
) {
1302 CLNT_DESTROY(client
);
1306 if (CLNT_CALL(client
, RPCBPROC_UADDR2TADDR
, (xdrproc_t
)xdr_wrapstring
,
1307 (char *)&uaddr
, (xdrproc_t
)xdr_netbuf
, (char *)taddr
,
1308 tottimeout
) != RPC_SUCCESS
) {
1312 CLNT_DESTROY(client
);