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