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