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