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