2 * Copyright (c) 2005 Andrey Simonenko
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/resource.h>
33 #include <sys/select.h>
34 #include <sys/socket.h>
35 #include <sys/ucred.h>
56 * There are tables with tests descriptions and pointers to test
57 * functions. Each t_*() function returns 0 if its test passed,
58 * -1 if its test failed, -2 if some system error occurred.
59 * If a test function returns -2, then a program exits.
61 * If a test function forks a client process, then it waits for its
62 * termination. If a return code of a client process is not equal
63 * to zero, or if a client process was terminated by a signal, then
64 * a test function returns -1 or -2 depending on exit status of
67 * Each function which can block, is run under TIMEOUT. If timeout
68 * occurs, then a test function returns -2 or a client process exits
69 * with a non-zero return code.
80 static int t_cmsgcred(void);
81 static int t_sockcred_1(void);
82 static int t_sockcred_2(void);
83 static int t_cmsgcred_sockcred(void);
84 static int t_timeval(void);
85 static int t_bintime(void);
86 static int t_cmsg_len(void);
87 static int t_peercred(void);
94 static const struct test_func test_stream_tbl[] = {
101 .desc = "Sending, receiving cmsgcred"
104 .func = t_sockcred_1,
105 .desc = "Receiving sockcred (listening socket)"
108 .func = t_sockcred_2,
109 .desc = "Receiving sockcred (accepted socket)"
112 .func = t_cmsgcred_sockcred,
113 .desc = "Sending cmsgcred, receiving sockcred"
117 .desc = "Sending, receiving timeval"
121 .desc = "Sending, receiving bintime"
125 .desc = "Check cmsghdr.cmsg_len"
129 .desc = "Check LOCAL_PEERCRED socket option"
133 #define TEST_STREAM_TBL_SIZE \
134 (sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0]))
136 static const struct test_func test_dgram_tbl[] = {
143 .desc = "Sending, receiving cmsgcred"
146 .func = t_sockcred_2,
147 .desc = "Receiving sockcred"
150 .func = t_cmsgcred_sockcred,
151 .desc = "Sending cmsgcred, receiving sockcred"
155 .desc = "Sending, receiving timeval"
159 .desc = "Sending, receiving bintime"
163 .desc = "Check cmsghdr.cmsg_len"
167 #define TEST_DGRAM_TBL_SIZE \
168 (sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0]))
170 static bool debug = false;
171 static bool server_flag = true;
172 static bool send_data_flag = true;
173 static bool send_array_flag = true;
174 static bool failed_flag = false;
176 static int sock_type;
177 static const char *sock_type_str;
179 static const char *proc_name;
181 static char work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX";
182 static int serv_sock_fd;
183 static struct sockaddr_un serv_addr_sun;
192 #define IPC_MSG_NUM_DEF 5
193 #define IPC_MSG_NUM_MAX 10
194 #define IPC_MSG_SIZE_DEF 7
195 #define IPC_MSG_SIZE_MAX 128
206 static pid_t client_pid;
208 #define SYNC_SERVER 0
209 #define SYNC_CLIENT 1
213 static int sync_fd[2][2];
215 #define LOGMSG_SIZE 128
217 static void logmsg(const char *, ...) __printflike(1, 2);
218 static void logmsgx(const char *, ...) __printflike(1, 2);
219 static void dbgmsg(const char *, ...) __printflike(1, 2);
220 static void output(const char *, ...) __printflike(1, 2);
227 printf("usage: %s [-dh] [-n num] [-s size] [-t type] "
228 "[-z value] [testno]\n", getprogname());
231 printf("\n Options are:\n\
232 -d Output debugging information\n\
233 -h Output the help message and exit\n\
234 -n num Number of messages to send\n\
235 -s size Specify size of data for IPC\n\
236 -t type Specify socket type (stream, dgram) for tests\n\
237 -z value Do not send data in a message (bit 0x1), do not send\n\
238 data array associated with a cmsghdr structure (bit 0x2)\n\
239 testno Run one test by its number (require the -t option)\n\n");
240 printf(" Available tests for stream sockets:\n");
241 for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i)
242 printf(" %u: %s\n", i, test_stream_tbl[i].desc);
243 printf("\n Available tests for datagram sockets:\n");
244 for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i)
245 printf(" %u: %s\n", i, test_dgram_tbl[i].desc);
249 output(const char *format, ...)
251 char buf[LOGMSG_SIZE];
254 va_start(ap, format);
255 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
256 err(EXIT_FAILURE, "output: vsnprintf failed");
257 write(STDOUT_FILENO, buf, strlen(buf));
262 logmsg(const char *format, ...)
264 char buf[LOGMSG_SIZE];
269 va_start(ap, format);
270 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
271 err(EXIT_FAILURE, "logmsg: vsnprintf failed");
273 output("%s: %s\n", proc_name, buf);
275 output("%s: %s: %s\n", proc_name, buf, strerror(errno_save));
281 vlogmsgx(const char *format, va_list ap)
283 char buf[LOGMSG_SIZE];
285 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
286 err(EXIT_FAILURE, "logmsgx: vsnprintf failed");
287 output("%s: %s\n", proc_name, buf);
292 logmsgx(const char *format, ...)
296 va_start(ap, format);
297 vlogmsgx(format, ap);
302 dbgmsg(const char *format, ...)
307 va_start(ap, format);
308 vlogmsgx(format, ap);
314 run_tests(int type, u_int testno1)
316 const struct test_func *tf;
317 u_int i, testno2, failed_num;
320 if (type == SOCK_STREAM) {
321 sock_type_str = "SOCK_STREAM";
322 tf = test_stream_tbl;
323 i = TEST_STREAM_TBL_SIZE - 1;
325 sock_type_str = "SOCK_DGRAM";
327 i = TEST_DGRAM_TBL_SIZE - 1;
335 output("Running tests for %s sockets:\n", sock_type_str);
337 for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) {
338 output(" %u: %s\n", i, tf->desc);
339 switch (tf->func()) {
344 logmsgx("some system error or timeout occurred");
352 if (testno1 != testno2) {
354 output("-- all tests passed!\n");
356 output("-- %u test%s failed!\n",
357 failed_num, failed_num == 1 ? "" : "s");
360 output("-- test passed!\n");
362 output("-- test failed!\n");
371 struct sigaction sigact;
375 proc_name = "SERVER";
377 sigact.sa_handler = SIG_IGN;
379 sigemptyset(&sigact.sa_mask);
380 if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) {
381 logmsg("init: sigaction");
385 if (ipc_msg.buf_size == 0)
386 ipc_msg.buf_send = ipc_msg.buf_recv = NULL;
388 ipc_msg.buf_send = malloc(ipc_msg.buf_size);
389 ipc_msg.buf_recv = malloc(ipc_msg.buf_size);
390 if (ipc_msg.buf_send == NULL || ipc_msg.buf_recv == NULL) {
391 logmsg("init: malloc");
394 for (idx = 0; idx < ipc_msg.buf_size; ++idx)
395 ipc_msg.buf_send[idx] = (char)idx;
398 proc_cred.uid = getuid();
399 proc_cred.euid = geteuid();
400 proc_cred.gid = getgid();
401 proc_cred.egid = getegid();
402 proc_cred.gid_num = getgroups(0, (gid_t *)NULL);
403 if (proc_cred.gid_num < 0) {
404 logmsg("init: getgroups");
407 proc_cred.gid_arr = malloc(proc_cred.gid_num *
408 sizeof(*proc_cred.gid_arr));
409 if (proc_cred.gid_arr == NULL) {
410 logmsg("init: malloc");
413 if (getgroups(proc_cred.gid_num, proc_cred.gid_arr) < 0) {
414 logmsg("init: getgroups");
418 memset(&serv_addr_sun, 0, sizeof(serv_addr_sun));
419 rv = snprintf(serv_addr_sun.sun_path, sizeof(serv_addr_sun.sun_path),
420 "%s/%s", work_dir, proc_name);
422 logmsg("init: snprintf");
425 if ((size_t)rv >= sizeof(serv_addr_sun.sun_path)) {
426 logmsgx("init: not enough space for socket pathname");
429 serv_addr_sun.sun_family = PF_LOCAL;
430 serv_addr_sun.sun_len = SUN_LEN(&serv_addr_sun);
440 if (pipe(sync_fd[SYNC_SERVER]) < 0 ||
441 pipe(sync_fd[SYNC_CLIENT]) < 0) {
442 logmsg("client_fork: pipe");
446 if (client_pid == (pid_t)-1) {
447 logmsg("client_fork: fork");
450 if (client_pid == 0) {
451 proc_name = "CLIENT";
453 fd1 = sync_fd[SYNC_SERVER][SYNC_RECV];
454 fd2 = sync_fd[SYNC_CLIENT][SYNC_SEND];
456 fd1 = sync_fd[SYNC_SERVER][SYNC_SEND];
457 fd2 = sync_fd[SYNC_CLIENT][SYNC_RECV];
459 if (close(fd1) < 0 || close(fd2) < 0) {
460 logmsg("client_fork: close");
463 return (client_pid != 0);
469 if (close(sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 ||
470 close(sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) {
471 logmsg("client_exit: close");
474 rv = rv == 0 ? EXIT_SUCCESS : -rv;
475 dbgmsg("exit: code %d", rv);
485 dbgmsg("waiting for client");
487 if (close(sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 ||
488 close(sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) {
489 logmsg("client_wait: close");
493 pid = waitpid(client_pid, &status, 0);
494 if (pid == (pid_t)-1) {
495 logmsg("client_wait: waitpid");
499 if (WIFEXITED(status)) {
500 if (WEXITSTATUS(status) != EXIT_SUCCESS) {
501 logmsgx("client exit status is %d",
502 WEXITSTATUS(status));
503 return (-WEXITSTATUS(status));
506 if (WIFSIGNALED(status))
507 logmsgx("abnormal termination of client, signal %d%s",
508 WTERMSIG(status), WCOREDUMP(status) ?
509 " (core file generated)" : "");
511 logmsgx("termination of client, unknown status");
519 main(int argc, char *argv[])
522 u_int testno, zvalue;
524 bool dgram_flag, stream_flag;
526 ipc_msg.buf_size = IPC_MSG_SIZE_DEF;
527 ipc_msg.msg_num = IPC_MSG_NUM_DEF;
528 dgram_flag = stream_flag = false;
529 while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1)
536 return (EXIT_SUCCESS);
538 ipc_msg.msg_num = strtonum(optarg, 1,
539 IPC_MSG_NUM_MAX, &errstr);
541 errx(EXIT_FAILURE, "option -n: number is %s",
545 ipc_msg.buf_size = strtonum(optarg, 0,
546 IPC_MSG_SIZE_MAX, &errstr);
548 errx(EXIT_FAILURE, "option -s: number is %s",
552 if (strcmp(optarg, "stream") == 0)
554 else if (strcmp(optarg, "dgram") == 0)
557 errx(EXIT_FAILURE, "option -t: "
558 "wrong socket type");
561 zvalue = strtonum(optarg, 0, 3, &errstr);
563 errx(EXIT_FAILURE, "option -z: number is %s",
566 send_data_flag = false;
568 send_array_flag = false;
572 return (EXIT_FAILURE);
576 if (optind + 1 != argc)
577 errx(EXIT_FAILURE, "too many arguments");
578 testno = strtonum(argv[optind], 0, UINT_MAX, &errstr);
580 errx(EXIT_FAILURE, "test number is %s", errstr);
581 if (stream_flag && testno >= TEST_STREAM_TBL_SIZE)
582 errx(EXIT_FAILURE, "given test %u for stream "
583 "sockets does not exist", testno);
584 if (dgram_flag && testno >= TEST_DGRAM_TBL_SIZE)
585 errx(EXIT_FAILURE, "given test %u for datagram "
586 "sockets does not exist", testno);
590 if (!dgram_flag && !stream_flag) {
592 errx(EXIT_FAILURE, "particular test number "
593 "can be used with the -t option only");
594 dgram_flag = stream_flag = true;
597 if (mkdtemp(work_dir) == NULL)
598 err(EXIT_FAILURE, "mkdtemp(%s)", work_dir);
605 if (run_tests(SOCK_STREAM, testno) < 0)
608 if (run_tests(SOCK_DGRAM, testno) < 0)
613 if (rmdir(work_dir) < 0) {
614 logmsg("rmdir(%s)", work_dir);
617 return (failed_flag ? EXIT_FAILURE : rv);
627 logmsg("socket_close: close");
630 if (server_flag && fd == serv_sock_fd)
631 if (unlink(serv_addr_sun.sun_path) < 0) {
632 logmsg("socket_close: unlink(%s)",
633 serv_addr_sun.sun_path);
645 fd = socket(PF_LOCAL, sock_type, 0);
647 logmsg("socket_create: socket(PF_LOCAL, %s, 0)", sock_type_str);
655 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 ||
656 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) {
657 logmsg("socket_create: setsockopt(SO_RCVTIMEO/SO_SNDTIMEO)");
662 if (bind(fd, (struct sockaddr *)&serv_addr_sun,
663 serv_addr_sun.sun_len) < 0) {
664 logmsg("socket_create: bind(%s)",
665 serv_addr_sun.sun_path);
668 if (sock_type == SOCK_STREAM) {
671 if (listen(fd, LISTENQ) < 0) {
672 logmsg("socket_create: listen");
675 val = fcntl(fd, F_GETFL, 0);
677 logmsg("socket_create: fcntl(F_GETFL)");
680 if (fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) {
681 logmsg("socket_create: fcntl(F_SETFL)");
691 logmsg("socket_create: close");
693 if (unlink(serv_addr_sun.sun_path) < 0)
694 logmsg("socket_close: unlink(%s)",
695 serv_addr_sun.sun_path);
700 socket_connect(int fd)
704 if (connect(fd, (struct sockaddr *)&serv_addr_sun,
705 serv_addr_sun.sun_len) < 0) {
706 logmsg("socket_connect: connect(%s)", serv_addr_sun.sun_path);
719 dbgmsg("sync: wait");
721 fd = sync_fd[server_flag ? SYNC_SERVER : SYNC_CLIENT][SYNC_RECV];
723 ssize = read(fd, &buf, 1);
725 logmsg("sync_recv: read");
729 logmsgx("sync_recv: read %zd of 1 byte", ssize);
733 dbgmsg("sync: received");
744 dbgmsg("sync: send");
746 fd = sync_fd[server_flag ? SYNC_CLIENT : SYNC_SERVER][SYNC_SEND];
748 ssize = write(fd, "", 1);
750 logmsg("sync_send: write");
754 logmsgx("sync_send: sent %zd of 1 byte", ssize);
762 message_send(int fd, const struct msghdr *msghdr)
764 const struct cmsghdr *cmsghdr;
768 size = msghdr->msg_iov != 0 ? msghdr->msg_iov->iov_len : 0;
769 dbgmsg("send: data size %zu", size);
770 dbgmsg("send: msghdr.msg_controllen %u",
771 (u_int)msghdr->msg_controllen);
772 cmsghdr = CMSG_FIRSTHDR(msghdr);
774 dbgmsg("send: cmsghdr.cmsg_len %u",
775 (u_int)cmsghdr->cmsg_len);
777 ssize = sendmsg(fd, msghdr, 0);
779 logmsg("message_send: sendmsg");
782 if ((size_t)ssize != size) {
783 logmsgx("message_send: sendmsg: sent %zd of %zu bytes",
796 message_sendn(int fd, struct msghdr *msghdr)
800 for (i = 1; i <= ipc_msg.msg_num; ++i) {
801 dbgmsg("message #%u", i);
802 if (message_send(fd, msghdr) < 0)
809 message_recv(int fd, struct msghdr *msghdr)
811 const struct cmsghdr *cmsghdr;
819 size = msghdr->msg_iov != NULL ? msghdr->msg_iov->iov_len : 0;
820 ssize = recvmsg(fd, msghdr, MSG_WAITALL);
822 logmsg("message_recv: recvmsg");
825 if ((size_t)ssize != size) {
826 logmsgx("message_recv: recvmsg: received %zd of %zu bytes",
831 dbgmsg("recv: data size %zd", ssize);
832 dbgmsg("recv: msghdr.msg_controllen %u",
833 (u_int)msghdr->msg_controllen);
834 cmsghdr = CMSG_FIRSTHDR(msghdr);
836 dbgmsg("recv: cmsghdr.cmsg_len %u",
837 (u_int)cmsghdr->cmsg_len);
839 if (memcmp(ipc_msg.buf_recv, ipc_msg.buf_send, size) != 0) {
840 logmsgx("message_recv: received message has wrong content");
848 socket_accept(int listenfd)
857 FD_SET(listenfd, &rset);
860 rv = select(listenfd + 1, &rset, (fd_set *)NULL, (fd_set *)NULL, &tv);
862 logmsg("socket_accept: select");
866 logmsgx("socket_accept: select timeout");
870 fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL);
872 logmsg("socket_accept: accept");
876 val = fcntl(fd, F_GETFL, 0);
878 logmsg("socket_accept: fcntl(F_GETFL)");
881 if (fcntl(fd, F_SETFL, val & ~O_NONBLOCK) < 0) {
882 logmsg("socket_accept: fcntl(F_SETFL)");
890 logmsg("socket_accept: close");
895 check_msghdr(const struct msghdr *msghdr, size_t size)
897 if (msghdr->msg_flags & MSG_TRUNC) {
898 logmsgx("msghdr.msg_flags has MSG_TRUNC");
901 if (msghdr->msg_flags & MSG_CTRUNC) {
902 logmsgx("msghdr.msg_flags has MSG_CTRUNC");
905 if (msghdr->msg_controllen < size) {
906 logmsgx("msghdr.msg_controllen %u < %zu",
907 (u_int)msghdr->msg_controllen, size);
910 if (msghdr->msg_controllen > 0 && size == 0) {
911 logmsgx("msghdr.msg_controllen %u > 0",
912 (u_int)msghdr->msg_controllen);
919 check_cmsghdr(const struct cmsghdr *cmsghdr, int type, size_t size)
921 if (cmsghdr == NULL) {
922 logmsgx("cmsghdr is NULL");
925 if (cmsghdr->cmsg_level != SOL_SOCKET) {
926 logmsgx("cmsghdr.cmsg_level %d != SOL_SOCKET",
927 cmsghdr->cmsg_level);
930 if (cmsghdr->cmsg_type != type) {
931 logmsgx("cmsghdr.cmsg_type %d != %d",
932 cmsghdr->cmsg_type, type);
935 if (cmsghdr->cmsg_len != CMSG_LEN(size)) {
936 logmsgx("cmsghdr.cmsg_len %u != %zu",
937 (u_int)cmsghdr->cmsg_len, CMSG_LEN(size));
944 check_groups(const char *gid_arr_str, const gid_t *gid_arr,
945 const char *gid_num_str, int gid_num, bool all_gids)
949 for (i = 0; i < gid_num; ++i)
950 dbgmsg("%s[%d] %lu", gid_arr_str, i, (u_long)gid_arr[i]);
953 if (gid_num != proc_cred.gid_num) {
954 logmsgx("%s %d != %d", gid_num_str, gid_num,
959 if (gid_num > proc_cred.gid_num) {
960 logmsgx("%s %d > %d", gid_num_str, gid_num,
965 if (memcmp(gid_arr, proc_cred.gid_arr,
966 gid_num * sizeof(*gid_arr)) != 0) {
967 logmsgx("%s content is wrong", gid_arr_str);
968 for (i = 0; i < gid_num; ++i)
969 if (gid_arr[i] != proc_cred.gid_arr[i]) {
970 logmsgx("%s[%d] %lu != %lu",
971 gid_arr_str, i, (u_long)gid_arr[i],
972 (u_long)proc_cred.gid_arr[i]);
981 check_xucred(const struct xucred *xucred, socklen_t len)
983 if (len != sizeof(*xucred)) {
984 logmsgx("option value size %zu != %zu",
985 (size_t)len, sizeof(*xucred));
989 dbgmsg("xucred.cr_version %u", xucred->cr_version);
990 dbgmsg("xucred.cr_uid %lu", (u_long)xucred->cr_uid);
991 dbgmsg("xucred.cr_ngroups %d", xucred->cr_ngroups);
993 if (xucred->cr_version != XUCRED_VERSION) {
994 logmsgx("xucred.cr_version %u != %d",
995 xucred->cr_version, XUCRED_VERSION);
998 if (xucred->cr_uid != proc_cred.euid) {
999 logmsgx("xucred.cr_uid %lu != %lu (EUID)",
1000 (u_long)xucred->cr_uid, (u_long)proc_cred.euid);
1003 if (xucred->cr_ngroups == 0) {
1004 logmsgx("xucred.cr_ngroups == 0");
1007 if (xucred->cr_ngroups < 0) {
1008 logmsgx("xucred.cr_ngroups < 0");
1011 if (xucred->cr_ngroups > XU_NGROUPS) {
1012 logmsgx("xucred.cr_ngroups %hu > %u (max)",
1013 xucred->cr_ngroups, XU_NGROUPS);
1016 if (xucred->cr_groups[0] != proc_cred.egid) {
1017 logmsgx("xucred.cr_groups[0] %lu != %lu (EGID)",
1018 (u_long)xucred->cr_groups[0], (u_long)proc_cred.egid);
1021 if (check_groups("xucred.cr_groups", xucred->cr_groups,
1022 "xucred.cr_ngroups", xucred->cr_ngroups, false) < 0)
1028 check_scm_creds_cmsgcred(struct cmsghdr *cmsghdr)
1030 const struct cmsgcred *cmsgcred;
1032 if (check_cmsghdr(cmsghdr, SCM_CREDS, sizeof(*cmsgcred)) < 0)
1035 cmsgcred = (struct cmsgcred *)CMSG_DATA(cmsghdr);
1037 dbgmsg("cmsgcred.cmcred_pid %ld", (long)cmsgcred->cmcred_pid);
1038 dbgmsg("cmsgcred.cmcred_uid %lu", (u_long)cmsgcred->cmcred_uid);
1039 dbgmsg("cmsgcred.cmcred_euid %lu", (u_long)cmsgcred->cmcred_euid);
1040 dbgmsg("cmsgcred.cmcred_gid %lu", (u_long)cmsgcred->cmcred_gid);
1041 dbgmsg("cmsgcred.cmcred_ngroups %d", cmsgcred->cmcred_ngroups);
1043 if (cmsgcred->cmcred_pid != client_pid) {
1044 logmsgx("cmsgcred.cmcred_pid %ld != %ld",
1045 (long)cmsgcred->cmcred_pid, (long)client_pid);
1048 if (cmsgcred->cmcred_uid != proc_cred.uid) {
1049 logmsgx("cmsgcred.cmcred_uid %lu != %lu",
1050 (u_long)cmsgcred->cmcred_uid, (u_long)proc_cred.uid);
1053 if (cmsgcred->cmcred_euid != proc_cred.euid) {
1054 logmsgx("cmsgcred.cmcred_euid %lu != %lu",
1055 (u_long)cmsgcred->cmcred_euid, (u_long)proc_cred.euid);
1058 if (cmsgcred->cmcred_gid != proc_cred.gid) {
1059 logmsgx("cmsgcred.cmcred_gid %lu != %lu",
1060 (u_long)cmsgcred->cmcred_gid, (u_long)proc_cred.gid);
1063 if (cmsgcred->cmcred_ngroups == 0) {
1064 logmsgx("cmsgcred.cmcred_ngroups == 0");
1067 if (cmsgcred->cmcred_ngroups < 0) {
1068 logmsgx("cmsgcred.cmcred_ngroups %d < 0",
1069 cmsgcred->cmcred_ngroups);
1072 if (cmsgcred->cmcred_ngroups > CMGROUP_MAX) {
1073 logmsgx("cmsgcred.cmcred_ngroups %d > %d",
1074 cmsgcred->cmcred_ngroups, CMGROUP_MAX);
1077 if (cmsgcred->cmcred_groups[0] != proc_cred.egid) {
1078 logmsgx("cmsgcred.cmcred_groups[0] %lu != %lu (EGID)",
1079 (u_long)cmsgcred->cmcred_groups[0], (u_long)proc_cred.egid);
1082 if (check_groups("cmsgcred.cmcred_groups", cmsgcred->cmcred_groups,
1083 "cmsgcred.cmcred_ngroups", cmsgcred->cmcred_ngroups, false) < 0)
1089 check_scm_creds_sockcred(struct cmsghdr *cmsghdr)
1091 const struct sockcred *sockcred;
1093 if (check_cmsghdr(cmsghdr, SCM_CREDS,
1094 SOCKCREDSIZE(proc_cred.gid_num)) < 0)
1097 sockcred = (struct sockcred *)CMSG_DATA(cmsghdr);
1099 dbgmsg("sockcred.sc_uid %lu", (u_long)sockcred->sc_uid);
1100 dbgmsg("sockcred.sc_euid %lu", (u_long)sockcred->sc_euid);
1101 dbgmsg("sockcred.sc_gid %lu", (u_long)sockcred->sc_gid);
1102 dbgmsg("sockcred.sc_egid %lu", (u_long)sockcred->sc_egid);
1103 dbgmsg("sockcred.sc_ngroups %d", sockcred->sc_ngroups);
1105 if (sockcred->sc_uid != proc_cred.uid) {
1106 logmsgx("sockcred.sc_uid %lu != %lu",
1107 (u_long)sockcred->sc_uid, (u_long)proc_cred.uid);
1110 if (sockcred->sc_euid != proc_cred.euid) {
1111 logmsgx("sockcred.sc_euid %lu != %lu",
1112 (u_long)sockcred->sc_euid, (u_long)proc_cred.euid);
1115 if (sockcred->sc_gid != proc_cred.gid) {
1116 logmsgx("sockcred.sc_gid %lu != %lu",
1117 (u_long)sockcred->sc_gid, (u_long)proc_cred.gid);
1120 if (sockcred->sc_egid != proc_cred.egid) {
1121 logmsgx("sockcred.sc_egid %lu != %lu",
1122 (u_long)sockcred->sc_egid, (u_long)proc_cred.egid);
1125 if (sockcred->sc_ngroups == 0) {
1126 logmsgx("sockcred.sc_ngroups == 0");
1129 if (sockcred->sc_ngroups < 0) {
1130 logmsgx("sockcred.sc_ngroups %d < 0",
1131 sockcred->sc_ngroups);
1134 if (sockcred->sc_ngroups != proc_cred.gid_num) {
1135 logmsgx("sockcred.sc_ngroups %d != %u",
1136 sockcred->sc_ngroups, proc_cred.gid_num);
1139 if (check_groups("sockcred.sc_groups", sockcred->sc_groups,
1140 "sockcred.sc_ngroups", sockcred->sc_ngroups, true) < 0)
1146 check_scm_timestamp(struct cmsghdr *cmsghdr)
1148 const struct timeval *timeval;
1150 if (check_cmsghdr(cmsghdr, SCM_TIMESTAMP, sizeof(struct timeval)) < 0)
1153 timeval = (struct timeval *)CMSG_DATA(cmsghdr);
1155 dbgmsg("timeval.tv_sec %"PRIdMAX", timeval.tv_usec %"PRIdMAX,
1156 (intmax_t)timeval->tv_sec, (intmax_t)timeval->tv_usec);
1162 check_scm_bintime(struct cmsghdr *cmsghdr)
1164 const struct bintime *bintime;
1166 if (check_cmsghdr(cmsghdr, SCM_BINTIME, sizeof(struct bintime)) < 0)
1169 bintime = (struct bintime *)CMSG_DATA(cmsghdr);
1171 dbgmsg("bintime.sec %"PRIdMAX", bintime.frac %"PRIu64,
1172 (intmax_t)bintime->sec, bintime->frac);
1178 msghdr_init_generic(struct msghdr *msghdr, struct iovec *iov, void *cmsg_data)
1180 msghdr->msg_name = NULL;
1181 msghdr->msg_namelen = 0;
1182 if (send_data_flag) {
1183 iov->iov_base = server_flag ?
1184 ipc_msg.buf_recv : ipc_msg.buf_send;
1185 iov->iov_len = ipc_msg.buf_size;
1186 msghdr->msg_iov = iov;
1187 msghdr->msg_iovlen = 1;
1189 msghdr->msg_iov = NULL;
1190 msghdr->msg_iovlen = 0;
1192 msghdr->msg_control = cmsg_data;
1193 msghdr->msg_flags = 0;
1197 msghdr_init_server(struct msghdr *msghdr, struct iovec *iov,
1198 void *cmsg_data, size_t cmsg_size)
1200 msghdr_init_generic(msghdr, iov, cmsg_data);
1201 msghdr->msg_controllen = cmsg_size;
1202 dbgmsg("init: data size %zu", msghdr->msg_iov != NULL ?
1203 msghdr->msg_iov->iov_len : (size_t)0);
1204 dbgmsg("init: msghdr.msg_controllen %u",
1205 (u_int)msghdr->msg_controllen);
1209 msghdr_init_client(struct msghdr *msghdr, struct iovec *iov,
1210 void *cmsg_data, size_t cmsg_size, int type, size_t arr_size)
1212 struct cmsghdr *cmsghdr;
1214 msghdr_init_generic(msghdr, iov, cmsg_data);
1215 if (cmsg_data != NULL) {
1216 msghdr->msg_controllen = send_array_flag ?
1217 cmsg_size : CMSG_SPACE(0);
1218 cmsghdr = CMSG_FIRSTHDR(msghdr);
1219 cmsghdr->cmsg_level = SOL_SOCKET;
1220 cmsghdr->cmsg_type = type;
1221 cmsghdr->cmsg_len = CMSG_LEN(send_array_flag ? arr_size : 0);
1223 msghdr->msg_controllen = 0;
1227 t_generic(int (*client_func)(int), int (*server_func)(int))
1229 int fd, rv, rv_client;
1231 switch (client_fork()) {
1233 fd = socket_create();
1237 rv = client_func(fd);
1238 if (socket_close(fd) < 0)
1244 fd = socket_create();
1248 rv = server_func(fd);
1249 rv_client = client_wait();
1250 if (rv == 0 || (rv == -2 && rv_client != 0))
1252 if (socket_close(fd) < 0)
1263 t_cmsgcred_client(int fd)
1265 struct msghdr msghdr;
1266 struct iovec iov[1];
1271 if (sync_recv() < 0)
1276 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
1277 cmsg_data = malloc(cmsg_size);
1278 if (cmsg_data == NULL) {
1282 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1283 SCM_CREDS, sizeof(struct cmsgcred));
1285 if (socket_connect(fd) < 0)
1288 if (message_sendn(fd, &msghdr) < 0)
1298 t_cmsgcred_server(int fd1)
1300 struct msghdr msghdr;
1301 struct iovec iov[1];
1302 struct cmsghdr *cmsghdr;
1308 if (sync_send() < 0)
1314 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
1315 cmsg_data = malloc(cmsg_size);
1316 if (cmsg_data == NULL) {
1321 if (sock_type == SOCK_STREAM) {
1322 fd2 = socket_accept(fd1);
1329 for (i = 1; i <= ipc_msg.msg_num; ++i) {
1330 dbgmsg("message #%u", i);
1332 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1333 if (message_recv(fd2, &msghdr) < 0) {
1338 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1341 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1342 if (check_scm_creds_cmsgcred(cmsghdr) < 0)
1345 if (i > ipc_msg.msg_num)
1349 if (sock_type == SOCK_STREAM && fd2 >= 0)
1350 if (socket_close(fd2) < 0)
1358 return (t_generic(t_cmsgcred_client, t_cmsgcred_server));
1362 t_sockcred_client(int type, int fd)
1364 struct msghdr msghdr;
1365 struct iovec iov[1];
1368 if (sync_recv() < 0)
1373 msghdr_init_client(&msghdr, iov, NULL, 0, 0, 0);
1375 if (socket_connect(fd) < 0)
1379 if (sync_recv() < 0)
1382 if (message_sendn(fd, &msghdr) < 0)
1391 t_sockcred_server(int type, int fd1)
1393 struct msghdr msghdr;
1394 struct iovec iov[1];
1395 struct cmsghdr *cmsghdr;
1404 cmsg_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num));
1405 cmsg_data = malloc(cmsg_size);
1406 if (cmsg_data == NULL) {
1412 dbgmsg("setting LOCAL_CREDS");
1414 if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
1415 logmsg("setsockopt(LOCAL_CREDS)");
1420 if (sync_send() < 0)
1423 if (sock_type == SOCK_STREAM) {
1424 fd2 = socket_accept(fd1);
1431 dbgmsg("setting LOCAL_CREDS");
1433 if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
1434 logmsg("setsockopt(LOCAL_CREDS)");
1437 if (sync_send() < 0)
1442 for (i = 1; i <= ipc_msg.msg_num; ++i) {
1443 dbgmsg("message #%u", i);
1445 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1446 if (message_recv(fd2, &msghdr) < 0) {
1451 if (i > 1 && sock_type == SOCK_STREAM) {
1452 if (check_msghdr(&msghdr, 0) < 0)
1455 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1458 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1459 if (check_scm_creds_sockcred(cmsghdr) < 0)
1463 if (i > ipc_msg.msg_num)
1467 if (sock_type == SOCK_STREAM && fd2 >= 0)
1468 if (socket_close(fd2) < 0)
1477 int fd, rv, rv_client;
1479 switch (client_fork()) {
1481 for (i = 1; i <= 2; ++i) {
1482 dbgmsg("client #%u", i);
1483 fd = socket_create();
1487 rv = t_sockcred_client(1, fd);
1488 if (socket_close(fd) < 0)
1497 fd = socket_create();
1501 rv = t_sockcred_server(1, fd);
1503 rv = t_sockcred_server(3, fd);
1504 rv_client = client_wait();
1505 if (rv == 0 || (rv == -2 && rv_client != 0))
1507 if (socket_close(fd) < 0)
1519 t_sockcred_2_client(int fd)
1521 return (t_sockcred_client(2, fd));
1525 t_sockcred_2_server(int fd)
1527 return (t_sockcred_server(2, fd));
1533 return (t_generic(t_sockcred_2_client, t_sockcred_2_server));
1537 t_cmsgcred_sockcred_server(int fd1)
1539 struct msghdr msghdr;
1540 struct iovec iov[1];
1541 struct cmsghdr *cmsghdr;
1542 void *cmsg_data, *cmsg1_data, *cmsg2_data;
1543 size_t cmsg_size, cmsg1_size, cmsg2_size;
1550 cmsg1_size = CMSG_SPACE(SOCKCREDSIZE(proc_cred.gid_num));
1551 cmsg2_size = CMSG_SPACE(sizeof(struct cmsgcred));
1552 cmsg1_data = malloc(cmsg1_size);
1553 cmsg2_data = malloc(cmsg2_size);
1554 if (cmsg1_data == NULL || cmsg2_data == NULL) {
1559 dbgmsg("setting LOCAL_CREDS");
1561 if (setsockopt(fd1, 0, LOCAL_CREDS, &val, sizeof(val)) < 0) {
1562 logmsg("setsockopt(LOCAL_CREDS)");
1566 if (sync_send() < 0)
1569 if (sock_type == SOCK_STREAM) {
1570 fd2 = socket_accept(fd1);
1576 cmsg_data = cmsg1_data;
1577 cmsg_size = cmsg1_size;
1579 for (i = 1; i <= ipc_msg.msg_num; ++i) {
1580 dbgmsg("message #%u", i);
1582 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1583 if (message_recv(fd2, &msghdr) < 0) {
1588 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1591 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1592 if (i == 1 || sock_type == SOCK_DGRAM) {
1593 if (check_scm_creds_sockcred(cmsghdr) < 0)
1596 if (check_scm_creds_cmsgcred(cmsghdr) < 0)
1600 cmsg_data = cmsg2_data;
1601 cmsg_size = cmsg2_size;
1603 if (i > ipc_msg.msg_num)
1608 if (sock_type == SOCK_STREAM && fd2 >= 0)
1609 if (socket_close(fd2) < 0)
1615 t_cmsgcred_sockcred(void)
1617 return (t_generic(t_cmsgcred_client, t_cmsgcred_sockcred_server));
1621 t_timeval_client(int fd)
1623 struct msghdr msghdr;
1624 struct iovec iov[1];
1629 if (sync_recv() < 0)
1634 cmsg_size = CMSG_SPACE(sizeof(struct timeval));
1635 cmsg_data = malloc(cmsg_size);
1636 if (cmsg_data == NULL) {
1640 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1641 SCM_TIMESTAMP, sizeof(struct timeval));
1643 if (socket_connect(fd) < 0)
1646 if (message_sendn(fd, &msghdr) < 0)
1656 t_timeval_server(int fd1)
1658 struct msghdr msghdr;
1659 struct iovec iov[1];
1660 struct cmsghdr *cmsghdr;
1666 if (sync_send() < 0)
1672 cmsg_size = CMSG_SPACE(sizeof(struct timeval));
1673 cmsg_data = malloc(cmsg_size);
1674 if (cmsg_data == NULL) {
1679 if (sock_type == SOCK_STREAM) {
1680 fd2 = socket_accept(fd1);
1687 for (i = 1; i <= ipc_msg.msg_num; ++i) {
1688 dbgmsg("message #%u", i);
1690 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1691 if (message_recv(fd2, &msghdr) < 0) {
1696 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1699 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1700 if (check_scm_timestamp(cmsghdr) < 0)
1703 if (i > ipc_msg.msg_num)
1707 if (sock_type == SOCK_STREAM && fd2 >= 0)
1708 if (socket_close(fd2) < 0)
1716 return (t_generic(t_timeval_client, t_timeval_server));
1720 t_bintime_client(int fd)
1722 struct msghdr msghdr;
1723 struct iovec iov[1];
1728 if (sync_recv() < 0)
1733 cmsg_size = CMSG_SPACE(sizeof(struct bintime));
1734 cmsg_data = malloc(cmsg_size);
1735 if (cmsg_data == NULL) {
1739 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1740 SCM_BINTIME, sizeof(struct bintime));
1742 if (socket_connect(fd) < 0)
1745 if (message_sendn(fd, &msghdr) < 0)
1755 t_bintime_server(int fd1)
1757 struct msghdr msghdr;
1758 struct iovec iov[1];
1759 struct cmsghdr *cmsghdr;
1765 if (sync_send() < 0)
1771 cmsg_size = CMSG_SPACE(sizeof(struct bintime));
1772 cmsg_data = malloc(cmsg_size);
1773 if (cmsg_data == NULL) {
1778 if (sock_type == SOCK_STREAM) {
1779 fd2 = socket_accept(fd1);
1786 for (i = 1; i <= ipc_msg.msg_num; ++i) {
1787 dbgmsg("message #%u", i);
1789 msghdr_init_server(&msghdr, iov, cmsg_data, cmsg_size);
1790 if (message_recv(fd2, &msghdr) < 0) {
1795 if (check_msghdr(&msghdr, sizeof(*cmsghdr)) < 0)
1798 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1799 if (check_scm_bintime(cmsghdr) < 0)
1802 if (i > ipc_msg.msg_num)
1806 if (sock_type == SOCK_STREAM && fd2 >= 0)
1807 if (socket_close(fd2) < 0)
1815 return (t_generic(t_bintime_client, t_bintime_server));
1819 t_cmsg_len_client(int fd)
1821 struct msghdr msghdr;
1822 struct iovec iov[1];
1823 struct cmsghdr *cmsghdr;
1825 size_t size, cmsg_size;
1829 if (sync_recv() < 0)
1834 cmsg_size = CMSG_SPACE(sizeof(struct cmsgcred));
1835 cmsg_data = malloc(cmsg_size);
1836 if (cmsg_data == NULL) {
1840 msghdr_init_client(&msghdr, iov, cmsg_data, cmsg_size,
1841 SCM_CREDS, sizeof(struct cmsgcred));
1842 cmsghdr = CMSG_FIRSTHDR(&msghdr);
1844 if (socket_connect(fd) < 0)
1847 size = msghdr.msg_iov != NULL ? msghdr.msg_iov->iov_len : 0;
1849 for (socklen = 0; socklen < CMSG_LEN(0); ++socklen) {
1850 cmsghdr->cmsg_len = socklen;
1851 dbgmsg("send: data size %zu", size);
1852 dbgmsg("send: msghdr.msg_controllen %u",
1853 (u_int)msghdr.msg_controllen);
1854 dbgmsg("send: cmsghdr.cmsg_len %u",
1855 (u_int)cmsghdr->cmsg_len);
1856 if (sendmsg(fd, &msghdr, 0) < 0)
1858 logmsgx("sent message with cmsghdr.cmsg_len %u < %u",
1859 (u_int)cmsghdr->cmsg_len, (u_int)CMSG_LEN(0));
1862 if (socklen == CMSG_LEN(0))
1865 if (sync_send() < 0) {
1875 t_cmsg_len_server(int fd1)
1879 if (sync_send() < 0)
1884 if (sock_type == SOCK_STREAM) {
1885 fd2 = socket_accept(fd1);
1891 if (sync_recv() < 0)
1896 if (sock_type == SOCK_STREAM && fd2 >= 0)
1897 if (socket_close(fd2) < 0)
1905 return (t_generic(t_cmsg_len_client, t_cmsg_len_server));
1909 t_peercred_client(int fd)
1911 struct xucred xucred;
1914 if (sync_recv() < 0)
1917 if (socket_connect(fd) < 0)
1920 len = sizeof(xucred);
1921 if (getsockopt(fd, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
1922 logmsg("getsockopt(LOCAL_PEERCRED)");
1926 if (check_xucred(&xucred, len) < 0)
1933 t_peercred_server(int fd1)
1935 struct xucred xucred;
1939 if (sync_send() < 0)
1942 fd2 = socket_accept(fd1);
1946 len = sizeof(xucred);
1947 if (getsockopt(fd2, 0, LOCAL_PEERCRED, &xucred, &len) < 0) {
1948 logmsg("getsockopt(LOCAL_PEERCRED)");
1953 if (check_xucred(&xucred, len) < 0) {
1960 if (socket_close(fd2) < 0)
1968 return (t_generic(t_peercred_client, t_peercred_server));