Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 13 Feb 2009 11:00:03 GMT
From:      Andrey Simonenko <simon@comsys.ntu-kpi.kiev.ua>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: bin/131567: Update for regression/sockets/unix_cmsg
Message-ID:  <200902131100.n1DB03uG079123@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/131567; it has been noted by GNATS.

From: Andrey Simonenko <simon@comsys.ntu-kpi.kiev.ua>
To: FreeBSD-gnats-submit@FreeBSD.org, freebsd-bugs@FreeBSD.org
Cc:  
Subject: Re: bin/131567: Update for regression/sockets/unix_cmsg
Date: Fri, 13 Feb 2009 12:57:23 +0200

 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)"



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200902131100.n1DB03uG079123>