hjl / source-git / glibc

Forked from source-git/glibc 3 years ago
Clone

Blame sunrpc/svc_unix.c

Packit 6c4009
/*
Packit 6c4009
 * svc_unix.c, Server side for TCP/IP based RPC.
Packit 6c4009
 *
Packit 6c4009
 * Copyright (C) 2012-2018 Free Software Foundation, Inc.
Packit 6c4009
 * This file is part of the GNU C Library.
Packit 6c4009
 *
Packit 6c4009
 * The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
 * modify it under the terms of the GNU Lesser General Public
Packit 6c4009
 * License as published by the Free Software Foundation; either
Packit 6c4009
 * version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
 *
Packit 6c4009
 * The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
 * Lesser General Public License for more details.
Packit 6c4009
 *
Packit 6c4009
 * You should have received a copy of the GNU Lesser General Public
Packit 6c4009
 * License along with the GNU C Library; if not, see
Packit 6c4009
 * <http://www.gnu.org/licenses/>.
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
 * Actually implements two flavors of transporter -
Packit 6c4009
 * a unix rendezvouser (a listener and connection establisher)
Packit 6c4009
 * and a record/unix stream.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <rpc/rpc.h>
Packit 6c4009
#include <rpc/svc.h>
Packit 6c4009
#include <sys/socket.h>
Packit 6c4009
#include <sys/uio.h>
Packit 6c4009
#include <sys/poll.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <wchar.h>
Packit 6c4009
#include <shlib-compat.h>
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Ops vector for AF_UNIX based rpc service handle
Packit 6c4009
 */
Packit 6c4009
static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
Packit 6c4009
static enum xprt_stat svcunix_stat (SVCXPRT *);
Packit 6c4009
static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
Packit 6c4009
static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
Packit 6c4009
static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
Packit 6c4009
static void svcunix_destroy (SVCXPRT *);
Packit 6c4009
Packit 6c4009
static const struct xp_ops svcunix_op =
Packit 6c4009
{
Packit 6c4009
  svcunix_recv,
Packit 6c4009
  svcunix_stat,
Packit 6c4009
  svcunix_getargs,
Packit 6c4009
  svcunix_reply,
Packit 6c4009
  svcunix_freeargs,
Packit 6c4009
  svcunix_destroy
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Ops vector for AF_UNIX rendezvous handler
Packit 6c4009
 */
Packit 6c4009
static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
Packit 6c4009
static enum xprt_stat rendezvous_stat (SVCXPRT *);
Packit 6c4009
static void svcunix_rendezvous_abort (void) __attribute__ ((__noreturn__));
Packit 6c4009
Packit 6c4009
/* This function makes sure abort() relocation goes through PLT
Packit 6c4009
   and thus can be lazy bound.  */
Packit 6c4009
static void
Packit 6c4009
svcunix_rendezvous_abort (void)
Packit 6c4009
{
Packit 6c4009
  abort ();
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static const struct xp_ops svcunix_rendezvous_op =
Packit 6c4009
{
Packit 6c4009
  rendezvous_request,
Packit 6c4009
  rendezvous_stat,
Packit 6c4009
  (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
Packit 6c4009
  (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
Packit 6c4009
  (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
Packit 6c4009
  svcunix_destroy
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static int readunix (char*, char *, int);
Packit 6c4009
static int writeunix (char *, char *, int);
Packit 6c4009
static SVCXPRT *makefd_xprt (int, u_int, u_int);
Packit 6c4009
Packit 6c4009
struct unix_rendezvous {        /* kept in xprt->xp_p1 */
Packit 6c4009
  u_int sendsize;
Packit 6c4009
  u_int recvsize;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
struct unix_conn {		/* kept in xprt->xp_p1 */
Packit 6c4009
  enum xprt_stat strm_stat;
Packit 6c4009
  u_long x_id;
Packit 6c4009
  XDR xdrs;
Packit 6c4009
  char verf_body[MAX_AUTH_BYTES];
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Usage:
Packit 6c4009
 *      xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
Packit 6c4009
 *
Packit 6c4009
 * Creates, registers, and returns a (rpc) unix based transporter.
Packit 6c4009
 * Once *xprt is initialized, it is registered as a transporter
Packit 6c4009
 * see (svc.h, xprt_register).  This routine returns
Packit 6c4009
 * a NULL if a problem occurred.
Packit 6c4009
 *
Packit 6c4009
 * If sock<0 then a socket is created, else sock is used.
Packit 6c4009
 * If the socket, sock is not bound to a port then svcunix_create
Packit 6c4009
 * binds it to an arbitrary port.  The routine then starts a unix
Packit 6c4009
 * listener on the socket's associated port.  In any (successful) case,
Packit 6c4009
 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
Packit 6c4009
 * associated port number.
Packit 6c4009
 *
Packit 6c4009
 * Since unix streams do buffered io similar to stdio, the caller can specify
Packit 6c4009
 * how big the send and receive buffers are via the second and third parms;
Packit 6c4009
 * 0 => use the system default.
Packit 6c4009
 */
Packit 6c4009
SVCXPRT *
Packit 6c4009
svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
Packit 6c4009
{
Packit 6c4009
  bool_t madesock = FALSE;
Packit 6c4009
  SVCXPRT *xprt;
Packit 6c4009
  struct unix_rendezvous *r;
Packit 6c4009
  struct sockaddr_un addr;
Packit 6c4009
  socklen_t len = sizeof (struct sockaddr_in);
Packit 6c4009
Packit 6c4009
  if (sock == RPC_ANYSOCK)
Packit 6c4009
    {
Packit 6c4009
      if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
Packit 6c4009
	{
Packit 6c4009
	  perror (_("svc_unix.c - AF_UNIX socket creation problem"));
Packit 6c4009
	  return (SVCXPRT *) NULL;
Packit 6c4009
	}
Packit 6c4009
      madesock = TRUE;
Packit 6c4009
    }
Packit 6c4009
  memset (&addr, '\0', sizeof (addr));
Packit 6c4009
  addr.sun_family = AF_UNIX;
Packit 6c4009
  len = strlen (path) + 1;
Packit 6c4009
  memcpy (addr.sun_path, path, len);
Packit 6c4009
  len += sizeof (addr.sun_family);
Packit 6c4009
Packit 6c4009
  __bind (sock, (struct sockaddr *) &addr, len);
Packit 6c4009
Packit 6c4009
  if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0
Packit 6c4009
      || __listen (sock, SOMAXCONN) != 0)
Packit 6c4009
    {
Packit 6c4009
      perror (_("svc_unix.c - cannot getsockname or listen"));
Packit 6c4009
      if (madesock)
Packit 6c4009
	__close (sock);
Packit 6c4009
      return (SVCXPRT *) NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
Packit 6c4009
  xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
Packit 6c4009
  if (r == NULL || xprt == NULL)
Packit 6c4009
    {
Packit 6c4009
      __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
Packit 6c4009
      mem_free (r, sizeof (*r));
Packit 6c4009
      mem_free (xprt, sizeof (SVCXPRT));
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
  r->sendsize = sendsize;
Packit 6c4009
  r->recvsize = recvsize;
Packit 6c4009
  xprt->xp_p2 = NULL;
Packit 6c4009
  xprt->xp_p1 = (caddr_t) r;
Packit 6c4009
  xprt->xp_verf = _null_auth;
Packit 6c4009
  xprt->xp_ops = &svcunix_rendezvous_op;
Packit 6c4009
  xprt->xp_port = -1;
Packit 6c4009
  xprt->xp_sock = sock;
Packit 6c4009
  xprt_register (xprt);
Packit 6c4009
  return xprt;
Packit 6c4009
}
Packit 6c4009
libc_hidden_nolink_sunrpc (svcunix_create, GLIBC_2_1)
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Like svunix_create(), except the routine takes any *open* UNIX file
Packit 6c4009
 * descriptor as its first input.
Packit 6c4009
 */
Packit 6c4009
SVCXPRT *
Packit 6c4009
svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
Packit 6c4009
{
Packit 6c4009
  return makefd_xprt (fd, sendsize, recvsize);
Packit 6c4009
}
Packit 6c4009
libc_hidden_nolink_sunrpc (svcunixfd_create, GLIBC_2_1)
Packit 6c4009
Packit 6c4009
static SVCXPRT *
Packit 6c4009
makefd_xprt (int fd, u_int sendsize, u_int recvsize)
Packit 6c4009
{
Packit 6c4009
  SVCXPRT *xprt;
Packit 6c4009
  struct unix_conn *cd;
Packit 6c4009
Packit 6c4009
  xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
Packit 6c4009
  cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
Packit 6c4009
  if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
Packit 6c4009
    {
Packit 6c4009
      (void) __fxprintf (NULL, "%s: %s", "svc_unix: makefd_xprt",
Packit 6c4009
			 _("out of memory\n"));
Packit 6c4009
      mem_free (xprt, sizeof (SVCXPRT));
Packit 6c4009
      mem_free (cd, sizeof (struct unix_conn));
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
  cd->strm_stat = XPRT_IDLE;
Packit 6c4009
  xdrrec_create (&(cd->xdrs), sendsize, recvsize,
Packit 6c4009
		 (caddr_t) xprt, readunix, writeunix);
Packit 6c4009
  xprt->xp_p2 = NULL;
Packit 6c4009
  xprt->xp_p1 = (caddr_t) cd;
Packit 6c4009
  xprt->xp_verf.oa_base = cd->verf_body;
Packit 6c4009
  xprt->xp_addrlen = 0;
Packit 6c4009
  xprt->xp_ops = &svcunix_op;	/* truly deals with calls */
Packit 6c4009
  xprt->xp_port = 0;		/* this is a connection, not a rendezvouser */
Packit 6c4009
  xprt->xp_sock = fd;
Packit 6c4009
  xprt_register (xprt);
Packit 6c4009
  return xprt;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static bool_t
Packit 6c4009
rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
Packit 6c4009
{
Packit 6c4009
  int sock;
Packit 6c4009
  struct unix_rendezvous *r;
Packit 6c4009
  struct sockaddr_un addr;
Packit 6c4009
  struct sockaddr_in in_addr;
Packit 6c4009
  socklen_t len;
Packit 6c4009
Packit 6c4009
  r = (struct unix_rendezvous *) xprt->xp_p1;
Packit 6c4009
again:
Packit 6c4009
  len = sizeof (struct sockaddr_un);
Packit 6c4009
  if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
Packit 6c4009
    {
Packit 6c4009
      if (errno == EINTR)
Packit 6c4009
	goto again;
Packit 6c4009
      __svc_accept_failed ();
Packit 6c4009
      return FALSE;
Packit 6c4009
    }
Packit 6c4009
  /*
Packit 6c4009
   * make a new transporter (re-uses xprt)
Packit 6c4009
   */
Packit 6c4009
  memset (&in_addr, '\0', sizeof (in_addr));
Packit 6c4009
  in_addr.sin_family = AF_UNIX;
Packit 6c4009
  xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
Packit 6c4009
  memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
Packit 6c4009
  xprt->xp_addrlen = len;
Packit 6c4009
  return FALSE;		/* there is never an rpc msg to be processed */
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static enum xprt_stat
Packit 6c4009
rendezvous_stat (SVCXPRT *xprt)
Packit 6c4009
{
Packit 6c4009
  return XPRT_IDLE;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
svcunix_destroy (SVCXPRT *xprt)
Packit 6c4009
{
Packit 6c4009
  struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
Packit 6c4009
Packit 6c4009
  xprt_unregister (xprt);
Packit 6c4009
  __close (xprt->xp_sock);
Packit 6c4009
  if (xprt->xp_port != 0)
Packit 6c4009
    {
Packit 6c4009
      /* a rendezvouser socket */
Packit 6c4009
      xprt->xp_port = 0;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* an actual connection socket */
Packit 6c4009
      XDR_DESTROY (&(cd->xdrs));
Packit 6c4009
    }
Packit 6c4009
  mem_free ((caddr_t) cd, sizeof (struct unix_conn));
Packit 6c4009
  mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifdef SCM_CREDENTIALS
Packit 6c4009
struct cmessage {
Packit 6c4009
  struct cmsghdr cmsg;
Packit 6c4009
  struct ucred cmcred;
Packit 6c4009
  /* hack to make sure we have enough memory */
Packit 6c4009
  char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* XXX This is not thread safe, but since the main functions in svc.c
Packit 6c4009
   and the rpcgen generated *_svc functions for the daemon are also not
Packit 6c4009
   thread safe and uses static global variables, it doesn't matter. */
Packit 6c4009
static struct cmessage cm;
Packit 6c4009
#endif
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
  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 = sizeof (struct cmessage);
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 = &cm.cmsg;
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
 * reads data from the unix connection.
Packit 6c4009
 * any error is fatal and the connection is closed.
Packit 6c4009
 * (And a read of zero bytes is a half closed stream => error.)
Packit 6c4009
 */
Packit 6c4009
static int
Packit 6c4009
readunix (char *xprtptr, char *buf, int len)
Packit 6c4009
{
Packit 6c4009
  SVCXPRT *xprt = (SVCXPRT *) xprtptr;
Packit 6c4009
  int sock = xprt->xp_sock;
Packit 6c4009
  int milliseconds = 35 * 1000;
Packit 6c4009
  struct pollfd pollfd;
Packit 6c4009
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      pollfd.fd = sock;
Packit 6c4009
      pollfd.events = POLLIN;
Packit 6c4009
      switch (__poll (&pollfd, 1, milliseconds))
Packit 6c4009
	{
Packit 6c4009
	case -1:
Packit 6c4009
	  if (errno == EINTR)
Packit 6c4009
	    continue;
Packit 6c4009
	  /*FALLTHROUGH*/
Packit 6c4009
	case 0:
Packit 6c4009
	  goto fatal_err;
Packit 6c4009
	default:
Packit 6c4009
	  if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
Packit 6c4009
	      || (pollfd.revents & POLLNVAL))
Packit 6c4009
	    goto fatal_err;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  while ((pollfd.revents & POLLIN) == 0);
Packit 6c4009
Packit 6c4009
  if ((len = __msgread (sock, buf, len)) > 0)
Packit 6c4009
    return len;
Packit 6c4009
Packit 6c4009
 fatal_err:
Packit 6c4009
  ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
Packit 6c4009
  return -1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * writes data to the unix connection.
Packit 6c4009
 * Any error is fatal and the connection is closed.
Packit 6c4009
 */
Packit 6c4009
static int
Packit 6c4009
writeunix (char *xprtptr, char * buf, int len)
Packit 6c4009
{
Packit 6c4009
  SVCXPRT *xprt = (SVCXPRT *) xprtptr;
Packit 6c4009
  int i, cnt;
Packit 6c4009
Packit 6c4009
  for (cnt = len; cnt > 0; cnt -= i, buf += i)
Packit 6c4009
    {
Packit 6c4009
      if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
Packit 6c4009
	{
Packit 6c4009
	  ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
Packit 6c4009
	  return -1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  return len;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static enum xprt_stat
Packit 6c4009
svcunix_stat (SVCXPRT *xprt)
Packit 6c4009
{
Packit 6c4009
  struct unix_conn *cd =
Packit 6c4009
  (struct unix_conn *) (xprt->xp_p1);
Packit 6c4009
Packit 6c4009
  if (cd->strm_stat == XPRT_DIED)
Packit 6c4009
    return XPRT_DIED;
Packit 6c4009
  if (!xdrrec_eof (&(cd->xdrs)))
Packit 6c4009
    return XPRT_MOREREQS;
Packit 6c4009
  return XPRT_IDLE;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static bool_t
Packit 6c4009
svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
Packit 6c4009
{
Packit 6c4009
  struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
Packit 6c4009
  XDR *xdrs = &(cd->xdrs);
Packit 6c4009
Packit 6c4009
  xdrs->x_op = XDR_DECODE;
Packit 6c4009
  xdrrec_skiprecord (xdrs);
Packit 6c4009
  if (xdr_callmsg (xdrs, msg))
Packit 6c4009
    {
Packit 6c4009
      cd->x_id = msg->rm_xid;
Packit 6c4009
      /* set up verifiers */
Packit 6c4009
#ifdef SCM_CREDENTIALS
Packit 6c4009
      msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
Packit 6c4009
      msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
Packit 6c4009
      msg->rm_call.cb_verf.oa_length = sizeof (cm);
Packit 6c4009
#endif
Packit 6c4009
      return TRUE;
Packit 6c4009
    }
Packit 6c4009
  cd->strm_stat = XPRT_DIED;	/* XXXX */
Packit 6c4009
  return FALSE;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static bool_t
Packit 6c4009
svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
Packit 6c4009
{
Packit 6c4009
  return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
Packit 6c4009
		      args_ptr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static bool_t
Packit 6c4009
svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
Packit 6c4009
{
Packit 6c4009
  XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
Packit 6c4009
Packit 6c4009
  xdrs->x_op = XDR_FREE;
Packit 6c4009
  return (*xdr_args) (xdrs, args_ptr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static bool_t
Packit 6c4009
svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
Packit 6c4009
{
Packit 6c4009
  struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
Packit 6c4009
  XDR *xdrs = &(cd->xdrs);
Packit 6c4009
  bool_t stat;
Packit 6c4009
Packit 6c4009
  xdrs->x_op = XDR_ENCODE;
Packit 6c4009
  msg->rm_xid = cd->x_id;
Packit 6c4009
  stat = xdr_replymsg (xdrs, msg);
Packit 6c4009
  (void) xdrrec_endofrecord (xdrs, TRUE);
Packit 6c4009
  return stat;
Packit 6c4009
}