1 /*	$OpenBSD: kqueue-fdpass.c,v 1.3 2016/09/20 23:05:27 bluhm Exp $	*/
2 /*
3  *	Written by Philip Guenther <guenther@openbsd.org> 2011 Public Domain
4  */
5 
6 #include <sys/types.h>
7 #include <sys/event.h>
8 #include <sys/socket.h>
9 #include <sys/un.h>
10 #include <sys/wait.h>
11 
12 #include <err.h>
13 #include <errno.h>
14 #include <signal.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 
20 #include "main.h"
21 
22 int
do_fdpass(void)23 do_fdpass(void)
24 {
25 	struct msghdr msg;
26 	union {
27 		struct cmsghdr hdr;
28 		char buf[CMSG_SPACE(sizeof(int))];
29 	} cmsgbuf;
30 	struct kevent ke;
31 	struct cmsghdr *cmp;
32 	pid_t pid;
33 	int pfd[2], fd, status;
34 
35 	ASS(socketpair(PF_LOCAL, SOCK_STREAM, 0, pfd) == 0,
36 	    warn("socketpair"));
37 
38 	pid = fork();
39 	if (pid == -1)
40 		err(1, "fork");
41 	if (pid == 0) {
42 		close(pfd[0]);
43 
44 		/* a kqueue with event to pass */
45 		fd = kqueue();
46 		EV_SET(&ke, SIGHUP, EVFILT_SIGNAL, EV_ADD|EV_ENABLE,
47 		    0, 0, NULL);
48 		if (kevent(fd, &ke, 1, NULL, 0, NULL) != 0)
49 			err(1, "can't register events on kqueue");
50 
51 		memset(&cmsgbuf.buf, 0, sizeof cmsgbuf.buf);
52 		memset(&msg, 0, sizeof msg);
53 		msg.msg_control = &cmsgbuf.buf;
54 		msg.msg_controllen = sizeof(cmsgbuf);
55 
56 		cmp = CMSG_FIRSTHDR(&msg);
57 		cmp->cmsg_len = CMSG_LEN(sizeof(int));
58 		cmp->cmsg_level = SOL_SOCKET;
59 		cmp->cmsg_type = SCM_RIGHTS;
60 
61 		*(int *)CMSG_DATA(cmp) = fd;
62 
63 		if (sendmsg(pfd[1], &msg, 0) == 0)
64 			errx(1, "sendmsg succeeded when it shouldn't");
65 		if (errno != EINVAL)
66 			err(1, "child sendmsg");
67 		printf("sendmsg failed with EINVAL as expected\n");
68 		close(pfd[1]);
69 		exit(0);
70 	}
71 
72 	close(pfd[1]);
73 	wait(&status);
74 	close(pfd[0]);
75 
76 	return (0);
77 }
78