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