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