Print this page
4729 __rpcb_findaddr_timed should try rpcbind protocol 4 first

*** 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 ----
*** 50,62 **** #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> --- 49,58 ----
*** 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); } --- 164,173 ----
*** 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) { --- 223,232 ----
*** 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) --- 240,249 ----
*** 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 --- 364,373 ----
*** 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) { --- 376,390 ----
*** 437,474 **** 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; --- 395,434 ---- 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; extern mutex_t loopnconf_lock; ! /* VARIABLES PROTECTED BY loopnconf_lock: hostname 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) || + ((hostname = strdup(utsname.nodename)) == NULL)) { #else if ((uname(&utsname) == -1) || ((hostname = strdup(utsname.nodename)) == NULL)) { + #endif syslog(LOG_ERR, "local_rpcb : strdup failed."); rpc_createerr.cf_stat = RPC_UNKNOWNHOST; (void) mutex_unlock(&loopnconf_lock); return (NULL); } + /* hostname is never freed */ } nc_handle = setnetconfig(); if (nc_handle == NULL) { /* fails to open netconfig file */ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
*** 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); } --- 557,566 ----
*** 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. */ --- 637,657 ---- 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 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,722 **** 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); --- 664,676 ---- 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; return (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) { --- 682,692 ----
*** 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 */ --- 698,708 ---- } 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); } --- 712,1055 ---- * 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; } ! client = _getclnthandle_timed(host, nconf_clts, ! &parms.r_addr, tp); break; } __rpc_endconf(handle); } } else { ! client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp); ! /* Sets cf_error members on failure */ ! } ! ! 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."); + /* cf_error is still zeroed */ + rpc_createerr.cf_error.re_errno = errno; rpc_createerr.cf_stat = RPC_SYSTEMERROR; 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); ! /* Sets error structure members in client handle */ ! 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) { client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp); ! /* Sets cf_error members on failure */ } ! 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."); ! /* cf_error is still zeroed */ ! rpc_createerr.cf_error.re_errno = errno; 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); clnt_st = CLNT_CALL(client, RPCBPROC_GETADDR, (xdrproc_t)xdr_rpcb, (char *)&parms, ! (xdrproc_t)xdr_wrapstring, (char *)&ua, *tp); ! /* Sets error structure members in client handle */ ! 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; ! } ! /* We don't know about your universal addr */ ! /* cf_error is still zeroed */ 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) { ! /* cf_error is still zeroed */ ! 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); ! /* cf_error is still zeroed */ ! 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; } ! client = _getclnthandle_timed(host, newnconf, ! &parms.r_addr, tp); ! /* Sets cf_error members on failure */ ! __rpc_endconf(handle); ! tmp_client = TRUE; ! } ! if (client == NULL) { ! /* cf_error members 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 */ + clnt_st = CLNT_CALL(client, PMAPPROC_GETPORT, + (xdrproc_t)xdr_pmap, (caddr_t)&pmapparms, + (xdrproc_t)xdr_u_short, (caddr_t)&port, *tp); + /* Sets error structure members in client handle */ + if (clnt_st != RPC_SUCCESS) { clnt_geterr(client, &rpc_createerr.cf_error); + rpc_createerr.cf_stat = RPC_RPCBFAILURE; + goto error; + } else if (port == 0) { + /* cf_error is still zeroed */ + 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)) { + /* cf_error is still zeroed */ + rpc_createerr.cf_error.re_errno = errno; + 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 { + /* Not NC_INET */ + if (client != NULL && clnt_st != RPC_SUCCESS) { + clnt_geterr(client, &rpc_createerr.cf_error); + rpc_createerr.cf_stat = clnt_st; + } else { + /* No client handle */ + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + } + } + #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); }