Blame sunrpc/clnt_unix.c

Packit 6c4009
/*
Packit 6c4009
 * clnt_unix.c, Implements a TCP/IP based, client side RPC.
Packit 6c4009
 *
Packit 6c4009
 * Copyright (c) 2010, Oracle America, Inc.
Packit 6c4009
 *
Packit 6c4009
 * Redistribution and use in source and binary forms, with or without
Packit 6c4009
 * modification, are permitted provided that the following conditions are
Packit 6c4009
 * met:
Packit 6c4009
 *
Packit 6c4009
 *     * Redistributions of source code must retain the above copyright
Packit 6c4009
 *       notice, this list of conditions and the following disclaimer.
Packit 6c4009
 *     * Redistributions in binary form must reproduce the above
Packit 6c4009
 *       copyright notice, this list of conditions and the following
Packit 6c4009
 *       disclaimer in the documentation and/or other materials
Packit 6c4009
 *       provided with the distribution.
Packit 6c4009
 *     * Neither the name of the "Oracle America, Inc." nor the names of its
Packit 6c4009
 *       contributors may be used to endorse or promote products derived
Packit 6c4009
 *       from this software without specific prior written permission.
Packit 6c4009
 *
Packit 6c4009
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 6c4009
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 6c4009
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
Packit 6c4009
 *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
Packit 6c4009
 *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
Packit 6c4009
 *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 6c4009
 *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
Packit 6c4009
 *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit 6c4009
 *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
Packit 6c4009
 *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
Packit 6c4009
 *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 6c4009
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 6c4009
 *
Packit 6c4009
 * TCP based RPC supports 'batched calls'.
Packit 6c4009
 * A sequence of calls may be batched-up in a send buffer.  The rpc call
Packit 6c4009
 * return immediately to the client even though the call was not necessarily
Packit 6c4009
 * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
Packit 6c4009
 * the rpc timeout value is zero (see clnt.h, rpc).
Packit 6c4009
 *
Packit 6c4009
 * Clients should NOT casually batch calls that in fact return results; that is,
Packit 6c4009
 * the server side should be aware that a call is batched and not produce any
Packit 6c4009
 * return message.  Batched calls that produce many result messages can
Packit 6c4009
 * deadlock (netlock) the client and the server....
Packit 6c4009
 *
Packit 6c4009
 * Now go hang yourself.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#include <netdb.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <rpc/rpc.h>
Packit 6c4009
#include <sys/uio.h>
Packit 6c4009
#include <sys/poll.h>
Packit 6c4009
#include <sys/socket.h>
Packit 6c4009
#include <rpc/pmap_clnt.h>
Packit 6c4009
#include <wchar.h>
Packit 6c4009
#include <shlib-compat.h>
Packit 6c4009
Packit 6c4009
extern u_long _create_xid (void);
Packit 6c4009
Packit 6c4009
#define MCALL_MSG_SIZE 24
Packit 6c4009
Packit 6c4009
struct ct_data
Packit 6c4009
  {
Packit 6c4009
    int ct_sock;
Packit 6c4009
    bool_t ct_closeit;
Packit 6c4009
    struct timeval ct_wait;
Packit 6c4009
    bool_t ct_waitset;		/* wait set by clnt_control? */
Packit 6c4009
    struct sockaddr_un ct_addr;
Packit 6c4009
    struct rpc_err ct_error;
Packit 6c4009
    char ct_mcall[MCALL_MSG_SIZE];	/* marshalled callmsg */
Packit 6c4009
    u_int ct_mpos;		/* pos after marshal */
Packit 6c4009
    XDR ct_xdrs;
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
static int readunix (char *, char *, int);
Packit 6c4009
static int writeunix (char *, char *, int);
Packit 6c4009
Packit 6c4009
static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
Packit 6c4009
				    xdrproc_t, caddr_t, struct timeval);
Packit 6c4009
static void clntunix_abort (void);
Packit 6c4009
static void clntunix_geterr (CLIENT *, struct rpc_err *);
Packit 6c4009
static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
Packit 6c4009
static bool_t clntunix_control (CLIENT *, int, char *);
Packit 6c4009
static void clntunix_destroy (CLIENT *);
Packit 6c4009
Packit 6c4009
static const struct clnt_ops unix_ops =
Packit 6c4009
{
Packit 6c4009
  clntunix_call,
Packit 6c4009
  clntunix_abort,
Packit 6c4009
  clntunix_geterr,
Packit 6c4009
  clntunix_freeres,
Packit 6c4009
  clntunix_destroy,
Packit 6c4009
  clntunix_control
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Create a client handle for a tcp/ip connection.
Packit 6c4009
 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
Packit 6c4009
 * connected to raddr.  If *sockp non-negative then
Packit 6c4009
 * raddr is ignored.  The rpc/tcp package does buffering
Packit 6c4009
 * similar to stdio, so the client must pick send and receive buffer sizes,];
Packit 6c4009
 * 0 => use the default.
Packit 6c4009
 * If raddr->sin_port is 0, then a binder on the remote machine is
Packit 6c4009
 * consulted for the right port number.
Packit 6c4009
 * NB: *sockp is copied into a private area.
Packit 6c4009
 * NB: It is the clients responsibility to close *sockp.
Packit 6c4009
 * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
Packit 6c4009
 * something more useful.
Packit 6c4009
 */
Packit 6c4009
CLIENT *
Packit 6c4009
clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
Packit 6c4009
		 int *sockp, u_int sendsz, u_int recvsz)
Packit 6c4009
{
Packit 6c4009
  CLIENT *h;
Packit 6c4009
  struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
Packit 6c4009
  struct rpc_msg call_msg;
Packit 6c4009
  int len;
Packit 6c4009
Packit 6c4009
  h = (CLIENT *) mem_alloc (sizeof (*h));
Packit 6c4009
  if (h == NULL || ct == NULL)
Packit 6c4009
    {
Packit 6c4009
      struct rpc_createerr *ce = &get_rpc_createerr ();
Packit 6c4009
      (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
Packit 6c4009
      ce->cf_stat = RPC_SYSTEMERROR;
Packit 6c4009
      ce->cf_error.re_errno = ENOMEM;
Packit 6c4009
      goto fooy;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * If no socket given, open one
Packit 6c4009
   */
Packit 6c4009
  if (*sockp < 0)
Packit 6c4009
    {
Packit 6c4009
      *sockp = __socket (AF_UNIX, SOCK_STREAM, 0);
Packit 6c4009
      len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
Packit 6c4009
      if (*sockp < 0
Packit 6c4009
	  || __connect (*sockp, (struct sockaddr *) raddr, len) < 0)
Packit 6c4009
	{
Packit 6c4009
	  struct rpc_createerr *ce = &get_rpc_createerr ();
Packit 6c4009
	  ce->cf_stat = RPC_SYSTEMERROR;
Packit 6c4009
	  ce->cf_error.re_errno = errno;
Packit 6c4009
	  if (*sockp != -1)
Packit 6c4009
	    __close (*sockp);
Packit 6c4009
	  goto fooy;
Packit 6c4009
	}
Packit 6c4009
      ct->ct_closeit = TRUE;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      ct->ct_closeit = FALSE;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * Set up private data struct
Packit 6c4009
   */
Packit 6c4009
  ct->ct_sock = *sockp;
Packit 6c4009
  ct->ct_wait.tv_usec = 0;
Packit 6c4009
  ct->ct_waitset = FALSE;
Packit 6c4009
  ct->ct_addr = *raddr;
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * Initialize call message
Packit 6c4009
   */
Packit 6c4009
  call_msg.rm_xid = _create_xid ();
Packit 6c4009
  call_msg.rm_direction = CALL;
Packit 6c4009
  call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
Packit 6c4009
  call_msg.rm_call.cb_prog = prog;
Packit 6c4009
  call_msg.rm_call.cb_vers = vers;
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * pre-serialize the static part of the call msg and stash it away
Packit 6c4009
   */
Packit 6c4009
  xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
Packit 6c4009
  if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
Packit 6c4009
    {
Packit 6c4009
      if (ct->ct_closeit)
Packit 6c4009
	__close (*sockp);
Packit 6c4009
      goto fooy;
Packit 6c4009
    }
Packit 6c4009
  ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
Packit 6c4009
  XDR_DESTROY (&(ct->ct_xdrs));
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * Create a client handle which uses xdrrec for serialization
Packit 6c4009
   * and authnone for authentication.
Packit 6c4009
   */
Packit 6c4009
  xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
Packit 6c4009
		 (caddr_t) ct, readunix, writeunix);
Packit 6c4009
  h->cl_ops = (struct clnt_ops *) &unix_ops;
Packit 6c4009
  h->cl_private = (caddr_t) ct;
Packit 6c4009
  h->cl_auth = authnone_create ();
Packit 6c4009
  return h;
Packit 6c4009
Packit 6c4009
fooy:
Packit 6c4009
  /*
Packit 6c4009
   * Something goofed, free stuff and barf
Packit 6c4009
   */
Packit 6c4009
  mem_free ((caddr_t) ct, sizeof (struct ct_data));
Packit 6c4009
  mem_free ((caddr_t) h, sizeof (CLIENT));
Packit 6c4009
  return (CLIENT *) NULL;
Packit 6c4009
}
Packit 6c4009
libc_hidden_nolink_sunrpc (clntunix_create, GLIBC_2_1)
Packit 6c4009
Packit 6c4009
static enum clnt_stat
Packit 6c4009
clntunix_call (CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr,
Packit 6c4009
	       xdrproc_t xdr_results, caddr_t results_ptr,
Packit 6c4009
	       struct timeval timeout)
Packit 6c4009
{
Packit 6c4009
  struct ct_data *ct = (struct ct_data *) h->cl_private;
Packit 6c4009
  XDR *xdrs = &(ct->ct_xdrs);
Packit 6c4009
  struct rpc_msg reply_msg;
Packit 6c4009
  u_long x_id;
Packit 6c4009
  uint32_t *msg_x_id = (uint32_t *) (ct->ct_mcall);	/* yuk */
Packit 6c4009
  bool_t shipnow;
Packit 6c4009
  int refreshes = 2;
Packit 6c4009
Packit 6c4009
  if (!ct->ct_waitset)
Packit 6c4009
    {
Packit 6c4009
      ct->ct_wait = timeout;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  shipnow =
Packit 6c4009
    (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
Packit 6c4009
     && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
Packit 6c4009
Packit 6c4009
call_again:
Packit 6c4009
  xdrs->x_op = XDR_ENCODE;
Packit 6c4009
  ct->ct_error.re_status = RPC_SUCCESS;
Packit 6c4009
  x_id = ntohl (--(*msg_x_id));
Packit 6c4009
  if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
Packit 6c4009
      (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
Packit 6c4009
      (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
Packit 6c4009
      (!(*xdr_args) (xdrs, args_ptr)))
Packit 6c4009
    {
Packit 6c4009
      if (ct->ct_error.re_status == RPC_SUCCESS)
Packit 6c4009
	ct->ct_error.re_status = RPC_CANTENCODEARGS;
Packit 6c4009
      (void) xdrrec_endofrecord (xdrs, TRUE);
Packit 6c4009
      return ct->ct_error.re_status;
Packit 6c4009
    }
Packit 6c4009
  if (!xdrrec_endofrecord (xdrs, shipnow))
Packit 6c4009
    return ct->ct_error.re_status = RPC_CANTSEND;
Packit 6c4009
  if (!shipnow)
Packit 6c4009
    return RPC_SUCCESS;
Packit 6c4009
  /*
Packit 6c4009
   * Hack to provide rpc-based message passing
Packit 6c4009
   */
Packit 6c4009
  if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
Packit 6c4009
    return ct->ct_error.re_status = RPC_TIMEDOUT;
Packit 6c4009
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * Keep receiving until we get a valid transaction id
Packit 6c4009
   */
Packit 6c4009
  xdrs->x_op = XDR_DECODE;
Packit 6c4009
  while (TRUE)
Packit 6c4009
    {
Packit 6c4009
      reply_msg.acpted_rply.ar_verf = _null_auth;
Packit 6c4009
      reply_msg.acpted_rply.ar_results.where = NULL;
Packit 6c4009
      reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
Packit 6c4009
      if (!xdrrec_skiprecord (xdrs))
Packit 6c4009
	return ct->ct_error.re_status;
Packit 6c4009
      /* now decode and validate the response header */
Packit 6c4009
      if (!xdr_replymsg (xdrs, &reply_msg))
Packit 6c4009
	{
Packit 6c4009
	  if (ct->ct_error.re_status == RPC_SUCCESS)
Packit 6c4009
	    continue;
Packit 6c4009
	  return ct->ct_error.re_status;
Packit 6c4009
	}
Packit 6c4009
      if (reply_msg.rm_xid == x_id)
Packit 6c4009
	break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * process header
Packit 6c4009
   */
Packit 6c4009
  _seterr_reply (&reply_msg, &(ct->ct_error));
Packit 6c4009
  if (ct->ct_error.re_status == RPC_SUCCESS)
Packit 6c4009
    {
Packit 6c4009
      if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
Packit 6c4009
	{
Packit 6c4009
	  ct->ct_error.re_status = RPC_AUTHERROR;
Packit 6c4009
	  ct->ct_error.re_why = AUTH_INVALIDRESP;
Packit 6c4009
	}
Packit 6c4009
      else if (!(*xdr_results) (xdrs, results_ptr))
Packit 6c4009
	{
Packit 6c4009
	  if (ct->ct_error.re_status == RPC_SUCCESS)
Packit 6c4009
	    ct->ct_error.re_status = RPC_CANTDECODERES;
Packit 6c4009
	}
Packit 6c4009
      /* free verifier ... */
Packit 6c4009
      if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
Packit 6c4009
	{
Packit 6c4009
	  xdrs->x_op = XDR_FREE;
Packit 6c4009
	  (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
Packit 6c4009
	}
Packit 6c4009
    }				/* end successful completion */
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* maybe our credentials need to be refreshed ... */
Packit 6c4009
      if (refreshes-- && AUTH_REFRESH (h->cl_auth))
Packit 6c4009
	goto call_again;
Packit 6c4009
    }				/* end of unsuccessful completion */
Packit 6c4009
  return ct->ct_error.re_status;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
clntunix_geterr (CLIENT *h, struct rpc_err *errp)
Packit 6c4009
{
Packit 6c4009
  struct ct_data *ct = (struct ct_data *) h->cl_private;
Packit 6c4009
Packit 6c4009
  *errp = ct->ct_error;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static bool_t
Packit 6c4009
clntunix_freeres (CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
Packit 6c4009
{
Packit 6c4009
  struct ct_data *ct = (struct ct_data *) cl->cl_private;
Packit 6c4009
  XDR *xdrs = &(ct->ct_xdrs);
Packit 6c4009
Packit 6c4009
  xdrs->x_op = XDR_FREE;
Packit 6c4009
  return (*xdr_res) (xdrs, res_ptr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
clntunix_abort (void)
Packit 6c4009
{
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static bool_t
Packit 6c4009
clntunix_control (CLIENT *cl, int request, char *info)
Packit 6c4009
{
Packit 6c4009
  struct ct_data *ct = (struct ct_data *) cl->cl_private;
Packit 6c4009
  u_long ul;
Packit 6c4009
  uint32_t ui32;
Packit 6c4009
Packit 6c4009
  switch (request)
Packit 6c4009
    {
Packit 6c4009
    case CLSET_FD_CLOSE:
Packit 6c4009
      ct->ct_closeit = TRUE;
Packit 6c4009
      break;
Packit 6c4009
    case CLSET_FD_NCLOSE:
Packit 6c4009
      ct->ct_closeit = FALSE;
Packit 6c4009
      break;
Packit 6c4009
    case CLSET_TIMEOUT:
Packit 6c4009
      ct->ct_wait = *(struct timeval *) info;
Packit 6c4009
      break;
Packit 6c4009
    case CLGET_TIMEOUT:
Packit 6c4009
      *(struct timeval *) info = ct->ct_wait;
Packit 6c4009
      break;
Packit 6c4009
    case CLGET_SERVER_ADDR:
Packit 6c4009
      *(struct sockaddr_un *) info = ct->ct_addr;
Packit 6c4009
      break;
Packit 6c4009
    case CLGET_FD:
Packit 6c4009
      *(int *)info = ct->ct_sock;
Packit 6c4009
      break;
Packit 6c4009
    case CLGET_XID:
Packit 6c4009
      /*
Packit 6c4009
       * use the knowledge that xid is the
Packit 6c4009
       * first element in the call structure *.
Packit 6c4009
       * This will get the xid of the PREVIOUS call
Packit 6c4009
       */
Packit 6c4009
      memcpy (&ui32, ct->ct_mcall, sizeof (ui32));
Packit 6c4009
      ul = ntohl (ui32);
Packit 6c4009
      memcpy (info, &ul, sizeof (ul));
Packit 6c4009
      break;
Packit 6c4009
    case CLSET_XID:
Packit 6c4009
      /* This will set the xid of the NEXT call */
Packit 6c4009
      memcpy (&ul, info, sizeof (ul));
Packit 6c4009
      ui32 = htonl (ul - 1);
Packit 6c4009
      memcpy (ct->ct_mcall, &ui32, sizeof (ui32));
Packit 6c4009
      /* decrement by 1 as clntunix_call() increments once */
Packit 6c4009
      break;
Packit 6c4009
    case CLGET_VERS:
Packit 6c4009
      /*
Packit 6c4009
       * This RELIES on the information that, in the call body,
Packit 6c4009
       * the version number field is the fifth field from the
Packit 6c4009
       * beginning of the RPC header. MUST be changed if the
Packit 6c4009
       * call_struct is changed
Packit 6c4009
       */
Packit 6c4009
      memcpy (&ui32, ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT, sizeof (ui32));
Packit 6c4009
      ul = ntohl (ui32);
Packit 6c4009
      memcpy (info, &ul, sizeof (ul));
Packit 6c4009
      break;
Packit 6c4009
    case CLSET_VERS:
Packit 6c4009
      memcpy (&ul, info, sizeof (ul));
Packit 6c4009
      ui32 = htonl (ul);
Packit 6c4009
      memcpy (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT, &ui32, sizeof (ui32));
Packit 6c4009
      break;
Packit 6c4009
    case CLGET_PROG:
Packit 6c4009
      /*
Packit 6c4009
       * This RELIES on the information that, in the call body,
Packit 6c4009
       * the program number field is the  field from the
Packit 6c4009
       * beginning of the RPC header. MUST be changed if the
Packit 6c4009
       * call_struct is changed
Packit 6c4009
       */
Packit 6c4009
      memcpy (&ui32, ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT, sizeof (ui32));
Packit 6c4009
      ul = ntohl (ui32);
Packit 6c4009
      memcpy (info, &ul, sizeof (ul));
Packit 6c4009
      break;
Packit 6c4009
    case CLSET_PROG:
Packit 6c4009
      memcpy (&ul, info, sizeof (ul));
Packit 6c4009
      ui32 = htonl (ul);
Packit 6c4009
      memcpy (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT, &ui32, sizeof (ui32));
Packit 6c4009
      break;
Packit 6c4009
    /* The following are only possible with TI-RPC */
Packit 6c4009
    case CLGET_RETRY_TIMEOUT:
Packit 6c4009
    case CLSET_RETRY_TIMEOUT:
Packit 6c4009
    case CLGET_SVC_ADDR:
Packit 6c4009
    case CLSET_SVC_ADDR:
Packit 6c4009
    case CLSET_PUSH_TIMOD:
Packit 6c4009
    case CLSET_POP_TIMOD:
Packit 6c4009
    default:
Packit 6c4009
      return FALSE;
Packit 6c4009
    }
Packit 6c4009
  return TRUE;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
clntunix_destroy (CLIENT *h)
Packit 6c4009
{
Packit 6c4009
  struct ct_data *ct =
Packit 6c4009
  (struct ct_data *) h->cl_private;
Packit 6c4009
Packit 6c4009
  if (ct->ct_closeit)
Packit 6c4009
    {
Packit 6c4009
      (void) __close (ct->ct_sock);
Packit 6c4009
    }
Packit 6c4009
  XDR_DESTROY (&(ct->ct_xdrs));
Packit 6c4009
  mem_free ((caddr_t) ct, sizeof (struct ct_data));
Packit 6c4009
  mem_free ((caddr_t) h, sizeof (CLIENT));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
__msgread (int sock, void *data, size_t cnt)
Packit 6c4009
{
Packit 6c4009
  struct iovec iov;
Packit 6c4009
  struct msghdr msg;
Packit 6c4009
#ifdef SCM_CREDENTIALS
Packit 6c4009
  static char cm[CMSG_SPACE(sizeof (struct ucred))];
Packit 6c4009
#endif
Packit 6c4009
  int len;
Packit 6c4009
Packit 6c4009
  iov.iov_base = data;
Packit 6c4009
  iov.iov_len = cnt;
Packit 6c4009
Packit 6c4009
  msg.msg_iov = &iov;
Packit 6c4009
  msg.msg_iovlen = 1;
Packit 6c4009
  msg.msg_name = NULL;
Packit 6c4009
  msg.msg_namelen = 0;
Packit 6c4009
#ifdef SCM_CREDENTIALS
Packit 6c4009
  msg.msg_control = (caddr_t) &cm;
Packit 6c4009
  msg.msg_controllen = CMSG_SPACE(sizeof (struct ucred));
Packit 6c4009
#endif
Packit 6c4009
  msg.msg_flags = 0;
Packit 6c4009
Packit 6c4009
#ifdef SO_PASSCRED
Packit 6c4009
  {
Packit 6c4009
    int on = 1;
Packit 6c4009
    if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
Packit 6c4009
      return -1;
Packit 6c4009
  }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
 restart:
Packit 6c4009
  len = __recvmsg (sock, &msg, 0);
Packit 6c4009
  if (len >= 0)
Packit 6c4009
    {
Packit 6c4009
      if (msg.msg_flags & MSG_CTRUNC || len == 0)
Packit 6c4009
	return 0;
Packit 6c4009
      else
Packit 6c4009
	return len;
Packit 6c4009
    }
Packit 6c4009
  if (errno == EINTR)
Packit 6c4009
    goto restart;
Packit 6c4009
  return -1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
__msgwrite (int sock, void *data, size_t cnt)
Packit 6c4009
{
Packit 6c4009
#ifndef SCM_CREDENTIALS
Packit 6c4009
  /* We cannot implement this reliably.  */
Packit 6c4009
  __set_errno (ENOSYS);
Packit 6c4009
  return -1;
Packit 6c4009
#else
Packit 6c4009
  struct iovec iov;
Packit 6c4009
  struct msghdr msg;
Packit 6c4009
  struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred)));
Packit 6c4009
  struct ucred cred;
Packit 6c4009
  int len;
Packit 6c4009
Packit 6c4009
  /* XXX I'm not sure, if gete?id() is always correct, or if we should use
Packit 6c4009
     get?id(). But since keyserv needs geteuid(), we have no other chance.
Packit 6c4009
     It would be much better, if the kernel could pass both to the server. */
Packit 6c4009
  cred.pid = __getpid ();
Packit 6c4009
  cred.uid = __geteuid ();
Packit 6c4009
  cred.gid = __getegid ();
Packit 6c4009
Packit 6c4009
  memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
Packit 6c4009
  cmsg->cmsg_level = SOL_SOCKET;
Packit 6c4009
  cmsg->cmsg_type = SCM_CREDENTIALS;
Packit 6c4009
  cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
Packit 6c4009
Packit 6c4009
  iov.iov_base = data;
Packit 6c4009
  iov.iov_len = cnt;
Packit 6c4009
Packit 6c4009
  msg.msg_iov = &iov;
Packit 6c4009
  msg.msg_iovlen = 1;
Packit 6c4009
  msg.msg_name = NULL;
Packit 6c4009
  msg.msg_namelen = 0;
Packit 6c4009
  msg.msg_control = cmsg;
Packit 6c4009
  msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
Packit 6c4009
  msg.msg_flags = 0;
Packit 6c4009
Packit 6c4009
 restart:
Packit 6c4009
  len = __sendmsg (sock, &msg, 0);
Packit 6c4009
  if (len >= 0)
Packit 6c4009
    return len;
Packit 6c4009
  if (errno == EINTR)
Packit 6c4009
    goto restart;
Packit 6c4009
  return -1;
Packit 6c4009
Packit 6c4009
#endif
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Interface between xdr serializer and unix connection.
Packit 6c4009
 * Behaves like the system calls, read & write, but keeps some error state
Packit 6c4009
 * around for the rpc level.
Packit 6c4009
 */
Packit 6c4009
static int
Packit 6c4009
readunix (char *ctptr, char *buf, int len)
Packit 6c4009
{
Packit 6c4009
  struct ct_data *ct = (struct ct_data *) ctptr;
Packit 6c4009
  struct pollfd fd;
Packit 6c4009
  int milliseconds = ((ct->ct_wait.tv_sec * 1000)
Packit 6c4009
		      + (ct->ct_wait.tv_usec / 1000));
Packit 6c4009
Packit 6c4009
  if (len == 0)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  fd.fd = ct->ct_sock;
Packit 6c4009
  fd.events = POLLIN;
Packit 6c4009
  while (TRUE)
Packit 6c4009
    {
Packit 6c4009
      switch (__poll (&fd, 1, milliseconds))
Packit 6c4009
	{
Packit 6c4009
	case 0:
Packit 6c4009
	  ct->ct_error.re_status = RPC_TIMEDOUT;
Packit 6c4009
	  return -1;
Packit 6c4009
Packit 6c4009
	case -1:
Packit 6c4009
	  if (errno == EINTR)
Packit 6c4009
	    continue;
Packit 6c4009
	  ct->ct_error.re_status = RPC_CANTRECV;
Packit 6c4009
	  ct->ct_error.re_errno = errno;
Packit 6c4009
	  return -1;
Packit 6c4009
	}
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
  switch (len = __msgread (ct->ct_sock, buf, len))
Packit 6c4009
    {
Packit 6c4009
Packit 6c4009
    case 0:
Packit 6c4009
      /* premature eof */
Packit 6c4009
      ct->ct_error.re_errno = ECONNRESET;
Packit 6c4009
      ct->ct_error.re_status = RPC_CANTRECV;
Packit 6c4009
      len = -1;			/* it's really an error */
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case -1:
Packit 6c4009
      ct->ct_error.re_errno = errno;
Packit 6c4009
      ct->ct_error.re_status = RPC_CANTRECV;
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
  return len;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
writeunix (char *ctptr, char *buf, int len)
Packit 6c4009
{
Packit 6c4009
  int i, cnt;
Packit 6c4009
  struct ct_data *ct = (struct ct_data *) ctptr;
Packit 6c4009
Packit 6c4009
  for (cnt = len; cnt > 0; cnt -= i, buf += i)
Packit 6c4009
    {
Packit 6c4009
      if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
Packit 6c4009
	{
Packit 6c4009
	  ct->ct_error.re_errno = errno;
Packit 6c4009
	  ct->ct_error.re_status = RPC_CANTSEND;
Packit 6c4009
	  return -1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  return len;
Packit 6c4009
}