xref: /freebsd/tools/regression/sockets/unix_cmsg/unix_cmsg.c (revision f4b37ed0f8b307b1f3f0f630ca725d68f1dff30d)
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 }
1970