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