Print this page
4729 __rpcb_findaddr_timed should try rpcbind protocol 4 first
Reviewed by: Marcel Telka <marcel@telka.sk>
*** 19,28 ****
--- 19,29 ----
*
* CDDL HEADER END
*/
/*
+ * Copyright 2014 Gary Mills
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
*** 31,42 ****
* Portions of this source code were derived from Berkeley
* 4.3 BSD under license from the Regents of the University of
* California.
*/
- #pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* interface to rpcbind rpc service.
*/
#include "mt.h"
--- 32,41 ----
*** 44,62 ****
#include <assert.h>
#include <rpc/rpc.h>
#include <rpc/rpcb_prot.h>
#include <netconfig.h>
#include <netdir.h>
#include <rpc/nettype.h>
#include <syslog.h>
#ifdef PORTMAP
#include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */
#include <rpc/pmap_prot.h>
#endif
- #ifdef ND_DEBUG
- #include <stdio.h>
- #endif
#include <sys/utsname.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
--- 43,59 ----
#include <assert.h>
#include <rpc/rpc.h>
#include <rpc/rpcb_prot.h>
#include <netconfig.h>
#include <netdir.h>
+ #include <netdb.h>
#include <rpc/nettype.h>
#include <syslog.h>
#ifdef PORTMAP
#include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */
#include <rpc/pmap_prot.h>
#endif
#include <sys/utsname.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
*** 168,181 ****
assert(RW_READ_HELD(&rpcbaddr_cache_lock));
for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
if ((strcmp(cptr->ac_host, host) == 0) &&
(strcmp(cptr->ac_netid, netid) == 0) &&
(time(NULL) <= cptr->ac_maxtime)) {
- #ifdef ND_DEBUG
- fprintf(stderr, "Found cache entry for %s: %s\n",
- host, netid);
- #endif
return (cptr);
}
}
return (NULL);
}
--- 165,174 ----
*** 231,243 ****
if (ad_cache->ac_taddr->buf == NULL) {
goto memerr1;
}
(void) memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
- #ifdef ND_DEBUG
- (void) fprintf(stderr, "Added to cache: %s : %s\n", host, netid);
- #endif
/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */
(void) rw_wrlock(&rpcbaddr_cache_lock);
if (cachesize < CACHESIZE) {
--- 224,233 ----
*** 251,264 ****
while (cptr->ac_next) {
prevptr = cptr;
cptr = cptr->ac_next;
}
- #ifdef ND_DEBUG
- fprintf(stderr, "Deleted from cache: %s : %s\n",
- cptr->ac_host, cptr->ac_netid);
- #endif
free(cptr->ac_host);
free(cptr->ac_netid);
free(cptr->ac_taddr->buf);
free(cptr->ac_taddr);
if (cptr->ac_uaddr)
--- 241,250 ----
*** 379,393 ****
(void) rw_unlock(&rpcbaddr_cache_lock);
free(addr_to_delete.buf);
}
rpcbind_hs.h_host = host;
rpcbind_hs.h_serv = "rpcbind";
- #ifdef ND_DEBUG
- fprintf(stderr, "rpcbind client routines: diagnostics :\n");
- fprintf(stderr, "\tGetting address for (%s, %s, %s) ... \n",
- rpcbind_hs.h_host, rpcbind_hs.h_serv, nconf->nc_netid);
- #endif
if ((neterr = netdir_getbyname(nconf, &rpcbind_hs, &nas)) != 0) {
if (neterr == ND_NOHOST)
rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
else
--- 365,374 ----
*** 396,432 ****
}
/* XXX nas should perhaps be cached for better performance */
for (j = 0; j < nas->n_cnt; j++) {
addr = &(nas->n_addrs[j]);
- #ifdef ND_DEBUG
- {
- int i;
- char *ua;
-
- ua = taddr2uaddr(nconf, &(nas->n_addrs[j]));
- fprintf(stderr, "Got it [%s]\n", ua);
- free(ua);
-
- fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n",
- addr->len, addr->maxlen);
- fprintf(stderr, "\tAddress is ");
- for (i = 0; i < addr->len; i++)
- fprintf(stderr, "%u.", addr->buf[i]);
- fprintf(stderr, "\n");
- }
- #endif
client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr, RPCBPROG,
RPCBVERS4, 0, 0, tp);
if (client)
break;
}
- #ifdef ND_DEBUG
- if (!client) {
- clnt_pcreateerror("rpcbind clnt interface");
- }
- #endif
if (client) {
tmpaddr = targaddr ? taddr2uaddr(nconf, addr) : NULL;
add_cache(host, nconf->nc_netid, addr, tmpaddr);
if (targaddr) {
--- 377,391 ----
*** 437,475 ****
return (client);
}
/*
* This routine will return a client handle that is connected to the local
! * rpcbind. Returns NULL on error and free's everything.
*/
static CLIENT *
local_rpcb(void)
{
static struct netconfig *loopnconf;
! static char *hostname;
extern mutex_t loopnconf_lock;
/* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
(void) mutex_lock(&loopnconf_lock);
if (loopnconf == NULL) {
- struct utsname utsname;
struct netconfig *nconf, *tmpnconf = NULL;
void *nc_handle;
! if (hostname == NULL) {
! #if defined(__i386) && !defined(__amd64)
! if ((_nuname(&utsname) == -1) ||
! #else
! if ((uname(&utsname) == -1) ||
! #endif
! ((hostname = strdup(utsname.nodename)) == NULL)) {
! syslog(LOG_ERR, "local_rpcb : strdup failed.");
rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
(void) mutex_unlock(&loopnconf_lock);
return (NULL);
}
- }
nc_handle = setnetconfig();
if (nc_handle == NULL) {
/* fails to open netconfig file */
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
(void) mutex_unlock(&loopnconf_lock);
--- 396,427 ----
return (client);
}
/*
* This routine will return a client handle that is connected to the local
! * rpcbind. Returns NULL on error.
*/
static CLIENT *
local_rpcb(void)
{
static struct netconfig *loopnconf;
! static char hostname[MAXHOSTNAMELEN + 1];
extern mutex_t loopnconf_lock;
/* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
(void) mutex_lock(&loopnconf_lock);
if (loopnconf == NULL) {
struct netconfig *nconf, *tmpnconf = NULL;
void *nc_handle;
! if ((hostname[0] == '\0') && (gethostname(hostname,
! sizeof (hostname)) < 0)) {
! syslog(LOG_ERR, "local_rpcb: gethostname failed.");
rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
(void) mutex_unlock(&loopnconf_lock);
return (NULL);
}
nc_handle = setnetconfig();
if (nc_handle == NULL) {
/* fails to open netconfig file */
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
(void) mutex_unlock(&loopnconf_lock);
*** 597,613 ****
if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
(strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
(nconf->nc_semantics == rmap->r_nc_semantics) &&
(rmap->r_maddr != NULL) && (rmap->r_maddr[0] != NULL)) {
na = uaddr2taddr(nconf, rmap->r_maddr);
- #ifdef ND_DEBUG
- fprintf(stderr, "\tRemote address is [%s].\n",
- rmap->r_maddr);
- if (!na)
- fprintf(stderr,
- "\tCouldn't resolve remote address!\n");
- #endif
break;
}
}
return (na);
}
--- 549,558 ----
*** 617,639 ****
* local transport.
*/
bool_t
__rpcbind_is_up(void)
{
! struct utsname name;
char uaddr[SYS_NMLN];
struct netbuf *addr;
int fd;
struct t_call *sndcall;
struct netconfig *netconf;
bool_t res;
! #if defined(__i386) && !defined(__amd64)
! if (_nuname(&name) == -1)
! #else
! if (uname(&name) == -1)
! #endif
return (TRUE);
if ((fd = t_open("/dev/ticotsord", O_RDWR, NULL)) == -1)
return (TRUE);
--- 562,580 ----
* local transport.
*/
bool_t
__rpcbind_is_up(void)
{
! char hostname[MAXHOSTNAMELEN + 1];
char uaddr[SYS_NMLN];
struct netbuf *addr;
int fd;
struct t_call *sndcall;
struct netconfig *netconf;
bool_t res;
! if (gethostname(hostname, sizeof (hostname)) < 0)
return (TRUE);
if ((fd = t_open("/dev/ticotsord", O_RDWR, NULL)) == -1)
return (TRUE);
*** 647,657 ****
(void) t_close(fd);
return (TRUE);
}
uaddr[0] = '\0';
! (void) strcpy(uaddr, name.nodename);
(void) strcat(uaddr, ".rpc");
if ((netconf = getnetconfigent("ticotsord")) == NULL) {
(void) t_free((char *)sndcall, T_CALL);
(void) t_close(fd);
return (FALSE);
--- 588,598 ----
(void) t_close(fd);
return (TRUE);
}
uaddr[0] = '\0';
! (void) strlcpy(uaddr, hostname, sizeof (uaddr) - 5);
(void) strcat(uaddr, ".rpc");
if ((netconf = getnetconfigent("ticotsord")) == NULL) {
(void) t_free((char *)sndcall, T_CALL);
(void) t_close(fd);
return (FALSE);
*** 684,705 ****
return (res);
}
/*
! * An internal function which optimizes rpcb_getaddr function. It also
* returns the client handle that it uses to contact the remote rpcbind.
*
! * The algorithm used: If the transports is TCP or UDP, it first tries
! * version 2 (portmap), 4 and then 3 (svr4). This order should be
! * changed in the next OS release to 4, 2 and 3. We are assuming that by
! * that time, version 4 would be available on many machines on the network.
* With this algorithm, we get performance as well as a plan for
* obsoleting version 2.
*
- * For all other transports, the algorithm remains as 4 and then 3.
- *
* XXX: Due to some problems with t_connect(), we do not reuse the same client
* handle for COTS cases and hence in these cases we do not return the
* client handle. This code will change if t_connect() ever
* starts working properly. Also look under clnt_vc.c.
*/
--- 625,645 ----
return (res);
}
/*
! * An internal function which optimizes rpcb_getaddr function. It returns
! * the universal address of the remote service or NULL. It also optionally
* returns the client handle that it uses to contact the remote rpcbind.
+ * The caller will re-purpose the client handle to contact the remote service.
*
! * The algorithm used: First try version 4. Then try version 3 (svr4).
! * Finally, if the transport is TCP or UDP, try version 2 (portmap).
! * Version 4 is now available with all current systems on the network.
* With this algorithm, we get performance as well as a plan for
* obsoleting version 2.
*
* XXX: Due to some problems with t_connect(), we do not reuse the same client
* handle for COTS cases and hence in these cases we do not return the
* client handle. This code will change if t_connect() ever
* starts working properly. Also look under clnt_vc.c.
*/
*** 712,726 ****
RPCB parms;
enum clnt_stat clnt_st;
char *ua = NULL;
uint_t vers;
struct netbuf *address = NULL;
! uint_t start_vers = RPCBVERS4;
/* parameter checking */
if (nconf == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (NULL);
}
parms.r_addr = NULL;
--- 652,672 ----
RPCB parms;
enum clnt_stat clnt_st;
char *ua = NULL;
uint_t vers;
struct netbuf *address = NULL;
! void *handle;
! rpcb_entry_list_ptr relp = NULL;
! bool_t tmp_client = FALSE;
/* parameter checking */
if (nconf == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ /*
+ * Setting rpc_createerr.cf_stat is sufficient.
+ * No details in rpc_createerr.cf_error needed.
+ */
return (NULL);
}
parms.r_addr = NULL;
*** 728,844 ****
* Use default total timeout if no timeout is specified.
*/
if (tp == NULL)
tp = &tottimeout;
- #ifdef PORTMAP
- /* Try version 2 for TCP or UDP */
- if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
- ushort_t port = 0;
- struct netbuf remote;
- uint_t pmapvers = 2;
- struct pmap pmapparms;
-
/*
- * Try UDP only - there are some portmappers out
- * there that use UDP only.
- */
- if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
- struct netconfig *newnconf;
- void *handle;
-
- if ((handle = __rpc_setconf("udp")) == NULL) {
- rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
- return (NULL);
- }
-
- /*
- * The following to reinforce that you can
- * only request for remote address through
- * the same transport you are requesting.
- * ie. requesting unversial address
- * of IPv4 has to be carried through IPv4.
- * Can't use IPv6 to send out the request.
- * The mergeaddr in rpcbind can't handle
- * this.
- */
- for (;;) {
- if ((newnconf = __rpc_getconf(handle))
- == NULL) {
- __rpc_endconf(handle);
- rpc_createerr.cf_stat =
- RPC_UNKNOWNPROTO;
- return (NULL);
- }
- /*
- * here check the protocol family to
- * be consistent with the request one
- */
- if (strcmp(newnconf->nc_protofmly,
- nconf->nc_protofmly) == NULL)
- break;
- }
-
- client = _getclnthandle_timed(host, newnconf,
- &parms.r_addr, tp);
- __rpc_endconf(handle);
- } else {
- client = _getclnthandle_timed(host, nconf,
- &parms.r_addr, tp);
- }
- if (client == NULL)
- return (NULL);
-
- /*
- * Set version and retry timeout.
- */
- CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
- CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
-
- pmapparms.pm_prog = program;
- pmapparms.pm_vers = version;
- pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
- IPPROTO_UDP : IPPROTO_TCP;
- pmapparms.pm_port = 0; /* not needed */
- clnt_st = CLNT_CALL(client, PMAPPROC_GETPORT,
- (xdrproc_t)xdr_pmap, (caddr_t)&pmapparms,
- (xdrproc_t)xdr_u_short, (caddr_t)&port,
- *tp);
- if (clnt_st != RPC_SUCCESS) {
- if ((clnt_st == RPC_PROGVERSMISMATCH) ||
- (clnt_st == RPC_PROGUNAVAIL))
- goto try_rpcbind; /* Try different versions */
- rpc_createerr.cf_stat = RPC_PMAPFAILURE;
- clnt_geterr(client, &rpc_createerr.cf_error);
- goto error;
- } else if (port == 0) {
- address = NULL;
- rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
- goto error;
- }
- port = htons(port);
- CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
- if (((address = malloc(sizeof (struct netbuf))) == NULL) ||
- ((address->buf = malloc(remote.len)) == NULL)) {
- rpc_createerr.cf_stat = RPC_SYSTEMERROR;
- clnt_geterr(client, &rpc_createerr.cf_error);
- if (address) {
- free(address);
- address = NULL;
- }
- goto error;
- }
- (void) memcpy(address->buf, remote.buf, remote.len);
- (void) memcpy(&address->buf[sizeof (short)], &port,
- sizeof (short));
- address->len = address->maxlen = remote.len;
- goto done;
- }
- #endif
-
- try_rpcbind:
- /*
* Check if rpcbind is up. This prevents needless delays when
* accessing applications such as the keyserver while booting
* disklessly.
*/
if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
--- 674,684 ----
*** 850,862 ****
}
check_rpcbind = FALSE;
}
/*
! * Now we try version 4 and then 3.
! * We also send the remote system the address we used to
! * contact it in case it can help to connect back with us
*/
parms.r_prog = program;
parms.r_vers = version;
parms.r_owner = (char *)&nullstring[0]; /* not needed; */
/* just for xdring */
--- 690,700 ----
}
check_rpcbind = FALSE;
}
/*
! * First try version 4.
*/
parms.r_prog = program;
parms.r_vers = version;
parms.r_owner = (char *)&nullstring[0]; /* not needed; */
/* just for xdring */
*** 866,1051 ****
* If a COTS transport is being used, try getting address via CLTS
* transport. This works only with version 4.
*/
if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
nconf->nc_semantics == NC_TPI_COTS) {
! void *handle;
struct netconfig *nconf_clts;
- rpcb_entry_list_ptr relp = NULL;
! if (client == NULL) {
! /* This did not go through the above PORTMAP/TCP code */
! if ((handle = __rpc_setconf("datagram_v")) != NULL) {
! while ((nconf_clts = __rpc_getconf(handle))
! != NULL) {
if (strcmp(nconf_clts->nc_protofmly,
nconf->nc_protofmly) != 0) {
continue;
}
! client = _getclnthandle_timed(host,
! nconf_clts, &parms.r_addr,
! tp);
break;
}
__rpc_endconf(handle);
}
- if (client == NULL)
- goto regular_rpcbind; /* Go the regular way */
} else {
! /* This is a UDP PORTMAP handle. Change to version 4 */
vers = RPCBVERS4;
CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
! }
/*
* We also send the remote system the address we used to
* contact it in case it can help it connect back with us
*/
if (parms.r_addr == NULL) {
parms.r_addr = strdup(""); /* for XDRing */
if (parms.r_addr == NULL) {
syslog(LOG_ERR, "__rpcb_findaddr_timed: "
"strdup failed.");
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
- address = NULL;
goto error;
}
}
! CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
clnt_st = CLNT_CALL(client, RPCBPROC_GETADDRLIST,
(xdrproc_t)xdr_rpcb, (char *)&parms,
! (xdrproc_t)xdr_rpcb_entry_list_ptr,
! (char *)&relp, *tp);
! if (clnt_st == RPC_SUCCESS) {
! if (address = got_entry(relp, nconf)) {
xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
(char *)&relp);
goto done;
}
! /* Entry not found for this transport */
! xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
! (char *)&relp);
/*
! * XXX: should have perhaps returned with error but
* since the remote machine might not always be able
* to send the address on all transports, we try the
! * regular way with regular_rpcbind
*/
! goto regular_rpcbind;
! } else if ((clnt_st == RPC_PROGVERSMISMATCH) ||
! (clnt_st == RPC_PROGUNAVAIL)) {
! start_vers = RPCBVERS; /* Try version 3 now */
! goto regular_rpcbind; /* Try different versions */
! } else {
! rpc_createerr.cf_stat = RPC_PMAPFAILURE;
clnt_geterr(client, &rpc_createerr.cf_error);
goto error;
}
- }
! regular_rpcbind:
! /* Now the same transport is to be used to get the address */
! if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
! (nconf->nc_semantics == NC_TPI_COTS))) {
! /* A CLTS type of client - destroy it */
CLNT_DESTROY(client);
client = NULL;
free(parms.r_addr);
parms.r_addr = NULL;
}
if (client == NULL) {
client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
- if (client == NULL) {
- address = NULL;
- goto error;
}
! }
if (parms.r_addr == NULL) {
parms.r_addr = strdup(""); /* for XDRing */
if (parms.r_addr == NULL) {
syslog(LOG_ERR, "__rpcb_findaddr_timed: "
"strdup failed.");
! address = NULL;
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
goto error;
}
}
! /* First try from start_vers and then version 3 (RPCBVERS) */
!
! CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
! for (vers = start_vers; vers >= RPCBVERS; vers--) {
! /* Set the version */
CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
clnt_st = CLNT_CALL(client, RPCBPROC_GETADDR,
(xdrproc_t)xdr_rpcb, (char *)&parms,
! (xdrproc_t)xdr_wrapstring,
! (char *)&ua, *tp);
! if (clnt_st == RPC_SUCCESS) {
! if ((ua == NULL) || (ua[0] == NULL)) {
! if (ua != NULL)
! xdr_free(xdr_wrapstring, (char *)&ua);
! /* address unknown */
rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
goto error;
}
! address = uaddr2taddr(nconf, ua);
! #ifdef ND_DEBUG
! fprintf(stderr, "\tRemote address is [%s]\n", ua);
! if (!address)
! fprintf(stderr,
! "\tCouldn't resolve remote address!\n");
#endif
! xdr_free((xdrproc_t)xdr_wrapstring, (char *)&ua);
!
! if (!address) {
! /* We don't know about your universal address */
! rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
goto error;
}
! goto done;
}
! if (clnt_st == RPC_PROGVERSMISMATCH) {
! struct rpc_err rpcerr;
! clnt_geterr(client, &rpcerr);
! if (rpcerr.re_vers.low > RPCBVERS4)
! goto error; /* a new version, can't handle */
! } else if (clnt_st != RPC_PROGUNAVAIL) {
! /* Cant handle this error */
goto error;
}
}
! if ((address == NULL) || (address->len == 0)) {
rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
clnt_geterr(client, &rpc_createerr.cf_error);
}
error:
! if (client) {
CLNT_DESTROY(client);
client = NULL;
}
done:
! if (nconf->nc_semantics != NC_TPI_CLTS) {
! /* This client is the connectionless one */
! if (client) {
CLNT_DESTROY(client);
client = NULL;
}
! }
! if (clpp) {
*clpp = client;
! } else if (client) {
CLNT_DESTROY(client);
}
- if (parms.r_addr)
free(parms.r_addr);
return (address);
}
--- 704,1076 ----
* If a COTS transport is being used, try getting address via CLTS
* transport. This works only with version 4.
*/
if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
nconf->nc_semantics == NC_TPI_COTS) {
! tmp_client = TRUE;
! if ((handle = __rpc_setconf("datagram_v")) != NULL) {
struct netconfig *nconf_clts;
! while ((nconf_clts = __rpc_getconf(handle)) != NULL) {
if (strcmp(nconf_clts->nc_protofmly,
nconf->nc_protofmly) != 0) {
continue;
}
! /*
! * Sets rpc_createerr.cf_error members
! * on failure
! */
! client = _getclnthandle_timed(host, nconf_clts,
! &parms.r_addr, tp);
break;
}
__rpc_endconf(handle);
}
} else {
! /* Sets rpc_createerr.cf_error members on failure */
! client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
! }
!
! if (client != NULL) {
!
! /* Set rpcbind version 4 */
vers = RPCBVERS4;
CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
!
/*
* We also send the remote system the address we used to
* contact it in case it can help it connect back with us
*/
if (parms.r_addr == NULL) {
parms.r_addr = strdup(""); /* for XDRing */
if (parms.r_addr == NULL) {
syslog(LOG_ERR, "__rpcb_findaddr_timed: "
"strdup failed.");
+ /* Construct a system error */
+ rpc_createerr.cf_error.re_errno = errno;
+ rpc_createerr.cf_error.re_terrno = 0;
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
goto error;
}
}
! CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
! (char *)&rpcbrmttime);
+ /* Sets error structure members in client handle */
clnt_st = CLNT_CALL(client, RPCBPROC_GETADDRLIST,
(xdrproc_t)xdr_rpcb, (char *)&parms,
! (xdrproc_t)xdr_rpcb_entry_list_ptr, (char *)&relp, *tp);
!
! switch (clnt_st) {
! case RPC_SUCCESS: /* Call succeeded */
! address = got_entry(relp, nconf);
xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
(char *)&relp);
+ if (address != NULL) {
+ /* Program number and version number matched */
goto done;
}
! /* Program and version not found for this transport */
/*
! * XXX: should have returned with RPC_PROGUNAVAIL
! * or perhaps RPC_PROGNOTREGISTERED error but
* since the remote machine might not always be able
* to send the address on all transports, we try the
! * regular way with version 3, then 2
*/
! /* Try the next version */
! break;
! case RPC_PROGVERSMISMATCH: /* RPC protocol mismatch */
clnt_geterr(client, &rpc_createerr.cf_error);
+ if (rpc_createerr.cf_error.re_vers.low > vers) {
+ rpc_createerr.cf_stat = clnt_st;
+ goto error; /* a new version, can't handle */
+ }
+ /* Try the next version */
+ break;
+ case RPC_PROCUNAVAIL: /* Procedure unavailable */
+ case RPC_PROGUNAVAIL: /* Program not available */
+ case RPC_TIMEDOUT: /* Call timed out */
+ /* Try the next version */
+ break;
+ default:
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ rpc_createerr.cf_stat = RPC_PMAPFAILURE;
goto error;
+ break;
}
! } else {
! /* No client */
! tmp_client = FALSE;
!
! } /* End of version 4 */
!
! /* Destroy a temporary client */
! if (client != NULL && tmp_client) {
CLNT_DESTROY(client);
client = NULL;
free(parms.r_addr);
parms.r_addr = NULL;
}
+ tmp_client = FALSE;
+ /*
+ * Try version 3
+ */
+
+ /* Now the same transport is to be used to get the address */
if (client == NULL) {
+ /* Sets rpc_createerr.cf_error members on failure */
client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
}
! address = NULL;
! if (client != NULL) {
if (parms.r_addr == NULL) {
parms.r_addr = strdup(""); /* for XDRing */
if (parms.r_addr == NULL) {
syslog(LOG_ERR, "__rpcb_findaddr_timed: "
"strdup failed.");
! /* Construct a system error */
! rpc_createerr.cf_error.re_errno = errno;
! rpc_createerr.cf_error.re_terrno = 0;
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
goto error;
}
}
! CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
! (char *)&rpcbrmttime);
! vers = RPCBVERS; /* Set the version */
CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
+
+ /* Sets error structure members in client handle */
clnt_st = CLNT_CALL(client, RPCBPROC_GETADDR,
(xdrproc_t)xdr_rpcb, (char *)&parms,
! (xdrproc_t)xdr_wrapstring, (char *)&ua, *tp);
! switch (clnt_st) {
! case RPC_SUCCESS: /* Call succeeded */
! if (ua != NULL) {
! if (ua[0] != '\0') {
! address = uaddr2taddr(nconf, ua);
! }
! xdr_free((xdrproc_t)xdr_wrapstring,
! (char *)&ua);
!
! if (address != NULL) {
! goto done;
! }
! /* NULL universal address */
! /* But client call was successful */
! clnt_geterr(client, &rpc_createerr.cf_error);
rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
goto error;
}
! #ifndef PORTMAP
! clnt_geterr(client, &rpc_createerr.cf_error);
! rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
! goto error;
#endif
! /* Try the next version */
! break;
! case RPC_PROGVERSMISMATCH: /* RPC protocol mismatch */
! clnt_geterr(client, &rpc_createerr.cf_error);
! #ifdef PORTMAP
! if (rpc_createerr.cf_error.re_vers.low > vers) {
! rpc_createerr.cf_stat = clnt_st;
! goto error; /* a new version, can't handle */
! }
! #else
! rpc_createerr.cf_stat = clnt_st;
goto error;
+ #endif
+ /* Try the next version */
+ break;
+ #ifdef PORTMAP
+ case RPC_PROCUNAVAIL: /* Procedure unavailable */
+ case RPC_PROGUNAVAIL: /* Program not available */
+ case RPC_TIMEDOUT: /* Call timed out */
+ /* Try the next version */
+ break;
+ #endif
+ default:
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+ goto error;
+ break;
}
! } /* End of version 3 */
! #ifndef PORTMAP
! /* cf_error members set by creation failure */
! rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
! #endif
! /*
! * Try version 2
! */
!
! #ifdef PORTMAP
! /* Try version 2 for TCP or UDP */
! if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
! ushort_t port = 0;
! struct netbuf remote;
! uint_t pmapvers = 2;
! struct pmap pmapparms;
!
! /*
! * Try UDP only - there are some portmappers out
! * there that use UDP only.
! */
! if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
! struct netconfig *newnconf;
!
! if (client != NULL) {
! CLNT_DESTROY(client);
! client = NULL;
! free(parms.r_addr);
! parms.r_addr = NULL;
}
! if ((handle = __rpc_setconf("udp")) == NULL) {
! /* Construct an unknown protocol error */
! rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
! goto error;
! }
! /*
! * The following to reinforce that you can
! * only request for remote address through
! * the same transport you are requesting.
! * ie. requesting unversial address
! * of IPv4 has to be carried through IPv4.
! * Can't use IPv6 to send out the request.
! * The mergeaddr in rpcbind can't handle
! * this.
! */
! for (;;) {
! if ((newnconf = __rpc_getconf(handle))
! == NULL) {
! __rpc_endconf(handle);
! /*
! * Construct an unknown protocol
! * error
! */
! rpc_createerr.cf_stat =
! RPC_UNKNOWNPROTO;
goto error;
}
+ /*
+ * here check the protocol family to
+ * be consistent with the request one
+ */
+ if (strcmp(newnconf->nc_protofmly,
+ nconf->nc_protofmly) == 0)
+ break;
}
! /* Sets rpc_createerr.cf_error members on failure */
! client = _getclnthandle_timed(host, newnconf,
! &parms.r_addr, tp);
! __rpc_endconf(handle);
! tmp_client = TRUE;
! }
! if (client == NULL) {
! /*
! * rpc_createerr. cf_error members were set by
! * creation failure
! */
rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+ tmp_client = FALSE;
+ goto error;
+ }
+
+ /*
+ * Set version and retry timeout.
+ */
+ CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
+ CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
+
+ pmapparms.pm_prog = program;
+ pmapparms.pm_vers = version;
+ pmapparms.pm_prot = (strcmp(nconf->nc_proto, NC_TCP) != 0) ?
+ IPPROTO_UDP : IPPROTO_TCP;
+ pmapparms.pm_port = 0; /* not needed */
+
+ /* Sets error structure members in client handle */
+ clnt_st = CLNT_CALL(client, PMAPPROC_GETPORT,
+ (xdrproc_t)xdr_pmap, (caddr_t)&pmapparms,
+ (xdrproc_t)xdr_u_short, (caddr_t)&port, *tp);
+
+ if (clnt_st != RPC_SUCCESS) {
clnt_geterr(client, &rpc_createerr.cf_error);
+ rpc_createerr.cf_stat = RPC_RPCBFAILURE;
+ goto error;
+ } else if (port == 0) {
+ /* Will be NULL universal address */
+ /* But client call was successful */
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+ goto error;
}
+ port = htons(port);
+ CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
+ if (((address = malloc(sizeof (struct netbuf))) == NULL) ||
+ ((address->buf = malloc(remote.len)) == NULL)) {
+ /* Construct a system error */
+ rpc_createerr.cf_error.re_errno = errno;
+ rpc_createerr.cf_error.re_terrno = 0;
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ free(address);
+ address = NULL;
+ goto error;
+ }
+ (void) memcpy(address->buf, remote.buf, remote.len);
+ (void) memcpy(&address->buf[sizeof (short)], &port,
+ sizeof (short));
+ address->len = address->maxlen = remote.len;
+ goto done;
+ } else {
+ /*
+ * This is not NC_INET.
+ * Always an error for version 2.
+ */
+ if (client != NULL && clnt_st != RPC_SUCCESS) {
+ /* There is a client that failed */
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ rpc_createerr.cf_stat = clnt_st;
+ } else {
+ /* Something else */
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ /*
+ * Setting rpc_createerr.cf_stat is sufficient.
+ * No details in rpc_createerr.cf_error needed.
+ */
+ }
+ }
+ #endif
error:
! /* Return NULL address and NULL client */
! address = NULL;
! if (client != NULL) {
CLNT_DESTROY(client);
client = NULL;
}
+
done:
! /* Return an address and optional client */
! if (client != NULL && tmp_client) {
! /* This client is the temporary one */
CLNT_DESTROY(client);
client = NULL;
}
! if (clpp != NULL) {
*clpp = client;
! } else if (client != NULL) {
CLNT_DESTROY(client);
}
free(parms.r_addr);
return (address);
}