1204917Sdes/* $OpenBSD: monitor_fdpass.c,v 1.19 2010/01/12 00:58:25 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>
37204917Sdes#ifdef HAVE_POLL_H
38204917Sdes#include <poll.h>
39204917Sdes#endif
40162852Sdes#include <string.h>
41162852Sdes#include <stdarg.h>
42162852Sdes
4398675Sdes#include "log.h"
4498675Sdes#include "monitor_fdpass.h"
4598675Sdes
46181111Sdesint
47137015Sdesmm_send_fd(int sock, int fd)
4898675Sdes{
4998937Sdes#if defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
5098675Sdes	struct msghdr msg;
5198937Sdes#ifndef HAVE_ACCRIGHTS_IN_MSGHDR
52180989Sdes	union {
53180989Sdes		struct cmsghdr hdr;
54180989Sdes		char buf[CMSG_SPACE(sizeof(int))];
55180989Sdes	} cmsgbuf;
5698937Sdes	struct cmsghdr *cmsg;
5798937Sdes#endif
58192595Sdes	struct iovec vec;
59192595Sdes	char ch = '\0';
60192595Sdes	ssize_t n;
61204917Sdes	struct pollfd pfd;
6298675Sdes
6398675Sdes	memset(&msg, 0, sizeof(msg));
6498937Sdes#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
6598937Sdes	msg.msg_accrights = (caddr_t)&fd;
6698937Sdes	msg.msg_accrightslen = sizeof(fd);
6798937Sdes#else
68180989Sdes	msg.msg_control = (caddr_t)&cmsgbuf.buf;
69180989Sdes	msg.msg_controllen = sizeof(cmsgbuf.buf);
7098675Sdes	cmsg = CMSG_FIRSTHDR(&msg);
7198675Sdes	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
7298675Sdes	cmsg->cmsg_level = SOL_SOCKET;
7398675Sdes	cmsg->cmsg_type = SCM_RIGHTS;
7498675Sdes	*(int *)CMSG_DATA(cmsg) = fd;
7598937Sdes#endif
7698675Sdes
7798675Sdes	vec.iov_base = &ch;
7898675Sdes	vec.iov_len = 1;
7998675Sdes	msg.msg_iov = &vec;
8098675Sdes	msg.msg_iovlen = 1;
8198675Sdes
82204917Sdes	pfd.fd = sock;
83204917Sdes	pfd.events = POLLOUT;
84204917Sdes	while ((n = sendmsg(sock, &msg, 0)) == -1 &&
85204917Sdes	    (errno == EAGAIN || errno == EINTR)) {
86192595Sdes		debug3("%s: sendmsg(%d): %s", __func__, fd, strerror(errno));
87204917Sdes		(void)poll(&pfd, 1, -1);
88204917Sdes	}
89192595Sdes	if (n == -1) {
90181111Sdes		error("%s: sendmsg(%d): %s", __func__, fd,
9198675Sdes		    strerror(errno));
92181111Sdes		return -1;
93181111Sdes	}
94181111Sdes
95181111Sdes	if (n != 1) {
96181111Sdes		error("%s: sendmsg: expected sent 1 got %ld",
97106121Sdes		    __func__, (long)n);
98181111Sdes		return -1;
99181111Sdes	}
100181111Sdes	return 0;
10198937Sdes#else
102181111Sdes	error("%s: file descriptor passing not supported", __func__);
103181111Sdes	return -1;
10498937Sdes#endif
10598675Sdes}
10698675Sdes
10798675Sdesint
108137015Sdesmm_receive_fd(int sock)
10998675Sdes{
11098937Sdes#if defined(HAVE_RECVMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
11198675Sdes	struct msghdr msg;
11298937Sdes#ifndef HAVE_ACCRIGHTS_IN_MSGHDR
113180989Sdes	union {
114180989Sdes		struct cmsghdr hdr;
115180989Sdes		char buf[CMSG_SPACE(sizeof(int))];
116180989Sdes	} cmsgbuf;
11798937Sdes	struct cmsghdr *cmsg;
11898937Sdes#endif
119192595Sdes	struct iovec vec;
120192595Sdes	ssize_t n;
121192595Sdes	char ch;
122192595Sdes	int fd;
123204917Sdes	struct pollfd pfd;
12498675Sdes
12598675Sdes	memset(&msg, 0, sizeof(msg));
12698675Sdes	vec.iov_base = &ch;
12798675Sdes	vec.iov_len = 1;
12898675Sdes	msg.msg_iov = &vec;
12998675Sdes	msg.msg_iovlen = 1;
13098937Sdes#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
13198937Sdes	msg.msg_accrights = (caddr_t)&fd;
13298937Sdes	msg.msg_accrightslen = sizeof(fd);
13398937Sdes#else
134180989Sdes	msg.msg_control = &cmsgbuf.buf;
135180989Sdes	msg.msg_controllen = sizeof(cmsgbuf.buf);
13698937Sdes#endif
13798675Sdes
138204917Sdes	pfd.fd = sock;
139204917Sdes	pfd.events = POLLIN;
140204917Sdes	while ((n = recvmsg(sock, &msg, 0)) == -1 &&
141204917Sdes	    (errno == EAGAIN || errno == EINTR)) {
142192595Sdes		debug3("%s: recvmsg: %s", __func__, strerror(errno));
143204917Sdes		(void)poll(&pfd, 1, -1);
144204917Sdes	}
145192595Sdes	if (n == -1) {
146181111Sdes		error("%s: recvmsg: %s", __func__, strerror(errno));
147181111Sdes		return -1;
148181111Sdes	}
149192595Sdes
150181111Sdes	if (n != 1) {
151181111Sdes		error("%s: recvmsg: expected received 1 got %ld",
152106121Sdes		    __func__, (long)n);
153181111Sdes		return -1;
154181111Sdes	}
15598675Sdes
15698937Sdes#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
157181111Sdes	if (msg.msg_accrightslen != sizeof(fd)) {
158181111Sdes		error("%s: no fd", __func__);
159181111Sdes		return -1;
160181111Sdes	}
16198937Sdes#else
16298675Sdes	cmsg = CMSG_FIRSTHDR(&msg);
163181111Sdes	if (cmsg == NULL) {
164181111Sdes		error("%s: no message header", __func__);
165181111Sdes		return -1;
166181111Sdes	}
167192595Sdes
168124208Sdes#ifndef BROKEN_CMSG_TYPE
169181111Sdes	if (cmsg->cmsg_type != SCM_RIGHTS) {
170181111Sdes		error("%s: expected type %d got %d", __func__,
17198675Sdes		    SCM_RIGHTS, cmsg->cmsg_type);
172181111Sdes		return -1;
173181111Sdes	}
174124208Sdes#endif
17598675Sdes	fd = (*(int *)CMSG_DATA(cmsg));
17698937Sdes#endif
17798675Sdes	return fd;
17898937Sdes#else
179181111Sdes	error("%s: file descriptor passing not supported", __func__);
180181111Sdes	return -1;
18198937Sdes#endif
18298675Sdes}
183