bin/131567: Update for regression/sockets/unix_cmsg

Andrey Simonenko simon at comsys.ntu-kpi.kiev.ua
Fri Feb 13 03:11:11 PST 2009


Updated patch: use getprogname(3) instead of __progname.

diff -ruN unix_cmsg.orig/README unix_cmsg/README
--- unix_cmsg.orig/README	2006-05-29 21:40:55.000000000 +0300
+++ unix_cmsg/README	2009-02-03 17:41:42.000000000 +0200
@@ -1,7 +1,7 @@
 $FreeBSD: src/tools/regression/sockets/unix_cmsg/README,v 1.1 2006/05/29 18:40:55 maxim Exp $
 
 About unix_cmsg
-================
+===============
 
 This program is a collection of regression tests for ancillary (control)
 data for PF_LOCAL sockets (local domain or Unix domain sockets).  There
@@ -13,8 +13,8 @@
 messages to Server.
 
 It is better to change the owner of unix_cmsg to some safe user
-(eg. nobody:nogroup) and set SUID and SGID bits, else some tests
-can give correct results for wrong implementation.
+(eg. nobody:nogroup) and set SUID and SGID bits, else some tests that
+check credentials can give correct results for wrong implementation.
 
 Available options
 =================
@@ -24,7 +24,7 @@
 
 -h	Output help message and exit.
 
--t <socktype>
+-t socktype
 	Run tests only for the given socket type: "stream" or "dgram".
 	With this option it is possible to run only particular test,
 	not all of them.
@@ -90,6 +90,13 @@
     message with data and control message with SCM_TIMESTAMP type
     followed by struct timeval{}.
 
+ 6: Check LOCAL_PEERCRED socket option
+
+    This test does not use control data for PF_LOCAL sockets, but can be
+    implemented here.  Client connects to Server.  Both Client and Server
+    verify that credentials of the peer are correct using LOCAL_PEERCRED
+    socket option.
+
 For SOCK_DGRAM sockets:
 ----------------------
 
@@ -110,7 +117,7 @@
     structure should contain correct information.
 
  3: Sending cmsgcred, receiving sockcred
- 
+
     Server creates datagram socket and set socket option LOCAL_CREDS
     for it.  Client sends one message with data and control message with
     SOCK_CREDS type to Server.  Server should receive one message with
diff -ruN unix_cmsg.orig/unix_cmsg.c unix_cmsg/unix_cmsg.c
--- unix_cmsg.orig/unix_cmsg.c	2006-05-31 11:10:34.000000000 +0300
+++ unix_cmsg/unix_cmsg.c	2009-02-13 12:47:39.000000000 +0200
@@ -27,10 +27,11 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/tools/regression/sockets/unix_cmsg/unix_cmsg.c,v 1.2 2006/05/31 08:10:34 maxim Exp $");
 
-#include <sys/types.h>
+#include <sys/param.h>
 #include <sys/resource.h>
 #include <sys/time.h>
 #include <sys/socket.h>
+#include <sys/ucred.h>
 #include <sys/un.h>
 #include <sys/wait.h>
 
@@ -68,7 +69,7 @@
  *
  * Each function which can block, is run under TIMEOUT, if timeout
  * occurs, then test function returns -2 or a client process exits
- * with nonzero return code.
+ * with non-zero return code.
  */
 
 #ifndef LISTENQ
@@ -76,14 +77,14 @@
 #endif
 
 #ifndef TIMEOUT
-# define TIMEOUT	60
+# define TIMEOUT	5
 #endif
 
 #define EXTRA_CMSG_SPACE 512	/* Memory for not expected control data. */
 
 static int	t_cmsgcred(void), t_sockcred_stream1(void);
 static int	t_sockcred_stream2(void), t_cmsgcred_sockcred(void);
-static int	t_sockcred_dgram(void), t_timestamp(void);
+static int	t_sockcred_dgram(void), t_timestamp(void), t_peercred(void);
 
 struct test_func {
 	int	(*func)(void);	/* Pointer to function.	*/
@@ -91,31 +92,57 @@
 };
 
 static struct test_func test_stream_tbl[] = {
-	{ NULL,			" 0: All tests" },
-	{ t_cmsgcred,		" 1: Sending, receiving cmsgcred" },
-	{ t_sockcred_stream1,	" 2: Receiving sockcred (listening socket has LOCAL_CREDS)" },
-	{ t_sockcred_stream2,	" 3: Receiving sockcred (accepted socket has LOCAL_CREDS)" },
-	{ t_cmsgcred_sockcred,	" 4: Sending cmsgcred, receiving sockcred" },
-	{ t_timestamp,		" 5: Sending, receiving timestamp" },
-	{ NULL, NULL }
+	{ .func = NULL,
+	  .desc = "All tests"
+	},
+	{ .func = t_cmsgcred,
+	  .desc = "Sending, receiving cmsgcred"
+	},
+	{ .func = t_sockcred_stream1,
+	  .desc = "Receiving sockcred (listening socket has LOCAL_CREDS)"
+	},
+	{ .func = t_sockcred_stream2,
+	  .desc = "Receiving sockcred (accepted socket has LOCAL_CREDS)"
+	},
+	{ .func = t_cmsgcred_sockcred,
+	  .desc = "Sending cmsgcred, receiving sockcred"
+	},
+	{ .func = t_timestamp,
+	  .desc = "Sending, receiving timestamp"
+	},
+	{ .func = t_peercred,
+	  .desc = "Check LOCAL_PEERCRED socket option"
+	}
 };
 
+#define TEST_STREAM_TBL_SIZE \
+	(sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0]))
+
 static struct test_func test_dgram_tbl[] = {
-	{ NULL,			" 0: All tests" },
-	{ t_cmsgcred,		" 1: Sending, receiving cmsgcred" },
-	{ t_sockcred_dgram,	" 2: Receiving sockcred" },
-	{ t_cmsgcred_sockcred,	" 3: Sending cmsgcred, receiving sockcred" },
-	{ t_timestamp,		" 4: Sending, receiving timestamp" },
-	{ NULL, NULL }
+	{ .func = NULL,
+	  .desc = "All tests"
+	},
+	{ .func = t_cmsgcred,
+	  .desc = "Sending, receiving cmsgcred"
+	},
+	{ .func = t_sockcred_dgram,
+	  .desc = "Receiving sockcred"
+	},
+	{ .func = t_cmsgcred_sockcred,
+	  .desc = "Sending cmsgcred, receiving sockcred"
+	},
+	{ .func = t_timestamp,
+	  .desc = "Sending, receiving timestamp"
+	}
 };
 
-#define TEST_STREAM_NO_MAX	(sizeof(test_stream_tbl) / sizeof(struct test_func) - 2)
-#define TEST_DGRAM_NO_MAX	(sizeof(test_dgram_tbl) / sizeof(struct test_func) - 2)
+#define TEST_DGRAM_TBL_SIZE \
+	(sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0]))
 
-static const char *myname = "SERVER";	/* "SERVER" or "CLIENT" */
+static const char *myname;		/* "SERVER" or "CLIENT" */
 
-static int	debug = 0;		/* 1, if -d. */
-static int	no_control_data = 0;	/* 1, if -z. */
+static int	debug = 0;		/* -d */
+static int	no_control_data = 0;	/* -z */
 
 static u_int	nfailed = 0;		/* Number of failed tests. */
 
@@ -156,32 +183,29 @@
 static void	logmsgx(const char *, ...) __printflike(1, 2);
 static void	output(const char *, ...) __printflike(1, 2);
 
-extern char	*__progname;		/* The name of program. */
-
 /*
  * Output the help message (-h switch).
  */
 static void
 usage(int quick)
 {
-	const struct test_func *test_func;
+	u_int i;
 
-	fprintf(stderr, "Usage: %s [-dhz] [-t <socktype>] [testno]\n",
-	    __progname);
+	fprintf(stderr, "usage: %s [-dhz] [-t socktype] [testno]\n",
+	    getprogname());
 	if (quick)
 		return;
 	fprintf(stderr, "\n Options are:\n\
   -d\t\t\tOutput debugging information\n\
   -h\t\t\tOutput this help message and exit\n\
-  -t <socktype>\t\tRun test only for the given socket type:\n\
-\t\t\tstream or dgram\n\
+  -t socktype\t\tRun test only for socket type: stream or dgram\n\
   -z\t\t\tDo not send real control data if possible\n\n");
 	fprintf(stderr, " Available tests for stream sockets:\n");
-	for (test_func = test_stream_tbl; test_func->desc != NULL; ++test_func)
-		fprintf(stderr, "  %s\n", test_func->desc);
+	for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i)
+		fprintf(stderr, "   %u: %s\n", i, test_stream_tbl[i].desc);
 	fprintf(stderr, "\n Available tests for datagram sockets:\n");
-	for (test_func = test_dgram_tbl; test_func->desc != NULL; ++test_func)
-		fprintf(stderr, "  %s\n", test_func->desc);
+	for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i)
+		fprintf(stderr, "   %u: %s\n", i, test_dgram_tbl[i].desc);
 }
 
 /*
@@ -210,8 +234,7 @@
 	va_list ap;
 	int errno_save;
 
-	errno_save = errno;		/* Save errno. */
-
+	errno_save = errno;
 	va_start(ap, format);
 	if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
 		err(EX_SOFTWARE, "logmsg: vsnprintf failed");
@@ -220,8 +243,7 @@
 	else
 		output("%s: %s: %s\n", myname, buf, strerror(errno_save));
 	va_end(ap);
-
-	errno = errno_save;		/* Restore errno. */
+	errno = errno_save;
 }
 
 /*
@@ -241,22 +263,35 @@
 }
 
 /*
- * Run tests from testno1 to testno2.
+ * Run tests for the given socket type.
  */
 static int
-run_tests(u_int testno1, u_int testno2)
+run_tests(int type, u_int testno1)
 {
-	const struct test_func *test_func;
-	u_int i, nfailed1;
+	const struct test_func *tf;
+	u_int i, nfailed1, testno2;
 
-	output("Running tests for %s sockets:\n", sock_type_str);
-	test_func = (sock_type == SOCK_STREAM ?
-	    test_stream_tbl : test_dgram_tbl) + testno1;
+	sock_type = type;
+	if (type == SOCK_STREAM) {
+		sock_type_str = "SOCK_STREAM";
+		tf = test_stream_tbl;
+		i = TEST_STREAM_TBL_SIZE - 1;
+	} else {
+		sock_type_str = "SOCK_DGRAM";
+		tf = test_dgram_tbl;
+		i = TEST_DGRAM_TBL_SIZE - 1;
+	}
+	if (testno1 == 0) {
+		testno1 = 1;
+		testno2 = i;
+	} else
+		testno2 = testno1;
 
+	output("Running tests for %s sockets:\n", sock_type_str);
 	nfailed1 = 0;
-	for (i = testno1; i <= testno2; ++test_func, ++i) {
-		output(" %s\n", test_func->desc);
-		switch (test_func->func()) {
+	for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) {
+		output("  %u: %s\n", i, tf->desc);
+		switch (tf->func()) {
 		case -1:
 			++nfailed1;
 			break;
@@ -300,22 +335,35 @@
 	struct sigaction sa;
 
 	sa.sa_handler = SIG_IGN;
-	sigemptyset(&sa.sa_mask);
 	sa.sa_flags = 0;
-	if (sigaction(SIGPIPE, &sa, (struct sigaction *)NULL) < 0) 
+	if (sigaction(SIGPIPE, &sa, (struct sigaction *)NULL) < 0)
 		err(EX_OSERR, "sigaction(SIGPIPE)");
 
 	sa.sa_handler = sig_alrm;
+	sigemptyset(&sa.sa_mask);
 	if (sigaction(SIGALRM, &sa, (struct sigaction *)NULL) < 0)
 		err(EX_OSERR, "sigaction(SIGALRM)");
 }
 
+static int
+fork_client(void)
+{
+	client_pid = fork();
+	if (client_pid == 0)
+		myname = "CLIENT";
+	else if (client_pid == (pid_t)-1) {
+		logmsg("fork");
+		return (-1);
+	}
+	return (0);
+}
+
 int
 main(int argc, char *argv[])
 {
 	const char *errstr;
-	int opt, dgramflag, streamflag;
-	u_int testno1, testno2;
+	u_int testno;
+	int opt, rv, dgramflag, streamflag;
 
 	dgramflag = streamflag = 0;
 	while ((opt = getopt(argc, argv, "dht:z")) != -1)
@@ -332,7 +380,7 @@
 			else if (strcmp(optarg, "dgram") == 0)
 				dgramflag = 1;
 			else
-				errx(EX_USAGE, "wrong socket type in -t option");
+				errx(EX_USAGE, "option -t: wrong socket type");
 			break;
 		case 'z':
 			no_control_data = 1;
@@ -346,38 +394,40 @@
 	if (optind < argc) {
 		if (optind + 1 != argc)
 			errx(EX_USAGE, "too many arguments");
-		testno1 = strtonum(argv[optind], 0, UINT_MAX, &errstr);
+		testno = strtonum(argv[optind], 0, UINT_MAX, &errstr);
 		if (errstr != NULL)
 			errx(EX_USAGE, "wrong test number: %s", errstr);
 	} else
-		testno1 = 0;
+		testno = 0;
 
 	if (dgramflag == 0 && streamflag == 0)
 		dgramflag = streamflag = 1;
 
-	if (dgramflag && streamflag && testno1 != 0)
-		errx(EX_USAGE, "you can use particular test, only with datagram or stream sockets");
+	if (dgramflag && streamflag && testno != 0)
+		errx(EX_USAGE, "you can use particular test, only with "
+		    "datagram or stream sockets");
 
 	if (streamflag) {
-		if (testno1 > TEST_STREAM_NO_MAX)
-			errx(EX_USAGE, "given test %u for stream sockets does not exist",
-			    testno1);
+		if (testno >= TEST_STREAM_TBL_SIZE)
+			errx(EX_USAGE, "given test %u for stream sockets "
+			    "does not exist", testno);
 	} else {
-		if (testno1 > TEST_DGRAM_NO_MAX)
-			errx(EX_USAGE, "given test %u for datagram sockets does not exist",
-			    testno1);
+		if (testno >= TEST_DGRAM_TBL_SIZE)
+			errx(EX_USAGE, "given test %u for datagram sockets "
+			    "does not exist", testno);
 	}
 
 	my_uid = getuid();
 	my_euid = geteuid();
 	my_gid = getgid();
 	my_egid = getegid();
-	switch (my_ngids = getgroups(sizeof(my_gids) / sizeof(my_gids[0]), my_gids)) {
+	my_ngids = getgroups(sizeof(my_gids) / sizeof(my_gids[0]), my_gids);
+	switch (my_ngids) {
 	case -1:
 		err(EX_SOFTWARE, "getgroups");
 		/* NOTREACHED */
 	case 0:
-		errx(EX_OSERR, "getgroups returned 0 groups");
+		errx(EX_OSERR, "getgroups returned no groups");
 	}
 
 	sig_init();
@@ -385,42 +435,21 @@
 	if (mkdtemp(tempdir) == NULL)
 		err(EX_OSERR, "mkdtemp");
 
-	if (streamflag) {
-		sock_type = SOCK_STREAM;
-		sock_type_str = "SOCK_STREAM";
-		if (testno1 == 0) {
-			testno1 = 1;
-			testno2 = TEST_STREAM_NO_MAX;
-		} else
-			testno2 = testno1;
-		if (run_tests(testno1, testno2) < 0)
-			goto failed;
-		testno1 = 0;
-	}
-
-	if (dgramflag) {
-		sock_type = SOCK_DGRAM;
-		sock_type_str = "SOCK_DGRAM";
-		if (testno1 == 0) {
-			testno1 = 1;
-			testno2 = TEST_DGRAM_NO_MAX;
-		} else
-			testno2 = testno1;
-		if (run_tests(testno1, testno2) < 0)
-			goto failed;
-	}
+	myname = "SERVER";
+	rv = EX_OK;
+	if (streamflag)
+		if (run_tests(SOCK_STREAM, testno) < 0)
+			rv = EX_OSERR;
+	if (dgramflag && rv == EX_OK)
+		if (run_tests(SOCK_DGRAM, testno) < 0)
+			rv = EX_OSERR;
 
 	if (rmdir(tempdir) < 0) {
 		logmsg("rmdir(%s)", tempdir);
-		return (EX_OSERR);
+		rv = EX_OSERR;
 	}
 
-	return (nfailed ? EX_OSERR : EX_OK);
-
-failed:
-	if (rmdir(tempdir) < 0)
-		logmsg("rmdir(%s)", tempdir);
-	return (EX_OSERR);
+	return (nfailed ? EX_OSERR : rv);
 }
 
 /*
@@ -433,27 +462,30 @@
 {
 	int rv, fd;
 
-	if ((fd = socket(PF_LOCAL, sock_type, 0)) < 0) {
+	fd = socket(PF_LOCAL, sock_type, 0);
+	if (fd < 0) {
 		logmsg("create_socket: socket(PF_LOCAL, %s, 0)", sock_type_str);
 		return (-1);
 	}
 
 	if (sock_path != NULL) {
-		if ((rv = snprintf(sock_path, sock_path_len, "%s/%s",
-		    tempdir, myname)) < 0) {
+		rv = snprintf(sock_path, sock_path_len, "%s/%s", tempdir,
+		    myname);
+		if (rv < 0) {
 			logmsg("create_socket: snprintf failed");
 			goto failed;
 		}
 		if ((size_t)rv >= sock_path_len) {
-			logmsgx("create_socket: too long path name for given buffer");
+			logmsgx("create_socket: too long path name for given "
+			    "buffer");
 			goto failed;
 		}
 
 		memset(addr, 0, sizeof(addr));
 		addr->sun_family = AF_LOCAL;
 		if (strlen(sock_path) >= sizeof(addr->sun_path)) {
-			logmsgx("create_socket: too long path name (>= %lu) for local domain socket",
-			    (u_long)sizeof(addr->sun_path));
+			logmsgx("create_socket: too long path name (>= %zu) "
+			    "for local domain socket", sizeof(addr->sun_path));
 			goto failed;
 		}
 		strcpy(addr->sun_path, sock_path);
@@ -479,7 +511,8 @@
 static int
 create_server_socket(void)
 {
-	return (create_socket(serv_sock_path, sizeof(serv_sock_path), &servaddr));
+	return (create_socket(serv_sock_path, sizeof(serv_sock_path),
+	    &servaddr));
 }
 
 /*
@@ -498,12 +531,13 @@
 static int
 close_socket(const char *sock_path, int fd)
 {
-	int error = 0;
+	int error;
 
 	if (close(fd) < 0) {
 		logmsg("close_socket: close");
 		error = -1;
-	}
+	} else
+		error = 0;
 	if (sock_path != NULL)
 		if (unlink(sock_path) < 0) {
 			logmsg("close_socket: unlink(%s)", sock_path);
@@ -540,17 +574,16 @@
 {
 	ssize_t nsent;
 
-	dbgmsg(("sending %lu bytes", (u_long)n));
+	dbgmsg(("sending %zu bytes", n));
 
 	if (sigsetjmp(env_alrm, 1) != 0) {
-		logmsgx("sendmsg_timeout: cannot send message to %s (timeout)", serv_sock_path);
+		logmsgx("sendmsg_timeout: cannot send message to %s (timeout)",
+		    serv_sock_path);
 		return (-1);
 	}
 
 	(void)alarm(TIMEOUT);
-
 	nsent = sendmsg(fd, msg, 0);
-
 	(void)alarm(0);
 
 	if (nsent < 0) {
@@ -559,8 +592,8 @@
 	}
 
 	if ((size_t)nsent != n) {
-		logmsgx("sendmsg_timeout: sendmsg: short send: %ld of %lu bytes",
-		    (long)nsent, (u_long)n);
+		logmsgx("sendmsg_timeout: sendmsg: short send: %zd of %zu "
+		    "bytes", nsent, n);
 		return (-1);
 	}
 
@@ -583,9 +616,7 @@
 	}
 
 	(void)alarm(TIMEOUT);
-
 	fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL);
-
 	(void)alarm(0);
 
 	if (fd < 0) {
@@ -604,7 +635,7 @@
 {
 	ssize_t nread;
 
-	dbgmsg(("receiving %lu bytes", (u_long)n));
+	dbgmsg(("receiving %zu bytes", n));
 
 	if (sigsetjmp(env_alrm, 1) != 0) {
 		logmsgx("recvmsg_timeout: cannot receive message (timeout)");
@@ -612,9 +643,7 @@
 	}
 
 	(void)alarm(TIMEOUT);
-
 	nread = recvmsg(fd, msg, MSG_WAITALL);
-
 	(void)alarm(0);
 
 	if (nread < 0) {
@@ -623,8 +652,8 @@
 	}
 
 	if ((size_t)nread != n) {
-		logmsgx("recvmsg_timeout: recvmsg: short read: %ld of %lu bytes",
-		    (long)nread, (u_long)n);
+		logmsgx("recvmsg_timeout: recvmsg: short read: %zd of %zu "
+		    "bytes", nread, n);
 		return (-1);
 	}
 
@@ -648,9 +677,7 @@
 	}
 
 	(void)alarm(TIMEOUT);
-
 	nread = read(fd, &buf, 1);
-
 	(void)alarm(0);
 
 	if (nread < 0) {
@@ -659,8 +686,7 @@
 	}
 
 	if (nread != 1) {
-		logmsgx("sync_recv: read: short read: %ld of 1 byte",
-		    (long)nread);
+		logmsgx("sync_recv: read: short read: %zd of 1 byte", nread);
 		return (-1);
 	}
 
@@ -683,9 +709,7 @@
 	}
 
 	(void)alarm(TIMEOUT);
-
 	nsent = write(fd, "", 1);
-
 	(void)alarm(0);
 
 	if (nsent < 0) {
@@ -694,8 +718,7 @@
 	}
 
 	if (nsent != 1) {
-		logmsgx("sync_send: write: short write: %ld of 1 byte",
-		    (long)nsent);
+		logmsgx("sync_send: write: short write: %zd of 1 byte", nsent);
 		return (-1);
 	}
 
@@ -712,15 +735,13 @@
 	pid_t pid;
 
 	if (sigsetjmp(env_alrm, 1) != 0) {
-		logmsgx("wait_client: cannot get exit status of client PID %ld (timeout)",
-		    (long)client_pid);
+		logmsgx("wait_client: cannot get exit status of client "
+		    "PID %ld (timeout)", (long)client_pid);
 		return (-1);
 	}
 
-	(void)alarm(TIMEOUT);
-
+	(void)alarm(TIMEOUT * 2);
 	pid = waitpid(client_pid, &status, 0);
-
 	(void)alarm(0);
 
 	if (pid == (pid_t)-1) {
@@ -730,17 +751,19 @@
 
 	if (WIFEXITED(status)) {
 		if (WEXITSTATUS(status) != 0) {
-			logmsgx("wait_client: exit status of client PID %ld is %d",
-			    (long)client_pid, WEXITSTATUS(status));
+			logmsgx("wait_client: exit status of client PID %ld "
+			    "is %d", (long)client_pid, WEXITSTATUS(status));
 			return (-1);
 		}
 	} else {
 		if (WIFSIGNALED(status))
-			logmsgx("wait_client: abnormal termination of client PID %ld, signal %d%s",
-			    (long)client_pid, WTERMSIG(status), WCOREDUMP(status) ? " (core file generated)" : "");
+			logmsgx("wait_client: abnormal termination of client "
+			    "PID %ld, signal %d%s", (long)client_pid,
+			    WTERMSIG(status), WCOREDUMP(status) ?
+			    " (core file generated)" : "");
 		else
-			logmsgx("wait_client: termination of client PID %ld, unknown status",
-			    (long)client_pid);
+			logmsgx("wait_client: termination of client PID %ld, "
+			    "unknown status", (long)client_pid);
 		return (-1);
 	}
 
@@ -754,12 +777,12 @@
 static int
 check_groups(const gid_t *gids, int n)
 {
+	int i, j, error;
 	char match[NGROUPS_MAX] = { 0 };
-	int error, i, j;
 
 	if (n != my_ngids - 1) {
-		logmsgx("wrong number of groups %d != %d (returned from getgroups() - 1)",
-		    n, my_ngids - 1);
+		logmsgx("wrong number of groups %d != %d (returned from "
+		    "getgroups() - 1)", n, my_ngids - 1);
 		error = -1;
 	} else
 		error = 0;
@@ -782,7 +805,8 @@
 	}
 	for (j = 1; j < my_ngids; ++j)
 		if (match[j] == 0) {
-			logmsgx("did not receive supplementary GID %u", my_gids[j]);
+			logmsgx("did not receive supplementary GID %lu",
+			    (u_long)my_gids[j]);
 			error = -1;
 		}
 	return (error);
@@ -802,16 +826,19 @@
 	struct msghdr msg;
 	struct iovec iov[1];
 	struct cmsghdr *cmptr;
-	int fd;
 	u_int i;
+	int fd, error;
 
 	assert(n == 1 || n == 2);
 
-	if ((fd = create_unbound_socket()) < 0)
+	error = 1;
+
+	fd = create_unbound_socket();
+	if (fd < 0)
 		goto failed;
 
 	if (connect_server(fd) < 0)
-		goto failed_close;
+		goto done;
 
 	iov[0].iov_base = ipc_message;
 	iov[0].iov_len = IPC_MESSAGE_SIZE;
@@ -835,19 +862,15 @@
 		dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i,
 		    (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
 		if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0)
-			goto failed_close;
+			goto done;
 	}
 
-	if (close_socket((const char *)NULL, fd) < 0)
-		goto failed;
-
-	_exit(0);
-
-failed_close:
-	(void)close_socket((const char *)NULL, fd);
-
+	error = 0;
+done:
+	if (close_socket((char *)NULL, fd))
+		error = 1;
 failed:
-	_exit(1);
+	_exit(error);
 }
 
 /*
@@ -858,29 +881,28 @@
 static int
 t_cmsgcred_server(int fd1)
 {
-	char buf[IPC_MESSAGE_SIZE];
 	union {
 		struct cmsghdr	cm;
-		char	control[CMSG_SPACE(sizeof(struct cmsgcred)) + EXTRA_CMSG_SPACE];
+		char	control[CMSG_SPACE(sizeof(struct cmsgcred)) +
+				EXTRA_CMSG_SPACE];
 	} control_un;
 	struct msghdr msg;
 	struct iovec iov[1];
 	struct cmsghdr *cmptr;
-	const struct cmsgcred *cmcredptr;
-	socklen_t controllen;
-	int error, error2, fd2;
+	const struct cmsgcred *cmcred;
 	u_int i;
+	int fd2, error;
+	char buf[IPC_MESSAGE_SIZE];
 
 	if (sock_type == SOCK_STREAM) {
-		if ((fd2 = accept_timeout(fd1)) < 0)
+		fd2 = accept_timeout(fd1);
+		if (fd2 < 0)
 			return (-2);
 	} else
 		fd2 = fd1;
 
 	error = 0;
 
-	controllen = sizeof(control_un.control);
-
 	for (i = 0; i < 2; ++i) {
 		iov[0].iov_base = buf;
 		iov[0].iov_len = sizeof(buf);
@@ -890,29 +912,31 @@
 		msg.msg_iov = iov;
 		msg.msg_iovlen = 1;
 		msg.msg_control = control_un.control;
-		msg.msg_controllen = controllen;
+		msg.msg_controllen = sizeof(control_un.control);
 		msg.msg_flags = 0;
 
-		controllen = CMSG_SPACE(sizeof(struct cmsgcred));
-
-		if (recvmsg_timeout(fd2, &msg, sizeof(buf)) < 0)
-			goto failed;
+		if (recvmsg_timeout(fd2, &msg, sizeof(buf)) < 0) {
+			error = -2;
+			break;
+		}
 
 		if (msg.msg_flags & MSG_CTRUNC) {
-			logmsgx("#%u control data was truncated, MSG_CTRUNC flag is on",
-			    i);
-			goto next_error;
+			logmsgx("#%u control data was truncated, MSG_CTRUNC "
+			    "flag is on", i);
+			goto next;
 		}
 
 		if (msg.msg_controllen < sizeof(struct cmsghdr)) {
-			logmsgx("#%u msg_controllen %u < %lu (sizeof(struct cmsghdr))",
-			    i, (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr));
-			goto next_error;
+			logmsgx("#%u msg_controllen %u < %zu "
+			    "(sizeof(struct cmsghdr))", i,
+			    (u_int)msg.msg_controllen, sizeof(struct cmsghdr));
+			goto next;
 		}
 
-		if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) {
+		cmptr = CMSG_FIRSTHDR(&msg);
+		if (cmptr == NULL) {
 			logmsgx("CMSG_FIRSTHDR is NULL");
-			goto next_error;
+			goto next;
 		}
 
 		dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i,
@@ -921,96 +945,90 @@
 		if (cmptr->cmsg_level != SOL_SOCKET) {
 			logmsgx("#%u cmsg_level %d != SOL_SOCKET", i,
 			    cmptr->cmsg_level);
-			goto next_error;
+			goto next;
 		}
 
 		if (cmptr->cmsg_type != SCM_CREDS) {
 			logmsgx("#%u cmsg_type %d != SCM_CREDS", i,
 			    cmptr->cmsg_type);
-			goto next_error;
+			goto next;
 		}
 
 		if (cmptr->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred))) {
-			logmsgx("#%u cmsg_len %u != %lu (CMSG_LEN(sizeof(struct cmsgcred))",
-			    i, (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(sizeof(struct cmsgcred)));
-			goto next_error;
+			logmsgx("#%u cmsg_len %u != %zu "
+			    "(CMSG_LEN(sizeof(struct cmsgcred))", i,
+			    (u_int)cmptr->cmsg_len,
+			    CMSG_LEN(sizeof(struct cmsgcred)));
+			goto next;
 		}
 
-		cmcredptr = (const struct cmsgcred *)CMSG_DATA(cmptr);
+		cmcred = (struct cmsgcred *)CMSG_DATA(cmptr);
 
-		error2 = 0;
-		if (cmcredptr->cmcred_pid != client_pid) {
+		if (cmcred->cmcred_pid != client_pid) {
 			logmsgx("#%u cmcred_pid %ld != %ld (PID of client)",
-			    i, (long)cmcredptr->cmcred_pid, (long)client_pid);
-			error2 = 1;
+			    i, (long)cmcred->cmcred_pid, (long)client_pid);
+			goto next;
 		}
-		if (cmcredptr->cmcred_uid != my_uid) {
-			logmsgx("#%u cmcred_uid %lu != %lu (UID of current process)",
-			    i, (u_long)cmcredptr->cmcred_uid, (u_long)my_uid);
-			error2 = 1;
-		}
-		if (cmcredptr->cmcred_euid != my_euid) {
-			logmsgx("#%u cmcred_euid %lu != %lu (EUID of current process)",
-			    i, (u_long)cmcredptr->cmcred_euid, (u_long)my_euid);
-			error2 = 1;
-		}
-		if (cmcredptr->cmcred_gid != my_gid) {
-			logmsgx("#%u cmcred_gid %lu != %lu (GID of current process)",
-			    i, (u_long)cmcredptr->cmcred_gid, (u_long)my_gid);
-			error2 = 1;
+		if (cmcred->cmcred_uid != my_uid) {
+			logmsgx("#%u cmcred_uid %lu != %lu (UID of current "
+			    "process)", i, (u_long)cmcred->cmcred_uid,
+			    (u_long)my_uid);
+			goto next;
+		}
+		if (cmcred->cmcred_euid != my_euid) {
+			logmsgx("#%u cmcred_euid %lu != %lu (EUID of current "
+			    "process)", i, (u_long)cmcred->cmcred_euid,
+			    (u_long)my_euid);
+			goto next;
+		}
+		if (cmcred->cmcred_gid != my_gid) {
+			logmsgx("#%u cmcred_gid %lu != %lu (GID of current "
+			    "process)", i, (u_long)cmcred->cmcred_gid,
+			    (u_long)my_gid);
+			goto next;
 		}
-		if (cmcredptr->cmcred_ngroups == 0) {
+		if (cmcred->cmcred_ngroups == 0) {
 			logmsgx("#%u cmcred_ngroups = 0, this is wrong", i);
-			error2 = 1;
-		} else {
-			if (cmcredptr->cmcred_ngroups > NGROUPS_MAX) {
-				logmsgx("#%u cmcred_ngroups %d > %u (NGROUPS_MAX)",
-				    i, cmcredptr->cmcred_ngroups, NGROUPS_MAX);
-				error2 = 1;
-			} else if (cmcredptr->cmcred_ngroups < 0) {
-				logmsgx("#%u cmcred_ngroups %d < 0",
-				    i, cmcredptr->cmcred_ngroups);
-				error2 = 1;
-			} else {
-				dbgmsg(("#%u cmcred_ngroups = %d", i,
-				    cmcredptr->cmcred_ngroups));
-				if (cmcredptr->cmcred_groups[0] != my_egid) {
-					logmsgx("#%u cmcred_groups[0] %lu != %lu (EGID of current process)",
-					    i, (u_long)cmcredptr->cmcred_groups[0], (u_long)my_egid);
-					error2 = 1;
-				}
-				if (check_groups(cmcredptr->cmcred_groups + 1, cmcredptr->cmcred_ngroups - 1) < 0) {
-					logmsgx("#%u cmcred_groups has wrong GIDs", i);
-					error2 = 1;
-				}
-			}
+			goto next;
 		}
-
-		if (error2)
-			goto next_error;
-
-		if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) {
-			logmsgx("#%u control data has extra header", i);
-			goto next_error;
+		if (cmcred->cmcred_ngroups > NGROUPS_MAX) {
+			logmsgx("#%u cmcred_ngroups %d > %u (NGROUPS_MAX)",
+			    i, cmcred->cmcred_ngroups, NGROUPS_MAX);
+			goto next;
+		}
+		if (cmcred->cmcred_ngroups < 0) {
+			logmsgx("#%u cmcred_ngroups %d < 0", i,
+			    cmcred->cmcred_ngroups);
+			goto next;
+		}
+
+		dbgmsg(("#%u cmcred_ngroups = %d", i, cmcred->cmcred_ngroups));
+		if (cmcred->cmcred_groups[0] != my_egid) {
+			logmsgx("#%u cmcred_groups[0] %lu != %lu (EGID of "
+			    "current process)", i,
+			    (u_long)cmcred->cmcred_groups[0], (u_long)my_egid);
+			goto next;
+		}
+		if (check_groups(cmcred->cmcred_groups + 1,
+		    cmcred->cmcred_ngroups - 1) < 0) {
+			logmsgx("#%u cmcred_groups has wrong GIDs", i);
+			goto next;
+		}
+
+		if (CMSG_NXTHDR(&msg, cmptr) != NULL) {
+			logmsgx("#%u control data has extra header, this is "
+			    "wrong", i);
+			goto next;
 		}
-
 		continue;
-next_error:
+next:
 		error = -1;
 	}
 
 	if (sock_type == SOCK_STREAM)
-		if (close(fd2) < 0) {
-			logmsg("close");
-			return (-2);
-		}
+		if (close_socket((char *)NULL, fd2) < 0)
+			error = -2;
 	return (error);
-
-failed:
-	if (sock_type == SOCK_STREAM)
-		if (close(fd2) < 0)
-			logmsg("close");
-	return (-2);
 }
 
 static int
@@ -1018,45 +1036,35 @@
 {
 	int error, fd;
 
-	if ((fd = create_server_socket()) < 0)
+	fd = create_server_socket();
+	if (fd < 0)
 		return (-2);
 
+	error = -2;
+
 	if (sock_type == SOCK_STREAM)
 		if (listen(fd, LISTENQ) < 0) {
 			logmsg("listen");
-			goto failed;
+			goto done;
 		}
 
-	if ((client_pid = fork()) == (pid_t)-1) {
-		logmsg("fork");
-		goto failed;
-	}
+	if (fork_client() < 0)
+		goto done;
 
 	if (client_pid == 0) {
-		myname = "CLIENT";
-		if (close_socket((const char *)NULL, fd) < 0)
+		if (close_socket((char *)NULL, fd) < 0)
 			_exit(1);
 		t_cmsgcred_client(2);
 	}
 
-	if ((error = t_cmsgcred_server(fd)) == -2) {
-		(void)wait_client();
-		goto failed;
-	}
+	error = t_cmsgcred_server(fd);
 
 	if (wait_client() < 0)
-		goto failed;
-
-	if (close_socket(serv_sock_path, fd) < 0) {
-		logmsgx("close_socket failed");
-		return (-2);
-	}
-	return (error);
-
-failed:
+		error = -2;
+done:
 	if (close_socket(serv_sock_path, fd) < 0)
-		logmsgx("close_socket failed");
-	return (-2);
+		error = -2;
+	return (error);
 }
 
 /*
@@ -1067,20 +1075,23 @@
 {
 	struct msghdr msg;
 	struct iovec iov[1];
-	int fd;
 	u_int i;
+	int fd, error;
 
 	assert(type == 0 || type == 1);
 
-	if ((fd = create_unbound_socket()) < 0)
+	error = 1;
+
+	fd = create_unbound_socket();
+	if (fd < 0)
 		goto failed;
 
 	if (connect_server(fd) < 0)
-		goto failed_close;
+		goto done;
 
 	if (type == 1)
 		if (sync_recv(fd) < 0)
-			goto failed_close;
+			goto done;
 
 	iov[0].iov_base = ipc_message;
 	iov[0].iov_len = IPC_MESSAGE_SIZE;
@@ -1095,18 +1106,14 @@
 
 	for (i = 0; i < 2; ++i)
 		if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0)
-			goto failed_close;
-
-	if (close_socket((const char *)NULL, fd) < 0)
-		goto failed;
-
-	_exit(0);
-
-failed_close:
-	(void)close_socket((const char *)NULL, fd);
+			goto done;
 
+	error = 0;
+done:
+	if (close_socket((char *)NULL, fd) < 0)
+		error = 1;
 failed:
-	_exit(1);
+	_exit(error);
 }
 
 /*
@@ -1122,33 +1129,37 @@
 	char buf[IPC_MESSAGE_SIZE];
 	union {
 		struct cmsghdr	cm;
-		char	control[CMSG_SPACE(SOCKCREDSIZE(NGROUPS_MAX)) + EXTRA_CMSG_SPACE];
+		char	control[CMSG_SPACE(SOCKCREDSIZE(NGROUPS_MAX)) +
+				EXTRA_CMSG_SPACE];
 	} control_un;
 	struct msghdr msg;
 	struct iovec iov[1];
 	struct cmsghdr *cmptr;
 	const struct sockcred *sockcred;
-	int error, error2, fd2, optval;
 	u_int i;
+	int fd2, error, optval;
 
 	assert(n == 1 || n == 2);
 	assert(type == 0 || type == 1);
 
+	error = -2;
+
 	if (sock_type == SOCK_STREAM) {
-		if ((fd2 = accept_timeout(fd1)) < 0)
+		fd2 = accept_timeout(fd1);
+		if (fd2 < 0)
 			return (-2);
 		if (type == 1) {
 			optval = 1;
-			if (setsockopt(fd2, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) {
-				logmsg("setsockopt(LOCAL_CREDS) for accepted socket");
-				if (errno == ENOPROTOOPT) {
+			if (setsockopt(fd2, 0, LOCAL_CREDS, &optval,
+			    sizeof(optval)) < 0) {
+				logmsg("setsockopt(LOCAL_CREDS) for accepted "
+				    "socket");
+				if (errno == ENOPROTOOPT)
 					error = -1;
-					goto done_close;
-				}
-				goto failed;
+				goto done;
 			}
 			if (sync_send(fd2) < 0)
-				goto failed;
+				goto done;
 		}
 	} else
 		fd2 = fd1;
@@ -1157,132 +1168,131 @@
 
 	for (i = 0; i < n; ++i) {
 		iov[0].iov_base = buf;
-		iov[0].iov_len = sizeof buf;
+		iov[0].iov_len = sizeof(buf);
 
 		msg.msg_name = NULL;
 		msg.msg_namelen = 0;
 		msg.msg_iov = iov;
 		msg.msg_iovlen = 1;
 		msg.msg_control = control_un.control;
-		msg.msg_controllen = sizeof control_un.control;
+		msg.msg_controllen = sizeof(control_un.control);
 		msg.msg_flags = 0;
 
-		if (recvmsg_timeout(fd2, &msg, sizeof buf) < 0)
-			goto failed;
+		if (recvmsg_timeout(fd2, &msg, sizeof(buf)) < 0) {
+			error = -2;
+			break;
+		}
 
 		if (msg.msg_flags & MSG_CTRUNC) {
-			logmsgx("control data was truncated, MSG_CTRUNC flag is on");
-			goto next_error;
+			logmsgx("control data was truncated, MSG_CTRUNC flag "
+			    "is on");
+			goto next;
 		}
 
+		dbgmsg(("#%u msg_controllen = %u", i,
+		    (u_int)msg.msg_controllen));
+
 		if (i != 0 && sock_type == SOCK_STREAM) {
 			if (msg.msg_controllen != 0) {
-				logmsgx("second message has control data, this is wrong for stream sockets");
-				goto next_error;
+				logmsgx("second message has control data, "
+				    "this is wrong for stream sockets");
+				goto next;
 			}
-			dbgmsg(("#%u msg_controllen = %u", i,
-			    (u_int)msg.msg_controllen));
 			continue;
 		}
 
 		if (msg.msg_controllen < sizeof(struct cmsghdr)) {
-			logmsgx("#%u msg_controllen %u < %lu (sizeof(struct cmsghdr))",
-			    i, (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr));
-			goto next_error;
+			logmsgx("#%u msg_controllen %u < %zu "
+			    "(sizeof(struct cmsghdr))", i,
+			    (u_int)msg.msg_controllen, sizeof(struct cmsghdr));
+			goto next;
 		}
 
-		if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) {
+		cmptr = CMSG_FIRSTHDR(&msg);
+		if (cmptr == NULL) {
 			logmsgx("CMSG_FIRSTHDR is NULL");
-			goto next_error;
+			goto next;
 		}
 
-		dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i,
-		    (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
+		dbgmsg(("#%u cmsg_len = %u", i, (u_int)cmptr->cmsg_len));
 
 		if (cmptr->cmsg_level != SOL_SOCKET) {
 			logmsgx("#%u cmsg_level %d != SOL_SOCKET", i,
 			    cmptr->cmsg_level);
-			goto next_error;
+			goto next;
 		}
 
 		if (cmptr->cmsg_type != SCM_CREDS) {
 			logmsgx("#%u cmsg_type %d != SCM_CREDS", i,
 			    cmptr->cmsg_type);
-			goto next_error;
+			goto next;
 		}
 
 		if (cmptr->cmsg_len < CMSG_LEN(SOCKCREDSIZE(1))) {
-			logmsgx("#%u cmsg_len %u != %lu (CMSG_LEN(SOCKCREDSIZE(1)))",
-			    i, (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(SOCKCREDSIZE(1)));
-			goto next_error;
+			logmsgx("#%u cmsg_len %u != %zu "
+			    "(CMSG_LEN(SOCKCREDSIZE(1)))", i,
+			    (u_int)cmptr->cmsg_len, CMSG_LEN(SOCKCREDSIZE(1)));
+			goto next;
 		}
 
-		sockcred = (const struct sockcred *)CMSG_DATA(cmptr);
+		sockcred = (struct sockcred *)CMSG_DATA(cmptr);
 
-		error2 = 0;
 		if (sockcred->sc_uid != my_uid) {
-			logmsgx("#%u sc_uid %lu != %lu (UID of current process)",
-			    i, (u_long)sockcred->sc_uid, (u_long)my_uid);
-			error2 = 1;
+			logmsgx("#%u sc_uid %lu != %lu (UID of current "
+			    "process)", i, (u_long)sockcred->sc_uid,
+			    (u_long)my_uid);
+			goto next;
 		}
 		if (sockcred->sc_euid != my_euid) {
-			logmsgx("#%u sc_euid %lu != %lu (EUID of current process)",
-			    i, (u_long)sockcred->sc_euid, (u_long)my_euid);
-			error2 = 1;
+			logmsgx("#%u sc_euid %lu != %lu (EUID of current "
+			    "process)", i, (u_long)sockcred->sc_euid,
+			    (u_long)my_euid);
+			goto next;
 		}
 		if (sockcred->sc_gid != my_gid) {
-			logmsgx("#%u sc_gid %lu != %lu (GID of current process)",
-			    i, (u_long)sockcred->sc_gid, (u_long)my_gid);
-			error2 = 1;
+			logmsgx("#%u sc_gid %lu != %lu (GID of current "
+			    "process)", i, (u_long)sockcred->sc_gid,
+			    (u_long)my_gid);
+			goto next;
 		}
 		if (sockcred->sc_egid != my_egid) {
-			logmsgx("#%u sc_egid %lu != %lu (EGID of current process)",
-			    i, (u_long)sockcred->sc_gid, (u_long)my_egid);
-			error2 = 1;
+			logmsgx("#%u sc_egid %lu != %lu (EGID of current "
+			    "process)", i, (u_long)sockcred->sc_gid,
+			    (u_long)my_egid);
+			goto next;
 		}
 		if (sockcred->sc_ngroups > NGROUPS_MAX) {
 			logmsgx("#%u sc_ngroups %d > %u (NGROUPS_MAX)",
 			    i, sockcred->sc_ngroups, NGROUPS_MAX);
-			error2 = 1;
-		} else if (sockcred->sc_ngroups < 0) {
-			logmsgx("#%u sc_ngroups %d < 0",
-			    i, sockcred->sc_ngroups);
-			error2 = 1;
-		} else {
-			dbgmsg(("#%u sc_ngroups = %d", i, sockcred->sc_ngroups));
-			if (check_groups(sockcred->sc_groups, sockcred->sc_ngroups) < 0) {
-				logmsgx("#%u sc_groups has wrong GIDs", i);
-				error2 = 1;
-			}
+			goto next;
+		}
+		if (sockcred->sc_ngroups < 0) {
+			logmsgx("#%u sc_ngroups %d < 0", i,
+			    sockcred->sc_ngroups);
+			goto next;
 		}
 
-		if (error2)
-			goto next_error;
-
-		if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) {
-			logmsgx("#%u control data has extra header, this is wrong",
-			    i);
-			goto next_error;
+		dbgmsg(("#%u sc_ngroups = %d", i, sockcred->sc_ngroups));
+		if (check_groups(sockcred->sc_groups,
+		    sockcred->sc_ngroups) < 0) {
+			logmsgx("#%u sc_groups has wrong GIDs", i);
+			goto next;
 		}
 
+		if (CMSG_NXTHDR(&msg, cmptr) != NULL) {
+			logmsgx("#%u control data has extra header, this is "
+			    "wrong", i);
+			goto next;
+		}
 		continue;
-next_error:
+next:
 		error = -1;
 	}
-
-done_close:
+done:
 	if (sock_type == SOCK_STREAM)
-		if (close(fd2) < 0) {
-			logmsg("close");
-			return (-2);
-		}
+		if (close_socket((char *)NULL, fd2) < 0)
+			error = -2;
 	return (error);
-
-failed:
-	if (sock_type == SOCK_STREAM)
-		if (close(fd2) < 0)
-			logmsg("close");
-	return (-2);
 }
 
 static int
@@ -1292,59 +1302,47 @@
 
 	assert(type == 0 || type == 1);
 
-	if ((fd = create_server_socket()) < 0)
+	fd = create_server_socket();
+	if (fd < 0)
 		return (-2);
 
+	error = -2;
+
 	if (sock_type == SOCK_STREAM)
 		if (listen(fd, LISTENQ) < 0) {
 			logmsg("listen");
-			goto failed;
+			goto done;
 		}
 
 	if (type == 0) {
 		optval = 1;
-		if (setsockopt(fd, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) {
+		if (setsockopt(fd, 0, LOCAL_CREDS, &optval,
+		    sizeof(optval)) < 0) {
 			logmsg("setsockopt(LOCAL_CREDS) for %s socket",
-			    sock_type == SOCK_STREAM ? "stream listening" : "datagram");
-			if (errno == ENOPROTOOPT) {
+			    sock_type_str);
+			if (errno == ENOPROTOOPT)
 				error = -1;
-				goto done_close;
-			}
-			goto failed;
+			goto done;
 		}
 	}
 
-	if ((client_pid = fork()) == (pid_t)-1) {
-		logmsg("fork");
-		goto failed;
-	}
+	if (fork_client() < 0)
+		goto done;
 
 	if (client_pid == 0) {
-		myname = "CLIENT";
-		if (close_socket((const char *)NULL, fd) < 0)
+		if (close_socket((char *)NULL, fd) < 0)
 			_exit(1);
 		t_sockcred_client(type);
 	}
 
-	if ((error = t_sockcred_server(type, fd, 2)) == -2) {
-		(void)wait_client();
-		goto failed;
-	}
+	error = t_sockcred_server(type, fd, 2);
 
 	if (wait_client() < 0)
-		goto failed;
-
-done_close:
-	if (close_socket(serv_sock_path, fd) < 0) {
-		logmsgx("close_socket failed");
-		return (-2);
-	}
-	return (error);
-
-failed:
+		error = -2;
+done:
 	if (close_socket(serv_sock_path, fd) < 0)
-		logmsgx("close_socket failed");
-	return (-2);
+		error = -2;
+	return (error);
 }
 
 static int
@@ -1368,59 +1366,45 @@
 static int
 t_cmsgcred_sockcred(void)
 {
-	int error, fd, optval;
+	int fd, error, optval;
 
-	if ((fd = create_server_socket()) < 0)
+	fd = create_server_socket();
+	if (fd < 0)
 		return (-2);
 
+	error = -2;
+
 	if (sock_type == SOCK_STREAM)
 		if (listen(fd, LISTENQ) < 0) {
 			logmsg("listen");
-			goto failed;
+			goto done;
 		}
 
 	optval = 1;
-	if (setsockopt(fd, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) {
-		logmsg("setsockopt(LOCAL_CREDS) for %s socket",
-		    sock_type == SOCK_STREAM ? "stream listening" : "datagram");
-		if (errno == ENOPROTOOPT) {
+	if (setsockopt(fd, 0, LOCAL_CREDS, &optval, sizeof(optval)) < 0) {
+		logmsg("setsockopt(LOCAL_CREDS) for %s socket", sock_type_str);
+		if (errno == ENOPROTOOPT)
 			error = -1;
-			goto done_close;
-		}
-		goto failed;
+		goto done;
 	}
 
-	if ((client_pid = fork()) == (pid_t)-1) {
-		logmsg("fork");
-		goto failed;
-	}
+	if (fork_client() < 0)
+		goto done;
 
 	if (client_pid == 0) {
-		myname = "CLIENT";
-		if (close_socket((const char *)NULL, fd) < 0)
+		if (close_socket((char *)NULL, fd) < 0)
 			_exit(1);
 		t_cmsgcred_client(1);
 	}
 
-	if ((error = t_sockcred_server(0, fd, 1)) == -2) {
-		(void)wait_client();
-		goto failed;
-	}
+	error = t_sockcred_server(0, fd, 1);
 
 	if (wait_client() < 0)
-		goto failed;
-
-done_close:
-	if (close_socket(serv_sock_path, fd) < 0) {
-		logmsgx("close_socket failed");
-		return (-2);
-	}
-	return (error);
-
-failed:
+		error = -2;
+done:
 	if (close_socket(serv_sock_path, fd) < 0)
-		logmsgx("close_socket failed");
-	return (-2);
+		error = -2;
+	return (error);
 }
 
 /*
@@ -1437,13 +1421,16 @@
 	struct msghdr msg;
 	struct iovec iov[1];
 	struct cmsghdr *cmptr;
-	int fd;
+	int fd, error;
+
+	error = 1;
 
-	if ((fd = create_unbound_socket()) < 0)
+	fd = create_unbound_socket();
+	if (fd < 0)
 		goto failed;
 
 	if (connect_server(fd) < 0)
-		goto failed_close;
+		goto done;
 
 	iov[0].iov_base = ipc_message;
 	iov[0].iov_len = IPC_MESSAGE_SIZE;
@@ -1454,7 +1441,7 @@
 	msg.msg_iovlen = 1;
 	msg.msg_control = control_un.control;
 	msg.msg_controllen = no_control_data ?
-	    sizeof(struct cmsghdr) :sizeof control_un.control;
+	    sizeof(struct cmsghdr) : sizeof(control_un.control);
 	msg.msg_flags = 0;
 
 	cmptr = CMSG_FIRSTHDR(&msg);
@@ -1467,18 +1454,14 @@
 	    (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
 
 	if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0)
-		goto failed_close;
-
-	if (close_socket((const char *)NULL, fd) < 0)
-		goto failed;
-
-	_exit(0);
-
-failed_close:
-	(void)close_socket((const char *)NULL, fd);
+		goto done;
 
+	error = 0;
+done:
+	if (close_socket((char *)NULL, fd) < 0)
+		error = 1;
 failed:
-	_exit(1);
+	_exit(error);
 }
 
 /*
@@ -1490,34 +1473,38 @@
 {
 	union {
 		struct cmsghdr	cm;
-		char	control[CMSG_SPACE(sizeof(struct timeval)) + EXTRA_CMSG_SPACE];
+		char	control[CMSG_SPACE(sizeof(struct timeval)) +
+				EXTRA_CMSG_SPACE];
 	} control_un;
-	char buf[IPC_MESSAGE_SIZE];
-	int error, fd2;
 	struct msghdr msg;
 	struct iovec iov[1];
 	struct cmsghdr *cmptr;
 	const struct timeval *timeval;
+	int error, fd2;
+	char buf[IPC_MESSAGE_SIZE];
 
 	if (sock_type == SOCK_STREAM) {
-		if ((fd2 = accept_timeout(fd1)) < 0)
+		fd2 = accept_timeout(fd1);
+		if (fd2 < 0)
 			return (-2);
 	} else
 		fd2 = fd1;
 
 	iov[0].iov_base = buf;
-	iov[0].iov_len = sizeof buf;
+	iov[0].iov_len = sizeof(buf);
 
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
 	msg.msg_iov = iov;
 	msg.msg_iovlen = 1;
 	msg.msg_control = control_un.control;
-	msg.msg_controllen = sizeof control_un.control;;
+	msg.msg_controllen = sizeof(control_un.control);
 	msg.msg_flags = 0;
 
-	if (recvmsg_timeout(fd2, &msg, sizeof buf) < 0)
-		goto failed;
+	if (recvmsg_timeout(fd2, &msg, sizeof(buf)) < 0) {
+		error = -2;
+		goto done;
+	}
 
 	error = -1;
 
@@ -1527,12 +1514,13 @@
 	}
 
 	if (msg.msg_controllen < sizeof(struct cmsghdr)) {
-		logmsgx("msg_controllen %u < %lu (sizeof(struct cmsghdr))",
-		    (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr));
+		logmsgx("msg_controllen %u < %zu (sizeof(struct cmsghdr))",
+		    (u_int)msg.msg_controllen, sizeof(struct cmsghdr));
 		goto done;
 	}
 
-	if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) {
+	cmptr = CMSG_FIRSTHDR(&msg);
+	if (cmptr == NULL) {
 		logmsgx("CMSG_FIRSTHDR is NULL");
 		goto done;
 	}
@@ -1551,36 +1539,27 @@
 	}
 
 	if (cmptr->cmsg_len != CMSG_LEN(sizeof(struct timeval))) {
-		logmsgx("cmsg_len %u != %lu (CMSG_LEN(sizeof(struct timeval))",
-		    (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(sizeof(struct timeval)));
+		logmsgx("cmsg_len %u != %zu (CMSG_LEN(sizeof(struct timeval))",
+		    (u_int)cmptr->cmsg_len, CMSG_LEN(sizeof(struct timeval)));
 		goto done;
 	}
 
-	timeval = (const struct timeval *)CMSG_DATA(cmptr);
+	timeval = (struct timeval *)CMSG_DATA(cmptr);
 
 	dbgmsg(("timeval tv_sec %jd, tv_usec %jd",
 	    (intmax_t)timeval->tv_sec, (intmax_t)timeval->tv_usec));
 
-	if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) {
-		logmsgx("control data has extra header");
+	if (CMSG_NXTHDR(&msg, cmptr) != NULL) {
+		logmsgx("control data has extra header, this is wrong");
 		goto done;
 	}
 
 	error = 0;
-
 done:
 	if (sock_type == SOCK_STREAM)
-		if (close(fd2) < 0) {
-			logmsg("close");
-			return (-2);
-		}
+		if (close_socket((char *)NULL, fd2) < 0)
+			error = -2;
 	return (error);
-
-failed:
-	if (sock_type == SOCK_STREAM)
-		if (close(fd2) < 0)
-			logmsg("close");
-	return (-2);
 }
 
 static int
@@ -1588,43 +1567,174 @@
 {
 	int error, fd;
 
-	if ((fd = create_server_socket()) < 0)
+	fd = create_server_socket();
+	if (fd < 0)
 		return (-2);
 
+	error = -2;
+
 	if (sock_type == SOCK_STREAM)
 		if (listen(fd, LISTENQ) < 0) {
 			logmsg("listen");
-			goto failed;
+			goto done;
 		}
 
-	if ((client_pid = fork()) == (pid_t)-1) {
-		logmsg("fork");
-		goto failed;
-	}
+	if (fork_client() < 0)
+		goto done;
 
 	if (client_pid == 0) {
-		myname = "CLIENT";
-		if (close_socket((const char *)NULL, fd) < 0)
+		if (close_socket((char *)NULL, fd) < 0)
 			_exit(1);
 		t_timestamp_client();
 	}
 
-	if ((error = t_timestamp_server(fd)) == -2) {
-		(void)wait_client();
-		goto failed;
-	}
+	error = t_timestamp_server(fd);
 
 	if (wait_client() < 0)
+		error = -2;
+done:
+	if (close_socket(serv_sock_path, fd) < 0)
+		error = -2;
+	return (error);
+}
+
+/*
+ * Verify that xucred structure has correct credentials.
+ */
+static int
+check_xucred(const struct xucred *xuc)
+{
+	if (xuc->cr_version != XUCRED_VERSION) {
+		logmsgx("cr_version %u != %d (XUCRED_VERSION)",
+		    xuc->cr_version, XUCRED_VERSION);
+		return (-1);
+	}
+	if (xuc->cr_uid != my_euid) {
+		logmsgx("cr_uid %lu != %lu (EUID of current process)",
+		   (u_long)xuc->cr_uid, (u_long)my_euid);
+		return (-1);
+	}
+	if (xuc->cr_ngroups == 0) {
+		logmsgx("cr_ngroups = 0, this is wrong");
+		return (-1);
+	}
+	if (xuc->cr_ngroups > NGROUPS) {
+		logmsgx("cr_ngroups %hu > %d (NGROUPS)",
+		    xuc->cr_ngroups, NGROUPS);
+		return (-1);
+	}
+	if (xuc->cr_groups[0] != my_egid) {
+		logmsgx("cr_groups[0] %lu != %lu (EGID of current process)",
+		    (u_long)xuc->cr_groups[0], (u_long)my_egid);
+		return (-1);
+	}
+	if (check_groups(xuc->cr_groups + 1, xuc->cr_ngroups - 1) < 0) {
+		logmsgx("cr_groups has wrong GIDs");
+		return (-1);
+	}
+	return (0);
+}
+
+/*
+ * Connect to server and set LOCAL_PEERCRED socket option for connected
+ * socket.  Verify that credentials of the peer are correct.
+ */
+static void
+t_peercred_client(void)
+{
+	struct xucred xuc;
+	socklen_t len;
+	int fd, error;
+
+	error = 1;
+
+	fd = create_unbound_socket();
+	if (fd < 0)
 		goto failed;
 
-	if (close_socket(serv_sock_path, fd) < 0) {
-		logmsgx("close_socket failed");
+	if (connect_server(fd) < 0)
+		goto done;
+
+	len = sizeof(xuc);
+	if (getsockopt(fd, 0, LOCAL_PEERCRED, &xuc, &len) < 0) {
+		logmsg("getsockopt(LOCAL_PEERCRED)");
+		goto done;
+	}
+
+	if (check_xucred(&xuc) < 0)
+		goto done;
+done:
+	error = close_socket((char *)NULL, fd) < 0 ? 1 : 0;
+failed:
+	_exit(error);
+}
+
+/*
+ * Accept connection from client and set LOCAL_PEERCRED socket option for
+ * connected socket.  Verify that credentials of the peer are correct.
+ */
+static int
+t_peercred_server(int fd1)
+{
+	struct xucred xuc;
+	socklen_t len;
+	int fd2, error;
+
+	fd2 = accept_timeout(fd1);
+	if (fd2 < 0)
 		return (-2);
+
+	len = sizeof(xuc);
+	if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xuc, &len) < 0) {
+		logmsg("getsockopt(LOCAL_PEERCRED)");
+		error = -2;
+		goto done;
 	}
+
+	if (check_xucred(&xuc) < 0) {
+		error = -1;
+		goto done;
+	}
+
+	error = 0;
+done:
+	if (close_socket((char *)NULL, fd2) < 0)
+		error = -2;
 	return (error);
+}
 
-failed:
+static int
+t_peercred(void)
+{
+	int fd, error;
+
+	fd = create_server_socket();
+	if (fd < 0)
+		return (-2);
+
+	error = -2;
+
+	if (sock_type == SOCK_STREAM)
+		if (listen(fd, LISTENQ) < 0) {
+			logmsg("listen");
+			goto done;
+		}
+
+	if (fork_client() < 0)
+		goto done;
+
+	if (client_pid == 0) {
+		if (close_socket((char *)NULL, fd) < 0)
+			_exit(1);
+		t_peercred_client();
+	}
+
+	error = t_peercred_server(fd);
+
+	if (wait_client() < 0)
+		error = -2;
+done:
 	if (close_socket(serv_sock_path, fd) < 0)
-		logmsgx("close_socket failed");
-	return (-2);
+		error = -2;
+	return (error);
 }
diff -ruN unix_cmsg.orig/unix_cmsg.t unix_cmsg/unix_cmsg.t
--- unix_cmsg.orig/unix_cmsg.t	2006-05-29 21:40:55.000000000 +0300
+++ unix_cmsg/unix_cmsg.t	2009-01-30 15:44:49.000000000 +0200
@@ -23,14 +23,15 @@
 	done
 }
 
-echo "1..15"
+echo "1..16"
 
 for desc in \
 	"Sending, receiving cmsgcred" \
 	"Receiving sockcred (listening socket has LOCAL_CREDS) # TODO" \
 	"Receiving sockcred (accepted socket has LOCAL_CREDS) # TODO" \
 	"Sending cmsgcred, receiving sockcred # TODO" \
-	"Sending, receiving timestamp"
+	"Sending, receiving timestamp" \
+	"Check LOCAL_PEERCRED socket option"
 do
 	n=`expr ${n} + 1`
 	run ${n} stream "" ${n} "STREAM ${desc}"
@@ -48,10 +49,10 @@
 	run ${n} dgram "" ${i} "DGRAM ${desc}"
 done
 
-run 10 stream -z 1 "STREAM Sending, receiving cmsgcred (no control data)"
-run 11 stream -z 4 "STREAM Sending cmsgcred, receiving sockcred (no control data) # TODO"
-run 12 stream -z 5 "STREAM Sending, receiving timestamp (no control data)"
+run 11 stream -z 1 "STREAM Sending, receiving cmsgcred (no control data)"
+run 12 stream -z 4 "STREAM Sending cmsgcred, receiving sockcred (no control data) # TODO"
+run 13 stream -z 5 "STREAM Sending, receiving timestamp (no control data)"
 
-run 13 dgram -z 1 "DGRAM Sending, receiving cmsgcred (no control data)"
-run 14 dgram -z 3 "DGRAM Sending cmsgcred, receiving sockcred (no control data) # TODO"
-run 15 dgram -z 4 "DGRAM Sending, receiving timestamp (no control data)"
+run 14 dgram -z 1 "DGRAM Sending, receiving cmsgcred (no control data)"
+run 15 dgram -z 3 "DGRAM Sending cmsgcred, receiving sockcred (no control data) # TODO"
+run 16 dgram -z 4 "DGRAM Sending, receiving timestamp (no control data)"


More information about the freebsd-bugs mailing list