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