1 /* $OpenBSD: monitor.c,v 1.14 2010/06/29 18:10:04 kjell 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(0, "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(0, "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 = 0, *spd_buf = 0; 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 if (sysctl(mib, sizeof mib / sizeof mib[0], NULL, &sz, NULL, 0) == -1 356 || sz == 0) { 357 sadb_buflen = 0; 358 goto try_spd; 359 } 360 361 sadb_buflen = sz; 362 if ((sadb_buf = malloc(sadb_buflen)) == NULL) { 363 log_err("m_priv_pfkey_snap: malloc"); 364 sadb_buflen = 0; 365 goto out; 366 } 367 368 if (sysctl(mib, sizeof mib / sizeof mib[0], sadb_buf, &sz, NULL, 0) 369 == -1) { 370 log_err("m_priv_pfkey_snap: sysctl"); 371 sadb_buflen = 0; 372 goto out; 373 } 374 375 /* Next, fetch SPD data */ 376 try_spd: 377 mib[3] = NET_KEY_SPD_DUMP; 378 379 if (sysctl(mib, sizeof mib / sizeof mib[0], NULL, &sz, NULL, 0) == -1 380 || sz == 0) { 381 spd_buflen = 0; 382 goto out; 383 } 384 385 spd_buflen = sz; 386 if ((spd_buf = malloc(spd_buflen)) == NULL) { 387 log_err("m_priv_pfkey_snap: malloc"); 388 spd_buflen = 0; 389 goto out; 390 } 391 392 if (sysctl(mib, sizeof mib / sizeof mib[0], spd_buf, &sz, NULL, 0) 393 == -1) { 394 log_err("m_priv_pfkey_snap: sysctl"); 395 spd_buflen = 0; 396 goto out; 397 } 398 399 out: 400 /* Return SADB data */ 401 v = (u_int32_t)sadb_buflen; 402 if (m_write(s, &v, sizeof v) == -1) { 403 log_err("m_priv_pfkey_snap: write"); 404 return; 405 } 406 if (sadb_buflen) { 407 if (m_write(s, sadb_buf, sadb_buflen) == -1) 408 log_err("m_priv_pfkey_snap: write"); 409 memset(sadb_buf, 0, sadb_buflen); 410 free(sadb_buf); 411 } 412 413 /* Return SPD data */ 414 v = (u_int32_t)spd_buflen; 415 if (m_write(s, &v, sizeof v) == -1) { 416 log_err("m_priv_pfkey_snap: write"); 417 return; 418 } 419 if (spd_buflen) { 420 if (m_write(s, spd_buf, spd_buflen) == -1) 421 log_err("m_priv_pfkey_snap: write"); 422 memset(spd_buf, 0, spd_buflen); 423 free(spd_buf); 424 } 425 return; 426 } 427 428 static int 429 m_priv_isakmpd_fifocmd(const char *cmd) 430 { 431 struct stat sb; 432 int fd = -1, ret = -1; 433 434 if ((fd = open(ISAKMPD_FIFO, O_WRONLY)) == -1) { 435 log_err("m_priv_isakmpd_fifocmd: open(%s)", ISAKMPD_FIFO); 436 goto out; 437 } 438 if (fstat(fd, &sb) == -1) { 439 log_err("m_priv_isakmpd_fifocmd: fstat(%s)", ISAKMPD_FIFO); 440 goto out; 441 } 442 if (!S_ISFIFO(sb.st_mode)) { 443 log_err("m_priv_isakmpd_fifocmd: %s not a fifo", ISAKMPD_FIFO); 444 goto out; 445 } 446 447 if (write(fd, cmd, strlen(cmd)) == -1) { 448 log_err("m_priv_isakmpd_fifocmd write"); 449 goto out; 450 } 451 452 ret = 0; 453 out: 454 if (fd != -1) 455 close(fd); 456 457 return (ret); 458 } 459 460 static int 461 m_priv_iked_imsg(u_int cmd) 462 { 463 struct sockaddr_un sun; 464 int fd = -1, ret = -1; 465 struct imsgbuf ibuf; 466 467 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 468 log_err("m_priv_iked_imsg: socket"); 469 goto out; 470 } 471 472 bzero(&sun, sizeof(sun)); 473 sun.sun_family = AF_UNIX; 474 strlcpy(sun.sun_path, IKED_SOCKET, sizeof(sun.sun_path)); 475 476 if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 477 log_err("m_priv_iked_imsg: connect"); 478 goto out; 479 } 480 481 imsg_init(&ibuf, fd); 482 if (imsg_compose(&ibuf, cmd, 0, 0, -1, NULL, 0) == -1) { 483 log_err("m_priv_iked_imsg: compose"); 484 goto err; 485 } 486 if (imsg_flush(&ibuf) == -1) { 487 log_err("m_priv_iked_imsg: flush"); 488 goto err; 489 } 490 491 ret = 0; 492 err: 493 imsg_clear(&ibuf); 494 out: 495 if (fd != -1) 496 close(fd); 497 498 return (ret); 499 } 500 501 static int 502 m_priv_control_activate(void) 503 { 504 if (cfgstate.flags & CTL_ISAKMPD) 505 if (m_priv_isakmpd_fifocmd("M active\n") == -1) 506 return (-1); 507 if (cfgstate.flags & CTL_IKED) 508 if (m_priv_iked_imsg(IMSG_CTL_ACTIVE) == -1) 509 return (-1); 510 return (0); 511 } 512 513 static int 514 m_priv_control_passivate(void) 515 { 516 if (cfgstate.flags & CTL_ISAKMPD) 517 if (m_priv_isakmpd_fifocmd("M passive\n") == -1) 518 return (-1); 519 if (cfgstate.flags & CTL_IKED) 520 if (m_priv_iked_imsg(IMSG_CTL_PASSIVE) == -1) 521 return (-1); 522 return (0); 523 } 524 525 ssize_t 526 m_write(int sock, void *buf, size_t len) 527 { 528 ssize_t n; 529 size_t pos = 0; 530 char *ptr = buf; 531 532 while (len > pos) { 533 switch (n = write(sock, ptr + pos, len - pos)) { 534 case -1: 535 if (errno == EINTR || errno == EAGAIN) 536 continue; 537 /* FALLTHROUGH */ 538 case 0: 539 return n; 540 /* NOTREACHED */ 541 default: 542 pos += n; 543 } 544 } 545 return pos; 546 } 547 548 ssize_t 549 m_read(int sock, void *buf, size_t len) 550 { 551 ssize_t n; 552 size_t pos = 0; 553 char *ptr = buf; 554 555 while (len > pos) { 556 switch (n = read(sock, ptr + pos, len - pos)) { 557 case -1: 558 if (errno == EINTR || errno == EAGAIN) 559 continue; 560 /* FALLTHROUGH */ 561 case 0: 562 return n; 563 /* NOTREACHED */ 564 default: 565 pos += n; 566 } 567 } 568 return pos; 569 } 570