/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
/*
fdpass.c - File descriptor passing between processes via UNIX sockets
This isn't fully portable, but pretty much all UNIXes nowadays should
support this. If you're having runtime problems with fd_read(), check the
end of fd_read() and play with the if condition. If you're having problems
with fd_send(), try defining BUGGY_CMSG_MACROS.
If this file doesn't compile at all, you should check if this is supported
in your system at all. It may require some extra #define to enable it.
If not, you're pretty much out of luck. Cygwin didn't last I checked.
*/
#define _XPG4_2
#endif
#if !defined(_AIX) && !defined(_XOPEN_SOURCE_EXTENDED)
#endif
#ifdef HAVE_CONFIG_H
# include "lib.h"
#else
# define i_assert(x)
#endif
#include <string.h>
#include <limits.h>
#include "fdpass.h"
#ifndef HAVE_CONFIG_H
struct const_iovec {
const void *iov_base;
};
#endif
/* RFC 2292 defines CMSG_*() macros, but some operating systems don't have them
so we'll define our own if they don't exist.
CMSG_LEN(data) is used to calculate size of sizeof(struct cmsghdr) +
sizeof(data) and padding between them.
CMSG_SPACE(data) also calculates the padding needed after the data, in case
multiple objects are sent.
cmsghdr contains cmsg_len field and two integers. cmsg_len is sometimes
defined as sockaddr_t and sometimes size_t, so it can be either 32bit or
64bit. This padding is added by compiler in sizeof(struct cmsghdr).
Padding required by CMSG_DATA() can vary. Usually it wants size_t or 32bit.
With Solaris it's in _CMSG_DATA_ALIGNMENT (32bit), we assume others want
size_t.
We don't really need CMSG_SPACE() to be exactly correct, because currently
we send only one object at a time. But anyway I'm trying to keep that
correct in case it's sometimes needed..
*/
#ifdef BUGGY_CMSG_MACROS
/* Some OSes have broken CMSG macros in 64bit systems. The macros use 64bit
alignment while kernel uses 32bit alignment. */
#endif
#ifndef CMSG_SPACE
/* Alignment between cmsghdr and data */
# ifndef _CMSG_DATA_ALIGNMENT
# endif
/* Alignment between data and next cmsghdr */
# ifndef _CMSG_HDR_ALIGNMENT
# endif
#endif
#ifdef SCM_RIGHTS
{
/* at least one byte is required to be sent with fd passing */
if (send_fd != -1) {
/* set the control and controllen before CMSG_FIRSTHDR(). */
/* set the real length we want to use. Do it after all is
set just in case CMSG macros required the extra padding
in the end. */
}
}
#ifdef LINUX20
/* Linux 2.0.x doesn't set any cmsg fields. Note that this might make some
attacks possible so don't do it unless you really have to. */
#else
#endif
{
if (ret <= 0) {
*fd = -1;
return ret;
}
/* at least one byte transferred - we should have the fd now.
do extra checks to make sure it really is an fd that is being
transferred to avoid potential DoS conditions. some systems don't
set all these values correctly however so CHECK_CMSG() is somewhat
system dependent */
if (!CHECK_CMSG(cmsg))
*fd = -1;
else
return ret;
}
#else
# ifdef __GNUC__
# endif
{
return -1;
}
{
return -1;
}
#endif