136da5199SPawel Jakub Dawidek /*- 25e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 35e53a4f9SPedro F. Giffuni * 436da5199SPawel Jakub Dawidek * Copyright (c) 2013 The FreeBSD Foundation 536da5199SPawel Jakub Dawidek * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org> 636da5199SPawel Jakub Dawidek * All rights reserved. 736da5199SPawel Jakub Dawidek * 836da5199SPawel Jakub Dawidek * This software was developed by Pawel Jakub Dawidek under sponsorship from 936da5199SPawel Jakub Dawidek * the FreeBSD Foundation. 1036da5199SPawel Jakub Dawidek * 1136da5199SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 1236da5199SPawel Jakub Dawidek * modification, are permitted provided that the following conditions 1336da5199SPawel Jakub Dawidek * are met: 1436da5199SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 1536da5199SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 1636da5199SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 1736da5199SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 1836da5199SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 1936da5199SPawel Jakub Dawidek * 2036da5199SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 2136da5199SPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2236da5199SPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2336da5199SPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 2436da5199SPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2536da5199SPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2636da5199SPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2736da5199SPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2836da5199SPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2936da5199SPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3036da5199SPawel Jakub Dawidek * SUCH DAMAGE. 3136da5199SPawel Jakub Dawidek */ 3236da5199SPawel Jakub Dawidek 3336da5199SPawel Jakub Dawidek #include <sys/cdefs.h> 3436da5199SPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 3536da5199SPawel Jakub Dawidek 36586c5854SPawel Jakub Dawidek #include <sys/param.h> 3736da5199SPawel Jakub Dawidek #include <sys/socket.h> 3836da5199SPawel Jakub Dawidek 3936da5199SPawel Jakub Dawidek #include <errno.h> 4036da5199SPawel Jakub Dawidek #include <fcntl.h> 4136da5199SPawel Jakub Dawidek #include <stdbool.h> 4236da5199SPawel Jakub Dawidek #include <stdint.h> 4336da5199SPawel Jakub Dawidek #include <stdlib.h> 4436da5199SPawel Jakub Dawidek #include <string.h> 4536da5199SPawel Jakub Dawidek #include <unistd.h> 4636da5199SPawel Jakub Dawidek 4736da5199SPawel Jakub Dawidek #ifdef HAVE_PJDLOG 4836da5199SPawel Jakub Dawidek #include <pjdlog.h> 4936da5199SPawel Jakub Dawidek #endif 5036da5199SPawel Jakub Dawidek 5136da5199SPawel Jakub Dawidek #include "common_impl.h" 5236da5199SPawel Jakub Dawidek #include "msgio.h" 5336da5199SPawel Jakub Dawidek 5436da5199SPawel Jakub Dawidek #ifndef HAVE_PJDLOG 5536da5199SPawel Jakub Dawidek #include <assert.h> 5636da5199SPawel Jakub Dawidek #define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 5736da5199SPawel Jakub Dawidek #define PJDLOG_RASSERT(expr, ...) assert(expr) 5836da5199SPawel Jakub Dawidek #define PJDLOG_ABORT(...) abort() 5936da5199SPawel Jakub Dawidek #endif 6036da5199SPawel Jakub Dawidek 61586c5854SPawel Jakub Dawidek #define PKG_MAX_SIZE (MCLBYTES / CMSG_SPACE(sizeof(int)) - 1) 62586c5854SPawel Jakub Dawidek 6336da5199SPawel Jakub Dawidek static int 6436da5199SPawel Jakub Dawidek msghdr_add_fd(struct cmsghdr *cmsg, int fd) 6536da5199SPawel Jakub Dawidek { 6636da5199SPawel Jakub Dawidek 6736da5199SPawel Jakub Dawidek PJDLOG_ASSERT(fd >= 0); 6836da5199SPawel Jakub Dawidek 6936da5199SPawel Jakub Dawidek cmsg->cmsg_level = SOL_SOCKET; 7036da5199SPawel Jakub Dawidek cmsg->cmsg_type = SCM_RIGHTS; 7136da5199SPawel Jakub Dawidek cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); 7236da5199SPawel Jakub Dawidek bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd)); 7336da5199SPawel Jakub Dawidek 7436da5199SPawel Jakub Dawidek return (0); 7536da5199SPawel Jakub Dawidek } 7636da5199SPawel Jakub Dawidek 7736da5199SPawel Jakub Dawidek static int 7836da5199SPawel Jakub Dawidek msghdr_get_fd(struct cmsghdr *cmsg) 7936da5199SPawel Jakub Dawidek { 8036da5199SPawel Jakub Dawidek int fd; 8136da5199SPawel Jakub Dawidek 8236da5199SPawel Jakub Dawidek if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET || 8336da5199SPawel Jakub Dawidek cmsg->cmsg_type != SCM_RIGHTS || 8436da5199SPawel Jakub Dawidek cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) { 8536da5199SPawel Jakub Dawidek errno = EINVAL; 8636da5199SPawel Jakub Dawidek return (-1); 8736da5199SPawel Jakub Dawidek } 8836da5199SPawel Jakub Dawidek 8936da5199SPawel Jakub Dawidek bcopy(CMSG_DATA(cmsg), &fd, sizeof(fd)); 9036da5199SPawel Jakub Dawidek #ifndef MSG_CMSG_CLOEXEC 9136da5199SPawel Jakub Dawidek /* 9236da5199SPawel Jakub Dawidek * If the MSG_CMSG_CLOEXEC flag is not available we cannot set the 9336da5199SPawel Jakub Dawidek * close-on-exec flag atomically, but we still want to set it for 9436da5199SPawel Jakub Dawidek * consistency. 9536da5199SPawel Jakub Dawidek */ 9636da5199SPawel Jakub Dawidek (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 9736da5199SPawel Jakub Dawidek #endif 9836da5199SPawel Jakub Dawidek 9936da5199SPawel Jakub Dawidek return (fd); 10036da5199SPawel Jakub Dawidek } 10136da5199SPawel Jakub Dawidek 10236da5199SPawel Jakub Dawidek static void 10336da5199SPawel Jakub Dawidek fd_wait(int fd, bool doread) 10436da5199SPawel Jakub Dawidek { 10536da5199SPawel Jakub Dawidek fd_set fds; 10636da5199SPawel Jakub Dawidek 10736da5199SPawel Jakub Dawidek PJDLOG_ASSERT(fd >= 0); 10836da5199SPawel Jakub Dawidek 10936da5199SPawel Jakub Dawidek FD_ZERO(&fds); 11036da5199SPawel Jakub Dawidek FD_SET(fd, &fds); 11136da5199SPawel Jakub Dawidek (void)select(fd + 1, doread ? &fds : NULL, doread ? NULL : &fds, 11236da5199SPawel Jakub Dawidek NULL, NULL); 11336da5199SPawel Jakub Dawidek } 11436da5199SPawel Jakub Dawidek 11536da5199SPawel Jakub Dawidek static int 11636da5199SPawel Jakub Dawidek msg_recv(int sock, struct msghdr *msg) 11736da5199SPawel Jakub Dawidek { 11836da5199SPawel Jakub Dawidek int flags; 11936da5199SPawel Jakub Dawidek 12036da5199SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 12136da5199SPawel Jakub Dawidek 12236da5199SPawel Jakub Dawidek #ifdef MSG_CMSG_CLOEXEC 12336da5199SPawel Jakub Dawidek flags = MSG_CMSG_CLOEXEC; 12436da5199SPawel Jakub Dawidek #else 12536da5199SPawel Jakub Dawidek flags = 0; 12636da5199SPawel Jakub Dawidek #endif 12736da5199SPawel Jakub Dawidek 12836da5199SPawel Jakub Dawidek for (;;) { 12936da5199SPawel Jakub Dawidek fd_wait(sock, true); 13036da5199SPawel Jakub Dawidek if (recvmsg(sock, msg, flags) == -1) { 13136da5199SPawel Jakub Dawidek if (errno == EINTR) 13236da5199SPawel Jakub Dawidek continue; 13336da5199SPawel Jakub Dawidek return (-1); 13436da5199SPawel Jakub Dawidek } 13536da5199SPawel Jakub Dawidek break; 13636da5199SPawel Jakub Dawidek } 13736da5199SPawel Jakub Dawidek 13836da5199SPawel Jakub Dawidek return (0); 13936da5199SPawel Jakub Dawidek } 14036da5199SPawel Jakub Dawidek 14136da5199SPawel Jakub Dawidek static int 14236da5199SPawel Jakub Dawidek msg_send(int sock, const struct msghdr *msg) 14336da5199SPawel Jakub Dawidek { 14436da5199SPawel Jakub Dawidek 14536da5199SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 14636da5199SPawel Jakub Dawidek 14736da5199SPawel Jakub Dawidek for (;;) { 14836da5199SPawel Jakub Dawidek fd_wait(sock, false); 14936da5199SPawel Jakub Dawidek if (sendmsg(sock, msg, 0) == -1) { 15036da5199SPawel Jakub Dawidek if (errno == EINTR) 15136da5199SPawel Jakub Dawidek continue; 15236da5199SPawel Jakub Dawidek return (-1); 15336da5199SPawel Jakub Dawidek } 15436da5199SPawel Jakub Dawidek break; 15536da5199SPawel Jakub Dawidek } 15636da5199SPawel Jakub Dawidek 15736da5199SPawel Jakub Dawidek return (0); 15836da5199SPawel Jakub Dawidek } 15936da5199SPawel Jakub Dawidek 160*032f0fbbSAlex Richardson /* 161*032f0fbbSAlex Richardson * MacOS/Linux do not define struct cmsgcred but we need to bootstrap libnv 162*032f0fbbSAlex Richardson * when building on non-FreeBSD systems. Since they are not used during 163*032f0fbbSAlex Richardson * bootstrap we can just omit these two functions there. 164*032f0fbbSAlex Richardson */ 165*032f0fbbSAlex Richardson #ifndef __FreeBSD__ 166*032f0fbbSAlex Richardson #warning "cred_send() not supported on non-FreeBSD systems" 167*032f0fbbSAlex Richardson #else 16836da5199SPawel Jakub Dawidek int 16936da5199SPawel Jakub Dawidek cred_send(int sock) 17036da5199SPawel Jakub Dawidek { 17136da5199SPawel Jakub Dawidek unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))]; 17236da5199SPawel Jakub Dawidek struct msghdr msg; 17336da5199SPawel Jakub Dawidek struct cmsghdr *cmsg; 17436da5199SPawel Jakub Dawidek struct iovec iov; 17536da5199SPawel Jakub Dawidek uint8_t dummy; 17636da5199SPawel Jakub Dawidek 17736da5199SPawel Jakub Dawidek bzero(credbuf, sizeof(credbuf)); 17836da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg)); 17936da5199SPawel Jakub Dawidek bzero(&iov, sizeof(iov)); 18036da5199SPawel Jakub Dawidek 18136da5199SPawel Jakub Dawidek /* 18236da5199SPawel Jakub Dawidek * XXX: We send one byte along with the control message, because 18336da5199SPawel Jakub Dawidek * setting msg_iov to NULL only works if this is the first 18436da5199SPawel Jakub Dawidek * packet send over the socket. Once we send some data we 18536da5199SPawel Jakub Dawidek * won't be able to send credentials anymore. This is most 18636da5199SPawel Jakub Dawidek * likely a kernel bug. 18736da5199SPawel Jakub Dawidek */ 18836da5199SPawel Jakub Dawidek dummy = 0; 18936da5199SPawel Jakub Dawidek iov.iov_base = &dummy; 19036da5199SPawel Jakub Dawidek iov.iov_len = sizeof(dummy); 19136da5199SPawel Jakub Dawidek 19236da5199SPawel Jakub Dawidek msg.msg_iov = &iov; 19336da5199SPawel Jakub Dawidek msg.msg_iovlen = 1; 19436da5199SPawel Jakub Dawidek msg.msg_control = credbuf; 19536da5199SPawel Jakub Dawidek msg.msg_controllen = sizeof(credbuf); 19636da5199SPawel Jakub Dawidek 19736da5199SPawel Jakub Dawidek cmsg = CMSG_FIRSTHDR(&msg); 19836da5199SPawel Jakub Dawidek cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); 19936da5199SPawel Jakub Dawidek cmsg->cmsg_level = SOL_SOCKET; 20036da5199SPawel Jakub Dawidek cmsg->cmsg_type = SCM_CREDS; 20136da5199SPawel Jakub Dawidek 20236da5199SPawel Jakub Dawidek if (msg_send(sock, &msg) == -1) 20336da5199SPawel Jakub Dawidek return (-1); 20436da5199SPawel Jakub Dawidek 20536da5199SPawel Jakub Dawidek return (0); 20636da5199SPawel Jakub Dawidek } 20736da5199SPawel Jakub Dawidek 20836da5199SPawel Jakub Dawidek int 20936da5199SPawel Jakub Dawidek cred_recv(int sock, struct cmsgcred *cred) 21036da5199SPawel Jakub Dawidek { 21136da5199SPawel Jakub Dawidek unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))]; 21236da5199SPawel Jakub Dawidek struct msghdr msg; 21336da5199SPawel Jakub Dawidek struct cmsghdr *cmsg; 21436da5199SPawel Jakub Dawidek struct iovec iov; 21536da5199SPawel Jakub Dawidek uint8_t dummy; 21636da5199SPawel Jakub Dawidek 21736da5199SPawel Jakub Dawidek bzero(credbuf, sizeof(credbuf)); 21836da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg)); 21936da5199SPawel Jakub Dawidek bzero(&iov, sizeof(iov)); 22036da5199SPawel Jakub Dawidek 22136da5199SPawel Jakub Dawidek iov.iov_base = &dummy; 22236da5199SPawel Jakub Dawidek iov.iov_len = sizeof(dummy); 22336da5199SPawel Jakub Dawidek 22436da5199SPawel Jakub Dawidek msg.msg_iov = &iov; 22536da5199SPawel Jakub Dawidek msg.msg_iovlen = 1; 22636da5199SPawel Jakub Dawidek msg.msg_control = credbuf; 22736da5199SPawel Jakub Dawidek msg.msg_controllen = sizeof(credbuf); 22836da5199SPawel Jakub Dawidek 22936da5199SPawel Jakub Dawidek if (msg_recv(sock, &msg) == -1) 23036da5199SPawel Jakub Dawidek return (-1); 23136da5199SPawel Jakub Dawidek 23236da5199SPawel Jakub Dawidek cmsg = CMSG_FIRSTHDR(&msg); 23336da5199SPawel Jakub Dawidek if (cmsg == NULL || 23436da5199SPawel Jakub Dawidek cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) || 23536da5199SPawel Jakub Dawidek cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) { 23636da5199SPawel Jakub Dawidek errno = EINVAL; 23736da5199SPawel Jakub Dawidek return (-1); 23836da5199SPawel Jakub Dawidek } 23936da5199SPawel Jakub Dawidek bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred)); 24036da5199SPawel Jakub Dawidek 24136da5199SPawel Jakub Dawidek return (0); 24236da5199SPawel Jakub Dawidek } 243*032f0fbbSAlex Richardson #endif 24436da5199SPawel Jakub Dawidek 245586c5854SPawel Jakub Dawidek static int 246586c5854SPawel Jakub Dawidek fd_package_send(int sock, const int *fds, size_t nfds) 24736da5199SPawel Jakub Dawidek { 24836da5199SPawel Jakub Dawidek struct msghdr msg; 24936da5199SPawel Jakub Dawidek struct cmsghdr *cmsg; 250586c5854SPawel Jakub Dawidek struct iovec iov; 25136da5199SPawel Jakub Dawidek unsigned int i; 25236da5199SPawel Jakub Dawidek int serrno, ret; 253586c5854SPawel Jakub Dawidek uint8_t dummy; 25436da5199SPawel Jakub Dawidek 255586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 256586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(fds != NULL); 257586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(nfds > 0); 25836da5199SPawel Jakub Dawidek 25936da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg)); 260586c5854SPawel Jakub Dawidek 261586c5854SPawel Jakub Dawidek /* 262586c5854SPawel Jakub Dawidek * XXX: Look into cred_send function for more details. 263586c5854SPawel Jakub Dawidek */ 264586c5854SPawel Jakub Dawidek dummy = 0; 265586c5854SPawel Jakub Dawidek iov.iov_base = &dummy; 266586c5854SPawel Jakub Dawidek iov.iov_len = sizeof(dummy); 267586c5854SPawel Jakub Dawidek 268586c5854SPawel Jakub Dawidek msg.msg_iov = &iov; 269586c5854SPawel Jakub Dawidek msg.msg_iovlen = 1; 27036da5199SPawel Jakub Dawidek msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int)); 27136da5199SPawel Jakub Dawidek msg.msg_control = calloc(1, msg.msg_controllen); 27236da5199SPawel Jakub Dawidek if (msg.msg_control == NULL) 27336da5199SPawel Jakub Dawidek return (-1); 27436da5199SPawel Jakub Dawidek 27536da5199SPawel Jakub Dawidek ret = -1; 27636da5199SPawel Jakub Dawidek 27736da5199SPawel Jakub Dawidek for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL; 27836da5199SPawel Jakub Dawidek i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) { 27936da5199SPawel Jakub Dawidek if (msghdr_add_fd(cmsg, fds[i]) == -1) 28036da5199SPawel Jakub Dawidek goto end; 28136da5199SPawel Jakub Dawidek } 28236da5199SPawel Jakub Dawidek 28336da5199SPawel Jakub Dawidek if (msg_send(sock, &msg) == -1) 28436da5199SPawel Jakub Dawidek goto end; 28536da5199SPawel Jakub Dawidek 28636da5199SPawel Jakub Dawidek ret = 0; 28736da5199SPawel Jakub Dawidek end: 28836da5199SPawel Jakub Dawidek serrno = errno; 28936da5199SPawel Jakub Dawidek free(msg.msg_control); 29036da5199SPawel Jakub Dawidek errno = serrno; 29136da5199SPawel Jakub Dawidek return (ret); 29236da5199SPawel Jakub Dawidek } 29336da5199SPawel Jakub Dawidek 294586c5854SPawel Jakub Dawidek static int 295586c5854SPawel Jakub Dawidek fd_package_recv(int sock, int *fds, size_t nfds) 29636da5199SPawel Jakub Dawidek { 29736da5199SPawel Jakub Dawidek struct msghdr msg; 29836da5199SPawel Jakub Dawidek struct cmsghdr *cmsg; 29936da5199SPawel Jakub Dawidek unsigned int i; 30036da5199SPawel Jakub Dawidek int serrno, ret; 301586c5854SPawel Jakub Dawidek struct iovec iov; 302586c5854SPawel Jakub Dawidek uint8_t dummy; 30336da5199SPawel Jakub Dawidek 304586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 305586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(nfds > 0); 306586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(fds != NULL); 30736da5199SPawel Jakub Dawidek 30836da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg)); 309586c5854SPawel Jakub Dawidek bzero(&iov, sizeof(iov)); 310586c5854SPawel Jakub Dawidek 311586c5854SPawel Jakub Dawidek /* 312586c5854SPawel Jakub Dawidek * XXX: Look into cred_send function for more details. 313586c5854SPawel Jakub Dawidek */ 314586c5854SPawel Jakub Dawidek iov.iov_base = &dummy; 315586c5854SPawel Jakub Dawidek iov.iov_len = sizeof(dummy); 316586c5854SPawel Jakub Dawidek 317586c5854SPawel Jakub Dawidek msg.msg_iov = &iov; 318586c5854SPawel Jakub Dawidek msg.msg_iovlen = 1; 31936da5199SPawel Jakub Dawidek msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int)); 32036da5199SPawel Jakub Dawidek msg.msg_control = calloc(1, msg.msg_controllen); 32136da5199SPawel Jakub Dawidek if (msg.msg_control == NULL) 32236da5199SPawel Jakub Dawidek return (-1); 32336da5199SPawel Jakub Dawidek 32436da5199SPawel Jakub Dawidek ret = -1; 32536da5199SPawel Jakub Dawidek 32636da5199SPawel Jakub Dawidek if (msg_recv(sock, &msg) == -1) 32736da5199SPawel Jakub Dawidek goto end; 32836da5199SPawel Jakub Dawidek 32936da5199SPawel Jakub Dawidek for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL; 33036da5199SPawel Jakub Dawidek i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) { 33136da5199SPawel Jakub Dawidek fds[i] = msghdr_get_fd(cmsg); 33236da5199SPawel Jakub Dawidek if (fds[i] < 0) 33336da5199SPawel Jakub Dawidek break; 33436da5199SPawel Jakub Dawidek } 33536da5199SPawel Jakub Dawidek 33636da5199SPawel Jakub Dawidek if (cmsg != NULL || i < nfds) { 33736da5199SPawel Jakub Dawidek int fd; 33836da5199SPawel Jakub Dawidek 33936da5199SPawel Jakub Dawidek /* 34036da5199SPawel Jakub Dawidek * We need to close all received descriptors, even if we have 34136da5199SPawel Jakub Dawidek * different control message (eg. SCM_CREDS) in between. 34236da5199SPawel Jakub Dawidek */ 34336da5199SPawel Jakub Dawidek for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 34436da5199SPawel Jakub Dawidek cmsg = CMSG_NXTHDR(&msg, cmsg)) { 34536da5199SPawel Jakub Dawidek fd = msghdr_get_fd(cmsg); 34636da5199SPawel Jakub Dawidek if (fd >= 0) 34736da5199SPawel Jakub Dawidek close(fd); 34836da5199SPawel Jakub Dawidek } 34936da5199SPawel Jakub Dawidek errno = EINVAL; 35036da5199SPawel Jakub Dawidek goto end; 35136da5199SPawel Jakub Dawidek } 35236da5199SPawel Jakub Dawidek 35336da5199SPawel Jakub Dawidek ret = 0; 35436da5199SPawel Jakub Dawidek end: 35536da5199SPawel Jakub Dawidek serrno = errno; 35636da5199SPawel Jakub Dawidek free(msg.msg_control); 35736da5199SPawel Jakub Dawidek errno = serrno; 35836da5199SPawel Jakub Dawidek return (ret); 35936da5199SPawel Jakub Dawidek } 36036da5199SPawel Jakub Dawidek 36136da5199SPawel Jakub Dawidek int 362586c5854SPawel Jakub Dawidek fd_recv(int sock, int *fds, size_t nfds) 363586c5854SPawel Jakub Dawidek { 364586c5854SPawel Jakub Dawidek unsigned int i, step, j; 365586c5854SPawel Jakub Dawidek int ret, serrno; 366586c5854SPawel Jakub Dawidek 367586c5854SPawel Jakub Dawidek if (nfds == 0 || fds == NULL) { 368586c5854SPawel Jakub Dawidek errno = EINVAL; 369586c5854SPawel Jakub Dawidek return (-1); 370586c5854SPawel Jakub Dawidek } 371586c5854SPawel Jakub Dawidek 372586c5854SPawel Jakub Dawidek ret = i = step = 0; 373586c5854SPawel Jakub Dawidek while (i < nfds) { 374586c5854SPawel Jakub Dawidek if (PKG_MAX_SIZE < nfds - i) 375586c5854SPawel Jakub Dawidek step = PKG_MAX_SIZE; 376586c5854SPawel Jakub Dawidek else 377586c5854SPawel Jakub Dawidek step = nfds - i; 378586c5854SPawel Jakub Dawidek ret = fd_package_recv(sock, fds + i, step); 379586c5854SPawel Jakub Dawidek if (ret != 0) { 380586c5854SPawel Jakub Dawidek /* Close all received descriptors. */ 381586c5854SPawel Jakub Dawidek serrno = errno; 382586c5854SPawel Jakub Dawidek for (j = 0; j < i; j++) 383586c5854SPawel Jakub Dawidek close(fds[j]); 384586c5854SPawel Jakub Dawidek errno = serrno; 385586c5854SPawel Jakub Dawidek break; 386586c5854SPawel Jakub Dawidek } 387586c5854SPawel Jakub Dawidek i += step; 388586c5854SPawel Jakub Dawidek } 389586c5854SPawel Jakub Dawidek 390586c5854SPawel Jakub Dawidek return (ret); 391586c5854SPawel Jakub Dawidek } 392586c5854SPawel Jakub Dawidek 393586c5854SPawel Jakub Dawidek int 394586c5854SPawel Jakub Dawidek fd_send(int sock, const int *fds, size_t nfds) 395586c5854SPawel Jakub Dawidek { 396586c5854SPawel Jakub Dawidek unsigned int i, step; 397586c5854SPawel Jakub Dawidek int ret; 398586c5854SPawel Jakub Dawidek 399586c5854SPawel Jakub Dawidek if (nfds == 0 || fds == NULL) { 400586c5854SPawel Jakub Dawidek errno = EINVAL; 401586c5854SPawel Jakub Dawidek return (-1); 402586c5854SPawel Jakub Dawidek } 403586c5854SPawel Jakub Dawidek 404586c5854SPawel Jakub Dawidek ret = i = step = 0; 405586c5854SPawel Jakub Dawidek while (i < nfds) { 406586c5854SPawel Jakub Dawidek if (PKG_MAX_SIZE < nfds - i) 407586c5854SPawel Jakub Dawidek step = PKG_MAX_SIZE; 408586c5854SPawel Jakub Dawidek else 409586c5854SPawel Jakub Dawidek step = nfds - i; 410586c5854SPawel Jakub Dawidek ret = fd_package_send(sock, fds + i, step); 411586c5854SPawel Jakub Dawidek if (ret != 0) 412586c5854SPawel Jakub Dawidek break; 413586c5854SPawel Jakub Dawidek i += step; 414586c5854SPawel Jakub Dawidek } 415586c5854SPawel Jakub Dawidek 416586c5854SPawel Jakub Dawidek return (ret); 417586c5854SPawel Jakub Dawidek } 418586c5854SPawel Jakub Dawidek 419586c5854SPawel Jakub Dawidek int 42036da5199SPawel Jakub Dawidek buf_send(int sock, void *buf, size_t size) 42136da5199SPawel Jakub Dawidek { 42236da5199SPawel Jakub Dawidek ssize_t done; 42336da5199SPawel Jakub Dawidek unsigned char *ptr; 42436da5199SPawel Jakub Dawidek 4253d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 4263d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(size > 0); 4273d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(buf != NULL); 4283d34eceaSPawel Jakub Dawidek 42936da5199SPawel Jakub Dawidek ptr = buf; 43036da5199SPawel Jakub Dawidek do { 43136da5199SPawel Jakub Dawidek fd_wait(sock, false); 43236da5199SPawel Jakub Dawidek done = send(sock, ptr, size, 0); 43336da5199SPawel Jakub Dawidek if (done == -1) { 43436da5199SPawel Jakub Dawidek if (errno == EINTR) 43536da5199SPawel Jakub Dawidek continue; 43636da5199SPawel Jakub Dawidek return (-1); 43736da5199SPawel Jakub Dawidek } else if (done == 0) { 43836da5199SPawel Jakub Dawidek errno = ENOTCONN; 43936da5199SPawel Jakub Dawidek return (-1); 44036da5199SPawel Jakub Dawidek } 44136da5199SPawel Jakub Dawidek size -= done; 44236da5199SPawel Jakub Dawidek ptr += done; 44336da5199SPawel Jakub Dawidek } while (size > 0); 44436da5199SPawel Jakub Dawidek 44536da5199SPawel Jakub Dawidek return (0); 44636da5199SPawel Jakub Dawidek } 44736da5199SPawel Jakub Dawidek 44836da5199SPawel Jakub Dawidek int 44936da5199SPawel Jakub Dawidek buf_recv(int sock, void *buf, size_t size) 45036da5199SPawel Jakub Dawidek { 45136da5199SPawel Jakub Dawidek ssize_t done; 45236da5199SPawel Jakub Dawidek unsigned char *ptr; 45336da5199SPawel Jakub Dawidek 4543d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 4553d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(buf != NULL); 4563d34eceaSPawel Jakub Dawidek 45736da5199SPawel Jakub Dawidek ptr = buf; 4587f7fe890SPawel Jakub Dawidek while (size > 0) { 45936da5199SPawel Jakub Dawidek fd_wait(sock, true); 46036da5199SPawel Jakub Dawidek done = recv(sock, ptr, size, 0); 46136da5199SPawel Jakub Dawidek if (done == -1) { 46236da5199SPawel Jakub Dawidek if (errno == EINTR) 46336da5199SPawel Jakub Dawidek continue; 46436da5199SPawel Jakub Dawidek return (-1); 46536da5199SPawel Jakub Dawidek } else if (done == 0) { 46636da5199SPawel Jakub Dawidek errno = ENOTCONN; 46736da5199SPawel Jakub Dawidek return (-1); 46836da5199SPawel Jakub Dawidek } 46936da5199SPawel Jakub Dawidek size -= done; 47036da5199SPawel Jakub Dawidek ptr += done; 4717f7fe890SPawel Jakub Dawidek } 47236da5199SPawel Jakub Dawidek 47336da5199SPawel Jakub Dawidek return (0); 47436da5199SPawel Jakub Dawidek } 475