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