Blame lib/passfd.c

Packit Service a2489d
/* Copyright (C) 2011-2018 Free Software Foundation, Inc.
Packit Service a2489d
Packit Service a2489d
   This program is free software: you can redistribute it and/or modify
Packit Service a2489d
   it under the terms of the GNU General Public License as published by
Packit Service a2489d
   the Free Software Foundation; either version 3 of the License, or
Packit Service a2489d
   (at your option) any later version.
Packit Service a2489d
Packit Service a2489d
   This program is distributed in the hope that it will be useful,
Packit Service a2489d
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2489d
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2489d
   GNU General Public License for more details.
Packit Service a2489d
Packit Service a2489d
   You should have received a copy of the GNU General Public License
Packit Service a2489d
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service a2489d
Packit Service a2489d
#include <config.h>
Packit Service a2489d
Packit Service a2489d
/* Specification.  */
Packit Service a2489d
#include "passfd.h"
Packit Service a2489d
Packit Service a2489d
#include <errno.h>
Packit Service a2489d
#include <fcntl.h>
Packit Service a2489d
#include <stddef.h>
Packit Service a2489d
#include <stdlib.h>
Packit Service a2489d
#include <string.h>
Packit Service a2489d
#include <sys/types.h>
Packit Service a2489d
#include <unistd.h>
Packit Service a2489d
Packit Service a2489d
#include <sys/socket.h>
Packit Service a2489d
Packit Service a2489d
#include "cloexec.h"
Packit Service a2489d
Packit Service a2489d
/* The code that uses CMSG_FIRSTHDR is enabled on
Packit Service a2489d
   Linux, Mac OS X, FreeBSD, OpenBSD, NetBSD, AIX, OSF/1, Cygwin.
Packit Service a2489d
   The code that uses HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS is enabled on
Packit Service a2489d
   HP-UX, IRIX, Solaris.  */
Packit Service a2489d
Packit Service a2489d
/* MSG_CMSG_CLOEXEC is defined only on Linux, as of 2011.  */
Packit Service a2489d
#ifndef MSG_CMSG_CLOEXEC
Packit Service a2489d
# define MSG_CMSG_CLOEXEC 0
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
#if HAVE_SENDMSG
Packit Service a2489d
/* sendfd sends the file descriptor fd along the socket
Packit Service a2489d
   to a process calling recvfd on the other end.
Packit Service a2489d
Packit Service a2489d
   Return 0 on success, or -1 with errno set in case of error.
Packit Service a2489d
*/
Packit Service a2489d
int
Packit Service a2489d
sendfd (int sock, int fd)
Packit Service a2489d
{
Packit Service a2489d
  char byte = 0;
Packit Service a2489d
  struct iovec iov;
Packit Service a2489d
  struct msghdr msg;
Packit Service a2489d
# ifdef CMSG_FIRSTHDR
Packit Service a2489d
  struct cmsghdr *cmsg;
Packit Service a2489d
  char buf[CMSG_SPACE (sizeof fd)];
Packit Service a2489d
# endif
Packit Service a2489d
Packit Service a2489d
  /* send at least one char */
Packit Service a2489d
  memset (&msg, 0, sizeof msg);
Packit Service a2489d
  iov.iov_base = &byte;
Packit Service a2489d
  iov.iov_len = 1;
Packit Service a2489d
  msg.msg_iov = &iov;
Packit Service a2489d
  msg.msg_iovlen = 1;
Packit Service a2489d
  msg.msg_name = NULL;
Packit Service a2489d
  msg.msg_namelen = 0;
Packit Service a2489d
Packit Service a2489d
# ifdef CMSG_FIRSTHDR
Packit Service a2489d
  msg.msg_control = buf;
Packit Service a2489d
  msg.msg_controllen = sizeof buf;
Packit Service a2489d
  cmsg = CMSG_FIRSTHDR (&msg;;
Packit Service a2489d
  cmsg->cmsg_level = SOL_SOCKET;
Packit Service a2489d
  cmsg->cmsg_type = SCM_RIGHTS;
Packit Service a2489d
  cmsg->cmsg_len = CMSG_LEN (sizeof fd);
Packit Service a2489d
  /* Initialize the payload: */
Packit Service a2489d
  memcpy (CMSG_DATA (cmsg), &fd, sizeof fd);
Packit Service a2489d
  msg.msg_controllen = cmsg->cmsg_len;
Packit Service a2489d
# elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
Packit Service a2489d
  msg.msg_accrights = &fd;
Packit Service a2489d
  msg.msg_accrightslen = sizeof fd;
Packit Service a2489d
# else
Packit Service a2489d
  errno = ENOSYS;
Packit Service a2489d
  return -1;
Packit Service a2489d
# endif
Packit Service a2489d
Packit Service a2489d
  if (sendmsg (sock, &msg, 0) != iov.iov_len)
Packit Service a2489d
    return -1;
Packit Service a2489d
  return 0;
Packit Service a2489d
}
Packit Service a2489d
#else
Packit Service a2489d
int
Packit Service a2489d
sendfd (int sock _GL_UNUSED, int fd _GL_UNUSED)
Packit Service a2489d
{
Packit Service a2489d
  errno = ENOSYS;
Packit Service a2489d
  return -1;
Packit Service a2489d
}
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
Packit Service a2489d
#if HAVE_RECVMSG
Packit Service a2489d
/* recvfd receives a file descriptor through the socket.
Packit Service a2489d
   The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>).
Packit Service a2489d
Packit Service a2489d
   Return the fd on success, or -1 with errno set in case of error.
Packit Service a2489d
*/
Packit Service a2489d
int
Packit Service a2489d
recvfd (int sock, int flags)
Packit Service a2489d
{
Packit Service a2489d
  char byte = 0;
Packit Service a2489d
  struct iovec iov;
Packit Service a2489d
  struct msghdr msg;
Packit Service a2489d
  int fd = -1;
Packit Service a2489d
  ssize_t len;
Packit Service a2489d
# ifdef CMSG_FIRSTHDR
Packit Service a2489d
  struct cmsghdr *cmsg;
Packit Service a2489d
  char buf[CMSG_SPACE (sizeof fd)];
Packit Service a2489d
  int flags_recvmsg = flags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0;
Packit Service a2489d
# endif
Packit Service a2489d
Packit Service a2489d
  if ((flags & ~O_CLOEXEC) != 0)
Packit Service a2489d
    {
Packit Service a2489d
      errno = EINVAL;
Packit Service a2489d
      return -1;
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  /* send at least one char */
Packit Service a2489d
  memset (&msg, 0, sizeof msg);
Packit Service a2489d
  iov.iov_base = &byte;
Packit Service a2489d
  iov.iov_len = 1;
Packit Service a2489d
  msg.msg_iov = &iov;
Packit Service a2489d
  msg.msg_iovlen = 1;
Packit Service a2489d
  msg.msg_name = NULL;
Packit Service a2489d
  msg.msg_namelen = 0;
Packit Service a2489d
Packit Service a2489d
# ifdef CMSG_FIRSTHDR
Packit Service a2489d
  msg.msg_control = buf;
Packit Service a2489d
  msg.msg_controllen = sizeof buf;
Packit Service a2489d
  cmsg = CMSG_FIRSTHDR (&msg;;
Packit Service a2489d
  cmsg->cmsg_level = SOL_SOCKET;
Packit Service a2489d
  cmsg->cmsg_type = SCM_RIGHTS;
Packit Service a2489d
  cmsg->cmsg_len = CMSG_LEN (sizeof fd);
Packit Service a2489d
  /* Initialize the payload: */
Packit Service a2489d
  memcpy (CMSG_DATA (cmsg), &fd, sizeof fd);
Packit Service a2489d
  msg.msg_controllen = cmsg->cmsg_len;
Packit Service a2489d
Packit Service a2489d
  len = recvmsg (sock, &msg, flags_recvmsg);
Packit Service a2489d
  if (len < 0)
Packit Service a2489d
    return -1;
Packit Service a2489d
Packit Service a2489d
  cmsg = CMSG_FIRSTHDR (&msg;;
Packit Service a2489d
  /* be paranoiac */
Packit Service a2489d
  if (len == 0 || cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof fd)
Packit Service a2489d
      || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
Packit Service a2489d
    {
Packit Service a2489d
      /* fake errno: at end the file is not available */
Packit Service a2489d
      errno = len ? EACCES : ENOTCONN;
Packit Service a2489d
      return -1;
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
  memcpy (&fd, CMSG_DATA (cmsg), sizeof fd);
Packit Service a2489d
Packit Service a2489d
  /* set close-on-exec flag */
Packit Service a2489d
  if (!MSG_CMSG_CLOEXEC && (flags & O_CLOEXEC))
Packit Service a2489d
    {
Packit Service a2489d
      if (set_cloexec_flag (fd, true) < 0)
Packit Service a2489d
        {
Packit Service a2489d
          int saved_errno = errno;
Packit Service a2489d
          (void) close (fd);
Packit Service a2489d
          errno = saved_errno;
Packit Service a2489d
          return -1;
Packit Service a2489d
        }
Packit Service a2489d
    }
Packit Service a2489d
Packit Service a2489d
# elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
Packit Service a2489d
  msg.msg_accrights = &fd;
Packit Service a2489d
  msg.msg_accrightslen = sizeof fd;
Packit Service a2489d
  if (recvmsg (sock, &msg, 0) < 0)
Packit Service a2489d
    return -1;
Packit Service a2489d
Packit Service a2489d
  /* set close-on-exec flag */
Packit Service a2489d
  if (flags & O_CLOEXEC)
Packit Service a2489d
    {
Packit Service a2489d
      if (set_cloexec_flag (fd, true) < 0)
Packit Service a2489d
        {
Packit Service a2489d
          int saved_errno = errno;
Packit Service a2489d
          close (fd);
Packit Service a2489d
          errno = saved_errno;
Packit Service a2489d
          return -1;
Packit Service a2489d
        }
Packit Service a2489d
    }
Packit Service a2489d
# else
Packit Service a2489d
  errno = ENOSYS;
Packit Service a2489d
# endif
Packit Service a2489d
Packit Service a2489d
  return fd;
Packit Service a2489d
}
Packit Service a2489d
#else
Packit Service a2489d
int
Packit Service a2489d
recvfd (int sock _GL_UNUSED, int flags _GL_UNUSED)
Packit Service a2489d
{
Packit Service a2489d
  errno = ENOSYS;
Packit Service a2489d
  return -1;
Packit Service a2489d
}
Packit Service a2489d
#endif