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 int rc; 984 985 if (len != sizeof(*xucred)) { 986 logmsgx("option value size %zu != %zu", 987 (size_t)len, sizeof(*xucred)); 988 return (-1); 989 } 990 991 dbgmsg("xucred.cr_version %u", xucred->cr_version); 992 dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid); 993 dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups); 994 995 rc = 0; 996 997 if (xucred->cr_version != XUCRED_VERSION) { 998 logmsgx("xucred.cr_version %u != %d", 999 xucred->cr_version, XUCRED_VERSION); 1000 rc = -1; 1001 } 1002 if (xucred->cr_uid != proc_cred.euid) { 1003 logmsgx("xucred.cr_uid %lu != %lu (EUID)", 1004 (u_long)xucred->cr_uid, (u_long)proc_cred.euid); 1005 rc = -1; 1006 } 1007 if (xucred->cr_ngroups == 0) { 1008 logmsgx("xucred.cr_ngroups == 0"); 1009 rc = -1; 1010 } 1011 if (xucred->cr_ngroups < 0) { 1012 logmsgx("xucred.cr_ngroups < 0"); 1013 rc = -1; 1014 } 1015 if (xucred->cr_ngroups > XU_NGROUPS) { 1016 logmsgx("xucred.cr_ngroups %hu > %u (max)", 1017 xucred->cr_ngroups, XU_NGROUPS); 1018 rc = -1; 1019 } 1020 if (xucred->cr_groups[0] != proc_cred.egid) { 1021 logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)", 1022 (u_long)xucred->cr_groups[0], (u_long)proc_cred.egid); 1023 rc = -1; 1024 } 1025 if (check_groups("xucred.cr_groups", xucred->cr_groups, 1026 "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0) 1027 rc = -1; 1028 return (rc); 1029 } 1030 1031 static int 1032 check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr) 1033 { 1034 const struct cmsgcred *cmcred; 1035 int rc; 1036 1037 if (check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(struct cmsgcred)) < 0) 1038 return (-1); 1039 1040 cmcred = (struct cmsgcred *)CMSG_DATA(cmsghdr); 1041 1042 dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmcred->cmcred_pid); 1043 dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmcred->cmcred_uid); 1044 dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmcred->cmcred_euid); 1045 dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmcred->cmcred_gid); 1046 dbgmsg("cmsgcred.cmcred_ngroups %d", cmcred->cmcred_ngroups); 1047 1048 rc = 0; 1049 1050 if (cmcred->cmcred_pid != client_pid) { 1051 logmsgx("cmsgcred.cmcred_pid %ld != %ld", 1052 (long)cmcred->cmcred_pid, (long)client_pid); 1053 rc = -1; 1054 } 1055 if (cmcred->cmcred_uid != proc_cred.uid) { 1056 logmsgx("cmsgcred.cmcred_uid %lu != %lu", 1057 (u_long)cmcred->cmcred_uid, (u_long)proc_cred.uid); 1058 rc = -1; 1059 } 1060 if (cmcred->cmcred_euid != proc_cred.euid) { 1061 logmsgx("cmsgcred.cmcred_euid %lu != %lu", 1062 (u_long)cmcred->cmcred_euid, (u_long)proc_cred.euid); 1063 rc = -1; 1064 } 1065 if (cmcred->cmcred_gid != proc_cred.gid) { 1066 logmsgx("cmsgcred.cmcred_gid %lu != %lu", 1067 (u_long)cmcred->cmcred_gid, (u_long)proc_cred.gid); 1068 rc = -1; 1069 } 1070 if (cmcred->cmcred_ngroups == 0) { 1071 logmsgx("cmsgcred.cmcred_ngroups == 0"); 1072 rc = -1; 1073 } 1074 if (cmcred->cmcred_ngroups < 0) { 1075 logmsgx("cmsgcred.cmcred_ngroups %d < 0", 1076 cmcred->cmcred_ngroups); 1077 rc = -1; 1078 } 1079 if (cmcred->cmcred_ngroups > CMGROUP_MAX) { 1080 logmsgx("cmsgcred.cmcred_ngroups %d > %d", 1081 cmcred->cmcred_ngroups, CMGROUP_MAX); 1082 rc = -1; 1083 } 1084 if (cmcred->cmcred_groups[0] != proc_cred.egid) { 1085 logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)", 1086 (u_long)cmcred->cmcred_groups[0], (u_long)proc_cred.egid); 1087 rc = -1; 1088 } 1089 if (check_groups("cmsgcred.cmcred_groups", cmcred->cmcred_groups, 1090 "cmsgcred.cmcred_ngroups", cmcred->cmcred_ngroups, false) < 0) 1091 rc = -1; 1092 return (rc); 1093 } 1094 1095 static int 1096 check_scm_creds_sockcred(struct cmsghdr *cmsghdr) 1097 { 1098 const struct sockcred *sc; 1099 int rc; 1100 1101 if (check_cmsghdr(cmsghdr, SCM_CREDS, 1102 SOCKCREDSIZE(proc_cred.gid_num)) < 0) 1103 return (-1); 1104 1105 sc = (struct sockcred *)CMSG_DATA(cmsghdr); 1106 1107 rc = 0; 1108 1109 dbgmsg("sockcred.sc_uid %lu", (u_long)sc->sc_uid); 1110 dbgmsg("sockcred.sc_euid %lu", (u_long)sc->sc_euid); 1111 dbgmsg("sockcred.sc_gid %lu", (u_long)sc->sc_gid); 1112 dbgmsg("sockcred.sc_egid %lu", (u_long)sc->sc_egid); 1113 dbgmsg("sockcred.sc_ngroups %d", sc->sc_ngroups); 1114 1115 if (sc->sc_uid != proc_cred.uid) { 1116 logmsgx("sockcred.sc_uid %lu != %lu", 1117 (u_long)sc->sc_uid, (u_long)proc_cred.uid); 1118 rc = -1; 1119 } 1120 if (sc->sc_euid != proc_cred.euid) { 1121 logmsgx("sockcred.sc_euid %lu != %lu", 1122 (u_long)sc->sc_euid, (u_long)proc_cred.euid); 1123 rc = -1; 1124 } 1125 if (sc->sc_gid != proc_cred.gid) { 1126 logmsgx("sockcred.sc_gid %lu != %lu", 1127 (u_long)sc->sc_gid, (u_long)proc_cred.gid); 1128 rc = -1; 1129 } 1130 if (sc->sc_egid != proc_cred.egid) { 1131 logmsgx("sockcred.sc_egid %lu != %lu", 1132 (u_long)sc->sc_egid, (u_long)proc_cred.egid); 1133 rc = -1; 1134 } 1135 if (sc->sc_ngroups == 0) { 1136 logmsgx("sockcred.sc_ngroups == 0"); 1137 rc = -1; 1138 } 1139 if (sc->sc_ngroups < 0) { 1140 logmsgx("sockcred.sc_ngroups %d < 0", 1141 sc->sc_ngroups); 1142 rc = -1; 1143 } 1144 if (sc->sc_ngroups != proc_cred.gid_num) { 1145 logmsgx("sockcred.sc_ngroups %d != %u", 1146 sc->sc_ngroups, proc_cred.gid_num); 1147 rc = -1; 1148 } 1149 if (check_groups("sockcred.sc_groups", sc->sc_groups, 1150 "sockcred.sc_ngroups", sc->sc_ngroups, true) < 0) 1151 rc = -1; 1152 return (rc); 1153 } 1154 1155 static int 1156 check_scm_timestamp(struct cmsghdr *cmsghdr) 1157 { 1158 const struct timeval *tv; 1159 1160 if (check_cmsghdr(cmsghdr, SCM_TIMESTAMP, sizeof(struct timeval)) < 0) 1161 return (-1); 1162 1163 tv = (struct timeval *)CMSG_DATA(cmsghdr); 1164 1165 dbgmsg("timeval.tv_sec %"PRIdMAX", timeval.tv_usec %"PRIdMAX, 1166 (intmax_t)tv->tv_sec, (intmax_t)tv->tv_usec); 1167 1168 return (0); 1169 } 1170 1171 static int 1172 check_scm_bintime(struct cmsghdr *cmsghdr) 1173 { 1174 const struct bintime *bt; 1175 1176 if (check_cmsghdr(cmsghdr, SCM_BINTIME, sizeof(struct bintime)) < 0) 1177 return (-1); 1178 1179 bt = (struct bintime *)CMSG_DATA(cmsghdr); 1180 1181 dbgmsg("bintime.sec %"PRIdMAX", bintime.frac %"PRIu64, 1182 (intmax_t)bt->sec, bt->frac); 1183 1184 return (0); 1185 } 1186 1187 static void 1188 msghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data) 1189 { 1190 msghdr->msg_name = NULL; 1191 msghdr->msg_namelen = 0; 1192 if (send_data_flag) { 1193 iov->iov_base = server_flag ? 1194 ipc_msg.buf_recv : ipc_msg.buf_send; 1195 iov->iov_len = ipc_msg.buf_size; 1196 msghdr->msg_iov = iov; 1197 msghdr->msg_iovlen = 1; 1198 } else { 1199 msghdr->msg_iov = NULL; 1200 msghdr->msg_iovlen = 0; 1201 } 1202 msghdr->msg_control = cmsg_data; 1203 msghdr->msg_flags = 0; 1204 } 1205 1206 static void 1207 msghdr_init_server(struct msghdr *msghdr, struct iovec *iov, 1208 void *cmsg_data, size_t cmsg_size) 1209 { 1210 msghdr_init_generic(msghdr, iov, cmsg_data); 1211 msghdr->msg_controllen = cmsg_size; 1212 dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ? 1213 msghdr->msg_iov->iov_len : (size_t)0); 1214 dbgmsg("init: msghdr.msg_controllen %u", 1215 (u_int)msghdr->msg_controllen); 1216 } 1217 1218 static void 1219 msghdr_init_client(struct msghdr *msghdr, struct iovec *iov, 1220 void *cmsg_data, size_t cmsg_size, int type, size_t arr_size) 1221 { 1222 struct cmsghdr *cmsghdr; 1223 1224 msghdr_init_generic(msghdr, iov, cmsg_data); 1225 if (cmsg_data != NULL) { 1226 if (send_array_flag) 1227 dbgmsg("sending an array"); 1228 else 1229 dbgmsg("sending a scalar"); 1230 msghdr->msg_controllen = send_array_flag ? 1231 cmsg_size : CMSG_SPACE(0); 1232 cmsghdr = CMSG_FIRSTHDR(msghdr); 1233 cmsghdr->cmsg_level = SOL_SOCKET; 1234 cmsghdr->cmsg_type = type; 1235 cmsghdr->cmsg_len = CMSG_LEN(send_array_flag ? arr_size : 0); 1236 } else 1237 msghdr->msg_controllen = 0; 1238 } 1239 1240 static int 1241 t_generic(int (*client_func)(int), int (*server_func)(int)) 1242 { 1243 int fd, rv, rv_client; 1244 1245 switch (client_fork()) { 1246 case 0: 1247 fd = socket_create(); 1248 if (fd < 0) 1249 rv = -2; 1250 else { 1251 rv = client_func(fd); 1252 if (socket_close(fd) < 0) 1253 rv = -2; 1254 } 1255 client_exit(rv); 1256 break; 1257 case 1: 1258 fd = socket_create(); 1259 if (fd < 0) 1260 rv = -2; 1261 else { 1262 rv = server_func(fd); 1263 rv_client = client_wait(); 1264 if (rv == 0 || (rv == -2 && rv_client != 0)) 1265 rv = rv_client; 1266 if (socket_close(fd) < 0) 1267 rv = -2; 1268 } 1269 break; 1270 default: 1271 rv = -2; 1272 } 1273 return (rv); 1274 } 1275 1276 static int 1277 t_cmsgcred_client(int fd) 1278 { 1279 struct msghdr msghdr; 1280 struct iovec iov[1]; 1281 void *cmsg_data; 1282 size_t cmsg_size; 1283 int rv; 1284 1285 if (sync_recv() < 0) 1286 return (-2); 1287 1288 rv = -2; 1289 1290 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1291 cmsg_data = malloc(cmsg_size); 1292 if (cmsg_data == NULL) { 1293 logmsg("malloc"); 1294 goto done; 1295 } 1296 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1297 SCM_CREDS, sizeof(struct cmsgcred)); 1298 1299 if (socket_connect(fd) < 0) 1300 goto done; 1301 1302 if (message_sendn(fd, &msghdr) < 0) 1303 goto done; 1304 1305 rv = 0; 1306 done: 1307 free(cmsg_data); 1308 return (rv); 1309 } 1310 1311 static int 1312 t_cmsgcred_server(int fd1) 1313 { 1314 struct msghdr msghdr; 1315 struct iovec iov[1]; 1316 struct cmsghdr *cmsghdr; 1317 void *cmsg_data; 1318 size_t cmsg_size; 1319 u_int i; 1320 int fd2, rv; 1321 1322 if (sync_send() < 0) 1323 return (-2); 1324 1325 fd2 = -1; 1326 rv = -2; 1327 1328 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1329 cmsg_data = malloc(cmsg_size); 1330 if (cmsg_data == NULL) { 1331 logmsg("malloc"); 1332 goto done; 1333 } 1334 1335 if (sock_type == SOCK_STREAM) { 1336 fd2 = socket_accept(fd1); 1337 if (fd2 < 0) 1338 goto done; 1339 } else 1340 fd2 = fd1; 1341 1342 rv = -1; 1343 for (i = 1; i <= ipc_msg.msg_num; ++i) { 1344 dbgmsg("message #%u", i); 1345 1346 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1347 if (message_recv(fd2, &msghdr) < 0) { 1348 rv = -2; 1349 break; 1350 } 1351 1352 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1353 break; 1354 1355 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1356 if (check_scm_creds_cmsgcred(cmsghdr) < 0) 1357 break; 1358 } 1359 if (i > ipc_msg.msg_num) 1360 rv = 0; 1361 done: 1362 free(cmsg_data); 1363 if (sock_type == SOCK_STREAM && fd2 >= 0) 1364 if (socket_close(fd2) < 0) 1365 rv = -2; 1366 return (rv); 1367 } 1368 1369 static int 1370 t_cmsgcred(void) 1371 { 1372 return (t_generic(t_cmsgcred_client, t_cmsgcred_server)); 1373 } 1374 1375 static int 1376 t_sockcred_client(int type, int fd) 1377 { 1378 struct msghdr msghdr; 1379 struct iovec iov[1]; 1380 int rv; 1381 1382 if (sync_recv() < 0) 1383 return (-2); 1384 1385 rv = -2; 1386 1387 msghdr_init_client(&msghdr, iov, NULL, 0, 0, 0); 1388 1389 if (socket_connect(fd) < 0) 1390 goto done; 1391 1392 if (type == 2) 1393 if (sync_recv() < 0) 1394 goto done; 1395 1396 if (message_sendn(fd, &msghdr) < 0) 1397 goto done; 1398 1399 rv = 0; 1400 done: 1401 return (rv); 1402 } 1403 1404 static int 1405 t_sockcred_server(int type, int fd1) 1406 { 1407 struct msghdr msghdr; 1408 struct iovec iov[1]; 1409 struct cmsghdr *cmsghdr; 1410 void *cmsg_data; 1411 size_t cmsg_size; 1412 u_int i; 1413 int fd2, rv, val; 1414 1415 fd2 = -1; 1416 rv = -2; 1417 1418 cmsg_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num)); 1419 cmsg_data = malloc(cmsg_size); 1420 if (cmsg_data == NULL) { 1421 logmsg("malloc"); 1422 goto done; 1423 } 1424 1425 if (type == 1) { 1426 dbgmsg("setting LOCAL_CREDS"); 1427 val = 1; 1428 if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { 1429 logmsg("setsockopt(LOCAL_CREDS)"); 1430 goto done; 1431 } 1432 } 1433 1434 if (sync_send() < 0) 1435 goto done; 1436 1437 if (sock_type == SOCK_STREAM) { 1438 fd2 = socket_accept(fd1); 1439 if (fd2 < 0) 1440 goto done; 1441 } else 1442 fd2 = fd1; 1443 1444 if (type == 2) { 1445 dbgmsg("setting LOCAL_CREDS"); 1446 val = 1; 1447 if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { 1448 logmsg("setsockopt(LOCAL_CREDS)"); 1449 goto done; 1450 } 1451 if (sync_send() < 0) 1452 goto done; 1453 } 1454 1455 rv = -1; 1456 for (i = 1; i <= ipc_msg.msg_num; ++i) { 1457 dbgmsg("message #%u", i); 1458 1459 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1460 if (message_recv(fd2, &msghdr) < 0) { 1461 rv = -2; 1462 break; 1463 } 1464 1465 if (i > 1 && sock_type == SOCK_STREAM) { 1466 if (check_msghdr(&msghdr, 0) < 0) 1467 break; 1468 } else { 1469 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1470 break; 1471 1472 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1473 if (check_scm_creds_sockcred(cmsghdr) < 0) 1474 break; 1475 } 1476 } 1477 if (i > ipc_msg.msg_num) 1478 rv = 0; 1479 done: 1480 free(cmsg_data); 1481 if (sock_type == SOCK_STREAM && fd2 >= 0) 1482 if (socket_close(fd2) < 0) 1483 rv = -2; 1484 return (rv); 1485 } 1486 1487 static int 1488 t_sockcred_1(void) 1489 { 1490 u_int i; 1491 int fd, rv, rv_client; 1492 1493 switch (client_fork()) { 1494 case 0: 1495 for (i = 1; i <= 2; ++i) { 1496 dbgmsg("client #%u", i); 1497 fd = socket_create(); 1498 if (fd < 0) 1499 rv = -2; 1500 else { 1501 rv = t_sockcred_client(1, fd); 1502 if (socket_close(fd) < 0) 1503 rv = -2; 1504 } 1505 if (rv != 0) 1506 break; 1507 } 1508 client_exit(rv); 1509 break; 1510 case 1: 1511 fd = socket_create(); 1512 if (fd < 0) 1513 rv = -2; 1514 else { 1515 rv = t_sockcred_server(1, fd); 1516 if (rv == 0) 1517 rv = t_sockcred_server(3, fd); 1518 rv_client = client_wait(); 1519 if (rv == 0 || (rv == -2 && rv_client != 0)) 1520 rv = rv_client; 1521 if (socket_close(fd) < 0) 1522 rv = -2; 1523 } 1524 break; 1525 default: 1526 rv = -2; 1527 } 1528 1529 return (rv); 1530 } 1531 1532 static int 1533 t_sockcred_2_client(int fd) 1534 { 1535 return (t_sockcred_client(2, fd)); 1536 } 1537 1538 static int 1539 t_sockcred_2_server(int fd) 1540 { 1541 return (t_sockcred_server(2, fd)); 1542 } 1543 1544 static int 1545 t_sockcred_2(void) 1546 { 1547 return (t_generic(t_sockcred_2_client, t_sockcred_2_server)); 1548 } 1549 1550 static int 1551 t_cmsgcred_sockcred_server(int fd1) 1552 { 1553 struct msghdr msghdr; 1554 struct iovec iov[1]; 1555 struct cmsghdr *cmsghdr; 1556 void *cmsg_data, *cmsg1_data, *cmsg2_data; 1557 size_t cmsg_size, cmsg1_size, cmsg2_size; 1558 u_int i; 1559 int fd2, rv, val; 1560 1561 fd2 = -1; 1562 rv = -2; 1563 1564 cmsg1_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num)); 1565 cmsg2_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1566 cmsg1_data = malloc(cmsg1_size); 1567 cmsg2_data = malloc(cmsg2_size); 1568 if (cmsg1_data == NULL || cmsg2_data == NULL) { 1569 logmsg("malloc"); 1570 goto done; 1571 } 1572 1573 dbgmsg("setting LOCAL_CREDS"); 1574 val = 1; 1575 if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) { 1576 logmsg("setsockopt(LOCAL_CREDS)"); 1577 goto done; 1578 } 1579 1580 if (sync_send() < 0) 1581 goto done; 1582 1583 if (sock_type == SOCK_STREAM) { 1584 fd2 = socket_accept(fd1); 1585 if (fd2 < 0) 1586 goto done; 1587 } else 1588 fd2 = fd1; 1589 1590 cmsg_data = cmsg1_data; 1591 cmsg_size = cmsg1_size; 1592 rv = -1; 1593 for (i = 1; i <= ipc_msg.msg_num; ++i) { 1594 dbgmsg("message #%u", i); 1595 1596 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1597 if (message_recv(fd2, &msghdr) < 0) { 1598 rv = -2; 1599 break; 1600 } 1601 1602 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1603 break; 1604 1605 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1606 if (i == 1 || sock_type == SOCK_DGRAM) { 1607 if (check_scm_creds_sockcred(cmsghdr) < 0) 1608 break; 1609 } else { 1610 if (check_scm_creds_cmsgcred(cmsghdr) < 0) 1611 break; 1612 } 1613 1614 cmsg_data = cmsg2_data; 1615 cmsg_size = cmsg2_size; 1616 } 1617 if (i > ipc_msg.msg_num) 1618 rv = 0; 1619 done: 1620 free(cmsg1_data); 1621 free(cmsg2_data); 1622 if (sock_type == SOCK_STREAM && fd2 >= 0) 1623 if (socket_close(fd2) < 0) 1624 rv = -2; 1625 return (rv); 1626 } 1627 1628 static int 1629 t_cmsgcred_sockcred(void) 1630 { 1631 return (t_generic(t_cmsgcred_client, t_cmsgcred_sockcred_server)); 1632 } 1633 1634 static int 1635 t_timeval_client(int fd) 1636 { 1637 struct msghdr msghdr; 1638 struct iovec iov[1]; 1639 void *cmsg_data; 1640 size_t cmsg_size; 1641 int rv; 1642 1643 if (sync_recv() < 0) 1644 return (-2); 1645 1646 rv = -2; 1647 1648 cmsg_size = CMSG_SPACE(sizeof(struct timeval)); 1649 cmsg_data = malloc(cmsg_size); 1650 if (cmsg_data == NULL) { 1651 logmsg("malloc"); 1652 goto done; 1653 } 1654 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1655 SCM_TIMESTAMP, sizeof(struct timeval)); 1656 1657 if (socket_connect(fd) < 0) 1658 goto done; 1659 1660 if (message_sendn(fd, &msghdr) < 0) 1661 goto done; 1662 1663 rv = 0; 1664 done: 1665 free(cmsg_data); 1666 return (rv); 1667 } 1668 1669 static int 1670 t_timeval_server(int fd1) 1671 { 1672 struct msghdr msghdr; 1673 struct iovec iov[1]; 1674 struct cmsghdr *cmsghdr; 1675 void *cmsg_data; 1676 size_t cmsg_size; 1677 u_int i; 1678 int fd2, rv; 1679 1680 if (sync_send() < 0) 1681 return (-2); 1682 1683 fd2 = -1; 1684 rv = -2; 1685 1686 cmsg_size = CMSG_SPACE(sizeof(struct timeval)); 1687 cmsg_data = malloc(cmsg_size); 1688 if (cmsg_data == NULL) { 1689 logmsg("malloc"); 1690 goto done; 1691 } 1692 1693 if (sock_type == SOCK_STREAM) { 1694 fd2 = socket_accept(fd1); 1695 if (fd2 < 0) 1696 goto done; 1697 } else 1698 fd2 = fd1; 1699 1700 rv = -1; 1701 for (i = 1; i <= ipc_msg.msg_num; ++i) { 1702 dbgmsg("message #%u", i); 1703 1704 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1705 if (message_recv(fd2, &msghdr) < 0) { 1706 rv = -2; 1707 break; 1708 } 1709 1710 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1711 break; 1712 1713 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1714 if (check_scm_timestamp(cmsghdr) < 0) 1715 break; 1716 } 1717 if (i > ipc_msg.msg_num) 1718 rv = 0; 1719 done: 1720 free(cmsg_data); 1721 if (sock_type == SOCK_STREAM && fd2 >= 0) 1722 if (socket_close(fd2) < 0) 1723 rv = -2; 1724 return (rv); 1725 } 1726 1727 static int 1728 t_timeval(void) 1729 { 1730 return (t_generic(t_timeval_client, t_timeval_server)); 1731 } 1732 1733 static int 1734 t_bintime_client(int fd) 1735 { 1736 struct msghdr msghdr; 1737 struct iovec iov[1]; 1738 void *cmsg_data; 1739 size_t cmsg_size; 1740 int rv; 1741 1742 if (sync_recv() < 0) 1743 return (-2); 1744 1745 rv = -2; 1746 1747 cmsg_size = CMSG_SPACE(sizeof(struct bintime)); 1748 cmsg_data = malloc(cmsg_size); 1749 if (cmsg_data == NULL) { 1750 logmsg("malloc"); 1751 goto done; 1752 } 1753 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1754 SCM_BINTIME, sizeof(struct bintime)); 1755 1756 if (socket_connect(fd) < 0) 1757 goto done; 1758 1759 if (message_sendn(fd, &msghdr) < 0) 1760 goto done; 1761 1762 rv = 0; 1763 done: 1764 free(cmsg_data); 1765 return (rv); 1766 } 1767 1768 static int 1769 t_bintime_server(int fd1) 1770 { 1771 struct msghdr msghdr; 1772 struct iovec iov[1]; 1773 struct cmsghdr *cmsghdr; 1774 void *cmsg_data; 1775 size_t cmsg_size; 1776 u_int i; 1777 int fd2, rv; 1778 1779 if (sync_send() < 0) 1780 return (-2); 1781 1782 fd2 = -1; 1783 rv = -2; 1784 1785 cmsg_size = CMSG_SPACE(sizeof(struct bintime)); 1786 cmsg_data = malloc(cmsg_size); 1787 if (cmsg_data == NULL) { 1788 logmsg("malloc"); 1789 goto done; 1790 } 1791 1792 if (sock_type == SOCK_STREAM) { 1793 fd2 = socket_accept(fd1); 1794 if (fd2 < 0) 1795 goto done; 1796 } else 1797 fd2 = fd1; 1798 1799 rv = -1; 1800 for (i = 1; i <= ipc_msg.msg_num; ++i) { 1801 dbgmsg("message #%u", i); 1802 1803 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size); 1804 if (message_recv(fd2, &msghdr) < 0) { 1805 rv = -2; 1806 break; 1807 } 1808 1809 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0) 1810 break; 1811 1812 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1813 if (check_scm_bintime(cmsghdr) < 0) 1814 break; 1815 } 1816 if (i > ipc_msg.msg_num) 1817 rv = 0; 1818 done: 1819 free(cmsg_data); 1820 if (sock_type == SOCK_STREAM && fd2 >= 0) 1821 if (socket_close(fd2) < 0) 1822 rv = -2; 1823 return (rv); 1824 } 1825 1826 static int 1827 t_bintime(void) 1828 { 1829 return (t_generic(t_bintime_client, t_bintime_server)); 1830 } 1831 1832 static int 1833 t_cmsg_len_client(int fd) 1834 { 1835 struct msghdr msghdr; 1836 struct iovec iov[1]; 1837 struct cmsghdr *cmsghdr; 1838 void *cmsg_data; 1839 size_t size, cmsg_size; 1840 socklen_t socklen; 1841 int rv; 1842 1843 if (sync_recv() < 0) 1844 return (-2); 1845 1846 rv = -2; 1847 1848 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred)); 1849 cmsg_data = malloc(cmsg_size); 1850 if (cmsg_data == NULL) { 1851 logmsg("malloc"); 1852 goto done; 1853 } 1854 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size, 1855 SCM_CREDS, sizeof(struct cmsgcred)); 1856 cmsghdr = CMSG_FIRSTHDR(&msghdr); 1857 1858 if (socket_connect(fd) < 0) 1859 goto done; 1860 1861 size = msghdr.msg_iov != NULL ? msghdr.msg_iov->iov_len : 0; 1862 rv = -1; 1863 for (socklen = 0; socklen < CMSG_LEN(0); ++socklen) { 1864 cmsghdr->cmsg_len = socklen; 1865 dbgmsg("send: data size %zu", size); 1866 dbgmsg("send: msghdr.msg_controllen %u", 1867 (u_int)msghdr.msg_controllen); 1868 dbgmsg("send: cmsghdr.cmsg_len %u", 1869 (u_int)cmsghdr->cmsg_len); 1870 if (sendmsg(fd, &msghdr, 0) < 0) { 1871 dbgmsg("sendmsg(2) failed: %s; retrying", 1872 strerror(errno)); 1873 continue; 1874 } 1875 logmsgx("sent message with cmsghdr.cmsg_len %u < %u", 1876 (u_int)cmsghdr->cmsg_len, (u_int)CMSG_LEN(0)); 1877 break; 1878 } 1879 if (socklen == CMSG_LEN(0)) 1880 rv = 0; 1881 1882 if (sync_send() < 0) { 1883 rv = -2; 1884 goto done; 1885 } 1886 done: 1887 free(cmsg_data); 1888 return (rv); 1889 } 1890 1891 static int 1892 t_cmsg_len_server(int fd1) 1893 { 1894 int fd2, rv; 1895 1896 if (sync_send() < 0) 1897 return (-2); 1898 1899 rv = -2; 1900 1901 if (sock_type == SOCK_STREAM) { 1902 fd2 = socket_accept(fd1); 1903 if (fd2 < 0) 1904 goto done; 1905 } else 1906 fd2 = fd1; 1907 1908 if (sync_recv() < 0) 1909 goto done; 1910 1911 rv = 0; 1912 done: 1913 if (sock_type == SOCK_STREAM && fd2 >= 0) 1914 if (socket_close(fd2) < 0) 1915 rv = -2; 1916 return (rv); 1917 } 1918 1919 static int 1920 t_cmsg_len(void) 1921 { 1922 return (t_generic(t_cmsg_len_client, t_cmsg_len_server)); 1923 } 1924 1925 static int 1926 t_peercred_client(int fd) 1927 { 1928 struct xucred xucred; 1929 socklen_t len; 1930 1931 if (sync_recv() < 0) 1932 return (-1); 1933 1934 if (socket_connect(fd) < 0) 1935 return (-1); 1936 1937 len = sizeof(xucred); 1938 if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { 1939 logmsg("getsockopt(LOCAL_PEERCRED)"); 1940 return (-1); 1941 } 1942 1943 if (check_xucred(&xucred, len) < 0) 1944 return (-1); 1945 1946 return (0); 1947 } 1948 1949 static int 1950 t_peercred_server(int fd1) 1951 { 1952 struct xucred xucred; 1953 socklen_t len; 1954 int fd2, rv; 1955 1956 if (sync_send() < 0) 1957 return (-2); 1958 1959 fd2 = socket_accept(fd1); 1960 if (fd2 < 0) 1961 return (-2); 1962 1963 len = sizeof(xucred); 1964 if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xucred, &len) < 0) { 1965 logmsg("getsockopt(LOCAL_PEERCRED)"); 1966 rv = -2; 1967 goto done; 1968 } 1969 1970 if (check_xucred(&xucred, len) < 0) { 1971 rv = -1; 1972 goto done; 1973 } 1974 1975 rv = 0; 1976 done: 1977 if (socket_close(fd2) < 0) 1978 rv = -2; 1979 return (rv); 1980 } 1981 1982 static int 1983 t_peercred(void) 1984 { 1985 return (t_generic(t_peercred_client, t_peercred_server)); 1986 } 1987