136da5199SPawel Jakub Dawidek /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 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> 383810ba1bSMariusz Zaborski #include <sys/select.h> 3936da5199SPawel Jakub Dawidek 4036da5199SPawel Jakub Dawidek #include <errno.h> 4136da5199SPawel Jakub Dawidek #include <fcntl.h> 4236da5199SPawel Jakub Dawidek #include <stdbool.h> 4336da5199SPawel Jakub Dawidek #include <stdint.h> 4436da5199SPawel Jakub Dawidek #include <stdlib.h> 4536da5199SPawel Jakub Dawidek #include <string.h> 4636da5199SPawel Jakub Dawidek #include <unistd.h> 4736da5199SPawel Jakub Dawidek 4836da5199SPawel Jakub Dawidek #ifdef HAVE_PJDLOG 4936da5199SPawel Jakub Dawidek #include <pjdlog.h> 5036da5199SPawel Jakub Dawidek #endif 5136da5199SPawel Jakub Dawidek 5236da5199SPawel Jakub Dawidek #include "common_impl.h" 5336da5199SPawel Jakub Dawidek #include "msgio.h" 5436da5199SPawel Jakub Dawidek 5536da5199SPawel Jakub Dawidek #ifndef HAVE_PJDLOG 5636da5199SPawel Jakub Dawidek #include <assert.h> 5736da5199SPawel Jakub Dawidek #define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 5836da5199SPawel Jakub Dawidek #define PJDLOG_RASSERT(expr, ...) assert(expr) 5936da5199SPawel Jakub Dawidek #define PJDLOG_ABORT(...) abort() 6036da5199SPawel Jakub Dawidek #endif 6136da5199SPawel Jakub Dawidek 623810ba1bSMariusz Zaborski #ifdef __linux__ 633810ba1bSMariusz Zaborski /* Linux: arbitrary size, but must be lower than SCM_MAX_FD. */ 643810ba1bSMariusz Zaborski #define PKG_MAX_SIZE ((64U - 1) * CMSG_SPACE(sizeof(int))) 653810ba1bSMariusz Zaborski #else 6607cf2bb6SMark Johnston /* 6707cf2bb6SMark Johnston * To work around limitations in 32-bit emulation on 64-bit kernels, use a 6807cf2bb6SMark Johnston * machine-independent limit on the number of FDs per message. Each control 6907cf2bb6SMark Johnston * message contains 1 FD and requires 12 bytes for the header, 4 pad bytes, 7007cf2bb6SMark Johnston * 4 bytes for the descriptor, and another 4 pad bytes. 7107cf2bb6SMark Johnston */ 7207cf2bb6SMark Johnston #define PKG_MAX_SIZE (MCLBYTES / 24) 733810ba1bSMariusz Zaborski #endif 74586c5854SPawel Jakub Dawidek 7536da5199SPawel Jakub Dawidek static int 7636da5199SPawel Jakub Dawidek msghdr_add_fd(struct cmsghdr *cmsg, int fd) 7736da5199SPawel Jakub Dawidek { 7836da5199SPawel Jakub Dawidek 7936da5199SPawel Jakub Dawidek PJDLOG_ASSERT(fd >= 0); 8036da5199SPawel Jakub Dawidek 8136da5199SPawel Jakub Dawidek cmsg->cmsg_level = SOL_SOCKET; 8236da5199SPawel Jakub Dawidek cmsg->cmsg_type = SCM_RIGHTS; 8336da5199SPawel Jakub Dawidek cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); 8436da5199SPawel Jakub Dawidek bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd)); 8536da5199SPawel Jakub Dawidek 8636da5199SPawel Jakub Dawidek return (0); 8736da5199SPawel Jakub Dawidek } 8836da5199SPawel Jakub Dawidek 8936da5199SPawel Jakub Dawidek static void 9036da5199SPawel Jakub Dawidek fd_wait(int fd, bool doread) 9136da5199SPawel Jakub Dawidek { 9236da5199SPawel Jakub Dawidek fd_set fds; 9336da5199SPawel Jakub Dawidek 9436da5199SPawel Jakub Dawidek PJDLOG_ASSERT(fd >= 0); 9536da5199SPawel Jakub Dawidek 9636da5199SPawel Jakub Dawidek FD_ZERO(&fds); 9736da5199SPawel Jakub Dawidek FD_SET(fd, &fds); 9836da5199SPawel Jakub Dawidek (void)select(fd + 1, doread ? &fds : NULL, doread ? NULL : &fds, 9936da5199SPawel Jakub Dawidek NULL, NULL); 10036da5199SPawel Jakub Dawidek } 10136da5199SPawel Jakub Dawidek 10236da5199SPawel Jakub Dawidek static int 10336da5199SPawel Jakub Dawidek msg_recv(int sock, struct msghdr *msg) 10436da5199SPawel Jakub Dawidek { 10536da5199SPawel Jakub Dawidek int flags; 10636da5199SPawel Jakub Dawidek 10736da5199SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 10836da5199SPawel Jakub Dawidek 10936da5199SPawel Jakub Dawidek #ifdef MSG_CMSG_CLOEXEC 11036da5199SPawel Jakub Dawidek flags = MSG_CMSG_CLOEXEC; 11136da5199SPawel Jakub Dawidek #else 11236da5199SPawel Jakub Dawidek flags = 0; 11336da5199SPawel Jakub Dawidek #endif 11436da5199SPawel Jakub Dawidek 11536da5199SPawel Jakub Dawidek for (;;) { 11636da5199SPawel Jakub Dawidek fd_wait(sock, true); 11736da5199SPawel Jakub Dawidek if (recvmsg(sock, msg, flags) == -1) { 11836da5199SPawel Jakub Dawidek if (errno == EINTR) 11936da5199SPawel Jakub Dawidek continue; 12036da5199SPawel Jakub Dawidek return (-1); 12136da5199SPawel Jakub Dawidek } 12236da5199SPawel Jakub Dawidek break; 12336da5199SPawel Jakub Dawidek } 12436da5199SPawel Jakub Dawidek 12536da5199SPawel Jakub Dawidek return (0); 12636da5199SPawel Jakub Dawidek } 12736da5199SPawel Jakub Dawidek 12836da5199SPawel Jakub Dawidek static int 12936da5199SPawel Jakub Dawidek msg_send(int sock, const struct msghdr *msg) 13036da5199SPawel Jakub Dawidek { 13136da5199SPawel Jakub Dawidek 13236da5199SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 13336da5199SPawel Jakub Dawidek 13436da5199SPawel Jakub Dawidek for (;;) { 13536da5199SPawel Jakub Dawidek fd_wait(sock, false); 13636da5199SPawel Jakub Dawidek if (sendmsg(sock, msg, 0) == -1) { 13736da5199SPawel Jakub Dawidek if (errno == EINTR) 13836da5199SPawel Jakub Dawidek continue; 13936da5199SPawel Jakub Dawidek return (-1); 14036da5199SPawel Jakub Dawidek } 14136da5199SPawel Jakub Dawidek break; 14236da5199SPawel Jakub Dawidek } 14336da5199SPawel Jakub Dawidek 14436da5199SPawel Jakub Dawidek return (0); 14536da5199SPawel Jakub Dawidek } 14636da5199SPawel Jakub Dawidek 1473810ba1bSMariusz Zaborski #ifdef __FreeBSD__ 14836da5199SPawel Jakub Dawidek int 14936da5199SPawel Jakub Dawidek cred_send(int sock) 15036da5199SPawel Jakub Dawidek { 15136da5199SPawel Jakub Dawidek unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))]; 15236da5199SPawel Jakub Dawidek struct msghdr msg; 15336da5199SPawel Jakub Dawidek struct cmsghdr *cmsg; 15436da5199SPawel Jakub Dawidek struct iovec iov; 15536da5199SPawel Jakub Dawidek uint8_t dummy; 15636da5199SPawel Jakub Dawidek 15736da5199SPawel Jakub Dawidek bzero(credbuf, sizeof(credbuf)); 15836da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg)); 15936da5199SPawel Jakub Dawidek bzero(&iov, sizeof(iov)); 16036da5199SPawel Jakub Dawidek 16136da5199SPawel Jakub Dawidek /* 16236da5199SPawel Jakub Dawidek * XXX: We send one byte along with the control message, because 16336da5199SPawel Jakub Dawidek * setting msg_iov to NULL only works if this is the first 16436da5199SPawel Jakub Dawidek * packet send over the socket. Once we send some data we 16536da5199SPawel Jakub Dawidek * won't be able to send credentials anymore. This is most 16636da5199SPawel Jakub Dawidek * likely a kernel bug. 16736da5199SPawel Jakub Dawidek */ 16836da5199SPawel Jakub Dawidek dummy = 0; 16936da5199SPawel Jakub Dawidek iov.iov_base = &dummy; 17036da5199SPawel Jakub Dawidek iov.iov_len = sizeof(dummy); 17136da5199SPawel Jakub Dawidek 17236da5199SPawel Jakub Dawidek msg.msg_iov = &iov; 17336da5199SPawel Jakub Dawidek msg.msg_iovlen = 1; 17436da5199SPawel Jakub Dawidek msg.msg_control = credbuf; 17536da5199SPawel Jakub Dawidek msg.msg_controllen = sizeof(credbuf); 17636da5199SPawel Jakub Dawidek 17736da5199SPawel Jakub Dawidek cmsg = CMSG_FIRSTHDR(&msg); 17836da5199SPawel Jakub Dawidek cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); 17936da5199SPawel Jakub Dawidek cmsg->cmsg_level = SOL_SOCKET; 18036da5199SPawel Jakub Dawidek cmsg->cmsg_type = SCM_CREDS; 18136da5199SPawel Jakub Dawidek 18236da5199SPawel Jakub Dawidek if (msg_send(sock, &msg) == -1) 18336da5199SPawel Jakub Dawidek return (-1); 18436da5199SPawel Jakub Dawidek 18536da5199SPawel Jakub Dawidek return (0); 18636da5199SPawel Jakub Dawidek } 18736da5199SPawel Jakub Dawidek 18836da5199SPawel Jakub Dawidek int 18936da5199SPawel Jakub Dawidek cred_recv(int sock, struct cmsgcred *cred) 19036da5199SPawel Jakub Dawidek { 19136da5199SPawel Jakub Dawidek unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))]; 19236da5199SPawel Jakub Dawidek struct msghdr msg; 19336da5199SPawel Jakub Dawidek struct cmsghdr *cmsg; 19436da5199SPawel Jakub Dawidek struct iovec iov; 19536da5199SPawel Jakub Dawidek uint8_t dummy; 19636da5199SPawel Jakub Dawidek 19736da5199SPawel Jakub Dawidek bzero(credbuf, sizeof(credbuf)); 19836da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg)); 19936da5199SPawel Jakub Dawidek bzero(&iov, sizeof(iov)); 20036da5199SPawel Jakub Dawidek 20136da5199SPawel Jakub Dawidek iov.iov_base = &dummy; 20236da5199SPawel Jakub Dawidek iov.iov_len = sizeof(dummy); 20336da5199SPawel Jakub Dawidek 20436da5199SPawel Jakub Dawidek msg.msg_iov = &iov; 20536da5199SPawel Jakub Dawidek msg.msg_iovlen = 1; 20636da5199SPawel Jakub Dawidek msg.msg_control = credbuf; 20736da5199SPawel Jakub Dawidek msg.msg_controllen = sizeof(credbuf); 20836da5199SPawel Jakub Dawidek 20936da5199SPawel Jakub Dawidek if (msg_recv(sock, &msg) == -1) 21036da5199SPawel Jakub Dawidek return (-1); 21136da5199SPawel Jakub Dawidek 21236da5199SPawel Jakub Dawidek cmsg = CMSG_FIRSTHDR(&msg); 21336da5199SPawel Jakub Dawidek if (cmsg == NULL || 21436da5199SPawel Jakub Dawidek cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) || 21536da5199SPawel Jakub Dawidek cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) { 21636da5199SPawel Jakub Dawidek errno = EINVAL; 21736da5199SPawel Jakub Dawidek return (-1); 21836da5199SPawel Jakub Dawidek } 21936da5199SPawel Jakub Dawidek bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred)); 22036da5199SPawel Jakub Dawidek 22136da5199SPawel Jakub Dawidek return (0); 22236da5199SPawel Jakub Dawidek } 223032f0fbbSAlex Richardson #endif 22436da5199SPawel Jakub Dawidek 225586c5854SPawel Jakub Dawidek static int 226586c5854SPawel Jakub Dawidek fd_package_send(int sock, const int *fds, size_t nfds) 22736da5199SPawel Jakub Dawidek { 22836da5199SPawel Jakub Dawidek struct msghdr msg; 22936da5199SPawel Jakub Dawidek struct cmsghdr *cmsg; 230586c5854SPawel Jakub Dawidek struct iovec iov; 23136da5199SPawel Jakub Dawidek unsigned int i; 23236da5199SPawel Jakub Dawidek int serrno, ret; 233586c5854SPawel Jakub Dawidek uint8_t dummy; 23436da5199SPawel Jakub Dawidek 235586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 236586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(fds != NULL); 237586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(nfds > 0); 23836da5199SPawel Jakub Dawidek 23936da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg)); 240586c5854SPawel Jakub Dawidek 241586c5854SPawel Jakub Dawidek /* 242586c5854SPawel Jakub Dawidek * XXX: Look into cred_send function for more details. 243586c5854SPawel Jakub Dawidek */ 244586c5854SPawel Jakub Dawidek dummy = 0; 245586c5854SPawel Jakub Dawidek iov.iov_base = &dummy; 246586c5854SPawel Jakub Dawidek iov.iov_len = sizeof(dummy); 247586c5854SPawel Jakub Dawidek 248586c5854SPawel Jakub Dawidek msg.msg_iov = &iov; 249586c5854SPawel Jakub Dawidek msg.msg_iovlen = 1; 25036da5199SPawel Jakub Dawidek msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int)); 25136da5199SPawel Jakub Dawidek msg.msg_control = calloc(1, msg.msg_controllen); 25236da5199SPawel Jakub Dawidek if (msg.msg_control == NULL) 25336da5199SPawel Jakub Dawidek return (-1); 25436da5199SPawel Jakub Dawidek 25536da5199SPawel Jakub Dawidek ret = -1; 25636da5199SPawel Jakub Dawidek 25736da5199SPawel Jakub Dawidek for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL; 25836da5199SPawel Jakub Dawidek i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) { 25936da5199SPawel Jakub Dawidek if (msghdr_add_fd(cmsg, fds[i]) == -1) 26036da5199SPawel Jakub Dawidek goto end; 26136da5199SPawel Jakub Dawidek } 26236da5199SPawel Jakub Dawidek 26336da5199SPawel Jakub Dawidek if (msg_send(sock, &msg) == -1) 26436da5199SPawel Jakub Dawidek goto end; 26536da5199SPawel Jakub Dawidek 26636da5199SPawel Jakub Dawidek ret = 0; 26736da5199SPawel Jakub Dawidek end: 26836da5199SPawel Jakub Dawidek serrno = errno; 26936da5199SPawel Jakub Dawidek free(msg.msg_control); 27036da5199SPawel Jakub Dawidek errno = serrno; 27136da5199SPawel Jakub Dawidek return (ret); 27236da5199SPawel Jakub Dawidek } 27336da5199SPawel Jakub Dawidek 274586c5854SPawel Jakub Dawidek static int 275586c5854SPawel Jakub Dawidek fd_package_recv(int sock, int *fds, size_t nfds) 27636da5199SPawel Jakub Dawidek { 27736da5199SPawel Jakub Dawidek struct msghdr msg; 27836da5199SPawel Jakub Dawidek struct cmsghdr *cmsg; 27936da5199SPawel Jakub Dawidek unsigned int i; 28036da5199SPawel Jakub Dawidek int serrno, ret; 281586c5854SPawel Jakub Dawidek struct iovec iov; 282586c5854SPawel Jakub Dawidek uint8_t dummy; 28336da5199SPawel Jakub Dawidek 284586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 285586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(nfds > 0); 286586c5854SPawel Jakub Dawidek PJDLOG_ASSERT(fds != NULL); 28736da5199SPawel Jakub Dawidek 28836da5199SPawel Jakub Dawidek bzero(&msg, sizeof(msg)); 289586c5854SPawel Jakub Dawidek bzero(&iov, sizeof(iov)); 290586c5854SPawel Jakub Dawidek 291586c5854SPawel Jakub Dawidek /* 292586c5854SPawel Jakub Dawidek * XXX: Look into cred_send function for more details. 293586c5854SPawel Jakub Dawidek */ 294586c5854SPawel Jakub Dawidek iov.iov_base = &dummy; 295586c5854SPawel Jakub Dawidek iov.iov_len = sizeof(dummy); 296586c5854SPawel Jakub Dawidek 297586c5854SPawel Jakub Dawidek msg.msg_iov = &iov; 298586c5854SPawel Jakub Dawidek msg.msg_iovlen = 1; 29936da5199SPawel Jakub Dawidek msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int)); 30036da5199SPawel Jakub Dawidek msg.msg_control = calloc(1, msg.msg_controllen); 30136da5199SPawel Jakub Dawidek if (msg.msg_control == NULL) 30236da5199SPawel Jakub Dawidek return (-1); 30336da5199SPawel Jakub Dawidek 30436da5199SPawel Jakub Dawidek ret = -1; 30536da5199SPawel Jakub Dawidek 30636da5199SPawel Jakub Dawidek if (msg_recv(sock, &msg) == -1) 30736da5199SPawel Jakub Dawidek goto end; 30836da5199SPawel Jakub Dawidek 3093810ba1bSMariusz Zaborski i = 0; 3103810ba1bSMariusz Zaborski cmsg = CMSG_FIRSTHDR(&msg); 3113810ba1bSMariusz Zaborski while (cmsg && i < nfds) { 3123810ba1bSMariusz Zaborski unsigned int n; 3133810ba1bSMariusz Zaborski 3143810ba1bSMariusz Zaborski if (cmsg->cmsg_level != SOL_SOCKET || 3153810ba1bSMariusz Zaborski cmsg->cmsg_type != SCM_RIGHTS) { 3163810ba1bSMariusz Zaborski errno = EINVAL; 31736da5199SPawel Jakub Dawidek break; 31836da5199SPawel Jakub Dawidek } 3193810ba1bSMariusz Zaborski n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); 3203810ba1bSMariusz Zaborski if (i + n > nfds) { 3213810ba1bSMariusz Zaborski errno = EINVAL; 3223810ba1bSMariusz Zaborski break; 3233810ba1bSMariusz Zaborski } 3243810ba1bSMariusz Zaborski bcopy(CMSG_DATA(cmsg), fds + i, sizeof(int) * n); 3253810ba1bSMariusz Zaborski cmsg = CMSG_NXTHDR(&msg, cmsg); 3263810ba1bSMariusz Zaborski i += n; 3273810ba1bSMariusz Zaborski } 32836da5199SPawel Jakub Dawidek 32936da5199SPawel Jakub Dawidek if (cmsg != NULL || i < nfds) { 3303810ba1bSMariusz Zaborski unsigned int last; 33136da5199SPawel Jakub Dawidek 33236da5199SPawel Jakub Dawidek /* 33336da5199SPawel Jakub Dawidek * We need to close all received descriptors, even if we have 33436da5199SPawel Jakub Dawidek * different control message (eg. SCM_CREDS) in between. 33536da5199SPawel Jakub Dawidek */ 3363810ba1bSMariusz Zaborski last = i; 3373810ba1bSMariusz Zaborski for (i = 0; i < last; i++) { 3383810ba1bSMariusz Zaborski if (fds[i] >= 0) { 3393810ba1bSMariusz Zaborski close(fds[i]); 3403810ba1bSMariusz Zaborski } 34136da5199SPawel Jakub Dawidek } 34236da5199SPawel Jakub Dawidek errno = EINVAL; 34336da5199SPawel Jakub Dawidek goto end; 34436da5199SPawel Jakub Dawidek } 34536da5199SPawel Jakub Dawidek 3463810ba1bSMariusz Zaborski #ifndef MSG_CMSG_CLOEXEC 3473810ba1bSMariusz Zaborski /* 3483810ba1bSMariusz Zaborski * If the MSG_CMSG_CLOEXEC flag is not available we cannot set the 3493810ba1bSMariusz Zaborski * close-on-exec flag atomically, but we still want to set it for 3503810ba1bSMariusz Zaborski * consistency. 3513810ba1bSMariusz Zaborski */ 3523810ba1bSMariusz Zaborski for (i = 0; i < nfds; i++) { 3533810ba1bSMariusz Zaborski (void) fcntl(fds[i], F_SETFD, FD_CLOEXEC); 3543810ba1bSMariusz Zaborski } 3553810ba1bSMariusz Zaborski #endif 3563810ba1bSMariusz Zaborski 35736da5199SPawel Jakub Dawidek ret = 0; 35836da5199SPawel Jakub Dawidek end: 35936da5199SPawel Jakub Dawidek serrno = errno; 36036da5199SPawel Jakub Dawidek free(msg.msg_control); 36136da5199SPawel Jakub Dawidek errno = serrno; 36236da5199SPawel Jakub Dawidek return (ret); 36336da5199SPawel Jakub Dawidek } 36436da5199SPawel Jakub Dawidek 36536da5199SPawel Jakub Dawidek int 366586c5854SPawel Jakub Dawidek fd_recv(int sock, int *fds, size_t nfds) 367586c5854SPawel Jakub Dawidek { 368586c5854SPawel Jakub Dawidek unsigned int i, step, j; 369586c5854SPawel Jakub Dawidek int ret, serrno; 370586c5854SPawel Jakub Dawidek 371586c5854SPawel Jakub Dawidek if (nfds == 0 || fds == NULL) { 372586c5854SPawel Jakub Dawidek errno = EINVAL; 373586c5854SPawel Jakub Dawidek return (-1); 374586c5854SPawel Jakub Dawidek } 375586c5854SPawel Jakub Dawidek 376586c5854SPawel Jakub Dawidek ret = i = step = 0; 377586c5854SPawel Jakub Dawidek while (i < nfds) { 378586c5854SPawel Jakub Dawidek if (PKG_MAX_SIZE < nfds - i) 379586c5854SPawel Jakub Dawidek step = PKG_MAX_SIZE; 380586c5854SPawel Jakub Dawidek else 381586c5854SPawel Jakub Dawidek step = nfds - i; 382586c5854SPawel Jakub Dawidek ret = fd_package_recv(sock, fds + i, step); 383586c5854SPawel Jakub Dawidek if (ret != 0) { 384586c5854SPawel Jakub Dawidek /* Close all received descriptors. */ 385586c5854SPawel Jakub Dawidek serrno = errno; 386586c5854SPawel Jakub Dawidek for (j = 0; j < i; j++) 387586c5854SPawel Jakub Dawidek close(fds[j]); 388586c5854SPawel Jakub Dawidek errno = serrno; 389586c5854SPawel Jakub Dawidek break; 390586c5854SPawel Jakub Dawidek } 391586c5854SPawel Jakub Dawidek i += step; 392586c5854SPawel Jakub Dawidek } 393586c5854SPawel Jakub Dawidek 394586c5854SPawel Jakub Dawidek return (ret); 395586c5854SPawel Jakub Dawidek } 396586c5854SPawel Jakub Dawidek 397586c5854SPawel Jakub Dawidek int 398586c5854SPawel Jakub Dawidek fd_send(int sock, const int *fds, size_t nfds) 399586c5854SPawel Jakub Dawidek { 400586c5854SPawel Jakub Dawidek unsigned int i, step; 401586c5854SPawel Jakub Dawidek int ret; 402586c5854SPawel Jakub Dawidek 403586c5854SPawel Jakub Dawidek if (nfds == 0 || fds == NULL) { 404586c5854SPawel Jakub Dawidek errno = EINVAL; 405586c5854SPawel Jakub Dawidek return (-1); 406586c5854SPawel Jakub Dawidek } 407586c5854SPawel Jakub Dawidek 408586c5854SPawel Jakub Dawidek ret = i = step = 0; 409586c5854SPawel Jakub Dawidek while (i < nfds) { 410586c5854SPawel Jakub Dawidek if (PKG_MAX_SIZE < nfds - i) 411586c5854SPawel Jakub Dawidek step = PKG_MAX_SIZE; 412586c5854SPawel Jakub Dawidek else 413586c5854SPawel Jakub Dawidek step = nfds - i; 414586c5854SPawel Jakub Dawidek ret = fd_package_send(sock, fds + i, step); 415586c5854SPawel Jakub Dawidek if (ret != 0) 416586c5854SPawel Jakub Dawidek break; 417586c5854SPawel Jakub Dawidek i += step; 418586c5854SPawel Jakub Dawidek } 419586c5854SPawel Jakub Dawidek 420586c5854SPawel Jakub Dawidek return (ret); 421586c5854SPawel Jakub Dawidek } 422586c5854SPawel Jakub Dawidek 423586c5854SPawel Jakub Dawidek int 42436da5199SPawel Jakub Dawidek buf_send(int sock, void *buf, size_t size) 42536da5199SPawel Jakub Dawidek { 42636da5199SPawel Jakub Dawidek ssize_t done; 42736da5199SPawel Jakub Dawidek unsigned char *ptr; 42836da5199SPawel Jakub Dawidek 4293d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 4303d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(size > 0); 4313d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(buf != NULL); 4323d34eceaSPawel Jakub Dawidek 43336da5199SPawel Jakub Dawidek ptr = buf; 43436da5199SPawel Jakub Dawidek do { 43536da5199SPawel Jakub Dawidek fd_wait(sock, false); 43636da5199SPawel Jakub Dawidek done = send(sock, ptr, size, 0); 43736da5199SPawel Jakub Dawidek if (done == -1) { 43836da5199SPawel Jakub Dawidek if (errno == EINTR) 43936da5199SPawel Jakub Dawidek continue; 44036da5199SPawel Jakub Dawidek return (-1); 44136da5199SPawel Jakub Dawidek } else if (done == 0) { 44236da5199SPawel Jakub Dawidek errno = ENOTCONN; 44336da5199SPawel Jakub Dawidek return (-1); 44436da5199SPawel Jakub Dawidek } 44536da5199SPawel Jakub Dawidek size -= done; 44636da5199SPawel Jakub Dawidek ptr += done; 44736da5199SPawel Jakub Dawidek } while (size > 0); 44836da5199SPawel Jakub Dawidek 44936da5199SPawel Jakub Dawidek return (0); 45036da5199SPawel Jakub Dawidek } 45136da5199SPawel Jakub Dawidek 45236da5199SPawel Jakub Dawidek int 453db158b99SRobert Wing buf_recv(int sock, void *buf, size_t size, int flags) 45436da5199SPawel Jakub Dawidek { 45536da5199SPawel Jakub Dawidek ssize_t done; 45636da5199SPawel Jakub Dawidek unsigned char *ptr; 45736da5199SPawel Jakub Dawidek 4583d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(sock >= 0); 4593d34eceaSPawel Jakub Dawidek PJDLOG_ASSERT(buf != NULL); 4603d34eceaSPawel Jakub Dawidek 46136da5199SPawel Jakub Dawidek ptr = buf; 4627f7fe890SPawel Jakub Dawidek while (size > 0) { 46336da5199SPawel Jakub Dawidek fd_wait(sock, true); 464db158b99SRobert Wing done = recv(sock, ptr, size, flags); 46536da5199SPawel Jakub Dawidek if (done == -1) { 46636da5199SPawel Jakub Dawidek if (errno == EINTR) 46736da5199SPawel Jakub Dawidek continue; 46836da5199SPawel Jakub Dawidek return (-1); 46936da5199SPawel Jakub Dawidek } else if (done == 0) { 47036da5199SPawel Jakub Dawidek errno = ENOTCONN; 47136da5199SPawel Jakub Dawidek return (-1); 47236da5199SPawel Jakub Dawidek } 47336da5199SPawel Jakub Dawidek size -= done; 47436da5199SPawel Jakub Dawidek ptr += done; 4757f7fe890SPawel Jakub Dawidek } 47636da5199SPawel Jakub Dawidek 47736da5199SPawel Jakub Dawidek return (0); 47836da5199SPawel Jakub Dawidek } 479