The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/rpc/rpcb_clnt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 254f53164e6689367e413d6240c9dabf


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.