1 #include <sys/types.h>
2 #include <sys/wait.h>
3 #include <sys/socket.h>
4 #include <sys/uio.h>
5 #include <unistd.h>
6 #include <err.h>
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 /* workaround leaky case */
13 #ifndef MSG_CMSG_CLOEXEC
14 #define MSG_CMSG_CLOEXEC 0
15 #endif
16 
17 #define CHECKFD_CMD	"checkfd"
18 #define CHECKFD_PATH	"/usr/local/bin/" CHECKFD_CMD
19 
20 int sendfd(int s, int fd);
21 int recvfd(int s);
22 
23 int main(void)
24 {
25 	pid_t pid;
26 	int s[2], status, ecode;
27 
28 	socketpair(AF_UNIX, SOCK_STREAM, 0, s);
29 
30 	pid = fork();
31 	if (pid < 0) {
32 		err(1, "fork failed");
33 	} else if (pid == 0) {
34 		close(0);
35 		close(1);
36 		/* close(2); */
37 
38 		int mysecretfd = recvfd(s[0]);
39 
40 		write(mysecretfd, "hello secret\n", 14);
41 
42 		char fd[8];
43 		snprintf(fd, sizeof(fd), "%d", mysecretfd);
44 		if (execl(CHECKFD_PATH, CHECKFD_CMD, fd, NULL) < 0)
45 			err(3, "execl failed");
46 	} else {
47 		sendfd(s[1], 1);
48 	}
49 
50 	if (waitpid(pid, &status, 0) < 0)
51 		err(1, "waitpid failed");
52 
53 	if (!WIFEXITED(status))
54 		errx(1, CHECKFD_CMD " did not exit");
55 
56 	ecode = WEXITSTATUS(status);
57 	if (ecode != 0) {
58 		warnx("exit code %d", ecode);
59 		abort();
60 	}
61 
62 	fprintf(stderr, "passed\n");
63 	exit(0);
64 
65 }
66 
67 int
68 sendfd(int s, int fd)
69 {
70 	char buf[1];
71 	struct iovec iov;
72 	struct msghdr msg;
73 	struct cmsghdr *cmsg;
74 	int n;
75 	char cms[CMSG_SPACE(sizeof(int))];
76 
77 	buf[0] = 0;
78 	iov.iov_base = buf;
79 	iov.iov_len = 1;
80 
81 	memset(&msg, 0, sizeof msg);
82 	msg.msg_iov = &iov;
83 	msg.msg_iovlen = 1;
84 	msg.msg_control = (caddr_t)cms;
85 	msg.msg_controllen = CMSG_LEN(sizeof(int));
86 
87 	cmsg = CMSG_FIRSTHDR(&msg);
88 	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
89 	cmsg->cmsg_level = SOL_SOCKET;
90 	cmsg->cmsg_type = SCM_RIGHTS;
91 	memmove(CMSG_DATA(cmsg), &fd, sizeof(int));
92 
93 	if ((n=sendmsg(s, &msg, 0)) != (int)iov.iov_len)
94 		return -1;
95 	return 0;
96 }
97 
98 int
99 recvfd(int s)
100 {
101 	int n;
102 	int fd;
103 	char buf[1];
104 	struct iovec iov;
105 	struct msghdr msg;
106 	struct cmsghdr *cmsg;
107 	char cms[CMSG_SPACE(sizeof(int))];
108 
109 	iov.iov_base = buf;
110 	iov.iov_len = 1;
111 
112 	memset(&msg, 0, sizeof msg);
113 	msg.msg_name = 0;
114 	msg.msg_namelen = 0;
115 	msg.msg_iov = &iov;
116 	msg.msg_iovlen = 1;
117 
118 	msg.msg_control = (caddr_t)cms;
119 	msg.msg_controllen = sizeof cms;
120 
121 	if ((n=recvmsg(s, &msg, MSG_CMSG_CLOEXEC)) < 0)
122 		return -1;
123 	if (n == 0){
124 		return -1;
125 	}
126 	cmsg = CMSG_FIRSTHDR(&msg);
127 	memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
128 	return fd;
129 }
130