aboutsummaryrefslogtreecommitdiff
path: root/tools/regression
diff options
context:
space:
mode:
authorMaxim Sobolev <sobomax@FreeBSD.org>2016-12-05 17:21:04 +0000
committerMaxim Sobolev <sobomax@FreeBSD.org>2016-12-05 17:21:04 +0000
commit1fab62b1e1d2e8667e1c7762d1d2b96bee4c8f0d (patch)
treef53e9f9d831558caea0b04833e5e104fa72e5604 /tools/regression
parent65d5084f54474900f7b41a325043cacf8a04bdcb (diff)
Notes
Diffstat (limited to 'tools/regression')
-rw-r--r--tools/regression/sockets/unix_cmsg/Makefile4
-rw-r--r--tools/regression/sockets/unix_cmsg/t_bintime.c156
-rw-r--r--tools/regression/sockets/unix_cmsg/t_bintime.h30
-rw-r--r--tools/regression/sockets/unix_cmsg/t_cmsg_len.c138
-rw-r--r--tools/regression/sockets/unix_cmsg/t_cmsg_len.h32
-rw-r--r--tools/regression/sockets/unix_cmsg/t_cmsgcred.c139
-rw-r--r--tools/regression/sockets/unix_cmsg/t_cmsgcred.h30
-rw-r--r--tools/regression/sockets/unix_cmsg/t_cmsgcred_sockcred.c125
-rw-r--r--tools/regression/sockets/unix_cmsg/t_cmsgcred_sockcred.h30
-rw-r--r--tools/regression/sockets/unix_cmsg/t_generic.c73
-rw-r--r--tools/regression/sockets/unix_cmsg/t_generic.h30
-rw-r--r--tools/regression/sockets/unix_cmsg/t_peercred.c153
-rw-r--r--tools/regression/sockets/unix_cmsg/t_peercred.h29
-rw-r--r--tools/regression/sockets/unix_cmsg/t_sockcred.c215
-rw-r--r--tools/regression/sockets/unix_cmsg/t_sockcred.h31
-rw-r--r--tools/regression/sockets/unix_cmsg/t_timeval.c155
-rw-r--r--tools/regression/sockets/unix_cmsg/t_timeval.h29
-rw-r--r--tools/regression/sockets/unix_cmsg/uc_common.c744
-rw-r--r--tools/regression/sockets/unix_cmsg/uc_common.h86
-rw-r--r--tools/regression/sockets/unix_cmsg/unix_cmsg.c1714
20 files changed, 2300 insertions, 1643 deletions
diff --git a/tools/regression/sockets/unix_cmsg/Makefile b/tools/regression/sockets/unix_cmsg/Makefile
index 9ccab6d2bd03..106798782941 100644
--- a/tools/regression/sockets/unix_cmsg/Makefile
+++ b/tools/regression/sockets/unix_cmsg/Makefile
@@ -1,6 +1,10 @@
# $FreeBSD$
PROG= unix_cmsg
+SRCS= unix_cmsg.c t_bintime.h t_bintime.c uc_common.h uc_common.c \
+ t_generic.h t_generic.c t_peercred.h t_peercred.c t_timeval.h \
+ t_timeval.c t_cmsgcred.h t_cmsgcred.c t_sockcred.h t_sockcred.c \
+ t_cmsgcred_sockcred.h t_cmsgcred_sockcred.c t_cmsg_len.h t_cmsg_len.c
MAN=
WARNS?= 3
diff --git a/tools/regression/sockets/unix_cmsg/t_bintime.c b/tools/regression/sockets/unix_cmsg/t_bintime.c
new file mode 100644
index 000000000000..4c3941370bea
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_bintime.c
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "t_bintime.h"
+#include "t_generic.h"
+#include "uc_common.h"
+
+static int
+check_scm_bintime(struct cmsghdr *cmsghdr)
+{
+ const struct bintime *bt;
+
+ if (uc_check_cmsghdr(cmsghdr, SCM_BINTIME, sizeof(struct bintime)) < 0)
+ return (-1);
+
+ bt = (struct bintime *)CMSG_DATA(cmsghdr);
+
+ uc_dbgmsg("bintime.sec %"PRIdMAX", bintime.frac %"PRIu64,
+ (intmax_t)bt->sec, bt->frac);
+
+ return (0);
+}
+
+static int
+t_bintime_client(int fd)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ void *cmsg_data;
+ size_t cmsg_size;
+ int rv;
+
+ if (uc_sync_recv() < 0)
+ return (-2);
+
+ rv = -2;
+
+ cmsg_size = CMSG_SPACE(sizeof(struct bintime));
+ cmsg_data = malloc(cmsg_size);
+ if (cmsg_data == NULL) {
+ uc_logmsg("malloc");
+ goto done;
+ }
+ uc_msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
+ SCM_BINTIME, sizeof(struct bintime));
+
+ if (uc_socket_connect(fd) < 0)
+ goto done;
+
+ if (uc_message_sendn(fd, &msghdr) < 0)
+ goto done;
+
+ rv = 0;
+done:
+ free(cmsg_data);
+ return (rv);
+}
+
+static int
+t_bintime_server(int fd1)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ struct cmsghdr *cmsghdr;
+ void *cmsg_data;
+ size_t cmsg_size;
+ u_int i;
+ int fd2, rv;
+
+ if (uc_sync_send() < 0)
+ return (-2);
+
+ fd2 = -1;
+ rv = -2;
+
+ cmsg_size = CMSG_SPACE(sizeof(struct bintime));
+ cmsg_data = malloc(cmsg_size);
+ if (cmsg_data == NULL) {
+ uc_logmsg("malloc");
+ goto done;
+ }
+
+ if (uc_cfg.sock_type == SOCK_STREAM) {
+ fd2 = uc_socket_accept(fd1);
+ if (fd2 < 0)
+ goto done;
+ } else
+ fd2 = fd1;
+
+ rv = -1;
+ for (i = 1; i <= uc_cfg.ipc_msg.msg_num; ++i) {
+ uc_dbgmsg("message #%u", i);
+
+ uc_msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
+ if (uc_message_recv(fd2, &msghdr) < 0) {
+ rv = -2;
+ break;
+ }
+
+ if (uc_check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
+ break;
+
+ cmsghdr = CMSG_FIRSTHDR(&msghdr);
+ if (check_scm_bintime(cmsghdr) < 0)
+ break;
+ }
+ if (i > uc_cfg.ipc_msg.msg_num)
+ rv = 0;
+done:
+ free(cmsg_data);
+ if (uc_cfg.sock_type == SOCK_STREAM && fd2 >= 0)
+ if (uc_socket_close(fd2) < 0)
+ rv = -2;
+ return (rv);
+}
+
+int
+t_bintime(void)
+{
+ return (t_generic(t_bintime_client, t_bintime_server));
+}
diff --git a/tools/regression/sockets/unix_cmsg/t_bintime.h b/tools/regression/sockets/unix_cmsg/t_bintime.h
new file mode 100644
index 000000000000..1fdfe1de7ec1
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_bintime.h
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * Copyright (c) 2016 Maksym Sobolyev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+int t_bintime(void);
diff --git a/tools/regression/sockets/unix_cmsg/t_cmsg_len.c b/tools/regression/sockets/unix_cmsg/t_cmsg_len.c
new file mode 100644
index 000000000000..3a88cebf1645
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_cmsg_len.c
@@ -0,0 +1,138 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "uc_common.h"
+#include "t_generic.h"
+#include "t_cmsg_len.h"
+
+#ifndef __LP64__
+static int
+t_cmsg_len_client(int fd)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ struct cmsghdr *cmsghdr;
+ void *cmsg_data;
+ size_t size, cmsg_size;
+ socklen_t socklen;
+ int rv;
+
+ if (uc_sync_recv() < 0)
+ return (-2);
+
+ rv = -2;
+
+ cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
+ cmsg_data = malloc(cmsg_size);
+ if (cmsg_data == NULL) {
+ uc_logmsg("malloc");
+ goto done;
+ }
+ uc_msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
+ SCM_CREDS, sizeof(struct cmsgcred));
+ cmsghdr = CMSG_FIRSTHDR(&msghdr);
+
+ if (uc_socket_connect(fd) < 0)
+ goto done;
+
+ size = msghdr.msg_iov != NULL ? msghdr.msg_iov->iov_len : 0;
+ rv = -1;
+ for (socklen = 0; socklen < CMSG_LEN(0); ++socklen) {
+ cmsghdr->cmsg_len = socklen;
+ uc_dbgmsg("send: data size %zu", size);
+ uc_dbgmsg("send: msghdr.msg_controllen %u",
+ (u_int)msghdr.msg_controllen);
+ uc_dbgmsg("send: cmsghdr.cmsg_len %u",
+ (u_int)cmsghdr->cmsg_len);
+ if (sendmsg(fd, &msghdr, 0) < 0) {
+ uc_dbgmsg("sendmsg(2) failed: %s; retrying",
+ strerror(errno));
+ continue;
+ }
+ uc_logmsgx("sent message with cmsghdr.cmsg_len %u < %u",
+ (u_int)cmsghdr->cmsg_len, (u_int)CMSG_LEN(0));
+ break;
+ }
+ if (socklen == CMSG_LEN(0))
+ rv = 0;
+
+ if (uc_sync_send() < 0) {
+ rv = -2;
+ goto done;
+ }
+done:
+ free(cmsg_data);
+ return (rv);
+}
+
+static int
+t_cmsg_len_server(int fd1)
+{
+ int fd2, rv;
+
+ if (uc_sync_send() < 0)
+ return (-2);
+
+ rv = -2;
+
+ if (uc_cfg.sock_type == SOCK_STREAM) {
+ fd2 = uc_socket_accept(fd1);
+ if (fd2 < 0)
+ goto done;
+ } else
+ fd2 = fd1;
+
+ if (uc_sync_recv() < 0)
+ goto done;
+
+ rv = 0;
+done:
+ if (uc_cfg.sock_type == SOCK_STREAM && fd2 >= 0)
+ if (uc_socket_close(fd2) < 0)
+ rv = -2;
+ return (rv);
+}
+
+int
+t_cmsg_len(void)
+{
+ return (t_generic(t_cmsg_len_client, t_cmsg_len_server));
+}
+#endif
diff --git a/tools/regression/sockets/unix_cmsg/t_cmsg_len.h b/tools/regression/sockets/unix_cmsg/t_cmsg_len.h
new file mode 100644
index 000000000000..5ec735144439
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_cmsg_len.h
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * Copyright (c) 2016 Maksym Sobolyev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LP64__
+int t_cmsg_len(void);
+#endif
diff --git a/tools/regression/sockets/unix_cmsg/t_cmsgcred.c b/tools/regression/sockets/unix_cmsg/t_cmsgcred.c
new file mode 100644
index 000000000000..3e3653c15179
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_cmsgcred.c
@@ -0,0 +1,139 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "uc_common.h"
+#include "t_generic.h"
+#include "t_cmsgcred.h"
+
+int
+t_cmsgcred_client(int fd)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ void *cmsg_data;
+ size_t cmsg_size;
+ int rv;
+
+ if (uc_sync_recv() < 0)
+ return (-2);
+
+ rv = -2;
+
+ cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
+ cmsg_data = malloc(cmsg_size);
+ if (cmsg_data == NULL) {
+ uc_logmsg("malloc");
+ goto done;
+ }
+ uc_msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
+ SCM_CREDS, sizeof(struct cmsgcred));
+
+ if (uc_socket_connect(fd) < 0)
+ goto done;
+
+ if (uc_message_sendn(fd, &msghdr) < 0)
+ goto done;
+
+ rv = 0;
+done:
+ free(cmsg_data);
+ return (rv);
+}
+
+static int
+t_cmsgcred_server(int fd1)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ struct cmsghdr *cmsghdr;
+ void *cmsg_data;
+ size_t cmsg_size;
+ u_int i;
+ int fd2, rv;
+
+ if (uc_sync_send() < 0)
+ return (-2);
+
+ fd2 = -1;
+ rv = -2;
+
+ cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
+ cmsg_data = malloc(cmsg_size);
+ if (cmsg_data == NULL) {
+ uc_logmsg("malloc");
+ goto done;
+ }
+
+ if (uc_cfg.sock_type == SOCK_STREAM) {
+ fd2 = uc_socket_accept(fd1);
+ if (fd2 < 0)
+ goto done;
+ } else
+ fd2 = fd1;
+
+ rv = -1;
+ for (i = 1; i <= uc_cfg.ipc_msg.msg_num; ++i) {
+ uc_dbgmsg("message #%u", i);
+
+ uc_msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
+ if (uc_message_recv(fd2, &msghdr) < 0) {
+ rv = -2;
+ break;
+ }
+
+ if (uc_check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
+ break;
+
+ cmsghdr = CMSG_FIRSTHDR(&msghdr);
+ if (uc_check_scm_creds_cmsgcred(cmsghdr) < 0)
+ break;
+ }
+ if (i > uc_cfg.ipc_msg.msg_num)
+ rv = 0;
+done:
+ free(cmsg_data);
+ if (uc_cfg.sock_type == SOCK_STREAM && fd2 >= 0)
+ if (uc_socket_close(fd2) < 0)
+ rv = -2;
+ return (rv);
+}
+
+int
+t_cmsgcred(void)
+{
+ return (t_generic(t_cmsgcred_client, t_cmsgcred_server));
+}
diff --git a/tools/regression/sockets/unix_cmsg/t_cmsgcred.h b/tools/regression/sockets/unix_cmsg/t_cmsgcred.h
new file mode 100644
index 000000000000..2aee226161df
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_cmsgcred.h
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+int t_cmsgcred_client(int fd);
+int t_cmsgcred(void);
diff --git a/tools/regression/sockets/unix_cmsg/t_cmsgcred_sockcred.c b/tools/regression/sockets/unix_cmsg/t_cmsgcred_sockcred.c
new file mode 100644
index 000000000000..72110b32af64
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_cmsgcred_sockcred.c
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "uc_common.h"
+#include "t_generic.h"
+#include "t_cmsgcred.h"
+#include "t_cmsgcred_sockcred.h"
+
+static int
+t_cmsgcred_sockcred_server(int fd1)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ struct cmsghdr *cmsghdr;
+ void *cmsg_data, *cmsg1_data, *cmsg2_data;
+ size_t cmsg_size, cmsg1_size, cmsg2_size;
+ u_int i;
+ int fd2, rv, val;
+
+ fd2 = -1;
+ rv = -2;
+
+ cmsg1_size = CMSG_SPACE(SOCKCREDSIZE(uc_cfg.proc_cred.gid_num));
+ cmsg2_size = CMSG_SPACE(sizeof(struct cmsgcred));
+ cmsg1_data = malloc(cmsg1_size);
+ cmsg2_data = malloc(cmsg2_size);
+ if (cmsg1_data == NULL || cmsg2_data == NULL) {
+ uc_logmsg("malloc");
+ goto done;
+ }
+
+ uc_dbgmsg("setting LOCAL_CREDS");
+ val = 1;
+ if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
+ uc_logmsg("setsockopt(LOCAL_CREDS)");
+ goto done;
+ }
+
+ if (uc_sync_send() < 0)
+ goto done;
+
+ if (uc_cfg.sock_type == SOCK_STREAM) {
+ fd2 = uc_socket_accept(fd1);
+ if (fd2 < 0)
+ goto done;
+ } else
+ fd2 = fd1;
+
+ cmsg_data = cmsg1_data;
+ cmsg_size = cmsg1_size;
+ rv = -1;
+ for (i = 1; i <= uc_cfg.ipc_msg.msg_num; ++i) {
+ uc_dbgmsg("message #%u", i);
+
+ uc_msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
+ if (uc_message_recv(fd2, &msghdr) < 0) {
+ rv = -2;
+ break;
+ }
+
+ if (uc_check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
+ break;
+
+ cmsghdr = CMSG_FIRSTHDR(&msghdr);
+ if (i == 1 || uc_cfg.sock_type == SOCK_DGRAM) {
+ if (uc_check_scm_creds_sockcred(cmsghdr) < 0)
+ break;
+ } else {
+ if (uc_check_scm_creds_cmsgcred(cmsghdr) < 0)
+ break;
+ }
+
+ cmsg_data = cmsg2_data;
+ cmsg_size = cmsg2_size;
+ }
+ if (i > uc_cfg.ipc_msg.msg_num)
+ rv = 0;
+done:
+ free(cmsg1_data);
+ free(cmsg2_data);
+ if (uc_cfg.sock_type == SOCK_STREAM && fd2 >= 0)
+ if (uc_socket_close(fd2) < 0)
+ rv = -2;
+ return (rv);
+}
+
+int
+t_cmsgcred_sockcred(void)
+{
+ return (t_generic(t_cmsgcred_client, t_cmsgcred_sockcred_server));
+}
diff --git a/tools/regression/sockets/unix_cmsg/t_cmsgcred_sockcred.h b/tools/regression/sockets/unix_cmsg/t_cmsgcred_sockcred.h
new file mode 100644
index 000000000000..df849c65afd7
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_cmsgcred_sockcred.h
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * Copyright (c) 2016 Maksym Sobolyev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+int t_cmsgcred_sockcred(void);
diff --git a/tools/regression/sockets/unix_cmsg/t_generic.c b/tools/regression/sockets/unix_cmsg/t_generic.c
new file mode 100644
index 000000000000..02a65255011d
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_generic.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include "uc_common.h"
+#include "t_generic.h"
+
+int
+t_generic(int (*client_func)(int), int (*server_func)(int))
+{
+ int fd, rv, rv_client;
+
+ switch (uc_client_fork()) {
+ case 0:
+ fd = uc_socket_create();
+ if (fd < 0)
+ rv = -2;
+ else {
+ rv = client_func(fd);
+ if (uc_socket_close(fd) < 0)
+ rv = -2;
+ }
+ uc_client_exit(rv);
+ break;
+ case 1:
+ fd = uc_socket_create();
+ if (fd < 0)
+ rv = -2;
+ else {
+ rv = server_func(fd);
+ rv_client = uc_client_wait();
+ if (rv == 0 || (rv == -2 && rv_client != 0))
+ rv = rv_client;
+ if (uc_socket_close(fd) < 0)
+ rv = -2;
+ }
+ break;
+ default:
+ rv = -2;
+ }
+ return (rv);
+}
diff --git a/tools/regression/sockets/unix_cmsg/t_generic.h b/tools/regression/sockets/unix_cmsg/t_generic.h
new file mode 100644
index 000000000000..a9b3d1be703c
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_generic.h
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * Copyright (c) 2016 Maksym Sobolyev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+int t_generic(int (*client_func)(int), int (*server_func)(int));
diff --git a/tools/regression/sockets/unix_cmsg/t_peercred.c b/tools/regression/sockets/unix_cmsg/t_peercred.c
new file mode 100644
index 000000000000..9b6e14868fcb
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_peercred.c
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ucred.h>
+#include <sys/un.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include "uc_common.h"
+#include "t_generic.h"
+#include "t_peercred.h"
+
+static int
+check_xucred(const struct xucred *xucred, socklen_t len)
+{
+ int rc;
+
+ if (len != sizeof(*xucred)) {
+ uc_logmsgx("option value size %zu != %zu",
+ (size_t)len, sizeof(*xucred));
+ return (-1);
+ }
+
+ uc_dbgmsg("xucred.cr_version %u", xucred->cr_version);
+ uc_dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid);
+ uc_dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups);
+
+ rc = 0;
+
+ if (xucred->cr_version != XUCRED_VERSION) {
+ uc_logmsgx("xucred.cr_version %u != %d",
+ xucred->cr_version, XUCRED_VERSION);
+ rc = -1;
+ }
+ if (xucred->cr_uid != uc_cfg.proc_cred.euid) {
+ uc_logmsgx("xucred.cr_uid %lu != %lu (EUID)",
+ (u_long)xucred->cr_uid, (u_long)uc_cfg.proc_cred.euid);
+ rc = -1;
+ }
+ if (xucred->cr_ngroups == 0) {
+ uc_logmsgx("xucred.cr_ngroups == 0");
+ rc = -1;
+ }
+ if (xucred->cr_ngroups < 0) {
+ uc_logmsgx("xucred.cr_ngroups < 0");
+ rc = -1;
+ }
+ if (xucred->cr_ngroups > XU_NGROUPS) {
+ uc_logmsgx("xucred.cr_ngroups %hu > %u (max)",
+ xucred->cr_ngroups, XU_NGROUPS);
+ rc = -1;
+ }
+ if (xucred->cr_groups[0] != uc_cfg.proc_cred.egid) {
+ uc_logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)",
+ (u_long)xucred->cr_groups[0], (u_long)uc_cfg.proc_cred.egid);
+ rc = -1;
+ }
+ if (uc_check_groups("xucred.cr_groups", xucred->cr_groups,
+ "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0)
+ rc = -1;
+ return (rc);
+}
+
+static int
+t_peercred_client(int fd)
+{
+ struct xucred xucred;
+ socklen_t len;
+
+ if (uc_sync_recv() < 0)
+ return (-1);
+
+ if (uc_socket_connect(fd) < 0)
+ return (-1);
+
+ len = sizeof(xucred);
+ if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
+ uc_logmsg("getsockopt(LOCAL_PEERCRED)");
+ return (-1);
+ }
+
+ if (check_xucred(&xucred, len) < 0)
+ return (-1);
+
+ return (0);
+}
+
+static int
+t_peercred_server(int fd1)
+{
+ struct xucred xucred;
+ socklen_t len;
+ int fd2, rv;
+
+ if (uc_sync_send() < 0)
+ return (-2);
+
+ fd2 = uc_socket_accept(fd1);
+ if (fd2 < 0)
+ return (-2);
+
+ len = sizeof(xucred);
+ if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
+ uc_logmsg("getsockopt(LOCAL_PEERCRED)");
+ rv = -2;
+ goto done;
+ }
+
+ if (check_xucred(&xucred, len) < 0) {
+ rv = -1;
+ goto done;
+ }
+
+ rv = 0;
+done:
+ if (uc_socket_close(fd2) < 0)
+ rv = -2;
+ return (rv);
+}
+
+int
+t_peercred(void)
+{
+ return (t_generic(t_peercred_client, t_peercred_server));
+}
diff --git a/tools/regression/sockets/unix_cmsg/t_peercred.h b/tools/regression/sockets/unix_cmsg/t_peercred.h
new file mode 100644
index 000000000000..1200734722ac
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_peercred.h
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+int t_peercred(void);
diff --git a/tools/regression/sockets/unix_cmsg/t_sockcred.c b/tools/regression/sockets/unix_cmsg/t_sockcred.c
new file mode 100644
index 000000000000..45ac5bfe823c
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_sockcred.c
@@ -0,0 +1,215 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "uc_common.h"
+#include "t_generic.h"
+#include "t_sockcred.h"
+
+static int
+t_sockcred_client(int type, int fd)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ int rv;
+
+ if (uc_sync_recv() < 0)
+ return (-2);
+
+ rv = -2;
+
+ uc_msghdr_init_client(&msghdr, iov, NULL, 0, 0, 0);
+
+ if (uc_socket_connect(fd) < 0)
+ goto done;
+
+ if (type == 2)
+ if (uc_sync_recv() < 0)
+ goto done;
+
+ if (uc_message_sendn(fd, &msghdr) < 0)
+ goto done;
+
+ rv = 0;
+done:
+ return (rv);
+}
+
+static int
+t_sockcred_server(int type, int fd1)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ struct cmsghdr *cmsghdr;
+ void *cmsg_data;
+ size_t cmsg_size;
+ u_int i;
+ int fd2, rv, val;
+
+ fd2 = -1;
+ rv = -2;
+
+ cmsg_size = CMSG_SPACE(SOCKCREDSIZE(uc_cfg.proc_cred.gid_num));
+ cmsg_data = malloc(cmsg_size);
+ if (cmsg_data == NULL) {
+ uc_logmsg("malloc");
+ goto done;
+ }
+
+ if (type == 1) {
+ uc_dbgmsg("setting LOCAL_CREDS");
+ val = 1;
+ if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
+ uc_logmsg("setsockopt(LOCAL_CREDS)");
+ goto done;
+ }
+ }
+
+ if (uc_sync_send() < 0)
+ goto done;
+
+ if (uc_cfg.sock_type == SOCK_STREAM) {
+ fd2 = uc_socket_accept(fd1);
+ if (fd2 < 0)
+ goto done;
+ } else
+ fd2 = fd1;
+
+ if (type == 2) {
+ uc_dbgmsg("setting LOCAL_CREDS");
+ val = 1;
+ if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
+ uc_logmsg("setsockopt(LOCAL_CREDS)");
+ goto done;
+ }
+ if (uc_sync_send() < 0)
+ goto done;
+ }
+
+ rv = -1;
+ for (i = 1; i <= uc_cfg.ipc_msg.msg_num; ++i) {
+ uc_dbgmsg("message #%u", i);
+
+ uc_msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
+ if (uc_message_recv(fd2, &msghdr) < 0) {
+ rv = -2;
+ break;
+ }
+
+ if (i > 1 && uc_cfg.sock_type == SOCK_STREAM) {
+ if (uc_check_msghdr(&msghdr, 0) < 0)
+ break;
+ } else {
+ if (uc_check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
+ break;
+
+ cmsghdr = CMSG_FIRSTHDR(&msghdr);
+ if (uc_check_scm_creds_sockcred(cmsghdr) < 0)
+ break;
+ }
+ }
+ if (i > uc_cfg.ipc_msg.msg_num)
+ rv = 0;
+done:
+ free(cmsg_data);
+ if (uc_cfg.sock_type == SOCK_STREAM && fd2 >= 0)
+ if (uc_socket_close(fd2) < 0)
+ rv = -2;
+ return (rv);
+}
+
+int
+t_sockcred_1(void)
+{
+ u_int i;
+ int fd, rv, rv_client;
+
+ switch (uc_client_fork()) {
+ case 0:
+ for (i = 1; i <= 2; ++i) {
+ uc_dbgmsg("client #%u", i);
+ fd = uc_socket_create();
+ if (fd < 0)
+ rv = -2;
+ else {
+ rv = t_sockcred_client(1, fd);
+ if (uc_socket_close(fd) < 0)
+ rv = -2;
+ }
+ if (rv != 0)
+ break;
+ }
+ uc_client_exit(rv);
+ break;
+ case 1:
+ fd = uc_socket_create();
+ if (fd < 0)
+ rv = -2;
+ else {
+ rv = t_sockcred_server(1, fd);
+ if (rv == 0)
+ rv = t_sockcred_server(3, fd);
+ rv_client = uc_client_wait();
+ if (rv == 0 || (rv == -2 && rv_client != 0))
+ rv = rv_client;
+ if (uc_socket_close(fd) < 0)
+ rv = -2;
+ }
+ break;
+ default:
+ rv = -2;
+ }
+
+ return (rv);
+}
+
+static int
+t_sockcred_2_client(int fd)
+{
+ return (t_sockcred_client(2, fd));
+}
+
+static int
+t_sockcred_2_server(int fd)
+{
+ return (t_sockcred_server(2, fd));
+}
+
+int
+t_sockcred_2(void)
+{
+ return (t_generic(t_sockcred_2_client, t_sockcred_2_server));
+}
diff --git a/tools/regression/sockets/unix_cmsg/t_sockcred.h b/tools/regression/sockets/unix_cmsg/t_sockcred.h
new file mode 100644
index 000000000000..c0c52b90fb65
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_sockcred.h
@@ -0,0 +1,31 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * Copyright (c) 2016 Maksym Sobolyev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+int t_sockcred_1(void);
+int t_sockcred_2(void);
diff --git a/tools/regression/sockets/unix_cmsg/t_timeval.c b/tools/regression/sockets/unix_cmsg/t_timeval.c
new file mode 100644
index 000000000000..4d4ab82cbcc0
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_timeval.c
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "uc_common.h"
+#include "t_generic.h"
+#include "t_timeval.h"
+
+static int
+check_scm_timestamp(struct cmsghdr *cmsghdr)
+{
+ const struct timeval *tv;
+
+ if (uc_check_cmsghdr(cmsghdr, SCM_TIMESTAMP, sizeof(struct timeval)) < 0)
+ return (-1);
+
+ tv = (struct timeval *)CMSG_DATA(cmsghdr);
+
+ uc_dbgmsg("timeval.tv_sec %"PRIdMAX", timeval.tv_usec %"PRIdMAX,
+ (intmax_t)tv->tv_sec, (intmax_t)tv->tv_usec);
+
+ return (0);
+}
+
+static int
+t_timeval_client(int fd)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ void *cmsg_data;
+ size_t cmsg_size;
+ int rv;
+
+ if (uc_sync_recv() < 0)
+ return (-2);
+
+ rv = -2;
+
+ cmsg_size = CMSG_SPACE(sizeof(struct timeval));
+ cmsg_data = malloc(cmsg_size);
+ if (cmsg_data == NULL) {
+ uc_logmsg("malloc");
+ goto done;
+ }
+ uc_msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
+ SCM_TIMESTAMP, sizeof(struct timeval));
+
+ if (uc_socket_connect(fd) < 0)
+ goto done;
+
+ if (uc_message_sendn(fd, &msghdr) < 0)
+ goto done;
+
+ rv = 0;
+done:
+ free(cmsg_data);
+ return (rv);
+}
+
+static int
+t_timeval_server(int fd1)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ struct cmsghdr *cmsghdr;
+ void *cmsg_data;
+ size_t cmsg_size;
+ u_int i;
+ int fd2, rv;
+
+ if (uc_sync_send() < 0)
+ return (-2);
+
+ fd2 = -1;
+ rv = -2;
+
+ cmsg_size = CMSG_SPACE(sizeof(struct timeval));
+ cmsg_data = malloc(cmsg_size);
+ if (cmsg_data == NULL) {
+ uc_logmsg("malloc");
+ goto done;
+ }
+
+ if (uc_cfg.sock_type == SOCK_STREAM) {
+ fd2 = uc_socket_accept(fd1);
+ if (fd2 < 0)
+ goto done;
+ } else
+ fd2 = fd1;
+
+ rv = -1;
+ for (i = 1; i <= uc_cfg.ipc_msg.msg_num; ++i) {
+ uc_dbgmsg("message #%u", i);
+
+ uc_msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
+ if (uc_message_recv(fd2, &msghdr) < 0) {
+ rv = -2;
+ break;
+ }
+
+ if (uc_check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
+ break;
+
+ cmsghdr = CMSG_FIRSTHDR(&msghdr);
+ if (check_scm_timestamp(cmsghdr) < 0)
+ break;
+ }
+ if (i > uc_cfg.ipc_msg.msg_num)
+ rv = 0;
+done:
+ free(cmsg_data);
+ if (uc_cfg.sock_type == SOCK_STREAM && fd2 >= 0)
+ if (uc_socket_close(fd2) < 0)
+ rv = -2;
+ return (rv);
+}
+
+int
+t_timeval(void)
+{
+ return (t_generic(t_timeval_client, t_timeval_server));
+}
diff --git a/tools/regression/sockets/unix_cmsg/t_timeval.h b/tools/regression/sockets/unix_cmsg/t_timeval.h
new file mode 100644
index 000000000000..081b4c2f01a0
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/t_timeval.h
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+int t_timeval(void);
diff --git a/tools/regression/sockets/unix_cmsg/uc_common.c b/tools/regression/sockets/unix_cmsg/uc_common.c
new file mode 100644
index 000000000000..0799df2e0d73
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/uc_common.c
@@ -0,0 +1,744 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <err.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "uc_common.h"
+
+#ifndef LISTENQ
+# define LISTENQ 1
+#endif
+
+#ifndef TIMEOUT
+# define TIMEOUT 2
+#endif
+
+#define SYNC_SERVER 0
+#define SYNC_CLIENT 1
+#define SYNC_RECV 0
+#define SYNC_SEND 1
+
+#define LOGMSG_SIZE 128
+
+void
+uc_output(const char *format, ...)
+{
+ char buf[LOGMSG_SIZE];
+ va_list ap;
+
+ va_start(ap, format);
+ if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
+ err(EXIT_FAILURE, "output: vsnprintf failed");
+ write(STDOUT_FILENO, buf, strlen(buf));
+ va_end(ap);
+}
+
+void
+uc_logmsg(const char *format, ...)
+{
+ char buf[LOGMSG_SIZE];
+ va_list ap;
+ int errno_save;
+
+ errno_save = errno;
+ va_start(ap, format);
+ if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
+ err(EXIT_FAILURE, "logmsg: vsnprintf failed");
+ if (errno_save == 0)
+ uc_output("%s: %s\n", uc_cfg.proc_name, buf);
+ else
+ uc_output("%s: %s: %s\n", uc_cfg.proc_name, buf,
+ strerror(errno_save));
+ va_end(ap);
+ errno = errno_save;
+}
+
+void
+uc_vlogmsgx(const char *format, va_list ap)
+{
+ char buf[LOGMSG_SIZE];
+
+ if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
+ err(EXIT_FAILURE, "uc_logmsgx: vsnprintf failed");
+ uc_output("%s: %s\n", uc_cfg.proc_name, buf);
+}
+
+void
+uc_logmsgx(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ uc_vlogmsgx(format, ap);
+ va_end(ap);
+}
+
+void
+uc_dbgmsg(const char *format, ...)
+{
+ va_list ap;
+
+ if (uc_cfg.debug) {
+ va_start(ap, format);
+ uc_vlogmsgx(format, ap);
+ va_end(ap);
+ }
+}
+
+int
+uc_socket_create(void)
+{
+ struct timeval tv;
+ int fd;
+
+ fd = socket(PF_LOCAL, uc_cfg.sock_type, 0);
+ if (fd < 0) {
+ uc_logmsg("socket_create: socket(PF_LOCAL, %s, 0)", uc_cfg.sock_type_str);
+ return (-1);
+ }
+ if (uc_cfg.server_flag)
+ uc_cfg.serv_sock_fd = fd;
+
+ tv.tv_sec = TIMEOUT;
+ tv.tv_usec = 0;
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 ||
+ setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
+ uc_logmsg("socket_create: setsockopt(SO_RCVTIMEO/SO_SNDTIMEO)");
+ goto failed;
+ }
+
+ if (uc_cfg.server_flag) {
+ if (bind(fd, (struct sockaddr *)&uc_cfg.serv_addr_sun,
+ uc_cfg.serv_addr_sun.sun_len) < 0) {
+ uc_logmsg("socket_create: bind(%s)",
+ uc_cfg.serv_addr_sun.sun_path);
+ goto failed;
+ }
+ if (uc_cfg.sock_type == SOCK_STREAM) {
+ int val;
+
+ if (listen(fd, LISTENQ) < 0) {
+ uc_logmsg("socket_create: listen");
+ goto failed;
+ }
+ val = fcntl(fd, F_GETFL, 0);
+ if (val < 0) {
+ uc_logmsg("socket_create: fcntl(F_GETFL)");
+ goto failed;
+ }
+ if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) {
+ uc_logmsg("socket_create: fcntl(F_SETFL)");
+ goto failed;
+ }
+ }
+ }
+
+ return (fd);
+
+failed:
+ if (close(fd) < 0)
+ uc_logmsg("socket_create: close");
+ if (uc_cfg.server_flag)
+ if (unlink(uc_cfg.serv_addr_sun.sun_path) < 0)
+ uc_logmsg("socket_close: unlink(%s)",
+ uc_cfg.serv_addr_sun.sun_path);
+ return (-1);
+}
+
+int
+uc_socket_close(int fd)
+{
+ int rv;
+
+ rv = 0;
+ if (close(fd) < 0) {
+ uc_logmsg("socket_close: close");
+ rv = -1;
+ }
+ if (uc_cfg.server_flag && fd == uc_cfg.serv_sock_fd)
+ if (unlink(uc_cfg.serv_addr_sun.sun_path) < 0) {
+ uc_logmsg("socket_close: unlink(%s)",
+ uc_cfg.serv_addr_sun.sun_path);
+ rv = -1;
+ }
+ return (rv);
+}
+
+int
+uc_socket_connect(int fd)
+{
+ uc_dbgmsg("connect");
+
+ if (connect(fd, (struct sockaddr *)&uc_cfg.serv_addr_sun,
+ uc_cfg.serv_addr_sun.sun_len) < 0) {
+ uc_logmsg("socket_connect: connect(%s)", uc_cfg.serv_addr_sun.sun_path);
+ return (-1);
+ }
+ return (0);
+}
+
+int
+uc_sync_recv(void)
+{
+ ssize_t ssize;
+ int fd;
+ char buf;
+
+ uc_dbgmsg("sync: wait");
+
+ fd = uc_cfg.sync_fd[uc_cfg.server_flag ? SYNC_SERVER : SYNC_CLIENT][SYNC_RECV];
+
+ ssize = read(fd, &buf, 1);
+ if (ssize < 0) {
+ uc_logmsg("sync_recv: read");
+ return (-1);
+ }
+ if (ssize < 1) {
+ uc_logmsgx("sync_recv: read %zd of 1 byte", ssize);
+ return (-1);
+ }
+
+ uc_dbgmsg("sync: received");
+
+ return (0);
+}
+
+int
+uc_sync_send(void)
+{
+ ssize_t ssize;
+ int fd;
+
+ uc_dbgmsg("sync: send");
+
+ fd = uc_cfg.sync_fd[uc_cfg.server_flag ? SYNC_CLIENT : SYNC_SERVER][SYNC_SEND];
+
+ ssize = write(fd, "", 1);
+ if (ssize < 0) {
+ uc_logmsg("uc_sync_send: write");
+ return (-1);
+ }
+ if (ssize < 1) {
+ uc_logmsgx("uc_sync_send: sent %zd of 1 byte", ssize);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+uc_message_send(int fd, const struct msghdr *msghdr)
+{
+ const struct cmsghdr *cmsghdr;
+ size_t size;
+ ssize_t ssize;
+
+ size = msghdr->msg_iov != 0 ? msghdr->msg_iov->iov_len : 0;
+ uc_dbgmsg("send: data size %zu", size);
+ uc_dbgmsg("send: msghdr.msg_controllen %u",
+ (u_int)msghdr->msg_controllen);
+ cmsghdr = CMSG_FIRSTHDR(msghdr);
+ if (cmsghdr != NULL)
+ uc_dbgmsg("send: cmsghdr.cmsg_len %u",
+ (u_int)cmsghdr->cmsg_len);
+
+ ssize = sendmsg(fd, msghdr, 0);
+ if (ssize < 0) {
+ uc_logmsg("message_send: sendmsg");
+ return (-1);
+ }
+ if ((size_t)ssize != size) {
+ uc_logmsgx("message_send: sendmsg: sent %zd of %zu bytes",
+ ssize, size);
+ return (-1);
+ }
+
+ if (!uc_cfg.send_data_flag)
+ if (uc_sync_send() < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+uc_message_sendn(int fd, struct msghdr *msghdr)
+{
+ u_int i;
+
+ for (i = 1; i <= uc_cfg.ipc_msg.msg_num; ++i) {
+ uc_dbgmsg("message #%u", i);
+ if (uc_message_send(fd, msghdr) < 0)
+ return (-1);
+ }
+ return (0);
+}
+
+int
+uc_message_recv(int fd, struct msghdr *msghdr)
+{
+ const struct cmsghdr *cmsghdr;
+ size_t size;
+ ssize_t ssize;
+
+ if (!uc_cfg.send_data_flag)
+ if (uc_sync_recv() < 0)
+ return (-1);
+
+ size = msghdr->msg_iov != NULL ? msghdr->msg_iov->iov_len : 0;
+ ssize = recvmsg(fd, msghdr, MSG_WAITALL);
+ if (ssize < 0) {
+ uc_logmsg("message_recv: recvmsg");
+ return (-1);
+ }
+ if ((size_t)ssize != size) {
+ uc_logmsgx("message_recv: recvmsg: received %zd of %zu bytes",
+ ssize, size);
+ return (-1);
+ }
+
+ uc_dbgmsg("recv: data size %zd", ssize);
+ uc_dbgmsg("recv: msghdr.msg_controllen %u",
+ (u_int)msghdr->msg_controllen);
+ cmsghdr = CMSG_FIRSTHDR(msghdr);
+ if (cmsghdr != NULL)
+ uc_dbgmsg("recv: cmsghdr.cmsg_len %u",
+ (u_int)cmsghdr->cmsg_len);
+
+ if (memcmp(uc_cfg.ipc_msg.buf_recv, uc_cfg.ipc_msg.buf_send, size) != 0) {
+ uc_logmsgx("message_recv: received message has wrong content");
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+uc_socket_accept(int listenfd)
+{
+ fd_set rset;
+ struct timeval tv;
+ int fd, rv, val;
+
+ uc_dbgmsg("accept");
+
+ FD_ZERO(&rset);
+ FD_SET(listenfd, &rset);
+ tv.tv_sec = TIMEOUT;
+ tv.tv_usec = 0;
+ rv = select(listenfd + 1, &rset, (fd_set *)NULL, (fd_set *)NULL, &tv);
+ if (rv < 0) {
+ uc_logmsg("socket_accept: select");
+ return (-1);
+ }
+ if (rv == 0) {
+ uc_logmsgx("socket_accept: select timeout");
+ return (-1);
+ }
+
+ fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL);
+ if (fd < 0) {
+ uc_logmsg("socket_accept: accept");
+ return (-1);
+ }
+
+ val = fcntl(fd, F_GETFL, 0);
+ if (val < 0) {
+ uc_logmsg("socket_accept: fcntl(F_GETFL)");
+ goto failed;
+ }
+ if (fcntl(fd, F_SETFL, val & ~O_NONBLOCK) < 0) {
+ uc_logmsg("socket_accept: fcntl(F_SETFL)");
+ goto failed;
+ }
+
+ return (fd);
+
+failed:
+ if (close(fd) < 0)
+ uc_logmsg("socket_accept: close");
+ return (-1);
+}
+
+int
+uc_check_msghdr(const struct msghdr *msghdr, size_t size)
+{
+ if (msghdr->msg_flags & MSG_TRUNC) {
+ uc_logmsgx("msghdr.msg_flags has MSG_TRUNC");
+ return (-1);
+ }
+ if (msghdr->msg_flags & MSG_CTRUNC) {
+ uc_logmsgx("msghdr.msg_flags has MSG_CTRUNC");
+ return (-1);
+ }
+ if (msghdr->msg_controllen < size) {
+ uc_logmsgx("msghdr.msg_controllen %u < %zu",
+ (u_int)msghdr->msg_controllen, size);
+ return (-1);
+ }
+ if (msghdr->msg_controllen > 0 && size == 0) {
+ uc_logmsgx("msghdr.msg_controllen %u > 0",
+ (u_int)msghdr->msg_controllen);
+ return (-1);
+ }
+ return (0);
+}
+
+int
+uc_check_cmsghdr(const struct cmsghdr *cmsghdr, int type, size_t size)
+{
+ if (cmsghdr == NULL) {
+ uc_logmsgx("cmsghdr is NULL");
+ return (-1);
+ }
+ if (cmsghdr->cmsg_level != SOL_SOCKET) {
+ uc_logmsgx("cmsghdr.cmsg_level %d != SOL_SOCKET",
+ cmsghdr->cmsg_level);
+ return (-1);
+ }
+ if (cmsghdr->cmsg_type != type) {
+ uc_logmsgx("cmsghdr.cmsg_type %d != %d",
+ cmsghdr->cmsg_type, type);
+ return (-1);
+ }
+ if (cmsghdr->cmsg_len != CMSG_LEN(size)) {
+ uc_logmsgx("cmsghdr.cmsg_len %u != %zu",
+ (u_int)cmsghdr->cmsg_len, CMSG_LEN(size));
+ return (-1);
+ }
+ return (0);
+}
+
+static void
+uc_msghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data)
+{
+ msghdr->msg_name = NULL;
+ msghdr->msg_namelen = 0;
+ if (uc_cfg.send_data_flag) {
+ iov->iov_base = uc_cfg.server_flag ?
+ uc_cfg.ipc_msg.buf_recv : uc_cfg.ipc_msg.buf_send;
+ iov->iov_len = uc_cfg.ipc_msg.buf_size;
+ msghdr->msg_iov = iov;
+ msghdr->msg_iovlen = 1;
+ } else {
+ msghdr->msg_iov = NULL;
+ msghdr->msg_iovlen = 0;
+ }
+ msghdr->msg_control = cmsg_data;
+ msghdr->msg_flags = 0;
+}
+
+void
+uc_msghdr_init_server(struct msghdr *msghdr, struct iovec *iov,
+ void *cmsg_data, size_t cmsg_size)
+{
+ uc_msghdr_init_generic(msghdr, iov, cmsg_data);
+ msghdr->msg_controllen = cmsg_size;
+ uc_dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ?
+ msghdr->msg_iov->iov_len : (size_t)0);
+ uc_dbgmsg("init: msghdr.msg_controllen %u",
+ (u_int)msghdr->msg_controllen);
+}
+
+void
+uc_msghdr_init_client(struct msghdr *msghdr, struct iovec *iov,
+ void *cmsg_data, size_t cmsg_size, int type, size_t arr_size)
+{
+ struct cmsghdr *cmsghdr;
+
+ uc_msghdr_init_generic(msghdr, iov, cmsg_data);
+ if (cmsg_data != NULL) {
+ if (uc_cfg.send_array_flag)
+ uc_dbgmsg("sending an array");
+ else
+ uc_dbgmsg("sending a scalar");
+ msghdr->msg_controllen = uc_cfg.send_array_flag ?
+ cmsg_size : CMSG_SPACE(0);
+ cmsghdr = CMSG_FIRSTHDR(msghdr);
+ cmsghdr->cmsg_level = SOL_SOCKET;
+ cmsghdr->cmsg_type = type;
+ cmsghdr->cmsg_len = CMSG_LEN(uc_cfg.send_array_flag ? arr_size : 0);
+ } else
+ msghdr->msg_controllen = 0;
+}
+
+int
+uc_client_fork(void)
+{
+ int fd1, fd2;
+
+ if (pipe(uc_cfg.sync_fd[SYNC_SERVER]) < 0 ||
+ pipe(uc_cfg.sync_fd[SYNC_CLIENT]) < 0) {
+ uc_logmsg("client_fork: pipe");
+ return (-1);
+ }
+ uc_cfg.client_pid = fork();
+ if (uc_cfg.client_pid == (pid_t)-1) {
+ uc_logmsg("client_fork: fork");
+ return (-1);
+ }
+ if (uc_cfg.client_pid == 0) {
+ uc_cfg.proc_name = "CLIENT";
+ uc_cfg.server_flag = false;
+ fd1 = uc_cfg.sync_fd[SYNC_SERVER][SYNC_RECV];
+ fd2 = uc_cfg.sync_fd[SYNC_CLIENT][SYNC_SEND];
+ } else {
+ fd1 = uc_cfg.sync_fd[SYNC_SERVER][SYNC_SEND];
+ fd2 = uc_cfg.sync_fd[SYNC_CLIENT][SYNC_RECV];
+ }
+ if (close(fd1) < 0 || close(fd2) < 0) {
+ uc_logmsg("client_fork: close");
+ return (-1);
+ }
+ return (uc_cfg.client_pid != 0);
+}
+
+void
+uc_client_exit(int rv)
+{
+ if (close(uc_cfg.sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 ||
+ close(uc_cfg.sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) {
+ uc_logmsg("client_exit: close");
+ rv = -1;
+ }
+ rv = rv == 0 ? EXIT_SUCCESS : -rv;
+ uc_dbgmsg("exit: code %d", rv);
+ _exit(rv);
+}
+
+int
+uc_client_wait(void)
+{
+ int status;
+ pid_t pid;
+
+ uc_dbgmsg("waiting for client");
+
+ if (close(uc_cfg.sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 ||
+ close(uc_cfg.sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) {
+ uc_logmsg("client_wait: close");
+ return (-1);
+ }
+
+ pid = waitpid(uc_cfg.client_pid, &status, 0);
+ if (pid == (pid_t)-1) {
+ uc_logmsg("client_wait: waitpid");
+ return (-1);
+ }
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != EXIT_SUCCESS) {
+ uc_logmsgx("client exit status is %d",
+ WEXITSTATUS(status));
+ return (-WEXITSTATUS(status));
+ }
+ } else {
+ if (WIFSIGNALED(status))
+ uc_logmsgx("abnormal termination of client, signal %d%s",
+ WTERMSIG(status), WCOREDUMP(status) ?
+ " (core file generated)" : "");
+ else
+ uc_logmsgx("termination of client, unknown status");
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+uc_check_groups(const char *gid_arr_str, const gid_t *gid_arr,
+ const char *gid_num_str, int gid_num, bool all_gids)
+{
+ int i;
+
+ for (i = 0; i < gid_num; ++i)
+ uc_dbgmsg("%s[%d] %lu", gid_arr_str, i, (u_long)gid_arr[i]);
+
+ if (all_gids) {
+ if (gid_num != uc_cfg.proc_cred.gid_num) {
+ uc_logmsgx("%s %d != %d", gid_num_str, gid_num,
+ uc_cfg.proc_cred.gid_num);
+ return (-1);
+ }
+ } else {
+ if (gid_num > uc_cfg.proc_cred.gid_num) {
+ uc_logmsgx("%s %d > %d", gid_num_str, gid_num,
+ uc_cfg.proc_cred.gid_num);
+ return (-1);
+ }
+ }
+ if (memcmp(gid_arr, uc_cfg.proc_cred.gid_arr,
+ gid_num * sizeof(*gid_arr)) != 0) {
+ uc_logmsgx("%s content is wrong", gid_arr_str);
+ for (i = 0; i < gid_num; ++i)
+ if (gid_arr[i] != uc_cfg.proc_cred.gid_arr[i]) {
+ uc_logmsgx("%s[%d] %lu != %lu",
+ gid_arr_str, i, (u_long)gid_arr[i],
+ (u_long)uc_cfg.proc_cred.gid_arr[i]);
+ break;
+ }
+ return (-1);
+ }
+ return (0);
+}
+
+int
+uc_check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr)
+{
+ const struct cmsgcred *cmcred;
+ int rc;
+
+ if (uc_check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(struct cmsgcred)) < 0)
+ return (-1);
+
+ cmcred = (struct cmsgcred *)CMSG_DATA(cmsghdr);
+
+ uc_dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmcred->cmcred_pid);
+ uc_dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmcred->cmcred_uid);
+ uc_dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmcred->cmcred_euid);
+ uc_dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmcred->cmcred_gid);
+ uc_dbgmsg("cmsgcred.cmcred_ngroups %d", cmcred->cmcred_ngroups);
+
+ rc = 0;
+
+ if (cmcred->cmcred_pid != uc_cfg.client_pid) {
+ uc_logmsgx("cmsgcred.cmcred_pid %ld != %ld",
+ (long)cmcred->cmcred_pid, (long)uc_cfg.client_pid);
+ rc = -1;
+ }
+ if (cmcred->cmcred_uid != uc_cfg.proc_cred.uid) {
+ uc_logmsgx("cmsgcred.cmcred_uid %lu != %lu",
+ (u_long)cmcred->cmcred_uid, (u_long)uc_cfg.proc_cred.uid);
+ rc = -1;
+ }
+ if (cmcred->cmcred_euid != uc_cfg.proc_cred.euid) {
+ uc_logmsgx("cmsgcred.cmcred_euid %lu != %lu",
+ (u_long)cmcred->cmcred_euid, (u_long)uc_cfg.proc_cred.euid);
+ rc = -1;
+ }
+ if (cmcred->cmcred_gid != uc_cfg.proc_cred.gid) {
+ uc_logmsgx("cmsgcred.cmcred_gid %lu != %lu",
+ (u_long)cmcred->cmcred_gid, (u_long)uc_cfg.proc_cred.gid);
+ rc = -1;
+ }
+ if (cmcred->cmcred_ngroups == 0) {
+ uc_logmsgx("cmsgcred.cmcred_ngroups == 0");
+ rc = -1;
+ }
+ if (cmcred->cmcred_ngroups < 0) {
+ uc_logmsgx("cmsgcred.cmcred_ngroups %d < 0",
+ cmcred->cmcred_ngroups);
+ rc = -1;
+ }
+ if (cmcred->cmcred_ngroups > CMGROUP_MAX) {
+ uc_logmsgx("cmsgcred.cmcred_ngroups %d > %d",
+ cmcred->cmcred_ngroups, CMGROUP_MAX);
+ rc = -1;
+ }
+ if (cmcred->cmcred_groups[0] != uc_cfg.proc_cred.egid) {
+ uc_logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)",
+ (u_long)cmcred->cmcred_groups[0], (u_long)uc_cfg.proc_cred.egid);
+ rc = -1;
+ }
+ if (uc_check_groups("cmsgcred.cmcred_groups", cmcred->cmcred_groups,
+ "cmsgcred.cmcred_ngroups", cmcred->cmcred_ngroups, false) < 0)
+ rc = -1;
+ return (rc);
+}
+
+int
+uc_check_scm_creds_sockcred(struct cmsghdr *cmsghdr)
+{
+ const struct sockcred *sc;
+ int rc;
+
+ if (uc_check_cmsghdr(cmsghdr, SCM_CREDS,
+ SOCKCREDSIZE(uc_cfg.proc_cred.gid_num)) < 0)
+ return (-1);
+
+ sc = (struct sockcred *)CMSG_DATA(cmsghdr);
+
+ rc = 0;
+
+ uc_dbgmsg("sockcred.sc_uid %lu", (u_long)sc->sc_uid);
+ uc_dbgmsg("sockcred.sc_euid %lu", (u_long)sc->sc_euid);
+ uc_dbgmsg("sockcred.sc_gid %lu", (u_long)sc->sc_gid);
+ uc_dbgmsg("sockcred.sc_egid %lu", (u_long)sc->sc_egid);
+ uc_dbgmsg("sockcred.sc_ngroups %d", sc->sc_ngroups);
+
+ if (sc->sc_uid != uc_cfg.proc_cred.uid) {
+ uc_logmsgx("sockcred.sc_uid %lu != %lu",
+ (u_long)sc->sc_uid, (u_long)uc_cfg.proc_cred.uid);
+ rc = -1;
+ }
+ if (sc->sc_euid != uc_cfg.proc_cred.euid) {
+ uc_logmsgx("sockcred.sc_euid %lu != %lu",
+ (u_long)sc->sc_euid, (u_long)uc_cfg.proc_cred.euid);
+ rc = -1;
+ }
+ if (sc->sc_gid != uc_cfg.proc_cred.gid) {
+ uc_logmsgx("sockcred.sc_gid %lu != %lu",
+ (u_long)sc->sc_gid, (u_long)uc_cfg.proc_cred.gid);
+ rc = -1;
+ }
+ if (sc->sc_egid != uc_cfg.proc_cred.egid) {
+ uc_logmsgx("sockcred.sc_egid %lu != %lu",
+ (u_long)sc->sc_egid, (u_long)uc_cfg.proc_cred.egid);
+ rc = -1;
+ }
+ if (sc->sc_ngroups == 0) {
+ uc_logmsgx("sockcred.sc_ngroups == 0");
+ rc = -1;
+ }
+ if (sc->sc_ngroups < 0) {
+ uc_logmsgx("sockcred.sc_ngroups %d < 0",
+ sc->sc_ngroups);
+ rc = -1;
+ }
+ if (sc->sc_ngroups != uc_cfg.proc_cred.gid_num) {
+ uc_logmsgx("sockcred.sc_ngroups %d != %u",
+ sc->sc_ngroups, uc_cfg.proc_cred.gid_num);
+ rc = -1;
+ }
+ if (uc_check_groups("sockcred.sc_groups", sc->sc_groups,
+ "sockcred.sc_ngroups", sc->sc_ngroups, true) < 0)
+ rc = -1;
+ return (rc);
+}
diff --git a/tools/regression/sockets/unix_cmsg/uc_common.h b/tools/regression/sockets/unix_cmsg/uc_common.h
new file mode 100644
index 000000000000..5e119cabc7e9
--- /dev/null
+++ b/tools/regression/sockets/unix_cmsg/uc_common.h
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2005 Andrey Simonenko
+ * Copyright (c) 2016 Maksym Sobolyev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+struct uc_cfg {
+ int sock_type;
+ const char *sock_type_str;
+ bool debug;
+ const char *proc_name;
+ int sync_fd[2][2];
+ int serv_sock_fd;
+ bool server_flag;
+ bool send_data_flag;
+ struct sockaddr_un serv_addr_sun;
+ bool send_array_flag;
+ pid_t client_pid;
+ struct {
+ char *buf_send;
+ char *buf_recv;
+ size_t buf_size;
+ u_int msg_num;
+ } ipc_msg;
+ struct {
+ uid_t uid;
+ uid_t euid;
+ gid_t gid;
+ gid_t egid;
+ gid_t *gid_arr;
+ int gid_num;
+ } proc_cred;
+};
+
+extern struct uc_cfg uc_cfg;
+
+int uc_check_msghdr(const struct msghdr *msghdr, size_t size);
+int uc_check_cmsghdr(const struct cmsghdr *cmsghdr, int type, size_t size);
+void uc_output(const char *format, ...) __printflike(1, 2);
+void uc_logmsgx(const char *format, ...) __printflike(1, 2);
+void uc_dbgmsg(const char *format, ...) __printflike(1, 2);
+void uc_logmsg(const char *format, ...) __printflike(1, 2);
+void uc_vlogmsgx(const char *format, va_list ap);
+int uc_message_recv(int fd, struct msghdr *msghdr);
+int uc_message_send(int fd, const struct msghdr *msghdr);
+int uc_message_sendn(int fd, struct msghdr *msghdr);
+void uc_msghdr_init_server(struct msghdr *msghdr, struct iovec *iov,
+ void *cmsg_data, size_t cmsg_size);
+void uc_msghdr_init_client(struct msghdr *msghdr, struct iovec *iov,
+ void *cmsg_data, size_t cmsg_size, int type, size_t arr_size);
+int uc_socket_create(void);
+int uc_socket_accept(int listenfd);
+int uc_socket_close(int fd);
+int uc_socket_connect(int fd);
+int uc_sync_recv(void);
+int uc_sync_send(void);
+int uc_client_fork(void);
+void uc_client_exit(int rv);
+int uc_client_wait(void);
+int uc_check_groups(const char *gid_arr_str, const gid_t *gid_arr,
+ const char *gid_num_str, int gid_num, bool all_gids);
+int uc_check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr);
+int uc_check_scm_creds_sockcred(struct cmsghdr *cmsghdr);
diff --git a/tools/regression/sockets/unix_cmsg/unix_cmsg.c b/tools/regression/sockets/unix_cmsg/unix_cmsg.c
index 7f6b45cf4270..7ce138b0e406 100644
--- a/tools/regression/sockets/unix_cmsg/unix_cmsg.c
+++ b/tools/regression/sockets/unix_cmsg/unix_cmsg.c
@@ -27,31 +27,32 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/param.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/limits.h>
#include <sys/socket.h>
-#include <sys/ucred.h>
#include <sys/un.h>
-#include <sys/wait.h>
-#include <ctype.h>
#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
#include <inttypes.h>
-#include <limits.h>
#include <paths.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include "uc_common.h"
+#include "t_cmsgcred.h"
+#include "t_bintime.h"
+#include "t_generic.h"
+#include "t_peercred.h"
+#include "t_timeval.h"
+#include "t_sockcred.h"
+#include "t_cmsgcred_sockcred.h"
+#include "t_cmsg_len.h"
+
/*
* There are tables with tests descriptions and pointers to test
* functions. Each t_*() function returns 0 if its test passed,
@@ -69,29 +70,6 @@ __FBSDID("$FreeBSD$");
* with a non-zero return code.
*/
-#ifndef LISTENQ
-# define LISTENQ 1
-#endif
-
-#ifndef TIMEOUT
-# define TIMEOUT 2
-#endif
-
-static int t_cmsgcred(void);
-static int t_sockcred_1(void);
-static int t_sockcred_2(void);
-static int t_cmsgcred_sockcred(void);
-static int t_timeval(void);
-static int t_bintime(void);
-/*
- * The testcase fails on 64-bit architectures (amd64), but passes on 32-bit
- * architectures (i386); see bug 206543
- */
-#ifndef __LP64__
-static int t_cmsg_len(void);
-#endif
-static int t_peercred(void);
-
struct test_func {
int (*func)(void);
const char *desc;
@@ -126,6 +104,10 @@ static const struct test_func test_stream_tbl[] = {
.func = t_bintime,
.desc = "Sending, receiving bintime"
},
+/*
+ * The testcase fails on 64-bit architectures (amd64), but passes on 32-bit
+ * architectures (i386); see bug 206543
+ */
#ifndef __LP64__
{
.func = t_cmsg_len,
@@ -177,58 +159,17 @@ static const struct test_func test_dgram_tbl[] = {
#define TEST_DGRAM_TBL_SIZE \
(sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0]))
-static bool debug = false;
-static bool server_flag = true;
-static bool send_data_flag = true;
-static bool send_array_flag = true;
static bool failed_flag = false;
-static int sock_type;
-static const char *sock_type_str;
-
-static const char *proc_name;
+struct uc_cfg uc_cfg;
static char work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX";
-static int serv_sock_fd;
-static struct sockaddr_un serv_addr_sun;
-
-static struct {
- char *buf_send;
- char *buf_recv;
- size_t buf_size;
- u_int msg_num;
-} ipc_msg;
#define IPC_MSG_NUM_DEF 5
#define IPC_MSG_NUM_MAX 10
#define IPC_MSG_SIZE_DEF 7
#define IPC_MSG_SIZE_MAX 128
-static struct {
- uid_t uid;
- uid_t euid;
- gid_t gid;
- gid_t egid;
- gid_t *gid_arr;
- int gid_num;
-} proc_cred;
-
-static pid_t client_pid;
-
-#define SYNC_SERVER 0
-#define SYNC_CLIENT 1
-#define SYNC_RECV 0
-#define SYNC_SEND 1
-
-static int sync_fd[2][2];
-
-#define LOGMSG_SIZE 128
-
-static void logmsg(const char *, ...) __printflike(1, 2);
-static void logmsgx(const char *, ...) __printflike(1, 2);
-static void dbgmsg(const char *, ...) __printflike(1, 2);
-static void output(const char *, ...) __printflike(1, 2);
-
static void
usage(bool verbose)
{
@@ -255,84 +196,19 @@ usage(bool verbose)
printf(" %u: %s\n", i, test_dgram_tbl[i].desc);
}
-static void
-output(const char *format, ...)
-{
- char buf[LOGMSG_SIZE];
- va_list ap;
-
- va_start(ap, format);
- if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
- err(EXIT_FAILURE, "output: vsnprintf failed");
- write(STDOUT_FILENO, buf, strlen(buf));
- va_end(ap);
-}
-
-static void
-logmsg(const char *format, ...)
-{
- char buf[LOGMSG_SIZE];
- va_list ap;
- int errno_save;
-
- errno_save = errno;
- va_start(ap, format);
- if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
- err(EXIT_FAILURE, "logmsg: vsnprintf failed");
- if (errno_save == 0)
- output("%s: %s\n", proc_name, buf);
- else
- output("%s: %s: %s\n", proc_name, buf, strerror(errno_save));
- va_end(ap);
- errno = errno_save;
-}
-
-static void
-vlogmsgx(const char *format, va_list ap)
-{
- char buf[LOGMSG_SIZE];
-
- if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
- err(EXIT_FAILURE, "logmsgx: vsnprintf failed");
- output("%s: %s\n", proc_name, buf);
-
-}
-
-static void
-logmsgx(const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- vlogmsgx(format, ap);
- va_end(ap);
-}
-
-static void
-dbgmsg(const char *format, ...)
-{
- va_list ap;
-
- if (debug) {
- va_start(ap, format);
- vlogmsgx(format, ap);
- va_end(ap);
- }
-}
-
static int
run_tests(int type, u_int testno1)
{
const struct test_func *tf;
u_int i, testno2, failed_num;
- sock_type = type;
+ uc_cfg.sock_type = type;
if (type == SOCK_STREAM) {
- sock_type_str = "SOCK_STREAM";
+ uc_cfg.sock_type_str = "SOCK_STREAM";
tf = test_stream_tbl;
i = TEST_STREAM_TBL_SIZE - 1;
} else {
- sock_type_str = "SOCK_DGRAM";
+ uc_cfg.sock_type_str = "SOCK_DGRAM";
tf = test_dgram_tbl;
i = TEST_DGRAM_TBL_SIZE - 1;
}
@@ -342,16 +218,16 @@ run_tests(int type, u_int testno1)
} else
testno2 = testno1;
- output("Running tests for %s sockets:\n", sock_type_str);
+ uc_output("Running tests for %s sockets:\n", uc_cfg.sock_type_str);
failed_num = 0;
for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) {
- output(" %u: %s\n", i, tf->desc);
+ uc_output(" %u: %s\n", i, tf->desc);
switch (tf->func()) {
case -1:
++failed_num;
break;
case -2:
- logmsgx("some system error or timeout occurred");
+ uc_logmsgx("some system error or timeout occurred");
return (-1);
}
}
@@ -361,15 +237,15 @@ run_tests(int type, u_int testno1)
if (testno1 != testno2) {
if (failed_num == 0)
- output("-- all tests passed!\n");
+ uc_output("-- all tests passed!\n");
else
- output("-- %u test%s failed!\n",
+ uc_output("-- %u test%s failed!\n",
failed_num, failed_num == 1 ? "" : "s");
} else {
if (failed_num == 0)
- output("-- test passed!\n");
+ uc_output("-- test passed!\n");
else
- output("-- test failed!\n");
+ uc_output("-- test failed!\n");
}
return (0);
@@ -382,145 +258,62 @@ init(void)
size_t idx;
int rv;
- proc_name = "SERVER";
+ uc_cfg.proc_name = "SERVER";
sigact.sa_handler = SIG_IGN;
sigact.sa_flags = 0;
sigemptyset(&sigact.sa_mask);
if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) {
- logmsg("init: sigaction");
+ uc_logmsg("init: sigaction");
return (-1);
}
- if (ipc_msg.buf_size == 0)
- ipc_msg.buf_send = ipc_msg.buf_recv = NULL;
+ if (uc_cfg.ipc_msg.buf_size == 0)
+ uc_cfg.ipc_msg.buf_send = uc_cfg.ipc_msg.buf_recv = NULL;
else {
- ipc_msg.buf_send = malloc(ipc_msg.buf_size);
- ipc_msg.buf_recv = malloc(ipc_msg.buf_size);
- if (ipc_msg.buf_send == NULL || ipc_msg.buf_recv == NULL) {
- logmsg("init: malloc");
+ uc_cfg.ipc_msg.buf_send = malloc(uc_cfg.ipc_msg.buf_size);
+ uc_cfg.ipc_msg.buf_recv = malloc(uc_cfg.ipc_msg.buf_size);
+ if (uc_cfg.ipc_msg.buf_send == NULL || uc_cfg.ipc_msg.buf_recv == NULL) {
+ uc_logmsg("init: malloc");
return (-1);
}
- for (idx = 0; idx < ipc_msg.buf_size; ++idx)
- ipc_msg.buf_send[idx] = (char)idx;
+ for (idx = 0; idx < uc_cfg.ipc_msg.buf_size; ++idx)
+ uc_cfg.ipc_msg.buf_send[idx] = (char)idx;
}
- proc_cred.uid = getuid();
- proc_cred.euid = geteuid();
- proc_cred.gid = getgid();
- proc_cred.egid = getegid();
- proc_cred.gid_num = getgroups(0, (gid_t *)NULL);
- if (proc_cred.gid_num < 0) {
- logmsg("init: getgroups");
+ uc_cfg.proc_cred.uid = getuid();
+ uc_cfg.proc_cred.euid = geteuid();
+ uc_cfg.proc_cred.gid = getgid();
+ uc_cfg.proc_cred.egid = getegid();
+ uc_cfg.proc_cred.gid_num = getgroups(0, (gid_t *)NULL);
+ if (uc_cfg.proc_cred.gid_num < 0) {
+ uc_logmsg("init: getgroups");
return (-1);
}
- proc_cred.gid_arr = malloc(proc_cred.gid_num *
- sizeof(*proc_cred.gid_arr));
- if (proc_cred.gid_arr == NULL) {
- logmsg("init: malloc");
+ uc_cfg.proc_cred.gid_arr = malloc(uc_cfg.proc_cred.gid_num *
+ sizeof(*uc_cfg.proc_cred.gid_arr));
+ if (uc_cfg.proc_cred.gid_arr == NULL) {
+ uc_logmsg("init: malloc");
return (-1);
}
- if (getgroups(proc_cred.gid_num, proc_cred.gid_arr) < 0) {
- logmsg("init: getgroups");
+ if (getgroups(uc_cfg.proc_cred.gid_num, uc_cfg.proc_cred.gid_arr) < 0) {
+ uc_logmsg("init: getgroups");
return (-1);
}
- memset(&serv_addr_sun, 0, sizeof(serv_addr_sun));
- rv = snprintf(serv_addr_sun.sun_path, sizeof(serv_addr_sun.sun_path),
- "%s/%s", work_dir, proc_name);
+ memset(&uc_cfg.serv_addr_sun, 0, sizeof(uc_cfg.serv_addr_sun));
+ rv = snprintf(uc_cfg.serv_addr_sun.sun_path, sizeof(uc_cfg.serv_addr_sun.sun_path),
+ "%s/%s", work_dir, uc_cfg.proc_name);
if (rv < 0) {
- logmsg("init: snprintf");
- return (-1);
- }
- if ((size_t)rv >= sizeof(serv_addr_sun.sun_path)) {
- logmsgx("init: not enough space for socket pathname");
- return (-1);
- }
- serv_addr_sun.sun_family = PF_LOCAL;
- serv_addr_sun.sun_len = SUN_LEN(&serv_addr_sun);
-
- return (0);
-}
-
-static int
-client_fork(void)
-{
- int fd1, fd2;
-
- if (pipe(sync_fd[SYNC_SERVER]) < 0 ||
- pipe(sync_fd[SYNC_CLIENT]) < 0) {
- logmsg("client_fork: pipe");
- return (-1);
- }
- client_pid = fork();
- if (client_pid == (pid_t)-1) {
- logmsg("client_fork: fork");
- return (-1);
- }
- if (client_pid == 0) {
- proc_name = "CLIENT";
- server_flag = false;
- fd1 = sync_fd[SYNC_SERVER][SYNC_RECV];
- fd2 = sync_fd[SYNC_CLIENT][SYNC_SEND];
- } else {
- fd1 = sync_fd[SYNC_SERVER][SYNC_SEND];
- fd2 = sync_fd[SYNC_CLIENT][SYNC_RECV];
- }
- if (close(fd1) < 0 || close(fd2) < 0) {
- logmsg("client_fork: close");
- return (-1);
- }
- return (client_pid != 0);
-}
-
-static void
-client_exit(int rv)
-{
- if (close(sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 ||
- close(sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) {
- logmsg("client_exit: close");
- rv = -1;
- }
- rv = rv == 0 ? EXIT_SUCCESS : -rv;
- dbgmsg("exit: code %d", rv);
- _exit(rv);
-}
-
-static int
-client_wait(void)
-{
- int status;
- pid_t pid;
-
- dbgmsg("waiting for client");
-
- if (close(sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 ||
- close(sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) {
- logmsg("client_wait: close");
+ uc_logmsg("init: snprintf");
return (-1);
}
-
- pid = waitpid(client_pid, &status, 0);
- if (pid == (pid_t)-1) {
- logmsg("client_wait: waitpid");
- return (-1);
- }
-
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) != EXIT_SUCCESS) {
- logmsgx("client exit status is %d",
- WEXITSTATUS(status));
- return (-WEXITSTATUS(status));
- }
- } else {
- if (WIFSIGNALED(status))
- logmsgx("abnormal termination of client, signal %d%s",
- WTERMSIG(status), WCOREDUMP(status) ?
- " (core file generated)" : "");
- else
- logmsgx("termination of client, unknown status");
+ if ((size_t)rv >= sizeof(uc_cfg.serv_addr_sun.sun_path)) {
+ uc_logmsgx("init: not enough space for socket pathname");
return (-1);
}
+ uc_cfg.serv_addr_sun.sun_family = PF_LOCAL;
+ uc_cfg.serv_addr_sun.sun_len = SUN_LEN(&uc_cfg.serv_addr_sun);
return (0);
}
@@ -533,26 +326,31 @@ main(int argc, char *argv[])
int opt, rv;
bool dgram_flag, stream_flag;
- ipc_msg.buf_size = IPC_MSG_SIZE_DEF;
- ipc_msg.msg_num = IPC_MSG_NUM_DEF;
+ memset(&uc_cfg, '\0', sizeof(uc_cfg));
+ uc_cfg.debug = false;
+ uc_cfg.server_flag = true;
+ uc_cfg.send_data_flag = true;
+ uc_cfg.send_array_flag = true;
+ uc_cfg.ipc_msg.buf_size = IPC_MSG_SIZE_DEF;
+ uc_cfg.ipc_msg.msg_num = IPC_MSG_NUM_DEF;
dgram_flag = stream_flag = false;
while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1)
switch (opt) {
case 'd':
- debug = true;
+ uc_cfg.debug = true;
break;
case 'h':
usage(true);
return (EXIT_SUCCESS);
case 'n':
- ipc_msg.msg_num = strtonum(optarg, 1,
+ uc_cfg.ipc_msg.msg_num = strtonum(optarg, 1,
IPC_MSG_NUM_MAX, &errstr);
if (errstr != NULL)
errx(EXIT_FAILURE, "option -n: number is %s",
errstr);
break;
case 's':
- ipc_msg.buf_size = strtonum(optarg, 0,
+ uc_cfg.ipc_msg.buf_size = strtonum(optarg, 0,
IPC_MSG_SIZE_MAX, &errstr);
if (errstr != NULL)
errx(EXIT_FAILURE, "option -s: number is %s",
@@ -573,9 +371,9 @@ main(int argc, char *argv[])
errx(EXIT_FAILURE, "option -z: number is %s",
errstr);
if (zvalue & 0x1)
- send_data_flag = false;
+ uc_cfg.send_data_flag = false;
if (zvalue & 0x2)
- send_array_flag = false;
+ uc_cfg.send_array_flag = false;
break;
default:
usage(false);
@@ -621,1378 +419,8 @@ main(int argc, char *argv[])
rv = EXIT_SUCCESS;
done:
if (rmdir(work_dir) < 0) {
- logmsg("rmdir(%s)", work_dir);
+ uc_logmsg("rmdir(%s)", work_dir);
rv = EXIT_FAILURE;
}
return (failed_flag ? EXIT_FAILURE : rv);
}
-
-static int
-socket_close(int fd)
-{
- int rv;
-
- rv = 0;
- if (close(fd) < 0) {
- logmsg("socket_close: close");
- rv = -1;
- }
- if (server_flag && fd == serv_sock_fd)
- if (unlink(serv_addr_sun.sun_path) < 0) {
- logmsg("socket_close: unlink(%s)",
- serv_addr_sun.sun_path);
- rv = -1;
- }
- return (rv);
-}
-
-static int
-socket_create(void)
-{
- struct timeval tv;
- int fd;
-
- fd = socket(PF_LOCAL, sock_type, 0);
- if (fd < 0) {
- logmsg("socket_create: socket(PF_LOCAL, %s, 0)", sock_type_str);
- return (-1);
- }
- if (server_flag)
- serv_sock_fd = fd;
-
- tv.tv_sec = TIMEOUT;
- tv.tv_usec = 0;
- if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 ||
- setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
- logmsg("socket_create: setsockopt(SO_RCVTIMEO/SO_SNDTIMEO)");
- goto failed;
- }
-
- if (server_flag) {
- if (bind(fd, (struct sockaddr *)&serv_addr_sun,
- serv_addr_sun.sun_len) < 0) {
- logmsg("socket_create: bind(%s)",
- serv_addr_sun.sun_path);
- goto failed;
- }
- if (sock_type == SOCK_STREAM) {
- int val;
-
- if (listen(fd, LISTENQ) < 0) {
- logmsg("socket_create: listen");
- goto failed;
- }
- val = fcntl(fd, F_GETFL, 0);
- if (val < 0) {
- logmsg("socket_create: fcntl(F_GETFL)");
- goto failed;
- }
- if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) {
- logmsg("socket_create: fcntl(F_SETFL)");
- goto failed;
- }
- }
- }
-
- return (fd);
-
-failed:
- if (close(fd) < 0)
- logmsg("socket_create: close");
- if (server_flag)
- if (unlink(serv_addr_sun.sun_path) < 0)
- logmsg("socket_close: unlink(%s)",
- serv_addr_sun.sun_path);
- return (-1);
-}
-
-static int
-socket_connect(int fd)
-{
- dbgmsg("connect");
-
- if (connect(fd, (struct sockaddr *)&serv_addr_sun,
- serv_addr_sun.sun_len) < 0) {
- logmsg("socket_connect: connect(%s)", serv_addr_sun.sun_path);
- return (-1);
- }
- return (0);
-}
-
-static int
-sync_recv(void)
-{
- ssize_t ssize;
- int fd;
- char buf;
-
- dbgmsg("sync: wait");
-
- fd = sync_fd[server_flag ? SYNC_SERVER : SYNC_CLIENT][SYNC_RECV];
-
- ssize = read(fd, &buf, 1);
- if (ssize < 0) {
- logmsg("sync_recv: read");
- return (-1);
- }
- if (ssize < 1) {
- logmsgx("sync_recv: read %zd of 1 byte", ssize);
- return (-1);
- }
-
- dbgmsg("sync: received");
-
- return (0);
-}
-
-static int
-sync_send(void)
-{
- ssize_t ssize;
- int fd;
-
- dbgmsg("sync: send");
-
- fd = sync_fd[server_flag ? SYNC_CLIENT : SYNC_SERVER][SYNC_SEND];
-
- ssize = write(fd, "", 1);
- if (ssize < 0) {
- logmsg("sync_send: write");
- return (-1);
- }
- if (ssize < 1) {
- logmsgx("sync_send: sent %zd of 1 byte", ssize);
- return (-1);
- }
-
- return (0);
-}
-
-static int
-message_send(int fd, const struct msghdr *msghdr)
-{
- const struct cmsghdr *cmsghdr;
- size_t size;
- ssize_t ssize;
-
- size = msghdr->msg_iov != 0 ? msghdr->msg_iov->iov_len : 0;
- dbgmsg("send: data size %zu", size);
- dbgmsg("send: msghdr.msg_controllen %u",
- (u_int)msghdr->msg_controllen);
- cmsghdr = CMSG_FIRSTHDR(msghdr);
- if (cmsghdr != NULL)
- dbgmsg("send: cmsghdr.cmsg_len %u",
- (u_int)cmsghdr->cmsg_len);
-
- ssize = sendmsg(fd, msghdr, 0);
- if (ssize < 0) {
- logmsg("message_send: sendmsg");
- return (-1);
- }
- if ((size_t)ssize != size) {
- logmsgx("message_send: sendmsg: sent %zd of %zu bytes",
- ssize, size);
- return (-1);
- }
-
- if (!send_data_flag)
- if (sync_send() < 0)
- return (-1);
-
- return (0);
-}
-
-static int
-message_sendn(int fd, struct msghdr *msghdr)
-{
- u_int i;
-
- for (i = 1; i <= ipc_msg.msg_num; ++i) {
- dbgmsg("message #%u", i);
- if (message_send(fd, msghdr) < 0)
- return (-1);
- }
- return (0);
-}
-
-static int
-message_recv(int fd, struct msghdr *msghdr)
-{
- const struct cmsghdr *cmsghdr;
- size_t size;
- ssize_t ssize;
-
- if (!send_data_flag)
- if (sync_recv() < 0)
- return (-1);
-
- size = msghdr->msg_iov != NULL ? msghdr->msg_iov->iov_len : 0;
- ssize = recvmsg(fd, msghdr, MSG_WAITALL);
- if (ssize < 0) {
- logmsg("message_recv: recvmsg");
- return (-1);
- }
- if ((size_t)ssize != size) {
- logmsgx("message_recv: recvmsg: received %zd of %zu bytes",
- ssize, size);
- return (-1);
- }
-
- dbgmsg("recv: data size %zd", ssize);
- dbgmsg("recv: msghdr.msg_controllen %u",
- (u_int)msghdr->msg_controllen);
- cmsghdr = CMSG_FIRSTHDR(msghdr);
- if (cmsghdr != NULL)
- dbgmsg("recv: cmsghdr.cmsg_len %u",
- (u_int)cmsghdr->cmsg_len);
-
- if (memcmp(ipc_msg.buf_recv, ipc_msg.buf_send, size) != 0) {
- logmsgx("message_recv: received message has wrong content");
- return (-1);
- }
-
- return (0);
-}
-
-static int
-socket_accept(int listenfd)
-{
- fd_set rset;
- struct timeval tv;
- int fd, rv, val;
-
- dbgmsg("accept");
-
- FD_ZERO(&rset);
- FD_SET(listenfd, &rset);
- tv.tv_sec = TIMEOUT;
- tv.tv_usec = 0;
- rv = select(listenfd + 1, &rset, (fd_set *)NULL, (fd_set *)NULL, &tv);
- if (rv < 0) {
- logmsg("socket_accept: select");
- return (-1);
- }
- if (rv == 0) {
- logmsgx("socket_accept: select timeout");
- return (-1);
- }
-
- fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL);
- if (fd < 0) {
- logmsg("socket_accept: accept");
- return (-1);
- }
-
- val = fcntl(fd, F_GETFL, 0);
- if (val < 0) {
- logmsg("socket_accept: fcntl(F_GETFL)");
- goto failed;
- }
- if (fcntl(fd, F_SETFL, val & ~O_NONBLOCK) < 0) {
- logmsg("socket_accept: fcntl(F_SETFL)");
- goto failed;
- }
-
- return (fd);
-
-failed:
- if (close(fd) < 0)
- logmsg("socket_accept: close");
- return (-1);
-}
-
-static int
-check_msghdr(const struct msghdr *msghdr, size_t size)
-{
- if (msghdr->msg_flags & MSG_TRUNC) {
- logmsgx("msghdr.msg_flags has MSG_TRUNC");
- return (-1);
- }
- if (msghdr->msg_flags & MSG_CTRUNC) {
- logmsgx("msghdr.msg_flags has MSG_CTRUNC");
- return (-1);
- }
- if (msghdr->msg_controllen < size) {
- logmsgx("msghdr.msg_controllen %u < %zu",
- (u_int)msghdr->msg_controllen, size);
- return (-1);
- }
- if (msghdr->msg_controllen > 0 && size == 0) {
- logmsgx("msghdr.msg_controllen %u > 0",
- (u_int)msghdr->msg_controllen);
- return (-1);
- }
- return (0);
-}
-
-static int
-check_cmsghdr(const struct cmsghdr *cmsghdr, int type, size_t size)
-{
- if (cmsghdr == NULL) {
- logmsgx("cmsghdr is NULL");
- return (-1);
- }
- if (cmsghdr->cmsg_level != SOL_SOCKET) {
- logmsgx("cmsghdr.cmsg_level %d != SOL_SOCKET",
- cmsghdr->cmsg_level);
- return (-1);
- }
- if (cmsghdr->cmsg_type != type) {
- logmsgx("cmsghdr.cmsg_type %d != %d",
- cmsghdr->cmsg_type, type);
- return (-1);
- }
- if (cmsghdr->cmsg_len != CMSG_LEN(size)) {
- logmsgx("cmsghdr.cmsg_len %u != %zu",
- (u_int)cmsghdr->cmsg_len, CMSG_LEN(size));
- return (-1);
- }
- return (0);
-}
-
-static int
-check_groups(const char *gid_arr_str, const gid_t *gid_arr,
- const char *gid_num_str, int gid_num, bool all_gids)
-{
- int i;
-
- for (i = 0; i < gid_num; ++i)
- dbgmsg("%s[%d] %lu", gid_arr_str, i, (u_long)gid_arr[i]);
-
- if (all_gids) {
- if (gid_num != proc_cred.gid_num) {
- logmsgx("%s %d != %d", gid_num_str, gid_num,
- proc_cred.gid_num);
- return (-1);
- }
- } else {
- if (gid_num > proc_cred.gid_num) {
- logmsgx("%s %d > %d", gid_num_str, gid_num,
- proc_cred.gid_num);
- return (-1);
- }
- }
- if (memcmp(gid_arr, proc_cred.gid_arr,
- gid_num * sizeof(*gid_arr)) != 0) {
- logmsgx("%s content is wrong", gid_arr_str);
- for (i = 0; i < gid_num; ++i)
- if (gid_arr[i] != proc_cred.gid_arr[i]) {
- logmsgx("%s[%d] %lu != %lu",
- gid_arr_str, i, (u_long)gid_arr[i],
- (u_long)proc_cred.gid_arr[i]);
- break;
- }
- return (-1);
- }
- return (0);
-}
-
-static int
-check_xucred(const struct xucred *xucred, socklen_t len)
-{
- int rc;
-
- if (len != sizeof(*xucred)) {
- logmsgx("option value size %zu != %zu",
- (size_t)len, sizeof(*xucred));
- return (-1);
- }
-
- dbgmsg("xucred.cr_version %u", xucred->cr_version);
- dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid);
- dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups);
-
- rc = 0;
-
- if (xucred->cr_version != XUCRED_VERSION) {
- logmsgx("xucred.cr_version %u != %d",
- xucred->cr_version, XUCRED_VERSION);
- rc = -1;
- }
- if (xucred->cr_uid != proc_cred.euid) {
- logmsgx("xucred.cr_uid %lu != %lu (EUID)",
- (u_long)xucred->cr_uid, (u_long)proc_cred.euid);
- rc = -1;
- }
- if (xucred->cr_ngroups == 0) {
- logmsgx("xucred.cr_ngroups == 0");
- rc = -1;
- }
- if (xucred->cr_ngroups < 0) {
- logmsgx("xucred.cr_ngroups < 0");
- rc = -1;
- }
- if (xucred->cr_ngroups > XU_NGROUPS) {
- logmsgx("xucred.cr_ngroups %hu > %u (max)",
- xucred->cr_ngroups, XU_NGROUPS);
- rc = -1;
- }
- if (xucred->cr_groups[0] != proc_cred.egid) {
- logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)",
- (u_long)xucred->cr_groups[0], (u_long)proc_cred.egid);
- rc = -1;
- }
- if (check_groups("xucred.cr_groups", xucred->cr_groups,
- "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0)
- rc = -1;
- return (rc);
-}
-
-static int
-check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr)
-{
- const struct cmsgcred *cmcred;
- int rc;
-
- if (check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(struct cmsgcred)) < 0)
- return (-1);
-
- cmcred = (struct cmsgcred *)CMSG_DATA(cmsghdr);
-
- dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmcred->cmcred_pid);
- dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmcred->cmcred_uid);
- dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmcred->cmcred_euid);
- dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmcred->cmcred_gid);
- dbgmsg("cmsgcred.cmcred_ngroups %d", cmcred->cmcred_ngroups);
-
- rc = 0;
-
- if (cmcred->cmcred_pid != client_pid) {
- logmsgx("cmsgcred.cmcred_pid %ld != %ld",
- (long)cmcred->cmcred_pid, (long)client_pid);
- rc = -1;
- }
- if (cmcred->cmcred_uid != proc_cred.uid) {
- logmsgx("cmsgcred.cmcred_uid %lu != %lu",
- (u_long)cmcred->cmcred_uid, (u_long)proc_cred.uid);
- rc = -1;
- }
- if (cmcred->cmcred_euid != proc_cred.euid) {
- logmsgx("cmsgcred.cmcred_euid %lu != %lu",
- (u_long)cmcred->cmcred_euid, (u_long)proc_cred.euid);
- rc = -1;
- }
- if (cmcred->cmcred_gid != proc_cred.gid) {
- logmsgx("cmsgcred.cmcred_gid %lu != %lu",
- (u_long)cmcred->cmcred_gid, (u_long)proc_cred.gid);
- rc = -1;
- }
- if (cmcred->cmcred_ngroups == 0) {
- logmsgx("cmsgcred.cmcred_ngroups == 0");
- rc = -1;
- }
- if (cmcred->cmcred_ngroups < 0) {
- logmsgx("cmsgcred.cmcred_ngroups %d < 0",
- cmcred->cmcred_ngroups);
- rc = -1;
- }
- if (cmcred->cmcred_ngroups > CMGROUP_MAX) {
- logmsgx("cmsgcred.cmcred_ngroups %d > %d",
- cmcred->cmcred_ngroups, CMGROUP_MAX);
- rc = -1;
- }
- if (cmcred->cmcred_groups[0] != proc_cred.egid) {
- logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)",
- (u_long)cmcred->cmcred_groups[0], (u_long)proc_cred.egid);
- rc = -1;
- }
- if (check_groups("cmsgcred.cmcred_groups", cmcred->cmcred_groups,
- "cmsgcred.cmcred_ngroups", cmcred->cmcred_ngroups, false) < 0)
- rc = -1;
- return (rc);
-}
-
-static int
-check_scm_creds_sockcred(struct cmsghdr *cmsghdr)
-{
- const struct sockcred *sc;
- int rc;
-
- if (check_cmsghdr(cmsghdr, SCM_CREDS,
- SOCKCREDSIZE(proc_cred.gid_num)) < 0)
- return (-1);
-
- sc = (struct sockcred *)CMSG_DATA(cmsghdr);
-
- rc = 0;
-
- dbgmsg("sockcred.sc_uid %lu", (u_long)sc->sc_uid);
- dbgmsg("sockcred.sc_euid %lu", (u_long)sc->sc_euid);
- dbgmsg("sockcred.sc_gid %lu", (u_long)sc->sc_gid);
- dbgmsg("sockcred.sc_egid %lu", (u_long)sc->sc_egid);
- dbgmsg("sockcred.sc_ngroups %d", sc->sc_ngroups);
-
- if (sc->sc_uid != proc_cred.uid) {
- logmsgx("sockcred.sc_uid %lu != %lu",
- (u_long)sc->sc_uid, (u_long)proc_cred.uid);
- rc = -1;
- }
- if (sc->sc_euid != proc_cred.euid) {
- logmsgx("sockcred.sc_euid %lu != %lu",
- (u_long)sc->sc_euid, (u_long)proc_cred.euid);
- rc = -1;
- }
- if (sc->sc_gid != proc_cred.gid) {
- logmsgx("sockcred.sc_gid %lu != %lu",
- (u_long)sc->sc_gid, (u_long)proc_cred.gid);
- rc = -1;
- }
- if (sc->sc_egid != proc_cred.egid) {
- logmsgx("sockcred.sc_egid %lu != %lu",
- (u_long)sc->sc_egid, (u_long)proc_cred.egid);
- rc = -1;
- }
- if (sc->sc_ngroups == 0) {
- logmsgx("sockcred.sc_ngroups == 0");
- rc = -1;
- }
- if (sc->sc_ngroups < 0) {
- logmsgx("sockcred.sc_ngroups %d < 0",
- sc->sc_ngroups);
- rc = -1;
- }
- if (sc->sc_ngroups != proc_cred.gid_num) {
- logmsgx("sockcred.sc_ngroups %d != %u",
- sc->sc_ngroups, proc_cred.gid_num);
- rc = -1;
- }
- if (check_groups("sockcred.sc_groups", sc->sc_groups,
- "sockcred.sc_ngroups", sc->sc_ngroups, true) < 0)
- rc = -1;
- return (rc);
-}
-
-static int
-check_scm_timestamp(struct cmsghdr *cmsghdr)
-{
- const struct timeval *tv;
-
- if (check_cmsghdr(cmsghdr, SCM_TIMESTAMP, sizeof(struct timeval)) < 0)
- return (-1);
-
- tv = (struct timeval *)CMSG_DATA(cmsghdr);
-
- dbgmsg("timeval.tv_sec %"PRIdMAX", timeval.tv_usec %"PRIdMAX,
- (intmax_t)tv->tv_sec, (intmax_t)tv->tv_usec);
-
- return (0);
-}
-
-static int
-check_scm_bintime(struct cmsghdr *cmsghdr)
-{
- const struct bintime *bt;
-
- if (check_cmsghdr(cmsghdr, SCM_BINTIME, sizeof(struct bintime)) < 0)
- return (-1);
-
- bt = (struct bintime *)CMSG_DATA(cmsghdr);
-
- dbgmsg("bintime.sec %"PRIdMAX", bintime.frac %"PRIu64,
- (intmax_t)bt->sec, bt->frac);
-
- return (0);
-}
-
-static void
-msghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data)
-{
- msghdr->msg_name = NULL;
- msghdr->msg_namelen = 0;
- if (send_data_flag) {
- iov->iov_base = server_flag ?
- ipc_msg.buf_recv : ipc_msg.buf_send;
- iov->iov_len = ipc_msg.buf_size;
- msghdr->msg_iov = iov;
- msghdr->msg_iovlen = 1;
- } else {
- msghdr->msg_iov = NULL;
- msghdr->msg_iovlen = 0;
- }
- msghdr->msg_control = cmsg_data;
- msghdr->msg_flags = 0;
-}
-
-static void
-msghdr_init_server(struct msghdr *msghdr, struct iovec *iov,
- void *cmsg_data, size_t cmsg_size)
-{
- msghdr_init_generic(msghdr, iov, cmsg_data);
- msghdr->msg_controllen = cmsg_size;
- dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ?
- msghdr->msg_iov->iov_len : (size_t)0);
- dbgmsg("init: msghdr.msg_controllen %u",
- (u_int)msghdr->msg_controllen);
-}
-
-static void
-msghdr_init_client(struct msghdr *msghdr, struct iovec *iov,
- void *cmsg_data, size_t cmsg_size, int type, size_t arr_size)
-{
- struct cmsghdr *cmsghdr;
-
- msghdr_init_generic(msghdr, iov, cmsg_data);
- if (cmsg_data != NULL) {
- if (send_array_flag)
- dbgmsg("sending an array");
- else
- dbgmsg("sending a scalar");
- msghdr->msg_controllen = send_array_flag ?
- cmsg_size : CMSG_SPACE(0);
- cmsghdr = CMSG_FIRSTHDR(msghdr);
- cmsghdr->cmsg_level = SOL_SOCKET;
- cmsghdr->cmsg_type = type;
- cmsghdr->cmsg_len = CMSG_LEN(send_array_flag ? arr_size : 0);
- } else
- msghdr->msg_controllen = 0;
-}
-
-static int
-t_generic(int (*client_func)(int), int (*server_func)(int))
-{
- int fd, rv, rv_client;
-
- switch (client_fork()) {
- case 0:
- fd = socket_create();
- if (fd < 0)
- rv = -2;
- else {
- rv = client_func(fd);
- if (socket_close(fd) < 0)
- rv = -2;
- }
- client_exit(rv);
- break;
- case 1:
- fd = socket_create();
- if (fd < 0)
- rv = -2;
- else {
- rv = server_func(fd);
- rv_client = client_wait();
- if (rv == 0 || (rv == -2 && rv_client != 0))
- rv = rv_client;
- if (socket_close(fd) < 0)
- rv = -2;
- }
- break;
- default:
- rv = -2;
- }
- return (rv);
-}
-
-static int
-t_cmsgcred_client(int fd)
-{
- struct msghdr msghdr;
- struct iovec iov[1];
- void *cmsg_data;
- size_t cmsg_size;
- int rv;
-
- if (sync_recv() < 0)
- return (-2);
-
- rv = -2;
-
- cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
- cmsg_data = malloc(cmsg_size);
- if (cmsg_data == NULL) {
- logmsg("malloc");
- goto done;
- }
- msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
- SCM_CREDS, sizeof(struct cmsgcred));
-
- if (socket_connect(fd) < 0)
- goto done;
-
- if (message_sendn(fd, &msghdr) < 0)
- goto done;
-
- rv = 0;
-done:
- free(cmsg_data);
- return (rv);
-}
-
-static int
-t_cmsgcred_server(int fd1)
-{
- struct msghdr msghdr;
- struct iovec iov[1];
- struct cmsghdr *cmsghdr;
- void *cmsg_data;
- size_t cmsg_size;
- u_int i;
- int fd2, rv;
-
- if (sync_send() < 0)
- return (-2);
-
- fd2 = -1;
- rv = -2;
-
- cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
- cmsg_data = malloc(cmsg_size);
- if (cmsg_data == NULL) {
- logmsg("malloc");
- goto done;
- }
-
- if (sock_type == SOCK_STREAM) {
- fd2 = socket_accept(fd1);
- if (fd2 < 0)
- goto done;
- } else
- fd2 = fd1;
-
- rv = -1;
- for (i = 1; i <= ipc_msg.msg_num; ++i) {
- dbgmsg("message #%u", i);
-
- msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
- if (message_recv(fd2, &msghdr) < 0) {
- rv = -2;
- break;
- }
-
- if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
- break;
-
- cmsghdr = CMSG_FIRSTHDR(&msghdr);
- if (check_scm_creds_cmsgcred(cmsghdr) < 0)
- break;
- }
- if (i > ipc_msg.msg_num)
- rv = 0;
-done:
- free(cmsg_data);
- if (sock_type == SOCK_STREAM && fd2 >= 0)
- if (socket_close(fd2) < 0)
- rv = -2;
- return (rv);
-}
-
-static int
-t_cmsgcred(void)
-{
- return (t_generic(t_cmsgcred_client, t_cmsgcred_server));
-}
-
-static int
-t_sockcred_client(int type, int fd)
-{
- struct msghdr msghdr;
- struct iovec iov[1];
- int rv;
-
- if (sync_recv() < 0)
- return (-2);
-
- rv = -2;
-
- msghdr_init_client(&msghdr, iov, NULL, 0, 0, 0);
-
- if (socket_connect(fd) < 0)
- goto done;
-
- if (type == 2)
- if (sync_recv() < 0)
- goto done;
-
- if (message_sendn(fd, &msghdr) < 0)
- goto done;
-
- rv = 0;
-done:
- return (rv);
-}
-
-static int
-t_sockcred_server(int type, int fd1)
-{
- struct msghdr msghdr;
- struct iovec iov[1];
- struct cmsghdr *cmsghdr;
- void *cmsg_data;
- size_t cmsg_size;
- u_int i;
- int fd2, rv, val;
-
- fd2 = -1;
- rv = -2;
-
- cmsg_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num));
- cmsg_data = malloc(cmsg_size);
- if (cmsg_data == NULL) {
- logmsg("malloc");
- goto done;
- }
-
- if (type == 1) {
- dbgmsg("setting LOCAL_CREDS");
- val = 1;
- if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
- logmsg("setsockopt(LOCAL_CREDS)");
- goto done;
- }
- }
-
- if (sync_send() < 0)
- goto done;
-
- if (sock_type == SOCK_STREAM) {
- fd2 = socket_accept(fd1);
- if (fd2 < 0)
- goto done;
- } else
- fd2 = fd1;
-
- if (type == 2) {
- dbgmsg("setting LOCAL_CREDS");
- val = 1;
- if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
- logmsg("setsockopt(LOCAL_CREDS)");
- goto done;
- }
- if (sync_send() < 0)
- goto done;
- }
-
- rv = -1;
- for (i = 1; i <= ipc_msg.msg_num; ++i) {
- dbgmsg("message #%u", i);
-
- msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
- if (message_recv(fd2, &msghdr) < 0) {
- rv = -2;
- break;
- }
-
- if (i > 1 && sock_type == SOCK_STREAM) {
- if (check_msghdr(&msghdr, 0) < 0)
- break;
- } else {
- if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
- break;
-
- cmsghdr = CMSG_FIRSTHDR(&msghdr);
- if (check_scm_creds_sockcred(cmsghdr) < 0)
- break;
- }
- }
- if (i > ipc_msg.msg_num)
- rv = 0;
-done:
- free(cmsg_data);
- if (sock_type == SOCK_STREAM && fd2 >= 0)
- if (socket_close(fd2) < 0)
- rv = -2;
- return (rv);
-}
-
-static int
-t_sockcred_1(void)
-{
- u_int i;
- int fd, rv, rv_client;
-
- switch (client_fork()) {
- case 0:
- for (i = 1; i <= 2; ++i) {
- dbgmsg("client #%u", i);
- fd = socket_create();
- if (fd < 0)
- rv = -2;
- else {
- rv = t_sockcred_client(1, fd);
- if (socket_close(fd) < 0)
- rv = -2;
- }
- if (rv != 0)
- break;
- }
- client_exit(rv);
- break;
- case 1:
- fd = socket_create();
- if (fd < 0)
- rv = -2;
- else {
- rv = t_sockcred_server(1, fd);
- if (rv == 0)
- rv = t_sockcred_server(3, fd);
- rv_client = client_wait();
- if (rv == 0 || (rv == -2 && rv_client != 0))
- rv = rv_client;
- if (socket_close(fd) < 0)
- rv = -2;
- }
- break;
- default:
- rv = -2;
- }
-
- return (rv);
-}
-
-static int
-t_sockcred_2_client(int fd)
-{
- return (t_sockcred_client(2, fd));
-}
-
-static int
-t_sockcred_2_server(int fd)
-{
- return (t_sockcred_server(2, fd));
-}
-
-static int
-t_sockcred_2(void)
-{
- return (t_generic(t_sockcred_2_client, t_sockcred_2_server));
-}
-
-static int
-t_cmsgcred_sockcred_server(int fd1)
-{
- struct msghdr msghdr;
- struct iovec iov[1];
- struct cmsghdr *cmsghdr;
- void *cmsg_data, *cmsg1_data, *cmsg2_data;
- size_t cmsg_size, cmsg1_size, cmsg2_size;
- u_int i;
- int fd2, rv, val;
-
- fd2 = -1;
- rv = -2;
-
- cmsg1_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num));
- cmsg2_size = CMSG_SPACE(sizeof(struct cmsgcred));
- cmsg1_data = malloc(cmsg1_size);
- cmsg2_data = malloc(cmsg2_size);
- if (cmsg1_data == NULL || cmsg2_data == NULL) {
- logmsg("malloc");
- goto done;
- }
-
- dbgmsg("setting LOCAL_CREDS");
- val = 1;
- if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
- logmsg("setsockopt(LOCAL_CREDS)");
- goto done;
- }
-
- if (sync_send() < 0)
- goto done;
-
- if (sock_type == SOCK_STREAM) {
- fd2 = socket_accept(fd1);
- if (fd2 < 0)
- goto done;
- } else
- fd2 = fd1;
-
- cmsg_data = cmsg1_data;
- cmsg_size = cmsg1_size;
- rv = -1;
- for (i = 1; i <= ipc_msg.msg_num; ++i) {
- dbgmsg("message #%u", i);
-
- msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
- if (message_recv(fd2, &msghdr) < 0) {
- rv = -2;
- break;
- }
-
- if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
- break;
-
- cmsghdr = CMSG_FIRSTHDR(&msghdr);
- if (i == 1 || sock_type == SOCK_DGRAM) {
- if (check_scm_creds_sockcred(cmsghdr) < 0)
- break;
- } else {
- if (check_scm_creds_cmsgcred(cmsghdr) < 0)
- break;
- }
-
- cmsg_data = cmsg2_data;
- cmsg_size = cmsg2_size;
- }
- if (i > ipc_msg.msg_num)
- rv = 0;
-done:
- free(cmsg1_data);
- free(cmsg2_data);
- if (sock_type == SOCK_STREAM && fd2 >= 0)
- if (socket_close(fd2) < 0)
- rv = -2;
- return (rv);
-}
-
-static int
-t_cmsgcred_sockcred(void)
-{
- return (t_generic(t_cmsgcred_client, t_cmsgcred_sockcred_server));
-}
-
-static int
-t_timeval_client(int fd)
-{
- struct msghdr msghdr;
- struct iovec iov[1];
- void *cmsg_data;
- size_t cmsg_size;
- int rv;
-
- if (sync_recv() < 0)
- return (-2);
-
- rv = -2;
-
- cmsg_size = CMSG_SPACE(sizeof(struct timeval));
- cmsg_data = malloc(cmsg_size);
- if (cmsg_data == NULL) {
- logmsg("malloc");
- goto done;
- }
- msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
- SCM_TIMESTAMP, sizeof(struct timeval));
-
- if (socket_connect(fd) < 0)
- goto done;
-
- if (message_sendn(fd, &msghdr) < 0)
- goto done;
-
- rv = 0;
-done:
- free(cmsg_data);
- return (rv);
-}
-
-static int
-t_timeval_server(int fd1)
-{
- struct msghdr msghdr;
- struct iovec iov[1];
- struct cmsghdr *cmsghdr;
- void *cmsg_data;
- size_t cmsg_size;
- u_int i;
- int fd2, rv;
-
- if (sync_send() < 0)
- return (-2);
-
- fd2 = -1;
- rv = -2;
-
- cmsg_size = CMSG_SPACE(sizeof(struct timeval));
- cmsg_data = malloc(cmsg_size);
- if (cmsg_data == NULL) {
- logmsg("malloc");
- goto done;
- }
-
- if (sock_type == SOCK_STREAM) {
- fd2 = socket_accept(fd1);
- if (fd2 < 0)
- goto done;
- } else
- fd2 = fd1;
-
- rv = -1;
- for (i = 1; i <= ipc_msg.msg_num; ++i) {
- dbgmsg("message #%u", i);
-
- msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
- if (message_recv(fd2, &msghdr) < 0) {
- rv = -2;
- break;
- }
-
- if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
- break;
-
- cmsghdr = CMSG_FIRSTHDR(&msghdr);
- if (check_scm_timestamp(cmsghdr) < 0)
- break;
- }
- if (i > ipc_msg.msg_num)
- rv = 0;
-done:
- free(cmsg_data);
- if (sock_type == SOCK_STREAM && fd2 >= 0)
- if (socket_close(fd2) < 0)
- rv = -2;
- return (rv);
-}
-
-static int
-t_timeval(void)
-{
- return (t_generic(t_timeval_client, t_timeval_server));
-}
-
-static int
-t_bintime_client(int fd)
-{
- struct msghdr msghdr;
- struct iovec iov[1];
- void *cmsg_data;
- size_t cmsg_size;
- int rv;
-
- if (sync_recv() < 0)
- return (-2);
-
- rv = -2;
-
- cmsg_size = CMSG_SPACE(sizeof(struct bintime));
- cmsg_data = malloc(cmsg_size);
- if (cmsg_data == NULL) {
- logmsg("malloc");
- goto done;
- }
- msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
- SCM_BINTIME, sizeof(struct bintime));
-
- if (socket_connect(fd) < 0)
- goto done;
-
- if (message_sendn(fd, &msghdr) < 0)
- goto done;
-
- rv = 0;
-done:
- free(cmsg_data);
- return (rv);
-}
-
-static int
-t_bintime_server(int fd1)
-{
- struct msghdr msghdr;
- struct iovec iov[1];
- struct cmsghdr *cmsghdr;
- void *cmsg_data;
- size_t cmsg_size;
- u_int i;
- int fd2, rv;
-
- if (sync_send() < 0)
- return (-2);
-
- fd2 = -1;
- rv = -2;
-
- cmsg_size = CMSG_SPACE(sizeof(struct bintime));
- cmsg_data = malloc(cmsg_size);
- if (cmsg_data == NULL) {
- logmsg("malloc");
- goto done;
- }
-
- if (sock_type == SOCK_STREAM) {
- fd2 = socket_accept(fd1);
- if (fd2 < 0)
- goto done;
- } else
- fd2 = fd1;
-
- rv = -1;
- for (i = 1; i <= ipc_msg.msg_num; ++i) {
- dbgmsg("message #%u", i);
-
- msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
- if (message_recv(fd2, &msghdr) < 0) {
- rv = -2;
- break;
- }
-
- if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
- break;
-
- cmsghdr = CMSG_FIRSTHDR(&msghdr);
- if (check_scm_bintime(cmsghdr) < 0)
- break;
- }
- if (i > ipc_msg.msg_num)
- rv = 0;
-done:
- free(cmsg_data);
- if (sock_type == SOCK_STREAM && fd2 >= 0)
- if (socket_close(fd2) < 0)
- rv = -2;
- return (rv);
-}
-
-static int
-t_bintime(void)
-{
- return (t_generic(t_bintime_client, t_bintime_server));
-}
-
-#ifndef __LP64__
-static int
-t_cmsg_len_client(int fd)
-{
- struct msghdr msghdr;
- struct iovec iov[1];
- struct cmsghdr *cmsghdr;
- void *cmsg_data;
- size_t size, cmsg_size;
- socklen_t socklen;
- int rv;
-
- if (sync_recv() < 0)
- return (-2);
-
- rv = -2;
-
- cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
- cmsg_data = malloc(cmsg_size);
- if (cmsg_data == NULL) {
- logmsg("malloc");
- goto done;
- }
- msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
- SCM_CREDS, sizeof(struct cmsgcred));
- cmsghdr = CMSG_FIRSTHDR(&msghdr);
-
- if (socket_connect(fd) < 0)
- goto done;
-
- size = msghdr.msg_iov != NULL ? msghdr.msg_iov->iov_len : 0;
- rv = -1;
- for (socklen = 0; socklen < CMSG_LEN(0); ++socklen) {
- cmsghdr->cmsg_len = socklen;
- dbgmsg("send: data size %zu", size);
- dbgmsg("send: msghdr.msg_controllen %u",
- (u_int)msghdr.msg_controllen);
- dbgmsg("send: cmsghdr.cmsg_len %u",
- (u_int)cmsghdr->cmsg_len);
- if (sendmsg(fd, &msghdr, 0) < 0) {
- dbgmsg("sendmsg(2) failed: %s; retrying",
- strerror(errno));
- continue;
- }
- logmsgx("sent message with cmsghdr.cmsg_len %u < %u",
- (u_int)cmsghdr->cmsg_len, (u_int)CMSG_LEN(0));
- break;
- }
- if (socklen == CMSG_LEN(0))
- rv = 0;
-
- if (sync_send() < 0) {
- rv = -2;
- goto done;
- }
-done:
- free(cmsg_data);
- return (rv);
-}
-
-static int
-t_cmsg_len_server(int fd1)
-{
- int fd2, rv;
-
- if (sync_send() < 0)
- return (-2);
-
- rv = -2;
-
- if (sock_type == SOCK_STREAM) {
- fd2 = socket_accept(fd1);
- if (fd2 < 0)
- goto done;
- } else
- fd2 = fd1;
-
- if (sync_recv() < 0)
- goto done;
-
- rv = 0;
-done:
- if (sock_type == SOCK_STREAM && fd2 >= 0)
- if (socket_close(fd2) < 0)
- rv = -2;
- return (rv);
-}
-
-static int
-t_cmsg_len(void)
-{
- return (t_generic(t_cmsg_len_client, t_cmsg_len_server));
-}
-#endif
-
-static int
-t_peercred_client(int fd)
-{
- struct xucred xucred;
- socklen_t len;
-
- if (sync_recv() < 0)
- return (-1);
-
- if (socket_connect(fd) < 0)
- return (-1);
-
- len = sizeof(xucred);
- if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
- logmsg("getsockopt(LOCAL_PEERCRED)");
- return (-1);
- }
-
- if (check_xucred(&xucred, len) < 0)
- return (-1);
-
- return (0);
-}
-
-static int
-t_peercred_server(int fd1)
-{
- struct xucred xucred;
- socklen_t len;
- int fd2, rv;
-
- if (sync_send() < 0)
- return (-2);
-
- fd2 = socket_accept(fd1);
- if (fd2 < 0)
- return (-2);
-
- len = sizeof(xucred);
- if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
- logmsg("getsockopt(LOCAL_PEERCRED)");
- rv = -2;
- goto done;
- }
-
- if (check_xucred(&xucred, len) < 0) {
- rv = -1;
- goto done;
- }
-
- rv = 0;
-done:
- if (socket_close(fd2) < 0)
- rv = -2;
- return (rv);
-}
-
-static int
-t_peercred(void)
-{
- return (t_generic(t_peercred_client, t_peercred_server));
-}