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/types.h>
31 #include <sys/resource.h>
33 #include <sys/socket.h>
54 * There are tables with tests descriptions and pointers to test
55 * functions. Each t_*() function returns 0 if its test passed,
56 * -1 if its test failed (something wrong was found in local domain
57 * control messages), -2 if some system error occurred. If test
58 * function returns -2, then a program exits.
60 * Each test function completely control what to do (eg. fork or
61 * do not fork a client process). If a test function forks a client
62 * process, then it waits for its termination. If a return code of a
63 * client process is not equal to zero, or if a client process was
64 * terminated by a signal, then test function returns -2.
66 * Each test function and complete program are not optimized
67 * a lot to allow easy to modify tests.
69 * Each function which can block, is run under TIMEOUT, if timeout
70 * occurs, then test function returns -2 or a client process exits
71 * with nonzero return code.
82 #define EXTRA_CMSG_SPACE 512 /* Memory for not expected control data. */
84 static int t_cmsgcred(void), t_sockcred_stream1(void);
85 static int t_sockcred_stream2(void), t_cmsgcred_sockcred(void);
86 static int t_sockcred_dgram(void), t_timestamp(void);
89 int (*func)(void); /* Pointer to function. */
90 const char *desc; /* Test description. */
93 static struct test_func test_stream_tbl[] = {
94 { NULL, " 0: All tests" },
95 { t_cmsgcred, " 1: Sending, receiving cmsgcred" },
96 { t_sockcred_stream1, " 2: Receiving sockcred (listening socket has LOCAL_CREDS)" },
97 { t_sockcred_stream2, " 3: Receiving sockcred (accepted socket has LOCAL_CREDS)" },
98 { t_cmsgcred_sockcred, " 4: Sending cmsgcred, receiving sockcred" },
99 { t_timestamp, " 5: Sending, receiving timestamp" },
103 static struct test_func test_dgram_tbl[] = {
104 { NULL, " 0: All tests" },
105 { t_cmsgcred, " 1: Sending, receiving cmsgcred" },
106 { t_sockcred_dgram, " 2: Receiving sockcred" },
107 { t_cmsgcred_sockcred, " 3: Sending cmsgcred, receiving sockcred" },
108 { t_timestamp, " 4: Sending, receiving timestamp" },
112 #define TEST_STREAM_NO_MAX (sizeof(test_stream_tbl) / sizeof(struct test_func) - 2)
113 #define TEST_DGRAM_NO_MAX (sizeof(test_dgram_tbl) / sizeof(struct test_func) - 2)
115 static const char *myname = "SERVER"; /* "SERVER" or "CLIENT" */
117 static int debug = 0; /* 1, if -d. */
118 static int no_control_data = 0; /* 1, if -z. */
120 static u_int nfailed = 0; /* Number of failed tests. */
122 static int sock_type; /* SOCK_STREAM or SOCK_DGRAM */
123 static const char *sock_type_str; /* "SOCK_STREAM" or "SOCK_DGRAN" */
125 static char tempdir[] = "/tmp/unix_cmsg.XXXXXXX";
126 static char serv_sock_path[PATH_MAX];
128 static char ipc_message[] = "hello";
130 #define IPC_MESSAGE_SIZE (sizeof(ipc_message))
132 static struct sockaddr_un servaddr; /* Server address. */
134 static sigjmp_buf env_alrm;
137 static uid_t my_euid;
139 static gid_t my_egid;
142 * my_gids[0] is EGID, next items are supplementary GIDs,
143 * my_ngids determines valid items in my_gids array.
145 static gid_t my_gids[NGROUPS_MAX];
148 static pid_t client_pid; /* PID of forked client. */
150 #define dbgmsg(x) do { \
153 } while (/* CONSTCOND */0)
155 static void logmsg(const char *, ...) __printflike(1, 2);
156 static void logmsgx(const char *, ...) __printflike(1, 2);
157 static void output(const char *, ...) __printflike(1, 2);
159 extern char *__progname; /* The name of program. */
162 * Output the help message (-h switch).
167 const struct test_func *test_func;
169 fprintf(stderr, "Usage: %s [-dhz] [-t <socktype>] [testno]\n",
173 fprintf(stderr, "\n Options are:\n\
174 -d\t\t\tOutput debugging information\n\
175 -h\t\t\tOutput this help message and exit\n\
176 -t <socktype>\t\tRun test only for the given socket type:\n\
177 \t\t\tstream or dgram\n\
178 -z\t\t\tDo not send real control data if possible\n\n");
179 fprintf(stderr, " Available tests for stream sockets:\n");
180 for (test_func = test_stream_tbl; test_func->desc != NULL; ++test_func)
181 fprintf(stderr, " %s\n", test_func->desc);
182 fprintf(stderr, "\n Available tests for datagram sockets:\n");
183 for (test_func = test_dgram_tbl; test_func->desc != NULL; ++test_func)
184 fprintf(stderr, " %s\n", test_func->desc);
188 * printf-like function for outputting to STDOUT_FILENO.
191 output(const char *format, ...)
196 va_start(ap, format);
197 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
198 err(EX_SOFTWARE, "output: vsnprintf failed");
199 write(STDOUT_FILENO, buf, strlen(buf));
204 * printf-like function for logging, also outputs message for errno.
207 logmsg(const char *format, ...)
213 errno_save = errno; /* Save errno. */
215 va_start(ap, format);
216 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
217 err(EX_SOFTWARE, "logmsg: vsnprintf failed");
219 output("%s: %s\n", myname, buf);
221 output("%s: %s: %s\n", myname, buf, strerror(errno_save));
224 errno = errno_save; /* Restore errno. */
228 * printf-like function for logging, do not output message for errno.
231 logmsgx(const char *format, ...)
236 va_start(ap, format);
237 if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
238 err(EX_SOFTWARE, "logmsgx: vsnprintf failed");
239 output("%s: %s\n", myname, buf);
244 * Run tests from testno1 to testno2.
247 run_tests(u_int testno1, u_int testno2)
249 const struct test_func *test_func;
252 output("Running tests for %s sockets:\n", sock_type_str);
253 test_func = (sock_type == SOCK_STREAM ?
254 test_stream_tbl : test_dgram_tbl) + testno1;
257 for (i = testno1; i <= testno2; ++test_func, ++i) {
258 output(" %s\n", test_func->desc);
259 switch (test_func->func()) {
264 logmsgx("some system error occurred, exiting");
271 if (testno1 != testno2) {
273 output("-- all tests were passed!\n");
275 output("-- %u test%s failed!\n", nfailed1,
276 nfailed1 == 1 ? "" : "s");
279 output("-- test was passed!\n");
281 output("-- test failed!\n");
289 sig_alrm(int signo __unused)
291 siglongjmp(env_alrm, 1);
295 * Initialize signals handlers.
302 sa.sa_handler = SIG_IGN;
303 sigemptyset(&sa.sa_mask);
305 if (sigaction(SIGPIPE, &sa, (struct sigaction *)NULL) < 0)
306 err(EX_OSERR, "sigaction(SIGPIPE)");
308 sa.sa_handler = sig_alrm;
309 if (sigaction(SIGALRM, &sa, (struct sigaction *)NULL) < 0)
310 err(EX_OSERR, "sigaction(SIGALRM)");
314 main(int argc, char *argv[])
317 int opt, dgramflag, streamflag;
318 u_int testno1, testno2;
320 dgramflag = streamflag = 0;
321 while ((opt = getopt(argc, argv, "dht:z")) != -1)
330 if (strcmp(optarg, "stream") == 0)
332 else if (strcmp(optarg, "dgram") == 0)
335 errx(EX_USAGE, "wrong socket type in -t option");
347 if (optind + 1 != argc)
348 errx(EX_USAGE, "too many arguments");
349 testno1 = strtonum(argv[optind], 0, UINT_MAX, &errstr);
351 errx(EX_USAGE, "wrong test number: %s", errstr);
355 if (dgramflag == 0 && streamflag == 0)
356 dgramflag = streamflag = 1;
358 if (dgramflag && streamflag && testno1 != 0)
359 errx(EX_USAGE, "you can use particular test, only with datagram or stream sockets");
362 if (testno1 > TEST_STREAM_NO_MAX)
363 errx(EX_USAGE, "given test %u for stream sockets does not exist",
366 if (testno1 > TEST_DGRAM_NO_MAX)
367 errx(EX_USAGE, "given test %u for datagram sockets does not exist",
375 switch (my_ngids = getgroups(sizeof(my_gids) / sizeof(my_gids[0]), my_gids)) {
377 err(EX_SOFTWARE, "getgroups");
380 errx(EX_OSERR, "getgroups returned 0 groups");
385 if (mkdtemp(tempdir) == NULL)
386 err(EX_OSERR, "mkdtemp");
389 sock_type = SOCK_STREAM;
390 sock_type_str = "SOCK_STREAM";
393 testno2 = TEST_STREAM_NO_MAX;
396 if (run_tests(testno1, testno2) < 0)
402 sock_type = SOCK_DGRAM;
403 sock_type_str = "SOCK_DGRAM";
406 testno2 = TEST_DGRAM_NO_MAX;
409 if (run_tests(testno1, testno2) < 0)
413 if (rmdir(tempdir) < 0) {
414 logmsg("rmdir(%s)", tempdir);
418 return (nfailed ? EX_OSERR : EX_OK);
421 if (rmdir(tempdir) < 0)
422 logmsg("rmdir(%s)", tempdir);
427 * Create PF_LOCAL socket, if sock_path is not equal to NULL, then
428 * bind() it. Return socket address in addr. Return file descriptor
429 * or -1 if some error occurred.
432 create_socket(char *sock_path, size_t sock_path_len, struct sockaddr_un *addr)
436 if ((fd = socket(PF_LOCAL, sock_type, 0)) < 0) {
437 logmsg("create_socket: socket(PF_LOCAL, %s, 0)", sock_type_str);
441 if (sock_path != NULL) {
442 if ((rv = snprintf(sock_path, sock_path_len, "%s/%s",
443 tempdir, myname)) < 0) {
444 logmsg("create_socket: snprintf failed");
447 if ((size_t)rv >= sock_path_len) {
448 logmsgx("create_socket: too long path name for given buffer");
452 memset(addr, 0, sizeof(addr));
453 addr->sun_family = AF_LOCAL;
454 if (strlen(sock_path) >= sizeof(addr->sun_path)) {
455 logmsgx("create_socket: too long path name (>= %lu) for local domain socket",
456 (u_long)sizeof(addr->sun_path));
459 strcpy(addr->sun_path, sock_path);
461 if (bind(fd, (struct sockaddr *)addr, SUN_LEN(addr)) < 0) {
462 logmsg("create_socket: bind(%s)", sock_path);
471 logmsg("create_socket: close");
476 * Call create_socket() for server listening socket.
477 * Return socket descriptor or -1 if some error occurred.
480 create_server_socket(void)
482 return (create_socket(serv_sock_path, sizeof(serv_sock_path), &servaddr));
486 * Create unbound socket.
489 create_unbound_socket(void)
491 return (create_socket((char *)NULL, 0, (struct sockaddr_un *)NULL));
495 * Close socket descriptor, if sock_path is not equal to NULL,
496 * then unlink the given path.
499 close_socket(const char *sock_path, int fd)
504 logmsg("close_socket: close");
507 if (sock_path != NULL)
508 if (unlink(sock_path) < 0) {
509 logmsg("close_socket: unlink(%s)", sock_path);
516 * Connect to server (socket address in servaddr).
519 connect_server(int fd)
521 dbgmsg(("connecting to %s", serv_sock_path));
524 * If PF_LOCAL listening socket's queue is full, then connect()
525 * returns ECONNREFUSED immediately, do not need timeout.
527 if (connect(fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
528 logmsg("connect_server: connect(%s)", serv_sock_path);
536 * sendmsg() with timeout.
539 sendmsg_timeout(int fd, struct msghdr *msg, size_t n)
543 dbgmsg(("sending %lu bytes", (u_long)n));
545 if (sigsetjmp(env_alrm, 1) != 0) {
546 logmsgx("sendmsg_timeout: cannot send message to %s (timeout)", serv_sock_path);
550 (void)alarm(TIMEOUT);
552 nsent = sendmsg(fd, msg, 0);
557 logmsg("sendmsg_timeout: sendmsg");
561 if ((size_t)nsent != n) {
562 logmsgx("sendmsg_timeout: sendmsg: short send: %ld of %lu bytes",
563 (long)nsent, (u_long)n);
571 * accept() with timeout.
574 accept_timeout(int listenfd)
578 dbgmsg(("accepting connection"));
580 if (sigsetjmp(env_alrm, 1) != 0) {
581 logmsgx("accept_timeout: cannot accept connection (timeout)");
585 (void)alarm(TIMEOUT);
587 fd = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL);
592 logmsg("accept_timeout: accept");
600 * recvmsg() with timeout.
603 recvmsg_timeout(int fd, struct msghdr *msg, size_t n)
607 dbgmsg(("receiving %lu bytes", (u_long)n));
609 if (sigsetjmp(env_alrm, 1) != 0) {
610 logmsgx("recvmsg_timeout: cannot receive message (timeout)");
614 (void)alarm(TIMEOUT);
616 nread = recvmsg(fd, msg, MSG_WAITALL);
621 logmsg("recvmsg_timeout: recvmsg");
625 if ((size_t)nread != n) {
626 logmsgx("recvmsg_timeout: recvmsg: short read: %ld of %lu bytes",
627 (long)nread, (u_long)n);
635 * Wait for synchronization message (1 byte) with timeout.
643 dbgmsg(("waiting for sync message"));
645 if (sigsetjmp(env_alrm, 1) != 0) {
646 logmsgx("sync_recv: cannot receive sync message (timeout)");
650 (void)alarm(TIMEOUT);
652 nread = read(fd, &buf, 1);
657 logmsg("sync_recv: read");
662 logmsgx("sync_recv: read: short read: %ld of 1 byte",
671 * Send synchronization message (1 byte) with timeout.
678 dbgmsg(("sending sync message"));
680 if (sigsetjmp(env_alrm, 1) != 0) {
681 logmsgx("sync_send: cannot send sync message (timeout)");
685 (void)alarm(TIMEOUT);
687 nsent = write(fd, "", 1);
692 logmsg("sync_send: write");
697 logmsgx("sync_send: write: short write: %ld of 1 byte",
706 * waitpid() for client with timeout.
714 if (sigsetjmp(env_alrm, 1) != 0) {
715 logmsgx("wait_client: cannot get exit status of client PID %ld (timeout)",
720 (void)alarm(TIMEOUT);
722 pid = waitpid(client_pid, &status, 0);
726 if (pid == (pid_t)-1) {
727 logmsg("wait_client: waitpid");
731 if (WIFEXITED(status)) {
732 if (WEXITSTATUS(status) != 0) {
733 logmsgx("wait_client: exit status of client PID %ld is %d",
734 (long)client_pid, WEXITSTATUS(status));
738 if (WIFSIGNALED(status))
739 logmsgx("wait_client: abnormal termination of client PID %ld, signal %d%s",
740 (long)client_pid, WTERMSIG(status), WCOREDUMP(status) ? " (core file generated)" : "");
742 logmsgx("wait_client: termination of client PID %ld, unknown status",
751 * Check if n supplementary GIDs in gids are correct. (my_gids + 1)
752 * has (my_ngids - 1) supplementary GIDs of current process.
755 check_groups(const gid_t *gids, int n)
757 char match[NGROUPS_MAX] = { 0 };
760 if (n != my_ngids - 1) {
761 logmsgx("wrong number of groups %d != %d (returned from getgroups() - 1)",
766 for (i = 0; i < n; ++i) {
767 for (j = 1; j < my_ngids; ++j) {
768 if (gids[i] == my_gids[j]) {
770 logmsgx("duplicated GID %lu",
779 logmsgx("unexpected GID %lu", (u_long)gids[i]);
783 for (j = 1; j < my_ngids; ++j)
785 logmsgx("did not receive supplementary GID %u", my_gids[j]);
792 * Send n messages with data and control message with SCM_CREDS type
793 * to server and exit.
796 t_cmsgcred_client(u_int n)
800 char control[CMSG_SPACE(sizeof(struct cmsgcred))];
804 struct cmsghdr *cmptr;
808 assert(n == 1 || n == 2);
810 if ((fd = create_unbound_socket()) < 0)
813 if (connect_server(fd) < 0)
816 iov[0].iov_base = ipc_message;
817 iov[0].iov_len = IPC_MESSAGE_SIZE;
823 msg.msg_control = control_un.control;
824 msg.msg_controllen = no_control_data ?
825 sizeof(struct cmsghdr) : sizeof(control_un.control);
828 cmptr = CMSG_FIRSTHDR(&msg);
829 cmptr->cmsg_len = CMSG_LEN(no_control_data ?
830 0 : sizeof(struct cmsgcred));
831 cmptr->cmsg_level = SOL_SOCKET;
832 cmptr->cmsg_type = SCM_CREDS;
834 for (i = 0; i < n; ++i) {
835 dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i,
836 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
837 if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0)
841 if (close_socket((const char *)NULL, fd) < 0)
847 (void)close_socket((const char *)NULL, fd);
854 * Receive two messages with data and control message with SCM_CREDS
855 * type followed by struct cmsgcred{} from client. fd1 is a listen
856 * socket for stream sockets or simply socket for datagram sockets.
859 t_cmsgcred_server(int fd1)
861 char buf[IPC_MESSAGE_SIZE];
864 char control[CMSG_SPACE(sizeof(struct cmsgcred)) + EXTRA_CMSG_SPACE];
868 struct cmsghdr *cmptr;
869 const struct cmsgcred *cmcredptr;
870 socklen_t controllen;
871 int error, error2, fd2;
874 if (sock_type == SOCK_STREAM) {
875 if ((fd2 = accept_timeout(fd1)) < 0)
882 controllen = sizeof(control_un.control);
884 for (i = 0; i < 2; ++i) {
885 iov[0].iov_base = buf;
886 iov[0].iov_len = sizeof(buf);
892 msg.msg_control = control_un.control;
893 msg.msg_controllen = controllen;
896 controllen = CMSG_SPACE(sizeof(struct cmsgcred));
898 if (recvmsg_timeout(fd2, &msg, sizeof(buf)) < 0)
901 if (msg.msg_flags & MSG_CTRUNC) {
902 logmsgx("#%u control data was truncated, MSG_CTRUNC flag is on",
907 if (msg.msg_controllen < sizeof(struct cmsghdr)) {
908 logmsgx("#%u msg_controllen %u < %lu (sizeof(struct cmsghdr))",
909 i, (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr));
913 if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) {
914 logmsgx("CMSG_FIRSTHDR is NULL");
918 dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i,
919 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
921 if (cmptr->cmsg_level != SOL_SOCKET) {
922 logmsgx("#%u cmsg_level %d != SOL_SOCKET", i,
927 if (cmptr->cmsg_type != SCM_CREDS) {
928 logmsgx("#%u cmsg_type %d != SCM_CREDS", i,
933 if (cmptr->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred))) {
934 logmsgx("#%u cmsg_len %u != %lu (CMSG_LEN(sizeof(struct cmsgcred))",
935 i, (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(sizeof(struct cmsgcred)));
939 cmcredptr = (const struct cmsgcred *)CMSG_DATA(cmptr);
942 if (cmcredptr->cmcred_pid != client_pid) {
943 logmsgx("#%u cmcred_pid %ld != %ld (PID of client)",
944 i, (long)cmcredptr->cmcred_pid, (long)client_pid);
947 if (cmcredptr->cmcred_uid != my_uid) {
948 logmsgx("#%u cmcred_uid %lu != %lu (UID of current process)",
949 i, (u_long)cmcredptr->cmcred_uid, (u_long)my_uid);
952 if (cmcredptr->cmcred_euid != my_euid) {
953 logmsgx("#%u cmcred_euid %lu != %lu (EUID of current process)",
954 i, (u_long)cmcredptr->cmcred_euid, (u_long)my_euid);
957 if (cmcredptr->cmcred_gid != my_gid) {
958 logmsgx("#%u cmcred_gid %lu != %lu (GID of current process)",
959 i, (u_long)cmcredptr->cmcred_gid, (u_long)my_gid);
962 if (cmcredptr->cmcred_ngroups == 0) {
963 logmsgx("#%u cmcred_ngroups = 0, this is wrong", i);
966 if (cmcredptr->cmcred_ngroups > NGROUPS_MAX) {
967 logmsgx("#%u cmcred_ngroups %d > %u (NGROUPS_MAX)",
968 i, cmcredptr->cmcred_ngroups, NGROUPS_MAX);
970 } else if (cmcredptr->cmcred_ngroups < 0) {
971 logmsgx("#%u cmcred_ngroups %d < 0",
972 i, cmcredptr->cmcred_ngroups);
975 dbgmsg(("#%u cmcred_ngroups = %d", i,
976 cmcredptr->cmcred_ngroups));
977 if (cmcredptr->cmcred_groups[0] != my_egid) {
978 logmsgx("#%u cmcred_groups[0] %lu != %lu (EGID of current process)",
979 i, (u_long)cmcredptr->cmcred_groups[0], (u_long)my_egid);
982 if (check_groups(cmcredptr->cmcred_groups + 1, cmcredptr->cmcred_ngroups - 1) < 0) {
983 logmsgx("#%u cmcred_groups has wrong GIDs", i);
992 if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) {
993 logmsgx("#%u control data has extra header", i);
1002 if (sock_type == SOCK_STREAM)
1003 if (close(fd2) < 0) {
1010 if (sock_type == SOCK_STREAM)
1021 if ((fd = create_server_socket()) < 0)
1024 if (sock_type == SOCK_STREAM)
1025 if (listen(fd, LISTENQ) < 0) {
1030 if ((client_pid = fork()) == (pid_t)-1) {
1035 if (client_pid == 0) {
1037 if (close_socket((const char *)NULL, fd) < 0)
1039 t_cmsgcred_client(2);
1042 if ((error = t_cmsgcred_server(fd)) == -2) {
1043 (void)wait_client();
1047 if (wait_client() < 0)
1050 if (close_socket(serv_sock_path, fd) < 0) {
1051 logmsgx("close_socket failed");
1057 if (close_socket(serv_sock_path, fd) < 0)
1058 logmsgx("close_socket failed");
1063 * Send two messages with data to server and exit.
1066 t_sockcred_client(int type)
1069 struct iovec iov[1];
1073 assert(type == 0 || type == 1);
1075 if ((fd = create_unbound_socket()) < 0)
1078 if (connect_server(fd) < 0)
1082 if (sync_recv(fd) < 0)
1085 iov[0].iov_base = ipc_message;
1086 iov[0].iov_len = IPC_MESSAGE_SIZE;
1088 msg.msg_name = NULL;
1089 msg.msg_namelen = 0;
1092 msg.msg_control = NULL;
1093 msg.msg_controllen = 0;
1096 for (i = 0; i < 2; ++i)
1097 if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0)
1100 if (close_socket((const char *)NULL, fd) < 0)
1106 (void)close_socket((const char *)NULL, fd);
1113 * Receive one message with data and control message with SCM_CREDS
1114 * type followed by struct sockcred{} and if n is not equal 1, then
1115 * receive another one message with data. fd1 is a listen socket for
1116 * stream sockets or simply socket for datagram sockets. If type is
1117 * 1, then set LOCAL_CREDS option for accepted stream socket.
1120 t_sockcred_server(int type, int fd1, u_int n)
1122 char buf[IPC_MESSAGE_SIZE];
1125 char control[CMSG_SPACE(SOCKCREDSIZE(NGROUPS_MAX)) + EXTRA_CMSG_SPACE];
1128 struct iovec iov[1];
1129 struct cmsghdr *cmptr;
1130 const struct sockcred *sockcred;
1131 int error, error2, fd2, optval;
1134 assert(n == 1 || n == 2);
1135 assert(type == 0 || type == 1);
1137 if (sock_type == SOCK_STREAM) {
1138 if ((fd2 = accept_timeout(fd1)) < 0)
1142 if (setsockopt(fd2, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) {
1143 logmsg("setsockopt(LOCAL_CREDS) for accepted socket");
1144 if (errno == ENOPROTOOPT) {
1150 if (sync_send(fd2) < 0)
1158 for (i = 0; i < n; ++i) {
1159 iov[0].iov_base = buf;
1160 iov[0].iov_len = sizeof buf;
1162 msg.msg_name = NULL;
1163 msg.msg_namelen = 0;
1166 msg.msg_control = control_un.control;
1167 msg.msg_controllen = sizeof control_un.control;
1170 if (recvmsg_timeout(fd2, &msg, sizeof buf) < 0)
1173 if (msg.msg_flags & MSG_CTRUNC) {
1174 logmsgx("control data was truncated, MSG_CTRUNC flag is on");
1178 if (i != 0 && sock_type == SOCK_STREAM) {
1179 if (msg.msg_controllen != 0) {
1180 logmsgx("second message has control data, this is wrong for stream sockets");
1183 dbgmsg(("#%u msg_controllen = %u", i,
1184 (u_int)msg.msg_controllen));
1188 if (msg.msg_controllen < sizeof(struct cmsghdr)) {
1189 logmsgx("#%u msg_controllen %u < %lu (sizeof(struct cmsghdr))",
1190 i, (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr));
1194 if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) {
1195 logmsgx("CMSG_FIRSTHDR is NULL");
1199 dbgmsg(("#%u msg_controllen = %u, cmsg_len = %u", i,
1200 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
1202 if (cmptr->cmsg_level != SOL_SOCKET) {
1203 logmsgx("#%u cmsg_level %d != SOL_SOCKET", i,
1208 if (cmptr->cmsg_type != SCM_CREDS) {
1209 logmsgx("#%u cmsg_type %d != SCM_CREDS", i,
1214 if (cmptr->cmsg_len < CMSG_LEN(SOCKCREDSIZE(1))) {
1215 logmsgx("#%u cmsg_len %u != %lu (CMSG_LEN(SOCKCREDSIZE(1)))",
1216 i, (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(SOCKCREDSIZE(1)));
1220 sockcred = (const struct sockcred *)CMSG_DATA(cmptr);
1223 if (sockcred->sc_uid != my_uid) {
1224 logmsgx("#%u sc_uid %lu != %lu (UID of current process)",
1225 i, (u_long)sockcred->sc_uid, (u_long)my_uid);
1228 if (sockcred->sc_euid != my_euid) {
1229 logmsgx("#%u sc_euid %lu != %lu (EUID of current process)",
1230 i, (u_long)sockcred->sc_euid, (u_long)my_euid);
1233 if (sockcred->sc_gid != my_gid) {
1234 logmsgx("#%u sc_gid %lu != %lu (GID of current process)",
1235 i, (u_long)sockcred->sc_gid, (u_long)my_gid);
1238 if (sockcred->sc_egid != my_egid) {
1239 logmsgx("#%u sc_egid %lu != %lu (EGID of current process)",
1240 i, (u_long)sockcred->sc_gid, (u_long)my_egid);
1243 if (sockcred->sc_ngroups > NGROUPS_MAX) {
1244 logmsgx("#%u sc_ngroups %d > %u (NGROUPS_MAX)",
1245 i, sockcred->sc_ngroups, NGROUPS_MAX);
1247 } else if (sockcred->sc_ngroups < 0) {
1248 logmsgx("#%u sc_ngroups %d < 0",
1249 i, sockcred->sc_ngroups);
1252 dbgmsg(("#%u sc_ngroups = %d", i, sockcred->sc_ngroups));
1253 if (check_groups(sockcred->sc_groups, sockcred->sc_ngroups) < 0) {
1254 logmsgx("#%u sc_groups has wrong GIDs", i);
1262 if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) {
1263 logmsgx("#%u control data has extra header, this is wrong",
1274 if (sock_type == SOCK_STREAM)
1275 if (close(fd2) < 0) {
1282 if (sock_type == SOCK_STREAM)
1289 t_sockcred(int type)
1291 int error, fd, optval;
1293 assert(type == 0 || type == 1);
1295 if ((fd = create_server_socket()) < 0)
1298 if (sock_type == SOCK_STREAM)
1299 if (listen(fd, LISTENQ) < 0) {
1306 if (setsockopt(fd, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) {
1307 logmsg("setsockopt(LOCAL_CREDS) for %s socket",
1308 sock_type == SOCK_STREAM ? "stream listening" : "datagram");
1309 if (errno == ENOPROTOOPT) {
1317 if ((client_pid = fork()) == (pid_t)-1) {
1322 if (client_pid == 0) {
1324 if (close_socket((const char *)NULL, fd) < 0)
1326 t_sockcred_client(type);
1329 if ((error = t_sockcred_server(type, fd, 2)) == -2) {
1330 (void)wait_client();
1334 if (wait_client() < 0)
1338 if (close_socket(serv_sock_path, fd) < 0) {
1339 logmsgx("close_socket failed");
1345 if (close_socket(serv_sock_path, fd) < 0)
1346 logmsgx("close_socket failed");
1351 t_sockcred_stream1(void)
1353 return (t_sockcred(0));
1357 t_sockcred_stream2(void)
1359 return (t_sockcred(1));
1363 t_sockcred_dgram(void)
1365 return (t_sockcred(0));
1369 t_cmsgcred_sockcred(void)
1371 int error, fd, optval;
1373 if ((fd = create_server_socket()) < 0)
1376 if (sock_type == SOCK_STREAM)
1377 if (listen(fd, LISTENQ) < 0) {
1383 if (setsockopt(fd, 0, LOCAL_CREDS, &optval, sizeof optval) < 0) {
1384 logmsg("setsockopt(LOCAL_CREDS) for %s socket",
1385 sock_type == SOCK_STREAM ? "stream listening" : "datagram");
1386 if (errno == ENOPROTOOPT) {
1393 if ((client_pid = fork()) == (pid_t)-1) {
1398 if (client_pid == 0) {
1400 if (close_socket((const char *)NULL, fd) < 0)
1402 t_cmsgcred_client(1);
1405 if ((error = t_sockcred_server(0, fd, 1)) == -2) {
1406 (void)wait_client();
1410 if (wait_client() < 0)
1414 if (close_socket(serv_sock_path, fd) < 0) {
1415 logmsgx("close_socket failed");
1421 if (close_socket(serv_sock_path, fd) < 0)
1422 logmsgx("close_socket failed");
1427 * Send one message with data and control message with SCM_TIMESTAMP
1428 * type to server and exit.
1431 t_timestamp_client(void)
1435 char control[CMSG_SPACE(sizeof(struct timeval))];
1438 struct iovec iov[1];
1439 struct cmsghdr *cmptr;
1442 if ((fd = create_unbound_socket()) < 0)
1445 if (connect_server(fd) < 0)
1448 iov[0].iov_base = ipc_message;
1449 iov[0].iov_len = IPC_MESSAGE_SIZE;
1451 msg.msg_name = NULL;
1452 msg.msg_namelen = 0;
1455 msg.msg_control = control_un.control;
1456 msg.msg_controllen = no_control_data ?
1457 sizeof(struct cmsghdr) :sizeof control_un.control;
1460 cmptr = CMSG_FIRSTHDR(&msg);
1461 cmptr->cmsg_len = CMSG_LEN(no_control_data ?
1462 0 : sizeof(struct timeval));
1463 cmptr->cmsg_level = SOL_SOCKET;
1464 cmptr->cmsg_type = SCM_TIMESTAMP;
1466 dbgmsg(("msg_controllen = %u, cmsg_len = %u",
1467 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
1469 if (sendmsg_timeout(fd, &msg, IPC_MESSAGE_SIZE) < 0)
1472 if (close_socket((const char *)NULL, fd) < 0)
1478 (void)close_socket((const char *)NULL, fd);
1485 * Receive one message with data and control message with SCM_TIMESTAMP
1486 * type followed by struct timeval{} from client.
1489 t_timestamp_server(int fd1)
1493 char control[CMSG_SPACE(sizeof(struct timeval)) + EXTRA_CMSG_SPACE];
1495 char buf[IPC_MESSAGE_SIZE];
1498 struct iovec iov[1];
1499 struct cmsghdr *cmptr;
1500 const struct timeval *timeval;
1502 if (sock_type == SOCK_STREAM) {
1503 if ((fd2 = accept_timeout(fd1)) < 0)
1508 iov[0].iov_base = buf;
1509 iov[0].iov_len = sizeof buf;
1511 msg.msg_name = NULL;
1512 msg.msg_namelen = 0;
1515 msg.msg_control = control_un.control;
1516 msg.msg_controllen = sizeof control_un.control;;
1519 if (recvmsg_timeout(fd2, &msg, sizeof buf) < 0)
1524 if (msg.msg_flags & MSG_CTRUNC) {
1525 logmsgx("control data was truncated, MSG_CTRUNC flag is on");
1529 if (msg.msg_controllen < sizeof(struct cmsghdr)) {
1530 logmsgx("msg_controllen %u < %lu (sizeof(struct cmsghdr))",
1531 (u_int)msg.msg_controllen, (u_long)sizeof(struct cmsghdr));
1535 if ((cmptr = CMSG_FIRSTHDR(&msg)) == NULL) {
1536 logmsgx("CMSG_FIRSTHDR is NULL");
1540 dbgmsg(("msg_controllen = %u, cmsg_len = %u",
1541 (u_int)msg.msg_controllen, (u_int)cmptr->cmsg_len));
1543 if (cmptr->cmsg_level != SOL_SOCKET) {
1544 logmsgx("cmsg_level %d != SOL_SOCKET", cmptr->cmsg_level);
1548 if (cmptr->cmsg_type != SCM_TIMESTAMP) {
1549 logmsgx("cmsg_type %d != SCM_TIMESTAMP", cmptr->cmsg_type);
1553 if (cmptr->cmsg_len != CMSG_LEN(sizeof(struct timeval))) {
1554 logmsgx("cmsg_len %u != %lu (CMSG_LEN(sizeof(struct timeval))",
1555 (u_int)cmptr->cmsg_len, (u_long)CMSG_LEN(sizeof(struct timeval)));
1559 timeval = (const struct timeval *)CMSG_DATA(cmptr);
1561 dbgmsg(("timeval tv_sec %jd, tv_usec %jd",
1562 (intmax_t)timeval->tv_sec, (intmax_t)timeval->tv_usec));
1564 if ((cmptr = CMSG_NXTHDR(&msg, cmptr)) != NULL) {
1565 logmsgx("control data has extra header");
1572 if (sock_type == SOCK_STREAM)
1573 if (close(fd2) < 0) {
1580 if (sock_type == SOCK_STREAM)
1591 if ((fd = create_server_socket()) < 0)
1594 if (sock_type == SOCK_STREAM)
1595 if (listen(fd, LISTENQ) < 0) {
1600 if ((client_pid = fork()) == (pid_t)-1) {
1605 if (client_pid == 0) {
1607 if (close_socket((const char *)NULL, fd) < 0)
1609 t_timestamp_client();
1612 if ((error = t_timestamp_server(fd)) == -2) {
1613 (void)wait_client();
1617 if (wait_client() < 0)
1620 if (close_socket(serv_sock_path, fd) < 0) {
1621 logmsgx("close_socket failed");
1627 if (close_socket(serv_sock_path, fd) < 0)
1628 logmsgx("close_socket failed");