1309554Ssobomax/*- 2309554Ssobomax * Copyright (c) 2005 Andrey Simonenko 3309554Ssobomax * All rights reserved. 4309554Ssobomax * 5309554Ssobomax * Redistribution and use in source and binary forms, with or without 6309554Ssobomax * modification, are permitted provided that the following conditions 7309554Ssobomax * are met: 8309554Ssobomax * 1. Redistributions of source code must retain the above copyright 9309554Ssobomax * notice, this list of conditions and the following disclaimer. 10309554Ssobomax * 2. Redistributions in binary form must reproduce the above copyright 11309554Ssobomax * notice, this list of conditions and the following disclaimer in the 12309554Ssobomax * documentation and/or other materials provided with the distribution. 13309554Ssobomax * 14309554Ssobomax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15309554Ssobomax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16309554Ssobomax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17309554Ssobomax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18309554Ssobomax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19309554Ssobomax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20309554Ssobomax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21309554Ssobomax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22309554Ssobomax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23309554Ssobomax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24309554Ssobomax * SUCH DAMAGE. 25309554Ssobomax */ 26309554Ssobomax 27309554Ssobomax#include <sys/cdefs.h> 28309554Ssobomax__FBSDID("$FreeBSD: stable/11/tools/regression/sockets/unix_cmsg/uc_common.c 339066 2018-10-01 17:26:41Z sobomax $"); 29309554Ssobomax 30309554Ssobomax#include <sys/socket.h> 31309554Ssobomax#include <sys/un.h> 32309554Ssobomax#include <err.h> 33309554Ssobomax#include <fcntl.h> 34309554Ssobomax#include <errno.h> 35309554Ssobomax#include <inttypes.h> 36309554Ssobomax#include <stdarg.h> 37309554Ssobomax#include <stdbool.h> 38309554Ssobomax#include <stdlib.h> 39309554Ssobomax#include <stdio.h> 40309554Ssobomax#include <string.h> 41309554Ssobomax#include <unistd.h> 42309554Ssobomax#include <sys/wait.h> 43309554Ssobomax 44309554Ssobomax#include "uc_common.h" 45309554Ssobomax 46309554Ssobomax#ifndef LISTENQ 47309554Ssobomax# define LISTENQ 1 48309554Ssobomax#endif 49309554Ssobomax 50309554Ssobomax#ifndef TIMEOUT 51309554Ssobomax# define TIMEOUT 2 52309554Ssobomax#endif 53309554Ssobomax 54309554Ssobomax#define SYNC_SERVER 0 55309554Ssobomax#define SYNC_CLIENT 1 56309554Ssobomax#define SYNC_RECV 0 57309554Ssobomax#define SYNC_SEND 1 58309554Ssobomax 59309554Ssobomax#define LOGMSG_SIZE 128 60309554Ssobomax 61309554Ssobomaxvoid 62309554Ssobomaxuc_output(const char *format, ...) 63309554Ssobomax{ 64309554Ssobomax char buf[LOGMSG_SIZE]; 65309554Ssobomax va_list ap; 66309554Ssobomax 67309554Ssobomax va_start(ap, format); 68309554Ssobomax if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 69309554Ssobomax err(EXIT_FAILURE, "output: vsnprintf failed"); 70309554Ssobomax write(STDOUT_FILENO, buf, strlen(buf)); 71309554Ssobomax va_end(ap); 72309554Ssobomax} 73309554Ssobomax 74309554Ssobomaxvoid 75309554Ssobomaxuc_logmsg(const char *format, ...) 76309554Ssobomax{ 77309554Ssobomax char buf[LOGMSG_SIZE]; 78309554Ssobomax va_list ap; 79309554Ssobomax int errno_save; 80309554Ssobomax 81309554Ssobomax errno_save = errno; 82309554Ssobomax va_start(ap, format); 83309554Ssobomax if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 84309554Ssobomax err(EXIT_FAILURE, "logmsg: vsnprintf failed"); 85309554Ssobomax if (errno_save == 0) 86309554Ssobomax uc_output("%s: %s\n", uc_cfg.proc_name, buf); 87309554Ssobomax else 88309554Ssobomax uc_output("%s: %s: %s\n", uc_cfg.proc_name, buf, 89309554Ssobomax strerror(errno_save)); 90309554Ssobomax va_end(ap); 91309554Ssobomax errno = errno_save; 92309554Ssobomax} 93309554Ssobomax 94309554Ssobomaxvoid 95309554Ssobomaxuc_vlogmsgx(const char *format, va_list ap) 96309554Ssobomax{ 97309554Ssobomax char buf[LOGMSG_SIZE]; 98309554Ssobomax 99309554Ssobomax if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 100309554Ssobomax err(EXIT_FAILURE, "uc_logmsgx: vsnprintf failed"); 101309554Ssobomax uc_output("%s: %s\n", uc_cfg.proc_name, buf); 102309554Ssobomax} 103309554Ssobomax 104309554Ssobomaxvoid 105309554Ssobomaxuc_logmsgx(const char *format, ...) 106309554Ssobomax{ 107309554Ssobomax va_list ap; 108309554Ssobomax 109309554Ssobomax va_start(ap, format); 110309554Ssobomax uc_vlogmsgx(format, ap); 111309554Ssobomax va_end(ap); 112309554Ssobomax} 113309554Ssobomax 114309554Ssobomaxvoid 115309554Ssobomaxuc_dbgmsg(const char *format, ...) 116309554Ssobomax{ 117309554Ssobomax va_list ap; 118309554Ssobomax 119309554Ssobomax if (uc_cfg.debug) { 120309554Ssobomax va_start(ap, format); 121309554Ssobomax uc_vlogmsgx(format, ap); 122309554Ssobomax va_end(ap); 123309554Ssobomax } 124309554Ssobomax} 125309554Ssobomax 126309554Ssobomaxint 127309554Ssobomaxuc_socket_create(void) 128309554Ssobomax{ 129309554Ssobomax struct timeval tv; 130309554Ssobomax int fd; 131309554Ssobomax 132309554Ssobomax fd = socket(PF_LOCAL, uc_cfg.sock_type, 0); 133309554Ssobomax if (fd < 0) { 134309554Ssobomax uc_logmsg("socket_create: socket(PF_LOCAL, %s, 0)", uc_cfg.sock_type_str); 135309554Ssobomax return (-1); 136309554Ssobomax } 137309554Ssobomax if (uc_cfg.server_flag) 138309554Ssobomax uc_cfg.serv_sock_fd = fd; 139309554Ssobomax 140309554Ssobomax tv.tv_sec = TIMEOUT; 141309554Ssobomax tv.tv_usec = 0; 142309554Ssobomax if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 || 143309554Ssobomax setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { 144309554Ssobomax uc_logmsg("socket_create: setsockopt(SO_RCVTIMEO/SO_SNDTIMEO)"); 145309554Ssobomax goto failed; 146309554Ssobomax } 147309554Ssobomax 148309554Ssobomax if (uc_cfg.server_flag) { 149309554Ssobomax if (bind(fd, (struct sockaddr *)&uc_cfg.serv_addr_sun, 150309554Ssobomax uc_cfg.serv_addr_sun.sun_len) < 0) { 151309554Ssobomax uc_logmsg("socket_create: bind(%s)", 152309554Ssobomax uc_cfg.serv_addr_sun.sun_path); 153309554Ssobomax goto failed; 154309554Ssobomax } 155309554Ssobomax if (uc_cfg.sock_type == SOCK_STREAM) { 156309554Ssobomax int val; 157309554Ssobomax 158309554Ssobomax if (listen(fd, LISTENQ) < 0) { 159309554Ssobomax uc_logmsg("socket_create: listen"); 160309554Ssobomax goto failed; 161309554Ssobomax } 162309554Ssobomax val = fcntl(fd, F_GETFL, 0); 163309554Ssobomax if (val < 0) { 164309554Ssobomax uc_logmsg("socket_create: fcntl(F_GETFL)"); 165309554Ssobomax goto failed; 166309554Ssobomax } 167309554Ssobomax if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) { 168309554Ssobomax uc_logmsg("socket_create: fcntl(F_SETFL)"); 169309554Ssobomax goto failed; 170309554Ssobomax } 171309554Ssobomax } 172309554Ssobomax } 173309554Ssobomax 174309554Ssobomax return (fd); 175309554Ssobomax 176309554Ssobomaxfailed: 177309554Ssobomax if (close(fd) < 0) 178309554Ssobomax uc_logmsg("socket_create: close"); 179309554Ssobomax if (uc_cfg.server_flag) 180309554Ssobomax if (unlink(uc_cfg.serv_addr_sun.sun_path) < 0) 181309554Ssobomax uc_logmsg("socket_close: unlink(%s)", 182309554Ssobomax uc_cfg.serv_addr_sun.sun_path); 183309554Ssobomax return (-1); 184309554Ssobomax} 185309554Ssobomax 186309554Ssobomaxint 187309554Ssobomaxuc_socket_close(int fd) 188309554Ssobomax{ 189309554Ssobomax int rv; 190309554Ssobomax 191309554Ssobomax rv = 0; 192309554Ssobomax if (close(fd) < 0) { 193309554Ssobomax uc_logmsg("socket_close: close"); 194309554Ssobomax rv = -1; 195309554Ssobomax } 196309554Ssobomax if (uc_cfg.server_flag && fd == uc_cfg.serv_sock_fd) 197309554Ssobomax if (unlink(uc_cfg.serv_addr_sun.sun_path) < 0) { 198309554Ssobomax uc_logmsg("socket_close: unlink(%s)", 199309554Ssobomax uc_cfg.serv_addr_sun.sun_path); 200309554Ssobomax rv = -1; 201309554Ssobomax } 202309554Ssobomax return (rv); 203309554Ssobomax} 204309554Ssobomax 205309554Ssobomaxint 206309554Ssobomaxuc_socket_connect(int fd) 207309554Ssobomax{ 208309554Ssobomax uc_dbgmsg("connect"); 209309554Ssobomax 210309554Ssobomax if (connect(fd, (struct sockaddr *)&uc_cfg.serv_addr_sun, 211309554Ssobomax uc_cfg.serv_addr_sun.sun_len) < 0) { 212309554Ssobomax uc_logmsg("socket_connect: connect(%s)", uc_cfg.serv_addr_sun.sun_path); 213309554Ssobomax return (-1); 214309554Ssobomax } 215309554Ssobomax return (0); 216309554Ssobomax} 217309554Ssobomax 218309554Ssobomaxint 219309554Ssobomaxuc_sync_recv(void) 220309554Ssobomax{ 221309554Ssobomax ssize_t ssize; 222309554Ssobomax int fd; 223309554Ssobomax char buf; 224309554Ssobomax 225309554Ssobomax uc_dbgmsg("sync: wait"); 226309554Ssobomax 227309554Ssobomax fd = uc_cfg.sync_fd[uc_cfg.server_flag ? SYNC_SERVER : SYNC_CLIENT][SYNC_RECV]; 228309554Ssobomax 229309554Ssobomax ssize = read(fd, &buf, 1); 230309554Ssobomax if (ssize < 0) { 231309554Ssobomax uc_logmsg("sync_recv: read"); 232309554Ssobomax return (-1); 233309554Ssobomax } 234309554Ssobomax if (ssize < 1) { 235309554Ssobomax uc_logmsgx("sync_recv: read %zd of 1 byte", ssize); 236309554Ssobomax return (-1); 237309554Ssobomax } 238309554Ssobomax 239309554Ssobomax uc_dbgmsg("sync: received"); 240309554Ssobomax 241309554Ssobomax return (0); 242309554Ssobomax} 243309554Ssobomax 244309554Ssobomaxint 245309554Ssobomaxuc_sync_send(void) 246309554Ssobomax{ 247309554Ssobomax ssize_t ssize; 248309554Ssobomax int fd; 249309554Ssobomax 250309554Ssobomax uc_dbgmsg("sync: send"); 251309554Ssobomax 252309554Ssobomax fd = uc_cfg.sync_fd[uc_cfg.server_flag ? SYNC_CLIENT : SYNC_SERVER][SYNC_SEND]; 253309554Ssobomax 254309554Ssobomax ssize = write(fd, "", 1); 255309554Ssobomax if (ssize < 0) { 256309554Ssobomax uc_logmsg("uc_sync_send: write"); 257309554Ssobomax return (-1); 258309554Ssobomax } 259309554Ssobomax if (ssize < 1) { 260309554Ssobomax uc_logmsgx("uc_sync_send: sent %zd of 1 byte", ssize); 261309554Ssobomax return (-1); 262309554Ssobomax } 263309554Ssobomax 264309554Ssobomax return (0); 265309554Ssobomax} 266309554Ssobomax 267309554Ssobomaxint 268309554Ssobomaxuc_message_send(int fd, const struct msghdr *msghdr) 269309554Ssobomax{ 270309554Ssobomax const struct cmsghdr *cmsghdr; 271309554Ssobomax size_t size; 272309554Ssobomax ssize_t ssize; 273309554Ssobomax 274309554Ssobomax size = msghdr->msg_iov != 0 ? msghdr->msg_iov->iov_len : 0; 275309554Ssobomax uc_dbgmsg("send: data size %zu", size); 276309554Ssobomax uc_dbgmsg("send: msghdr.msg_controllen %u", 277309554Ssobomax (u_int)msghdr->msg_controllen); 278309554Ssobomax cmsghdr = CMSG_FIRSTHDR(msghdr); 279309554Ssobomax if (cmsghdr != NULL) 280309554Ssobomax uc_dbgmsg("send: cmsghdr.cmsg_len %u", 281309554Ssobomax (u_int)cmsghdr->cmsg_len); 282309554Ssobomax 283309554Ssobomax ssize = sendmsg(fd, msghdr, 0); 284309554Ssobomax if (ssize < 0) { 285309554Ssobomax uc_logmsg("message_send: sendmsg"); 286309554Ssobomax return (-1); 287309554Ssobomax } 288309554Ssobomax if ((size_t)ssize != size) { 289309554Ssobomax uc_logmsgx("message_send: sendmsg: sent %zd of %zu bytes", 290309554Ssobomax ssize, size); 291309554Ssobomax return (-1); 292309554Ssobomax } 293309554Ssobomax 294309554Ssobomax if (!uc_cfg.send_data_flag) 295309554Ssobomax if (uc_sync_send() < 0) 296309554Ssobomax return (-1); 297309554Ssobomax 298309554Ssobomax return (0); 299309554Ssobomax} 300309554Ssobomax 301309554Ssobomaxint 302309554Ssobomaxuc_message_sendn(int fd, struct msghdr *msghdr) 303309554Ssobomax{ 304309554Ssobomax u_int i; 305309554Ssobomax 306309554Ssobomax for (i = 1; i <= uc_cfg.ipc_msg.msg_num; ++i) { 307309554Ssobomax uc_dbgmsg("message #%u", i); 308309554Ssobomax if (uc_message_send(fd, msghdr) < 0) 309309554Ssobomax return (-1); 310309554Ssobomax } 311309554Ssobomax return (0); 312309554Ssobomax} 313309554Ssobomax 314309554Ssobomaxint 315309554Ssobomaxuc_message_recv(int fd, struct msghdr *msghdr) 316309554Ssobomax{ 317309554Ssobomax const struct cmsghdr *cmsghdr; 318309554Ssobomax size_t size; 319309554Ssobomax ssize_t ssize; 320309554Ssobomax 321309554Ssobomax if (!uc_cfg.send_data_flag) 322309554Ssobomax if (uc_sync_recv() < 0) 323309554Ssobomax return (-1); 324309554Ssobomax 325309554Ssobomax size = msghdr->msg_iov != NULL ? msghdr->msg_iov->iov_len : 0; 326309554Ssobomax ssize = recvmsg(fd, msghdr, MSG_WAITALL); 327309554Ssobomax if (ssize < 0) { 328309554Ssobomax uc_logmsg("message_recv: recvmsg"); 329309554Ssobomax return (-1); 330309554Ssobomax } 331309554Ssobomax if ((size_t)ssize != size) { 332309554Ssobomax uc_logmsgx("message_recv: recvmsg: received %zd of %zu bytes", 333309554Ssobomax ssize, size); 334309554Ssobomax return (-1); 335309554Ssobomax } 336309554Ssobomax 337309554Ssobomax uc_dbgmsg("recv: data size %zd", ssize); 338309554Ssobomax uc_dbgmsg("recv: msghdr.msg_controllen %u", 339309554Ssobomax (u_int)msghdr->msg_controllen); 340309554Ssobomax cmsghdr = CMSG_FIRSTHDR(msghdr); 341309554Ssobomax if (cmsghdr != NULL) 342309554Ssobomax uc_dbgmsg("recv: cmsghdr.cmsg_len %u", 343309554Ssobomax (u_int)cmsghdr->cmsg_len); 344309554Ssobomax 345309554Ssobomax if (memcmp(uc_cfg.ipc_msg.buf_recv, uc_cfg.ipc_msg.buf_send, size) != 0) { 346309554Ssobomax uc_logmsgx("message_recv: received message has wrong content"); 347309554Ssobomax return (-1); 348309554Ssobomax } 349309554Ssobomax 350309554Ssobomax return (0); 351309554Ssobomax} 352309554Ssobomax 353309554Ssobomaxint 354309554Ssobomaxuc_socket_accept(int listenfd) 355309554Ssobomax{ 356309554Ssobomax fd_set rset; 357309554Ssobomax struct timeval tv; 358309554Ssobomax int fd, rv, val; 359309554Ssobomax 360309554Ssobomax uc_dbgmsg("accept"); 361309554Ssobomax 362309554Ssobomax FD_ZERO(&rset); 363309554Ssobomax FD_SET(listenfd, &rset); 364309554Ssobomax tv.tv_sec = TIMEOUT; 365309554Ssobomax tv.tv_usec = 0; 366309554Ssobomax rv = select(listenfd + 1, &rset, (fd_set *)NULL, (fd_set *)NULL, &tv); 367309554Ssobomax if (rv < 0) { 368309554Ssobomax uc_logmsg("socket_accept: select"); 369309554Ssobomax return (-1); 370309554Ssobomax } 371309554Ssobomax if (rv == 0) { 372309554Ssobomax uc_logmsgx("socket_accept: select timeout"); 373309554Ssobomax return (-1); 374309554Ssobomax } 375309554Ssobomax 376309554Ssobomax fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL); 377309554Ssobomax if (fd < 0) { 378309554Ssobomax uc_logmsg("socket_accept: accept"); 379309554Ssobomax return (-1); 380309554Ssobomax } 381309554Ssobomax 382309554Ssobomax val = fcntl(fd, F_GETFL, 0); 383309554Ssobomax if (val < 0) { 384309554Ssobomax uc_logmsg("socket_accept: fcntl(F_GETFL)"); 385309554Ssobomax goto failed; 386309554Ssobomax } 387309554Ssobomax if (fcntl(fd, F_SETFL, val & ~O_NONBLOCK) < 0) { 388309554Ssobomax uc_logmsg("socket_accept: fcntl(F_SETFL)"); 389309554Ssobomax goto failed; 390309554Ssobomax } 391309554Ssobomax 392309554Ssobomax return (fd); 393309554Ssobomax 394309554Ssobomaxfailed: 395309554Ssobomax if (close(fd) < 0) 396309554Ssobomax uc_logmsg("socket_accept: close"); 397309554Ssobomax return (-1); 398309554Ssobomax} 399309554Ssobomax 400309554Ssobomaxint 401309554Ssobomaxuc_check_msghdr(const struct msghdr *msghdr, size_t size) 402309554Ssobomax{ 403309554Ssobomax if (msghdr->msg_flags & MSG_TRUNC) { 404309554Ssobomax uc_logmsgx("msghdr.msg_flags has MSG_TRUNC"); 405309554Ssobomax return (-1); 406309554Ssobomax } 407309554Ssobomax if (msghdr->msg_flags & MSG_CTRUNC) { 408309554Ssobomax uc_logmsgx("msghdr.msg_flags has MSG_CTRUNC"); 409309554Ssobomax return (-1); 410309554Ssobomax } 411309554Ssobomax if (msghdr->msg_controllen < size) { 412309554Ssobomax uc_logmsgx("msghdr.msg_controllen %u < %zu", 413309554Ssobomax (u_int)msghdr->msg_controllen, size); 414309554Ssobomax return (-1); 415309554Ssobomax } 416309554Ssobomax if (msghdr->msg_controllen > 0 && size == 0) { 417309554Ssobomax uc_logmsgx("msghdr.msg_controllen %u > 0", 418309554Ssobomax (u_int)msghdr->msg_controllen); 419309554Ssobomax return (-1); 420309554Ssobomax } 421309554Ssobomax return (0); 422309554Ssobomax} 423309554Ssobomax 424309554Ssobomaxint 425309554Ssobomaxuc_check_cmsghdr(const struct cmsghdr *cmsghdr, int type, size_t size) 426309554Ssobomax{ 427309554Ssobomax if (cmsghdr == NULL) { 428309554Ssobomax uc_logmsgx("cmsghdr is NULL"); 429309554Ssobomax return (-1); 430309554Ssobomax } 431309554Ssobomax if (cmsghdr->cmsg_level != SOL_SOCKET) { 432309554Ssobomax uc_logmsgx("cmsghdr.cmsg_level %d != SOL_SOCKET", 433309554Ssobomax cmsghdr->cmsg_level); 434309554Ssobomax return (-1); 435309554Ssobomax } 436309554Ssobomax if (cmsghdr->cmsg_type != type) { 437309554Ssobomax uc_logmsgx("cmsghdr.cmsg_type %d != %d", 438309554Ssobomax cmsghdr->cmsg_type, type); 439309554Ssobomax return (-1); 440309554Ssobomax } 441309554Ssobomax if (cmsghdr->cmsg_len != CMSG_LEN(size)) { 442309554Ssobomax uc_logmsgx("cmsghdr.cmsg_len %u != %zu", 443309554Ssobomax (u_int)cmsghdr->cmsg_len, CMSG_LEN(size)); 444309554Ssobomax return (-1); 445309554Ssobomax } 446309554Ssobomax return (0); 447309554Ssobomax} 448309554Ssobomax 449309554Ssobomaxstatic void 450309554Ssobomaxuc_msghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data) 451309554Ssobomax{ 452309554Ssobomax msghdr->msg_name = NULL; 453309554Ssobomax msghdr->msg_namelen = 0; 454309554Ssobomax if (uc_cfg.send_data_flag) { 455309554Ssobomax iov->iov_base = uc_cfg.server_flag ? 456309554Ssobomax uc_cfg.ipc_msg.buf_recv : uc_cfg.ipc_msg.buf_send; 457309554Ssobomax iov->iov_len = uc_cfg.ipc_msg.buf_size; 458309554Ssobomax msghdr->msg_iov = iov; 459309554Ssobomax msghdr->msg_iovlen = 1; 460309554Ssobomax } else { 461309554Ssobomax msghdr->msg_iov = NULL; 462309554Ssobomax msghdr->msg_iovlen = 0; 463309554Ssobomax } 464309554Ssobomax msghdr->msg_control = cmsg_data; 465309554Ssobomax msghdr->msg_flags = 0; 466309554Ssobomax} 467309554Ssobomax 468309554Ssobomaxvoid 469309554Ssobomaxuc_msghdr_init_server(struct msghdr *msghdr, struct iovec *iov, 470309554Ssobomax void *cmsg_data, size_t cmsg_size) 471309554Ssobomax{ 472309554Ssobomax uc_msghdr_init_generic(msghdr, iov, cmsg_data); 473309554Ssobomax msghdr->msg_controllen = cmsg_size; 474309554Ssobomax uc_dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ? 475309554Ssobomax msghdr->msg_iov->iov_len : (size_t)0); 476309554Ssobomax uc_dbgmsg("init: msghdr.msg_controllen %u", 477309554Ssobomax (u_int)msghdr->msg_controllen); 478309554Ssobomax} 479309554Ssobomax 480309554Ssobomaxvoid 481309554Ssobomaxuc_msghdr_init_client(struct msghdr *msghdr, struct iovec *iov, 482309554Ssobomax void *cmsg_data, size_t cmsg_size, int type, size_t arr_size) 483309554Ssobomax{ 484309554Ssobomax struct cmsghdr *cmsghdr; 485309554Ssobomax 486309554Ssobomax uc_msghdr_init_generic(msghdr, iov, cmsg_data); 487309554Ssobomax if (cmsg_data != NULL) { 488309554Ssobomax if (uc_cfg.send_array_flag) 489309554Ssobomax uc_dbgmsg("sending an array"); 490309554Ssobomax else 491309554Ssobomax uc_dbgmsg("sending a scalar"); 492309554Ssobomax msghdr->msg_controllen = uc_cfg.send_array_flag ? 493309554Ssobomax cmsg_size : CMSG_SPACE(0); 494309554Ssobomax cmsghdr = CMSG_FIRSTHDR(msghdr); 495309554Ssobomax cmsghdr->cmsg_level = SOL_SOCKET; 496309554Ssobomax cmsghdr->cmsg_type = type; 497309554Ssobomax cmsghdr->cmsg_len = CMSG_LEN(uc_cfg.send_array_flag ? arr_size : 0); 498309554Ssobomax } else 499309554Ssobomax msghdr->msg_controllen = 0; 500309554Ssobomax} 501309554Ssobomax 502309554Ssobomaxint 503309554Ssobomaxuc_client_fork(void) 504309554Ssobomax{ 505309554Ssobomax int fd1, fd2; 506309554Ssobomax 507309554Ssobomax if (pipe(uc_cfg.sync_fd[SYNC_SERVER]) < 0 || 508309554Ssobomax pipe(uc_cfg.sync_fd[SYNC_CLIENT]) < 0) { 509309554Ssobomax uc_logmsg("client_fork: pipe"); 510309554Ssobomax return (-1); 511309554Ssobomax } 512309554Ssobomax uc_cfg.client_pid = fork(); 513309554Ssobomax if (uc_cfg.client_pid == (pid_t)-1) { 514309554Ssobomax uc_logmsg("client_fork: fork"); 515309554Ssobomax return (-1); 516309554Ssobomax } 517309554Ssobomax if (uc_cfg.client_pid == 0) { 518309554Ssobomax uc_cfg.proc_name = "CLIENT"; 519309554Ssobomax uc_cfg.server_flag = false; 520309554Ssobomax fd1 = uc_cfg.sync_fd[SYNC_SERVER][SYNC_RECV]; 521309554Ssobomax fd2 = uc_cfg.sync_fd[SYNC_CLIENT][SYNC_SEND]; 522309554Ssobomax } else { 523309554Ssobomax fd1 = uc_cfg.sync_fd[SYNC_SERVER][SYNC_SEND]; 524309554Ssobomax fd2 = uc_cfg.sync_fd[SYNC_CLIENT][SYNC_RECV]; 525309554Ssobomax } 526309554Ssobomax if (close(fd1) < 0 || close(fd2) < 0) { 527309554Ssobomax uc_logmsg("client_fork: close"); 528309554Ssobomax return (-1); 529309554Ssobomax } 530309554Ssobomax return (uc_cfg.client_pid != 0); 531309554Ssobomax} 532309554Ssobomax 533309554Ssobomaxvoid 534309554Ssobomaxuc_client_exit(int rv) 535309554Ssobomax{ 536309554Ssobomax if (close(uc_cfg.sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 || 537309554Ssobomax close(uc_cfg.sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) { 538309554Ssobomax uc_logmsg("client_exit: close"); 539309554Ssobomax rv = -1; 540309554Ssobomax } 541309554Ssobomax rv = rv == 0 ? EXIT_SUCCESS : -rv; 542309554Ssobomax uc_dbgmsg("exit: code %d", rv); 543309554Ssobomax _exit(rv); 544309554Ssobomax} 545309554Ssobomax 546309554Ssobomaxint 547309554Ssobomaxuc_client_wait(void) 548309554Ssobomax{ 549309554Ssobomax int status; 550309554Ssobomax pid_t pid; 551309554Ssobomax 552309554Ssobomax uc_dbgmsg("waiting for client"); 553309554Ssobomax 554309554Ssobomax if (close(uc_cfg.sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 || 555309554Ssobomax close(uc_cfg.sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) { 556309554Ssobomax uc_logmsg("client_wait: close"); 557309554Ssobomax return (-1); 558309554Ssobomax } 559309554Ssobomax 560309554Ssobomax pid = waitpid(uc_cfg.client_pid, &status, 0); 561309554Ssobomax if (pid == (pid_t)-1) { 562309554Ssobomax uc_logmsg("client_wait: waitpid"); 563309554Ssobomax return (-1); 564309554Ssobomax } 565309554Ssobomax 566309554Ssobomax if (WIFEXITED(status)) { 567309554Ssobomax if (WEXITSTATUS(status) != EXIT_SUCCESS) { 568309554Ssobomax uc_logmsgx("client exit status is %d", 569309554Ssobomax WEXITSTATUS(status)); 570309554Ssobomax return (-WEXITSTATUS(status)); 571309554Ssobomax } 572309554Ssobomax } else { 573309554Ssobomax if (WIFSIGNALED(status)) 574309554Ssobomax uc_logmsgx("abnormal termination of client, signal %d%s", 575309554Ssobomax WTERMSIG(status), WCOREDUMP(status) ? 576309554Ssobomax " (core file generated)" : ""); 577309554Ssobomax else 578309554Ssobomax uc_logmsgx("termination of client, unknown status"); 579309554Ssobomax return (-1); 580309554Ssobomax } 581309554Ssobomax 582309554Ssobomax return (0); 583309554Ssobomax} 584309554Ssobomax 585309554Ssobomaxint 586309554Ssobomaxuc_check_groups(const char *gid_arr_str, const gid_t *gid_arr, 587309554Ssobomax const char *gid_num_str, int gid_num, bool all_gids) 588309554Ssobomax{ 589309554Ssobomax int i; 590309554Ssobomax 591309554Ssobomax for (i = 0; i < gid_num; ++i) 592309554Ssobomax uc_dbgmsg("%s[%d] %lu", gid_arr_str, i, (u_long)gid_arr[i]); 593309554Ssobomax 594309554Ssobomax if (all_gids) { 595309554Ssobomax if (gid_num != uc_cfg.proc_cred.gid_num) { 596309554Ssobomax uc_logmsgx("%s %d != %d", gid_num_str, gid_num, 597309554Ssobomax uc_cfg.proc_cred.gid_num); 598309554Ssobomax return (-1); 599309554Ssobomax } 600309554Ssobomax } else { 601309554Ssobomax if (gid_num > uc_cfg.proc_cred.gid_num) { 602309554Ssobomax uc_logmsgx("%s %d > %d", gid_num_str, gid_num, 603309554Ssobomax uc_cfg.proc_cred.gid_num); 604309554Ssobomax return (-1); 605309554Ssobomax } 606309554Ssobomax } 607309554Ssobomax if (memcmp(gid_arr, uc_cfg.proc_cred.gid_arr, 608309554Ssobomax gid_num * sizeof(*gid_arr)) != 0) { 609309554Ssobomax uc_logmsgx("%s content is wrong", gid_arr_str); 610309554Ssobomax for (i = 0; i < gid_num; ++i) 611309554Ssobomax if (gid_arr[i] != uc_cfg.proc_cred.gid_arr[i]) { 612309554Ssobomax uc_logmsgx("%s[%d] %lu != %lu", 613309554Ssobomax gid_arr_str, i, (u_long)gid_arr[i], 614309554Ssobomax (u_long)uc_cfg.proc_cred.gid_arr[i]); 615309554Ssobomax break; 616309554Ssobomax } 617309554Ssobomax return (-1); 618309554Ssobomax } 619309554Ssobomax return (0); 620309554Ssobomax} 621309554Ssobomax 622309554Ssobomaxint 623309554Ssobomaxuc_check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr) 624309554Ssobomax{ 625309554Ssobomax const struct cmsgcred *cmcred; 626309554Ssobomax int rc; 627309554Ssobomax 628309554Ssobomax if (uc_check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(struct cmsgcred)) < 0) 629309554Ssobomax return (-1); 630309554Ssobomax 631309554Ssobomax cmcred = (struct cmsgcred *)CMSG_DATA(cmsghdr); 632309554Ssobomax 633309554Ssobomax uc_dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmcred->cmcred_pid); 634309554Ssobomax uc_dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmcred->cmcred_uid); 635309554Ssobomax uc_dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmcred->cmcred_euid); 636309554Ssobomax uc_dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmcred->cmcred_gid); 637309554Ssobomax uc_dbgmsg("cmsgcred.cmcred_ngroups %d", cmcred->cmcred_ngroups); 638309554Ssobomax 639309554Ssobomax rc = 0; 640309554Ssobomax 641309554Ssobomax if (cmcred->cmcred_pid != uc_cfg.client_pid) { 642309554Ssobomax uc_logmsgx("cmsgcred.cmcred_pid %ld != %ld", 643309554Ssobomax (long)cmcred->cmcred_pid, (long)uc_cfg.client_pid); 644309554Ssobomax rc = -1; 645309554Ssobomax } 646309554Ssobomax if (cmcred->cmcred_uid != uc_cfg.proc_cred.uid) { 647309554Ssobomax uc_logmsgx("cmsgcred.cmcred_uid %lu != %lu", 648309554Ssobomax (u_long)cmcred->cmcred_uid, (u_long)uc_cfg.proc_cred.uid); 649309554Ssobomax rc = -1; 650309554Ssobomax } 651309554Ssobomax if (cmcred->cmcred_euid != uc_cfg.proc_cred.euid) { 652309554Ssobomax uc_logmsgx("cmsgcred.cmcred_euid %lu != %lu", 653309554Ssobomax (u_long)cmcred->cmcred_euid, (u_long)uc_cfg.proc_cred.euid); 654309554Ssobomax rc = -1; 655309554Ssobomax } 656309554Ssobomax if (cmcred->cmcred_gid != uc_cfg.proc_cred.gid) { 657309554Ssobomax uc_logmsgx("cmsgcred.cmcred_gid %lu != %lu", 658309554Ssobomax (u_long)cmcred->cmcred_gid, (u_long)uc_cfg.proc_cred.gid); 659309554Ssobomax rc = -1; 660309554Ssobomax } 661309554Ssobomax if (cmcred->cmcred_ngroups == 0) { 662309554Ssobomax uc_logmsgx("cmsgcred.cmcred_ngroups == 0"); 663309554Ssobomax rc = -1; 664309554Ssobomax } 665309554Ssobomax if (cmcred->cmcred_ngroups < 0) { 666309554Ssobomax uc_logmsgx("cmsgcred.cmcred_ngroups %d < 0", 667309554Ssobomax cmcred->cmcred_ngroups); 668309554Ssobomax rc = -1; 669309554Ssobomax } 670309554Ssobomax if (cmcred->cmcred_ngroups > CMGROUP_MAX) { 671309554Ssobomax uc_logmsgx("cmsgcred.cmcred_ngroups %d > %d", 672309554Ssobomax cmcred->cmcred_ngroups, CMGROUP_MAX); 673309554Ssobomax rc = -1; 674309554Ssobomax } 675309554Ssobomax if (cmcred->cmcred_groups[0] != uc_cfg.proc_cred.egid) { 676309554Ssobomax uc_logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)", 677309554Ssobomax (u_long)cmcred->cmcred_groups[0], (u_long)uc_cfg.proc_cred.egid); 678309554Ssobomax rc = -1; 679309554Ssobomax } 680309554Ssobomax if (uc_check_groups("cmsgcred.cmcred_groups", cmcred->cmcred_groups, 681309554Ssobomax "cmsgcred.cmcred_ngroups", cmcred->cmcred_ngroups, false) < 0) 682309554Ssobomax rc = -1; 683309554Ssobomax return (rc); 684309554Ssobomax} 685309554Ssobomax 686309554Ssobomaxint 687309554Ssobomaxuc_check_scm_creds_sockcred(struct cmsghdr *cmsghdr) 688309554Ssobomax{ 689309554Ssobomax const struct sockcred *sc; 690309554Ssobomax int rc; 691309554Ssobomax 692309554Ssobomax if (uc_check_cmsghdr(cmsghdr, SCM_CREDS, 693309554Ssobomax SOCKCREDSIZE(uc_cfg.proc_cred.gid_num)) < 0) 694309554Ssobomax return (-1); 695309554Ssobomax 696309554Ssobomax sc = (struct sockcred *)CMSG_DATA(cmsghdr); 697309554Ssobomax 698309554Ssobomax rc = 0; 699309554Ssobomax 700309554Ssobomax uc_dbgmsg("sockcred.sc_uid %lu", (u_long)sc->sc_uid); 701309554Ssobomax uc_dbgmsg("sockcred.sc_euid %lu", (u_long)sc->sc_euid); 702309554Ssobomax uc_dbgmsg("sockcred.sc_gid %lu", (u_long)sc->sc_gid); 703309554Ssobomax uc_dbgmsg("sockcred.sc_egid %lu", (u_long)sc->sc_egid); 704309554Ssobomax uc_dbgmsg("sockcred.sc_ngroups %d", sc->sc_ngroups); 705309554Ssobomax 706309554Ssobomax if (sc->sc_uid != uc_cfg.proc_cred.uid) { 707309554Ssobomax uc_logmsgx("sockcred.sc_uid %lu != %lu", 708309554Ssobomax (u_long)sc->sc_uid, (u_long)uc_cfg.proc_cred.uid); 709309554Ssobomax rc = -1; 710309554Ssobomax } 711309554Ssobomax if (sc->sc_euid != uc_cfg.proc_cred.euid) { 712309554Ssobomax uc_logmsgx("sockcred.sc_euid %lu != %lu", 713309554Ssobomax (u_long)sc->sc_euid, (u_long)uc_cfg.proc_cred.euid); 714309554Ssobomax rc = -1; 715309554Ssobomax } 716309554Ssobomax if (sc->sc_gid != uc_cfg.proc_cred.gid) { 717309554Ssobomax uc_logmsgx("sockcred.sc_gid %lu != %lu", 718309554Ssobomax (u_long)sc->sc_gid, (u_long)uc_cfg.proc_cred.gid); 719309554Ssobomax rc = -1; 720309554Ssobomax } 721309554Ssobomax if (sc->sc_egid != uc_cfg.proc_cred.egid) { 722309554Ssobomax uc_logmsgx("sockcred.sc_egid %lu != %lu", 723309554Ssobomax (u_long)sc->sc_egid, (u_long)uc_cfg.proc_cred.egid); 724309554Ssobomax rc = -1; 725309554Ssobomax } 726309554Ssobomax if (sc->sc_ngroups == 0) { 727309554Ssobomax uc_logmsgx("sockcred.sc_ngroups == 0"); 728309554Ssobomax rc = -1; 729309554Ssobomax } 730309554Ssobomax if (sc->sc_ngroups < 0) { 731309554Ssobomax uc_logmsgx("sockcred.sc_ngroups %d < 0", 732309554Ssobomax sc->sc_ngroups); 733309554Ssobomax rc = -1; 734309554Ssobomax } 735309554Ssobomax if (sc->sc_ngroups != uc_cfg.proc_cred.gid_num) { 736309554Ssobomax uc_logmsgx("sockcred.sc_ngroups %d != %u", 737309554Ssobomax sc->sc_ngroups, uc_cfg.proc_cred.gid_num); 738309554Ssobomax rc = -1; 739309554Ssobomax } 740309554Ssobomax if (uc_check_groups("sockcred.sc_groups", sc->sc_groups, 741309554Ssobomax "sockcred.sc_ngroups", sc->sc_ngroups, true) < 0) 742309554Ssobomax rc = -1; 743309554Ssobomax return (rc); 744309554Ssobomax} 745