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