#define _XPG4_2
#if defined(irix) || defined (__irix__) || defined(sgi) || defined (__sgi__)
# define _XOPEN_SOURCE 4
#endif
#if !defined(_AIX) && !defined(_XOPEN_SOURCE_EXTENDED)
# define _XOPEN_SOURCE_EXTENDED
#endif
#ifdef HAVE_CONFIG_H
# include "lib.h"
#else
# define i_assert(x)
#endif
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include "fdpass.h"
#ifndef HAVE_CONFIG_H
struct const_iovec {
const void *iov_base;
size_t iov_len;
};
#endif
#ifdef BUGGY_CMSG_MACROS
# undef CMSG_SPACE
# undef CMSG_LEN
# undef CMSG_DATA
# define CMSG_DATA(cmsg) ((char *)((cmsg) + 1))
# define _CMSG_DATA_ALIGNMENT 4
# define _CMSG_HDR_ALIGNMENT 4
#endif
#ifndef CMSG_SPACE
# define MY_ALIGN(len, align) \
(((len) + align - 1) & ~(align - 1))
# ifndef _CMSG_DATA_ALIGNMENT
# define _CMSG_DATA_ALIGNMENT sizeof(size_t)
# endif
# ifndef _CMSG_HDR_ALIGNMENT
# define _CMSG_HDR_ALIGNMENT sizeof(size_t)
# endif
# define CMSG_SPACE(len) \
(MY_ALIGN(sizeof(struct cmsghdr), _CMSG_DATA_ALIGNMENT) + \
MY_ALIGN(len, _CMSG_HDR_ALIGNMENT))
# define CMSG_LEN(len) \
(MY_ALIGN(sizeof(struct cmsghdr), _CMSG_DATA_ALIGNMENT) + (len))
#endif
#ifdef SCM_RIGHTS
ssize_t fd_send(int handle, int send_fd, const void *data, size_t size)
{
struct msghdr msg;
struct const_iovec iov;
struct cmsghdr *cmsg;
char buf[CMSG_SPACE(sizeof(int))];
i_assert(size > 0 && size < INT_MAX);
memset(&msg, 0, sizeof(struct msghdr));
iov.iov_base = data;
iov.iov_len = size;
msg.msg_iov = (void *)&iov;
msg.msg_iovlen = 1;
if (send_fd != -1) {
memset(buf, 0, sizeof(buf));
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &send_fd, sizeof(send_fd));
msg.msg_controllen = cmsg->cmsg_len;
}
return sendmsg(handle, &msg, 0);
}
#ifdef __osf__
# define CHECK_MSG(msg) TRUE
#else
# define CHECK_MSG(msg) (msg).msg_controllen >= CMSG_SPACE(sizeof(int))
#endif
#ifdef LINUX20
# define CHECK_CMSG(cmsg) ((cmsg) != NULL)
#else
# define CHECK_CMSG(cmsg) \
((cmsg) != NULL && \
(size_t)(cmsg)->cmsg_len >= (size_t)CMSG_LEN(sizeof(int)) && \
(cmsg)->cmsg_level == SOL_SOCKET && (cmsg)->cmsg_type == SCM_RIGHTS)
#endif
ssize_t fd_read(int handle, void *data, size_t size, int *fd)
{
struct msghdr msg;
struct iovec iov;
struct cmsghdr *cmsg;
ssize_t ret;
char buf[CMSG_SPACE(sizeof(int))];
i_assert(size > 0 && size < INT_MAX);
memset(&msg, 0, sizeof (struct msghdr));
iov.iov_base = data;
iov.iov_len = size;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
memset(buf, 0, sizeof(buf));
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
ret = recvmsg(handle, &msg, 0);
if (ret <= 0) {
*fd = -1;
return ret;
}
cmsg = CMSG_FIRSTHDR(&msg);
if (!CHECK_MSG(msg) || !CHECK_CMSG(cmsg))
*fd = -1;
else
memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));
return ret;
}
#else
# ifdef __GNUC__
# warning SCM_RIGHTS not supported, privilege separation not possible
# endif
ssize_t fd_send(int handle ATTR_UNUSED, int send_fd ATTR_UNUSED,
const void *data ATTR_UNUSED, size_t size ATTR_UNUSED)
{
errno = ENOSYS;
return -1;
}
ssize_t fd_read(int handle ATTR_UNUSED, void *data ATTR_UNUSED,
size_t size ATTR_UNUSED, int *fd ATTR_UNUSED)
{
errno = ENOSYS;
return -1;
}
#endif