1 /*- 2 * Copyright (c) 2005 Andrey Simonenko 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/resource.h> 32 #include <sys/time.h> 33 #include <sys/select.h> 34 #include <sys/socket.h> 35 #include <sys/ucred.h> 36 #include <sys/un.h> 37 #include <sys/wait.h> 38 39 #include <ctype.h> 40 #include <err.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <inttypes.h> 44 #include <limits.h> 45 #include <paths.h> 46 #include <signal.h> 47 #include <stdarg.h> 48 #include <stdbool.h> 49 #include <stdint.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 55 /* 56 * There are tables with tests descriptions and pointers to test 57 * functions. Each t_*() function returns 0 if its test passed, 58 * -1 if its test failed, -2 if some system error occurred. 59 * If a test function returns -2, then a program exits. 60 * 61 * If a test function forks a client process, then it waits for its 62 * termination. If a return code of a client process is not equal 63 * to zero, or if a client process was terminated by a signal, then 64 * a test function returns -1 or -2 depending on exit status of 65 * a client process. 66 * 67 * Each function which can block, is run under TIMEOUT. If timeout 68 * occurs, then a test function returns -2 or a client process exits 69 * with a non-zero return code. 70 */ 71 72 #ifndef LISTENQ 73 # define LISTENQ 1 74 #endif 75 76 #ifndef TIMEOUT 77 # define TIMEOUT 2 78 #endif 79 80 static int t_cmsgcred(void); 81 static int t_sockcred_1(void); 82 static int t_sockcred_2(void); 83 static int t_cmsgcred_sockcred(void); 84 static int t_timeval(void); 85 static int t_bintime(void); 86 static int t_cmsg_len(void); 87 static int t_peercred(void); 88 89 struct test_func { 90 int (*func)(void); 91 const char *desc; 92 }; 93 94 static const struct test_func test_stream_tbl[] = { 95 { 96 .func = NULL, 97 .desc = "All tests" 98 }, 99 { 100 .func = t_cmsgcred, 101 .desc = "Sending, receiving cmsgcred" 102 }, 103 { 104 .func = t_sockcred_1, 105 .desc = "Receiving sockcred (listening socket)" 106 }, 107 { 108 .func = t_sockcred_2, 109 .desc = "Receiving sockcred (accepted socket)" 110 }, 111 { 112 .func = t_cmsgcred_sockcred, 113 .desc = "Sending cmsgcred, receiving sockcred" 114 }, 115 { 116 .func = t_timeval, 117 .desc = "Sending, receiving timeval" 118 }, 119 { 120 .func = t_bintime, 121 .desc = "Sending, receiving bintime" 122 }, 123 { 124 .func = t_cmsg_len, 125 .desc = "Check cmsghdr.cmsg_len" 126 }, 127 { 128 .func = t_peercred, 129 .desc = "Check LOCAL_PEERCRED socket option" 130 } 131 }; 132 133 #define TEST_STREAM_TBL_SIZE \ 134 (sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0])) 135 136 static const struct test_func test_dgram_tbl[] = { 137 { 138 .func = NULL, 139 .desc = "All tests" 140 }, 141 { 142 .func = t_cmsgcred, 143 .desc = "Sending, receiving cmsgcred" 144 }, 145 { 146 .func = t_sockcred_2, 147 .desc = "Receiving sockcred" 148 }, 149 { 150 .func = t_cmsgcred_sockcred, 151 .desc = "Sending cmsgcred, receiving sockcred" 152 }, 153 { 154 .func = t_timeval, 155 .desc = "Sending, receiving timeval" 156 }, 157 { 158 .func = t_bintime, 159 .desc = "Sending, receiving bintime" 160 }, 161 { 162 .func = t_cmsg_len, 163 .desc = "Check cmsghdr.cmsg_len" 164 } 165 }; 166 167 #define TEST_DGRAM_TBL_SIZE \ 168 (sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0])) 169 170 static bool debug = false; 171 static bool server_flag = true; 172 static bool send_data_flag = true; 173 static bool send_array_flag = true; 174 static bool failed_flag = false; 175 176 static int sock_type; 177 static const char *sock_type_str; 178 179 static const char *proc_name; 180 181 static char work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX"; 182 static int serv_sock_fd; 183 static struct sockaddr_un serv_addr_sun; 184 185 static struct { 186 char *buf_send; 187 char *buf_recv; 188 size_t buf_size; 189 u_int msg_num; 190 } ipc_msg; 191 192 #define IPC_MSG_NUM_DEF 5 193 #define IPC_MSG_NUM_MAX 10 194 #define IPC_MSG_SIZE_DEF 7 195 #define IPC_MSG_SIZE_MAX 128 196 197 static struct { 198 uid_t uid; 199 uid_t euid; 200 gid_t gid; 201 gid_t egid; 202 gid_t *gid_arr; 203 int gid_num; 204 } proc_cred; 205 206 static pid_t client_pid; 207 208 #define SYNC_SERVER 0 209 #define SYNC_CLIENT 1 210 #define SYNC_RECV 0 211 #define SYNC_SEND 1 212 213 static int sync_fd[2][2]; 214 215 #define LOGMSG_SIZE 128 216 217 static void logmsg(const char *, ...) __printflike(1, 2); 218 static void logmsgx(const char *, ...) __printflike(1, 2); 219 static void dbgmsg(const char *, ...) __printflike(1, 2); 220 static void output(const char *, ...) __printflike(1, 2); 221 222 static void 223 usage(bool verbose) 224 { 225 u_int i; 226 227 printf("usage: %s [-dh] [-n num] [-s size] [-t type] " 228 "[-z value] [testno]\n", getprogname()); 229 if (!verbose) 230 return; 231 printf("\n Options are:\n\ 232 -d Output debugging information\n\ 233 -h Output the help message and exit\n\ 234 -n num Number of messages to send\n\ 235 -s size Specify size of data for IPC\n\ 236 -t type Specify socket type (stream, dgram) for tests\n\ 237 -z value Do not send data in a message (bit 0x1), do not send\n\ 238 data array associated with a cmsghdr structure (bit 0x2)\n\ 239 testno Run one test by its number (require the -t option)\n\n"); 240 printf(" Available tests for stream sockets:\n"); 241 for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i) 242 printf(" %u: %s\n", i, test_stream_tbl[i].desc); 243 printf("\n Available tests for datagram sockets:\n"); 244 for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i) 245 printf(" %u: %s\n", i, test_dgram_tbl[i].desc); 246 } 247 248 static void 249 output(const char *format, ...) 250 { 251 char buf[LOGMSG_SIZE]; 252 va_list ap; 253 254 va_start(ap, format); 255 if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 256 err(EXIT_FAILURE, "output: vsnprintf failed"); 257 write(STDOUT_FILENO, buf, strlen(buf)); 258 va_end(ap); 259 } 260 261 static void 262 logmsg(const char *format, ...) 263 { 264 char buf[LOGMSG_SIZE]; 265 va_list ap; 266 int errno_save; 267 268 errno_save = errno; 269 va_start(ap, format); 270 if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 271 err(EXIT_FAILURE, "logmsg: vsnprintf failed"); 272 if (errno_save == 0) 273 output("%s: %s\n", proc_name, buf); 274 else 275 output("%s: %s: %s\n", proc_name, buf, strerror(errno_save)); 276 va_end(ap); 277 errno = errno_save; 278 } 279 280 static void 281 vlogmsgx(const char *format, va_list ap) 282 { 283 char buf[LOGMSG_SIZE]; 284 285 if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 286 err(EXIT_FAILURE, "logmsgx: vsnprintf failed"); 287 output("%s: %s\n", proc_name, buf); 288 289 } 290 291 static void 292 logmsgx(const char *format, ...) 293 { 294 va_list ap; 295 296 va_start(ap, format); 297 vlogmsgx(format, ap); 298 va_end(ap); 299 } 300 301 static void 302 dbgmsg(const char *format, ...) 303 { 304 va_list ap; 305 306 if (debug) { 307 va_start(ap, format); 308 vlogmsgx(format, ap); 309 va_end(ap); 310 } 311 } 312 313 static int 314 run_tests(int type, u_int testno1) 315 { 316 const struct test_func *tf; 317 u_int i, testno2, failed_num; 318 319 sock_type = type; 320 if (type == SOCK_STREAM) { 321 sock_type_str = "SOCK_STREAM"; 322 tf = test_stream_tbl; 323 i = TEST_STREAM_TBL_SIZE - 1; 324 } else { 325 sock_type_str = "SOCK_DGRAM"; 326 tf = test_dgram_tbl; 327 i = TEST_DGRAM_TBL_SIZE - 1; 328 } 329 if (testno1 == 0) { 330 testno1 = 1; 331 testno2 = i; 332 } else 333 testno2 = testno1; 334 335 output("Running tests for %s sockets:\n", sock_type_str); 336 failed_num = 0; 337 for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) { 338 output(" %u: %s\n", i, tf->desc); 339 switch (tf->func()) { 340 case -1: 341 ++failed_num; 342 break; 343 case -2: 344 logmsgx("some system error or timeout occurred"); 345 return (-1); 346 } 347 } 348 349 if (failed_num != 0) 350 failed_flag = true; 351 352 if (testno1 != testno2) { 353 if (failed_num == 0) 354 output("-- all tests passed!\n"); 355 else 356 output("-- %u test%s failed!\n", 357 failed_num, failed_num == 1 ? "" : "s"); 358 } else { 359 if (failed_num == 0) 360 output("-- test passed!\n"); 361 else 362 output("-- test failed!\n"); 363 } 364 365 return (0); 366 } 367 368 static int 369 init(void) 370 { 371 struct sigaction sigact; 372 size_t idx; 373 int rv; 374 375 proc_name = "SERVER"; 376 377 sigact.sa_handler = SIG_IGN; 378 sigact.sa_flags = 0; 379 sigemptyset(&sigact.sa_mask); 380 if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) { 381 logmsg("init: sigaction"); 382 return (-1); 383 } 384 385 if (ipc_msg.buf_size == 0) 386 ipc_msg.buf_send = ipc_msg.buf_recv = NULL; 387 else { 388 ipc_msg.buf_send = malloc(ipc_msg.buf_size); 389 ipc_msg.buf_recv = malloc(ipc_msg.buf_size); 390 if (ipc_msg.buf_send == NULL || ipc_msg.buf_recv == NULL) { 391 logmsg("init: malloc"); 392 return (-1); 393 } 394 for (idx = 0; idx < ipc_msg.buf_size; ++idx) 395 ipc_msg.buf_send[idx] = (char)idx; 396 } 397 398 proc_cred.uid = getuid(); 399 proc_cred.euid = geteuid(); 400 proc_cred.gid = getgid(); 401 proc_cred.egid = getegid(); 402 proc_cred.gid_num = getgroups(0, (gid_t *)NULL); 403 if (proc_cred.gid_num < 0) { 404 logmsg("init: getgroups"); 405 return (-1); 406 } 407 proc_cred.gid_arr = malloc(proc_cred.gid_num * 408 sizeof(*proc_cred.gid_arr)); 409 if (proc_cred.gid_arr == NULL) { 410 logmsg("init: malloc"); 411 return (-1); 412 } 413 if (getgroups(proc_cred.gid_num, proc_cred.gid_arr) < 0) { 414 logmsg("init: getgroups"); 415 return (-1); 416 } 417 418 memset(&serv_addr_sun, 0, sizeof(serv_addr_sun)); 419 rv = snprintf(serv_addr_sun.sun_path, sizeof(serv_addr_sun.sun_path), 420 "%s/%s", work_dir, proc_name); 421 if (rv < 0) { 422 logmsg("init: snprintf"); 423 return (-1); 424 } 425 if ((size_t)rv >= sizeof(serv_addr_sun.sun_path)) { 426 logmsgx("init: not enough space for socket pathname"); 427 return (-1); 428 } 429 serv_addr_sun.sun_family = PF_LOCAL; 430 serv_addr_sun.sun_len = SUN_LEN(&serv_addr_sun); 431 432 return (0); 433 } 434 435 static int 436 client_fork(void) 437 { 438 int fd1, fd2; 439 440 if (pipe(sync_fd[SYNC_SERVER]) < 0 || 441 pipe(sync_fd[SYNC_CLIENT]) < 0) { 442 logmsg("client_fork: pipe"); 443 return (-1); 444 } 445 client_pid = fork(); 446 if (client_pid == (pid_t)-1) { 447 logmsg("client_fork: fork"); 448 return (-1); 449 } 450 if (client_pid == 0) { 451 proc_name = "CLIENT"; 452 server_flag = false; 453 fd1 = sync_fd[SYNC_SERVER][SYNC_RECV]; 454 fd2 = sync_fd[SYNC_CLIENT][SYNC_SEND]; 455 } else { 456 fd1 = sync_fd[SYNC_SERVER][SYNC_SEND]; 457 fd2 = sync_fd[SYNC_CLIENT][SYNC_RECV]; 458 } 459 if (close(fd1) < 0 || close(fd2) < 0) { 460 logmsg("client_fork: close"); 461 return (-1); 462 } 463 return (client_pid != 0); 464 } 465 466 static void 467 client_exit(int rv) 468 { 469 if (close(sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 || 470 close(sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) { 471 logmsg("client_exit: close"); 472 rv = -1; 473 } 474 rv = rv == 0 ? EXIT_SUCCESS : -rv; 475 dbgmsg("exit: code %d", rv); 476 _exit(rv); 477 } 478 479 static int 480 client_wait(void) 481 { 482 int status; 483 pid_t pid; 484 485 dbgmsg("waiting for client"); 486 487 if (close(sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 || 488 close(sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) { 489 logmsg("client_wait: close"); 490 return (-1); 491 } 492 493 pid = waitpid(client_pid, &status, 0); 494 if (pid == (pid_t)-1) { 495 logmsg("client_wait: waitpid"); 496 return (-1); 497 } 498 499 if (WIFEXITED(status)) { 500 if (WEXITSTATUS(status) != EXIT_SUCCESS) { 501 logmsgx("client exit status is %d", 502 WEXITSTATUS(status)); 503 return (-WEXITSTATUS(status)); 504 } 505 } else { 506 if (WIFSIGNALED(status)) 507 logmsgx("abnormal termination of client, signal %d%s", 508 WTERMSIG(status), WCOREDUMP(status) ? 509 " (core file generated)" : ""); 510 else 511 logmsgx("termination of client, unknown status"); 512 return (-1); 513 } 514 515 return (0); 516 } 517 518 int 519 main(int argc, char *argv[]) 520 { 521 const char *errstr; 522 u_int testno, zvalue; 523 int opt, rv; 524 bool dgram_flag, stream_flag; 525 526 ipc_msg.buf_size = IPC_MSG_SIZE_DEF; 527 ipc_msg.msg_num = IPC_MSG_NUM_DEF; 528 dgram_flag = stream_flag = false; 529 while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1) 530 switch (opt) { 531 case 'd': 532 debug = true; 533 break; 534 case 'h': 535 usage(true); 536 return (EXIT_SUCCESS); 537 case 'n': 538 ipc_msg.msg_num = strtonum(optarg, 1, 539 IPC_MSG_NUM_MAX, &errstr); 540 if (errstr != NULL) 541 errx(EXIT_FAILURE, "option -n: number is %s", 542 errstr); 543 break; 544 case 's': 545 ipc_msg.buf_size = strtonum(optarg, 0, 546 IPC_MSG_SIZE_MAX, &errstr); 547 if (errstr != NULL) 548 errx(EXIT_FAILURE, "option -s: number is %s", 549 errstr); 550 break; 551 case 't': 552 if (strcmp(optarg, "stream") == 0) 553 stream_flag = true; 554 else if (strcmp(optarg, "dgram") == 0) 555 dgram_flag = true; 556 else 557 errx(EXIT_FAILURE, "option -t: " 558 "wrong socket type"); 559 break; 560 case 'z': 561 zvalue = strtonum(optarg, 0, 3, &errstr); 562 if (errstr != NULL) 563 errx(EXIT_FAILURE, "option -z: number is %s", 564 errstr); 565 if (zvalue & 0x1) 566 send_data_flag = false; 567 if (zvalue & 0x2) 568 send_array_flag = false; 569 break; 570 default: 571 usage(false); 572 return (EXIT_FAILURE); 573 } 574 575 if (optind < argc) { 576 if (optind + 1 != argc) 577 errx(EXIT_FAILURE, "too many arguments"); 578 testno = strtonum(argv[optind], 0, UINT_MAX, &errstr); 579 if (errstr != NULL) 580 errx(EXIT_FAILURE, "test number is %s", errstr); 581 if (stream_flag && testno >= TEST_STREAM_TBL_SIZE) 582 errx(EXIT_FAILURE, "given test %u for stream " 583 "sockets does not exist", testno); 584 if (dgram_flag && testno >= TEST_DGRAM_TBL_SIZE) 585 errx(EXIT_FAILURE, "given test %u for datagram " 586 "sockets does not exist", testno); 587 } else 588 testno = 0; 589 590 if (!dgram_flag && !stream_flag) { 591 if (testno != 0) 592 errx(EXIT_FAILURE, "particular test number " 593 "can be used with the -t option only"); 594 dgram_flag = stream_flag = true; 595 } 596 597 if (mkdtemp(work_dir) == NULL) 598 err(EXIT_FAILURE, "mkdtemp(%s)", work_dir); 599 600 rv = EXIT_FAILURE; 601 if (init() < 0) 602 goto done; 603 604 if (stream_flag) 605 if (run_tests(SOCK_STREAM, testno) < 0) 606 goto done; 607 if (dgram_flag) 608 if (run_tests(SOCK_DGRAM, testno) < 0) 609 goto done; 610 611 rv = EXIT_SUCCESS; 612 done: 613 if (rmdir(work_dir) < 0) { 614 logmsg("rmdir(%s)", work_dir); 615 rv = EXIT_FAILURE; 616 } 617 return (failed_flag ? EXIT_FAILURE : rv); 618 } 619 620 static int 621 socket_close(int fd) 622 { 623 int rv; 624 625 rv = 0; 626 if (close(fd) < 0) { 627 logmsg("socket_close: close"); 628 rv = -1; 629 } 630 if (server_flag && fd == serv_sock_fd) 631 if (unlink(serv_addr_sun.sun_path) < 0) { 632 logmsg("socket_close: unlink(%s)", 633 serv_addr_sun.sun_path); 634 rv = -1; 635 } 636 return (rv); 637 } 638 639 static int 640 socket_create(void) 641 { 642 struct timeval tv; 643 int fd; 644 645 fd = socket(PF_LOCAL, sock_type, 0); 646 if (fd < 0) { 647 logmsg("socket_create: socket(PF_LOCAL, %s, 0)", sock_type_str); 648 return (-1); 649 } 650 if (server_flag) 651 serv_sock_fd = fd; 652 653 tv.tv_sec = TIMEOUT; 654 tv.tv_usec = 0; 655 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 || 656 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { 657 logmsg("socket_create: setsockopt(SO_RCVTIMEO/SO_SNDTIMEO)"); 658 goto failed; 659 } 660 661 if (server_flag) { 662 if (bind(fd, (struct sockaddr *)&serv_addr_sun, 663 serv_addr_sun.sun_len) < 0) { 664 logmsg("socket_create: bind(%s)", 665 serv_addr_sun.sun_path); 666 goto failed; 667 } 668 if (sock_type == SOCK_STREAM) { 669 int val; 670 671 if (listen(fd, LISTENQ) < 0) { 672 logmsg("socket_create: listen"); 673 goto failed; 674 } 675 val = fcntl(fd, F_GETFL, 0); 676 if (val < 0) { 677 logmsg("socket_create: fcntl(F_GETFL)"); 678 goto failed; 679 } 680 if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) { 681 logmsg("socket_create: fcntl(F_SETFL)"); 682 goto failed; 683 } 684 } 685 } 686 687 return (fd); 688 689 failed: 690 if (close(fd) < 0) 691 logmsg("socket_create: close"); 692 if (server_flag) 693 if (unlink(serv_addr_sun.sun_path) < 0) 694 logmsg("socket_close: unlink(%s)", 695 serv_addr_sun.sun_path); 696 return (-1); 697 } 698 699 static int 700 socket_connect(int fd) 701 { 702 dbgmsg("connect"); 703 704 if (connect(fd, (struct sockaddr *)&serv_addr_sun, 705 serv_addr_sun.sun_len) < 0) { 706 logmsg("socket_connect: connect(%s)", serv_addr_sun.sun_path); 707 return (-1); 708 } 709 return (0); 710 } 711 712 static int 713 sync_recv(void) 714 { 715 ssize_t ssize; 716 int fd; 717 char buf; 718 719 dbgmsg("sync: wait"); 720 721 fd = sync_fd[server_flag ? SYNC_SERVER : SYNC_CLIENT][SYNC_RECV]; 722 723 ssize = read(fd, &buf, 1); 724 if (ssize < 0) { 725 logmsg("sync_recv: read"); 726 return (-1); 727 } 728 if (ssize < 1) { 729 logmsgx("sync_recv: read %zd of 1 byte", ssize); 730 return (-1); 731 } 732 733 dbgmsg("sync: received"); 734 735 return (0); 736 } 737 738 static int 739 sync_send(void) 740 { 741 ssize_t ssize; 742 int fd; 743 744 dbgmsg("sync: send"); 745 746 fd = sync_fd[server_flag ? SYNC_CLIENT : SYNC_SERVER][SYNC_SEND]; 747 748 ssize = write(fd, "", 1); 749 if (ssize < 0) { 750 logmsg("sync_send: write"); 751 return (-1); 752 } 753 if (ssize < 1) { 754 logmsgx("sync_send: sent %zd of 1 byte", ssize); 755 return (-1); 756 } 757 758 return (0); 759 } 760 761 static int 762 message_send(int fd, const struct msghdr *msghdr) 763 { 764 const struct cmsghdr *cmsghdr; 765 size_t size; 766 ssize_t ssize; 767 768 size = msghdr->msg_iov != 0 ? msghdr->msg_iov->iov_len : 0; 769 dbgmsg("send: data size %zu", size); 770 dbgmsg("send: msghdr.msg_controllen %u", 771 (u_int)msghdr->msg_controllen); 772 cmsghdr = CMSG_FIRSTHDR(msghdr); 773 if (cmsghdr != NULL) 774 dbgmsg("send: cmsghdr.cmsg_len %u", 775 (u_int)cmsghdr->cmsg_len); 776 777 ssize = sendmsg(fd, msghdr, 0); 778 if (ssize < 0) { 779 logmsg("message_send: sendmsg"); 780 return (-1); 781 } 782 if ((size_t)ssize != size) { 783 logmsgx("message_send: sendmsg: sent %zd of %zu bytes", 784 ssize, size); 785 return (-1); 786 } 787 788 if (!send_data_flag) 789 if (sync_send() < 0) 790 return (-1); 791 792 return (0); 793 } 794 795 static int 796 message_sendn(int fd, struct msghdr *msghdr) 797 { 798 u_int i; 799 800 for (i = 1; i <= ipc_msg.msg_num; ++i) { 801 dbgmsg("message #%u", i); 802 if (message_send(fd, msghdr) < 0) 803 return (-1); 804 } 805 return (0); 806 } 807 808 static int 809 message_recv(int fd, struct msghdr *msghdr) 810 { 811 const struct cmsghdr *cmsghdr; 812 size_t size; 813 ssize_t ssize; 814 815 if (!send_data_flag) 816 if (sync_recv() < 0) 817 return (-1); 818 819 size = msghdr->msg_iov != NULL ? msghdr->msg_iov->iov_len : 0; 820 ssize = recvmsg(fd, msghdr, MSG_WAITALL); 821 if (ssize < 0) { 822 logmsg("message_recv: recvmsg"); 823 return (-1); 824 } 825 if ((size_t)ssize != size) { 826 logmsgx("message_recv: recvmsg: received %zd of %zu bytes", 827 ssize, size); 828 return (-1); 829 } 830 831 dbgmsg("recv: data size %zd", ssize); 832 dbgmsg("recv: msghdr.msg_controllen %u", 833 (u_int)msghdr->msg_controllen); 834 cmsghdr = CMSG_FIRSTHDR(msghdr); 835 if (cmsghdr != NULL) 836 dbgmsg("recv: cmsghdr.cmsg_len %u", 837 (u_int)cmsghdr->cmsg_len); 838 839 if (memcmp(ipc_msg.buf_recv, ipc_msg.buf_send, size) != 0) { 840 logmsgx("message_recv: received message has wrong content"); 841 return (-1); 842 } 843 844 return (0); 845 } 846 847 static int 848 socket_accept(int listenfd) 849 { 850 fd_set rset; 851 struct timeval tv; 852 int fd, rv, val; 853 854 dbgmsg("accept"); 855 856 FD_ZERO(&rset); 857 FD_SET(listenfd, &rset); 858 tv.tv_sec = TIMEOUT; 859 tv.tv_usec = 0; 860 rv = select(listenfd + 1, &rset, (fd_set *)NULL, (fd_set *)NULL, &tv); 861 if (rv < 0) { 862 logmsg("socket_accept: select"); 863 return (-1); 864 } 865 if (rv == 0) { 866 logmsgx("socket_accept: select timeout"); 867 return (-1); 868 } 869 870 fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL); 871 if (fd < 0) { 872 logmsg("socket_accept: accept"); 873 return (-1); 874 } 875 876 val = fcntl(fd, F_GETFL, 0); 877 if (val < 0) { 878 logmsg("socket_accept: fcntl(F_GETFL)"); 879 goto failed; 880 } 881 if (fcntl(fd, F_SETFL, val & ~O_NONBLOCK) < 0) { 882 logmsg("socket_accept: fcntl(F_SETFL)"); 883 goto failed; 884 } 885 886 return (fd); 887 888 failed: 889 if (close(fd) < 0) 890 logmsg("socket_accept: close"); 891 return (-1); 892 } 893 894 static int 895 check_msghdr(const struct msghdr *msghdr, size_t size) 896 { 897 if (msghdr->msg_flags & MSG_TRUNC) { 898 logmsgx("msghdr.msg_flags has MSG_TRUNC"); 899 return (-1); 900 } 901 if (msghdr->msg_flags & MSG_CTRUNC) { 902 logmsgx("msghdr.msg_flags has MSG_CTRUNC"); 903 return (-1); 904 } 905 if (msghdr->msg_controllen < size) { 906 logmsgx("msghdr.msg_controllen %u < %zu", 907 (u_int)msghdr->msg_controllen, size); 908 return (-1); 909 } 910 if (msghdr->msg_controllen > 0 && size == 0) { 911 logmsgx("msghdr.msg_controllen %u > 0", 912 (u_int)msghdr->msg_controllen); 913 return (-1); 914 } 915 return (0); 916 } 917 918 static int 919 check_cmsghdr(const struct cmsghdr *cmsghdr, int type, size_t size) 920 { 921 if (cmsghdr == NULL) { 922 logmsgx("cmsghdr is NULL"); 923 return (-1); 924 } 925 if (cmsghdr->cmsg_level != SOL_SOCKET) { 926 logmsgx("cmsghdr.cmsg_level %d != SOL_SOCKET", 927 cmsghdr->cmsg_level); 928 return (-1); 929 } 930 if (cmsghdr->cmsg_type != type) { 931 logmsgx("cmsghdr.cmsg_type %d != %d", 932 cmsghdr->cmsg_type, type); 933 return (-1); 934 } 935 if (cmsghdr->cmsg_len != CMSG_LEN(size)) { 936 logmsgx("cmsghdr.cmsg_len %u != %zu", 937 (u_int)cmsghdr->cmsg_len, CMSG_LEN(size)); 938 return (-1); 939 } 940 return (0); 941 } 942 943 static int 944 check_groups(const char *gid_arr_str, const gid_t *gid_arr, 945 const char *gid_num_str, int gid_num, bool all_gids) 946 { 947 int i; 948 949 for (i = 0; i < gid_num; ++i) 950 dbgmsg("%s[%d] %lu", gid_arr_str, i, (u_long)gid_arr[i]); 951 952 if (all_gids) { 953 if (gid_num != proc_cred.gid_num) { 954 logmsgx("%s %d != %d", gid_num_str, gid_num, 955 proc_cred.gid_num); 956 return (-1); 957 } 958 } else { 959 if (gid_num > proc_cred.gid_num) { 960 logmsgx("%s %d > %d", gid_num_str, gid_num, 961 proc_cred.gid_num); 962 return (-1); 963 } 964 } 965 if (memcmp(gid_arr, proc_cred.gid_arr, 966 gid_num * sizeof(*gid_arr)) != 0) { 967 logmsgx("%s content is wrong", gid_arr_str); 968 for (i = 0; i < gid_num; ++i) 969 if (gid_arr[i] != proc_cred.gid_arr[i]) { 970 logmsgx("%s[%d] %lu != %lu", 971 gid_arr_str, i, (u_long)gid_arr[i], 972 (u_long)proc_cred.gid_arr[i]); 973 break; 974 } 975 return (-1); 976 } 977 return (0); 978 } 979 980 static int 981 check_xucred(const struct xucred *xucred, socklen_t len) 982 { 983 if (len != sizeof(*xucred)) { 984 logmsgx("option value size %zu != %zu", 985 (size_t)len, sizeof(*xucred)); 986 return (-1); 987 } 988 989 dbgmsg("xucred.cr_version %u", xucred->cr_version); 990 dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid); 991 dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups); 992 993 if (xucred->cr_version != XUCRED_VERSION) { 994 logmsgx("xucred.cr_version %u != %d", 995 xucred->cr_version, XUCRED_VERSION); 996 return (-1); 997 } 998 if (xucred->cr_uid != proc_cred.euid) { 999 logmsgx("xucred.cr_uid %lu != %lu (EUID)", 1000 (u_long)xucred->cr_uid, (u_long)proc_cred.euid); 1001 return (-1); 1002 } 1003 if (xucred->cr_ngroups == 0) { 1004 logmsgx("xucred.cr_ngroups == 0"); 1005 return (-1); 1006 } 1007 if (xucred->cr_ngroups < 0) { 1008 logmsgx("xucred.cr_ngroups < 0"); 1009 return (-1); 1010 } 1011 if (xucred->cr_ngroups > XU_NGROUPS) { 1012 logmsgx("xucred.cr_ngroups %hu > %u (max)", 1013 xucred->cr_ngroups, XU_NGROUPS); 1014 return (-1); 1015 } 1016 if (xucred->cr_groups[0] != proc_cred.egid) { 1017 logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)", 1018 (u_long)xucred->cr_groups[0], (u_long)proc_cred.egid); 1019 return (-1); 1020 } 1021 if (check_groups("xucred.cr_groups", xucred->cr_groups, 1022 "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0) 1023 return (-1); 1024 return (0); 1025 } 1026 1027 static int 1028 check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr) 1029 { 1030 const struct cmsgcred *cmsgcred; 1031 1032 if (check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(*cmsgcred)) < 0) 1033 return (-1); 1034 1035 cmsgcred = (struct cmsgcred *)CMSG_DATA(cmsghdr); 1036 1037 dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmsgcred->cmcred_pid); 1038 dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmsgcred->cmcred_uid); 1039 dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmsgcred->cmcred_euid); 1040 dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmsgcred->cmcred_gid); 1041 dbgmsg("cmsgcred.cmcred_ngroups %d", cmsgcred->cmcred_ngroups); 1042 1043 if (cmsgcred->cmcred_pid != client_pid) { 1044 logmsgx("cmsgcred.cmcred_pid %ld != %ld", 1045 (long)cmsgcred->cmcred_pid, (long)client_pid); 1046 return (-1); 1047 } 1048 if (cmsgcred->cmcred_uid != proc_cred.uid) { 1049 logmsgx("cmsgcred.cmcred_uid %lu != %lu", 1050 (u_long)cmsgcred->cmcred_uid, (u_long)proc_cred.uid); 1051 return (-1); 1052 } 1053 if (cmsgcred->cmcred_euid != proc_cred.euid) { 1054 logmsgx("cmsgcred.cmcred_euid %lu != %lu", 1055 (u_long)cmsgcred->cmcred_euid, (u_long)proc_cred.euid); 1056 return (-1); 1057 } 1058 if (cmsgcred->cmcred_gid != proc_cred.gid) { 1059 logmsgx("cmsgcred.cmcred_gid %lu != %lu", 1060 (u_long)cmsgcred->cmcred_gid, (u_long)proc_cred.gid); 1061 return (-1); 1062 } 1063 if (cmsgcred->cmcred_ngroups == 0) { 1064 logmsgx("cmsgcred.cmcred_ngroups == 0"); 1065 return (-1); 1066 } 1067 if (cmsgcred->cmcred_ngroups < 0) { 1068 logmsgx("cmsgcred.cmcred_ngroups %d < 0", 1069 cmsgcred->cmcred_ngroups); 1070 return (-1); 1071 } 1072 if (cmsgcred->cmcred_ngroups > CMGROUP_MAX) { 1073 logmsgx("cmsgcred.cmcred_ngroups %d > %d", 1074 cmsgcred->cmcred_ngroups, CMGROUP_MAX); 1075 return (-1); 1076 } 1077 if (cmsgcred->cmcred_groups[0] != proc_cred.egid) { 1078 logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)", 1079 (u_long)cmsgcred->cmcred_groups[0], (u_long)proc_cred.egid); 1080 return (-1); 1081 } 1082 if (check_groups("cmsgcred.cmcred_groups", cmsgcred->cmcred_groups, 1083 "cmsgcred.cmcred_ngroups", cmsgcred->cmcred_ngroups, false) < 0) 1084 return (-1); 1085 return (0); 1086 } 1087 1088 static int 1089 check_scm_creds_sockcred(struct cmsghdr *cmsghdr) 1090 { 1091 const struct sockcred *sockcred; 1092 1093 if (check_cmsghdr(cmsghdr, SCM_CREDS, 1094 SOCKCREDSIZE(proc_cred.gid_num)) < 0) 1095 return (-1); 1096 1097 sockcred = (struct sockcred *)CMSG_DATA(cmsghdr); 1098 1099 dbgmsg("sockcred.sc_uid %lu", (u_long)sockcred->sc_uid); 1100 dbgmsg("sockcred.sc_euid %lu", (u_long)sockcred->sc_euid); 1101 dbgmsg("sockcred.sc_gid %lu", (u_long)sockcred->sc_gid); 1102 dbgmsg("sockcred.sc_egid %lu", (u_long)sockcred->sc_egid); 1103 dbgmsg("sockcred.sc_ngroups %d", sockcred->sc_ngroups); 1104 1105 if (sockcred->sc_uid != proc_cred.uid) { 1106 logmsgx("sockcred.sc_uid %lu != %lu", 1107 (u_long)sockcred->sc_uid, (u_long)proc_cred.uid); 1108 return (-1); 1109 } 1110 if (sockcred->sc_euid != proc_cred.euid) { 1111 logmsgx("sockcred.sc_euid %lu != %lu", 1112 (u_long)sockcred->sc_euid, (u_long)proc_cred.euid); 1113 return (-1); 1114 } 1115 if (sockcred->sc_gid != proc_cred.gid) { 1116 logmsgx("sockcred.sc_gid %lu != %lu", 1117 (u_long)sockcred->sc_gid, (u_long)proc_cred.gid); 1118 return (-1); 1119 } 1120 if (sockcred->sc_egid != proc_cred.egid) { 1121 logmsgx("sockcred.sc_egid %lu != %lu", 1122 (u_long)sockcred->sc_egid, (u_long)proc_cred.egid); 1123 return (-1); 1124 } 1125 if (sockcred->sc_ngroups == 0) { 1126 logmsgx("sockcred.sc_ngroups == 0"); 1127 return (-1); 1128 } 1129 if (sockcred->sc_ngroups < 0) { 1130 logmsgx("sockcred.sc_ngroups %d < 0", 1131 sockcred->sc_ngroups); 1132 return (-1); 1133 } 1134 if (sockcred->sc_ngroups != proc_cred.gid_num) { 1135 logmsgx("sockcred.sc_ngroups %d != %u", 1136 sockcred->sc_ngroups, proc_cred.gid_num); 1137 return (-1); 1138 } 1139 if (check_groups("sockcred.sc_groups", sockcred->sc_groups, 1140 "sockcred.sc_ngroups", sockcred->sc_ngroups, true) < 0) 1141 return (-1); 1142 return (0); 1143 } 1144 1145 static int 1146 check_scm_timestamp(struct cmsghdr *cmsghdr) 1147 { 1148 const struct timeval *timeval; 1149 1150 if (check_cmsghdr(cmsghdr, SCM_TIMESTAMP, sizeof(struct timeval)) < 0) 1151 return (-1); 1152 1153 timeval = (struct timeval *)CMSG_DATA(cmsghdr); 1154 1155 dbgmsg("timeval.tv_sec %"PRIdMAX", timeval.tv_usec %"PRIdMAX, 1156 (intmax_t)timeval->tv_sec, (intmax_t)timeval->tv_usec); 1157 1158 return (0); 1159 } 1160 1161 static int 1162 check_scm_bintime(struct cmsghdr *cmsghdr) 1163 { 1164 const struct bintime *bintime; 1165 1166 if (check_cmsghdr(cmsghdr, SCM_BINTIME, sizeof(struct bintime)) < 0) 1167 return (-1); 1168 1169 bintime = (struct bintime *)CMSG_DATA(cmsghdr); 1170 1171 dbgmsg("bintime.sec %"PRIdMAX", bintime.frac %"PRIu64, 1172 (intmax_t)bintime->sec, bintime->frac); 1173 1174 return (0); 1175 } 1176 1177 static void 1178 msghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data) 1179 { 1180 msghdr->msg_name = NULL; 1181 msghdr->msg_namelen = 0; 1182 if (send_data_flag) { 1183 iov->iov_base = server_flag ? 1184 ipc_msg.buf_recv : ipc_msg.buf_send; 1185 iov->iov_len = ipc_msg.buf_size; 1186 msghdr->msg_iov = iov; 1187 msghdr->msg_iovlen = 1; 1188 } else { 1189 msghdr->msg_iov = NULL; 1190 msghdr->msg_iovlen = 0; 1191 } 1192 msghdr->msg_control = cmsg_data; 1193 msghdr->msg_flags = 0; 1194 } 1195 1196 static void 1197 msghdr_init_server(struct msghdr *msghdr, struct iovec *iov, 1198 void *cmsg_data, size_t cmsg_size) 1199 { 1200 msghdr_init_generic(msghdr, iov, cmsg_data); 1201 msghdr->msg_controllen = cmsg_size; 1202 dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ? 1203 msghdr->msg_iov->iov_len : (size_t)0); 1204 dbgmsg("init: msghdr.msg_controllen %u", 1205 (u_int)msghdr->msg_controllen); 1206 } 1207 1208 static void 1209 msghdr_init_client(struct msghdr *msghdr, struct iovec *iov, 1210 void *cmsg_data, size_t cmsg_size, int type, size_t arr_size) 1211 { 1212 struct cmsghdr *cmsghdr; 1213 1214 msghdr_init_generic(msghdr, iov, cmsg_data); 1215 if (cmsg_data != NULL) { 1216 msghdr->msg_controllen = send_array_flag ? 1217 cmsg_size : CMSG_SPACE(0); 1218 cmsghdr = CMSG_FIRSTHDR(msghdr); 1219 cmsghdr->cmsg_level = SOL_SOCKET; 1220 cmsghdr->cmsg_type = type; 1221 cmsghdr->cmsg_len = CMSG_LEN(send_array_flag ? arr_size : 0); 1222 } else 1223 msghdr->msg_controllen = 0; 1224 } 1225 1226 static int 1227 t_generic(int (*client_func)(int), int (*server_func)(int)) 1228 { 1229 int fd, rv, rv_client; 1230 1231 switch (client_fork()) { 1232 case 0: 1233 fd = socket_create(); 1234 if (fd < 0) 1235 rv = -2; 1236 else { 1237 rv = client_func(fd); 1238 if (socket_close(fd) < 0) 1239 rv = -2; 1240 } 1241 client_exit(rv); 1242 break; 1243 case 1: 1244 fd = socket_create(); 1245 if (fd < 0) 1246 rv = -2; 1247 else { 1248 rv = server_func(fd); 1249 rv_client = client_wait(); 1250 if (rv == 0 || (rv == -2 && rv_client != 0)) 1251 rv = rv_client; 1252 if (socket_close(fd) < 0) 1253 rv = -2; 1254 } 1255 break; 1256 default: 1257 rv = -2; 1258 } 1259 return (rv); 1260 } 1261 1262 static int 1263 t_cmsgcred_client(int fd) 1264 { 1265 struct msghdr msghdr; 1266 struct iovec iov[1]; 1267 void *cmsg_data; 1268 size_t cmsg_size; 1269 int rv; 1270 1271 if (sync_recv() < 0) 1272 return (-2); 1273 1274 rv = -2; 1275 1276 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1277 cmsg_data = malloc(cmsg_size); 1278 if (cmsg_data == NULL) { 1279 logmsg("malloc"); 1280 goto done; 1281 } 1282 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1283 SCM_CREDS, sizeof(struct cmsgcred)); 1284 1285 if (socket_connect(fd) < 0) 1286 goto done; 1287 1288 if (message_sendn(fd, &msghdr) < 0) 1289 goto done; 1290 1291 rv = 0; 1292 done: 1293 free(cmsg_data); 1294 return (rv); 1295 } 1296 1297 static int 1298 t_cmsgcred_server(int fd1) 1299 { 1300 struct msghdr msghdr; 1301 struct iovec iov[1]; 1302 struct cmsghdr *cmsghdr; 1303 void *cmsg_data; 1304 size_t cmsg_size; 1305 u_int i; 1306 int fd2, rv; 1307 1308 if (sync_send() < 0) 1309 return (-2); 1310 1311 fd2 = -1; 1312 rv = -2; 1313 1314 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1315 cmsg_data = malloc(cmsg_size); 1316 if (cmsg_data == NULL) { 1317 logmsg("malloc"); 1318 goto done; 1319 } 1320 1321 if (sock_type == SOCK_STREAM) { 1322 fd2 = socket_accept(fd1); 1323 if (fd2 < 0) 1324 goto done; 1325 } else 1326 fd2 = fd1; 1327 1328 rv = -1; 1329 for (i = 1; i <= ipc_msg.msg_num; ++i) { 1330 dbgmsg("message #%u", i); 1331 1332 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1333 if (message_recv(fd2, &msghdr) < 0) { 1334 rv = -2; 1335 break; 1336 } 1337 1338 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1339 break; 1340 1341 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1342 if (check_scm_creds_cmsgcred(cmsghdr) < 0) 1343 break; 1344 } 1345 if (i > ipc_msg.msg_num) 1346 rv = 0; 1347 done: 1348 free(cmsg_data); 1349 if (sock_type == SOCK_STREAM && fd2 >= 0) 1350 if (socket_close(fd2) < 0) 1351 rv = -2; 1352 return (rv); 1353 } 1354 1355 static int 1356 t_cmsgcred(void) 1357 { 1358 return (t_generic(t_cmsgcred_client, t_cmsgcred_server)); 1359 } 1360 1361 static int 1362 t_sockcred_client(int type, int fd) 1363 { 1364 struct msghdr msghdr; 1365 struct iovec iov[1]; 1366 int rv; 1367 1368 if (sync_recv() < 0) 1369 return (-2); 1370 1371 rv = -2; 1372 1373 msghdr_init_client(&msghdr, iov, NULL, 0, 0, 0); 1374 1375 if (socket_connect(fd) < 0) 1376 goto done; 1377 1378 if (type == 2) 1379 if (sync_recv() < 0) 1380 goto done; 1381 1382 if (message_sendn(fd, &msghdr) < 0) 1383 goto done; 1384 1385 rv = 0; 1386 done: 1387 return (rv); 1388 } 1389 1390 static int 1391 t_sockcred_server(int type, int fd1) 1392 { 1393 struct msghdr msghdr; 1394 struct iovec iov[1]; 1395 struct cmsghdr *cmsghdr; 1396 void *cmsg_data; 1397 size_t cmsg_size; 1398 u_int i; 1399 int fd2, rv, val; 1400 1401 fd2 = -1; 1402 rv = -2; 1403 1404 cmsg_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num)); 1405 cmsg_data = malloc(cmsg_size); 1406 if (cmsg_data == NULL) { 1407 logmsg("malloc"); 1408 goto done; 1409 } 1410 1411 if (type == 1) { 1412 dbgmsg("setting LOCAL_CREDS"); 1413 val = 1; 1414 if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { 1415 logmsg("setsockopt(LOCAL_CREDS)"); 1416 goto done; 1417 } 1418 } 1419 1420 if (sync_send() < 0) 1421 goto done; 1422 1423 if (sock_type == SOCK_STREAM) { 1424 fd2 = socket_accept(fd1); 1425 if (fd2 < 0) 1426 goto done; 1427 } else 1428 fd2 = fd1; 1429 1430 if (type == 2) { 1431 dbgmsg("setting LOCAL_CREDS"); 1432 val = 1; 1433 if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { 1434 logmsg("setsockopt(LOCAL_CREDS)"); 1435 goto done; 1436 } 1437 if (sync_send() < 0) 1438 goto done; 1439 } 1440 1441 rv = -1; 1442 for (i = 1; i <= ipc_msg.msg_num; ++i) { 1443 dbgmsg("message #%u", i); 1444 1445 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1446 if (message_recv(fd2, &msghdr) < 0) { 1447 rv = -2; 1448 break; 1449 } 1450 1451 if (i > 1 && sock_type == SOCK_STREAM) { 1452 if (check_msghdr(&msghdr, 0) < 0) 1453 break; 1454 } else { 1455 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1456 break; 1457 1458 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1459 if (check_scm_creds_sockcred(cmsghdr) < 0) 1460 break; 1461 } 1462 } 1463 if (i > ipc_msg.msg_num) 1464 rv = 0; 1465 done: 1466 free(cmsg_data); 1467 if (sock_type == SOCK_STREAM && fd2 >= 0) 1468 if (socket_close(fd2) < 0) 1469 rv = -2; 1470 return (rv); 1471 } 1472 1473 static int 1474 t_sockcred_1(void) 1475 { 1476 u_int i; 1477 int fd, rv, rv_client; 1478 1479 switch (client_fork()) { 1480 case 0: 1481 for (i = 1; i <= 2; ++i) { 1482 dbgmsg("client #%u", i); 1483 fd = socket_create(); 1484 if (fd < 0) 1485 rv = -2; 1486 else { 1487 rv = t_sockcred_client(1, fd); 1488 if (socket_close(fd) < 0) 1489 rv = -2; 1490 } 1491 if (rv != 0) 1492 break; 1493 } 1494 client_exit(rv); 1495 break; 1496 case 1: 1497 fd = socket_create(); 1498 if (fd < 0) 1499 rv = -2; 1500 else { 1501 rv = t_sockcred_server(1, fd); 1502 if (rv == 0) 1503 rv = t_sockcred_server(3, fd); 1504 rv_client = client_wait(); 1505 if (rv == 0 || (rv == -2 && rv_client != 0)) 1506 rv = rv_client; 1507 if (socket_close(fd) < 0) 1508 rv = -2; 1509 } 1510 break; 1511 default: 1512 rv = -2; 1513 } 1514 1515 return (rv); 1516 } 1517 1518 static int 1519 t_sockcred_2_client(int fd) 1520 { 1521 return (t_sockcred_client(2, fd)); 1522 } 1523 1524 static int 1525 t_sockcred_2_server(int fd) 1526 { 1527 return (t_sockcred_server(2, fd)); 1528 } 1529 1530 static int 1531 t_sockcred_2(void) 1532 { 1533 return (t_generic(t_sockcred_2_client, t_sockcred_2_server)); 1534 } 1535 1536 static int 1537 t_cmsgcred_sockcred_server(int fd1) 1538 { 1539 struct msghdr msghdr; 1540 struct iovec iov[1]; 1541 struct cmsghdr *cmsghdr; 1542 void *cmsg_data, *cmsg1_data, *cmsg2_data; 1543 size_t cmsg_size, cmsg1_size, cmsg2_size; 1544 u_int i; 1545 int fd2, rv, val; 1546 1547 fd2 = -1; 1548 rv = -2; 1549 1550 cmsg1_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num)); 1551 cmsg2_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1552 cmsg1_data = malloc(cmsg1_size); 1553 cmsg2_data = malloc(cmsg2_size); 1554 if (cmsg1_data == NULL || cmsg2_data == NULL) { 1555 logmsg("malloc"); 1556 goto done; 1557 } 1558 1559 dbgmsg("setting LOCAL_CREDS"); 1560 val = 1; 1561 if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { 1562 logmsg("setsockopt(LOCAL_CREDS)"); 1563 goto done; 1564 } 1565 1566 if (sync_send() < 0) 1567 goto done; 1568 1569 if (sock_type == SOCK_STREAM) { 1570 fd2 = socket_accept(fd1); 1571 if (fd2 < 0) 1572 goto done; 1573 } else 1574 fd2 = fd1; 1575 1576 cmsg_data = cmsg1_data; 1577 cmsg_size = cmsg1_size; 1578 rv = -1; 1579 for (i = 1; i <= ipc_msg.msg_num; ++i) { 1580 dbgmsg("message #%u", i); 1581 1582 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1583 if (message_recv(fd2, &msghdr) < 0) { 1584 rv = -2; 1585 break; 1586 } 1587 1588 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1589 break; 1590 1591 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1592 if (i == 1 || sock_type == SOCK_DGRAM) { 1593 if (check_scm_creds_sockcred(cmsghdr) < 0) 1594 break; 1595 } else { 1596 if (check_scm_creds_cmsgcred(cmsghdr) < 0) 1597 break; 1598 } 1599 1600 cmsg_data = cmsg2_data; 1601 cmsg_size = cmsg2_size; 1602 } 1603 if (i > ipc_msg.msg_num) 1604 rv = 0; 1605 done: 1606 free(cmsg1_data); 1607 free(cmsg2_data); 1608 if (sock_type == SOCK_STREAM && fd2 >= 0) 1609 if (socket_close(fd2) < 0) 1610 rv = -2; 1611 return (rv); 1612 } 1613 1614 static int 1615 t_cmsgcred_sockcred(void) 1616 { 1617 return (t_generic(t_cmsgcred_client, t_cmsgcred_sockcred_server)); 1618 } 1619 1620 static int 1621 t_timeval_client(int fd) 1622 { 1623 struct msghdr msghdr; 1624 struct iovec iov[1]; 1625 void *cmsg_data; 1626 size_t cmsg_size; 1627 int rv; 1628 1629 if (sync_recv() < 0) 1630 return (-2); 1631 1632 rv = -2; 1633 1634 cmsg_size = CMSG_SPACE(sizeof(struct timeval)); 1635 cmsg_data = malloc(cmsg_size); 1636 if (cmsg_data == NULL) { 1637 logmsg("malloc"); 1638 goto done; 1639 } 1640 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1641 SCM_TIMESTAMP, sizeof(struct timeval)); 1642 1643 if (socket_connect(fd) < 0) 1644 goto done; 1645 1646 if (message_sendn(fd, &msghdr) < 0) 1647 goto done; 1648 1649 rv = 0; 1650 done: 1651 free(cmsg_data); 1652 return (rv); 1653 } 1654 1655 static int 1656 t_timeval_server(int fd1) 1657 { 1658 struct msghdr msghdr; 1659 struct iovec iov[1]; 1660 struct cmsghdr *cmsghdr; 1661 void *cmsg_data; 1662 size_t cmsg_size; 1663 u_int i; 1664 int fd2, rv; 1665 1666 if (sync_send() < 0) 1667 return (-2); 1668 1669 fd2 = -1; 1670 rv = -2; 1671 1672 cmsg_size = CMSG_SPACE(sizeof(struct timeval)); 1673 cmsg_data = malloc(cmsg_size); 1674 if (cmsg_data == NULL) { 1675 logmsg("malloc"); 1676 goto done; 1677 } 1678 1679 if (sock_type == SOCK_STREAM) { 1680 fd2 = socket_accept(fd1); 1681 if (fd2 < 0) 1682 goto done; 1683 } else 1684 fd2 = fd1; 1685 1686 rv = -1; 1687 for (i = 1; i <= ipc_msg.msg_num; ++i) { 1688 dbgmsg("message #%u", i); 1689 1690 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1691 if (message_recv(fd2, &msghdr) < 0) { 1692 rv = -2; 1693 break; 1694 } 1695 1696 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1697 break; 1698 1699 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1700 if (check_scm_timestamp(cmsghdr) < 0) 1701 break; 1702 } 1703 if (i > ipc_msg.msg_num) 1704 rv = 0; 1705 done: 1706 free(cmsg_data); 1707 if (sock_type == SOCK_STREAM && fd2 >= 0) 1708 if (socket_close(fd2) < 0) 1709 rv = -2; 1710 return (rv); 1711 } 1712 1713 static int 1714 t_timeval(void) 1715 { 1716 return (t_generic(t_timeval_client, t_timeval_server)); 1717 } 1718 1719 static int 1720 t_bintime_client(int fd) 1721 { 1722 struct msghdr msghdr; 1723 struct iovec iov[1]; 1724 void *cmsg_data; 1725 size_t cmsg_size; 1726 int rv; 1727 1728 if (sync_recv() < 0) 1729 return (-2); 1730 1731 rv = -2; 1732 1733 cmsg_size = CMSG_SPACE(sizeof(struct bintime)); 1734 cmsg_data = malloc(cmsg_size); 1735 if (cmsg_data == NULL) { 1736 logmsg("malloc"); 1737 goto done; 1738 } 1739 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1740 SCM_BINTIME, sizeof(struct bintime)); 1741 1742 if (socket_connect(fd) < 0) 1743 goto done; 1744 1745 if (message_sendn(fd, &msghdr) < 0) 1746 goto done; 1747 1748 rv = 0; 1749 done: 1750 free(cmsg_data); 1751 return (rv); 1752 } 1753 1754 static int 1755 t_bintime_server(int fd1) 1756 { 1757 struct msghdr msghdr; 1758 struct iovec iov[1]; 1759 struct cmsghdr *cmsghdr; 1760 void *cmsg_data; 1761 size_t cmsg_size; 1762 u_int i; 1763 int fd2, rv; 1764 1765 if (sync_send() < 0) 1766 return (-2); 1767 1768 fd2 = -1; 1769 rv = -2; 1770 1771 cmsg_size = CMSG_SPACE(sizeof(struct bintime)); 1772 cmsg_data = malloc(cmsg_size); 1773 if (cmsg_data == NULL) { 1774 logmsg("malloc"); 1775 goto done; 1776 } 1777 1778 if (sock_type == SOCK_STREAM) { 1779 fd2 = socket_accept(fd1); 1780 if (fd2 < 0) 1781 goto done; 1782 } else 1783 fd2 = fd1; 1784 1785 rv = -1; 1786 for (i = 1; i <= ipc_msg.msg_num; ++i) { 1787 dbgmsg("message #%u", i); 1788 1789 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1790 if (message_recv(fd2, &msghdr) < 0) { 1791 rv = -2; 1792 break; 1793 } 1794 1795 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1796 break; 1797 1798 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1799 if (check_scm_bintime(cmsghdr) < 0) 1800 break; 1801 } 1802 if (i > ipc_msg.msg_num) 1803 rv = 0; 1804 done: 1805 free(cmsg_data); 1806 if (sock_type == SOCK_STREAM && fd2 >= 0) 1807 if (socket_close(fd2) < 0) 1808 rv = -2; 1809 return (rv); 1810 } 1811 1812 static int 1813 t_bintime(void) 1814 { 1815 return (t_generic(t_bintime_client, t_bintime_server)); 1816 } 1817 1818 static int 1819 t_cmsg_len_client(int fd) 1820 { 1821 struct msghdr msghdr; 1822 struct iovec iov[1]; 1823 struct cmsghdr *cmsghdr; 1824 void *cmsg_data; 1825 size_t size, cmsg_size; 1826 socklen_t socklen; 1827 int rv; 1828 1829 if (sync_recv() < 0) 1830 return (-2); 1831 1832 rv = -2; 1833 1834 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1835 cmsg_data = malloc(cmsg_size); 1836 if (cmsg_data == NULL) { 1837 logmsg("malloc"); 1838 goto done; 1839 } 1840 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1841 SCM_CREDS, sizeof(struct cmsgcred)); 1842 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1843 1844 if (socket_connect(fd) < 0) 1845 goto done; 1846 1847 size = msghdr.msg_iov != NULL ? msghdr.msg_iov->iov_len : 0; 1848 rv = -1; 1849 for (socklen = 0; socklen < CMSG_LEN(0); ++socklen) { 1850 cmsghdr->cmsg_len = socklen; 1851 dbgmsg("send: data size %zu", size); 1852 dbgmsg("send: msghdr.msg_controllen %u", 1853 (u_int)msghdr.msg_controllen); 1854 dbgmsg("send: cmsghdr.cmsg_len %u", 1855 (u_int)cmsghdr->cmsg_len); 1856 if (sendmsg(fd, &msghdr, 0) < 0) 1857 continue; 1858 logmsgx("sent message with cmsghdr.cmsg_len %u < %u", 1859 (u_int)cmsghdr->cmsg_len, (u_int)CMSG_LEN(0)); 1860 break; 1861 } 1862 if (socklen == CMSG_LEN(0)) 1863 rv = 0; 1864 1865 if (sync_send() < 0) { 1866 rv = -2; 1867 goto done; 1868 } 1869 done: 1870 free(cmsg_data); 1871 return (rv); 1872 } 1873 1874 static int 1875 t_cmsg_len_server(int fd1) 1876 { 1877 int fd2, rv; 1878 1879 if (sync_send() < 0) 1880 return (-2); 1881 1882 rv = -2; 1883 1884 if (sock_type == SOCK_STREAM) { 1885 fd2 = socket_accept(fd1); 1886 if (fd2 < 0) 1887 goto done; 1888 } else 1889 fd2 = fd1; 1890 1891 if (sync_recv() < 0) 1892 goto done; 1893 1894 rv = 0; 1895 done: 1896 if (sock_type == SOCK_STREAM && fd2 >= 0) 1897 if (socket_close(fd2) < 0) 1898 rv = -2; 1899 return (rv); 1900 } 1901 1902 static int 1903 t_cmsg_len(void) 1904 { 1905 return (t_generic(t_cmsg_len_client, t_cmsg_len_server)); 1906 } 1907 1908 static int 1909 t_peercred_client(int fd) 1910 { 1911 struct xucred xucred; 1912 socklen_t len; 1913 1914 if (sync_recv() < 0) 1915 return (-1); 1916 1917 if (socket_connect(fd) < 0) 1918 return (-1); 1919 1920 len = sizeof(xucred); 1921 if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { 1922 logmsg("getsockopt(LOCAL_PEERCRED)"); 1923 return (-1); 1924 } 1925 1926 if (check_xucred(&xucred, len) < 0) 1927 return (-1); 1928 1929 return (0); 1930 } 1931 1932 static int 1933 t_peercred_server(int fd1) 1934 { 1935 struct xucred xucred; 1936 socklen_t len; 1937 int fd2, rv; 1938 1939 if (sync_send() < 0) 1940 return (-2); 1941 1942 fd2 = socket_accept(fd1); 1943 if (fd2 < 0) 1944 return (-2); 1945 1946 len = sizeof(xucred); 1947 if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { 1948 logmsg("getsockopt(LOCAL_PEERCRED)"); 1949 rv = -2; 1950 goto done; 1951 } 1952 1953 if (check_xucred(&xucred, len) < 0) { 1954 rv = -1; 1955 goto done; 1956 } 1957 1958 rv = 0; 1959 done: 1960 if (socket_close(fd2) < 0) 1961 rv = -2; 1962 return (rv); 1963 } 1964 1965 static int 1966 t_peercred(void) 1967 { 1968 return (t_generic(t_peercred_client, t_peercred_server)); 1969 } 1970