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