1294332Sdes/* $OpenBSD: monitor_fdpass.c,v 1.20 2015/02/25 23:05:47 djm Exp $ */
298675Sdes/*
398675Sdes * Copyright 2001 Niels Provos <provos@citi.umich.edu>
498675Sdes * All rights reserved.
598675Sdes *
698675Sdes * Redistribution and use in source and binary forms, with or without
798675Sdes * modification, are permitted provided that the following conditions
898675Sdes * are met:
998675Sdes * 1. Redistributions of source code must retain the above copyright
1098675Sdes *    notice, this list of conditions and the following disclaimer.
1198675Sdes * 2. Redistributions in binary form must reproduce the above copyright
1298675Sdes *    notice, this list of conditions and the following disclaimer in the
1398675Sdes *    documentation and/or other materials provided with the distribution.
1498675Sdes *
1598675Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1698675Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1798675Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1898675Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1998675Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2098675Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2198675Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2298675Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2398675Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2498675Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2598675Sdes */
2698675Sdes
2798675Sdes#include "includes.h"
2898675Sdes
29162852Sdes#include <sys/types.h>
30162852Sdes#include <sys/socket.h>
3198675Sdes#include <sys/uio.h>
32164146Sdes#ifdef HAVE_SYS_UN_H
33164146Sdes#include <sys/un.h>
34164146Sdes#endif
3598675Sdes
36162852Sdes#include <errno.h>
37162852Sdes#include <string.h>
38162852Sdes#include <stdarg.h>
39162852Sdes
40294328Sdes#ifdef HAVE_POLL_H
41294328Sdes# include <poll.h>
42294328Sdes#else
43294328Sdes# ifdef HAVE_SYS_POLL_H
44294328Sdes#  include <sys/poll.h>
45294328Sdes# endif
46294328Sdes#endif
47294328Sdes
4898675Sdes#include "log.h"
4998675Sdes#include "monitor_fdpass.h"
5098675Sdes
51181111Sdesint
52137015Sdesmm_send_fd(int sock, int fd)
5398675Sdes{
5498937Sdes#if defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
5598675Sdes	struct msghdr msg;
5698937Sdes#ifndef HAVE_ACCRIGHTS_IN_MSGHDR
57180989Sdes	union {
58180989Sdes		struct cmsghdr hdr;
59180989Sdes		char buf[CMSG_SPACE(sizeof(int))];
60180989Sdes	} cmsgbuf;
6198937Sdes	struct cmsghdr *cmsg;
6298937Sdes#endif
63192595Sdes	struct iovec vec;
64192595Sdes	char ch = '\0';
65192595Sdes	ssize_t n;
66204917Sdes	struct pollfd pfd;
6798675Sdes
6898675Sdes	memset(&msg, 0, sizeof(msg));
6998937Sdes#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
7098937Sdes	msg.msg_accrights = (caddr_t)&fd;
7198937Sdes	msg.msg_accrightslen = sizeof(fd);
7298937Sdes#else
73294332Sdes	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
74180989Sdes	msg.msg_control = (caddr_t)&cmsgbuf.buf;
75180989Sdes	msg.msg_controllen = sizeof(cmsgbuf.buf);
7698675Sdes	cmsg = CMSG_FIRSTHDR(&msg);
7798675Sdes	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
7898675Sdes	cmsg->cmsg_level = SOL_SOCKET;
7998675Sdes	cmsg->cmsg_type = SCM_RIGHTS;
8098675Sdes	*(int *)CMSG_DATA(cmsg) = fd;
8198937Sdes#endif
8298675Sdes
8398675Sdes	vec.iov_base = &ch;
8498675Sdes	vec.iov_len = 1;
8598675Sdes	msg.msg_iov = &vec;
8698675Sdes	msg.msg_iovlen = 1;
8798675Sdes
88204917Sdes	pfd.fd = sock;
89204917Sdes	pfd.events = POLLOUT;
90204917Sdes	while ((n = sendmsg(sock, &msg, 0)) == -1 &&
91204917Sdes	    (errno == EAGAIN || errno == EINTR)) {
92192595Sdes		debug3("%s: sendmsg(%d): %s", __func__, fd, strerror(errno));
93204917Sdes		(void)poll(&pfd, 1, -1);
94204917Sdes	}
95192595Sdes	if (n == -1) {
96181111Sdes		error("%s: sendmsg(%d): %s", __func__, fd,
9798675Sdes		    strerror(errno));
98181111Sdes		return -1;
99181111Sdes	}
100181111Sdes
101181111Sdes	if (n != 1) {
102181111Sdes		error("%s: sendmsg: expected sent 1 got %ld",
103106121Sdes		    __func__, (long)n);
104181111Sdes		return -1;
105181111Sdes	}
106181111Sdes	return 0;
10798937Sdes#else
108181111Sdes	error("%s: file descriptor passing not supported", __func__);
109181111Sdes	return -1;
11098937Sdes#endif
11198675Sdes}
11298675Sdes
11398675Sdesint
114137015Sdesmm_receive_fd(int sock)
11598675Sdes{
11698937Sdes#if defined(HAVE_RECVMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
11798675Sdes	struct msghdr msg;
11898937Sdes#ifndef HAVE_ACCRIGHTS_IN_MSGHDR
119180989Sdes	union {
120180989Sdes		struct cmsghdr hdr;
121180989Sdes		char buf[CMSG_SPACE(sizeof(int))];
122180989Sdes	} cmsgbuf;
12398937Sdes	struct cmsghdr *cmsg;
12498937Sdes#endif
125192595Sdes	struct iovec vec;
126192595Sdes	ssize_t n;
127192595Sdes	char ch;
128192595Sdes	int fd;
129204917Sdes	struct pollfd pfd;
13098675Sdes
13198675Sdes	memset(&msg, 0, sizeof(msg));
13298675Sdes	vec.iov_base = &ch;
13398675Sdes	vec.iov_len = 1;
13498675Sdes	msg.msg_iov = &vec;
13598675Sdes	msg.msg_iovlen = 1;
13698937Sdes#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
13798937Sdes	msg.msg_accrights = (caddr_t)&fd;
13898937Sdes	msg.msg_accrightslen = sizeof(fd);
13998937Sdes#else
140294332Sdes	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
141180989Sdes	msg.msg_control = &cmsgbuf.buf;
142180989Sdes	msg.msg_controllen = sizeof(cmsgbuf.buf);
14398937Sdes#endif
14498675Sdes
145204917Sdes	pfd.fd = sock;
146204917Sdes	pfd.events = POLLIN;
147204917Sdes	while ((n = recvmsg(sock, &msg, 0)) == -1 &&
148204917Sdes	    (errno == EAGAIN || errno == EINTR)) {
149192595Sdes		debug3("%s: recvmsg: %s", __func__, strerror(errno));
150204917Sdes		(void)poll(&pfd, 1, -1);
151204917Sdes	}
152192595Sdes	if (n == -1) {
153181111Sdes		error("%s: recvmsg: %s", __func__, strerror(errno));
154181111Sdes		return -1;
155181111Sdes	}
156192595Sdes
157181111Sdes	if (n != 1) {
158181111Sdes		error("%s: recvmsg: expected received 1 got %ld",
159106121Sdes		    __func__, (long)n);
160181111Sdes		return -1;
161181111Sdes	}
16298675Sdes
16398937Sdes#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
164181111Sdes	if (msg.msg_accrightslen != sizeof(fd)) {
165181111Sdes		error("%s: no fd", __func__);
166181111Sdes		return -1;
167181111Sdes	}
16898937Sdes#else
16998675Sdes	cmsg = CMSG_FIRSTHDR(&msg);
170181111Sdes	if (cmsg == NULL) {
171181111Sdes		error("%s: no message header", __func__);
172181111Sdes		return -1;
173181111Sdes	}
174192595Sdes
175124208Sdes#ifndef BROKEN_CMSG_TYPE
176181111Sdes	if (cmsg->cmsg_type != SCM_RIGHTS) {
177181111Sdes		error("%s: expected type %d got %d", __func__,
17898675Sdes		    SCM_RIGHTS, cmsg->cmsg_type);
179181111Sdes		return -1;
180181111Sdes	}
181124208Sdes#endif
18298675Sdes	fd = (*(int *)CMSG_DATA(cmsg));
18398937Sdes#endif
18498675Sdes	return fd;
18598937Sdes#else
186181111Sdes	error("%s: file descriptor passing not supported", __func__);
187181111Sdes	return -1;
18898937Sdes#endif
18998675Sdes}
190