1323129Sdes/* $OpenBSD: monitor_fdpass.c,v 1.21 2016/02/29 20:22:36 jca 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) {
102323129Sdes		error("%s: sendmsg: expected sent 1 got %zd", __func__, n);
103181111Sdes		return -1;
104181111Sdes	}
105181111Sdes	return 0;
10698937Sdes#else
107181111Sdes	error("%s: file descriptor passing not supported", __func__);
108181111Sdes	return -1;
10998937Sdes#endif
11098675Sdes}
11198675Sdes
11298675Sdesint
113137015Sdesmm_receive_fd(int sock)
11498675Sdes{
11598937Sdes#if defined(HAVE_RECVMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
11698675Sdes	struct msghdr msg;
11798937Sdes#ifndef HAVE_ACCRIGHTS_IN_MSGHDR
118180989Sdes	union {
119180989Sdes		struct cmsghdr hdr;
120180989Sdes		char buf[CMSG_SPACE(sizeof(int))];
121180989Sdes	} cmsgbuf;
12298937Sdes	struct cmsghdr *cmsg;
12398937Sdes#endif
124192595Sdes	struct iovec vec;
125192595Sdes	ssize_t n;
126192595Sdes	char ch;
127192595Sdes	int fd;
128204917Sdes	struct pollfd pfd;
12998675Sdes
13098675Sdes	memset(&msg, 0, sizeof(msg));
13198675Sdes	vec.iov_base = &ch;
13298675Sdes	vec.iov_len = 1;
13398675Sdes	msg.msg_iov = &vec;
13498675Sdes	msg.msg_iovlen = 1;
13598937Sdes#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
13698937Sdes	msg.msg_accrights = (caddr_t)&fd;
13798937Sdes	msg.msg_accrightslen = sizeof(fd);
13898937Sdes#else
139294332Sdes	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
140180989Sdes	msg.msg_control = &cmsgbuf.buf;
141180989Sdes	msg.msg_controllen = sizeof(cmsgbuf.buf);
14298937Sdes#endif
14398675Sdes
144204917Sdes	pfd.fd = sock;
145204917Sdes	pfd.events = POLLIN;
146204917Sdes	while ((n = recvmsg(sock, &msg, 0)) == -1 &&
147204917Sdes	    (errno == EAGAIN || errno == EINTR)) {
148192595Sdes		debug3("%s: recvmsg: %s", __func__, strerror(errno));
149204917Sdes		(void)poll(&pfd, 1, -1);
150204917Sdes	}
151192595Sdes	if (n == -1) {
152181111Sdes		error("%s: recvmsg: %s", __func__, strerror(errno));
153181111Sdes		return -1;
154181111Sdes	}
155192595Sdes
156181111Sdes	if (n != 1) {
157323129Sdes		error("%s: recvmsg: expected received 1 got %zd", __func__, n);
158181111Sdes		return -1;
159181111Sdes	}
16098675Sdes
16198937Sdes#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
162181111Sdes	if (msg.msg_accrightslen != sizeof(fd)) {
163181111Sdes		error("%s: no fd", __func__);
164181111Sdes		return -1;
165181111Sdes	}
16698937Sdes#else
16798675Sdes	cmsg = CMSG_FIRSTHDR(&msg);
168181111Sdes	if (cmsg == NULL) {
169181111Sdes		error("%s: no message header", __func__);
170181111Sdes		return -1;
171181111Sdes	}
172192595Sdes
173124208Sdes#ifndef BROKEN_CMSG_TYPE
174181111Sdes	if (cmsg->cmsg_type != SCM_RIGHTS) {
175181111Sdes		error("%s: expected type %d got %d", __func__,
17698675Sdes		    SCM_RIGHTS, cmsg->cmsg_type);
177181111Sdes		return -1;
178181111Sdes	}
179124208Sdes#endif
18098675Sdes	fd = (*(int *)CMSG_DATA(cmsg));
18198937Sdes#endif
18298675Sdes	return fd;
18398937Sdes#else
184181111Sdes	error("%s: file descriptor passing not supported", __func__);
185181111Sdes	return -1;
18698937Sdes#endif
18798675Sdes}
188