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