1  /*
       2   * pmap_rmt.c
       3   * Client interface to pmap rpc service.
       4   * remote call and broadcast service
       5   *
       6   * Copyright (c) 2010, Oracle America, Inc.
       7   *
       8   * Redistribution and use in source and binary forms, with or without
       9   * modification, are permitted provided that the following conditions are
      10   * met:
      11   *
      12   *     * Redistributions of source code must retain the above copyright
      13   *       notice, this list of conditions and the following disclaimer.
      14   *     * Redistributions in binary form must reproduce the above
      15   *       copyright notice, this list of conditions and the following
      16   *       disclaimer in the documentation and/or other materials
      17   *       provided with the distribution.
      18   *     * Neither the name of the "Oracle America, Inc." nor the names of its
      19   *       contributors may be used to endorse or promote products derived
      20   *       from this software without specific prior written permission.
      21   *
      22   *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      23   *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      24   *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
      25   *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
      26   *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
      27   *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28   *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
      29   *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      30   *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      31   *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      32   *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      33   *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      34   */
      35  
      36  #include <unistd.h>
      37  #include <string.h>
      38  #include <libintl.h>
      39  #include <rpc/rpc.h>
      40  #include <rpc/pmap_prot.h>
      41  #include <rpc/pmap_clnt.h>
      42  #include <rpc/pmap_rmt.h>
      43  #include <sys/poll.h>
      44  #include <sys/socket.h>
      45  #include <stdio.h>
      46  #include <errno.h>
      47  #include <sys/param.h>
      48  #include <net/if.h>
      49  #include <ifaddrs.h>
      50  #include <sys/ioctl.h>
      51  #include <arpa/inet.h>
      52  #include <shlib-compat.h>
      53  
      54  #define MAX_BROADCAST_SIZE 1400
      55  
      56  extern u_long _create_xid (void);
      57  
      58  static const struct timeval timeout = {3, 0};
      59  
      60  /*
      61   * pmapper remote-call-service interface.
      62   * This routine is used to call the pmapper remote call service
      63   * which will look up a service program in the port maps, and then
      64   * remotely call that routine with the given parameters.  This allows
      65   * programs to do a lookup and call in one step.
      66   */
      67  enum clnt_stat
      68  pmap_rmtcall (struct sockaddr_in *addr, u_long prog, u_long vers, u_long proc,
      69  	      xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp,
      70  	      struct timeval tout, u_long *port_ptr)
      71  {
      72    int socket = -1;
      73    CLIENT *client;
      74    struct rmtcallargs a;
      75    struct rmtcallres r;
      76    enum clnt_stat stat;
      77  
      78    addr->sin_port = htons (PMAPPORT);
      79    client = clntudp_create (addr, PMAPPROG, PMAPVERS, timeout, &socket);
      80    if (client != (CLIENT *) NULL)
      81      {
      82        a.prog = prog;
      83        a.vers = vers;
      84        a.proc = proc;
      85        a.args_ptr = argsp;
      86        a.xdr_args = xdrargs;
      87        r.port_ptr = port_ptr;
      88        r.results_ptr = resp;
      89        r.xdr_results = xdrres;
      90        stat = CLNT_CALL (client, PMAPPROC_CALLIT,
      91  			(xdrproc_t)xdr_rmtcall_args,
      92  			(caddr_t)&a, (xdrproc_t)xdr_rmtcallres,
      93  			(caddr_t)&r, tout);
      94        CLNT_DESTROY (client);
      95      }
      96    else
      97      {
      98        stat = RPC_FAILED;
      99      }
     100    /* (void)__close(socket); CLNT_DESTROY already closed it */
     101    addr->sin_port = 0;
     102    return stat;
     103  }
     104  libc_hidden_nolink_sunrpc (pmap_rmtcall, GLIBC_2_0)
     105  
     106  
     107  /*
     108   * XDR remote call arguments
     109   * written for XDR_ENCODE direction only
     110   */
     111  bool_t
     112  xdr_rmtcall_args (XDR *xdrs, struct rmtcallargs *cap)
     113  {
     114    u_int lenposition, argposition, position;
     115  
     116    if (xdr_u_long (xdrs, &(cap->prog)) &&
     117        xdr_u_long (xdrs, &(cap->vers)) &&
     118        xdr_u_long (xdrs, &(cap->proc)))
     119      {
     120        u_long dummy_arglen = 0;
     121        lenposition = XDR_GETPOS (xdrs);
     122        if (!xdr_u_long (xdrs, &dummy_arglen))
     123  	return FALSE;
     124        argposition = XDR_GETPOS (xdrs);
     125        if (!(*(cap->xdr_args)) (xdrs, cap->args_ptr))
     126  	return FALSE;
     127        position = XDR_GETPOS (xdrs);
     128        cap->arglen = (u_long) position - (u_long) argposition;
     129        XDR_SETPOS (xdrs, lenposition);
     130        if (!xdr_u_long (xdrs, &(cap->arglen)))
     131  	return FALSE;
     132        XDR_SETPOS (xdrs, position);
     133        return TRUE;
     134      }
     135    return FALSE;
     136  }
     137  libc_hidden_nolink_sunrpc (xdr_rmtcall_args, GLIBC_2_0)
     138  
     139  /*
     140   * XDR remote call results
     141   * written for XDR_DECODE direction only
     142   */
     143  bool_t
     144  xdr_rmtcallres (XDR *xdrs, struct rmtcallres *crp)
     145  {
     146    caddr_t port_ptr;
     147  
     148    port_ptr = (caddr_t) crp->port_ptr;
     149    if (xdr_reference (xdrs, &port_ptr, sizeof (u_long),
     150  		     (xdrproc_t) xdr_u_long)
     151        && xdr_u_long (xdrs, &crp->resultslen))
     152      {
     153        crp->port_ptr = (u_long *) port_ptr;
     154        return (*(crp->xdr_results)) (xdrs, crp->results_ptr);
     155      }
     156    return FALSE;
     157  }
     158  libc_hidden_nolink_sunrpc (xdr_rmtcallres, GLIBC_2_0)
     159  
     160  
     161  /*
     162   * The following is kludged-up support for simple rpc broadcasts.
     163   * Someday a large, complicated system will replace these trivial
     164   * routines which only support udp/ip .
     165   */
     166  
     167  static int
     168  getbroadcastnets (struct in_addr *addrs, int naddrs)
     169  {
     170    struct ifaddrs *ifa;
     171  
     172    if (getifaddrs (&ifa) != 0)
     173      {
     174        perror ("broadcast: getifaddrs");
     175        return 0;
     176      }
     177  
     178    int i = 0;
     179    struct ifaddrs *run = ifa;
     180    while (run != NULL && i < naddrs)
     181      {
     182        if ((run->ifa_flags & IFF_BROADCAST) != 0
     183  	  && (run->ifa_flags & IFF_UP) != 0
     184  	  && run->ifa_addr != NULL
     185  	  && run->ifa_addr->sa_family == AF_INET)
     186  	/* Copy the broadcast address.  */
     187  	addrs[i++] = ((struct sockaddr_in *) run->ifa_broadaddr)->sin_addr;
     188  
     189        run = run->ifa_next;
     190      }
     191  
     192    freeifaddrs (ifa);
     193  
     194    return i;
     195  }
     196  
     197  
     198  enum clnt_stat
     199  clnt_broadcast (/* program number */
     200  		u_long prog,
     201  		/* version number */
     202  		u_long vers,
     203  		/* procedure number */
     204  		u_long proc,
     205  		/* xdr routine for args */
     206  		xdrproc_t xargs,
     207  		/* pointer to args */
     208  		caddr_t argsp,
     209  		/* xdr routine for results */
     210  		xdrproc_t xresults,
     211  		/* pointer to results */
     212  		caddr_t resultsp,
     213  		/* call with each result obtained */
     214  		resultproc_t eachresult)
     215  {
     216    enum clnt_stat stat = RPC_FAILED;
     217    AUTH *unix_auth = authunix_create_default ();
     218    XDR xdr_stream;
     219    XDR *xdrs = &xdr_stream;
     220    struct timeval t;
     221    int outlen, inlen, nets;
     222    socklen_t fromlen;
     223    int sock;
     224    int on = 1;
     225    struct pollfd fd;
     226    int milliseconds;
     227    int i;
     228    bool_t done = FALSE;
     229    u_long xid;
     230    u_long port;
     231    struct in_addr addrs[20];
     232    struct sockaddr_in baddr, raddr;	/* broadcast and response addresses */
     233    struct rmtcallargs a;
     234    struct rmtcallres r;
     235    struct rpc_msg msg;
     236    char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
     237  
     238    /*
     239     * initialization: create a socket, a broadcast address, and
     240     * preserialize the arguments into a send buffer.
     241     */
     242    if ((sock = __socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
     243      {
     244        perror (_("Cannot create socket for broadcast rpc"));
     245        stat = RPC_CANTSEND;
     246        goto done_broad;
     247      }
     248  #ifdef SO_BROADCAST
     249    if (__setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0)
     250      {
     251        perror (_("Cannot set socket option SO_BROADCAST"));
     252        stat = RPC_CANTSEND;
     253        goto done_broad;
     254      }
     255  #endif /* def SO_BROADCAST */
     256    fd.fd = sock;
     257    fd.events = POLLIN;
     258    nets = getbroadcastnets (addrs, sizeof (addrs) / sizeof (addrs[0]));
     259    memset ((char *) &baddr, 0, sizeof (baddr));
     260    baddr.sin_family = AF_INET;
     261    baddr.sin_port = htons (PMAPPORT);
     262    baddr.sin_addr.s_addr = htonl (INADDR_ANY);
     263  /*      baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
     264    msg.rm_xid = xid = _create_xid ();
     265    t.tv_usec = 0;
     266    msg.rm_direction = CALL;
     267    msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
     268    msg.rm_call.cb_prog = PMAPPROG;
     269    msg.rm_call.cb_vers = PMAPVERS;
     270    msg.rm_call.cb_proc = PMAPPROC_CALLIT;
     271    msg.rm_call.cb_cred = unix_auth->ah_cred;
     272    msg.rm_call.cb_verf = unix_auth->ah_verf;
     273    a.prog = prog;
     274    a.vers = vers;
     275    a.proc = proc;
     276    a.xdr_args = xargs;
     277    a.args_ptr = argsp;
     278    r.port_ptr = &port;
     279    r.xdr_results = xresults;
     280    r.results_ptr = resultsp;
     281    xdrmem_create (xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
     282    if ((!xdr_callmsg (xdrs, &msg))
     283        || (!xdr_rmtcall_args (xdrs, &a)))
     284      {
     285        stat = RPC_CANTENCODEARGS;
     286        goto done_broad;
     287      }
     288    outlen = (int) xdr_getpos (xdrs);
     289    xdr_destroy (xdrs);
     290    /*
     291     * Basic loop: broadcast a packet and wait a while for response(s).
     292     * The response timeout grows larger per iteration.
     293     */
     294    for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2)
     295      {
     296        for (i = 0; i < nets; i++)
     297  	{
     298  	  baddr.sin_addr = addrs[i];
     299  	  if (__sendto (sock, outbuf, outlen, 0,
     300  			(struct sockaddr *) &baddr,
     301  			sizeof (struct sockaddr)) != outlen)
     302  	    {
     303  	      perror (_("Cannot send broadcast packet"));
     304  	      stat = RPC_CANTSEND;
     305  	      goto done_broad;
     306  	    }
     307  	}
     308        if (eachresult == NULL)
     309  	{
     310  	  stat = RPC_SUCCESS;
     311  	  goto done_broad;
     312  	}
     313      recv_again:
     314        msg.acpted_rply.ar_verf = _null_auth;
     315        msg.acpted_rply.ar_results.where = (caddr_t) & r;
     316        msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_rmtcallres;
     317        milliseconds = t.tv_sec * 1000 + t.tv_usec / 1000;
     318        switch (__poll(&fd, 1, milliseconds))
     319  	{
     320  
     321  	case 0:		/* timed out */
     322  	  stat = RPC_TIMEDOUT;
     323  	  continue;
     324  
     325  	case -1:		/* some kind of error */
     326  	  if (errno == EINTR)
     327  	    goto recv_again;
     328  	  perror (_("Broadcast poll problem"));
     329  	  stat = RPC_CANTRECV;
     330  	  goto done_broad;
     331  
     332  	}			/* end of poll results switch */
     333      try_again:
     334        fromlen = sizeof (struct sockaddr);
     335        inlen = __recvfrom (sock, inbuf, UDPMSGSIZE, 0,
     336  			  (struct sockaddr *) &raddr, &fromlen);
     337        if (inlen < 0)
     338  	{
     339  	  if (errno == EINTR)
     340  	    goto try_again;
     341  	  perror (_("Cannot receive reply to broadcast"));
     342  	  stat = RPC_CANTRECV;
     343  	  goto done_broad;
     344  	}
     345        if ((size_t) inlen < sizeof (u_long))
     346  	goto recv_again;
     347        /*
     348         * see if reply transaction id matches sent id.
     349         * If so, decode the results.
     350         */
     351        xdrmem_create (xdrs, inbuf, (u_int) inlen, XDR_DECODE);
     352        if (xdr_replymsg (xdrs, &msg))
     353  	{
     354  	  if (((uint32_t) msg.rm_xid == (uint32_t) xid) &&
     355  	      (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
     356  	      (msg.acpted_rply.ar_stat == SUCCESS))
     357  	    {
     358  	      raddr.sin_port = htons ((u_short) port);
     359  	      done = (*eachresult) (resultsp, &raddr);
     360  	    }
     361  	  /* otherwise, we just ignore the errors ... */
     362  	}
     363        else
     364  	{
     365  #ifdef notdef
     366  	  /* some kind of deserialization problem ... */
     367  	  if ((uint32_t) msg.rm_xid == (uint32_t) xid)
     368  	    fprintf (stderr, "Broadcast deserialization problem");
     369  	  /* otherwise, just random garbage */
     370  #endif
     371  	}
     372        xdrs->x_op = XDR_FREE;
     373        msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
     374        (void) xdr_replymsg (xdrs, &msg);
     375        (void) (*xresults) (xdrs, resultsp);
     376        xdr_destroy (xdrs);
     377        if (done)
     378  	{
     379  	  stat = RPC_SUCCESS;
     380  	  goto done_broad;
     381  	}
     382        else
     383  	{
     384  	  goto recv_again;
     385  	}
     386      }
     387  done_broad:
     388    (void) __close (sock);
     389    AUTH_DESTROY (unix_auth);
     390    return stat;
     391  }
     392  libc_hidden_nolink_sunrpc (clnt_broadcast, GLIBC_2_0)