fdpass.c revision f493639f3313637a8313613ea7a4fda618f1980a
5f5870385cff47efd2f58e7892f251cf13761528Timo 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
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen support this. If you're having runtime problems, check the end of fd_read()
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen and play with the if condition.
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen If this file doesn't compile at all, you should check if this is supported
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen in your system at all. It may require some extra #define to enable it.
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen If not, you're pretty much out of luck. Cygwin didn't last I checked.
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen Copyright (c) 2002-2003 Timo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen Permission is hereby granted, free of charge, to any person obtaining
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen a copy of this software and associated documentation files (the
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen "Software"), to deal in the Software without restriction, including
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen without limitation the rights to use, copy, modify, merge, publish,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen distribute, sublicense, and/or sell copies of the Software, and to
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen permit persons to whom the Software is furnished to do so, subject to
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen the following conditions:
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen The above copyright notice and this permission notice shall be
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen included in all copies or substantial portions of the Software.
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo 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
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen*/
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen#define _XPG4_2
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen#ifndef _AIX
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen# define _XOPEN_SOURCE_EXTENDED /* for Tru64, breaks AIX */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen#endif
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen#include "lib.h"
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen#include "fdpass.h"
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen#include <sys/socket.h>
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen#include <sys/un.h>
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen#include <sys/uio.h>
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo 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) \
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen (CMSG_ALIGN(len) + CMSG_ALIGN(sizeof(struct cmsghdr)))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen# define CMSG_LEN(len) \
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#endif
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenssize_t fd_send(int handle, int send_fd, const void *data, size_t size)
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen{
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen struct msghdr msg;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct iovec iov;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen struct cmsghdr *cmsg;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen char buf[CMSG_SPACE(sizeof(int))];
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* at least one byte is required to be sent with fd passing */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_assert(size > 0 && size < SSIZE_T_MAX);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen memset(&msg, 0, sizeof (struct msghdr));
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen iov.iov_base = (void *) data;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen iov.iov_len = size;
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen msg.msg_iov = &iov;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen msg.msg_iovlen = 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (send_fd != -1) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* set the control and controllen before CMSG_FIRSTHDR() */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg.msg_control = buf;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen msg.msg_controllen = sizeof(buf);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen cmsg = CMSG_FIRSTHDR(&msg);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen cmsg->cmsg_level = SOL_SOCKET;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen cmsg->cmsg_type = SCM_RIGHTS;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen cmsg->cmsg_len = CMSG_LEN(sizeof(int));
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen *((int *) CMSG_DATA(cmsg)) = send_fd;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* set the real length we want to use. it's different than
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen sizeof(buf) in 64bit systems. */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen msg.msg_controllen = cmsg->cmsg_len;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return sendmsg(handle, &msg, 0);
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenssize_t fd_read(int handle, void *data, size_t size, int *fd)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct msghdr msg;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct iovec iov;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct cmsghdr *cmsg;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ssize_t ret;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen char buf[CMSG_SPACE(sizeof(int))];
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(size > 0 && size < SSIZE_T_MAX);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen memset(&msg, 0, sizeof (struct msghdr));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen iov.iov_base = data;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen iov.iov_len = size;
53cd46dd843c22f21f7e6efcc52a3e0f76cd1e52Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen msg.msg_iov = &iov;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen msg.msg_iovlen = 1;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen memset(buf, 0, sizeof(buf));
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen msg.msg_control = buf;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen msg.msg_controllen = sizeof(buf);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = recvmsg(handle, &msg, 0);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (ret <= 0) {
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen *fd = -1;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen return ret;
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen }
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen /* at least one byte transferred - we should have the fd now.
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen do extra checks to make sure it really is an fd that is being
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen transferred to avoid potential DoS conditions. some systems don't
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen set all these values correctly however:
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen Linux 2.0.x - cmsg_len, cmsg_level, cmsg_type are not set
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen Tru64 - msg_controllen isn't set */
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen cmsg = CMSG_FIRSTHDR(&msg);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#ifndef __osf__
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen msg.msg_controllen < CMSG_SPACE(sizeof(int)) ||
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#endif
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen cmsg == NULL || cmsg->cmsg_len < CMSG_LEN(sizeof(int)) ||
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen *fd = -1;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen else
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen *fd = *((int *) CMSG_DATA(cmsg));
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen return ret;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen}
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen