Print this page
4729 __rpcb_findaddr_timed should try rpcbind protocol 4 first

*** 19,28 **** --- 19,29 ---- * * CDDL HEADER END */ /* + * Copyright (c) 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 ----
*** 456,469 **** 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); } --- 455,469 ---- 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); }
*** 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. */ --- 684,703 ---- 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 algorithm used: First try version 4. Then try version 3 (svr4). ! * Finally, if the transport is TCP or UDP, try version 2 (portmap). ! * We assume that version 4 is now available on many machines 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); --- 710,722 ---- 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) { --- 728,738 ----
*** 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 */ --- 744,754 ---- } 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,882 **** * 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; --- 758,775 ---- * 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) { ! handle = __rpc_setconf("datagram_v"); ! } else { ! handle = __rpc_setconf(nconf->nc_proto); ! } ! ! if (handle != NULL) { struct netconfig *nconf_clts; while ((nconf_clts = __rpc_getconf(handle)) != NULL) { if (strcmp(nconf_clts->nc_protofmly, nconf->nc_protofmly) != 0) { continue;
*** 886,902 **** 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) { --- 779,798 ---- tp); break; } __rpc_endconf(handle); } ! if (client != NULL) { ! ! if (nconf->nc_semantics == NC_TPI_COTS_ORD || ! nconf->nc_semantics == NC_TPI_COTS) ! tmp_client = TRUE; ! ! /* 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) {
*** 908,924 **** 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; } --- 804,822 ---- 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); ! switch (clnt_st) { ! case RPC_SUCCESS: if (address = got_entry(relp, nconf)) { xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr, (char *)&relp); goto done; }
*** 927,951 **** (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 */ --- 825,853 ---- (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 version 3, then 2 */ ! /* Try the next version */ ! break; ! case RPC_PROGVERSMISMATCH: ! case RPC_PROGUNAVAIL: ! /* Try the next version */ ! break; ! default: rpc_createerr.cf_stat = RPC_PMAPFAILURE; clnt_geterr(client, &rpc_createerr.cf_error); goto error; + break; } ! } /* End of version 4 */ ! /* ! * Try version 3 ! */ /* 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 */
*** 955,969 **** 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."); --- 857,869 ---- parms.r_addr = NULL; } if (client == NULL) { client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp); } ! if (client != NULL) { ! tmp_client = FALSE; if (parms.r_addr == NULL) { parms.r_addr = strdup(""); /* for XDRing */ if (parms.r_addr == NULL) { syslog(LOG_ERR, "__rpcb_findaddr_timed: " "strdup failed.");
*** 971,1040 **** 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; } } --- 871,1056 ---- 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); ! switch (clnt_st) { ! case RPC_SUCCESS: ! if ((ua != NULL) && (ua[0] != '\0')) { ! address = uaddr2taddr(nconf, ua); ! #ifdef ND_DEBUG ! fprintf(stderr, "\tRemote address is [%s]\n", ! ua); ! #endif ! xdr_free((xdrproc_t)xdr_wrapstring, ! (char *)&ua); ! } else if (ua != NULL) { xdr_free(xdr_wrapstring, (char *)&ua); } ! ! if (ua != NULL && address != NULL) { ! goto done; ! } else if (address == NULL) { ! /* We don't know about your universal addr */ #ifdef ND_DEBUG fprintf(stderr, "\tCouldn't resolve remote address!\n"); #endif ! rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; goto error; } ! /* Try the next version */ ! break; ! case RPC_PROGVERSMISMATCH: ! clnt_geterr(client, &rpc_createerr.cf_error); ! if (rpc_createerr.cf_error.re_vers.low > RPCBVERS4) goto error; /* a new version, can't handle */ ! /* Try the next version */ ! break; ! case RPC_PROGUNAVAIL: ! /* Try the next version */ ! break; ! default: ! clnt_geterr(client, &rpc_createerr.cf_error); ! rpc_createerr.cf_stat = RPC_PMAPFAILURE; goto error; + break; } + } else { + address = NULL; + } /* End of version 3 */ + + /* + * 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) { + CLNT_DESTROY(client); + client = NULL; + free(parms.r_addr); + parms.r_addr = NULL; } + 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); ! } ! if (client == NULL) ! return (NULL); ! ! if (strcmp(nconf->nc_proto, NC_TCP) == 0) ! tmp_client = TRUE; ! ! /* ! * 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) { ! 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 error: + /* Return NULL address and NULL client */ if (client) { CLNT_DESTROY(client); client = NULL; } + done: ! /* Return an address and optional client */ ! if (tmp_client) { ! /* This client is the temporary one */ if (client) { CLNT_DESTROY(client); client = NULL; } }