1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23 /*
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * Copyright 2014 Gary Mills
29 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
30 * Use is subject to license terms.
31 */
32
33 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
34 /* All Rights Reserved */
35 /*
36 * Portions of this source code were derived from Berkeley
37 * 4.3 BSD under license from the Regents of the University of
38 * California.
39 */
40
41 /*
42 * interface to rpcbind rpc service.
43 */
44
45 #include "mt.h"
46 #include "rpc_mt.h"
47 #include <assert.h>
48 #include <rpc/rpc.h>
49 #include <rpc/rpcb_prot.h>
50 #include <netconfig.h>
51 #include <netdir.h>
52 #include <netdb.h>
53 #include <rpc/nettype.h>
54 #include <syslog.h>
55 #ifdef PORTMAP
56 #include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */
57 #include <rpc/pmap_prot.h>
58 #endif
59 #include <errno.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63
64 static struct timeval tottimeout = { 60, 0 };
65 static const struct timeval rmttimeout = { 3, 0 };
66 static struct timeval rpcbrmttime = { 15, 0 };
67
68 extern bool_t xdr_wrapstring(XDR *, char **);
69
70 static const char nullstring[] = "\000";
71
72 extern CLIENT *_clnt_tli_create_timed(int, const struct netconfig *,
73 struct netbuf *, rpcprog_t, rpcvers_t, uint_t, uint_t,
74 const struct timeval *);
75
76 static CLIENT *_getclnthandle_timed(char *, struct netconfig *, char **,
77 struct timeval *);
78
79
80 /*
81 * The life time of a cached entry should not exceed 5 minutes
82 * since automountd attempts an unmount every 5 minutes.
83 * It is arbitrarily set a little lower (3 min = 180 sec)
84 * to reduce the time during which an entry is stale.
85 */
86 #define CACHE_TTL 180
87 #define CACHESIZE 6
88
89 struct address_cache {
90 char *ac_host;
91 char *ac_netid;
92 char *ac_uaddr;
93 struct netbuf *ac_taddr;
94 struct address_cache *ac_next;
95 time_t ac_maxtime;
96 };
97
98 static struct address_cache *front;
99 static int cachesize;
100
101 extern int lowvers;
102 extern int authdes_cachesz;
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
__rpc_control(int request,void * info)110 __rpc_control(int request, void *info)
111 {
112 switch (request) {
113 case CLCR_GET_RPCB_TIMEOUT:
114 *(struct timeval *)info = tottimeout;
115 break;
116 case CLCR_SET_RPCB_TIMEOUT:
117 tottimeout = *(struct timeval *)info;
118 break;
119 case CLCR_GET_LOWVERS:
120 *(int *)info = lowvers;
121 break;
122 case CLCR_SET_LOWVERS:
123 lowvers = *(int *)info;
124 break;
125 case CLCR_GET_RPCB_RMTTIME:
126 *(struct timeval *)info = rpcbrmttime;
127 break;
128 case CLCR_SET_RPCB_RMTTIME:
129 rpcbrmttime = *(struct timeval *)info;
130 break;
131 case CLCR_GET_CRED_CACHE_SZ:
132 *(int *)info = authdes_cachesz;
133 break;
134 case CLCR_SET_CRED_CACHE_SZ:
135 authdes_cachesz = *(int *)info;
136 break;
137 default:
138 return (FALSE);
139 }
140 return (TRUE);
141 }
142
143 /*
144 * It might seem that a reader/writer lock would be more reasonable here.
145 * However because getclnthandle(), the only user of the cache functions,
146 * may do a delete_cache() operation if a check_cache() fails to return an
147 * address useful to clnt_tli_create(), we may as well use a mutex.
148 */
149 /*
150 * As it turns out, if the cache lock is *not* a reader/writer lock, we will
151 * block all clnt_create's if we are trying to connect to a host that's down,
152 * since the lock will be held all during that time.
153 */
154 extern rwlock_t rpcbaddr_cache_lock;
155
156 /*
157 * The routines check_cache(), add_cache(), delete_cache() manage the
158 * cache of rpcbind addresses for (host, netid).
159 */
160
161 static struct address_cache *
check_cache(char * host,char * netid)162 check_cache(char *host, char *netid)
163 {
164 struct address_cache *cptr;
165
166 /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
167
168 assert(RW_READ_HELD(&rpcbaddr_cache_lock));
169 for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
170 if ((strcmp(cptr->ac_host, host) == 0) &&
171 (strcmp(cptr->ac_netid, netid) == 0) &&
172 (time(NULL) <= cptr->ac_maxtime)) {
173 return (cptr);
174 }
175 }
176 return (NULL);
177 }
178
179 static void
delete_cache(struct netbuf * addr)180 delete_cache(struct netbuf *addr)
181 {
182 struct address_cache *cptr, *prevptr = NULL;
183
184 /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
185 assert(RW_WRITE_HELD(&rpcbaddr_cache_lock));
186 for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
187 if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
188 free(cptr->ac_host);
189 free(cptr->ac_netid);
190 free(cptr->ac_taddr->buf);
191 free(cptr->ac_taddr);
192 if (cptr->ac_uaddr)
193 free(cptr->ac_uaddr);
194 if (prevptr)
195 prevptr->ac_next = cptr->ac_next;
196 else
197 front = cptr->ac_next;
198 free(cptr);
199 cachesize--;
200 break;
201 }
202 prevptr = cptr;
203 }
204 }
205
206 static void
add_cache(char * host,char * netid,struct netbuf * taddr,char * uaddr)207 add_cache(char *host, char *netid, struct netbuf *taddr, char *uaddr)
208 {
209 struct address_cache *ad_cache, *cptr, *prevptr;
210
211 ad_cache = malloc(sizeof (struct address_cache));
212 if (!ad_cache) {
213 goto memerr;
214 }
215 ad_cache->ac_maxtime = time(NULL) + CACHE_TTL;
216 ad_cache->ac_host = strdup(host);
217 ad_cache->ac_netid = strdup(netid);
218 ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL;
219 ad_cache->ac_taddr = malloc(sizeof (struct netbuf));
220 if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr ||
221 (uaddr && !ad_cache->ac_uaddr)) {
222 goto memerr1;
223 }
224
225 ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len;
226 ad_cache->ac_taddr->buf = malloc(taddr->len);
227 if (ad_cache->ac_taddr->buf == NULL) {
228 goto memerr1;
229 }
230
231 (void) memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
232
233 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */
234
235 (void) rw_wrlock(&rpcbaddr_cache_lock);
236 if (cachesize < CACHESIZE) {
237 ad_cache->ac_next = front;
238 front = ad_cache;
239 cachesize++;
240 } else {
241 /* Free the last entry */
242 cptr = front;
243 prevptr = NULL;
244 while (cptr->ac_next) {
245 prevptr = cptr;
246 cptr = cptr->ac_next;
247 }
248
249 free(cptr->ac_host);
250 free(cptr->ac_netid);
251 free(cptr->ac_taddr->buf);
252 free(cptr->ac_taddr);
253 if (cptr->ac_uaddr)
254 free(cptr->ac_uaddr);
255
256 if (prevptr) {
257 prevptr->ac_next = NULL;
258 ad_cache->ac_next = front;
259 front = ad_cache;
260 } else {
261 front = ad_cache;
262 ad_cache->ac_next = NULL;
263 }
264 free(cptr);
265 }
266 (void) rw_unlock(&rpcbaddr_cache_lock);
267 return;
268 memerr1:
269 if (ad_cache->ac_host)
270 free(ad_cache->ac_host);
271 if (ad_cache->ac_netid)
272 free(ad_cache->ac_netid);
273 if (ad_cache->ac_uaddr)
274 free(ad_cache->ac_uaddr);
275 if (ad_cache->ac_taddr)
276 free(ad_cache->ac_taddr);
277 free(ad_cache);
278 memerr:
279 syslog(LOG_ERR, "add_cache : out of memory.");
280 }
281
282 /*
283 * This routine will return a client handle that is connected to the
284 * rpcbind. Returns NULL on error and free's everything.
285 */
286 static CLIENT *
getclnthandle(char * host,struct netconfig * nconf,char ** targaddr)287 getclnthandle(char *host, struct netconfig *nconf, char **targaddr)
288 {
289 return (_getclnthandle_timed(host, nconf, targaddr, NULL));
290 }
291
292 /*
293 * Same as getclnthandle() except it takes an extra timeout argument.
294 * This is for bug 4049792: clnt_create_timed does not timeout.
295 *
296 * If tp is NULL, use default timeout to get a client handle.
297 */
298 static CLIENT *
_getclnthandle_timed(char * host,struct netconfig * nconf,char ** targaddr,struct timeval * tp)299 _getclnthandle_timed(char *host, struct netconfig *nconf, char **targaddr,
300 struct timeval *tp)
301 {
302 CLIENT *client = NULL;
303 struct netbuf *addr;
304 struct netbuf addr_to_delete;
305 struct nd_addrlist *nas;
306 struct nd_hostserv rpcbind_hs;
307 struct address_cache *ad_cache;
308 char *tmpaddr;
309 int neterr;
310 int j;
311
312 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */
313
314 /* Get the address of the rpcbind. Check cache first */
315 addr_to_delete.len = 0;
316 (void) rw_rdlock(&rpcbaddr_cache_lock);
317 ad_cache = check_cache(host, nconf->nc_netid);
318 if (ad_cache != NULL) {
319 addr = ad_cache->ac_taddr;
320 client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr,
321 RPCBPROG, RPCBVERS4, 0, 0, tp);
322 if (client != NULL) {
323 if (targaddr) {
324 /*
325 * case where a client handle is created
326 * without a targaddr and the handle is
327 * requested with a targaddr
328 */
329 if (ad_cache->ac_uaddr != NULL) {
330 *targaddr = strdup(ad_cache->ac_uaddr);
331 if (*targaddr == NULL) {
332 syslog(LOG_ERR,
333 "_getclnthandle_timed: strdup "
334 "failed.");
335 rpc_createerr.cf_stat =
336 RPC_SYSTEMERROR;
337 (void) rw_unlock(
338 &rpcbaddr_cache_lock);
339 return (NULL);
340 }
341 } else {
342 *targaddr = NULL;
343 }
344 }
345 (void) rw_unlock(&rpcbaddr_cache_lock);
346 return (client);
347 }
348 if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) {
349 (void) rw_unlock(&rpcbaddr_cache_lock);
350 return (NULL);
351 }
352 addr_to_delete.len = addr->len;
353 addr_to_delete.buf = malloc(addr->len);
354 if (addr_to_delete.buf == NULL) {
355 addr_to_delete.len = 0;
356 } else {
357 (void) memcpy(addr_to_delete.buf, addr->buf, addr->len);
358 }
359 }
360 (void) rw_unlock(&rpcbaddr_cache_lock);
361 if (addr_to_delete.len != 0) {
362 /*
363 * Assume this may be due to cache data being
364 * outdated
365 */
366 (void) rw_wrlock(&rpcbaddr_cache_lock);
367 delete_cache(&addr_to_delete);
368 (void) rw_unlock(&rpcbaddr_cache_lock);
369 free(addr_to_delete.buf);
370 }
371 rpcbind_hs.h_host = host;
372 rpcbind_hs.h_serv = "rpcbind";
373
374 if ((neterr = netdir_getbyname(nconf, &rpcbind_hs, &nas)) != 0) {
375 if (neterr == ND_NOHOST)
376 rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
377 else
378 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
379 return (NULL);
380 }
381 /* XXX nas should perhaps be cached for better performance */
382
383 for (j = 0; j < nas->n_cnt; j++) {
384 addr = &(nas->n_addrs[j]);
385 client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr, RPCBPROG,
386 RPCBVERS4, 0, 0, tp);
387 if (client)
388 break;
389 }
390
391 if (client) {
392 tmpaddr = targaddr ? taddr2uaddr(nconf, addr) : NULL;
393 add_cache(host, nconf->nc_netid, addr, tmpaddr);
394 if (targaddr) {
395 *targaddr = tmpaddr;
396 }
397 }
398 netdir_free((char *)nas, ND_ADDRLIST);
399 return (client);
400 }
401
402 /*
403 * This routine will return a client handle that is connected to the local
404 * rpcbind. Returns NULL on error.
405 */
406 static CLIENT *
local_rpcb(void)407 local_rpcb(void)
408 {
409 static struct netconfig *loopnconf;
410 extern mutex_t loopnconf_lock;
411
412 /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
413 (void) mutex_lock(&loopnconf_lock);
414 if (loopnconf == NULL) {
415 struct netconfig *nconf, *tmpnconf = NULL;
416 void *nc_handle;
417
418 nc_handle = setnetconfig();
419 if (nc_handle == NULL) {
420 /* fails to open netconfig file */
421 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
422 (void) mutex_unlock(&loopnconf_lock);
423 return (NULL);
424 }
425 while (nconf = getnetconfig(nc_handle)) {
426 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
427 tmpnconf = nconf;
428 if (nconf->nc_semantics == NC_TPI_CLTS)
429 break;
430 }
431 }
432 if (tmpnconf == NULL) {
433 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
434 (void) mutex_unlock(&loopnconf_lock);
435 return (NULL);
436 }
437 loopnconf = getnetconfigent(tmpnconf->nc_netid);
438 /* loopnconf is never freed */
439 (void) endnetconfig(nc_handle);
440 }
441 (void) mutex_unlock(&loopnconf_lock);
442 return (getclnthandle(HOST_SELF_CONNECT, loopnconf, NULL));
443 }
444
445 /*
446 * Set a mapping between program, version and address.
447 * Calls the rpcbind service to do the mapping.
448 */
449 bool_t
rpcb_set(const rpcprog_t program,const rpcvers_t version,const struct netconfig * nconf,const struct netbuf * address)450 rpcb_set(const rpcprog_t program, const rpcvers_t version,
451 const struct netconfig *nconf, const struct netbuf *address)
452 {
453 CLIENT *client;
454 bool_t rslt = FALSE;
455 RPCB parms;
456 char uidbuf[32];
457
458 /* parameter checking */
459 if (nconf == NULL) {
460 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
461 return (FALSE);
462 }
463 if (address == NULL) {
464 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
465 return (FALSE);
466 }
467 client = local_rpcb();
468 if (!client)
469 return (FALSE);
470
471 parms.r_addr = taddr2uaddr((struct netconfig *)nconf,
472 (struct netbuf *)address); /* convert to universal */
473 if (!parms.r_addr) {
474 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
475 return (FALSE); /* no universal address */
476 }
477 parms.r_prog = program;
478 parms.r_vers = version;
479 parms.r_netid = nconf->nc_netid;
480 /*
481 * Though uid is not being used directly, we still send it for
482 * completeness. For non-unix platforms, perhaps some other
483 * string or an empty string can be sent.
484 */
485 (void) sprintf(uidbuf, "%d", (int)geteuid());
486 parms.r_owner = uidbuf;
487
488 CLNT_CALL(client, RPCBPROC_SET, (xdrproc_t)xdr_rpcb, (char *)&parms,
489 (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
490
491 CLNT_DESTROY(client);
492 free(parms.r_addr);
493 return (rslt);
494 }
495
496 /*
497 * Remove the mapping between program, version and netbuf address.
498 * Calls the rpcbind service to do the un-mapping.
499 * If netbuf is NULL, unset for all the transports, otherwise unset
500 * only for the given transport.
501 */
502 bool_t
rpcb_unset(const rpcprog_t program,const rpcvers_t version,const struct netconfig * nconf)503 rpcb_unset(const rpcprog_t program, const rpcvers_t version,
504 const struct netconfig *nconf)
505 {
506 CLIENT *client;
507 bool_t rslt = FALSE;
508 RPCB parms;
509 char uidbuf[32];
510
511 client = local_rpcb();
512 if (!client)
513 return (FALSE);
514
515 parms.r_prog = program;
516 parms.r_vers = version;
517 if (nconf)
518 parms.r_netid = nconf->nc_netid;
519 else
520 parms.r_netid = (char *)&nullstring[0]; /* unsets all */
521 parms.r_addr = (char *)&nullstring[0];
522 (void) sprintf(uidbuf, "%d", (int)geteuid());
523 parms.r_owner = uidbuf;
524
525 CLNT_CALL(client, RPCBPROC_UNSET, (xdrproc_t)xdr_rpcb, (char *)&parms,
526 (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
527
528 CLNT_DESTROY(client);
529 return (rslt);
530 }
531
532 /*
533 * From the merged list, find the appropriate entry
534 */
535 static struct netbuf *
got_entry(rpcb_entry_list_ptr relp,struct netconfig * nconf)536 got_entry(rpcb_entry_list_ptr relp, struct netconfig *nconf)
537 {
538 struct netbuf *na = NULL;
539 rpcb_entry_list_ptr sp;
540 rpcb_entry *rmap;
541
542 for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) {
543 rmap = &sp->rpcb_entry_map;
544 if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
545 (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
546 (nconf->nc_semantics == rmap->r_nc_semantics) &&
547 (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != NULL)) {
548 na = uaddr2taddr(nconf, rmap->r_maddr);
549 break;
550 }
551 }
552 return (na);
553 }
554
555 /*
556 * Quick check to see if rpcbind is up. Tries to connect over
557 * local transport.
558 */
559 bool_t
__rpcbind_is_up(void)560 __rpcbind_is_up(void)
561 {
562 struct netbuf *addr;
563 int fd;
564 struct t_call *sndcall;
565 struct netconfig *netconf;
566 bool_t res;
567
568 if ((fd = t_open("/dev/ticotsord", O_RDWR, NULL)) == -1)
569 return (TRUE);
570
571 if (t_bind(fd, NULL, NULL) == -1) {
572 (void) t_close(fd);
573 return (TRUE);
574 }
575
576 /* LINTED pointer cast */
577 if ((sndcall = (struct t_call *)t_alloc(fd, T_CALL, 0)) == NULL) {
578 (void) t_close(fd);
579 return (TRUE);
580 }
581
582 if ((netconf = getnetconfigent("ticotsord")) == NULL) {
583 (void) t_free((char *)sndcall, T_CALL);
584 (void) t_close(fd);
585 return (FALSE);
586 }
587 addr = uaddr2taddr(netconf, "localhost.rpc");
588 freenetconfigent(netconf);
589 if (addr == NULL || addr->buf == NULL) {
590 if (addr)
591 free(addr);
592 (void) t_free((char *)sndcall, T_CALL);
593 (void) t_close(fd);
594 return (FALSE);
595 }
596 sndcall->addr.maxlen = addr->maxlen;
597 sndcall->addr.len = addr->len;
598 sndcall->addr.buf = addr->buf;
599
600 if (t_connect(fd, sndcall, NULL) == -1)
601 res = FALSE;
602 else
603 res = TRUE;
604
605 sndcall->addr.maxlen = sndcall->addr.len = 0;
606 sndcall->addr.buf = NULL;
607 (void) t_free((char *)sndcall, T_CALL);
608 free(addr->buf);
609 free(addr);
610 (void) t_close(fd);
611
612 return (res);
613 }
614
615
616 /*
617 * An internal function which optimizes rpcb_getaddr function. It returns
618 * the universal address of the remote service or NULL. It also optionally
619 * returns the client handle that it uses to contact the remote rpcbind.
620 * The caller will re-purpose the client handle to contact the remote service.
621 *
622 * The algorithm used: First try version 4. Then try version 3 (svr4).
623 * Finally, if the transport is TCP or UDP, try version 2 (portmap).
624 * Version 4 is now available with all current systems on the network.
625 * With this algorithm, we get performance as well as a plan for
626 * obsoleting version 2.
627 *
628 * XXX: Due to some problems with t_connect(), we do not reuse the same client
629 * handle for COTS cases and hence in these cases we do not return the
630 * client handle. This code will change if t_connect() ever
631 * starts working properly. Also look under clnt_vc.c.
632 */
633 struct netbuf *
__rpcb_findaddr_timed(rpcprog_t program,rpcvers_t version,struct netconfig * nconf,char * host,CLIENT ** clpp,struct timeval * tp)634 __rpcb_findaddr_timed(rpcprog_t program, rpcvers_t version,
635 struct netconfig *nconf, char *host, CLIENT **clpp, struct timeval *tp)
636 {
637 static bool_t check_rpcbind = TRUE;
638 CLIENT *client = NULL;
639 RPCB parms;
640 enum clnt_stat clnt_st;
641 char *ua = NULL;
642 uint_t vers;
643 struct netbuf *address = NULL;
644 void *handle;
645 rpcb_entry_list_ptr relp = NULL;
646 bool_t tmp_client = FALSE;
647
648 /* parameter checking */
649 if (nconf == NULL) {
650 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
651 /*
652 * Setting rpc_createerr.cf_stat is sufficient.
653 * No details in rpc_createerr.cf_error needed.
654 */
655 return (NULL);
656 }
657
658 parms.r_addr = NULL;
659
660 /*
661 * Use default total timeout if no timeout is specified.
662 */
663 if (tp == NULL)
664 tp = &tottimeout;
665
666 /*
667 * Check if rpcbind is up. This prevents needless delays when
668 * accessing applications such as the keyserver while booting
669 * disklessly.
670 */
671 if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
672 if (!__rpcbind_is_up()) {
673 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
674 rpc_createerr.cf_error.re_errno = 0;
675 rpc_createerr.cf_error.re_terrno = 0;
676 goto error;
677 }
678 check_rpcbind = FALSE;
679 }
680
681 /*
682 * First try version 4.
683 */
684 parms.r_prog = program;
685 parms.r_vers = version;
686 parms.r_owner = (char *)&nullstring[0]; /* not needed; */
687 /* just for xdring */
688 parms.r_netid = nconf->nc_netid; /* not really needed */
689
690 /*
691 * If a COTS transport is being used, try getting address via CLTS
692 * transport. This works only with version 4.
693 */
694 if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
695 nconf->nc_semantics == NC_TPI_COTS) {
696 tmp_client = TRUE;
697 if ((handle = __rpc_setconf("datagram_v")) != NULL) {
698 struct netconfig *nconf_clts;
699
700 while ((nconf_clts = __rpc_getconf(handle)) != NULL) {
701 if (strcmp(nconf_clts->nc_protofmly,
702 nconf->nc_protofmly) != 0) {
703 continue;
704 }
705 /*
706 * Sets rpc_createerr.cf_error members
707 * on failure
708 */
709 client = _getclnthandle_timed(host, nconf_clts,
710 &parms.r_addr, tp);
711 break;
712 }
713 __rpc_endconf(handle);
714 }
715 } else {
716 /* Sets rpc_createerr.cf_error members on failure */
717 client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
718 }
719
720 if (client != NULL) {
721
722 /* Set rpcbind version 4 */
723 vers = RPCBVERS4;
724 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
725
726 /*
727 * We also send the remote system the address we used to
728 * contact it in case it can help it connect back with us
729 */
730 if (parms.r_addr == NULL) {
731 parms.r_addr = strdup(""); /* for XDRing */
732 if (parms.r_addr == NULL) {
733 syslog(LOG_ERR, "__rpcb_findaddr_timed: "
734 "strdup failed.");
735 /* Construct a system error */
736 rpc_createerr.cf_error.re_errno = errno;
737 rpc_createerr.cf_error.re_terrno = 0;
738 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
739 goto error;
740 }
741 }
742
743 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
744 (char *)&rpcbrmttime);
745
746 /* Sets error structure members in client handle */
747 clnt_st = CLNT_CALL(client, RPCBPROC_GETADDRLIST,
748 (xdrproc_t)xdr_rpcb, (char *)&parms,
749 (xdrproc_t)xdr_rpcb_entry_list_ptr, (char *)&relp, *tp);
750
751 switch (clnt_st) {
752 case RPC_SUCCESS: /* Call succeeded */
753 address = got_entry(relp, nconf);
754 xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
755 (char *)&relp);
756 if (address != NULL) {
757 /* Program number and version number matched */
758 goto done;
759 }
760 /* Program and version not found for this transport */
761 /*
762 * XXX: should have returned with RPC_PROGUNAVAIL
763 * or perhaps RPC_PROGNOTREGISTERED error but
764 * since the remote machine might not always be able
765 * to send the address on all transports, we try the
766 * regular way with version 3, then 2
767 */
768 /* Try the next version */
769 break;
770 case RPC_PROGVERSMISMATCH: /* RPC protocol mismatch */
771 clnt_geterr(client, &rpc_createerr.cf_error);
772 if (rpc_createerr.cf_error.re_vers.low > vers) {
773 rpc_createerr.cf_stat = clnt_st;
774 goto error; /* a new version, can't handle */
775 }
776 /* Try the next version */
777 break;
778 case RPC_PROCUNAVAIL: /* Procedure unavailable */
779 case RPC_PROGUNAVAIL: /* Program not available */
780 case RPC_TIMEDOUT: /* Call timed out */
781 /* Try the next version */
782 break;
783 default:
784 clnt_geterr(client, &rpc_createerr.cf_error);
785 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
786 goto error;
787 break;
788 }
789
790 } else {
791
792 /* No client */
793 tmp_client = FALSE;
794
795 } /* End of version 4 */
796
797 /* Destroy a temporary client */
798 if (client != NULL && tmp_client) {
799 CLNT_DESTROY(client);
800 client = NULL;
801 free(parms.r_addr);
802 parms.r_addr = NULL;
803 }
804 tmp_client = FALSE;
805
806 /*
807 * Try version 3
808 */
809
810 /* Now the same transport is to be used to get the address */
811 if (client == NULL) {
812 /* Sets rpc_createerr.cf_error members on failure */
813 client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
814 }
815 address = NULL;
816 if (client != NULL) {
817 if (parms.r_addr == NULL) {
818 parms.r_addr = strdup(""); /* for XDRing */
819 if (parms.r_addr == NULL) {
820 syslog(LOG_ERR, "__rpcb_findaddr_timed: "
821 "strdup failed.");
822 /* Construct a system error */
823 rpc_createerr.cf_error.re_errno = errno;
824 rpc_createerr.cf_error.re_terrno = 0;
825 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
826 goto error;
827 }
828 }
829
830 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
831 (char *)&rpcbrmttime);
832 vers = RPCBVERS; /* Set the version */
833 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
834
835 /* Sets error structure members in client handle */
836 clnt_st = CLNT_CALL(client, RPCBPROC_GETADDR,
837 (xdrproc_t)xdr_rpcb, (char *)&parms,
838 (xdrproc_t)xdr_wrapstring, (char *)&ua, *tp);
839
840 switch (clnt_st) {
841 case RPC_SUCCESS: /* Call succeeded */
842 if (ua != NULL) {
843 if (ua[0] != '\0') {
844 address = uaddr2taddr(nconf, ua);
845 }
846 xdr_free((xdrproc_t)xdr_wrapstring,
847 (char *)&ua);
848
849 if (address != NULL) {
850 goto done;
851 }
852 /* NULL universal address */
853 /* But client call was successful */
854 clnt_geterr(client, &rpc_createerr.cf_error);
855 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
856 goto error;
857 }
858 #ifndef PORTMAP
859 clnt_geterr(client, &rpc_createerr.cf_error);
860 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
861 goto error;
862 #endif
863 /* Try the next version */
864 break;
865 case RPC_PROGVERSMISMATCH: /* RPC protocol mismatch */
866 clnt_geterr(client, &rpc_createerr.cf_error);
867 #ifdef PORTMAP
868 if (rpc_createerr.cf_error.re_vers.low > vers) {
869 rpc_createerr.cf_stat = clnt_st;
870 goto error; /* a new version, can't handle */
871 }
872 #else
873 rpc_createerr.cf_stat = clnt_st;
874 goto error;
875 #endif
876 /* Try the next version */
877 break;
878 #ifdef PORTMAP
879 case RPC_PROCUNAVAIL: /* Procedure unavailable */
880 case RPC_PROGUNAVAIL: /* Program not available */
881 case RPC_TIMEDOUT: /* Call timed out */
882 /* Try the next version */
883 break;
884 #endif
885 default:
886 clnt_geterr(client, &rpc_createerr.cf_error);
887 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
888 goto error;
889 break;
890 }
891 } /* End of version 3 */
892 #ifndef PORTMAP
893 /* cf_error members set by creation failure */
894 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
895 #endif
896 /*
897 * Try version 2
898 */
899
900 #ifdef PORTMAP
901 /* Try version 2 for TCP or UDP */
902 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
903 ushort_t port = 0;
904 struct netbuf remote;
905 uint_t pmapvers = 2;
906 struct pmap pmapparms;
907
908 /*
909 * Try UDP only - there are some portmappers out
910 * there that use UDP only.
911 */
912 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
913 struct netconfig *newnconf;
914
915 if (client != NULL) {
916 CLNT_DESTROY(client);
917 client = NULL;
918 free(parms.r_addr);
919 parms.r_addr = NULL;
920 }
921 if ((handle = __rpc_setconf("udp")) == NULL) {
922 /* Construct an unknown protocol error */
923 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
924 goto error;
925 }
926
927 /*
928 * The following to reinforce that you can
929 * only request for remote address through
930 * the same transport you are requesting.
931 * ie. requesting unversial address
932 * of IPv4 has to be carried through IPv4.
933 * Can't use IPv6 to send out the request.
934 * The mergeaddr in rpcbind can't handle
935 * this.
936 */
937 for (;;) {
938 if ((newnconf = __rpc_getconf(handle))
939 == NULL) {
940 __rpc_endconf(handle);
941 /*
942 * Construct an unknown protocol
943 * error
944 */
945 rpc_createerr.cf_stat =
946 RPC_UNKNOWNPROTO;
947 goto error;
948 }
949 /*
950 * here check the protocol family to
951 * be consistent with the request one
952 */
953 if (strcmp(newnconf->nc_protofmly,
954 nconf->nc_protofmly) == 0)
955 break;
956 }
957
958 /* Sets rpc_createerr.cf_error members on failure */
959 client = _getclnthandle_timed(host, newnconf,
960 &parms.r_addr, tp);
961 __rpc_endconf(handle);
962 tmp_client = TRUE;
963 }
964 if (client == NULL) {
965 /*
966 * rpc_createerr. cf_error members were set by
967 * creation failure
968 */
969 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
970 tmp_client = FALSE;
971 goto error;
972 }
973
974 /*
975 * Set version and retry timeout.
976 */
977 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
978 CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
979
980 pmapparms.pm_prog = program;
981 pmapparms.pm_vers = version;
982 pmapparms.pm_prot = (strcmp(nconf->nc_proto, NC_TCP) != 0) ?
983 IPPROTO_UDP : IPPROTO_TCP;
984 pmapparms.pm_port = 0; /* not needed */
985
986 /* Sets error structure members in client handle */
987 clnt_st = CLNT_CALL(client, PMAPPROC_GETPORT,
988 (xdrproc_t)xdr_pmap, (caddr_t)&pmapparms,
989 (xdrproc_t)xdr_u_short, (caddr_t)&port, *tp);
990
991 if (clnt_st != RPC_SUCCESS) {
992 clnt_geterr(client, &rpc_createerr.cf_error);
993 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
994 goto error;
995 } else if (port == 0) {
996 /* Will be NULL universal address */
997 /* But client call was successful */
998 clnt_geterr(client, &rpc_createerr.cf_error);
999 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
1000 goto error;
1001 }
1002 port = htons(port);
1003 CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
1004 if (((address = malloc(sizeof (struct netbuf))) == NULL) ||
1005 ((address->buf = malloc(remote.len)) == NULL)) {
1006 /* Construct a system error */
1007 rpc_createerr.cf_error.re_errno = errno;
1008 rpc_createerr.cf_error.re_terrno = 0;
1009 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1010 free(address);
1011 address = NULL;
1012 goto error;
1013 }
1014 (void) memcpy(address->buf, remote.buf, remote.len);
1015 (void) memcpy(&address->buf[sizeof (short)], &port,
1016 sizeof (short));
1017 address->len = address->maxlen = remote.len;
1018 goto done;
1019 } else {
1020 /*
1021 * This is not NC_INET.
1022 * Always an error for version 2.
1023 */
1024 if (client != NULL && clnt_st != RPC_SUCCESS) {
1025 /* There is a client that failed */
1026 clnt_geterr(client, &rpc_createerr.cf_error);
1027 rpc_createerr.cf_stat = clnt_st;
1028 } else {
1029 /* Something else */
1030 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1031 /*
1032 * Setting rpc_createerr.cf_stat is sufficient.
1033 * No details in rpc_createerr.cf_error needed.
1034 */
1035 }
1036 }
1037 #endif
1038
1039 error:
1040 /* Return NULL address and NULL client */
1041 address = NULL;
1042 if (client != NULL) {
1043 CLNT_DESTROY(client);
1044 client = NULL;
1045 }
1046
1047 done:
1048 /* Return an address and optional client */
1049 if (client != NULL && tmp_client) {
1050 /* This client is the temporary one */
1051 CLNT_DESTROY(client);
1052 client = NULL;
1053 }
1054 if (clpp != NULL) {
1055 *clpp = client;
1056 } else if (client != NULL) {
1057 CLNT_DESTROY(client);
1058 }
1059 free(parms.r_addr);
1060 return (address);
1061 }
1062
1063
1064 /*
1065 * Find the mapped address for program, version.
1066 * Calls the rpcbind service remotely to do the lookup.
1067 * Uses the transport specified in nconf.
1068 * Returns FALSE (0) if no map exists, else returns 1.
1069 *
1070 * Assuming that the address is all properly allocated
1071 */
1072 int
rpcb_getaddr(const rpcprog_t program,const rpcvers_t version,const struct netconfig * nconf,struct netbuf * address,const char * host)1073 rpcb_getaddr(const rpcprog_t program, const rpcvers_t version,
1074 const struct netconfig *nconf, struct netbuf *address, const char *host)
1075 {
1076 struct netbuf *na;
1077
1078 if ((na = __rpcb_findaddr_timed(program, version,
1079 (struct netconfig *)nconf, (char *)host, NULL, NULL)) == NULL)
1080 return (FALSE);
1081
1082 if (na->len > address->maxlen) {
1083 /* Too long address */
1084 netdir_free((char *)na, ND_ADDR);
1085 rpc_createerr.cf_stat = RPC_FAILED;
1086 return (FALSE);
1087 }
1088 (void) memcpy(address->buf, na->buf, (int)na->len);
1089 address->len = na->len;
1090 netdir_free((char *)na, ND_ADDR);
1091 return (TRUE);
1092 }
1093
1094 /*
1095 * Get a copy of the current maps.
1096 * Calls the rpcbind service remotely to get the maps.
1097 *
1098 * It returns only a list of the services
1099 * It returns NULL on failure.
1100 */
1101 rpcblist *
rpcb_getmaps(const struct netconfig * nconf,const char * host)1102 rpcb_getmaps(const struct netconfig *nconf, const char *host)
1103 {
1104 rpcblist_ptr head = NULL;
1105 CLIENT *client;
1106 enum clnt_stat clnt_st;
1107 int vers = 0;
1108
1109 client = getclnthandle((char *)host,
1110 (struct netconfig *)nconf, NULL);
1111 if (client == NULL)
1112 return (NULL);
1113
1114 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
1115 (xdrproc_t)xdr_void, NULL,
1116 (xdrproc_t)xdr_rpcblist_ptr,
1117 (char *)&head, tottimeout);
1118 if (clnt_st == RPC_SUCCESS)
1119 goto done;
1120
1121 if ((clnt_st != RPC_PROGVERSMISMATCH) &&
1122 (clnt_st != RPC_PROGUNAVAIL)) {
1123 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1124 clnt_geterr(client, &rpc_createerr.cf_error);
1125 goto done;
1126 }
1127
1128 /* fall back to earlier version */
1129 CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
1130 if (vers == RPCBVERS4) {
1131 vers = RPCBVERS;
1132 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
1133 if (CLNT_CALL(client, RPCBPROC_DUMP,
1134 (xdrproc_t)xdr_void,
1135 NULL, (xdrproc_t)xdr_rpcblist_ptr,
1136 (char *)&head, tottimeout) == RPC_SUCCESS)
1137 goto done;
1138 }
1139 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1140 clnt_geterr(client, &rpc_createerr.cf_error);
1141
1142 done:
1143 CLNT_DESTROY(client);
1144 return (head);
1145 }
1146
1147 /*
1148 * rpcbinder remote-call-service interface.
1149 * This routine is used to call the rpcbind remote call service
1150 * which will look up a service program in the address maps, and then
1151 * remotely call that routine with the given parameters. This allows
1152 * programs to do a lookup and call in one step.
1153 */
1154 enum clnt_stat
rpcb_rmtcall(const struct netconfig * nconf,const char * host,const rpcprog_t prog,const rpcvers_t vers,const rpcproc_t proc,const xdrproc_t xdrargs,const caddr_t argsp,const xdrproc_t xdrres,const caddr_t resp,const struct timeval tout,struct netbuf * addr_ptr)1155 rpcb_rmtcall(const struct netconfig *nconf, const char *host,
1156 const rpcprog_t prog, const rpcvers_t vers, const rpcproc_t proc,
1157 const xdrproc_t xdrargs, const caddr_t argsp, const xdrproc_t xdrres,
1158 const caddr_t resp, const struct timeval tout, struct netbuf *addr_ptr)
1159 {
1160 CLIENT *client;
1161 enum clnt_stat stat;
1162 struct r_rpcb_rmtcallargs a;
1163 struct r_rpcb_rmtcallres r;
1164 int rpcb_vers;
1165
1166 client = getclnthandle((char *)host, (struct netconfig *)nconf, NULL);
1167 if (client == NULL)
1168 return (RPC_FAILED);
1169 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rmttimeout);
1170 a.prog = prog;
1171 a.vers = vers;
1172 a.proc = proc;
1173 a.args.args_val = argsp;
1174 a.xdr_args = xdrargs;
1175 r.addr = NULL;
1176 r.results.results_val = resp;
1177 r.xdr_res = xdrres;
1178
1179 for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) {
1180 CLNT_CONTROL(client, CLSET_VERS, (char *)&rpcb_vers);
1181 stat = CLNT_CALL(client, RPCBPROC_CALLIT,
1182 (xdrproc_t)xdr_rpcb_rmtcallargs, (char *)&a,
1183 (xdrproc_t)xdr_rpcb_rmtcallres, (char *)&r, tout);
1184 if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) {
1185 struct netbuf *na;
1186
1187 na = uaddr2taddr((struct netconfig *)nconf, r.addr);
1188 if (!na) {
1189 stat = RPC_N2AXLATEFAILURE;
1190 ((struct netbuf *)addr_ptr)->len = 0;
1191 goto error;
1192 }
1193 if (na->len > addr_ptr->maxlen) {
1194 /* Too long address */
1195 stat = RPC_FAILED; /* XXX A better error no */
1196 netdir_free((char *)na, ND_ADDR);
1197 ((struct netbuf *)addr_ptr)->len = 0;
1198 goto error;
1199 }
1200 (void) memcpy(addr_ptr->buf, na->buf, (int)na->len);
1201 ((struct netbuf *)addr_ptr)->len = na->len;
1202 netdir_free((char *)na, ND_ADDR);
1203 break;
1204 }
1205 if ((stat != RPC_PROGVERSMISMATCH) &&
1206 (stat != RPC_PROGUNAVAIL))
1207 goto error;
1208 }
1209 error:
1210 CLNT_DESTROY(client);
1211 if (r.addr)
1212 xdr_free((xdrproc_t)xdr_wrapstring, (char *)&r.addr);
1213 return (stat);
1214 }
1215
1216 /*
1217 * Gets the time on the remote host.
1218 * Returns 1 if succeeds else 0.
1219 */
1220 bool_t
rpcb_gettime(const char * host,time_t * timep)1221 rpcb_gettime(const char *host, time_t *timep)
1222 {
1223 CLIENT *client = NULL;
1224 void *handle;
1225 struct netconfig *nconf;
1226 int vers;
1227 enum clnt_stat st;
1228
1229 if ((host == NULL) || (host[0] == NULL)) {
1230 (void) time(timep);
1231 return (TRUE);
1232 }
1233
1234 if ((handle = __rpc_setconf("netpath")) == NULL) {
1235 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1236 return (FALSE);
1237 }
1238 rpc_createerr.cf_stat = RPC_SUCCESS;
1239 while (client == NULL) {
1240 if ((nconf = __rpc_getconf(handle)) == NULL) {
1241 if (rpc_createerr.cf_stat == RPC_SUCCESS)
1242 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1243 break;
1244 }
1245 client = getclnthandle((char *)host, nconf, NULL);
1246 if (client)
1247 break;
1248 }
1249 __rpc_endconf(handle);
1250 if (client == NULL)
1251 return (FALSE);
1252
1253 st = CLNT_CALL(client, RPCBPROC_GETTIME,
1254 (xdrproc_t)xdr_void, NULL,
1255 (xdrproc_t)xdr_time_t, (char *)timep, tottimeout);
1256
1257 if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) {
1258 CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
1259 if (vers == RPCBVERS4) {
1260 /* fall back to earlier version */
1261 vers = RPCBVERS;
1262 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
1263 st = CLNT_CALL(client, RPCBPROC_GETTIME,
1264 (xdrproc_t)xdr_void, NULL,
1265 (xdrproc_t)xdr_time_t, (char *)timep,
1266 tottimeout);
1267 }
1268 }
1269 CLNT_DESTROY(client);
1270 return (st == RPC_SUCCESS? TRUE : FALSE);
1271 }
1272
1273 /*
1274 * Converts taddr to universal address. This routine should never
1275 * really be called because local n2a libraries are always provided.
1276 */
1277 char *
rpcb_taddr2uaddr(struct netconfig * nconf,struct netbuf * taddr)1278 rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr)
1279 {
1280 CLIENT *client;
1281 char *uaddr = NULL;
1282
1283 /* parameter checking */
1284 if (nconf == NULL) {
1285 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1286 return (NULL);
1287 }
1288 if (taddr == NULL) {
1289 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
1290 return (NULL);
1291 }
1292 client = local_rpcb();
1293 if (!client)
1294 return (NULL);
1295
1296 CLNT_CALL(client, RPCBPROC_TADDR2UADDR, (xdrproc_t)xdr_netbuf,
1297 (char *)taddr, (xdrproc_t)xdr_wrapstring, (char *)&uaddr,
1298 tottimeout);
1299 CLNT_DESTROY(client);
1300 return (uaddr);
1301 }
1302
1303 /*
1304 * Converts universal address to netbuf. This routine should never
1305 * really be called because local n2a libraries are always provided.
1306 */
1307 struct netbuf *
rpcb_uaddr2taddr(struct netconfig * nconf,char * uaddr)1308 rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr)
1309 {
1310 CLIENT *client;
1311 struct netbuf *taddr;
1312
1313 /* parameter checking */
1314 if (nconf == NULL) {
1315 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1316 return (NULL);
1317 }
1318 if (uaddr == NULL) {
1319 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
1320 return (NULL);
1321 }
1322 client = local_rpcb();
1323 if (!client)
1324 return (NULL);
1325
1326 taddr = calloc(1, sizeof (struct netbuf));
1327 if (taddr == NULL) {
1328 CLNT_DESTROY(client);
1329 return (NULL);
1330 }
1331
1332 if (CLNT_CALL(client, RPCBPROC_UADDR2TADDR, (xdrproc_t)xdr_wrapstring,
1333 (char *)&uaddr, (xdrproc_t)xdr_netbuf, (char *)taddr,
1334 tottimeout) != RPC_SUCCESS) {
1335 free(taddr);
1336 taddr = NULL;
1337 }
1338 CLNT_DESTROY(client);
1339 return (taddr);
1340 }
1341