fdpass.c revision 4567f85883fcfd7e5bf61b5a360589410df8c5cf
/* Copyright (c) 2002-2004 Timo Sirainen */
/*
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)
# define _XOPEN_SOURCE_EXTENDED /* for Tru64, breaks AIX */
#endif
#include <string.h>
#include <limits.h>
#ifdef HAVE_CONFIG_H
# include "lib.h"
#else
# define i_assert(x)
#endif
#include "fdpass.h"
/* 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
alignmentation while kernel uses 32bit alignmentation. */
# define _CMSG_DATA_ALIGNMENT 4
# define _CMSG_HDR_ALIGNMENT 4
#endif
#ifndef CMSG_SPACE
/* Alignment between cmsghdr and data */
# ifndef _CMSG_DATA_ALIGNMENT
# define _CMSG_DATA_ALIGNMENT sizeof(size_t)
# endif
/* Alignment between data and next cmsghdr */
# ifndef _CMSG_HDR_ALIGNMENT
# define _CMSG_HDR_ALIGNMENT sizeof(size_t)
# endif
# define CMSG_SPACE(len) \
#endif
#ifdef SCM_RIGHTS
{
char buf[CMSG_SPACE(sizeof(int))];
/* 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 __osf__
#else
#endif
#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
# define CHECK_CMSG(cmsg) \
#endif
{
char buf[CMSG_SPACE(sizeof(int))];
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_MSG() and
CHECK_CMSG() are somewhat system dependent */
*fd = -1;
else
return ret;
}
#else
# ifdef __GNUC__
# endif
{
return -1;
}
{
return -1;
}
#endif