fdpass.c revision 6e2ca11362aa76c02508adf2178cd34d54e499f7
5e0ce63bb65db34d7f48b34bbb5545fa791781c4Timo Sirainen/*
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fdpass.c - File descriptor passing between processes via UNIX sockets
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen This isn't fully portable, but pretty much all UNIXes nowadays should
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen support this. If you're having runtime problems, check the end of fd_read()
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen and play with the if condition.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
daf029d2a627daa39d05507140f385162828172eTimo Sirainen If this file doesn't compile at all, you should check if this is supported
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen in your system at all. It may require some extra #define to enable it.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen If not, you're pretty much out of luck. Cygwin didn't last I checked.
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen Copyright (c) 2002-2003 Timo Sirainen
daf029d2a627daa39d05507140f385162828172eTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen Permission is hereby granted, free of charge, to any person obtaining
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen a copy of this software and associated documentation files (the
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen "Software"), to deal in the Software without restriction, including
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen without limitation the rights to use, copy, modify, merge, publish,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen distribute, sublicense, and/or sell copies of the Software, and to
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen permit persons to whom the Software is furnished to do so, subject to
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen the following conditions:
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen The above copyright notice and this permission notice shall be
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen included in all copies or substantial portions of the Software.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
daf029d2a627daa39d05507140f385162828172eTimo Sirainen THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
daf029d2a627daa39d05507140f385162828172eTimo Sirainen SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
daf029d2a627daa39d05507140f385162828172eTimo Sirainen*/
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define _XPG4_2
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
f923659c0e5298263d80622c99f4dc4132b4675bTimo Sirainen#if defined(irix) || defined (__irix__) || defined(sgi) || defined (__sgi__)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen# define _XOPEN_SOURCE /* for IRIX */
daf029d2a627daa39d05507140f385162828172eTimo Sirainen#endif
f923659c0e5298263d80622c99f4dc4132b4675bTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#if !defined(_AIX) && !defined(_XOPEN_SOURCE_EXTENDED)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen# define _XOPEN_SOURCE_EXTENDED /* for Tru64, breaks AIX */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#endif
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#include "lib.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "fdpass.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <sys/socket.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <sys/un.h>
6449bd276af37b3e0b81a9c47ecd01f39a2cba53Timo Sirainen#include <sys/uio.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#ifndef CMSG_SPACE
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen# define CMSG_ALIGN(len) \
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen# define CMSG_SPACE(len) \
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen (CMSG_ALIGN(len) + CMSG_ALIGN(sizeof(struct cmsghdr)))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen# define CMSG_LEN(len) \
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen#endif
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenssize_t fd_send(int handle, int send_fd, const void *data, size_t size)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct msghdr msg;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct iovec iov;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct cmsghdr *cmsg;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen char buf[CMSG_SPACE(sizeof(int))];
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* at least one byte is required to be sent with fd passing */
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen i_assert(size > 0 && size < SSIZE_T_MAX);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen memset(&msg, 0, sizeof (struct msghdr));
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen iov.iov_base = (void *) data;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen iov.iov_len = size;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg.msg_iov = &iov;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg.msg_iovlen = 1;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (send_fd != -1) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* set the control and controllen before CMSG_FIRSTHDR() */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg.msg_control = buf;
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen msg.msg_controllen = sizeof(buf);
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen cmsg = CMSG_FIRSTHDR(&msg);
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen cmsg->cmsg_level = SOL_SOCKET;
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen cmsg->cmsg_type = SCM_RIGHTS;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen cmsg->cmsg_len = CMSG_LEN(sizeof(int));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *((int *) CMSG_DATA(cmsg)) = send_fd;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen /* set the real length we want to use. it's different than
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen sizeof(buf) in 64bit systems. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg.msg_controllen = cmsg->cmsg_len;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return sendmsg(handle, &msg, 0);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenssize_t fd_read(int handle, void *data, size_t size, int *fd)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct msghdr msg;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct iovec iov;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct cmsghdr *cmsg;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen ssize_t ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen char buf[CMSG_SPACE(sizeof(int))];
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(size > 0 && size < SSIZE_T_MAX);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen memset(&msg, 0, sizeof (struct msghdr));
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen iov.iov_base = data;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen iov.iov_len = size;
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg.msg_iov = &iov;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg.msg_iovlen = 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen memset(buf, 0, sizeof(buf));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg.msg_control = buf;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg.msg_controllen = sizeof(buf);
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = recvmsg(handle, &msg, 0);
3e25b17126e9536736d5da03697613e4c3af5f76Timo Sirainen if (ret <= 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *fd = -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* at least one byte transferred - we should have the fd now.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen do extra checks to make sure it really is an fd that is being
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen transferred to avoid potential DoS conditions. some systems don't
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen set all these values correctly however:
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen Linux 2.0.x - cmsg_len, cmsg_level, cmsg_type are not set
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen Tru64 - msg_controllen isn't set */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen cmsg = CMSG_FIRSTHDR(&msg);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#ifndef __osf__
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg.msg_controllen < CMSG_SPACE(sizeof(int)) ||
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#endif
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen cmsg == NULL || cmsg->cmsg_len < CMSG_LEN(sizeof(int)) ||
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen *fd = -1;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen else
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen *fd = *((int *) CMSG_DATA(cmsg));
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen return ret;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen}
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen