1 /* $OpenBSD: control.c,v 1.129 2023/03/08 04:43:15 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> 5 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/stat.h> 22 #include <sys/un.h> 23 24 #include <errno.h> 25 #include <pwd.h> 26 #include <signal.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "smtpd.h" 32 #include "log.h" 33 34 #define CONTROL_BACKLOG 5 35 36 struct ctl_conn { 37 uint32_t id; 38 uint8_t flags; 39 #define CTL_CONN_NOTIFY 0x01 40 struct mproc mproc; 41 uid_t euid; 42 gid_t egid; 43 }; 44 45 struct { 46 struct event ev; 47 int fd; 48 } control_state; 49 50 static void control_imsg(struct mproc *, struct imsg *); 51 static void control_shutdown(void); 52 static void control_listen(void); 53 static void control_accept(int, short, void *); 54 static void control_close(struct ctl_conn *); 55 static void control_dispatch_ext(struct mproc *, struct imsg *); 56 static void control_digest_update(const char *, size_t, int); 57 static void control_broadcast_verbose(int, int); 58 59 static struct stat_backend *stat_backend = NULL; 60 extern const char *backend_stat; 61 62 static uint64_t connid = 0; 63 static struct tree ctl_conns; 64 static struct tree ctl_count; 65 static struct stat_digest digest; 66 67 #define CONTROL_FD_RESERVE 5 68 #define CONTROL_MAXCONN_PER_CLIENT 32 69 70 static void 71 control_imsg(struct mproc *p, struct imsg *imsg) 72 { 73 struct ctl_conn *c; 74 struct stat_value val; 75 struct msg m; 76 const char *key; 77 const void *data; 78 size_t sz; 79 80 if (imsg == NULL) { 81 if (p->proc != PROC_CLIENT) 82 control_shutdown(); 83 return; 84 } 85 86 switch (imsg->hdr.type) { 87 case IMSG_CTL_OK: 88 case IMSG_CTL_FAIL: 89 case IMSG_CTL_LIST_MESSAGES: 90 case IMSG_CTL_LIST_ENVELOPES: 91 case IMSG_CTL_DISCOVER_EVPID: 92 case IMSG_CTL_DISCOVER_MSGID: 93 case IMSG_CTL_MTA_SHOW_HOSTS: 94 case IMSG_CTL_MTA_SHOW_RELAYS: 95 case IMSG_CTL_MTA_SHOW_ROUTES: 96 case IMSG_CTL_MTA_SHOW_HOSTSTATS: 97 case IMSG_CTL_MTA_SHOW_BLOCK: 98 c = tree_get(&ctl_conns, imsg->hdr.peerid); 99 if (c == NULL) 100 return; 101 imsg->hdr.peerid = 0; 102 m_forward(&c->mproc, imsg); 103 return; 104 105 case IMSG_CTL_SMTP_SESSION: 106 c = tree_get(&ctl_conns, imsg->hdr.peerid); 107 if (c == NULL) 108 return; 109 m_compose(&c->mproc, IMSG_CTL_OK, 0, 0, imsg->fd, NULL, 0); 110 return; 111 112 case IMSG_STAT_INCREMENT: 113 m_msg(&m, imsg); 114 m_get_string(&m, &key); 115 m_get_data(&m, &data, &sz); 116 m_end(&m); 117 if (sz != sizeof(val)) 118 fatalx("control: IMSG_STAT_INCREMENT size mismatch"); 119 memmove(&val, data, sz); 120 if (stat_backend) 121 stat_backend->increment(key, val.u.counter); 122 control_digest_update(key, val.u.counter, 1); 123 return; 124 125 case IMSG_STAT_DECREMENT: 126 m_msg(&m, imsg); 127 m_get_string(&m, &key); 128 m_get_data(&m, &data, &sz); 129 m_end(&m); 130 if (sz != sizeof(val)) 131 fatalx("control: IMSG_STAT_DECREMENT size mismatch"); 132 memmove(&val, data, sz); 133 if (stat_backend) 134 stat_backend->decrement(key, val.u.counter); 135 control_digest_update(key, val.u.counter, 0); 136 return; 137 138 case IMSG_STAT_SET: 139 m_msg(&m, imsg); 140 m_get_string(&m, &key); 141 m_get_data(&m, &data, &sz); 142 m_end(&m); 143 if (sz != sizeof(val)) 144 fatalx("control: IMSG_STAT_SET size mismatch"); 145 memmove(&val, data, sz); 146 if (stat_backend) 147 stat_backend->set(key, &val); 148 return; 149 } 150 151 fatalx("control_imsg: unexpected %s imsg", 152 imsg_to_str(imsg->hdr.type)); 153 } 154 155 int 156 control_create_socket(void) 157 { 158 struct sockaddr_un s_un; 159 int fd; 160 mode_t old_umask; 161 162 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 163 fatal("control: socket"); 164 165 memset(&s_un, 0, sizeof(s_un)); 166 s_un.sun_family = AF_UNIX; 167 if (strlcpy(s_un.sun_path, SMTPD_SOCKET, 168 sizeof(s_un.sun_path)) >= sizeof(s_un.sun_path)) 169 fatal("control: socket name too long"); 170 171 if (connect(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == 0) 172 fatalx("control socket already listening"); 173 174 if (unlink(SMTPD_SOCKET) == -1) 175 if (errno != ENOENT) 176 fatal("control: cannot unlink socket"); 177 178 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 179 if (bind(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) { 180 (void)umask(old_umask); 181 fatal("control: bind"); 182 } 183 (void)umask(old_umask); 184 185 if (chmod(SMTPD_SOCKET, 186 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) == -1) { 187 (void)unlink(SMTPD_SOCKET); 188 fatal("control: chmod"); 189 } 190 191 io_set_nonblocking(fd); 192 control_state.fd = fd; 193 194 return fd; 195 } 196 197 int 198 control(void) 199 { 200 struct passwd *pw; 201 202 purge_config(PURGE_EVERYTHING); 203 204 if ((pw = getpwnam(SMTPD_USER)) == NULL) 205 fatalx("unknown user " SMTPD_USER); 206 207 stat_backend = env->sc_stat; 208 stat_backend->init(); 209 210 if (chroot(PATH_CHROOT) == -1) 211 fatal("control: chroot"); 212 if (chdir("/") == -1) 213 fatal("control: chdir(\"/\")"); 214 215 config_process(PROC_CONTROL); 216 217 if (setgroups(1, &pw->pw_gid) || 218 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 219 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 220 fatal("control: cannot drop privileges"); 221 222 imsg_callback = control_imsg; 223 event_init(); 224 225 signal(SIGINT, SIG_IGN); 226 signal(SIGTERM, SIG_IGN); 227 signal(SIGPIPE, SIG_IGN); 228 signal(SIGHUP, SIG_IGN); 229 230 tree_init(&ctl_conns); 231 tree_init(&ctl_count); 232 233 memset(&digest, 0, sizeof digest); 234 digest.startup = time(NULL); 235 236 config_peer(PROC_SCHEDULER); 237 config_peer(PROC_QUEUE); 238 config_peer(PROC_PARENT); 239 config_peer(PROC_LKA); 240 config_peer(PROC_DISPATCHER); 241 config_peer(PROC_CA); 242 243 control_listen(); 244 245 if (pledge("stdio unix recvfd sendfd", NULL) == -1) 246 fatal("pledge"); 247 248 event_dispatch(); 249 fatalx("exited event loop"); 250 251 return (0); 252 } 253 254 static void 255 control_shutdown(void) 256 { 257 log_debug("debug: control agent exiting"); 258 _exit(0); 259 } 260 261 static void 262 control_listen(void) 263 { 264 if (listen(control_state.fd, CONTROL_BACKLOG) == -1) 265 fatal("control_listen"); 266 267 event_set(&control_state.ev, control_state.fd, EV_READ|EV_PERSIST, 268 control_accept, NULL); 269 event_add(&control_state.ev, NULL); 270 } 271 272 static void 273 control_accept(int listenfd, short event, void *arg) 274 { 275 int connfd; 276 socklen_t len; 277 struct sockaddr_un s_un; 278 struct ctl_conn *c; 279 size_t *count; 280 uid_t euid; 281 gid_t egid; 282 283 if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE) 284 goto pause; 285 286 len = sizeof(s_un); 287 if ((connfd = accept(listenfd, (struct sockaddr *)&s_un, &len)) == -1) { 288 if (errno == ENFILE || errno == EMFILE) 289 goto pause; 290 if (errno == EINTR || errno == EWOULDBLOCK || 291 errno == ECONNABORTED) 292 return; 293 fatal("control_accept: accept"); 294 } 295 296 io_set_nonblocking(connfd); 297 298 if (getpeereid(connfd, &euid, &egid) == -1) 299 fatal("getpeereid"); 300 301 count = tree_get(&ctl_count, euid); 302 if (count == NULL) { 303 count = xcalloc(1, sizeof *count); 304 tree_xset(&ctl_count, euid, count); 305 } 306 307 if (*count == CONTROL_MAXCONN_PER_CLIENT) { 308 close(connfd); 309 log_warnx("warn: too many connections to control socket " 310 "from user with uid %lu", (unsigned long int)euid); 311 return; 312 } 313 (*count)++; 314 315 do { 316 ++connid; 317 } while (tree_get(&ctl_conns, connid)); 318 319 c = xcalloc(1, sizeof(*c)); 320 c->euid = euid; 321 c->egid = egid; 322 c->id = connid; 323 c->mproc.proc = PROC_CLIENT; 324 c->mproc.handler = control_dispatch_ext; 325 c->mproc.data = c; 326 if ((c->mproc.name = strdup(proc_title(c->mproc.proc))) == NULL) 327 fatal("strdup"); 328 mproc_init(&c->mproc, connfd); 329 mproc_enable(&c->mproc); 330 tree_xset(&ctl_conns, c->id, c); 331 332 stat_backend->increment("control.session", 1); 333 return; 334 335 pause: 336 log_warnx("warn: ctl client limit hit, disabling new connections"); 337 event_del(&control_state.ev); 338 } 339 340 static void 341 control_close(struct ctl_conn *c) 342 { 343 size_t *count; 344 345 count = tree_xget(&ctl_count, c->euid); 346 (*count)--; 347 if (*count == 0) { 348 tree_xpop(&ctl_count, c->euid); 349 free(count); 350 } 351 tree_xpop(&ctl_conns, c->id); 352 mproc_clear(&c->mproc); 353 free(c); 354 355 stat_backend->decrement("control.session", 1); 356 357 if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE) 358 return; 359 360 if (!event_pending(&control_state.ev, EV_READ, NULL)) { 361 log_warnx("warn: re-enabling ctl connections"); 362 event_add(&control_state.ev, NULL); 363 } 364 } 365 366 static void 367 control_digest_update(const char *key, size_t value, int incr) 368 { 369 size_t *p; 370 371 p = NULL; 372 373 if (!strcmp(key, "smtp.session")) { 374 if (incr) 375 p = &digest.clt_connect; 376 else 377 digest.clt_disconnect += value; 378 } 379 else if (!strcmp(key, "scheduler.envelope")) { 380 if (incr) 381 p = &digest.evp_enqueued; 382 else 383 digest.evp_dequeued += value; 384 } 385 else if (!strcmp(key, "scheduler.envelope.expired")) 386 p = &digest.evp_expired; 387 else if (!strcmp(key, "scheduler.envelope.removed")) 388 p = &digest.evp_removed; 389 else if (!strcmp(key, "scheduler.delivery.ok")) 390 p = &digest.dlv_ok; 391 else if (!strcmp(key, "scheduler.delivery.permfail")) 392 p = &digest.dlv_permfail; 393 else if (!strcmp(key, "scheduler.delivery.tempfail")) 394 p = &digest.dlv_tempfail; 395 else if (!strcmp(key, "scheduler.delivery.loop")) 396 p = &digest.dlv_loop; 397 398 else if (!strcmp(key, "queue.bounce")) 399 p = &digest.evp_bounce; 400 401 if (p) { 402 if (incr) 403 *p = *p + value; 404 else 405 *p = *p - value; 406 } 407 } 408 409 static void 410 control_dispatch_ext(struct mproc *p, struct imsg *imsg) 411 { 412 struct sockaddr_storage ss; 413 struct ctl_conn *c; 414 int v; 415 struct stat_kv *kvp; 416 char *key; 417 struct stat_value val; 418 size_t len; 419 uint64_t evpid; 420 uint32_t msgid; 421 422 c = p->data; 423 424 if (imsg == NULL) { 425 control_close(c); 426 return; 427 } 428 429 if (imsg->hdr.peerid != IMSG_VERSION) { 430 m_compose(p, IMSG_CTL_FAIL, IMSG_VERSION, 0, -1, NULL, 0); 431 return; 432 } 433 434 switch (imsg->hdr.type) { 435 case IMSG_CTL_SMTP_SESSION: 436 if (env->sc_flags & SMTPD_SMTP_PAUSED) { 437 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 438 return; 439 } 440 m_compose(p_dispatcher, IMSG_CTL_SMTP_SESSION, c->id, 0, -1, 441 &c->euid, sizeof(c->euid)); 442 return; 443 444 case IMSG_CTL_GET_DIGEST: 445 if (c->euid) 446 goto badcred; 447 digest.timestamp = time(NULL); 448 m_compose(p, IMSG_CTL_GET_DIGEST, 0, 0, -1, &digest, sizeof digest); 449 return; 450 451 case IMSG_CTL_GET_STATS: 452 if (c->euid) 453 goto badcred; 454 kvp = imsg->data; 455 if (!stat_backend->iter(&kvp->iter, &key, &val)) 456 kvp->iter = NULL; 457 else { 458 (void)strlcpy(kvp->key, key, sizeof kvp->key); 459 kvp->val = val; 460 } 461 m_compose(p, IMSG_CTL_GET_STATS, 0, 0, -1, kvp, sizeof *kvp); 462 return; 463 464 case IMSG_CTL_VERBOSE: 465 if (c->euid) 466 goto badcred; 467 468 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 469 goto badcred; 470 471 memcpy(&v, imsg->data, sizeof(v)); 472 log_trace_verbose(v); 473 474 control_broadcast_verbose(IMSG_CTL_VERBOSE, v); 475 476 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 477 return; 478 479 case IMSG_CTL_TRACE_ENABLE: 480 if (c->euid) 481 goto badcred; 482 483 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 484 goto badcred; 485 486 memcpy(&v, imsg->data, sizeof(v)); 487 tracing |= v; 488 log_trace_verbose(tracing); 489 490 control_broadcast_verbose(IMSG_CTL_VERBOSE, tracing); 491 492 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 493 return; 494 495 case IMSG_CTL_TRACE_DISABLE: 496 if (c->euid) 497 goto badcred; 498 499 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 500 goto badcred; 501 502 memcpy(&v, imsg->data, sizeof(v)); 503 tracing &= ~v; 504 log_trace_verbose(tracing); 505 506 control_broadcast_verbose(IMSG_CTL_VERBOSE, tracing); 507 508 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 509 return; 510 511 case IMSG_CTL_PROFILE_ENABLE: 512 if (c->euid) 513 goto badcred; 514 515 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 516 goto badcred; 517 518 memcpy(&v, imsg->data, sizeof(v)); 519 profiling |= v; 520 521 control_broadcast_verbose(IMSG_CTL_PROFILE, profiling); 522 523 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 524 return; 525 526 case IMSG_CTL_PROFILE_DISABLE: 527 if (c->euid) 528 goto badcred; 529 530 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(v)) 531 goto badcred; 532 533 memcpy(&v, imsg->data, sizeof(v)); 534 profiling &= ~v; 535 536 control_broadcast_verbose(IMSG_CTL_PROFILE, profiling); 537 538 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 539 return; 540 541 case IMSG_CTL_PAUSE_EVP: 542 if (c->euid) 543 goto badcred; 544 545 imsg->hdr.peerid = c->id; 546 m_forward(p_scheduler, imsg); 547 return; 548 549 case IMSG_CTL_PAUSE_MDA: 550 if (c->euid) 551 goto badcred; 552 553 if (env->sc_flags & SMTPD_MDA_PAUSED) { 554 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 555 return; 556 } 557 log_info("info: mda paused"); 558 env->sc_flags |= SMTPD_MDA_PAUSED; 559 m_compose(p_queue, IMSG_CTL_PAUSE_MDA, 0, 0, -1, NULL, 0); 560 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 561 return; 562 563 case IMSG_CTL_PAUSE_MTA: 564 if (c->euid) 565 goto badcred; 566 567 if (env->sc_flags & SMTPD_MTA_PAUSED) { 568 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 569 return; 570 } 571 log_info("info: mta paused"); 572 env->sc_flags |= SMTPD_MTA_PAUSED; 573 m_compose(p_queue, IMSG_CTL_PAUSE_MTA, 0, 0, -1, NULL, 0); 574 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 575 return; 576 577 case IMSG_CTL_PAUSE_SMTP: 578 if (c->euid) 579 goto badcred; 580 581 if (env->sc_flags & SMTPD_SMTP_PAUSED) { 582 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 583 return; 584 } 585 log_info("info: smtp paused"); 586 env->sc_flags |= SMTPD_SMTP_PAUSED; 587 m_compose(p_dispatcher, IMSG_CTL_PAUSE_SMTP, 0, 0, -1, NULL, 0); 588 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 589 return; 590 591 case IMSG_CTL_RESUME_EVP: 592 if (c->euid) 593 goto badcred; 594 595 imsg->hdr.peerid = c->id; 596 m_forward(p_scheduler, imsg); 597 return; 598 599 case IMSG_CTL_RESUME_MDA: 600 if (c->euid) 601 goto badcred; 602 603 if (!(env->sc_flags & SMTPD_MDA_PAUSED)) { 604 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 605 return; 606 } 607 log_info("info: mda resumed"); 608 env->sc_flags &= ~SMTPD_MDA_PAUSED; 609 m_compose(p_queue, IMSG_CTL_RESUME_MDA, 0, 0, -1, NULL, 0); 610 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 611 return; 612 613 case IMSG_CTL_RESUME_MTA: 614 if (c->euid) 615 goto badcred; 616 617 if (!(env->sc_flags & SMTPD_MTA_PAUSED)) { 618 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 619 return; 620 } 621 log_info("info: mta resumed"); 622 env->sc_flags &= ~SMTPD_MTA_PAUSED; 623 m_compose(p_queue, IMSG_CTL_RESUME_MTA, 0, 0, -1, NULL, 0); 624 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 625 return; 626 627 case IMSG_CTL_RESUME_SMTP: 628 if (c->euid) 629 goto badcred; 630 631 if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) { 632 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 633 return; 634 } 635 log_info("info: smtp resumed"); 636 env->sc_flags &= ~SMTPD_SMTP_PAUSED; 637 m_forward(p_dispatcher, imsg); 638 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 639 return; 640 641 case IMSG_CTL_RESUME_ROUTE: 642 if (c->euid) 643 goto badcred; 644 645 m_forward(p_dispatcher, imsg); 646 m_compose(p, IMSG_CTL_OK, 0, 0, -1, NULL, 0); 647 return; 648 649 case IMSG_CTL_LIST_MESSAGES: 650 if (c->euid) 651 goto badcred; 652 m_compose(p_scheduler, IMSG_CTL_LIST_MESSAGES, c->id, 0, -1, 653 imsg->data, imsg->hdr.len - sizeof(imsg->hdr)); 654 return; 655 656 case IMSG_CTL_LIST_ENVELOPES: 657 if (c->euid) 658 goto badcred; 659 m_compose(p_scheduler, IMSG_CTL_LIST_ENVELOPES, c->id, 0, -1, 660 imsg->data, imsg->hdr.len - sizeof(imsg->hdr)); 661 return; 662 663 case IMSG_CTL_MTA_SHOW_HOSTS: 664 case IMSG_CTL_MTA_SHOW_RELAYS: 665 case IMSG_CTL_MTA_SHOW_ROUTES: 666 case IMSG_CTL_MTA_SHOW_HOSTSTATS: 667 case IMSG_CTL_MTA_SHOW_BLOCK: 668 if (c->euid) 669 goto badcred; 670 671 imsg->hdr.peerid = c->id; 672 m_forward(p_dispatcher, imsg); 673 return; 674 675 case IMSG_CTL_SHOW_STATUS: 676 if (c->euid) 677 goto badcred; 678 679 m_compose(p, IMSG_CTL_SHOW_STATUS, 0, 0, -1, &env->sc_flags, 680 sizeof(env->sc_flags)); 681 return; 682 683 case IMSG_CTL_MTA_BLOCK: 684 case IMSG_CTL_MTA_UNBLOCK: 685 if (c->euid) 686 goto badcred; 687 688 if (imsg->hdr.len - IMSG_HEADER_SIZE <= sizeof(ss)) 689 goto invalid; 690 memmove(&ss, imsg->data, sizeof(ss)); 691 m_create(p_dispatcher, imsg->hdr.type, c->id, 0, -1); 692 m_add_sockaddr(p_dispatcher, (struct sockaddr *)&ss); 693 m_add_string(p_dispatcher, (char *)imsg->data + sizeof(ss)); 694 m_close(p_dispatcher); 695 return; 696 697 case IMSG_CTL_SCHEDULE: 698 if (c->euid) 699 goto badcred; 700 701 imsg->hdr.peerid = c->id; 702 m_forward(p_scheduler, imsg); 703 return; 704 705 case IMSG_CTL_REMOVE: 706 if (c->euid) 707 goto badcred; 708 709 imsg->hdr.peerid = c->id; 710 m_forward(p_scheduler, imsg); 711 return; 712 713 case IMSG_CTL_UPDATE_TABLE: 714 if (c->euid) 715 goto badcred; 716 717 /* table name too long */ 718 len = strlen(imsg->data); 719 if (len >= LINE_MAX) 720 goto invalid; 721 722 imsg->hdr.peerid = c->id; 723 m_forward(p_lka, imsg); 724 return; 725 726 case IMSG_CTL_DISCOVER_EVPID: 727 if (c->euid) 728 goto badcred; 729 730 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof evpid) 731 goto invalid; 732 733 memmove(&evpid, imsg->data, sizeof evpid); 734 m_create(p_queue, imsg->hdr.type, c->id, 0, -1); 735 m_add_evpid(p_queue, evpid); 736 m_close(p_queue); 737 return; 738 739 case IMSG_CTL_DISCOVER_MSGID: 740 if (c->euid) 741 goto badcred; 742 743 if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof msgid) 744 goto invalid; 745 746 memmove(&msgid, imsg->data, sizeof msgid); 747 m_create(p_queue, imsg->hdr.type, c->id, 0, -1); 748 m_add_msgid(p_queue, msgid); 749 m_close(p_queue); 750 return; 751 752 default: 753 log_debug("debug: control_dispatch_ext: " 754 "error handling %s imsg", 755 imsg_to_str(imsg->hdr.type)); 756 return; 757 } 758 badcred: 759 invalid: 760 m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0); 761 } 762 763 static void 764 control_broadcast_verbose(int msg, int v) 765 { 766 m_create(p_lka, msg, 0, 0, -1); 767 m_add_int(p_lka, v); 768 m_close(p_lka); 769 770 m_create(p_dispatcher, msg, 0, 0, -1); 771 m_add_int(p_dispatcher, v); 772 m_close(p_dispatcher); 773 774 m_create(p_queue, msg, 0, 0, -1); 775 m_add_int(p_queue, v); 776 m_close(p_queue); 777 778 m_create(p_ca, msg, 0, 0, -1); 779 m_add_int(p_ca, v); 780 m_close(p_ca); 781 782 m_create(p_scheduler, msg, 0, 0, -1); 783 m_add_int(p_scheduler, v); 784 m_close(p_scheduler); 785 786 m_create(p_parent, msg, 0, 0, -1); 787 m_add_int(p_parent, v); 788 m_close(p_parent); 789 } 790