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

Cache object: a0f768f8a0d2e3d95bbf29ec42b86a0a


[ 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.