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