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/types.h> 31 #include <sys/resource.h> 32 #include <sys/time.h> 33 #include <sys/socket.h> 34 #include <sys/un.h> 35 #include <sys/wait.h> 36 37 #include <assert.h> 38 #include <ctype.h> 39 #include <err.h> 40 #include <errno.h> 41 #include <inttypes.h> 42 #include <limits.h> 43 #include <setjmp.h> 44 #include <signal.h> 45 #include <stdarg.h> 46 #include <stdint.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <sysexits.h> 51 #include <unistd.h> 52 53 /* 54 * There are tables with tests descriptions and pointers to test 55 * functions. Each t_*() function returns 0 if its test passed, 56 * -1 if its test failed (something wrong was found in local domain 57 * control messages), -2 if some system error occurred. If test 58 * function returns -2, then a program exits. 59 * 60 * Each test function completely control what to do (eg. fork or 61 * do not fork a client process). If a test function forks a client 62 * process, then it waits for its termination. If a return code of a 63 * client process is not equal to zero, or if a client process was 64 * terminated by a signal, then test function returns -2. 65 * 66 * Each test function and complete program are not optimized 67 * a lot to allow easy to modify tests. 68 * 69 * Each function which can block, is run under TIMEOUT, if timeout 70 * occurs, then test function returns -2 or a client process exits 71 * with nonzero return code. 72 */ 73 74 #ifndef LISTENQ 75 # define LISTENQ 1 76 #endif 77 78 #ifndef TIMEOUT 79 # define TIMEOUT 60 80 #endif 81 82 #define EXTRA_CMSG_SPACE 512 /* Memory for not expected control data. */ 83 84 static int t_cmsgcred(void), t_sockcred_stream1(void); 85 static int t_sockcred_stream2(void), t_cmsgcred_sockcred(void); 86 static int t_sockcred_dgram(void), t_timestamp(void); 87 88 struct test_func { 89 int (*func)(void); /* Pointer to function. */ 90 const char *desc; /* Test description. */ 91 }; 92 93 static struct test_func test_stream_tbl[] = { 94 { NULL, " 0: All tests" }, 95 { t_cmsgcred, " 1: Sending, receiving cmsgcred" }, 96 { t_sockcred_stream1, " 2: Receiving sockcred (listening socket has LOCAL_CREDS)" }, 97 { t_sockcred_stream2, " 3: Receiving sockcred (accepted socket has LOCAL_CREDS)" }, 98 { t_cmsgcred_sockcred, " 4: Sending cmsgcred, receiving sockcred" }, 99 { t_timestamp, " 5: Sending, receiving timestamp" }, 100 { NULL, NULL } 101 }; 102 103 static struct test_func test_dgram_tbl[] = { 104 { NULL, " 0: All tests" }, 105 { t_cmsgcred, " 1: Sending, receiving cmsgcred" }, 106 { t_sockcred_dgram, " 2: Receiving sockcred" }, 107 { t_cmsgcred_sockcred, " 3: Sending cmsgcred, receiving sockcred" }, 108 { t_timestamp, " 4: Sending, receiving timestamp" }, 109 { NULL, NULL } 110 }; 111 112 #define TEST_STREAM_NO_MAX (sizeof(test_stream_tbl) / sizeof(struct test_func) - 2) 113 #define TEST_DGRAM_NO_MAX (sizeof(test_dgram_tbl) / sizeof(struct test_func) - 2) 114 115 static const char *myname = "SERVER"; /* "SERVER" or "CLIENT" */ 116 117 static int debug = 0; /* 1, if -d. */ 118 static int no_control_data = 0; /* 1, if -z. */ 119 120 static u_int nfailed = 0; /* Number of failed tests. */ 121 122 static int sock_type; /* SOCK_STREAM or SOCK_DGRAM */ 123 static const char *sock_type_str; /* "SOCK_STREAM" or "SOCK_DGRAN" */ 124 125 static char tempdir[] = "/tmp/unix_cmsg.XXXXXXX"; 126 static char serv_sock_path[PATH_MAX]; 127 128 static char ipc_message[] = "hello"; 129 130 #define IPC_MESSAGE_SIZE (sizeof(ipc_message)) 131 132 static struct sockaddr_un servaddr; /* Server address. */ 133 134 static sigjmp_buf env_alrm; 135 136 static uid_t my_uid; 137 static uid_t my_euid; 138 static gid_t my_gid; 139 static gid_t my_egid; 140 141 /* 142 * my_gids[0] is EGID, next items are supplementary GIDs, 143 * my_ngids determines valid items in my_gids array. 144 */ 145 static gid_t my_gids[NGROUPS_MAX]; 146 static int my_ngids; 147 148 static pid_t client_pid; /* PID of forked client. */ 149 150 #define dbgmsg(x) do { \ 151 if (debug) \ 152 logmsgx x ; \ 153 } while (/* CONSTCOND */0) 154 155 static void logmsg(const char *, ...) __printflike(1, 2); 156 static void logmsgx(const char *, ...) __printflike(1, 2); 157 static void output(const char *, ...) __printflike(1, 2); 158 159 extern char *__progname; /* The name of program. */ 160 161 /* 162 * Output the help message (-h switch). 163 */ 164 static void 165 usage(void) 166 { 167 const struct test_func *test_func; 168 169 fprintf(stderr, "Usage: %s [-dhz] [-t <socktype>] [testno]\n\n", __progname); 170 fprintf(stderr, " Options are:\n\ 171 -d\t\t\tOutput debugging information\n\ 172 -h\t\t\tOutput this help message and exit\n\ 173 -t <socktype>\t\tRun test only for the given socket type:\n\ 174 \t\t\tstream or dgram\n\ 175 -z\t\t\tDo not send real control data if possible\n\n"); 176 fprintf(stderr, " Available tests for stream sockets:\n"); 177 for (test_func = test_stream_tbl; test_func->desc != NULL; ++test_func) 178 fprintf(stderr, " %s\n", test_func->desc); 179 fprintf(stderr, "\n Available tests for datagram sockets:\n"); 180 for (test_func = test_dgram_tbl; test_func->desc != NULL; ++test_func) 181 fprintf(stderr, " %s\n", test_func->desc); 182 } 183 184 /* 185 * printf-like function for outputting to STDOUT_FILENO. 186 */ 187 static void 188 output(const char *format, ...) 189 { 190 char buf[128]; 191 va_list ap; 192 193 va_start(ap, format); 194 if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 195 err(EX_SOFTWARE, "output: vsnprintf failed"); 196 write(STDOUT_FILENO, buf, strlen(buf)); 197 va_end(ap); 198 } 199 200 /* 201 * printf-like function for logging, also outputs message for errno. 202 */ 203 static void 204 logmsg(const char *format, ...) 205 { 206 char buf[128]; 207 va_list ap; 208 int errno_save; 209 210 errno_save = errno; /* Save errno. */ 211 212 va_start(ap, format); 213 if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 214 err(EX_SOFTWARE, "logmsg: vsnprintf failed"); 215 if (errno_save == 0) 216 output("%s: %s\n", myname, buf); 217 else 218 output("%s: %s: %s\n", myname, buf, strerror(errno_save)); 219 va_end(ap); 220 221 errno = errno_save; /* Restore errno. */ 222 } 223 224 /* 225 * printf-like function for logging, do not output message for errno. 226 */ 227 static void 228 logmsgx(const char *format, ...) 229 { 230 char buf[128]; 231 va_list ap; 232 233 va_start(ap, format); 234 if (vsnprintf(buf, sizeof(buf), format, ap) < 0) 235 err(EX_SOFTWARE, "logmsgx: vsnprintf failed"); 236 output("%s: %s\n", myname, buf); 237 va_end(ap); 238 } 239 240 /* 241 * Run tests from testno1 to testno2. 242 */ 243 static int 244 run_tests(u_int testno1, u_int testno2) 245 { 246 const struct test_func *test_func; 247 u_int i, nfailed1; 248 249 output("Running tests for %s sockets:\n", sock_type_str); 250 test_func = (sock_type == SOCK_STREAM ? 251 test_stream_tbl : test_dgram_tbl) + testno1; 252 253 nfailed1 = 0; 254 for (i = testno1; i <= testno2; ++test_func, ++i) { 255 output(" %s\n", test_func->desc); 256 switch (test_func->func()) { 257 case -1: 258 ++nfailed1; 259 break; 260 case -2: 261 logmsgx("some system error occurred, exiting"); 262 return (-1); 263 } 264 } 265 266 nfailed += nfailed1; 267 268 if (testno1 != testno2) { 269 if (nfailed1 == 0) 270 output("-- all tests were passed!\n"); 271 else 272 output("-- %u test%s failed!\n", nfailed1, 273 nfailed1 == 1 ? "" : "s"); 274 } else { 275 if (nfailed == 0) 276 output("-- test was passed!\n"); 277 else 278 output("-- test failed!\n"); 279 } 280 281 return (0); 282 } 283 284 /* ARGSUSED */ 285 static void 286 sig_alrm(int signo __unused) 287 { 288 siglongjmp(env_alrm, 1); 289 } 290 291 /* 292 * Initialize signals handlers. 293 */ 294 static void 295 sig_init(void) 296 { 297 struct sigaction sa; 298 299 sa.sa_handler = SIG_IGN; 300 sigemptyset(&sa.sa_mask); 301 sa.sa_flags = 0; 302 if (sigaction(SIGPIPE, &sa, (struct sigaction *)NULL) < 0) 303 err(EX_OSERR, "sigaction(SIGPIPE)"); 304 305 sa.sa_handler = sig_alrm; 306 if (sigaction(SIGALRM, &sa, (struct sigaction *)NULL) < 0) 307 err(EX_OSERR, "sigaction(SIGALRM)"); 308 } 309 310 int 311 main(int argc, char *argv[]) 312 { 313 const char *errstr; 314 int opt, dgramflag, streamflag; 315 u_int testno1, testno2; 316 317 opterr = 0; 318 dgramflag = streamflag = 0; 319 while ((opt = getopt(argc, argv, ":dht:z")) != -1) 320 switch (opt) { 321 case 'd': 322 debug = 1; 323 break; 324 case 'h': 325 usage(); 326 return (EX_OK); 327 case 't': 328 if (strcmp(optarg, "stream") == 0) 329 streamflag = 1; 330 else if (strcmp(optarg, "dgram") == 0) 331 dgramflag = 1; 332 else 333 errx(EX_USAGE, "wrong socket type in -t option"); 334 break; 335 case 'z': 336 no_control_data = 1; 337 break; 338 case ':': 339 errx(EX_USAGE, "option -%c requires an argument", optopt); 340 /* NOTREACHED */ 341 case '?': 342 errx(EX_USAGE, "invalid switch -%c", optopt); 343 /* NOTREACHED */ 344 default: 345 errx(EX_SOFTWARE, "unexpected option -%c", optopt); 346 } 347 348 if (optind < argc) { 349 if (optind + 1 != argc) 350 errx(EX_USAGE, "too many arguments"); 351 testno1 = strtonum(argv[optind], 0, UINT_MAX, &errstr); 352 if (errstr != NULL) 353 errx(EX_USAGE, "wrong test number"); 354 } else 355 testno1 = 0; 356 357 if (dgramflag == 0 && streamflag == 0) 358 dgramflag = streamflag = 1; 359 360 if (dgramflag && streamflag && testno1 != 0) 361 errx(EX_USAGE, "you can use particular test, only with datagram or stream sockets"); 362 363 if (streamflag) { 364 if (testno1 > TEST_STREAM_NO_MAX) 365 errx(EX_USAGE, "given test %u for stream sockets does not exist", 366 testno1); 367 } else { 368 if (testno1 > TEST_DGRAM_NO_MAX) 369 errx(EX_USAGE, "given test %u for datagram sockets does not exist", 370 testno1); 371 } 372 373 my_uid = getuid(); 374 my_euid = geteuid(); 375 my_gid = getgid(); 376 my_egid = getegid(); 377 switch (my_ngids = getgroups(sizeof(my_gids) / sizeof(my_gids[0]), my_gids)) { 378 case -1: 379 err(EX_SOFTWARE, "getgroups"); 380 /* NOTREACHED */ 381 case 0: 382 errx(EX_OSERR, "getgroups returned 0 groups"); 383 } 384 385 sig_init(); 386 387 if (mkdtemp(tempdir) == NULL) 388 err(EX_OSERR, "mkdtemp"); 389 390 if (streamflag) { 391 sock_type = SOCK_STREAM; 392 sock_type_str = "SOCK_STREAM"; 393 if (testno1 == 0) { 394 testno1 = 1; 395 testno2 = TEST_STREAM_NO_MAX; 396 } else 397 testno2 = testno1; 398 if (run_tests(testno1, testno2) < 0) 399 goto failed; 400 testno1 = 0; 401 } 402 403 if (dgramflag) { 404 sock_type = SOCK_DGRAM; 405 sock_type_str = "SOCK_DGRAM"; 406 if (testno1 == 0) { 407 testno1 = 1; 408 testno2 = TEST_DGRAM_NO_MAX; 409 } else 410 testno2 = testno1; 411 if (run_tests(testno1, testno2) < 0) 412 goto failed; 413 } 414 415 if (rmdir(tempdir) < 0) { 416 logmsg("rmdir(%s)", tempdir); 417 return (EX_OSERR); 418 } 419 420 return (nfailed ? EX_OSERR : EX_OK); 421 422 failed: 423 if (rmdir(tempdir) < 0) 424 logmsg("rmdir(%s)", tempdir); 425 return (EX_OSERR); 426 } 427 428 /* 429 * Create PF_LOCAL socket, if sock_path is not equal to NULL, then 430 * bind() it. Return socket address in addr. Return file descriptor 431 * or -1 if some error occurred. 432 */ 433 static int 434 create_socket(char *sock_path, size_t sock_path_len, struct sockaddr_un *addr) 435 { 436 int rv, fd; 437 438 if ((fd = socket(PF_LOCAL, sock_type, 0)) < 0) { 439 logmsg("create_socket: socket(PF_LOCAL, %s, 0)", sock_type_str); 440 return (-1); 441 } 442 443 if (sock_path != NULL) { 444 if ((rv = snprintf(sock_path, sock_path_len, "%s/%s", 445 tempdir, myname)) < 0) { 446 logmsg("create_socket: snprintf failed"); 447 goto failed; 448 } 449 if ((size_t)rv >= sock_path_len) { 450 logmsgx("create_socket: too long path name for given buffer"); 451 goto failed; 452 } 453 454 memset(addr, 0, sizeof(addr)); 455 addr->sun_family = AF_LOCAL; 456 if (strlen(sock_path) >= sizeof(addr->sun_path)) { 457 logmsgx("create_socket: too long path name (>= %lu) for local domain socket", 458 (u_long)sizeof(addr->sun_path)); 459 goto failed; 460 } 461 strcpy(addr->sun_path, sock_path); 462 463 if (bind(fd, (struct sockaddr *)addr, SUN_LEN(addr)) < 0) { 464 logmsg("create_socket: bind(%s)", sock_path); 465 goto failed; 466 } 467 } 468 469 return (fd); 470 471 failed: 472 if (close(fd) < 0) 473 logmsg("create_socket: close"); 474 return (-1); 475 } 476 477 /* 478 * Call create_socket() for server listening socket. 479 * Return socket descriptor or -1 if some error occurred. 480 */ 481 static int 482 create_server_socket(void) 483 { 484 return (create_socket(serv_sock_path, sizeof(serv_sock_path), &servaddr)); 485 } 486 487 /* 488 * Create unbound socket. 489 */ 490 static int 491 create_unbound_socket(void) 492 { 493 return (create_socket((char *)NULL, 0, (struct sockaddr_un *)NULL)); 494 } 495 496 /* 497 * Close socket descriptor, if sock_path is not equal to NULL, 498 * then unlink the given path. 499 */ 500 static int 501 close_socket(const char *sock_path, int fd) 502 { 503 int error = 0; 504 505 if (close(fd) < 0) { 506 logmsg("close_socket: close"); 507 error = -1; 508 } 509 if (sock_path != NULL) 510 if (unlink(sock_path) < 0) { 511 logmsg("close_socket: unlink(%s)", sock_path); 512 error = -1; 513 } 514 return (error); 515 } 516 517 /* 518 * Connect to server (socket address in servaddr). 519 */ 520 static int 521 connect_server(int fd) 522 { 523 dbgmsg(("connecting to %s", serv_sock_path)); 524 525 /* 526 * If PF_LOCAL listening socket's queue is full, then connect() 527 * returns ECONNREFUSED immediately, do not need timeout. 528 */ 529 if (connect(fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { 530 logmsg("connect_server: connect(%s)", serv_sock_path); 531 return (-1); 532 } 533 534 return (0); 535 } 536 537 /* 538 * sendmsg() with timeout. 539 */ 540 static int 541 sendmsg_timeout(int fd, struct msghdr *msg, size_t n) 542 { 543 ssize_t nsent; 544 545 dbgmsg(("sending %lu bytes", (u_long)n)); 546 547 if (sigsetjmp(env_alrm, 1) != 0) { 548 logmsgx("sendmsg_timeout: cannot send message to %s (timeout)", serv_sock_path); 549 return (-1); 550 } 551 552 (void)alarm(TIMEOUT); 553 554 nsent = sendmsg(fd, msg, 0); 555 556 (void)alarm(0); 557 558 if (nsent < 0) { 559 logmsg("sendmsg_timeout: sendmsg"); 560 return (-1); 561 } 562 563 if ((size_t)nsent != n) { 564 logmsgx("sendmsg_timeout: sendmsg: short send: %ld of %lu bytes", 565 (long)nsent, (u_long)n); 566 return (-1); 567 } 568 569 return (0); 570 } 571 572 /* 573 * accept() with timeout. 574 */ 575 static int 576 accept_timeout(int listenfd) 577 { 578 int fd; 579 580 dbgmsg(("accepting connection")); 581 582 if (sigsetjmp(env_alrm, 1) != 0) { 583 logmsgx("accept_timeout: cannot accept connection (timeout)"); 584 return (-1); 585 } 586 587 (void)alarm(TIMEOUT); 588 589 fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL); 590 591 (void)alarm(0); 592 593 if (fd < 0) { 594 logmsg("accept_timeout: accept"); 595 return (-1); 596 } 597 598 return (fd); 599 } 600 601 /* 602 * recvmsg() with timeout. 603 */ 604 static int 605 recvmsg_timeout(int fd, struct msghdr *msg, size_t n) 606 { 607 ssize_t nread; 608 609 dbgmsg(("receiving %lu bytes", (u_long)n)); 610 611 if (sigsetjmp(env_alrm, 1) != 0) { 612 logmsgx("recvmsg_timeout: cannot receive message (timeout)"); 613 return (-1); 614 } 615 616 (void)alarm(TIMEOUT); 617 618 nread = recvmsg(fd, msg, MSG_WAITALL); 619 620 (void)alarm(0); 621 622 if (nread < 0) { 623 logmsg("recvmsg_timeout: recvmsg"); 624 return (-1); 625 } 626 627 if ((size_t)nread != n) { 628 logmsgx("recvmsg_timeout: recvmsg: short read: %ld of %lu bytes", 629 (long)nread, (u_long)n); 630 return (-1); 631 } 632 633 return (0); 634 } 635 636 /* 637 * Wait for synchronization message (1 byte) with timeout. 638 */ 639 static int 640 sync_recv(int fd) 641 { 642 ssize_t nread; 643 char buf; 644 645 dbgmsg(("waiting for sync message")); 646 647 if (sigsetjmp(env_alrm, 1) != 0) { 648 logmsgx("sync_recv: cannot receive sync message (timeout)"); 649 return (-1); 650 } 651 652 (void)alarm(TIMEOUT); 653 654 nread = read(fd, &buf, 1); 655 656 (void)alarm(0); 657 658 if (nread < 0) { 659 logmsg("sync_recv: read"); 660 return (-1); 661 } 662 663 if (nread != 1) { 664 logmsgx("sync_recv: read: short read: %ld of 1 byte", 665 (long)nread); 666 return (-1); 667 } 668 669 return (0); 670 } 671 672 /* 673 * Send synchronization message (1 byte) with timeout. 674 */ 675 static int 676 sync_send(int fd) 677 { 678 ssize_t nsent; 679 680 dbgmsg(("sending sync message")); 681 682 if (sigsetjmp(env_alrm, 1) != 0) { 683 logmsgx("sync_send: cannot send sync message (timeout)"); 684 return (-1); 685 } 686 687 (void)alarm(TIMEOUT); 688 689 nsent = write(fd, "", 1); 690 691 (void)alarm(0); 692 693 if (nsent < 0) { 694 logmsg("sync_send: write"); 695 return (-1); 696 } 697 698 if (nsent != 1) { 699 logmsgx("sync_send: write: short write: %ld of 1 byte", 700 (long)nsent); 701 return (-1); 702 } 703 704 return (0); 705 } 706 707 /* 708 * waitpid() for client with timeout. 709 */ 710 static int 711 wait_client(void) 712 { 713 int status; 714 pid_t pid; 715 716 if (sigsetjmp(env_alrm, 1) != 0) { 717 logmsgx("wait_client: cannot get exit status of client PID %ld (timeout)", 718 (long)client_pid); 719 return (-1); 720 } 721 722 (void)alarm(TIMEOUT); 723 724 pid = waitpid(client_pid, &status, 0); 725 726 (void)alarm(0); 727 728 if (pid == (pid_t)-1) { 729 logmsg("wait_client: waitpid"); 730 return (-1); 731 } 732 733 if (WIFEXITED(status)) { 734 if (WEXITSTATUS(status) != 0) { 735 logmsgx("wait_client: exit status of client PID %ld is %d", 736 (long)client_pid, WEXITSTATUS(status)); 737 return (-1); 738 } 739 } else { 740 if (WIFSIGNALED(status)) 741 logmsgx("wait_client: abnormal termination of client PID %ld, signal %d%s", 742 (long)client_pid, WTERMSIG(status), WCOREDUMP(status) ? " (core file generated)" : ""); 743 else 744 logmsgx("wait_client: termination of client PID %ld, unknown status", 745 (long)client_pid); 746 return (-1); 747 } 748 749 return (0); 750 } 751 752 /* 753 * Check if n supplementary GIDs in gids are correct. (my_gids + 1) 754 * has (my_ngids - 1) supplementary GIDs of current process. 755 */ 756 static int 757 check_groups(const gid_t *gids, int n) 758 { 759 char match[NGROUPS_MAX] = { 0 }; 760 int error, i, j; 761 762 if (n != my_ngids - 1) { 763 logmsgx("wrong number of groups %d != %d (returned from getgroups() - 1)", 764 n, my_ngids - 1); 765 error = -1; 766 } else 767 error = 0; 768 for (i = 0; i < n; ++i) { 769 for (j = 1; j < my_ngids; ++j) { 770 if (gids[i] == my_gids[j]) { 771 if (match[j]) { 772 logmsgx("duplicated GID %lu", 773 (u_long)gids[i]); 774 error = -1; 775 } else 776 match[j] = 1; 777 break; 778 } 779 } 780 if (j == my_ngids) { 781 logmsgx("unexpected GID %lu", (u_long)gids[i]); 782 error = -1; 783 } 784 } 785 for (j = 1; j < my_ngids; ++j) 786 if (match[j] == 0) { 787 logmsgx("did not receive supplementary GID %u", my_gids[j]); 788 error = -1; 789 } 790 return (error); 791 } 792 793 /* 794 * Send n messages with data and control message with SCM_CREDS type 795 * to server and exit. 796 */ 797 static void 798 t_cmsgcred_client(u_int n) 799 { 800 union { 801 struct cmsghdr cm; 802 char control[CMSG_SPACE(sizeof(struct cmsgcred))]; 803 } control_un; 804 struct msghdr msg; 805 struct iovec iov[1]; 806 struct cmsghdr *cmptr; 807 int fd; 808 u_int i; 809 810 assert(n == 1 || n == 2); 811 812 if ((fd = create_unbound_socket()) < 0) 813 goto failed; 814 815 if (connect_server(fd) < 0) 816 goto failed_close; 817 818 iov[0].iov_base = ipc_message; 819 iov[0].iov_len = IPC_MESSAGE_SIZE; 820 821 msg.msg_name = NULL; 822 msg.msg_namelen = 0; 823 msg.msg_iov = iov; 824 msg.msg_iovlen = 1; 825 msg.msg_control = control_un.control; 826 msg.msg_controllen = no_control_data ? 827 sizeof(struct cmsghdr) : sizeof(control_un.control); 828 msg.msg_flags = 0; 829 830 cmptr = CMSG_FIRSTHDR(&msg); 831 cmptr->cmsg_len = CMSG_LEN(no_control_data ? 832 0 : sizeof(struct cmsgcred)); 833 cmptr->cmsg_level = SOL_SOCKET; 834 cmptr->cmsg_type = SCM_CREDS; 835 836 for (i = 0; i < n; ++i) { 837 dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i, 838 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len)); 839 if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0) 840 goto failed_close; 841 } 842 843 if (close_socket((const char *)NULL, fd) < 0) 844 goto failed; 845 846 _exit(0); 847 848 failed_close: 849 (void)close_socket((const char *)NULL, fd); 850 851 failed: 852 _exit(1); 853 } 854 855 /* 856 * Receive two messages with data and control message with SCM_CREDS 857 * type followed by struct cmsgcred{} from client. fd1 is a listen 858 * socket for stream sockets or simply socket for datagram sockets. 859 */ 860 static int 861 t_cmsgcred_server(int fd1) 862 { 863 char buf[IPC_MESSAGE_SIZE]; 864 union { 865 struct cmsghdr cm; 866 char control[CMSG_SPACE(sizeof(struct cmsgcred)) + EXTRA_CMSG_SPACE]; 867 } control_un; 868 struct msghdr msg; 869 struct iovec iov[1]; 870 struct cmsghdr *cmptr; 871 const struct cmsgcred *cmcredptr; 872 socklen_t controllen; 873 int error, error2, fd2; 874 u_int i; 875 876 if (sock_type == SOCK_STREAM) { 877 if ((fd2 = accept_timeout(fd1)) < 0) 878 return (-2); 879 } else 880 fd2 = fd1; 881 882 error = 0; 883 884 controllen = sizeof(control_un.control); 885 886 for (i = 0; i < 2; ++i) { 887 iov[0].iov_base = buf; 888 iov[0].iov_len = sizeof(buf); 889 890 msg.msg_name = NULL; 891 msg.msg_namelen = 0; 892 msg.msg_iov = iov; 893 msg.msg_iovlen = 1; 894 msg.msg_control = control_un.control; 895 msg.msg_controllen = controllen; 896 msg.msg_flags = 0; 897 898 controllen = CMSG_SPACE(sizeof(struct cmsgcred)); 899 900 if (recvmsg_timeout(fd2, &msg, sizeof(buf)) < 0) 901 goto failed; 902 903 if (msg.msg_flags & MSG_CTRUNC) { 904 logmsgx("#%u control data was truncated, MSG_CTRUNC flag is on", 905 i); 906 goto next_error; 907 } 908 909 if (msg.msg_controllen < sizeof(struct cmsghdr)) { 910 logmsgx("#%u msg_controllen %u < %lu (sizeof(struct cmsghdr))", 911 i, (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr)); 912 goto next_error; 913 } 914 915 if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) { 916 logmsgx("CMSG_FIRSTHDR is NULL"); 917 goto next_error; 918 } 919 920 dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i, 921 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len)); 922 923 if (cmptr->cmsg_level != SOL_SOCKET) { 924 logmsgx("#%u cmsg_level %d != SOL_SOCKET", i, 925 cmptr->cmsg_level); 926 goto next_error; 927 } 928 929 if (cmptr->cmsg_type != SCM_CREDS) { 930 logmsgx("#%u cmsg_type %d != SCM_CREDS", i, 931 cmptr->cmsg_type); 932 goto next_error; 933 } 934 935 if (cmptr->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred))) { 936 logmsgx("#%u cmsg_len %u != %lu (CMSG_LEN(sizeof(struct cmsgcred))", 937 i, (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(sizeof(struct cmsgcred))); 938 goto next_error; 939 } 940 941 cmcredptr = (const struct cmsgcred *)CMSG_DATA(cmptr); 942 943 error2 = 0; 944 if (cmcredptr->cmcred_pid != client_pid) { 945 logmsgx("#%u cmcred_pid %ld != %ld (PID of client)", 946 i, (long)cmcredptr->cmcred_pid, (long)client_pid); 947 error2 = 1; 948 } 949 if (cmcredptr->cmcred_uid != my_uid) { 950 logmsgx("#%u cmcred_uid %lu != %lu (UID of current process)", 951 i, (u_long)cmcredptr->cmcred_uid, (u_long)my_uid); 952 error2 = 1; 953 } 954 if (cmcredptr->cmcred_euid != my_euid) { 955 logmsgx("#%u cmcred_euid %lu != %lu (EUID of current process)", 956 i, (u_long)cmcredptr->cmcred_euid, (u_long)my_euid); 957 error2 = 1; 958 } 959 if (cmcredptr->cmcred_gid != my_gid) { 960 logmsgx("#%u cmcred_gid %lu != %lu (GID of current process)", 961 i, (u_long)cmcredptr->cmcred_gid, (u_long)my_gid); 962 error2 = 1; 963 } 964 if (cmcredptr->cmcred_ngroups == 0) { 965 logmsgx("#%u cmcred_ngroups = 0, this is wrong", i); 966 error2 = 1; 967 } else { 968 if (cmcredptr->cmcred_ngroups > NGROUPS_MAX) { 969 logmsgx("#%u cmcred_ngroups %d > %u (NGROUPS_MAX)", 970 i, cmcredptr->cmcred_ngroups, NGROUPS_MAX); 971 error2 = 1; 972 } else if (cmcredptr->cmcred_ngroups < 0) { 973 logmsgx("#%u cmcred_ngroups %d < 0", 974 i, cmcredptr->cmcred_ngroups); 975 error2 = 1; 976 } else { 977 dbgmsg(("#%u cmcred_ngroups = %d", i, 978 cmcredptr->cmcred_ngroups)); 979 if (cmcredptr->cmcred_groups[0] != my_egid) { 980 logmsgx("#%u cmcred_groups[0] %lu != %lu (EGID of current process)", 981 i, (u_long)cmcredptr->cmcred_groups[0], (u_long)my_egid); 982 error2 = 1; 983 } 984 if (check_groups(cmcredptr->cmcred_groups + 1, cmcredptr->cmcred_ngroups - 1) < 0) { 985 logmsgx("#%u cmcred_groups has wrong GIDs", i); 986 error2 = 1; 987 } 988 } 989 } 990 991 if (error2) 992 goto next_error; 993 994 if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) { 995 logmsgx("#%u control data has extra header", i); 996 goto next_error; 997 } 998 999 continue; 1000 next_error: 1001 error = -1; 1002 } 1003 1004 if (sock_type == SOCK_STREAM) 1005 if (close(fd2) < 0) { 1006 logmsg("close"); 1007 return (-2); 1008 } 1009 return (error); 1010 1011 failed: 1012 if (sock_type == SOCK_STREAM) 1013 if (close(fd2) < 0) 1014 logmsg("close"); 1015 return (-2); 1016 } 1017 1018 static int 1019 t_cmsgcred(void) 1020 { 1021 int error, fd; 1022 1023 if ((fd = create_server_socket()) < 0) 1024 return (-2); 1025 1026 if (sock_type == SOCK_STREAM) 1027 if (listen(fd, LISTENQ) < 0) { 1028 logmsg("listen"); 1029 goto failed; 1030 } 1031 1032 if ((client_pid = fork()) == (pid_t)-1) { 1033 logmsg("fork"); 1034 goto failed; 1035 } 1036 1037 if (client_pid == 0) { 1038 myname = "CLIENT"; 1039 if (close_socket((const char *)NULL, fd) < 0) 1040 _exit(1); 1041 t_cmsgcred_client(2); 1042 } 1043 1044 if ((error = t_cmsgcred_server(fd)) == -2) { 1045 (void)wait_client(); 1046 goto failed; 1047 } 1048 1049 if (wait_client() < 0) 1050 goto failed; 1051 1052 if (close_socket(serv_sock_path, fd) < 0) { 1053 logmsgx("close_socket failed"); 1054 return (-2); 1055 } 1056 return (error); 1057 1058 failed: 1059 if (close_socket(serv_sock_path, fd) < 0) 1060 logmsgx("close_socket failed"); 1061 return (-2); 1062 } 1063 1064 /* 1065 * Send two messages with data to server and exit. 1066 */ 1067 static void 1068 t_sockcred_client(int type) 1069 { 1070 struct msghdr msg; 1071 struct iovec iov[1]; 1072 int fd; 1073 u_int i; 1074 1075 assert(type == 0 || type == 1); 1076 1077 if ((fd = create_unbound_socket()) < 0) 1078 goto failed; 1079 1080 if (connect_server(fd) < 0) 1081 goto failed_close; 1082 1083 if (type == 1) 1084 if (sync_recv(fd) < 0) 1085 goto failed_close; 1086 1087 iov[0].iov_base = ipc_message; 1088 iov[0].iov_len = IPC_MESSAGE_SIZE; 1089 1090 msg.msg_name = NULL; 1091 msg.msg_namelen = 0; 1092 msg.msg_iov = iov; 1093 msg.msg_iovlen = 1; 1094 msg.msg_control = NULL; 1095 msg.msg_controllen = 0; 1096 msg.msg_flags = 0; 1097 1098 for (i = 0; i < 2; ++i) 1099 if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0) 1100 goto failed_close; 1101 1102 if (close_socket((const char *)NULL, fd) < 0) 1103 goto failed; 1104 1105 _exit(0); 1106 1107 failed_close: 1108 (void)close_socket((const char *)NULL, fd); 1109 1110 failed: 1111 _exit(1); 1112 } 1113 1114 /* 1115 * Receive one message with data and control message with SCM_CREDS 1116 * type followed by struct sockcred{} and if n is not equal 1, then 1117 * receive another one message with data. fd1 is a listen socket for 1118 * stream sockets or simply socket for datagram sockets. If type is 1119 * 1, then set LOCAL_CREDS option for accepted stream socket. 1120 */ 1121 static int 1122 t_sockcred_server(int type, int fd1, u_int n) 1123 { 1124 char buf[IPC_MESSAGE_SIZE]; 1125 union { 1126 struct cmsghdr cm; 1127 char control[CMSG_SPACE(SOCKCREDSIZE(NGROUPS_MAX)) + EXTRA_CMSG_SPACE]; 1128 } control_un; 1129 struct msghdr msg; 1130 struct iovec iov[1]; 1131 struct cmsghdr *cmptr; 1132 const struct sockcred *sockcred; 1133 int error, error2, fd2, optval; 1134 u_int i; 1135 1136 assert(n == 1 || n == 2); 1137 assert(type == 0 || type == 1); 1138 1139 if (sock_type == SOCK_STREAM) { 1140 if ((fd2 = accept_timeout(fd1)) < 0) 1141 return (-2); 1142 if (type == 1) { 1143 optval = 1; 1144 if (setsockopt(fd2, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) { 1145 logmsg("setsockopt(LOCAL_CREDS) for accepted socket"); 1146 if (errno == ENOPROTOOPT) { 1147 error = -1; 1148 goto done_close; 1149 } 1150 goto failed; 1151 } 1152 if (sync_send(fd2) < 0) 1153 goto failed; 1154 } 1155 } else 1156 fd2 = fd1; 1157 1158 error = 0; 1159 1160 for (i = 0; i < n; ++i) { 1161 iov[0].iov_base = buf; 1162 iov[0].iov_len = sizeof buf; 1163 1164 msg.msg_name = NULL; 1165 msg.msg_namelen = 0; 1166 msg.msg_iov = iov; 1167 msg.msg_iovlen = 1; 1168 msg.msg_control = control_un.control; 1169 msg.msg_controllen = sizeof control_un.control; 1170 msg.msg_flags = 0; 1171 1172 if (recvmsg_timeout(fd2, &msg, sizeof buf) < 0) 1173 goto failed; 1174 1175 if (msg.msg_flags & MSG_CTRUNC) { 1176 logmsgx("control data was truncated, MSG_CTRUNC flag is on"); 1177 goto next_error; 1178 } 1179 1180 if (i != 0 && sock_type == SOCK_STREAM) { 1181 if (msg.msg_controllen != 0) { 1182 logmsgx("second message has control data, this is wrong for stream sockets"); 1183 goto next_error; 1184 } 1185 dbgmsg(("#%u msg_controllen = %u", i, 1186 (u_int)msg.msg_controllen)); 1187 continue; 1188 } 1189 1190 if (msg.msg_controllen < sizeof(struct cmsghdr)) { 1191 logmsgx("#%u msg_controllen %u < %lu (sizeof(struct cmsghdr))", 1192 i, (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr)); 1193 goto next_error; 1194 } 1195 1196 if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) { 1197 logmsgx("CMSG_FIRSTHDR is NULL"); 1198 goto next_error; 1199 } 1200 1201 dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i, 1202 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len)); 1203 1204 if (cmptr->cmsg_level != SOL_SOCKET) { 1205 logmsgx("#%u cmsg_level %d != SOL_SOCKET", i, 1206 cmptr->cmsg_level); 1207 goto next_error; 1208 } 1209 1210 if (cmptr->cmsg_type != SCM_CREDS) { 1211 logmsgx("#%u cmsg_type %d != SCM_CREDS", i, 1212 cmptr->cmsg_type); 1213 goto next_error; 1214 } 1215 1216 if (cmptr->cmsg_len < CMSG_LEN(SOCKCREDSIZE(1))) { 1217 logmsgx("#%u cmsg_len %u != %lu (CMSG_LEN(SOCKCREDSIZE(1)))", 1218 i, (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(SOCKCREDSIZE(1))); 1219 goto next_error; 1220 } 1221 1222 sockcred = (const struct sockcred *)CMSG_DATA(cmptr); 1223 1224 error2 = 0; 1225 if (sockcred->sc_uid != my_uid) { 1226 logmsgx("#%u sc_uid %lu != %lu (UID of current process)", 1227 i, (u_long)sockcred->sc_uid, (u_long)my_uid); 1228 error2 = 1; 1229 } 1230 if (sockcred->sc_euid != my_euid) { 1231 logmsgx("#%u sc_euid %lu != %lu (EUID of current process)", 1232 i, (u_long)sockcred->sc_euid, (u_long)my_euid); 1233 error2 = 1; 1234 } 1235 if (sockcred->sc_gid != my_gid) { 1236 logmsgx("#%u sc_gid %lu != %lu (GID of current process)", 1237 i, (u_long)sockcred->sc_gid, (u_long)my_gid); 1238 error2 = 1; 1239 } 1240 if (sockcred->sc_egid != my_egid) { 1241 logmsgx("#%u sc_egid %lu != %lu (EGID of current process)", 1242 i, (u_long)sockcred->sc_gid, (u_long)my_egid); 1243 error2 = 1; 1244 } 1245 if (sockcred->sc_ngroups > NGROUPS_MAX) { 1246 logmsgx("#%u sc_ngroups %d > %u (NGROUPS_MAX)", 1247 i, sockcred->sc_ngroups, NGROUPS_MAX); 1248 error2 = 1; 1249 } else if (sockcred->sc_ngroups < 0) { 1250 logmsgx("#%u sc_ngroups %d < 0", 1251 i, sockcred->sc_ngroups); 1252 error2 = 1; 1253 } else { 1254 dbgmsg(("#%u sc_ngroups = %d", i, sockcred->sc_ngroups)); 1255 if (check_groups(sockcred->sc_groups, sockcred->sc_ngroups) < 0) { 1256 logmsgx("#%u sc_groups has wrong GIDs", i); 1257 error2 = 1; 1258 } 1259 } 1260 1261 if (error2) 1262 goto next_error; 1263 1264 if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) { 1265 logmsgx("#%u control data has extra header, this is wrong", 1266 i); 1267 goto next_error; 1268 } 1269 1270 continue; 1271 next_error: 1272 error = -1; 1273 } 1274 1275 done_close: 1276 if (sock_type == SOCK_STREAM) 1277 if (close(fd2) < 0) { 1278 logmsg("close"); 1279 return (-2); 1280 } 1281 return (error); 1282 1283 failed: 1284 if (sock_type == SOCK_STREAM) 1285 if (close(fd2) < 0) 1286 logmsg("close"); 1287 return (-2); 1288 } 1289 1290 static int 1291 t_sockcred(int type) 1292 { 1293 int error, fd, optval; 1294 1295 assert(type == 0 || type == 1); 1296 1297 if ((fd = create_server_socket()) < 0) 1298 return (-2); 1299 1300 if (sock_type == SOCK_STREAM) 1301 if (listen(fd, LISTENQ) < 0) { 1302 logmsg("listen"); 1303 goto failed; 1304 } 1305 1306 if (type == 0) { 1307 optval = 1; 1308 if (setsockopt(fd, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) { 1309 logmsg("setsockopt(LOCAL_CREDS) for %s socket", 1310 sock_type == SOCK_STREAM ? "stream listening" : "datagram"); 1311 if (errno == ENOPROTOOPT) { 1312 error = -1; 1313 goto done_close; 1314 } 1315 goto failed; 1316 } 1317 } 1318 1319 if ((client_pid = fork()) == (pid_t)-1) { 1320 logmsg("fork"); 1321 goto failed; 1322 } 1323 1324 if (client_pid == 0) { 1325 myname = "CLIENT"; 1326 if (close_socket((const char *)NULL, fd) < 0) 1327 _exit(1); 1328 t_sockcred_client(type); 1329 } 1330 1331 if ((error = t_sockcred_server(type, fd, 2)) == -2) { 1332 (void)wait_client(); 1333 goto failed; 1334 } 1335 1336 if (wait_client() < 0) 1337 goto failed; 1338 1339 done_close: 1340 if (close_socket(serv_sock_path, fd) < 0) { 1341 logmsgx("close_socket failed"); 1342 return (-2); 1343 } 1344 return (error); 1345 1346 failed: 1347 if (close_socket(serv_sock_path, fd) < 0) 1348 logmsgx("close_socket failed"); 1349 return (-2); 1350 } 1351 1352 static int 1353 t_sockcred_stream1(void) 1354 { 1355 return (t_sockcred(0)); 1356 } 1357 1358 static int 1359 t_sockcred_stream2(void) 1360 { 1361 return (t_sockcred(1)); 1362 } 1363 1364 static int 1365 t_sockcred_dgram(void) 1366 { 1367 return (t_sockcred(0)); 1368 } 1369 1370 static int 1371 t_cmsgcred_sockcred(void) 1372 { 1373 int error, fd, optval; 1374 1375 if ((fd = create_server_socket()) < 0) 1376 return (-2); 1377 1378 if (sock_type == SOCK_STREAM) 1379 if (listen(fd, LISTENQ) < 0) { 1380 logmsg("listen"); 1381 goto failed; 1382 } 1383 1384 optval = 1; 1385 if (setsockopt(fd, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) { 1386 logmsg("setsockopt(LOCAL_CREDS) for %s socket", 1387 sock_type == SOCK_STREAM ? "stream listening" : "datagram"); 1388 if (errno == ENOPROTOOPT) { 1389 error = -1; 1390 goto done_close; 1391 } 1392 goto failed; 1393 } 1394 1395 if ((client_pid = fork()) == (pid_t)-1) { 1396 logmsg("fork"); 1397 goto failed; 1398 } 1399 1400 if (client_pid == 0) { 1401 myname = "CLIENT"; 1402 if (close_socket((const char *)NULL, fd) < 0) 1403 _exit(1); 1404 t_cmsgcred_client(1); 1405 } 1406 1407 if ((error = t_sockcred_server(0, fd, 1)) == -2) { 1408 (void)wait_client(); 1409 goto failed; 1410 } 1411 1412 if (wait_client() < 0) 1413 goto failed; 1414 1415 done_close: 1416 if (close_socket(serv_sock_path, fd) < 0) { 1417 logmsgx("close_socket failed"); 1418 return (-2); 1419 } 1420 return (error); 1421 1422 failed: 1423 if (close_socket(serv_sock_path, fd) < 0) 1424 logmsgx("close_socket failed"); 1425 return (-2); 1426 } 1427 1428 /* 1429 * Send one message with data and control message with SCM_TIMESTAMP 1430 * type to server and exit. 1431 */ 1432 static void 1433 t_timestamp_client(void) 1434 { 1435 union { 1436 struct cmsghdr cm; 1437 char control[CMSG_SPACE(sizeof(struct timeval))]; 1438 } control_un; 1439 struct msghdr msg; 1440 struct iovec iov[1]; 1441 struct cmsghdr *cmptr; 1442 int fd; 1443 1444 if ((fd = create_unbound_socket()) < 0) 1445 goto failed; 1446 1447 if (connect_server(fd) < 0) 1448 goto failed_close; 1449 1450 iov[0].iov_base = ipc_message; 1451 iov[0].iov_len = IPC_MESSAGE_SIZE; 1452 1453 msg.msg_name = NULL; 1454 msg.msg_namelen = 0; 1455 msg.msg_iov = iov; 1456 msg.msg_iovlen = 1; 1457 msg.msg_control = control_un.control; 1458 msg.msg_controllen = no_control_data ? 1459 sizeof(struct cmsghdr) :sizeof control_un.control; 1460 msg.msg_flags = 0; 1461 1462 cmptr = CMSG_FIRSTHDR(&msg); 1463 cmptr->cmsg_len = CMSG_LEN(no_control_data ? 1464 0 : sizeof(struct timeval)); 1465 cmptr->cmsg_level = SOL_SOCKET; 1466 cmptr->cmsg_type = SCM_TIMESTAMP; 1467 1468 dbgmsg(("msg_controllen = %u, cmsg_len = %u", 1469 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len)); 1470 1471 if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0) 1472 goto failed_close; 1473 1474 if (close_socket((const char *)NULL, fd) < 0) 1475 goto failed; 1476 1477 _exit(0); 1478 1479 failed_close: 1480 (void)close_socket((const char *)NULL, fd); 1481 1482 failed: 1483 _exit(1); 1484 } 1485 1486 /* 1487 * Receive one message with data and control message with SCM_TIMESTAMP 1488 * type followed by struct timeval{} from client. 1489 */ 1490 static int 1491 t_timestamp_server(int fd1) 1492 { 1493 union { 1494 struct cmsghdr cm; 1495 char control[CMSG_SPACE(sizeof(struct timeval)) + EXTRA_CMSG_SPACE]; 1496 } control_un; 1497 char buf[IPC_MESSAGE_SIZE]; 1498 int error, fd2; 1499 struct msghdr msg; 1500 struct iovec iov[1]; 1501 struct cmsghdr *cmptr; 1502 const struct timeval *timeval; 1503 1504 if (sock_type == SOCK_STREAM) { 1505 if ((fd2 = accept_timeout(fd1)) < 0) 1506 return (-2); 1507 } else 1508 fd2 = fd1; 1509 1510 iov[0].iov_base = buf; 1511 iov[0].iov_len = sizeof buf; 1512 1513 msg.msg_name = NULL; 1514 msg.msg_namelen = 0; 1515 msg.msg_iov = iov; 1516 msg.msg_iovlen = 1; 1517 msg.msg_control = control_un.control; 1518 msg.msg_controllen = sizeof control_un.control;; 1519 msg.msg_flags = 0; 1520 1521 if (recvmsg_timeout(fd2, &msg, sizeof buf) < 0) 1522 goto failed; 1523 1524 error = -1; 1525 1526 if (msg.msg_flags & MSG_CTRUNC) { 1527 logmsgx("control data was truncated, MSG_CTRUNC flag is on"); 1528 goto done; 1529 } 1530 1531 if (msg.msg_controllen < sizeof(struct cmsghdr)) { 1532 logmsgx("msg_controllen %u < %lu (sizeof(struct cmsghdr))", 1533 (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr)); 1534 goto done; 1535 } 1536 1537 if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) { 1538 logmsgx("CMSG_FIRSTHDR is NULL"); 1539 goto done; 1540 } 1541 1542 dbgmsg(("msg_controllen = %u, cmsg_len = %u", 1543 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len)); 1544 1545 if (cmptr->cmsg_level != SOL_SOCKET) { 1546 logmsgx("cmsg_level %d != SOL_SOCKET", cmptr->cmsg_level); 1547 goto done; 1548 } 1549 1550 if (cmptr->cmsg_type != SCM_TIMESTAMP) { 1551 logmsgx("cmsg_type %d != SCM_TIMESTAMP", cmptr->cmsg_type); 1552 goto done; 1553 } 1554 1555 if (cmptr->cmsg_len != CMSG_LEN(sizeof(struct timeval))) { 1556 logmsgx("cmsg_len %u != %lu (CMSG_LEN(sizeof(struct timeval))", 1557 (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(sizeof(struct timeval))); 1558 goto done; 1559 } 1560 1561 timeval = (const struct timeval *)CMSG_DATA(cmptr); 1562 1563 dbgmsg(("timeval tv_sec %jd, tv_usec %jd", 1564 (intmax_t)timeval->tv_sec, (intmax_t)timeval->tv_usec)); 1565 1566 if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) { 1567 logmsgx("control data has extra header"); 1568 goto done; 1569 } 1570 1571 error = 0; 1572 1573 done: 1574 if (sock_type == SOCK_STREAM) 1575 if (close(fd2) < 0) { 1576 logmsg("close"); 1577 return (-2); 1578 } 1579 return (error); 1580 1581 failed: 1582 if (sock_type == SOCK_STREAM) 1583 if (close(fd2) < 0) 1584 logmsg("close"); 1585 return (-2); 1586 } 1587 1588 static int 1589 t_timestamp(void) 1590 { 1591 int error, fd; 1592 1593 if ((fd = create_server_socket()) < 0) 1594 return (-2); 1595 1596 if (sock_type == SOCK_STREAM) 1597 if (listen(fd, LISTENQ) < 0) { 1598 logmsg("listen"); 1599 goto failed; 1600 } 1601 1602 if ((client_pid = fork()) == (pid_t)-1) { 1603 logmsg("fork"); 1604 goto failed; 1605 } 1606 1607 if (client_pid == 0) { 1608 myname = "CLIENT"; 1609 if (close_socket((const char *)NULL, fd) < 0) 1610 _exit(1); 1611 t_timestamp_client(); 1612 } 1613 1614 if ((error = t_timestamp_server(fd)) == -2) { 1615 (void)wait_client(); 1616 goto failed; 1617 } 1618 1619 if (wait_client() < 0) 1620 goto failed; 1621 1622 if (close_socket(serv_sock_path, fd) < 0) { 1623 logmsgx("close_socket failed"); 1624 return (-2); 1625 } 1626 return (error); 1627 1628 failed: 1629 if (close_socket(serv_sock_path, fd) < 0) 1630 logmsgx("close_socket failed"); 1631 return (-2); 1632 } 1633