xref: /freebsd/tools/regression/sockets/unix_cmsg/unix_cmsg.c (revision 78cd93ff95c5db47a3e087e0db56c379ac64c874)
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 	int rc;
984 
985 	if (len != sizeof(*xucred)) {
986 		logmsgx("option value size %zu != %zu",
987 		    (size_t)len, sizeof(*xucred));
988 		return (-1);
989 	}
990 
991 	dbgmsg("xucred.cr_version %u", xucred->cr_version);
992 	dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid);
993 	dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups);
994 
995 	rc = 0;
996 
997 	if (xucred->cr_version != XUCRED_VERSION) {
998 		logmsgx("xucred.cr_version %u != %d",
999 		    xucred->cr_version, XUCRED_VERSION);
1000 		rc = -1;
1001 	}
1002 	if (xucred->cr_uid != proc_cred.euid) {
1003 		logmsgx("xucred.cr_uid %lu != %lu (EUID)",
1004 		   (u_long)xucred->cr_uid, (u_long)proc_cred.euid);
1005 		rc = -1;
1006 	}
1007 	if (xucred->cr_ngroups == 0) {
1008 		logmsgx("xucred.cr_ngroups == 0");
1009 		rc = -1;
1010 	}
1011 	if (xucred->cr_ngroups < 0) {
1012 		logmsgx("xucred.cr_ngroups < 0");
1013 		rc = -1;
1014 	}
1015 	if (xucred->cr_ngroups > XU_NGROUPS) {
1016 		logmsgx("xucred.cr_ngroups %hu > %u (max)",
1017 		    xucred->cr_ngroups, XU_NGROUPS);
1018 		rc = -1;
1019 	}
1020 	if (xucred->cr_groups[0] != proc_cred.egid) {
1021 		logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)",
1022 		    (u_long)xucred->cr_groups[0], (u_long)proc_cred.egid);
1023 		rc = -1;
1024 	}
1025 	if (check_groups("xucred.cr_groups", xucred->cr_groups,
1026 	    "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0)
1027 		rc = -1;
1028 	return (rc);
1029 }
1030 
1031 static int
1032 check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr)
1033 {
1034 	const struct cmsgcred *cmcred;
1035 	int rc;
1036 
1037 	if (check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(struct cmsgcred)) < 0)
1038 		return (-1);
1039 
1040 	cmcred = (struct cmsgcred *)CMSG_DATA(cmsghdr);
1041 
1042 	dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmcred->cmcred_pid);
1043 	dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmcred->cmcred_uid);
1044 	dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmcred->cmcred_euid);
1045 	dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmcred->cmcred_gid);
1046 	dbgmsg("cmsgcred.cmcred_ngroups %d", cmcred->cmcred_ngroups);
1047 
1048 	rc = 0;
1049 
1050 	if (cmcred->cmcred_pid != client_pid) {
1051 		logmsgx("cmsgcred.cmcred_pid %ld != %ld",
1052 		    (long)cmcred->cmcred_pid, (long)client_pid);
1053 		rc = -1;
1054 	}
1055 	if (cmcred->cmcred_uid != proc_cred.uid) {
1056 		logmsgx("cmsgcred.cmcred_uid %lu != %lu",
1057 		    (u_long)cmcred->cmcred_uid, (u_long)proc_cred.uid);
1058 		rc = -1;
1059 	}
1060 	if (cmcred->cmcred_euid != proc_cred.euid) {
1061 		logmsgx("cmsgcred.cmcred_euid %lu != %lu",
1062 		    (u_long)cmcred->cmcred_euid, (u_long)proc_cred.euid);
1063 		rc = -1;
1064 	}
1065 	if (cmcred->cmcred_gid != proc_cred.gid) {
1066 		logmsgx("cmsgcred.cmcred_gid %lu != %lu",
1067 		    (u_long)cmcred->cmcred_gid, (u_long)proc_cred.gid);
1068 		rc = -1;
1069 	}
1070 	if (cmcred->cmcred_ngroups == 0) {
1071 		logmsgx("cmsgcred.cmcred_ngroups == 0");
1072 		rc = -1;
1073 	}
1074 	if (cmcred->cmcred_ngroups < 0) {
1075 		logmsgx("cmsgcred.cmcred_ngroups %d < 0",
1076 		    cmcred->cmcred_ngroups);
1077 		rc = -1;
1078 	}
1079 	if (cmcred->cmcred_ngroups > CMGROUP_MAX) {
1080 		logmsgx("cmsgcred.cmcred_ngroups %d > %d",
1081 		    cmcred->cmcred_ngroups, CMGROUP_MAX);
1082 		rc = -1;
1083 	}
1084 	if (cmcred->cmcred_groups[0] != proc_cred.egid) {
1085 		logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)",
1086 		    (u_long)cmcred->cmcred_groups[0], (u_long)proc_cred.egid);
1087 		rc = -1;
1088 	}
1089 	if (check_groups("cmsgcred.cmcred_groups", cmcred->cmcred_groups,
1090 	    "cmsgcred.cmcred_ngroups", cmcred->cmcred_ngroups, false) < 0)
1091 		rc = -1;
1092 	return (rc);
1093 }
1094 
1095 static int
1096 check_scm_creds_sockcred(struct cmsghdr *cmsghdr)
1097 {
1098 	const struct sockcred *sc;
1099 	int rc;
1100 
1101 	if (check_cmsghdr(cmsghdr, SCM_CREDS,
1102 	    SOCKCREDSIZE(proc_cred.gid_num)) < 0)
1103 		return (-1);
1104 
1105 	sc = (struct sockcred *)CMSG_DATA(cmsghdr);
1106 
1107 	rc = 0;
1108 
1109 	dbgmsg("sockcred.sc_uid %lu", (u_long)sc->sc_uid);
1110 	dbgmsg("sockcred.sc_euid %lu", (u_long)sc->sc_euid);
1111 	dbgmsg("sockcred.sc_gid %lu", (u_long)sc->sc_gid);
1112 	dbgmsg("sockcred.sc_egid %lu", (u_long)sc->sc_egid);
1113 	dbgmsg("sockcred.sc_ngroups %d", sc->sc_ngroups);
1114 
1115 	if (sc->sc_uid != proc_cred.uid) {
1116 		logmsgx("sockcred.sc_uid %lu != %lu",
1117 		    (u_long)sc->sc_uid, (u_long)proc_cred.uid);
1118 		rc = -1;
1119 	}
1120 	if (sc->sc_euid != proc_cred.euid) {
1121 		logmsgx("sockcred.sc_euid %lu != %lu",
1122 		    (u_long)sc->sc_euid, (u_long)proc_cred.euid);
1123 		rc = -1;
1124 	}
1125 	if (sc->sc_gid != proc_cred.gid) {
1126 		logmsgx("sockcred.sc_gid %lu != %lu",
1127 		    (u_long)sc->sc_gid, (u_long)proc_cred.gid);
1128 		rc = -1;
1129 	}
1130 	if (sc->sc_egid != proc_cred.egid) {
1131 		logmsgx("sockcred.sc_egid %lu != %lu",
1132 		    (u_long)sc->sc_egid, (u_long)proc_cred.egid);
1133 		rc = -1;
1134 	}
1135 	if (sc->sc_ngroups == 0) {
1136 		logmsgx("sockcred.sc_ngroups == 0");
1137 		rc = -1;
1138 	}
1139 	if (sc->sc_ngroups < 0) {
1140 		logmsgx("sockcred.sc_ngroups %d < 0",
1141 		    sc->sc_ngroups);
1142 		rc = -1;
1143 	}
1144 	if (sc->sc_ngroups != proc_cred.gid_num) {
1145 		logmsgx("sockcred.sc_ngroups %d != %u",
1146 		    sc->sc_ngroups, proc_cred.gid_num);
1147 		rc = -1;
1148 	}
1149 	if (check_groups("sockcred.sc_groups", sc->sc_groups,
1150 	    "sockcred.sc_ngroups", sc->sc_ngroups, true) < 0)
1151 		rc = -1;
1152 	return (rc);
1153 }
1154 
1155 static int
1156 check_scm_timestamp(struct cmsghdr *cmsghdr)
1157 {
1158 	const struct timeval *tv;
1159 
1160 	if (check_cmsghdr(cmsghdr, SCM_TIMESTAMP, sizeof(struct timeval)) < 0)
1161 		return (-1);
1162 
1163 	tv = (struct timeval *)CMSG_DATA(cmsghdr);
1164 
1165 	dbgmsg("timeval.tv_sec %"PRIdMAX", timeval.tv_usec %"PRIdMAX,
1166 	    (intmax_t)tv->tv_sec, (intmax_t)tv->tv_usec);
1167 
1168 	return (0);
1169 }
1170 
1171 static int
1172 check_scm_bintime(struct cmsghdr *cmsghdr)
1173 {
1174 	const struct bintime *bt;
1175 
1176 	if (check_cmsghdr(cmsghdr, SCM_BINTIME, sizeof(struct bintime)) < 0)
1177 		return (-1);
1178 
1179 	bt = (struct bintime *)CMSG_DATA(cmsghdr);
1180 
1181 	dbgmsg("bintime.sec %"PRIdMAX", bintime.frac %"PRIu64,
1182 	    (intmax_t)bt->sec, bt->frac);
1183 
1184 	return (0);
1185 }
1186 
1187 static void
1188 msghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data)
1189 {
1190 	msghdr->msg_name = NULL;
1191 	msghdr->msg_namelen = 0;
1192 	if (send_data_flag) {
1193 		iov->iov_base = server_flag ?
1194 		    ipc_msg.buf_recv : ipc_msg.buf_send;
1195 		iov->iov_len = ipc_msg.buf_size;
1196 		msghdr->msg_iov = iov;
1197 		msghdr->msg_iovlen = 1;
1198 	} else {
1199 		msghdr->msg_iov = NULL;
1200 		msghdr->msg_iovlen = 0;
1201 	}
1202 	msghdr->msg_control = cmsg_data;
1203 	msghdr->msg_flags = 0;
1204 }
1205 
1206 static void
1207 msghdr_init_server(struct msghdr *msghdr, struct iovec *iov,
1208     void *cmsg_data, size_t cmsg_size)
1209 {
1210 	msghdr_init_generic(msghdr, iov, cmsg_data);
1211 	msghdr->msg_controllen = cmsg_size;
1212 	dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ?
1213 	    msghdr->msg_iov->iov_len : (size_t)0);
1214 	dbgmsg("init: msghdr.msg_controllen %u",
1215 	    (u_int)msghdr->msg_controllen);
1216 }
1217 
1218 static void
1219 msghdr_init_client(struct msghdr *msghdr, struct iovec *iov,
1220     void *cmsg_data, size_t cmsg_size, int type, size_t arr_size)
1221 {
1222 	struct cmsghdr *cmsghdr;
1223 
1224 	msghdr_init_generic(msghdr, iov, cmsg_data);
1225 	if (cmsg_data != NULL) {
1226 		if (send_array_flag)
1227 			dbgmsg("sending an array");
1228 		else
1229 			dbgmsg("sending a scalar");
1230 		msghdr->msg_controllen = send_array_flag ?
1231 		    cmsg_size : CMSG_SPACE(0);
1232 		cmsghdr = CMSG_FIRSTHDR(msghdr);
1233 		cmsghdr->cmsg_level = SOL_SOCKET;
1234 		cmsghdr->cmsg_type = type;
1235 		cmsghdr->cmsg_len = CMSG_LEN(send_array_flag ? arr_size : 0);
1236 	} else
1237 		msghdr->msg_controllen = 0;
1238 }
1239 
1240 static int
1241 t_generic(int (*client_func)(int), int (*server_func)(int))
1242 {
1243 	int fd, rv, rv_client;
1244 
1245 	switch (client_fork()) {
1246 	case 0:
1247 		fd = socket_create();
1248 		if (fd < 0)
1249 			rv = -2;
1250 		else {
1251 			rv = client_func(fd);
1252 			if (socket_close(fd) < 0)
1253 				rv = -2;
1254 		}
1255 		client_exit(rv);
1256 		break;
1257 	case 1:
1258 		fd = socket_create();
1259 		if (fd < 0)
1260 			rv = -2;
1261 		else {
1262 			rv = server_func(fd);
1263 			rv_client = client_wait();
1264 			if (rv == 0 || (rv == -2 && rv_client != 0))
1265 				rv = rv_client;
1266 			if (socket_close(fd) < 0)
1267 				rv = -2;
1268 		}
1269 		break;
1270 	default:
1271 		rv = -2;
1272 	}
1273 	return (rv);
1274 }
1275 
1276 static int
1277 t_cmsgcred_client(int fd)
1278 {
1279 	struct msghdr msghdr;
1280 	struct iovec iov[1];
1281 	void *cmsg_data;
1282 	size_t cmsg_size;
1283 	int rv;
1284 
1285 	if (sync_recv() < 0)
1286 		return (-2);
1287 
1288 	rv = -2;
1289 
1290 	cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
1291 	cmsg_data = malloc(cmsg_size);
1292 	if (cmsg_data == NULL) {
1293 		logmsg("malloc");
1294 		goto done;
1295 	}
1296 	msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1297 	    SCM_CREDS, sizeof(struct cmsgcred));
1298 
1299 	if (socket_connect(fd) < 0)
1300 		goto done;
1301 
1302 	if (message_sendn(fd, &msghdr) < 0)
1303 		goto done;
1304 
1305 	rv = 0;
1306 done:
1307 	free(cmsg_data);
1308 	return (rv);
1309 }
1310 
1311 static int
1312 t_cmsgcred_server(int fd1)
1313 {
1314 	struct msghdr msghdr;
1315 	struct iovec iov[1];
1316 	struct cmsghdr *cmsghdr;
1317 	void *cmsg_data;
1318 	size_t cmsg_size;
1319 	u_int i;
1320 	int fd2, rv;
1321 
1322 	if (sync_send() < 0)
1323 		return (-2);
1324 
1325 	fd2 = -1;
1326 	rv = -2;
1327 
1328 	cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
1329 	cmsg_data = malloc(cmsg_size);
1330 	if (cmsg_data == NULL) {
1331 		logmsg("malloc");
1332 		goto done;
1333 	}
1334 
1335 	if (sock_type == SOCK_STREAM) {
1336 		fd2 = socket_accept(fd1);
1337 		if (fd2 < 0)
1338 			goto done;
1339 	} else
1340 		fd2 = fd1;
1341 
1342 	rv = -1;
1343 	for (i = 1; i <= ipc_msg.msg_num; ++i) {
1344 		dbgmsg("message #%u", i);
1345 
1346 		msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1347 		if (message_recv(fd2, &msghdr) < 0) {
1348 			rv = -2;
1349 			break;
1350 		}
1351 
1352 		if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1353 			break;
1354 
1355 		cmsghdr = CMSG_FIRSTHDR(&msghdr);
1356 		if (check_scm_creds_cmsgcred(cmsghdr) < 0)
1357 			break;
1358 	}
1359 	if (i > ipc_msg.msg_num)
1360 		rv = 0;
1361 done:
1362 	free(cmsg_data);
1363 	if (sock_type == SOCK_STREAM && fd2 >= 0)
1364 		if (socket_close(fd2) < 0)
1365 			rv = -2;
1366 	return (rv);
1367 }
1368 
1369 static int
1370 t_cmsgcred(void)
1371 {
1372 	return (t_generic(t_cmsgcred_client, t_cmsgcred_server));
1373 }
1374 
1375 static int
1376 t_sockcred_client(int type, int fd)
1377 {
1378 	struct msghdr msghdr;
1379 	struct iovec iov[1];
1380 	int rv;
1381 
1382 	if (sync_recv() < 0)
1383 		return (-2);
1384 
1385 	rv = -2;
1386 
1387 	msghdr_init_client(&msghdr, iov, NULL, 0, 0, 0);
1388 
1389 	if (socket_connect(fd) < 0)
1390 		goto done;
1391 
1392 	if (type == 2)
1393 		if (sync_recv() < 0)
1394 			goto done;
1395 
1396 	if (message_sendn(fd, &msghdr) < 0)
1397 		goto done;
1398 
1399 	rv = 0;
1400 done:
1401 	return (rv);
1402 }
1403 
1404 static int
1405 t_sockcred_server(int type, int fd1)
1406 {
1407 	struct msghdr msghdr;
1408 	struct iovec iov[1];
1409 	struct cmsghdr *cmsghdr;
1410 	void *cmsg_data;
1411 	size_t cmsg_size;
1412 	u_int i;
1413 	int fd2, rv, val;
1414 
1415 	fd2 = -1;
1416 	rv = -2;
1417 
1418 	cmsg_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num));
1419 	cmsg_data = malloc(cmsg_size);
1420 	if (cmsg_data == NULL) {
1421 		logmsg("malloc");
1422 		goto done;
1423 	}
1424 
1425 	if (type == 1) {
1426 		dbgmsg("setting LOCAL_CREDS");
1427 		val = 1;
1428 		if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
1429 			logmsg("setsockopt(LOCAL_CREDS)");
1430 			goto done;
1431 		}
1432 	}
1433 
1434 	if (sync_send() < 0)
1435 		goto done;
1436 
1437 	if (sock_type == SOCK_STREAM) {
1438 		fd2 = socket_accept(fd1);
1439 		if (fd2 < 0)
1440 			goto done;
1441 	} else
1442 		fd2 = fd1;
1443 
1444 	if (type == 2) {
1445 		dbgmsg("setting LOCAL_CREDS");
1446 		val = 1;
1447 		if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
1448 			logmsg("setsockopt(LOCAL_CREDS)");
1449 			goto done;
1450 		}
1451 		if (sync_send() < 0)
1452 			goto done;
1453 	}
1454 
1455 	rv = -1;
1456 	for (i = 1; i <= ipc_msg.msg_num; ++i) {
1457 		dbgmsg("message #%u", i);
1458 
1459 		msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1460 		if (message_recv(fd2, &msghdr) < 0) {
1461 			rv = -2;
1462 			break;
1463 		}
1464 
1465 		if (i > 1 && sock_type == SOCK_STREAM) {
1466 			if (check_msghdr(&msghdr, 0) < 0)
1467 				break;
1468 		} else {
1469 			if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1470 				break;
1471 
1472 			cmsghdr = CMSG_FIRSTHDR(&msghdr);
1473 			if (check_scm_creds_sockcred(cmsghdr) < 0)
1474 				break;
1475 		}
1476 	}
1477 	if (i > ipc_msg.msg_num)
1478 		rv = 0;
1479 done:
1480 	free(cmsg_data);
1481 	if (sock_type == SOCK_STREAM && fd2 >= 0)
1482 		if (socket_close(fd2) < 0)
1483 			rv = -2;
1484 	return (rv);
1485 }
1486 
1487 static int
1488 t_sockcred_1(void)
1489 {
1490 	u_int i;
1491 	int fd, rv, rv_client;
1492 
1493 	switch (client_fork()) {
1494 	case 0:
1495 		for (i = 1; i <= 2; ++i) {
1496 			dbgmsg("client #%u", i);
1497 			fd = socket_create();
1498 			if (fd < 0)
1499 				rv = -2;
1500 			else {
1501 				rv = t_sockcred_client(1, fd);
1502 				if (socket_close(fd) < 0)
1503 					rv = -2;
1504 			}
1505 			if (rv != 0)
1506 				break;
1507 		}
1508 		client_exit(rv);
1509 		break;
1510 	case 1:
1511 		fd = socket_create();
1512 		if (fd < 0)
1513 			rv = -2;
1514 		else {
1515 			rv = t_sockcred_server(1, fd);
1516 			if (rv == 0)
1517 				rv = t_sockcred_server(3, fd);
1518 			rv_client = client_wait();
1519 			if (rv == 0 || (rv == -2 && rv_client != 0))
1520 				rv = rv_client;
1521 			if (socket_close(fd) < 0)
1522 				rv = -2;
1523 		}
1524 		break;
1525 	default:
1526 		rv = -2;
1527 	}
1528 
1529 	return (rv);
1530 }
1531 
1532 static int
1533 t_sockcred_2_client(int fd)
1534 {
1535 	return (t_sockcred_client(2, fd));
1536 }
1537 
1538 static int
1539 t_sockcred_2_server(int fd)
1540 {
1541 	return (t_sockcred_server(2, fd));
1542 }
1543 
1544 static int
1545 t_sockcred_2(void)
1546 {
1547 	return (t_generic(t_sockcred_2_client, t_sockcred_2_server));
1548 }
1549 
1550 static int
1551 t_cmsgcred_sockcred_server(int fd1)
1552 {
1553 	struct msghdr msghdr;
1554 	struct iovec iov[1];
1555 	struct cmsghdr *cmsghdr;
1556 	void *cmsg_data, *cmsg1_data, *cmsg2_data;
1557 	size_t cmsg_size, cmsg1_size, cmsg2_size;
1558 	u_int i;
1559 	int fd2, rv, val;
1560 
1561 	fd2 = -1;
1562 	rv = -2;
1563 
1564 	cmsg1_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num));
1565 	cmsg2_size = CMSG_SPACE(sizeof(struct cmsgcred));
1566 	cmsg1_data = malloc(cmsg1_size);
1567 	cmsg2_data = malloc(cmsg2_size);
1568 	if (cmsg1_data == NULL || cmsg2_data == NULL) {
1569 		logmsg("malloc");
1570 		goto done;
1571 	}
1572 
1573 	dbgmsg("setting LOCAL_CREDS");
1574 	val = 1;
1575 	if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
1576 		logmsg("setsockopt(LOCAL_CREDS)");
1577 		goto done;
1578 	}
1579 
1580 	if (sync_send() < 0)
1581 		goto done;
1582 
1583 	if (sock_type == SOCK_STREAM) {
1584 		fd2 = socket_accept(fd1);
1585 		if (fd2 < 0)
1586 			goto done;
1587 	} else
1588 		fd2 = fd1;
1589 
1590 	cmsg_data = cmsg1_data;
1591 	cmsg_size = cmsg1_size;
1592 	rv = -1;
1593 	for (i = 1; i <= ipc_msg.msg_num; ++i) {
1594 		dbgmsg("message #%u", i);
1595 
1596 		msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1597 		if (message_recv(fd2, &msghdr) < 0) {
1598 			rv = -2;
1599 			break;
1600 		}
1601 
1602 		if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1603 			break;
1604 
1605 		cmsghdr = CMSG_FIRSTHDR(&msghdr);
1606 		if (i == 1 || sock_type == SOCK_DGRAM) {
1607 			if (check_scm_creds_sockcred(cmsghdr) < 0)
1608 				break;
1609 		} else {
1610 			if (check_scm_creds_cmsgcred(cmsghdr) < 0)
1611 				break;
1612 		}
1613 
1614 		cmsg_data = cmsg2_data;
1615 		cmsg_size = cmsg2_size;
1616 	}
1617 	if (i > ipc_msg.msg_num)
1618 		rv = 0;
1619 done:
1620 	free(cmsg1_data);
1621 	free(cmsg2_data);
1622 	if (sock_type == SOCK_STREAM && fd2 >= 0)
1623 		if (socket_close(fd2) < 0)
1624 			rv = -2;
1625 	return (rv);
1626 }
1627 
1628 static int
1629 t_cmsgcred_sockcred(void)
1630 {
1631 	return (t_generic(t_cmsgcred_client, t_cmsgcred_sockcred_server));
1632 }
1633 
1634 static int
1635 t_timeval_client(int fd)
1636 {
1637 	struct msghdr msghdr;
1638 	struct iovec iov[1];
1639 	void *cmsg_data;
1640 	size_t cmsg_size;
1641 	int rv;
1642 
1643 	if (sync_recv() < 0)
1644 		return (-2);
1645 
1646 	rv = -2;
1647 
1648 	cmsg_size = CMSG_SPACE(sizeof(struct timeval));
1649 	cmsg_data = malloc(cmsg_size);
1650 	if (cmsg_data == NULL) {
1651 		logmsg("malloc");
1652 		goto done;
1653 	}
1654 	msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1655 	    SCM_TIMESTAMP, sizeof(struct timeval));
1656 
1657 	if (socket_connect(fd) < 0)
1658 		goto done;
1659 
1660 	if (message_sendn(fd, &msghdr) < 0)
1661 		goto done;
1662 
1663 	rv = 0;
1664 done:
1665 	free(cmsg_data);
1666 	return (rv);
1667 }
1668 
1669 static int
1670 t_timeval_server(int fd1)
1671 {
1672 	struct msghdr msghdr;
1673 	struct iovec iov[1];
1674 	struct cmsghdr *cmsghdr;
1675 	void *cmsg_data;
1676 	size_t cmsg_size;
1677 	u_int i;
1678 	int fd2, rv;
1679 
1680 	if (sync_send() < 0)
1681 		return (-2);
1682 
1683 	fd2 = -1;
1684 	rv = -2;
1685 
1686 	cmsg_size = CMSG_SPACE(sizeof(struct timeval));
1687 	cmsg_data = malloc(cmsg_size);
1688 	if (cmsg_data == NULL) {
1689 		logmsg("malloc");
1690 		goto done;
1691 	}
1692 
1693 	if (sock_type == SOCK_STREAM) {
1694 		fd2 = socket_accept(fd1);
1695 		if (fd2 < 0)
1696 			goto done;
1697 	} else
1698 		fd2 = fd1;
1699 
1700 	rv = -1;
1701 	for (i = 1; i <= ipc_msg.msg_num; ++i) {
1702 		dbgmsg("message #%u", i);
1703 
1704 		msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1705 		if (message_recv(fd2, &msghdr) < 0) {
1706 			rv = -2;
1707 			break;
1708 		}
1709 
1710 		if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1711 			break;
1712 
1713 		cmsghdr = CMSG_FIRSTHDR(&msghdr);
1714 		if (check_scm_timestamp(cmsghdr) < 0)
1715 			break;
1716 	}
1717 	if (i > ipc_msg.msg_num)
1718 		rv = 0;
1719 done:
1720 	free(cmsg_data);
1721 	if (sock_type == SOCK_STREAM && fd2 >= 0)
1722 		if (socket_close(fd2) < 0)
1723 			rv = -2;
1724 	return (rv);
1725 }
1726 
1727 static int
1728 t_timeval(void)
1729 {
1730 	return (t_generic(t_timeval_client, t_timeval_server));
1731 }
1732 
1733 static int
1734 t_bintime_client(int fd)
1735 {
1736 	struct msghdr msghdr;
1737 	struct iovec iov[1];
1738 	void *cmsg_data;
1739 	size_t cmsg_size;
1740 	int rv;
1741 
1742 	if (sync_recv() < 0)
1743 		return (-2);
1744 
1745 	rv = -2;
1746 
1747 	cmsg_size = CMSG_SPACE(sizeof(struct bintime));
1748 	cmsg_data = malloc(cmsg_size);
1749 	if (cmsg_data == NULL) {
1750 		logmsg("malloc");
1751 		goto done;
1752 	}
1753 	msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1754 	    SCM_BINTIME, sizeof(struct bintime));
1755 
1756 	if (socket_connect(fd) < 0)
1757 		goto done;
1758 
1759 	if (message_sendn(fd, &msghdr) < 0)
1760 		goto done;
1761 
1762 	rv = 0;
1763 done:
1764 	free(cmsg_data);
1765 	return (rv);
1766 }
1767 
1768 static int
1769 t_bintime_server(int fd1)
1770 {
1771 	struct msghdr msghdr;
1772 	struct iovec iov[1];
1773 	struct cmsghdr *cmsghdr;
1774 	void *cmsg_data;
1775 	size_t cmsg_size;
1776 	u_int i;
1777 	int fd2, rv;
1778 
1779 	if (sync_send() < 0)
1780 		return (-2);
1781 
1782 	fd2 = -1;
1783 	rv = -2;
1784 
1785 	cmsg_size = CMSG_SPACE(sizeof(struct bintime));
1786 	cmsg_data = malloc(cmsg_size);
1787 	if (cmsg_data == NULL) {
1788 		logmsg("malloc");
1789 		goto done;
1790 	}
1791 
1792 	if (sock_type == SOCK_STREAM) {
1793 		fd2 = socket_accept(fd1);
1794 		if (fd2 < 0)
1795 			goto done;
1796 	} else
1797 		fd2 = fd1;
1798 
1799 	rv = -1;
1800 	for (i = 1; i <= ipc_msg.msg_num; ++i) {
1801 		dbgmsg("message #%u", i);
1802 
1803 		msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1804 		if (message_recv(fd2, &msghdr) < 0) {
1805 			rv = -2;
1806 			break;
1807 		}
1808 
1809 		if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1810 			break;
1811 
1812 		cmsghdr = CMSG_FIRSTHDR(&msghdr);
1813 		if (check_scm_bintime(cmsghdr) < 0)
1814 			break;
1815 	}
1816 	if (i > ipc_msg.msg_num)
1817 		rv = 0;
1818 done:
1819 	free(cmsg_data);
1820 	if (sock_type == SOCK_STREAM && fd2 >= 0)
1821 		if (socket_close(fd2) < 0)
1822 			rv = -2;
1823 	return (rv);
1824 }
1825 
1826 static int
1827 t_bintime(void)
1828 {
1829 	return (t_generic(t_bintime_client, t_bintime_server));
1830 }
1831 
1832 static int
1833 t_cmsg_len_client(int fd)
1834 {
1835 	struct msghdr msghdr;
1836 	struct iovec iov[1];
1837 	struct cmsghdr *cmsghdr;
1838 	void *cmsg_data;
1839 	size_t size, cmsg_size;
1840 	socklen_t socklen;
1841 	int rv;
1842 
1843 	if (sync_recv() < 0)
1844 		return (-2);
1845 
1846 	rv = -2;
1847 
1848 	cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
1849 	cmsg_data = malloc(cmsg_size);
1850 	if (cmsg_data == NULL) {
1851 		logmsg("malloc");
1852 		goto done;
1853 	}
1854 	msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1855 	    SCM_CREDS, sizeof(struct cmsgcred));
1856 	cmsghdr = CMSG_FIRSTHDR(&msghdr);
1857 
1858 	if (socket_connect(fd) < 0)
1859 		goto done;
1860 
1861 	size = msghdr.msg_iov != NULL ? msghdr.msg_iov->iov_len : 0;
1862 	rv = -1;
1863 	for (socklen = 0; socklen < CMSG_LEN(0); ++socklen) {
1864 		cmsghdr->cmsg_len = socklen;
1865 		dbgmsg("send: data size %zu", size);
1866 		dbgmsg("send: msghdr.msg_controllen %u",
1867 		    (u_int)msghdr.msg_controllen);
1868 		dbgmsg("send: cmsghdr.cmsg_len %u",
1869 		    (u_int)cmsghdr->cmsg_len);
1870 		if (sendmsg(fd, &msghdr, 0) < 0) {
1871 			dbgmsg("sendmsg(2) failed: %s; retrying",
1872 			    strerror(errno));
1873 			continue;
1874 		}
1875 		logmsgx("sent message with cmsghdr.cmsg_len %u < %u",
1876 		    (u_int)cmsghdr->cmsg_len, (u_int)CMSG_LEN(0));
1877 		break;
1878 	}
1879 	if (socklen == CMSG_LEN(0))
1880 		rv = 0;
1881 
1882 	if (sync_send() < 0) {
1883 		rv = -2;
1884 		goto done;
1885 	}
1886 done:
1887 	free(cmsg_data);
1888 	return (rv);
1889 }
1890 
1891 static int
1892 t_cmsg_len_server(int fd1)
1893 {
1894 	int fd2, rv;
1895 
1896 	if (sync_send() < 0)
1897 		return (-2);
1898 
1899 	rv = -2;
1900 
1901 	if (sock_type == SOCK_STREAM) {
1902 		fd2 = socket_accept(fd1);
1903 		if (fd2 < 0)
1904 			goto done;
1905 	} else
1906 		fd2 = fd1;
1907 
1908 	if (sync_recv() < 0)
1909 		goto done;
1910 
1911 	rv = 0;
1912 done:
1913 	if (sock_type == SOCK_STREAM && fd2 >= 0)
1914 		if (socket_close(fd2) < 0)
1915 			rv = -2;
1916 	return (rv);
1917 }
1918 
1919 static int
1920 t_cmsg_len(void)
1921 {
1922 	return (t_generic(t_cmsg_len_client, t_cmsg_len_server));
1923 }
1924 
1925 static int
1926 t_peercred_client(int fd)
1927 {
1928 	struct xucred xucred;
1929 	socklen_t len;
1930 
1931 	if (sync_recv() < 0)
1932 		return (-1);
1933 
1934 	if (socket_connect(fd) < 0)
1935 		return (-1);
1936 
1937 	len = sizeof(xucred);
1938 	if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
1939 		logmsg("getsockopt(LOCAL_PEERCRED)");
1940 		return (-1);
1941 	}
1942 
1943 	if (check_xucred(&xucred, len) < 0)
1944 		return (-1);
1945 
1946 	return (0);
1947 }
1948 
1949 static int
1950 t_peercred_server(int fd1)
1951 {
1952 	struct xucred xucred;
1953 	socklen_t len;
1954 	int fd2, rv;
1955 
1956 	if (sync_send() < 0)
1957 		return (-2);
1958 
1959 	fd2 = socket_accept(fd1);
1960 	if (fd2 < 0)
1961 		return (-2);
1962 
1963 	len = sizeof(xucred);
1964 	if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
1965 		logmsg("getsockopt(LOCAL_PEERCRED)");
1966 		rv = -2;
1967 		goto done;
1968 	}
1969 
1970 	if (check_xucred(&xucred, len) < 0) {
1971 		rv = -1;
1972 		goto done;
1973 	}
1974 
1975 	rv = 0;
1976 done:
1977 	if (socket_close(fd2) < 0)
1978 		rv = -2;
1979 	return (rv);
1980 }
1981 
1982 static int
1983 t_peercred(void)
1984 {
1985 	return (t_generic(t_peercred_client, t_peercred_server));
1986 }
1987