PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

lib/libc/rpc/rpcb_clnt.c

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