1 /*
2  * Copyright (c) 2019 Tobias Kortkamp <t@tobik.me>
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "config.h"
18 
19 #if HAVE_CAPSICUM
20 # include <sys/capsicum.h>
21 # include "capsicum_helpers.h"
22 #endif
23 #ifdef __FreeBSD__
24 # include <sys/sysctl.h>
25 #endif
26 #include <assert.h>
27 #if HAVE_ERR
28 # include <err.h>
29 #endif
30 #include <sys/param.h>
31 #include <assert.h>
32 #include <err.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <poll.h>
36 #include <string.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 
41 #if defined(__DragonFly__)
42 #include <dev/misc/evdev/input.h>
43 #elif defined(__FreeBSD__)
44 #include <dev/evdev/input.h>
45 #else
46 #include <linux/input.h>
47 #endif
48 
49 #include "stroke.h"
50 
51 #ifndef nitems
52 #define	nitems(x)	(sizeof((x)) / sizeof((x)[0]))
53 #endif
54 
55 static struct pollfd fds[32];
56 static size_t nfds;
57 static int props_by_sysctl = 0;
58 #if HAVE_CAPSICUM
59 static int command_runner_fd[2] = { -1, -1 };
60 #endif
61 
62 // From libudev-devd's udev-utils.c
63 #define	LONG_BITS	(sizeof(long) * 8)
64 #define	NLONGS(x)	(((x) + LONG_BITS - 1) / LONG_BITS)
65 
66 static inline int
bit_is_set(const unsigned long * array,int bit)67 bit_is_set(const unsigned long *array, int bit)
68 {
69 	return !!(array[bit / LONG_BITS] & (1LL << (bit % LONG_BITS)));
70 }
71 
72 static int
open_device(size_t i)73 open_device(size_t i)
74 {
75 	char buf[PATH_MAX];
76 	unsigned long prp_bits[NLONGS(INPUT_PROP_CNT)];
77 	size_t len = sizeof(prp_bits);
78 
79 #ifdef __FreeBSD__
80 	if (props_by_sysctl) {
81 		snprintf(buf, sizeof(buf), "kern.evdev.input.%zu.props", i);
82 		if (sysctlbyname(buf, prp_bits, &len, NULL, 0) < 0) {
83 			return -1;
84 		}
85 		if (!bit_is_set(prp_bits, INPUT_PROP_POINTER)) {
86 			return -1;
87 		}
88 	}
89 #endif
90 
91 	snprintf(buf, sizeof(buf), "/dev/input/event%zu", i);
92 	int fd = open(buf, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
93 	if (fd == -1) {
94 		return -1;
95 	}
96 	if (!props_by_sysctl) {
97 		if (ioctl(fd, EVIOCGPROP(len), prp_bits) < 0) {
98 			close(fd);
99 			return -1;
100 		}
101 		if (!bit_is_set(prp_bits, INPUT_PROP_POINTER)) {
102 			close(fd);
103 			return -1;
104 		}
105 	}
106 
107 #if HAVE_CAPSICUM
108 	cap_rights_t rights;
109 	cap_rights_init(&rights, CAP_READ, CAP_EVENT);
110 
111 	if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) {
112 		err(1, "cap_rights_limit");
113 	}
114 #endif
115 
116 	return fd;
117 }
118 
119 #if HAVE_CAPSICUM
120 static void
evdev_create_command_runner(void)121 evdev_create_command_runner(void)
122 {
123 	int read_pipe[2];
124 	int write_pipe[2];
125 
126 	if (pipe2(read_pipe, O_CLOEXEC) == -1) {
127 		err(1, "pipe2");
128 	}
129 	if (pipe2(write_pipe, O_CLOEXEC) == -1) {
130 		err(1, "pipe2");
131 	}
132 
133 	cap_rights_t rights;
134 	cap_rights_init(&rights, CAP_WRITE);
135 	command_runner_fd[0] = read_pipe[1];
136 	if (cap_rights_limit(command_runner_fd[0], &rights) < 0 && errno != ENOSYS) {
137 		err(1, "cap_rights_limit");
138 	}
139 	if (cap_rights_limit(write_pipe[1], &rights) < 0 && errno != ENOSYS) {
140 		err(1, "cap_rights_limit");
141 	}
142 
143 	cap_rights_init(&rights, CAP_READ, CAP_EVENT);
144 	command_runner_fd[1] = write_pipe[0];
145 	if (cap_rights_limit(read_pipe[0], &rights) < 0 && errno != ENOSYS) {
146 		err(1, "cap_rights_limit");
147 	}
148 	if (cap_rights_limit(write_pipe[0], &rights) < 0 && errno != ENOSYS) {
149 		err(1, "cap_rights_limit");
150 	}
151 
152 	pid_t child = fork();
153 	if (child > 0) {
154 		return;
155 	} else if (child == -1) {
156 		err(1, "fork");
157 	}
158 
159 	// Drop suid privileges now
160 	if (getuid() != geteuid() || getgid() != getegid()) {
161 		if (setuid(getuid()) != 0 || setgid(getgid()) != 0) {
162 			err(1, "setuid");
163 		}
164 	}
165 	if (setuid(0) != -1) {
166 		errx(1, "still root?");
167 	}
168 
169 	setproctitle("command runner: %s", command);
170 
171 	close(read_pipe[1]);
172 	close(write_pipe[0]);
173 	closefrom(MAX(read_pipe[0], MAX(write_pipe[1], STDERR_FILENO)) + 1);
174 
175 	if (write(write_pipe[1], "done", 5) != 5) {
176 		err(1, "write");
177 	}
178 	char buf[4];
179 	ssize_t n;
180 	while ((n = read(read_pipe[0], buf, 4)) > -1) {
181 		if (n == 4 && strncmp(buf, "run", 3) == 0) {
182 			tracker_run_command_internal();
183 			if (write(write_pipe[1], "done", 5) != 5) {
184 				err(1, "write");
185 			}
186 		}
187 	}
188 
189 	err(1, "read");
190 }
191 
192 static void
evdev_run_command(void)193 evdev_run_command(void)
194 {
195 	assert(command != NULL);
196 
197 	char buf[5];
198 	if (read(command_runner_fd[1], buf, 5) != 5) {
199 		err(1, "read");
200 	}
201 	if (strncmp(buf, "done", 4) != 0) {
202 		errx(1, "invalid response");
203 	}
204 
205 	if (write(command_runner_fd[0], "run", 4) != 4) {
206 		err(1, "write");
207 	}
208 }
209 #endif
210 
211 
212 static int
evdev_init(void)213 evdev_init(void)
214 {
215 #if HAVE_CAPSICUM
216 	close(STDIN_FILENO);
217 	closefrom(STDERR_FILENO + 1);
218 
219 	if (command != NULL) {
220 		evdev_create_command_runner();
221 	}
222 
223 	if (caph_limit_stderr() < 0) {
224 		err(1, "caph_limit_stderr");
225 	}
226 	if (caph_limit_stdout() < 0) {
227 		err(1, "caph_limit_stdout");
228 	}
229 
230 #endif
231 
232 #ifdef __FreeBSD__
233 	// Getting device properties via sysctls is not supported on all
234 	// FreeBSD versions.  As a heuristic just check the 0th
235 	// device to see if it supported.  Fallback is graceful if
236 	// this fails at the cost of a bunch of extra open(2) and
237 	// ioctl(2).
238 	if (sysctlbyname("kern.evdev.input.0.props", NULL, 0, NULL, 0) >= 0) {
239 		props_by_sysctl = 1;
240 	}
241 #endif
242 
243 	int maxfd = 0;
244 	memset(fds, 0, sizeof(fds));
245 	for (size_t i = 0; i < nitems(fds); i++) {
246 		int fd = open_device(i);
247 		if (fd < 0) {
248 			continue;
249 		}
250 		maxfd = MAX(maxfd, fd);
251 		fds[nfds].fd = fd;
252 		fds[nfds].events = POLLIN;
253 		fds[nfds].revents = 0;
254 		nfds++;
255 	}
256 
257 	// Drop suid privileges now
258 	if (getuid() != geteuid() || getgid() != getegid()) {
259 		if (setuid(getuid()) != 0 || setgid(getgid()) != 0) {
260 			err(1, "setuid");
261 		}
262 	}
263 	if (setuid(0) != -1) {
264 		errx(1, "still root?");
265 	}
266 
267 	if (nfds == 0) {
268 		warnx("evdev: no mouse found");
269 		return 0;
270 	}
271 
272 #if HAVE_CAPSICUM
273 	closefrom(maxfd + 1);
274 
275 	if (caph_enter() < 0) {
276 		err(1, "cap_enter");
277 	}
278 #endif
279 
280 	return 1;
281 }
282 
283 static int
evdev_record_stroke(struct stroke * stroke)284 evdev_record_stroke(/* out */ struct stroke *stroke)
285 {
286 	double x = 0.0;
287 	double y = 0.0;
288 	while (poll(fds, nfds, -1) > -1) {
289 		for (size_t i = 0; i < nfds; i++) {
290 			struct input_event ev;
291 			if ((fds[i].revents & POLLHUP) ||
292 			    (fds[i].revents & POLLIN) == 0) {
293 				continue;
294 			}
295 			while (read(fds[i].fd, &ev, sizeof(struct input_event)) > 0) {
296 				if (stroke != NULL && ev.type == EV_REL) {
297 					switch (ev.code) {
298 						case REL_X:
299 							x += ev.value;
300 							break;
301 						case REL_Y:
302 							y += ev.value;
303 							break;
304 					}
305 					stroke_add_point(stroke, x, y);
306 				} else if (ev.type == EV_KEY) {
307 					goto end;
308 				}
309 			}
310 		}
311 	}
312 
313 end:
314 	if (stroke != NULL) {
315 		stroke_finish(stroke);
316 	}
317 
318 	return 1;
319 }
320