1159045Smaxim/*- 2159045Smaxim * Copyright (c) 2005 Andrey Simonenko 3159045Smaxim * All rights reserved. 4159045Smaxim * 5159045Smaxim * Redistribution and use in source and binary forms, with or without 6159045Smaxim * modification, are permitted provided that the following conditions 7159045Smaxim * are met: 8159045Smaxim * 1. Redistributions of source code must retain the above copyright 9159045Smaxim * notice, this list of conditions and the following disclaimer. 10159045Smaxim * 2. Redistributions in binary form must reproduce the above copyright 11159045Smaxim * notice, this list of conditions and the following disclaimer in the 12159045Smaxim * documentation and/or other materials provided with the distribution. 13159045Smaxim * 14159045Smaxim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15159045Smaxim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16159045Smaxim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17159045Smaxim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18159045Smaxim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19159045Smaxim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20159045Smaxim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21159045Smaxim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22159045Smaxim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23159045Smaxim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24159045Smaxim * SUCH DAMAGE. 25159045Smaxim */ 26159045Smaxim 27159045Smaxim#include <sys/cdefs.h> 28159045Smaxim__FBSDID("$FreeBSD$"); 29159045Smaxim 30246670Spluknet#include <sys/param.h> 31159045Smaxim#include <sys/resource.h> 32159045Smaxim#include <sys/time.h> 33246670Spluknet#include <sys/select.h> 34159045Smaxim#include <sys/socket.h> 35246670Spluknet#include <sys/ucred.h> 36159045Smaxim#include <sys/un.h> 37159045Smaxim#include <sys/wait.h> 38159045Smaxim 39159045Smaxim#include <ctype.h> 40159045Smaxim#include <err.h> 41159045Smaxim#include <errno.h> 42246670Spluknet#include <fcntl.h> 43159045Smaxim#include <inttypes.h> 44159045Smaxim#include <limits.h> 45246670Spluknet#include <paths.h> 46159045Smaxim#include <signal.h> 47159045Smaxim#include <stdarg.h> 48246670Spluknet#include <stdbool.h> 49159045Smaxim#include <stdint.h> 50159045Smaxim#include <stdio.h> 51159045Smaxim#include <stdlib.h> 52159045Smaxim#include <string.h> 53159045Smaxim#include <unistd.h> 54159045Smaxim 55159045Smaxim/* 56159045Smaxim * There are tables with tests descriptions and pointers to test 57159045Smaxim * functions. Each t_*() function returns 0 if its test passed, 58246670Spluknet * -1 if its test failed, -2 if some system error occurred. 59246670Spluknet * If a test function returns -2, then a program exits. 60159045Smaxim * 61246670Spluknet * If a test function forks a client process, then it waits for its 62246670Spluknet * termination. If a return code of a client process is not equal 63246670Spluknet * to zero, or if a client process was terminated by a signal, then 64246670Spluknet * a test function returns -1 or -2 depending on exit status of 65246670Spluknet * a client process. 66159045Smaxim * 67246670Spluknet * Each function which can block, is run under TIMEOUT. If timeout 68246670Spluknet * occurs, then a test function returns -2 or a client process exits 69246670Spluknet * with a non-zero return code. 70159045Smaxim */ 71159045Smaxim 72159045Smaxim#ifndef LISTENQ 73159045Smaxim# define LISTENQ 1 74159045Smaxim#endif 75159045Smaxim 76159045Smaxim#ifndef TIMEOUT 77246670Spluknet# define TIMEOUT 2 78159045Smaxim#endif 79159045Smaxim 80246670Spluknetstatic int t_cmsgcred(void); 81246670Spluknetstatic int t_sockcred_1(void); 82246670Spluknetstatic int t_sockcred_2(void); 83246670Spluknetstatic int t_cmsgcred_sockcred(void); 84246670Spluknetstatic int t_timeval(void); 85246670Spluknetstatic int t_bintime(void); 86246670Spluknetstatic int t_cmsg_len(void); 87246670Spluknetstatic int t_peercred(void); 88159045Smaxim 89159045Smaximstruct test_func { 90246670Spluknet int (*func)(void); 91246670Spluknet const char *desc; 92159045Smaxim}; 93159045Smaxim 94246670Spluknetstatic const struct test_func test_stream_tbl[] = { 95246670Spluknet { 96246670Spluknet .func = NULL, 97246670Spluknet .desc = "All tests" 98246670Spluknet }, 99246670Spluknet { 100246670Spluknet .func = t_cmsgcred, 101246670Spluknet .desc = "Sending, receiving cmsgcred" 102246670Spluknet }, 103246670Spluknet { 104246670Spluknet .func = t_sockcred_1, 105246670Spluknet .desc = "Receiving sockcred (listening socket)" 106246670Spluknet }, 107246670Spluknet { 108246670Spluknet .func = t_sockcred_2, 109246670Spluknet .desc = "Receiving sockcred (accepted socket)" 110246670Spluknet }, 111246670Spluknet { 112246670Spluknet .func = t_cmsgcred_sockcred, 113246670Spluknet .desc = "Sending cmsgcred, receiving sockcred" 114246670Spluknet }, 115246670Spluknet { 116246670Spluknet .func = t_timeval, 117246670Spluknet .desc = "Sending, receiving timeval" 118246670Spluknet }, 119246670Spluknet { 120246670Spluknet .func = t_bintime, 121246670Spluknet .desc = "Sending, receiving bintime" 122246670Spluknet }, 123246670Spluknet { 124246670Spluknet .func = t_cmsg_len, 125246670Spluknet .desc = "Check cmsghdr.cmsg_len" 126246670Spluknet }, 127246670Spluknet { 128246670Spluknet .func = t_peercred, 129246670Spluknet .desc = "Check LOCAL_PEERCRED socket option" 130246670Spluknet } 131159045Smaxim}; 132159045Smaxim 133246670Spluknet#define TEST_STREAM_TBL_SIZE \ 134246670Spluknet (sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0])) 135246670Spluknet 136246670Spluknetstatic const struct test_func test_dgram_tbl[] = { 137246670Spluknet { 138246670Spluknet .func = NULL, 139246670Spluknet .desc = "All tests" 140246670Spluknet }, 141246670Spluknet { 142246670Spluknet .func = t_cmsgcred, 143246670Spluknet .desc = "Sending, receiving cmsgcred" 144246670Spluknet }, 145246670Spluknet { 146246670Spluknet .func = t_sockcred_2, 147246670Spluknet .desc = "Receiving sockcred" 148246670Spluknet }, 149246670Spluknet { 150246670Spluknet .func = t_cmsgcred_sockcred, 151246670Spluknet .desc = "Sending cmsgcred, receiving sockcred" 152246670Spluknet }, 153246670Spluknet { 154246670Spluknet .func = t_timeval, 155246670Spluknet .desc = "Sending, receiving timeval" 156246670Spluknet }, 157246670Spluknet { 158246670Spluknet .func = t_bintime, 159246670Spluknet .desc = "Sending, receiving bintime" 160246670Spluknet }, 161246670Spluknet { 162246670Spluknet .func = t_cmsg_len, 163246670Spluknet .desc = "Check cmsghdr.cmsg_len" 164246670Spluknet } 165159045Smaxim}; 166159045Smaxim 167246670Spluknet#define TEST_DGRAM_TBL_SIZE \ 168246670Spluknet (sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0])) 169159045Smaxim 170246670Spluknetstatic bool debug = false; 171246670Spluknetstatic bool server_flag = true; 172246670Spluknetstatic bool send_data_flag = true; 173246670Spluknetstatic bool send_array_flag = true; 174246670Spluknetstatic bool failed_flag = false; 175159045Smaxim 176246670Spluknetstatic int sock_type; 177246670Spluknetstatic const char *sock_type_str; 178159045Smaxim 179246670Spluknetstatic const char *proc_name; 180159045Smaxim 181246670Spluknetstatic char work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX"; 182246670Spluknetstatic int serv_sock_fd; 183246670Spluknetstatic struct sockaddr_un serv_addr_sun; 184159045Smaxim 185246670Spluknetstatic struct { 186246670Spluknet char *buf_send; 187246670Spluknet char *buf_recv; 188246670Spluknet size_t buf_size; 189246670Spluknet u_int msg_num; 190246670Spluknet} ipc_msg; 191159045Smaxim 192246670Spluknet#define IPC_MSG_NUM_DEF 5 193246670Spluknet#define IPC_MSG_NUM_MAX 10 194246670Spluknet#define IPC_MSG_SIZE_DEF 7 195246670Spluknet#define IPC_MSG_SIZE_MAX 128 196159045Smaxim 197246670Spluknetstatic struct { 198246670Spluknet uid_t uid; 199246670Spluknet uid_t euid; 200246670Spluknet gid_t gid; 201246670Spluknet gid_t egid; 202246670Spluknet gid_t *gid_arr; 203246670Spluknet int gid_num; 204246670Spluknet} proc_cred; 205159045Smaxim 206246670Spluknetstatic pid_t client_pid; 207159045Smaxim 208246670Spluknet#define SYNC_SERVER 0 209246670Spluknet#define SYNC_CLIENT 1 210246670Spluknet#define SYNC_RECV 0 211246670Spluknet#define SYNC_SEND 1 212159045Smaxim 213246670Spluknetstatic int sync_fd[2][2]; 214159045Smaxim 215246670Spluknet#define LOGMSG_SIZE 128 216159045Smaxim 217159045Smaximstatic void logmsg(const char *, ...) __printflike(1, 2); 218159045Smaximstatic void logmsgx(const char *, ...) __printflike(1, 2); 219246670Spluknetstatic void dbgmsg(const char *, ...) __printflike(1, 2); 220159045Smaximstatic void output(const char *, ...) __printflike(1, 2); 221159045Smaxim 222159045Smaximstatic void 223246670Spluknetusage(bool verbose) 224159045Smaxim{ 225246670Spluknet u_int i; 226159045Smaxim 227246670Spluknet printf("usage: %s [-dh] [-n num] [-s size] [-t type] " 228246670Spluknet "[-z value] [testno]\n", getprogname()); 229246670Spluknet if (!verbose) 230159095Smaxim return; 231246670Spluknet printf("\n Options are:\n\ 232246670Spluknet -d Output debugging information\n\ 233246670Spluknet -h Output the help message and exit\n\ 234246670Spluknet -n num Number of messages to send\n\ 235246670Spluknet -s size Specify size of data for IPC\n\ 236246670Spluknet -t type Specify socket type (stream, dgram) for tests\n\ 237246670Spluknet -z value Do not send data in a message (bit 0x1), do not send\n\ 238246670Spluknet data array associated with a cmsghdr structure (bit 0x2)\n\ 239246670Spluknet testno Run one test by its number (require the -t option)\n\n"); 240246670Spluknet printf(" Available tests for stream sockets:\n"); 241246670Spluknet for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i) 242246670Spluknet printf(" %u: %s\n", i, test_stream_tbl[i].desc); 243246670Spluknet printf("\n Available tests for datagram sockets:\n"); 244246670Spluknet for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i) 245246670Spluknet printf(" %u: %s\n", i, test_dgram_tbl[i].desc); 246159045Smaxim} 247159045Smaxim 248159045Smaximstatic void 249159045Smaximoutput(const char *format, ...) 250159045Smaxim{ 251246670Spluknet char buf[LOGMSG_SIZE]; 252159045Smaxim va_list ap; 253159045Smaxim 254159045Smaxim va_start(ap, format); 255159045Smaxim if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 256246670Spluknet err(EXIT_FAILURE, "output: vsnprintf failed"); 257159045Smaxim write(STDOUT_FILENO, buf, strlen(buf)); 258159045Smaxim va_end(ap); 259159045Smaxim} 260159045Smaxim 261159045Smaximstatic void 262159045Smaximlogmsg(const char *format, ...) 263159045Smaxim{ 264246670Spluknet char buf[LOGMSG_SIZE]; 265159045Smaxim va_list ap; 266159045Smaxim int errno_save; 267159045Smaxim 268246670Spluknet errno_save = errno; 269159045Smaxim va_start(ap, format); 270159045Smaxim if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 271246670Spluknet err(EXIT_FAILURE, "logmsg: vsnprintf failed"); 272159045Smaxim if (errno_save == 0) 273246670Spluknet output("%s: %s\n", proc_name, buf); 274159045Smaxim else 275246670Spluknet output("%s: %s: %s\n", proc_name, buf, strerror(errno_save)); 276159045Smaxim va_end(ap); 277246670Spluknet errno = errno_save; 278246670Spluknet} 279159045Smaxim 280246670Spluknetstatic void 281246670Spluknetvlogmsgx(const char *format, va_list ap) 282246670Spluknet{ 283246670Spluknet char buf[LOGMSG_SIZE]; 284246670Spluknet 285246670Spluknet if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 286246670Spluknet err(EXIT_FAILURE, "logmsgx: vsnprintf failed"); 287246670Spluknet output("%s: %s\n", proc_name, buf); 288246670Spluknet 289159045Smaxim} 290159045Smaxim 291159045Smaximstatic void 292159045Smaximlogmsgx(const char *format, ...) 293159045Smaxim{ 294159045Smaxim va_list ap; 295159045Smaxim 296159045Smaxim va_start(ap, format); 297246670Spluknet vlogmsgx(format, ap); 298159045Smaxim va_end(ap); 299159045Smaxim} 300159045Smaxim 301246670Spluknetstatic void 302246670Spluknetdbgmsg(const char *format, ...) 303246670Spluknet{ 304246670Spluknet va_list ap; 305246670Spluknet 306246670Spluknet if (debug) { 307246670Spluknet va_start(ap, format); 308246670Spluknet vlogmsgx(format, ap); 309246670Spluknet va_end(ap); 310246670Spluknet } 311246670Spluknet} 312246670Spluknet 313159045Smaximstatic int 314246670Spluknetrun_tests(int type, u_int testno1) 315159045Smaxim{ 316246670Spluknet const struct test_func *tf; 317246670Spluknet u_int i, testno2, failed_num; 318159045Smaxim 319246670Spluknet sock_type = type; 320246670Spluknet if (type == SOCK_STREAM) { 321246670Spluknet sock_type_str = "SOCK_STREAM"; 322246670Spluknet tf = test_stream_tbl; 323246670Spluknet i = TEST_STREAM_TBL_SIZE - 1; 324246670Spluknet } else { 325246670Spluknet sock_type_str = "SOCK_DGRAM"; 326246670Spluknet tf = test_dgram_tbl; 327246670Spluknet i = TEST_DGRAM_TBL_SIZE - 1; 328246670Spluknet } 329246670Spluknet if (testno1 == 0) { 330246670Spluknet testno1 = 1; 331246670Spluknet testno2 = i; 332246670Spluknet } else 333246670Spluknet testno2 = testno1; 334246670Spluknet 335159045Smaxim output("Running tests for %s sockets:\n", sock_type_str); 336246670Spluknet failed_num = 0; 337246670Spluknet for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) { 338246670Spluknet output(" %u: %s\n", i, tf->desc); 339246670Spluknet switch (tf->func()) { 340159045Smaxim case -1: 341246670Spluknet ++failed_num; 342159045Smaxim break; 343159045Smaxim case -2: 344246670Spluknet logmsgx("some system error or timeout occurred"); 345159045Smaxim return (-1); 346159045Smaxim } 347159045Smaxim } 348159045Smaxim 349246670Spluknet if (failed_num != 0) 350246670Spluknet failed_flag = true; 351159045Smaxim 352159045Smaxim if (testno1 != testno2) { 353246670Spluknet if (failed_num == 0) 354246670Spluknet output("-- all tests passed!\n"); 355159045Smaxim else 356246670Spluknet output("-- %u test%s failed!\n", 357246670Spluknet failed_num, failed_num == 1 ? "" : "s"); 358159045Smaxim } else { 359246670Spluknet if (failed_num == 0) 360246670Spluknet output("-- test passed!\n"); 361159045Smaxim else 362159045Smaxim output("-- test failed!\n"); 363159045Smaxim } 364159045Smaxim 365159045Smaxim return (0); 366159045Smaxim} 367159045Smaxim 368246670Spluknetstatic int 369246670Spluknetinit(void) 370159045Smaxim{ 371246670Spluknet struct sigaction sigact; 372246670Spluknet size_t idx; 373246670Spluknet int rv; 374246670Spluknet 375246670Spluknet proc_name = "SERVER"; 376246670Spluknet 377246670Spluknet sigact.sa_handler = SIG_IGN; 378246670Spluknet sigact.sa_flags = 0; 379246670Spluknet sigemptyset(&sigact.sa_mask); 380246670Spluknet if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) { 381246670Spluknet logmsg("init: sigaction"); 382246670Spluknet return (-1); 383246670Spluknet } 384246670Spluknet 385246670Spluknet if (ipc_msg.buf_size == 0) 386246670Spluknet ipc_msg.buf_send = ipc_msg.buf_recv = NULL; 387246670Spluknet else { 388246670Spluknet ipc_msg.buf_send = malloc(ipc_msg.buf_size); 389246670Spluknet ipc_msg.buf_recv = malloc(ipc_msg.buf_size); 390246670Spluknet if (ipc_msg.buf_send == NULL || ipc_msg.buf_recv == NULL) { 391246670Spluknet logmsg("init: malloc"); 392246670Spluknet return (-1); 393246670Spluknet } 394246670Spluknet for (idx = 0; idx < ipc_msg.buf_size; ++idx) 395246670Spluknet ipc_msg.buf_send[idx] = (char)idx; 396246670Spluknet } 397246670Spluknet 398246670Spluknet proc_cred.uid = getuid(); 399246670Spluknet proc_cred.euid = geteuid(); 400246670Spluknet proc_cred.gid = getgid(); 401246670Spluknet proc_cred.egid = getegid(); 402246670Spluknet proc_cred.gid_num = getgroups(0, (gid_t *)NULL); 403246670Spluknet if (proc_cred.gid_num < 0) { 404246670Spluknet logmsg("init: getgroups"); 405246670Spluknet return (-1); 406246670Spluknet } 407246670Spluknet proc_cred.gid_arr = malloc(proc_cred.gid_num * 408246670Spluknet sizeof(*proc_cred.gid_arr)); 409246670Spluknet if (proc_cred.gid_arr == NULL) { 410246670Spluknet logmsg("init: malloc"); 411246670Spluknet return (-1); 412246670Spluknet } 413246670Spluknet if (getgroups(proc_cred.gid_num, proc_cred.gid_arr) < 0) { 414246670Spluknet logmsg("init: getgroups"); 415246670Spluknet return (-1); 416246670Spluknet } 417246670Spluknet 418246670Spluknet memset(&serv_addr_sun, 0, sizeof(serv_addr_sun)); 419246670Spluknet rv = snprintf(serv_addr_sun.sun_path, sizeof(serv_addr_sun.sun_path), 420246670Spluknet "%s/%s", work_dir, proc_name); 421246670Spluknet if (rv < 0) { 422246670Spluknet logmsg("init: snprintf"); 423246670Spluknet return (-1); 424246670Spluknet } 425246670Spluknet if ((size_t)rv >= sizeof(serv_addr_sun.sun_path)) { 426246670Spluknet logmsgx("init: not enough space for socket pathname"); 427246670Spluknet return (-1); 428246670Spluknet } 429246670Spluknet serv_addr_sun.sun_family = PF_LOCAL; 430246670Spluknet serv_addr_sun.sun_len = SUN_LEN(&serv_addr_sun); 431246670Spluknet 432246670Spluknet return (0); 433159045Smaxim} 434159045Smaxim 435246670Spluknetstatic int 436246670Spluknetclient_fork(void) 437246670Spluknet{ 438246670Spluknet int fd1, fd2; 439246670Spluknet 440246670Spluknet if (pipe(sync_fd[SYNC_SERVER]) < 0 || 441246670Spluknet pipe(sync_fd[SYNC_CLIENT]) < 0) { 442246670Spluknet logmsg("client_fork: pipe"); 443246670Spluknet return (-1); 444246670Spluknet } 445246670Spluknet client_pid = fork(); 446246670Spluknet if (client_pid == (pid_t)-1) { 447246670Spluknet logmsg("client_fork: fork"); 448246670Spluknet return (-1); 449246670Spluknet } 450246670Spluknet if (client_pid == 0) { 451246670Spluknet proc_name = "CLIENT"; 452246670Spluknet server_flag = false; 453246670Spluknet fd1 = sync_fd[SYNC_SERVER][SYNC_RECV]; 454246670Spluknet fd2 = sync_fd[SYNC_CLIENT][SYNC_SEND]; 455246670Spluknet } else { 456246670Spluknet fd1 = sync_fd[SYNC_SERVER][SYNC_SEND]; 457246670Spluknet fd2 = sync_fd[SYNC_CLIENT][SYNC_RECV]; 458246670Spluknet } 459246670Spluknet if (close(fd1) < 0 || close(fd2) < 0) { 460246670Spluknet logmsg("client_fork: close"); 461246670Spluknet return (-1); 462246670Spluknet } 463246670Spluknet return (client_pid != 0); 464246670Spluknet} 465246670Spluknet 466159045Smaximstatic void 467246670Spluknetclient_exit(int rv) 468159045Smaxim{ 469246670Spluknet if (close(sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 || 470246670Spluknet close(sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) { 471246670Spluknet logmsg("client_exit: close"); 472246670Spluknet rv = -1; 473246670Spluknet } 474246670Spluknet rv = rv == 0 ? EXIT_SUCCESS : -rv; 475246670Spluknet dbgmsg("exit: code %d", rv); 476246670Spluknet _exit(rv); 477246670Spluknet} 478159045Smaxim 479246670Spluknetstatic int 480246670Spluknetclient_wait(void) 481246670Spluknet{ 482246670Spluknet int status; 483246670Spluknet pid_t pid; 484159045Smaxim 485246670Spluknet dbgmsg("waiting for client"); 486246670Spluknet 487246670Spluknet if (close(sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 || 488246670Spluknet close(sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) { 489246670Spluknet logmsg("client_wait: close"); 490246670Spluknet return (-1); 491246670Spluknet } 492246670Spluknet 493246670Spluknet pid = waitpid(client_pid, &status, 0); 494246670Spluknet if (pid == (pid_t)-1) { 495246670Spluknet logmsg("client_wait: waitpid"); 496246670Spluknet return (-1); 497246670Spluknet } 498246670Spluknet 499246670Spluknet if (WIFEXITED(status)) { 500246670Spluknet if (WEXITSTATUS(status) != EXIT_SUCCESS) { 501246670Spluknet logmsgx("client exit status is %d", 502246670Spluknet WEXITSTATUS(status)); 503246670Spluknet return (-WEXITSTATUS(status)); 504246670Spluknet } 505246670Spluknet } else { 506246670Spluknet if (WIFSIGNALED(status)) 507246670Spluknet logmsgx("abnormal termination of client, signal %d%s", 508246670Spluknet WTERMSIG(status), WCOREDUMP(status) ? 509246670Spluknet " (core file generated)" : ""); 510246670Spluknet else 511246670Spluknet logmsgx("termination of client, unknown status"); 512246670Spluknet return (-1); 513246670Spluknet } 514246670Spluknet 515246670Spluknet return (0); 516159045Smaxim} 517159045Smaxim 518159045Smaximint 519159045Smaximmain(int argc, char *argv[]) 520159045Smaxim{ 521159045Smaxim const char *errstr; 522246670Spluknet u_int testno, zvalue; 523246670Spluknet int opt, rv; 524246670Spluknet bool dgram_flag, stream_flag; 525159045Smaxim 526246670Spluknet ipc_msg.buf_size = IPC_MSG_SIZE_DEF; 527246670Spluknet ipc_msg.msg_num = IPC_MSG_NUM_DEF; 528246670Spluknet dgram_flag = stream_flag = false; 529246670Spluknet while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1) 530159045Smaxim switch (opt) { 531159045Smaxim case 'd': 532246670Spluknet debug = true; 533159045Smaxim break; 534159045Smaxim case 'h': 535246670Spluknet usage(true); 536246670Spluknet return (EXIT_SUCCESS); 537246670Spluknet case 'n': 538246670Spluknet ipc_msg.msg_num = strtonum(optarg, 1, 539246670Spluknet IPC_MSG_NUM_MAX, &errstr); 540246670Spluknet if (errstr != NULL) 541246670Spluknet errx(EXIT_FAILURE, "option -n: number is %s", 542246670Spluknet errstr); 543246670Spluknet break; 544246670Spluknet case 's': 545246670Spluknet ipc_msg.buf_size = strtonum(optarg, 0, 546246670Spluknet IPC_MSG_SIZE_MAX, &errstr); 547246670Spluknet if (errstr != NULL) 548246670Spluknet errx(EXIT_FAILURE, "option -s: number is %s", 549246670Spluknet errstr); 550246670Spluknet break; 551159045Smaxim case 't': 552159045Smaxim if (strcmp(optarg, "stream") == 0) 553246670Spluknet stream_flag = true; 554159045Smaxim else if (strcmp(optarg, "dgram") == 0) 555246670Spluknet dgram_flag = true; 556159045Smaxim else 557246670Spluknet errx(EXIT_FAILURE, "option -t: " 558246670Spluknet "wrong socket type"); 559159045Smaxim break; 560159045Smaxim case 'z': 561246670Spluknet zvalue = strtonum(optarg, 0, 3, &errstr); 562246670Spluknet if (errstr != NULL) 563246670Spluknet errx(EXIT_FAILURE, "option -z: number is %s", 564246670Spluknet errstr); 565246670Spluknet if (zvalue & 0x1) 566246670Spluknet send_data_flag = false; 567246670Spluknet if (zvalue & 0x2) 568246670Spluknet send_array_flag = false; 569159045Smaxim break; 570159045Smaxim default: 571246670Spluknet usage(false); 572246670Spluknet return (EXIT_FAILURE); 573159045Smaxim } 574159045Smaxim 575159045Smaxim if (optind < argc) { 576159045Smaxim if (optind + 1 != argc) 577246670Spluknet errx(EXIT_FAILURE, "too many arguments"); 578246670Spluknet testno = strtonum(argv[optind], 0, UINT_MAX, &errstr); 579159045Smaxim if (errstr != NULL) 580246670Spluknet errx(EXIT_FAILURE, "test number is %s", errstr); 581246670Spluknet if (stream_flag && testno >= TEST_STREAM_TBL_SIZE) 582246670Spluknet errx(EXIT_FAILURE, "given test %u for stream " 583246670Spluknet "sockets does not exist", testno); 584246670Spluknet if (dgram_flag && testno >= TEST_DGRAM_TBL_SIZE) 585246670Spluknet errx(EXIT_FAILURE, "given test %u for datagram " 586246670Spluknet "sockets does not exist", testno); 587159045Smaxim } else 588246670Spluknet testno = 0; 589159045Smaxim 590246670Spluknet if (!dgram_flag && !stream_flag) { 591246670Spluknet if (testno != 0) 592246670Spluknet errx(EXIT_FAILURE, "particular test number " 593246670Spluknet "can be used with the -t option only"); 594246670Spluknet dgram_flag = stream_flag = true; 595159045Smaxim } 596159045Smaxim 597246670Spluknet if (mkdtemp(work_dir) == NULL) 598246670Spluknet err(EXIT_FAILURE, "mkdtemp(%s)", work_dir); 599159045Smaxim 600246670Spluknet rv = EXIT_FAILURE; 601246670Spluknet if (init() < 0) 602246670Spluknet goto done; 603159045Smaxim 604246670Spluknet if (stream_flag) 605246670Spluknet if (run_tests(SOCK_STREAM, testno) < 0) 606246670Spluknet goto done; 607246670Spluknet if (dgram_flag) 608246670Spluknet if (run_tests(SOCK_DGRAM, testno) < 0) 609246670Spluknet goto done; 610159045Smaxim 611246670Spluknet rv = EXIT_SUCCESS; 612246670Spluknetdone: 613246670Spluknet if (rmdir(work_dir) < 0) { 614246670Spluknet logmsg("rmdir(%s)", work_dir); 615246670Spluknet rv = EXIT_FAILURE; 616159045Smaxim } 617246670Spluknet return (failed_flag ? EXIT_FAILURE : rv); 618246670Spluknet} 619159045Smaxim 620246670Spluknetstatic int 621246670Spluknetsocket_close(int fd) 622246670Spluknet{ 623246670Spluknet int rv; 624159045Smaxim 625246670Spluknet rv = 0; 626246670Spluknet if (close(fd) < 0) { 627246670Spluknet logmsg("socket_close: close"); 628246670Spluknet rv = -1; 629159045Smaxim } 630246670Spluknet if (server_flag && fd == serv_sock_fd) 631246670Spluknet if (unlink(serv_addr_sun.sun_path) < 0) { 632246670Spluknet logmsg("socket_close: unlink(%s)", 633246670Spluknet serv_addr_sun.sun_path); 634246670Spluknet rv = -1; 635246670Spluknet } 636246670Spluknet return (rv); 637159045Smaxim} 638159045Smaxim 639159045Smaximstatic int 640246670Spluknetsocket_create(void) 641159045Smaxim{ 642246670Spluknet struct timeval tv; 643246670Spluknet int fd; 644159045Smaxim 645246670Spluknet fd = socket(PF_LOCAL, sock_type, 0); 646246670Spluknet if (fd < 0) { 647246670Spluknet logmsg("socket_create: socket(PF_LOCAL, %s, 0)", sock_type_str); 648159045Smaxim return (-1); 649159045Smaxim } 650246670Spluknet if (server_flag) 651246670Spluknet serv_sock_fd = fd; 652159045Smaxim 653246670Spluknet tv.tv_sec = TIMEOUT; 654246670Spluknet tv.tv_usec = 0; 655246670Spluknet if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 || 656246670Spluknet setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { 657246670Spluknet logmsg("socket_create: setsockopt(SO_RCVTIMEO/SO_SNDTIMEO)"); 658246670Spluknet goto failed; 659246670Spluknet } 660159045Smaxim 661246670Spluknet if (server_flag) { 662246670Spluknet if (bind(fd, (struct sockaddr *)&serv_addr_sun, 663246670Spluknet serv_addr_sun.sun_len) < 0) { 664246670Spluknet logmsg("socket_create: bind(%s)", 665246670Spluknet serv_addr_sun.sun_path); 666159045Smaxim goto failed; 667159045Smaxim } 668246670Spluknet if (sock_type == SOCK_STREAM) { 669246670Spluknet int val; 670159045Smaxim 671246670Spluknet if (listen(fd, LISTENQ) < 0) { 672246670Spluknet logmsg("socket_create: listen"); 673246670Spluknet goto failed; 674246670Spluknet } 675246670Spluknet val = fcntl(fd, F_GETFL, 0); 676246670Spluknet if (val < 0) { 677246670Spluknet logmsg("socket_create: fcntl(F_GETFL)"); 678246670Spluknet goto failed; 679246670Spluknet } 680246670Spluknet if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) { 681246670Spluknet logmsg("socket_create: fcntl(F_SETFL)"); 682246670Spluknet goto failed; 683246670Spluknet } 684159045Smaxim } 685159045Smaxim } 686159045Smaxim 687159045Smaxim return (fd); 688159045Smaxim 689159045Smaximfailed: 690159045Smaxim if (close(fd) < 0) 691246670Spluknet logmsg("socket_create: close"); 692246670Spluknet if (server_flag) 693246670Spluknet if (unlink(serv_addr_sun.sun_path) < 0) 694246670Spluknet logmsg("socket_close: unlink(%s)", 695246670Spluknet serv_addr_sun.sun_path); 696159045Smaxim return (-1); 697159045Smaxim} 698159045Smaxim 699159045Smaximstatic int 700246670Spluknetsocket_connect(int fd) 701159045Smaxim{ 702246670Spluknet dbgmsg("connect"); 703159045Smaxim 704246670Spluknet if (connect(fd, (struct sockaddr *)&serv_addr_sun, 705246670Spluknet serv_addr_sun.sun_len) < 0) { 706246670Spluknet logmsg("socket_connect: connect(%s)", serv_addr_sun.sun_path); 707246670Spluknet return (-1); 708246670Spluknet } 709246670Spluknet return (0); 710159045Smaxim} 711159045Smaxim 712159045Smaximstatic int 713246670Spluknetsync_recv(void) 714159045Smaxim{ 715246670Spluknet ssize_t ssize; 716246670Spluknet int fd; 717246670Spluknet char buf; 718159045Smaxim 719246670Spluknet dbgmsg("sync: wait"); 720159045Smaxim 721246670Spluknet fd = sync_fd[server_flag ? SYNC_SERVER : SYNC_CLIENT][SYNC_RECV]; 722159045Smaxim 723246670Spluknet ssize = read(fd, &buf, 1); 724246670Spluknet if (ssize < 0) { 725246670Spluknet logmsg("sync_recv: read"); 726159045Smaxim return (-1); 727159045Smaxim } 728246670Spluknet if (ssize < 1) { 729246670Spluknet logmsgx("sync_recv: read %zd of 1 byte", ssize); 730246670Spluknet return (-1); 731246670Spluknet } 732159045Smaxim 733246670Spluknet dbgmsg("sync: received"); 734246670Spluknet 735159045Smaxim return (0); 736159045Smaxim} 737159045Smaxim 738159045Smaximstatic int 739246670Spluknetsync_send(void) 740159045Smaxim{ 741246670Spluknet ssize_t ssize; 742246670Spluknet int fd; 743159045Smaxim 744246670Spluknet dbgmsg("sync: send"); 745159045Smaxim 746246670Spluknet fd = sync_fd[server_flag ? SYNC_CLIENT : SYNC_SERVER][SYNC_SEND]; 747159045Smaxim 748246670Spluknet ssize = write(fd, "", 1); 749246670Spluknet if (ssize < 0) { 750246670Spluknet logmsg("sync_send: write"); 751159045Smaxim return (-1); 752159045Smaxim } 753246670Spluknet if (ssize < 1) { 754246670Spluknet logmsgx("sync_send: sent %zd of 1 byte", ssize); 755159045Smaxim return (-1); 756159045Smaxim } 757159045Smaxim 758159045Smaxim return (0); 759159045Smaxim} 760159045Smaxim 761159045Smaximstatic int 762246670Spluknetmessage_send(int fd, const struct msghdr *msghdr) 763159045Smaxim{ 764246670Spluknet const struct cmsghdr *cmsghdr; 765246670Spluknet size_t size; 766246670Spluknet ssize_t ssize; 767159045Smaxim 768246670Spluknet size = msghdr->msg_iov != 0 ? msghdr->msg_iov->iov_len : 0; 769246670Spluknet dbgmsg("send: data size %zu", size); 770246670Spluknet dbgmsg("send: msghdr.msg_controllen %u", 771246670Spluknet (u_int)msghdr->msg_controllen); 772246670Spluknet cmsghdr = CMSG_FIRSTHDR(msghdr); 773246670Spluknet if (cmsghdr != NULL) 774246670Spluknet dbgmsg("send: cmsghdr.cmsg_len %u", 775246670Spluknet (u_int)cmsghdr->cmsg_len); 776159045Smaxim 777246670Spluknet ssize = sendmsg(fd, msghdr, 0); 778246670Spluknet if (ssize < 0) { 779246670Spluknet logmsg("message_send: sendmsg"); 780159045Smaxim return (-1); 781159045Smaxim } 782246670Spluknet if ((size_t)ssize != size) { 783246670Spluknet logmsgx("message_send: sendmsg: sent %zd of %zu bytes", 784246670Spluknet ssize, size); 785246670Spluknet return (-1); 786246670Spluknet } 787159045Smaxim 788246670Spluknet if (!send_data_flag) 789246670Spluknet if (sync_send() < 0) 790246670Spluknet return (-1); 791159045Smaxim 792246670Spluknet return (0); 793246670Spluknet} 794159045Smaxim 795246670Spluknetstatic int 796246670Spluknetmessage_sendn(int fd, struct msghdr *msghdr) 797246670Spluknet{ 798246670Spluknet u_int i; 799159045Smaxim 800246670Spluknet for (i = 1; i <= ipc_msg.msg_num; ++i) { 801246670Spluknet dbgmsg("message #%u", i); 802246670Spluknet if (message_send(fd, msghdr) < 0) 803246670Spluknet return (-1); 804159045Smaxim } 805246670Spluknet return (0); 806159045Smaxim} 807159045Smaxim 808159045Smaximstatic int 809246670Spluknetmessage_recv(int fd, struct msghdr *msghdr) 810159045Smaxim{ 811246670Spluknet const struct cmsghdr *cmsghdr; 812246670Spluknet size_t size; 813246670Spluknet ssize_t ssize; 814159045Smaxim 815246670Spluknet if (!send_data_flag) 816246670Spluknet if (sync_recv() < 0) 817246670Spluknet return (-1); 818159045Smaxim 819246670Spluknet size = msghdr->msg_iov != NULL ? msghdr->msg_iov->iov_len : 0; 820246670Spluknet ssize = recvmsg(fd, msghdr, MSG_WAITALL); 821246670Spluknet if (ssize < 0) { 822246670Spluknet logmsg("message_recv: recvmsg"); 823159045Smaxim return (-1); 824159045Smaxim } 825246670Spluknet if ((size_t)ssize != size) { 826246670Spluknet logmsgx("message_recv: recvmsg: received %zd of %zu bytes", 827246670Spluknet ssize, size); 828159045Smaxim return (-1); 829159045Smaxim } 830159045Smaxim 831246670Spluknet dbgmsg("recv: data size %zd", ssize); 832246670Spluknet dbgmsg("recv: msghdr.msg_controllen %u", 833246670Spluknet (u_int)msghdr->msg_controllen); 834246670Spluknet cmsghdr = CMSG_FIRSTHDR(msghdr); 835246670Spluknet if (cmsghdr != NULL) 836246670Spluknet dbgmsg("recv: cmsghdr.cmsg_len %u", 837246670Spluknet (u_int)cmsghdr->cmsg_len); 838246670Spluknet 839246670Spluknet if (memcmp(ipc_msg.buf_recv, ipc_msg.buf_send, size) != 0) { 840246670Spluknet logmsgx("message_recv: received message has wrong content"); 841159045Smaxim return (-1); 842159045Smaxim } 843159045Smaxim 844159045Smaxim return (0); 845159045Smaxim} 846159045Smaxim 847159045Smaximstatic int 848246670Spluknetsocket_accept(int listenfd) 849159045Smaxim{ 850246670Spluknet fd_set rset; 851246670Spluknet struct timeval tv; 852246670Spluknet int fd, rv, val; 853159045Smaxim 854246670Spluknet dbgmsg("accept"); 855159045Smaxim 856246670Spluknet FD_ZERO(&rset); 857246670Spluknet FD_SET(listenfd, &rset); 858246670Spluknet tv.tv_sec = TIMEOUT; 859246670Spluknet tv.tv_usec = 0; 860246670Spluknet rv = select(listenfd + 1, &rset, (fd_set *)NULL, (fd_set *)NULL, &tv); 861246670Spluknet if (rv < 0) { 862246670Spluknet logmsg("socket_accept: select"); 863159045Smaxim return (-1); 864159045Smaxim } 865246670Spluknet if (rv == 0) { 866246670Spluknet logmsgx("socket_accept: select timeout"); 867159045Smaxim return (-1); 868159045Smaxim } 869159045Smaxim 870246670Spluknet fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL); 871246670Spluknet if (fd < 0) { 872246670Spluknet logmsg("socket_accept: accept"); 873159045Smaxim return (-1); 874159045Smaxim } 875159045Smaxim 876246670Spluknet val = fcntl(fd, F_GETFL, 0); 877246670Spluknet if (val < 0) { 878246670Spluknet logmsg("socket_accept: fcntl(F_GETFL)"); 879246670Spluknet goto failed; 880246670Spluknet } 881246670Spluknet if (fcntl(fd, F_SETFL, val & ~O_NONBLOCK) < 0) { 882246670Spluknet logmsg("socket_accept: fcntl(F_SETFL)"); 883246670Spluknet goto failed; 884246670Spluknet } 885246670Spluknet 886246670Spluknet return (fd); 887246670Spluknet 888246670Spluknetfailed: 889246670Spluknet if (close(fd) < 0) 890246670Spluknet logmsg("socket_accept: close"); 891246670Spluknet return (-1); 892159045Smaxim} 893159045Smaxim 894159045Smaximstatic int 895246670Spluknetcheck_msghdr(const struct msghdr *msghdr, size_t size) 896159045Smaxim{ 897246670Spluknet if (msghdr->msg_flags & MSG_TRUNC) { 898246670Spluknet logmsgx("msghdr.msg_flags has MSG_TRUNC"); 899159045Smaxim return (-1); 900159045Smaxim } 901246670Spluknet if (msghdr->msg_flags & MSG_CTRUNC) { 902246670Spluknet logmsgx("msghdr.msg_flags has MSG_CTRUNC"); 903159045Smaxim return (-1); 904159045Smaxim } 905246670Spluknet if (msghdr->msg_controllen < size) { 906246670Spluknet logmsgx("msghdr.msg_controllen %u < %zu", 907246670Spluknet (u_int)msghdr->msg_controllen, size); 908159045Smaxim return (-1); 909159045Smaxim } 910246670Spluknet if (msghdr->msg_controllen > 0 && size == 0) { 911246670Spluknet logmsgx("msghdr.msg_controllen %u > 0", 912246670Spluknet (u_int)msghdr->msg_controllen); 913246670Spluknet return (-1); 914246670Spluknet } 915159045Smaxim return (0); 916159045Smaxim} 917159045Smaxim 918159045Smaximstatic int 919246670Spluknetcheck_cmsghdr(const struct cmsghdr *cmsghdr, int type, size_t size) 920159045Smaxim{ 921246670Spluknet if (cmsghdr == NULL) { 922246670Spluknet logmsgx("cmsghdr is NULL"); 923159045Smaxim return (-1); 924159045Smaxim } 925246670Spluknet if (cmsghdr->cmsg_level != SOL_SOCKET) { 926246670Spluknet logmsgx("cmsghdr.cmsg_level %d != SOL_SOCKET", 927246670Spluknet cmsghdr->cmsg_level); 928159045Smaxim return (-1); 929159045Smaxim } 930246670Spluknet if (cmsghdr->cmsg_type != type) { 931246670Spluknet logmsgx("cmsghdr.cmsg_type %d != %d", 932246670Spluknet cmsghdr->cmsg_type, type); 933159045Smaxim return (-1); 934159045Smaxim } 935246670Spluknet if (cmsghdr->cmsg_len != CMSG_LEN(size)) { 936246670Spluknet logmsgx("cmsghdr.cmsg_len %u != %zu", 937246670Spluknet (u_int)cmsghdr->cmsg_len, CMSG_LEN(size)); 938246670Spluknet return (-1); 939246670Spluknet } 940159045Smaxim return (0); 941159045Smaxim} 942159045Smaxim 943159045Smaximstatic int 944246670Spluknetcheck_groups(const char *gid_arr_str, const gid_t *gid_arr, 945246670Spluknet const char *gid_num_str, int gid_num, bool all_gids) 946159045Smaxim{ 947246670Spluknet int i; 948159045Smaxim 949246670Spluknet for (i = 0; i < gid_num; ++i) 950246670Spluknet dbgmsg("%s[%d] %lu", gid_arr_str, i, (u_long)gid_arr[i]); 951246670Spluknet 952246670Spluknet if (all_gids) { 953246670Spluknet if (gid_num != proc_cred.gid_num) { 954246670Spluknet logmsgx("%s %d != %d", gid_num_str, gid_num, 955246670Spluknet proc_cred.gid_num); 956246670Spluknet return (-1); 957159045Smaxim } 958246670Spluknet } else { 959246670Spluknet if (gid_num > proc_cred.gid_num) { 960246670Spluknet logmsgx("%s %d > %d", gid_num_str, gid_num, 961246670Spluknet proc_cred.gid_num); 962246670Spluknet return (-1); 963159045Smaxim } 964159045Smaxim } 965246670Spluknet if (memcmp(gid_arr, proc_cred.gid_arr, 966246670Spluknet gid_num * sizeof(*gid_arr)) != 0) { 967246670Spluknet logmsgx("%s content is wrong", gid_arr_str); 968246670Spluknet for (i = 0; i < gid_num; ++i) 969246670Spluknet if (gid_arr[i] != proc_cred.gid_arr[i]) { 970246670Spluknet logmsgx("%s[%d] %lu != %lu", 971246670Spluknet gid_arr_str, i, (u_long)gid_arr[i], 972246670Spluknet (u_long)proc_cred.gid_arr[i]); 973246670Spluknet break; 974246670Spluknet } 975246670Spluknet return (-1); 976246670Spluknet } 977246670Spluknet return (0); 978159045Smaxim} 979159045Smaxim 980246670Spluknetstatic int 981246670Spluknetcheck_xucred(const struct xucred *xucred, socklen_t len) 982159045Smaxim{ 983246670Spluknet if (len != sizeof(*xucred)) { 984246670Spluknet logmsgx("option value size %zu != %zu", 985246670Spluknet (size_t)len, sizeof(*xucred)); 986246670Spluknet return (-1); 987246670Spluknet } 988159045Smaxim 989246670Spluknet dbgmsg("xucred.cr_version %u", xucred->cr_version); 990246670Spluknet dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid); 991246670Spluknet dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups); 992159045Smaxim 993246670Spluknet if (xucred->cr_version != XUCRED_VERSION) { 994246670Spluknet logmsgx("xucred.cr_version %u != %d", 995246670Spluknet xucred->cr_version, XUCRED_VERSION); 996246670Spluknet return (-1); 997246670Spluknet } 998246670Spluknet if (xucred->cr_uid != proc_cred.euid) { 999246670Spluknet logmsgx("xucred.cr_uid %lu != %lu (EUID)", 1000246670Spluknet (u_long)xucred->cr_uid, (u_long)proc_cred.euid); 1001246670Spluknet return (-1); 1002246670Spluknet } 1003246670Spluknet if (xucred->cr_ngroups == 0) { 1004246670Spluknet logmsgx("xucred.cr_ngroups == 0"); 1005246670Spluknet return (-1); 1006246670Spluknet } 1007246670Spluknet if (xucred->cr_ngroups < 0) { 1008246670Spluknet logmsgx("xucred.cr_ngroups < 0"); 1009246670Spluknet return (-1); 1010246670Spluknet } 1011246670Spluknet if (xucred->cr_ngroups > XU_NGROUPS) { 1012246670Spluknet logmsgx("xucred.cr_ngroups %hu > %u (max)", 1013246670Spluknet xucred->cr_ngroups, XU_NGROUPS); 1014246670Spluknet return (-1); 1015246670Spluknet } 1016246670Spluknet if (xucred->cr_groups[0] != proc_cred.egid) { 1017246670Spluknet logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)", 1018246670Spluknet (u_long)xucred->cr_groups[0], (u_long)proc_cred.egid); 1019246670Spluknet return (-1); 1020246670Spluknet } 1021246670Spluknet if (check_groups("xucred.cr_groups", xucred->cr_groups, 1022246670Spluknet "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0) 1023246670Spluknet return (-1); 1024246670Spluknet return (0); 1025246670Spluknet} 1026159045Smaxim 1027246670Spluknetstatic int 1028246670Spluknetcheck_scm_creds_cmsgcred(struct cmsghdr *cmsghdr) 1029246670Spluknet{ 1030246670Spluknet const struct cmsgcred *cmsgcred; 1031159045Smaxim 1032246670Spluknet if (check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(*cmsgcred)) < 0) 1033246670Spluknet return (-1); 1034159045Smaxim 1035246670Spluknet cmsgcred = (struct cmsgcred *)CMSG_DATA(cmsghdr); 1036159045Smaxim 1037246670Spluknet dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmsgcred->cmcred_pid); 1038246670Spluknet dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmsgcred->cmcred_uid); 1039246670Spluknet dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmsgcred->cmcred_euid); 1040246670Spluknet dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmsgcred->cmcred_gid); 1041246670Spluknet dbgmsg("cmsgcred.cmcred_ngroups %d", cmsgcred->cmcred_ngroups); 1042159045Smaxim 1043246670Spluknet if (cmsgcred->cmcred_pid != client_pid) { 1044246670Spluknet logmsgx("cmsgcred.cmcred_pid %ld != %ld", 1045246670Spluknet (long)cmsgcred->cmcred_pid, (long)client_pid); 1046246670Spluknet return (-1); 1047159045Smaxim } 1048246670Spluknet if (cmsgcred->cmcred_uid != proc_cred.uid) { 1049246670Spluknet logmsgx("cmsgcred.cmcred_uid %lu != %lu", 1050246670Spluknet (u_long)cmsgcred->cmcred_uid, (u_long)proc_cred.uid); 1051246670Spluknet return (-1); 1052246670Spluknet } 1053246670Spluknet if (cmsgcred->cmcred_euid != proc_cred.euid) { 1054246670Spluknet logmsgx("cmsgcred.cmcred_euid %lu != %lu", 1055246670Spluknet (u_long)cmsgcred->cmcred_euid, (u_long)proc_cred.euid); 1056246670Spluknet return (-1); 1057246670Spluknet } 1058246670Spluknet if (cmsgcred->cmcred_gid != proc_cred.gid) { 1059246670Spluknet logmsgx("cmsgcred.cmcred_gid %lu != %lu", 1060246670Spluknet (u_long)cmsgcred->cmcred_gid, (u_long)proc_cred.gid); 1061246670Spluknet return (-1); 1062246670Spluknet } 1063246670Spluknet if (cmsgcred->cmcred_ngroups == 0) { 1064246670Spluknet logmsgx("cmsgcred.cmcred_ngroups == 0"); 1065246670Spluknet return (-1); 1066246670Spluknet } 1067246670Spluknet if (cmsgcred->cmcred_ngroups < 0) { 1068246670Spluknet logmsgx("cmsgcred.cmcred_ngroups %d < 0", 1069246670Spluknet cmsgcred->cmcred_ngroups); 1070246670Spluknet return (-1); 1071246670Spluknet } 1072246670Spluknet if (cmsgcred->cmcred_ngroups > CMGROUP_MAX) { 1073246670Spluknet logmsgx("cmsgcred.cmcred_ngroups %d > %d", 1074246670Spluknet cmsgcred->cmcred_ngroups, CMGROUP_MAX); 1075246670Spluknet return (-1); 1076246670Spluknet } 1077246670Spluknet if (cmsgcred->cmcred_groups[0] != proc_cred.egid) { 1078246670Spluknet logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)", 1079246670Spluknet (u_long)cmsgcred->cmcred_groups[0], (u_long)proc_cred.egid); 1080246670Spluknet return (-1); 1081246670Spluknet } 1082246670Spluknet if (check_groups("cmsgcred.cmcred_groups", cmsgcred->cmcred_groups, 1083246670Spluknet "cmsgcred.cmcred_ngroups", cmsgcred->cmcred_ngroups, false) < 0) 1084246670Spluknet return (-1); 1085246670Spluknet return (0); 1086246670Spluknet} 1087159045Smaxim 1088246670Spluknetstatic int 1089246670Spluknetcheck_scm_creds_sockcred(struct cmsghdr *cmsghdr) 1090246670Spluknet{ 1091246670Spluknet const struct sockcred *sockcred; 1092159045Smaxim 1093246670Spluknet if (check_cmsghdr(cmsghdr, SCM_CREDS, 1094246670Spluknet SOCKCREDSIZE(proc_cred.gid_num)) < 0) 1095246670Spluknet return (-1); 1096159045Smaxim 1097246670Spluknet sockcred = (struct sockcred *)CMSG_DATA(cmsghdr); 1098159045Smaxim 1099246670Spluknet dbgmsg("sockcred.sc_uid %lu", (u_long)sockcred->sc_uid); 1100246670Spluknet dbgmsg("sockcred.sc_euid %lu", (u_long)sockcred->sc_euid); 1101246670Spluknet dbgmsg("sockcred.sc_gid %lu", (u_long)sockcred->sc_gid); 1102246670Spluknet dbgmsg("sockcred.sc_egid %lu", (u_long)sockcred->sc_egid); 1103246670Spluknet dbgmsg("sockcred.sc_ngroups %d", sockcred->sc_ngroups); 1104246670Spluknet 1105246670Spluknet if (sockcred->sc_uid != proc_cred.uid) { 1106246670Spluknet logmsgx("sockcred.sc_uid %lu != %lu", 1107246670Spluknet (u_long)sockcred->sc_uid, (u_long)proc_cred.uid); 1108246670Spluknet return (-1); 1109246670Spluknet } 1110246670Spluknet if (sockcred->sc_euid != proc_cred.euid) { 1111246670Spluknet logmsgx("sockcred.sc_euid %lu != %lu", 1112246670Spluknet (u_long)sockcred->sc_euid, (u_long)proc_cred.euid); 1113246670Spluknet return (-1); 1114246670Spluknet } 1115246670Spluknet if (sockcred->sc_gid != proc_cred.gid) { 1116246670Spluknet logmsgx("sockcred.sc_gid %lu != %lu", 1117246670Spluknet (u_long)sockcred->sc_gid, (u_long)proc_cred.gid); 1118246670Spluknet return (-1); 1119246670Spluknet } 1120246670Spluknet if (sockcred->sc_egid != proc_cred.egid) { 1121246670Spluknet logmsgx("sockcred.sc_egid %lu != %lu", 1122246670Spluknet (u_long)sockcred->sc_egid, (u_long)proc_cred.egid); 1123246670Spluknet return (-1); 1124246670Spluknet } 1125246670Spluknet if (sockcred->sc_ngroups == 0) { 1126246670Spluknet logmsgx("sockcred.sc_ngroups == 0"); 1127246670Spluknet return (-1); 1128246670Spluknet } 1129246670Spluknet if (sockcred->sc_ngroups < 0) { 1130246670Spluknet logmsgx("sockcred.sc_ngroups %d < 0", 1131246670Spluknet sockcred->sc_ngroups); 1132246670Spluknet return (-1); 1133246670Spluknet } 1134246670Spluknet if (sockcred->sc_ngroups != proc_cred.gid_num) { 1135246670Spluknet logmsgx("sockcred.sc_ngroups %d != %u", 1136246670Spluknet sockcred->sc_ngroups, proc_cred.gid_num); 1137246670Spluknet return (-1); 1138246670Spluknet } 1139246670Spluknet if (check_groups("sockcred.sc_groups", sockcred->sc_groups, 1140246670Spluknet "sockcred.sc_ngroups", sockcred->sc_ngroups, true) < 0) 1141246670Spluknet return (-1); 1142246670Spluknet return (0); 1143159045Smaxim} 1144159045Smaxim 1145159045Smaximstatic int 1146246670Spluknetcheck_scm_timestamp(struct cmsghdr *cmsghdr) 1147159045Smaxim{ 1148246670Spluknet const struct timeval *timeval; 1149159045Smaxim 1150246670Spluknet if (check_cmsghdr(cmsghdr, SCM_TIMESTAMP, sizeof(struct timeval)) < 0) 1151246670Spluknet return (-1); 1152159045Smaxim 1153246670Spluknet timeval = (struct timeval *)CMSG_DATA(cmsghdr); 1154159045Smaxim 1155246670Spluknet dbgmsg("timeval.tv_sec %"PRIdMAX", timeval.tv_usec %"PRIdMAX, 1156246670Spluknet (intmax_t)timeval->tv_sec, (intmax_t)timeval->tv_usec); 1157159045Smaxim 1158246670Spluknet return (0); 1159246670Spluknet} 1160159045Smaxim 1161246670Spluknetstatic int 1162246670Spluknetcheck_scm_bintime(struct cmsghdr *cmsghdr) 1163246670Spluknet{ 1164246670Spluknet const struct bintime *bintime; 1165159045Smaxim 1166246670Spluknet if (check_cmsghdr(cmsghdr, SCM_BINTIME, sizeof(struct bintime)) < 0) 1167246670Spluknet return (-1); 1168159045Smaxim 1169246670Spluknet bintime = (struct bintime *)CMSG_DATA(cmsghdr); 1170159045Smaxim 1171246670Spluknet dbgmsg("bintime.sec %"PRIdMAX", bintime.frac %"PRIu64, 1172246670Spluknet (intmax_t)bintime->sec, bintime->frac); 1173159045Smaxim 1174246670Spluknet return (0); 1175246670Spluknet} 1176159045Smaxim 1177246670Spluknetstatic void 1178246670Spluknetmsghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data) 1179246670Spluknet{ 1180246670Spluknet msghdr->msg_name = NULL; 1181246670Spluknet msghdr->msg_namelen = 0; 1182246670Spluknet if (send_data_flag) { 1183246670Spluknet iov->iov_base = server_flag ? 1184246670Spluknet ipc_msg.buf_recv : ipc_msg.buf_send; 1185246670Spluknet iov->iov_len = ipc_msg.buf_size; 1186246670Spluknet msghdr->msg_iov = iov; 1187246670Spluknet msghdr->msg_iovlen = 1; 1188246670Spluknet } else { 1189246670Spluknet msghdr->msg_iov = NULL; 1190246670Spluknet msghdr->msg_iovlen = 0; 1191246670Spluknet } 1192246670Spluknet msghdr->msg_control = cmsg_data; 1193246670Spluknet msghdr->msg_flags = 0; 1194246670Spluknet} 1195159045Smaxim 1196246670Spluknetstatic void 1197246670Spluknetmsghdr_init_server(struct msghdr *msghdr, struct iovec *iov, 1198246670Spluknet void *cmsg_data, size_t cmsg_size) 1199246670Spluknet{ 1200246670Spluknet msghdr_init_generic(msghdr, iov, cmsg_data); 1201246670Spluknet msghdr->msg_controllen = cmsg_size; 1202246670Spluknet dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ? 1203246670Spluknet msghdr->msg_iov->iov_len : (size_t)0); 1204246670Spluknet dbgmsg("init: msghdr.msg_controllen %u", 1205246670Spluknet (u_int)msghdr->msg_controllen); 1206246670Spluknet} 1207159045Smaxim 1208246670Spluknetstatic void 1209246670Spluknetmsghdr_init_client(struct msghdr *msghdr, struct iovec *iov, 1210246670Spluknet void *cmsg_data, size_t cmsg_size, int type, size_t arr_size) 1211246670Spluknet{ 1212246670Spluknet struct cmsghdr *cmsghdr; 1213159045Smaxim 1214246670Spluknet msghdr_init_generic(msghdr, iov, cmsg_data); 1215246670Spluknet if (cmsg_data != NULL) { 1216246670Spluknet msghdr->msg_controllen = send_array_flag ? 1217246670Spluknet cmsg_size : CMSG_SPACE(0); 1218246670Spluknet cmsghdr = CMSG_FIRSTHDR(msghdr); 1219246670Spluknet cmsghdr->cmsg_level = SOL_SOCKET; 1220246670Spluknet cmsghdr->cmsg_type = type; 1221246670Spluknet cmsghdr->cmsg_len = CMSG_LEN(send_array_flag ? arr_size : 0); 1222246670Spluknet } else 1223246670Spluknet msghdr->msg_controllen = 0; 1224246670Spluknet} 1225159045Smaxim 1226246670Spluknetstatic int 1227246670Spluknett_generic(int (*client_func)(int), int (*server_func)(int)) 1228246670Spluknet{ 1229246670Spluknet int fd, rv, rv_client; 1230159045Smaxim 1231246670Spluknet switch (client_fork()) { 1232246670Spluknet case 0: 1233246670Spluknet fd = socket_create(); 1234246670Spluknet if (fd < 0) 1235246670Spluknet rv = -2; 1236246670Spluknet else { 1237246670Spluknet rv = client_func(fd); 1238246670Spluknet if (socket_close(fd) < 0) 1239246670Spluknet rv = -2; 1240159045Smaxim } 1241246670Spluknet client_exit(rv); 1242246670Spluknet break; 1243246670Spluknet case 1: 1244246670Spluknet fd = socket_create(); 1245246670Spluknet if (fd < 0) 1246246670Spluknet rv = -2; 1247246670Spluknet else { 1248246670Spluknet rv = server_func(fd); 1249246670Spluknet rv_client = client_wait(); 1250246670Spluknet if (rv == 0 || (rv == -2 && rv_client != 0)) 1251246670Spluknet rv = rv_client; 1252246670Spluknet if (socket_close(fd) < 0) 1253246670Spluknet rv = -2; 1254159045Smaxim } 1255246670Spluknet break; 1256246670Spluknet default: 1257246670Spluknet rv = -2; 1258246670Spluknet } 1259246670Spluknet return (rv); 1260246670Spluknet} 1261159045Smaxim 1262246670Spluknetstatic int 1263246670Spluknett_cmsgcred_client(int fd) 1264246670Spluknet{ 1265246670Spluknet struct msghdr msghdr; 1266246670Spluknet struct iovec iov[1]; 1267246670Spluknet void *cmsg_data; 1268246670Spluknet size_t cmsg_size; 1269246670Spluknet int rv; 1270159045Smaxim 1271246670Spluknet if (sync_recv() < 0) 1272246670Spluknet return (-2); 1273159045Smaxim 1274246670Spluknet rv = -2; 1275246670Spluknet 1276246670Spluknet cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1277246670Spluknet cmsg_data = malloc(cmsg_size); 1278246670Spluknet if (cmsg_data == NULL) { 1279246670Spluknet logmsg("malloc"); 1280246670Spluknet goto done; 1281159045Smaxim } 1282246670Spluknet msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1283246670Spluknet SCM_CREDS, sizeof(struct cmsgcred)); 1284159045Smaxim 1285246670Spluknet if (socket_connect(fd) < 0) 1286246670Spluknet goto done; 1287159045Smaxim 1288246670Spluknet if (message_sendn(fd, &msghdr) < 0) 1289246670Spluknet goto done; 1290246670Spluknet 1291246670Spluknet rv = 0; 1292246670Spluknetdone: 1293246670Spluknet free(cmsg_data); 1294246670Spluknet return (rv); 1295159045Smaxim} 1296159045Smaxim 1297159045Smaximstatic int 1298246670Spluknett_cmsgcred_server(int fd1) 1299159045Smaxim{ 1300246670Spluknet struct msghdr msghdr; 1301246670Spluknet struct iovec iov[1]; 1302246670Spluknet struct cmsghdr *cmsghdr; 1303246670Spluknet void *cmsg_data; 1304246670Spluknet size_t cmsg_size; 1305246670Spluknet u_int i; 1306246670Spluknet int fd2, rv; 1307159045Smaxim 1308246670Spluknet if (sync_send() < 0) 1309159045Smaxim return (-2); 1310159045Smaxim 1311246670Spluknet fd2 = -1; 1312246670Spluknet rv = -2; 1313159045Smaxim 1314246670Spluknet cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1315246670Spluknet cmsg_data = malloc(cmsg_size); 1316246670Spluknet if (cmsg_data == NULL) { 1317246670Spluknet logmsg("malloc"); 1318246670Spluknet goto done; 1319159045Smaxim } 1320159045Smaxim 1321246670Spluknet if (sock_type == SOCK_STREAM) { 1322246670Spluknet fd2 = socket_accept(fd1); 1323246670Spluknet if (fd2 < 0) 1324246670Spluknet goto done; 1325246670Spluknet } else 1326246670Spluknet fd2 = fd1; 1327159045Smaxim 1328246670Spluknet rv = -1; 1329246670Spluknet for (i = 1; i <= ipc_msg.msg_num; ++i) { 1330246670Spluknet dbgmsg("message #%u", i); 1331159045Smaxim 1332246670Spluknet msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1333246670Spluknet if (message_recv(fd2, &msghdr) < 0) { 1334246670Spluknet rv = -2; 1335246670Spluknet break; 1336246670Spluknet } 1337159045Smaxim 1338246670Spluknet if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1339246670Spluknet break; 1340246670Spluknet 1341246670Spluknet cmsghdr = CMSG_FIRSTHDR(&msghdr); 1342246670Spluknet if (check_scm_creds_cmsgcred(cmsghdr) < 0) 1343246670Spluknet break; 1344159045Smaxim } 1345246670Spluknet if (i > ipc_msg.msg_num) 1346246670Spluknet rv = 0; 1347246670Spluknetdone: 1348246670Spluknet free(cmsg_data); 1349246670Spluknet if (sock_type == SOCK_STREAM && fd2 >= 0) 1350246670Spluknet if (socket_close(fd2) < 0) 1351246670Spluknet rv = -2; 1352246670Spluknet return (rv); 1353246670Spluknet} 1354159045Smaxim 1355246670Spluknetstatic int 1356246670Spluknett_cmsgcred(void) 1357246670Spluknet{ 1358246670Spluknet return (t_generic(t_cmsgcred_client, t_cmsgcred_server)); 1359159045Smaxim} 1360159045Smaxim 1361246670Spluknetstatic int 1362246670Spluknett_sockcred_client(int type, int fd) 1363159045Smaxim{ 1364246670Spluknet struct msghdr msghdr; 1365159045Smaxim struct iovec iov[1]; 1366246670Spluknet int rv; 1367159045Smaxim 1368246670Spluknet if (sync_recv() < 0) 1369246670Spluknet return (-2); 1370159045Smaxim 1371246670Spluknet rv = -2; 1372159045Smaxim 1373246670Spluknet msghdr_init_client(&msghdr, iov, NULL, 0, 0, 0); 1374159045Smaxim 1375246670Spluknet if (socket_connect(fd) < 0) 1376246670Spluknet goto done; 1377159045Smaxim 1378246670Spluknet if (type == 2) 1379246670Spluknet if (sync_recv() < 0) 1380246670Spluknet goto done; 1381159045Smaxim 1382246670Spluknet if (message_sendn(fd, &msghdr) < 0) 1383246670Spluknet goto done; 1384159045Smaxim 1385246670Spluknet rv = 0; 1386246670Spluknetdone: 1387246670Spluknet return (rv); 1388159045Smaxim} 1389159045Smaxim 1390159045Smaximstatic int 1391246670Spluknett_sockcred_server(int type, int fd1) 1392159045Smaxim{ 1393246670Spluknet struct msghdr msghdr; 1394159045Smaxim struct iovec iov[1]; 1395246670Spluknet struct cmsghdr *cmsghdr; 1396246670Spluknet void *cmsg_data; 1397246670Spluknet size_t cmsg_size; 1398159045Smaxim u_int i; 1399246670Spluknet int fd2, rv, val; 1400159045Smaxim 1401246670Spluknet fd2 = -1; 1402246670Spluknet rv = -2; 1403159045Smaxim 1404246670Spluknet cmsg_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num)); 1405246670Spluknet cmsg_data = malloc(cmsg_size); 1406246670Spluknet if (cmsg_data == NULL) { 1407246670Spluknet logmsg("malloc"); 1408246670Spluknet goto done; 1409246670Spluknet } 1410159045Smaxim 1411246670Spluknet if (type == 1) { 1412246670Spluknet dbgmsg("setting LOCAL_CREDS"); 1413246670Spluknet val = 1; 1414246670Spluknet if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { 1415246670Spluknet logmsg("setsockopt(LOCAL_CREDS)"); 1416246670Spluknet goto done; 1417159045Smaxim } 1418246670Spluknet } 1419159045Smaxim 1420246670Spluknet if (sync_send() < 0) 1421246670Spluknet goto done; 1422159045Smaxim 1423246670Spluknet if (sock_type == SOCK_STREAM) { 1424246670Spluknet fd2 = socket_accept(fd1); 1425246670Spluknet if (fd2 < 0) 1426246670Spluknet goto done; 1427246670Spluknet } else 1428246670Spluknet fd2 = fd1; 1429159045Smaxim 1430246670Spluknet if (type == 2) { 1431246670Spluknet dbgmsg("setting LOCAL_CREDS"); 1432246670Spluknet val = 1; 1433246670Spluknet if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { 1434246670Spluknet logmsg("setsockopt(LOCAL_CREDS)"); 1435246670Spluknet goto done; 1436159045Smaxim } 1437246670Spluknet if (sync_send() < 0) 1438246670Spluknet goto done; 1439246670Spluknet } 1440159045Smaxim 1441246670Spluknet rv = -1; 1442246670Spluknet for (i = 1; i <= ipc_msg.msg_num; ++i) { 1443246670Spluknet dbgmsg("message #%u", i); 1444159045Smaxim 1445246670Spluknet msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1446246670Spluknet if (message_recv(fd2, &msghdr) < 0) { 1447246670Spluknet rv = -2; 1448246670Spluknet break; 1449159045Smaxim } 1450159045Smaxim 1451246670Spluknet if (i > 1 && sock_type == SOCK_STREAM) { 1452246670Spluknet if (check_msghdr(&msghdr, 0) < 0) 1453246670Spluknet break; 1454246670Spluknet } else { 1455246670Spluknet if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1456246670Spluknet break; 1457159045Smaxim 1458246670Spluknet cmsghdr = CMSG_FIRSTHDR(&msghdr); 1459246670Spluknet if (check_scm_creds_sockcred(cmsghdr) < 0) 1460246670Spluknet break; 1461159045Smaxim } 1462246670Spluknet } 1463246670Spluknet if (i > ipc_msg.msg_num) 1464246670Spluknet rv = 0; 1465246670Spluknetdone: 1466246670Spluknet free(cmsg_data); 1467246670Spluknet if (sock_type == SOCK_STREAM && fd2 >= 0) 1468246670Spluknet if (socket_close(fd2) < 0) 1469246670Spluknet rv = -2; 1470246670Spluknet return (rv); 1471246670Spluknet} 1472159045Smaxim 1473246670Spluknetstatic int 1474246670Spluknett_sockcred_1(void) 1475246670Spluknet{ 1476246670Spluknet u_int i; 1477246670Spluknet int fd, rv, rv_client; 1478159045Smaxim 1479246670Spluknet switch (client_fork()) { 1480246670Spluknet case 0: 1481246670Spluknet for (i = 1; i <= 2; ++i) { 1482246670Spluknet dbgmsg("client #%u", i); 1483246670Spluknet fd = socket_create(); 1484246670Spluknet if (fd < 0) 1485246670Spluknet rv = -2; 1486246670Spluknet else { 1487246670Spluknet rv = t_sockcred_client(1, fd); 1488246670Spluknet if (socket_close(fd) < 0) 1489246670Spluknet rv = -2; 1490159045Smaxim } 1491246670Spluknet if (rv != 0) 1492246670Spluknet break; 1493159045Smaxim } 1494246670Spluknet client_exit(rv); 1495246670Spluknet break; 1496246670Spluknet case 1: 1497246670Spluknet fd = socket_create(); 1498246670Spluknet if (fd < 0) 1499246670Spluknet rv = -2; 1500246670Spluknet else { 1501246670Spluknet rv = t_sockcred_server(1, fd); 1502246670Spluknet if (rv == 0) 1503246670Spluknet rv = t_sockcred_server(3, fd); 1504246670Spluknet rv_client = client_wait(); 1505246670Spluknet if (rv == 0 || (rv == -2 && rv_client != 0)) 1506246670Spluknet rv = rv_client; 1507246670Spluknet if (socket_close(fd) < 0) 1508246670Spluknet rv = -2; 1509159045Smaxim } 1510246670Spluknet break; 1511246670Spluknet default: 1512246670Spluknet rv = -2; 1513159045Smaxim } 1514159045Smaxim 1515246670Spluknet return (rv); 1516246670Spluknet} 1517159045Smaxim 1518246670Spluknetstatic int 1519246670Spluknett_sockcred_2_client(int fd) 1520246670Spluknet{ 1521246670Spluknet return (t_sockcred_client(2, fd)); 1522159045Smaxim} 1523159045Smaxim 1524159045Smaximstatic int 1525246670Spluknett_sockcred_2_server(int fd) 1526159045Smaxim{ 1527246670Spluknet return (t_sockcred_server(2, fd)); 1528246670Spluknet} 1529159045Smaxim 1530246670Spluknetstatic int 1531246670Spluknett_sockcred_2(void) 1532246670Spluknet{ 1533246670Spluknet return (t_generic(t_sockcred_2_client, t_sockcred_2_server)); 1534246670Spluknet} 1535159045Smaxim 1536246670Spluknetstatic int 1537246670Spluknett_cmsgcred_sockcred_server(int fd1) 1538246670Spluknet{ 1539246670Spluknet struct msghdr msghdr; 1540246670Spluknet struct iovec iov[1]; 1541246670Spluknet struct cmsghdr *cmsghdr; 1542246670Spluknet void *cmsg_data, *cmsg1_data, *cmsg2_data; 1543246670Spluknet size_t cmsg_size, cmsg1_size, cmsg2_size; 1544246670Spluknet u_int i; 1545246670Spluknet int fd2, rv, val; 1546159045Smaxim 1547246670Spluknet fd2 = -1; 1548246670Spluknet rv = -2; 1549159045Smaxim 1550246670Spluknet cmsg1_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num)); 1551246670Spluknet cmsg2_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1552246670Spluknet cmsg1_data = malloc(cmsg1_size); 1553246670Spluknet cmsg2_data = malloc(cmsg2_size); 1554246670Spluknet if (cmsg1_data == NULL || cmsg2_data == NULL) { 1555246670Spluknet logmsg("malloc"); 1556246670Spluknet goto done; 1557159045Smaxim } 1558159045Smaxim 1559246670Spluknet dbgmsg("setting LOCAL_CREDS"); 1560246670Spluknet val = 1; 1561246670Spluknet if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { 1562246670Spluknet logmsg("setsockopt(LOCAL_CREDS)"); 1563246670Spluknet goto done; 1564159045Smaxim } 1565159045Smaxim 1566246670Spluknet if (sync_send() < 0) 1567246670Spluknet goto done; 1568159045Smaxim 1569246670Spluknet if (sock_type == SOCK_STREAM) { 1570246670Spluknet fd2 = socket_accept(fd1); 1571246670Spluknet if (fd2 < 0) 1572246670Spluknet goto done; 1573246670Spluknet } else 1574246670Spluknet fd2 = fd1; 1575159045Smaxim 1576246670Spluknet cmsg_data = cmsg1_data; 1577246670Spluknet cmsg_size = cmsg1_size; 1578246670Spluknet rv = -1; 1579246670Spluknet for (i = 1; i <= ipc_msg.msg_num; ++i) { 1580246670Spluknet dbgmsg("message #%u", i); 1581159045Smaxim 1582246670Spluknet msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1583246670Spluknet if (message_recv(fd2, &msghdr) < 0) { 1584246670Spluknet rv = -2; 1585246670Spluknet break; 1586246670Spluknet } 1587246670Spluknet 1588246670Spluknet if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1589246670Spluknet break; 1590246670Spluknet 1591246670Spluknet cmsghdr = CMSG_FIRSTHDR(&msghdr); 1592246670Spluknet if (i == 1 || sock_type == SOCK_DGRAM) { 1593246670Spluknet if (check_scm_creds_sockcred(cmsghdr) < 0) 1594246670Spluknet break; 1595246670Spluknet } else { 1596246670Spluknet if (check_scm_creds_cmsgcred(cmsghdr) < 0) 1597246670Spluknet break; 1598246670Spluknet } 1599246670Spluknet 1600246670Spluknet cmsg_data = cmsg2_data; 1601246670Spluknet cmsg_size = cmsg2_size; 1602159045Smaxim } 1603246670Spluknet if (i > ipc_msg.msg_num) 1604246670Spluknet rv = 0; 1605246670Spluknetdone: 1606246670Spluknet free(cmsg1_data); 1607246670Spluknet free(cmsg2_data); 1608246670Spluknet if (sock_type == SOCK_STREAM && fd2 >= 0) 1609246670Spluknet if (socket_close(fd2) < 0) 1610246670Spluknet rv = -2; 1611246670Spluknet return (rv); 1612159045Smaxim} 1613159045Smaxim 1614159045Smaximstatic int 1615246670Spluknett_cmsgcred_sockcred(void) 1616159045Smaxim{ 1617246670Spluknet return (t_generic(t_cmsgcred_client, t_cmsgcred_sockcred_server)); 1618159045Smaxim} 1619159045Smaxim 1620159045Smaximstatic int 1621246670Spluknett_timeval_client(int fd) 1622159045Smaxim{ 1623246670Spluknet struct msghdr msghdr; 1624246670Spluknet struct iovec iov[1]; 1625246670Spluknet void *cmsg_data; 1626246670Spluknet size_t cmsg_size; 1627246670Spluknet int rv; 1628159045Smaxim 1629246670Spluknet if (sync_recv() < 0) 1630246670Spluknet return (-2); 1631246670Spluknet 1632246670Spluknet rv = -2; 1633246670Spluknet 1634246670Spluknet cmsg_size = CMSG_SPACE(sizeof(struct timeval)); 1635246670Spluknet cmsg_data = malloc(cmsg_size); 1636246670Spluknet if (cmsg_data == NULL) { 1637246670Spluknet logmsg("malloc"); 1638246670Spluknet goto done; 1639246670Spluknet } 1640246670Spluknet msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1641246670Spluknet SCM_TIMESTAMP, sizeof(struct timeval)); 1642246670Spluknet 1643246670Spluknet if (socket_connect(fd) < 0) 1644246670Spluknet goto done; 1645246670Spluknet 1646246670Spluknet if (message_sendn(fd, &msghdr) < 0) 1647246670Spluknet goto done; 1648246670Spluknet 1649246670Spluknet rv = 0; 1650246670Spluknetdone: 1651246670Spluknet free(cmsg_data); 1652246670Spluknet return (rv); 1653159045Smaxim} 1654159045Smaxim 1655159045Smaximstatic int 1656246670Spluknett_timeval_server(int fd1) 1657159045Smaxim{ 1658246670Spluknet struct msghdr msghdr; 1659246670Spluknet struct iovec iov[1]; 1660246670Spluknet struct cmsghdr *cmsghdr; 1661246670Spluknet void *cmsg_data; 1662246670Spluknet size_t cmsg_size; 1663246670Spluknet u_int i; 1664246670Spluknet int fd2, rv; 1665159045Smaxim 1666246670Spluknet if (sync_send() < 0) 1667159045Smaxim return (-2); 1668159045Smaxim 1669246670Spluknet fd2 = -1; 1670246670Spluknet rv = -2; 1671159045Smaxim 1672246670Spluknet cmsg_size = CMSG_SPACE(sizeof(struct timeval)); 1673246670Spluknet cmsg_data = malloc(cmsg_size); 1674246670Spluknet if (cmsg_data == NULL) { 1675246670Spluknet logmsg("malloc"); 1676246670Spluknet goto done; 1677159045Smaxim } 1678159045Smaxim 1679246670Spluknet if (sock_type == SOCK_STREAM) { 1680246670Spluknet fd2 = socket_accept(fd1); 1681246670Spluknet if (fd2 < 0) 1682246670Spluknet goto done; 1683246670Spluknet } else 1684246670Spluknet fd2 = fd1; 1685159045Smaxim 1686246670Spluknet rv = -1; 1687246670Spluknet for (i = 1; i <= ipc_msg.msg_num; ++i) { 1688246670Spluknet dbgmsg("message #%u", i); 1689159045Smaxim 1690246670Spluknet msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1691246670Spluknet if (message_recv(fd2, &msghdr) < 0) { 1692246670Spluknet rv = -2; 1693246670Spluknet break; 1694246670Spluknet } 1695159045Smaxim 1696246670Spluknet if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1697246670Spluknet break; 1698159045Smaxim 1699246670Spluknet cmsghdr = CMSG_FIRSTHDR(&msghdr); 1700246670Spluknet if (check_scm_timestamp(cmsghdr) < 0) 1701246670Spluknet break; 1702159045Smaxim } 1703246670Spluknet if (i > ipc_msg.msg_num) 1704246670Spluknet rv = 0; 1705246670Spluknetdone: 1706246670Spluknet free(cmsg_data); 1707246670Spluknet if (sock_type == SOCK_STREAM && fd2 >= 0) 1708246670Spluknet if (socket_close(fd2) < 0) 1709246670Spluknet rv = -2; 1710246670Spluknet return (rv); 1711246670Spluknet} 1712159045Smaxim 1713246670Spluknetstatic int 1714246670Spluknett_timeval(void) 1715246670Spluknet{ 1716246670Spluknet return (t_generic(t_timeval_client, t_timeval_server)); 1717159045Smaxim} 1718159045Smaxim 1719246670Spluknetstatic int 1720246670Spluknett_bintime_client(int fd) 1721159045Smaxim{ 1722246670Spluknet struct msghdr msghdr; 1723159045Smaxim struct iovec iov[1]; 1724246670Spluknet void *cmsg_data; 1725246670Spluknet size_t cmsg_size; 1726246670Spluknet int rv; 1727159045Smaxim 1728246670Spluknet if (sync_recv() < 0) 1729246670Spluknet return (-2); 1730159045Smaxim 1731246670Spluknet rv = -2; 1732159045Smaxim 1733246670Spluknet cmsg_size = CMSG_SPACE(sizeof(struct bintime)); 1734246670Spluknet cmsg_data = malloc(cmsg_size); 1735246670Spluknet if (cmsg_data == NULL) { 1736246670Spluknet logmsg("malloc"); 1737246670Spluknet goto done; 1738246670Spluknet } 1739246670Spluknet msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1740246670Spluknet SCM_BINTIME, sizeof(struct bintime)); 1741159045Smaxim 1742246670Spluknet if (socket_connect(fd) < 0) 1743246670Spluknet goto done; 1744159045Smaxim 1745246670Spluknet if (message_sendn(fd, &msghdr) < 0) 1746246670Spluknet goto done; 1747159045Smaxim 1748246670Spluknet rv = 0; 1749246670Spluknetdone: 1750246670Spluknet free(cmsg_data); 1751246670Spluknet return (rv); 1752159045Smaxim} 1753159045Smaxim 1754159045Smaximstatic int 1755246670Spluknett_bintime_server(int fd1) 1756159045Smaxim{ 1757246670Spluknet struct msghdr msghdr; 1758159045Smaxim struct iovec iov[1]; 1759246670Spluknet struct cmsghdr *cmsghdr; 1760246670Spluknet void *cmsg_data; 1761246670Spluknet size_t cmsg_size; 1762246670Spluknet u_int i; 1763246670Spluknet int fd2, rv; 1764159045Smaxim 1765246670Spluknet if (sync_send() < 0) 1766246670Spluknet return (-2); 1767246670Spluknet 1768246670Spluknet fd2 = -1; 1769246670Spluknet rv = -2; 1770246670Spluknet 1771246670Spluknet cmsg_size = CMSG_SPACE(sizeof(struct bintime)); 1772246670Spluknet cmsg_data = malloc(cmsg_size); 1773246670Spluknet if (cmsg_data == NULL) { 1774246670Spluknet logmsg("malloc"); 1775246670Spluknet goto done; 1776246670Spluknet } 1777246670Spluknet 1778159045Smaxim if (sock_type == SOCK_STREAM) { 1779246670Spluknet fd2 = socket_accept(fd1); 1780246670Spluknet if (fd2 < 0) 1781246670Spluknet goto done; 1782159045Smaxim } else 1783159045Smaxim fd2 = fd1; 1784159045Smaxim 1785246670Spluknet rv = -1; 1786246670Spluknet for (i = 1; i <= ipc_msg.msg_num; ++i) { 1787246670Spluknet dbgmsg("message #%u", i); 1788159045Smaxim 1789246670Spluknet msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1790246670Spluknet if (message_recv(fd2, &msghdr) < 0) { 1791246670Spluknet rv = -2; 1792246670Spluknet break; 1793246670Spluknet } 1794159045Smaxim 1795246670Spluknet if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1796246670Spluknet break; 1797159045Smaxim 1798246670Spluknet cmsghdr = CMSG_FIRSTHDR(&msghdr); 1799246670Spluknet if (check_scm_bintime(cmsghdr) < 0) 1800246670Spluknet break; 1801159045Smaxim } 1802246670Spluknet if (i > ipc_msg.msg_num) 1803246670Spluknet rv = 0; 1804246670Spluknetdone: 1805246670Spluknet free(cmsg_data); 1806246670Spluknet if (sock_type == SOCK_STREAM && fd2 >= 0) 1807246670Spluknet if (socket_close(fd2) < 0) 1808246670Spluknet rv = -2; 1809246670Spluknet return (rv); 1810246670Spluknet} 1811159045Smaxim 1812246670Spluknetstatic int 1813246670Spluknett_bintime(void) 1814246670Spluknet{ 1815246670Spluknet return (t_generic(t_bintime_client, t_bintime_server)); 1816246670Spluknet} 1817159045Smaxim 1818246670Spluknetstatic int 1819246670Spluknett_cmsg_len_client(int fd) 1820246670Spluknet{ 1821246670Spluknet struct msghdr msghdr; 1822246670Spluknet struct iovec iov[1]; 1823246670Spluknet struct cmsghdr *cmsghdr; 1824246670Spluknet void *cmsg_data; 1825246670Spluknet size_t size, cmsg_size; 1826246670Spluknet socklen_t socklen; 1827246670Spluknet int rv; 1828159045Smaxim 1829246670Spluknet if (sync_recv() < 0) 1830246670Spluknet return (-2); 1831159045Smaxim 1832246670Spluknet rv = -2; 1833246670Spluknet 1834246670Spluknet cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1835246670Spluknet cmsg_data = malloc(cmsg_size); 1836246670Spluknet if (cmsg_data == NULL) { 1837246670Spluknet logmsg("malloc"); 1838159045Smaxim goto done; 1839159045Smaxim } 1840246670Spluknet msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1841246670Spluknet SCM_CREDS, sizeof(struct cmsgcred)); 1842246670Spluknet cmsghdr = CMSG_FIRSTHDR(&msghdr); 1843159045Smaxim 1844246670Spluknet if (socket_connect(fd) < 0) 1845159045Smaxim goto done; 1846246670Spluknet 1847246670Spluknet size = msghdr.msg_iov != NULL ? msghdr.msg_iov->iov_len : 0; 1848246670Spluknet rv = -1; 1849246670Spluknet for (socklen = 0; socklen < CMSG_LEN(0); ++socklen) { 1850246670Spluknet cmsghdr->cmsg_len = socklen; 1851246670Spluknet dbgmsg("send: data size %zu", size); 1852246670Spluknet dbgmsg("send: msghdr.msg_controllen %u", 1853246670Spluknet (u_int)msghdr.msg_controllen); 1854246670Spluknet dbgmsg("send: cmsghdr.cmsg_len %u", 1855246670Spluknet (u_int)cmsghdr->cmsg_len); 1856246670Spluknet if (sendmsg(fd, &msghdr, 0) < 0) 1857246670Spluknet continue; 1858246670Spluknet logmsgx("sent message with cmsghdr.cmsg_len %u < %u", 1859246670Spluknet (u_int)cmsghdr->cmsg_len, (u_int)CMSG_LEN(0)); 1860246670Spluknet break; 1861159045Smaxim } 1862246670Spluknet if (socklen == CMSG_LEN(0)) 1863246670Spluknet rv = 0; 1864159045Smaxim 1865246670Spluknet if (sync_send() < 0) { 1866246670Spluknet rv = -2; 1867159045Smaxim goto done; 1868159045Smaxim } 1869246670Spluknetdone: 1870246670Spluknet free(cmsg_data); 1871246670Spluknet return (rv); 1872246670Spluknet} 1873159045Smaxim 1874246670Spluknetstatic int 1875246670Spluknett_cmsg_len_server(int fd1) 1876246670Spluknet{ 1877246670Spluknet int fd2, rv; 1878159045Smaxim 1879246670Spluknet if (sync_send() < 0) 1880246670Spluknet return (-2); 1881159045Smaxim 1882246670Spluknet rv = -2; 1883246670Spluknet 1884246670Spluknet if (sock_type == SOCK_STREAM) { 1885246670Spluknet fd2 = socket_accept(fd1); 1886246670Spluknet if (fd2 < 0) 1887246670Spluknet goto done; 1888246670Spluknet } else 1889246670Spluknet fd2 = fd1; 1890246670Spluknet 1891246670Spluknet if (sync_recv() < 0) 1892159045Smaxim goto done; 1893159045Smaxim 1894246670Spluknet rv = 0; 1895159045Smaximdone: 1896246670Spluknet if (sock_type == SOCK_STREAM && fd2 >= 0) 1897246670Spluknet if (socket_close(fd2) < 0) 1898246670Spluknet rv = -2; 1899246670Spluknet return (rv); 1900246670Spluknet} 1901159045Smaxim 1902246670Spluknetstatic int 1903246670Spluknett_cmsg_len(void) 1904246670Spluknet{ 1905246670Spluknet return (t_generic(t_cmsg_len_client, t_cmsg_len_server)); 1906159045Smaxim} 1907159045Smaxim 1908159045Smaximstatic int 1909246670Spluknett_peercred_client(int fd) 1910159045Smaxim{ 1911246670Spluknet struct xucred xucred; 1912246670Spluknet socklen_t len; 1913159045Smaxim 1914246670Spluknet if (sync_recv() < 0) 1915246670Spluknet return (-1); 1916159045Smaxim 1917246670Spluknet if (socket_connect(fd) < 0) 1918246670Spluknet return (-1); 1919159045Smaxim 1920246670Spluknet len = sizeof(xucred); 1921246670Spluknet if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { 1922246670Spluknet logmsg("getsockopt(LOCAL_PEERCRED)"); 1923246670Spluknet return (-1); 1924159045Smaxim } 1925159045Smaxim 1926246670Spluknet if (check_xucred(&xucred, len) < 0) 1927246670Spluknet return (-1); 1928159045Smaxim 1929246670Spluknet return (0); 1930246670Spluknet} 1931159045Smaxim 1932246670Spluknetstatic int 1933246670Spluknett_peercred_server(int fd1) 1934246670Spluknet{ 1935246670Spluknet struct xucred xucred; 1936246670Spluknet socklen_t len; 1937246670Spluknet int fd2, rv; 1938159045Smaxim 1939246670Spluknet if (sync_send() < 0) 1940159045Smaxim return (-2); 1941246670Spluknet 1942246670Spluknet fd2 = socket_accept(fd1); 1943246670Spluknet if (fd2 < 0) 1944246670Spluknet return (-2); 1945246670Spluknet 1946246670Spluknet len = sizeof(xucred); 1947246670Spluknet if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { 1948246670Spluknet logmsg("getsockopt(LOCAL_PEERCRED)"); 1949246670Spluknet rv = -2; 1950246670Spluknet goto done; 1951159045Smaxim } 1952159045Smaxim 1953246670Spluknet if (check_xucred(&xucred, len) < 0) { 1954246670Spluknet rv = -1; 1955246670Spluknet goto done; 1956246670Spluknet } 1957246670Spluknet 1958246670Spluknet rv = 0; 1959246670Spluknetdone: 1960246670Spluknet if (socket_close(fd2) < 0) 1961246670Spluknet rv = -2; 1962246670Spluknet return (rv); 1963159045Smaxim} 1964246670Spluknet 1965246670Spluknetstatic int 1966246670Spluknett_peercred(void) 1967246670Spluknet{ 1968246670Spluknet return (t_generic(t_peercred_client, t_peercred_server)); 1969246670Spluknet} 1970