1 /* $OpenBSD: monitor.c,v 1.24 2024/11/21 13:42:49 claudio Exp $ */
2
3 /*
4 * Copyright (c) 2005 H�kan Olsson. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <sys/types.h>
29 #include <sys/ioctl.h>
30 #include <sys/socket.h>
31 #include <sys/stat.h>
32 #include <sys/sysctl.h>
33 #include <sys/queue.h>
34 #include <sys/wait.h>
35 #include <sys/un.h>
36 #include <net/pfkeyv2.h>
37
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <pwd.h>
41 #include <signal.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <limits.h>
46 #include <imsg.h>
47
48 #include "types.h" /* iked imsg types */
49
50 #include "monitor.h"
51 #include "sasyncd.h"
52
53 struct m_state {
54 pid_t pid;
55 int s;
56 } m_state;
57
58 volatile sig_atomic_t sigchld = 0;
59
60 static void got_sigchld(int);
61 static void sig_to_child(int);
62 static void m_priv_pfkey_snap(int);
63 static int m_priv_control_activate(void);
64 static int m_priv_control_passivate(void);
65 static ssize_t m_write(int, void *, size_t);
66 static ssize_t m_read(int, void *, size_t);
67
68 pid_t
monitor_init(void)69 monitor_init(void)
70 {
71 struct passwd *pw = getpwnam(SASYNCD_USER);
72 extern char *__progname;
73 char root[PATH_MAX];
74 int p[2];
75
76 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, p) != 0) {
77 log_err("%s: socketpair failed - %s", __progname,
78 strerror(errno));
79 exit(1);
80 }
81
82 if (!pw) {
83 log_err("%s: getpwnam(\"%s\") failed", __progname,
84 SASYNCD_USER);
85 exit(1);
86 }
87 strlcpy(root, pw->pw_dir, sizeof root);
88 endpwent();
89
90 signal(SIGCHLD, got_sigchld);
91 signal(SIGTERM, sig_to_child);
92 signal(SIGHUP, sig_to_child);
93 signal(SIGINT, sig_to_child);
94
95 m_state.pid = fork();
96
97 if (m_state.pid == -1) {
98 log_err("%s: fork failed - %s", __progname, strerror(errno));
99 exit(1);
100 } else if (m_state.pid == 0) {
101 /* Child */
102 m_state.s = p[0];
103 close(p[1]);
104
105 if (chroot(pw->pw_dir) != 0 || chdir("/") != 0) {
106 log_err("%s: chroot failed", __progname);
107 exit(1);
108 }
109
110 if (setgroups(1, &pw->pw_gid) ||
111 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
112 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) {
113 log_err("%s: failed to drop privileges", __progname);
114 exit(1);
115 }
116 } else {
117 /* Parent */
118 setproctitle("[priv]");
119 m_state.s = p[1];
120 close(p[0]);
121 }
122 return m_state.pid;
123 }
124
125 static void
got_sigchld(int s)126 got_sigchld(int s)
127 {
128 sigchld = 1;
129 }
130
131 static void
sig_to_child(int s)132 sig_to_child(int s)
133 {
134 if (m_state.pid != -1)
135 kill(m_state.pid, s);
136 }
137
138 static void
monitor_drain_input(void)139 monitor_drain_input(void)
140 {
141 int one = 1;
142 u_int8_t tmp;
143
144 ioctl(m_state.s, FIONBIO, &one);
145 while (m_read(m_state.s, &tmp, 1) > 0)
146 ;
147 ioctl(m_state.s, FIONBIO, 0);
148 }
149
150 /* We only use privsep to get in-kernel SADB and SPD snapshots via sysctl */
151 void
monitor_loop(void)152 monitor_loop(void)
153 {
154 u_int32_t v, vn;
155 ssize_t r;
156 fd_set rfds;
157 int ret;
158 struct timeval *tvp, tv;
159
160 FD_ZERO(&rfds);
161 tvp = NULL;
162 vn = 0;
163
164 for (;;) {
165 ret = 0;
166 v = 0;
167
168 if (sigchld) {
169 pid_t pid;
170 int status;
171 do {
172 pid = waitpid(m_state.pid, &status, WNOHANG);
173 } while (pid == -1 && errno == EINTR);
174
175 if (pid == m_state.pid &&
176 (WIFEXITED(status) || WIFSIGNALED(status)))
177 break;
178 }
179
180 FD_SET(m_state.s, &rfds);
181 if (select(m_state.s + 1, &rfds, NULL, NULL, tvp) == -1) {
182 if (errno == EINTR || errno == EAGAIN)
183 continue;
184 log_err("monitor_loop: select()");
185 break;
186 }
187
188 /* Wait for next task */
189 if (FD_ISSET(m_state.s, &rfds)) {
190 if ((r = m_read(m_state.s, &v, sizeof v)) < 1) {
191 if (r == -1)
192 log_err("monitor_loop: read()");
193 break;
194 }
195 }
196
197 /* Retry after timeout */
198 if (v == 0 && tvp != NULL) {
199 v = vn;
200 tvp = NULL;
201 vn = 0;
202 }
203
204 switch (v) {
205 case MONITOR_GETSNAP:
206 /* Get the data. */
207 m_priv_pfkey_snap(m_state.s);
208 break;
209 case MONITOR_CARPINC:
210 carp_demote(CARP_INC, 1);
211 break;
212 case MONITOR_CARPDEC:
213 carp_demote(CARP_DEC, 1);
214 break;
215 case MONITOR_CONTROL_ACTIVATE:
216 ret = m_priv_control_activate();
217 break;
218 case MONITOR_CONTROL_PASSIVATE:
219 ret = m_priv_control_passivate();
220 break;
221 }
222
223 if (ret == -1) {
224 /* Trigger retry after timeout */
225 tv.tv_sec = MONITOR_RETRY_TIMEOUT;
226 tv.tv_usec = 0;
227 tvp = &tv;
228 vn = v;
229 }
230 }
231
232 monitor_carpundemote(NULL);
233
234 if (!sigchld)
235 log_msg(0, "monitor_loop: priv process exiting abnormally");
236 exit(0);
237 }
238
239 void
monitor_carpundemote(void * v)240 monitor_carpundemote(void *v)
241 {
242 u_int32_t mtype = MONITOR_CARPDEC;
243 if (!carp_demoted)
244 return;
245 if (m_write(m_state.s, &mtype, sizeof mtype) < 1)
246 log_msg(1, "monitor_carpundemote: unable to write to monitor");
247 else
248 carp_demoted = 0;
249 }
250
251 void
monitor_carpdemote(void * v)252 monitor_carpdemote(void *v)
253 {
254 u_int32_t mtype = MONITOR_CARPINC;
255 if (carp_demoted)
256 return;
257 if (m_write(m_state.s, &mtype, sizeof mtype) < 1)
258 log_msg(1, "monitor_carpdemote: unable to write to monitor");
259 else
260 carp_demoted = 1;
261 }
262
263 int
monitor_get_pfkey_snap(u_int8_t ** sadb,u_int32_t * sadbsize,u_int8_t ** spd,u_int32_t * spdsize)264 monitor_get_pfkey_snap(u_int8_t **sadb, u_int32_t *sadbsize, u_int8_t **spd,
265 u_int32_t *spdsize)
266 {
267 u_int32_t v;
268 ssize_t rbytes;
269
270 v = MONITOR_GETSNAP;
271 if (m_write(m_state.s, &v, sizeof v) < 1)
272 return -1;
273
274 /* Read SADB data. */
275 *sadb = *spd = NULL;
276 *spdsize = 0;
277 if (m_read(m_state.s, sadbsize, sizeof *sadbsize) < 1)
278 return -1;
279 if (*sadbsize) {
280 *sadb = malloc(*sadbsize);
281 if (!*sadb) {
282 log_err("monitor_get_pfkey_snap: malloc()");
283 monitor_drain_input();
284 return -1;
285 }
286 rbytes = m_read(m_state.s, *sadb, *sadbsize);
287 if (rbytes < 1) {
288 freezero(*sadb, *sadbsize);
289 return -1;
290 }
291 }
292
293 /* Read SPD data */
294 if (m_read(m_state.s, spdsize, sizeof *spdsize) < 1) {
295 freezero(*sadb, *sadbsize);
296 return -1;
297 }
298 if (*spdsize) {
299 *spd = malloc(*spdsize);
300 if (!*spd) {
301 log_err("monitor_get_pfkey_snap: malloc()");
302 monitor_drain_input();
303 freezero(*sadb, *sadbsize);
304 return -1;
305 }
306 rbytes = m_read(m_state.s, *spd, *spdsize);
307 if (rbytes < 1) {
308 freezero(*spd, *spdsize);
309 freezero(*sadb, *sadbsize);
310 return -1;
311 }
312 }
313
314 log_msg(2, "monitor_get_pfkey_snap: got %u bytes SADB, %u bytes SPD",
315 *sadbsize, *spdsize);
316 return 0;
317 }
318
319 int
monitor_control_active(int active)320 monitor_control_active(int active)
321 {
322 u_int32_t cmd =
323 active ? MONITOR_CONTROL_ACTIVATE : MONITOR_CONTROL_PASSIVATE;
324 if (write(m_state.s, &cmd, sizeof cmd) < 1)
325 return -1;
326 return 0;
327 }
328
329 /* Privileged */
330 static void
m_priv_pfkey_snap(int s)331 m_priv_pfkey_snap(int s)
332 {
333 u_int8_t *sadb_buf = NULL, *spd_buf = NULL;
334 size_t sadb_buflen = 0, spd_buflen = 0, sz;
335 int mib[5];
336 u_int32_t v;
337
338 mib[0] = CTL_NET;
339 mib[1] = PF_KEY;
340 mib[2] = PF_KEY_V2;
341 mib[3] = NET_KEY_SADB_DUMP;
342 mib[4] = 0; /* Unspec SA type */
343
344 /* First, fetch SADB data */
345 for (;;) {
346 if (sysctl(mib, sizeof mib / sizeof mib[0], NULL, &sz, NULL, 0)
347 == -1)
348 break;
349
350 if (!sz)
351 break;
352
353 /* Try to catch newly added data */
354 sz *= 2;
355
356 if ((sadb_buf = malloc(sz)) == NULL)
357 break;
358
359 if (sysctl(mib, sizeof mib / sizeof mib[0], sadb_buf, &sz, NULL, 0)
360 == -1) {
361 free(sadb_buf);
362 sadb_buf = NULL;
363 /*
364 * If new SAs were added meanwhile and the given buffer is
365 * too small, retry.
366 */
367 if (errno == ENOMEM)
368 continue;
369 break;
370 }
371
372 sadb_buflen = sz;
373 break;
374 }
375
376 /* Next, fetch SPD data */
377 mib[3] = NET_KEY_SPD_DUMP;
378
379 for (;;) {
380 if (sysctl(mib, sizeof mib / sizeof mib[0], NULL, &sz, NULL, 0)
381 == -1)
382 break;
383
384 if (!sz)
385 break;
386
387 /* Try to catch newly added data */
388 sz *= 2;
389
390 if ((spd_buf = malloc(sz)) == NULL)
391 break;
392
393 if (sysctl(mib, sizeof mib / sizeof mib[0], spd_buf, &sz, NULL, 0)
394 == -1) {
395 free(spd_buf);
396 spd_buf = NULL;
397 /*
398 * If new SPDs were added meanwhile and the given buffer is
399 * too small, retry.
400 */
401 if (errno == ENOMEM)
402 continue;
403 break;
404 }
405
406 spd_buflen = sz;
407 break;
408 }
409
410 /* Return SADB data */
411 v = (u_int32_t)sadb_buflen;
412 if (m_write(s, &v, sizeof v) == -1) {
413 log_err("m_priv_pfkey_snap: write");
414 goto cleanup;
415 }
416 if (m_write(s, sadb_buf, sadb_buflen) == -1) {
417 log_err("m_priv_pfkey_snap: write");
418 goto cleanup;
419 }
420
421 /* Return SPD data */
422 v = (u_int32_t)spd_buflen;
423 if (m_write(s, &v, sizeof v) == -1) {
424 log_err("m_priv_pfkey_snap: write");
425 goto cleanup;
426 }
427 if (m_write(s, spd_buf, spd_buflen) == -1) {
428 log_err("m_priv_pfkey_snap: write");
429 goto cleanup;
430 }
431
432 cleanup:
433 freezero(sadb_buf, sadb_buflen);
434 freezero(spd_buf, spd_buflen);
435 }
436
437 static int
m_priv_isakmpd_fifocmd(const char * cmd)438 m_priv_isakmpd_fifocmd(const char *cmd)
439 {
440 struct stat sb;
441 int fd = -1, ret = -1;
442
443 if ((fd = open(ISAKMPD_FIFO, O_WRONLY)) == -1) {
444 log_err("m_priv_isakmpd_fifocmd: open(%s)", ISAKMPD_FIFO);
445 goto out;
446 }
447 if (fstat(fd, &sb) == -1) {
448 log_err("m_priv_isakmpd_fifocmd: fstat(%s)", ISAKMPD_FIFO);
449 goto out;
450 }
451 if (!S_ISFIFO(sb.st_mode)) {
452 log_err("m_priv_isakmpd_fifocmd: %s not a fifo", ISAKMPD_FIFO);
453 goto out;
454 }
455
456 if (write(fd, cmd, strlen(cmd)) == -1) {
457 log_err("m_priv_isakmpd_fifocmd write");
458 goto out;
459 }
460
461 ret = 0;
462 out:
463 if (fd != -1)
464 close(fd);
465
466 return (ret);
467 }
468
469 static int
m_priv_iked_imsg(u_int cmd)470 m_priv_iked_imsg(u_int cmd)
471 {
472 struct sockaddr_un sun;
473 int fd = -1, ret = -1;
474 struct imsgbuf ibuf;
475
476 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
477 log_err("m_priv_iked_imsg: socket");
478 goto out;
479 }
480
481 bzero(&sun, sizeof(sun));
482 sun.sun_family = AF_UNIX;
483 strlcpy(sun.sun_path, IKED_SOCKET, sizeof(sun.sun_path));
484
485 if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
486 log_err("m_priv_iked_imsg: connect");
487 goto out;
488 }
489
490 if (imsgbuf_init(&ibuf, fd) == -1) {
491 log_err("m_priv_iked_imsg: imsgbuf_init");
492 goto out;
493 }
494 if (imsg_compose(&ibuf, cmd, 0, 0, -1, NULL, 0) == -1) {
495 log_err("m_priv_iked_imsg: compose");
496 goto err;
497 }
498 if (imsgbuf_flush(&ibuf) == -1) {
499 log_err("m_priv_iked_imsg: flush");
500 goto err;
501 }
502
503 ret = 0;
504 err:
505 imsgbuf_clear(&ibuf);
506 out:
507 if (fd != -1)
508 close(fd);
509
510 return (ret);
511 }
512
513 static int
m_priv_control_activate(void)514 m_priv_control_activate(void)
515 {
516 if (cfgstate.flags & CTL_ISAKMPD)
517 if (m_priv_isakmpd_fifocmd("M active\n") == -1)
518 return (-1);
519 if (cfgstate.flags & CTL_IKED)
520 if (m_priv_iked_imsg(IMSG_CTL_ACTIVE) == -1)
521 return (-1);
522 return (0);
523 }
524
525 static int
m_priv_control_passivate(void)526 m_priv_control_passivate(void)
527 {
528 if (cfgstate.flags & CTL_ISAKMPD)
529 if (m_priv_isakmpd_fifocmd("M passive\n") == -1)
530 return (-1);
531 if (cfgstate.flags & CTL_IKED)
532 if (m_priv_iked_imsg(IMSG_CTL_PASSIVE) == -1)
533 return (-1);
534 return (0);
535 }
536
537 ssize_t
m_write(int sock,void * buf,size_t len)538 m_write(int sock, void *buf, size_t len)
539 {
540 ssize_t n;
541 size_t pos = 0;
542 char *ptr = buf;
543
544 while (len > pos) {
545 switch (n = write(sock, ptr + pos, len - pos)) {
546 case -1:
547 if (errno == EINTR || errno == EAGAIN)
548 continue;
549 /* FALLTHROUGH */
550 case 0:
551 return n;
552 /* NOTREACHED */
553 default:
554 pos += n;
555 }
556 }
557 return pos;
558 }
559
560 ssize_t
m_read(int sock,void * buf,size_t len)561 m_read(int sock, void *buf, size_t len)
562 {
563 ssize_t n;
564 size_t pos = 0;
565 char *ptr = buf;
566
567 while (len > pos) {
568 switch (n = read(sock, ptr + pos, len - pos)) {
569 case -1:
570 if (errno == EINTR || errno == EAGAIN)
571 continue;
572 /* FALLTHROUGH */
573 case 0:
574 return n;
575 /* NOTREACHED */
576 default:
577 pos += n;
578 }
579 }
580 return pos;
581 }
582