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